use max-latency and min-latency information in AirPlay ANNOUNCE packets, remove different latency settings except one fixed one
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user