From 617deead73fba1b89d1192dc0113cedce735b8c2 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Wed, 25 Apr 2018 18:05:19 +0100 Subject: [PATCH 01/10] Make the options for the dbus and mpris interfaces --with-dbus-interface and --with-mpris-interface rather than --with-dbus and --with-mpris. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 592fb996..4eb96637 100644 --- a/configure.ac +++ b/configure.ac @@ -277,7 +277,7 @@ AC_ARG_WITH(dns_sd, [ --with-dns_sd = choose dns_sd mDNS support], [ AM_CONDITIONAL([USE_DNS_SD], [test "x$HAS_DNS_SD" = "x1"]) # Look for dbus flag -AC_ARG_WITH(dbus, [ --with-dbus-interface = include support for the native Shairport Sync D-Bus interface], [ +AC_ARG_WITH(dbus-interface, [ --with-dbus-interface = include support for the native Shairport Sync D-Bus interface], [ AC_MSG_RESULT(>>Including dbus support) HAS_DBUS=1 AC_DEFINE([HAVE_DBUS], 1, [Needed by the compiler.]) @@ -295,7 +295,7 @@ AC_ARG_WITH(dbus-test-client, [ --with-dbus-test-client = compile dbus test cli AM_CONDITIONAL([USE_DBUS_CLIENT], [test "x$HAS_DBUS_CLIENT" = "x1"]) # Look for mpris flag -AC_ARG_WITH(mpris, [ --with-mpris-interface = include support for a Shairport Sync D-Bus interface conforming to the MPRIS standard], [ +AC_ARG_WITH(mpris-interface, [ --with-mpris-interface = include support for a Shairport Sync D-Bus interface conforming to the MPRIS standard], [ AC_MSG_RESULT(>>Including the MPRIS D-Bus Interface) HAS_MPRIS=1 AC_DEFINE([HAVE_MPRIS], 1, [Needed by the compiler.]) From b4b68ae3361e7167ff4a47d7874ed91e25df096c Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Wed, 25 Apr 2018 18:05:35 +0100 Subject: [PATCH 02/10] Make the options for the dbus and mpris interfaces --with-dbus-interface and --with-mpris-interface rather than --with-dbus and --with-mpris. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4eb96637..5bb0fb64 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.50]) -AC_INIT([shairport-sync], [3.2d43], [mikebrady@eircom.net]) +AC_INIT([shairport-sync], [3.2d44], [mikebrady@eircom.net]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([shairport.c]) AC_CONFIG_HEADERS([config.h]) From 4d7d6b349820075221a87c1694ba233bd9a0097f Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 27 Apr 2018 11:48:23 +0100 Subject: [PATCH 03/10] Update RELEASENOTES.md --- RELEASENOTES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5a74968e..7a37ee83 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,3 +1,9 @@ +Version 3.2d44 +==== +**Bug Fixes** +When errors occur sending resend requests, back off for 0.5 seconds, rather than 10 seconds, and make the code work! +Make the configuration options to include the dbus ionterface and the mpris interfaces be `--with-dbus-interface` and `--with-mpris-interface` as expected, not `--with-dbus` and `--with-mpris` as they actually were. + Version 3.2d42 ==== This version just brings some small changes made to the Release Candidates back into the `development` branch. From 952a37d1a83ac6049d003234ac35f6b14a16f9ab Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 27 Apr 2018 11:48:45 +0100 Subject: [PATCH 04/10] Update RELEASENOTES.md --- RELEASENOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7a37ee83..b1d129b3 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -11,7 +11,7 @@ This version just brings some small changes made to the Release Candidates back Version 3.2d41 ==== **Bug Fixes** -* Fixed a "silent" bug that prevented Shairport Sync working properly with AirAudio. According to the [unofficial standard](https://nto.github.io/AirPlay.html), requests for resending missing packets come from the control port; however, up until now, Shairport Sync sent them on the audio port. All AirPlay sources responded to these improperly-delivered requests except AirAudio, which discards requests that do not come from the correct source. Fixed now, with many thanks to [funtax](https://github.com/funtax) and to [Janusz Kowalczyk](https://github.com/kowalcj0) for bringing the issue to the fore. +* Fixed a hitherto-silent bug that prevented Shairport Sync working properly with AirAudio. According to the [unofficial standard](https://nto.github.io/AirPlay.html), requests for resending missing packets come from the control port; however, up until now, Shairport Sync sent them on the audio port. All AirPlay sources responded to these improperly-delivered requests except AirAudio, which discards requests that do not come from the correct source. Fixed now, with many thanks to [funtax](https://github.com/funtax) and to [Janusz Kowalczyk](https://github.com/kowalcj0) for bringing the issue to the fore. Version 3.2d40 ==== From 5f5047c79de95e5c46fef8fd82ebec8cabe55e46 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 27 Apr 2018 11:49:57 +0100 Subject: [PATCH 05/10] Update RELEASENOTES.md --- RELEASENOTES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b1d129b3..5896513a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,8 +1,8 @@ Version 3.2d44 ==== **Bug Fixes** -When errors occur sending resend requests, back off for 0.5 seconds, rather than 10 seconds, and make the code work! -Make the configuration options to include the dbus ionterface and the mpris interfaces be `--with-dbus-interface` and `--with-mpris-interface` as expected, not `--with-dbus` and `--with-mpris` as they actually were. +* When errors occur sending resend requests, back off for 0.5 seconds, rather than 10 seconds, and make the code actually work. +* Make the configuration options to include the dbus ionterface and the mpris interfaces be `--with-dbus-interface` and `--with-mpris-interface` as expected, not `--with-dbus` and `--with-mpris` as they actually were. Version 3.2d42 ==== From ca5b5f94dc5daa2f55bbe5920790e000d5bdb6ec Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 27 Apr 2018 11:50:49 +0100 Subject: [PATCH 06/10] Update RELEASENOTES.md --- RELEASENOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5896513a..8562681b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -2,7 +2,7 @@ Version 3.2d44 ==== **Bug Fixes** * When errors occur sending resend requests, back off for 0.5 seconds, rather than 10 seconds, and make the code actually work. -* Make the configuration options to include the dbus ionterface and the mpris interfaces be `--with-dbus-interface` and `--with-mpris-interface` as expected, not `--with-dbus` and `--with-mpris` as they actually were. +* Make the configuration options for including the dbus interface and the mpris interface be `--with-dbus-interface` and `--with-mpris-interface` as expected, not `--with-dbus` and `--with-mpris` as they actually were. Version 3.2d42 ==== From 21e1e12c765e885c8bac37ec3ee897db0e17511d Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 4 May 2018 18:25:52 +0100 Subject: [PATCH 07/10] If it's an AirPlay user agent up to and including version 363 (iOS 11.1.2) use the old offset calculation by adding 11,205 frames to the offset. --- player.h | 1 + rtp.c | 24 +++++++++++++++++------- rtsp.c | 12 ++++++++++++ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/player.h b/player.h index 031813a9..7ede6e9f 100644 --- a/player.h +++ b/player.h @@ -57,6 +57,7 @@ typedef struct { typedef struct { int connection_number; // for debug ID purposes, nothing else... + int AirPlayVersion; // zero if not an AirPlay session. Used to help calculate latency int64_t latency; // the actual latency used for this play session int64_t minimum_latency; // set if an a=min-latency: line appears in the ANNOUNCE message; zero // otherwise diff --git a/rtp.c b/rtp.c index a6cf2229..61a62262 100644 --- a/rtp.c +++ b/rtp.c @@ -292,6 +292,8 @@ void *rtp_control_receiver(void *arg) { // delay of 11,025 frames should be added -- iTunes set this field to 7 and // AirPlay sets it to 4. + // However, on older versions of AirPlay, the 11,025 frames seem to be necessary too + // The value of 11,025 (0.25 seconds) is a guess based on the "Audio-Latency" // parameter // returned by an AE. @@ -300,9 +302,14 @@ void *rtp_control_receiver(void *arg) { uint16_t flags = nctohs(&packet[2]); int64_t la = sync_rtp_timestamp - rtp_timestamp_less_latency; - if (flags == 7) + debug(3, "Latency derived just from the sync packet is %" PRId64 " frames.", la); + if ((flags == 7) || ((conn->AirPlayVersion > 0) && (conn->AirPlayVersion <= 363))) { la += config.fixedLatencyOffset; - // debug(1,"Latency calculated from the sync packet is %" PRId64 " frames.",la); + debug(3, "A fixed latency offset of %d frames has been added, giving a latency of " + "%" PRId64 + " frames with flags: %d and AirPlay version %d (triggers if 363 or less).", + config.fixedLatencyOffset, la, flags, conn->AirPlayVersion); + } if ((conn->maximum_latency) && (conn->maximum_latency < la)) la = conn->maximum_latency; if ((conn->minimum_latency) && (conn->minimum_latency > la)) @@ -969,8 +976,8 @@ void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn) { } #endif uint64_t time_of_sending_fp = get_absolute_time_in_fp(); - uint64_t resend_error_backoff_time = (uint64_t)1 << (32-1); // half a second - if ((conn->rtp_time_of_last_resend_request_error_fp==0) || + uint64_t resend_error_backoff_time = (uint64_t)1 << (32 - 1); // half a second + if ((conn->rtp_time_of_last_resend_request_error_fp == 0) || ((time_of_sending_fp - conn->rtp_time_of_last_resend_request_error_fp) > resend_error_backoff_time)) { if ((config.diagnostic_drop_packet_fraction == 0.0) || @@ -979,17 +986,20 @@ void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn) { (struct sockaddr *)&conn->rtp_client_control_socket, msgsize) == -1) { char em[1024]; strerror_r(errno, em, sizeof(em)); - debug(1, "Error %d using send-to to an audio socket: \"%s\". Backing off for 0.5 seconds.", errno, em); + debug(1, + "Error %d using send-to to an audio socket: \"%s\". Backing off for 0.5 seconds.", + errno, em); conn->rtp_time_of_last_resend_request_error_fp = time_of_sending_fp; } else { conn->rtp_time_of_last_resend_request_error_fp = 0; } } else { - debug(3, "Dropping resend request packet to simulate a bad network. Backing off for 0.5 seconds."); + debug(3, "Dropping resend request packet to simulate a bad network. Backing off for 0.5 " + "seconds."); conn->rtp_time_of_last_resend_request_error_fp = time_of_sending_fp; } } else { - debug(3,"Backing off sending resend requests due to a previous send-to error"); + debug(3, "Backing off sending resend requests due to a previous send-to error"); } } else { // if (!request_sent) { diff --git a/rtsp.c b/rtsp.c index 3fb6ba39..516e9968 100644 --- a/rtsp.c +++ b/rtsp.c @@ -1593,6 +1593,18 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag if (hdr) { debug(2, "Play connection from user agent \"%s\" on RTSP conversation thread %d.", hdr, conn->connection_number); + // if the user agent is AirPlay and has a version number of 353 or less (from iOS 11.1) + // use the older way of calculating the latency + + char *p = strstr(hdr, "AirPlay"); + if (p) { + p = strchr(p, '/'); + if (p) { + conn->AirPlayVersion = atoi(p + 1); // unsigned integer -- up to 2^32-1 + debug(1, "AirPlay version %d detected.", conn->AirPlayVersion); + } + } + #ifdef CONFIG_METADATA send_metadata('ssnc', 'snua', hdr, strlen(hdr), req, 1); #endif From bb64c644a627f9546445930cd8aa76f5033f83f0 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 4 May 2018 18:27:39 +0100 Subject: [PATCH 08/10] If it's an AirPlay user agent up to and including version 363 (iOS 11.1.2) use the old offset calculation by adding 11,205 frames to the offset. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5bb0fb64..ce66e32d 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.50]) -AC_INIT([shairport-sync], [3.2d44], [mikebrady@eircom.net]) +AC_INIT([shairport-sync], [3.2d45], [mikebrady@eircom.net]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([shairport.c]) AC_CONFIG_HEADERS([config.h]) From 368a63e1e3d71ab5ea6cfb826d2fea767dca2e17 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 4 May 2018 18:32:07 +0100 Subject: [PATCH 09/10] Update RELEASENOTES.md --- RELEASENOTES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 8562681b..c3bfa526 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,3 +1,8 @@ +Version 3.2d45 +==== +**Enhancement** +* Restore the old method for calculating latency for older AirPlay sources: an AirPlay source displaying an AirPlay User Agent string verion of 363 or older -- corresponding to iOS 11.1.2 or older -- will add an extra 0.25 seconds to the latency requested. This seems to be right. + Version 3.2d44 ==== **Bug Fixes** From b0db1b228c68b2abd3405041d82eefb2c8061224 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 4 May 2018 20:21:47 +0100 Subject: [PATCH 10/10] Its 353 not 363. --- RELEASENOTES.md | 2 +- rtp.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c3bfa526..400dc504 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,7 +1,7 @@ Version 3.2d45 ==== **Enhancement** -* Restore the old method for calculating latency for older AirPlay sources: an AirPlay source displaying an AirPlay User Agent string verion of 363 or older -- corresponding to iOS 11.1.2 or older -- will add an extra 0.25 seconds to the latency requested. This seems to be right. +* Restore the old method for calculating latency for older AirPlay sources: an AirPlay source displaying an AirPlay User Agent string verion of 353 or older -- corresponding to iOS 11.1.2 or older -- will add an extra 0.25 seconds to the latency requested. This seems to be right. Version 3.2d44 ==== diff --git a/rtp.c b/rtp.c index 61a62262..18bcc198 100644 --- a/rtp.c +++ b/rtp.c @@ -303,11 +303,11 @@ void *rtp_control_receiver(void *arg) { uint16_t flags = nctohs(&packet[2]); int64_t la = sync_rtp_timestamp - rtp_timestamp_less_latency; debug(3, "Latency derived just from the sync packet is %" PRId64 " frames.", la); - if ((flags == 7) || ((conn->AirPlayVersion > 0) && (conn->AirPlayVersion <= 363))) { + if ((flags == 7) || ((conn->AirPlayVersion > 0) && (conn->AirPlayVersion <= 353))) { la += config.fixedLatencyOffset; debug(3, "A fixed latency offset of %d frames has been added, giving a latency of " "%" PRId64 - " frames with flags: %d and AirPlay version %d (triggers if 363 or less).", + " frames with flags: %d and AirPlay version %d (triggers if 353 or less).", config.fixedLatencyOffset, la, flags, conn->AirPlayVersion); } if ((conn->maximum_latency) && (conn->maximum_latency < la))