From: Mike Brady Date: Sun, 30 Apr 2017 14:29:22 +0000 (+0100) Subject: Only set volume if it has been asked for externally. Clean up mute. Add ability do... X-Git-Tag: 3.1d16~43 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fc492bea3a4e14a93d33848cc62ca2216d733160;p=thirdparty%2Fshairport-sync.git Only set volume if it has been asked for externally. Clean up mute. Add ability do disable hardware mute --- diff --git a/audio_alsa.c b/audio_alsa.c index 43542ec5..297ea7ea 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -44,6 +44,9 @@ static void stop(void); static void flush(void); int delay(long *the_delay); static void volume(double vol); +void do_volume(double vol); +void do_mute(int request); + static void linear_volume(double vol); static void parameters(audio_parameters *info); static void mute(int do_mute); @@ -84,6 +87,10 @@ static char *alsa_mix_ctrl = "Master"; static int alsa_mix_index = 0; static int hardware_mixer = 0; static int has_softvol = 0; +static int volume_set_request = 0; // set when an external request is made to set the volume. +int mute_request_pending = 0; // set when an external request is made to mute or unmute. +int mute_request_state = 0; // 1 = mute; 0 = unmute requested +int use_playback_switch_for_mute = 1; // set to 0 for some cards, e.g. VMWare Fusion's emulated sound card static snd_pcm_sframes_t (*alsa_pcm_write)(snd_pcm_t *, const void *, snd_pcm_uframes_t) = snd_pcm_writei; @@ -138,6 +145,7 @@ static int init(int argc, char **argv) { set_period_size_request = 0; set_buffer_size_request = 0; + use_playback_switch_for_mute = 1; config.audio_backend_latency_offset = 0; config.audio_backend_buffer_desired_length = 0.15; @@ -235,7 +243,17 @@ static int init(int argc, char **argv) { else die("Invalid disable_synchronization option choice \"%s\". It should be \"yes\" or \"no\""); } - + + /* Get the mute_using_playback_switch setting. */ + if (config_lookup_string(config.cfg, "alsa.mute_using_playback_switch", &str)) { + if (strcasecmp(str, "no") == 0) + use_playback_switch_for_mute = 0; + else if (strcasecmp(str, "yes") == 0) + use_playback_switch_for_mute = 1; + else + die("Invalid mute_use_playback_switch option choice \"%s\". It should be \"yes\" or \"no\""); + } + /* Get the output format, using the same names as aplay does*/ if (config_lookup_string(config.cfg, "alsa.output_format", &str)) { if (strcasecmp(str, "S16") == 0) @@ -411,9 +429,9 @@ static int init(int argc, char **argv) { */ } } - if (snd_mixer_selem_has_playback_switch(alsa_mix_elem)) { + if ((use_playback_switch_for_mute==1) && (snd_mixer_selem_has_playback_switch(alsa_mix_elem))) { audio_alsa.mute = &mute; // insert the mute function now we know it can do muting stuff - debug(1, "Has mute ability."); + debug(1, "Has mute ability we will use."); } snd_mixer_close(alsa_mix_handle); @@ -806,16 +824,11 @@ static void play(short buf[], int samples) { ret = open_alsa_device(); if (hardware_mixer) open_mixer(); - pthread_mutex_unlock(&alsa_mutex); - // the mutex must be unlocked for the following call to proceed if ((hardware_mixer) && (ret == 0) && (audio_alsa.volume)) - audio_alsa.volume(set_volume); - - pthread_mutex_lock(&alsa_mutex); - int derr; - if (hardware_mixer && alsa_mix_handle) { - // debug(1,"unmute"); - snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 1); + do_volume(set_volume); + if ((hardware_mixer) && (audio_alsa.mute)) { + // debug(1,"Play unmute"); + do_mute(0); } pthread_mutex_unlock(&alsa_mutex); } @@ -854,8 +867,8 @@ static void flush(void) { pthread_mutex_lock(&alsa_mutex); int derr; if (hardware_mixer && alsa_mix_handle) { - // debug(1,"Mute"); - snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 0); + // debug(1,"Flush mute"); + do_mute(1); snd_mixer_close(alsa_mix_handle); alsa_mix_handle = NULL; } @@ -918,8 +931,7 @@ static void parameters(audio_parameters *info) { info->maximum_volume_dB = alsa_mix_maxdb; } -static void volume(double vol) { - pthread_mutex_lock(&alsa_mutex); +void do_volume(double vol) { // caller is assumed to have the alsa_mutex when using this function debug(3, "Setting volume db to %f.", vol); set_volume = vol; if (hardware_mixer && alsa_mix_handle) { @@ -948,7 +960,15 @@ static void volume(double vol) { debug(1,"Could not set playback dB volume on the mixer."); } } + volume_set_request = 0; // any external request that has been made is now satisfied + // debug(1,"Alsa volume actually set."); } +} + +void volume(double vol) { + pthread_mutex_lock(&alsa_mutex); + volume_set_request = 1; // an external request has been made to set the volume + do_volume(vol); pthread_mutex_unlock(&alsa_mutex); } @@ -967,17 +987,32 @@ static void linear_volume(double vol) { } } -static void mute(int do_mute) { +static void mute(int mute_state_requested) { + // debug(1,"External Mute Request"); pthread_mutex_lock(&alsa_mutex); - // debug(2,"audio_alsa mute called."); + mute_request_pending = 1; + mute_request_state = mute_state_requested; + do_mute(mute_state_requested); + pthread_mutex_unlock(&alsa_mutex); +} + +void do_mute(int mute_state_requested) { + // The mute state requested will be actioned unless mute_request_pending is set + // If it is set, then that will be actioned. + // If the hardware isn't there, or we are not allowed to use it, nothing will be done + // The caller must have the alsa mutex if (hardware_mixer && alsa_mix_handle) { - if (do_mute) { - // debug(1,"Mute"); - snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 0); - } else { - // debug(1,"Unmute"); - snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 1); + if (use_playback_switch_for_mute==1) { + if (mute_request_pending==0) + mute_request_state = mute_state_requested; + if (mute_request_state) { + // debug(1,"Playback Switch mute actually done"); + snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 0); + } else { + // debug(1,"Playback Switch unmute actually done"); + snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 1); + } } + mute_request_pending = 0; } - pthread_mutex_unlock(&alsa_mutex); }