use max-latency and min-latency information in AirPlay ANNOUNCE packets, remove different latency settings except one fixed one

This commit is contained in:
Mike Brady
2018-01-09 17:54:24 +00:00
parent dafdc686b8
commit 9cfc6c475b
5 changed files with 34 additions and 164 deletions
+2 -3
View File
@@ -123,9 +123,8 @@ typedef struct {
int buffer_start_fill;
int64_t latency;
int64_t userSuppliedLatency; // overrides all other latencies -- use with caution
int64_t iTunesLatency; // supplied with --iTunesLatency option
int64_t AirPlayLatency; // supplied with --AirPlayLatency option
int64_t ForkedDaapdLatency; // supplied with --ForkedDaapdLatency option
int64_t fixedLatencyOffset; // add this to all automatic latencies supplied to get the actual total latency
// the total latency will be limited to the min and max-latency values, if supplied
int daemonise;
int daemonise_store_pid; // don't try to save a PID file
char *piddir;
+3 -2
View File
@@ -63,8 +63,9 @@ typedef struct {
typedef struct {
int connection_number; // for debug ID purposes, nothing else...
int64_t staticLatencyCorrection; // it seems iTunes needs some offset before it's more or less
// right. Odd.
int64_t minimum_latency; // set if an a=min-latency: line appears in the ANNOUNCE message; zero otherwise
int64_t maximum_latency; // set if an a=max-latency: line appears in the ANNOUNCE message; zero otherwise
#if defined(HAVE_DBUS) || defined(HAVE_MPRIS)
enum session_status_type play_state;
#endif
+16 -6
View File
@@ -226,18 +226,28 @@ void *rtp_control_receiver(void *arg) {
rtp_timestamp_less_latency = monotonic_timestamp(ntohl(*((uint32_t *)&packet[4])), conn);
sync_rtp_timestamp = monotonic_timestamp(ntohl(*((uint32_t *)&packet[16])), conn);
if (config.use_negotiated_latencies) {
if (config.userSuppliedLatency) {
if (config.userSuppliedLatency != config.latency) {
debug(1,"Using the user-supplied latency: %lld.",config.userSuppliedLatency);
}
config.latency = config.userSuppliedLatency;
} else {
int64_t la =
sync_rtp_timestamp - rtp_timestamp_less_latency + conn->staticLatencyCorrection;
sync_rtp_timestamp - rtp_timestamp_less_latency + config.fixedLatencyOffset;
if ((conn->maximum_latency) && (conn->maximum_latency<la))
la = conn->maximum_latency;
if ((conn->minimum_latency) && (conn->minimum_latency>la))
la = conn->minimum_latency;
if (la != config.latency) {
config.latency = la;
// debug(1,
// "Using negotiated latency of %lld frames and a static latency correction of
// %lld",
// sync_rtp_timestamp - rtp_timestamp_less_latency, conn->staticLatencyCorrection);
debug(1,"New latency: %lld, sync latency: %lld, minimum latency: %lld, maximum latency: %lld, fixed offset: %lld.",
la,sync_rtp_timestamp - rtp_timestamp_less_latency,conn->minimum_latency,conn->maximum_latency,config.fixedLatencyOffset);
}
}
// need to clarify this.
if (packet[0] & 0x10) {
// if it's a packet right after a flush or resume
sync_rtp_timestamp += 352; // add frame_size -- can't see a reference to this anywhere,
+6 -69
View File
@@ -3,7 +3,7 @@
* Copyright (c) James Laird 2013
* Modifications associated with audio synchronization, mutithreading and
* metadata handling copyright (c) Mike Brady 2014-2017
* metadata handling copyright (c) Mike Brady 2014-2018
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
@@ -771,70 +771,7 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
send_metadata('ssnc', 'daid', ar, strlen(ar), req, 1);
#endif
}
// This latency-setting mechanism is deprecated and will be removed.
// If no non-standard latency is chosen, automatic negotiated latency setting
// is permitted.
// Select a static latency
// if iTunes V10 or later is detected, use the iTunes latency setting
// if AirPlay is detected, use the AirPlay latency setting
// for everything else, use the general latency setting, if given, or
// else use the default latency setting
config.latency = -1;
if (config.userSuppliedLatency)
config.latency = config.userSuppliedLatency;
char *ua = msg_get_header(req, "User-Agent");
if (ua == 0) {
debug(1, "No User-Agent string found in the SETUP message. Using latency "
"of %d frames.",
config.latency);
} else {
if (strstr(ua, "iTunes") == ua) {
int iTunesVersion = 0;
// now check it's version 10 or later
char *pp = strchr(ua, '/') + 1;
if (pp)
iTunesVersion = atoi(pp);
else
debug(2, "iTunes Version Number not found.");
if (iTunesVersion >= 10) {
debug(1, "User-Agent is iTunes 10 or better, (actual version is %d); "
"selecting the iTunes "
"latency of %d frames.",
iTunesVersion, config.iTunesLatency);
config.latency = config.iTunesLatency;
conn->staticLatencyCorrection = 11025;
}
} else if (strstr(ua, "AirPlay") == ua) {
debug(2, "User-Agent is AirPlay; selecting the AirPlay latency of %d frames.",
config.AirPlayLatency);
config.latency = config.AirPlayLatency;
} else if (strstr(ua, "forked-daapd") == ua) {
debug(2, "User-Agent is forked-daapd; selecting the forked-daapd latency "
"of %d frames.",
config.ForkedDaapdLatency);
config.latency = config.ForkedDaapdLatency;
conn->staticLatencyCorrection = 11025;
} else if (strstr(ua, "Airfoil") == ua) {
debug(2, "User-Agent is Airfoil");
conn->staticLatencyCorrection = 11025;
} else {
debug(2, "Unrecognised User-Agent. Using latency of %d frames.", config.latency);
}
}
if (config.latency == -1) {
// this means that no static latency was set, so we'll allow it to be set
// dynamically
config.latency = 88198; // to be sure, to be sure -- make it slighty
// different from the default to ensure we get a
// debug message when set to 88200
config.use_negotiated_latencies = 1;
}
char *hdr = msg_get_header(req, "Transport");
if (!hdr)
goto error;
@@ -1541,13 +1478,13 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
}
if (pminlatency) {
int minl = atoi(pminlatency);
debug(1,"Minimum latency %d specified",minl);
conn->minimum_latency = atoi(pminlatency);
debug(1,"Minimum latency %d specified",conn->minimum_latency);
}
if (pmaxlatency) {
int maxl = atoi(pmaxlatency);
debug(1,"Maximum latency %d specified",maxl);
conn->maximum_latency = atoi(pmaxlatency);
debug(1,"Maximum latency %d specified",conn->maximum_latency);
}
if ((paesiv == NULL) && (prsaaeskey == NULL)) {
+7 -84
View File
@@ -279,18 +279,9 @@ void usage(char *progname) {
printf(" -v, --verbose -v print debug information; -vv more; -vvv lots.\n");
printf(" -p, --port=PORT set RTSP listening port.\n");
printf(" -a, --name=NAME set advertised name.\n");
// printf(" -A, --AirPlayLatency=FRAMES [Deprecated] Set the latency for audio sent from an "
// "AirPlay device.\n");
// printf(" The default is to set it automatically.\n");
// printf(" -i, --iTunesLatency=FRAMES [Deprecated] Set the latency for audio sent from iTunes
// "
// "10 or later.\n");
// printf(" The default is to set it automatically.\n");
printf(" -L, --latency=FRAMES [Deprecated] Set the latency for audio sent from an unknown "
"device.\n");
printf(" The default is to set it automatically.\n");
printf(" --forkedDaapdLatency=FRAMES [Deprecated] Set the latency for audio sent from "
"forked-daapd.\n");
printf(" The default is to set it automatically.\n");
printf(" -S, --stuffing=MODE set how to adjust current latency to match desired latency, "
"where \n");
@@ -369,9 +360,6 @@ int parse_options(int argc, char **argv) {
{"wait-cmd", 'w', POPT_ARG_NONE, &config.cmd_blocking, 0, NULL},
{"mdns", 'm', POPT_ARG_STRING, &config.mdns_name, 0, NULL},
{"latency", 'L', POPT_ARG_INT, &config.userSuppliedLatency, 0, NULL},
{"AirPlayLatency", 'A', POPT_ARG_INT, &config.AirPlayLatency, 0, NULL},
{"iTunesLatency", 'i', POPT_ARG_INT, &config.iTunesLatency, 0, NULL},
{"forkedDaapdLatency", 'f', POPT_ARG_INT, &config.ForkedDaapdLatency, 0, NULL},
{"stuffing", 'S', POPT_ARG_STRING, &stuffing, 'S', NULL},
{"resync", 'r', POPT_ARG_INT, &fResyncthreshold, 0, NULL},
{"timeout", 't', POPT_ARG_INT, &config.timeout, 't', NULL},
@@ -408,15 +396,15 @@ int parse_options(int argc, char **argv) {
inform("Warning: the option -R or --reconnectToOutput is deprecated.");
break;
case 'A':
inform("Warning: the option -A or --AirPlayLatency is deprecated. This setting is now "
inform("Warning: the option -A or --AirPlayLatency is deprecated and ignored. This setting is now "
"automatically received from the AirPlay device.");
break;
case 'i':
inform("Warning: the option -i or --iTunesLatency is deprecated. This setting is now "
inform("Warning: the option -i or --iTunesLatency is deprecated and ignored. This setting is now "
"automatically received from iTunes");
break;
case 'f':
inform("Warning: the option --forkedDaapdLatency is deprecated. This setting is now "
inform("Warning: the option --forkedDaapdLatency is deprecated and ignored. This setting is now "
"automatically received from forkedDaapd");
break;
case 'r':
@@ -447,6 +435,7 @@ int parse_options(int argc, char **argv) {
config.audio_backend_silent_lead_in_time = -1.0; // flag to indicate it has not been set
config.airplay_volume = -18.0; // if no volume is ever set, default to initial default value if
// nothing else comes in first.
config.fixedLatencyOffset = 11025; // this sounds like it works properly.
config_setting_t *setting;
const char *str = 0;
@@ -710,18 +699,6 @@ int parse_options(int argc, char **argv) {
if (config_lookup_int(config.cfg, "latencies.default", &value))
config.userSuppliedLatency = value;
/* Get the itunes latency. Deprecated! */
if (config_lookup_int(config.cfg, "latencies.itunes", &value))
config.iTunesLatency = value;
/* Get the AirPlay latency. Deprecated! */
if (config_lookup_int(config.cfg, "latencies.airplay", &value))
config.AirPlayLatency = value;
/* Get the forkedDaapd latency. Deprecated! */
if (config_lookup_int(config.cfg, "latencies.forkedDaapd", &value))
config.ForkedDaapdLatency = value;
#ifdef CONFIG_METADATA
/* Get the metadata setting. */
if (config_lookup_string(config.cfg, "metadata.enabled", &str)) {
@@ -1135,14 +1112,6 @@ int main(int argc, char **argv) {
config.latency = -1; // -1 means not set. 88200 works well. This is also reset in rtsp.c when play
// is about to start
config.userSuppliedLatency = 0; // zero means none supplied
config.iTunesLatency =
-1; // -1 means not supplied. 99400 seems to work pretty well for iTunes from Version 10 (?)
// upwards-- two left-ear headphones, one from the iMac jack, one
// from an NSLU2 running a cheap "3D Sound" USB Soundcard
config.AirPlayLatency =
-1; // -1 means not set. 88200 seems to work well for AirPlay -- Syncs sound and
// vision on AppleTV, but also used for iPhone/iPod/iPad sources
config.ForkedDaapdLatency = -1; // -1 means not set. 99400 seems to be right
config.resyncthreshold = 0.05; // 50 ms
config.timeout = 120; // this number of seconds to wait for [more] audio before switching to idle.
config.tolerance =
@@ -1374,55 +1343,12 @@ int main(int argc, char **argv) {
}
/* Mess around with the latency options */
// Basically, we used to rely on static latencies -- 99400 for iTunes 10 or later and forkedDaapd,
// 88200 for everything else
// Nowadays we allow the source to set the latency, which works out at 99651 for iTunes 10 and
// forkedDaapd and 88220 for everything else
// What we want to do here is allow the source to set the latency unless the user has specified an
// non-standard latency.
// If the user has specified a standard latency, we suggest to them to stop doing it.
// Basically, we expect the source to set the latency and add a fixed offset of 11025 frames to it, which sounds right
// If this latency is outside the max and min latensies that may be set by the source, clamp it to fit.
// If they specify a non-standard latency, we suggest the user to use the
// audio_backend_latency_offset instead.
if (config.AirPlayLatency != -1) {
if (config.AirPlayLatency == 88200) {
inform("It is not necessary to set the AirPlay latency to 88200 -- you should remove this "
"setting or configuration option, as it is deprecated.");
config.AirPlayLatency = -1;
} else {
inform("The AirPlay latency setting is deprecated, as Shairport Sync can now get the correct "
"latency from the source.");
inform("Please remove this setting and use the relevant audio_backend_latency_offset "
"setting, if necessary, to compensate for delays elsewhere.");
}
}
if (config.iTunesLatency != -1) {
if (config.iTunesLatency == 99400) {
inform("It is not necessary to set the iTunes latency to 99400 -- you should remove this "
"setting or configuration option, as it is deprecated and ignored.");
config.iTunesLatency = -1;
} else {
inform("The iTunes latency setting is deprecated, as Shairport Sync can now get the correct "
"latency from the source.");
inform("Please remove this setting and use the relevant audio_backend_latency_offset "
"setting, if necessary, to compensate for delays elsewhere.");
}
}
if (config.ForkedDaapdLatency != -1) {
if (config.ForkedDaapdLatency == 99400) {
inform("It is not necessary to set the forkedDaapd latency to 99400 -- you should remove "
"this setting or configuration option, as it is deprecated and ignored.");
config.ForkedDaapdLatency = -1;
} else {
inform("The forkedDaapd latency setting is deprecated, as Shairport Sync can now get the "
"correct latency from the source.");
inform("Please remove this setting and use the relevant audio_backend_latency_offset "
"setting, if necessary, to compensate for delays elsewhere.");
}
}
if (config.userSuppliedLatency) {
inform("The default latency setting is deprecated, as Shairport Sync can now get the correct "
"latency from the source.");
@@ -1455,9 +1381,6 @@ int main(int argc, char **argv) {
debug(1, "on-start returns output is %d.", config.cmd_start_returns_output);
debug(1, "mdns backend \"%s\".", config.mdns_name);
debug(2, "userSuppliedLatency is %d.", config.userSuppliedLatency);
debug(2, "AirPlayLatency is %d.", config.AirPlayLatency);
debug(2, "iTunesLatency is %d.", config.iTunesLatency);
debug(2, "forkedDaapdLatency is %d.", config.ForkedDaapdLatency);
debug(1, "stuffing option is \"%d\" (0-basic, 1-soxr).", config.packet_stuffing);
debug(1, "resync time is %f seconds.", config.resyncthreshold);
debug(1, "allow a session to be interrupted: %d.", config.allow_session_interruption);