]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Work in progress, doesn't compile
authorMike Brady <mikebrady@eircom.net>
Thu, 5 Nov 2015 18:03:58 +0000 (18:03 +0000)
committerMike Brady <mikebrady@eircom.net>
Thu, 5 Nov 2015 18:03:58 +0000 (18:03 +0000)
audio.h
audio_alsa.c
audio_ao.c
audio_dummy.c
audio_pipe.c
audio_pulse.c
audio_sndio.c
audio_stdout.c
common.h
player.c

diff --git a/audio.h b/audio.h
index 4738a0718043b1b0173900f84d7c0276df831269..359f3402f247e5702e61ea1fbb3de1e9ef47716c 100644 (file)
--- a/audio.h
+++ b/audio.h
@@ -5,13 +5,9 @@
 #include <libconfig.h>
 
 typedef struct {
-  double airplay_volume;
   double current_volume_dB;
-  int minimum_volume_dB;
-  int maximum_volume_dB;
-  int has_true_mute;
-  int is_muted;
-  int valid;
+  int32_t minimum_volume_dB;
+  int32_t maximum_volume_dB;
 } audio_parameters;
 
 typedef struct {
@@ -42,6 +38,10 @@ typedef struct {
 
   // may be NULL, in which case soft volume parameters are used
   void (*parameters)(audio_parameters *info);
+  
+  // may be NULL, in which case software muting is used.
+  void (*mute)(int do_mute);
+  
 } audio_output;
 
 audio_output *audio_get_output(char *name);
index f9851f18cfb40eaf91d704c576e215ccf7788287..4a11260d86f7e47842708ddcb0d6ee890f61bcda 100644 (file)
@@ -46,6 +46,7 @@ static uint32_t delay(void);
 static void volume(double vol);
 static void linear_volume(double vol);
 static void parameters(audio_parameters *info);
+static void mute(int do_mute);
 static int has_mute = 0;
 static double set_volume;
 
@@ -234,13 +235,6 @@ static int init(int argc, char **argv) {
       }
       debug(1, "Hardware mixer has dB volume from %f to %f.", (1.0 * alsa_mix_mindb) / 100.0,
             (1.0 * alsa_mix_maxdb) / 100.0);
-      if (config.volume_range_db) {
-        long suggested_alsa_min_db = alsa_mix_maxdb - (long)trunc(config.volume_range_db*100);
-        if (suggested_alsa_min_db > alsa_mix_mindb)
-          alsa_mix_mindb = suggested_alsa_min_db;
-        else
-          inform("The volume_range_db setting, %f is greater than the native range of the mixer %f, so it is ignored.",config.volume_range_db,(alsa_mix_maxdb-alsa_mix_mindb)/100.0);
-      }
     } else {
       // use the linear scale and do the db conversion ourselves
       debug(1, "note: the hardware mixer specified -- \"%s\" -- does not have a dB volume scale, so it can't be used.",alsa_mix_ctrl);
@@ -447,35 +441,30 @@ static void stop(void) {
 }
 
 static void parameters(audio_parameters *info) {
-  info->has_true_mute = has_mute;
-  info->is_muted = ((has_mute) && (set_volume == -144.0));
   info->minimum_volume_dB = alsa_mix_mindb;
   info->maximum_volume_dB = alsa_mix_maxdb;
-  info->airplay_volume = set_volume;
-  info->current_volume_dB = vol2attn(set_volume, alsa_mix_maxdb, alsa_mix_mindb);
 }
 
 static void volume(double vol) {
-  // debug(1,"Volume called %f.",vol);
-  set_volume = vol;
-  double vol_setting = vol2attn(vol, alsa_mix_maxdb, alsa_mix_mindb);
   // debug(1,"Setting volume db to %f, for volume input of %f.",vol_setting/100,vol);
-  if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol_setting, -1) != 0)
+  if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, -1) != 0)
     die("Failed to set playback dB volume");
-  if (has_mute)
-    snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, (vol != -144.0));
 }
 
 static void linear_volume(double vol) {
-  set_volume = vol;
-  double vol_setting = vol2attn(vol, 0, alsa_mix_mindb)/2000;
-  // debug(1,"Adjusted volume is %f.",vol_setting);
-  double linear_volume = pow(10, vol_setting);
+  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) * linear_volume;
   // debug(1,"Setting volume to %ld, for volume input of %f.",int_vol,vol);
   if (snd_mixer_selem_set_playback_volume_all(alsa_mix_elem, int_vol) != 0)
     die("Failed to set playback volume");
-  if (has_mute)
-    snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, (vol != -144.0));
+}
+
+static void mute(int do_mute) {
+  if (has_mute) {
+       if (do_mute)
+       snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 0);
+    else
+       snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 1);    
+  }            
 }
