From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Sat, 14 Jan 2023 12:48:18 +0000 (+0000) Subject: Add a new setting: resync_recovery_time to give the systems a little time to restart. X-Git-Tag: 4.2.1d0~46 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=28f54af281ce805f8b36eea719f4dcfce8fe33bb;p=thirdparty%2Fshairport-sync.git Add a new setting: resync_recovery_time to give the systems a little time to restart. Clean up the tolerance and resync threshold times. --- diff --git a/common.h b/common.h index 66c02ca6..93f04ec6 100644 --- 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. diff --git a/player.c b/player.c index 15fa80a0..293bde26 100644 --- 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 diff --git a/scripts/shairport-sync.conf b/scripts/shairport-sync.conf index 61a56684..918ad377 100644 --- a/scripts/shairport-sync.conf +++ b/scripts/shairport-sync.conf @@ -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. diff --git a/shairport.c b/shairport.c index 96fdcbec..b5ecd030 100644 --- a/shairport.c +++ b/shairport.c @@ -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);