]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Take advantage of the mute capability of a device that mutes at its lowest setting
authorMike Brady <mikebrady@eircom.net>
Sat, 13 Jan 2018 20:09:51 +0000 (20:09 +0000)
committerMike Brady <mikebrady@eircom.net>
Sat, 13 Jan 2018 20:09:51 +0000 (20:09 +0000)
audio_alsa.c

index ab7b7a90d175a03a9c3f835a2dbe10877aa518bb..85b935515bec8494cb54e58c5f297e39833c8027 100644 (file)
@@ -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 = &parameters; // 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();
     }