index a6f9cf25fb484d048550c40fed24ef7fe1a541cb..6cd98eaba6c41cac77ff99c7f3ee8bc0ab159e37 100644 (file)
@@ -153,4 +153,5 @@ audio_output audio_ao = {.name = "ao",
                          .delay = NULL,
                          .play = &play,
                          .volume = NULL,
-                         .parameters = NULL};
+                         .parameters = NULL,
+                         .mute = NULL};
index 9742c58cb5cde3ccb8e8a84a3ff7ecf5beaf415d..a544031b3a156e953cc4a1de2b25793132adf991 100644 (file)
@@ -60,4 +60,5 @@ audio_output audio_dummy = {.name = "dummy",
                             .delay = NULL,
                             .play = &play,
                             .volume = NULL,
-                            .parameters = NULL};
+                            .parameters = NULL,
+                            .mute = NULL};
index d38cd8f88f1c68b2d4f20f21213162b5c8154ef7..e18b4e835889b0fa7163ed829b814f552b9c20c6 100644 (file)
@@ -133,4 +133,5 @@ audio_output audio_pipe = {.name = "pipe",
                            .delay = NULL,
                            .play = &play,
                            .volume = NULL,
-                           .parameters = NULL};
+                           .parameters = NULL,
+                           .mute = NULL};
index 29feed88e0db7c13e900251250ab8fb428a882ab..96c547c2729c183fc2560ce4fe54281489cec834 100644 (file)
@@ -137,4 +137,5 @@ audio_output audio_pulse = {.name = "pulse",
                             .delay = NULL,
                             .play = &play,
                             .volume = NULL,
-                            .parameters = NULL};
+                            .parameters = NULL,
+                            .mute = NULL};
index e59dbb85d6afa4a1bf16a6c45c3047a460da3b25..eb3be35d2f7a75c23692c8153f5210dbc8a05427 100644 (file)
@@ -81,4 +81,5 @@ audio_output audio_sndio = {.name = "sndio",
                             .delay = NULL,
                             .play = &play,
                             .volume = &volume,
-                            .parameters = NULL};
+                            .parameters = NULL,
+                            .mute= NULL};
index 1637c825b3c11fc90a0c50354f79d5b302f8fdd9..3b908db48153c942d6fd6d28e5eed80e3460da35 100644 (file)
@@ -96,4 +96,5 @@ audio_output audio_stdout = {.name = "stdout",
                            .delay = NULL,
                            .play = &play,
                            .volume = NULL,
-                           .parameters = NULL};
+                           .parameters = NULL,
+                           .mute = NULL};
index 16c3c0e95fb693f330eec0f9d67ffa58301a2476..72e2758cc00e5f879204da695efe4a82db05f810 100644 (file)
--- a/common.h
+++ b/common.h
@@ -121,7 +121,7 @@ uint32_t uatoi(const char *nptr);
 shairport_cfg config;
 config_t config_file_stuff;
 
-uint32_t buffer_occupancy;
+int32_t buffer_occupancy; // allow it to be negative because seq_diff may be negative
 int64_t session_corrections;
 uint32_t play_segment_reference_frame;
 uint64_t play_segment_reference_frame_remote_time;
index 92ebedf9c5b64576c23984a5a4c668714fe84825..4538e4defc986ebb1112f1048292f75622eeb06a 100644 (file)
--- a/player.c
+++ b/player.c
@@ -95,7 +95,6 @@ static uint64_t packet_count = 0;
 static int32_t last_seqno_read;
 
 // interthread variables
-static double software_mixer_volume = 1.0;
 static int fix_volume = 0x10000;
 static pthread_mutex_t vol_mutex = PTHREAD_MUTEX_INITIALIZER;
 
