From: Mike Brady Date: Sat, 13 Jan 2018 20:09:51 +0000 (+0000) Subject: Take advantage of the mute capability of a device that mutes at its lowest setting X-Git-Tag: 3.2d29~124 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a4bfb037892c95adc4455df93a57b927f55a160;p=thirdparty%2Fshairport-sync.git Take advantage of the mute capability of a device that mutes at its lowest setting --- diff --git a/audio_alsa.c b/audio_alsa.c index ab7b7a90..85b93551 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -88,9 +88,13 @@ 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 overriding_mute_state_requested = 0; // 1 = mute; 0 = unmute requested +int mixer_volume_setting_gives_mute = 0; // set when it is discovered that particular mixer volume setting causes a mute. +long alsa_mix_mute; // setting the volume to this value mutes output, if mixer_volume_setting_gives_mute is true +int volume_based_mute_is_active = 0; // set when muting is being done by a setting the volume to a magic value static snd_pcm_sframes_t (*alsa_pcm_write)(snd_pcm_t *, const void *, snd_pcm_uframes_t) = snd_pcm_writei; @@ -148,9 +152,14 @@ void close_mixer() { } } -#define RELEASE_ALSA_MUTEX_AND_DIE(X) \ - pthread_mutex_unlock(&alsa_mutex); \ - die(X); +void do_snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t * mix_elem, double vol) { + if (snd_mixer_selem_set_playback_dB_all(mix_elem, vol, 0) != 0) { + debug(1, "Can't set playback volume accurately to %f dB.", vol); + if (snd_mixer_selem_set_playback_dB_all(mix_elem, vol, -1) != 0) + if (snd_mixer_selem_set_playback_dB_all(mix_elem, vol, 1) != 0) + debug(1, "Could not set playback dB volume on the mixer."); + } +} static int init(int argc, char **argv) { pthread_mutex_lock(&alsa_mutex); @@ -365,8 +374,11 @@ static int init(int argc, char **argv) { audio_alsa.volume = &volume; // insert the volume function now we know it can do dB stuff audio_alsa.parameters = ¶meters; // likewise the parameters stuff if (alsa_mix_mindb == SND_CTL_TLV_DB_GAIN_MUTE) { - // Raspberry Pi does this - debug(1, "Lowest dB value is a mute -- try minimum volume +1"); + // For instance, the Raspberry Pi does this + debug(1, "Lowest dB value is a mute"); + mixer_volume_setting_gives_mute = 1; + alsa_mix_mute = SND_CTL_TLV_DB_GAIN_MUTE; // this may not be necessary -- it's always going to be SND_CTL_TLV_DB_GAIN_MUTE, right? + debug(1, "Lowest dB value is a mute -- try minimum volume + 1 as lowest true attenuation value"); if (snd_mixer_selem_ask_playback_vol_dB(alsa_mix_elem, alsa_mix_minv + 1, &alsa_mix_mindb) != 0) debug(1, "Can't get dB value corresponding to a minimum volume + 1."); @@ -417,7 +429,7 @@ static int init(int argc, char **argv) { } } if ((config.alsa_use_playback_switch_for_mute == 1) && - (snd_mixer_selem_has_playback_switch(alsa_mix_elem))) { + (snd_mixer_selem_has_playback_switch(alsa_mix_elem)) || mixer_volume_setting_gives_mute) { audio_alsa.mute = &mute; // insert the mute function now we know it can do muting stuff // debug(1, "Has mixer and mute ability we will use."); } else { @@ -949,11 +961,10 @@ void do_volume(double vol) { // caller is assumed to have the alsa_mutex when us "control."); } } else { - if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, 0) != 0) { - debug(1, "Can't set playback volume accurately to %f dB.", vol); - if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, -1) != 0) - if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, 1) != 0) - debug(1, "Could not set playback dB volume on the mixer."); + if (volume_based_mute_is_active==0) + do_snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol); + else { + debug(1,"Not setting volume because volume-based mute is active"); } } volume_set_request = 0; // any external request that has been made is now satisfied @@ -1011,16 +1022,28 @@ void do_mute(int mute_state_requested) { // 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 (config.alsa_use_playback_switch_for_mute == 1) { + if ((config.alsa_use_playback_switch_for_mute == 1) || mixer_volume_setting_gives_mute){ if (mute_request_pending == 0) local_mute_state_requested = mute_state_requested; if (open_mixer()) { if (local_mute_state_requested) { // debug(1,"Playback Switch mute actually done"); - snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 0); + if (config.alsa_use_playback_switch_for_mute == 1) + snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 0); + else { + debug(1,"Activating volume-based mute."); + volume_based_mute_is_active = 1; + do_snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, alsa_mix_mute); + } } else if (overriding_mute_state_requested == 0) { // debug(1,"Playback Switch unmute actually done"); - snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 1); + if (config.alsa_use_playback_switch_for_mute == 1) + snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 1); + else { + debug(1,"Deactivating volume-based mute."); + volume_based_mute_is_active = 0; + do_snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, set_volume); + } } close_mixer(); }