diff --git a/LIBSOXR.md b/LIBSOXR.md index 4883b9b2..2c703ab6 100644 --- a/LIBSOXR.md +++ b/LIBSOXR.md @@ -1,5 +1,7 @@ -The Raspbian image at the time of writing is `2015-01-31-raspbian`. It does not include `libsoxr`, nor is `libsoxr` available as a package via `apt-get`. -Libsoxr is, however, easy to compile, and works well with Shairport Sync on the Raspberry Pi. Here are very brief instructions to download, compile and install it on the Raspberry Pi, so that it can be used with Shairport Sync. + +The Raspbian image at the time of writing is the `May 2016` version, with the release date of `2016-05-10`. It does not include `libsoxr`, but it is available as a package via `apt-get`. + +Alternatively, `libsoxr` is very easy to compile. Here are very brief instructions to download, compile and install it: * Install `cmake`. This is used in the building of libsoxr: ``` diff --git a/Makefile.am b/Makefile.am index f576001d..f9fd8976 100644 --- a/Makefile.am +++ b/Makefile.am @@ -62,5 +62,5 @@ if INSTALL_SYSTEMV endif if INSTALL_SYSTEMD [ -e $(DESTDIR)$(systemdsystemunitdir) ] || mkdir -p $(DESTDIR)$(systemdsystemunitdir) - cp scripts/shairport-sync.service $(DESTDIR)$(systemdsystemunitdir) + [ -f $(DESTDIR)$(systemdsystemunitdir)/shairport-sync.service ] || cp scripts/shairport-sync.service $(DESTDIR)$(systemdsystemunitdir) endif diff --git a/README.md b/README.md index f2066ae8..08d3edf1 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Audio played by a Shairport Sync-powered device stays synchronised with the sour Shairport Sync does not support AirPlay video or photo streaming. -This 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. +This is the unstable "development" branch. Changes and updates are incorporated into this branch quickly. To access the stable version, where changes are made after due time, please switch to the "master" branch. More Information ---------- @@ -29,7 +29,7 @@ What else? * Hardware Mute — Shairport Sync will mute properly if the hardware supports it. * Fast Response — With hardware volume control, response is instantaneous; otherwise the response time is 0.15 seconds. * Non-Interruptible — Shairport Sync sends back a "busy" signal if it's already playing audio from another source, so other sources can't disrupt an existing Shairport Sync session. (If a source disappears without warning, the session automatically terminates after two minutes and the device becomes available again.) -* Metadata — Shairport Sync can deliver metadata supplied by the source, such as Album Name, Artist Name, Cover Art, etc. through a pipe to a recipient application program — see https://github.com/mikebrady/shairport-sync-metadata-reader for a sample recipient. Sources that supply metadata include iTunes and the Music app in iOS. +* Metadata — Shairport Sync can deliver metadata supplied by the source, such as Album Name, Artist Name, Cover Art, etc. through a pipe 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. @@ -49,42 +49,11 @@ For information about changes and updates, please refer to the RELEASENOTES.md f Note: Historically, Shairport Sync has taken its settings from command line arguments. While this is still the case, it does not always work well across distributions. Accordingly, from version 2.4 onwards, Shairport Sync reads settings from the file `/etc/shairport-sync.conf`. Access to new features will only be provided via the settings file. -Building And Installing +Building And Installing the Development Version --------------------- -If you wish to install Shairport Sync on OpenWrt, Arch or Fedora platforms, please follow the appropriate instructions below. Limited support is also available for Mac OS X. Otherwise follow the General Build Instructions. Then, when the program has been installed, refer to the section on Configuring Shairport Sync that follows. - -**Note** - The following procedures will install the shairport-sync application into your system. Before continuing, you should check to see if shairport-sync is already installed – you can use `which shairport-sync` to find where it is located, if installed. If it is installed you should delete it – you may need superuser privileges. After deleting, check again in case further copies are installed elsewhere. (If the existing installation of shairport-sync is where the new copy will be installed into, it will be overwritten; sometimes, however, the installation is to another location, so it is safer, initially, to delete previous versions manually.) -**Ubuntu:** -Personal Package Archives for Shairport Sync master and development branches are available at https://launchpad.net/~dantheperson. A `shairport-sync` installer package is available in Ubuntu 16.04, currently in its late beta phase. - -**Debian:** -`shairport-sync` is in the Debian archive and is scheduled for release with Debian Stretch (9): https://tracker.debian.org/shairport-sync. A backport for Debian Jessie (8) may be provided given enough demand. - -**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 available at [EliaCereda/shairport-sync-PKGBUILD](https://github.com/EliaCereda/shairport-sync-PKGBUILD). - -**Mac OS X:** -A [HomeBrew](http://brew.sh) package exists for Shairport Sync. With HomeBrew installed, Shairport Sync can be installed using the command `$brew install shairport-sync`. Note that the installation uses the `libao` library and so synchronisation is not available — playback glitches will occur occasionally, when the `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! - -**General Build Instructions** - To build Shairport Sync from sources on Debian, Ubuntu, Raspbian, etc. follow these instructions. The following libraries are required: @@ -105,12 +74,12 @@ Many Linux distributions have Avahi and OpenSSL already in place, so normally it Debian, Ubuntu and Raspbian users can get the basics with: -- `apt-get install build-essential git` – these may already be installed. +- `apt-get install build-essential git xmltoman` – these may already be installed. - `apt-get install autoconf automake libtool libdaemon-dev libasound2-dev libpopt-dev libconfig-dev` - `apt-get install avahi-daemon libavahi-client-dev` if you want to use Avahi (recommended). - `apt-get install libssl-dev` if you want to use OpenSSL and libcrypto, or use PolarSSL otherwise. - `apt-get install libpolarssl-dev` if you want to use PolarSSL, or use OpenSSL/libcrypto otherwise. -- `apt-get install libsoxr-dev` if you want support for libsoxr-based resampling. This library is in many recent distributions, including Jessie and Raspioan Jessie; if not, instructions for how to build it from source for Raspian/Debian Wheezy are available at [LIBSOXR.md](https://github.com/mikebrady/shairport-sync/blob/master/LIBSOXR.md). +- `apt-get install libsoxr-dev` if you want support for libsoxr-based resampling. This library is in many recent distributions, including Jessie and Raspbian Jessie; 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/development/LIBSOXR.md). Download Shairport Sync: @@ -119,6 +88,7 @@ Download Shairport Sync: Next, `cd` into the shairport-sync directory and execute the following command: ``` +$ git checkout development $ autoreconf -i -f ``` (Note that the `autoreconf...` step may take some time on less powerful machines.) @@ -210,7 +180,7 @@ $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 +You can view the man page here: http://htmlpreview.github.io/?https://github.com/mikebrady/shairport-sync/blob/development/man/shairport-sync.html Configuring Shairport Sync -------- @@ -268,7 +238,7 @@ Another setting to consider is the `general` `drift` setting: you should set it *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. +As previously mentioned, you can use command line arguments to provide settings to Shairport Sync as before, though newer settings will only be available via the configuration file. For full information, please read the Shairport Sync `man` page, also available at http://htmlpreview.github.io/?https://github.com/mikebrady/shairport-sync/blob/development/man/shairport-sync.html. Apart from the following options, all command line options can be replaced by settings in the configuration file. Here is a brief description of command line options that are not replicated by settings in the settings file. @@ -372,6 +342,14 @@ alsa = { }; ``` +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. @@ -411,5 +389,5 @@ It's not unusual to have resend requests, late packets and even missing packets Troubleshooting --------------- -Please refer to [TROUBLESHOOTING](https://github.com/mikebrady/shairport-sync/blob/master/TROUBLESHOOTING.md) for a few hints, contributed by users. +Please refer to [TROUBLESHOOTING](https://github.com/mikebrady/shairport-sync/blob/development/TROUBLESHOOTING.md) for a few hints, contributed by users. diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 26de412e..8759c567 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,3 +1,114 @@ +Version 2.8.4 – Stable Version (Candidate Release) +---- +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. diff --git a/audio_alsa.c b/audio_alsa.c index 2a2096a6..f7462e55 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -59,9 +59,9 @@ audio_output audio_alsa = { .flush = &flush, .delay = &delay, .play = &play, - .mute = NULL, // to be set later on... - .volume = NULL, // to be set later on... - .parameters = NULL // to be set later on... + .mute = &mute, + .volume = &volume, + .parameters = ¶meters }; static pthread_mutex_t alsa_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -70,7 +70,8 @@ static unsigned int desired_sample_rate; static snd_pcm_t *alsa_handle = NULL; static snd_pcm_hw_params_t *alsa_params = NULL; - +static snd_ctl_t *ctl = NULL; +static snd_ctl_elem_id_t *elem_id = NULL; static snd_mixer_t *alsa_mix_handle = NULL; static snd_mixer_elem_t *alsa_mix_elem = NULL; static snd_mixer_selem_id_t *alsa_mix_sid = NULL; @@ -82,7 +83,7 @@ static char *alsa_mix_dev = NULL; static char *alsa_mix_ctrl = "Master"; static int alsa_mix_index = 0; static int hardware_mixer = 0; - +static int has_softvol = 0; static int play_number; static int64_t accumulated_delay, accumulated_da_delay; @@ -289,18 +290,39 @@ static int init(int argc, char **argv) { audio_alsa.parameters = ¶meters; // likewise the parameters stuff if (alsa_mix_mindb == SND_CTL_TLV_DB_GAIN_MUTE) { // Raspberry Pi does this - debug(1, "Lowest dB value is a mute."); + debug(1, "Lowest dB value is a mute -- try minimum volume +1"); if (snd_mixer_selem_ask_playback_vol_dB( - alsa_mix_elem, alsa_mix_minv + 1, &alsa_mix_mindb) == 0) - debug(1, "Can't get dB value corresponding to a \"volume\" of 1."); + alsa_mix_elem, alsa_mix_minv + 1, &alsa_mix_mindb) != 0) + debug(1, "Can't get dB value corresponding to a minimum volume + 1."); } debug(1, "Hardware mixer has dB volume from %f to %f.", (1.0 * alsa_mix_mindb) / 100.0, (1.0 * alsa_mix_maxdb) / 100.0); } else { // use the linear scale and do the db conversion ourselves debug(1, "note: the hardware mixer specified -- \"%s\" -- does not have " - "a dB volume scale, so it can't be used.", + "a dB volume scale, so it can't be used. Trying software " + "volume control.", alsa_mix_ctrl); + + if (snd_ctl_open(&ctl, alsa_mix_dev, 0) < 0) + die("Cannot open control \"%s\"", alsa_mix_dev); + if (snd_ctl_elem_id_malloc(&elem_id) < 0) + die("Cannot allocate memory for control \"%s\"", alsa_mix_dev); + snd_ctl_elem_id_set_interface(elem_id, SND_CTL_ELEM_IFACE_MIXER); + snd_ctl_elem_id_set_name(elem_id, alsa_mix_ctrl); + + if (snd_ctl_get_dB_range(ctl, elem_id, &alsa_mix_mindb, + &alsa_mix_maxdb) == 0) { + debug(1, "Volume control \"%s\" has dB volume from %f to %f.", + alsa_mix_ctrl, + (1.0 * alsa_mix_mindb) / 100.0, + (1.0 * alsa_mix_maxdb) / 100.0); + has_softvol = 1; + } else { + debug(1, "Cannot get the dB range from the volume control \"%s\"", + alsa_mix_ctrl); + } + /* debug(1, "Min and max volumes are %d and %d.",alsa_mix_minv,alsa_mix_maxv); @@ -465,7 +487,7 @@ int open_alsa_device(void) { if (alsa_characteristics_already_listed==0) { alsa_characteristics_already_listed=1; - + int log_level = 2; // the level at which debug information should be output int rc; snd_pcm_access_t access_type; snd_pcm_format_t format_type; @@ -476,7 +498,7 @@ int open_alsa_device(void) { int dir; snd_pcm_uframes_t frames; - debug(1,"PCM handle name = '%s'", + debug(log_level,"PCM handle name = '%s'", snd_pcm_name(alsa_handle)); // ret = snd_pcm_hw_params_any(alsa_handle, alsa_params); @@ -486,103 +508,103 @@ int open_alsa_device(void) { // alsa_out_dev); // } - debug(1,"alsa device parameters:"); + debug(log_level,"alsa device parameters:"); snd_pcm_hw_params_get_access(alsa_params,&access_type); - debug(1," access type = %s", snd_pcm_access_name(access_type)); + debug(log_level," access type = %s", snd_pcm_access_name(access_type)); snd_pcm_hw_params_get_format(alsa_params,&format_type); - debug(1," format = '%s' (%s)",snd_pcm_format_name(format_type),snd_pcm_format_description(format_type)); + debug(log_level," format = '%s' (%s)",snd_pcm_format_name(format_type),snd_pcm_format_description(format_type)); snd_pcm_hw_params_get_subformat(alsa_params,&subformat_type); - debug(1," subformat = '%s' (%s)",snd_pcm_subformat_name(subformat_type),snd_pcm_subformat_description(subformat_type)); + debug(log_level," subformat = '%s' (%s)",snd_pcm_subformat_name(subformat_type),snd_pcm_subformat_description(subformat_type)); snd_pcm_hw_params_get_channels(alsa_params, &uval); - debug(1," number of channels = %u", uval); + debug(log_level," number of channels = %u", uval); sval = snd_pcm_hw_params_get_sbits(alsa_params); - debug(1," number of significant bits = %d", sval); + debug(log_level," number of significant bits = %d", sval); snd_pcm_hw_params_get_rate(alsa_params, &uval, &dir); switch (dir) { case -1: - debug(1," rate = %u frames per second (<).", uval); + debug(log_level," rate = %u frames per second (<).", uval); break; case 0: - debug(1," rate = %u frames per second (precisely).", uval); + debug(log_level," rate = %u frames per second (precisely).", uval); break; case 1: - debug(1," rate = %u frames per second (>).", uval); + debug(log_level," rate = %u frames per second (>).", uval); break; } if (snd_pcm_hw_params_get_rate_numden(alsa_params,&uval, &uval2)==0) - debug(1," precise (rational) rate = %.3f frames per second (i.e. %u/%u).", uval, uval2, ((double)uval)/uval2); + debug(log_level," precise (rational) rate = %.3f frames per second (i.e. %u/%u).", uval, uval2, ((double)uval)/uval2); else - debug(1," precise (rational) rate information unavailable."); + debug(log_level," precise (rational) rate information unavailable."); snd_pcm_hw_params_get_period_time(alsa_params,&uval, &dir); switch (dir) { case -1: - debug(1," period_time = %u us (<).", uval); + debug(log_level," period_time = %u us (<).", uval); break; case 0: - debug(1," period_time = %u us (precisely).", uval); + debug(log_level," period_time = %u us (precisely).", uval); break; case 1: - debug(1," period_time = %u us (>).", uval); + debug(log_level," period_time = %u us (>).", uval); break; } snd_pcm_hw_params_get_period_size(alsa_params,&frames, &dir); switch (dir) { case -1: - debug(1," period_size = %lu frames (<).", frames); + debug(log_level," period_size = %lu frames (<).", frames); break; case 0: - debug(1," period_size = %lu frames (precisely).", frames); + debug(log_level," period_size = %lu frames (precisely).", frames); break; case 1: - debug(1," period_size = %lu frames (>).", frames); + debug(log_level," period_size = %lu frames (>).", frames); break; } snd_pcm_hw_params_get_buffer_time(alsa_params,&uval, &dir); switch (dir) { case -1: - debug(1," buffer_time = %u us (<).", uval); + debug(log_level," buffer_time = %u us (<).", uval); break; case 0: - debug(1," buffer_time = %u us (precisely).", uval); + debug(log_level," buffer_time = %u us (precisely).", uval); break; case 1: - debug(1," buffer_time = %u us (>).", uval); + debug(log_level," buffer_time = %u us (>).", uval); break; } snd_pcm_hw_params_get_buffer_size(alsa_params,&frames); switch (dir) { case -1: - debug(1," buffer_size = %lu frames (<).", frames); + debug(log_level," buffer_size = %lu frames (<).", frames); break; case 0: - debug(1," buffer_size = %lu frames (precisely).", frames); + debug(log_level," buffer_size = %lu frames (precisely).", frames); break; case 1: - debug(1," buffer_size = %lu frames (>).", frames); + debug(log_level," buffer_size = %lu frames (>).", frames); break; } snd_pcm_hw_params_get_periods(alsa_params, &uval, &dir); switch (dir) { case -1: - debug(1," periods_per_buffer = %u (<).", uval); + debug(log_level," periods_per_buffer = %u (<).", uval); break; case 0: - debug(1," periods_per_buffer = %u (precisely).", uval); + debug(log_level," periods_per_buffer = %u (precisely).", uval); break; case 1: - debug(1," periods_per_buffer = %u (>).", uval); + debug(log_level," periods_per_buffer = %u (>).", uval); break; } } @@ -645,9 +667,10 @@ static void play(short buf[], int samples) { if (alsa_handle == NULL) { pthread_mutex_lock(&alsa_mutex); ret = open_alsa_device(); - open_mixer(); + if (hardware_mixer) + open_mixer(); pthread_mutex_unlock(&alsa_mutex); - if ((ret == 0) && (audio_alsa.volume)) + if ((hardware_mixer) && (ret == 0) && (audio_alsa.volume)) audio_alsa.volume(set_volume); } if (ret == 0) { @@ -656,11 +679,17 @@ static void play(short buf[], int samples) { int err, ignore; if ((snd_pcm_state(alsa_handle) == SND_PCM_STATE_PREPARED) || (snd_pcm_state(alsa_handle) == SND_PCM_STATE_RUNNING)) { - err = snd_pcm_writei(alsa_handle, (char *)buf, samples); - if (err < 0) { - debug(1, "Error %d writing %d samples in play(): \"%s\".", err, samples, - snd_strerror(err)); - ignore = snd_pcm_recover(alsa_handle, err, 1); + if (buf==NULL) + debug(1,"NULL buffer passed to pcm_writei -- skipping it"); + if (samples==0) + debug(1,"empty buffer being passed to pcm_writei -- skipping it"); + if ((samples!=0) && (buf!=NULL)) { + err = snd_pcm_writei(alsa_handle, (char *)buf, samples); + if (err < 0) { + debug(1, "Error %d writing %d samples in play(): \"%s\".", err, samples, + snd_strerror(err)); + ignore = snd_pcm_recover(alsa_handle, err, 1); + } } } else { debug(1, "Error -- ALSA device in incorrect state (%d) for play.", @@ -728,11 +757,30 @@ static void volume(double vol) { debug(2, "Setting volume db to %f.", vol); set_volume = vol; if (hardware_mixer && alsa_mix_handle) { - if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, 0) != 0) { - debug(1, "Can't set playback volume accurately to %f dB.", vol); - if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, -1) != 0) - if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, 1) != 0) - die("Failed to set playback dB volume"); + if (has_softvol) { + if (ctl && elem_id) { + snd_ctl_elem_value_t *value; + long raw; + + if (snd_ctl_convert_from_dB(ctl, elem_id, (long) vol, &raw, 0) < 0) + debug(1, "Failed converting dB gain to raw volume value for the " + "software volume control."); + + snd_ctl_elem_value_alloca(&value); + snd_ctl_elem_value_set_id(value, elem_id); + snd_ctl_elem_value_set_integer(value, 0, raw); + snd_ctl_elem_value_set_integer(value, 1, raw); + if (snd_ctl_elem_write(ctl, value) < 0) + debug(1, "Failed to set playback dB volume for the software volume " + "control."); + } + } else { + if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, 0) != 0) { + debug(1, "Can't set playback volume accurately to %f dB.", vol); + if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, -1) != 0) + if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, 1) != 0) + die("Failed to set playback dB volume"); + } } } pthread_mutex_unlock(&alsa_mutex); diff --git a/common.c b/common.c index bc077732..0dc8a0b7 100644 --- a/common.c +++ b/common.c @@ -437,7 +437,7 @@ double vol2attn(double vol, long max_db, long min_db) { #define order 3 - double vol_setting = max_db; + double vol_setting = 0; if ((vol <= 0.0) && (vol >= -30.0)) { long range_db = max_db - min_db; // this will be a positive nunmber @@ -465,6 +465,7 @@ double vol2attn(double vol, long max_db, long min_db) { } else if (vol != -144.0) { debug(1, "Volume request value %f is out of range: should be from 0.0 to -30.0 or -144.0.", vol); + vol_setting = min_db; // for safety, return the lowest setting... } else { vol_setting = min_db; // for safety, return the lowest setting... } @@ -512,27 +513,68 @@ uint64_t get_absolute_time_in_fp() { return time_now_fp; } +#ifdef CONFIG_METADATA ssize_t non_blocking_write(int fd, const void *buf, size_t count) { - // debug(1,"writing %u to pipe...",count); - // we are assuming that the count is always smaller than the FIFO's buffer + void *ibuf = (void *)buf; + size_t bytes_remaining = count; + int rc = 0; struct pollfd ufds[1]; - ssize_t reply; - do { - ufds[0].fd = fd; + while ((bytes_remaining>0) && (rc==0)) { + // check that we can do some writing + ufds[0].fd = fd; ufds[0].events = POLLOUT; - int rv = poll(ufds, 1, 5000); - if (rv == -1) - debug(1, "error waiting for pipe to unblock..."); - if (rv == 0) - debug(1, "timeout waiting for pipe to unblock"); - reply = write(fd, buf, count); - if ((reply == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) - debug(1, "writing to pipe will block..."); - // else - // debug(1,"writing %u to pipe done...",reply); - } while ((reply == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))); - return reply; - + rc = poll(ufds, 1, config.metadata_pipe_timeout); + if (rc < 0) { + // debug(1, "non-blocking write error waiting for pipe to become ready for writing..."); + } else if (rc == 0) { + // warn("non-blocking write timeout waiting for pipe to become ready for writing"); + rc = -2; + } else { //rc > 0, implying it might be ready + size_t bytes_written = write(fd,ibuf,bytes_remaining); + if (bytes_written==-1) { + // debug(1,"Error %d in non_blocking_write: \"%s\".",errno,strerror(errno)); + rc = -1; + } else { + ibuf += bytes_written; + bytes_remaining -= bytes_written; + } + } + } + if (rc==0) + return count-bytes_remaining; // this is just to mimic a normal write/3. + else + return rc; // return write(fd,buf,count); } +#endif +/* from http://coding.debuntu.org/c-implementing-str_replace-replace-all-occurrences-substring#comment-722 */ + +char *str_replace ( const char *string, const char *substr, const char *replacement ){ + char *tok = NULL; + char *newstr = NULL; + char *oldstr = NULL; + char *head = NULL; + + /* if either substr or replacement is NULL, duplicate string a let caller handle it */ + if ( substr == NULL || replacement == NULL ) return strdup (string); + newstr = strdup (string); + head = newstr; + while ( (tok = strstr ( head, substr ))){ + oldstr = newstr; + newstr = malloc ( strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) + 1 ); + /*failed to alloc mem, free old string and return NULL */ + if ( newstr == NULL ){ + free (oldstr); + return NULL; + } + memcpy ( newstr, oldstr, tok - oldstr ); + memcpy ( newstr + (tok - oldstr), replacement, strlen ( replacement ) ); + memcpy ( newstr + (tok - oldstr) + strlen( replacement ), tok + strlen ( substr ), strlen ( oldstr ) - strlen ( substr ) - ( tok - oldstr ) ); + memset ( newstr + strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) , 0, 1 ); + /* move back head right after the last replacement */ + head = newstr + (tok - oldstr) + strlen( replacement ); + free (oldstr); + } + return newstr; +} diff --git a/common.h b/common.h index 7520b0c0..5924be79 100644 --- a/common.h +++ b/common.h @@ -43,13 +43,22 @@ enum stuffing_type { ST_soxr, } type; +enum playback_mode_type { + ST_stereo = 0, + ST_mono, +} playback_mode_type; + typedef struct { config_t *cfg; char *password; - char *apname; + char *service_name; // the name for the shairport service, e.g. "Shairport Sync Version %v running on host %h" #ifdef CONFIG_METADATA int metadata_enabled; + int metadata_pipe_timeout; // in milliseconds char *metadata_pipename; + char *metadata_sockaddr; + int metadata_sockport; + int metadata_sockmsglength; int get_coverart; #endif uint8_t hw_addr[6]; @@ -77,6 +86,7 @@ typedef struct { int32_t ForkedDaapdLatency; // supplied with --ForkedDaapdLatency option int daemonise; int statistics_requested,use_negotiated_latencies; + enum playback_mode_type playback_mode; char *cmd_start, *cmd_stop; int cmd_blocking; int tolerance; // allow this much drift before attempting to correct it @@ -88,9 +98,8 @@ typedef struct { char *regtype; // The regtype is the service type followed by the protocol, separated by a dot, by default “_raop._tcp.”. long audio_backend_buffer_desired_length; // this will be the desired number of frames in the // audio backend buffer -- the DAC buffer for ALSA - long audio_backend_latency_offset; // this will be the offset to compensate for any fixed latency + long audio_backend_latency_offset; // this will be the offset to compensate for any fixed latency there might be in the audio path uint32_t volume_range_db; // the range, in dB, from max dB to min dB. Zero means use the mixer's native range. - // there might be in the audio } shairport_cfg; // true if Shairport Sync is supposed to be sending output to the output device, false otherwise @@ -101,6 +110,9 @@ void set_requested_connection_state_to_output(int v); ssize_t non_blocking_write(int fd, const void *buf, size_t count); // used in a few places +/* from http://coding.debuntu.org/c-implementing-str_replace-replace-all-occurrences-substring#comment-722 */ +char *str_replace ( const char *string, const char *substr, const char *replacement ); + int debuglev; void die(char *format, ...); void warn(char *format, ...); diff --git a/configure.ac b/configure.ac index fe28922e..f91c9a11 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.50]) -AC_INIT([shairport-sync], [2.8.3], [mikebrady@eircom.net]) +AC_INIT([shairport-sync], [2.8.4], [mikebrady@eircom.net]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([shairport.c]) AC_CONFIG_HEADERS([config.h]) diff --git a/man/shairport-sync.7 b/man/shairport-sync.7 index b261ec60..85202518 100644 --- a/man/shairport-sync.7 +++ b/man/shairport-sync.7 @@ -6,8 +6,6 @@ shairport-sync \- Synchronised Audio Player for iTunes / AirPlay shairport-sync -D\fB -shairport-sync -h\fB - shairport-sync -k\fB shairport-sync -h\fB @@ -49,7 +47,7 @@ Settings are organised into groups, for example, there is a "general" group of s \fB};\f1 -Most settings have sensible default values, so -- as in the example above -- users generally only need to set (1) the service name, (2) a password (if desired) and (3) the output device. If the output device has a mixer that can be used for volume control, then (4) the volume control's name should be specificed. It is highly desirable to use the output device's mixer for volume control, if available -- response time is reduced to zero and the processor load is reduced. In the example above, "soxr" interpolation was also enabled. +Most settings have sensible default values, so -- as in the example above -- users generally only need to set (1) the service name, (2) a password (if desired) and (3) the output device. If the output device has a mixer that can be used for volume control, then (4) the volume control's name should be specified. It is highly desirable to use the output device's mixer for volume control, if available -- response time is reduced to zero and the processor load is reduced. In the example above, "soxr" interpolation was also enabled. A sample configuration file with all possible settings, but with all of them commented out, is installed at \fI/etc/shairport-sync.conf.sample\f1. @@ -61,7 +59,11 @@ The configuration file is processed using the \fIlibconfig\f1 library -- see \fB These are the settings available within the \fBgeneral\f1 group: .TP \fBname=\f1\fI"service_name"\f1\fB;\f1 -Use this \fIservice_name\f1 to identify this player in iTunes, etc. The default name is "Shairport Sync on ". +Use this \fIservice_name\f1 to identify this player in iTunes, etc. + +The following substitutions are allowed: \fB%h\f1 for the computer's hostname, \fB%H\f1 for the computer's hostname with the first letter capitalised (ASCII only), \fB%v\f1 for the Shairport Sync version number, e.g. "2.8.4" and \fB%V\f1 for the Shairport Sync version string, e.g. "2.8.4-OpenSSL-Avahi-ALSA-soxr-metadata". + +The default is "%H", which is replaced by the hostname with the first letter capitalised. .TP \fBpassword=\f1\fI"password"\f1\fB;\f1 Require the password \fIpassword\f1 to connect to the service. If you leave this setting commented out, no password is needed. @@ -100,7 +102,21 @@ Use this to specify how much debugging information should be output or logged. " Set this \fIchoice\f1 to "yes" if you want the volume to be at 100% no matter what the source's volume control is set to. This might be useful if you want to set the volume on the output device, independently of the setting at the source. The default is "no". .TP \fBvolume_range_db=\f1\fIdBvalue\f1\fB;\f1 -Set this \fIdBvalue\f1 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 -- indeed, many domestic HiFi systmes have a volume copntrol range of just 60 to 80dB. Another potential use might be where the range specified by the mixer does not match the 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 setting 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. If you omit this setting, the full "native" range of the mixer is used. +Use this \fIdBvalue\f1 to reduce or increase the attenuation range, in decibels, between the minimum and maximum volume. + +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 -- indeed, many domestic HiFi systems have a volume control range of just 60 to 80dB. + +Another potential use might be where the range specified by the mixer does not match the 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 setting 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. + +As a third example, you can actually extend the range provided by a mixer. Many cheaper DACs have hardware mixers that offer a restricted attenuation range. If you specify a volume range greater than the range of the mixer, software attenuation and hardware attenuation will be combined to give the specified range. + +If you omit this setting, the full "native" range of the mixer is used. +.TP +\fBregtype=\f1\fI"regTypeString"\f1\fB;\f1 +Use this advanced setting to set the service type and transport to be advertised by Zeroconf/Bonjour. Default is "_raop._tcp". +.TP +\fBplayback_mode=\f1\fI"mode"\f1\fB;\f1 +The \fImode\f1 can be "stereo" or "mono". Default is "stereo". .TP \fB"ALSA" SETTINGS\f1 These settings are for the ALSA back end, used to communicate with audio output devices in the ALSA system. (By the way, you can use tools such as \fBalsamixer\f1 or \fBaplay\f1 to discover what devices are available.) Use these settings to select the output device and the mixer control to be used to control the output volume. You can additionally set the desired size of the output buffer and you can adjust overall latency. Here are the \fBalsa\f1 group settings: @@ -122,6 +138,15 @@ Set this \fIoffset\f1, in frames, to compensate for a fixed delay in the audio b \fBaudio_backend_buffer_desired_length=\f1\fIlength\f1\fB;\f1 Use this to set the desired number frames to be in the output device's hardware output buffer. The default is 6,615 frames, or 0.15 seconds. If set too small, buffer underflow may occur on low-powered machines. If too large, the response times when using software volume control (i.e. when not using a mixer control to control volume) become annoying, or it may exceed the hardware buffer size. It may need to be larger on low-powered machines that are also performing other tasks, such as processing metadata. .TP +\fBdisable_synchronization=\f1\fI"no"\f1\fB;\f1 +This is an advanced setting and is for debugging only. Set to "yes" to disable synchronization. Default is "no". If you use it to disable synchronisation, then soner or later you'll experience audio glitches due to audio buffer overflow or underflow. +.TP +\fBperiod_size=\f1\fInumber\f1\fB;\f1 +Use this optional advanced setting to set the alsa period size near to this value. +.TP +\fBbuffer_size=\f1\fInumber\f1\fB;\f1 +Use this optional advanced setting to set the alsa buffer size near to this value. +.TP \fB"PIPE" SETTINGS\f1 These settings are for the PIPE backend, used to route audio to a named unix pipe. The audio is in raw CD audio format: PCM 16 bit little endian, 44,100 samples per second, stereo. @@ -182,8 +207,17 @@ Set the \fIchoice\f1 to "yes" to enable shairport-sync to look for cover art fro \fBpipe_name=\f1\fI"filepathname"\f1\fB;\f1 Specify the absolute path name of the pipe through which metadata should be sent The default is \fI/tmp/shairport-sync-metadata\f1". .TP +\fBsocket_address=\f1\fI"hostnameOrIP"\f1\fB;\f1 +If \fIhostnameOrIP\f1 is set to a host name or and IP address, UDP packets containing metadata will be sent to this address. May be a multicast address. "socket-port" must be non-zero and "enabled" must be set to "yes". +.TP +\fBsocket_port=\f1\fIport\f1\fB;\f1 +If \fBsocket_address\f1 is set, use \fIport\f1 to specify the port to send UDP packets to. Must not be zero. +.TP +\fBsocket_msglength=\f1\fI65000\f1\fB;\f1 +The maximum packet size for any UDP metadata. This must be between 500 or 65000. The default is 500. +.TP \fB"SESSIONCONTROL" SETTINGS\f1 -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. +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. .TP \fBrun_this_before_play_begins=\f1\fI"/path/to/application and args"\f1\fB;\f1 Here you can specify a program and its arguments that will be run just before a play session begins. Be careful to include the full path to the application. The application must be marked as executable and, if it is a script, its first line must begin with the standard \fI#!/bin/...\f1 as appropriate. @@ -207,9 +241,9 @@ Latency is the exact time from a sound signal's original timestamp until that si Shairport Sync now sets latencies automatically using information supplied by the source, typically either 88,200 or 99,577 frames. -The following relates to the old scheme of using fixed latencies, which ignores the latency information supplied by the source. There are four default latency settings. One latency matches the latency used by recent versions of iTunes when playing audio and another matches the latency used by so-called "AirPlay" devices, including iOS devices and iTunes and Quicktime Player when they are playing video. A third latency is used when the audio source is forked-daapd. The fourth latency is the default if no other latency is chosen and is used for older versions of iTunes. +The following relates to the old scheme of using fixed latencies, which ignored the latency information supplied by the source. There are four default latency settings. One latency matches the latency used by recent versions of iTunes when playing audio and another matches the latency used by so-called "AirPlay" devices, including iOS devices and iTunes and Quicktime Player when they are playing video. A third latency is used when the audio source is forked-daapd. The fourth latency is the default if no other latency is chosen and is used for older versions of iTunes. -Note: If you are thinking of changing latencies to compensate for a delay in the audio output device, then instead of changing these individual latencies, consider using the \fBaudio_backend_latency_offset\f1 setting in the \fBalsa\f1 group (or the appropriate other group if you're not outputing through the alsa backend). +Note: If you are thinking of changing latencies to compensate for a delay in the audio output device, then instead of changing these individual latencies, use the \fBaudio_backend_latency_offset\f1 setting in the \fBalsa\f1 group (or the appropriate other group if you're not outputing through the alsa backend). .TP \fBitunes=\f1\fIlatency\f1\fB;\f1 This is the \fIlatency\f1, in frames, used for iTunes 10 or later. Default is 99,400. @@ -232,10 +266,14 @@ The command line for shairport-sync can take two kinds of options: regular \fBpr These options are used by shairport-sync itself. .TP \fB-a \f1\fIservice name\f1\fB | --name=\f1\fIservice name\f1 -Use this \fIservice name\f1 to identify this player in iTunes, etc. The default name is "Shairport Sync on ". +Use this \fIservice name\f1 to identify this player in iTunes, etc. The following substitutions are allowed: \fB%h\f1 for the computer's hostname, \fB%H\f1 for the computer's hostname with the first letter capitalised (ASCII only), \fB%v\f1 for the Shairport Sync version number, e.g. "2.8.4" and \fB%V\f1 for the Shairport Sync version string, e.g. "2.8.4-OpenSSL-Avahi-ALSA-soxr-metadata". + +The default is "%H", which is replaced by the hostname with the first letter capitalised. .TP \fB-A | --AirPlayLatency=\f1\fIlatency\f1 Use this \fIlatency\f1, in frames, for audio streamed from an AirPlay device. The default is 88,200 frames, where there are 44,100 frames to the second. + +Please note that this feature is deprecated and will be removed in a future version of Shairport Sync. .TP \fB-B \f1\fIprogram\f1\fB | --on-start=\f1\fIprogram\f1 Execute \fIprogram\f1 when playback is about to begin. Specify the full path to the program, e.g. \fI/usr/bin/logger\f1. Executable scripts can be used, but they must have \fI#!/bin/sh\f1 (or whatever is appropriate) in the headline. @@ -247,6 +285,8 @@ Read configuration settings from \fIfilename\f1. The default is to read them fro .TP \fB-D | --disconnectFromOutput\f1 Disconnect the shairport-sync daemon from the output device and exit. (Requires that the daemon has written its PID to an agreed file -- see the \fB-d\f1 option). + +Please note that this feature is deprecated and will be removed in a future version of Shairport Sync. .TP \fB-d | --daemon\f1 Instruct shairport-sync to demonise itself. It will write its Process ID (PID) to a file, usually at \fI/var/run/shairport-sync.pid\f1, which is used by the \fB-k\f1, \fB-D\f1 and \fB-R\f1 options to locate the daemon at a later time. @@ -258,6 +298,8 @@ If you want shairport-sync to wait until the command has completed before contin .TP \fB--forkedDaapdLatency=\f1\fIlatency\f1 Use this \fIlatency\f1, in frames, for audio streamed from a forked-daapd based source. The default is 99,400 frames, where there are 44,100 frames to the second. + +Please note that this feature is deprecated and will be removed in a future version of Shairport Sync. .TP \fB--get-coverart\f1 This option requires the \fB--meta-dir\f1 option to be set, and enables shairport-sync to request cover art from the source and to transmit it through the metadata pipe. @@ -269,12 +311,16 @@ Print brief help message and exit. .TP \fB-i | --iTunesLatency=\f1\fIlatency\f1 Use this \fIlatency\f1, in frames, for audio streamed from an iTunes source, where iTunes is Version 10 or later. The default is 99,400 frames, where there are 44,100 frames to the second. If the source is iTunes but is earler than Version 10, the \fIdefault latency\f1 is used (see the \fB-L\f1 option). Some third party programs masquerade as older versions of iTunes. + +Please note that this feature is deprecated and will be removed in a future version of Shairport Sync. .TP \fB-k | --kill\f1 Kill the shairport-sync daemon and exit. (Requires that the daemon has written its PID to an agreed file -- see the \fB-d\f1 option). .TP \fB-L | --latency=\f1\fIlatency\f1 Use this to set the \fIdefault latency\f1, in frames, for audio coming from an unidentified source or from an iTunes Version 9 or earlier source. The standard value for the \fIdefault latency\f1 is 88,200 frames, where there are 44,100 frames to the second. + +Please note that this feature is deprecated and will be removed in a future version of Shairport Sync. .TP \fB--meta-dir=\f1\fIdirectory\f1 Listen for metadata coming from the source and send it, along with metadata from shairport-sync itself, to a pipe called \fIshairport-sync-metadata\f1 in the \fIdirectory\f1 you specify. If you add the \fB--get-cover-art\f1 then cover art will be sent through the pipe too. See \fBhttps://github.com/mikebrady/shairport-sync-metadata-reader\f1 for a sample metadata reader. @@ -293,6 +339,8 @@ Require the password \fIsecret\f1 to be able to connect and stream to the servic .TP \fB-R | --reconnectToOutput\f1 Reconnect the shairport-sync daemon to the output device and exit. It may take a few seconds to synchronise. (Requires that the daemon has written its PID to an agreed file -- see the \fB-d\f1 option). + +Please note that this feature is deprecated and will be removed in a future version of Shairport Sync. .TP \fB-r \f1\fIthreshold\f1\fB | --resync=\f1\fIthreshold\f1 Resynchronise if timings differ by more than \fIthreshold\f1 frames. If the output timing differs from the source timing by more than the threshold, output will be muted and a full resynchronisation will occur. The default threshold is 2,205 frames, i.e. 50 milliseconds. Specify \fB0\f1 to disable resynchronisation. @@ -320,9 +368,9 @@ Print debug information. Repeat up to three times to get more detail. \fB-w | --wait-cmd\f1 Wait for commands specified using \fB-B\f1 or \fB-E\f1 to complete before continuing execution. .SH AUDIO BACKEND OPTIONS -These options are passed to the chosen audio backend. (At present, the only backend implemented is for ALSA.) The audio backend options are preceded by a \fB--\f1 symbol to introduce them and to separate them from any program options. In this way, option letters can be used as program options and also as audio backend options without ambiguity. +These options are passed to the chosen audio backend. The audio backend options are preceded by a \fB--\f1 symbol to introduce them and to separate them from any program options. In this way, option letters can be used as program options and also as audio backend options without ambiguity. -In the ALSA backend, audio is sent to an output device which you can specify using the \fB-d\f1 option. The output level (the "volume") is controlled using a level control associated with a mixer. By default, the mixer is implemented in shairport-sync itself, i.e. the type of the mixer is "software". To use a level control on a mixer on the sound card, you must (a) specify that the mixer's type is "hardware" with the \fB-t\f1 option; (b) you must specify where the mixer is to be found using the \fB-m\f1 option and finally (c) you must specify the name of the level control you are using with the \fB-c\f1 option. +In the ALSA backend, audio is sent to an output device which you can specify using the \fB-d\f1 option. The output level (the "volume") is controlled using a level control associated with a mixer. By default, the mixer is implemented in shairport-sync itself in software. To use a hardware level control on a mixer on the sound card, specify the name of the mixer control with the \fB-c\f1 option. If the mixer is not associated with the output device, then you need to specify where the mixer is to be found with the \fB-m\f1 option. .TP \fB-c \f1\fIcontrolname\f1 Use the level control called \fIcontrolname\f1 on the hardware mixer for controlling volume. This is needed if the mixer type is specified, using the \fB-t\f1 option, to be \fBhardware\f1. There is no default. @@ -336,7 +384,7 @@ Use the specified hardware \fImixer\f1 for volume control. Use this to specify w \fB-t \f1\fIdevicetype\f1 This option is deprecated and is ignored. For your information, its functionality has been automatically incorporated in the -c option -- if you specify a mixer name with the -c option, it is assumed that the mixer is implemented in hardware. .SH EXAMPLES -Here is a slightly contrived but typical example: +Here is a slightly contrived example: shairport-sync \fB-d\f1 \fB-a "Joe's Stereo"\f1 \fB-S soxr\f1 \fB--\f1 \fB-d hw:1,0\f1 \fB-m hw:1\f1 \fB-c PCM\f1 diff --git a/man/shairport-sync.7.xml b/man/shairport-sync.7.xml index 3738eb9a..0ba76f56 100644 --- a/man/shairport-sync.7.xml +++ b/man/shairport-sync.7.xml @@ -3,8 +3,8 @@