@@ -452,7 +451,7 @@ static abuf_t *buffer_get_frame(void) {
     if (ab_synced) {
       do {
         curframe = audio_buffer + BUFIDX(ab_read);
-        if (curframe->ready) {
+        if ((ab_read!=ab_write) && (curframe->ready)) { // it could be synced and empty, under exceptional circumstances, with the frame unused, thus apparently ready
 
           if (curframe->sequence_number != ab_read) {
             // some kind of sync problem has occurred.
@@ -838,7 +837,7 @@ static int stuff_buffer_soxr(short *inptr, short *outptr, int stuff) {
     }
 
     // finally, adjust the volume, if necessary
-    if (software_mixer_volume != 1.0) {
+    if (fix_volume != 65536.0) {
       // pthread_mutex_lock(&vol_mutex);
       op = outptr;
       for (i = 0; i < frame_size + stuff; i++) {
@@ -1171,7 +1170,7 @@ static void *player_thread_func(void *arg) {
                                                                inform("Sync error: %.1f (frames); net correction: %.1f (ppm); corrections: %.1f "
                                                                                         "(ppm); missing packets %llu; late packets %llu; too late packets %llu; "
                                                                                         "resend requests %llu; min DAC queue size %lli, min and max buffer occupancy "
-                                                                                        "%u and %u.",
+                                                                                        "%d and %d.",
                                                                                         moving_average_sync_error, moving_average_correction * 1000000 / 352,
                                                                                         moving_average_insertions_plus_deletions * 1000000 / 352, missing_packets,
                                                                                         late_packets, too_late_packets, resend_requests, minimum_dac_queue_size,
@@ -1179,7 +1178,7 @@ static void *player_thread_func(void *arg) {
               else
                                                                inform("Synchronisation disabled. Missing packets %llu; late packets %llu; too late packets %llu; "
                                                                                         "resend requests %llu; min and max buffer occupancy "
-                                                                                        "%u and %u.",
+                                                                                        "%d and %d.",
                                                                                         missing_packets,
                                                                                         late_packets, too_late_packets, resend_requests,
                                                                                         minimum_buffer_occupancy, maximum_buffer_occupancy);            
@@ -1201,7 +1200,7 @@ static void *player_thread_func(void *arg) {
 }
 
 // takes the volume as specified by the airplay protocol
-void player_volume(double f) {
+void player_volume(double airplay_volume) {
 
   // The volume ranges -144.0 (mute) or -30 -- 0. See
   // http://git.zx2c4.com/Airtunes2/about/#setting-volume
@@ -1218,50 +1217,71 @@ void player_volume(double f) {
   // or 20 times the log of the ratio. Then multiplied by 100 for convenience.
   // Thus, we ask our vol2attn function for an appropriate dB between -96.3 and 0 dB and translate
   // it back to a number.
-
-  double linear_volume = 0.0;
-
-  if (config.output->volume) {
-    // debug(1,"Set volume to %f.",f);
-    config.output->volume(f); // volume will be sent as metadata by the config.output device
-    linear_volume = 1.0; // no attenuation needed -- this value is used as a flag to avoid calculations
-  }
-
-  if (config.output->parameters)
+  
+  
+  // get the audio parameters
+  
+  int32_t min,max;
+  
+  if (config.output->parameters) {
     config.output->parameters(&audio_information);
-  else {
-    long mindb = -9630;
-    if (config.volume_range_db) {
-      long suggested_alsa_min_db = -(long)trunc(config.volume_range_db*100);
-      if (suggested_alsa_min_db > mindb)
-        mindb = suggested_alsa_min_db;
-      else
-        inform("The volume_range_db setting, %f is greater than the native range of the mixer %f, so it is ignored.",config.volume_range_db,mindb/100.0);
-    }
-    double scaled_volume = vol2attn(f, 0, mindb);
-    linear_volume = pow(10, scaled_volume / 2000);
-    audio_information.airplay_volume = f;
-    audio_information.minimum_volume_dB = mindb;
-    audio_information.maximum_volume_dB = 0;
-    audio_information.current_volume_dB = scaled_volume;
-    audio_information.has_true_mute = 0;
-    audio_information.is_muted = 0;
-    // debug(1,"Minimum software volume set to %d centi-dB",f,mindb);
+    max = audio_information.maximum_volume_dB;
+    min = audio_information.minimum_volume_dB;
+  } else {
+       max = 0;
+       min = -9630;
   }
-  audio_information.valid = 1;
-  // debug(1,"Software volume set to %f on scale with a %f dB",f,linear_volume);
+  
+       double temp_fix_volume = 65536.0;
+       double scaled_volume;
+       
+  if (airplay_volume==-144.0) { // if we are muting
+       scaled_volume = min; // this is just for the metadata
+       if (config.output->mute)
+               config.output->mute(1); // use real mute if it's there
+       else if (config.output->volume) {
+               config.output_.volume(min); // otherwise set the output to the lowest value
+               temp_fix_volume = 0; // and set the software multiplier to 0.
+       }
+  } else { // not muting
+
+               if (config.volume_range_db) {
+                       int32_t possible_min = max - (int)trunc(config.volume_range_db*100);
+               if (possible_min > min)
+                       min = possible_min;
+               }
+       
+               // now we have the true desired range, get the volume that is being set
+               scaled_volume = vol2attn(airplay_volume, max, min);     
+               double software_volume = 0; dB or attenuation
+               
+               if (config.output->volume) {
+                       if (scaled_volume>=min) {
+                               config.output->volume(scaled_volume);
+                       } else {
+                               config.output->volume(min);
+                               software_volume = scaled_volume-min;  // this is the attenuation in dB needed in software
+                       }
+               } else {
+                       software_volume = scaled_volume;
+               }
+               if (config.output->mute) // if there is hardware mute...
+                       config.output->mute(0); // turn it off
+               temp_fix_volume = 65536.0 * pow(10, software_volume / 2000);
+  }
+  // debug(1,"Software volume set to %f on scale with a %f dB",airplay_volume,pow(10, software_volume / 2000));
   pthread_mutex_lock(&vol_mutex);
-  software_mixer_volume = linear_volume;
-  fix_volume = 65536.0 * software_mixer_volume;
+  fix_volume = temp_fix_volume;
   pthread_mutex_unlock(&vol_mutex);
+
 #ifdef CONFIG_METADATA
   char *dv = malloc(128); // will be freed in the metadata thread
   if (dv) {
     memset(dv, 0, 128);
-    snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", audio_information.airplay_volume,
-             audio_information.current_volume_dB / 100.0,
-             audio_information.minimum_volume_dB / 100.0,
-             audio_information.maximum_volume_dB / 100.0);
+    snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume,
+             scaled_volume / 100.0,
+             min / 100.0,
+             max / 100.0);
     send_ssnc_metadata('pvol', dv, strlen(dv), 1);
   }
 #endif