Add a new setting: resync_recovery_time to give the systems a little time to restart.

Clean up the tolerance and resync threshold times.
This commit is contained in:
Mike Brady
2023-01-14 12:48:18 +00:00
parent b35d470c77
commit 28f54af281
4 changed files with 32 additions and 26 deletions
+3 -3
View File
@@ -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.
+8 -9
View File
@@ -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
+1 -1
View 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.
+20 -13
View 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);