]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
add standard timing -- more compatible -- and precision timing -- more precise. Add...
authorMike Brady <mikebrady@eircom.net>
Tue, 9 Apr 2019 09:23:23 +0000 (10:23 +0100)
committerMike Brady <mikebrady@eircom.net>
Tue, 9 Apr 2019 09:23:23 +0000 (10:23 +0100)
audio_alsa.c
common.h

index 50d502f0c75df778604b57fcdb814b5807a51c46..4987ee125ffb64c129f6d62ad158bc347eca0797 100644 (file)
@@ -148,9 +148,17 @@ long alsa_mix_mute;                      // setting the volume to this value mut
 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 *,
+// use this to allow the use of snd_pcm_writei or snd_pcm_mmap_writei
+snd_pcm_sframes_t (*alsa_pcm_write)(snd_pcm_t *, const void *,
                                            snd_pcm_uframes_t) = snd_pcm_writei;
 
+
+int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk_type *using_update_timestamps);
+int standard_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk_type *using_update_timestamps);
+
+// use this to allow the use of standard or precision delay calculations, with standard the, uh, standard.
+int (*delay_and_status)(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk_type *using_update_timestamps) = standard_delay_and_status;
+
 // static int play_number;
 // static int64_t accumulated_delay, accumulated_da_delay;
 int alsa_characteristics_already_listed = 0;
@@ -819,6 +827,10 @@ static int init(int argc, char **argv) {
 
   stall_monitor_start_time = 0;
   stall_monitor_frame_count = 0;
+  
+  config.disable_standby_mode = disable_standby_off;
+  config.keep_dac_busy = 0;
+  config.use_precision_timing = YNA_AUTO;
 
   // get settings from settings file first, allow them to be overridden by
   // command line options
@@ -997,8 +1009,6 @@ static int init(int argc, char **argv) {
 
 
     /* Get the optional disable_standby_mode setting. */
-    config.disable_standby_mode = disable_standby_off;
-    config.keep_dac_busy = 0;
     if (config_lookup_string(config.cfg, "alsa.disable_standby_mode", &str)) {
       if ((strcasecmp(str, "no") == 0) || (strcasecmp(str, "off") == 0) || (strcasecmp(str, "never") == 0))
         config.disable_standby_mode = disable_standby_off;
@@ -1014,6 +1024,22 @@ static int init(int argc, char **argv) {
       }
     }
 
+    
+    if (config_lookup_string(config.cfg, "alsa.use_precision_timing", &str)) {
+      if ((strcasecmp(str, "no") == 0) || (strcasecmp(str, "off") == 0) || (strcasecmp(str, "never") == 0))
+        config.use_precision_timing = YNA_NO;
+      else if ((strcasecmp(str, "yes") == 0) || (strcasecmp(str, "on") == 0) || (strcasecmp(str, "always") == 0)) {
+        config.use_precision_timing = YNA_YES;
+        config.keep_dac_busy = 1;
+      } else if (strcasecmp(str, "auto") == 0)
+        config.use_precision_timing = YNA_AUTO;
+      else {
+        warn("Invalid use_precision_timing option choice \"%s\". It should be "
+             "\"yes\", \"auto\" or \"no\". "
+             "It is set to \"auto\".");
+      }
+    }
+
     debug(1, "alsa: disable_standby_mode is \"%s\".", config.disable_standby_mode == disable_standby_off ? "never" : config.disable_standby_mode == disable_standby_always ? "always" : "while_active");
   }
 
@@ -1142,7 +1168,7 @@ static void start(int i_sample_rate, int i_sample_format) {
   }
 }
 
-int delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk_type *using_update_timestamps) {
+int standard_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk_type *using_update_timestamps) {
   int ret = 0;
   if (using_update_timestamps)
     *using_update_timestamps = YNDK_NO;
@@ -1150,21 +1176,20 @@ int delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk
   if ((*state == SND_PCM_STATE_RUNNING) || (*state == SND_PCM_STATE_DRAINING)) {
     ret = snd_pcm_delay(alsa_handle,delay);
   } else {
+  // not running, thus no delay information, thus can't check for frame
+  // rates
+    frame_index = 0; // we'll be starting over...
+    measurement_data_is_valid = 0;
     *delay = 0;  
   }
     
   stall_monitor_start_time = 0;  // zero if not initialised / not started / zeroed by flush
   stall_monitor_frame_count = 0; // set to delay at start of time, incremented by any writes
 
-  // not running, thus no delay information, thus can't check for frame
-  // rates
-  frame_index = 0; // we'll be starting over...
-  measurement_data_is_valid = 0;
   return ret;
 }
 
-
-int real_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk_type *using_update_timestamps) {
+int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk_type *using_update_timestamps) {
   snd_pcm_status_t *alsa_snd_pcm_status;
   snd_pcm_status_alloca(&alsa_snd_pcm_status);
   
@@ -1677,7 +1702,7 @@ int precision_delay_available() {
           precision_delay_available_status = YNDK_NO;
           debug(2,"alsa: precision delay timing not available.");
           if (config.disable_standby_mode != disable_standby_off)
-            inform("Note: disable_standby_mode has been turned off because the output device is not capable of precision delay timing.");
+            inform("Note: disable_standby_mode has been turned off because the output device \"%s\" does not support precision delay timing.", snd_pcm_name(alsa_handle));
         }
       }
     }
index ae6cef8cd730f3222491a27ee703c2d583e2f7d2..1a2dd8a52789eaa4d56aef9b4d5476d572d75ea3 100644 (file)
--- a/common.h
+++ b/common.h
@@ -33,6 +33,14 @@ enum dbus_session_type {
 #define sps_extra_code_output_stalled 32768
 #define sps_extra_code_output_state_cannot_make_ready 32769
 
+// yeah/no/auto
+enum yna_type {
+  YNA_AUTO = -1,
+  YNA_NO = 0,
+  YNA_YES = 1
+} yna_type;
+
+// yeah/no/dont-care
 enum yndk_type {
   YNDK_DONT_KNOW = -1,
   YNDK_NO = 0,
@@ -215,6 +223,7 @@ typedef struct {
   double alsa_maximum_stall_time;
   enum disable_standby_mode_type disable_standby_mode;
   volatile int keep_dac_busy;
+  enum yna_type use_precision_timing; // defaults to no
 
 #if defined(CONFIG_DBUS_INTERFACE)
   enum dbus_session_type dbus_service_bus_type;