From 7b1c85b40b731e4f9ff1d9f7ca576a0b39b09ef7 Mon Sep 17 00:00:00 2001 From: Chris Boot Date: Sun, 21 Jan 2018 13:02:29 +0000 Subject: Import shairport-sync_3.1.7.orig.tar.gz [dgit import orig shairport-sync_3.1.7.orig.tar.gz] --- .gitignore | 43 + .travis.yml | 34 + AUTHORS | 0 CONTRIBUTING.md | 24 + COPYING | 1 + CYGWIN.md | 49 + ChangeLog | 0 FEDORA.md | 24 + FFTConvolver/AudioFFT.cpp | 1018 ++++++++ FFTConvolver/AudioFFT.h | 176 ++ FFTConvolver/FFTConvolver.cpp | 202 ++ FFTConvolver/FFTConvolver.h | 100 + FFTConvolver/Utilities.cpp | 113 + FFTConvolver/Utilities.h | 352 +++ FFTConvolver/convolver.cpp | 67 + FFTConvolver/convolver.h | 14 + FREEBSD.md | 99 + INSTALL.md | 4 + LIBSOXR.md | 42 + LICENSES | 35 + Makefile.am | 161 ++ NEWS | 1 + README | 0 README.md | 550 +++++ RELEASENOTES.md | 954 +++++++ TROUBLESHOOTING.md | 157 ++ UPDATING.md | 63 + alac.c | 1010 ++++++++ alac.h | 48 + apple_alac.cpp | 58 + apple_alac.h | 20 + audio.c | 187 ++ audio.h | 52 + audio_alsa.c | 1029 ++++++++ audio_ao.c | 138 ++ audio_dummy.c | 68 + audio_pa.c | 407 +++ audio_pipe.c | 141 ++ audio_sndio.c | 269 ++ audio_soundio.c | 224 ++ audio_stdout.c | 86 + common.c | 864 +++++++ common.h | 241 ++ configure.ac | 335 +++ definitions.h | 37 + documents/Fudge Factor Calculation.pdf | Bin 0 -> 15869 bytes .../Shairport Volume Control Transfer Function.pdf | Bin 0 -> 32213 bytes .../Fudge Factor Calculation.graffle | Bin 0 -> 2912 bytes .../Shairport Volume Control Transfer Function.gcx | Bin 0 -> 101748 bytes loudness.c | 50 + loudness.h | 14 + man/Makefile.am | 11 + man/shairport-sync.7 | 418 ++++ man/shairport-sync.7.xml | 852 +++++++ man/shairport-sync.html | 847 +++++++ man/xmltoman.css | 36 + man/xmltoman.dtd | 45 + man/xmltoman.xsl | 135 + mdns.c | 129 + mdns.h | 49 + mdns_avahi.c | 471 ++++ mdns_dns_sd.c | 97 + mdns_external.c | 171 ++ mdns_tinysvcmdns.c | 168 ++ player.c | 2591 ++++++++++++++++++++ player.h | 208 ++ rtp.c | 803 ++++++ rtp.h | 28 + rtsp.c | 2103 ++++++++++++++++ rtsp.h | 24 + scripts/shairport-sync.conf | 146 ++ scripts/shairport-sync.freebsd | 28 + scripts/shairport-sync.in | 175 ++ scripts/shairport-sync.service.in | 15 + shairport-sync.spec | 122 + shairport.c | 1569 ++++++++++++ tinysvcmdns.c | 1736 +++++++++++++ tinysvcmdns.h | 233 ++ 78 files changed, 22771 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 AUTHORS create mode 100644 CONTRIBUTING.md create mode 100644 COPYING create mode 100644 CYGWIN.md create mode 100644 ChangeLog create mode 100644 FEDORA.md create mode 100755 FFTConvolver/AudioFFT.cpp create mode 100755 FFTConvolver/AudioFFT.h create mode 100755 FFTConvolver/FFTConvolver.cpp create mode 100755 FFTConvolver/FFTConvolver.h create mode 100644 FFTConvolver/Utilities.cpp create mode 100644 FFTConvolver/Utilities.h create mode 100644 FFTConvolver/convolver.cpp create mode 100644 FFTConvolver/convolver.h create mode 100644 FREEBSD.md create mode 100644 INSTALL.md create mode 100644 LIBSOXR.md create mode 100644 LICENSES create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 README.md create mode 100644 RELEASENOTES.md create mode 100644 TROUBLESHOOTING.md create mode 100644 UPDATING.md create mode 100644 alac.c create mode 100644 alac.h create mode 100644 apple_alac.cpp create mode 100644 apple_alac.h create mode 100644 audio.c create mode 100644 audio.h create mode 100644 audio_alsa.c create mode 100644 audio_ao.c create mode 100644 audio_dummy.c create mode 100644 audio_pa.c create mode 100644 audio_pipe.c create mode 100644 audio_sndio.c create mode 100644 audio_soundio.c create mode 100644 audio_stdout.c create mode 100644 common.c create mode 100644 common.h create mode 100644 configure.ac create mode 100644 definitions.h create mode 100644 documents/Fudge Factor Calculation.pdf create mode 100644 documents/Shairport Volume Control Transfer Function.pdf create mode 100644 documents/Source Documents/Fudge Factor Calculation.graffle create mode 100644 documents/Source Documents/Shairport Volume Control Transfer Function.gcx create mode 100644 loudness.c create mode 100644 loudness.h create mode 100644 man/Makefile.am create mode 100644 man/shairport-sync.7 create mode 100644 man/shairport-sync.7.xml create mode 100644 man/shairport-sync.html create mode 100644 man/xmltoman.css create mode 100644 man/xmltoman.dtd create mode 100644 man/xmltoman.xsl create mode 100644 mdns.c create mode 100644 mdns.h create mode 100644 mdns_avahi.c create mode 100644 mdns_dns_sd.c create mode 100644 mdns_external.c create mode 100644 mdns_tinysvcmdns.c create mode 100644 player.c create mode 100644 player.h create mode 100644 rtp.c create mode 100644 rtp.h create mode 100644 rtsp.c create mode 100644 rtsp.h create mode 100644 scripts/shairport-sync.conf create mode 100644 scripts/shairport-sync.freebsd create mode 100755 scripts/shairport-sync.in create mode 100644 scripts/shairport-sync.service.in create mode 100644 shairport-sync.spec create mode 100644 shairport.c create mode 100644 tinysvcmdns.c create mode 100644 tinysvcmdns.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ffed6d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +/INSTALL +/shairport-sync +/shairport-sync.exe +/shairport-sync-dbus-test-client +/shairport-sync-mpris-test-client + +*.o +/*~ +*.xml~ +/config.mk +/config.h +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +compile +config.* +configure +depcomp +install-sh +missing +stamp-h1 +.dirstamp +.deps +man/Makefile +man/Makefile.in +scripts/shairport-sync.service +scripts/shairport-sync +shairport-sync.core + +#Some dbus files that are automatically generated +/org.gnome.ShairportSync.service +/dbus-interface.* +/mpris-interface.* +/mpris-player-interface.* + +# Some eclipse project files +.cproject +.project + +# macOS stuff +.DS_Store +shairport-sync.xcodeproj diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..37c4fd6 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,34 @@ +language: c +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=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-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" + +script: + - autoreconf -fi + - ./configure $CFG + - make + +before_install: + - sudo apt-get -qq update + - sudo apt-get install -y libdaemon-dev avahi-daemon libavahi-client-dev + +addons: + apt: + packages: + - libasound2-dev + - libsoxr-dev + - libpopt-dev + - libssl-dev + - libpolarssl-dev + - libconfig-dev + - xmltoman + - libao-dev diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..e69de29 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..ab4d544 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,24 @@ + +Contributing to Shairport Sync +==== + +Pull Requests +---- +If you would like to contribute to the development of Shairport Sync, please make you changes to the `development` branch and make a pull request. + +Changes and additions in the development branch make their way eventually to the `master` branch. + +Issue Reports +---- +Issue reports are welcome, but before you report an issue, please have a look though the existing [issues](https://github.com/mikebrady/shairport-sync/issues), both open and closed, and check for hints in the [TROUBLESHOOTING](TROUBLESHOOTING.md) page. It would be great to give some details of the device and version of Linux or FreeBSD in use along with the version of Shairport Sync you are using (use `$ shairport-sync -V` to get this). Then, if possible, some diagnostic information from the log or logfile would be useful. + +In general, a log verbosity of 2 is adequate (`-vv`, or the relevant entry in the configuration file), and it's usually helpful if statistics have been enabled (`--statistics` on the command line, or the relevant entry in the configuration file). + +If you are pasting in code or a log file, format it as code by preceding it and following it with a line containing exactly three backquotes and nothing else ([see here](https://guides.github.com/features/mastering-markdown/) for more on formatting): + +\`\`\` +``` +code or log file entries +``` +\`\`\` + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..6518e8f --- /dev/null +++ b/COPYING @@ -0,0 +1 @@ +Please refer to the individual source files for licenses. diff --git a/CYGWIN.md b/CYGWIN.md new file mode 100644 index 0000000..3c9027b --- /dev/null +++ b/CYGWIN.md @@ -0,0 +1,49 @@ +Installing to Cygwin +---- + +This is based on installing onto a fresh default installation of Cygwin 2.4.1 (64-bit installation) running in Windows 10 +inside VMWare Fusion on a Mac. + +Note: to enable Cygwin to resolve domain names, it was found necessary to go to Windows `Control Panel` > `Network and Internet` > `Network Connections` > +`Ethernet0` > `Properties` > `Internet Protocol Version 4 (TCP/IPv4)` > `Properties`, select `Use the following DNS server addresses` +and enter valid DNS server addresses, e.g. `8.8.8.8`. + +* Use `Cygwin Setup` to install the following packages: + * `pkg-config` + * `autoconf` + * `automake` + * `clang` + * `libdaemon-devel` + * `popt-devel` + * `make` + * `libao-devel` + * `openssl-devel` + * `libtool` + * `git` + * `wget` for convenience, + * `flex` for compiling `libconfig` + * `bison` for compiling `libconfig` + +* Download, configure, compile and install `libconfig`. + +For this, if your home directory name has a space in it, which happens by default with Cygwin, you should +temporarily rename it to a single word, e.g. `Mike Brady` -> `mike`. This is to allow the `make install` script to work properly. +``` +$ wget http://www.hyperrealm.com/libconfig/libconfig-1.5.tar.gz +$ tar -xvzf libconfig-1.5.tar.gz +$ cd libconfig-1.5 +$ ./configure +$ make +$ make install +$ cd .. +``` +* Next, download, configure and compile Shairport Sync: +``` +$ git clone https://github.com/mikebrady/shairport-sync.git +$ cd shairport-sync +$ autoreconf -fi +$ PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./configure --with-ao --with-ssl=openssl --with-tinysvcmdns +$ make +$ make install +``` +* That's it. There should be a `shairport-sync.exe` file in your directory. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/FEDORA.md b/FEDORA.md new file mode 100644 index 0000000..ae581cb --- /dev/null +++ b/FEDORA.md @@ -0,0 +1,24 @@ +Fedora Installation Guide +----- + +Install the toolchain and pre-requisites, if necessary: +``` +% sudo yum install make automake gcc gcc-c++ kernel-devel +% sudo yum install alsa-lib-devel autoconf automake avahi-devel libconfig-devel libdaemon-devel openssl-devel popt-devel soxr-devel +``` +Download the tarball from the "releases" tab on github or use `wget` and then use `rpmbuild`. This example is for version 2.6: +``` +% wget -O shairport-sync-2.6.tar.gz https://github.com/mikebrady/shairport-sync/archive/2.6.tar.gz +% rpmbuild -ta shairport-sync-2.6.tar.gz +``` +The `-ta` means "build all from this tarball". + +The RPM will be built in a directory and will have a pathname like, for example, `~/rpmbuild/RPMS/i686/shairport-sync-2.6-1.fc22.i686.rpm` You should then install it with (for this example): +``` +%sudo rpm -i ~/rpmbuild/RPMS/i686/shairport-sync-2.6-1.fc22.i686.rpm +``` +You may have to manually create the directory `/var/shairport-sync` for the installation to succeed. Having edited the configuration file `/etc/shairport-sync.conf` as appropriate (see ("Configuring Shairport Sync")[https://github.com/mikebrady/shairport-sync/blob/master/README.md#configuring-shairport-sync]), enable and start the service with: +``` +%sudo systemctl enable shairport-sync.service +%sudo systemctl start shairport-sync.service +``` diff --git a/FFTConvolver/AudioFFT.cpp b/FFTConvolver/AudioFFT.cpp new file mode 100755 index 0000000..32b3dda --- /dev/null +++ b/FFTConvolver/AudioFFT.cpp @@ -0,0 +1,1018 @@ +// ================================================================================== +// Copyright (c) 2016 HiFi-LoFi +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is furnished +// to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ================================================================================== + +#include "AudioFFT.h" + +#include +#include +#include + + +#if defined(AUDIOFFT_APPLE_ACCELERATE) + #define AUDIOFFT_APPLE_ACCELERATE_USED + #include + #include +#elif defined (AUDIOFFT_FFTW3) + #define AUDIOFFT_FFTW3_USED + #include +#else + #if !defined(AUDIOFFT_OOURA) + #define AUDIOFFT_OOURA + #endif + #define AUDIOFFT_OOURA_USED + #include +#endif + + +namespace audiofft +{ + + namespace details + { + + static bool IsPowerOf2(size_t val) + { + return (val == 1 || (val & (val-1)) == 0); + } + + + template + void ConvertBuffer(TypeDest* dest, const TypeSrc* src, size_t len) + { + for (size_t i=0; i(src[i]); + } + } + + + template + void ScaleBuffer(TypeDest* dest, const TypeSrc* src, const TypeFactor factor, size_t len) + { + for (size_t i=0; i(static_cast(src[i]) * factor); + } + } + + + // ================================================================ + + +#ifdef AUDIOFFT_OOURA_USED + + /** + * @internal + * @class OouraFFT + * @brief FFT implementation based on the great radix-4 routines by Takuya Ooura + */ + class OouraFFT : public AudioFFTImpl + { + public: + OouraFFT() : + AudioFFTImpl(), + _size(0), + _ip(), + _w(), + _buffer() + { + } + + virtual void init(size_t size) override + { + if (_size != size) + { + _ip.resize(2 + static_cast(std::sqrt(static_cast(size)))); + _w.resize(size / 2); + _buffer.resize(size); + _size = size; + + const int size4 = static_cast(_size) / 4; + makewt(size4, _ip.data(), _w.data()); + makect(size4, _ip.data(), _w.data() + size4); + } + } + + virtual void fft(const float* data, float* re, float* im) override + { + // Convert into the format as required by the Ooura FFT + ConvertBuffer(&_buffer[0], data, _size); + + rdft(static_cast(_size), +1, _buffer.data(), _ip.data(), _w.data()); + + // Convert back to split-complex + { + double* b = &_buffer[0]; + double* bEnd = b + _size; + float *r = re; + float *i = im; + while (b != bEnd) + { + *(r++) = static_cast(*(b++)); + *(i++) = static_cast(-(*(b++))); + } + } + const size_t size2 = _size / 2; + re[size2] = -im[0]; + im[0] = 0.0; + im[size2] = 0.0; + } + + virtual void ifft(float* data, const float* re, const float* im) override + { + // Convert into the format as required by the Ooura FFT + { + double* b = &_buffer[0]; + double* bEnd = b + _size; + const float *r = re; + const float *i = im; + while (b != bEnd) + { + *(b++) = static_cast(*(r++)); + *(b++) = -static_cast(*(i++)); + } + _buffer[1] = re[_size / 2]; + } + + rdft(static_cast(_size), -1, _buffer.data(), _ip.data(), _w.data()); + + // Convert back to split-complex + ScaleBuffer(data, &_buffer[0], 2.0 / static_cast(_size), _size); + } + + private: + size_t _size; + std::vector _ip; + std::vector _w; + std::vector _buffer; + + void rdft(int n, int isgn, double *a, int *ip, double *w) + { + int nw = ip[0]; + int nc = ip[1]; + + if (isgn >= 0) + { + if (n > 4) + { + bitrv2(n, ip + 2, a); + cftfsub(n, a, w); + rftfsub(n, a, nc, w + nw); + } + else if (n == 4) + { + cftfsub(n, a, w); + } + double xi = a[0] - a[1]; + a[0] += a[1]; + a[1] = xi; + } + else + { + a[1] = 0.5 * (a[0] - a[1]); + a[0] -= a[1]; + if (n > 4) + { + rftbsub(n, a, nc, w + nw); + bitrv2(n, ip + 2, a); + cftbsub(n, a, w); + } + else if (n == 4) + { + cftfsub(n, a, w); + } + } + } + + + /* -------- initializing routines -------- */ + + void makewt(int nw, int *ip, double *w) + { + int j, nwh; + double delta, x, y; + + ip[0] = nw; + ip[1] = 1; + if (nw > 2) { + nwh = nw >> 1; + delta = atan(1.0) / nwh; + w[0] = 1; + w[1] = 0; + w[nwh] = cos(delta * nwh); + w[nwh + 1] = w[nwh]; + if (nwh > 2) { + for (j = 2; j < nwh; j += 2) { + x = cos(delta * j); + y = sin(delta * j); + w[j] = x; + w[j + 1] = y; + w[nw - j] = y; + w[nw - j + 1] = x; + } + bitrv2(nw, ip + 2, w); + } + } + } + + + void makect(int nc, int *ip, double *c) + { + int j, nch; + double delta; + + ip[1] = nc; + if (nc > 1) { + nch = nc >> 1; + delta = atan(1.0) / nch; + c[0] = cos(delta * nch); + c[nch] = 0.5 * c[0]; + for (j = 1; j < nch; j++) { + c[j] = 0.5 * cos(delta * j); + c[nc - j] = 0.5 * sin(delta * j); + } + } + } + + + /* -------- child routines -------- */ + + + void bitrv2(int n, int *ip, double *a) + { + int j, j1, k, k1, l, m, m2; + double xr, xi, yr, yi; + + ip[0] = 0; + l = n; + m = 1; + while ((m << 3) < l) { + l >>= 1; + for (j = 0; j < m; j++) { + ip[m + j] = ip[j] + l; + } + m <<= 1; + } + m2 = 2 * m; + if ((m << 3) == l) { + for (k = 0; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 -= m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + j1 = 2 * k + m2 + ip[k]; + k1 = j1 + m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + } else { + for (k = 1; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + } + } + } + + + void cftfsub(int n, double *a, double *w) + { + int j, j1, j2, j3, l; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + l = 2; + if (n > 8) { + cft1st(n, a, w); + l = 8; + while ((l << 2) < n) { + cftmdl(n, l, a, w); + l <<= 2; + } + } + if ((l << 2) == n) { + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } + } else { + for (j = 0; j < l; j += 2) { + j1 = j + l; + x0r = a[j] - a[j1]; + x0i = a[j + 1] - a[j1 + 1]; + a[j] += a[j1]; + a[j + 1] += a[j1 + 1]; + a[j1] = x0r; + a[j1 + 1] = x0i; + } + } + } + + + void cftbsub(int n, double *a, double *w) + { + int j, j1, j2, j3, l; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + l = 2; + if (n > 8) { + cft1st(n, a, w); + l = 8; + while ((l << 2) < n) { + cftmdl(n, l, a, w); + l <<= 2; + } + } + if ((l << 2) == n) { + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = -a[j + 1] - a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = -a[j + 1] + a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i - x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i + x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i - x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i + x3r; + } + } else { + for (j = 0; j < l; j += 2) { + j1 = j + l; + x0r = a[j] - a[j1]; + x0i = -a[j + 1] + a[j1 + 1]; + a[j] += a[j1]; + a[j + 1] = -a[j + 1] - a[j1 + 1]; + a[j1] = x0r; + a[j1 + 1] = x0i; + } + } + } + + + void cft1st(int n, double *a, double *w) + { + int j, k1, k2; + double wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + x0r = a[0] + a[2]; + x0i = a[1] + a[3]; + x1r = a[0] - a[2]; + x1i = a[1] - a[3]; + x2r = a[4] + a[6]; + x2i = a[5] + a[7]; + x3r = a[4] - a[6]; + x3i = a[5] - a[7]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[4] = x0r - x2r; + a[5] = x0i - x2i; + a[2] = x1r - x3i; + a[3] = x1i + x3r; + a[6] = x1r + x3i; + a[7] = x1i - x3r; + wk1r = w[2]; + x0r = a[8] + a[10]; + x0i = a[9] + a[11]; + x1r = a[8] - a[10]; + x1i = a[9] - a[11]; + x2r = a[12] + a[14]; + x2i = a[13] + a[15]; + x3r = a[12] - a[14]; + x3i = a[13] - a[15]; + a[8] = x0r + x2r; + a[9] = x0i + x2i; + a[12] = x2i - x0i; + a[13] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[10] = wk1r * (x0r - x0i); + a[11] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[14] = wk1r * (x0i - x0r); + a[15] = wk1r * (x0i + x0r); + k1 = 0; + for (j = 16; j < n; j += 16) { + k1 += 2; + k2 = 2 * k1; + wk2r = w[k1]; + wk2i = w[k1 + 1]; + wk1r = w[k2]; + wk1i = w[k2 + 1]; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + x0r = a[j] + a[j + 2]; + x0i = a[j + 1] + a[j + 3]; + x1r = a[j] - a[j + 2]; + x1i = a[j + 1] - a[j + 3]; + x2r = a[j + 4] + a[j + 6]; + x2i = a[j + 5] + a[j + 7]; + x3r = a[j + 4] - a[j + 6]; + x3i = a[j + 5] - a[j + 7]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 4] = wk2r * x0r - wk2i * x0i; + a[j + 5] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 2] = wk1r * x0r - wk1i * x0i; + a[j + 3] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 6] = wk3r * x0r - wk3i * x0i; + a[j + 7] = wk3r * x0i + wk3i * x0r; + wk1r = w[k2 + 2]; + wk1i = w[k2 + 3]; + wk3r = wk1r - 2 * wk2r * wk1i; + wk3i = 2 * wk2r * wk1r - wk1i; + x0r = a[j + 8] + a[j + 10]; + x0i = a[j + 9] + a[j + 11]; + x1r = a[j + 8] - a[j + 10]; + x1i = a[j + 9] - a[j + 11]; + x2r = a[j + 12] + a[j + 14]; + x2i = a[j + 13] + a[j + 15]; + x3r = a[j + 12] - a[j + 14]; + x3i = a[j + 13] - a[j + 15]; + a[j + 8] = x0r + x2r; + a[j + 9] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 12] = -wk2i * x0r - wk2r * x0i; + a[j + 13] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 10] = wk1r * x0r - wk1i * x0i; + a[j + 11] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 14] = wk3r * x0r - wk3i * x0i; + a[j + 15] = wk3r * x0i + wk3i * x0r; + } + } + + + void cftmdl(int n, int l, double *a, double *w) + { + int j, j1, j2, j3, k, k1, k2, m, m2; + double wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + m = l << 2; + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } + wk1r = w[2]; + for (j = m; j < l + m; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x2i - x0i; + a[j2 + 1] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * (x0r - x0i); + a[j1 + 1] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[j3] = wk1r * (x0i - x0r); + a[j3 + 1] = wk1r * (x0i + x0r); + } + k1 = 0; + m2 = 2 * m; + for (k = m2; k < n; k += m2) { + k1 += 2; + k2 = 2 * k1; + wk2r = w[k1]; + wk2i = w[k1 + 1]; + wk1r = w[k2]; + wk1i = w[k2 + 1]; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + for (j = k; j < l + k; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2] = wk2r * x0r - wk2i * x0i; + a[j2 + 1] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + wk1r = w[k2 + 2]; + wk1i = w[k2 + 3]; + wk3r = wk1r - 2 * wk2r * wk1i; + wk3i = 2 * wk2r * wk1r - wk1i; + for (j = k + m; j < l + (k + m); j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2] = -wk2i * x0r - wk2r * x0i; + a[j2 + 1] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + } + } + + + void rftfsub(int n, double *a, int nc, double *c) + { + int j, k, kk, ks, m; + double wkr, wki, xr, xi, yr, yi; + + m = n >> 1; + ks = 2 * nc / m; + kk = 0; + for (j = 2; j < m; j += 2) { + k = n - j; + kk += ks; + wkr = 0.5 - c[nc - kk]; + wki = c[kk]; + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = wkr * xr - wki * xi; + yi = wkr * xi + wki * xr; + a[j] -= yr; + a[j + 1] -= yi; + a[k] += yr; + a[k + 1] -= yi; + } + } + + + void rftbsub(int n, double *a, int nc, double *c) + { + int j, k, kk, ks, m; + double wkr, wki, xr, xi, yr, yi; + + a[1] = -a[1]; + m = n >> 1; + ks = 2 * nc / m; + kk = 0; + for (j = 2; j < m; j += 2) { + k = n - j; + kk += ks; + wkr = 0.5 - c[nc - kk]; + wki = c[kk]; + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = wkr * xr + wki * xi; + yi = wkr * xi - wki * xr; + a[j] -= yr; + a[j + 1] = yi - a[j + 1]; + a[k] += yr; + a[k + 1] = yi - a[k + 1]; + } + a[m + 1] = -a[m + 1]; + } + + OouraFFT(const OouraFFT&) = delete; + OouraFFT& operator=(const OouraFFT&) = delete; + }; + + std::unique_ptr MakeAudioFFTImpl() + { + return std::unique_ptr(new OouraFFT()); + } + + +#endif // AUDIOFFT_OOURA_USED + + + // ================================================================ + + +#ifdef AUDIOFFT_APPLE_ACCELERATE_USED + + + /** + * @internal + * @class AppleAccelerateFFT + * @brief FFT implementation using the Apple Accelerate framework internally + */ + class AppleAccelerateFFT : public AudioFFTImpl + { + public: + AppleAccelerateFFT() : + AudioFFTImpl(), + _size(0), + _powerOf2(0), + _fftSetup(0), + _re(), + _im() + { + } + + virtual ~AppleAccelerateFFT() + { + init(0); + } + + virtual void init(size_t size) override + { + if (_fftSetup) + { + vDSP_destroy_fftsetup(_fftSetup); + _size = 0; + _powerOf2 = 0; + _fftSetup = 0; + _re.clear(); + _im.clear(); + } + + if (size > 0) + { + _size = size; + _powerOf2 = 0; + while ((1 << _powerOf2) < _size) + { + ++_powerOf2; + } + _fftSetup = vDSP_create_fftsetup(_powerOf2, FFT_RADIX2); + _re.resize(_size / 2); + _im.resize(_size / 2); + } + } + + virtual void fft(const float* data, float* re, float* im) override + { + const size_t size2 = _size / 2; + DSPSplitComplex splitComplex; + splitComplex.realp = re; + splitComplex.imagp = im; + vDSP_ctoz(reinterpret_cast(data), 2, &splitComplex, 1, size2); + vDSP_fft_zrip(_fftSetup, &splitComplex, 1, _powerOf2, FFT_FORWARD); + const float factor = 0.5f; + vDSP_vsmul(re, 1, &factor, re, 1, size2); + vDSP_vsmul(im, 1, &factor, im, 1, size2); + re[size2] = im[0]; + im[0] = 0.0f; + im[size2] = 0.0f; + } + + virtual void ifft(float* data, const float* re, const float* im) override + { + const size_t size2 = _size / 2; + ::memcpy(_re.data(), re, size2 * sizeof(float)); + ::memcpy(_im.data(), im, size2 * sizeof(float)); + _im[0] = re[size2]; + DSPSplitComplex splitComplex; + splitComplex.realp = _re.data(); + splitComplex.imagp = _im.data(); + vDSP_fft_zrip(_fftSetup, &splitComplex, 1, _powerOf2, FFT_INVERSE); + vDSP_ztoc(&splitComplex, 1, reinterpret_cast(data), 2, size2); + const float factor = 1.0f / static_cast(_size); + vDSP_vsmul(data, 1, &factor, data, 1, _size); + } + + private: + size_t _size; + size_t _powerOf2; + FFTSetup _fftSetup; + std::vector _re; + std::vector _im; + + AppleAccelerateFFT(const AppleAccelerateFFT&) = delete; + AppleAccelerateFFT& operator=(const AppleAccelerateFFT&) = delete; + }; + + + std::unique_ptr MakeAudioFFTImpl() + { + return std::unique_ptr(new AppleAccelerateFFT()); + } + + +#endif // AUDIOFFT_APPLE_ACCELERATE_USED + + + // ================================================================ + + +#ifdef AUDIOFFT_FFTW3_USED + + + /** + * @internal + * @class FFTW3FFT + * @brief FFT implementation using FFTW3 internally (see fftw.org) + */ + class FFTW3FFT : public AudioFFTImpl + { + public: + FFTW3FFT() : + AudioFFTImpl(), + _size(0), + _complexSize(0), + _planForward(0), + _planBackward(0), + _data(0), + _re(0), + _im(0) + { + } + + virtual ~FFTW3FFT() + { + init(0); + } + + virtual void init(size_t size) override + { + if (_size != size) + { + if (_size > 0) + { + fftwf_destroy_plan(_planForward); + fftwf_destroy_plan(_planBackward); + _planForward = 0; + _planBackward = 0; + _size = 0; + _complexSize = 0; + + if (_data) + { + fftwf_free(_data); + _data = 0; + } + + if (_re) + { + fftwf_free(_re); + _re = 0; + } + + if (_im) + { + fftwf_free(_im); + _im = 0; + } + } + + if (size > 0) + { + _size = size; + _complexSize = AudioFFT::ComplexSize(_size); + const size_t complexSize = AudioFFT::ComplexSize(_size); + _data = reinterpret_cast(fftwf_malloc(_size * sizeof(float))); + _re = reinterpret_cast(fftwf_malloc(complexSize * sizeof(float))); + _im = reinterpret_cast(fftwf_malloc(complexSize * sizeof(float))); + + fftw_iodim dim; + dim.n = static_cast(size); + dim.is = 1; + dim.os = 1; + _planForward = fftwf_plan_guru_split_dft_r2c(1, &dim, 0, 0, _data, _re, _im, FFTW_MEASURE); + _planBackward = fftwf_plan_guru_split_dft_c2r(1, &dim, 0, 0, _re, _im, _data, FFTW_MEASURE); + } + } + } + + virtual void fft(const float* data, float* re, float* im) override + { + ::memcpy(_data, data, _size * sizeof(float)); + fftwf_execute_split_dft_r2c(_planForward, _data, _re, _im); + ::memcpy(re, _re, _complexSize * sizeof(float)); + ::memcpy(im, _im, _complexSize * sizeof(float)); + } + + void ifft(float* data, const float* re, const float* im) + { + ::memcpy(_re, re, _complexSize * sizeof(float)); + ::memcpy(_im, im, _complexSize * sizeof(float)); + fftwf_execute_split_dft_c2r(_planBackward, _re, _im, _data); + ScaleBuffer(data, _data, 1.0f / static_cast(_size), _size); + } + + private: + size_t _size; + size_t _complexSize; + fftwf_plan _planForward; + fftwf_plan _planBackward; + float* _data; + float* _re; + float* _im; + + FFTW3FFT(const FFTW3FFT&) = delete; + FFTW3FFT& operator=(const FFTW3FFT&) = delete; + }; + + + std::unique_ptr MakeAudioFFTImpl() + { + return std::unique_ptr(new FFTW3FFT()); + } + + +#endif // AUDIOFFT_FFTW3_USED + + } // End of namespace details + + + // ============================================================= + + + AudioFFT::AudioFFT() : + _impl(details::MakeAudioFFTImpl()) + { + } + + + void AudioFFT::init(size_t size) + { + assert(details::IsPowerOf2(size)); + _impl->init(size); + } + + + void AudioFFT::fft(const float* data, float* re, float* im) + { + _impl->fft(data, re, im); + } + + + void AudioFFT::ifft(float* data, const float* re, const float* im) + { + _impl->ifft(data, re, im); + } + + + size_t AudioFFT::ComplexSize(size_t size) + { + return (size / 2) + 1; + } + +} // End of namespace diff --git a/FFTConvolver/AudioFFT.h b/FFTConvolver/AudioFFT.h new file mode 100755 index 0000000..80cd2ed --- /dev/null +++ b/FFTConvolver/AudioFFT.h @@ -0,0 +1,176 @@ +// ================================================================================== +// Copyright (c) 2016 HiFi-LoFi +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is furnished +// to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ================================================================================== + +#ifndef _AUDIOFFT_H +#define _AUDIOFFT_H + + +/** +* AudioFFT provides real-to-complex/complex-to-real FFT routines. +* +* Features: +* +* - Real-complex FFT and complex-real inverse FFT for power-of-2-sized real data. +* +* - Uniform interface to different FFT implementations (currently Ooura, FFTW3 and Apple Accelerate). +* +* - Complex data is handled in "split-complex" format, i.e. there are separate +* arrays for the real and imaginary parts which can be useful for SIMD optimizations +* (split-complex arrays have to be of length (size/2+1) representing bins from DC +* to Nyquist frequency). +* +* - Output is "ready to use" (all scaling etc. is already handled internally). +* +* - No allocations/deallocations after the initialization which makes it usable +* for real-time audio applications (that's what I wrote it for and using it). +* +* +* How to use it in your project: +* +* - Add the .h and .cpp file to your project - that's all. +* +* - To get extra speed, you can link FFTW3 to your project and define +* AUDIOFFT_FFTW3 (however, please check whether your project suits the +* according license). +* +* - To get the best speed on Apple platforms, you can link the Apple +* Accelerate framework to your project and define +* AUDIOFFT_APPLE_ACCELERATE (however, please check whether your +* project suits the according license). +* +* +* Remarks: +* +* - AudioFFT is not intended to be the fastest FFT, but to be a fast-enough +* FFT suitable for most audio applications. +* +* - AudioFFT uses the quite liberal MIT license. +* +* +* Example usage: +* @code +* #include "AudioFFT.h" +* +* void Example() +* { +* const size_t fftSize = 1024; // Needs to be power of 2! +* +* std::vector input(fftSize, 0.0f); +* std::vector re(audiofft::AudioFFT::ComplexSize(fftSize)); +* std::vector im(audiofft::AudioFFT::ComplexSize(fftSize)); +* std::vector output(fftSize); +* +* audiofft::AudioFFT fft; +* fft.init(1024); +* fft.fft(input.data(), re.data(), im.data()); +* fft.ifft(output.data(), re.data(), im.data()); +* } +* @endcode +*/ + + +#include +#include + + +namespace audiofft +{ + + namespace details + { + + class AudioFFTImpl + { + public: + AudioFFTImpl() = default; + virtual ~AudioFFTImpl() = default; + virtual void init(size_t size) = 0; + virtual void fft(const float* data, float* re, float* im) = 0; + virtual void ifft(float* data, const float* re, const float* im) = 0; + + private: + AudioFFTImpl(const AudioFFTImpl&) = delete; + AudioFFTImpl& operator=(const AudioFFTImpl&) = delete; + }; + } + + + // ====================================================== + + + /** + * @class AudioFFT + * @brief Performs 1D FFTs + */ + class AudioFFT + { + public: + /** + * @brief Constructor + */ + AudioFFT(); + + /** + * @brief Initializes the FFT object + * @param size Size of the real input (must be power 2) + */ + void init(size_t size); + + /** + * @brief Performs the forward FFT + * @param data The real input data (has to be of the length as specified in init()) + * @param re The real part of the complex output (has to be of length as returned by ComplexSize()) + * @param im The imaginary part of the complex output (has to be of length as returned by ComplexSize()) + */ + void fft(const float* data, float* re, float* im); + + /** + * @brief Performs the inverse FFT + * @param data The real output data (has to be of the length as specified in init()) + * @param re The real part of the complex input (has to be of length as returned by ComplexSize()) + * @param im The imaginary part of the complex input (has to be of length as returned by ComplexSize()) + */ + void ifft(float* data, const float* re, const float* im); + + /** + * @brief Calculates the necessary size of the real/imaginary complex arrays + * @param size The size of the real data + * @return The size of the real/imaginary complex arrays + */ + static size_t ComplexSize(size_t size); + + private: + std::unique_ptr _impl; + + AudioFFT(const AudioFFT&) = delete; + AudioFFT& operator=(const AudioFFT&) = delete; + }; + + + /** + * @deprecated + * @brief Let's keep an AudioFFTBase type around for now because it has been here already in the 1st version in order to avoid breaking existing code. + */ + typedef AudioFFT AudioFFTBase; + +} // End of namespace + +#endif // Header guard diff --git a/FFTConvolver/FFTConvolver.cpp b/FFTConvolver/FFTConvolver.cpp new file mode 100755 index 0000000..049dbed --- /dev/null +++ b/FFTConvolver/FFTConvolver.cpp @@ -0,0 +1,202 @@ +// ================================================================================== +// Copyright (c) 2012 HiFi-LoFi +// +// This is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ================================================================================== + +#include "FFTConvolver.h" + +#include +#include + +#if defined (FFTCONVOLVER_USE_SSE) + #include +#endif + + +namespace fftconvolver +{ + +FFTConvolver::FFTConvolver() : + _blockSize(0), + _segSize(0), + _segCount(0), + _fftComplexSize(0), + _segments(), + _segmentsIR(), + _fftBuffer(), + _fft(), + _preMultiplied(), + _conv(), + _overlap(), + _current(0), + _inputBuffer(), + _inputBufferFill(0) +{ +} + + +FFTConvolver::~FFTConvolver() +{ + reset(); +} + + +void FFTConvolver::reset() +{ + for (size_t i=0; i<_segCount; ++i) + { + delete _segments[i]; + delete _segmentsIR[i]; + } + + _blockSize = 0; + _segSize = 0; + _segCount = 0; + _fftComplexSize = 0; + _segments.clear(); + _segmentsIR.clear(); + _fftBuffer.clear(); + _fft.init(0); + _preMultiplied.clear(); + _conv.clear(); + _overlap.clear(); + _current = 0; + _inputBuffer.clear(); + _inputBufferFill = 0; +} + + +bool FFTConvolver::init(size_t blockSize, const Sample* ir, size_t irLen) +{ + reset(); + + if (blockSize == 0) + { + return false; + } + + // Ignore zeros at the end of the impulse response because they only waste computation time + while (irLen > 0 && ::fabs(ir[irLen-1]) < 0.000001f) + { + --irLen; + } + + if (irLen == 0) + { + return true; + } + + _blockSize = NextPowerOf2(blockSize); + _segSize = 2 * _blockSize; + _segCount = static_cast(::ceil(static_cast(irLen) / static_cast(_blockSize))); + _fftComplexSize = audiofft::AudioFFT::ComplexSize(_segSize); + + // FFT + _fft.init(_segSize); + _fftBuffer.resize(_segSize); + + // Prepare segments + for (size_t i=0; i<_segCount; ++i) + { + _segments.push_back(new SplitComplex(_fftComplexSize)); + } + + // Prepare IR + for (size_t i=0; i<_segCount; ++i) + { + SplitComplex* segment = new SplitComplex(_fftComplexSize); + const size_t remaining = irLen - (i * _blockSize); + const size_t sizeCopy = (remaining >= _blockSize) ? _blockSize : remaining; + CopyAndPad(_fftBuffer, &ir[i*_blockSize], sizeCopy); + _fft.fft(_fftBuffer.data(), segment->re(), segment->im()); + _segmentsIR.push_back(segment); + } + + // Prepare convolution buffers + _preMultiplied.resize(_fftComplexSize); + _conv.resize(_fftComplexSize); + _overlap.resize(_blockSize); + + // Prepare input buffer + _inputBuffer.resize(_blockSize); + _inputBufferFill = 0; + + // Reset current position + _current = 0; + + return true; +} + + +void FFTConvolver::process(const Sample* input, Sample* output, size_t len) +{ + if (_segCount == 0) + { + ::memset(output, 0, len * sizeof(Sample)); + return; + } + + size_t processed = 0; + while (processed < len) + { + const bool inputBufferWasEmpty = (_inputBufferFill == 0); + const size_t processing = std::min(len-processed, _blockSize-_inputBufferFill); + const size_t inputBufferPos = _inputBufferFill; + ::memcpy(_inputBuffer.data()+inputBufferPos, input+processed, processing * sizeof(Sample)); + + // Forward FFT + CopyAndPad(_fftBuffer, &_inputBuffer[0], _blockSize); + _fft.fft(_fftBuffer.data(), _segments[_current]->re(), _segments[_current]->im()); + + // Complex multiplication + if (inputBufferWasEmpty) + { + _preMultiplied.setZero(); + for (size_t i=1; i<_segCount; ++i) + { + const size_t indexIr = i; + const size_t indexAudio = (_current + i) % _segCount; + ComplexMultiplyAccumulate(_preMultiplied, *_segmentsIR[indexIr], *_segments[indexAudio]); + } + } + _conv.copyFrom(_preMultiplied); + ComplexMultiplyAccumulate(_conv, *_segments[_current], *_segmentsIR[0]); + + // Backward FFT + _fft.ifft(_fftBuffer.data(), _conv.re(), _conv.im()); + + // Add overlap + Sum(output+processed, _fftBuffer.data()+inputBufferPos, _overlap.data()+inputBufferPos, processing); + + // Input buffer full => Next block + _inputBufferFill += processing; + if (_inputBufferFill == _blockSize) + { + // Input buffer is empty again now + _inputBuffer.setZero(); + _inputBufferFill = 0; + + // Save the overlap + ::memcpy(_overlap.data(), _fftBuffer.data()+_blockSize, _blockSize * sizeof(Sample)); + + // Update current segment + _current = (_current > 0) ? (_current - 1) : (_segCount - 1); + } + + processed += processing; + } +} + +} // End of namespace fftconvolver diff --git a/FFTConvolver/FFTConvolver.h b/FFTConvolver/FFTConvolver.h new file mode 100755 index 0000000..0c44608 --- /dev/null +++ b/FFTConvolver/FFTConvolver.h @@ -0,0 +1,100 @@ +// ================================================================================== +// Copyright (c) 2012 HiFi-LoFi +// +// This is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ================================================================================== + +#ifndef _FFTCONVOLVER_FFTCONVOLVER_H +#define _FFTCONVOLVER_FFTCONVOLVER_H + +#include "AudioFFT.h" +#include "Utilities.h" + +#include + + +namespace fftconvolver +{ + +/** +* @class FFTConvolver +* @brief Implementation of a partitioned FFT convolution algorithm with uniform block size +* +* Some notes on how to use it: +* +* - After initialization with an impulse response, subsequent data portions of +* arbitrary length can be convolved. The convolver internally can handle +* this by using appropriate buffering. +* +* - The convolver works without "latency" (except for the required +* processing time, of course), i.e. the output always is the convolved +* input for each processing call. +* +* - The convolver is suitable for real-time processing which means that no +* "unpredictable" operations like allocations, locking, API calls, etc. are +* performed during processing (all necessary allocations and preparations take +* place during initialization). +*/ +class FFTConvolver +{ +public: + FFTConvolver(); + virtual ~FFTConvolver(); + + /** + * @brief Initializes the convolver + * @param blockSize Block size internally used by the convolver (partition size) + * @param ir The impulse response + * @param irLen Length of the impulse response + * @return true: Success - false: Failed + */ + bool init(size_t blockSize, const Sample* ir, size_t irLen); + + /** + * @brief Convolves the the given input samples and immediately outputs the result + * @param input The input samples + * @param output The convolution result + * @param len Number of input/output samples + */ + void process(const Sample* input, Sample* output, size_t len); + + /** + * @brief Resets the convolver and discards the set impulse response + */ + void reset(); + +private: + size_t _blockSize; + size_t _segSize; + size_t _segCount; + size_t _fftComplexSize; + std::vector _segments; + std::vector _segmentsIR; + SampleBuffer _fftBuffer; + audiofft::AudioFFT _fft; + SplitComplex _preMultiplied; + SplitComplex _conv; + SampleBuffer _overlap; + size_t _current; + SampleBuffer _inputBuffer; + size_t _inputBufferFill; + + // Prevent uncontrolled usage + FFTConvolver(const FFTConvolver&); + FFTConvolver& operator=(const FFTConvolver&); +}; + +} // End of namespace fftconvolver + +#endif // Header guard diff --git a/FFTConvolver/Utilities.cpp b/FFTConvolver/Utilities.cpp new file mode 100644 index 0000000..a30ff14 --- /dev/null +++ b/FFTConvolver/Utilities.cpp @@ -0,0 +1,113 @@ +// ================================================================================== +// Copyright (c) 2012 HiFi-LoFi +// +// This is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ================================================================================== + +#include "Utilities.h" + + +namespace fftconvolver +{ + +bool SSEEnabled() +{ +#if defined(FFTCONVOLVER_USE_SSE) + return true; +#else + return false; +#endif +} + + +void Sum(Sample* FFTCONVOLVER_RESTRICT result, + const Sample* FFTCONVOLVER_RESTRICT a, + const Sample* FFTCONVOLVER_RESTRICT b, + size_t len) +{ + const size_t end4 = 4 * (len / 4); + for (size_t i=0; i. +// ================================================================================== + +#ifndef _FFTCONVOLVER_UTILITIES_H +#define _FFTCONVOLVER_UTILITIES_H + +#include +#include +#include +#include +#include + + +namespace fftconvolver +{ + +#if defined(__SSE__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2) + #if !defined(FFTCONVOLVER_USE_SSE) && !defined(FFTCONVOLVER_DONT_USE_SSE) + #define FFTCONVOLVER_USE_SSE + #endif +#endif + + +#if defined (FFTCONVOLVER_USE_SSE) + #include +#endif + + +#if defined(__GNUC__) + #define FFTCONVOLVER_RESTRICT __restrict__ +#else + #define FFTCONVOLVER_RESTRICT +#endif + + +/** +* @brief Returns whether SSE optimization for the convolver is enabled +* @return true: Enabled - false: Disabled +*/ +bool SSEEnabled(); + + +/** +* @class Buffer +* @brief Simple buffer implementation (uses 16-byte alignment if SSE optimization is enabled) +*/ +template +class Buffer +{ +public: + explicit Buffer(size_t initialSize = 0) : + _data(0), + _size(0) + { + resize(initialSize); + } + + virtual ~Buffer() + { + clear(); + } + + void clear() + { + deallocate(_data); + _data = 0; + _size = 0; + } + + void resize(size_t size) + { + if (_size != size) + { + clear(); + + if (size > 0) + { + assert(!_data && _size == 0); + _data = allocate(size); + _size = size; + } + } + if (_data) + setZero(); + } + + size_t size() const + { + return _size; + } + + void setZero() + { + ::memset(_data, 0, _size * sizeof(T)); + } + + void copyFrom(const Buffer& other) + { + assert(_size == other._size); + if (this != &other) + { + ::memcpy(_data, other._data, _size * sizeof(T)); + } + } + + T& operator[](size_t index) + { + assert(_data && index < _size); + return _data[index]; + } + + const T& operator[](size_t index) const + { + assert(_data && index < _size); + return _data[index]; + } + + operator bool() const + { + return (_data != 0 && _size > 0); + } + + T* data() + { + return _data; + } + + const T* data() const + { + return _data; + } + + static void Swap(Buffer& a, Buffer& b) + { + std::swap(a._data, b._data); + std::swap(a._size, b._size); + } + +private: + T* allocate(size_t size) + { +#if defined(FFTCONVOLVER_USE_SSE) + return static_cast(_mm_malloc(size * sizeof(T), 16)); +#else + return new T[size]; +#endif + } + + void deallocate(T* ptr) + { +#if defined(FFTCONVOLVER_USE_SSE) + _mm_free(ptr); +#else + delete [] ptr; +#endif + } + + T* _data; + size_t _size; + + // Prevent uncontrolled usage + Buffer(const Buffer&); + Buffer& operator=(const Buffer&); +}; + + +/** +* @brief Type of one sample +*/ +typedef float Sample; + + +/** +* @brief Buffer for samples +*/ +typedef Buffer SampleBuffer; + + +/** +* @class SplitComplex +* @brief Buffer for split-complex representation of FFT results +* +* The split-complex representation stores the real and imaginary parts +* of FFT results in two different memory buffers which is useful e.g. for +* SIMD optimizations. +*/ +class SplitComplex +{ +public: + explicit SplitComplex(size_t initialSize = 0) : + _size(0), + _re(), + _im() + { + resize(initialSize); + } + + ~SplitComplex() + { + clear(); + } + + void clear() + { + _re.clear(); + _im.clear(); + _size = 0; + } + + void resize(size_t newSize) + { + _re.resize(newSize); + _im.resize(newSize); + _size = newSize; + } + + void setZero() + { + _re.setZero(); + _im.setZero(); + } + + void copyFrom(const SplitComplex& other) + { + _re.copyFrom(other._re); + _im.copyFrom(other._im); + } + + Sample* re() + { + return _re.data(); + } + + const Sample* re() const + { + return _re.data(); + } + + Sample* im() + { + return _im.data(); + } + + const Sample* im() const + { + return _im.data(); + } + + size_t size() const + { + return _size; + } + +private: + size_t _size; + SampleBuffer _re; + SampleBuffer _im; + + // Prevent uncontrolled usage + SplitComplex(const SplitComplex&); + SplitComplex& operator=(const SplitComplex&); +}; + + +/** +* @brief Returns the next power of 2 of a given number +* @param val The number +* @return The next power of 2 +*/ +template +T NextPowerOf2(const T& val) +{ + T nextPowerOf2 = 1; + while (nextPowerOf2 < val) + { + nextPowerOf2 *= 2; + } + return nextPowerOf2; +} + + +/** +* @brief Sums two given sample arrays +* @param result The result array +* @param a The 1st array +* @param b The 2nd array +* @param len The length of the arrays +*/ +void Sum(Sample* FFTCONVOLVER_RESTRICT result, + const Sample* FFTCONVOLVER_RESTRICT a, + const Sample* FFTCONVOLVER_RESTRICT b, + size_t len); + + +/** +* @brief Copies a source array into a destination buffer and pads the destination buffer with zeros +* @param dest The destination buffer +* @param src The source array +* @param srcSize The size of the source array +*/ +template +void CopyAndPad(Buffer& dest, const T* src, size_t srcSize) +{ + assert(dest.size() >= srcSize); + ::memcpy(dest.data(), src, srcSize * sizeof(T)); + ::memset(dest.data() + srcSize, 0, (dest.size()-srcSize) * sizeof(T)); +} + + +/** +* @brief Adds the complex product of two split-complex buffers to a result buffer +* @param result The result buffer +* @param a The 1st factor of the complex product +* @param b The 2nd factor of the complex product +*/ +void ComplexMultiplyAccumulate(SplitComplex& result, const SplitComplex& a, const SplitComplex& b); + + +/** +* @brief Adds the complex product of two split-complex arrays to a result array +* @param re The real part of the result buffer +* @param im The imaginary part of the result buffer +* @param reA The real part of the 1st factor of the complex product +* @param imA The imaginary part of the 1st factor of the complex product +* @param reB The real part of the 2nd factor of the complex product +* @param imB The imaginary part of the 2nd factor of the complex product +*/ +void ComplexMultiplyAccumulate(Sample* FFTCONVOLVER_RESTRICT re, + Sample* FFTCONVOLVER_RESTRICT im, + const Sample* FFTCONVOLVER_RESTRICT reA, + const Sample* FFTCONVOLVER_RESTRICT imA, + const Sample* FFTCONVOLVER_RESTRICT reB, + const Sample* FFTCONVOLVER_RESTRICT imB, + const size_t len); + +} // End of namespace fftconvolver + +#endif // Header guard diff --git a/FFTConvolver/convolver.cpp b/FFTConvolver/convolver.cpp new file mode 100644 index 0000000..4589c8e --- /dev/null +++ b/FFTConvolver/convolver.cpp @@ -0,0 +1,67 @@ + + +#include "convolver.h" +#include +#include "FFTConvolver.h" +#include "Utilities.h" +extern "C" { +#include "../common.h" +} + + +static fftconvolver::FFTConvolver convolver_l; +static fftconvolver::FFTConvolver convolver_r; + + +void convolver_init(const char* filename, int max_length) +{ + SF_INFO info; + assert(filename); + SNDFILE* file = sf_open(filename, SFM_READ, &info); + assert(file); + + if (info.samplerate != 44100) + die("Impulse file \"%s\" sample rate is %d Hz. Only 44100 Hz is supported", filename, info.samplerate); + + if (info.channels != 1 && info.channels != 2) + die("Impulse file \"%s\" contains %d channels. Only 1 or 2 is supported.", filename, info.channels); + + const size_t size = info.frames > max_length ? max_length : info.frames; + float buffer[size*info.channels]; + + size_t l = sf_readf_float(file, buffer, size); + assert(l == size); + + if (info.channels == 1) { + convolver_l.init(352, buffer, size); + convolver_r.init(352, buffer, size); + } else { + // deinterleave + float buffer_l[size]; + float buffer_r[size]; + + int i; + for (i=0; i + +Shairport Sync: + Copyright (c) 2014–2017 Mike Brady + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..48ef77a --- /dev/null +++ b/Makefile.am @@ -0,0 +1,161 @@ +SUBDIRS = man + +bin_PROGRAMS = shairport-sync + +# See below for the flags for the test client program + +shairport_sync_SOURCES = shairport.c rtsp.c mdns.c mdns_external.c common.c rtp.c player.c alac.c audio.c loudness.c + +AM_CFLAGS = -Wno-multichar -DSYSCONFDIR=\"$(sysconfdir)\" +if BUILD_FOR_FREEBSD + AM_CPPFLAGS = -I/usr/local/include -Wno-multichar -DSYSCONFDIR=\"$(sysconfdir)\" -O2 +else + AM_CPPFLAGS = -Wno-multichar -DSYSCONFDIR=\"$(sysconfdir)\" +endif + +if USE_APPLE_ALAC + shairport_sync_SOURCES += apple_alac.cpp +endif + +if USE_CUSTOMPIDDIR +AM_CFLAGS+= \ + -DPIDDIR=\"$(CUSTOM_PID_DIR)\" +endif + +if USE_AVAHI +shairport_sync_SOURCES += mdns_avahi.c +endif + +if USE_TINYSVCMDNS +shairport_sync_SOURCES += mdns_tinysvcmdns.c tinysvcmdns.c +endif + +if USE_ALSA +shairport_sync_SOURCES += audio_alsa.c +endif + +if USE_SNDIO +shairport_sync_SOURCES += audio_sndio.c +endif + +if USE_STDOUT +shairport_sync_SOURCES += audio_stdout.c +endif + +if USE_PIPE +shairport_sync_SOURCES += audio_pipe.c +endif + +if USE_DUMMY +shairport_sync_SOURCES += audio_dummy.c +endif + +if USE_AO +shairport_sync_SOURCES += audio_ao.c +endif + +if USE_SOUNDIO +shairport_sync_SOURCES += audio_soundio.c +endif + +if USE_PA +shairport_sync_SOURCES += audio_pa.c +endif + +if USE_CONVOLUTION +shairport_sync_SOURCES += FFTConvolver/AudioFFT.cpp FFTConvolver/FFTConvolver.cpp FFTConvolver/Utilities.cpp FFTConvolver/convolver.cpp +AM_CXXFLAGS = -std=c++11 +endif + +if USE_DNS_SD +shairport_sync_SOURCES += mdns_dns_sd.c +endif + +if USE_DBUS +shairport_sync_SOURCES += dbus-service.c dbus-interface.c +BUILT_SOURCES = dbus-interface.h dbus-interface.c +# We don't want to install this header +noinst_HEADERS = $(BUILT_SOURCES) +# Correctly clean the generated headers, but keep the xml description +CLEANFILES = $(BUILT_SOURCES) + +#Rule to generate the binding headers +dbus-interface.h: org.gnome.ShairportSync.xml + gdbus-codegen --interface-prefix org.gnome --generate-c-code dbus-interface org.gnome.ShairportSync.xml + +dbus-interface.c: org.gnome.ShairportSync.xml + gdbus-codegen --interface-prefix org.gnome --generate-c-code dbus-interface org.gnome.ShairportSync.xml +endif + +if USE_DBUS_CORE_AND_DACP +shairport_sync_SOURCES += dacp.c +endif + +if USE_MPRIS +shairport_sync_SOURCES += mpris-service.c mpris-interface.c mpris-player-interface.c +BUILT_SOURCES = mpris-interface.h mpris-interface.c mpris-player-interface.h mpris-player-interface.c +# We don't want to install this header +noinst_HEADERS = $(BUILT_SOURCES) +# Correctly clean the generated headers, but keep the xml description +CLEANFILES = $(BUILT_SOURCES) + +#Rule to generate the binding headers +mpris-interface.h: org.mpris.MediaPlayer2.xml + gdbus-codegen --interface-prefix org.mpris --generate-c-code mpris-interface org.mpris.MediaPlayer2.xml + +mpris-interface.c: org.mpris.MediaPlayer2.xml + gdbus-codegen --interface-prefix org.mpris --generate-c-code mpris-interface org.mpris.MediaPlayer2.xml + +mpris-player-interface.h: org.mpris.MediaPlayer2.Player.xml + gdbus-codegen --interface-prefix org.mpris --generate-c-code mpris-player-interface org.mpris.MediaPlayer2.Player.xml + +mpris-player-interface.c: org.mpris.MediaPlayer2.Player.xml + gdbus-codegen --interface-prefix org.mpris --generate-c-code mpris-player-interface org.mpris.MediaPlayer2.Player.xml +endif + +if USE_DBUS_CLIENT + #Make it, but don't install it anywhere +noinst_PROGRAMS = shairport-sync-dbus-test-client +shairport_sync_dbus_test_client_SOURCES = dbus-interface.c dbus-interface.h shairport-sync-dbus-test-client.c +endif + +if USE_MPRIS_CLIENT + #Make it, but don't install it anywhere +noinst_PROGRAMS = shairport-sync-mpris-test-client +shairport_sync_mpris_test_client_SOURCES = mpris-interface.c mpris-interface.h mpris-player-interface.c mpris-player-interface.h shairport-sync-mpris-test-client.c +endif + +install-exec-hook: +if INSTALL_CONFIG_FILES + [ -e $(DESTDIR)$(sysconfdir) ] || mkdir $(DESTDIR)$(sysconfdir) + cp scripts/shairport-sync.conf $(DESTDIR)$(sysconfdir)/shairport-sync.conf.sample + [ -f $(DESTDIR)$(sysconfdir)/shairport-sync.conf ] || cp scripts/shairport-sync.conf $(DESTDIR)$(sysconfdir)/shairport-sync.conf +if USE_DBUS + cp scripts/shairport-sync-dbus-policy.conf $(DESTDIR)$(sysconfdir)/dbus-1/system.d/shairport-sync-dbus.conf +endif +if USE_MPRIS + cp scripts/shairport-sync-mpris-policy.conf $(DESTDIR)$(sysconfdir)/dbus-1/system.d/shairport-sync-mpris.conf +endif +endif +if INSTALL_SYSTEMV + getent group shairport-sync &>/dev/null || groupadd -r shairport-sync >/dev/null + getent passwd shairport-sync &> /dev/null || useradd -r -M -g shairport-sync -s /usr/bin/nologin -G audio shairport-sync >/dev/null + [ -e /var/run/shairport-sync ] || mkdir -p /var/run/shairport-sync + chown shairport-sync:shairport-sync /var/run/shairport-sync + [ -e $(DESTDIR)$(sysconfdir)/init.d ] || mkdir -p $(DESTDIR)$(sysconfdir)/init.d + [ -f $(DESTDIR)$(sysconfdir)/init.d/shairport-sync ] || cp scripts/shairport-sync $(DESTDIR)$(sysconfdir)/init.d/ +endif +if INSTALL_SYSTEMD + getent group shairport-sync &>/dev/null || groupadd -r shairport-sync >/dev/null + getent passwd shairport-sync &> /dev/null || useradd -r -M -g shairport-sync -s /usr/bin/nologin -G audio shairport-sync >/dev/null + [ -e $(DESTDIR)$(systemdsystemunitdir) ] || mkdir -p $(DESTDIR)$(systemdsystemunitdir) + [ -f $(DESTDIR)$(systemdsystemunitdir)/shairport-sync.service ] || cp scripts/shairport-sync.service $(DESTDIR)$(systemdsystemunitdir) +endif +if INSTALL_FREEBSD_SERVICE + pw showgroup shairport-sync > /dev/null 2>&1 || pw addgroup shairport-sync > /dev/null 2>&1 + pw showuser shairport-sync > /dev/null 2>&1 || pw adduser shairport-sync > /dev/null 2>&1 + [ -e /var/run/shairport-sync ] || mkdir -p /var/run/shairport-sync + chown shairport-sync:shairport-sync /var/run/shairport-sync + [ -f /usr/local/etc/rc.d/shairport_sync ] || cp scripts/shairport-sync.freebsd /usr/local/etc/rc.d/shairport_sync + chmod 555 /usr/local/etc/rc.d/shairport_sync +endif diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..cff5c18 --- /dev/null +++ b/NEWS @@ -0,0 +1 @@ +Please refer to RELEASENOTES.md and README.md for news. diff --git a/README b/README new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..2cb2f7f --- /dev/null +++ b/README.md @@ -0,0 +1,550 @@ +Shairport Sync +============= +Shairport Sync is an AirPlay audio player – it plays audio streamed from iTunes, iOS, Apple TV and macOS devices and AirPlay sources such as Quicktime Player and [ForkedDaapd](http://ejurgensen.github.io/forked-daapd/), 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 for suitable players. (Hence the name Shairport Sync, BTW.) + +Shairport Sync runs on Linux and FreeBSD. It does not support AirPlay video or photo streaming. + +This is the stable "master" branch. Changes and updates are incorporated into this branch relatively slowly. To access the development version, where all the latest changes are made first, please switch to the "development" branch. + +More Information +---------- +Shairport Sync offers *full audio synchronisation*, a feature of AirPlay that previous implementations do not provide. Full audio synchronisation means that audio is played on the output device at exactly the time specified by the audio source. To accomplish this, Shairport Sync needs access to audio systems – such as `alsa` on Linux and `sndio` on FreeBSD – that provide very accurate timing information about output devices. Shairport Sync must have direct access to the output device used, which must be a real sound card capable of working with 44,100, 88,200 or 176,400 samples per second, interleaved PCM stereo of 8, 16, 24 or 32 bits. The default is 44,100 samples per second / 16 bits (you'll get a message in the logfile if there's a problem). + +Alternatively, Shairport Sync works well with PulseAudio, a widely used sound server found on many desktop Linuxes. While the timing information is not as accurate as that of `alsa` or `sndio`, it is often impractical to remove or disable PulseAudio. In that case, the `pa` backend can be used. An older backend for PulseAudio called `pulse` does not support synchronisation and is deprecated. + +For other use cases, Shairport Sync can provide synchronised audio output to a unix pipe or to standard output, or to audio systems that do not provide timing information. This could perhaps be described as *partial audio synchronisation*, where synchronised audio is provided by Shairport Sync, but what happens to it in the subsequent processing chain, before it reaches the listener's ear, is outside the control of Shairport Sync. + +For more about the motivation behind Shairport Sync, please see the wiki at https://github.com/mikebrady/shairport-sync/wiki. + +Synchronisation, Latency, "Stuffing" +--------- +The AirPlay protocol uses an agreed *latency* – the time difference, or delay, between the time represented by a sound sample's `timestamp` and the time it is actually played by the audio output device, typically a Digital to Audio Converter (DAC). The latency to be used is specified by the audio source when it negotiates with Shairport Sync. Most sources set a latency of two seconds. Recent versions of iTunes and forkedDaapd use a latency of just over 2.25 seconds. A latency of this length allows AirPlay players to correct for network delays, processing time variations and so on. + +As mentioned previously, Shairport Sync implements full audio synchronisation when used with `alsa`, `sndio` or PulseAudio systems. This is done by monitoring the timestamps present in data coming from the audio source and the timing information from the audio system, e.g. `alsa`. To maintain the latency required for exact synchronisation, if the 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”. + +Stuffing is not done for partial audio synchronisation – the audio samples are simply presented at exactly the right time to the next stage in the processing chain. + +Timestamps are referenced 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`. So, another thing Shairport Sync has to do is to synchronize the source clock and the local clock, and it does this usually to within a fraction of a millisecond, using a variant of NTP synchronisation protocols. + +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. In addition, Shairport Sync can offer an extended volume control range on devices with a restricted range. +* Hardware Mute — Shairport Sync can mute properly if the hardware supports it. +* Support for the Apple ALAC decoder. +* Output bit depths of 8, 16, 24 and 32 bits, rather than the standard 16 bits. +* Fast Response — With hardware volume control, response is instantaneous; otherwise the response time is 0.15 seconds with `alsa`, 0.35 seconds with `sndio`. +* 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 deliver metadata supplied by the source, such as Album Name, Artist Name, Cover Art, etc. through a pipe or UDP socket 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 — 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. + +Heritage +------- +Shairport Sync is a 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. + +Status +------ +Shairport Sync works on a wide variety of Linux devices and FreeBSD. It works on standard Ubuntu laptops, on the Raspberry Pi with Raspbian Stretch, Jessie and Wheezy, 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. + +Shairport Sync will work with PulseAudio, which is installed in many desktop Linuxes. PulseAudio normally runs in the *user mode* but can be configured to run in *system mode*, though this is not recommended. Shairport Sync can work with it in either mode. + +Shairport Sync runs well on the Raspberry Pi on USB and I2S cards. It can drive the built-in sound card – see the note below on configuring the Raspberry Pi to make best use of it. It runs well on the Raspberry Pi Zero W with a suitable USB or I2S card. + +Shairport Sync runs natively on FreeBSD using the `sndio` sound system. + +Shairport Sync runs on Ubuntu, OpenWrt, Debian, Arch Linux, Fedora and FreeBSD inside VMWare Fusion on a Mac, but synchronisation in inaccurate — possibly because the sound card is being emulated. + +In addition, Shairport Sync can output to standard output, pipes, `soundio` and `ao` devices using appropriate backends. + +For information about changes and updates, please refer to the RELEASENOTES.md file in the distribution. + +Building And Installing +--------------------- +Shairport Sync may already be available as a package in your Linux distribution (search for `shairport-sync` – the package named `shairport` is a different program). Packages are available on recent versions of Debian, Ubuntu, Arch, OpenWrt and possibly more: + +**Ubuntu:** A `shairport-sync` installer package is available for Ubuntu. Additionally, a Personal Package Archives for Shairport Sync master and development branches are available at https://launchpad.net/~dantheperson. + +**Debian:** shairport-sync is in the Debian archive. + +**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. + +**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/. +An Arch Linux installation package, suitable for compilation on any platform, is also available at [EliaCereda/shairport-sync-PKGBUILD](https://github.com/EliaCereda/shairport-sync-PKGBUILD). + +**Mac OS X:** A HomeBrew 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:** Please see the guide at [FEDORA.md](https://github.com/mikebrady/shairport-sync/blob/master/FEDORA.md). + +**Cygwin:** Please see the guide at [CYGWIN.md](https://github.com/mikebrady/shairport-sync/blob/master/CYGWIN.md). + +Sincere thanks to all package contributors! + +If you wish to build and install the latest version of Shairport Sync on Debian, Ubuntu, Fedora or Arch platforms, please continue to follow these instructions. When the program has been compiled and installed, refer to the section on Configuring Shairport Sync that follows. To build Shairport Sync from sources on FreeBSD please refer to [FREEBSD.md](https://github.com/mikebrady/shairport-sync/blob/master/FREEBSD.md). + +**Remove Old Versions Of Shairport Sync** + +You should check to see if `shairport-sync` is already installed – you can use the command `$ 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. + + +**Determine The Configuration Needed** + +Shairport Sync has a number of different "backends" that connnect it to the system's audio handling infrastructure. Most recent Linux distributions that have a GUI – including Ubuntu, Debian and others – use PulseAudio to handle sound. In such cases, it is inadvisable to attempt to disable or remove PulseAudio. Thus, if your system uses PulseAudio, you should build Shairport Sync with the PulseAudio backend. You can check to see if PulseAudio is running by opening a Terminal window and entering the command `$ pactl info`. Here is an example of what you'll get if PulseAudio is installed, though the exact details may vary: +``` +$ pactl info +Server String: unix:/run/user/1000/pulse/native +Library Protocol Version: 30 +Server Protocol Version: 30 +Is Local: yes +Client Index: 9 +Tile Size: 65472 +User Name: mike +Host Name: ubuntu +Server Name: pulseaudio +Server Version: 8.0 +Default Sample Specification: s16le 2ch 44100Hz +Default Channel Map: front-left,front-right +Default Sink: alsa_output.pci-0000_02_02.0.analog-stereo +Default Source: alsa_input.pci-0000_02_02.0.analog-stereo +Cookie: 96f9:3e8d +$ +``` +If PulseAudio in not installed, you'll get something like this: +``` +$ pactl info +-bash: pactl: command not found +$ +``` +If your system does not use PulseAudio, then it is likely that it uses the Advanced Linux Sound Architecture (ALSA), so you should build Shairport Sync with the ALSA backend. By the way, many systems with PulseAudio also have ALSA (in fact, PulseAudio is effectively a client of ALSA); in those cases you should choose the PulseAudio backend. + +If PulseAudio is not installed, there is no necessity to install it for Shairport Sync. In fact, Shairport Sync works better without it. + +**Building** + +To build Shairport Sync from sources on Debian, Ubuntu, Raspbian, etc. follow these instructions. + +The following libraries are required: +* OpenSSL or mbed TLS (PolarSSL is supported but deprecated) +* Avahi +* ALSA and/or PulseAudio +* libdaemon +* autoconf +* automake +* libtool +* libpopt +* libconfig + +Optional: +* libsoxr +* libalac (This is a library containing the Apple ALAC decoder.) + +Many Linux distributions have Avahi and OpenSSL already in place, so normally it probably makes sense to choose those options rather than tinysvcmdns or mbed TLS. The `libsoxr` library 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. + +Debian, Ubuntu and Raspbian users can get the basics with: + +- `# apt-get install build-essential git xmltoman` – these may already be installed. +- `# apt-get install autoconf automake libtool libdaemon-dev libpopt-dev libconfig-dev` +- `# apt-get install libasound2-dev` for the ALSA libraries +- `# apt-get install libpulse-dev` for the PulseAudio libraries +- `# 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 mbed TLS otherwise. +- `# apt-get install libmbedtls-dev` if you want to use mbed TLS, or use OpenSSL/libcrypto otherwise. You can still use PolarSSL with `apt-get install libpolarssl-dev` if you want to use PolarSSL, but it is deprecated as it's not longer being supported. +- `# apt-get install libsoxr-dev` if you want support for libsoxr-based resampling. This library is in many recent distributions; if not, instructions for how to build it from source for Rasbpian/Debian Wheezy are available at [LIBSOXR.md](https://github.com/mikebrady/shairport-sync/blob/master/LIBSOXR.md). +- `# apt-get install libsndfile1-dev` if you want to use the convolution filter. + +If you wish to include the Apple ALAC decoder, you need install it first – please refer to the [ALAC](https://github.com/mikebrady/alac) repository for more information. + +**Download Shairport Sync:** +``` +$ git clone https://github.com/mikebrady/shairport-sync.git +``` + +Next, `cd` into the shairport-sync directory and execute the following commands: +``` +$ autoreconf -i -f +``` +(Note that the `autoreconf...` step may take some time on less powerful machines.) + +**Choose the appropriate `--with-*` options:** + +(Don't worry -- there's a recommended set of configuration options further down.) + +- `--with-alsa` include the ALSA backend module to audio to be output through the Advanced Linux Sound Architecture (ALSA) system directly. This is recommended for highest quality. +- `--with-pa` include the PulseAudio audio back end. This is recommended if your Linux installation already has PulseAudio installed. Although ALSA would be better, it requires direct and exclusive access to to a real (hardware) soundcard, and this is often impractical if PulseAudio is installed. +- `--with-stdout` include an optional backend module to enable raw audio to be output through standard output (stdout). +- `--with-pipe` include an optional backend module to enable raw audio to be output through a unix pipe. +- `--with-soundio` include an optional backend module to enable raw audio to be output through the soundio system. +- `--with-avahi` or `--with-tinysvcmdns` for mdns support. Avahi is a widely-used system-wide zero-configuration networking (zeroconf) service — it may already be in your system. If you don't have Avahi, or similar, then consider including tinysvcmdns, which is a tiny zeroconf service embedded inside the shairport-sync application itself. To enable multicast for `tinysvcmdns`, you may have to add a default route with the following command: `route add -net 224.0.0.0 netmask 224.0.0.0 eth0` (substitute the correct network port for `eth0`). You should not have more than one zeroconf service on the same system — bad things may happen, according to RFC 6762, §15. +- `--with-ssl=openssl`, `--with-ssl=mbedtls` or `--with-ssl=polarssl` (deprecated) for encryption and related utilities using either OpenSSL, mbed TLS or PolarSSL. +- `--with-soxr` for libsoxr-based resampling. +- `--with-piddir` for specifying where the PID file should be stored. This directory is normally chosen automatically. The directory must be writable. If you use this option, you may have to edit the init script to search for the PID file in your new location. +- `--with-metadata` to add support for Shairport Sync to pipe metadata to a compatible application of your choice. See https://github.com/mikebrady/shairport-sync-metadata-reader for a sample metadata reader. +- `--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. +- `--with-apple-alac` to include the Apple ALAC Decoder. +- `--with-convolution` to include a convolution filter that can be used to apply effects such as frequency and phase correction, and a loudness filter that compensates for human ear non-linearity. Requires `libsndfile`. +- `--with-systemd` to include a script to create a Shairport Sync service that can optionally launch automatically at startup on `systemd`-based Linuxes. Default is not to to install. +- `--with-systemv` to include a script to create a Shairport Sync service that can optionally launch automatically at startup on System V based Linuxes. Default is not to to install. + +**Determine if it's a `systemd` or a "System V" installation:** + +If you wish to have Shairport Sync start automatically when your system boots, you need to figure out what so-called "init system" your system is using. (If you are using Shairport Sync with PulseAudio, as installed in many desktop systems, this section doesn't apply.) + +There are a number of init systems in use: `systemd`, `upstart` and "System V" among others, and it's actually difficult to be certain which one your system is using. Fortunately, for Shairport Sync, all you have to do is figure out if it's a `systemd` init system or not. If it is not a `systemd` init system, you can assume that it is either a System V init system or else it is compatible with a System V init system. Recent systems tend to use `systemd`, whereas older systems use `upstart` or the earlier System V init system. + +The easiest way to look at the first few lines of the `init` manual. Enter the command: + +``` +$ man init +``` +In a `systemd` system, the top lines of the `man` page make it clear that it's a `systemd` system, as follows (from Ubuntu 16.04): +``` +SYSTEMD(1) systemd SYSTEMD(1) + +NAME + systemd, init - systemd system and service manager +... +``` +Other init systems will look considerably different. For instance, in an `upstart` system, the top lines of the `man` page indicate it's using `upstart` system, as follows (from Ubuntu 14.04): + +``` +init(8) System Manager's Manual init(8) + +NAME + init - Upstart process management daemon + +SYNOPSIS + init [OPTION]... +... +``` +In a System V system, the top lines of the `man` page are as follows (from Debian 7.11): +``` +INIT(8) Linux System Administrator's Manual INIT(8) + +NAME + init, telinit - process control initialization + +SYNOPSIS + /sbin/init [ -a ] [ -s ] [ -b ] [ -z xxx ] [ 0123456Ss ] + /sbin/telinit [ -t SECONDS ] [ 0123456sSQqabcUu ] + /sbin/telinit [ -e VAR[=VAL] ] + +... +``` +If your system is definitely a `systemd` system, choose `--with-systemd` below. Otherwise, choose `--with-systemv`. + +**Choose the location of the configuration file** + +A final consideration is the location of the configuration file `shairport-sync.conf`. This will be placed in the directory specified by the `sysconfdir` configuration variable, which defaults to `/usr/local/etc`. This is normal in BSD Unixes, but is unusual in Linux. Hence, for Linux installations, you need to set the `sysconfdir` variable to `/etc` using the configuration setting `--sysconfdir=/etc`. + +**Sample `./configure` command with parameters for a typical Linux `systemd` installation:** + +Here is a recommended set of configuration options suitable for Linux installations that use `systemd`, such as Ubuntu 15.10 and later, and Raspbian Stretch and Jessie. It specifies both the ALSA and PulseAudio backends and includes a sample configuration file and an script for automatic startup on system boot: + +`$ ./configure --sysconfdir=/etc --with-alsa --with-pa --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 System V system, replace the `--with-systemd` with `--with-systemv`. +* If you intend to use Shairport Sync with PulseAudio in the standard user mode, it can not be a system service, so you should omit both `--with-systemd` and `--with-systemv`. + +**Build and Install the Application:** + +Enter: + +``` +$ make +``` + +to build the application. + +Assuming you have used the `./configure` settings suggested above, you can now install the application: + +``` +$ sudo make install +``` +The user and group `shairport-sync` will be created if necessary, and a runtime folder will be created at `/var/run/shairport-sync` if you have chosen `--with-systemv`. In addition, a `man` page, a default configuration file and automatic power-on startup script will be installed. + + +**Complete installation into to a `systemd` system** + +If you have chosen the `--with-systemd` configuration option, then, to enable Shairport Sync to start automatically at system startup, enter: + +``` +$ sudo systemctl enable shairport-sync +``` + +**Complete installation into a System V system** + +If you have chosen the `--with-systemv` configuration option, 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/master/man/shairport-sync.html + +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. + +**(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. + +If you are using PulseAudio in the standard "user" mode, you can not start Shairport Sync automatically at boot time – it must be started when the user logs in to a GUI session. Various GUI tools exist to enable you to build a Startup Application. However, there does not appear to be a similar tool for terminating the program when you log out. Also, it the GUI switches to another user, the user's PulseAudio session is disconnected from the output device. + +**(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. and (b) specify the backend you wish to use - `alsa` for the ALSA backend, or `pa` for the PulseAudio back end. If only one backend is included at compilation, or if the backend is ALSA, there is no need to explicitly specify the backend. + +For the ALSA backend you may need to (c) specify the output device to use and (d) specify the name of the mixer volume control to use to control the output level. To get values for (b) and (c) 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` (note that in FreeBSD it will be at `/usr/local/etc/shairport-sync.conf`). When you run `$sudo make install`, a sample configuration file is installed or updated at `/etc/shairport-sync.conf.sample` (`/usr/local/etc/shairport-sync.conf.sample` in FreeBSD). 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, 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 use `libsoxr` interpolation, then you should do the following: + +``` +general = +{ + name = "Front Room"; + password = "secret"; + interpolation = "soxr"; + // ... other general settings +}; +``` +(Remember, anything preceded by `//` is a comment and will have no effect on the setting of Shairport Sync.) No backend is specified here, so it will default to the `alsa` backend if more than one back end has been compiled. To route the output to PulseAudio, add: + +``` + output_backend = "pa"; +``` +to the `general` stanza. + +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. +* The `mixer_control_name` tag allows you to specify the name of the mixer volume control. +* The `mixer_device` tag allows you specify where the mixer is. By default, the mixer is on the `output_device`, so you only need to use the `mixer_device` tag if the mixer is elsewhere. This can happen if you specify a *device* rather than a *card* with the `output_device` tag, because normally a mixer is associated with a *card* rather than a device. Suppose you wish to use the output device `5` of card `hw:0` and the mixer volume-control named `PCM`: + +``` +alsa = +{ + output_device = "hw:0,5"; + mixer_device = "hw:0"; + mixer_control_name = "PCM"; + // ... other alsa settings +}; +``` + +The `pa` group is used to specify settings relevant to the PulseAudio backend. You can set the "Application Name" that will appear in the "Sound" control panel. + +Shairport Sync can run programs just before it starts to play an audio stream and just after it finishes. You specify them using the `sessioncontrol` group settings `run_this_before_play_begins` and `run_this_after_play_ends`. This is to facilitate situations where something has to be done before and after playing, e.g. switching on an amplifier beforehand and switching it off afterwards. Set the `wait_for_completion` value to `"yes"` for Shairport Sync to wait until the respective commands have been completed before continuing. + +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.) + +Shairport Sync can run a program whenever the volume is set or changed. You specify them using the `general` group settings `run_this_when_volume_changes`. This is to facilitate situations where something has to be done when the volume changes, e.g. adjust an external mixer value. Set the `wait_for_completion` value to `"yes"` for Shairport Sync to wait until the command has been completed before continuing. Again, please note that the full path to the program must be specified, and script files will not be executed unless they are marked as executable and have the standard `#!/bin/...` first line. + +Note: Shairport Sync can take configuration settings from command line options. This is mainly for backward compatibility, 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. An updated audio driver has greatly improved the quality of the output – see [#525](https://github.com/mikebrady/shairport-sync/issues/525) for details. To activate the updated driver, add the line: +``` +audio_pwm_mode=2 +``` +to `/boot/config.txt` and reboot. +Apart from a loud click when used for the first time after power-up, it is quite adequate for casual listening. A 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 40dB 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` group 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 40, the top 40 dB of the range will the used. With this setting on the Raspberry Pi, maximum volume will be +4dB and minimum volume will be -36dB, 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_tolerance_in_seconds` setting: you should set it to a larger tolerance, say 10 milliseconds – `drift_tolerance_in_seconds=0.010;` – to reduce the amount of overcorrection that seems to occur when using the Raspberry Pi's built-in DAC. + +*Command Line Arguments* + +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/master/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. + +* The `-c` option allows you to specify the location of the configuration file. +* The `-V` option gives you version information about Shairport Sync and then quits. +* The `-d` option causes Shairport Sync to properly daemonise itself, that is, to run in the background. You may need sudo privileges for this. +* The `-k` option causes Shairport Sync to kill an existing Shairport Sync daemon. You may need to have sudo privileges for this. + +The System V init script at `/etc/init.d/shairport-sync` has a bare minimum : +`-d`. Basically all it does is put the program in daemon mode. The program will read its settings from the configuration file. + +Examples +-------- + +Here are some examples of complete configuration files. + +``` +general = { + name = "Joe's Stereo"; +}; + +alsa = { + output_device = "hw:0"; +}; +``` + +This gives the service a particular name — "Joe's Stereo" and specifies that audio device hw:0 be used. + +For best results with the `alsa` backend — including getting true mute and instant response to volume control and pause commands — you should access the hardware volume controls. Use `amixer` or `alsamixer` or similar to discover the name of the mixer control to be used as the `mixer_control_name`. + +Here is an example for for a Raspberry Pi using its internal soundcard — device hw:0 — that drives the headphone jack: +``` +general = { + name = "Mike's Boombox"; +}; + +alsa = { + output_device = "hw:0"; + mixer_control_name = "PCM"; +}; +``` + +Here is an example of using soxr-based resampling and driving a Topping TP30 Digital Amplifier, which has an integrated USB DAC and which is connected as audio device `hw:1`: +``` +general = { + name = "Kitchen"; + interpolation = "soxr"; +}; + +alsa = { + output_device = "hw:1"; + mixer_control_name = "PCM"; +}; +``` + +For a cheapo "3D Sound" USB card (Stereo output and input only) on a Raspberry Pi: +``` +general = { + name = "Front Room"; +}; + +alsa = { + output_device = "hw:1"; + mixer_control_name = "Speaker"; +}; +``` + +For a first generation Griffin iMic on a Raspberry Pi: +``` +general = { + name = "Attic"; +}; + +alsa = { + output_device = "hw:1"; + mixer_control_name = "PCM"; +}; +``` + +For an NSLU2, which has no internal sound card, there appears to be a bug in ALSA — you can not specify a device other than "default". Thus: + +On an NSLU2, to drive a first generation Griffin iMic: +``` +general = { + name = "Den"; +}; + +alsa = { + mixer_control_name = "PCM"; +}; +``` + +On an NSLU2, to drive the "3D Sound" USB card: +``` +general = { + name = "TV Room"; +}; + +alsa = { + mixer_control_name = "Speaker"; +}; +``` + +Finally, here is an example of using the PulseAudio backend: +``` +general = { + name = "Zoe's Computer"; + output_backend = "pa"; +}; + +``` + + +Metadata +-------- + +Shairport Sync can deliver metadata supplied by the source, such as Album Name, Artist Name, Cover Art, etc. through a pipe or UDP socket 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 broadcasting over UDP** + +As an alternative to sending metadata to a pipe, the `socket_address` and `socket_port` tags may be set in the metadata group to cause Shairport Sync to broadcast UDP packets containing the track metadata. + +The advantage of UDP is that packets can be sent to a single listener or, if a multicast address is used, to multiple listeners. It also allows metadata to be routed to a different host. However UDP has a maximum packet size of about 65000 bytes; while large enough for most data, Cover Art will often exceed this value. Any metadata exceeding this limit will not be sent over the socket interface. The maximum packet size may be set with the `socket_msglength` tag to any value between 500 and 65000 to control this - lower values may be used to ensure that each UDP packet is sent in a single network frame. The default is 500. Other than this restriction, metadata sent over the socket interface is identical to metadata sent over the pipe interface. + +The UDP metadata format is very simple - the first four bytes are the metadata *type*, and the next four bytes are the metadata *code* (both are sent in network byte order - see https://github.com/mikebrady/shairport-sync-metadata-reader for a definition of those terms). The remaining bytes of the packet, if any, make up the raw value of the metadata. + +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 2 seconds or just over 2.25 seconds. You shouldn't need to change them. + +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_in_seconds`. 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 -0.1. + +Resynchronisation +------------- +Shairport Sync actively maintains synchronisation with the source. +If synchronisation is lost — say due to a busy source or a congested network — Shairport Sync will mute its output and resynchronise. The loss-of-sync threshold is a very conservative 0.050 seconds — i.e. the actual time and the expected time must differ by more than 50 ms to trigger a resynchronisation. Smaller disparities are corrected by insertions or deletions, as described above. +* You can vary the resync threshold, or turn resync off completely, with the `general` `resync_threshold_in_seconds` setting. + +Tolerance +--------- +Playback synchronisation is allowed to wander — to "drift" — a small amount before attempting to correct it. The default is 0.002 seconds, 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_tolerance_in_seconds` setting. + +Some Statistics +--------------- +If you turn on the `general` `statistics` setting, a heading like this will be output to the console or log file: +``` +sync error in milliseconds, net correction in ppm, corrections in ppm, total packets, missing packets, late packets, too late packets, resend requests, min DAC queue size, min buffer occupancy, max buffer occupancy +``` +This will be followed by the statistics themselves at regular intervals, for example: +``` + -1.3, 25.9, 25.9, 3758, 0, 0, 0, 0, 4444, 263, 270 + -2.0, 96.0, 96.0, 7516, 0, 0, 0, 0, 5357, 260, 267 + -2.0, 96.0, 96.0, 11274, 0, 0, 0, 0, 4956, 262, 268 + -2.0, 94.5, 94.5, 15032, 0, 0, 0, 0, 5430, 263, 267 + -2.0, 99.8, 99.8, 18790, 0, 0, 0, 0, 5047, 261, 268 + -2.0, 91.5, 91.5, 22548, 0, 0, 0, 0, 5258, 260, 267 + -2.0, 90.7, 90.7, 26306, 0, 0, 0, 0, 5279, 262, 267 + -2.0, 96.0, 96.0, 30064, 0, 0, 0, 0, 5551, 260, 266 +``` + +"Sync error in milliseconds" is the average deviation from exact synchronisation. The first line of the example above indicates that the output is on average 1.3 milliseconds behind exact synchronisation. Sync is allowed to drift by the `general` `drift_tolerance_in_seconds` setting — (± 0.002 seconds) by default — before a correction will be made. + +"Net correction in ppm" is actually the net sum of corrections — the number of frame insertions less the number of frame deletions — given as a moving average in parts per million. After an initial settling period, it represents the drift — the divergence between the rate at which frames are generated at the source and the rate at which the output device consumes them. The first line of the example above indicates that the output device is consuming frames 25.9 ppm faster than the source is generating them. The subsequent lines indicate that the stable actual difference in the clocks is around 95 ppm. + +"Corrections in ppm" is the number of frame insertions plus the number of frame deletions (i.e. the total number of corrections), given as a moving average in parts per million. The closer this is to the net corrections, the fewer "unnecessary" corrections that are being made. Third party programs tend to have much larger levels of corrections. + +For reference, a drift of one second per day is approximately 11.57 ppm. Left uncorrected, even a drift this small between two audio outputs will be audible after a short time. The above sample is from an Ethernet-connected iMac driving a WiFi-connected Raspberry Pi 3 using an IQaudIO Pi-DigiAMP+. + +It's not unusual to have resend requests, late packets and even missing packets if some part of the connection to the Shairport Sync device is over WiFi. Late packets can sometimes be asked for and received multiple times. Sometimes late packets are sent and arrive too late, but have already been sent and received in time, so weren't needed anyway... + +"Min DAC queue size" is the minimum size the queue of samples in the output device's hardware buffer was measured at. It is meant to stand at 0.15 seconds = 6,615 frames at 44,100 frames per second, and will go low if the processor is very busy. If it goes below about 2,000 then it's an indication that the processor can't really keep up. + +WiFi Issues +--------- +If you are using WiFi, you should ensure that WiFi power management is off. See [TROUBLESHOOTING](https://github.com/mikebrady/shairport-sync/blob/master/TROUBLESHOOTING.md) for more details. + +Troubleshooting +--------------- +Please refer to [TROUBLESHOOTING](https://github.com/mikebrady/shairport-sync/blob/master/TROUBLESHOOTING.md) for a few hints, contributed by users. + diff --git a/RELEASENOTES.md b/RELEASENOTES.md new file mode 100644 index 0000000..7f086d5 --- /dev/null +++ b/RELEASENOTES.md @@ -0,0 +1,954 @@ +Version 3.1.7 +==== + +**Bug Fixes** +* In recent versions of iOS (11.2) and mac OS (10.13.2), when play is resumed after a pause, the volume level is not always restored, and, if software volume control is being used, Shairport Sync plays at full volume. This issue has been addressed by storing the last airplay volume setting when a play session ends and using it as a default when a new play session begins. +* Better AirPlay synchronisation. Older versions of Shairport Sync added an 11,025 frame (0.25 seconds) offset to all the latencies negotiated with the sender. This seems now only to be correct for iTunes and ForkedDaapd sources, but incorrect for AirPlay sources. Accordingly, the offset is only added for iTunes and ForkedDaapd. The result is better sync with videos, e.g, YouTube, while iTunes and ForkedDaapd synchronisation is unaffected. +* A bug in the hardware volume control affected output devices that have hardware mixers but that do not allow the volume to be set in dB. One example is the Softvol plugin in ALSA. Shairport Sync failed silently when presented with such a device when hardware volume control is enabled: the volume events have no effect. The bug has been fixed by adding two missing lines of code to the `init()` function in `audio_alsa.c`. Thanks to [Jakub Nabaglo](https://github.com/nbgl) for finding and fixing the bug. +* A number of bug fixes due to [belboj](https://github.com/belboj). Many thanks for these! +* Enhancements to the handling of quit requests by threads, thanks(again) to [belboj](https://github.com/belboj)! + +**Other Stuff** +* Typo fix! Thanks to [corbinsantin](https://github.com/corbinsantin). +* Stable 3.1.5 and 3.1.6 skipped to synchronise the shairport-sync.spec file contents with the release. + +**Enhancement** +* The metdata output stream can include a `dapo` message carrying the DACP port number to be used when communicating with the DACP remote control. This might be useful because the port number is actually pretty hard to find and requires the use of asynchronous mdns operations. You must be using the Avahi mdns back end. + +Version 3.1.4 +==== + +**Security Update** + +* The version of `tinysvcmdns` bundled in Shairport Sync has a buffer overflow bug: *"An exploitable heap overflow vulnerability exists in the tinysvcmdns library version 2016-07-18. A specially crafted packet can make the library overwrite an arbitrary amount of data on the heap with attacker controlled values. An attacker needs send a dns packet to trigger this vulnerability."* The vulnerability is addressed by additional checking on packet sizes. See also [CVE-2017-12087](https://bugs.launchpad.net/bugs/cve/2017-12087) and [Vulnerability in tinysvcmdns](https://bugs.launchpad.net/ubuntu/+source/shairport-sync/+bug/1729668). +Thanks and [Chris Boot](https://github.com/bootc) for fixing this bug. + +**Bug Fix** + +* Somewhere in version 3.x, the `softvol` plugin got broken as the volume change is not applied anymore. Turned out that, for the `softvol` plugin, no `volume()` and `parameters()` are defined. Thanks to [Jörg Krause](https://github.com/joerg-krause) for locating and fixing this bug. + +Version 3.1.3 +==== + +**Bug Fixes** +* Fixed a bug that prevented Shairport Sync from starting automatically on systems using the System V startup system (e.g. Ubuntu 14.04). The problem was that the directory to be used – `/var/run/shairport-sync/` – was deleted on power down and needed to be recreated on startup. In it's absence, Shairport Sync would not start and would report a mysterious daemon error \#2. + +Version 3.1.2 +==== + +Shairport Sync is more stable playing audio from YouTube and SoundCloud on the Mac. + +**Pesky Changes You Should Not Ignore** +* When you update from a previous version of Shairport Sync, your output device may have been left in a muted state. You should use a command line tool like `alsamixer` or `amixer` to unmute the output device before further use. + +**Change of Default** +* The default value for the `alsa` setting `mute_using_playback_switch` has been changed to `"no"` for compatability with other audio players on the same machine. The reason is that when this setting is set to `"yes"`, the output device will be muted when Shairport Sync releases it. Unfortunately, other audio players using the output device expect it to be unmuted, causing problems. Thanks to [Tim Curtis](https://github.com/moodeaudio) at [Moode Audio](http://moodeaudio.org) and [Peter Pablo](https://github.com/PeterPablo) for clarifying the issue. + +**Bug Fixes** +* Fixed bugs that made Shairport Sync drop out or become unavailable when playing YouTube videos, SoundCloud streams etc. from the Mac. Background: there has been a persistent problem with Shairport Sync becoming unavailable after playing, say, a YouTube clip in a browser on the Mac. Shairport Sync 3.1.2 incorporates a change to how certain AirPlay messages are handled. Introduced in nascent form in 3.1.1, further follow-on changes have improved the handling of player lock and have simplified and improved the handling of unexpected loss of connection. Shairport Sync also now works properly with SoundCloud clips played in a browser on the Mac. +* Using [infer](https://github.com/facebook/infer/blob/master/README.md), a number of silent issues have been detected, such as not checking some calls to `malloc` to ensure the response is not NULL. Most of these have been addressed by additional checks. + +Version 3.1.1 +==== + +**Bug Fixes** +* A bug in the `sndio` backend has been fixed that caused problems on some versions of Linux. +* A change has been made to how Shairport Sync responds to a `TEARDOWN` request, which should make it respond better to sequences of rapid termination and restarting of play sessions. This can happen, for example, playing YouTube videos in Safari or Chrome on a Mac. +* Choosing `soxr` interpolation in the configuration file will now cause Shairport Sync to terminate with a message if Shairport Sync has not been compiled with SoX support. +* Other small changes. + +Version 3.1 +==== +Version 3.1 brings two new backends, optional loudness and convolution filters, improvements in non-synchronised backends, enhancements, stability improvements and bug fixes. + +**New Features** +* A `sndio` backend gives Shairport Sync native fully synchronised output on OpenBSD and FreeBSD, thanks to the work of [Tobias Kortkamp (t6)](https://github.com/t6). +* A `pa` backend now allows Shairport Sync to provide synchronised output on PulseAudio-equipped systems -- many desktop Linuxes use PulseAudio as their sound manager. +* Optional loudness and convolution filters can be incorporated in the audio processing chain, thanks to the fantastic work of [yannpom](https://github.com/yannpom). +* A volume-change program hook `run_this_when_volume_is_set` has been added to the `general` settings stanza to execute an application whenever the volume is changed. + +**Pesky Changes You Should Know About** +* The `audio_backend_buffer_desired_length_in_seconds` and `audio_backend_latency_offset_in_seconds` settings have been moved from individual backend stanzas to the `general` stanza. They now have an effect on every type of backend. +* If you are using a System V (aka `systemv`) installation, please note that the default location for PID file has moved -- it is now stored at `/var/run/shairport-sync/shairport-sync.pid`. This change is needed to improve security a little and to improve compatability across platforms. If you're not doing anything strange, this should make no difference. + +**Enhancements** +* Resynchronisation, which happens when the synchronisation is incorrect by more than 50 ms by default, should be a lot less intrusive when it occurs – it should now either insert silence or skip frames, as appropriate. +* The Linux installer has been improved and simplified and a FreeBSD installer introduced. +* A new setting, `audio_backend_silent_lead_in_time`, allows you to set the duration of the period of silence played (the "silent lead-in") before a play session starts. +* A new command-line option, `--logOutputLevel`, allows you to output the volume levels to the log whenever they are changed. This may be useful during setup. +* Improvements have been made to the handling of large items of metadata over UDP. +* A new command line option, `-j`, demonizes Shairport Sync without creating a PID file. +* A new `alsa`-only setting, `mute_using_playback_switch`, is available for advanced use. +* Other minor enhancements. + +**Bug Fixes** +* Stability improvements. More care has been taken (!) to make code thread-safe, resulting in improved stability. +* Conversion from stereo to mono has been fixed to avoid clipping while preserving full resolution. Thanks to [Robert Jones (RobDeBagel)](https://github.com/RobDeBagel) for bringing this to notice. +* Short intrusions of audio at the start of a new session from the end of the previous session have been eliminated. +* Many (many!) miscellaneous bugs fixed. + +Version 3.0.2 +==== +**Bug Fixes** +* Fixed bugs in the `ao`, `pulseaudio` and `sndio` back ends. Basically they were expecting default sample rate and depth information, and were terminating when they saw explicit rate and depth data. + +Version 3.0.1 +==== +This update fixes one alarming and potentially very noisy bug and restores the identification of Shairport Sync as "ShairportSync" so that TuneBlade recognises it as an open source application. +**Bug Fixes** +* Fixed a bug that was causing Shairport Sync to possibly make a very loud and alarming noise whenever an audio frame was missing. +* In 2.8.6, a change was made to the way Shairport Sync identified itself, so that it could be recognised by TuneBlade as an open source application and treated preferentially. That change was inadventently lost in the transition from 2.8.6 to 3.0. Now it's restored. + +Version 3.0 +==== + +Big Update +---- +Version 3 brings in support for 24-bit and 32-bit (and 8 bit!) DACs and for DACs running at multiples of 44,100 samples per second. + +The most obvious audible change is if you are using software volume control and can take advantage of 32- or 24-bit DACs. Dithering can now occur on a 32-bit or 24-bit sample rather than on a 16-bit sample, making the noise floor very much lower. This is the case, for example, with a Pimoroni PHAT DAC. + +Here is the list of new features: + +**New Features** +* 8-bit, 16-bit, 24-bit, 24-bit three-byte (S24_3LE and S24_3BE) and 32-bit output to ALSA devices. +* 44,100, 88,200, 176,400 and 352,800 sample per second output. This is done using simple upsampling. It's only worth doing if 44,100 samples per second output is not available. +* Internal processing including software volume control and interpolation is done after sample size and rate conversion. +* Apple ALAC decoder support. This needs the `libalac` library, available at [ALAC](https://github.com/mikebrady/alac), to be installed. Add the flag `--with-apple-alac` to the `./configure` arguments. Then you can choose the Apple ALAC decoder in the configuration file. +* Support for `mbed TLS` has been added and the use of `PolarSSL` is deprecated, as `mbed TLS` is a development of `PolarSSL` and `PolarSSL` itself is not being developed further. +* Choose Network Interface. Add a new setting, for advanced users only, in the `general` section. Use the `interface` setting to allow you to specify the interface on which to provide the AirPlay service. Omit the setting to get the default, which is to choose the interfaces automatically. +* Set Max Volume. Add a new setting, for advanced users only, in the `general` section. Use the `volume_max_db` setting to allow you to specify the maximum level to set on the hardware mixer (if chosen) or the built-in software mixer otherwise. The software mixer's range is 0.0 dB to -96.1 dB. The setting must be a number with a decimal point, e.g. 21.3. +* An experimental new back end for `libsoundio`, a C library for cross-platform real-time audio input and output. Many thanks to [Serg Podtynnyi](https://github.com/shtirlic). Please see https://github.com/mikebrady/shairport-sync/pull/433 for more details. + + +Pesky Changes You Cannot Ignore +---- +* Processor load is up by about 11%. +* Settings have changed -- basically, any timings that were denominated in frames are now in seconds. Please refer to the shairport-sync.conf.sample file for details. +* Sox-based interpolation at higher sample rates may overload your CPU -- you might have to choose between higher sample rates and sox-based interpolation. + + +Version 3.0rc0 – Release Candidate 0 +---- +Note: all Version 3 changes are summarized above. + +**New Feature** +* An experimental new back end for `libsoundio`, a C library for cross-platform real-time audio input and output. Many thanks to [Serg Podtynnyi](https://github.com/shtirlic). Please see https://github.com/mikebrady/shairport-sync/pull/433 for more details. + +**Other changes** +* Updates to `man` page and [README](https://github.com/mikebrady/shairport-sync/blob/development/README.md). Reports of typos or suggestions for improvement are welcome! + +Version 3.0d24 – Development Version +---- +Note: all Version 3 changes are summarized above. + +**New Feature** +* Set Max Volume. Add a new setting, for advanced users only, in the `general` section. Use the `volume_max_db` setting to allow you to specify the maximum level to set on the hardware mixer (if chosen) or the built-in software mixer otherwise. The software mixer's range is 0.0 dB to -96.1 dB. The setting must be a number with a decimal point, e.g. 21.3. + +Version 3.0d23 – Development Version +---- +Note: all Version 3 changes are summarized above. + +**New Feature** +* Choose Interface. Add a new setting, for advanced users only, in the `general` section. Use the `interface` setting to allow you to specify the interface on which to provide the AirPlay service. Omit the setting to get the default, which is to choose the interfaces automatically. + +Version 3.0d22 – Development Version +---- +Note: all Version 3 changes are summarized above. + +**Bug Fix** +* Fixed a bug which prevented successful building in the OpenWrt build system. The problem was caused by an `#include apple_alac.h` in `player.c` which was actioned even if the apple alac decoder was not selected. This caused the OpenWrt build system to expect the standard C++ library – required by the apple alac code – to be referenced, but it was not specified on the build manifest and therefore stopped the build. The solution was to make the `#include` conditional on selecting the apple alac decoder. + +Version 3.0d21 – Development Version +---- +Note: all Version 3 changes are summarized above. + +**Bug Fix** +* Fixed a bug which turned off resync by default. Duh. + +Version 3.0d20 – Development Version +---- +Note: all Version 3 changes are summarized above. + +**Bug Fix** +* Fix a small and generally silent error in configure.ac so that it only looks for the systemd direcotry if systemd has been chosen. It caused a warning when cross-compiling. + +Version 3.0d19 – Development Version +---- +Note: all Version 3 changes are summarized above. + +**New Feature** +* Reduces processor load back to V2.X levels by using a precalculated array of pseudorandom numbers to do dithering. Doesn't seem to make any audible difference. + +Version 3.0d18 – Development Version +---- +Note: all Version 3 changes are summarized above. + +**New Features** +* 8-bit, 16-bit, 24-bit, 24-bit three-byte (S24_3LE and S24_3BE) and 32-bit output to ALSA devices. (Other back ends are not updated yet.) +* 44,100, 88,200, 176,400 and 352,800 sample per second output. This is done using simple upsampling. +* Internal processing including software volume control and interpolation is done after sample size and rate conversion. +* Apple ALAC decoder support. This needs the `libalac` library, available at [ALAC](https://github.com/mikebrady/alac). Add the flag `--with-apple-alac` to the `./configure` arguments. Then you can choose the Apple ALAC decoder in the configuration file. +* Support for `mbed TLS` has been added and the use of `PolarSSL` is deprecated, as `mbed TLS` is a development of `PolarSSL` and `PolarSSL` itself is not being developed further. +* Settings that were denominated in frames are now deprecated but still honoured. Deprecation warnings are issued. + +Pesky Changes You Cannot Ignore +==== +* Settings have changed -- basically, any timings that were denominated in frames are now in seconds. Please refer to the shairport-sync.conf.sample file for details. +* Sox-based interpolation at higher sample rates may overload your CPU -- yopu might have to choose between higher sample rates and sox-based interpolation. + +**Bugs** +* Documentation is not updated. + +Version 2.8.6 – Stable Candidate +---- + +**Enhancements** +* This release contains a small change – it identifies itself as a ShairportSync device rather than an AirPort device. This should make it possible for Tuneblade, and possibly other players, to recognise it correctly. + +Version 2.8.5 – Stable Version +---- +This release includes bug fixes and minor enhancements and is recommended for all users. + +Note: if you're upgrading, there is a new `./configure` option: +==== +The build process now uses the directory path `sysconfdir` to determine where to place the configuration file `shairport-sync.conf`. +The default value for `sysconfdir` is `/usr/local/etc` which is used in the BSD family, whereas `/etc` is normally used in Linux. +To retain the present behaviour of Shairport Sync, *you must add an extra parameter to the `./configure... ` command.* The parameter you must add is `--sysconfdir=/etc`. (This has been added to the sample configuration command line in README.md.) + +The enhancements and bug fixes in 2.8.5 were made in versions 2.8.4.1 to 2.8.4.8 inclusive. Please read below for the full list. + +For advice on updating an installation you built yourself, +please visit the [UPDATING](https://github.com/mikebrady/shairport-sync/blob/master/UPDATING.md) page. + +Version 2.8.4.8 – Development Version +---- +**Enhancements** +* Add a new metadata item `clip` (for `CL`ient `IP`). This item is a string comprising the IP number of the "client", and is sent when a play session is starting. The "client" is the sender of the audio stream, e.g. iTunes on a Mac, or the Music player in iOS. +* When synchronisation has been disabled on the ALSA device (you should only do this for testing), Shairport Sync now refrains from asking for buffer length information from the device. + +Version 2.8.4.7 – Development Version +---- + +* This update means the build process now uses the directory path `sysconfdir` to determine where to place the configuration file `shairport-sync.conf`. The default value for `sysconfdir` is `/usr/local/etc` which is used in the BSD family, whereas `/etc` is normally used in Linux. So, to retain the present behaviour of Shairport Sync, you must add an extra parameter to the `./configure... ` command. The parameter you must add is `--sysconfdir=/etc`. (This has been added to the sample configuration command line in README.md.) +* Shairport Sync has been updated to use the value of `sysconfdir` to determine where to look for the configuration file. If `sysconfdir` has been left with its default value of `/usr/local/etc`, then Shairport Sync will look for `/usr/local/etc/shairport-sync.conf`. If, as recommended for Linux, `sysconfdir` has been set to `/etc`, then Shairport Sync will look, as before, for `/etc/shairport-sync.conf`. + +**Enhancement** +* The version string output when you use the command-line option `-V` now includes the value of the `sysconfdir`, e.g. `2.8.4.7-OpenSSL-Avahi-ALSA-soxr-sysconfdir:/etc`. + +Version 2.8.4.6 – Development Version +---- +**Enhancement** +* Add a new `alsa` configuration setting: `use_mmap_if_available` to control the use of mmap. The default is `"yes"` -- see [#351](https://github.com/mikebrady/shairport-sync/issues/351). + +Version 2.8.4.5 – Development Version +---- +**Enhancement** +* Handle varying packet lengths -- this makes it compatible with the HTC Connect, HTCs AirPlay implementation. Thanks to [Jörg Krause](https://github.com/joerg-krause) for his detective work, and see [#338](https://github.com/mikebrady/shairport-sync/issues/338). + +Version 2.8.4.4 – Development Version +---- +**Enhancement** +* Use alsa direct access (mmap) feature to improve performance if mmap is supported. Thanks to [Yihui Xiong](https://github.com/xiongyihui). + +Version 2.8.4.3 – Development Version +---- +**Bug Fix** + +* Set the RTSP socket to close on `exec()` of child processes; otherwise, background `run_this_before_play_begins` or `run_this_after_play_ends` commands that are sleeping prevent the daemon from being restarted because the listening RTSP port is still in use. Fixes [#329](https://github.com/mikebrady/shairport-sync/issues/329). + +Version 2.8.4.2 – Development Version +---- +**Bug Fixes** + +* Fixed an issue where you could not compile the audio_pipe back end without enabling metadata support (thanks to [busa-projects](https://github.com/busa-projects) for reporting the issue). +* Fixed a few small issues causing compiler warnings in `mdns_dns_sd.c`. + + +**Other** +* Removed the INSTALL file – it's generated automatically by `autoreconf -fi` anyway – added it to the files to be ignored in `.gitignore` and added a simple `INSTALL.md` file. + +Version 2.8.4.1 – Development Version +---- +**Bug Fixes** + +* Fixed two issues when including support for `pulseaudio`. +* Corrected two small errors in sample parameters for the UDP metadata stream settings, thanks to [rkam](https://github.com/rkam). + +Version 2.8.4 – Stable Version +---- +This release includes important bug fixes and minor enhancements and is recommended for all users. No settings need to be changed. For advice on updating an installation you built yourself, please visit the [UPDATING](https://github.com/mikebrady/shairport-sync/blob/master/UPDATING.md) page. + +The following is a summary of the bug fixes and enhancements since version 2.8.3. + +**Bug Fixes** + +* Checks have been added for empty or NULL audio buffers that were causing assertion violations and subsequent abnormal program termination. + +* An IPv6 bug has been fixed — a bug in the networking software would not allow an IPv6 link-local connection to be made from a client if Shairport Sync was running on a device with more than one network interface. The solution was to take account of the `config_id` information. + +* Some problems have been fixed with the non-blocking write function used to write metadata. + +* A bug in the volume control transfer function has been fixed, thanks to [Jörg Krause](https://github.com/joerg-krause). + +**Enhancements** + +* Shairport Sync now works with [AllConnect/Streambels](http://allconnectapp.com) on Android with password protection. (As with all Android clients, you should set the `drift` to something large, like 500 or 1,000, as the timekeeping of these clients isn't as accurate as that of iTunes, etc.) + +* The networking subsystem has been modified to always use the same IP number during a session. Background: the computer Shairport Sync is running on can have many IP numbers active at the same time – various IPv6 numbers and also various IPv4 numbers. During a play session, when Shairport Sync has to create connections back to the source, it would use an automatically-assigned IP number for itself, but that number might not be same as the the number used earlier in the session. From now on, it will always use the same IP number it used when the connection was first established. Thanks to [ejurgensen](https://github.com/ejurgensen) for help with this. + +* Experimental support has been added for a softvol plugin, thanks to the work of [Jörg Krause](https://github.com/joerg-krause) -- see [#293](https://github.com/mikebrady/shairport-sync/pull/293). + +* A `playback_mode` setting has been added to allow the selection of `stereo` (default) or `mono` playback -- thanks to [faceless2](https://github.com/faceless2). + +* The new default service name is now the device's `hostname`, with its first character capitalised (ASCII only). + +* Substitutions can now be made in the service name. The following substitutions can be used in the service name: `%h` for the `hostname`, `%H` for the `hostname` with the first letter capitalised, `%v` for the version number and `%V` for the full version string. Maximum length is 50 characters. + +* An existing `shairport-sync.service` file will not be overwritten by `sudo make install`. + +* The text strings advertising the capabilities of Shairport Sync over Bonjour/Zeroconf/Avahi have been changed and now more closely match those of an AirPort Express Base Station (First Generation). + +* It is now possible to set the amount of time to wait for the metadata pipe to become ready for writing. The setting is called `pipe_timeout` in the `metadata` section. Default is 5,000 milliseconds. + +* Metadata can now be provided via UDP -- thanks to [faceless2](https://github.com/faceless2). + +* Statistics output is more machine readable -- thanks to [Jörg Krause](https://github.com/joerg-krause) +* The `shairport-sync.spec` file has been updated for compatability with building Debian packages using `checkinstall` -- thanks to [vru1](https://github.com/vru1). + +Version 2.8.3.11 – Development Version +---- +**Bug Fix** + +Fixed some problems with the non-blocking write function used to write to the metadata pipe. + +**Enhancement** + +It is now possible to set the amount of time to wait for the metadata pipe to become ready for writing. The setting is called `pipe_timeout` in the `metadata` section. Default is 5,000 milliseconds. + +Version 2.8.3.10 – Development Version +---- +**Bug Fix** + +* Restored metadata feed lost in 2.8.3.7. + +Version 2.8.3.9 – Development Version +---- +**Enhancements** + +* Substitutions can now be made in the service name, i.e. the name that appears in iTunes, etc. The following substitutions can be used in the service name you specify: `%h` for the hostname, `%H` for the hostname with the first letter capitalised, `%v` for the version number and `%V` for the full version string. Maximum length is 50 characters. + +* The new default service name is simply the hostname, with its first character capitalised. + +* An existing `shairport-sync.service` file will not be overwritten by `sudo make install`. + +Version 2.8.3.7 – Development Version +---- +**Enhancements** + +* Shairport Sync now works with AllConnect/Streambels on Android with password protection. (As with all Android clients, you should set the `drift` to something large, like 500 or 1,000, as the timekeeping of these clients isn't as accurate as that of iTunes, etc.) + +* The text strings advertising the capabilities of Shairport Sync over Bonjour/Zeroconf/Avahi have been changed and now more closely match those of an AirPort Express Base Station (First Generation). + +Version 2.8.3.6 – Development Version +---- +**Bug fix** + +An IPv6 link-local connection issue was fixed. A bug in the networking software would not allow an IPv6 link-local connection to be made from a client if Shairport Sync was running on a device with more than one network interface. The solution was to take account of the `config_id` information. + +Version 2.8.3.5 – Development Version +---- +**Enhancement** + +Experimental support for a softvol plugin, thanks to the work of [Jörg Krause](https://github.com/joerg-krause) -- see [#293](https://github.com/mikebrady/shairport-sync/pull/293). + +**Bug fix** + +Add checks for empty or NULL audio buffers that seem to be causing assertion violations and subsequent abnormal program termination. + +Version 2.8.3.4 – Development Version +---- + +**Bug Fix** + +The networking subsystem has been modified to always use the same IP number during a session. Background: the computer Shairport Sync is running on can have many IP numbers active at the same time – various IPv6 numbers and also various IPv4 numbers. During a play session, when Shairport Sync has to create connections back to the source, it would use an automatically-assigned IP number for itself, but that number might not be same as the the number used earlier in the session. From now on, it will always use the same IP number it used when the connection was first established. Thanks to [ejurgensen](https://github.com/ejurgensen) for help with this. + + +Changed the `mono` setting for a `playback_mode` setting with two possible values: `stereo` (default) and `mono`. + +Version 2.8.3.3 – Deleted +---- + +Version 2.8.3.2 – Deleted +---- + +Version 2.8.3.1 – Development Version +---- +Added a new `mono` setting -- thanks to [faceless2](https://github.com/faceless2). Documentation to follow. + +Version 2.8.3 – Stable Version +---- +A bug in 2.8.2 caused Avahi to fail at startup under some circumstances with older installations. The problem was that sometimes the `regtype` setting would not be initialised properly. + +Version 2.8.2 – Stable Version +---- +Version 2.8.2 is derived from development version 2.9.5.7 and has stability improvements, bug fixes and a few special-purpose enhancements. + +For full details, please refer to the release notes here, back as far as 2.8.1. + +Version 2.9.5.7 – Development Version +---- +Version 2.9.5.7 contains general bug fixes and enhancements for some special situations. + +**Bug Fixes** + +* Getting delay and latency information from the `alsa` subsystem has been improved -- bugs fixed, error codes handled better, arithmetic handling (hopefully) better. +* If latency information is temporarily unavailable from the `alsa` subsystem, skip trying to synchronise until the next time. +* Some condition variables and a mutex were uninitialised, yikes! Fixed. +* A bug that set the output volume to maximum at the same time as muting the output has been fixed. AFAIK, this was inaudible, but it was scary looking. +* Recover from name collisions in Avahi. +* Detect and handle empty buffers better. + +**Enhancements** + +* Turn off synchronisation. This is an advanced feature and generally leads to buffer underrun or overrun. +* Set `alsa` buffer size and `alsa` period size. There are advanced features, mainly for debugging. They may be removed. +* Change the Zeroconf/Bonjour `regtype` to enable Shairport Sync to continue to run but to be invisible to AirPlay clients. Special purpose usage only. +* Output total number of packets and the play time of a session when statistics are enabled. + +Version 2.9.4 – Development Version +---- +Version 2.9.4 corrects some bugs in how Avahi error conditions are handled. + +**Bug Fix** +* During operation, if the network disappeared, Avahi would occasionally report an error. This would cause Shairport Sync to attempt to terminate gracefully (which is the wrong thing to do in the circumstances). However, the termination attempt was actually causing an assertion violation crash. These errors are now simply logged. + +Version 2.9.3 – Development Version +---- +Version 2.9.3 is 2.8.1 with documentation and version changes to indicate that it's in the development branch. + +Version 2.8.1 – Stable Version +---- +Version 2.8.1 is derived from development version 2.9.2 and has stability improvements and important bug fixes. + +For full details, please refer to the release notes here, back as far as 2.9.1. + +Version 2.9.2 – Development Version +---- +Version 2.9.2 focusses on further bug fixes and stability improvements. +* Enhanced stability: an important bug has been fixed in the handling of missing audio frames – i.e. what happens when a frame of audio is truly missing, after all attempts to fetch it have been unsuccessful. The bug would cause Shairport Sync to do an unnecessary resynchronisation, or, if resync was turned off, to jump out of sync. This is a long-standing bug – thanks to [Jörg Krause](https://github.com/joerg-krause) for identifying it. +* An extra diagnostic has been added which gives the mean, standard deviation and maximum values for inter-packet reception time on the audio port. It may be useful for exploring line quality. + +Version 2.9.1 – Development Version +---- +Version 2.9.1 focusses on bug fixes and stability improvements. +* Stability improvements are concentrated on what happens when a play sessions ends and is followed immediately by a new session. This happens in iOS 9.2 when you click to the next track or to the previous track. It also happens playing YouTube videos when a Mac's System Audio is routed through AirPlay. Thanks to [Tim Curtis](https://github.com/moodeaudio) for help with these issues. +* A workaround for an apparent flushing issue in TuneBlade has been included. Thanks to [gibman](https://github.com/gibman) for reporting this issue. +* A number of bug fixes have been made to `configure.ac` – thanks to [Jörg Krause](https://github.com/joerg-krause). + +Version 2.8 – Stable Version +---- +Version 2.8 is derived from version 2.7.10 with slight documentation updates. Here is a summary of changes between the last stable version – 2.6 – and this version. For full details, refer to the release notes here, back as far as 2.7. + +**New Feature** +* For hardware mixers with a restricted range (including many cheaper USB DACS), the general `volume_range_db` can be used to specify a wider range than the hardware provides – the extra range is provided by software. + +**Enhancements** +* The `man` manual and the html version of it are automagically rebuilt if `xml2man` and friends are available. +* Volume-setting metadata is now sent even when the volume level is to be ignored by Shairport Sync itself. +* Shairport Sync waits a little longer before asking for missing packets to be resent. Sometimes packets are just arriving slightly out of order and don't need to be asked for again. +* The build scripts have been modified to be a little more compatible with standard practice. +* A Continuous Integration (CI) system – Travis CI – is now used to do some limited build checking (thanks guys!). +* Support added for compiling on Cygwin. +* Added `rtptime` tags to metadata and picture metadata. +* Replaced and improved the dither algorithm used with the software volume control. The new dither code gives a two bit peak-to-peak dither based on a Triangular Probability Distribution Function (TPDF). +* Disabled picture sending if pictures haven’t been asked for. + +**Bug fixes** +* Fixed a bug that prevented Shairport Sync from correctly setting the hardware mixer volume if it had been altered externally. Thanks to [Tim Curtis](https://github.com/moodeaudio) for help with these issues. +* Modified the shutdown behaviour so that a shutdown followed immediately by a play request is handled better. This was causing iOS 9.2 sometimes to drop the Airplay link between tunes. +* Fixed a data-alignment bug that would cause a crash in certain circumstances on ARM processors with metadata enabled. +* Corrected the names for a few settings tags. +* Fixed some typos and misspellings. +* Miscellaneous small bug fixes. + +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** +* 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** +* 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** +* 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** +* 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 +---- +**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 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 +---- +**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). + +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). + +**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 +---- +**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 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 Probability Distribution 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 +---- +**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 whenever problems are detected with the proposed 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** +* 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, is very small). 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 as for stdout. +* Add `shairport-sync.exe` to `.gitignore`. +* 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. + + +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. + +**Fixes** +* For `systemd` users, the `shairport-sync.service` file is updated to point to the correct location of the shairport-sync application. +* For Fedora users, the `shairport-sync.spec` file is updated to refer to 2.6. + + +Version 2.4.2 +---- +This release has important enhancements, bug fixes and documentation updates. It also appears to bring compatiblity with Synology NAS devices. + + +**New Features** +* Source-specified Latencies. Shairport Sync now uses the latencies specified by the audio source. Background: the AirPlay protocol used by Shairport Sync allows the audio source to specify the exact delay or latency that should be applied to the audio stream. Until now, Shairport Sync ignored this information and used fixed preset latencies that were selected on the basis of the "User-Agent" setting. Using source-specified latencies means that Shairport Sync is able adapt automatically to different sources. +Using source-specified latencies is now automatic unless non-standard static latencies have been specified in the configuration file or command line. Using non-standard latencies is usually done to compensate for delays in the back end of the system. For example, if the audio amplifier being driven by Shairport Sync has an inherent delay of its own -- as happens with many home theatre and surround sound systems -- then some users have reduced the latencies used by Shairport Sync to compensate. This usage is discouraged -- the `audio_backend_latency_offset` in the appropriate backend stanza (e.g. in the "alsa" stanza) should be used for this. Static latency settings are now deprecated, and will be removed in a future version of Shairport Sync. +* Set Volume Range. This is a new setting that allows you to use just a portion of the full range of attenuation offered by a mixer. For example, if a mixer has a minimum volume of -80 dB and a maximum of +20 dB, you might wish to use only 60 dB of the 100 dB available. This might be because the sound becomes inaudible at the lowest setting and unbearably loud at the highest setting. It is for this reason that many domestic HiFi systems have a volume control range of only 60 to 80 dB. + Another possible reason to use this setting might be because the range specified by the mixer does not match the actual capabilities of the device. For example, the Raspberry Pi's DAC that feeds the built-in audio jack claims a range of 106 dB but has a useful range of only about 35dB. The new `volume_range_db` setting in the `general` stanza allows you to specify the maximum range from highest to lowest. The range suggested for the Raspberry Pi's built-in audio DAC, which feeds the headphone jack, is 35. Using it in this case gives the volume control a much more useful range of settings. + +**Bug fixes** +* Sometimes, especially when using Shairport Sync as a system output, it would not play the audio stream. This was caused by an improperly initialised variable. Fixed. Synology NAS devices now seem to be working with Shairport Sync. +* Fix in the `shairport.c`: the USE_CUSTOM_LOCAL_STATE_DIR macro was still being used when it should have been USE_CUSTOM_PID_DIR. +* Fix a crashing bug -- if metadata was enabled but a pipename was not supplied, boom. + +**Other Changes** +* Initial timing accuracy improved. The estimate of when to play the starting frame of the audio sequence has improved significantly. This leads to fewer corrections being needed at the start. +* Volume ratios expressed in decibels are now consistently denominated in voltage decibels rather than power decibels. The rationale is that the levels refer to voltage levels, and power is proportional to the square of voltage. +Thus a ratio of levels of 65535 to 1 is 96.3 dB rather than the 48.15 dB used before. +* The latency figure returned to the source as part of the response to an rtsp request packet is 11,025, which may (?) be meant to indicate the minimum latency the device is capable of. +* An experimental handler for a GET_PARAMETER rtsp request has been added. It does nothing except log the occurence. +* The RTSP request dispatcher now logs an event whenever an unrecognised rtsp has been made. + + +Version 2.4.1 +---- +This release has three small bug fixes and some small documentation updates. + +**Bug Fixes** + +Changes from the previous stable version -- 2.4 -- are summarised here: + * The USE_CUSTOM_LOCAL_STATE_DIR macro was still being used when it should have been USE_CUSTOM_PID_DIR. This could affect users using a custom location for the PID directory. + * A compiler error has been fixed that occured if metadata was enabled and tinysvcmdns was included. + * A crash has been fixed that occured if metadata was enabled and a metadata pipename was not specified. +(Thanks to the contributors who reported bugs.) + +**Small Changes** + * If a mixer being used to control volume does not have a control denominated in dB, a warning is logged and the mixer is not used. + * Slight revisions have been made to the configuration file `configure.ac` to make compilation on FreeBSD a little easier. + +Version 2.4 +---- +**Stable release** + +This stable release is the culmination of the 2.3.X sequence of development releases. + +**Change Summary** + +Changes from the previous stable version -- 2.2.5 -- are summarised here: + * Settings are now read from a configuration file. Command-line settings are supported but discouraged. + * Metadata is now supported -- it can be delivered to a unix pipe for processing by a helper application. See https://github.com/mikebrady/shairport-sync-metadata-reader for a sample metadata reader. + * Raw PCM audio can be delivered to standard output ("stdout") or to a unix pipe. The internal architecture has changed considerably to support this. + * Support for compilation on OpenWrt back to Attitude Adjustment. + * Can play unencrypted audio streams -- complatible with, e.g. Whaale. + * Uses the libconfig library. + * Runs on a wider range of platforms, including Arch Linux and Fedora. + * Bug fixes. + +Please note that building instructions have changed slightly from the previous version. +Also, the `-t hardware/software` option has been deprecated in the alsa back end. + +Version 2.3.13 +---- +**Note** +* We're getting ready to release the development branch as the new, stable, master branch at 2.4. If you're packaging Shairport Sync, you might prefer to wait a short while as we add a little polish before the release. + +**Changes** +* Harmonise version numbers on the release and on the `shairport.spec` file used in Fedora. + +Version 2.3.12 +---- +**Note** +* We're getting ready to release the development branch as the new, stable, master branch at 2.4. If you're packaging Shairport Sync, you might prefer to wait a short while as we add a little polish before the release. + +**Changes** +* `update-rc.d` has been removed from the installation script for System V because it causes problems for package makers. It's now noted in the user installation instructions. +* The `alsa` group `mixer_type` setting is deprecated and you should stop using it. Its functionality has been subsumed into `mixer_name` – when you specify a `mixer_name` it automatically chooses the `hardware` mixer type. + + +**Enhancements** +* 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. + +**Documentation Update** +* Nearly there with updates concerning the configuration file. + +Version 2.3.11 +---- +Documentation Update +* Beginning to update the `man` document to include information about the configuration file. It's pretty sparse, but it's a start. + +Version 2.3.10 +---- +Bug fix +* The "pipe" backend used output code that would block if the pipe didn't have a reader. This has been replaced by non-blocking code. Here are some implications: + * When the pipe is created, Shairport Sync will not block if a reader isn't present. + * If the pipe doesn't have a reader when Shairport Sync wants to output to it, the output will be discarded. + * If a reader disappears while writing is occuring, the write will time out after five seconds. + * Shairport Sync will only close the pipe on termination. + +Version 2.3.9 +---- +* Bug fix + * Specifying the configuration file using a *relative* file path now works properly. + * The debug verbosity requested with `-v`, `-vv`, etc. is now honoured before the configuration file is read. It is read and honoured from when the command line arguments are scanned the first time to get a possible configuration file path. + +Version 2.3.8 +---- +* Annoying changes you must make + * You probably need to change your `./configure` arguments. The flag `with-initscript` has changed to `with-systemv`. It was previously enabled by default; now you must enable it explicitly. + +* Changes + * Added limited support for installing into `systemd` and Fedora systems. For `systemd` support, use the configuration flag `--with-systemd` in place of `--with-systemv`. The installation does not do everything needed, such as defining special users and groups. + * Renamed `with-initscript` configuration flag to `with-systemv` to describe its role more accurately. + * A System V startup script is no longer installed by default; if you want it, ask for it with the `--with-systemv` configuration flag. + * Added limited support for FreeBSD. You must specify `LDFLAGS='-I/usr/local/lib'` and `CPPFLAGS='-L/usr/local/include'` before running `./configure --with-foo etc.` + * Removed the `-configfile` annotation from the version string because it's no longer optional; it's always there. + * Removed the `dummy`, `pipe` and `stdout` backends from the standard build – they are now optional and are no longer automatically included in the build. + +* Bug fixes + * Allow more stack space to prevent a segfault in certain configurations (thanks to https://github.com/joerg-krause). + * Add missing header files(thanks to https://github.com/joerg-krause). + * Removed some (hopefully) mostly silent bugs from the configure.ac file. + +Version 2.3.7 +---- +* Changes + * Removed the two different buffer lengths for the alsa back end that made a brief appearance in 2.3.5. +* Enhancements + * Command line arguments are now given precedence over config file settings. This conforms to standard unix practice. + * A `–without-pkg-config` configuration argument now allows for build systems, e.g. for older OpenWrt builds, that haven't fully implemented it. There is still some unhappiness in arch linux builds. +* More + * Quite a bit of extra diagnostic code was written to investigate clock drift, DAC timings and so on. It was useful but has been commented out. If might be useful in the future. + +Version 2.3.5 +---- +* Changes + * The metadata item 'sndr' is no longer sent in metadata. It's been replaced by 'snam' and 'snua' -- see below. +* Enhancements + * When a play session is initiated by a source, it attempts to reserve the player by sending an "ANNOUNCE" packet. Typically, a source device name and/or a source "user agent" is sent as part of the packet. The "user agent" is usually the name of the sending application along with some more information. If metadata is enabled, the source name, if provided, is emitted as a metadata item with the type `ssnc` and code `snam` and similarly the user agent, if provided, is sent with the type `ssnc` and code `snua`. + * Two default buffer lengths for ALSA -- default 6615 frames if a software volume control is used, to minimise the response time to pause and volume control changes; default 22050 frames if a hardware volume control is used, to give more resilience to timing problems, sudden processor loading, etc. This is especially useful if you are processing metadata and artwork on the same machine. + * Extra metadata: when a play session starts, the "Active-Remote" and "DACP-ID" fields -- information that can be used to identify the source -- are provided as metadata, with the type `ssnc` and the codes `acre` and `daid` respectively. The IDs are provided as strings. + * Unencrypted audio data. The iOS player "Whaale" attempts to send unencrypted audio, presumably to save processing effort; if unsuccessful, it will send encrypted audio as normal. Shairport Sync now recognises and handles unencrypted audio data. (Apparently it always advertised that it could process unencrypted audio!) + * Handle retransmitted audio in the control channel. When a packet of audio is missed, Shairport Sync will ask for it to be retransmitted. Normally the retransmitted audio comes back the audio channel, but "Whaale" sends it back in the control channel. (I think this is a bug in "Whaale".) Shairport Sync will now correctly handle retransmitted audio packets coming back in the control channel. +* Bugfixes + * Generate properly-formed `..` items of information. + +Version 2.3.4 +---- +* Enhancement + * When a play session starts, Shairport Sync opens three UDP ports to communicate with the source. Until now, those ports could be any high numbered port. Now, they are located within a range of 100 port locations starting at port 6001. The starting port and the port range are settable by two new general settings in `/etc/shairport-sync.conf` -- `udp_port_base` (default 6001) and `udp_port_range` (default 100). To retain the previous behaviour, set the `udp_port_base` to `0`. +* Bugfixes + * Fix an out-of-stack-space error that can occur in certain cases (thanks to https://github.com/joerg-krause). + * Fix a couple of compiler warnings (thanks to https://github.com/joerg-krause). + * Tidy up a couple of debug messages that were emitting misleading information. + +Version 2.3.3.2 +---- +* Bugfix -- fixed an error in the sample configuration file. + +Version 2.3.3.1 +---- +* Enhancement + * Metadata format has changed slightly -- the format of each item is now `........`, where the `..` part is present if the length is non-zero. The change is that everything is now enclosed in an `..` pair. + +Version 2.3.2 and 2.3.3 +---- +These releases were faulty and have been deleted. + +Version 2.3.1 +----- +Some big changes "under the hood" have been made, leading to limited support for unsynchronised output to `stdout` or to a named pipe and continuation of defacto support for unsynchronised PulseAudio. Also, support for a configuration file in preference to command line options, an option to ignore volume control and other improvements are provided. + +In this release, Shairport Sync gains the ability to read settings from `/etc/shairport-sync.conf`. +This gives more flexibility in adding features gives better compatability across different versions of Linux. +Existing command-line options continue to work, but some will be deprecated and may disappear in a future version of Shairport Sync. New settings will only be available via the configuration file. + +Note that, for the present, settings in the configuration will have priority over command line options for Shairport Sync itself, in contravention of the normal unix convention. Audio back end command line options, i.e. those after the `--`, have priority over configuration file settings for the audio backends. + +In moving to the the use of a configuration file, some "housekeeping" is being done -- some logical corrections and other small changes are being made to option names and modes of operations, so the settings in the configuration file do not exactly match command line options. + +When `make install` is executed, a sample configuration is installed or updated at `/etc/shairport-sync.conf.sample`. The same file is also installed as `/etc/shairport-sync.conf` if that file doesn't already exist. To prevent the configuration files being installed, use the configuration option `--without-configfiles`. + +* Pesky Change You Must Do Something About + +If you are using metadata, please note that the option has changed somewhat. The option `-M` has a new long name equivalent: `--metadata-pipename` and the argument you provide must now be the full name of the metadata pipe, e.g. `-M /tmp/shairport-sync-metadata`. + +* Enhancements + * Shairport Sync now reads settings from the configuration file `/etc/shairport-sync.conf`. This has settings for most command-line options and it's where any new settings will go. A default configuration file will be installed if one doesn't exist, and a sample file configuration file is always installed or updated. Details of settings are provided in the sample file. Shairport Sync relies on the `libconfig` library to read configuration files. For the present, you can disable the new feature (and save the space taken up by `libconfig`) by using the configure option `--without-configfile-support`. + * New command-line option `-c ` or `--configfile=` allows you to specify a configuration file other than `/etc/shairport-sync.conf`. + * Session Timeout and Allow Session Interruption can now be set independently. This is really some "housekeeping" as referred to above -- it's a kind of a bug fix, where the bug in question is an inappropriate connection of the setting of two parameters. To explain: (1) By default, when a source such as iTunes starts playing to the Shairport Sync device, any other source attempting to start a play session receives a "busy" signal. If a source disappears without warning, Shairport Sync will wait for 120 seconds before dropping the session and allowing another source to start a play session. (2) The command-line option `-t` or `--timeout` allows you to set the wait time before dropping the session. If you set this parameter to `0`, Shairport Sync will not send a "busy" signal, thus allowing another source to interrupt an existing one. (3) The problem is that if you set the parameter to `0`, a session will never be dropped if the source disappears without warning. + The (obvious) fix for this is to separate the setting of the two parameters, and this is now done in the configuration file `/etc/shairport-sync.conf` -- please see the settings `allow_session_interruption` and `session_timeout`. The behaviour of the `-t` and `--timeout` command-line options is unchanged but deprecated. + * New Option -- "Ignore Volume Control" ('ignore_volume_control'). If you set this to "yes", the output from Shairport Sync is always set at 100%. This is useful when you want to set the volume locally. Available via the settings file only. + * Statistics option correctly reports when no frames are received in a sampling interval and when output is not being synchronised. + * A new, supported audio back end called `stdout` provides raw 16-bit 44.1kHz stereo PCM output. To activate, set `output_backend = "stdout"` in the general section of the configuration file. Output is provided synchronously with the source feed. No stuffing or stripping is done. If you are feeding it to an output device that runs slower or faster, you'll eventually get buffer overflow or underflow in that device. To include support for this back end, use the configuration option `--with-stdout`. + * Support for the `pipe` back end has been enhanced to provide raw 16-bit 44.1kHz stereo PCM output to a named pipe. To activate, set `output_backend = "pipe"` in the general section of the configuration and give the fully-specified pathname to the pipe in the pipe section of the configuration file -- see `etc/shairport-sync.conf.sample` for an example. No stuffing or stripping is done. If you are feeding it to an output device that runs slower or faster, you'll eventually get buffer overflow or underflow in that device. To include support for this back end, use the configuration option `--with-pipe`. + * Support for the `dummy` audio backend device continues. To activate, set `output_backend = "dummy"` in in the general section of the configuration. To include support for this back end, use the configuration option `--with-dummy`. + * Limited support for the PulseAudio audio backend continues. To activate, set `output_backend = "pulse"` in in the general section of the configuration. You must still enter its settings via the command line, after the `--` as before. Note that no stuffing or stripping is done: if the PulseAudio sink runs slower or faster, you'll eventually get buffer overflow or underflow. + * New backend-specific settings are provided for setting the size of the backend's buffer and for adding or removing a fixed offset to the overall latency. The `audio_backend_buffer_desired_length` default is 6615 frames, or 0.15 seconds. On some slower machines, particularly with metadata processing going on, the DAC buffer can underflow on this setting, so it might be worth making the buffer larger. A problem on software mixers only is that changes to volume control settings have to propagate through the buffer to be heard, so the larger the buffer, the longer the response time. If you're using an alsa back end and are using a hardware mixers, this isn't a problem. The `audio_backend_latency_offset` allows you emit frames to the audio back end some time before or after the synchronised time. This would be useful, for example, if you are outputting to a device that takes 20 ms to process audio; yoou would specify a `audio_backend_latency_offset = -882`, where 882 is the number of frames in 20 ms, to compensate for the device delay. + +Version 2.3 +----- +* Enhancements + * Adding the System V startup script (the "initscript") is now a configuration option. The default is to include it, so if you want to omit the installation of the initscript, add the configuration option `--without-initscript`. + * Metadata support is now a compile-time option: `--with-metadata`. + * A metadata feed has been added. Use the option `-M `, e.g. `-M /tmp`. Shairport Sync will provide metadata in a pipe called `/shairport-sync-metadata`. (This is changed in 2.3.1.) There's a sample metadata reader at https://github.com/mikebrady/shairport-sync-metadata-reader. The format of the metadata is a mixture of XML-style tags, 4-character codes and base64 data. Please look at `rtsp.c` and `player.c` for examples. Please note that the format of the metadata may change. +Beware: there appears to be a serious bug in iTunes before 12.1.2, such that it may stall for a long period when sending large (more than a few hundred kilobytes) coverart images. + +* Bugfix + * Fix a bug when compiling for Arch Linux on Raspberry Pi 2 (thanks to https://github.com/joaodriessen). + * Fix a bug whereby if the ANNOUNCE and/or SETUP method fails, the play_lock mutex is never unlocked, thus blocking other clients from connecting. This can affect all types of users, but particularly Pulseaudio users. (Thanks to https://github.com/jclehner.) + * Modify the init script to start after all services are ready. Add in a commented-out sleep command if users find it necessary (thanks to https://github.com/BNoiZe). + * Two memory leaks fixed (thanks to https://github.com/pdgendt). + * An error handling time specifications for flushes was causing an audible glitch when pausing and resuming some tracks. This has been fixed (thanks to https://github.com/Hamster128). + +Version 2.2.5 +----- +* Bugfixes + * Fix a segfault error that can occur in certain cases (thanks again to https://github.com/joerg-krause). + * Include header files in common.c (thanks again to https://github.com/joerg-krause). + +Version 2.2.4 +----- +* Bugfixes + * Fix an out-of-stack-space error that can occur in certain cases (thanks to https://github.com/joerg-krause). + * Fix a couple of compiler warnings (thanks to https://github.com/joerg-krause). + +Version 2.2.3 +----- +* NOTE: all the metadata stuff has been moved to the "development" branch. This will become the stable branch henceforward, with just bug fixes or minor enhancements. Apologies for the inconvenience. +* Bugfixes + * Fix a bug when compiling for Arch Linux on Raspberry Pi 2 (thanks to https://github.com/joaodriessen). + * Fix a compiler warning (thanks to https://github.com/sdigit). + +Version 2.2.2 +----- +* Enhancement + * An extra latency setting for forked-daapd sources -- 99,400 frames, settable via a new option `--forkedDaapdLatency`. + +Version 2.2.1 +----- +* Bugfixes: + * If certain kinds of malformed RTSP packets were received, Shairport Sync would stop streaming. Now, it generally ignores faulty RTSP packets. + * The `with-pulseaudio` compile option wasn't including a required library. This is fixed. Note that the PulseAudio back end doesn't work properly and is just included in the application because it was there in the original shairport. Play with it for experimentation only. + * Fix typo in init.d script: "Headphones" -> "Headphone". +* Extra documentation + * A brief note on how to compile `libsoxr` from source is included for the Raspberry Pi. + +Version 2.2 +----- +* Enhancements: + * New password option: `--password=SECRET` + * New tolerance option: `--tolerance=FRAMES`. Use this option to specify the largest synchronisation error to allow before making corrections. The default is 88 frames, i.e. 2 milliseconds. The default tolerance is fine for streaming over wired ethernet; however, if some of the stream's path is via WiFi, or if the source is a third-party product, it may lead to much overcorrection -- i.e. the difference between "corrections" and "net correction" in the `--statistics` option. Increasing the tolerence may reduce the amount of overcorrection. + +Version 2.1.15 +----- +* Changes to latency calculations: + * The default latency is now 88,200 frames, exactly 2 seconds. It was 99,400 frames. As before, the `-L` option allows you to set the default latency. + * The `-L` option is no longer deprecated. + * The `-L` option no longer overrides the `-A` or `-i` options. + * The default latency for iTunes is now 99,400 frames for iTunes 10 or later and 88,200 for earlier versions. + * The `-i` or `--iTunesLatency` option only applies to iTunes 10 or later sources. + +Version 2.1.14 +----- +* Documentation update: add information about the `-m` audio backend option. +The `-m` audio backend option allows you to specify the hardware mixer you are using. Not previously documented. +Functionality of shairport-sync is unchanged. + +Version 2.1.13 +----- +* Compilation change: Begin to use PKG_CHECK_MODULES (in configure.ac) to statically link some of the libraries used by shairport-sync. It is intended to make it easier to build in the buildroot system. While sufficient for that purpose, note that PKG_CHECK_MODULES is not used for checking all the libraries yet. +Functionality of shairport-sync is unchanged. + +Version 2.1.12 +----- +* Enhancement: `--statistics` + Statistics are periodically written to the console (or the logfile) if this command-line option is included. They are no longer produced in verbose (`-v`) mode. +* Bugfixes for `tinysvcmdns` + * A bug that prevented the device's IP number(s) and port numbers being advertised when using `tinysvcmdns` has been fixed. (Cause: name needed to have a `.local` suffix.) + * Bugs causing the shairport service to semi-randomly disappear and reappear seem to be fixed. (Possible cause: incorrect timing settings when using `tinysvcmdns`.) + +Version 2.1.11 +----- +* Enhancement + * A man page is now installed -- do `man shairport-sync` or see it here: http://htmlpreview.github.io/?https://github.com/mikebrady/shairport-sync/blob/2.1/man/shairport-sync.html. + +Version 2.1.10 +----- +* Bugfix + * A bug that caused the `-t` timeout value to be incorrectly assigned has been fixed. (Cause: `config.timeout` defined as `int64_t` instead on `int`.) + +Version 2.1.9 +----- +* Bugfixes + * A bug that sometimes caused the initial volume setting to be ignored has been fixed. (Cause: setting volume before opening device.) + * a bug that caused shairport-sync to become unresponsive or unavailable has been fixed. (Cause: draining rather than flushing the alsa device before stopping.) + +Version 2.1.8: +----- +* Enhancements + * (This feature is intended to be useful to integrators.) Shairport Sync now the ability to immediately disconnect and reconnect to the sound output device while continuing to stream audio data from its client. +Send a `SIGUSR2` to the shairport-sync process to disconnect or send it a `SIGHUP` to reconnect. If shairport-sync has been started as a daemon using `shairport-sync -d`, then executing `shairport-sync -D` or `--disconnectFromOutput` will request the daemon to disconnect, and executing `shairport-sync -R` or `--reconnectToOutput` will request it to reconnect. +With this feature, you can allow Shairport Sync always to advertise and provide the streaming service, but still be able to disconnect it locally to enable other audio services to access the output device. + +* Annoying things you should know about if you're updating from a previous version: + * Options `--with-openssl`, `--with-polarssl` have been replaced with a new option `--with-ssl= + +