]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
restore full code for checking for precise timing but stop making it necessary for...
authorMike Brady <mikebrady@eircom.net>
Mon, 17 Jun 2019 06:54:04 +0000 (07:54 +0100)
committerMike Brady <mikebrady@eircom.net>
Mon, 17 Jun 2019 06:54:04 +0000 (07:54 +0100)
audio_alsa.c

index 956deba5f23bee40811818d1bd16bc03a753f460..f56cb478c2373f8dede84be51535966a4f4a8393 100644 (file)
@@ -162,12 +162,70 @@ int standard_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
 // 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;
 
+// this will return true if the DAC can return precision delay information and false if not
+// if it is not yet known, it will test the output device to find out
+
+// note -- once it has done the test, it decides -- even if the delay comes back with
+// "don't know", it will take that as a "No" and remember it.
+// If you want it to check again, set precision_delay_available_status to YNDK_DONT_KNOW
+// first.
+
 int precision_delay_available() {
-  // this is very crude -- if the device is a hardware device, then it's assumed the delay is precise
-  const char *output_device_name = snd_pcm_name(alsa_handle);
-  return (strstr(output_device_name,"hw:") == output_device_name);
+  if (precision_delay_available_status == YNDK_DONT_KNOW) {
+    // At present, the only criterion as to whether precision delay is available
+    // is whether the device driver returns non-zero update timestamps
+    // If it does, it is considered precision delay is available
+    // Otherwise, it's considered to be unavailable
+    
+    // To test, we play a silence buffer (fairly large to avoid underflow)
+    // and then we check the delay return. It will tell us if it 
+    // was able to use the (non-zero) update timestamps
+        
+    int frames_of_silence = 4410;
+    size_t size_of_silence_buffer = frames_of_silence * frame_size;
+    void *silence = malloc(size_of_silence_buffer);
+    if (silence == NULL) {
+      debug(1, "alsa: precision_delay_available -- failed to "
+               "allocate memory for a "
+               "silent frame buffer.");
+    } else {
+      pthread_cleanup_push(malloc_cleanup, silence);
+      int use_dither = 0;
+      if ((hardware_mixer == 0) && (config.ignore_volume_control == 0) &&
+          (config.airplay_volume != 0.0))
+        use_dither = 1;
+      dither_random_number_store =
+          generate_zero_frames(silence, frames_of_silence, config.output_format,
+                               use_dither, // i.e. with dither
+                               dither_random_number_store);
+      // debug(1,"Play %d frames of silence with most_recent_write_time of
+      // %" PRIx64 ".",
+      //    frames_of_silence,most_recent_write_time);
+      do_play(silence, frames_of_silence);
+      pthread_cleanup_pop(1);
+      // now we can get the delay, and we'll note if it uses update timestamps
+      enum yndk_type uses_update_timestamps;
+      snd_pcm_state_t state;
+      snd_pcm_sframes_t delay;     
+      int ret = delay_and_status(&state, &delay, &uses_update_timestamps);
+      // debug(3,"alsa: precision_delay_available asking for delay and status with a return status of %d, a delay of %ld and a uses_update_timestamps of %d.", ret, delay, uses_update_timestamps);     
+      if (ret == 0) {
+        if (uses_update_timestamps == YNDK_YES) {
+          precision_delay_available_status = YNDK_YES;
+          debug(2,"alsa: precision delay timing available.");
+        } else {
+          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.");
+        }
+      }
+    }
+  }
+  return (precision_delay_available_status == YNDK_YES);
 }
 
+
 // static int play_number;
 // static int64_t accumulated_delay, accumulated_da_delay;
 int alsa_characteristics_already_listed = 0;
@@ -1850,8 +1908,8 @@ void *alsa_buffer_monitor_thread_code(__attribute__((unused)) void *arg) {
     // and config.keep_dac_busy is true (at the present, this has to be the case
     // to be in the
     // abm_connected state in the first place...) then do the silence-filling
-    // thing, if needed, and if the output device is capable of precision delay.
-    if ((alsa_backend_state != abm_disconnected) && (config.keep_dac_busy != 0) && precision_delay_available()) {
+    // thing, if needed /* only if the output device is capable of precision delay */.
+    if ((alsa_backend_state != abm_disconnected) && (config.keep_dac_busy != 0) /* && precision_delay_available() */ ) {
       int reply;
       long buffer_size = 0;
       snd_pcm_state_t state;