]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
ensure alsa mixer is initialised before trying to set volume. Normalise the 'pvol...
authorMike Brady <mikebrady@eircom.net>
Tue, 10 Sep 2019 12:03:54 +0000 (13:03 +0100)
committerMike Brady <mikebrady@eircom.net>
Tue, 10 Sep 2019 12:03:54 +0000 (13:03 +0100)
audio_alsa.c
player.c

index 454d27ff8c365f9d3f80c127416ce6c18826460f..22aad33393719d535b2fa009f57879b715fd5559 100644 (file)
@@ -139,9 +139,8 @@ static long alsa_mix_mindb, alsa_mix_maxdb;
 
 static char *alsa_out_dev = "default";
 static char *alsa_mix_dev = NULL;
-static char *alsa_mix_ctrl = "Master";
+static char *alsa_mix_ctrl = NULL;
 static int alsa_mix_index = 0;
-static int hardware_mixer = 0;
 static int has_softvol = 0;
 
 int64_t dither_random_number_store = 0;
@@ -204,7 +203,7 @@ int precision_delay_available() {
     } else {
       pthread_cleanup_push(malloc_cleanup, silence);
       int use_dither = 0;
-      if ((hardware_mixer == 0) && (config.ignore_volume_control == 0) &&
+      if ((alsa_mix_ctrl == NULL) && (config.ignore_volume_control == 0) &&
           (config.airplay_volume != 0.0))
         use_dither = 1;
       dither_random_number_store =
@@ -279,7 +278,7 @@ void set_alsa_out_dev(char *dev) { alsa_out_dev = dev; }
 // assuming pthread cancellation is disabled
 int open_mixer() {
   int response = 0;
-  if (hardware_mixer) {
+  if (alsa_mix_ctrl != NULL) {
     debug(3, "Open Mixer");
     int ret = 0;
     snd_mixer_selem_id_alloca(&alsa_mix_sid);
@@ -865,15 +864,17 @@ int open_alsa_device(int do_auto_setup) {
   return result;
 }
 
-int do_alsa_device_init_if_needed() {
+int prepare_mixer() {
   int response = 0;
-  // do any alsa device initialisation (general case) if needed
+  // do any alsa device initialisation (general case)
   // at present, this is only needed if a hardware mixer is being used
-  // if there's a hardware mixer, it needs to be initialised before first use
-  if (alsa_device_initialised == 0) {
-    alsa_device_initialised = 1;
-    if (hardware_mixer) {
-      debug(2, "alsa: hardware mixer init");
+  // if there's a hardware mixer, it needs to be initialised before use
+    if (alsa_mix_ctrl == NULL) {
+      audio_alsa.volume = NULL;
+      audio_alsa.parameters = NULL;
+      audio_alsa.mute = NULL;
+    } else {
+      debug(2, "alsa: hardware mixer prepare");
       int oldState;
       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState); // make this un-cancellable
 
@@ -975,10 +976,14 @@ int do_alsa_device_init_if_needed() {
       pthread_cleanup_pop(0);
       pthread_setcancelstate(oldState, NULL);
     }
-  }
   return response;
 }
 
+int alsa_device_init() {
+  return prepare_mixer();
+}
+
+
 static int init(int argc, char **argv) {
   // for debugging
   snd_output_stdio_attach(&output, stdout, 0);
@@ -1050,7 +1055,6 @@ static int init(int argc, char **argv) {
     /* Get the Mixer Control Name. */
     if (config_lookup_string(config.cfg, "alsa.mixer_control_name", &str)) {
       alsa_mix_ctrl = (char *)str;
-      hardware_mixer = 1;
     }
 
     /* Get the disable_synchronization setting. */
@@ -1325,7 +1329,6 @@ static int init(int argc, char **argv) {
       break;
     case 'c':
       alsa_mix_ctrl = optarg;
-      hardware_mixer = 1;
       break;
     case 'i':
       alsa_mix_index = strtol(optarg, NULL, 10);
@@ -1412,8 +1415,9 @@ static void start(__attribute__((unused)) int i_sample_rate,
   stall_monitor_start_time = 0;
   stall_monitor_frame_count = 0;
   if (alsa_device_initialised == 0) {
-    debug(2, "alsa: start() calling do_alsa_device_init_if_needed.");
-    do_alsa_device_init_if_needed();
+    debug(1, "alsa: start() calling alsa_device_init.");
+    alsa_device_init();
+    alsa_device_initialised = 1;
   }
 }
 
@@ -1799,6 +1803,11 @@ int prepare(void) {
   pthread_cleanup_debug_mutex_lock(&alsa_mutex, 50000, 0);
 
   if (alsa_backend_state == abm_disconnected) {
+    if (alsa_device_initialised == 0) {
+      debug(1, "alsa: prepare() calling alsa_device_init.");
+      alsa_device_init();
+      alsa_device_initialised = 1;
+    }
     ret = do_open(1); // do auto setup
     if (ret == 0)
       debug(2, "alsa: prepare() -- opened output device");
@@ -1891,7 +1900,7 @@ void volume(double vol) {
 static void linear_volume(double vol) {
   debug(2, "Setting linear volume to %f.", vol);
   set_volume = vol;
-  if (hardware_mixer && alsa_mix_handle) {
+  if ((alsa_mix_ctrl == NULL) && alsa_mix_handle) {
     double linear_volume = pow(10, vol);
     // debug(1,"Linear volume is %f.",linear_volume);
     long int_vol = alsa_mix_minv + (alsa_mix_maxv - alsa_mix_minv) *
@@ -1933,8 +1942,9 @@ void *alsa_buffer_monitor_thread_code(__attribute__((unused)) void *arg) {
     }
     if ((config.keep_dac_busy != 0) && (alsa_device_initialised == 0)) {
       debug(2, "alsa: alsa_buffer_monitor_thread_code() calling "
-               "do_alsa_device_init_if_needed.");
-      do_alsa_device_init_if_needed();
+               "alsa_device_init.");
+      alsa_device_init();
+      alsa_device_initialised = 1;
     }
     int sleep_time_ms = (int)(config.disable_standby_mode_silence_scan_interval * 1000);
     pthread_cleanup_debug_mutex_lock(&alsa_mutex, 200000, 0);
@@ -1992,7 +2002,7 @@ void *alsa_buffer_monitor_thread_code(__attribute__((unused)) void *arg) {
             int ret;
             pthread_cleanup_push(malloc_cleanup, silence);
             int use_dither = 0;
-            if ((hardware_mixer == 0) && (config.ignore_volume_control == 0) &&
+            if ((alsa_mix_ctrl == NULL) && (config.ignore_volume_control == 0) &&
                 (config.airplay_volume != 0.0))
               use_dither = 1;
             dither_random_number_store =
index ba1c07a6e952360df2036873bf206c07eb53e0fe..9ad4d0511e911127dd77346b1c64184faf828ef5 100644 (file)
--- a/player.c
+++ b/player.c
@@ -2689,7 +2689,6 @@ void *player_thread_func(void *arg) {
 
 void player_volume_without_notification(double airplay_volume, rtsp_conn_info *conn) {
   debug_mutex_lock(&conn->volume_control_mutex, 5000, 1);
-  debug(2, "player_volume_without_notification %f", airplay_volume);
   // first, see if we are hw only, sw only, both with hw attenuation on the top or both with sw
   // attenuation on top
 
@@ -2701,6 +2700,7 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
 
   int32_t hw_max_db = 0, hw_min_db = 0; // zeroed to quieten an incorrect uninitialised warning
   int32_t sw_max_db = 0, sw_min_db = -9630;
+  
   if (config.output->parameters) {
     volume_mode = vol_hw_only;
     audio_parameters audio_information;
@@ -2877,8 +2877,14 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
       char *dv = malloc(128); // will be freed in the metadata thread
       if (dv) {
         memset(dv, 0, 128);
-        snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, scaled_attenuation / 100.0,
+        if (volume_mode == vol_both) {
+          // normalise the maximum output to the hardware device's max output
+          snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, (scaled_attenuation - max_db + hw_max_db) / 100.0,
+                   (min_db - max_db + hw_max_db) / 100.0, (max_db - max_db + hw_max_db) / 100.0);        
+        } else {
+          snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, scaled_attenuation / 100.0,
                    min_db / 100.0, max_db / 100.0);
+        }
         send_ssnc_metadata('pvol', dv, strlen(dv), 1);
       }
 #endif
@@ -2898,7 +2904,7 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
 #ifdef CONFIG_METADATA
  else {
       // here, send the 'pvol' metadata message when the airplay volume information
-      // is not being used by shairport sync to control the output volume
+      // is being used by shairport sync to control the output volume
       char *dv = malloc(128); // will be freed in the metadata thread
       if (dv) {
         memset(dv, 0, 128);