From c52bc672aad2e46da1d14abc456cec0cd0d863a1 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 21 Oct 2015 09:39:56 +0100
Subject: [PATCH 001/144] Start development version 2.7
---
configure.ac | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index cae6b143..19ec1993 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], [2.6], [mikebrady@eircom.net])
+AC_INIT([shairport-sync], [2.7], [mikebrady@eircom.net])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([shairport.c])
AC_CONFIG_HEADERS([config.h])
From 55f90e3eef42dcec1d9b81ca81eb4a3acd68b58e Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 21 Oct 2015 09:52:10 +0100
Subject: [PATCH 002/144] Generalise note about deleting old versions.
---
README.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 665862cb..f9ff1dfc 100644
--- a/README.md
+++ b/README.md
@@ -52,7 +52,9 @@ Building And Installing
If you wish to install Shairport Sync on OpenWrt, Arch or Fedora platforms, please follow the appropriate instructions below. Otherwise follow the General Build Instructions. Then, when the program has been installed, refer to the section on Configuring Shairport Sync that follows.
**Note**
-The following procedures will install shairport-sync at `/usr/local/bin/shairport-sync`. Before continuing, you should check to see if shairport-sync is already installed on your system -- use `which shairport-sync` to find where it is located, if installed. If it is installed anywhere other than at `/usr/local/bin/shairport-sync`, you should delete it -- you may need to have superuser privileges.
+
+The following procedures will install the shairport-sync application into your system. Before continuing, you should check to see if shairport-sync is already installed -- you can use `which shairport-sync` to find where it is located, if installed. If it is installed you should delete it -- you may need to have superuser privileges. After deleting, check again in case further copies are installed elsewhere.
+(If the existing installation of shairport-sync is where the new copy will be installed into, it will be overwritten; sometimes, however, the installation is to another location, so it is safer, initially, to delete previous versions manually.)
**OpenWrt:**
There is a Shairport Sync package in OpenWrt `trunk`. Also, there's an OpenWrt package at https://github.com/mikebrady/shairport-sync-for-openwrt, including one that builds back to `Attitude Adjustment`.
From 29c54d0dee81e24384ff49e633ddfb9483dee3f5 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 21 Oct 2015 09:54:10 +0100
Subject: [PATCH 003/144] Update README.md
---
README.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index f9ff1dfc..132b7431 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Audio played by a Shairport Sync-powered device stays synchronised with the sour
Shairport Sync does not support AirPlay video or photo streaming.
-This branch -- "master" -- is the stable branch of Shairport Sync. To access the development version, please switch to the "development" branch.
+This branch -- "development" -- is unstable and may change quickly. To access the stable version, please switch to the "master" branch.
More Information
----------
@@ -211,7 +211,7 @@ To enable Shairport Sync to start automatically at system startup, enter:
**Man Page**
-You can view the man page here: http://htmlpreview.github.io/?https://github.com/mikebrady/shairport-sync/blob/master/man/shairport-sync.html
+You can view the man page here: http://htmlpreview.github.io/?https://github.com/mikebrady/shairport-sync/blob/development/man/shairport-sync.html
Configuring Shairport Sync
--------
@@ -263,7 +263,7 @@ From a user's point of view, the effect of using this setting is to move the min
*Command Line Arguments*
-You can use command line arguments to provide settings to Shairport Sync as before. For full information, please read the Shairport Sync `man` page, also available at http://htmlpreview.github.io/?https://github.com/mikebrady/shairport-sync/blob/master/man/shairport-sync.html.
+You can use command line arguments to provide settings to Shairport Sync as before. For full information, please read the Shairport Sync `man` page, also available at http://htmlpreview.github.io/?https://github.com/mikebrady/shairport-sync/blob/development/man/shairport-sync.html.
Apart from the following options, all command line options can be replaced by settings in the configuration file. Here is a brief description of command line options that are not replicated by settings in the settings file.
From a314d086f9c3a559f9de8598fd17f47fd73d0e84 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 21 Oct 2015 10:06:39 +0100
Subject: [PATCH 004/144] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 132b7431..af85dd3e 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
Shairport Sync
=============
-Shairport Sync is an AirPlay audio player -- it plays audio streamed from iTunes, iOS devices and third-party AirPlay sources such as ForkedDaapd and others.
+Shairport Sync is an AirPlay audio player -- it plays audio streamed from iTunes, iOS devices and other AirPlay sources such as Quicktime Player, ForkedDaapd among others.
Audio played by a Shairport Sync-powered device stays synchronised with the source and hence with similar devices playing the same source. In this way, synchronised multi-room audio is possible without difficulty. (Hence the name Shairport Sync, BTW.)
Shairport Sync does not support AirPlay video or photo streaming.
From 3b88d051376aac5becd2c2476d7500554be02050 Mon Sep 17 00:00:00 2001
From: Mke Brady
Date: Wed, 21 Oct 2015 10:22:56 +0100
Subject: [PATCH 005/144] Add CYGWIN flag check to be recognised as
Posix-enough (?)
---
common.c | 2 +-
common.h | 4 ++--
player.c | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/common.c b/common.c
index bb6dafa2..f39c746b 100644
--- a/common.c
+++ b/common.c
@@ -474,7 +474,7 @@ double vol2attn(double vol, long max_db, long min_db) {
uint64_t get_absolute_time_in_fp() {
uint64_t time_now_fp;
-#ifdef COMPILE_FOR_LINUX_AND_FREEBSD
+#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN
struct timespec tn;
// can't use CLOCK_MONOTONIC_RAW as it's not implemented in OpenWrt
clock_gettime(CLOCK_MONOTONIC, &tn);
diff --git a/common.h b/common.h
index ef3f84b3..16c3c0e9 100644
--- a/common.h
+++ b/common.h
@@ -18,9 +18,9 @@
#endif
#endif
-#if defined(__linux__) || defined(__FreeBSD__)
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__CYGWIN__)
/* Linux and FreeBSD */
-#define COMPILE_FOR_LINUX_AND_FREEBSD 1
+#define COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN 1
#endif
// struct sockaddr_in6 is bigger than struct sockaddr. derp
diff --git a/player.c b/player.c
index 52a93f5f..92ebedf9 100644
--- a/player.c
+++ b/player.c
@@ -675,7 +675,7 @@ static abuf_t *buffer_get_frame(void) {
time_to_wait_for_wakeup_fp *= 4 * 352; // four full 352-frame packets
time_to_wait_for_wakeup_fp /= 3; // four thirds of a packet time
-#ifdef COMPILE_FOR_LINUX_AND_FREEBSD
+#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN
uint64_t time_of_wakeup_fp = local_time_now + time_to_wait_for_wakeup_fp;
uint64_t sec = time_of_wakeup_fp >> 32;
uint64_t nsec = ((time_of_wakeup_fp & 0xffffffff) * 1000000000) >> 32;
@@ -1307,7 +1307,7 @@ int player_play(stream_cfg *stream) {
#endif
// set the flowcontrol condition variable to wait on a monotonic clock
-#ifdef COMPILE_FOR_LINUX_AND_FREEBSD
+#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN
pthread_condattr_t attr;
pthread_condattr_init(&attr);
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); // can't do this in OS X, and don't need it.
From cc2900aa15bbf71bc831a8e653c3c2e4b3554b28 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 21 Oct 2015 10:24:54 +0100
Subject: [PATCH 006/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 50eefd50..c777c2d7 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,4 +1,9 @@
-Version 2.6
+Version 2.7 -- Development Version
+----
+Add a check to see if compilation is for a CYGWIN platform.
+
+
+Version 2.6 -- Stable Version
----
This is basically version 2.4.2 with two small fixes. It's been bumped to 2.6 because (1) the new features added between 2.4.1 and 2.4.2 deserve more than just a bug-fix increment and (2) the development versions (2.5.x) should have lower numbers than the release versions, so that releases are always seen as upgrades. For example: 2.5.0.9 --> 2.6 looks like an upgrade, whereas 2.5.0.9 --> 2.4.2 looks like a downgrade.
From 90f8ccd0c5a77cdc098696339f1e17669e00e233 Mon Sep 17 00:00:00 2001
From: Mke Brady
Date: Wed, 21 Oct 2015 11:58:38 +0100
Subject: [PATCH 007/144] Add rtptime info to mdst and mden tokens and emit
those tags also around PICT metadata.
---
rtsp.c | 51 +++++++++++++++++++++++++++++++++++++--------------
1 file changed, 37 insertions(+), 14 deletions(-)
diff --git a/rtsp.c b/rtsp.c
index 3925ab1a..1ddc6d96 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -603,9 +603,9 @@ static void handle_record(rtsp_conn_info *conn, rtsp_message *req, rtsp_message
// get the rtp timestamp
p = strstr(hdr, "rtptime=");
if (p) {
- p = strchr(p, '=') + 1;
+ p = strchr(p, '=');
if (p) {
- rtptime = uatoi(p); // unsigned integer -- up to 2^32-1
+ rtptime = uatoi(p+1); // unsigned integer -- up to 2^32-1
rtptime--;
// debug(1,"RTSP Flush Requested by handle_record: %u.",rtptime);
player_flush(rtptime);
@@ -641,9 +641,9 @@ static void handle_flush(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
// get the rtp timestamp
p = strstr(hdr, "rtptime=");
if (p) {
- p = strchr(p, '=') + 1;
+ p = strchr(p, '=');
if (p)
- rtptime = uatoi(p); // unsigned integer -- up to 2^32-1
+ rtptime = uatoi(p+1); // unsigned integer -- up to 2^32-1
}
}
// debug(1,"RTSP Flush Requested: %u.",rtptime);
@@ -1083,11 +1083,6 @@ static void handle_set_parameter_metadata(rtsp_conn_info *conn, rtsp_message *re
unsigned int off = 8;
- // inform the listener that a set of metadata is starting
- // this doesn't include the cover art though...
-
- send_metadata('ssnc', 'mdst', NULL, 0, NULL, 1);
-
while (off < cl) {
// pick up the metadata tag as an unsigned longint
uint32_t itag = ntohl(*(uint32_t *)(cp + off));
@@ -1106,9 +1101,6 @@ static void handle_set_parameter_metadata(rtsp_conn_info *conn, rtsp_message *re
// move on to the next item
off += vl;
}
-
- // inform the listener that a set of metadata is ending
- send_metadata('ssnc', 'mden', NULL, 0, NULL, 1);
}
#endif
@@ -1122,28 +1114,59 @@ static void handle_get_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
// if (!req->contentlength)
// debug(1, "received empty SET_PARAMETER request.");
+
+ msg_print_debug_headers(req);
char *ct = msg_get_header(req, "Content-Type");
if (ct) {
debug(2, "SET_PARAMETER Content-Type:\"%s\".", ct);
+
#ifdef CONFIG_METADATA
+ // It seems that the rtptime of the message is used as a kind of an ID that can be used
+ // to link items of metadata, including pictures, that refer to the same entity.
+ // If they refer to the same item, they have the same rtptime.
+ // So we send the rtptime before and after both the metadata items and the picture item
+ // get the rtptime
+ char *p = NULL;
+ char *hdr = msg_get_header(req, "RTP-Info");
+
+ if (hdr) {
+ p = strstr(hdr, "rtptime=");
+ if (p) {
+ p = strchr(p, '=');
+ }
+ } else {
+ debug(1,"Missing RTP-Info item in SET_PARAMETER");
+ }
+
+
if (!strncmp(ct, "application/x-dmap-tagged", 25)) {
debug(2, "received metadata tags in SET_PARAMETER request.");
+ if (p)
+ send_metadata('ssnc', 'mdst', p+1, strlen(p+1), req, 1); // metadata starting
handle_set_parameter_metadata(conn, req, resp);
+ if (p)
+ send_metadata('ssnc', 'mden', p+1, strlen(p+1), req, 1); // metadata ending
+
+
} else if (!strncmp(ct, "image", 5)) {
// debug(1, "received image in SET_PARAMETER request.");
// note: the image/type tag isn't reliable, so it's not being sent
// -- best look at the first few bytes of the image
+ if (p)
+ send_metadata('ssnc', 'mdst', p+1, strlen(p+1), req, 1); // metadata starting
send_metadata('ssnc', 'PICT', req->content, req->contentlength, req, 1);
+ if (p)
+ send_metadata('ssnc', 'mden', p+1, strlen(p+1), req, 1); // metadata ending
} else
#endif
if (!strncmp(ct, "text/parameters", 15)) {
debug(2, "received parameters in SET_PARAMETER request.");
- handle_set_parameter_parameter(conn, req, resp);
+ handle_set_parameter_parameter(conn, req, resp); // this could be volume or progress
} else {
debug(1, "received unknown Content-Type \"%s\" in SET_PARAMETER request.", ct);
- }
+ }
} else {
debug(1, "missing Content-Type header in SET_PARAMETER request.");
}
From 30231258d9b76f68a5ceec7cd2ecb2610d44ee6f Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 21 Oct 2015 12:09:09 +0100
Subject: [PATCH 008/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index c777c2d7..49061fbc 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,6 +1,8 @@
Version 2.7 -- Development Version
----
-Add a check to see if compilation is for a CYGWIN platform.
+**New Features**
+* Add a check to see if compilation is for a CYGWIN platform.
+* Add `rtptime` tags to metadata and picture information. Background: it seems that metadata and picture information for the same item, e.g. a track, are tagged with a timestamp called the `rtptime` -- if they refer to the same item, they will have the same `rtptime` tags. The update here is to add the `rtptime` value as data to the `mdst` and `mden` metadata items, which are sent before ("MetaData STart") and after ("MetaData ENd") a metadata sequence. In addition, the same tags are now sent before and after a picture. By the way, the progress metadata (`prgr` for "PRoGRess"), which is sent just when a track starts, contains the same `rtptime` as its middle element.
Version 2.6 -- Stable Version
From 07c3993096fab5587b836fb3bb75c80feb3c0e74 Mon Sep 17 00:00:00 2001
From: Mke Brady
Date: Wed, 21 Oct 2015 12:32:59 +0100
Subject: [PATCH 009/144] Turn off some debug messages
---
rtsp.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/rtsp.c b/rtsp.c
index 1ddc6d96..16c19bbc 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -1115,7 +1115,7 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
// if (!req->contentlength)
// debug(1, "received empty SET_PARAMETER request.");
- msg_print_debug_headers(req);
+ // msg_print_debug_headers(req);
char *ct = msg_get_header(req, "Content-Type");
@@ -1136,13 +1136,14 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
if (p) {
p = strchr(p, '=');
}
- } else {
- debug(1,"Missing RTP-Info item in SET_PARAMETER");
}
+ // not all items have RTP-time stuff in them, which is okay
if (!strncmp(ct, "application/x-dmap-tagged", 25)) {
debug(2, "received metadata tags in SET_PARAMETER request.");
+ if (p=NULL)
+ debug(1,"Missing RTP-Time info for metadata");
if (p)
send_metadata('ssnc', 'mdst', p+1, strlen(p+1), req, 1); // metadata starting
handle_set_parameter_metadata(conn, req, resp);
@@ -1154,6 +1155,8 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
// debug(1, "received image in SET_PARAMETER request.");
// note: the image/type tag isn't reliable, so it's not being sent
// -- best look at the first few bytes of the image
+ if (p=NULL)
+ debug(1,"Missing RTP-Time info for picture item");
if (p)
send_metadata('ssnc', 'mdst', p+1, strlen(p+1), req, 1); // metadata starting
send_metadata('ssnc', 'PICT', req->content, req->contentlength, req, 1);
From ced68dd045f46d383eda65757a5b61d5b70a5f5d Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sun, 25 Oct 2015 13:50:23 +0000
Subject: [PATCH 010/144] Emit mdst and mden even if no rtptime is available.
Use pcst and pcen tags to distinguish between metadata and picture tags
---
RELEASENOTES.md | 4 +++-
rtsp.c | 25 ++++++++++++++++++++-----
2 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 49061fbc..b82970bb 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -2,7 +2,9 @@ Version 2.7 -- Development Version
----
**New Features**
* Add a check to see if compilation is for a CYGWIN platform.
-* Add `rtptime` tags to metadata and picture information. Background: it seems that metadata and picture information for the same item, e.g. a track, are tagged with a timestamp called the `rtptime` -- if they refer to the same item, they will have the same `rtptime` tags. The update here is to add the `rtptime` value as data to the `mdst` and `mden` metadata items, which are sent before ("MetaData STart") and after ("MetaData ENd") a metadata sequence. In addition, the same tags are now sent before and after a picture. By the way, the progress metadata (`prgr` for "PRoGRess"), which is sent just when a track starts, contains the same `rtptime` as its middle element.
+* Add `rtptime` tags to metadata and picture information and add two new metadata items to precede and follow the transmission of a picture. Background: it seems that metadata and picture information for the same item, e.g. a track, are normally tagged with a timestamp called the `rtptime`; if they refer to the same item, they will have the same `rtptime` tags. The update here is to add the `rtptime` value, if available, as data to the `mdst` and `mden` metadata items, which are sent before ("MetaData STart") and after ("MetaData ENd") a metadata sequence.
+In addition, similar tags -- `pcst` ("PiCture STart") and `pcen` ("PiCture ENd") are now sent before and after a picture with the `rtptime` value, if available, sent as data.
+By the way, the progress metadata (`prgr` for "PRoGRess"), which is sent just when a track starts, contains the same `rtptime` as its middle element.
Version 2.6 -- Stable Version
diff --git a/rtsp.c b/rtsp.c
index 16c19bbc..503fb7eb 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -857,8 +857,10 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *r
// 'prgr' -- progress -- this is metadata from AirPlay consisting of RTP timestamps for the start
// of the current play sequence, the current play point and the end of the play sequence.
// I guess the timestamps wrap at 2^32.
-// 'mdst' -- a sequence of metadata is about to start
-// 'mden' -- a sequence of metadata has ended
+// 'mdst' -- a sequence of metadata is about to start; will have, as data, the rtptime associated with the metadata, if available
+// 'mden' -- a sequence of metadata has ended; will have, as data, the rtptime associated with the metadata, if available
+// 'pcst' -- a picture is about to be sent; will have, as data, the rtptime associated with the picture, if available
+// 'pcen' -- a picture has been sent; will have, as data, the rtptime associated with the metadata, if available
// 'snam' -- A device -- e.g. "Joe's iPhone" -- has opened a play session. Specifically, it's the "X-Apple-Client-Name" string
// 'snua' -- A "user agent" -- e.g. "iTunes/12..." -- has opened a play session. Specifically, it's the "User-Agent" string
// The next two two tokens are to facilitiate remote control of the source.
@@ -1145,10 +1147,16 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
if (p=NULL)
debug(1,"Missing RTP-Time info for metadata");
if (p)
- send_metadata('ssnc', 'mdst', p+1, strlen(p+1), req, 1); // metadata starting
+ send_metadata('ssnc', 'mdst', p+1, strlen(p+1), req, 1); // metadata starting
+ else
+ send_metadata('ssnc', 'mdst', NULL, 0, NULL, 0); // metadata starting, if rtptime is not available
+
handle_set_parameter_metadata(conn, req, resp);
+
if (p)
send_metadata('ssnc', 'mden', p+1, strlen(p+1), req, 1); // metadata ending
+ else
+ send_metadata('ssnc', 'mden', NULL, 0, NULL, 0); // metadata starting, if rtptime is not available
} else if (!strncmp(ct, "image", 5)) {
@@ -1158,10 +1166,17 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
if (p=NULL)
debug(1,"Missing RTP-Time info for picture item");
if (p)
- send_metadata('ssnc', 'mdst', p+1, strlen(p+1), req, 1); // metadata starting
+ send_metadata('ssnc', 'pcst', p+1, strlen(p+1), req, 1); // picture starting
+ else
+ send_metadata('ssnc', 'pcst', NULL, 0, NULL, 0); // picture starting, if rtptime is not available
+
send_metadata('ssnc', 'PICT', req->content, req->contentlength, req, 1);
+
if (p)
- send_metadata('ssnc', 'mden', p+1, strlen(p+1), req, 1); // metadata ending
+ send_metadata('ssnc', 'pcen', p+1, strlen(p+1), req, 1); // picture ending
+ else
+ send_metadata('ssnc', 'pcen', NULL, 0, NULL, 0); // picture ending, if rtptime is not available
+
} else
#endif
if (!strncmp(ct, "text/parameters", 15)) {
From 22a8664d6157e43c0cf12d30c5c2843ae26a7031 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sat, 31 Oct 2015 12:42:42 +0000
Subject: [PATCH 011/144] Add some extra error checking to alsa initialisation,
add shairport-sync.exe to .gitignore
---
.gitignore | 1 +
audio_alsa.c | 39 +++++++++++++++++++++++++++++++--------
2 files changed, 32 insertions(+), 8 deletions(-)
diff --git a/.gitignore b/.gitignore
index a7708cab..d42ad865 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
/shairport-sync
+/shairport-sync.exe
/*.o
/*~
*.xml~
diff --git a/audio_alsa.c b/audio_alsa.c
index 3cfacea1..4660ad20 100644
--- a/audio_alsa.c
+++ b/audio_alsa.c
@@ -283,21 +283,44 @@ int open_alsa_device(void) {
// die("Alsa initialization failed: unable to open pcm device: %s.", snd_strerror(ret));
snd_pcm_hw_params_alloca(&alsa_params);
- snd_pcm_hw_params_any(alsa_handle, alsa_params);
- snd_pcm_hw_params_set_access(alsa_handle, alsa_params, SND_PCM_ACCESS_RW_INTERLEAVED);
- snd_pcm_hw_params_set_format(alsa_handle, alsa_params, SND_PCM_FORMAT_S16);
- snd_pcm_hw_params_set_channels(alsa_handle, alsa_params, 2);
- snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params, &my_sample_rate, &dir);
+
+ ret = snd_pcm_hw_params_any(alsa_handle, alsa_params);
+ if (ret < 0) {
+ die("audio_alsa: Broken configuration for %s: no configurations available", alsa_out_dev);
+ }
+
+ ret = snd_pcm_hw_params_set_access(alsa_handle, alsa_params, SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (ret < 0) {
+ die("audio_alsa: Access type not available for %s: %s", alsa_out_dev, snd_strerror(ret));
+ }
+
+ ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, SND_PCM_FORMAT_S16);
+ if (ret < 0) {
+ die("audio_alsa: Sample format not available for %s: %s", alsa_out_dev, snd_strerror(ret));
+ }
+
+ ret = snd_pcm_hw_params_set_channels(alsa_handle, alsa_params, 2);
+ if (ret < 0) {
+ die("audio_alsa: Channels count (2) not available for %s: %s", alsa_out_dev, snd_strerror(ret));
+ }
+
+ ret = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params, &my_sample_rate, &dir);
+ if (ret < 0) {
+ die("audio_alsa: Rate %iHz not available for playback: %s", desired_sample_rate, snd_strerror(ret));
+ }
+
// snd_pcm_hw_params_set_period_size_near(alsa_handle, alsa_params, &frames, &dir);
// snd_pcm_hw_params_set_buffer_size_near(alsa_handle, alsa_params, &buffer_size);
+
ret = snd_pcm_hw_params(alsa_handle, alsa_params);
if (ret < 0) {
- die("unable to set hw parameters: %s.", snd_strerror(ret));
+ die("audio_alsa: Unable to set hw parameters for %s: %s.", alsa_out_dev, snd_strerror(ret));
}
+
if (my_sample_rate != desired_sample_rate) {
- die("Can't set the D/A converter to %d -- set to %d instead./n", desired_sample_rate,
- my_sample_rate);
+ die("Can't set the D/A converter to %d.", desired_sample_rate);
}
+
return (0);
}
From c9601426a16668aaa0eb6bc0316d028837e50069 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sat, 31 Oct 2015 13:27:15 +0000
Subject: [PATCH 012/144] Check desired buffer length -- abort if not feasible
---
audio_alsa.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/audio_alsa.c b/audio_alsa.c
index 4660ad20..f9851f18 100644
--- a/audio_alsa.c
+++ b/audio_alsa.c
@@ -272,11 +272,11 @@ static void deinit(void) {
}
int open_alsa_device(void) {
-
+ const snd_pcm_uframes_t buffer_headroom = 352*3; // the hardware buffer must be this much bigger than the desired buffer length
int ret, dir = 0;
unsigned int my_sample_rate = desired_sample_rate;
- snd_pcm_uframes_t frames = 441 * 10;
- snd_pcm_uframes_t buffer_size = frames * 4;
+ //snd_pcm_uframes_t frames = 441 * 10;
+ snd_pcm_uframes_t buffer_size, actual_buffer_length;
ret = snd_pcm_open(&alsa_handle, alsa_out_dev, SND_PCM_STREAM_PLAYBACK, 0);
if (ret < 0)
return (ret);
@@ -321,6 +321,21 @@ int open_alsa_device(void) {
die("Can't set the D/A converter to %d.", desired_sample_rate);
}
+ ret = snd_pcm_hw_params_get_buffer_size(alsa_params,&actual_buffer_length);
+ if (ret < 0) {
+ die("audio_alsa: Unable to get hw buffer length for %s: %s.", alsa_out_dev, snd_strerror(ret));
+ }
+
+ if (actual_buffer_length < config.audio_backend_buffer_desired_length+buffer_headroom) {
+ // the dac buffer is too small, so let's try to set it
+ buffer_size = config.audio_backend_buffer_desired_length+buffer_headroom;
+ ret = snd_pcm_hw_params_set_buffer_size_near(alsa_handle, alsa_params, &buffer_size);
+ if (ret < 0)
+ die("audio_alsa: Unable to set hw buffer size to %lu for %s: %s.", config.audio_backend_buffer_desired_length+buffer_headroom, alsa_out_dev, snd_strerror(ret));
+ if (config.audio_backend_buffer_desired_length+buffer_headroom > buffer_size)
+ die("audio_alsa: Can't set hw buffer size to %lu for %s: %s.", config.audio_backend_buffer_desired_length+buffer_headroom, alsa_out_dev, snd_strerror(ret));
+ }
+
return (0);
}
From 026b970680a19634f0901d4537ab1baaf0a1ca7a Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sat, 31 Oct 2015 13:51:08 +0000
Subject: [PATCH 013/144] Add latency and buffer length options for libao
---
audio_ao.c | 33 ++++++++++++++++++++++++++++++---
man/shairport-sync.7.xml | 31 +++++++++++++++++++++++++++++--
scripts/shairport-sync.conf | 7 +++++++
3 files changed, 66 insertions(+), 5 deletions(-)
diff --git a/audio_ao.c b/audio_ao.c
index 0acc8114..a6f9cf25 100644
--- a/audio_ao.c
+++ b/audio_ao.c
@@ -41,17 +41,44 @@ static void help(void) {
}
static int init(int argc, char **argv) {
+ const char *str;
+ int value;
ao_initialize();
int driver = ao_default_driver_id();
ao_option *ao_opts = NULL;
+ config.audio_backend_buffer_desired_length = 44100; // one second.
+ config.audio_backend_latency_offset = 0;
+
+ // get settings from settings file first, allow them to be overridden by command line options
+
+ if (config.cfg != NULL) {
+ /* Get the desired buffer size setting. */
+ if (config_lookup_int(config.cfg, "ao.audio_backend_buffer_desired_length_software", &value)) {
+ if ((value < 0) || (value > 66150))
+ die("Invalid a0 audio backend buffer desired length \"%d\". It should be between 0 and "
+ "66150, default is 44100",
+ value);
+ else {
+ config.audio_backend_buffer_desired_length = value;
+ }
+ }
+
+ /* Get the latency offset. */
+ if (config_lookup_int(config.cfg, "ao.audio_backend_latency_offset", &value)) {
+ if ((value < -66150) || (value > 66150))
+ die("Invalid ao audio backend buffer latency offset \"%d\". It should be between -66150 and +66150, default is 0",
+ value);
+ else
+ config.audio_backend_latency_offset = value;
+ }
+ }
+
+
optind = 1; // optind=0 is equivalent to optind=1 plus special behaviour
argv--; // so we shift the arguments to satisfy getopt()
argc++;
- config.audio_backend_buffer_desired_length = 44100; // one second.
- config.audio_backend_latency_offset = 0;
-
// some platforms apparently require optreset = 1; - which?
int opt;
char *mid;
diff --git a/man/shairport-sync.7.xml b/man/shairport-sync.7.xml
index ff1c7380..1e009686 100644
--- a/man/shairport-sync.7.xml
+++ b/man/shairport-sync.7.xml
@@ -295,7 +295,7 @@
You can offset the time of initial audio output relative to its nominal time using this setting.
For example to send an audio stream to stdout 100 milliseconds before it is due to be played, set this to -4410. Default setting is 0.
-
+
-
+
+
+
These settings are for the AO backend, used for the libao audio library.
+
There are two settings affecting timing. The audio_backend_latency_offset affects precisely when the first audio packet is sent
+ and the audio_backend_buffer_desired_length setting affects the nominal output buffer size.
+
These are the settings available within the ao group:
+
+
+
+
+
+
shairport-sync can process metadata provided by the source, such as Track Number, Album Name, cover art, etc. and can provide additional metadata such as volume level,
pause/resume, etc. It sends the metadata to a pipe, by default /tmp/shairport-sync-metadata.
diff --git a/scripts/shairport-sync.conf b/scripts/shairport-sync.conf
index ff2651aa..797bd15c 100644
--- a/scripts/shairport-sync.conf
+++ b/scripts/shairport-sync.conf
@@ -65,6 +65,13 @@ stdout =
// audio_backend_buffer_desired_length = 44100; // Having started to send audio at the right time, send all subsequent audio this many frames ahead of time, creating a buffer this size.
};
+// These are parameters for the "ao" audio back end. No interpolation is done.
+ao =
+{
+// audio_backend_latency_offset = 0; // Set this offset to compensate for a fixed delay in the audio back end. E.g. if the output device delays by 100 ms, set this to -4410.
+// audio_backend_buffer_desired_length = 44100; // Having started to send audio at the right time, send all subsequent audio this many frames ahead of time, creating a buffer this size.
+};
+
// The following static latency settings are deprecated -- do not use them for new installations. Shairport Sync now sets latencies automatically.
// To compensate for a delay in the output device please use the alsa/stdio/pipe "audio_backend_latency_offset" setting.
From 70d1fd3821affa6b5b7444991cc493f6ddd82d81 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sat, 31 Oct 2015 13:57:59 +0000
Subject: [PATCH 014/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index b82970bb..407ae83c 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,6 +1,9 @@
Version 2.7 -- Development Version
----
**New Features**
+* Add extra debug messages to the alsa back end to diagnose strange DACs.
+* Add configuration file for the libao back end -- to change the buffer size and the latency offset, same is for stdout.
+* Add shairport-sync.exe to .gitignore.
* Add a check to see if compilation is for a CYGWIN platform.
* Add `rtptime` tags to metadata and picture information and add two new metadata items to precede and follow the transmission of a picture. Background: it seems that metadata and picture information for the same item, e.g. a track, are normally tagged with a timestamp called the `rtptime`; if they refer to the same item, they will have the same `rtptime` tags. The update here is to add the `rtptime` value, if available, as data to the `mdst` and `mden` metadata items, which are sent before ("MetaData STart") and after ("MetaData ENd") a metadata sequence.
In addition, similar tags -- `pcst` ("PiCture STart") and `pcen` ("PiCture ENd") are now sent before and after a picture with the `rtptime` value, if available, sent as data.
From 4c70223f5a5e50ffca321b6ebc1875777acfd3bd Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Thu, 5 Nov 2015 18:03:58 +0000
Subject: [PATCH 015/144] Work in progress, doesn't compile
---
audio.h | 12 +++---
audio_alsa.c | 35 ++++++-----------
audio_ao.c | 3 +-
audio_dummy.c | 3 +-
audio_pipe.c | 3 +-
audio_pulse.c | 3 +-
audio_sndio.c | 3 +-
audio_stdout.c | 3 +-
common.h | 2 +-
player.c | 104 +++++++++++++++++++++++++++++--------------------
10 files changed, 93 insertions(+), 78 deletions(-)
diff --git a/audio.h b/audio.h
index 4738a071..359f3402 100644
--- a/audio.h
+++ b/audio.h
@@ -5,13 +5,9 @@
#include
typedef struct {
- double airplay_volume;
double current_volume_dB;
- int minimum_volume_dB;
- int maximum_volume_dB;
- int has_true_mute;
- int is_muted;
- int valid;
+ int32_t minimum_volume_dB;
+ int32_t maximum_volume_dB;
} audio_parameters;
typedef struct {
@@ -42,6 +38,10 @@ typedef struct {
// may be NULL, in which case soft volume parameters are used
void (*parameters)(audio_parameters *info);
+
+ // may be NULL, in which case software muting is used.
+ void (*mute)(int do_mute);
+
} audio_output;
audio_output *audio_get_output(char *name);
diff --git a/audio_alsa.c b/audio_alsa.c
index f9851f18..4a11260d 100644
--- a/audio_alsa.c
+++ b/audio_alsa.c
@@ -46,6 +46,7 @@ static uint32_t delay(void);
static void volume(double vol);
static void linear_volume(double vol);
static void parameters(audio_parameters *info);
+static void mute(int do_mute);
static int has_mute = 0;
static double set_volume;
@@ -234,13 +235,6 @@ static int init(int argc, char **argv) {
}
debug(1, "Hardware mixer has dB volume from %f to %f.", (1.0 * alsa_mix_mindb) / 100.0,
(1.0 * alsa_mix_maxdb) / 100.0);
- if (config.volume_range_db) {
- long suggested_alsa_min_db = alsa_mix_maxdb - (long)trunc(config.volume_range_db*100);
- if (suggested_alsa_min_db > alsa_mix_mindb)
- alsa_mix_mindb = suggested_alsa_min_db;
- else
- inform("The volume_range_db setting, %f is greater than the native range of the mixer %f, so it is ignored.",config.volume_range_db,(alsa_mix_maxdb-alsa_mix_mindb)/100.0);
- }
} else {
// use the linear scale and do the db conversion ourselves
debug(1, "note: the hardware mixer specified -- \"%s\" -- does not have a dB volume scale, so it can't be used.",alsa_mix_ctrl);
@@ -447,35 +441,30 @@ static void stop(void) {
}
static void parameters(audio_parameters *info) {
- info->has_true_mute = has_mute;
- info->is_muted = ((has_mute) && (set_volume == -144.0));
info->minimum_volume_dB = alsa_mix_mindb;
info->maximum_volume_dB = alsa_mix_maxdb;
- info->airplay_volume = set_volume;
- info->current_volume_dB = vol2attn(set_volume, alsa_mix_maxdb, alsa_mix_mindb);
}
static void volume(double vol) {
- // debug(1,"Volume called %f.",vol);
- set_volume = vol;
- double vol_setting = vol2attn(vol, alsa_mix_maxdb, alsa_mix_mindb);
// debug(1,"Setting volume db to %f, for volume input of %f.",vol_setting/100,vol);
- if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol_setting, -1) != 0)
+ if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, -1) != 0)
die("Failed to set playback dB volume");
- if (has_mute)
- snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, (vol != -144.0));
}
static void linear_volume(double vol) {
- set_volume = vol;
- double vol_setting = vol2attn(vol, 0, alsa_mix_mindb)/2000;
- // debug(1,"Adjusted volume is %f.",vol_setting);
- double linear_volume = pow(10, vol_setting);
+ double linear_volume = pow(10, vol);
// debug(1,"Linear volume is %f.",linear_volume);
long int_vol = alsa_mix_minv + (alsa_mix_maxv - alsa_mix_minv) * linear_volume;
// debug(1,"Setting volume to %ld, for volume input of %f.",int_vol,vol);
if (snd_mixer_selem_set_playback_volume_all(alsa_mix_elem, int_vol) != 0)
die("Failed to set playback volume");
- if (has_mute)
- snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, (vol != -144.0));
+}
+
+static void mute(int do_mute) {
+ if (has_mute) {
+ if (do_mute)
+ snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 0);
+ else
+ snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 1);
+ }
}
diff --git a/audio_ao.c b/audio_ao.c
index a6f9cf25..6cd98eab 100644
--- a/audio_ao.c
+++ b/audio_ao.c
@@ -153,4 +153,5 @@ audio_output audio_ao = {.name = "ao",
.delay = NULL,
.play = &play,
.volume = NULL,
- .parameters = NULL};
+ .parameters = NULL,
+ .mute = NULL};
diff --git a/audio_dummy.c b/audio_dummy.c
index 9742c58c..a544031b 100644
--- a/audio_dummy.c
+++ b/audio_dummy.c
@@ -60,4 +60,5 @@ audio_output audio_dummy = {.name = "dummy",
.delay = NULL,
.play = &play,
.volume = NULL,
- .parameters = NULL};
+ .parameters = NULL,
+ .mute = NULL};
diff --git a/audio_pipe.c b/audio_pipe.c
index d38cd8f8..e18b4e83 100644
--- a/audio_pipe.c
+++ b/audio_pipe.c
@@ -133,4 +133,5 @@ audio_output audio_pipe = {.name = "pipe",
.delay = NULL,
.play = &play,
.volume = NULL,
- .parameters = NULL};
+ .parameters = NULL,
+ .mute = NULL};
diff --git a/audio_pulse.c b/audio_pulse.c
index 29feed88..96c547c2 100644
--- a/audio_pulse.c
+++ b/audio_pulse.c
@@ -137,4 +137,5 @@ audio_output audio_pulse = {.name = "pulse",
.delay = NULL,
.play = &play,
.volume = NULL,
- .parameters = NULL};
+ .parameters = NULL,
+ .mute = NULL};
diff --git a/audio_sndio.c b/audio_sndio.c
index e59dbb85..eb3be35d 100644
--- a/audio_sndio.c
+++ b/audio_sndio.c
@@ -81,4 +81,5 @@ audio_output audio_sndio = {.name = "sndio",
.delay = NULL,
.play = &play,
.volume = &volume,
- .parameters = NULL};
+ .parameters = NULL,
+ .mute= NULL};
diff --git a/audio_stdout.c b/audio_stdout.c
index 1637c825..3b908db4 100644
--- a/audio_stdout.c
+++ b/audio_stdout.c
@@ -96,4 +96,5 @@ audio_output audio_stdout = {.name = "stdout",
.delay = NULL,
.play = &play,
.volume = NULL,
- .parameters = NULL};
+ .parameters = NULL,
+ .mute = NULL};
diff --git a/common.h b/common.h
index 16c3c0e9..72e2758c 100644
--- a/common.h
+++ b/common.h
@@ -121,7 +121,7 @@ uint32_t uatoi(const char *nptr);
shairport_cfg config;
config_t config_file_stuff;
-uint32_t buffer_occupancy;
+int32_t buffer_occupancy; // allow it to be negative because seq_diff may be negative
int64_t session_corrections;
uint32_t play_segment_reference_frame;
uint64_t play_segment_reference_frame_remote_time;
diff --git a/player.c b/player.c
index 92ebedf9..4538e4de 100644
--- a/player.c
+++ b/player.c
@@ -95,7 +95,6 @@ static uint64_t packet_count = 0;
static int32_t last_seqno_read;
// interthread variables
-static double software_mixer_volume = 1.0;
static int fix_volume = 0x10000;
static pthread_mutex_t vol_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -452,7 +451,7 @@ static abuf_t *buffer_get_frame(void) {
if (ab_synced) {
do {
curframe = audio_buffer + BUFIDX(ab_read);
- if (curframe->ready) {
+ if ((ab_read!=ab_write) && (curframe->ready)) { // it could be synced and empty, under exceptional circumstances, with the frame unused, thus apparently ready
if (curframe->sequence_number != ab_read) {
// some kind of sync problem has occurred.
@@ -838,7 +837,7 @@ static int stuff_buffer_soxr(short *inptr, short *outptr, int stuff) {
}
// finally, adjust the volume, if necessary
- if (software_mixer_volume != 1.0) {
+ if (fix_volume != 65536.0) {
// pthread_mutex_lock(&vol_mutex);
op = outptr;
for (i = 0; i < frame_size + stuff; i++) {
@@ -1171,7 +1170,7 @@ static void *player_thread_func(void *arg) {
inform("Sync error: %.1f (frames); net correction: %.1f (ppm); corrections: %.1f "
"(ppm); missing packets %llu; late packets %llu; too late packets %llu; "
"resend requests %llu; min DAC queue size %lli, min and max buffer occupancy "
- "%u and %u.",
+ "%d and %d.",
moving_average_sync_error, moving_average_correction * 1000000 / 352,
moving_average_insertions_plus_deletions * 1000000 / 352, missing_packets,
late_packets, too_late_packets, resend_requests, minimum_dac_queue_size,
@@ -1179,7 +1178,7 @@ static void *player_thread_func(void *arg) {
else
inform("Synchronisation disabled. Missing packets %llu; late packets %llu; too late packets %llu; "
"resend requests %llu; min and max buffer occupancy "
- "%u and %u.",
+ "%d and %d.",
missing_packets,
late_packets, too_late_packets, resend_requests,
minimum_buffer_occupancy, maximum_buffer_occupancy);
@@ -1201,7 +1200,7 @@ static void *player_thread_func(void *arg) {
}
// takes the volume as specified by the airplay protocol
-void player_volume(double f) {
+void player_volume(double airplay_volume) {
// The volume ranges -144.0 (mute) or -30 -- 0. See
// http://git.zx2c4.com/Airtunes2/about/#setting-volume
@@ -1218,50 +1217,71 @@ void player_volume(double f) {
// or 20 times the log of the ratio. Then multiplied by 100 for convenience.
// Thus, we ask our vol2attn function for an appropriate dB between -96.3 and 0 dB and translate
// it back to a number.
-
- double linear_volume = 0.0;
-
- if (config.output->volume) {
- // debug(1,"Set volume to %f.",f);
- config.output->volume(f); // volume will be sent as metadata by the config.output device
- linear_volume = 1.0; // no attenuation needed -- this value is used as a flag to avoid calculations
- }
-
- if (config.output->parameters)
+
+
+ // get the audio parameters
+
+ int32_t min,max;
+
+ if (config.output->parameters) {
config.output->parameters(&audio_information);
- else {
- long mindb = -9630;
- if (config.volume_range_db) {
- long suggested_alsa_min_db = -(long)trunc(config.volume_range_db*100);
- if (suggested_alsa_min_db > mindb)
- mindb = suggested_alsa_min_db;
- else
- inform("The volume_range_db setting, %f is greater than the native range of the mixer %f, so it is ignored.",config.volume_range_db,mindb/100.0);
- }
- double scaled_volume = vol2attn(f, 0, mindb);
- linear_volume = pow(10, scaled_volume / 2000);
- audio_information.airplay_volume = f;
- audio_information.minimum_volume_dB = mindb;
- audio_information.maximum_volume_dB = 0;
- audio_information.current_volume_dB = scaled_volume;
- audio_information.has_true_mute = 0;
- audio_information.is_muted = 0;
- // debug(1,"Minimum software volume set to %d centi-dB",f,mindb);
+ max = audio_information.maximum_volume_dB;
+ min = audio_information.minimum_volume_dB;
+ } else {
+ max = 0;
+ min = -9630;
}
- audio_information.valid = 1;
- // debug(1,"Software volume set to %f on scale with a %f dB",f,linear_volume);
+
+ double temp_fix_volume = 65536.0;
+ double scaled_volume;
+
+ if (airplay_volume==-144.0) { // if we are muting
+ scaled_volume = min; // this is just for the metadata
+ if (config.output->mute)
+ config.output->mute(1); // use real mute if it's there
+ else if (config.output->volume) {
+ config.output_.volume(min); // otherwise set the output to the lowest value
+ temp_fix_volume = 0; // and set the software multiplier to 0.
+ }
+ } else { // not muting
+
+ if (config.volume_range_db) {
+ int32_t possible_min = max - (int)trunc(config.volume_range_db*100);
+ if (possible_min > min)
+ min = possible_min;
+ }
+
+ // now we have the true desired range, get the volume that is being set
+ scaled_volume = vol2attn(airplay_volume, max, min);
+ double software_volume = 0; dB or attenuation
+
+ if (config.output->volume) {
+ if (scaled_volume>=min) {
+ config.output->volume(scaled_volume);
+ } else {
+ config.output->volume(min);
+ software_volume = scaled_volume-min; // this is the attenuation in dB needed in software
+ }
+ } else {
+ software_volume = scaled_volume;
+ }
+ if (config.output->mute) // if there is hardware mute...
+ config.output->mute(0); // turn it off
+ temp_fix_volume = 65536.0 * pow(10, software_volume / 2000);
+ }
+ // debug(1,"Software volume set to %f on scale with a %f dB",airplay_volume,pow(10, software_volume / 2000));
pthread_mutex_lock(&vol_mutex);
- software_mixer_volume = linear_volume;
- fix_volume = 65536.0 * software_mixer_volume;
+ fix_volume = temp_fix_volume;
pthread_mutex_unlock(&vol_mutex);
+
#ifdef CONFIG_METADATA
char *dv = malloc(128); // will be freed in the metadata thread
if (dv) {
memset(dv, 0, 128);
- snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", audio_information.airplay_volume,
- audio_information.current_volume_dB / 100.0,
- audio_information.minimum_volume_dB / 100.0,
- audio_information.maximum_volume_dB / 100.0);
+ snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume,
+ scaled_volume / 100.0,
+ min / 100.0,
+ max / 100.0);
send_ssnc_metadata('pvol', dv, strlen(dv), 1);
}
#endif
From f424c6dbf7dcd1404858bee112965e1c447c8078 Mon Sep 17 00:00:00 2001
From: Mke Brady
Date: Thu, 5 Nov 2015 22:35:38 +0000
Subject: [PATCH 016/144] Compiles, sorta runs, flaky
---
player.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/player.c b/player.c
index 4538e4de..e6842fc7 100644
--- a/player.c
+++ b/player.c
@@ -887,7 +887,6 @@ static void *player_thread_func(void *arg) {
int32_t minimum_buffer_occupancy = BUFFER_FRAMES;
int32_t maximum_buffer_occupancy = 0;
- audio_information.valid = 0;
buffer_occupancy = 0;
int play_samples;
@@ -1240,8 +1239,9 @@ void player_volume(double airplay_volume) {
if (config.output->mute)
config.output->mute(1); // use real mute if it's there
else if (config.output->volume) {
- config.output_.volume(min); // otherwise set the output to the lowest value
+ config.output->volume(min); // otherwise set the output to the lowest value
temp_fix_volume = 0; // and set the software multiplier to 0.
+ debug(1,"Software mute: mixer volume set to minimum: %d and software volume will be set to 0.",min);
}
} else { // not muting
@@ -1253,15 +1253,17 @@ void player_volume(double airplay_volume) {
// now we have the true desired range, get the volume that is being set
scaled_volume = vol2attn(airplay_volume, max, min);
- double software_volume = 0; dB or attenuation
+ double software_volume = 0; // dB of attenuation
if (config.output->volume) {
if (scaled_volume>=min) {
config.output->volume(scaled_volume);
+ debug(1,"Set Volume, no split: mixer volume set to: %f",scaled_volume);
} else {
config.output->volume(min);
software_volume = scaled_volume-min; // this is the attenuation in dB needed in software
- }
+ debug(1,"Set Volume, split: mixer volume set to: %f, software volume set to: %f.",min,software_volume);
+ }
} else {
software_volume = scaled_volume;
}
@@ -1269,7 +1271,7 @@ void player_volume(double airplay_volume) {
config.output->mute(0); // turn it off
temp_fix_volume = 65536.0 * pow(10, software_volume / 2000);
}
- // debug(1,"Software volume set to %f on scale with a %f dB",airplay_volume,pow(10, software_volume / 2000));
+ debug(1,"Software linear volume set to %f ",temp_fix_volume);
pthread_mutex_lock(&vol_mutex);
fix_volume = temp_fix_volume;
pthread_mutex_unlock(&vol_mutex);
From b74705b7b6df4bfe49e98a9b6599c47d99ccb8b0 Mon Sep 17 00:00:00 2001
From: Mke Brady
Date: Sat, 7 Nov 2015 18:10:56 +0000
Subject: [PATCH 017/144] Extensively revise the volume splitting -- put
hardware at the bottom of the attenuation range.
---
player.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 127 insertions(+), 6 deletions(-)
diff --git a/player.c b/player.c
index e6842fc7..16c91815 100644
--- a/player.c
+++ b/player.c
@@ -1207,17 +1207,136 @@ void player_volume(double airplay_volume) {
// equal increments. Since the human ear's response is roughly logarithmic, we imagine these to
// be power dB, i.e. from -30dB to 0dB.
- // So, if we have a hardware mixer, we will pass this on to its dB volume settings.
- // Without a hardware mixer, we have to do attenuation in software, so
- // here, we ask for an attenuation we will apply to the signal amplitude in software.
+ // We may have a hardware mixer, and if so, we will give it priority.
+ // If a desired volume range is given, then we will try to accommodate it from
+ // the top of the hardware mixer's range downwards.
+
+ // If not desired volume range is given, we will use the native resolution of the hardware mixer, if any,
+ // or failing that, the software mixer. The software mixer has a range of from -96.3 dB up to 0 dB,
+ // corresponding to a multiplier of 1 to 65535.
+
+ // Otherwise, we will accommodate the desired volume range in the combination of the software and hardware mixer
+ // Intuitively (!), it seems best to give the hardware mixer as big a role as possible, so
+ // we will use it's full range and then accommodate the rest of the attenuation in software.
+ // A problem is that we don't know whether the lowest hardware volume actually mutes the output
+ // so we must assume that it does, so that the colume control goes at the "bottom" of the adjustment range
+
// The dB range of a value from 1 to 65536 is about 96.3 dB (log10 of 65536 is 4.8164).
// Since the levels correspond with amplitude, they correspond to voltage, hence voltage dB,
// or 20 times the log of the ratio. Then multiplied by 100 for convenience.
// Thus, we ask our vol2attn function for an appropriate dB between -96.3 and 0 dB and translate
// it back to a number.
+ int32_t hw_min_db, hw_max_db, hw_range_db, range_to_use, min_db, max_db; // hw_range_db is a flag; if - means no mixer
+ int32_t sw_min_db = -9630;
+ int32_t sw_max_db = 0;
+ int32_t sw_range_db = sw_max_db - sw_min_db;
+ int32_t desired_range_db; // this is used as a flag
+
+ if (config.volume_range_db)
+ desired_range_db = (int32_t)trunc(config.volume_range_db*100);
+ else
+ desired_range_db = 0;
+
+ if (config.output->parameters) {
+ // have a hardware mixer
+ config.output->parameters(&audio_information);
+ hw_max_db = audio_information.maximum_volume_dB;
+ hw_min_db = audio_information.minimum_volume_dB;
+ hw_range_db = hw_max_db-hw_min_db;
+ } else {
+ // don't have a hardware mixer
+ hw_max_db = hw_min_db = hw_range_db = 0;
+ }
+
+ if (desired_range_db) {
+ debug(1,"An attenuation range of %d is requested.",desired_range_db);
+ // we have a desired volume range.
+ if (hw_range_db) {
+ // we have a hardware mixer
+ if (hw_range_db>=desired_range_db) {
+ // the hardware mixer can accommodate the desired range
+ max_db = hw_max_db;
+ min_db = max_db - desired_range_db;
+ } else {
+ if ((hw_range_db+sw_range_db)mute) {
+ config.output->mute(1); // use real mute if it's there
+ } else {
+ hardware_attenuation = hw_min_db;
+ software_attenuation = sw_min_db;
+ debug(1,"Software mute.");
+ }
+
+ } else {
+ if (config.output->mute)
+ config.output->mute(0); // unmute mute if it's there
+ scaled_attenuation = vol2attn(airplay_volume, max_db, min_db);
+ if (hw_range_db) {
+ // if there is a hardware mixer
+ if (scaled_attenuation<=hw_max_db) {
+ // the attenuation is so low that's it's in the hardware mixer's range
+ debug(1,"Attenuation all taken care of by the hardware mixer.");
+ hardware_attenuation = scaled_attenuation;
+ software_attenuation = sw_max_db - (max_db-hw_max_db); // e.g. if the hw_max_db is +4 and the max is +40, this will be -36 (all by 100, of course)
+ } else {
+ debug(1,"Attenuation taken care of by hardware and software mixer.");
+ hardware_attenuation = hw_max_db; // the hardware mixer is turned up full
+ software_attenuation = sw_max_db - (max_db-scaled_attenuation);
+ }
+ } else {
+ // if there is no hardware mixer, the scaled_volume is the software volume
+ debug(1,"Attenuation all taken care of by the software mixer.");
+ software_attenuation = scaled_attenuation;
+ }
+ }
+
+ if ((config.output->volume) && (hw_range_db)) {
+ config.output->volume(hardware_attenuation); // otherwise set the output to the lowest value
+ debug(1,"Hardware attenuation set to %f for airplay volume of %f.",hardware_attenuation,airplay_volume);
+ }
+ double temp_fix_volume = 65536.0 * pow(10, software_attenuation / 2000);
+ debug(1,"Software attenuation set to %f, i.e %f out of 65,536, for airplay volume of %f",software_attenuation,temp_fix_volume,airplay_volume);
+
+
+ /*
// get the audio parameters
int32_t min,max;
@@ -1272,6 +1391,8 @@ void player_volume(double airplay_volume) {
temp_fix_volume = 65536.0 * pow(10, software_volume / 2000);
}
debug(1,"Software linear volume set to %f ",temp_fix_volume);
+ */
+
pthread_mutex_lock(&vol_mutex);
fix_volume = temp_fix_volume;
pthread_mutex_unlock(&vol_mutex);
@@ -1281,9 +1402,9 @@ void player_volume(double airplay_volume) {
if (dv) {
memset(dv, 0, 128);
snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume,
- scaled_volume / 100.0,
- min / 100.0,
- max / 100.0);
+ scaled_attenuation / 100.0,
+ min_db / 100.0,
+ max_db / 100.0);
send_ssnc_metadata('pvol', dv, strlen(dv), 1);
}
#endif
From b5e4b258f9c6b905d0248222fbdd6f627b91cd7a Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sat, 7 Nov 2015 19:07:37 +0000
Subject: [PATCH 018/144] Hook up the mute function.
---
audio_alsa.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/audio_alsa.c b/audio_alsa.c
index 4a11260d..f2afc1a5 100644
--- a/audio_alsa.c
+++ b/audio_alsa.c
@@ -47,7 +47,6 @@ static void volume(double vol);
static void linear_volume(double vol);
static void parameters(audio_parameters *info);
static void mute(int do_mute);
-static int has_mute = 0;
static double set_volume;
audio_output audio_alsa = {
@@ -60,6 +59,7 @@ audio_output audio_alsa = {
.flush = &flush,
.delay = &delay,
.play = &play,
+ .mute = NULL, // to be set later on...
.volume = NULL, // to be set later on...
.parameters = NULL // to be set later on...
};
@@ -252,7 +252,7 @@ static int init(int argc, char **argv) {
}
}
if (snd_mixer_selem_has_playback_switch(alsa_mix_elem)) {
- has_mute = 1;
+ audio_alsa.mute = &mute; // insert the mute function now we know it can do muting stuff
debug(1, "Has mute ability.");
}
return 0;
@@ -461,10 +461,11 @@ static void linear_volume(double vol) {
}
static void mute(int do_mute) {
- if (has_mute) {
- if (do_mute)
- snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 0);
- else
- snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 1);
- }
+ if (do_mute) {
+ // debug(1,"Mute");
+ snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 0);
+ } else {
+ // debug(1,"Unmute");
+ snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 1);
+ }
}
From 3557835b687cd1fa7b3ec40e147d6a41de456e66 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sat, 7 Nov 2015 19:08:10 +0000
Subject: [PATCH 019/144] Tidy up some debug messages
---
player.c | 92 ++++++++++----------------------------------------------
1 file changed, 16 insertions(+), 76 deletions(-)
diff --git a/player.c b/player.c
index 16c91815..34d7ad1d 100644
--- a/player.c
+++ b/player.c
@@ -1206,21 +1206,20 @@ void player_volume(double airplay_volume) {
// By examination, the -30 -- 0 range is linear on the slider; i.e. the slider is calibrated in 30
// equal increments. Since the human ear's response is roughly logarithmic, we imagine these to
// be power dB, i.e. from -30dB to 0dB.
-
-
+
// We may have a hardware mixer, and if so, we will give it priority.
// If a desired volume range is given, then we will try to accommodate it from
// the top of the hardware mixer's range downwards.
- // If not desired volume range is given, we will use the native resolution of the hardware mixer, if any,
+ // If no desired volume range is given, we will use the native resolution of the hardware mixer, if any,
// or failing that, the software mixer. The software mixer has a range of from -96.3 dB up to 0 dB,
// corresponding to a multiplier of 1 to 65535.
// Otherwise, we will accommodate the desired volume range in the combination of the software and hardware mixer
// Intuitively (!), it seems best to give the hardware mixer as big a role as possible, so
- // we will use it's full range and then accommodate the rest of the attenuation in software.
+ // we will use its full range and then accommodate the rest of the attenuation in software.
// A problem is that we don't know whether the lowest hardware volume actually mutes the output
- // so we must assume that it does, so that the colume control goes at the "bottom" of the adjustment range
+ // so we must assume that it does, and for this reason, the volume control goes at the "bottom" of the adjustment range
// The dB range of a value from 1 to 65536 is about 96.3 dB (log10 of 65536 is 4.8164).
// Since the levels correspond with amplitude, they correspond to voltage, hence voltage dB,
@@ -1228,12 +1227,12 @@ void player_volume(double airplay_volume) {
// Thus, we ask our vol2attn function for an appropriate dB between -96.3 and 0 dB and translate
// it back to a number.
- int32_t hw_min_db, hw_max_db, hw_range_db, range_to_use, min_db, max_db; // hw_range_db is a flag; if - means no mixer
+ int32_t hw_min_db, hw_max_db, hw_range_db, range_to_use, min_db, max_db; // hw_range_db is a flag; if 0 means no mixer
int32_t sw_min_db = -9630;
int32_t sw_max_db = 0;
int32_t sw_range_db = sw_max_db - sw_min_db;
- int32_t desired_range_db; // this is used as a flag
+ int32_t desired_range_db; // this is used as a flag; if 0 means no desired range
if (config.volume_range_db)
desired_range_db = (int32_t)trunc(config.volume_range_db*100);
@@ -1252,7 +1251,7 @@ void player_volume(double airplay_volume) {
}
if (desired_range_db) {
- debug(1,"An attenuation range of %d is requested.",desired_range_db);
+ // debug(1,"An attenuation range of %d is requested.",desired_range_db);
// we have a desired volume range.
if (hw_range_db) {
// we have a hardware mixer
@@ -1279,7 +1278,7 @@ void player_volume(double airplay_volume) {
}
} else {
// we do not have a desired volume range, so use the mixer's volume range, if there is one.
- debug(1,"No attenuation range requested.");
+ // debug(1,"No attenuation range requested.");
if (hw_range_db) {
min_db = hw_min_db;
max_db = hw_max_db;
@@ -1291,18 +1290,17 @@ void player_volume(double airplay_volume) {
double hardware_attenuation, software_attenuation;
double scaled_attenuation = hw_min_db+sw_min_db;
-
- debug(1, "Hardware range, max and min: %d,%d,%d. Software range, max and min: %d,%d,%d. Min and Max %d,%d.",hw_range_db,hw_max_db,hw_min_db,sw_range_db,sw_max_db,sw_min_db,min_db,max_db);
-
+
// now, we can map the input to the desired output volume
if (airplay_volume==-144.0) {
// do a mute
if (config.output->mute) {
config.output->mute(1); // use real mute if it's there
+ software_attenuation = sw_min_db; // needed for when sound is unmuted; otherwise it might be very loud.
} else {
hardware_attenuation = hw_min_db;
software_attenuation = sw_min_db;
- debug(1,"Software mute.");
+ // debug(1,"Software mute.");
}
} else {
@@ -1313,85 +1311,27 @@ void player_volume(double airplay_volume) {
// if there is a hardware mixer
if (scaled_attenuation<=hw_max_db) {
// the attenuation is so low that's it's in the hardware mixer's range
- debug(1,"Attenuation all taken care of by the hardware mixer.");
+ // debug(1,"Attenuation all taken care of by the hardware mixer.");
hardware_attenuation = scaled_attenuation;
software_attenuation = sw_max_db - (max_db-hw_max_db); // e.g. if the hw_max_db is +4 and the max is +40, this will be -36 (all by 100, of course)
} else {
- debug(1,"Attenuation taken care of by hardware and software mixer.");
+ // debug(1,"Attenuation taken care of by hardware and software mixer.");
hardware_attenuation = hw_max_db; // the hardware mixer is turned up full
software_attenuation = sw_max_db - (max_db-scaled_attenuation);
}
} else {
// if there is no hardware mixer, the scaled_volume is the software volume
- debug(1,"Attenuation all taken care of by the software mixer.");
+ // debug(1,"Attenuation all taken care of by the software mixer.");
software_attenuation = scaled_attenuation;
}
}
if ((config.output->volume) && (hw_range_db)) {
config.output->volume(hardware_attenuation); // otherwise set the output to the lowest value
- debug(1,"Hardware attenuation set to %f for airplay volume of %f.",hardware_attenuation,airplay_volume);
+ //debug(1,"Hardware attenuation set to %f for airplay volume of %f.",hardware_attenuation,airplay_volume);
}
double temp_fix_volume = 65536.0 * pow(10, software_attenuation / 2000);
- debug(1,"Software attenuation set to %f, i.e %f out of 65,536, for airplay volume of %f",software_attenuation,temp_fix_volume,airplay_volume);
-
-
- /*
- // get the audio parameters
-
- int32_t min,max;
-
- if (config.output->parameters) {
- config.output->parameters(&audio_information);
- max = audio_information.maximum_volume_dB;
- min = audio_information.minimum_volume_dB;
- } else {
- max = 0;
- min = -9630;
- }
-
- double temp_fix_volume = 65536.0;
- double scaled_volume;
-
- if (airplay_volume==-144.0) { // if we are muting
- scaled_volume = min; // this is just for the metadata
- if (config.output->mute)
- config.output->mute(1); // use real mute if it's there
- else if (config.output->volume) {
- config.output->volume(min); // otherwise set the output to the lowest value
- temp_fix_volume = 0; // and set the software multiplier to 0.
- debug(1,"Software mute: mixer volume set to minimum: %d and software volume will be set to 0.",min);
- }
- } else { // not muting
-
- if (config.volume_range_db) {
- int32_t possible_min = max - (int)trunc(config.volume_range_db*100);
- if (possible_min > min)
- min = possible_min;
- }
-
- // now we have the true desired range, get the volume that is being set
- scaled_volume = vol2attn(airplay_volume, max, min);
- double software_volume = 0; // dB of attenuation
-
- if (config.output->volume) {
- if (scaled_volume>=min) {
- config.output->volume(scaled_volume);
- debug(1,"Set Volume, no split: mixer volume set to: %f",scaled_volume);
- } else {
- config.output->volume(min);
- software_volume = scaled_volume-min; // this is the attenuation in dB needed in software
- debug(1,"Set Volume, split: mixer volume set to: %f, software volume set to: %f.",min,software_volume);
- }
- } else {
- software_volume = scaled_volume;
- }
- if (config.output->mute) // if there is hardware mute...
- config.output->mute(0); // turn it off
- temp_fix_volume = 65536.0 * pow(10, software_volume / 2000);
- }
- debug(1,"Software linear volume set to %f ",temp_fix_volume);
- */
+ // debug(1,"Software attenuation set to %f, i.e %f out of 65,536, for airplay volume of %f",software_attenuation,temp_fix_volume,airplay_volume);
pthread_mutex_lock(&vol_mutex);
fix_volume = temp_fix_volume;
From 3d75ba381d349e6137848915ad57680b7031472d Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sat, 7 Nov 2015 19:20:43 +0000
Subject: [PATCH 020/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 407ae83c..2da0ce51 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,6 +1,7 @@
Version 2.7 -- Development Version
----
**New Features**
+* Extend the volume range for some DACs. Background: some of the cheaper DACS have a very small volume range (that is, the ratio of the highest to the lowest volume, expressed in decibels). In some really cheap DACs it's only around 30 dB. That means that the difference betweeen the lowest and highest volume settings isn't large enough. With the new feature, if you set the `general` `volume_range_db` to more than the hardware mixer's range, Shairport Sync will combine the hardware mixer's range with a software attenuator to give the desired range. For example, suppose you want a volume range of 70 dB and the hardware mixer offers only 30 dB, then Shairport Sync will make up ther other 40 dB with a software attenuator. The drawbacks are that, when the volume is being changed, there may be a slight delay (0.15 seconds by default) as the audio, whose volume may have been adjusted in software, propagetes through the system. The other slight possible drawback is a slightly heavier load on the processor.
* Add extra debug messages to the alsa back end to diagnose strange DACs.
* Add configuration file for the libao back end -- to change the buffer size and the latency offset, same is for stdout.
* Add shairport-sync.exe to .gitignore.
From 78196928007c927d916792c997139306bc1d5640 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sun, 8 Nov 2015 12:22:46 +0000
Subject: [PATCH 021/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 2da0ce51..3b48314d 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -2,6 +2,7 @@ Version 2.7 -- Development Version
----
**New Features**
* Extend the volume range for some DACs. Background: some of the cheaper DACS have a very small volume range (that is, the ratio of the highest to the lowest volume, expressed in decibels). In some really cheap DACs it's only around 30 dB. That means that the difference betweeen the lowest and highest volume settings isn't large enough. With the new feature, if you set the `general` `volume_range_db` to more than the hardware mixer's range, Shairport Sync will combine the hardware mixer's range with a software attenuator to give the desired range. For example, suppose you want a volume range of 70 dB and the hardware mixer offers only 30 dB, then Shairport Sync will make up ther other 40 dB with a software attenuator. The drawbacks are that, when the volume is being changed, there may be a slight delay (0.15 seconds by default) as the audio, whose volume may have been adjusted in software, propagetes through the system. The other slight possible drawback is a slightly heavier load on the processor.
+* Check for underflow a little better when buffer alisaing occurs on very bad connections...
* Add extra debug messages to the alsa back end to diagnose strange DACs.
* Add configuration file for the libao back end -- to change the buffer size and the latency offset, same is for stdout.
* Add shairport-sync.exe to .gitignore.
From 26cb5675c50a58f9d0bdd7b952f48ba8023f6234 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sun, 8 Nov 2015 12:23:52 +0000
Subject: [PATCH 022/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 3b48314d..2fe25877 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -2,7 +2,7 @@ Version 2.7 -- Development Version
----
**New Features**
* Extend the volume range for some DACs. Background: some of the cheaper DACS have a very small volume range (that is, the ratio of the highest to the lowest volume, expressed in decibels). In some really cheap DACs it's only around 30 dB. That means that the difference betweeen the lowest and highest volume settings isn't large enough. With the new feature, if you set the `general` `volume_range_db` to more than the hardware mixer's range, Shairport Sync will combine the hardware mixer's range with a software attenuator to give the desired range. For example, suppose you want a volume range of 70 dB and the hardware mixer offers only 30 dB, then Shairport Sync will make up ther other 40 dB with a software attenuator. The drawbacks are that, when the volume is being changed, there may be a slight delay (0.15 seconds by default) as the audio, whose volume may have been adjusted in software, propagetes through the system. The other slight possible drawback is a slightly heavier load on the processor.
-* Check for underflow a little better when buffer alisaing occurs on very bad connections...
+* Check for underflow a little better when buffer aliasing occurs on very bad connections...
* Add extra debug messages to the alsa back end to diagnose strange DACs.
* Add configuration file for the libao back end -- to change the buffer size and the latency offset, same is for stdout.
* Add shairport-sync.exe to .gitignore.
From 5898c5b29f43a30fd6d942272bd5add787701b83 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sun, 8 Nov 2015 12:25:21 +0000
Subject: [PATCH 023/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 2fe25877..e05a4fbd 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,7 +1,7 @@
Version 2.7 -- Development Version
----
**New Features**
-* Extend the volume range for some DACs. Background: some of the cheaper DACS have a very small volume range (that is, the ratio of the highest to the lowest volume, expressed in decibels). In some really cheap DACs it's only around 30 dB. That means that the difference betweeen the lowest and highest volume settings isn't large enough. With the new feature, if you set the `general` `volume_range_db` to more than the hardware mixer's range, Shairport Sync will combine the hardware mixer's range with a software attenuator to give the desired range. For example, suppose you want a volume range of 70 dB and the hardware mixer offers only 30 dB, then Shairport Sync will make up ther other 40 dB with a software attenuator. The drawbacks are that, when the volume is being changed, there may be a slight delay (0.15 seconds by default) as the audio, whose volume may have been adjusted in software, propagetes through the system. The other slight possible drawback is a slightly heavier load on the processor.
+* Extend the volume range for some DACs. Background: some of the cheaper DACS have a very small volume range (that is, the ratio of the highest to the lowest volume, expressed in decibels). In some really cheap DACs it's only around 30 dB. That means that the difference betweeen the lowest and highest volume settings isn't large enough. With the new feature, if you set the `general` `volume_range_db` to more than the hardware mixer's range, Shairport Sync will combine the hardware mixer's range with a software attenuator to give the desired range. For example, suppose you want a volume range of 70 dB and the hardware mixer offers only 30 dB, then Shairport Sync will make up the other 40 dB with a software attenuator. The drawbacks are that, when the volume is being changed, there may be a slight delay (0.15 seconds by default) as the audio, whose volume may have been adjusted in software, propagetes through the system. The other slight possible drawback is a slightly heavier load on the processor.
* Check for underflow a little better when buffer aliasing occurs on very bad connections...
* Add extra debug messages to the alsa back end to diagnose strange DACs.
* Add configuration file for the libao back end -- to change the buffer size and the latency offset, same is for stdout.
From 44a74d4e27f7e6d587fff24ca673cc60c87bac7f Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 9 Nov 2015 11:51:27 +0000
Subject: [PATCH 024/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index e05a4fbd..918020cb 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,7 +1,7 @@
Version 2.7 -- Development Version
----
**New Features**
-* Extend the volume range for some DACs. Background: some of the cheaper DACS have a very small volume range (that is, the ratio of the highest to the lowest volume, expressed in decibels). In some really cheap DACs it's only around 30 dB. That means that the difference betweeen the lowest and highest volume settings isn't large enough. With the new feature, if you set the `general` `volume_range_db` to more than the hardware mixer's range, Shairport Sync will combine the hardware mixer's range with a software attenuator to give the desired range. For example, suppose you want a volume range of 70 dB and the hardware mixer offers only 30 dB, then Shairport Sync will make up the other 40 dB with a software attenuator. The drawbacks are that, when the volume is being changed, there may be a slight delay (0.15 seconds by default) as the audio, whose volume may have been adjusted in software, propagetes through the system. The other slight possible drawback is a slightly heavier load on the processor.
+* Extend the volume range for some DACs. Background: some of the cheaper DACS have a very small volume range (that is, the ratio of the highest to the lowest volume, expressed in decibels). In some really cheap DACs it's only around 30 dB. That means that the difference betweeen the lowest and highest volume settings isn't large enough. With the new feature, if you set the `general` `volume_range_db` to more than the hardware mixer's range, Shairport Sync will combine the hardware mixer's range with a software attenuator to give the desired range. For example, suppose you want a volume range of 70 dB and the hardware mixer offers only 30 dB, then Shairport Sync will make up the other 40 dB with a software attenuator. The drawbacks are that, when the volume is being changed, there may be a slight delay (0.15 seconds by default) as the audio, whose volume may have been adjusted in software, propagates through the system. The other slight possible drawback is a slightly heavier load on the processor.
* Check for underflow a little better when buffer aliasing occurs on very bad connections...
* Add extra debug messages to the alsa back end to diagnose strange DACs.
* Add configuration file for the libao back end -- to change the buffer size and the latency offset, same is for stdout.
From 6ff36f56a8f6d3b983c35fdf1419ea0e70d82cad Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 9 Nov 2015 11:55:26 +0000
Subject: [PATCH 025/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 918020cb..921f73e3 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,11 +1,11 @@
Version 2.7 -- Development Version
----
**New Features**
-* Extend the volume range for some DACs. Background: some of the cheaper DACS have a very small volume range (that is, the ratio of the highest to the lowest volume, expressed in decibels). In some really cheap DACs it's only around 30 dB. That means that the difference betweeen the lowest and highest volume settings isn't large enough. With the new feature, if you set the `general` `volume_range_db` to more than the hardware mixer's range, Shairport Sync will combine the hardware mixer's range with a software attenuator to give the desired range. For example, suppose you want a volume range of 70 dB and the hardware mixer offers only 30 dB, then Shairport Sync will make up the other 40 dB with a software attenuator. The drawbacks are that, when the volume is being changed, there may be a slight delay (0.15 seconds by default) as the audio, whose volume may have been adjusted in software, propagates through the system. The other slight possible drawback is a slightly heavier load on the processor.
+* Extend the volume range for some DACs. Background: some of the cheaper DACS have a very small volume range (that is, the ratio of the highest to the lowest volume, expressed in decibels). In some really cheap DACs it's only around 30 dB. That means that the difference betweeen the lowest and highest volume settings isn't large enough. With the new feature, if you set the `general` `volume_range_db` to more than the hardware mixer's range, Shairport Sync will combine the hardware mixer's range with a software attenuator to give the desired range. For example, suppose you want a volume range of 70 dB and the hardware mixer offers only 30 dB, then Shairport Sync will make up the other 40 dB with a software attenuator. One drawback is that, when the volume is being changed, there may be a slight delay (0.15 seconds by default) as the audio, whose volume may have been adjusted in software, propagates through the system. Another slight possible drawback is a slightly heavier load on the processor.
* Check for underflow a little better when buffer aliasing occurs on very bad connections...
* Add extra debug messages to the alsa back end to diagnose strange DACs.
-* Add configuration file for the libao back end -- to change the buffer size and the latency offset, same is for stdout.
-* Add shairport-sync.exe to .gitignore.
+* Add configuration file for the `libao` back end -- to change the buffer size and the latency offset, same as for stdout.
+* Add `shairport-sync.exe` to `.gitignore`.
* Add a check to see if compilation is for a CYGWIN platform.
* Add `rtptime` tags to metadata and picture information and add two new metadata items to precede and follow the transmission of a picture. Background: it seems that metadata and picture information for the same item, e.g. a track, are normally tagged with a timestamp called the `rtptime`; if they refer to the same item, they will have the same `rtptime` tags. The update here is to add the `rtptime` value, if available, as data to the `mdst` and `mden` metadata items, which are sent before ("MetaData STart") and after ("MetaData ENd") a metadata sequence.
In addition, similar tags -- `pcst` ("PiCture STart") and `pcen` ("PiCture ENd") are now sent before and after a picture with the `rtptime` value, if available, sent as data.
From 0602bc1f18f01b73e7202b16b82b96563e284fab Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 9 Nov 2015 11:59:44 +0000
Subject: [PATCH 026/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 921f73e3..74f37a97 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -102,7 +102,7 @@ Version 2.3.12
**Enhancements**
-* Larger range of interpolation. Shairport Sync has previously constrained not to make interpolations ("corrections") of more than about 1 per 1000 real frames. This contraint has been relaxed, and it is now able to make corrections of up to 1 in 352 real frames. This might result in a faster and undesirably sudden correction early during a play session, so a number of further changes have been made. The full set of these changes is as follows:
+* Larger range of interpolation. Shairport Sync was previously constrained not to make interpolations ("corrections") of more than about 1 per 1000 frames. This contraint has been relaxed, and it is now able to make corrections of up to 1 in 352 frames. This might result in a faster and undesirably sudden correction early during a play session, so a number of further changes have been made. The full set of these changes is as follows:
* No corrections happen for the first five seconds.
* Corrections of up to about 1 in 1000 for the next 25 seconds.
* Corrections of up to 1 in 352 thereafter.
From d1a61a75a45bb6909d9119970438e4d9795249f9 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 9 Nov 2015 12:05:44 +0000
Subject: [PATCH 027/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 74f37a97..2a45990e 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -6,7 +6,7 @@ Version 2.7 -- Development Version
* Add extra debug messages to the alsa back end to diagnose strange DACs.
* Add configuration file for the `libao` back end -- to change the buffer size and the latency offset, same as for stdout.
* Add `shairport-sync.exe` to `.gitignore`.
-* Add a check to see if compilation is for a CYGWIN platform.
+* Add a check to support compilation on a CYGWIN platform.
* Add `rtptime` tags to metadata and picture information and add two new metadata items to precede and follow the transmission of a picture. Background: it seems that metadata and picture information for the same item, e.g. a track, are normally tagged with a timestamp called the `rtptime`; if they refer to the same item, they will have the same `rtptime` tags. The update here is to add the `rtptime` value, if available, as data to the `mdst` and `mden` metadata items, which are sent before ("MetaData STart") and after ("MetaData ENd") a metadata sequence.
In addition, similar tags -- `pcst` ("PiCture STart") and `pcen` ("PiCture ENd") are now sent before and after a picture with the `rtptime` value, if available, sent as data.
By the way, the progress metadata (`prgr` for "PRoGRess"), which is sent just when a track starts, contains the same `rtptime` as its middle element.
From 1aee9bd2dce28e64d6425c49674f94774e31dc97 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 9 Nov 2015 12:22:37 +0000
Subject: [PATCH 028/144] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index af85dd3e..aebf32a6 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ Shairport Sync works by using timing information and timestamps present in data
To maintain the exact latency required, if an output device is running slow relative to the source, Shairport Sync will delete frames of audio to allow the device to keep up. If the output device is running fast, Shairport Sync will insert frames to keep time. The number of frames inserted or deleted is so small as to be almost inaudible on normal audio material. Frames are inserted or deleted as necessary at pseudorandom intervals. Alternatively, with `libsoxr` support, Shairport Sync can resample the audio feed to ensure the output device can keep up. This is less obtrusive than insertion and deletion but requires a good deal of processing power — most embedded devices probably can't support it. The process of insertion/deletion or resampling is rather inelegantly called “stuffing”.
-The exact latency to be used is specified by the source when it negotiates with Shaiport Sync. Most sources set a latency of 88,200 frames -- exactly two seconds. Recent versions of iTunes and forkedDaapd use a latency of 99,577 frames (pretty close to the 99,400 frames estimated from listening tests!).
+The exact latency to be used is specified by the source when it negotiates with Shairport Sync. Most sources set a latency of 88,200 frames -- exactly two seconds. Recent versions of iTunes and forkedDaapd use a latency of 99,577 frames (pretty close to the 99,400 frames estimated from listening tests!).
Shairport Sync is a pretty substantial rewrite of the fantastic work done in Shairport 1.0 by James Laird and others — please see https://github.com/abrasive/shairport/blob/master/README.md#contributors-to-version-1x for a list of the contributors to Shairport 1.x and Shairport 0.x. From a "heritage" point of view, Shairport Sync is a fork of Shairport 1.0.
From b0bfbdc04e4a4fb1784c529e56945ce874b14425 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 9 Nov 2015 13:29:04 +0000
Subject: [PATCH 029/144] Add back in the code used to store the volume level
set initially.
---
audio_alsa.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/audio_alsa.c b/audio_alsa.c
index f2afc1a5..018563ee 100644
--- a/audio_alsa.c
+++ b/audio_alsa.c
@@ -447,6 +447,7 @@ static void parameters(audio_parameters *info) {
static void volume(double vol) {
// debug(1,"Setting volume db to %f, for volume input of %f.",vol_setting/100,vol);
+ set_volume = vol;
if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, -1) != 0)
die("Failed to set playback dB volume");
}
From 66166026c9bf6a8f0514d95628447f3052f53307 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 9 Nov 2015 13:31:02 +0000
Subject: [PATCH 030/144] Bump to 2.7.1 due to bug fix w.r.t. alsa stored
volume control
---
configure.ac | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index 19ec1993..8a02fad5 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], [2.7], [mikebrady@eircom.net])
+AC_INIT([shairport-sync], [2.7.1], [mikebrady@eircom.net])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([shairport.c])
AC_CONFIG_HEADERS([config.h])
From df70b8a2418622d4b4829a43621eb7d643a94b16 Mon Sep 17 00:00:00 2001
From: Richard Joyce
Date: Wed, 18 Nov 2015 08:05:07 -0800
Subject: [PATCH 031/144] Update LIBSOXR.md
Fix the shairport-sync build option
---
LIBSOXR.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/LIBSOXR.md b/LIBSOXR.md
index 80a67987..4883b9b2 100644
--- a/LIBSOXR.md
+++ b/LIBSOXR.md
@@ -25,4 +25,4 @@ Finally, for Shairport Sync to be able to locate `libsoxr-dev` during compilatio
```
sudo ldconfig -v
```
-That's it. Now you can select the `--with-libsoxr` option when you're building Shairport Sync.
+That's it. Now you can select the `--with-soxr` option when you're building Shairport Sync.
From 145b4457e0dd3f10770f95a6ddc0a7cf343c9c6c Mon Sep 17 00:00:00 2001
From: Nick Steel
Date: Sat, 21 Nov 2015 16:07:25 +0000
Subject: [PATCH 032/144] Fix git not ignoring generated files in man/
---
.gitignore | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.gitignore b/.gitignore
index d42ad865..4aa1c87b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,5 @@ install-sh
missing
stamp-h1
.deps
+man/Makefile
+man/Makefile.in
From 33e39b7eb7cbce58ee58df4982e8d8597c135f13 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 24 Nov 2015 12:18:29 +0000
Subject: [PATCH 033/144] Add some extra information to the notices placed in
the logfile if there are prtoblems with alsa
---
audio_alsa.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/audio_alsa.c b/audio_alsa.c
index 018563ee..76d00742 100644
--- a/audio_alsa.c
+++ b/audio_alsa.c
@@ -280,22 +280,22 @@ int open_alsa_device(void) {
ret = snd_pcm_hw_params_any(alsa_handle, alsa_params);
if (ret < 0) {
- die("audio_alsa: Broken configuration for %s: no configurations available", alsa_out_dev);
+ die("audio_alsa: Broken configuration for device \"%s\": no configurations available", alsa_out_dev);
}
ret = snd_pcm_hw_params_set_access(alsa_handle, alsa_params, SND_PCM_ACCESS_RW_INTERLEAVED);
if (ret < 0) {
- die("audio_alsa: Access type not available for %s: %s", alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Access type not available for device \"%s\": %s", alsa_out_dev, snd_strerror(ret));
}
ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, SND_PCM_FORMAT_S16);
if (ret < 0) {
- die("audio_alsa: Sample format not available for %s: %s", alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Sample format not available for device \"%s\": %s", alsa_out_dev, snd_strerror(ret));
}
ret = snd_pcm_hw_params_set_channels(alsa_handle, alsa_params, 2);
if (ret < 0) {
- die("audio_alsa: Channels count (2) not available for %s: %s", alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Channels count (2) not available for device \"%s\": %s", alsa_out_dev, snd_strerror(ret));
}
ret = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params, &my_sample_rate, &dir);
@@ -308,7 +308,7 @@ int open_alsa_device(void) {
ret = snd_pcm_hw_params(alsa_handle, alsa_params);
if (ret < 0) {
- die("audio_alsa: Unable to set hw parameters for %s: %s.", alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Unable to set hw parameters for device \"%s\": %s.", alsa_out_dev, snd_strerror(ret));
}
if (my_sample_rate != desired_sample_rate) {
@@ -317,7 +317,7 @@ int open_alsa_device(void) {
ret = snd_pcm_hw_params_get_buffer_size(alsa_params,&actual_buffer_length);
if (ret < 0) {
- die("audio_alsa: Unable to get hw buffer length for %s: %s.", alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Unable to get hw buffer length for device \"%s\": %s.", alsa_out_dev, snd_strerror(ret));
}
if (actual_buffer_length < config.audio_backend_buffer_desired_length+buffer_headroom) {
@@ -325,9 +325,9 @@ int open_alsa_device(void) {
buffer_size = config.audio_backend_buffer_desired_length+buffer_headroom;
ret = snd_pcm_hw_params_set_buffer_size_near(alsa_handle, alsa_params, &buffer_size);
if (ret < 0)
- die("audio_alsa: Unable to set hw buffer size to %lu for %s: %s.", config.audio_backend_buffer_desired_length+buffer_headroom, alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Unable to set hw buffer size to %lu for device \"%s\": %s.", config.audio_backend_buffer_desired_length+buffer_headroom, alsa_out_dev, snd_strerror(ret));
if (config.audio_backend_buffer_desired_length+buffer_headroom > buffer_size)
- die("audio_alsa: Can't set hw buffer size to %lu for %s: %s.", config.audio_backend_buffer_desired_length+buffer_headroom, alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Can't set hw buffer size to %lu for device \"%s\": %s.", config.audio_backend_buffer_desired_length+buffer_headroom, alsa_out_dev, snd_strerror(ret));
}
return (0);
@@ -335,7 +335,7 @@ int open_alsa_device(void) {
static void start(int sample_rate) {
if (sample_rate != 44100)
- die("Unexpected sample rate %d -- only 44,100 supported!", sample_rate);
+ die("Unexpected sample rate %d -- only 44,100 supported!", sample_rate);
desired_sample_rate = sample_rate; // must be a variable
}
From f705d2367a661b990d6cea18415af49f0266853b Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 24 Nov 2015 12:19:12 +0000
Subject: [PATCH 034/144] Fix a stupind error what supressed the rtptime
information regarding metadata and pictures
---
rtsp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/rtsp.c b/rtsp.c
index 503fb7eb..2657b4d0 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -1144,7 +1144,7 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
if (!strncmp(ct, "application/x-dmap-tagged", 25)) {
debug(2, "received metadata tags in SET_PARAMETER request.");
- if (p=NULL)
+ if (p==NULL)
debug(1,"Missing RTP-Time info for metadata");
if (p)
send_metadata('ssnc', 'mdst', p+1, strlen(p+1), req, 1); // metadata starting
@@ -1163,7 +1163,7 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
// debug(1, "received image in SET_PARAMETER request.");
// note: the image/type tag isn't reliable, so it's not being sent
// -- best look at the first few bytes of the image
- if (p=NULL)
+ if (p==NULL)
debug(1,"Missing RTP-Time info for picture item");
if (p)
send_metadata('ssnc', 'pcst', p+1, strlen(p+1), req, 1); // picture starting
From 223d52144e40db96fa0c3a7e55e6bfcfa3720412 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 24 Nov 2015 12:20:11 +0000
Subject: [PATCH 035/144] Fix a metadata bug and add some extra diagnostic
information for alsa
---
configure.ac | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index 8a02fad5..3cb2e034 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], [2.7.1], [mikebrady@eircom.net])
+AC_INIT([shairport-sync], [2.7.2], [mikebrady@eircom.net])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([shairport.c])
AC_CONFIG_HEADERS([config.h])
@@ -201,7 +201,7 @@ AC_ARG_WITH(pulseaudio, [ --with-pulseaudio = choose native PulseAudio API supp
AC_MSG_RESULT(>>Including a PulseAudio back end -- N.B. no synchronisation -- so underflow or overflow is inevitable!)
HAS_PULSE=1
AC_DEFINE([CONFIG_PULSE], 1, [Needed by the compiler.])
- AC_CHECK_LIB([pulse-simple], [pa_simple_new], , AC_MSG_ERROR(PulseAudio support requires the pulse-simple library!))
+ AC_CHECK_LIB([pulse-simple], [pa_simple_new], , AC_MSG_ERROR(PulseAudio support requires the pulse-simple library, possibly in the package libpulse-dev!))
AC_CHECK_LIB([pulse], [pa_stream_peek], , AC_MSG_ERROR(PulseAudio support requires the libpulse-dev library!))], )
AM_CONDITIONAL([USE_PULSE], [test "x$HAS_PULSE" = "x1"])
From 5449851920c79140728ab6558a5e39e53e4705f9 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 24 Nov 2015 12:26:48 +0000
Subject: [PATCH 036/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 2a45990e..5216c1c4 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,3 +1,15 @@
+Version 2.7.2 -- Development Version
+----
+**Bug Fix**
+* Fix a bug that suppressed output of the `rtptime` associated with metadata and with picture information coming from the audio source and passed on via the metadata pipe.
+**Other Changes**
+* Added some more information to the log outputs whenever problems are detected with the output alsa device.
+
+Version 2.7.1 -- Development Version
+----
+**Bug Fix**
+* The new volume-extension code was not correctly setting the volume after a pause / resume. Fixed.
+
Version 2.7 -- Development Version
----
**New Features**
From a8cfe68921bd173d609b5acefa7d6aee5c28a185 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 24 Nov 2015 12:28:13 +0000
Subject: [PATCH 037/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 5216c1c4..d25e78a1 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -2,8 +2,9 @@ Version 2.7.2 -- Development Version
----
**Bug Fix**
* Fix a bug that suppressed output of the `rtptime` associated with metadata and with picture information coming from the audio source and passed on via the metadata pipe.
+
**Other Changes**
-* Added some more information to the log outputs whenever problems are detected with the output alsa device.
+* Added some more information to the log whenever problems are detected with the proposed alsa device.
Version 2.7.1 -- Development Version
----
From c15c49fd2e468cf93c3ce97fb3e47cad1fd61226 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Thu, 26 Nov 2015 17:32:08 +0000
Subject: [PATCH 038/144] Fix the software-volume control dither algorithm,
which was (a) broken [by me] and (b) not best practice anyway.
---
configure.ac | 2 +-
player.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 53 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index 3cb2e034..55e236d3 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], [2.7.2], [mikebrady@eircom.net])
+AC_INIT([shairport-sync], [2.7.3], [mikebrady@eircom.net])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([shairport.c])
AC_CONFIG_HEADERS([config.h])
diff --git a/player.c b/player.c
index 34d7ad1d..ed525d79 100644
--- a/player.c
+++ b/player.c
@@ -373,18 +373,68 @@ void player_put_packet(seq_t seqno, uint32_t timestamp, uint8_t *data, int len)
pthread_mutex_unlock(&ab_mutex);
}
+int32_t rand_in_range(int32_t exclusive_range_limit) {
+ static uint32_t lcg_prev = 12345;
+ // returns a pseudo random integer in the range 0 to (exclusive_range_limit-1) inclusive
+ int64_t sp = lcg_prev;
+ int64_t rl = exclusive_range_limit;
+ lcg_prev = lcg_prev * 69069 + 3; // crappy psrg
+ sp = sp*rl; // 64 bit calculation. INtersting part if above the 32 rightmost bits;
+ return sp >> 32;
+}
+
+static inline short dithered_vol(short sample) {
+ int32_t out;
+
+ out = (int32_t)sample * fix_volume;
+ if (fix_volume < 0x10000) {
+
+ // add a TPDF dither -- see http://www.users.qwest.net/%7Evolt42/cadenzarecording/DitherExplained.pdf
+ // and the discussion around https://www.hydrogenaud.io/forums/index.php?showtopic=16963&st=25
+
+ // I think, for a 32 --> 16 bits, the range of
+ // random numbers needs to be from -2^16 to 2^16, i.e. from -65536 to 65536 inclusive, not from -32768 to +32767
+
+ // See the original paper at http://www.ece.rochester.edu/courses/ECE472/resources/Papers/Lipshitz_1992.pdf
+ // by Lipshitz, Wannamaker and Vanderkooy, 1992.
+
+ int32_t tpdf = rand_in_range(65536+1) - rand_in_range(65536+1);
+ // Check there's no clipping -- if there is,
+ if (tpdf>=0) {
+ if (LONG_MAX-tpdf>=out)
+ out += tpdf;
+ else
+ out = LONG_MAX;
+ } else {
+ if (LONG_MIN-tpdf<=out)
+ out += tpdf;
+ else
+ out = LONG_MIN;
+ }
+ }
+ return out >> 16;
+}
+
+
+/*
static inline short lcg_rand(void) {
static unsigned long lcg_prev = 12345;
lcg_prev = lcg_prev * 69069 + 3;
return lcg_prev & 0xffff;
}
+
static inline short dithered_vol(short sample) {
- short rand_a, rand_b;
+ static short rand_a;
+ short rand_b;
long out;
out = (long)sample * fix_volume;
if (fix_volume < 0x10000) {
+ // add a TPDF dither -- see http://www.users.qwest.net/%7Evolt42/cadenzarecording/DitherExplained.pdf
+ // and the discussion around https://www.hydrogenaud.io/forums/index.php?showtopic=16963&st=25
+ // I think it's wrong. I think, for a 32 --> 16 bits, the range of
+ // random numbers needs to be from 0 to 2^16, i.e. from 0 to 65536, not from -32768bto +32767
rand_b = rand_a;
rand_a = lcg_rand();
out += rand_a;
@@ -392,6 +442,7 @@ static inline short dithered_vol(short sample) {
}
return out >> 16;
}
+*/
// get the next frame, when available. return 0 if underrun/stream reset.
static abuf_t *buffer_get_frame(void) {
From b5bff1c0f6a07e084d69012471143a4ec597dd1a Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Thu, 26 Nov 2015 17:38:06 +0000
Subject: [PATCH 039/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index d25e78a1..0b6464b6 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,3 +1,8 @@
+Version 2.7.3 -- Development Version
+----
+**Bug Fix**
+* The dither algorithm was broken (by me) and also less than ideal anyway. Fixed and improved. More later...
+
Version 2.7.2 -- Development Version
----
**Bug Fix**
From 977816d07397a987930e4a7acaeced40bb6d0055 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Fri, 27 Nov 2015 10:38:26 +0000
Subject: [PATCH 040/144] Add note about dither
---
RELEASENOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 0b6464b6..d26815e2 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,7 +1,7 @@
Version 2.7.3 -- Development Version
----
**Bug Fix**
-* The dither algorithm was broken (by me) and also less than ideal anyway. Fixed and improved. More later...
+* The dither code was broken in Shairport Sync and also less than ideal anyway. Fixed and improved. Dither is added whenever you use the software volume control. See http://www.ece.rochester.edu/courses/ECE472/resources/Papers/Lipshitz_1992.pdf for a very influential paper by Lipshitz, Wannamaker and Vanderkooy, 1992. The dither code in Shairport Sync was inherited from Shairport and does not conform to the recommendations in the paper -- specifically the implementation wold give one bit of dither where the paper recommends two bits peak-to-peak. The other thing is that the inherited dither code was actually broken in Shairport Sync. So, the new dither code gives a two bit peak-to-peak dither based on a Triangular Propability Distributing Function (TPDF). It sounds like a very low-level white noise, unmodulated by the audio material. It would be nice if it was even lower, but it's better than listening to the artifacts present when dithering is disabled.
Version 2.7.2 -- Development Version
----
From f33997ca785a7ce4daf6e2092ee38f7f4798da69 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Fri, 27 Nov 2015 10:43:55 +0000
Subject: [PATCH 041/144] Edit one about dither -- typo.
---
RELEASENOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index d26815e2..f6655005 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,7 +1,7 @@
Version 2.7.3 -- Development Version
----
**Bug Fix**
-* The dither code was broken in Shairport Sync and also less than ideal anyway. Fixed and improved. Dither is added whenever you use the software volume control. See http://www.ece.rochester.edu/courses/ECE472/resources/Papers/Lipshitz_1992.pdf for a very influential paper by Lipshitz, Wannamaker and Vanderkooy, 1992. The dither code in Shairport Sync was inherited from Shairport and does not conform to the recommendations in the paper -- specifically the implementation wold give one bit of dither where the paper recommends two bits peak-to-peak. The other thing is that the inherited dither code was actually broken in Shairport Sync. So, the new dither code gives a two bit peak-to-peak dither based on a Triangular Propability Distributing Function (TPDF). It sounds like a very low-level white noise, unmodulated by the audio material. It would be nice if it was even lower, but it's better than listening to the artifacts present when dithering is disabled.
+* The dither code was broken in Shairport Sync and also less than ideal anyway. Fixed and improved. Dither is added whenever you use the software volume control. See http://www.ece.rochester.edu/courses/ECE472/resources/Papers/Lipshitz_1992.pdf for a very influential paper by Lipshitz, Wannamaker and Vanderkooy, 1992. The dither code in Shairport Sync was inherited from Shairport and does not conform to the recommendations in the paper -- specifically the implementation would give one bit of dither where the paper recommends two bits peak-to-peak. The other thing is that the inherited dither code was actually broken in Shairport Sync. So, the new dither code gives a two bit peak-to-peak dither based on a Triangular Propability Distributing Function (TPDF). It sounds like a very low-level white noise, unmodulated by the audio material. It would be nice if it was even lower, but it's better than listening to the artifacts present when dithering is disabled.
Version 2.7.2 -- Development Version
----
From 5b607422b0c395091bb0e5d9fde65cab3b2f5272 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Fri, 27 Nov 2015 10:46:36 +0000
Subject: [PATCH 042/144] Clarify that dither is not added at full volujme
---
RELEASENOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index f6655005..a3d0b3eb 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,7 +1,7 @@
Version 2.7.3 -- Development Version
----
**Bug Fix**
-* The dither code was broken in Shairport Sync and also less than ideal anyway. Fixed and improved. Dither is added whenever you use the software volume control. See http://www.ece.rochester.edu/courses/ECE472/resources/Papers/Lipshitz_1992.pdf for a very influential paper by Lipshitz, Wannamaker and Vanderkooy, 1992. The dither code in Shairport Sync was inherited from Shairport and does not conform to the recommendations in the paper -- specifically the implementation would give one bit of dither where the paper recommends two bits peak-to-peak. The other thing is that the inherited dither code was actually broken in Shairport Sync. So, the new dither code gives a two bit peak-to-peak dither based on a Triangular Propability Distributing Function (TPDF). It sounds like a very low-level white noise, unmodulated by the audio material. It would be nice if it was even lower, but it's better than listening to the artifacts present when dithering is disabled.
+* The dither code was broken in Shairport Sync and also less than ideal anyway. Fixed and improved. Dither is added whenever you use the software volume control at less than full volume. See http://www.ece.rochester.edu/courses/ECE472/resources/Papers/Lipshitz_1992.pdf for a very influential paper by Lipshitz, Wannamaker and Vanderkooy, 1992. The dither code in Shairport Sync was inherited from Shairport and does not conform to the recommendations in the paper -- specifically the implementation would give one bit of dither where the paper recommends two bits peak-to-peak. The other thing is that the inherited dither code was actually broken in Shairport Sync. So, the new dither code gives a two bit peak-to-peak dither based on a Triangular Propability Distributing Function (TPDF). It sounds like a very low-level white noise, unmodulated by the audio material. It would be nice if it was even lower, but it's better than listening to the artifacts present when dithering is disabled.
Version 2.7.2 -- Development Version
----
From de6fee22d76f57c099f1dac0b56a281ae77663ac Mon Sep 17 00:00:00 2001
From: Mke Brady
Date: Sun, 29 Nov 2015 09:18:18 +0000
Subject: [PATCH 043/144] Fix typo which could have become a bug
---
rtp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rtp.c b/rtp.c
index fcffd860..78a19a36 100644
--- a/rtp.c
+++ b/rtp.c
@@ -691,7 +691,7 @@ void rtp_request_resend(seq_t first, uint32_t count) {
*(unsigned short *)(req + 6) = htons(count); // count
socklen_t msgsize = sizeof(struct sockaddr_in);
#ifdef AF_INET6
- if (rtp_client_timing_socket.SAFAMILY == AF_INET6) {
+ if (rtp_client_control_socket.SAFAMILY == AF_INET6) {
msgsize = sizeof(struct sockaddr_in6);
}
#endif
From 7b2208fe3604c817f0edd346db62c242587d2718 Mon Sep 17 00:00:00 2001
From: Mke Brady
Date: Sun, 29 Nov 2015 09:19:42 +0000
Subject: [PATCH 044/144] Quiten the diagnostic and error messages
---
tinysvcmdns.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tinysvcmdns.c b/tinysvcmdns.c
index bdb6c090..cadea483 100644
--- a/tinysvcmdns.c
+++ b/tinysvcmdns.c
@@ -33,7 +33,7 @@
#include "tinysvcmdns.h"
#include "common.h"
-#define DEBUG_PRINTF(...) debug(1, __VA_ARGS__)
+#define DEBUG_PRINTF(...) debug(3, __VA_ARGS__)
#define log_message(level, ...) \
do { \
switch (level) { \
@@ -41,7 +41,7 @@
warn(__VA_ARGS__); \
break; \
default: \
- debug(1, __VA_ARGS__); \
+ debug(3, __VA_ARGS__); \
} \
} while (0)
From af0bde477791742ba569b9c05a4dfa8ab51f9775 Mon Sep 17 00:00:00 2001
From: Mke Brady
Date: Sun, 29 Nov 2015 09:40:56 +0000
Subject: [PATCH 045/144] Update some of the help text.
---
shairport.c | 40 +++++++++++++++++++++-------------------
1 file changed, 21 insertions(+), 19 deletions(-)
diff --git a/shairport.c b/shairport.c
index 5aa521d7..db62a0a5 100644
--- a/shairport.c
+++ b/shairport.c
@@ -157,31 +157,33 @@ void usage(char *progname) {
printf(" or: %s [options...] -- [audio output-specific options]\n", progname);
printf("\n");
printf("Options:\n");
- printf(" -h, --help show this help\n");
+ printf(" -h, --help show this help.\n");
printf(" -d, --daemon daemonise.\n");
- printf(" -V, --version show version information\n");
+ printf(" -V, --version show version information.\n");
printf(" -k, --kill kill the existing shairport daemon.\n");
printf(" -D, --disconnectFromOutput disconnect immediately from the output device.\n");
printf(" -R, --reconnectToOutput reconnect to the output device.\n");
printf(" -c, --configfile=FILE read configuration settings from FILE. Default is "
"/etc/shairport-sync.conf.\n");
- 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("\n");
+ printf("The following general options from here onwards have corresponding settings in the configuration file, by default /etc/shairport-sync.conf:\n");
+ 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 set the latency for audio sent from an AirPlay device.\n");
- printf(" The default value is %d frames.\n", config.AirPlayLatency);
+ " -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 set the latency for audio sent from iTunes 10 or later.\n");
- printf(" The default value is %d frames.\n", config.iTunesLatency);
- printf(" -L, --latency=FRAMES set the latency for audio sent from an unknown device\n");
- printf(" or from an old version of iTunes. Default is %d frames.\n",
- config.latency);
- printf(" --forkedDaapdLatency=FRAMES set the latency for audio sent from forked-daapd.\n");
- printf(" -S, --stuffing=MODE set how to adjust current latency to match desired latency \n");
+ " -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");
printf(" \"basic\" (default) inserts or deletes audio frames from "
- "packet frames with low processor overhead.\n");
+ "packet frames with low processor overhead, and \n");
printf(" \"soxr\" uses libsoxr to minimally resample packet frames -- "
"moderate processor overhead.\n");
printf(
@@ -192,9 +194,9 @@ void usage(char *progname) {
"e.g. /usr/bin/logger.\n");
printf(" Executable scripts work, but must have #!/bin/sh (or "
"whatever) in the headline.\n");
- printf(" -w, --wait-cmd wait until the -B or -E programs finish before continuing\n");
- printf(" -o, --output=BACKEND select audio output method\n");
- printf(" -m, --mdns=BACKEND force the use of BACKEND to advertize the service\n");
+ printf(" -w, --wait-cmd wait until the -B or -E programs finish before continuing.\n");
+ printf(" -o, --output=BACKEND select audio output method.\n");
+ printf(" -m, --mdns=BACKEND force the use of BACKEND to advertize the service.\n");
printf(" if no mdns provider is specified,\n");
printf(" shairport tries them all until one works.\n");
printf(" -r, --resync=THRESHOLD resync if error exceeds this number of frames. Set to 0 to "
@@ -210,9 +212,9 @@ void usage(char *progname) {
#ifdef CONFIG_METADATA
printf(" --metadata-pipename=PIPE send metadata to PIPE, e.g. "
"--metadata-pipename=/tmp/shairport-sync-metadata.\n");
+ printf(" The default is /tmp/shairport-sync-metadata.\n");
printf(" --get-coverart send cover art through the metadata pipe.\n");
#endif
- printf("\nGeneral options can be configured in /etc/%s.conf.\n", appName);
printf("\n");
mdns_ls_backends();
printf("\n");
From 5d646e795b7523189a7a0c6c8d22845e6a249bfc Mon Sep 17 00:00:00 2001
From: Mke Brady
Date: Sun, 29 Nov 2015 09:55:03 +0000
Subject: [PATCH 046/144] Clarify the help wording a little.
---
shairport.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/shairport.c b/shairport.c
index db62a0a5..93be47e2 100644
--- a/shairport.c
+++ b/shairport.c
@@ -167,7 +167,7 @@ void usage(char *progname) {
"/etc/shairport-sync.conf.\n");
printf("\n");
- printf("The following general options from here onwards have corresponding settings in the configuration file, by default /etc/shairport-sync.conf:\n");
+ printf("The following general options are for backward compatability. These and all new options have settings in the configuration file, by default /etc/shairport-sync.conf:\n");
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");
From 73c3744e4ceb2421c1f4caf9e3efb25ba962564a Mon Sep 17 00:00:00 2001
From: Mke Brady
Date: Sun, 29 Nov 2015 20:59:11 +0000
Subject: [PATCH 047/144] Add check for processor endianness. Fix a small
warning.
---
common.h | 2 ++
player.c | 35 +++--------------------------------
shairport.c | 33 +++++++++++++++++++++++++++++++++
3 files changed, 38 insertions(+), 32 deletions(-)
diff --git a/common.h b/common.h
index 72e2758c..01ce9de0 100644
--- a/common.h
+++ b/common.h
@@ -2,6 +2,7 @@
#define _COMMON_H
#include
+#include
#include
#include
@@ -116,6 +117,7 @@ uint64_t get_absolute_time_in_fp(void);
// this is for reading an unsigned 32 bit number, such as an RTP timestamp
+long endianness;
uint32_t uatoi(const char *nptr);
shairport_cfg config;
diff --git a/player.c b/player.c
index ed525d79..de2a980f 100644
--- a/player.c
+++ b/player.c
@@ -384,9 +384,9 @@ int32_t rand_in_range(int32_t exclusive_range_limit) {
}
static inline short dithered_vol(short sample) {
- int32_t out;
+ long out;
- out = (int32_t)sample * fix_volume;
+ out = (long)sample * fix_volume;
if (fix_volume < 0x10000) {
// add a TPDF dither -- see http://www.users.qwest.net/%7Evolt42/cadenzarecording/DitherExplained.pdf
@@ -398,7 +398,7 @@ static inline short dithered_vol(short sample) {
// See the original paper at http://www.ece.rochester.edu/courses/ECE472/resources/Papers/Lipshitz_1992.pdf
// by Lipshitz, Wannamaker and Vanderkooy, 1992.
- int32_t tpdf = rand_in_range(65536+1) - rand_in_range(65536+1);
+ long tpdf = rand_in_range(65536+1) - rand_in_range(65536+1);
// Check there's no clipping -- if there is,
if (tpdf>=0) {
if (LONG_MAX-tpdf>=out)
@@ -415,35 +415,6 @@ static inline short dithered_vol(short sample) {
return out >> 16;
}
-
-/*
-static inline short lcg_rand(void) {
- static unsigned long lcg_prev = 12345;
- lcg_prev = lcg_prev * 69069 + 3;
- return lcg_prev & 0xffff;
-}
-
-
-static inline short dithered_vol(short sample) {
- static short rand_a;
- short rand_b;
- long out;
-
- out = (long)sample * fix_volume;
- if (fix_volume < 0x10000) {
- // add a TPDF dither -- see http://www.users.qwest.net/%7Evolt42/cadenzarecording/DitherExplained.pdf
- // and the discussion around https://www.hydrogenaud.io/forums/index.php?showtopic=16963&st=25
- // I think it's wrong. I think, for a 32 --> 16 bits, the range of
- // random numbers needs to be from 0 to 2^16, i.e. from 0 to 65536, not from -32768bto +32767
- rand_b = rand_a;
- rand_a = lcg_rand();
- out += rand_a;
- out -= rand_b;
- }
- return out >> 16;
-}
-*/
-
// get the next frame, when available. return 0 if underrun/stream reset.
static abuf_t *buffer_get_frame(void) {
int16_t buf_fill;
diff --git a/shairport.c b/shairport.c
index 93be47e2..20fce74b 100644
--- a/shairport.c
+++ b/shairport.c
@@ -641,6 +641,27 @@ int main(int argc, char **argv) {
free(basec);
// set defaults
+
+
+ // get thje endianness
+ union {
+ uint32_t u32;
+ uint8_t arr[4];
+ } xn;
+
+ xn.arr[0] = 0x44; /* Lowest-address byte */
+ xn.arr[1] = 0x33;
+ xn.arr[2] = 0x22;
+ xn.arr[3] = 0x11; /* Highest-address byte */
+
+ if (xn.u32==0x11223344)
+ endianness = __LITTLE_ENDIAN;
+ else if (xn.u32==0x33441122)
+ endianness = __PDP_ENDIAN;
+ else if (xn.u32==0x44332211)
+ endianness = __BIG_ENDIAN;
+ else die("Can not recognise the endianness of the processor.");
+
strcpy(configuration_file_path, "/etc/");
strcat(configuration_file_path, appName);
strcat(configuration_file_path, ".conf");
@@ -832,6 +853,18 @@ int main(int argc, char **argv) {
daemon_log(LOG_NOTICE, "startup");
+ switch (endianness) {
+ case __LITTLE_ENDIAN:
+ debug(2,"The processor is running little-endian.");
+ break;
+ case __BIG_ENDIAN:
+ debug(2,"The processor is running big-endian.");
+ break;
+ case __PDP_ENDIAN:
+ debug(2,"The processor is running pdp-endian.");
+ break;
+ }
+
/* 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
From faa583398dfe5c0aa55d3b4574dc43c9e15eb43e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rg=20Krause?=
Date: Sat, 12 Dec 2015 21:44:16 +0100
Subject: [PATCH 048/144] Fix data allignment issue
Different processor targets may have different word alignment restrictions.
Typically, a two or four byte integer should start on a four-byte address in
order to be fetched correctly over a bus. An access of a misaligned memory
element may cause a bus error.
Therefore, we need to adjust the contents of a message by copying it into a new
location, before interpreting it.
---
rtsp.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/rtsp.c b/rtsp.c
index 2657b4d0..d046249d 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -1085,13 +1085,16 @@ static void handle_set_parameter_metadata(rtsp_conn_info *conn, rtsp_message *re
unsigned int off = 8;
+ uint32_t itag, vl;
while (off < cl) {
// pick up the metadata tag as an unsigned longint
- uint32_t itag = ntohl(*(uint32_t *)(cp + off));
+ memcpy(&itag, (uint32_t *)(cp + off), sizeof(uint32_t)); /* can be misaligned, thus memcpy */
+ itag = ntohl(itag);
off += sizeof(uint32_t);
// pick up the length of the data
- uint32_t vl = ntohl(*(uint32_t *)(cp + off));
+ memcpy(&vl, (uint32_t *)(cp + off), sizeof(uint32_t)); /* can be misaligned, thus memcpy */
+ vl = ntohl(vl);
off += sizeof(uint32_t);
// pass the data over
From 6802f4ae2af1193d97d5804e62959aa0217644d1 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 14 Dec 2015 17:12:03 +0000
Subject: [PATCH 049/144] Add a little diagnostic to the output of the alac
decoder.
---
alac.c | 6 +++---
player.c | 12 +++++++++---
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/alac.c b/alac.c
index 7259d458..d5833c61 100644
--- a/alac.c
+++ b/alac.c
@@ -810,7 +810,7 @@ void alac_decode_frame(alac_file *alac,
}
else
{
- fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type);
+ fprintf(stderr, "FIXME: unhandled prediction type for compressed case: %i\n", prediction_type);
/* i think the only other prediction type (or perhaps this is just a
* boolean?) runs adaptive fir twice.. like:
* predictor_decompress_fir_adapt(predictor_error, tempout, ...)
@@ -1010,7 +1010,7 @@ void alac_decode_frame(alac_file *alac,
}
else
{ /* see mono case */
- fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type_a);
+ fprintf(stderr, "FIXME: unhandled prediction type on channel 1: %i\n", prediction_type_a);
}
/* channel 2 */
@@ -1035,7 +1035,7 @@ void alac_decode_frame(alac_file *alac,
}
else
{
- fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type_b);
+ fprintf(stderr, "FIXME: unhandled prediction type on channel 2: %i\n", prediction_type_b);
}
}
else
diff --git a/player.c b/player.c
index de2a980f..3a8e7542 100644
--- a/player.c
+++ b/player.c
@@ -242,7 +242,13 @@ static void alac_decode(short *dest, uint8_t *buf, int len) {
} else {
alac_decode_frame(decoder_info, buf, dest, &outsize);
}
-
+ if (outsize!=FRAME_BYTES(frame_size)) {
+ if(outsize> 1);
//*outptr++ = dithered_vol(((long)inptr[-1] + (long)inptr[1]) >> 1);
*outptr++ = dithered_vol(shortmean(inptr[-2], inptr[0]));
*outptr++ = dithered_vol(shortmean(inptr[-1], inptr[1]));
} else if (stuff == -1) {
- debug(3, "---------");
+ // debug(3, "---------");
inptr++;
inptr++;
}
From eac3620f69cc9bfcd9b31d7042878dc8e29e0ece Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 15 Dec 2015 08:10:43 +0000
Subject: [PATCH 050/144] Update README.md
---
README.md | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index aebf32a6..5cbcbd64 100644
--- a/README.md
+++ b/README.md
@@ -9,12 +9,14 @@ This branch -- "development" -- is unstable and may change quickly. To access th
More Information
----------
-Shairport Sync works by using timing information and timestamps present in data coming from the audio source (e.g. an iPhone) to "play" audio at exactly the right time. It does this by monitoring and controlling the *latency* — the time between a sound frame is supposed to be played, as specified by its `timestamp`, and the time when it is actually played by the audio output device, usually a Digital to Audio Converter (DAC). Timestamps are measured relative to the source computer's clocks, the `source clock`, but timing must be done relative to the clock of the computer running Shairport Sync, the `local clock`. The source and local clocks are synchronised, usually to within a fraction of a millisecond, using a variant of NTP synchronisation protocols.
+Shairport Sync works by using timing information and timestamps present in data coming from the audio source (e.g. an iPhone) to "play" audio at exactly the right time. It does this by monitoring and controlling the *latency* — the time between a sound frame is supposed to be played, as specified by its `timestamp`, and the time when it is actually played by the audio output device, usually a Digital to Audio Converter (DAC).
+
+The latency to be used is specified by the source when it negotiates with Shairport Sync. Most sources set a latency of 88,200 frames -- exactly two seconds. Recent versions of iTunes and forkedDaapd use a latency of 99,577 frames.
+
+Timestamps are measured relative to the source computer's clocks, the `source clock`, but timing must be done relative to the clock of the computer running Shairport Sync, the `local clock`. The source and local clocks are synchronised, usually to within a fraction of a millisecond, using a variant of NTP synchronisation protocols.
To maintain the exact latency required, if an output device is running slow relative to the source, Shairport Sync will delete frames of audio to allow the device to keep up. If the output device is running fast, Shairport Sync will insert frames to keep time. The number of frames inserted or deleted is so small as to be almost inaudible on normal audio material. Frames are inserted or deleted as necessary at pseudorandom intervals. Alternatively, with `libsoxr` support, Shairport Sync can resample the audio feed to ensure the output device can keep up. This is less obtrusive than insertion and deletion but requires a good deal of processing power — most embedded devices probably can't support it. The process of insertion/deletion or resampling is rather inelegantly called “stuffing”.
-The exact latency to be used is specified by the source when it negotiates with Shairport Sync. Most sources set a latency of 88,200 frames -- exactly two seconds. Recent versions of iTunes and forkedDaapd use a latency of 99,577 frames (pretty close to the 99,400 frames estimated from listening tests!).
-
Shairport Sync is a pretty substantial rewrite of the fantastic work done in Shairport 1.0 by James Laird and others — please see https://github.com/abrasive/shairport/blob/master/README.md#contributors-to-version-1x for a list of the contributors to Shairport 1.x and Shairport 0.x. From a "heritage" point of view, Shairport Sync is a fork of Shairport 1.0.
Shairport Sync is mainly designed for `alsa` and thus for Linux, although since `alsa` has been ported to FreeBSD, Shairport Sync runs in FreeBSD too. It must have direct access to the output device, which must be a real sound card capable of working with 44,100 samples per second interleaved PCM stereo (you'll get a message in the logfile if there's a problem).
From f74843d1e4cd9041a5d331fb2160ff157b30345e Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 15 Dec 2015 14:25:25 +0000
Subject: [PATCH 051/144] Update README.md
---
README.md | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 5cbcbd64..740c4053 100644
--- a/README.md
+++ b/README.md
@@ -98,6 +98,7 @@ The following libraries are required:
* ALSA
* libdaemon
* autoconf
+* automake
* libtool
* libpopt
* libconfig
@@ -109,11 +110,11 @@ Many Linux distributions have Avahi and OpenSSL already in place, so normally it
Assuming the usual build essentials and git, Debian, Ubuntu and Raspbian users can get the basics with:
-- `apt-get install autoconf libtool libdaemon-dev libasound2-dev libpopt-dev libconfig-dev`
+- `apt-get install autoconf automake libtool libdaemon-dev libasound2-dev libpopt-dev libconfig-dev`
- `apt-get install avahi-daemon libavahi-client-dev` if you want to use Avahi (recommended).
- `apt-get install libssl-dev` if you want to use OpenSSL and libcrypto, or use PolarSSL otherwise.
- `apt-get install libpolarssl-dev` if you want to use PolarSSL, or use OpenSSL/libcrypto otherwise.
-- `apt-get install libsoxr-dev` if you want support for libsoxr-based resampling. This library is not yet part of Raspbian; instructions for how to build it from source are available at [LIBSOXR.md](https://github.com/mikebrady/shairport-sync/blob/development/LIBSOXR.md).
+- `apt-get install libsoxr-dev` if you want support for libsoxr-based resampling. This library is not yet part of every distribution; instructions for how to build it from source for Raspian/Debian Wheezy are available at [LIBSOXR.md](https://github.com/mikebrady/shairport-sync/blob/development/LIBSOXR.md).
Download Shairport Sync:
From 186e4181e62206860f392c63b11b2872fb69072f Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 15 Dec 2015 18:10:34 +0000
Subject: [PATCH 052/144] Remove pesky assert on alac_decode ooutput size
---
player.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/player.c b/player.c
index 3a8e7542..5330f49d 100644
--- a/player.c
+++ b/player.c
@@ -249,7 +249,6 @@ static void alac_decode(short *dest, uint8_t *buf, int len) {
debug(1,"OUtput from alac_decode larger than expected -- truncated, but buffer overflow possible! Encrypted = %d.",encrypted);
}
}
- assert(outsize == FRAME_BYTES(frame_size));
}
static int init_decoder(int32_t fmtp[12]) {
From 9628b8b2b363a9acfe685633671139c258d1e752 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 16 Dec 2015 10:06:12 +0000
Subject: [PATCH 053/144] Update README.md
---
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 740c4053..2166ca0b 100644
--- a/README.md
+++ b/README.md
@@ -108,8 +108,9 @@ Optional:
Many Linux distributions have Avahi and OpenSSL already in place, so normally it probably makes sense to choose those options rather than tinysvcmdns or PolarSSL. Libsoxr is available in recent Linux distributions, but it requires lots of processor power — chances are an embedded processor won't be able to keep up.
-Assuming the usual build essentials and git, Debian, Ubuntu and Raspbian users can get the basics with:
+Debian, Ubuntu and Raspbian users can get the basics with:
+- `apt-get install build-essential git` – these may already be installed.
- `apt-get install autoconf automake libtool libdaemon-dev libasound2-dev libpopt-dev libconfig-dev`
- `apt-get install avahi-daemon libavahi-client-dev` if you want to use Avahi (recommended).
- `apt-get install libssl-dev` if you want to use OpenSSL and libcrypto, or use PolarSSL otherwise.
From 18108ebdfe727c72c1d4c0e4177d2b58c71a9ecc Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 16 Dec 2015 10:14:17 +0000
Subject: [PATCH 054/144] Update README.md
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 2166ca0b..de32c98c 100644
--- a/README.md
+++ b/README.md
@@ -127,6 +127,7 @@ Next, `cd` into the shairport-sync directory and execute the following commands:
$ git checkout development #select the development branch
$ autoreconf -i -f
```
+(Note that the `autoreconf...` step may take some time on less powerful machines.)
Choose the appropriate `--with-*` options:
From 1af53b769e22be16851a204ca5ed26d5f2ddbc12 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rg=20Krause?=
Date: Wed, 16 Dec 2015 11:17:16 +0100
Subject: [PATCH 055/144] rtsp: remove trailing whitespaces and fix indentation
---
rtsp.c | 33 ++++++++++++++++-----------------
1 file changed, 16 insertions(+), 17 deletions(-)
diff --git a/rtsp.c b/rtsp.c
index d046249d..650afb98 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -588,12 +588,12 @@ static void handle_record(rtsp_conn_info *conn, rtsp_message *req, rtsp_message
resp->respcode = 200;
// I think this is for telling the client what the absolute minimum latency actually is,
// and when the client specifies a latency, it should be added to this figure.
-
+
// Thus, AirPlay's latency figure of 77175, when added to 11025 gives you exactly 88200
// and iTunes' latency figure of 88553, when added to 11025 gives you 99578, pretty close to the 99400 we guessed.
-
+
msg_add_header(resp, "Audio-Latency", "11025");
-
+
char *p;
uint32_t rtptime = 0;
char *hdr = msg_get_header(req, "RTP-Info");
@@ -678,7 +678,7 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
// 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
@@ -721,7 +721,7 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
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
@@ -1050,7 +1050,7 @@ int send_metadata(uint32_t type, uint32_t code, char *data, uint32_t length, rts
// the rtsp_message is sent for 'core' messages, because it contains the data and must not be
// freed until the data has been read. So, it is passed to send_metadata to be retained,
// sent to the thread where metadata is processed and released (and probably freed).
-
+
// The rtsp_message is also sent for certain non-'core' messages.
// The reading of the parameters is a bit complex
@@ -1119,7 +1119,7 @@ static void handle_get_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
// if (!req->contentlength)
// debug(1, "received empty SET_PARAMETER request.");
-
+
// msg_print_debug_headers(req);
char *ct = msg_get_header(req, "Content-Type");
@@ -1132,7 +1132,7 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
// to link items of metadata, including pictures, that refer to the same entity.
// If they refer to the same item, they have the same rtptime.
// So we send the rtptime before and after both the metadata items and the picture item
- // get the rtptime
+ // get the rtptime
char *p = NULL;
char *hdr = msg_get_header(req, "RTP-Info");
@@ -1153,7 +1153,7 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
send_metadata('ssnc', 'mdst', p+1, strlen(p+1), req, 1); // metadata starting
else
send_metadata('ssnc', 'mdst', NULL, 0, NULL, 0); // metadata starting, if rtptime is not available
-
+
handle_set_parameter_metadata(conn, req, resp);
if (p)
@@ -1161,7 +1161,6 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
else
send_metadata('ssnc', 'mden', NULL, 0, NULL, 0); // metadata starting, if rtptime is not available
-
} else if (!strncmp(ct, "image", 5)) {
// debug(1, "received image in SET_PARAMETER request.");
// note: the image/type tag isn't reliable, so it's not being sent
@@ -1169,8 +1168,8 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
if (p==NULL)
debug(1,"Missing RTP-Time info for picture item");
if (p)
- send_metadata('ssnc', 'pcst', p+1, strlen(p+1), req, 1); // picture starting
- else
+ send_metadata('ssnc', 'pcst', p+1, strlen(p+1), req, 1); // picture starting
+ else
send_metadata('ssnc', 'pcst', NULL, 0, NULL, 0); // picture starting, if rtptime is not available
send_metadata('ssnc', 'PICT', req->content, req->contentlength, req, 1);
@@ -1182,12 +1181,12 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
} else
#endif
- if (!strncmp(ct, "text/parameters", 15)) {
+ if (!strncmp(ct, "text/parameters", 15)) {
debug(2, "received parameters in SET_PARAMETER request.");
handle_set_parameter_parameter(conn, req, resp); // this could be volume or progress
} else {
debug(1, "received unknown Content-Type \"%s\" in SET_PARAMETER request.", ct);
- }
+ }
} else {
debug(1, "missing Content-Type header in SET_PARAMETER request.");
}
@@ -1220,7 +1219,7 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
cp = next;
}
-
+
if ((paesiv==NULL) && (prsaaeskey==NULL)) {
//debug(1,"Unencrypted session requested?");
conn->stream.encrypted = 0;
@@ -1228,7 +1227,7 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
conn->stream.encrypted = 1;
//debug(1,"Encrypted session requested");
}
-
+
if (!pfmtp) {
warn("FMTP params missing from the following ANNOUNCE message:");
// print each line of the request content
@@ -1243,7 +1242,7 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
}
goto out;
}
-
+
if (conn->stream.encrypted) {
int len, keylen;
uint8_t *aesiv = base64_dec(paesiv, &len);
From e5e4b3bb8945ac6df018c185dd76b0ab1b7a6b99 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rg=20Krause?=
Date: Wed, 16 Dec 2015 11:26:29 +0100
Subject: [PATCH 056/144] rtsp: ignore received picture if include_covert_art
is set to no
---
rtsp.c | 36 +++++++++++++++++++++---------------
1 file changed, 21 insertions(+), 15 deletions(-)
diff --git a/rtsp.c b/rtsp.c
index 650afb98..ac173b31 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -1162,23 +1162,29 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
send_metadata('ssnc', 'mden', NULL, 0, NULL, 0); // metadata starting, if rtptime is not available
} else if (!strncmp(ct, "image", 5)) {
- // debug(1, "received image in SET_PARAMETER request.");
- // note: the image/type tag isn't reliable, so it's not being sent
- // -- best look at the first few bytes of the image
- if (p==NULL)
- debug(1,"Missing RTP-Time info for picture item");
- if (p)
- send_metadata('ssnc', 'pcst', p+1, strlen(p+1), req, 1); // picture starting
- else
- send_metadata('ssnc', 'pcst', NULL, 0, NULL, 0); // picture starting, if rtptime is not available
+ // Some server simply ignore the md field from the TXT record. If The
+ // config says 'please, do not include any cover art', we are polite and
+ // do not write them to the pipe.
+ if (config.get_coverart) {
+ // debug(1, "received image in SET_PARAMETER request.");
+ // note: the image/type tag isn't reliable, so it's not being sent
+ // -- best look at the first few bytes of the image
+ if (p==NULL)
+ debug(1,"Missing RTP-Time info for picture item");
+ if (p)
+ send_metadata('ssnc', 'pcst', p+1, strlen(p+1), req, 1); // picture starting
+ else
+ send_metadata('ssnc', 'pcst', NULL, 0, NULL, 0); // picture starting, if rtptime is not available
- send_metadata('ssnc', 'PICT', req->content, req->contentlength, req, 1);
-
- if (p)
- send_metadata('ssnc', 'pcen', p+1, strlen(p+1), req, 1); // picture ending
- else
- send_metadata('ssnc', 'pcen', NULL, 0, NULL, 0); // picture ending, if rtptime is not available
+ send_metadata('ssnc', 'PICT', req->content, req->contentlength, req, 1);
+ if (p)
+ send_metadata('ssnc', 'pcen', p+1, strlen(p+1), req, 1); // picture ending
+ else
+ send_metadata('ssnc', 'pcen', NULL, 0, NULL, 0); // picture ending, if rtptime is not available
+ } else {
+ debug(1, "Ignore received picture item (include_cover_art = no).");
+ }
} else
#endif
if (!strncmp(ct, "text/parameters", 15)) {
From 9725830d9aed8e617e696f95345f30c4cf8c7d8d Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Fri, 18 Dec 2015 13:39:51 +0000
Subject: [PATCH 057/144] Use the correct tag name for desired alsa buffer
length -- audio_backend_buffer_desired_length
---
audio_alsa.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/audio_alsa.c b/audio_alsa.c
index 76d00742..465caec4 100644
--- a/audio_alsa.c
+++ b/audio_alsa.c
@@ -94,7 +94,8 @@ static void help(void) {
}
static int init(int argc, char **argv) {
- const char *str;
+ // debug(1,"audio_alsa init called.");
+ const char *str;
int value;
int hardware_mixer = 0;
@@ -108,9 +109,9 @@ static int init(int argc, char **argv) {
if (config.cfg != NULL) {
/* Get the desired buffer size setting. */
- if (config_lookup_int(config.cfg, "alsa.audio_backend_buffer_desired_length_software", &value)) {
+ if (config_lookup_int(config.cfg, "alsa.audio_backend_buffer_desired_length", &value)) {
if ((value < 0) || (value > 66150))
- die("Invalid alsa audio backend buffer desired length (software) \"%d\". It should be between 0 and "
+ die("Invalid alsa audio backend buffer desired length \"%d\". It should be between 0 and "
"66150, default is 6615",
value);
else {
From 49788bd6e62f8ea2c77ca0df7e972745ccd3be6e Mon Sep 17 00:00:00 2001
From: Nick Steel
Date: Sun, 20 Dec 2015 19:48:31 +0000
Subject: [PATCH 058/144] Substitute $PREFIX in the systemd unit file (Fixes
#139).
---
configure.ac | 2 +-
scripts/{shairport-sync.service => shairport-sync.service.in} | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
rename scripts/{shairport-sync.service => shairport-sync.service.in} (84%)
diff --git a/configure.ac b/configure.ac
index 55e236d3..dcaabbb4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -239,5 +239,5 @@ AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_CHECK_FUNCS([atexit clock_gettime gethostname inet_ntoa memchr memmove memset mkfifo pow select socket stpcpy strcasecmp strchr strdup strerror strstr strtol strtoul])
-AC_CONFIG_FILES([Makefile man/Makefile])
+AC_CONFIG_FILES([Makefile man/Makefile scripts/shairport-sync.service])
AC_OUTPUT
diff --git a/scripts/shairport-sync.service b/scripts/shairport-sync.service.in
similarity index 84%
rename from scripts/shairport-sync.service
rename to scripts/shairport-sync.service.in
index 54bfcd18..3cc662e7 100644
--- a/scripts/shairport-sync.service
+++ b/scripts/shairport-sync.service.in
@@ -5,7 +5,7 @@ Requires=avahi-daemon.service
After=avahi-daemon.service
[Service]
-ExecStart=/usr/local/bin/shairport-sync
+ExecStart=@prefix@/bin/shairport-sync
User=shairport-sync
Group=shairport-sync
From f79ffc61c4d3008318483855201b895d7e2ba9b2 Mon Sep 17 00:00:00 2001
From: Nick Steel
Date: Mon, 21 Dec 2015 09:15:03 +0000
Subject: [PATCH 059/144] Git should ignore new generated systemd file
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index 4aa1c87b..261468a6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,3 +19,4 @@ stamp-h1
.deps
man/Makefile
man/Makefile.in
+scripts/shairport-sync.service
From 25356fe1d7bcacec7c6826211e9965552a56e40a Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 21 Dec 2015 11:03:10 +0000
Subject: [PATCH 060/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index a3d0b3eb..3aa000bf 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,3 +1,8 @@
+Version 2.7.4 -- Development Version
+----
+**Enhancements**
+* Rather than hardwire the path `/usr/local/bin` as the path to the shairport-sync executable, the value of `$PREFIX` is now used.
+
Version 2.7.3 -- Development Version
----
**Bug Fix**
From 0ad11fb12295cc9d4c787110905ae2cdbf809d05 Mon Sep 17 00:00:00 2001
From: dantheperson
Date: Tue, 22 Dec 2015 00:40:24 +1300
Subject: [PATCH 061/144] Correct method to determine systemd unit path
As recomended by debain maintainers and
http://www.freedesktop.org/software/systemd/man/daemon.html#Installing%20Systemd%20Service%20Files
---
Makefile.am | 4 ++--
configure.ac | 16 ++++++++++++++++
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index fcf68059..f576001d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -61,6 +61,6 @@ if INSTALL_SYSTEMV
[ -f $(DESTDIR)/etc/init.d/shairport-sync ] || cp scripts/shairport-sync $(DESTDIR)/etc/init.d/
endif
if INSTALL_SYSTEMD
- [ -e $(DESTDIR)/usr/lib/systemd/system ] || mkdir -p $(DESTDIR)/usr/lib/systemd/system
- cp scripts/shairport-sync.service $(DESTDIR)/usr/lib/systemd/system
+ [ -e $(DESTDIR)$(systemdsystemunitdir) ] || mkdir -p $(DESTDIR)$(systemdsystemunitdir)
+ cp scripts/shairport-sync.service $(DESTDIR)$(systemdsystemunitdir)
endif
diff --git a/configure.ac b/configure.ac
index dcaabbb4..cf3cb22c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -213,6 +213,22 @@ AC_ARG_WITH(dns_sd, [ --with-dns_sd = choose dns_sd mDNS support], [
AC_SEARCH_LIBS([DNSServiceRefDeallocate], [dns_sd], , AC_MSG_ERROR(dns_sd support requires the dns_sd library!))], )
AM_CONDITIONAL([USE_DNS_SD], [test "x$HAS_DNS_SD" = "x1"])
+# Find systemd unit dir
+AC_ARG_WITH([systemdsystemunitdir],
+ [AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],,
+ [with_systemdsystemunitdir=auto])
+AS_IF([test "x$with_systemdsystemunitdir" = "xyes" -o "x$with_systemdsystemunitdir" = "xauto"], [
+ def_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)
+
+ AS_IF([test "x$def_systemdsystemunitdir" = "x"],
+ [AS_IF([test "x$with_systemdsystemunitdir" = "xyes"],
+ [AC_MSG_ERROR([systemd support requested but pkg-config unable to query systemd package])])
+ with_systemdsystemunitdir=no],
+ [with_systemdsystemunitdir="$def_systemdsystemunitdir"])])
+AS_IF([test "x$with_systemdsystemunitdir" != "xno"],
+ [AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])])
+AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemdsystemunitdir" != "xno"])
+
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([getopt_long.h])
From d5881f636e750fa50000cb1605100f38547e273b Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 21 Dec 2015 13:12:31 +0000
Subject: [PATCH 062/144] Add some extra diagnostics to setting the desired
buffer length in ALSA
---
audio_alsa.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/audio_alsa.c b/audio_alsa.c
index 465caec4..57c2981b 100644
--- a/audio_alsa.c
+++ b/audio_alsa.c
@@ -267,8 +267,8 @@ static void deinit(void) {
}
int open_alsa_device(void) {
- const snd_pcm_uframes_t buffer_headroom = 352*3; // the hardware buffer must be this much bigger than the desired buffer length
- int ret, dir = 0;
+ const snd_pcm_uframes_t minimal_buffer_headroom = 352*2; // we accept this much headroom in the hardware buffer, but we'll accept less
+ const snd_pcm_uframes_t requested_buffer_headroom = minimal_buffer_headroom+2048; // we ask for this much headroom in the hardware buffer, but we'll accept less
unsigned int my_sample_rate = desired_sample_rate;
//snd_pcm_uframes_t frames = 441 * 10;
snd_pcm_uframes_t buffer_size, actual_buffer_length;
@@ -321,14 +321,16 @@ int open_alsa_device(void) {
die("audio_alsa: Unable to get hw buffer length for device \"%s\": %s.", alsa_out_dev, snd_strerror(ret));
}
- if (actual_buffer_length < config.audio_backend_buffer_desired_length+buffer_headroom) {
+ if (actual_buffer_length < config.audio_backend_buffer_desired_length+minimal_buffer_headroom) {
// the dac buffer is too small, so let's try to set it
- buffer_size = config.audio_backend_buffer_desired_length+buffer_headroom;
+ buffer_size = config.audio_backend_buffer_desired_length+requested_buffer_headroom;
ret = snd_pcm_hw_params_set_buffer_size_near(alsa_handle, alsa_params, &buffer_size);
if (ret < 0)
- die("audio_alsa: Unable to set hw buffer size to %lu for device \"%s\": %s.", config.audio_backend_buffer_desired_length+buffer_headroom, alsa_out_dev, snd_strerror(ret));
- if (config.audio_backend_buffer_desired_length+buffer_headroom > buffer_size)
- die("audio_alsa: Can't set hw buffer size to %lu for device \"%s\": %s.", config.audio_backend_buffer_desired_length+buffer_headroom, alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Unable to set hw buffer size to %lu for device \"%s\": %s.", config.audio_backend_buffer_desired_length+requested_buffer_headroom, alsa_out_dev, snd_strerror(ret));
+ if (config.audio_backend_buffer_desired_length+minimal_buffer_headroom > buffer_size) {
+ die("audio_alsa: Can't set hw buffer size to %lu or more for device \"%s\". Requested size: %lu, granted size: %lu.", config.audio_backend_buffer_desired_length+minimal_buffer_headroom,
+ alsa_out_dev,config.audio_backend_buffer_desired_length+requested_buffer_headroom,buffer_size);
+ }
}
return (0);
From 2279cc4697ed9a288b8599ede11b16f147e32b85 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 21 Dec 2015 13:27:44 +0000
Subject: [PATCH 063/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 3aa000bf..7add08ed 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,7 +1,14 @@
Version 2.7.4 -- Development Version
----
**Enhancements**
-* Rather than hardwire the path `/usr/local/bin` as the path to the shairport-sync executable, the value of `$PREFIX` is now used.
+* Rather than hardwire the path `/usr/local/bin` as the path to the shairport-sync executable, the value of `$PREFIX` is now used during configuration. Thanks to [Nick Steel](https://github.com/kingosticks).
+* Add some extra diagnostic messages if the hardware buffer in the DAC is smaller than desired.
+* If metadata has been enabled, but if picture sending has not been requested and the source sends pictures anyway, omit them from the metadata feed. Thanks to [Jörg Krause](https://github.com/joerg-krause).
+
+**Bug Fixes**
+* Fixed a data alignment issue in the handling of metadata on some processors. Thanks to [Jörg Krause](https://github.com/joerg-krause).
+* Removed an `assert` which would terminate the program if a malformed packet of data was received.
+* Look for the correct tag name for desired alsa buffer length: `audio_backend_buffer_desired_length` rather than `audio_backend_buffer_desired_length_software`.
Version 2.7.3 -- Development Version
----
From 53b289618d4347c4378d1d74710a353ed6f7ba21 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 21 Dec 2015 13:44:59 +0000
Subject: [PATCH 064/144] Fix unintended deletion of two definitions
---
audio_alsa.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/audio_alsa.c b/audio_alsa.c
index 57c2981b..64656ef3 100644
--- a/audio_alsa.c
+++ b/audio_alsa.c
@@ -269,9 +269,11 @@ static void deinit(void) {
int open_alsa_device(void) {
const snd_pcm_uframes_t minimal_buffer_headroom = 352*2; // we accept this much headroom in the hardware buffer, but we'll accept less
const snd_pcm_uframes_t requested_buffer_headroom = minimal_buffer_headroom+2048; // we ask for this much headroom in the hardware buffer, but we'll accept less
+ int ret, dir = 0;
unsigned int my_sample_rate = desired_sample_rate;
//snd_pcm_uframes_t frames = 441 * 10;
snd_pcm_uframes_t buffer_size, actual_buffer_length;
+
ret = snd_pcm_open(&alsa_handle, alsa_out_dev, SND_PCM_STREAM_PLAYBACK, 0);
if (ret < 0)
return (ret);
From 19362e9720ca2abc7364f676aad2ba866a6c212a Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 21 Dec 2015 13:55:00 +0000
Subject: [PATCH 065/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 7add08ed..bf931460 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,6 +1,8 @@
Version 2.7.4 -- Development Version
----
**Enhancements**
+* Use the correct method for finding the `systemd` unit path, as recomended by debain maintainers and
+http://www.freedesktop.org/software/systemd/man/daemon.html#Installing%20Systemd%20Service%20Files. Thanks to [dantheperson](https://github.com/dantheperson).
* Rather than hardwire the path `/usr/local/bin` as the path to the shairport-sync executable, the value of `$PREFIX` is now used during configuration. Thanks to [Nick Steel](https://github.com/kingosticks).
* Add some extra diagnostic messages if the hardware buffer in the DAC is smaller than desired.
* If metadata has been enabled, but if picture sending has not been requested and the source sends pictures anyway, omit them from the metadata feed. Thanks to [Jörg Krause](https://github.com/joerg-krause).
From fa21a9cbacde4b2e601d7ecb478f4da400cac10d Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 21 Dec 2015 13:56:22 +0000
Subject: [PATCH 066/144] Update configure.ac
---
configure.ac | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index cf3cb22c..ba31af0d 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], [2.7.3], [mikebrady@eircom.net])
+AC_INIT([shairport-sync], [2.7.4], [mikebrady@eircom.net])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([shairport.c])
AC_CONFIG_HEADERS([config.h])
From cd035602144f46760c04bd85328209165e0544d1 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 22 Dec 2015 14:34:36 +0000
Subject: [PATCH 067/144] Update README.md
---
README.md | 32 ++++++++++++++++++--------------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/README.md b/README.md
index de32c98c..c11f356c 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ What else?
* Hardware Mute — Shairport Sync will mute properly if the hardware supports it.
* Fast Response — With hardware volume control, response is instantaneous; otherwise the response time is 0.15 seconds.
* Non-Interruptible — Shairport Sync sends back a "busy" signal if it's already playing audio from another source, so other sources can't disrupt an existing Shairport Sync session. (If a source disappears without warning, the session automatically terminates after two minutes and the device becomes available again.)
-* Metadata — Shairport Sync can be configured to deliver metadata supplied by the source, such as Album Name, Artist Name, Cover Art, etc. through a pipe to a recipient application program — see https://github.com/mikebrady/shairport-sync-metadata-reader for a sample recipient. Sources that supply metadata include iTunes among others but the Music app in iOS 9 only supplies volume control metadata.
+* Metadata — Shairport Sync can be configured to deliver metadata supplied by the source, such as Album Name, Artist Name, Cover Art, etc. through a pipe to a recipient application program — see https://github.com/mikebrady/shairport-sync-metadata-reader for a sample recipient. Sources that supply metadata include iTunes and the Music app in iOS.
* Raw Audio — Shairport Sync can deliver raw PCM audio to standard output or to a pipe. This output is delivered synchronously with the source after the appropriate latency and is not interpolated or "stuffed" on its way through Shairport Sync.
* Autotools and Libtool Support — One important difference between Shairport Sync and other versions of Shairport is that the Shairport Sync build process uses GNU autotools and libtool to examine and configure the build environment — very important for cross compilation. Previous versions of Shairport looked at the current system to determine which packages were available, instead of looking at the target system for what packages were available.
@@ -37,7 +37,7 @@ Status
------
Shairport Sync works on a wide variety of Linux devices. It works on standard Ubuntu laptops, on the Raspberry Pi with Raspbian Wheezy and Jessie, Arch Linux and OpenWrt, and it runs on a Linksys NSLU2 and a TP-Link 710N using OpenWrt. It works with built-in audio and with a variety of USB-connected audio amplifiers and DACs, including a cheapo USB "3D Sound" dongle, a first generation iMic and a Topping TP30 amplifier with a USB DAC input. It will not work properly – if at all – with a PulseAudio (pseudo-)output device. Using a port of the `alsa` system, Shairport Sync runs rather well on FreeBSD.
-Shairport Sync runs well on the Raspberry Pi. It can drive the built-in sound card, though the audio out of the card is of poor quality (see the note below on configuring the Raspberry Pi to make best use of it). USB-connected sound cards work well on recent versions of Raspbian; however older versions of Raspbian appear to suffer from a problem — see http://www.raspberrypi.org/forums/viewtopic.php?t=23544, so it is wise to update. Shairport Sync works well with the IQAudIO Pi-DAC — see http://www.iqaudio.com.
+Shairport Sync runs well on the Raspberry Pi. It can drive the built-in sound card, though the audio out of the card is of poor quality (see the note below on configuring the Raspberry Pi to make best use of it). USB-connected sound cards work well, though [very] old versions of Raspbian appear to suffer from a problem — see http://www.raspberrypi.org/forums/viewtopic.php?t=23544, so it is wise to update. Shairport Sync works well with the IQAudIO Pi-DAC — see http://www.iqaudio.com.
At the time of writing, OpenWrt trunk does not support USB audio well on the Raspberry Pi.
@@ -146,11 +146,11 @@ Choose the appropriate `--with-*` options:
**System V and `systemd`**
-At the time of writing, there are two general systems for automatically starting programs automatically at startup: "System V" or `systemd`. To see if the `systemd` process is running on your system, enter the following command:
+At the time of writing, there are two widely-used systems for automatically starting programs automatically at startup: "System V" and `systemd`. (There are others, but they are not considered here.) To see if the `systemd` process is running on your system, enter the following command:
`ps aux | grep systemd | grep -v grep`
-On a system using `systemd` (this is a Raspberry Pi running Raspbian Jessie) you'll get many lines containing `systemd`, for example:
+On a system using `systemd` (this is from a Raspberry Pi running Raspbian Jessie) you'll get many lines containing `systemd`, for example:
```
pi@raspberrypi ~ $ ps aux | grep systemd | grep -v grep
root 90 0.1 0.6 8088 2764 ? Ss 08:00 0:01 /lib/systemd/systemd-journald
@@ -160,14 +160,14 @@ message+ 528 0.0 0.7 5568 3172 ? Ss 08:00 0:01 /usr/bin/dbus-d
pi 983 0.0 0.7 4912 3256 ? Ss 08:00 0:00 /lib/systemd/systemd --user
pi@raspberrypi ~ $
```
-whereas on a system without `systemd` -- presumably using System V -- (this is a Raspberry Pi running Raspbian Wheezy) , you'll get nothing:
+whereas on a system without `systemd` -- presumably using System V -- (this is a from a Raspberry Pi running Raspbian Wheezy) , you'll get nothing:
```
pi@raspberrypi ~ $ ps aux | grep systemd | grep -v grep
pi@raspberrypi ~ $
```
Choose `--with-systemd` or `--with-systemv` on the basis of the outcome.
-Here is an example, suitable for installations such as Ubuntu and Raspbian:
+Here is an example, suitable for installations such as Ubuntu and Raspbian Wheezy:
`$ ./configure --with-alsa --with-avahi --with-ssl=openssl --with-metadata --with-soxr --with-systemv`
@@ -226,9 +226,7 @@ Starting and stopping automatically is taken care of differently in different ve
To get the best from Shairport Sync, you’ll need to (1) give Shairport Sync a service name by which it will be seen in iTunes etc., (2) specify the output device to use and (3) specify the name of the mixer volume control to use to control the output level. To get values for (2) and (3) you might need to explore the ALSA output devices with a program like `alsamixer` or similar.
-Shairport Sync reads settings from a configuration file at `/etc/shairport-sync.conf`. While it can also take configuration settings from command line options, it is recommended that you use the configuration file method. When you run `$sudo make install`, a default configuration is installed at `/etc/shairport-sync.conf` (it won't replace an existing one) which should work in almost any system with a sound card.
-
-A sample configuration file is installed (or updated) at `/etc/shairport-sync.conf.sample`. This contains all the setting groups and all the settings available, but they all are commented out (comments begin with `//`) so that default values are used. The file contains explanations of the settings, useful hints and suggestions.
+Shairport Sync reads settings from a configuration file at `/etc/shairport-sync.conf`. When you run `$sudo make install`, a sample configuration file is installed (or updated) at `/etc/shairport-sync.conf.sample`. This contains all the setting groups and all the settings available, but they all are commented out (comments begin with `//`) so that default values are used. The file contains explanations of the settings, useful hints and suggestions. In addition, if the file doesn't already exist, a default configuration is installed at `/etc/shairport-sync.conf`, which should work in almost any system with a sound card.
Settings in the configuration file are grouped. For instance, there is a `general` group within which you can use the `name` tag to set the service name. Suppose you wanted to set the name of the service to `Front Room`, give the service the password `secret` and used `libsoxr` interpolation, then you should do the following:
@@ -241,6 +239,8 @@ general =
// ... other general settings
};
```
+(Remember, anything preceded by `//` is a comment and will have no effect on the setting of Shairport Sync.)
+
The `alsa` group is used to specify properties of the output device. The most obvious setting is the name of the output device which you can set using the `output_device` tag.
The following `alsa` group settings are very important for maximum performance. If your audio device has a mixer that can be use to control the volume, then Shairport Sync can use it to give instant response to volume and mute commands and it can offload some work from the processor.
@@ -261,14 +261,18 @@ Shairport Sync can run programs just before it starts to play an audio stream an
Please note that the full path to the programs must be specified, and script files will not be executed unless they are marked as executable and have the standard `#!/bin/...` first line. (This behaviour may be different from other Shairports.)
+Note: Shairport Sync can take configuration settings from command line options. This is mainly for backward compatability, but sometimes still useful. For normal use, it is strongly recommended that you use the configuration file method.
+
**Raspberry Pi**
-The Raspberry Pi has a built-in audio DAC that is connected to the device's headphone jack. This provides a low-quality output that is nevertheless useful for testing purposes and may be adequate for [very] casual listening. It is not HiFi -- it is quite noisy and can't play anything above about 15kHz. A further problem is that it declares itself to have a very large mixer volume control range -- all the way from -102.38dB up to +4dB, a range of 106.38 dB. In reality, only the top 35dB of it is in any way usable. To help get the most from the DAC, consider using the `volume_range_db` setting in the `general` stanza to instruct Shairport Sync to use the top of the DAC mixer's declared range. For example, if you set the `volume_range_db` figure to 35, the top 35 dB of the range will the used. With this setting on the Raspberry Pi, maximum volume will be +4dB and minimum volume will be -31dB, below which muting will occur.
+The Raspberry Pi has a built-in audio DAC that is connected to the device's headphone jack. This provides a low-quality output that is nevertheless useful for testing purposes and may be adequate for [very] casual listening. It is not HiFi -- it is quite noisy and can't play anything above about 15kHz. A further problem is that it declares itself to have a very large mixer volume control range -- all the way from -102.38dB up to +4dB, a range of 106.38 dB. In reality, only the top 30dB of it is in any way usable. To help get the most from the DAC, consider using the `volume_range_db` setting in the `general` stanza to instruct Shairport Sync to use the top of the DAC mixer's declared range. For example, if you set the `volume_range_db` figure to 30, the top 30 dB of the range will the used. With this setting on the Raspberry Pi, maximum volume will be +4dB and minimum volume will be -26dB, below which muting will occur.
From a user's point of view, the effect of using this setting is to move the minimum usable volume all the way down to the bottom of the user's volume control, rather than have the minimum usable volume concentrated very close to the maximum volume.
+Another setting to consider is the `general` `drift` setting: you should set it to a larger number, such as 352, to reduce the amount of overcorrection that seems to occur when using the Raspberry Pi's built-in DAC.
+
*Command Line Arguments*
-You can use command line arguments to provide settings to Shairport Sync as before. For full information, please read the Shairport Sync `man` page, also available at http://htmlpreview.github.io/?https://github.com/mikebrady/shairport-sync/blob/development/man/shairport-sync.html.
+As previously mentioned, you can use command line arguments to provide settings to Shairport Sync as before, though newer settings will only be available via the configuration file. For full information, please read the Shairport Sync `man` page, also available at http://htmlpreview.github.io/?https://github.com/mikebrady/shairport-sync/blob/development/man/shairport-sync.html.
Apart from the following options, all command line options can be replaced by settings in the configuration file. Here is a brief description of command line options that are not replicated by settings in the settings file.
@@ -376,9 +380,9 @@ Latency
-------
Latency is the exact time from a sound signal's original timestamp until that signal actually "appears" on the output of the audio output device, usually a Digital to Audio Converter (DAC), irrespective of any internal delays, processing times, etc. in the computer.
-Shairport Sync uses latencies supplied by the source, typically either 88,200 or 99,577 frames. You shouldn't need to change them. (The `latencies` stanza in the configuration file and the various latency command-line options are deprecated.)
+Shairport Sync uses latencies supplied by the source, typically either 88,200 or 99,577 frames. You shouldn't need to change them. (The `latencies` stanza in the configuration file and the various latency command-line options are now obselete and are deprecated.)
-Problems can arise when you are trying to synchronise with speaker systems — typically surround-sound home theatre systems — that have their own inherent delays. You can compensate for an inherent delay using the appropriate backend (typically `alsa`) `audio_backend_latency_offset`. Set this offset (in frames) to compensate for a fixed delay in the audio back end, for example, if the output device delays by 100 ms, set this to -4410.
+Problems can arise when you are trying to synchronise with speaker systems — typically surround-sound home theatre systems — that have their own inherent delays. You can compensate for an inherent delay using the appropriate backend (typically `alsa`) `audio_backend_latency_offset`. Set this offset (in frames) to compensate for a fixed delay in the audio back end; for example, if the output device delays by 100 ms, set this to -4410.
Resynchronisation
-------------
@@ -388,7 +392,7 @@ If synchronisation is lost — say due to a busy source or a congested network
Tolerance
---------
-Playback synchronisation is allowed to wander, or to "drift") a small amount before attempting to correct it. The default is 88 frames, i.e. 2 ms. The smaller the tolerance, the more likely it is that overcorrection will occur. Overcorrection is when more corrections (insertions and deletions) are made than are strictly necessary to keep the stream in sync. Use the statistics setting to monitor correction levels. Corrections should not greatly exceed net corrections.
+Playback synchronisation is allowed to wander — to "drift" — a small amount before attempting to correct it. The default is 88 frames, i.e. 2 ms. The smaller the tolerance, the more likely it is that overcorrection will occur. Overcorrection is when more corrections (insertions and deletions) are made than are strictly necessary to keep the stream in sync. Use the `statistics` setting to monitor correction levels. Corrections should not greatly exceed net corrections.
* You can vary the tolerance with the `general` `drift` setting.
Some Statistics
From 935160180aecb4c95caf7df0649b6d258c811488 Mon Sep 17 00:00:00 2001
From: dan carter
Date: Wed, 23 Dec 2015 12:55:25 +1300
Subject: [PATCH 068/144] User $PREFIX in the init file
---
.gitignore | 1 +
configure.ac | 1 +
scripts/{shairport-sync => shairport-sync.in} | 2 +-
3 files changed, 3 insertions(+), 1 deletion(-)
rename scripts/{shairport-sync => shairport-sync.in} (99%)
diff --git a/.gitignore b/.gitignore
index 261468a6..cdbef556 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,4 @@ stamp-h1
man/Makefile
man/Makefile.in
scripts/shairport-sync.service
+scripts/shairport-sync
\ No newline at end of file
diff --git a/configure.ac b/configure.ac
index ba31af0d..75e4db9e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -256,4 +256,5 @@ AC_FUNC_REALLOC
AC_CHECK_FUNCS([atexit clock_gettime gethostname inet_ntoa memchr memmove memset mkfifo pow select socket stpcpy strcasecmp strchr strdup strerror strstr strtol strtoul])
AC_CONFIG_FILES([Makefile man/Makefile scripts/shairport-sync.service])
+AC_CONFIG_FILES([scripts/shairport-sync],[chmod +x scripts/shairport-sync])
AC_OUTPUT
diff --git a/scripts/shairport-sync b/scripts/shairport-sync.in
similarity index 99%
rename from scripts/shairport-sync
rename to scripts/shairport-sync.in
index d1175504..7e0dd767 100755
--- a/scripts/shairport-sync
+++ b/scripts/shairport-sync.in
@@ -17,7 +17,7 @@
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="AirPlay Synchronous Audio Service"
NAME=shairport-sync
-DAEMON=/usr/local/bin/$NAME
+DAEMON=@prefix@/bin/$NAME
# We don't use the DAEMON_ARGS variable here because some of the identifiers may have spaces in them, and so are
# impossible to pass as arguments.
From b56409b5938b58757d678df38e60a67cb1fe9dda Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 23 Dec 2015 10:32:09 +0000
Subject: [PATCH 069/144] Update README.md
---
README.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/README.md b/README.md
index c11f356c..dd9f4a77 100644
--- a/README.md
+++ b/README.md
@@ -58,6 +58,9 @@ If you wish to install Shairport Sync on OpenWrt, Arch or Fedora platforms, plea
The following procedures will install the shairport-sync application into your system. Before continuing, you should check to see if shairport-sync is already installed -- you can use `which shairport-sync` to find where it is located, if installed. If it is installed you should delete it -- you may need to have superuser privileges. After deleting, check again in case further copies are installed elsewhere.
(If the existing installation of shairport-sync is where the new copy will be installed into, it will be overwritten; sometimes, however, the installation is to another location, so it is safer, initially, to delete previous versions manually.)
+**Ubuntu**
+Personal Package Archives for Shairport Sync master and development branches are available at https://launchpad.net/~dantheperson.
+
**OpenWrt:**
There is a Shairport Sync package in OpenWrt `trunk`. Also, there's an OpenWrt package at https://github.com/mikebrady/shairport-sync-for-openwrt, including one that builds back to `Attitude Adjustment`.
From 85baa361bf7b8403a20fdeea3c56927c4581c33a Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 23 Dec 2015 10:35:33 +0000
Subject: [PATCH 070/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index bf931460..f2c4792e 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -3,7 +3,7 @@ Version 2.7.4 -- Development Version
**Enhancements**
* Use the correct method for finding the `systemd` unit path, as recomended by debain maintainers and
http://www.freedesktop.org/software/systemd/man/daemon.html#Installing%20Systemd%20Service%20Files. Thanks to [dantheperson](https://github.com/dantheperson).
-* Rather than hardwire the path `/usr/local/bin` as the path to the shairport-sync executable, the value of `$PREFIX` is now used during configuration. Thanks to [Nick Steel](https://github.com/kingosticks).
+* Rather than hardwire the path `/usr/local/bin` as the path to the shairport-sync executable, the value of `$PREFIX` is now used during configuration. Thanks to [Nick Steel](https://github.com/kingosticks) and [dantheperson](https://github.com/dantheperson).
* Add some extra diagnostic messages if the hardware buffer in the DAC is smaller than desired.
* If metadata has been enabled, but if picture sending has not been requested and the source sends pictures anyway, omit them from the metadata feed. Thanks to [Jörg Krause](https://github.com/joerg-krause).
From 6a08977404fc6fb5d89c85b4b360281c873bcf30 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 23 Dec 2015 10:37:38 +0000
Subject: [PATCH 071/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index f2c4792e..aac0a1f6 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,9 +1,14 @@
+Version 2.7.5 -- Development Version
+----
+**Enhancements**
+* Broaden the use of the value `$PREFIX` instead of the path `/usr/local/bin` during configuration. Thanks to [dantheperson](https://github.com/dantheperson).
+
Version 2.7.4 -- Development Version
----
**Enhancements**
* Use the correct method for finding the `systemd` unit path, as recomended by debain maintainers and
http://www.freedesktop.org/software/systemd/man/daemon.html#Installing%20Systemd%20Service%20Files. Thanks to [dantheperson](https://github.com/dantheperson).
-* Rather than hardwire the path `/usr/local/bin` as the path to the shairport-sync executable, the value of `$PREFIX` is now used during configuration. Thanks to [Nick Steel](https://github.com/kingosticks) and [dantheperson](https://github.com/dantheperson).
+* Rather than hardwire the path `/usr/local/bin` as the path to the shairport-sync executable, the value of `$PREFIX` is now used during configuration. Thanks to [Nick Steel](https://github.com/kingosticks).
* Add some extra diagnostic messages if the hardware buffer in the DAC is smaller than desired.
* If metadata has been enabled, but if picture sending has not been requested and the source sends pictures anyway, omit them from the metadata feed. Thanks to [Jörg Krause](https://github.com/joerg-krause).
From d4fbdacccd1a8446330b683aff11f7dcb7e71ded Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 23 Dec 2015 10:40:30 +0000
Subject: [PATCH 072/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index aac0a1f6..edc34638 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,5 +1,8 @@
Version 2.7.5 -- Development Version
----
+**New Features**
+* Ubuntu PPA files now available at https://launchpad.net/~dantheperson.
+
**Enhancements**
* Broaden the use of the value `$PREFIX` instead of the path `/usr/local/bin` during configuration. Thanks to [dantheperson](https://github.com/dantheperson).
From d0d7b8b228e5d12f2b5cd19d2dabf3728c3993ca Mon Sep 17 00:00:00 2001
From: Chris Boot
Date: Sat, 26 Dec 2015 14:51:25 +0000
Subject: [PATCH 073/144] manpage: correct compatable => compatible typos
Update the source XML manpage, then re-generate the manpage and HTML
version using xmltoman and xmlmantohtml.
---
man/shairport-sync.7 | 17 +++++++++++++++--
man/shairport-sync.7.xml | 4 ++--
man/shairport-sync.html | 35 +++++++++++++++++++++++++++++++----
3 files changed, 48 insertions(+), 8 deletions(-)
diff --git a/man/shairport-sync.7 b/man/shairport-sync.7
index 7534e5df..b261ec60 100644
--- a/man/shairport-sync.7
+++ b/man/shairport-sync.7
@@ -53,7 +53,7 @@ Most settings have sensible default values, so -- as in the example above -- use
A sample configuration file with all possible settings, but with all of them commented out, is installed at \fI/etc/shairport-sync.conf.sample\f1.
-To retain backwards compatability with previous versions of shairport-sync you can use still use command line options, but any new features, etc. will be available only via configuration file settings.
+To retain backwards compatibility with previous versions of shairport-sync you can use still use command line options, but any new features, etc. will be available only via configuration file settings.
The configuration file is processed using the \fIlibconfig\f1 library -- see \fBhttp://www.hyperrealm.com/libconfig/libconfig_manual.html\f1.
.TP
@@ -153,6 +153,19 @@ Packets of audio frames are written to stdout synchronously -- that is, they are
\fBaudio_backend_buffer_desired_length=\f1\fIbuffer_length_in_frames\f1\fB;\f1
Use this setting, in frames, to set the size of the output buffer. It works by determining how soon the second and subsequent packets of audio frames are sent to stdout. For example, if you send the first packet of audio exactly when it is due and, using a \fIaudio_backend_buffer_desired_length\f1 setting of 44100, send subsequent packets of audio a second before they are due to be played, they will be buffered in the stdout reader's buffer, giving it a nominal buffer size of 44,100 frames. Note that if the stdout reader consumes audio packets faster or slower than they are supplied, the buffer will eventually empty or overflow -- shairport-sync performs no stuffing or interpolation when writing to stdout. Default setting is 44,100 frames.
.TP
+\fB"AO" SETTINGS\f1
+These settings are for the AO backend, used for the libao audio library.
+
+There are two settings affecting timing. The \fIaudio_backend_latency_offset\f1 affects precisely when the first audio packet is sent and the \fIaudio_backend_buffer_desired_length\f1 setting affects the nominal output buffer size.
+
+These are the settings available within the \fBao\f1 group:
+.TP
+\fBaudio_backend_latency_offset=\f1\fIoffset_in_frames\f1\fB;\f1
+Packets of audio frames are written to the libao system synchronously -- that is, they are written at exactly the time they should be played. You can offset the time of initial audio output relative to its nominal time using this setting. For example to send an audio stream to stdout 100 milliseconds before it is due to be played, set this to -4410. Default setting is 0.
+.TP
+\fBaudio_backend_buffer_desired_length=\f1\fIbuffer_length_in_frames\f1\fB;\f1
+Use this setting, in frames, to set the size of the output buffer. It works by determining how soon the second and subsequent packets of audio frames are sent to to the libao system. For example, if you send the first packet of audio exactly when it is due and, using a \fIaudio_backend_buffer_desired_length\f1 setting of 44100, send subsequent packets of audio a second before they are due to be played, they will be buffered in the stdout reader's buffer, giving it a nominal buffer size of 44,100 frames. Note that if the libao system consumes audio packets faster or slower than they are supplied, the buffer will eventually empty or overflow -- shairport-sync performs no stuffing or interpolation when writing to libao. Default setting is 44,100 frames.
+.TP
\fB"METADATA" SETTINGS\f1
shairport-sync can process metadata provided by the source, such as Track Number, Album Name, cover art, etc. and can provide additional metadata such as volume level, pause/resume, etc. It sends the metadata to a pipe, by default \fI/tmp/shairport-sync-metadata\f1. To process metadata, shairport-sync must have been compiled with metadata support included. You can check that this is so by running \fBshairport-sync -V\f1; the identification string will contain the word \fBmetadata\f1.
@@ -210,7 +223,7 @@ This is the \fIlatency\f1, in frames, used for forkedDaapd sources. Default is 9
\fBdefault=\f1\fIlatency\f1\fB;\f1
This is the \fIlatency\f1, in frames, used when the source is unrecognised. Default is 88,200.
.SH OPTIONS
-Note: if you are setting up Shairport Sync for the first time or are updating an existing installation, you are encouraged to use the configuration file settings described above. Most of the options described below simply replicate the configuration settings and are retained to provide backward compatability with older installations of Shairport Sync.
+Note: if you are setting up Shairport Sync for the first time or are updating an existing installation, you are encouraged to use the configuration file settings described above. Most of the options described below simply replicate the configuration settings and are retained to provide backward compatibility with older installations of Shairport Sync.
Many of the options take sensible default values, so you can normally ignore most of them. See the EXAMPLES section for typical usages.
diff --git a/man/shairport-sync.7.xml b/man/shairport-sync.7.xml
index 1e009686..3738eb9a 100644
--- a/man/shairport-sync.7.xml
+++ b/man/shairport-sync.7.xml
@@ -106,7 +106,7 @@
A sample configuration file with all possible settings, but with all of them commented out, is installed at /etc/shairport-sync.conf.sample.
-
To retain backwards compatability with previous versions of shairport-sync
+
To retain backwards compatibility with previous versions of shairport-sync
you can use still use command line options, but any new features, etc. will
be available only via configuration file settings.
@@ -433,7 +433,7 @@
Note: if you are setting up Shairport Sync for the first time or are updating an existing installation,
you are encouraged to use the configuration file settings described above. Most of the options described below
- simply replicate the configuration settings and are retained to provide backward compatability with older installations of Shairport Sync.
+ simply replicate the configuration settings and are retained to provide backward compatibility with older installations of Shairport Sync.
Many of the options take sensible default values, so you can normally
ignore most of them. See the EXAMPLES section for typical usages.
A sample configuration file with all possible settings, but with all of them commented out, is installed at /etc/shairport-sync.conf.sample.
-
To retain backwards compatability with previous versions of shairport-sync
+
To retain backwards compatibility with previous versions of shairport-sync
you can use still use command line options, but any new features, etc. will
be available only via configuration file settings.
@@ -277,7 +277,7 @@
You can offset the time of initial audio output relative to its nominal time using this setting.
For example to send an audio stream to stdout 100 milliseconds before it is due to be played, set this to -4410. Default setting is 0.
-
+
@@ -288,7 +288,34 @@
shairport-sync performs no stuffing or interpolation when writing to stdout. Default setting is 44,100 frames.
-
+
+
"AO" SETTINGS
+
These settings are for the AO backend, used for the libao audio library.
+
There are two settings affecting timing. The audio_backend_latency_offset affects precisely when the first audio packet is sent
+ and the audio_backend_buffer_desired_length setting affects the nominal output buffer size.
+
These are the settings available within the ao group:
+
+
+
+
audio_backend_latency_offset=offset_in_frames;
+
+ Packets of audio frames are written to the libao system synchronously -- that is, they are written at exactly the time they should be played.
+ You can offset the time of initial audio output relative to its nominal time using this setting.
+ For example to send an audio stream to stdout 100 milliseconds before it is due to be played, set this to -4410. Default setting is 0.
+
+
+
+
+
+ Use this setting, in frames, to set the size of the output buffer. It works by determining how soon the second and subsequent packets of
+ audio frames are sent to to the libao system.
+ For example, if you send the first packet of audio exactly when it is due and, using a audio_backend_buffer_desired_length setting of 44100,
+ send subsequent packets of audio a second before they are due to be played, they will be buffered in the stdout reader's buffer, giving it a nominal buffer size of 44,100 frames.
+ Note that if the libao system consumes audio packets faster or slower than they are supplied, the buffer will eventually empty or overflow --
+ shairport-sync performs no stuffing or interpolation when writing to libao. Default setting is 44,100 frames.
+
+
+
"METADATA" SETTINGS
shairport-sync can process metadata provided by the source, such as Track Number, Album Name, cover art, etc. and can provide additional metadata such as volume level,
pause/resume, etc. It sends the metadata to a pipe, by default /tmp/shairport-sync-metadata.
@@ -390,7 +417,7 @@
Note: if you are setting up Shairport Sync for the first time or are updating an existing installation,
you are encouraged to use the configuration file settings described above. Most of the options described below
- simply replicate the configuration settings and are retained to provide backward compatability with older installations of Shairport Sync.
+ simply replicate the configuration settings and are retained to provide backward compatibility with older installations of Shairport Sync.
Many of the options take sensible default values, so you can normally
ignore most of them. See the EXAMPLES section for typical usages.
From 6f8ee38d33d939fac36e35f73c0df2664504081a Mon Sep 17 00:00:00 2001
From: Chris Boot
Date: Sat, 26 Dec 2015 14:57:34 +0000
Subject: [PATCH 074/144] Rebuild manpage and HTML doc when xmltoman is
available
Adjust configure.ac to detect if xmltoman is available; use that in
man/Makefile.am to rebuild the manpage and HTML file (generated from the
same source) if necessary.
---
configure.ac | 7 +++++++
man/Makefile.am | 10 ++++++++++
2 files changed, 17 insertions(+)
diff --git a/configure.ac b/configure.ac
index 75e4db9e..439f74b3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -229,6 +229,13 @@ AS_IF([test "x$with_systemdsystemunitdir" != "xno"],
[AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])])
AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemdsystemunitdir" != "xno"])
+# Look for xmltoman
+AC_CHECK_PROGS([XMLTOMAN], [xmltoman])
+if test -z "$XMLTOMAN"; then
+ AC_MSG_WARN([>>xmltoman not found - not rebuilding man pages])
+fi
+AM_CONDITIONAL([HAVE_XMLTOMAN], [test -n "$XMLTOMAN"])
+
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([getopt_long.h])
diff --git a/man/Makefile.am b/man/Makefile.am
index cbaf9165..e40bfb85 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -1 +1,11 @@
man_MANS = shairport-sync.7
+
+if HAVE_XMLTOMAN
+all-local: shairport-sync.html
+
+shairport-sync.7: shairport-sync.7.xml
+ xmltoman $< > $@
+
+shairport-sync.html: shairport-sync.7.xml
+ xmlmantohtml $< > $@
+endif
From 4e395ff3a50315709fb7c388389285793c6fef12 Mon Sep 17 00:00:00 2001
From: Mke Brady
Date: Sat, 26 Dec 2015 15:14:01 +0000
Subject: [PATCH 075/144] Tiny changes
---
audio_alsa.c | 8 ++++++--
player.c | 3 +--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/audio_alsa.c b/audio_alsa.c
index 64656ef3..b725d78a 100644
--- a/audio_alsa.c
+++ b/audio_alsa.c
@@ -453,8 +453,12 @@ static void parameters(audio_parameters *info) {
static void volume(double vol) {
// debug(1,"Setting volume db to %f, for volume input of %f.",vol_setting/100,vol);
set_volume = vol;
- if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, -1) != 0)
- die("Failed to set playback dB volume");
+ if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, 0) != 0) {
+ debug(1,"Can't set playback volume accurately to %f dB.",vol);
+ if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, -1) != 0)
+ if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, 1) != 0)
+ die("Failed to set playback dB volume");
+ }
}
static void linear_volume(double vol) {
diff --git a/player.c b/player.c
index 5330f49d..0b24a67e 100644
--- a/player.c
+++ b/player.c
@@ -579,9 +579,8 @@ static abuf_t *buffer_get_frame(void) {
<< 32) /
44100;
- uint32_t filler_size = frame_size;
uint32_t max_dac_delay = 4410;
- filler_size = 4410; // 0.1 second -- the maximum we'll add to the DAC
+ uint32_t filler_size = max_dac_delay; // 0.1 second -- the maximum we'll add to the DAC
if (local_time_now >= first_packet_time_to_play) {
// we've gone past the time...
From 4d73fa23b36fc2a0328f1213dcb3b4874ae9b0a7 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 28 Dec 2015 15:18:09 +0000
Subject: [PATCH 076/144] Prefer to use a public ipv6 number where privacy
extensions are enabled
---
rtp.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/rtp.c b/rtp.c
index 78a19a36..0e4f1aaf 100644
--- a/rtp.c
+++ b/rtp.c
@@ -41,6 +41,10 @@
#include "player.h"
#include "rtp.h"
+#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN
+#include
+#endif
+
typedef struct {
uint32_t seconds;
uint32_t fraction;
@@ -524,6 +528,19 @@ static int bind_port(SOCKADDR *remote, int *sock) {
die("failed to get usable addrinfo?! %s.", gai_strerror(ret));
*sock = socket(remote->SAFAMILY, SOCK_DGRAM, IPPROTO_UDP);
+
+ #ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN
+ #ifdef AF_INET6
+ // now, if we are on IPv6, prefer a public ipv6 address
+ if (remote->SAFAMILY==AF_INET6) {
+ int value = IPV6_PREFER_SRC_PUBLIC;
+ ret = setsockopt(*sock, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES, &value, sizeof(value));
+ if (ret<0)
+ die("error: could not select a preference for public IPv6 address");
+ }
+ #endif
+ #endif
+
ret = bind(*sock, info->ai_addr, info->ai_addrlen);
freeaddrinfo(info);
From b8b5b7fa1ef949698a24bdc6ccaa094999056b70 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 28 Dec 2015 20:38:51 +0000
Subject: [PATCH 077/144] Restore ability to compile in FreeBSD
---
common.h | 7 ++++++-
rtp.c | 4 ++--
shairport.c | 12 ++++++------
3 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/common.h b/common.h
index 01ce9de0..4f67cd47 100644
--- a/common.h
+++ b/common.h
@@ -2,7 +2,6 @@
#define _COMMON_H
#include
-#include
#include
#include
@@ -33,6 +32,12 @@
#define SAFAMILY sa_family
#endif
+enum endian_type {
+ SS_LITTLE_ENDIAN = 0,
+ SS_PDP_ENDIAN,
+ SS_BIG_ENDIAN,
+} endian_type;
+
enum stuffing_type {
ST_basic = 0,
ST_soxr,
diff --git a/rtp.c b/rtp.c
index 0e4f1aaf..328b9f41 100644
--- a/rtp.c
+++ b/rtp.c
@@ -41,7 +41,7 @@
#include "player.h"
#include "rtp.h"
-#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN
+#if defined(__linux__)
#include
#endif
@@ -529,7 +529,7 @@ static int bind_port(SOCKADDR *remote, int *sock) {
*sock = socket(remote->SAFAMILY, SOCK_DGRAM, IPPROTO_UDP);
- #ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN
+ #if defined(__linux__)
#ifdef AF_INET6
// now, if we are on IPv6, prefer a public ipv6 address
if (remote->SAFAMILY==AF_INET6) {
diff --git a/shairport.c b/shairport.c
index 20fce74b..e6286891 100644
--- a/shairport.c
+++ b/shairport.c
@@ -655,11 +655,11 @@ int main(int argc, char **argv) {
xn.arr[3] = 0x11; /* Highest-address byte */
if (xn.u32==0x11223344)
- endianness = __LITTLE_ENDIAN;
+ endianness = SS_LITTLE_ENDIAN;
else if (xn.u32==0x33441122)
- endianness = __PDP_ENDIAN;
+ endianness = SS_PDP_ENDIAN;
else if (xn.u32==0x44332211)
- endianness = __BIG_ENDIAN;
+ endianness = SS_BIG_ENDIAN;
else die("Can not recognise the endianness of the processor.");
strcpy(configuration_file_path, "/etc/");
@@ -854,13 +854,13 @@ int main(int argc, char **argv) {
daemon_log(LOG_NOTICE, "startup");
switch (endianness) {
- case __LITTLE_ENDIAN:
+ case SS_LITTLE_ENDIAN:
debug(2,"The processor is running little-endian.");
break;
- case __BIG_ENDIAN:
+ case SS_BIG_ENDIAN:
debug(2,"The processor is running big-endian.");
break;
- case __PDP_ENDIAN:
+ case SS_PDP_ENDIAN:
debug(2,"The processor is running pdp-endian.");
break;
}
From d546f4bbdb4346189d905396fcec9bcfbcd87632 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 30 Dec 2015 10:11:20 +0000
Subject: [PATCH 078/144] Correct option tag in the ao subsystem to read
audio_backend_buffer_desired_length rather than
audio_backend_buffer_desired_length_software
---
audio_ao.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/audio_ao.c b/audio_ao.c
index 6cd98eab..41b823b0 100644
--- a/audio_ao.c
+++ b/audio_ao.c
@@ -54,7 +54,7 @@ static int init(int argc, char **argv) {
if (config.cfg != NULL) {
/* Get the desired buffer size setting. */
- if (config_lookup_int(config.cfg, "ao.audio_backend_buffer_desired_length_software", &value)) {
+ if (config_lookup_int(config.cfg, "ao.audio_backend_buffer_desired_length", &value)) {
if ((value < 0) || (value > 66150))
die("Invalid a0 audio backend buffer desired length \"%d\". It should be between 0 and "
"66150, default is 44100",
From 14e27cb477df88e7b87600ea349347cb99629379 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 30 Dec 2015 10:11:45 +0000
Subject: [PATCH 079/144] Update some of the message texts
---
configure.ac | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/configure.ac b/configure.ac
index 439f74b3..d9f5f037 100644
--- a/configure.ac
+++ b/configure.ac
@@ -164,7 +164,7 @@ AC_ARG_WITH(tinysvcmdns, [ --with-tinysvcmdns = choose tinysvcmdns-based mDNS s
AM_CONDITIONAL([USE_TINYSVCMDNS], [test "x$HAS_TINYSVCMDNS" = "x1"])
# Look for ALSA flag
-AC_ARG_WITH(alsa, [ --with-alsa = choose native ALSA API support (GNU/Linux only)],
+AC_ARG_WITH(alsa, [ --with-alsa = choose ALSA API support (GNU/Linux only)],
[AC_MSG_RESULT(>>Including an ALSA back end)
HAS_ALSA=1
AM_CONDITIONAL([USE_ALSA], [test 0])
@@ -181,24 +181,24 @@ AC_ARG_WITH(alsa, [ --with-alsa = choose native ALSA API support (GNU/Linux onl
AM_CONDITIONAL([USE_ALSA], [test "x$HAS_ALSA" = "x1"])
# Look for SNDIO flag
-AC_ARG_WITH(sndio, [ --with-sndio = choose native SNDIO API support (FreeBSD) -- probably broken], [
- AC_MSG_RESULT(>>Including a SNDIO back end --- N.B. this is probably broken!)
+AC_ARG_WITH(sndio, [ --with-sndio = choose SNDIO API support (FreeBSD) -- probably broken], [
+ AC_MSG_RESULT(>>Including a SNDIO back end -- N.B. this is probably broken!)
HAS_SNDIO=1
AC_DEFINE([CONFIG_SNDIO], 1, [Needed by the compiler.])
AC_CHECK_LIB([sndio], [sio_open], , AC_MSG_ERROR(SNDIO support requires the sndio library!))], )
AM_CONDITIONAL([USE_SNDIO], [test "x$HAS_SNDIO" = "x1"])
# Look for AO flag
-AC_ARG_WITH(ao, [ --with-ao = choose native AO (Audio Output?) API support -- probably broken], [
- AC_MSG_RESULT(>>Including an AO back end --- N.B. this is probably broken!)
+AC_ARG_WITH(ao, [ --with-ao = choose AO (Audio Output?) API support. N.B. no synchronisation -- so underflow or overflow is inevitable!], [
+ AC_MSG_RESULT(>>Including an AO back end. N.B. no synchronisation -- so underflow or overflow is inevitable!)
HAS_AO=1
AC_DEFINE([CONFIG_AO], 1, [Needed by the compiler.])
AC_CHECK_LIB([ao], [ao_initialize], , AC_MSG_ERROR(AO support requires the ao library!))], )
AM_CONDITIONAL([USE_AO], [test "x$HAS_AO" = "x1"])
# Look for pulseaudio flag
-AC_ARG_WITH(pulseaudio, [ --with-pulseaudio = choose native PulseAudio API support -- N.B. no synchronisation -- so underflow or overflow is inevitable!], [
- AC_MSG_RESULT(>>Including a PulseAudio back end -- N.B. no synchronisation -- so underflow or overflow is inevitable!)
+AC_ARG_WITH(pulseaudio, [ --with-pulseaudio = choose PulseAudio API support. N.B. no synchronisation -- so underflow or overflow is inevitable!], [
+ AC_MSG_RESULT(>>Including a PulseAudio back end. N.B. no synchronisation -- so underflow or overflow is inevitable!)
HAS_PULSE=1
AC_DEFINE([CONFIG_PULSE], 1, [Needed by the compiler.])
AC_CHECK_LIB([pulse-simple], [pa_simple_new], , AC_MSG_ERROR(PulseAudio support requires the pulse-simple library, possibly in the package libpulse-dev!))
From 647663ab61e67df8dc4109f599f37ed2314d8c86 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 30 Dec 2015 10:16:26 +0000
Subject: [PATCH 080/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index edc34638..e4db7e8c 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,3 +1,12 @@
+Version 2.7.6 -- Development Version
+----
+**Bug Fixes**
+* Look for the correct tag name for desired `ao` buffer length: `audio_backend_buffer_desired_length` rather than `audio_backend_buffer_desired_length_software`.
+* Fix a few FreeBSD compilation bugs.
+
+**Enhancements**
+* Favour the use of "public" IPv6 addresses as source adresses when connecting to a distant IPv6 port.
+
Version 2.7.5 -- Development Version
----
**New Features**
From 9465dd885b7b186fdad5a87c1fbe43c62182f29a Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 30 Dec 2015 10:17:31 +0000
Subject: [PATCH 081/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index e4db7e8c..fd45767e 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -5,7 +5,7 @@ Version 2.7.6 -- Development Version
* Fix a few FreeBSD compilation bugs.
**Enhancements**
-* Favour the use of "public" IPv6 addresses as source adresses when connecting to a distant IPv6 port.
+* Favour the use of "public" IPv6 addresses as source addresses when connecting to a distant IPv6 port.
Version 2.7.5 -- Development Version
----
From a1ba8bc0b128629bab42f05384ed22c59bf8f883 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 30 Dec 2015 11:42:21 +0000
Subject: [PATCH 082/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index fd45767e..9b0a6822 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -3,8 +3,11 @@ Version 2.7.6 -- Development Version
**Bug Fixes**
* Look for the correct tag name for desired `ao` buffer length: `audio_backend_buffer_desired_length` rather than `audio_backend_buffer_desired_length_software`.
* Fix a few FreeBSD compilation bugs.
+* Fix a few documentation issues and typos. Thanks to [Chris Boot](https://github.com/bootc).
**Enhancements**
+* Add note about installing to Mac OS X. Thanks to [Serg Podtynnyi](https://github.com/shtirlic).
+* Add automatic rebuild of manapage and html doc when xmltoman and friends are available. Thanks to [Chris Boot](https://github.com/bootc).
* Favour the use of "public" IPv6 addresses as source addresses when connecting to a distant IPv6 port.
Version 2.7.5 -- Development Version
From 4707b420fa3fea785e9ef95d424bb6ca1abf6a0e Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 30 Dec 2015 12:09:14 +0000
Subject: [PATCH 083/144] Update README.md
---
README.md | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index dd9f4a77..f0f2e3e0 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,10 @@ If you wish to install Shairport Sync on OpenWrt, Arch or Fedora platforms, plea
**Note**
The following procedures will install the shairport-sync application into your system. Before continuing, you should check to see if shairport-sync is already installed -- you can use `which shairport-sync` to find where it is located, if installed. If it is installed you should delete it -- you may need to have superuser privileges. After deleting, check again in case further copies are installed elsewhere.
-(If the existing installation of shairport-sync is where the new copy will be installed into, it will be overwritten; sometimes, however, the installation is to another location, so it is safer, initially, to delete previous versions manually.)
+(If the existing installation of shairport-sync is where the new copy will be installed into, it will be overwritten; sometimes, however, the installation is to another location, so it is safer, initially, to delete previous versions manually.)
+
+**Mac OS X**
+A [HomeBrew](http://brew.sh) package exists for Shairport Sync. With HomeBrew installed, Shairport Sync can be installed using the command `$brew install shairport-sync`. Note that the installation uses the `libao` library and so synchronisation is not available – playback glitches will occur occasionally, when the buffers overflow or underflow.
**Ubuntu**
Personal Package Archives for Shairport Sync master and development branches are available at https://launchpad.net/~dantheperson.
From 3a6a943eb512f28ed8b96935bd0a8c0ad26eb436 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 30 Dec 2015 12:17:12 +0000
Subject: [PATCH 084/144] Update README.md
---
README.md | 48 ++++++++++++++++++++++++------------------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/README.md b/README.md
index f0f2e3e0..6eb7b388 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
Shairport Sync
=============
-Shairport Sync is an AirPlay audio player -- it plays audio streamed from iTunes, iOS devices and other AirPlay sources such as Quicktime Player, ForkedDaapd among others.
+Shairport Sync is an AirPlay audio player — it plays audio streamed from iTunes, iOS devices and other AirPlay sources such as Quicktime Player, ForkedDaapd among others.
Audio played by a Shairport Sync-powered device stays synchronised with the source and hence with similar devices playing the same source. In this way, synchronised multi-room audio is possible without difficulty. (Hence the name Shairport Sync, BTW.)
Shairport Sync does not support AirPlay video or photo streaming.
@@ -35,7 +35,7 @@ What else?
Status
------
-Shairport Sync works on a wide variety of Linux devices. It works on standard Ubuntu laptops, on the Raspberry Pi with Raspbian Wheezy and Jessie, Arch Linux and OpenWrt, and it runs on a Linksys NSLU2 and a TP-Link 710N using OpenWrt. It works with built-in audio and with a variety of USB-connected audio amplifiers and DACs, including a cheapo USB "3D Sound" dongle, a first generation iMic and a Topping TP30 amplifier with a USB DAC input. It will not work properly – if at all – with a PulseAudio (pseudo-)output device. Using a port of the `alsa` system, Shairport Sync runs rather well on FreeBSD.
+Shairport Sync works on a wide variety of Linux devices. It works on standard Ubuntu laptops, on the Raspberry Pi with Raspbian Wheezy and Jessie, Arch Linux and OpenWrt, and it runs on a Linksys NSLU2 and a TP-Link 710N using OpenWrt. It works with built-in audio and with a variety of USB-connected audio amplifiers and DACs, including a cheapo USB "3D Sound" dongle, a first generation iMic and a Topping TP30 amplifier with a USB DAC input. It will not work properly — if at all — with a PulseAudio (pseudo-)output device. Using a port of the `alsa` system, Shairport Sync runs rather well on FreeBSD.
Shairport Sync runs well on the Raspberry Pi. It can drive the built-in sound card, though the audio out of the card is of poor quality (see the note below on configuring the Raspberry Pi to make best use of it). USB-connected sound cards work well, though [very] old versions of Raspbian appear to suffer from a problem — see http://www.raspberrypi.org/forums/viewtopic.php?t=23544, so it is wise to update. Shairport Sync works well with the IQAudIO Pi-DAC — see http://www.iqaudio.com.
@@ -55,7 +55,7 @@ If you wish to install Shairport Sync on OpenWrt, Arch or Fedora platforms, plea
**Note**
-The following procedures will install the shairport-sync application into your system. Before continuing, you should check to see if shairport-sync is already installed -- you can use `which shairport-sync` to find where it is located, if installed. If it is installed you should delete it -- you may need to have superuser privileges. After deleting, check again in case further copies are installed elsewhere.
+The following procedures will install the shairport-sync application into your system. Before continuing, you should check to see if shairport-sync is already installed – you can use `which shairport-sync` to find where it is located, if installed. If it is installed you should delete it – you may need superuser privileges. After deleting, check again in case further copies are installed elsewhere.
(If the existing installation of shairport-sync is where the new copy will be installed into, it will be overwritten; sometimes, however, the installation is to another location, so it is safer, initially, to delete previous versions manually.)
**Mac OS X**
@@ -152,7 +152,7 @@ Choose the appropriate `--with-*` options:
**System V and `systemd`**
-At the time of writing, there are two widely-used systems for automatically starting programs automatically at startup: "System V" and `systemd`. (There are others, but they are not considered here.) To see if the `systemd` process is running on your system, enter the following command:
+At the time of writing, there are two widely-used systems for automatically starting programs automatically at startup: `systemd` and "System V" . (There are others, but they are not considered here.) To see if the `systemd` process is running on your system, enter the following command:
`ps aux | grep systemd | grep -v grep`
@@ -166,19 +166,19 @@ message+ 528 0.0 0.7 5568 3172 ? Ss 08:00 0:01 /usr/bin/dbus-d
pi 983 0.0 0.7 4912 3256 ? Ss 08:00 0:00 /lib/systemd/systemd --user
pi@raspberrypi ~ $
```
-whereas on a system without `systemd` -- presumably using System V -- (this is a from a Raspberry Pi running Raspbian Wheezy) , you'll get nothing:
+whereas on a system without `systemd` – presumably using System V – (this is a from a Raspberry Pi running Raspbian Wheezy) , you'll get nothing:
```
pi@raspberrypi ~ $ ps aux | grep systemd | grep -v grep
pi@raspberrypi ~ $
```
Choose `--with-systemd` or `--with-systemv` on the basis of the outcome.
-Here is an example, suitable for installations such as Ubuntu and Raspbian Wheezy:
+Here is an example, suitable for installations such as Ubuntu 15.10 and Raspbian Jessie that use `systemd`:
-`$ ./configure --with-alsa --with-avahi --with-ssl=openssl --with-metadata --with-soxr --with-systemv`
+`$ ./configure --with-alsa --with-avahi --with-ssl=openssl --with-metadata --with-soxr --with-systemd`
* Omit the `--with-soxr` if the libsoxr library is not available.
-* For installation into a `systemd` system, replace the `--with-systemv` with `--with-systemd`.
+* For installation into a `systemv` system, replace the `--with-systemd` with `--with-systemv`.
Enter:
@@ -186,22 +186,8 @@ Enter:
to build the application.
-**Installation to a System V system**
-If you are installing onto a System V system:
-
-```
-$sudo make install
-```
-
-to install `shairport-sync` along with a `man` page, a default configuration file and a System V startup script to launch it automatically at system startup.
-
-To complete the installation, enter:
-```
-$sudo update-rc.d shairport-sync defaults 90 10
-```
-
**Installation to a `systemd` system**
-To complete the installation, you need to define a `shairport-sync` group and user. This is a security measure -- the user and group are relatively unprivileged, and the user does not have login priviliges. The user must be a member of the `audio` group to be able to access the audio hardware. The following commands define the group and user correctly if they do not already exist (note the use of `sudo` -- omit this if you already have superuser privileges:
+To complete the installation, you need to define a `shairport-sync` group and user. This is a security measure – the user and group are relatively unprivileged, and the user does not have login priviliges. The user must be a member of the `audio` group to be able to access the audio hardware. The following commands define the group and user correctly if they do not already exist (note the use of `sudo` – omit this if you already have superuser privileges:
```
$getent group shairport-sync &>/dev/null || sudo groupadd -r shairport-sync >/dev/null
@@ -220,6 +206,20 @@ To enable Shairport Sync to start automatically at system startup, enter:
`$sudo systemctl enable shairport-sync`
+**Installation to a System V system**
+If you are installing onto a System V system:
+
+```
+$sudo make install
+```
+
+to install `shairport-sync` along with a `man` page, a default configuration file and a System V startup script to launch it automatically at system startup.
+
+To complete the installation, enter:
+```
+$sudo update-rc.d shairport-sync defaults 90 10
+```
+
**Man Page**
You can view the man page here: http://htmlpreview.github.io/?https://github.com/mikebrady/shairport-sync/blob/development/man/shairport-sync.html
@@ -228,7 +228,7 @@ Configuring Shairport Sync
--------
There are two logically distinct parts to getting Shairport Sync to run properly on your machine — (1) starting and stopping it and (2) ensuring it has the right settings.
-Starting and stopping automatically is taken care of differently in different versions of Linux -- see the previous section for an example of installing into a System V or a `systemd` based system.
+Starting and stopping automatically is taken care of differently in different versions of Linux – see the previous section for an example of installing into a System V or a `systemd` based system.
To get the best from Shairport Sync, you’ll need to (1) give Shairport Sync a service name by which it will be seen in iTunes etc., (2) specify the output device to use and (3) specify the name of the mixer volume control to use to control the output level. To get values for (2) and (3) you might need to explore the ALSA output devices with a program like `alsamixer` or similar.
From 71b67474dc8e760ac27c286a7e8179f8f1a07013 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 30 Dec 2015 12:17:49 +0000
Subject: [PATCH 085/144] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 6eb7b388..2f0fbcc7 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Audio played by a Shairport Sync-powered device stays synchronised with the sour
Shairport Sync does not support AirPlay video or photo streaming.
-This branch -- "development" -- is unstable and may change quickly. To access the stable version, please switch to the "master" branch.
+This branch — "development" — is unstable and may change quickly. To access the stable version, please switch to the "master" branch.
More Information
----------
From df64c98e8309351e34a8c30f8366aa43194901ab Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 30 Dec 2015 12:25:57 +0000
Subject: [PATCH 086/144] Update README.md
---
README.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 2f0fbcc7..4fa3c961 100644
--- a/README.md
+++ b/README.md
@@ -51,16 +51,13 @@ Note: Historically, Shairport Sync has taken its settings from command line argu
Building And Installing
---------------------
-If you wish to install Shairport Sync on OpenWrt, Arch or Fedora platforms, please follow the appropriate instructions below. Otherwise follow the General Build Instructions. Then, when the program has been installed, refer to the section on Configuring Shairport Sync that follows.
+If you wish to install Shairport Sync on OpenWrt, Arch or Fedora platforms, please follow the appropriate instructions below. Limited support is also available for MAc OS X. Otherwise follow the General Build Instructions. Then, when the program has been installed, refer to the section on Configuring Shairport Sync that follows.
**Note**
The following procedures will install the shairport-sync application into your system. Before continuing, you should check to see if shairport-sync is already installed – you can use `which shairport-sync` to find where it is located, if installed. If it is installed you should delete it – you may need superuser privileges. After deleting, check again in case further copies are installed elsewhere.
(If the existing installation of shairport-sync is where the new copy will be installed into, it will be overwritten; sometimes, however, the installation is to another location, so it is safer, initially, to delete previous versions manually.)
-**Mac OS X**
-A [HomeBrew](http://brew.sh) package exists for Shairport Sync. With HomeBrew installed, Shairport Sync can be installed using the command `$brew install shairport-sync`. Note that the installation uses the `libao` library and so synchronisation is not available – playback glitches will occur occasionally, when the buffers overflow or underflow.
-
**Ubuntu**
Personal Package Archives for Shairport Sync master and development branches are available at https://launchpad.net/~dantheperson.
@@ -70,6 +67,9 @@ There is a Shairport Sync package in OpenWrt `trunk`. Also, there's an OpenWrt p
**Arch Linux:**
An Arch Linux installation package is available at [EliaCereda/shairport-sync-PKGBUILD](https://github.com/EliaCereda/shairport-sync-PKGBUILD).
+**Mac OS X**
+A [HomeBrew](http://brew.sh) package exists for Shairport Sync. With HomeBrew installed, Shairport Sync can be installed using the command `$brew install shairport-sync`. Note that the installation uses the `libao` library and so synchronisation is not available — playback glitches will occur occasionally, when the buffers overflow or underflow.
+
**Fedora:**
Install the toolchain and pre-requisites, if necessary:
```
From 317084e391e6202bce1fab0d9e8ea886c4d256dd Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 30 Dec 2015 12:37:09 +0000
Subject: [PATCH 087/144] Update README.md
---
README.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 4fa3c961..7c874812 100644
--- a/README.md
+++ b/README.md
@@ -58,7 +58,7 @@ If you wish to install Shairport Sync on OpenWrt, Arch or Fedora platforms, plea
The following procedures will install the shairport-sync application into your system. Before continuing, you should check to see if shairport-sync is already installed – you can use `which shairport-sync` to find where it is located, if installed. If it is installed you should delete it – you may need superuser privileges. After deleting, check again in case further copies are installed elsewhere.
(If the existing installation of shairport-sync is where the new copy will be installed into, it will be overwritten; sometimes, however, the installation is to another location, so it is safer, initially, to delete previous versions manually.)
-**Ubuntu**
+**Ubuntu:**
Personal Package Archives for Shairport Sync master and development branches are available at https://launchpad.net/~dantheperson.
**OpenWrt:**
@@ -67,7 +67,7 @@ There is a Shairport Sync package in OpenWrt `trunk`. Also, there's an OpenWrt p
**Arch Linux:**
An Arch Linux installation package is available at [EliaCereda/shairport-sync-PKGBUILD](https://github.com/EliaCereda/shairport-sync-PKGBUILD).
-**Mac OS X**
+**Mac OS X:**
A [HomeBrew](http://brew.sh) package exists for Shairport Sync. With HomeBrew installed, Shairport Sync can be installed using the command `$brew install shairport-sync`. Note that the installation uses the `libao` library and so synchronisation is not available — playback glitches will occur occasionally, when the buffers overflow or underflow.
**Fedora:**
@@ -173,12 +173,12 @@ pi@raspberrypi ~ $
```
Choose `--with-systemd` or `--with-systemv` on the basis of the outcome.
-Here is an example, suitable for installations such as Ubuntu 15.10 and Raspbian Jessie that use `systemd`:
+Here is an example, suitable for installations that use `systemd`, such as Ubuntu 15.10 and Raspbian Jessie:
`$ ./configure --with-alsa --with-avahi --with-ssl=openssl --with-metadata --with-soxr --with-systemd`
* Omit the `--with-soxr` if the libsoxr library is not available.
-* For installation into a `systemv` system, replace the `--with-systemd` with `--with-systemv`.
+* For installation into a System V system, replace the `--with-systemd` with `--with-systemv`.
Enter:
From 3bc6ceefd29ec299a0c0827e4fba60b91905b582 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 30 Dec 2015 12:38:07 +0000
Subject: [PATCH 088/144] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 7c874812..5ed4ef9c 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ More Information
----------
Shairport Sync works by using timing information and timestamps present in data coming from the audio source (e.g. an iPhone) to "play" audio at exactly the right time. It does this by monitoring and controlling the *latency* — the time between a sound frame is supposed to be played, as specified by its `timestamp`, and the time when it is actually played by the audio output device, usually a Digital to Audio Converter (DAC).
-The latency to be used is specified by the source when it negotiates with Shairport Sync. Most sources set a latency of 88,200 frames -- exactly two seconds. Recent versions of iTunes and forkedDaapd use a latency of 99,577 frames.
+The latency to be used is specified by the source when it negotiates with Shairport Sync. Most sources set a latency of 88,200 frames — exactly two seconds. Recent versions of iTunes and forkedDaapd use a latency of 99,577 frames.
Timestamps are measured relative to the source computer's clocks, the `source clock`, but timing must be done relative to the clock of the computer running Shairport Sync, the `local clock`. The source and local clocks are synchronised, usually to within a fraction of a millisecond, using a variant of NTP synchronisation protocols.
From 8eed253c98c9b95cd8eb635045cfe0b673bbdc02 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 30 Dec 2015 19:33:56 +0000
Subject: [PATCH 089/144] Comment out the IPv6 public stuff -- OpenWrt doesnt
like it
---
rtp.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/rtp.c b/rtp.c
index 328b9f41..baf95124 100644
--- a/rtp.c
+++ b/rtp.c
@@ -41,10 +41,12 @@
#include "player.h"
#include "rtp.h"
+/*
+// this does not compile properly with OpenWrt Barrier Breaker...
#if defined(__linux__)
#include
#endif
-
+*/
typedef struct {
uint32_t seconds;
uint32_t fraction;
@@ -529,6 +531,8 @@ static int bind_port(SOCKADDR *remote, int *sock) {
*sock = socket(remote->SAFAMILY, SOCK_DGRAM, IPPROTO_UDP);
+/*
+ // this doesn't compile properly with OpenWrt Barrier Breaker.
#if defined(__linux__)
#ifdef AF_INET6
// now, if we are on IPv6, prefer a public ipv6 address
@@ -540,7 +544,7 @@ static int bind_port(SOCKADDR *remote, int *sock) {
}
#endif
#endif
-
+*/
ret = bind(*sock, info->ai_addr, info->ai_addrlen);
freeaddrinfo(info);
From ba915ab270683d1cc3c0cacb544059128a3a2b02 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 6 Jan 2016 08:55:58 +0000
Subject: [PATCH 090/144] Update README.md
---
README.md | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 5ed4ef9c..3cd642e8 100644
--- a/README.md
+++ b/README.md
@@ -65,10 +65,12 @@ Personal Package Archives for Shairport Sync master and development branches are
There is a Shairport Sync package in OpenWrt `trunk`. Also, there's an OpenWrt package at https://github.com/mikebrady/shairport-sync-for-openwrt, including one that builds back to `Attitude Adjustment`.
**Arch Linux:**
-An Arch Linux installation package is available at [EliaCereda/shairport-sync-PKGBUILD](https://github.com/EliaCereda/shairport-sync-PKGBUILD).
+Shairport Sync is available for `x86_64` and `i686` platforms in the Arch Linux Community Repository -- search for `shairport-sync`. See also https://www.archlinux.org/packages/.
+
+An Arch Linux installation package, suitable for compilation on any platform, is available at [EliaCereda/shairport-sync-PKGBUILD](https://github.com/EliaCereda/shairport-sync-PKGBUILD).
**Mac OS X:**
-A [HomeBrew](http://brew.sh) package exists for Shairport Sync. With HomeBrew installed, Shairport Sync can be installed using the command `$brew install shairport-sync`. Note that the installation uses the `libao` library and so synchronisation is not available — playback glitches will occur occasionally, when the buffers overflow or underflow.
+A [HomeBrew](http://brew.sh) package exists for Shairport Sync. With HomeBrew installed, Shairport Sync can be installed using the command `$brew install shairport-sync`. Note that the installation uses the `libao` library and so synchronisation is not available — playback glitches will occur occasionally, when the `ao` system's buffers overflow or underflow.
**Fedora:**
Install the toolchain and pre-requisites, if necessary:
From 77b1c2ddc7e5348913f77fc8681b67cbd612126b Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 6 Jan 2016 09:05:32 +0000
Subject: [PATCH 091/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 9b0a6822..28a204a9 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,3 +1,11 @@
+Head
+----
+**Enhancements**
+* Add note about the Arch Linux Community repository package `shairport-sync`. Thanks to [Anatol Pomozov](https://github.com/anatol).
+
+**Bug Fixes**
+* Remove code favouring the use of "public" IPv6 addresses as source addresses when connecting to a distant IPv6 port – Neither OpenWrt nor FreeBSD can use it at present. Also, it's not clear if any problems are being caused by not favouring public IPv6 addresses.
+
Version 2.7.6 -- Development Version
----
**Bug Fixes**
From 643e84a85dedd25bebc9799e6b56c7d613f2f6be Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 12:08:08 +0000
Subject: [PATCH 092/144] Create .travis.yml
---
.travis.yml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 .travis.yml
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..02621c16
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,5 @@
+language: c
+script: autoreconf -fi && --with-alsa --with-avahi --with-ssl=openssl --with-metadata --with-soxr --with-systemv && make
+branches:
+ only:
+ - development
From 2820dd92edb5056c2b21b9d93d36cb6dc6f184a0 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 12:10:26 +0000
Subject: [PATCH 093/144] Update .travis.yml
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 02621c16..b298670d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,5 @@
language: c
-script: autoreconf -fi && --with-alsa --with-avahi --with-ssl=openssl --with-metadata --with-soxr --with-systemv && make
+script: autoreconf -fi && ./configure --with-alsa --with-avahi --with-ssl=openssl --with-metadata --with-soxr --with-systemv && make
branches:
only:
- development
From 1ff8c36c3956730dd3495a24f553a3c3b351bdfb Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 12:13:14 +0000
Subject: [PATCH 094/144] Update .travis.yml
---
.travis.yml | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/.travis.yml b/.travis.yml
index b298670d..991ab14f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,3 +3,10 @@ script: autoreconf -fi && ./configure --with-alsa --with-avahi --with-ssl=openss
branches:
only:
- development
+addons:
+ apt:
+ packages:
+ - libdaemon-dev
+ - libasound2-dev
+ - libpopt-dev
+ - libconfig-dev
From bbed28cde556a66af33848637fbf3f4fe53c0d96 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 12:14:09 +0000
Subject: [PATCH 095/144] Update .travis.yml
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 991ab14f..2b30bfed 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,7 +6,7 @@ branches:
addons:
apt:
packages:
- - libdaemon-dev
+ - libdaemon
- libasound2-dev
- libpopt-dev
- libconfig-dev
From 18d3d409f3bad542a0c3888ef7d3692532904ee3 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 12:28:37 +0000
Subject: [PATCH 096/144] Update .travis.yml
---
.travis.yml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 2b30bfed..23239f28 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,10 +3,12 @@ script: autoreconf -fi && ./configure --with-alsa --with-avahi --with-ssl=openss
branches:
only:
- development
+before_install:
+ - sudo apt-get -qq update
+ - sudo apt-get install -y libdaemon-dev
addons:
apt:
packages:
- - libdaemon
- libasound2-dev
- libpopt-dev
- libconfig-dev
From a1269daea85910c3efa39b5288538b85335139dc Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 12:31:59 +0000
Subject: [PATCH 097/144] Update .travis.yml
---
.travis.yml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/.travis.yml b/.travis.yml
index 23239f28..9606f51f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,3 +12,7 @@ addons:
- libasound2-dev
- libpopt-dev
- libconfig-dev
+ - libsoxr-dev
+ - avahi-daemon
+ - libavahi-client-dev
+ - libssl-dev
From 97dabbbac93b76a5b9bba3918036b032adf74960 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 12:35:34 +0000
Subject: [PATCH 098/144] Update .travis.yml
---
.travis.yml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 9606f51f..586f2b8f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,12 +5,11 @@ branches:
- development
before_install:
- sudo apt-get -qq update
- - sudo apt-get install -y libdaemon-dev
+ - sudo apt-get install -y libdaemon-dev libpopt-dev
addons:
apt:
packages:
- libasound2-dev
- - libpopt-dev
- libconfig-dev
- libsoxr-dev
- avahi-daemon
From 61174ea9b4d2c5d05dbde995b120568deae0c36f Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 12:40:00 +0000
Subject: [PATCH 099/144] Update .travis.yml
---
.travis.yml | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 586f2b8f..631c1ba4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,13 +5,11 @@ branches:
- development
before_install:
- sudo apt-get -qq update
- - sudo apt-get install -y libdaemon-dev libpopt-dev
+ - sudo apt-get install -y libdaemon-dev libpopt-dev avahi-daemon libavahi-client-dev
addons:
apt:
packages:
- libasound2-dev
- libconfig-dev
- libsoxr-dev
- - avahi-daemon
- - libavahi-client-dev
- libssl-dev
From c69fa727f7078e7f82c6d765e4cb4df655f71fc6 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 12:42:25 +0000
Subject: [PATCH 100/144] Update .travis.yml
---
.travis.yml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 631c1ba4..43f2b8e6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,7 +5,10 @@ branches:
- development
before_install:
- sudo apt-get -qq update
- - sudo apt-get install -y libdaemon-dev libpopt-dev avahi-daemon libavahi-client-dev
+ - sudo apt-get install -y libdaemon-dev
+ - sudo apt-get install -y libpopt-dev
+ - sudo apt-get install -y avahi-daemon
+ - sudo apt-get install -y libavahi-client-dev
addons:
apt:
packages:
From dc24c4f07e9b1b38b52134c0d1952df9e69d71ec Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 12:45:08 +0000
Subject: [PATCH 101/144] Update .travis.yml
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 43f2b8e6..3911b148 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -15,4 +15,4 @@ addons:
- libasound2-dev
- libconfig-dev
- libsoxr-dev
- - libssl-dev
+ - libpolarssl-dev
From b991138eef2fe7645c01b99c673787fe632019c8 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 12:48:29 +0000
Subject: [PATCH 102/144] Update .travis.yml
---
.travis.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 3911b148..9c8597ed 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,10 +9,11 @@ before_install:
- sudo apt-get install -y libpopt-dev
- sudo apt-get install -y avahi-daemon
- sudo apt-get install -y libavahi-client-dev
+ - sudo apt-get install -y libconfig-dev
addons:
apt:
packages:
- libasound2-dev
- libconfig-dev
- libsoxr-dev
- - libpolarssl-dev
+ - libssl-dev
From 11ea4b2313f6ff6a2332a2f7eaed0e1208765702 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 12:51:09 +0000
Subject: [PATCH 103/144] Update .travis.yml
---
.travis.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.travis.yml b/.travis.yml
index 9c8597ed..dbc47d8d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,6 +10,8 @@ before_install:
- sudo apt-get install -y avahi-daemon
- sudo apt-get install -y libavahi-client-dev
- sudo apt-get install -y libconfig-dev
+ - sudo apt-get install -y libsoxr-dev
+
addons:
apt:
packages:
From 6a48e333fb2f9f1f09d0e96f9e31bf1a80ba93fb Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 12:54:29 +0000
Subject: [PATCH 104/144] Update .travis.yml
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index dbc47d8d..5105dcd5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,7 +10,7 @@ before_install:
- sudo apt-get install -y avahi-daemon
- sudo apt-get install -y libavahi-client-dev
- sudo apt-get install -y libconfig-dev
- - sudo apt-get install -y libsoxr-dev
+ - sudo apt-get install -y libssl-dev
addons:
apt:
From 5ac7049646c57c20230861d384e5b668c1c3a4d9 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 12:57:31 +0000
Subject: [PATCH 105/144] Update .travis.yml
---
.travis.yml | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 5105dcd5..f777e369 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,5 @@
language: c
-script: autoreconf -fi && ./configure --with-alsa --with-avahi --with-ssl=openssl --with-metadata --with-soxr --with-systemv && make
+script: autoreconf -fi && ./configure --with-alsa --with-avahi --with-ssl=openssl --with-metadata --with-systemv && make
branches:
only:
- development
@@ -16,6 +16,3 @@ addons:
apt:
packages:
- libasound2-dev
- - libconfig-dev
- - libsoxr-dev
- - libssl-dev
From 0db81e28cb7c9a1565c87aa5fad17befe78b3a7b Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 13:07:27 +0000
Subject: [PATCH 106/144] Update .travis.yml
---
.travis.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.travis.yml b/.travis.yml
index f777e369..d30750fe 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,6 @@
language: c
+sudo: required
+dist: trusty
script: autoreconf -fi && ./configure --with-alsa --with-avahi --with-ssl=openssl --with-metadata --with-systemv && make
branches:
only:
From 3d55ea1c891b015798c19447f0ede38486be27bc Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 13:11:27 +0000
Subject: [PATCH 107/144] Update .travis.yml
---
.travis.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index d30750fe..ab3d3b4f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,7 @@
language: c
sudo: required
dist: trusty
-script: autoreconf -fi && ./configure --with-alsa --with-avahi --with-ssl=openssl --with-metadata --with-systemv && make
+script: autoreconf -fi && ./configure --with-alsa --with-avahi --with-ssl=openssl --with-soxr --with-metadata --with-systemv && make
branches:
only:
- development
@@ -18,3 +18,4 @@ addons:
apt:
packages:
- libasound2-dev
+ - libsoxr-dev
From ced7a0081744ab4b1ad81aa4bb6f705de9f32845 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 13:15:01 +0000
Subject: [PATCH 108/144] Update .travis.yml
---
.travis.yml | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index ab3d3b4f..22d1bb44 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,11 +7,9 @@ branches:
- development
before_install:
- sudo apt-get -qq update
- - sudo apt-get install -y libdaemon-dev
- - sudo apt-get install -y libpopt-dev
+ - sudo apt-get install -y libdaemon-dev libpopt-dev
- sudo apt-get install -y avahi-daemon
- - sudo apt-get install -y libavahi-client-dev
- - sudo apt-get install -y libconfig-dev
+ - sudo apt-get install -y libavahi-client-dev libconfig-dev
- sudo apt-get install -y libssl-dev
addons:
@@ -19,3 +17,4 @@ addons:
packages:
- libasound2-dev
- libsoxr-dev
+ - libpopt-dev
From 340881cf61fdc45fd3c9c05284b60f069449e361 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 13:18:49 +0000
Subject: [PATCH 109/144] Update .travis.yml
---
.travis.yml | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 22d1bb44..7ab9905c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,10 +7,7 @@ branches:
- development
before_install:
- sudo apt-get -qq update
- - sudo apt-get install -y libdaemon-dev libpopt-dev
- - sudo apt-get install -y avahi-daemon
- - sudo apt-get install -y libavahi-client-dev libconfig-dev
- - sudo apt-get install -y libssl-dev
+ - sudo apt-get install -y libdaemon-dev libpopt-dev avahi-daemon libavahi-client-dev libconfig-dev
addons:
apt:
@@ -18,3 +15,4 @@ addons:
- libasound2-dev
- libsoxr-dev
- libpopt-dev
+ - libssl-dev
From 3cdc24779fe60f0613cf92618ad1e7c1231416bc Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 13:21:00 +0000
Subject: [PATCH 110/144] Update .travis.yml
---
.travis.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 7ab9905c..f165c9ce 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,7 +7,7 @@ branches:
- development
before_install:
- sudo apt-get -qq update
- - sudo apt-get install -y libdaemon-dev libpopt-dev avahi-daemon libavahi-client-dev libconfig-dev
+ - sudo apt-get install -y libdaemon-dev avahi-daemon libavahi-client-dev
addons:
apt:
@@ -16,3 +16,4 @@ addons:
- libsoxr-dev
- libpopt-dev
- libssl-dev
+ - libconfig-dev
From 0564f4aedbfdad33f72ec9a1112cbbd3edf62877 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 13:22:56 +0000
Subject: [PATCH 111/144] Update .travis.yml
---
.travis.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index f165c9ce..7e125a1c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,7 +7,7 @@ branches:
- development
before_install:
- sudo apt-get -qq update
- - sudo apt-get install -y libdaemon-dev avahi-daemon libavahi-client-dev
+ - sudo apt-get install -y avahi-daemon libavahi-client-dev
addons:
apt:
@@ -17,3 +17,4 @@ addons:
- libpopt-dev
- libssl-dev
- libconfig-dev
+ - libdaemon-dev
From 0c7aac7eaa89f1d883c330aba727ddf602df7e6d Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 13:27:06 +0000
Subject: [PATCH 112/144] Update .travis.yml
---
.travis.yml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 7e125a1c..f165c9ce 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,7 +7,7 @@ branches:
- development
before_install:
- sudo apt-get -qq update
- - sudo apt-get install -y avahi-daemon libavahi-client-dev
+ - sudo apt-get install -y libdaemon-dev avahi-daemon libavahi-client-dev
addons:
apt:
@@ -17,4 +17,3 @@ addons:
- libpopt-dev
- libssl-dev
- libconfig-dev
- - libdaemon-dev
From db8a3f5624b80c8d9dac7ce44f96ccb5c33f9752 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 13:27:58 +0000
Subject: [PATCH 113/144] Update .travis.yml
---
.travis.yml | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index f165c9ce..78be6cbd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,10 +1,15 @@
language: c
sudo: required
dist: trusty
-script: autoreconf -fi && ./configure --with-alsa --with-avahi --with-ssl=openssl --with-soxr --with-metadata --with-systemv && make
+script:
+ - autoreconf -fi
+ - ./configure --with-alsa --with-avahi --with-ssl=openssl --with-soxr --with-metadata --with-systemv
+ - make
+
branches:
only:
- development
+
before_install:
- sudo apt-get -qq update
- sudo apt-get install -y libdaemon-dev avahi-daemon libavahi-client-dev
From 1eb20ba8aa0737ec638de979a587d212de864c28 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 14:41:06 +0000
Subject: [PATCH 114/144] Update .travis.yml
---
.travis.yml | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/.travis.yml b/.travis.yml
index 78be6cbd..1fe5478d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,6 +5,13 @@ script:
- autoreconf -fi
- ./configure --with-alsa --with-avahi --with-ssl=openssl --with-soxr --with-metadata --with-systemv
- make
+ - ./configure --with-alsa --with-avahi --with-ssl=polarssl --with-soxr --with-metadata --with-systemd
+ - make
+ - ./configure --with-alsa --with-tinysvcmdns --with-ssl=polarssl --with-soxr --with-metadata --with-systemv --with-stdout --with-pipe
+ - make
+ - ./configure --with-alsa --with-tinysvcmdns --with-ssl=polarssl --with-soxr --with-metadata --with-systemd --with-stdout --with-pipe --without-pkgconfig
+ - make
+
branches:
only:
From 9274e3fcb85b86e70ab159dfaafa56177f59f606 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Mon, 18 Jan 2016 14:47:44 +0000
Subject: [PATCH 115/144] Update .travis.yml
---
.travis.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 1fe5478d..02417c51 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -19,7 +19,7 @@ branches:
before_install:
- sudo apt-get -qq update
- - sudo apt-get install -y libdaemon-dev avahi-daemon libavahi-client-dev
+ - sudo apt-get install -y libdaemon-dev avahi-daemon libavahi-client-dev
addons:
apt:
@@ -28,4 +28,5 @@ addons:
- libsoxr-dev
- libpopt-dev
- libssl-dev
+ - libpolarssl-dev
- libconfig-dev
From ca45b22ffc61dfadc58e98a0e311d8ea07e28ebe Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 19 Jan 2016 16:06:56 +0000
Subject: [PATCH 116/144] Update .travis.yml
---
.travis.yml | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 02417c51..932c4192 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,17 +1,14 @@
language: c
sudo: required
dist: trusty
+env:
+ matrix:
+ - CFG="--with-alsa --with-avahi --with-ssl=openssl --with-soxr --with-metadata --with-systemv"
+
script:
- autoreconf -fi
- - ./configure --with-alsa --with-avahi --with-ssl=openssl --with-soxr --with-metadata --with-systemv
+ - ./configure $CFG
- make
- - ./configure --with-alsa --with-avahi --with-ssl=polarssl --with-soxr --with-metadata --with-systemd
- - make
- - ./configure --with-alsa --with-tinysvcmdns --with-ssl=polarssl --with-soxr --with-metadata --with-systemv --with-stdout --with-pipe
- - make
- - ./configure --with-alsa --with-tinysvcmdns --with-ssl=polarssl --with-soxr --with-metadata --with-systemd --with-stdout --with-pipe --without-pkgconfig
- - make
-
branches:
only:
From 9094bceb80b2f634ff3fb9951b8816e9b3068c85 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 19 Jan 2016 16:25:28 +0000
Subject: [PATCH 117/144] Update .travis.yml
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 932c4192..c781de63 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,7 +3,7 @@ sudo: required
dist: trusty
env:
matrix:
- - CFG="--with-alsa --with-avahi --with-ssl=openssl --with-soxr --with-metadata --with-systemv"
+ - CFG=--with-alsa --with-avahi --with-ssl=openssl --with-soxr --with-metadata --with-systemv
script:
- autoreconf -fi
From 4234e5a12507abb77305e74ee5e0c2f1824d5a8f Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 19 Jan 2016 16:33:13 +0000
Subject: [PATCH 118/144] Update .travis.yml
---
.travis.yml | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index c781de63..e956618b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,7 +3,16 @@ sudo: required
dist: trusty
env:
matrix:
- - CFG=--with-alsa --with-avahi --with-ssl=openssl --with-soxr --with-metadata --with-systemv
+ - CFG="--with-alsa --with-avahi --with-ssl=openssl --with-soxr --with-metadata --with-systemv"
+ - CFG="--with-alsa --with-avahi --with-ssl=polarssl --with-soxr --with-metadata --with-systemv"
+ - CFG="--with-alsa --with-avahi --with-ssl=openssl --with-soxr --with-metadata --with-systemd"
+ - CFG="--with-alsa --with-avahi --with-ssl=polarssl --with-soxr --with-metadata --with-systemd"
+ - CFG="--with-alsa --with-avahi --with-ssl=polarssl --with-soxr --with-metadata --with-systemd"
+ - CFG="--with-alsa --with-avahi --with-ssl=openssl --with-soxr --with-metadata --with-systemd"
+ - CFG="--with-stdio --with-avahi --with-ssl=openssl --with-metadata --with-systemd"
+ - CFG="--with-stdio --with-avahi --with-ssl=polarssl --with-metadata --with-systemd"
+ - CFG="--with-pipe --with-avahi --with-ssl=openssl --with-metadata --with-systemd"
+ - CFG="--with-pipe --with-avahi --with-ssl=polarssl --with-metadata --with-systemd"
script:
- autoreconf -fi
From ef2a47897659a2d4fad54ad5880c258579e44fcc Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 19 Jan 2016 16:47:41 +0000
Subject: [PATCH 119/144] Update .travis.yml
---
.travis.yml | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/.travis.yml b/.travis.yml
index e956618b..c089df2d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,6 +13,20 @@ env:
- CFG="--with-stdio --with-avahi --with-ssl=polarssl --with-metadata --with-systemd"
- CFG="--with-pipe --with-avahi --with-ssl=openssl --with-metadata --with-systemd"
- CFG="--with-pipe --with-avahi --with-ssl=polarssl --with-metadata --with-systemd"
+ - CFG="--with-ao --with-avahi --with-ssl=openssl --with-metadata --with-systemd"
+ - CFG="--with-ao --with-avahi --with-ssl=polarssl --with-metadata --with-systemd"
+ - CFG="--with-alsa --with-tinysvcmdns --with-ssl=openssl --with-soxr --with-metadata --with-systemv"
+ - CFG="--with-alsa --with-tinysvcmdns --with-ssl=polarssl --with-soxr --with-metadata --with-systemv"
+ - CFG="--with-alsa --with-tinysvcmdns --with-ssl=openssl --with-soxr --with-metadata --with-systemd"
+ - CFG="--with-alsa --with-tinysvcmdns --with-ssl=polarssl --with-soxr --with-metadata --with-systemd"
+ - CFG="--with-alsa --with-tinysvcmdns --with-ssl=polarssl --with-soxr --with-metadata --with-systemd"
+ - CFG="--with-alsa --with-tinysvcmdns --with-ssl=openssl --with-soxr --with-metadata --with-systemd"
+ - CFG="--with-stdio --with-tinysvcmdns --with-ssl=openssl --with-metadata --with-systemd"
+ - CFG="--with-stdio --with-tinysvcmdns --with-ssl=polarssl --with-metadata --with-systemd"
+ - CFG="--with-pipe --with-tinysvcmdns --with-ssl=openssl --with-metadata --with-systemd"
+ - CFG="--with-pipe --with-tinysvcmdns --with-ssl=polarssl --with-metadata --with-systemd"
+ - CFG="--with-ao --with-tinysvcmdns --with-ssl=openssl --with-metadata --with-systemd"
+ - CFG="--with-ao --with-tinysvcmdns --with-ssl=polarssl --with-metadata --with-systemd"
script:
- autoreconf -fi
@@ -36,3 +50,4 @@ addons:
- libssl-dev
- libpolarssl-dev
- libconfig-dev
+ - xmltoman
From 628a5a2b5fc2177b853883e89d824ff8aaed84ee Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 19 Jan 2016 17:06:07 +0000
Subject: [PATCH 120/144] Update .travis.yml
---
.travis.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.travis.yml b/.travis.yml
index c089df2d..6f793c58 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -51,3 +51,4 @@ addons:
- libpolarssl-dev
- libconfig-dev
- xmltoman
+ - libao-dev
From 21fb39d22f8ccf88eaf271d71a6dd595316c6f17 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Fri, 22 Jan 2016 17:47:25 +0000
Subject: [PATCH 121/144] Begin to clean up the 'stop' signalling among the
threads -- try to remove as many globals as possible
---
player.c | 60 ++++++++++++++++++++++++++++++++++--------------
player.h | 4 ++--
rtp.c | 70 +++++++++++++++++++++++++++++---------------------------
rtp.h | 4 ++++
rtsp.c | 25 ++++++++++----------
5 files changed, 98 insertions(+), 65 deletions(-)
diff --git a/player.c b/player.c
index 0b24a67e..856b3142 100644
--- a/player.c
+++ b/player.c
@@ -81,7 +81,7 @@ static int sampling_rate, frame_size;
static aes_context dctx;
#endif
-static pthread_t player_thread;
+//static pthread_t player_thread = NULL;
static int please_stop;
static int encrypted; // Normally the audio is encrypted, but it may not be
@@ -893,6 +893,13 @@ typedef struct stats { // statistics for running averages
} stats_t;
static void *player_thread_func(void *arg) {
+ int threads_stop = 0;
+ // create and start the timing, control and audio receiver threads
+ pthread_t rtp_audio_thread, rtp_control_thread, rtp_timing_thread;
+ pthread_create(&rtp_audio_thread, NULL, &rtp_audio_receiver, (void *)&threads_stop);
+ pthread_create(&rtp_control_thread, NULL, &rtp_control_receiver, (void *)&threads_stop);
+ pthread_create(&rtp_timing_thread, NULL, &rtp_timing_receiver, (void *)&threads_stop);
+
session_corrections = 0;
play_segment_reference_frame = 0; // zero signals that we are not in a play segment
// check that there are enough buffers to accommodate the desired latency and the latency offset
@@ -1219,8 +1226,22 @@ static void *player_thread_func(void *arg) {
}
}
}
+ if (config.output->stop)
+ config.output->stop();
free(outbuf);
free(silence);
+ debug(1,"Shut down audio, control and timing threads");
+
+ pthread_kill(rtp_audio_thread, SIGUSR1);
+ pthread_kill(rtp_control_thread, SIGUSR1);
+ pthread_kill(rtp_timing_thread, SIGUSR1);
+ pthread_join(rtp_timing_thread, NULL);
+ debug(1,"timing thread joined");
+ pthread_join(rtp_audio_thread, NULL);
+ debug(1,"audio thread joined");
+ pthread_join(rtp_control_thread, NULL);
+ debug(1,"control thread joined");
+ debug(1,"Player thread exit");
return 0;
}
@@ -1389,7 +1410,9 @@ void player_flush(uint32_t timestamp) {
#endif
}
-int player_play(stream_cfg *stream) {
+int player_play(stream_cfg *stream, pthread_t *player_thread) {
+ //if (*player_thread!=NULL)
+ // die("Trying to create a second player thread for this RTSP session");
packet_count = 0;
encrypted = stream->encrypted;
if (config.buffer_start_fill > BUFFER_FRAMES)
@@ -1434,23 +1457,26 @@ int player_play(stream_cfg *stream) {
rc = pthread_attr_setstacksize(&tattr, size);
if (rc)
debug(1, "Error setting stack size for player_thread: %s", strerror(errno));
- pthread_create(&player_thread, &tattr, player_thread_func, NULL);
+ pthread_create(player_thread, &tattr, player_thread_func, NULL);
pthread_attr_destroy(&tattr);
return 0;
}
-void player_stop(void) {
- please_stop = 1;
- pthread_cond_signal(&flowcontrol); // tell it to give up
- pthread_join(player_thread, NULL);
-#ifdef CONFIG_METADATA
- send_ssnc_metadata('pend', NULL, 0, 1);
-#endif
- config.output->stop();
- command_stop();
- free_buffer();
- free_decoder();
- int rc = pthread_cond_destroy(&flowcontrol);
- if (rc)
- debug(1, "Error destroying condition variable.");
+void player_stop(pthread_t *player_thread) {
+ //if (*thread==NULL)
+ // debug(1,"Trying to stop a non-existent player thread");
+ // else {
+ please_stop = 1;
+ pthread_cond_signal(&flowcontrol); // tell it to give up
+ pthread_join(*player_thread, NULL);
+ #ifdef CONFIG_METADATA
+ send_ssnc_metadata('pend', NULL, 0, 1);
+ #endif
+ command_stop();
+ free_buffer();
+ free_decoder();
+ int rc = pthread_cond_destroy(&flowcontrol);
+ if (rc)
+ debug(1, "Error destroying condition variable.");
+ // }
}
diff --git a/player.h b/player.h
index b9cc900a..9012b0cb 100644
--- a/player.h
+++ b/player.h
@@ -14,8 +14,8 @@ typedef uint16_t seq_t;
// wrapped number between two seq_t.
int32_t seq_diff(seq_t a, seq_t b);
-int player_play(stream_cfg *cfg);
-void player_stop(void);
+int player_play(stream_cfg *cfg, pthread_t *thread);
+void player_stop(pthread_t *thread);
void player_volume(double f);
void player_flush(uint32_t timestamp);
diff --git a/rtp.c b/rtp.c
index baf95124..2870e612 100644
--- a/rtp.c
+++ b/rtp.c
@@ -61,7 +61,6 @@ typedef struct time_ping_record {
// only one RTP session can be active at a time.
static int running = 0;
-static int please_shutdown;
static char client_ip_string[INET6_ADDRSTRLEN]; // the ip string pointing to the client
static short client_ip_family; // AF_INET / AF_INET6
@@ -72,7 +71,7 @@ static SOCKADDR rtp_client_timing_socket; // a socket pointing to the timing po
static int audio_socket; // our local [server] audio socket
static int control_socket; // our local [server] control socket
static int timing_socket; // local timing socket
-static pthread_t rtp_audio_thread, rtp_control_thread, rtp_timing_thread;
+//static pthread_t rtp_audio_thread, rtp_control_thread, rtp_timing_thread;
static uint32_t reference_timestamp;
static uint64_t reference_timestamp_time;
@@ -96,16 +95,16 @@ static pthread_mutex_t reference_time_mutex = PTHREAD_MUTEX_INITIALIZER;
uint64_t static local_to_remote_time_difference; // used to switch between local and remote clocks
-static void *rtp_audio_receiver(void *arg) {
+void *rtp_audio_receiver(void *arg) {
// we inherit the signal mask (SIGUSR1)
+ int *stop = arg; // when set to 1, we should stop
+
int32_t last_seqno = -1;
uint8_t packet[2048], *pktp;
ssize_t nread;
- while (1) {
- if (please_shutdown)
- break;
+ while (*stop==0) {
nread = recv(audio_socket, packet, sizeof(packet), 0);
if (nread < 0)
break;
@@ -158,17 +157,18 @@ static void *rtp_audio_receiver(void *arg) {
return NULL;
}
-static void *rtp_control_receiver(void *arg) {
+void *rtp_control_receiver(void *arg) {
// we inherit the signal mask (SIGUSR1)
+
+ int *stop = arg; // when set to 1, we should stop
+
reference_timestamp = 0; // nothing valid received yet
uint8_t packet[2048], *pktp;
struct timespec tn;
uint64_t remote_time_of_sync, local_time_now, remote_time_now;
uint32_t sync_rtp_timestamp, rtp_timestamp_less_latency;
ssize_t nread;
- while (1) {
- if (please_shutdown)
- break;
+ while (*stop==0) {
nread = recv(control_socket, packet, sizeof(packet), 0);
local_time_now = get_absolute_time_in_fp();
// clock_gettime(CLOCK_MONOTONIC,&tn);
@@ -259,7 +259,8 @@ static void *rtp_control_receiver(void *arg) {
return NULL;
}
-static void *rtp_timing_sender(void *arg) {
+void *rtp_timing_sender(void *arg) {
+ int *stop = arg; // the parameter points to this request to stop thing
struct timing_request {
char leader;
char type;
@@ -280,9 +281,8 @@ static void *rtp_timing_sender(void *arg) {
time_ping_count = 0;
// we inherit the signal mask (SIGUSR1)
- while (1) {
- if (please_shutdown)
- break;
+ while (*stop==0) {
+ // debug(1,"Send a timing request");
if (!running)
die("rtp_timing_sender called without active stream!");
@@ -314,12 +314,16 @@ static void *rtp_timing_sender(void *arg) {
return NULL;
}
-static void *rtp_timing_receiver(void *arg) {
+void *rtp_timing_receiver(void *arg) {
// we inherit the signal mask (SIGUSR1)
+
+ int *stop = arg; // when set to 1, we should stop
+
uint8_t packet[2048], *pktp;
ssize_t nread;
+ int request_stop = 0;
pthread_t timer_requester;
- pthread_create(&timer_requester, NULL, &rtp_timing_sender, NULL);
+ pthread_create(&timer_requester, NULL, &rtp_timing_sender, (void *)&request_stop);
// struct timespec att;
uint64_t distant_receive_time, distant_transmit_time, arrival_time, return_time, transit_time,
processing_time;
@@ -331,9 +335,7 @@ static void *rtp_timing_receiver(void *arg) {
uint64_t first_local_to_remote_time_difference = 0;
uint64_t first_local_to_remote_time_difference_time;
uint64_t l2rtd = 0;
- while (1) {
- if (please_shutdown)
- break;
+ while (*stop==0) {
nread = recv(timing_socket, packet, sizeof(packet), 0);
arrival_time = get_absolute_time_in_fp();
// clock_gettime(CLOCK_MONOTONIC,&att);
@@ -497,7 +499,8 @@ static void *rtp_timing_receiver(void *arg) {
}
}
- debug(1, "Timing RTP thread interrupted. terminating.");
+ debug(1, "Timing thread interrupted. terminating.");
+ request_stop = 1;
void *retval;
pthread_kill(timer_requester, SIGUSR1);
pthread_join(timer_requester, &retval);
@@ -655,11 +658,10 @@ void rtp_setup(SOCKADDR *remote, int cport, int tport, uint32_t active_remote, i
debug(2, "listening for audio, control and timing on ports %d, %d, %d.", *lsport, *lcport,
*ltport);
- please_shutdown = 0;
reference_timestamp = 0;
- pthread_create(&rtp_audio_thread, NULL, &rtp_audio_receiver, NULL);
- pthread_create(&rtp_control_thread, NULL, &rtp_control_receiver, NULL);
- pthread_create(&rtp_timing_thread, NULL, &rtp_timing_receiver, NULL);
+ //pthread_create(&rtp_audio_thread, NULL, &rtp_audio_receiver, NULL);
+ //pthread_create(&rtp_control_thread, NULL, &rtp_control_receiver, NULL);
+ //pthread_create(&rtp_timing_thread, NULL, &rtp_timing_receiver, NULL);
running = 1;
request_sent = 0;
@@ -682,18 +684,18 @@ void clear_reference_timestamp(void) {
void rtp_shutdown(void) {
if (!running)
- die("rtp_shutdown called without active stream!");
+ debug(1,"rtp_shutdown called without active stream!");
debug(2, "shutting down RTP thread");
- please_shutdown = 1;
- void *retval;
- reference_timestamp = 0;
- pthread_kill(rtp_audio_thread, SIGUSR1);
- pthread_join(rtp_audio_thread, &retval);
- pthread_kill(rtp_control_thread, SIGUSR1);
- pthread_join(rtp_control_thread, &retval);
- pthread_kill(rtp_timing_thread, SIGUSR1);
- pthread_join(rtp_timing_thread, &retval);
+ clear_reference_timestamp();
+// debug(1,"Shut down audio, control and timing threads");
+// usleep(3000000); // hack
+// pthread_kill(rtp_audio_thread, SIGUSR1);
+// pthread_kill(rtp_control_thread, SIGUSR1);
+// pthread_kill(rtp_timing_thread, SIGUSR1);
+// pthread_join(rtp_audio_thread, &retval);
+// pthread_join(rtp_control_thread, &retval);
+// pthread_join(rtp_timing_thread, &retval);
running = 0;
}
diff --git a/rtp.h b/rtp.h
index 8045d2bb..cc0776da 100644
--- a/rtp.h
+++ b/rtp.h
@@ -5,6 +5,10 @@
#include "player.h"
+void *rtp_audio_receiver(void *arg);
+void *rtp_control_receiver(void *arg);
+void *rtp_timing_receiver(void *arg);
+
void rtp_setup(SOCKADDR *remote, int controlport, int timingport, uint32_t active_remote,
int *local_server_port, int *local_control_port, int *local_timing_port);
void rtp_shutdown(void);
diff --git a/rtsp.c b/rtsp.c
index ac173b31..7d6063f0 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -92,6 +92,7 @@ typedef struct {
SOCKADDR remote;
int running;
pthread_t thread;
+ pthread_t player_thread;
} rtsp_conn_info;
#ifdef CONFIG_METADATA
@@ -426,7 +427,7 @@ static int msg_handle_line(rtsp_message **pmsg, char *line) {
*p = 0;
p += 2;
msg_add_header(msg, line, p);
- debug(2, " %s: %s.", line, p);
+ // debug(2, " %s: %s.", line, p);
return -1;
} else {
char *cl = msg_get_header(msg, "Content-Length");
@@ -568,7 +569,7 @@ static void msg_write_response(int fd, rtsp_message *resp) {
p += n;
for (i = 0; i < resp->nheaders; i++) {
- debug(2, " %s: %s.", resp->name[i], resp->value[i]);
+// debug(3, " %s: %s.", resp->name[i], resp->value[i]);
n = snprintf(p, pktfree, "%s: %s\r\n", resp->name[i], resp->value[i]);
pktfree -= n;
p += n;
@@ -764,7 +765,7 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
strcat(hdr, q); // should unsplice the timing port entry
}
- player_play(&conn->stream);
+ player_play(&conn->stream,&conn->player_thread); // the tread better be null
char *resphdr = alloca(200);
*resphdr = 0;
@@ -1535,12 +1536,12 @@ static void *rtsp_conversation_thread_func(void *pconn) {
int method_selected = 0;
for (mh = method_handlers; mh->method; mh++) {
if (!strcmp(mh->method, req->method)) {
- //debug(1,"RTSP Packet received of type \"%s\":",mh->method),
- //msg_print_debug_headers(req);
+ // debug(1,"RTSP Packet received of type \"%s\":",mh->method),
+ // msg_print_debug_headers(req);
method_selected = 1;
mh->handler(conn, req, resp);
- //debug(1,"RTSP Response:");
- //msg_print_debug_headers(resp);
+ // debug(1,"RTSP Response:");
+ // msg_print_debug_headers(resp);
break;
}
}
@@ -1557,20 +1558,20 @@ static void *rtsp_conversation_thread_func(void *pconn) {
}
} while (reply != rtsp_read_request_response_shutdown_requested);
- debug(1, "closing RTSP connection.");
+ debug(1, "Now closing RTSP connection.");
if (conn->fd > 0)
close(conn->fd);
if (rtsp_playing()) {
+ player_stop(&conn->player_thread); // might be less noisy doing this first
rtp_shutdown();
- player_stop();
pthread_mutex_unlock(&play_lock);
- please_shutdown = 0;
pthread_mutex_unlock(&playing_mutex);
}
if (auth_nonce)
free(auth_nonce);
conn->running = 0;
- debug(2, "terminating RTSP thread.");
+ debug(2, "Now terminating RTSP conversation thread.");
+ please_shutdown = 0;
return NULL;
}
@@ -1699,7 +1700,7 @@ void rtsp_listen_loop(void) {
memset(conn, 0, sizeof(rtsp_conn_info));
socklen_t slen = sizeof(conn->remote);
- debug(1, "new RTSP connection.");
+ debug(1, "New RTSP connection on port %d",config.port);
conn->fd = accept(acceptfd, (struct sockaddr *)&conn->remote, &slen);
if (conn->fd < 0) {
perror("failed to accept connection");
From 9a9c9842fcc79a8868d4e4df40d01eb1617ebc8c Mon Sep 17 00:00:00 2001
From: Mke Brady
Date: Sat, 23 Jan 2016 17:50:36 +0000
Subject: [PATCH 122/144] Remove global signalling for stopping threads
---
player.c | 2 +-
rtsp.c | 46 +++++++++++++++++++++++++++++++---------------
2 files changed, 32 insertions(+), 16 deletions(-)
diff --git a/player.c b/player.c
index 856b3142..d81c045e 100644
--- a/player.c
+++ b/player.c
@@ -1231,7 +1231,7 @@ static void *player_thread_func(void *arg) {
free(outbuf);
free(silence);
debug(1,"Shut down audio, control and timing threads");
-
+ // usleep(1000000);
pthread_kill(rtp_audio_thread, SIGUSR1);
pthread_kill(rtp_control_thread, SIGUSR1);
pthread_kill(rtp_timing_thread, SIGUSR1);
diff --git a/rtsp.c b/rtsp.c
index 7d6063f0..0a3d71cc 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -83,13 +83,14 @@ static pthread_mutex_t reference_counter_lock = PTHREAD_MUTEX_INITIALIZER;
// only one thread is allowed to use the player at once.
// it monitors the request variable (at least when interrupted)
static pthread_mutex_t playing_mutex = PTHREAD_MUTEX_INITIALIZER;
-static int please_shutdown = 0;
+//static int please_shutdown = 0;
static pthread_t playing_thread = 0;
typedef struct {
int fd;
stream_cfg stream;
SOCKADDR remote;
+ int stop;
int running;
pthread_t thread;
pthread_t player_thread;
@@ -134,6 +135,8 @@ typedef struct {
rtsp_message *carrier;
} metadata_package;
+void ask_other_rtsp_conversation_threads_to_stop(pthread_t except_this_thread);
+
void pc_queue_init(pc_queue *the_queue, char *items, size_t item_size, uint32_t number_of_items) {
the_queue->item_size = item_size;
the_queue->items = items;
@@ -240,8 +243,7 @@ static inline int rtsp_playing(void) {
}
void rtsp_request_shutdown_stream(void) {
- please_shutdown = 1;
- pthread_kill(playing_thread, SIGUSR1);
+ ask_other_rtsp_conversation_threads_to_stop(0); // i.e. ask all playing threads to stop
}
static void rtsp_take_player(void) {
@@ -249,10 +251,8 @@ static void rtsp_take_player(void) {
return;
if (pthread_mutex_trylock(&playing_mutex)) {
- debug(1, "shutting down playing thread.");
- // XXX minor race condition between please_shutdown and signal delivery
- please_shutdown = 1;
- pthread_kill(playing_thread, SIGUSR1);
+ debug(1, "asking all other playing threads to stop.");
+ ask_other_rtsp_conversation_threads_to_stop(pthread_self()); // all threads apart from self
pthread_mutex_lock(&playing_mutex);
}
playing_thread = pthread_self(); // make us the currently-playing thread (why?)
@@ -290,6 +290,21 @@ static void cleanup_threads(void) {
}
}
+// ask all rtsp_conversation threads to stop -- there should be at most one, but ya never know.
+
+void ask_other_rtsp_conversation_threads_to_stop(pthread_t except_this_thread) {
+ int i;
+ debug(2, "asking playing threads to stop");
+ for (i = 0; i < nconns;i++) {
+ if (((except_this_thread==0) || (pthread_equal(conns[i]->thread,except_this_thread)==0)) && (conns[i]->running != 0)) {
+ conns[i]->stop = 1;
+ pthread_kill(conns[i]->thread,SIGUSR1);
+ }
+ }
+}
+
+
+
// park a null at the line ending, and return the next line pointer
// accept \r, \n, or \r\n
static char *nextline(char *in, int inbuf) {
@@ -443,7 +458,7 @@ fail:
return 0;
}
-static enum rtsp_read_request_response rtsp_read_request(int fd, rtsp_message **the_packet) {
+static enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, rtsp_message **the_packet) {
enum rtsp_read_request_response reply = rtsp_read_request_response_ok;
ssize_t buflen = 512;
char *buf = malloc(buflen + 1);
@@ -455,12 +470,12 @@ static enum rtsp_read_request_response rtsp_read_request(int fd, rtsp_message **
int msg_size = -1;
while (msg_size < 0) {
- if (please_shutdown) {
+ if (conn->stop!=0) {
debug(1, "RTSP shutdown requested.");
reply = rtsp_read_request_response_shutdown_requested;
goto shutdown;
}
- nread = read(fd, buf + inbuf, buflen - inbuf);
+ nread = read(conn->fd, buf + inbuf, buflen - inbuf);
if (!nread) {
debug(1, "RTSP connection closed.");
reply = rtsp_read_request_response_shutdown_requested;
@@ -525,7 +540,7 @@ static enum rtsp_read_request_response rtsp_read_request(int fd, rtsp_message **
ssize_t read_chunk = msg_size - inbuf;
if (read_chunk > max_read_chunk)
read_chunk = max_read_chunk;
- nread = read(fd, buf + inbuf, read_chunk);
+ nread = read(conn->fd, buf + inbuf, read_chunk);
if (!nread) {
reply = rtsp_read_request_response_error;
goto shutdown;
@@ -627,7 +642,7 @@ static void handle_teardown(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
return;
resp->respcode = 200;
msg_add_header(resp, "Connection", "close");
- please_shutdown = 1;
+ conn->stop = 1;
}
static void handle_flush(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
@@ -765,7 +780,7 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
strcat(hdr, q); // should unsplice the timing port entry
}
- player_play(&conn->stream,&conn->player_thread); // the tread better be null
+ player_play(&conn->stream,&conn->player_thread); // the thread better be 0
char *resphdr = alloca(200);
*resphdr = 0;
@@ -1518,7 +1533,7 @@ static void *rtsp_conversation_thread_func(void *pconn) {
enum rtsp_read_request_response reply;
do {
- reply = rtsp_read_request(conn->fd, &req);
+ reply = rtsp_read_request(conn, &req);
if (reply == rtsp_read_request_response_ok) {
resp = msg_init();
resp->respcode = 400;
@@ -1571,7 +1586,7 @@ static void *rtsp_conversation_thread_func(void *pconn) {
free(auth_nonce);
conn->running = 0;
debug(2, "Now terminating RTSP conversation thread.");
- please_shutdown = 0;
+// please_shutdown = 0;
return NULL;
}
@@ -1712,6 +1727,7 @@ void rtsp_listen_loop(void) {
die("Failed to create RTSP receiver thread!");
conn->thread = rtsp_conversation_thread;
+ conn -> stop = 0;
conn->running = 1;
track_thread(conn);
}
From 9f7a3ff4e1fc77bd0ea4d6cc998c8355f4980a20 Mon Sep 17 00:00:00 2001
From: Mke Brady
Date: Sat, 23 Jan 2016 17:57:43 +0000
Subject: [PATCH 123/144] Ask for the correct number of packets to be resent --
it was asking for one too many in some situations.
---
player.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/player.c b/player.c
index d81c045e..2309eaa7 100644
--- a/player.c
+++ b/player.c
@@ -308,7 +308,7 @@ void player_put_packet(seq_t seqno, uint32_t timestamp, uint8_t *data, int len)
if ((flush_rtp_timestamp != 0) &&
((timestamp == flush_rtp_timestamp) || seq32_order(timestamp, flush_rtp_timestamp))) {
- debug(2, "Dropping flushed packet in player_put_packet, seqno %u, timestamp %u, flushing to "
+ debug(3, "Dropping flushed packet in player_put_packet, seqno %u, timestamp %u, flushing to "
"timestamp: %u.",
seqno, timestamp, flush_rtp_timestamp);
} else {
@@ -332,7 +332,7 @@ void player_put_packet(seq_t seqno, uint32_t timestamp, uint8_t *data, int len)
// if (ORDINATE(seqno)>(BUFFER_FRAMES*7)/8)
// debug(1,"An interval of %u frames has opened, with ab_read: %u, ab_write: %u and seqno:
// %u.",seq_diff(ab_read,seqno),ab_read,ab_write,seqno);
- int32_t gap = seq_diff(ab_write, PREDECESSOR(seqno)) + 1;
+ int32_t gap = seq_diff(ab_write, (seqno);
if (gap <= 0)
debug(1, "Unexpected gap size: %d.", gap);
int i;
@@ -1398,7 +1398,7 @@ void player_volume(double airplay_volume) {
}
void player_flush(uint32_t timestamp) {
- // debug(1,"Flush requested up to %u. It seems as if 0 is special.",timestamp);
+ debug(3,"Flush requested up to %u. It seems as if 0 is special.",timestamp);
pthread_mutex_lock(&flush_mutex);
flush_requested = 1;
// if (timestamp!=0)
From 28198c69841dfef0ef340df3e13f0d68fde3631e Mon Sep 17 00:00:00 2001
From: Mke Brady
Date: Sat, 23 Jan 2016 17:58:03 +0000
Subject: [PATCH 124/144] Quieten some debug messages.
---
rtp.c | 2 +-
rtsp.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/rtp.c b/rtp.c
index 2870e612..6a1e35ff 100644
--- a/rtp.c
+++ b/rtp.c
@@ -702,7 +702,7 @@ void rtp_shutdown(void) {
void rtp_request_resend(seq_t first, uint32_t count) {
if (running) {
if (!request_sent) {
- debug(2, "requesting resend on %d packets starting at %u.", count, first);
+ debug(2, "requesting resend of %d packets starting at %u.", count, first);
request_sent = 1;
}
diff --git a/rtsp.c b/rtsp.c
index 0a3d71cc..fe53e658 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -442,7 +442,7 @@ static int msg_handle_line(rtsp_message **pmsg, char *line) {
*p = 0;
p += 2;
msg_add_header(msg, line, p);
- // debug(2, " %s: %s.", line, p);
+ debug(3, " %s: %s.", line, p);
return -1;
} else {
char *cl = msg_get_header(msg, "Content-Length");
From 09d9905328c208fbc1d6a604afe199d570360106 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sat, 23 Jan 2016 18:00:45 +0000
Subject: [PATCH 125/144] Fix silly error
---
player.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/player.c b/player.c
index 2309eaa7..17b5477a 100644
--- a/player.c
+++ b/player.c
@@ -332,7 +332,7 @@ void player_put_packet(seq_t seqno, uint32_t timestamp, uint8_t *data, int len)
// if (ORDINATE(seqno)>(BUFFER_FRAMES*7)/8)
// debug(1,"An interval of %u frames has opened, with ab_read: %u, ab_write: %u and seqno:
// %u.",seq_diff(ab_read,seqno),ab_read,ab_write,seqno);
- int32_t gap = seq_diff(ab_write, (seqno);
+ int32_t gap = seq_diff(ab_write, seqno);
if (gap <= 0)
debug(1, "Unexpected gap size: %d.", gap);
int i;
From 51ae68e0954d84bf9a15834c802328a9898b187a Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sat, 23 Jan 2016 19:02:49 +0000
Subject: [PATCH 126/144] Experiment with waiting a little while before sending
resend requests.
---
player.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/player.c b/player.c
index 17b5477a..c35c6b99 100644
--- a/player.c
+++ b/player.c
@@ -344,8 +344,8 @@ void player_put_packet(seq_t seqno, uint32_t timestamp, uint8_t *data, int len)
}
// debug(1,"N %d s %u.",seq_diff(ab_write,PREDECESSOR(seqno))+1,ab_write);
abuf = audio_buffer + BUFIDX(seqno);
- rtp_request_resend(ab_write, gap);
- resend_requests++;
+// rtp_request_resend(ab_write, gap);
+// resend_requests++;
ab_write = SUCCESSOR(seqno);
} else if (seq_order(ab_read, seqno)) { // late but not yet played
late_packets++;
From db52a7b1272240856ce3d5216c044877d9695876 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sat, 23 Jan 2016 20:07:49 +0000
Subject: [PATCH 127/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 28a204a9..aa781f98 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -15,7 +15,7 @@ Version 2.7.6 -- Development Version
**Enhancements**
* Add note about installing to Mac OS X. Thanks to [Serg Podtynnyi](https://github.com/shtirlic).
-* Add automatic rebuild of manapage and html doc when xmltoman and friends are available. Thanks to [Chris Boot](https://github.com/bootc).
+* Add automatic rebuild of manpage and html documentation when `xmltoman` and friends are available. Thanks to [Chris Boot](https://github.com/bootc).
* Favour the use of "public" IPv6 addresses as source addresses when connecting to a distant IPv6 port.
Version 2.7.5 -- Development Version
From 45061e993ed5014cdf8b3d415714667e8449769a Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sun, 24 Jan 2016 13:36:16 +0000
Subject: [PATCH 128/144] Turn on extra debugging
---
rtp.c | 12 ++++++------
rtsp.c | 10 +++++++---
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/rtp.c b/rtp.c
index 6a1e35ff..bc40948d 100644
--- a/rtp.c
+++ b/rtp.c
@@ -701,10 +701,10 @@ void rtp_shutdown(void) {
void rtp_request_resend(seq_t first, uint32_t count) {
if (running) {
- if (!request_sent) {
+ //if (!request_sent) {
debug(2, "requesting resend of %d packets starting at %u.", count, first);
- request_sent = 1;
- }
+ // request_sent = 1;
+ //}
char req[8]; // *not* a standard RTCP NACK
req[0] = 0x80;
@@ -723,10 +723,10 @@ void rtp_request_resend(seq_t first, uint32_t count) {
perror("Error sendto-ing to audio socket");
}
} else {
- if (!request_sent) {
+ //if (!request_sent) {
debug(2, "rtp_request_resend called without active stream!");
- request_sent = 1;
- }
+ // request_sent = 1;
+ //}
}
}
diff --git a/rtsp.c b/rtsp.c
index fe53e658..6e8f1df7 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -243,6 +243,7 @@ static inline int rtsp_playing(void) {
}
void rtsp_request_shutdown_stream(void) {
+ debug(1,"Request to shut down all rtsp conversation threads");
ask_other_rtsp_conversation_threads_to_stop(0); // i.e. ask all playing threads to stop
}
@@ -251,7 +252,7 @@ static void rtsp_take_player(void) {
return;
if (pthread_mutex_trylock(&playing_mutex)) {
- debug(1, "asking all other playing threads to stop.");
+ debug(1, "Request to all other playing threads to stop.");
ask_other_rtsp_conversation_threads_to_stop(pthread_self()); // all threads apart from self
pthread_mutex_lock(&playing_mutex);
}
@@ -639,7 +640,7 @@ static void handle_options(rtsp_conn_info *conn, rtsp_message *req, rtsp_message
static void handle_teardown(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
if (!rtsp_playing())
- return;
+ debug(1,"This RTSP conversation thread doesn't think it's playing, but it's sending a response to teardown anyway");
resp->respcode = 200;
msg_add_header(resp, "Connection", "close");
conn->stop = 1;
@@ -647,7 +648,7 @@ static void handle_teardown(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
static void handle_flush(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
if (!rtsp_playing())
- return;
+ debug(1,"This RTSP conversation thread doesn't think it's playing, but it's sending a response to flush anyway");
char *p;
uint32_t rtptime = 0;
char *hdr = msg_get_header(req, "RTP-Info");
@@ -1581,6 +1582,8 @@ static void *rtsp_conversation_thread_func(void *pconn) {
rtp_shutdown();
pthread_mutex_unlock(&play_lock);
pthread_mutex_unlock(&playing_mutex);
+ } else {
+ debug(1,"This RTSP conversation thread doesn't think it's playing for a close RTSP connection.");
}
if (auth_nonce)
free(auth_nonce);
@@ -1654,6 +1657,7 @@ void rtsp_listen_loop(void) {
// one of the address families will fail on some systems that
// report its availability. do not complain.
+
if (ret) {
debug(1, "Failed to bind to address %s.", format_address(p->ai_addr));
continue;
From 8d75fdbb3cfee11da535c38ed9ad27ceca8accb0 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sun, 24 Jan 2016 22:04:57 +0000
Subject: [PATCH 129/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index aa781f98..af15fb10 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,10 +1,12 @@
-Head
+Version 2.7.7
----
**Enhancements**
* Add note about the Arch Linux Community repository package `shairport-sync`. Thanks to [Anatol Pomozov](https://github.com/anatol).
**Bug Fixes**
+* Improve Shairport Sync's behavious when it's asked to stop a play session and immediately start another. The signalling system used to stop threads was sometimes stopping threads belonging to the new session. This affected iOS 9.2 users going to the next track -- sometimes the player be unavailable for an instant and disconnect the session. The problem is must less now, but still happens occasionally.
* Remove code favouring the use of "public" IPv6 addresses as source addresses when connecting to a distant IPv6 port – Neither OpenWrt nor FreeBSD can use it at present. Also, it's not clear if any problems are being caused by not favouring public IPv6 addresses.
+* Shairport Sync doesn't ask for packets to be resent quite so quickly -- it waits aboout half a second now.
Version 2.7.6 -- Development Version
----
From 9337effe3f3e6a3e6d544702d3dc58e3ce5fc6d0 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sun, 24 Jan 2016 22:07:15 +0000
Subject: [PATCH 130/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index af15fb10..cdaee22f 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -2,11 +2,11 @@ Version 2.7.7
----
**Enhancements**
* Add note about the Arch Linux Community repository package `shairport-sync`. Thanks to [Anatol Pomozov](https://github.com/anatol).
+* Shairport Sync doesn't ask for packets to be resent quite so quickly -- it waits about half a second now before asking for missing packets to be resent.
**Bug Fixes**
-* Improve Shairport Sync's behavious when it's asked to stop a play session and immediately start another. The signalling system used to stop threads was sometimes stopping threads belonging to the new session. This affected iOS 9.2 users going to the next track -- sometimes the player be unavailable for an instant and disconnect the session. The problem is must less now, but still happens occasionally.
-* Remove code favouring the use of "public" IPv6 addresses as source addresses when connecting to a distant IPv6 port – Neither OpenWrt nor FreeBSD can use it at present. Also, it's not clear if any problems are being caused by not favouring public IPv6 addresses.
-* Shairport Sync doesn't ask for packets to be resent quite so quickly -- it waits aboout half a second now.
+* Improved Shairport Sync's behaviour when it's asked to stop a play session and immediately start another. The signalling system used to stop threads was sometimes stopping threads belonging to the new session. This affected iOS 9.2 users going to the next track -- sometimes the player would become unavailable for an instant and disconnect the session. Th problem still happens occasionally.
+* Removed code favouring the use of "public" IPv6 addresses as source addresses when connecting to a distant IPv6 port – Neither OpenWrt nor FreeBSD can use it at present. Also, it's not clear if any problems are being caused by not favouring public IPv6 addresses.
Version 2.7.6 -- Development Version
----
From e99015b3816c558821b878bce2100255a2a0877b Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sun, 24 Jan 2016 22:07:50 +0000
Subject: [PATCH 131/144] Update configure.ac
---
configure.ac | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index d9f5f037..f84362e9 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], [2.7.4], [mikebrady@eircom.net])
+AC_INIT([shairport-sync], [2.7.7], [mikebrady@eircom.net])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([shairport.c])
AC_CONFIG_HEADERS([config.h])
From 62206e8a7ebf2d3bdb8b2b3d3f9bccf7da9c5131 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sun, 24 Jan 2016 22:08:30 +0000
Subject: [PATCH 132/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index cdaee22f..6935d7a4 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,4 +1,4 @@
-Version 2.7.7
+Version 2.7.7 -- Development Version
----
**Enhancements**
* Add note about the Arch Linux Community repository package `shairport-sync`. Thanks to [Anatol Pomozov](https://github.com/anatol).
From ae0c9745125f8d80ead1b21b3586533786af8064 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 26 Jan 2016 13:22:10 +0000
Subject: [PATCH 133/144] Release and reacquire the hardware mixer in tandem
with the output device. This ensures the mixer volume setting is correctly
reset by the mixer on resumption after a pause, and not ignored as before.
---
audio_alsa.c | 309 +++++++++++++++++++++++++++++++--------------------
1 file changed, 190 insertions(+), 119 deletions(-)
diff --git a/audio_alsa.c b/audio_alsa.c
index b725d78a..26f50d9a 100644
--- a/audio_alsa.c
+++ b/audio_alsa.c
@@ -59,7 +59,7 @@ audio_output audio_alsa = {
.flush = &flush,
.delay = &delay,
.play = &play,
- .mute = NULL, // to be set later on...
+ .mute = NULL, // to be set later on...
.volume = NULL, // to be set later on...
.parameters = NULL // to be set later on...
};
@@ -93,36 +93,64 @@ static void help(void) {
" *) default option\n");
}
+int open_mixer() {
+ debug(3, "Open Mixer");
+ int ret = 0;
+ snd_mixer_selem_id_alloca(&alsa_mix_sid);
+ snd_mixer_selem_id_set_index(alsa_mix_sid, alsa_mix_index);
+ snd_mixer_selem_id_set_name(alsa_mix_sid, alsa_mix_ctrl);
+
+ if ((snd_mixer_open(&alsa_mix_handle, 0)) < 0)
+ die("Failed to open mixer");
+ debug(3, "Mixer device name is \"%s\".", alsa_mix_dev);
+ if ((snd_mixer_attach(alsa_mix_handle, alsa_mix_dev)) < 0)
+ die("Failed to attach mixer");
+ if ((snd_mixer_selem_register(alsa_mix_handle, NULL, NULL)) < 0)
+ die("Failed to register mixer element");
+
+ ret = snd_mixer_load(alsa_mix_handle);
+ if (ret < 0)
+ die("Failed to load mixer element");
+ debug(3, "Mixer Control name is \"%s\".", alsa_mix_ctrl);
+ alsa_mix_elem = snd_mixer_find_selem(alsa_mix_handle, alsa_mix_sid);
+ if (!alsa_mix_elem)
+ die("Failed to find mixer element");
+}
+
static int init(int argc, char **argv) {
- // debug(1,"audio_alsa init called.");
- const char *str;
+ // debug(1,"audio_alsa init called.");
+ const char *str;
int value;
int hardware_mixer = 0;
- config.audio_backend_latency_offset = 0; // this is the default for ALSA
- config.audio_backend_buffer_desired_length = 6615; // default for alsa with a software mixer
-
-
+ config.audio_backend_latency_offset = 0; // this is the default for ALSA
+ config.audio_backend_buffer_desired_length =
+ 6615; // default for alsa with a software mixer
- // get settings from settings file first, allow them to be overridden by command line options
+ // get settings from settings file first, allow them to be overridden by
+ // command line options
if (config.cfg != NULL) {
/* Get the desired buffer size setting. */
- if (config_lookup_int(config.cfg, "alsa.audio_backend_buffer_desired_length", &value)) {
+ if (config_lookup_int(config.cfg,
+ "alsa.audio_backend_buffer_desired_length", &value)) {
if ((value < 0) || (value > 66150))
- die("Invalid alsa audio backend buffer desired length \"%d\". It should be between 0 and "
+ die("Invalid alsa audio backend buffer desired length \"%d\". It "
+ "should be between 0 and "
"66150, default is 6615",
value);
else {
config.audio_backend_buffer_desired_length = value;
}
}
-
+
/* Get the latency offset. */
- if (config_lookup_int(config.cfg, "alsa.audio_backend_latency_offset", &value)) {
+ if (config_lookup_int(config.cfg, "alsa.audio_backend_latency_offset",
+ &value)) {
if ((value < -66150) || (value > 66150))
- die("Invalid alsa audio backend buffer latency offset \"%d\". It should be between -66150 and +66150, default is 0",
+ die("Invalid alsa audio backend buffer latency offset \"%d\". It "
+ "should be between -66150 and +66150, default is 0",
value);
else
config.audio_backend_latency_offset = value;
@@ -133,13 +161,13 @@ static int init(int argc, char **argv) {
alsa_out_dev = (char *)str;
}
-
/* Get the Mixer Type setting. */
if (config_lookup_string(config.cfg, "alsa.mixer_type", &str)) {
- inform("The alsa mixer_type setting is deprecated and has been ignored. FYI, using the \"mixer_control_name\" setting automatically chooses a hardware mixer.");
+ inform("The alsa mixer_type setting is deprecated and has been ignored. "
+ "FYI, using the \"mixer_control_name\" setting automatically "
+ "chooses a hardware mixer.");
}
-
/* Get the Mixer Device Name. */
if (config_lookup_string(config.cfg, "alsa.mixer_device", &str)) {
@@ -165,7 +193,9 @@ static int init(int argc, char **argv) {
break;
case 't':
- inform("The alsa backend -t option is deprecated and has been ignored. FYI, using the -c option automatically chooses a hardware mixer.");
+ inform("The alsa backend -t option is deprecated and has been ignored. "
+ "FYI, using the -c option automatically chooses a hardware "
+ "mixer.");
break;
case 'm':
@@ -186,8 +216,8 @@ static int init(int argc, char **argv) {
if (optind < argc)
die("Invalid audio argument: %s", argv[optind]);
-
- debug(1,"Output device name is \"%s\".",alsa_out_dev);
+
+ debug(1, "Output device name is \"%s\".", alsa_out_dev);
if (!hardware_mixer)
return 0;
@@ -195,67 +225,58 @@ static int init(int argc, char **argv) {
if (alsa_mix_dev == NULL)
alsa_mix_dev = alsa_out_dev;
- int ret = 0;
-
- snd_mixer_selem_id_alloca(&alsa_mix_sid);
- snd_mixer_selem_id_set_index(alsa_mix_sid, alsa_mix_index);
- snd_mixer_selem_id_set_name(alsa_mix_sid, alsa_mix_ctrl);
+ // Open mixer
- if ((snd_mixer_open(&alsa_mix_handle, 0)) < 0)
- die("Failed to open mixer");
- debug(1,"Mixer device name is \"%s\".",alsa_mix_dev);
- if ((snd_mixer_attach(alsa_mix_handle, alsa_mix_dev)) < 0)
- die("Failed to attach mixer");
- if ((snd_mixer_selem_register(alsa_mix_handle, NULL, NULL)) < 0)
- die("Failed to register mixer element");
+ open_mixer();
- ret = snd_mixer_load(alsa_mix_handle);
- if (ret < 0)
- die("Failed to load mixer element");
-
- debug(1,"Mixer Control name is \"%s\".",alsa_mix_ctrl);
-
- alsa_mix_elem = snd_mixer_find_selem(alsa_mix_handle, alsa_mix_sid);
- if (!alsa_mix_elem)
- die("Failed to find mixer element");
-
-
- if (snd_mixer_selem_get_playback_volume_range(alsa_mix_elem, &alsa_mix_minv, &alsa_mix_maxv) < 0)
+ if (snd_mixer_selem_get_playback_volume_range(alsa_mix_elem, &alsa_mix_minv,
+ &alsa_mix_maxv) < 0)
debug(1, "Can't read mixer's [linear] min and max volumes.");
else {
- if (snd_mixer_selem_get_playback_dB_range (alsa_mix_elem, &alsa_mix_mindb, &alsa_mix_maxdb) == 0) {
+ if (snd_mixer_selem_get_playback_dB_range(alsa_mix_elem, &alsa_mix_mindb,
+ &alsa_mix_maxdb) == 0) {
- audio_alsa.volume = &volume; // insert the volume function now we know it can do dB stuff
+ audio_alsa.volume =
+ &volume; // insert the volume function now we know it can do dB stuff
audio_alsa.parameters = ¶meters; // likewise the parameters stuff
if (alsa_mix_mindb == SND_CTL_TLV_DB_GAIN_MUTE) {
// Raspberry Pi does this
debug(1, "Lowest dB value is a mute.");
- if (snd_mixer_selem_ask_playback_vol_dB(alsa_mix_elem, alsa_mix_minv + 1,
- &alsa_mix_mindb) == 0)
+ if (snd_mixer_selem_ask_playback_vol_dB(
+ alsa_mix_elem, alsa_mix_minv + 1, &alsa_mix_mindb) == 0)
debug(1, "Can't get dB value corresponding to a \"volume\" of 1.");
}
- debug(1, "Hardware mixer has dB volume from %f to %f.", (1.0 * alsa_mix_mindb) / 100.0,
- (1.0 * alsa_mix_maxdb) / 100.0);
+ debug(1, "Hardware mixer has dB volume from %f to %f.",
+ (1.0 * alsa_mix_mindb) / 100.0, (1.0 * alsa_mix_maxdb) / 100.0);
} else {
// use the linear scale and do the db conversion ourselves
- debug(1, "note: the hardware mixer specified -- \"%s\" -- does not have a dB volume scale, so it can't be used.",alsa_mix_ctrl);
+ debug(1, "note: the hardware mixer specified -- \"%s\" -- does not have "
+ "a dB volume scale, so it can't be used.",
+ alsa_mix_ctrl);
/*
- debug(1, "Min and max volumes are %d and %d.",alsa_mix_minv,alsa_mix_maxv);
+ debug(1, "Min and max volumes are %d and
+ %d.",alsa_mix_minv,alsa_mix_maxv);
alsa_mix_maxdb = 0;
if ((alsa_mix_maxv!=0) && (alsa_mix_minv!=0))
- alsa_mix_mindb = -20*100*(log10(alsa_mix_maxv*1.0)-log10(alsa_mix_minv*1.0));
+ alsa_mix_mindb =
+ -20*100*(log10(alsa_mix_maxv*1.0)-log10(alsa_mix_minv*1.0));
else if (alsa_mix_maxv!=0)
alsa_mix_mindb = -20*100*log10(alsa_mix_maxv*1.0);
audio_alsa.volume = &linear_volume; // insert the linear volume function
audio_alsa.parameters = ¶meters; // likewise the parameters stuff
- debug(1,"Max and min dB calculated are %d and %d.",alsa_mix_maxdb,alsa_mix_mindb);
+ debug(1,"Max and min dB calculated are %d and
+ %d.",alsa_mix_maxdb,alsa_mix_mindb);
*/
- }
+ }
}
if (snd_mixer_selem_has_playback_switch(alsa_mix_elem)) {
- audio_alsa.mute = &mute; // insert the mute function now we know it can do muting stuff
+ audio_alsa.mute =
+ &mute; // insert the mute function now we know it can do muting stuff
debug(1, "Has mute ability.");
}
+
+ snd_mixer_close(alsa_mix_handle);
+ alsa_mix_handle = NULL;
return 0;
}
@@ -267,80 +288,110 @@ static void deinit(void) {
}
int open_alsa_device(void) {
- const snd_pcm_uframes_t minimal_buffer_headroom = 352*2; // we accept this much headroom in the hardware buffer, but we'll accept less
- const snd_pcm_uframes_t requested_buffer_headroom = minimal_buffer_headroom+2048; // we ask for this much headroom in the hardware buffer, but we'll accept less
+ const snd_pcm_uframes_t minimal_buffer_headroom =
+ 352 * 2; // we accept this much headroom in the hardware buffer, but we'll
+ // accept less
+ const snd_pcm_uframes_t requested_buffer_headroom =
+ minimal_buffer_headroom + 2048; // we ask for this much headroom in the
+ // hardware buffer, but we'll accept less
int ret, dir = 0;
unsigned int my_sample_rate = desired_sample_rate;
- //snd_pcm_uframes_t frames = 441 * 10;
+ // snd_pcm_uframes_t frames = 441 * 10;
snd_pcm_uframes_t buffer_size, actual_buffer_length;
-
+
ret = snd_pcm_open(&alsa_handle, alsa_out_dev, SND_PCM_STREAM_PLAYBACK, 0);
if (ret < 0)
return (ret);
- // die("Alsa initialization failed: unable to open pcm device: %s.", snd_strerror(ret));
+ // die("Alsa initialization failed: unable to open pcm device: %s.",
+ // snd_strerror(ret));
snd_pcm_hw_params_alloca(&alsa_params);
ret = snd_pcm_hw_params_any(alsa_handle, alsa_params);
if (ret < 0) {
- die("audio_alsa: Broken configuration for device \"%s\": no configurations available", alsa_out_dev);
+ die("audio_alsa: Broken configuration for device \"%s\": no configurations "
+ "available",
+ alsa_out_dev);
}
-
- ret = snd_pcm_hw_params_set_access(alsa_handle, alsa_params, SND_PCM_ACCESS_RW_INTERLEAVED);
+
+ ret = snd_pcm_hw_params_set_access(alsa_handle, alsa_params,
+ SND_PCM_ACCESS_RW_INTERLEAVED);
if (ret < 0) {
- die("audio_alsa: Access type not available for device \"%s\": %s", alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Access type not available for device \"%s\": %s",
+ alsa_out_dev, snd_strerror(ret));
}
-
- ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, SND_PCM_FORMAT_S16);
+
+ ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params,
+ SND_PCM_FORMAT_S16);
if (ret < 0) {
- die("audio_alsa: Sample format not available for device \"%s\": %s", alsa_out_dev, snd_strerror(ret));
- }
-
+ die("audio_alsa: Sample format not available for device \"%s\": %s",
+ alsa_out_dev, snd_strerror(ret));
+ }
+
ret = snd_pcm_hw_params_set_channels(alsa_handle, alsa_params, 2);
if (ret < 0) {
- die("audio_alsa: Channels count (2) not available for device \"%s\": %s", alsa_out_dev, snd_strerror(ret));
- }
+ die("audio_alsa: Channels count (2) not available for device \"%s\": %s",
+ alsa_out_dev, snd_strerror(ret));
+ }
- ret = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params, &my_sample_rate, &dir);
+ ret = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params,
+ &my_sample_rate, &dir);
if (ret < 0) {
- die("audio_alsa: Rate %iHz not available for playback: %s", desired_sample_rate, snd_strerror(ret));
- }
-
- // snd_pcm_hw_params_set_period_size_near(alsa_handle, alsa_params, &frames, &dir);
- // snd_pcm_hw_params_set_buffer_size_near(alsa_handle, alsa_params, &buffer_size);
-
+ die("audio_alsa: Rate %iHz not available for playback: %s",
+ desired_sample_rate, snd_strerror(ret));
+ }
+
+ // snd_pcm_hw_params_set_period_size_near(alsa_handle, alsa_params, &frames,
+ // &dir);
+ // snd_pcm_hw_params_set_buffer_size_near(alsa_handle, alsa_params,
+ // &buffer_size);
+
ret = snd_pcm_hw_params(alsa_handle, alsa_params);
if (ret < 0) {
- die("audio_alsa: Unable to set hw parameters for device \"%s\": %s.", alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Unable to set hw parameters for device \"%s\": %s.",
+ alsa_out_dev, snd_strerror(ret));
}
-
+
if (my_sample_rate != desired_sample_rate) {
die("Can't set the D/A converter to %d.", desired_sample_rate);
}
-
- ret = snd_pcm_hw_params_get_buffer_size(alsa_params,&actual_buffer_length);
- if (ret < 0) {
- die("audio_alsa: Unable to get hw buffer length for device \"%s\": %s.", alsa_out_dev, snd_strerror(ret));
+
+ ret = snd_pcm_hw_params_get_buffer_size(alsa_params, &actual_buffer_length);
+ if (ret < 0) {
+ die("audio_alsa: Unable to get hw buffer length for device \"%s\": %s.",
+ alsa_out_dev, snd_strerror(ret));
}
-
- if (actual_buffer_length < config.audio_backend_buffer_desired_length+minimal_buffer_headroom) {
+
+ if (actual_buffer_length <
+ config.audio_backend_buffer_desired_length + minimal_buffer_headroom) {
// the dac buffer is too small, so let's try to set it
- buffer_size = config.audio_backend_buffer_desired_length+requested_buffer_headroom;
- ret = snd_pcm_hw_params_set_buffer_size_near(alsa_handle, alsa_params, &buffer_size);
+ buffer_size =
+ config.audio_backend_buffer_desired_length + requested_buffer_headroom;
+ ret = snd_pcm_hw_params_set_buffer_size_near(alsa_handle, alsa_params,
+ &buffer_size);
if (ret < 0)
- die("audio_alsa: Unable to set hw buffer size to %lu for device \"%s\": %s.", config.audio_backend_buffer_desired_length+requested_buffer_headroom, alsa_out_dev, snd_strerror(ret));
- if (config.audio_backend_buffer_desired_length+minimal_buffer_headroom > buffer_size) {
- die("audio_alsa: Can't set hw buffer size to %lu or more for device \"%s\". Requested size: %lu, granted size: %lu.", config.audio_backend_buffer_desired_length+minimal_buffer_headroom,
- alsa_out_dev,config.audio_backend_buffer_desired_length+requested_buffer_headroom,buffer_size);
+ die("audio_alsa: Unable to set hw buffer size to %lu for device \"%s\": "
+ "%s.",
+ config.audio_backend_buffer_desired_length +
+ requested_buffer_headroom,
+ alsa_out_dev, snd_strerror(ret));
+ if (config.audio_backend_buffer_desired_length + minimal_buffer_headroom >
+ buffer_size) {
+ die("audio_alsa: Can't set hw buffer size to %lu or more for device "
+ "\"%s\". Requested size: %lu, granted size: %lu.",
+ config.audio_backend_buffer_desired_length + minimal_buffer_headroom,
+ alsa_out_dev, config.audio_backend_buffer_desired_length +
+ requested_buffer_headroom,
+ buffer_size);
}
}
-
+
return (0);
}
static void start(int sample_rate) {
if (sample_rate != 44100)
- die("Unexpected sample rate %d -- only 44,100 supported!", sample_rate);
+ die("Unexpected sample rate %d -- only 44,100 supported!", sample_rate);
desired_sample_rate = sample_rate; // must be a variable
}
@@ -356,8 +407,8 @@ static uint32_t delay() {
// current_avail not used
if (derr != 0) {
ignore = snd_pcm_recover(alsa_handle, derr, 0);
- debug(1, "Error %d in delay(): %s. Delay reported is %d frames.", derr, snd_strerror(derr),
- current_delay);
+ debug(1, "Error %d in delay(): %s. Delay reported is %d frames.", derr,
+ snd_strerror(derr), current_delay);
current_delay = -1;
}
} else if (snd_pcm_state(alsa_handle) == SND_PCM_STATE_PREPARED) {
@@ -367,7 +418,8 @@ static uint32_t delay() {
current_delay = 0;
else {
current_delay = -1;
- debug(1, "Error -- ALSA delay(): bad state: %d.", snd_pcm_state(alsa_handle));
+ debug(1, "Error -- ALSA delay(): bad state: %d.",
+ snd_pcm_state(alsa_handle));
}
if ((derr = snd_pcm_prepare(alsa_handle))) {
ignore = snd_pcm_recover(alsa_handle, derr, 0);
@@ -384,6 +436,7 @@ static void play(short buf[], int samples) {
int ret = 0;
if (alsa_handle == NULL) {
ret = open_alsa_device();
+ open_mixer();
if ((ret == 0) && (audio_alsa.volume))
audio_alsa.volume(set_volume);
}
@@ -396,7 +449,8 @@ static void play(short buf[], int samples) {
err = snd_pcm_writei(alsa_handle, (char *)buf, samples);
if (err < 0) {
ignore = snd_pcm_recover(alsa_handle, err, 0);
- debug(1, "Error %d writing %d samples in play() %s.", err, samples, snd_strerror(err));
+ debug(1, "Error %d writing %d samples in play() %s.", err, samples,
+ snd_strerror(err));
}
} else {
debug(1, "Error -- ALSA device in incorrect state (%d) for play.",
@@ -412,6 +466,10 @@ static void play(short buf[], int samples) {
static void flush(void) {
int derr;
+ if (alsa_mix_handle) {
+ snd_mixer_close(alsa_mix_handle);
+ alsa_mix_handle = NULL;
+ }
if (alsa_handle) {
// debug(1,"Dropping frames for flush...");
if ((derr = snd_pcm_drop(alsa_handle)))
@@ -428,7 +486,8 @@ static void flush(void) {
*/
if (!((snd_pcm_state(alsa_handle) == SND_PCM_STATE_PREPARED) ||
(snd_pcm_state(alsa_handle) == SND_PCM_STATE_RUNNING)))
- debug(1, "Flush returning unexpected state -- %d.", snd_pcm_state(alsa_handle));
+ debug(1, "Flush returning unexpected state -- %d.",
+ snd_pcm_state(alsa_handle));
// flush also closes the device
snd_pcm_close(alsa_handle);
@@ -439,7 +498,8 @@ static void flush(void) {
static void stop(void) {
if (alsa_handle != 0)
// when we want to stop, we want the alsa device
- // to be closed immediately -- we may even be killing the thread, so we don't wish to wait
+ // to be closed immediately -- we may even be killing the thread, so we
+ // don't wish to wait
// so we should flush first
flush(); // flush will also close the device
// close_alsa_device();
@@ -451,31 +511,42 @@ static void parameters(audio_parameters *info) {
}
static void volume(double vol) {
- // debug(1,"Setting volume db to %f, for volume input of %f.",vol_setting/100,vol);
+ debug(2, "Setting volume db to %f.", vol);
set_volume = vol;
- if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, 0) != 0) {
- debug(1,"Can't set playback volume accurately to %f dB.",vol);
- if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, -1) != 0)
- if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, 1) != 0)
- die("Failed to set playback dB volume");
+ if (alsa_mix_handle) {
+ if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, 0) != 0) {
+ debug(1, "Can't set playback volume accurately to %f dB.", vol);
+ if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, -1) != 0)
+ if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, 1) != 0)
+ die("Failed to set playback dB volume");
+ }
}
}
static void linear_volume(double vol) {
- double linear_volume = pow(10, vol);
- // debug(1,"Linear volume is %f.",linear_volume);
- long int_vol = alsa_mix_minv + (alsa_mix_maxv - alsa_mix_minv) * linear_volume;
- // debug(1,"Setting volume to %ld, for volume input of %f.",int_vol,vol);
- if (snd_mixer_selem_set_playback_volume_all(alsa_mix_elem, int_vol) != 0)
- die("Failed to set playback volume");
+ debug(2, "Setting linear volume to %f.", vol);
+ set_volume = vol;
+ if (alsa_mix_handle) {
+ double linear_volume = pow(10, vol);
+ // debug(1,"Linear volume is %f.",linear_volume);
+ long int_vol =
+ alsa_mix_minv + (alsa_mix_maxv - alsa_mix_minv) * linear_volume;
+ // debug(1,"Setting volume to %ld, for volume input of %f.",int_vol,vol);
+ if (alsa_mix_handle) {
+ if (snd_mixer_selem_set_playback_volume_all(alsa_mix_elem, int_vol) != 0)
+ die("Failed to set playback volume");
+ }
+ }
}
static void mute(int do_mute) {
- if (do_mute) {
- // debug(1,"Mute");
- snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 0);
- } else {
- // debug(1,"Unmute");
- snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 1);
- }
+ if (alsa_mix_handle) {
+ if (do_mute) {
+ // debug(1,"Mute");
+ snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 0);
+ } else {
+ // debug(1,"Unmute");
+ snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 1);
+ }
+ }
}
From 7e771f10bea72f12d8b14851a149787be5a328f4 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 26 Jan 2016 13:32:23 +0000
Subject: [PATCH 134/144] Update configure.ac
---
configure.ac | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index f84362e9..9c8a0b9b 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], [2.7.7], [mikebrady@eircom.net])
+AC_INIT([shairport-sync], [2.7.8], [mikebrady@eircom.net])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([shairport.c])
AC_CONFIG_HEADERS([config.h])
From 623be1a503ae447999f4972dc022b7eca2ac6b4c Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 26 Jan 2016 13:37:55 +0000
Subject: [PATCH 135/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 6935d7a4..f26a2d88 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,3 +1,8 @@
+Version 2.7.8 -- Development Version
+----
+**Bug Fixes**
+* Fixed an issue whereby Shairport Sync did not reset the hardware mixer volume level before resuming playing. The issue was caused by not releasing and later reaquiring the mixer when pausing and resuming. Thanks to [Tim Curtis](https://github.com/moodeaudio) for reporting the issue.
+
Version 2.7.7 -- Development Version
----
**Enhancements**
From 79581bc97256dfa695ad7eea930a72e51d0da2c5 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 26 Jan 2016 13:39:40 +0000
Subject: [PATCH 136/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index f26a2d88..086e8cfe 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,6 +1,6 @@
Version 2.7.8 -- Development Version
----
-**Bug Fixes**
+**Bug Fix**
* Fixed an issue whereby Shairport Sync did not reset the hardware mixer volume level before resuming playing. The issue was caused by not releasing and later reaquiring the mixer when pausing and resuming. Thanks to [Tim Curtis](https://github.com/moodeaudio) for reporting the issue.
Version 2.7.7 -- Development Version
From d414c07ec369e720817fe52454d5eef363ad4292 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 26 Jan 2016 22:32:51 +0000
Subject: [PATCH 137/144] Check for existence of a hardware mixer before
messing with it.
---
audio_alsa.c | 44 +++++++++++++++++++++++---------------------
1 file changed, 23 insertions(+), 21 deletions(-)
diff --git a/audio_alsa.c b/audio_alsa.c
index 26f50d9a..a389ee28 100644
--- a/audio_alsa.c
+++ b/audio_alsa.c
@@ -81,6 +81,8 @@ static char *alsa_out_dev = "default";
static char *alsa_mix_dev = NULL;
static char *alsa_mix_ctrl = "Master";
static int alsa_mix_index = 0;
+static int hardware_mixer = 0;
+
static int play_number;
static int64_t accumulated_delay, accumulated_da_delay;
@@ -94,27 +96,29 @@ static void help(void) {
}
int open_mixer() {
- debug(3, "Open Mixer");
- int ret = 0;
- snd_mixer_selem_id_alloca(&alsa_mix_sid);
- snd_mixer_selem_id_set_index(alsa_mix_sid, alsa_mix_index);
- snd_mixer_selem_id_set_name(alsa_mix_sid, alsa_mix_ctrl);
+ if (hardware_mixer) {
+ debug(3, "Open Mixer");
+ int ret = 0;
+ snd_mixer_selem_id_alloca(&alsa_mix_sid);
+ snd_mixer_selem_id_set_index(alsa_mix_sid, alsa_mix_index);
+ snd_mixer_selem_id_set_name(alsa_mix_sid, alsa_mix_ctrl);
- if ((snd_mixer_open(&alsa_mix_handle, 0)) < 0)
- die("Failed to open mixer");
- debug(3, "Mixer device name is \"%s\".", alsa_mix_dev);
- if ((snd_mixer_attach(alsa_mix_handle, alsa_mix_dev)) < 0)
- die("Failed to attach mixer");
- if ((snd_mixer_selem_register(alsa_mix_handle, NULL, NULL)) < 0)
- die("Failed to register mixer element");
+ if ((snd_mixer_open(&alsa_mix_handle, 0)) < 0)
+ die("Failed to open mixer");
+ debug(3, "Mixer device name is \"%s\".", alsa_mix_dev);
+ if ((snd_mixer_attach(alsa_mix_handle, alsa_mix_dev)) < 0)
+ die("Failed to attach mixer");
+ if ((snd_mixer_selem_register(alsa_mix_handle, NULL, NULL)) < 0)
+ die("Failed to register mixer element");
- ret = snd_mixer_load(alsa_mix_handle);
- if (ret < 0)
- die("Failed to load mixer element");
- debug(3, "Mixer Control name is \"%s\".", alsa_mix_ctrl);
- alsa_mix_elem = snd_mixer_find_selem(alsa_mix_handle, alsa_mix_sid);
- if (!alsa_mix_elem)
- die("Failed to find mixer element");
+ ret = snd_mixer_load(alsa_mix_handle);
+ if (ret < 0)
+ die("Failed to load mixer element");
+ debug(3, "Mixer Control name is \"%s\".", alsa_mix_ctrl);
+ alsa_mix_elem = snd_mixer_find_selem(alsa_mix_handle, alsa_mix_sid);
+ if (!alsa_mix_elem)
+ die("Failed to find mixer element");
+ }
}
static int init(int argc, char **argv) {
@@ -122,8 +126,6 @@ static int init(int argc, char **argv) {
const char *str;
int value;
- int hardware_mixer = 0;
-
config.audio_backend_latency_offset = 0; // this is the default for ALSA
config.audio_backend_buffer_desired_length =
6615; // default for alsa with a software mixer
From 8087624f070eee9199ddcf384fb8e678314e07bb Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 26 Jan 2016 22:36:31 +0000
Subject: [PATCH 138/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 086e8cfe..48186fba 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,3 +1,8 @@
+Version 2.7.9 -- Development Version
+----
+**Bug Fix**
+* Oops – brown-bag update. Fixed a crashing bug introduced in the last release, caused by not checking for a hardware mixer before trying to access it, duh.
+
Version 2.7.8 -- Development Version
----
**Bug Fix**
From 38f08f6fd9cf47111254c40ed95b212ba60889b6 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Tue, 26 Jan 2016 22:37:00 +0000
Subject: [PATCH 139/144] Update configure.ac
---
configure.ac | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index 9c8a0b9b..5bf199af 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], [2.7.8], [mikebrady@eircom.net])
+AC_INIT([shairport-sync], [2.7.9], [mikebrady@eircom.net])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([shairport.c])
AC_CONFIG_HEADERS([config.h])
From 4b749c4066a7648e3f57b1caf9362dac7a055973 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 27 Jan 2016 11:06:33 +0000
Subject: [PATCH 140/144] Output volume metadata (pvol) even when ignoring the
volume setting. AirPLay volume is output, but the actual db, min and max dB
are set to zero, as they are meaningless in the context.
---
rtsp.c | 463 +++++++++++++++++++++++++++++++++++----------------------
1 file changed, 289 insertions(+), 174 deletions(-)
diff --git a/rtsp.c b/rtsp.c
index 6e8f1df7..7a768c3a 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -44,7 +44,6 @@
#include
#include
-
#include "config.h"
#ifdef HAVE_LIBSSL
@@ -83,7 +82,7 @@ static pthread_mutex_t reference_counter_lock = PTHREAD_MUTEX_INITIALIZER;
// only one thread is allowed to use the player at once.
// it monitors the request variable (at least when interrupted)
static pthread_mutex_t playing_mutex = PTHREAD_MUTEX_INITIALIZER;
-//static int please_shutdown = 0;
+// static int please_shutdown = 0;
static pthread_t playing_thread = 0;
typedef struct {
@@ -137,7 +136,8 @@ typedef struct {
void ask_other_rtsp_conversation_threads_to_stop(pthread_t except_this_thread);
-void pc_queue_init(pc_queue *the_queue, char *items, size_t item_size, uint32_t number_of_items) {
+void pc_queue_init(pc_queue *the_queue, char *items, size_t item_size,
+ uint32_t number_of_items) {
the_queue->item_size = item_size;
the_queue->items = items;
the_queue->count = 0;
@@ -146,8 +146,8 @@ void pc_queue_init(pc_queue *the_queue, char *items, size_t item_size, uint32_t
the_queue->eoq = 0;
}
-int send_metadata(uint32_t type, uint32_t code, char *data, uint32_t length, rtsp_message *carrier,
- int block);
+int send_metadata(uint32_t type, uint32_t code, char *data, uint32_t length,
+ rtsp_message *carrier, int block);
int send_ssnc_metadata(uint32_t code, char *data, uint32_t length, int block) {
return send_metadata('ssnc', code, data, length, NULL, block);
@@ -165,7 +165,8 @@ int pc_queue_add_item(pc_queue *the_queue, const void *the_stuff, int block) {
if (rc)
debug(1, "Error locking for pc_queue_add_item");
while (the_queue->count == the_queue->capacity) {
- rc = pthread_cond_wait(&the_queue->pc_queue_item_removed_signal, &the_queue->pc_queue_lock);
+ rc = pthread_cond_wait(&the_queue->pc_queue_item_removed_signal,
+ &the_queue->pc_queue_lock);
if (rc)
debug(1, "Error waiting for item to be removed");
}
@@ -202,7 +203,8 @@ int pc_queue_get_item(pc_queue *the_queue, void *the_stuff) {
if (rc)
debug(1, "Error locking for pc_queue_get_item");
while (the_queue->count == 0) {
- rc = pthread_cond_wait(&the_queue->pc_queue_item_added_signal, &the_queue->pc_queue_lock);
+ rc = pthread_cond_wait(&the_queue->pc_queue_item_added_signal,
+ &the_queue->pc_queue_lock);
if (rc)
debug(1, "Error waiting for item to be added");
}
@@ -243,8 +245,9 @@ static inline int rtsp_playing(void) {
}
void rtsp_request_shutdown_stream(void) {
- debug(1,"Request to shut down all rtsp conversation threads");
- ask_other_rtsp_conversation_threads_to_stop(0); // i.e. ask all playing threads to stop
+ debug(1, "Request to shut down all rtsp conversation threads");
+ ask_other_rtsp_conversation_threads_to_stop(
+ 0); // i.e. ask all playing threads to stop
}
static void rtsp_take_player(void) {
@@ -252,11 +255,13 @@ static void rtsp_take_player(void) {
return;
if (pthread_mutex_trylock(&playing_mutex)) {
- debug(1, "Request to all other playing threads to stop.");
- ask_other_rtsp_conversation_threads_to_stop(pthread_self()); // all threads apart from self
+ debug(1, "Request to all other playing threads to stop.");
+ ask_other_rtsp_conversation_threads_to_stop(
+ pthread_self()); // all threads apart from self
pthread_mutex_lock(&playing_mutex);
}
- playing_thread = pthread_self(); // make us the currently-playing thread (why?)
+ playing_thread =
+ pthread_self(); // make us the currently-playing thread (why?)
}
void rtsp_shutdown_stream(void) {
@@ -291,21 +296,22 @@ static void cleanup_threads(void) {
}
}
-// ask all rtsp_conversation threads to stop -- there should be at most one, but ya never know.
+// ask all rtsp_conversation threads to stop -- there should be at most one, but
+// ya never know.
void ask_other_rtsp_conversation_threads_to_stop(pthread_t except_this_thread) {
int i;
debug(2, "asking playing threads to stop");
- for (i = 0; i < nconns;i++) {
- if (((except_this_thread==0) || (pthread_equal(conns[i]->thread,except_this_thread)==0)) && (conns[i]->running != 0)) {
+ for (i = 0; i < nconns; i++) {
+ if (((except_this_thread == 0) ||
+ (pthread_equal(conns[i]->thread, except_this_thread) == 0)) &&
+ (conns[i]->running != 0)) {
conns[i]->stop = 1;
- pthread_kill(conns[i]->thread,SIGUSR1);
+ pthread_kill(conns[i]->thread, SIGUSR1);
}
}
}
-
-
// park a null at the line ending, and return the next line pointer
// accept \r, \n, or \r\n
static char *nextline(char *in, int inbuf) {
@@ -346,7 +352,8 @@ static void msg_retain(rtsp_message *msg) {
static rtsp_message *msg_init(void) {
rtsp_message *msg = malloc(sizeof(rtsp_message));
memset(msg, 0, sizeof(rtsp_message));
- msg->referenceCount = 1; // from now on, any access to this must be protected with the lock
+ msg->referenceCount =
+ 1; // from now on, any access to this must be protected with the lock
return msg;
}
@@ -387,7 +394,8 @@ static void msg_free(rtsp_message *msg) {
msg->referenceCount--;
rc = pthread_mutex_unlock(&reference_counter_lock);
if (rc)
- debug(1, "Error %d unlocking reference counter lock during msg_free()", rc);
+ debug(1, "Error %d unlocking reference counter lock during msg_free()",
+ rc);
if (msg->referenceCount == 0) {
int i;
for (i = 0; i < msg->nheaders; i++) {
@@ -398,7 +406,8 @@ static void msg_free(rtsp_message *msg) {
free(msg->content);
free(msg);
} // else {
- // debug(1,"rtsp_message reference count non-zero: %d!",msg->referenceCount);
+ // debug(1,"rtsp_message reference count non-zero:
+ // %d!",msg->referenceCount);
//}
} else {
debug(1, "null rtsp_message pointer passed to msg_free()");
@@ -459,7 +468,8 @@ fail:
return 0;
}
-static enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, rtsp_message **the_packet) {
+static enum rtsp_read_request_response
+rtsp_read_request(rtsp_conn_info *conn, rtsp_message **the_packet) {
enum rtsp_read_request_response reply = rtsp_read_request_response_ok;
ssize_t buflen = 512;
char *buf = malloc(buflen + 1);
@@ -471,7 +481,7 @@ static enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, r
int msg_size = -1;
while (msg_size < 0) {
- if (conn->stop!=0) {
+ if (conn->stop != 0) {
debug(1, "RTSP shutdown requested.");
reply = rtsp_read_request_response_shutdown_requested;
goto shutdown;
@@ -517,21 +527,24 @@ static enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, r
buflen = msg_size;
}
- uint64_t threshold_time =
- get_absolute_time_in_fp() + ((uint64_t)5 << 32); // i.e. five seconds from now
+ uint64_t threshold_time = get_absolute_time_in_fp() +
+ ((uint64_t)5 << 32); // i.e. five seconds from now
int warning_message_sent = 0;
const size_t max_read_chunk = 50000;
while (inbuf < msg_size) {
- // we are going to read the stream in chunks and time how long it takes to do so.
- // If it's taking too long, (and we find out about it), we will send an error message as
+ // we are going to read the stream in chunks and time how long it takes to
+ // do so.
+ // If it's taking too long, (and we find out about it), we will send an
+ // error message as
// metadata
if (warning_message_sent == 0) {
uint64_t time_now = get_absolute_time_in_fp();
if (time_now > threshold_time) { // it's taking too long
- debug(1, "Error receiving metadata from source -- transmission seems to be stalled.");
+ debug(1, "Error receiving metadata from source -- transmission seems "
+ "to be stalled.");
#ifdef CONFIG_METADATA
send_ssnc_metadata('stal', NULL, 0, 1);
#endif
@@ -585,7 +598,7 @@ static void msg_write_response(int fd, rtsp_message *resp) {
p += n;
for (i = 0; i < resp->nheaders; i++) {
-// debug(3, " %s: %s.", resp->name[i], resp->value[i]);
+ // debug(3, " %s: %s.", resp->name[i], resp->value[i]);
n = snprintf(p, pktfree, "%s: %s\r\n", resp->name[i], resp->value[i]);
pktfree -= n;
p += n;
@@ -600,14 +613,18 @@ static void msg_write_response(int fd, rtsp_message *resp) {
int ignore = write(fd, pkt, p - pkt + 2);
}
-static void handle_record(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
- //debug(1,"Handle Record");
+static void handle_record(rtsp_conn_info *conn, rtsp_message *req,
+ rtsp_message *resp) {
+ // debug(1,"Handle Record");
resp->respcode = 200;
- // I think this is for telling the client what the absolute minimum latency actually is,
- // and when the client specifies a latency, it should be added to this figure.
+ // I think this is for telling the client what the absolute minimum latency
+ // actually is,
+ // and when the client specifies a latency, it should be added to this figure.
- // Thus, AirPlay's latency figure of 77175, when added to 11025 gives you exactly 88200
- // and iTunes' latency figure of 88553, when added to 11025 gives you 99578, pretty close to the 99400 we guessed.
+ // Thus, AirPlay's latency figure of 77175, when added to 11025 gives you
+ // exactly 88200
+ // and iTunes' latency figure of 88553, when added to 11025 gives you 99578,
+ // pretty close to the 99400 we guessed.
msg_add_header(resp, "Audio-Latency", "11025");
@@ -622,33 +639,38 @@ static void handle_record(rtsp_conn_info *conn, rtsp_message *req, rtsp_message
if (p) {
p = strchr(p, '=');
if (p) {
- rtptime = uatoi(p+1); // unsigned integer -- up to 2^32-1
- rtptime--;
- // debug(1,"RTSP Flush Requested by handle_record: %u.",rtptime);
- player_flush(rtptime);
+ rtptime = uatoi(p + 1); // unsigned integer -- up to 2^32-1
+ rtptime--;
+ // debug(1,"RTSP Flush Requested by handle_record: %u.",rtptime);
+ player_flush(rtptime);
}
}
}
}
-static void handle_options(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
+static void handle_options(rtsp_conn_info *conn, rtsp_message *req,
+ rtsp_message *resp) {
resp->respcode = 200;
msg_add_header(resp, "Public", "ANNOUNCE, SETUP, RECORD, "
"PAUSE, FLUSH, TEARDOWN, "
"OPTIONS, GET_PARAMETER, SET_PARAMETER");
}
-static void handle_teardown(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
+static void handle_teardown(rtsp_conn_info *conn, rtsp_message *req,
+ rtsp_message *resp) {
if (!rtsp_playing())
- debug(1,"This RTSP conversation thread doesn't think it's playing, but it's sending a response to teardown anyway");
+ debug(1, "This RTSP conversation thread doesn't think it's playing, but "
+ "it's sending a response to teardown anyway");
resp->respcode = 200;
msg_add_header(resp, "Connection", "close");
conn->stop = 1;
}
-static void handle_flush(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
+static void handle_flush(rtsp_conn_info *conn, rtsp_message *req,
+ rtsp_message *resp) {
if (!rtsp_playing())
- debug(1,"This RTSP conversation thread doesn't think it's playing, but it's sending a response to flush anyway");
+ debug(1, "This RTSP conversation thread doesn't think it's playing, but "
+ "it's sending a response to flush anyway");
char *p;
uint32_t rtptime = 0;
char *hdr = msg_get_header(req, "RTP-Info");
@@ -660,7 +682,7 @@ static void handle_flush(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
if (p) {
p = strchr(p, '=');
if (p)
- rtptime = uatoi(p+1); // unsigned integer -- up to 2^32-1
+ rtptime = uatoi(p + 1); // unsigned integer -- up to 2^32-1
}
}
// debug(1,"RTSP Flush Requested: %u.",rtptime);
@@ -668,7 +690,8 @@ static void handle_flush(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
resp->respcode = 200;
}
-static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
+static void handle_setup(rtsp_conn_info *conn, rtsp_message *req,
+ rtsp_message *resp) {
// debug(1,"Handle Setup");
int cport, tport;
int lsport, lcport, ltport;
@@ -676,25 +699,26 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
char *ar = msg_get_header(req, "Active-Remote");
if (ar) {
- debug(1,"Active-Remote string seen: \"%s\".",ar);
+ debug(1, "Active-Remote string seen: \"%s\".", ar);
// get the active remote
char *p;
active_remote = strtoul(ar, &p, 10);
#ifdef CONFIG_METADATA
- send_metadata('ssnc','acre',ar,strlen(ar),req,1);
+ send_metadata('ssnc', 'acre', ar, strlen(ar), req, 1);
#endif
}
#ifdef CONFIG_METADATA
ar = msg_get_header(req, "DACP-ID");
if (ar) {
- debug(1,"DACP-ID string seen: \"%s\".",ar);
- send_metadata('ssnc','daid',ar,strlen(ar),req,1);
+ debug(1, "DACP-ID string seen: \"%s\".", ar);
+ 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.
+ // 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
@@ -709,7 +733,8 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
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.",
+ debug(1, "No User-Agent string found in the SETUP message. Using latency "
+ "of %d frames.",
config.latency);
} else {
if (strstr(ua, "iTunes") == ua) {
@@ -721,27 +746,35 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
else
debug(2, "iTunes Version Number not found.");
if (iTunesVersion >= 10) {
- debug(2, "User-Agent is iTunes 10 or better, (actual version is %d); selecting the iTunes "
+ debug(2, "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;
}
} else if (strstr(ua, "AirPlay") == ua) {
- debug(2, "User-Agent is AirPlay; selecting the AirPlay latency of %d frames.",
- config.AirPlayLatency);
+ 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.",
+ debug(2, "User-Agent is forked-daapd; selecting the forked-daapd latency "
+ "of %d frames.",
config.ForkedDaapdLatency);
config.latency = config.ForkedDaapdLatency;
} else {
- debug(2, "Unrecognised User-Agent. Using latency of %d frames.", config.latency);
+ 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
+ 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");
@@ -762,7 +795,8 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
tport = atoi(p);
rtsp_take_player();
- rtp_setup(&conn->remote, cport, tport, active_remote, &lsport, &lcport, <port);
+ rtp_setup(&conn->remote, cport, tport, active_remote, &lsport, &lcport,
+ <port);
if (!lsport)
goto error;
char *q;
@@ -781,12 +815,13 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
strcat(hdr, q); // should unsplice the timing port entry
}
- player_play(&conn->stream,&conn->player_thread); // the thread better be 0
+ player_play(&conn->stream, &conn->player_thread); // the thread better be 0
char *resphdr = alloca(200);
*resphdr = 0;
sprintf(resphdr, "RTP/AVP/"
- "UDP;unicast;interleaved=0-1;mode=record;control_port=%d;timing_port=%d;server_"
+ "UDP;unicast;interleaved=0-1;mode=record;control_port=%d;"
+ "timing_port=%d;server_"
"port=%d",
lcport, ltport, lsport);
@@ -803,11 +838,13 @@ error:
resp->respcode = 451; // invalid arguments
}
-static void handle_ignore(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
+static void handle_ignore(rtsp_conn_info *conn, rtsp_message *req,
+ rtsp_message *resp) {
resp->respcode = 200;
}
-static void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *req,
+static void handle_set_parameter_parameter(rtsp_conn_info *conn,
+ rtsp_message *req,
rtsp_message *resp) {
char *cp = req->content;
int cp_left = req->contentlength;
@@ -817,11 +854,21 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *r
cp_left -= next - cp;
if (!strncmp(cp, "volume: ", 8)) {
+ float volume = atof(cp + 8);
if (config.ignore_volume_control == 0) {
- float volume = atof(cp + 8);
debug(2, "volume: %f\n", volume);
player_volume(volume);
}
+#ifdef CONFIG_METADATA
+ else { // if ignore volume is on...
+ char *dv = malloc(128); // will be freed in the metadata thread
+ if (dv) {
+ memset(dv, 0, 128);
+ snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", volume, 0.0, 0.0, 0.0);
+ send_ssnc_metadata('pvol', dv, strlen(dv), 1);
+ }
+ }
+#endif
} else
#ifdef CONFIG_METADATA
if (!strncmp(cp, "progress: ", 10)) {
@@ -840,51 +887,71 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *r
#ifdef CONFIG_METADATA
// Metadata is not used by shairport-sync.
-// Instead we send all metadata to a fifo pipe, so that other apps can listen to the pipe and use
+// Instead we send all metadata to a fifo pipe, so that other apps can listen to
+// the pipe and use
// the metadata.
-// We use two 4-character codes to identify each piece of data and we send the data itself, if any,
+// We use two 4-character codes to identify each piece of data and we send the
+// data itself, if any,
// in base64 form.
// The first 4-character code, called the "type", is either:
// 'core' for all the regular metadadata coming from iTunes, etc., or
-// 'ssnc' (for 'shairport-sync') for all metadata coming from Shairport Sync itself, such as
+// 'ssnc' (for 'shairport-sync') for all metadata coming from Shairport Sync
+// itself, such as
// start/end delimiters, etc.
-// For 'core' metadata, the second 4-character code is the 4-character metadata code coming from
+// For 'core' metadata, the second 4-character code is the 4-character metadata
+// code coming from
// iTunes etc.
-// For 'ssnc' metadata, the second 4-character code is used to distinguish the messages.
+// For 'ssnc' metadata, the second 4-character code is used to distinguish the
+// messages.
-// Cover art is not tagged in the same way as other metadata, it seems, so is sent as an 'ssnc' type
+// Cover art is not tagged in the same way as other metadata, it seems, so is
+// sent as an 'ssnc' type
// metadata message with the code 'PICT'
// Here are the 'ssnc' codes defined so far:
-// 'PICT' -- the payload is a picture, either a JPEG or a PNG. Check the first few bytes to see
+// 'PICT' -- the payload is a picture, either a JPEG or a PNG. Check the
+// first few bytes to see
// which.
// 'pbeg' -- play stream begin. No arguments
// 'pend' -- play stream end. No arguments
// 'pfls' -- play stream flush. No arguments
// 'prsm' -- play stream resume. No arguments
// 'pvol' -- play volume. The volume is sent as a string --
-// "airplay_volume,volume,lowest_volume,highest_volume,has_true_mute,is_muted"
-// volume, lowest_volume and highest_volume are given in dB
-// is_muted is 1 if [true] mute is enabled, 0 otherwise.
-// The "airplay_volume" is what's sent to the player, and is from 0.00 down to -30.00,
+// "airplay_volume,volume,lowest_volume,highest_volume"
+// volume, lowest_volume and highest_volume are given in dB.
+// The "airplay_volume" is what's sent to the player, and is from
+// 0.00 down to -30.00,
// with -144.00 meaning mute.
-// This is linear on the volume control slider of iTunes or iOS AirPLay
-// 'prgr' -- progress -- this is metadata from AirPlay consisting of RTP timestamps for the start
-// of the current play sequence, the current play point and the end of the play sequence.
+// This is linear on the volume control slider of iTunes or iOS
+// AirPlay.
+// 'prgr' -- progress -- this is metadata from AirPlay consisting of RTP
+// timestamps for the start
+// of the current play sequence, the current play point and the end of the
+// play sequence.
// I guess the timestamps wrap at 2^32.
-// 'mdst' -- a sequence of metadata is about to start; will have, as data, the rtptime associated with the metadata, if available
-// 'mden' -- a sequence of metadata has ended; will have, as data, the rtptime associated with the metadata, if available
-// 'pcst' -- a picture is about to be sent; will have, as data, the rtptime associated with the picture, if available
-// 'pcen' -- a picture has been sent; will have, as data, the rtptime associated with the metadata, if available
-// 'snam' -- A device -- e.g. "Joe's iPhone" -- has opened a play session. Specifically, it's the "X-Apple-Client-Name" string
-// 'snua' -- A "user agent" -- e.g. "iTunes/12..." -- has opened a play session. Specifically, it's the "User-Agent" string
+// 'mdst' -- a sequence of metadata is about to start; will have, as data,
+// the rtptime associated with the metadata, if available
+// 'mden' -- a sequence of metadata has ended; will have, as data, the
+// rtptime associated with the metadata, if available
+// 'pcst' -- a picture is about to be sent; will have, as data, the rtptime
+// associated with the picture, if available
+// 'pcen' -- a picture has been sent; will have, as data, the rtptime
+// associated with the metadata, if available
+// 'snam' -- A device -- e.g. "Joe's iPhone" -- has opened a play session.
+// Specifically, it's the "X-Apple-Client-Name" string
+// 'snua' -- A "user agent" -- e.g. "iTunes/12..." -- has opened a play
+// session. Specifically, it's the "User-Agent" string
// The next two two tokens are to facilitiate remote control of the source.
-// There is some information at http://nto.github.io/AirPlay.html about remote control of the source.
+// There is some information at http://nto.github.io/AirPlay.html about
+// remote control of the source.
//
-// 'daid' -- this is the source's DACP-ID (if it has one -- it's not guaranteed), useful if you want to remotely control the source. Use this string to identify the source's remote control on the network.
-// 'acre' -- this is the source's Active-Remote token, necessary if you want to send commands to the source's remote control (if it has one).
+// 'daid' -- this is the source's DACP-ID (if it has one -- it's not
+// guaranteed), useful if you want to remotely control the source. Use this
+// string to identify the source's remote control on the network.
+// 'acre' -- this is the source's Active-Remote token, necessary if you want
+// to send commands to the source's remote control (if it has one).
//
// including a simple base64 encoder to minimise malloc/free activity
@@ -896,20 +963,22 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *r
// add _so to end of name to avoid confusion with polarssl's implementation
-static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
- 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
+static char encoding_table[] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
static int mod_table[] = {0, 2, 1};
-// pass in a pointer to the data, its length, a pointer to the output buffer and a pointer to an int
+// pass in a pointer to the data, its length, a pointer to the output buffer and
+// a pointer to an int
// containing its maximum length
// the actual length will be returned.
-char *base64_encode_so(const unsigned char *data, size_t input_length, char *encoded_data,
- size_t *output_length) {
+char *base64_encode_so(const unsigned char *data, size_t input_length,
+ char *encoded_data, size_t *output_length) {
size_t calculated_output_length = 4 * ((input_length + 2) / 3);
if (calculated_output_length > *output_length)
@@ -974,7 +1043,8 @@ void metadata_open(void) {
fd = open(path, O_WRONLY | O_NONBLOCK);
// if (fd < 0)
- // debug(1, "Could not open metadata FIFO %s. Will try again later.", path);
+ // debug(1, "Could not open metadata FIFO %s. Will try again later.",
+ // path);
free(path);
}
@@ -984,8 +1054,10 @@ static void metadata_close(void) {
fd = -1;
}
-void metadata_process(uint32_t type, uint32_t code, char *data, uint32_t length) {
- debug(2, "Process metadata with type %x, code %x and length %u.", type, code, length);
+void metadata_process(uint32_t type, uint32_t code, char *data,
+ uint32_t length) {
+ debug(2, "Process metadata with type %x, code %x and length %u.", type, code,
+ length);
int ret;
// readers may go away and come back
if (fd < 0)
@@ -993,8 +1065,9 @@ void metadata_process(uint32_t type, uint32_t code, char *data, uint32_t length)
if (fd < 0)
return;
char thestring[1024];
- snprintf(thestring, 1024, "%x%x%u", type, code,
- length);
+ snprintf(thestring, 1024,
+ "%x%x%u", type,
+ code, length);
ret = non_blocking_write(fd, thestring, strlen(thestring));
if (ret < 1)
return;
@@ -1004,7 +1077,8 @@ void metadata_process(uint32_t type, uint32_t code, char *data, uint32_t length)
if (ret < 1) // no reader
return;
// here, we write the data in base64 form using our nice base64 encoder
- // but, we break it into lines of 76 output characters, except for the last one.
+ // but, we break it into lines of 76 output characters, except for the last
+ // one.
// thus, we send groups of (76/4)*3 = 57 bytes to the encoder at a time
size_t remaining_count = length;
char *remaining_data = data;
@@ -1014,10 +1088,13 @@ void metadata_process(uint32_t type, uint32_t code, char *data, uint32_t length)
size_t towrite_count = remaining_count;
if (towrite_count > 57)
towrite_count = 57;
- size_t outbuf_size = 76; // size of output buffer on entry, length of result on exit
- if (base64_encode_so((unsigned char *)remaining_data, towrite_count, outbuf, &outbuf_size) == NULL)
+ size_t outbuf_size =
+ 76; // size of output buffer on entry, length of result on exit
+ if (base64_encode_so((unsigned char *)remaining_data, towrite_count,
+ outbuf, &outbuf_size) == NULL)
debug(1, "Error encoding base64 data.");
- // debug(1,"Remaining count: %d ret: %d, outbuf_size: %d.",remaining_count,ret,outbuf_size);
+ // debug(1,"Remaining count: %d ret: %d, outbuf_size:
+ // %d.",remaining_count,ret,outbuf_size);
ret = non_blocking_write(fd, outbuf, outbuf_size);
if (ret < 0)
return;
@@ -1052,32 +1129,42 @@ void *metadata_thread_function(void *ignore) {
void metadata_init(void) {
// create a pc_queue for passing information to a threaded metadata handler
- pc_queue_init(&metadata_queue, (char *)&metadata_queue_items, sizeof(metadata_package),
- metadata_queue_size);
- int ret = pthread_create(&metadata_thread, NULL, metadata_thread_function, NULL);
+ pc_queue_init(&metadata_queue, (char *)&metadata_queue_items,
+ sizeof(metadata_package), metadata_queue_size);
+ int ret =
+ pthread_create(&metadata_thread, NULL, metadata_thread_function, NULL);
if (ret)
debug(1, "Failed to create metadata thread!");
}
-int send_metadata(uint32_t type, uint32_t code, char *data, uint32_t length, rtsp_message *carrier,
- int block) {
+int send_metadata(uint32_t type, uint32_t code, char *data, uint32_t length,
+ rtsp_message *carrier, int block) {
- // parameters: type, code, pointer to data or NULL, length of data or NULL, the rtsp_message or
+ // parameters: type, code, pointer to data or NULL, length of data or NULL,
+ // the rtsp_message or
// NULL
- // the rtsp_message is sent for 'core' messages, because it contains the data and must not be
- // freed until the data has been read. So, it is passed to send_metadata to be retained,
- // sent to the thread where metadata is processed and released (and probably freed).
+ // the rtsp_message is sent for 'core' messages, because it contains the data
+ // and must not be
+ // freed until the data has been read. So, it is passed to send_metadata to be
+ // retained,
+ // sent to the thread where metadata is processed and released (and probably
+ // freed).
// The rtsp_message is also sent for certain non-'core' messages.
// The reading of the parameters is a bit complex
- // If the rtsp_message field is non-null, then it represents an rtsp_message which should be freed
- // in the thread handler when the parameter pointed to by the pointer and specified by the length
+ // If the rtsp_message field is non-null, then it represents an rtsp_message
+ // which should be freed
+ // in the thread handler when the parameter pointed to by the pointer and
+ // specified by the length
// is finished with
- // If the rtsp_message is NULL, then if the pointer is non-null, it points to a malloc'ed block
- // and should be freed when the thread is finished with it. The length of the data in the block is
+ // If the rtsp_message is NULL, then if the pointer is non-null, it points to
+ // a malloc'ed block
+ // and should be freed when the thread is finished with it. The length of the
+ // data in the block is
// given in length
- // If the rtsp_message is NULL and the pointer is also NULL, nothing further is done.
+ // If the rtsp_message is NULL and the pointer is also NULL, nothing further
+ // is done.
metadata_package pack;
pack.type = type;
@@ -1091,11 +1178,14 @@ int send_metadata(uint32_t type, uint32_t code, char *data, uint32_t length, rts
if ((rc == EBUSY) && (carrier))
msg_free(carrier);
if (rc == EBUSY)
- warn("Metadata queue is busy, dropping message of type 0x%08X, code 0x%08X.", type, code);
+ warn(
+ "Metadata queue is busy, dropping message of type 0x%08X, code 0x%08X.",
+ type, code);
return rc;
}
-static void handle_set_parameter_metadata(rtsp_conn_info *conn, rtsp_message *req,
+static void handle_set_parameter_metadata(rtsp_conn_info *conn,
+ rtsp_message *req,
rtsp_message *resp) {
char *cp = req->content;
int cl = req->contentlength;
@@ -1105,12 +1195,14 @@ static void handle_set_parameter_metadata(rtsp_conn_info *conn, rtsp_message *re
uint32_t itag, vl;
while (off < cl) {
// pick up the metadata tag as an unsigned longint
- memcpy(&itag, (uint32_t *)(cp + off), sizeof(uint32_t)); /* can be misaligned, thus memcpy */
+ memcpy(&itag, (uint32_t *)(cp + off),
+ sizeof(uint32_t)); /* can be misaligned, thus memcpy */
itag = ntohl(itag);
off += sizeof(uint32_t);
// pick up the length of the data
- memcpy(&vl, (uint32_t *)(cp + off), sizeof(uint32_t)); /* can be misaligned, thus memcpy */
+ memcpy(&vl, (uint32_t *)(cp + off),
+ sizeof(uint32_t)); /* can be misaligned, thus memcpy */
vl = ntohl(vl);
off += sizeof(uint32_t);
@@ -1127,13 +1219,14 @@ static void handle_set_parameter_metadata(rtsp_conn_info *conn, rtsp_message *re
#endif
-static void handle_get_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
+static void handle_get_parameter(rtsp_conn_info *conn, rtsp_message *req,
+ rtsp_message *resp) {
debug(1, "received GET_PARAMETER request.");
resp->respcode = 200;
}
-
-static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
+static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req,
+ rtsp_message *resp) {
// if (!req->contentlength)
// debug(1, "received empty SET_PARAMETER request.");
@@ -1145,11 +1238,14 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
debug(2, "SET_PARAMETER Content-Type:\"%s\".", ct);
#ifdef CONFIG_METADATA
- // It seems that the rtptime of the message is used as a kind of an ID that can be used
- // to link items of metadata, including pictures, that refer to the same entity.
+ // It seems that the rtptime of the message is used as a kind of an ID that
+ // can be used
+ // to link items of metadata, including pictures, that refer to the same
+ // entity.
// If they refer to the same item, they have the same rtptime.
- // So we send the rtptime before and after both the metadata items and the picture item
- // get the rtptime
+ // So we send the rtptime before and after both the metadata items and the
+ // picture item
+ // get the rtptime
char *p = NULL;
char *hdr = msg_get_header(req, "RTP-Info");
@@ -1164,19 +1260,23 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
if (!strncmp(ct, "application/x-dmap-tagged", 25)) {
debug(2, "received metadata tags in SET_PARAMETER request.");
- if (p==NULL)
- debug(1,"Missing RTP-Time info for metadata");
+ if (p == NULL)
+ debug(1, "Missing RTP-Time info for metadata");
if (p)
- send_metadata('ssnc', 'mdst', p+1, strlen(p+1), req, 1); // metadata starting
+ send_metadata('ssnc', 'mdst', p + 1, strlen(p + 1), req,
+ 1); // metadata starting
else
- send_metadata('ssnc', 'mdst', NULL, 0, NULL, 0); // metadata starting, if rtptime is not available
+ send_metadata('ssnc', 'mdst', NULL, 0, NULL,
+ 0); // metadata starting, if rtptime is not available
handle_set_parameter_metadata(conn, req, resp);
if (p)
- send_metadata('ssnc', 'mden', p+1, strlen(p+1), req, 1); // metadata ending
+ send_metadata('ssnc', 'mden', p + 1, strlen(p + 1), req,
+ 1); // metadata ending
else
- send_metadata('ssnc', 'mden', NULL, 0, NULL, 0); // metadata starting, if rtptime is not available
+ send_metadata('ssnc', 'mden', NULL, 0, NULL,
+ 0); // metadata starting, if rtptime is not available
} else if (!strncmp(ct, "image", 5)) {
// Some server simply ignore the md field from the TXT record. If The
@@ -1186,29 +1286,35 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
// debug(1, "received image in SET_PARAMETER request.");
// note: the image/type tag isn't reliable, so it's not being sent
// -- best look at the first few bytes of the image
- if (p==NULL)
- debug(1,"Missing RTP-Time info for picture item");
+ if (p == NULL)
+ debug(1, "Missing RTP-Time info for picture item");
if (p)
- send_metadata('ssnc', 'pcst', p+1, strlen(p+1), req, 1); // picture starting
+ send_metadata('ssnc', 'pcst', p + 1, strlen(p + 1), req,
+ 1); // picture starting
else
- send_metadata('ssnc', 'pcst', NULL, 0, NULL, 0); // picture starting, if rtptime is not available
+ send_metadata('ssnc', 'pcst', NULL, 0, NULL,
+ 0); // picture starting, if rtptime is not available
send_metadata('ssnc', 'PICT', req->content, req->contentlength, req, 1);
if (p)
- send_metadata('ssnc', 'pcen', p+1, strlen(p+1), req, 1); // picture ending
+ send_metadata('ssnc', 'pcen', p + 1, strlen(p + 1), req,
+ 1); // picture ending
else
- send_metadata('ssnc', 'pcen', NULL, 0, NULL, 0); // picture ending, if rtptime is not available
+ send_metadata('ssnc', 'pcen', NULL, 0, NULL,
+ 0); // picture ending, if rtptime is not available
} else {
debug(1, "Ignore received picture item (include_cover_art = no).");
}
} else
#endif
- if (!strncmp(ct, "text/parameters", 15)) {
+ if (!strncmp(ct, "text/parameters", 15)) {
debug(2, "received parameters in SET_PARAMETER request.");
- handle_set_parameter_parameter(conn, req, resp); // this could be volume or progress
+ handle_set_parameter_parameter(conn, req,
+ resp); // this could be volume or progress
} else {
- debug(1, "received unknown Content-Type \"%s\" in SET_PARAMETER request.", ct);
+ debug(1, "received unknown Content-Type \"%s\" in SET_PARAMETER request.",
+ ct);
}
} else {
debug(1, "missing Content-Type header in SET_PARAMETER request.");
@@ -1217,9 +1323,11 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_m
resp->respcode = 200;
}
-static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
+static void handle_announce(rtsp_conn_info *conn, rtsp_message *req,
+ rtsp_message *resp) {
// interrupt session if permitted
- if ((config.allow_session_interruption == 1) || (pthread_mutex_trylock(&play_lock) == 0)) {
+ if ((config.allow_session_interruption == 1) ||
+ (pthread_mutex_trylock(&play_lock) == 0)) {
resp->respcode = 456; // 456 - Header Field Not Valid for Resource
char *paesiv = NULL;
char *prsaaeskey = NULL;
@@ -1243,25 +1351,26 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
cp = next;
}
- if ((paesiv==NULL) && (prsaaeskey==NULL)) {
- //debug(1,"Unencrypted session requested?");
+ if ((paesiv == NULL) && (prsaaeskey == NULL)) {
+ // debug(1,"Unencrypted session requested?");
conn->stream.encrypted = 0;
} else {
conn->stream.encrypted = 1;
- //debug(1,"Encrypted session requested");
+ // debug(1,"Encrypted session requested");
}
if (!pfmtp) {
warn("FMTP params missing from the following ANNOUNCE message:");
// print each line of the request content
- // the problem is that nextline has replace all returns, newlines, etc. by NULLs
+ // the problem is that nextline has replace all returns, newlines, etc. by
+ // NULLs
char *cp = req->content;
int cp_left = req->contentlength;
- while (cp_left>1) {
- if (strlen(cp)!=0)
- warn(" %s",cp);
- cp+=strlen(cp)+1;
- cp_left-=strlen(cp)+1;
+ while (cp_left > 1) {
+ if (strlen(cp) != 0)
+ warn(" %s", cp);
+ cp += strlen(cp) + 1;
+ cp_left -= strlen(cp) + 1;
}
goto out;
}
@@ -1289,22 +1398,23 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
free(aeskey);
}
int i;
- for (i = 0; i < sizeof(conn->stream.fmtp) / sizeof(conn->stream.fmtp[0]); i++)
+ for (i = 0; i < sizeof(conn->stream.fmtp) / sizeof(conn->stream.fmtp[0]);
+ i++)
conn->stream.fmtp[i] = atoi(strsep(&pfmtp, " \t"));
char *hdr = msg_get_header(req, "X-Apple-Client-Name");
if (hdr) {
debug(1, "Play connection from device named \"%s\".", hdr);
- #ifdef CONFIG_METADATA
- send_metadata('ssnc','snam',hdr,strlen(hdr),req,1);
- #endif
+#ifdef CONFIG_METADATA
+ send_metadata('ssnc', 'snam', hdr, strlen(hdr), req, 1);
+#endif
}
hdr = msg_get_header(req, "User-Agent");
if (hdr) {
debug(1, "Play connection from user agent \"%s\".", hdr);
- #ifdef CONFIG_METADATA
- send_metadata('ssnc','snua',hdr,strlen(hdr),req,1);
- #endif
+#ifdef CONFIG_METADATA
+ send_metadata('ssnc', 'snua', hdr, strlen(hdr), req, 1);
+#endif
}
resp->respcode = 200;
} else {
@@ -1464,7 +1574,8 @@ static int rtsp_auth(char **nonce, rtsp_message *req, rtsp_message *resp) {
md5_update(&tctx, (unsigned char *)":", 1);
md5_update(&tctx, (const unsigned char *)realm, strlen(realm));
md5_update(&tctx, (unsigned char *)":", 1);
- md5_update(&tctx, (const unsigned char *)config.password, strlen(config.password));
+ md5_update(&tctx, (const unsigned char *)config.password,
+ strlen(config.password));
md5_finish(&tctx, digest_urp);
md5_starts(&tctx);
md5_update(&tctx, (const unsigned char *)req->method, strlen(req->method));
@@ -1561,8 +1672,9 @@ static void *rtsp_conversation_thread_func(void *pconn) {
break;
}
}
- if (method_selected==0)
- debug(1,"Unrecognised and unhandled rtsp request \"%s\".",req->method);
+ if (method_selected == 0)
+ debug(1, "Unrecognised and unhandled rtsp request \"%s\".",
+ req->method);
respond:
msg_write_response(conn->fd, resp);
@@ -1583,13 +1695,14 @@ static void *rtsp_conversation_thread_func(void *pconn) {
pthread_mutex_unlock(&play_lock);
pthread_mutex_unlock(&playing_mutex);
} else {
- debug(1,"This RTSP conversation thread doesn't think it's playing for a close RTSP connection.");
+ debug(1, "This RTSP conversation thread doesn't think it's playing for a "
+ "close RTSP connection.");
}
if (auth_nonce)
free(auth_nonce);
conn->running = 0;
debug(2, "Now terminating RTSP conversation thread.");
-// please_shutdown = 0;
+ // please_shutdown = 0;
return NULL;
}
@@ -1637,7 +1750,8 @@ void rtsp_listen_loop(void) {
// Handle socket open failures if protocol unavailable (or IPV6 not handled)
if (fd == -1) {
- // debug(1, "Failed to get socket: fam=%d, %s\n", p->ai_family, strerror(errno));
+ // debug(1, "Failed to get socket: fam=%d, %s\n", p->ai_family,
+ // strerror(errno));
continue;
}
@@ -1657,7 +1771,7 @@ void rtsp_listen_loop(void) {
// one of the address families will fail on some systems that
// report its availability. do not complain.
-
+
if (ret) {
debug(1, "Failed to bind to address %s.", format_address(p->ai_addr));
continue;
@@ -1719,19 +1833,20 @@ void rtsp_listen_loop(void) {
memset(conn, 0, sizeof(rtsp_conn_info));
socklen_t slen = sizeof(conn->remote);
- debug(1, "New RTSP connection on port %d",config.port);
+ debug(1, "New RTSP connection on port %d", config.port);
conn->fd = accept(acceptfd, (struct sockaddr *)&conn->remote, &slen);
if (conn->fd < 0) {
perror("failed to accept connection");
free(conn);
} else {
pthread_t rtsp_conversation_thread;
- ret = pthread_create(&rtsp_conversation_thread, NULL, rtsp_conversation_thread_func, conn);
+ ret = pthread_create(&rtsp_conversation_thread, NULL,
+ rtsp_conversation_thread_func, conn);
if (ret)
die("Failed to create RTSP receiver thread!");
conn->thread = rtsp_conversation_thread;
- conn -> stop = 0;
+ conn->stop = 0;
conn->running = 1;
track_thread(conn);
}
From f9c264e34ab2dee97924329772a3109e27cee43c Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 27 Jan 2016 11:13:27 +0000
Subject: [PATCH 141/144] Update RELEASENOTES.md
---
RELEASENOTES.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 48186fba..9d0d3612 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,3 +1,8 @@
+Version 2.7.10 -- Development Version
+----
+**New Feature**
+* If the `ignore_volume_control` setting was `yes`, Shairport Sync really did ignore volume control settings and did not send any volume metadata (i.e. `pvol` coded metadata). Now, while continuing to ignore volume control settings, it sends a `pvol` token where the first number is the AirPlay volume, as before, but the remaining three parameters are set to zero.
+
Version 2.7.9 -- Development Version
----
**Bug Fix**
From b4d68ee32cb63aecd3463852faf251fd4114df5b Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Wed, 27 Jan 2016 11:13:50 +0000
Subject: [PATCH 142/144] Update configure.ac
---
configure.ac | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index 5bf199af..5d3070a1 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], [2.7.9], [mikebrady@eircom.net])
+AC_INIT([shairport-sync], [2.7.10], [mikebrady@eircom.net])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([shairport.c])
AC_CONFIG_HEADERS([config.h])
From ed756489bd719b5d646ed79c73d02dff1c451a75 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Thu, 28 Jan 2016 19:05:46 +0000
Subject: [PATCH 143/144] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 3cd642e8..99320be3 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,7 @@ The following procedures will install the shairport-sync application into your s
Personal Package Archives for Shairport Sync master and development branches are available at https://launchpad.net/~dantheperson.
**OpenWrt:**
-There is a Shairport Sync package in OpenWrt `trunk`. Also, there's an OpenWrt package at https://github.com/mikebrady/shairport-sync-for-openwrt, including one that builds back to `Attitude Adjustment`.
+There is a Shairport Sync package in OpenWrt `trunk`. Also, there's an OpenWrt package at https://github.com/mikebrady/shairport-sync-for-openwrt, including one that builds back to `Barrier Breaker`.
**Arch Linux:**
Shairport Sync is available for `x86_64` and `i686` platforms in the Arch Linux Community Repository -- search for `shairport-sync`. See also https://www.archlinux.org/packages/.
From 6f9fe47351fdd2a1eeaaa4e0ec68513fefd87e82 Mon Sep 17 00:00:00 2001
From: Mike Brady
Date: Sat, 30 Jan 2016 15:50:47 +0000
Subject: [PATCH 144/144] Update README.md
---
README.md | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
index 99320be3..cda6f0ff 100644
--- a/README.md
+++ b/README.md
@@ -9,11 +9,11 @@ This branch — "development" — is unstable and may change quickly. To access
More Information
----------
-Shairport Sync works by using timing information and timestamps present in data coming from the audio source (e.g. an iPhone) to "play" audio at exactly the right time. It does this by monitoring and controlling the *latency* — the time between a sound frame is supposed to be played, as specified by its `timestamp`, and the time when it is actually played by the audio output device, usually a Digital to Audio Converter (DAC).
+Shairport Sync works by using timing information and timestamps present in data coming from the audio source (e.g. an iPhone) to play audio at exactly the right time. It does this by monitoring and controlling the *latency* — the time-gap between when a sound frame is supposed to be played, as specified by its `timestamp`, and the time when it is actually played by the audio output device, usually a Digital to Audio Converter (DAC).
The latency to be used is specified by the source when it negotiates with Shairport Sync. Most sources set a latency of 88,200 frames — exactly two seconds. Recent versions of iTunes and forkedDaapd use a latency of 99,577 frames.
-Timestamps are measured relative to the source computer's clocks, the `source clock`, but timing must be done relative to the clock of the computer running Shairport Sync, the `local clock`. The source and local clocks are synchronised, usually to within a fraction of a millisecond, using a variant of NTP synchronisation protocols.
+Timestamps are measured relative to the source computer's clock – the `source clock`, but timing must be done relative to the clock of the computer running Shairport Sync – the `local clock`. The source and local clocks are synchronised by Shairport Sync, usually to within a fraction of a millisecond, using a variant of NTP synchronisation protocols.
To maintain the exact latency required, if an output device is running slow relative to the source, Shairport Sync will delete frames of audio to allow the device to keep up. If the output device is running fast, Shairport Sync will insert frames to keep time. The number of frames inserted or deleted is so small as to be almost inaudible on normal audio material. Frames are inserted or deleted as necessary at pseudorandom intervals. Alternatively, with `libsoxr` support, Shairport Sync can resample the audio feed to ensure the output device can keep up. This is less obtrusive than insertion and deletion but requires a good deal of processing power — most embedded devices probably can't support it. The process of insertion/deletion or resampling is rather inelegantly called “stuffing”.
@@ -25,13 +25,13 @@ For more about the motivation behind Shairport Sync, please see the wiki at http
What else?
--------------
-* Better Volume Control — Shairport Sync offers finer control at very top and very bottom of the volume range. See http://tangentsoft.net/audio/atten.html for a good discussion of audio "attenuators", upon which volume control in Shairport Sync is modelled. See also the diagram of the volume transfer function in the documents folder.
+* Better Volume Control — Shairport Sync offers finer control at very top and very bottom of the volume range. See http://tangentsoft.net/audio/atten.html for a good discussion of audio "attenuators", upon which volume control in Shairport Sync is modelled. See also the diagram of the volume transfer function in the documents folder. In addition, Shairport Sync can offer an extended volume control range on devices with a restricted range.
* Hardware Mute — Shairport Sync will mute properly if the hardware supports it.
* Fast Response — With hardware volume control, response is instantaneous; otherwise the response time is 0.15 seconds.
* Non-Interruptible — Shairport Sync sends back a "busy" signal if it's already playing audio from another source, so other sources can't disrupt an existing Shairport Sync session. (If a source disappears without warning, the session automatically terminates after two minutes and the device becomes available again.)
-* Metadata — Shairport Sync can be configured to deliver metadata supplied by the source, such as Album Name, Artist Name, Cover Art, etc. through a pipe to a recipient application program — see https://github.com/mikebrady/shairport-sync-metadata-reader for a sample recipient. Sources that supply metadata include iTunes and the Music app in iOS.
+* Metadata — Shairport Sync can deliver metadata supplied by the source, such as Album Name, Artist Name, Cover Art, etc. through a pipe to a recipient application program — see https://github.com/mikebrady/shairport-sync-metadata-reader for a sample recipient. Sources that supply metadata include iTunes and the Music app in iOS.
* Raw Audio — Shairport Sync can deliver raw PCM audio to standard output or to a pipe. This output is delivered synchronously with the source after the appropriate latency and is not interpolated or "stuffed" on its way through Shairport Sync.
-* Autotools and Libtool Support — One important difference between Shairport Sync and other versions of Shairport is that the Shairport Sync build process uses GNU autotools and libtool to examine and configure the build environment — very important for cross compilation. Previous versions of Shairport looked at the current system to determine which packages were available, instead of looking at the target system for what packages were available.
+* Autotools and Libtool Support — the Shairport Sync build process uses GNU `autotools` and `libtool` to examine and configure the build environment — important for portability and for cross compilation. Previous versions of Shairport looked at the current system to determine which packages were available, instead of looking at the target system for what packages were available.
Status
------
@@ -59,7 +59,7 @@ The following procedures will install the shairport-sync application into your s
(If the existing installation of shairport-sync is where the new copy will be installed into, it will be overwritten; sometimes, however, the installation is to another location, so it is safer, initially, to delete previous versions manually.)
**Ubuntu:**
-Personal Package Archives for Shairport Sync master and development branches are available at https://launchpad.net/~dantheperson.
+Personal Package Archives for Shairport Sync master and development branches are available at https://launchpad.net/~dantheperson. A `shairport-sync` installer package is available in Ubuntu 16.04, currently in its alpha phase.
**OpenWrt:**
There is a Shairport Sync package in OpenWrt `trunk`. Also, there's an OpenWrt package at https://github.com/mikebrady/shairport-sync-for-openwrt, including one that builds back to `Barrier Breaker`.
@@ -123,7 +123,7 @@ Debian, Ubuntu and Raspbian users can get the basics with:
- `apt-get install avahi-daemon libavahi-client-dev` if you want to use Avahi (recommended).
- `apt-get install libssl-dev` if you want to use OpenSSL and libcrypto, or use PolarSSL otherwise.
- `apt-get install libpolarssl-dev` if you want to use PolarSSL, or use OpenSSL/libcrypto otherwise.
-- `apt-get install libsoxr-dev` if you want support for libsoxr-based resampling. This library is not yet part of every distribution; instructions for how to build it from source for Raspian/Debian Wheezy are available at [LIBSOXR.md](https://github.com/mikebrady/shairport-sync/blob/development/LIBSOXR.md).
+- `apt-get install libsoxr-dev` if you want support for libsoxr-based resampling. This library is in many recent distributions, including Jessie and Raspioan Jessie; if not, instructions for how to build it from source for Raspian/Debian Wheezy are available at [LIBSOXR.md](https://github.com/mikebrady/shairport-sync/blob/development/LIBSOXR.md).
Download Shairport Sync:
@@ -152,7 +152,7 @@ Choose the appropriate `--with-*` options:
- `--with-configfile` to install a configuration file and a separate sample file at the `make install` stage. Default is to install. An existing `/etc/shairport-sync.conf` will not be overwritten.
- `--with-pkg-config` to use pkg-config to find libraries. Default is to use pkg-config — this option is for special purpose use.
-**System V and `systemd`**
+**`systemd` and "System V"**
At the time of writing, there are two widely-used systems for automatically starting programs automatically at startup: `systemd` and "System V" . (There are others, but they are not considered here.) To see if the `systemd` process is running on your system, enter the following command:
@@ -230,9 +230,11 @@ Configuring Shairport Sync
--------
There are two logically distinct parts to getting Shairport Sync to run properly on your machine — (1) starting and stopping it and (2) ensuring it has the right settings.
-Starting and stopping automatically is taken care of differently in different versions of Linux – see the previous section for an example of installing into a System V or a `systemd` based system.
+**(1) Starting and Stopping:**
+Starting and stopping Shairport Sync automatically is taken care of differently in different versions of Linux – see the previous section for an example of installing into a `systemd` or a System V based system.
-To get the best from Shairport Sync, you’ll need to (1) give Shairport Sync a service name by which it will be seen in iTunes etc., (2) specify the output device to use and (3) specify the name of the mixer volume control to use to control the output level. To get values for (2) and (3) you might need to explore the ALSA output devices with a program like `alsamixer` or similar.
+**(2) Settings:**
+To get the best from Shairport Sync, you’ll need to (a) give Shairport Sync a service name by which it will be seen in iTunes etc., (b) specify the output device to use and (c) specify the name of the mixer volume control to use to control the output level. To get values for (b) and (b) you might need to explore the ALSA output devices with a program like `alsamixer` or similar.
Shairport Sync reads settings from a configuration file at `/etc/shairport-sync.conf`. When you run `$sudo make install`, a sample configuration file is installed (or updated) at `/etc/shairport-sync.conf.sample`. This contains all the setting groups and all the settings available, but they all are commented out (comments begin with `//`) so that default values are used. The file contains explanations of the settings, useful hints and suggestions. In addition, if the file doesn't already exist, a default configuration is installed at `/etc/shairport-sync.conf`, which should work in almost any system with a sound card.