]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Add a new setting: resync_recovery_time to give the systems a little time to restart.
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Sat, 14 Jan 2023 12:48:18 +0000 (12:48 +0000)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Sat, 14 Jan 2023 12:48:18 +0000 (12:48 +0000)
Clean up the tolerance and resync threshold times.

common.h
player.c
scripts/shairport-sync.conf
shairport.c

index 66c02ca6bc216062399f3975b57d5954aa7c4e4b..93f04ec68259451d1f735bff5e4589c2bb919985 100644 (file)
--- a/common.h
+++ b/common.h
@@ -171,9 +171,9 @@ typedef struct {
   int volume_max_db;
   int no_sync;            // disable synchronisation, even if it's available
   int no_mmap;            // disable use of mmap-based output, even if it's available
-  double resyncthreshold; // if it get's out of whack my more than this number of seconds, resync.
-                          // Zero means never
-                          // resync.
+  double resync_threshold; // if it gets out of whack by more than this number of seconds, do a resync.
+                          // if zero, never do a resync.
+  double resync_recovery_time; // if sync is late, drop the delay but also drop the following frames up to the resync_recovery_time
   int allow_session_interruption;
   int timeout; // while in play mode, exit if no packets of audio come in for more than this number
                // of seconds . Zero means never exit.
index 15fa80a049b8fe8a67e00f36dc4887ccca742307..293bde264d2ae6ae6b1be782eb32ed7e40e630fb 100644 (file)
--- a/player.c
+++ b/player.c
@@ -4,7 +4,7 @@
  * All rights reserved.
  *
  * Modifications for audio synchronisation, AirPlay 2
- * and related work, copyright (c) Mike Brady 2014 -- 2022
+ * and related work, copyright (c) Mike Brady 2014 -- 2023
  * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person
@@ -2791,8 +2791,8 @@ void *player_thread_func(void *arg) {
               abs_sync_error = -abs_sync_error;
 
             if ((config.no_sync == 0) && (inframe->given_timestamp != 0) &&
-                (config.resyncthreshold > 0.0) &&
-                (abs_sync_error > config.resyncthreshold * config.output_rate)) {
+                (config.resync_threshold > 0.0) &&
+                (abs_sync_error > config.resync_threshold * config.output_rate)) {
               sync_error_out_of_bounds++;
             } else {
               sync_error_out_of_bounds = 0;
@@ -2815,7 +2815,7 @@ void *player_thread_func(void *arg) {
               }
 
               int64_t filler_length =
-                  (int64_t)(config.resyncthreshold * config.output_rate); // number of samples
+                  (int64_t)(config.resync_threshold * config.output_rate); // number of samples
               if ((sync_error > 0) && (sync_error > filler_length)) {
                 debug(1,
                       "Large positive (i.e. late) sync error of %" PRId64
@@ -2831,9 +2831,8 @@ void *player_thread_func(void *arg) {
                 int64_t source_frames_to_drop = sync_error;
                 source_frames_to_drop = source_frames_to_drop / conn->output_sample_ratio;
 
-                // add some time to give the pipeline a chance to recover -- a bit hacky
-                double extra_time_to_drop = 0.1; // seconds
-                int64_t extra_frames_to_drop = (int64_t)(conn->input_rate * extra_time_to_drop);
+                // drop some extra frames to give the pipeline a chance to recover
+                int64_t extra_frames_to_drop = (int64_t)(conn->input_rate * config.resync_recovery_time);
                 source_frames_to_drop += extra_frames_to_drop;
 
                 uint32_t frames_to_drop = source_frames_to_drop;
@@ -3086,8 +3085,8 @@ void *player_thread_func(void *arg) {
               // timestamp of zero means an inserted silent frame in place of a missing frame
               /*
               if ((config.no_sync == 0) && (inframe->timestamp != 0) &&
-                  && (config.resyncthreshold > 0.0) &&
-                  (abs_sync_error > config.resyncthreshold * config.output_rate)) {
+                  && (config.resync_threshold > 0.0) &&
+                  (abs_sync_error > config.resync_threshold * config.output_rate)) {
                 sync_error_out_of_bounds++;
                 // debug(1,"Sync error out of bounds: Error: %lld; previous error: %lld; DAC: %lld;
                 // timestamp: %llx, time now
index 61a566848e0fcf36e5836f3ca88071059a56ebf3..918ad3774b01c0b0357ada8e4568089155da1d27 100644 (file)
@@ -28,7 +28,7 @@ general =
 
 //     drift_tolerance_in_seconds = 0.002; // allow a timing error of this number of seconds of drift away from exact synchronisation before attempting to correct it
 //     resync_threshold_in_seconds = 0.050; // a synchronisation error greater than this number of seconds will cause resynchronisation; 0 disables it
-
+//     resync_recovery_time_in_seconds = 0.100; // allow this extra time to recover after a late resync. Increase the value, possibly to 0.5, in a virtual machine.
 //     playback_mode = "stereo"; // This can be "stereo", "mono", "reverse stereo", "both left" or "both right". Default is "stereo".
 //     alac_decoder = "hammerton"; // This can be "hammerton" or "apple". This advanced setting allows you to choose
 //             the original Shairport decoder by David Hammerton or the Apple Lossless Audio Codec (ALAC) decoder written by Apple.
index 96fdcbec5fd8029f6bf993bf778bd40806c232d6..b5ecd030ef54a66c9daa964803a51caa6457c01d 100644 (file)
@@ -2,7 +2,7 @@
  * Shairport, an Apple Airplay receiver
  * Copyright (c) James Laird 2013
  * All rights reserved.
- * Modifications and additions (c) Mike Brady 2014--2022
+ * Modifications and additions (c) Mike Brady 2014--2023
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -343,8 +343,8 @@ int parse_options(int argc, char **argv) {
   char *stuffing = NULL;         /* used for picking up the stuffing option */
   signed char c;                 /* used for argument parsing */
   // int i = 0;                     /* used for tracking options */
-  int fResyncthreshold = (int)(config.resyncthreshold * 44100);
-  int fTolerance = (int)(config.tolerance * 44100);
+  int resync_threshold_in_frames = 0;
+  int tolerance_in_frames = 0;
   poptContext optCon; /* context for parsing command-line options */
   struct poptOption optionsTable[] = {
       {"verbose", 'v', POPT_ARG_NONE, NULL, 'v', NULL, NULL},
@@ -365,10 +365,10 @@ int parse_options(int argc, char **argv) {
       {"mdns", 'm', POPT_ARG_STRING, &config.mdns_name, 0, NULL, NULL},
       {"latency", 'L', POPT_ARG_INT, &config.userSuppliedLatency, 0, NULL, NULL},
       {"stuffing", 'S', POPT_ARG_STRING, &stuffing, 'S', NULL, NULL},
-      {"resync", 'r', POPT_ARG_INT, &fResyncthreshold, 0, NULL, NULL},
+      {"resync", 'r', POPT_ARG_INT, &resync_threshold_in_frames, 'r', NULL, NULL},
       {"timeout", 't', POPT_ARG_INT, &config.timeout, 't', NULL, NULL},
       {"password", 0, POPT_ARG_STRING, &config.password, 0, NULL, NULL},
-      {"tolerance", 'z', POPT_ARG_INT, &fTolerance, 0, NULL, NULL},
+      {"tolerance", 'z', POPT_ARG_INT, &tolerance_in_frames, 'z', NULL, NULL},
       {"use-stderr", 'u', POPT_ARG_NONE, NULL, 'u', NULL, NULL},
       {"log-to-syslog", 0, POPT_ARG_NONE, &log_to_syslog_selected, 0, NULL, NULL},
 #ifdef CONFIG_METADATA
@@ -424,10 +424,12 @@ int parse_options(int argc, char **argv) {
           "automatically received from forkedDaapd");
       break;
     case 'r':
+      config.resync_threshold = (resync_threshold_in_frames * 1.0) / 44100;
       inform("Warning: the option -r or --resync is deprecated. Please use the "
              "\"resync_threshold_in_seconds\" setting in the config file instead.");
       break;
     case 'z':
+      config.tolerance = (tolerance_in_frames * 1.0) / 44100;
       inform("Warning: the option --tolerance is deprecated. Please use the "
              "\"drift_tolerance_in_seconds\" setting in the config file instead.");
       break;
@@ -462,8 +464,6 @@ int parse_options(int argc, char **argv) {
   };
 #endif
 
-  config.resyncthreshold = 1.0 * fResyncthreshold / 44100;
-  config.tolerance = 1.0 * fTolerance / 44100;
   config.audio_backend_silent_lead_in_time_auto =
       1;                         // start outputting silence as soon as packets start arriving
   config.airplay_volume = -24.0; // if no volume is ever set, default to initial default value if
@@ -692,7 +692,7 @@ int parse_options(int argc, char **argv) {
       if (config_lookup_int(config.cfg, "general.resync_threshold", &value)) {
         inform("The resync_threshold setting is deprecated. Use "
                "resync_threshold_in_seconds instead");
-        config.resyncthreshold = 1.0 * value / 44100;
+        config.resync_threshold = 1.0 * value / 44100;
       }
 
       /* Get the drift tolerance setting. */
@@ -701,7 +701,11 @@ int parse_options(int argc, char **argv) {
 
       /* Get the resync setting. */
       if (config_lookup_float(config.cfg, "general.resync_threshold_in_seconds", &dvalue))
-        config.resyncthreshold = dvalue;
+        config.resync_threshold = dvalue;
+
+      /* Get the resync recovery time setting. */
+      if (config_lookup_float(config.cfg, "general.resync_recovery_time_in_seconds", &dvalue))
+        config.resync_recovery_time = dvalue;
 
       /* Get the verbosity setting. */
       if (config_lookup_int(config.cfg, "general.log_verbosity", &value)) {
@@ -1983,11 +1987,13 @@ int main(int argc, char **argv) {
       1; // by default, log the file and line of the originating message
   config.debugger_show_relative_time =
       1;                         // by default, log the  time back to the previous debug message
-  config.resyncthreshold = 0.05; // 50 ms
   config.timeout = 120; // this number of seconds to wait for [more] audio before switching to idle.
-  config.tolerance =
-      0.002; // this number of seconds of timing error before attempting to correct it.
   config.buffer_start_fill = 220;
+  
+  config.resync_threshold = 0.050; // default
+  config.resync_recovery_time = 0.1; // drop this amount of frames following the resync delay.
+  config.tolerance = 0.002;
+
 
 #ifdef CONFIG_AIRPLAY_2
   config.timeout = 0; // disable watchdog
@@ -2372,7 +2378,8 @@ int main(int argc, char **argv) {
         : config.packet_stuffing == ST_soxr ? "soxr"
                                             : "auto");
   debug(1, "interpolation soxr_delay_threshold is %d.", config.soxr_delay_threshold);
-  debug(1, "resync time is %f seconds.", config.resyncthreshold);
+  debug(1, "resync time is %f seconds.", config.resync_threshold);
+  debug(1, "resync recovery time is %f seconds.", config.resync_recovery_time);
   debug(1, "allow a session to be interrupted: %d.", config.allow_session_interruption);
   debug(1, "busy timeout time is %d.", config.timeout);
   debug(1, "drift tolerance is %f seconds.", config.tolerance);