Merge branch 'development'
Updates from the development branch.
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
# Adjusting Synchronisation on Shairport Sync ("SPS")
|
||||
|
||||
Sometimes, a timing difference can be heard, where the audio coming from the SPS-powered device is slightly ahead or slightly behind another device playing in synchrony. This can sometimes be heard as an irritating "echo".
|
||||
|
||||
This is usually due to audio amplifier delays:
|
||||
|
||||
* If your audio output device (including the amplifier in a TV) includes any digital processing component, it probably delays audio while amplifying it.
|
||||
|
||||
* If your output device is a HDMI-connected device such as a TV or an AV Receiver (AVR), it will almost certainly delay audio by anything up to several hundred milliseconds.
|
||||
|
||||
In these circumstances, if the output from the SPS device is amplified by a conventional analog-only HiFi amplifier – which has almost no delay – it will be early by comparison with audio coming from the other device.
|
||||
|
||||
Conversely, if the output from the SPS device is passed through an AVR, then it could be late by comparison with audio amplified by a conventional audio amplifier.
|
||||
|
||||
The fix for this is to get Shairport Sync to compensate for delays by providing audio to the output device _slightly late_ or _slightly early_, so that when audio emerges from the amplifier, it is in exact synchrony with audio from the other devices.
|
||||
|
||||
The setting to look for is in the `general` section of the Shairport Sync configuration file and is called `audio_backend_latency_offset_in_seconds`. By default it is `0.0` seconds.
|
||||
|
||||
For example, to delay the output from the SPS device by 100 milliseconds (0.1 seconds), set the `audio_backend_latency_offset_in_seconds` to `0.1`, so that audio is provided to your output device 100 milliseconds later than nominal synchronisation time.
|
||||
|
||||
Similarly, to get the output from the SPS device 50 milliseconds (0.05 seconds) early, set the `audio_backend_latency_offset_in_seconds` to `-0.05`, so that audio is provided to your output device 50 milliseconds earlier than nominal synchronisation time.
|
||||
|
||||
Latency adjustments should be small, not more than about ± 250 milliseconds.
|
||||
|
||||
Remember to uncomment the line by removing the initial `//` and then restart Shairport Sync (or reboot the device) for the changed setting to take effect.
|
||||
@@ -1,6 +1,7 @@
|
||||
# Advanced Topics
|
||||
Here you will find links to some advanced features and things you can do with Shairport Sync.
|
||||
* [Finish Setting Up](InitialConfiguration.md).
|
||||
* [Adjusting Sync](AdjustingSync.md) – advance or delay the timing of the output from Shairport Sync to compensate for amplifier delays.
|
||||
* [Get The Best](GetTheBest.md) from your system.
|
||||
* [Metadata](Metadata.md).
|
||||
* [Events](Events.md).
|
||||
|
||||
@@ -37,7 +37,7 @@ Okay, now let's get the tools and libraries for building and installing Shairpor
|
||||
```
|
||||
# apt update
|
||||
# apt upgrade # this is optional but recommended
|
||||
# apt install --no-install-recommends build-essential git xmltoman autoconf automake libtool \
|
||||
# apt install --no-install-recommends build-essential git autoconf automake libtool \
|
||||
libpopt-dev libconfig-dev libasound2-dev avahi-daemon libavahi-client-dev libssl-dev libsoxr-dev \
|
||||
libplist-dev libsodium-dev libavutil-dev libavcodec-dev libavformat-dev uuid-dev libgcrypt-dev xxd
|
||||
```
|
||||
@@ -45,7 +45,7 @@ If you are building classic Shairport Sync, the list of packages is shorter:
|
||||
```
|
||||
# apt update
|
||||
# apt upgrade # this is optional but recommended
|
||||
# apt-get install --no-install-recommends build-essential git xmltoman autoconf automake libtool \
|
||||
# apt-get install --no-install-recommends build-essential git autoconf automake libtool \
|
||||
libpopt-dev libconfig-dev libasound2-dev avahi-daemon libavahi-client-dev libssl-dev libsoxr-dev
|
||||
```
|
||||
### Fedora
|
||||
@@ -53,7 +53,7 @@ For AirPlay 2 operation, _before you install the libraries_, please ensure the y
|
||||
```
|
||||
# yum update
|
||||
# yum install make automake gcc gcc-c++ \
|
||||
git xmltoman autoconf automake avahi-devel libconfig-devel openssl-devel popt-devel soxr-devel \
|
||||
git autoconf automake avahi-devel libconfig-devel openssl-devel popt-devel soxr-devel \
|
||||
ffmpeg ffmpeg-devel libplist-devel libsodium-devel libgcrypt-dev libuuid-devel vim-common \
|
||||
alsa-lib-devel
|
||||
```
|
||||
@@ -61,7 +61,7 @@ If you are building classic Shairport Sync, the list of packages is shorter:
|
||||
```
|
||||
# yum update
|
||||
# yum install make automake gcc gcc-c++ \
|
||||
git xmltoman autoconf automake avahi-devel libconfig-devel openssl-devel popt-devel soxr-devel \
|
||||
git autoconf automake avahi-devel libconfig-devel openssl-devel popt-devel soxr-devel \
|
||||
alsa-lib-devel
|
||||
```
|
||||
### Arch Linux
|
||||
@@ -193,4 +193,4 @@ With AirPlay 2, you can follow the steps in [ADDINGTOHOME.md](ADDINGTOHOME.md) t
|
||||
### Wait, there's more...
|
||||
Instead of using default values for everything, you can use the configuration file to get finer control over the setup, particularly the output device and mixer control -- see [Finish Setting Up](ADVANCED%20TOPICS/InitialConfiguration.md).
|
||||
|
||||
Please take a look at [Advanced Topics](ADVANCED%20TOPICS/README.md) for some ideas about what else you can do to enhance the operation of Shairport Sync.
|
||||
Please take a look at [Advanced Topics](ADVANCED%20TOPICS/README.md) for some ideas about what else you can do to enhance the operation of Shairport Sync. For example, you can adjust synchronisation to compensate for delays in your system.
|
||||
|
||||
+1
-1
@@ -240,7 +240,7 @@ From this point on, if you reboot the machine, it will connect to the network it
|
||||
|
||||
4. Reboot and do Normal Updating
|
||||
|
||||
You can perform updates in the normal way -- see [UPDATING](https://github.com/mikebrady/shairport-sync/blob/master/UPDATING.md). When you are finished, you need to undo the temporary changes you made to the setup, as follows:
|
||||
You can perform updates in the normal way. When you are finished, you need to undo the temporary changes you made to the setup, as follows:
|
||||
|
||||
5. If you had temporarily re-enabled services that are normally disabled, then it's time to disable them again:
|
||||
`# systemctl disable dhcpcd.service`
|
||||
|
||||
+7
-6
@@ -1,6 +1,7 @@
|
||||
SUBDIRS = man
|
||||
ARFLAGS = cr
|
||||
|
||||
man_MANS = $(top_srcdir)/man/shairport-sync.7
|
||||
|
||||
lib_pair_ap_a_CFLAGS = -Wall -g -DCONFIG_GCRYPT -pthread
|
||||
lib_tinyhttp_a_CFLAGS = -pthread
|
||||
lib_dbus_interface_a_CFLAGS = -pthread
|
||||
@@ -31,20 +32,20 @@ if BUILD_FOR_OPENBSD
|
||||
AM_CXXFLAGS = -I/usr/local/include -Wno-multichar -Wall -Wextra -Wno-clobbered -Wno-psabi -pthread -DSYSCONFDIR=\"$(sysconfdir)\"
|
||||
AM_CFLAGS = -Wno-multichar -Wall -Wextra -pthread -DSYSCONFDIR=\"$(sysconfdir)\"
|
||||
else
|
||||
AM_CXXFLAGS = -fno-common -Wno-multichar -Wall -Wextra -Wno-clobbered -Wno-psabi -pthread -DSYSCONFDIR=\"$(sysconfdir)\"
|
||||
AM_CFLAGS = -fno-common -Wno-multichar -Wall -Wextra -Wno-clobbered -Wno-psabi -pthread -DSYSCONFDIR=\"$(sysconfdir)\"
|
||||
AM_CXXFLAGS = -I$(srcdir) -fno-common -Wno-multichar -Wall -Wextra -Wno-clobbered -Wno-psabi -pthread -DSYSCONFDIR=\"$(sysconfdir)\"
|
||||
AM_CFLAGS = -I$(srcdir) -fno-common -Wno-multichar -Wall -Wextra -Wno-clobbered -Wno-psabi -pthread -DSYSCONFDIR=\"$(sysconfdir)\"
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# include information generated by 'git describe --dirty' if requested
|
||||
# include information generated by 'git describe --tags --dirty' if requested
|
||||
if USE_GIT_VERSION
|
||||
common.c: gitversion.h
|
||||
gitversion.h: .git/index
|
||||
printf "// Do not edit!\n" > gitversion.h
|
||||
printf "// This file is automatically generated by 'git describe --dirty', if available.\n" >> gitversion.h
|
||||
printf "// This file is automatically generated by 'git describe --tags --dirty', if available.\n" >> gitversion.h
|
||||
printf " char git_version_string[] = \"" >> gitversion.h
|
||||
git describe --dirty | tr -d '[[:space:]]' >> gitversion.h
|
||||
git describe --tags --dirty | tr -d '[[:space:]]' >> gitversion.h
|
||||
printf "\";\n" >> gitversion.h
|
||||
CLEANFILES += gitversion.h
|
||||
endif
|
||||
|
||||
@@ -557,9 +557,6 @@ To retain the present behaviour of Shairport Sync, *you must add an extra parame
|
||||
|
||||
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**
|
||||
@@ -616,7 +613,6 @@ Version 2.8.4.1 – Development Version
|
||||
|
||||
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.
|
||||
|
||||
|
||||
+2
-8
@@ -15,14 +15,8 @@ If you are using the default ALSA backend, don't forget to check two simple thin
|
||||
|
||||
You can use `alsamixer` for both of theses checks. A muted output has the letter(s) `M` as its value. Select it and type `M` again to unmute.
|
||||
|
||||
### Audio is Delayed!
|
||||
If the audio from your Shairport Sync device is delayed slightly by comparison with audio from other devices, it may be that the output device being fed by Shairport Sync is introducing a delay while it processes the audio. If your output device include any digital processing component, it probably delays the audio while it processing occurs.
|
||||
|
||||
For instance, if your output device is a HDMI-connected device such as a TV or an AV Receiver, it will almost certainly delay audio by anything up to several hundred milliseconds.
|
||||
|
||||
The fix for this is to ask Shairport Sync to provide the audio to the output device _slightly ahead of time_, so that by the time the output device has processed it, the audio emerges at exactly the right time. The setting to look for is in the `general` section of the Shairport Sync configuration file and is called `audio_backend_latency_offset_in_seconds`. By default it is `0.0` seconds.
|
||||
|
||||
For example, if your output device is delaying audio by 100 milliseconds (0.1 seconds), set the `audio_backend_latency_offset_in_seconds` to `-0.1`, so that audio is provided to your output device 0.1 seconds early. Remember to uncomment the line by removing the initial `//` and then restart Shairport Sync (or reboot the device) for the changed setting to take effect.
|
||||
### Sync is slightly off!
|
||||
Please see [Adjusting Sync](./ADVANCED%20TOPICS/AdjustingSync.md).
|
||||
|
||||
### WiFi adapter running in power-saving / low-power mode
|
||||
|
||||
|
||||
+1
-1
@@ -141,7 +141,7 @@ static void deinit(void) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void help(void) { printf(" specify the pathname of the pipe to write to.\n"); }
|
||||
static void help(void) { printf(" Provide the pipe's pathname. The default is \"%s\".\n", default_pipe_name); }
|
||||
|
||||
audio_output audio_pipe = {.name = "pipe",
|
||||
.help = &help,
|
||||
|
||||
+1
-3
@@ -208,10 +208,8 @@ static void flush(void) {
|
||||
debug(1, "libsoundio output flushed\n");
|
||||
}
|
||||
|
||||
static void help(void) { printf(" There are no options for libsoundio.\n"); }
|
||||
|
||||
audio_output audio_soundio = {.name = "soundio",
|
||||
.help = &help,
|
||||
.help = NULL,
|
||||
.init = &init,
|
||||
.deinit = &deinit,
|
||||
.prepare = NULL,
|
||||
|
||||
@@ -112,7 +112,6 @@ void set_alsa_out_dev(char *);
|
||||
|
||||
config_t config_file_stuff;
|
||||
int type_of_exit_cleanup;
|
||||
pthread_t main_thread_id;
|
||||
uint64_t ns_time_at_startup, ns_time_at_last_debug_message;
|
||||
|
||||
// always lock use this when accessing the ns_time_at_last_debug_message
|
||||
|
||||
@@ -37,7 +37,7 @@ typedef enum {
|
||||
typedef enum {
|
||||
TOE_normal,
|
||||
TOE_emergency,
|
||||
TOE_dbus // a dbus request was made -- don't wait for the dbus thread to exit
|
||||
TOE_dbus // a request was made on a D-Bus interface (the native D-Bus or MPRIS interfaces)-- don't wait for the dbus thread to exit
|
||||
} type_of_exit_type;
|
||||
|
||||
#define sps_extra_code_output_stalled 32768
|
||||
@@ -401,9 +401,6 @@ extern uint64_t ns_time_at_startup, ns_time_at_last_debug_message;
|
||||
|
||||
uint32_t uatoi(const char *nptr);
|
||||
|
||||
// this is for allowing us to cancel the whole program
|
||||
extern pthread_t main_thread_id;
|
||||
|
||||
extern shairport_cfg config;
|
||||
extern config_t config_file_stuff;
|
||||
extern int type_of_exit_cleanup; // normal, emergency, dbus requested...
|
||||
|
||||
+1
-8
@@ -444,13 +444,6 @@ if test "x${with_systemd}" = xyes ; then
|
||||
[AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])])
|
||||
fi
|
||||
|
||||
# Look for xmltoman
|
||||
AC_CHECK_PROGS([XMLTOMAN], [xmltoman])
|
||||
if test -z "$XMLTOMAN"; then
|
||||
AC_MSG_WARN([xmltoman not found - not rebuilding man pages])
|
||||
fi
|
||||
AM_CONDITIONAL([HAVE_XMLTOMAN], [test -n "$XMLTOMAN"])
|
||||
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([getopt_long.h])
|
||||
AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h mach/mach.h memory.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h syslog.h unistd.h])
|
||||
@@ -475,6 +468,6 @@ AC_FUNC_FORK
|
||||
AC_CHECK_FUNCS([atexit clock_gettime gethostname inet_ntoa memchr memmove memset mkfifo pow select socket stpcpy strcasecmp strchr strdup strerror strstr strtol strtoul])
|
||||
|
||||
# Note -- there are AC_CONFIG_FILES directives further back, conditional on Avahi
|
||||
AC_CONFIG_FILES([Makefile man/Makefile])
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_CONFIG_FILES([scripts/shairport-sync],[chmod +x scripts/shairport-sync])
|
||||
AC_OUTPUT
|
||||
|
||||
+4
-3
@@ -1129,10 +1129,11 @@ int start_dbus_service() {
|
||||
|
||||
void stop_dbus_service() {
|
||||
debug(2, "stopping dbus service");
|
||||
if (ownerID)
|
||||
if (ownerID) {
|
||||
g_bus_unown_name(ownerID);
|
||||
else
|
||||
debug(1, "Zero OwnerID for \"org.gnome.ShairportSync\".");
|
||||
} else if (service_is_running != 0) {
|
||||
debug(1, "Zero OwnerID for running \"org.gnome.ShairportSync\" dbus service.");
|
||||
}
|
||||
service_is_running = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
shairport-sync.7: shairport-sync.7.xml
|
||||
xmltoman shairport-sync.7.xml > shairport-sync.7
|
||||
|
||||
shairport-sync.html: shairport-sync.7.xml
|
||||
xsltproc xmltoman.xsl shairport-sync.7.xml > shairport-sync.html
|
||||
|
||||
all: shairport-sync.7 shairport-sync.html
|
||||
|
||||
clean:
|
||||
rm shairport-sync.7
|
||||
rm shairport-sync.html
|
||||
@@ -1,11 +0,0 @@
|
||||
man_MANS = shairport-sync.7
|
||||
|
||||
if HAVE_XMLTOMAN
|
||||
all-local: shairport-sync.html
|
||||
|
||||
shairport-sync.7: shairport-sync.7.xml
|
||||
xmltoman $< > $@
|
||||
|
||||
shairport-sync.html: shairport-sync.7.xml
|
||||
xmlmantohtml $< > $@
|
||||
endif
|
||||
+54
-346
@@ -1,44 +1,36 @@
|
||||
.TH shairport-sync 7 User Manuals
|
||||
.SH NAME
|
||||
shairport-sync \- Synchronised Audio Player for iTunes / AirPlay
|
||||
shairport-sync \- AirPlay and AirPlay 2 Audio Player
|
||||
.SH SYNOPSIS
|
||||
\fBshairport-sync [-djvuw]\fB [-a \fB\fIname\fB]\fB [-A \fB\fIlatency\fB]\fB [-B \fB\fIcommand\fB]\fB [-c \fB\fIconfigurationfile\fB]\fB [-E \fB\fIcommand\fB]\fB [--get-cover-art]\fB [--logOutputLevel]\fB [-L \fB\fIlatency\fB]\fB [-m \fB\fIbackend\fB]\fB [--meta-dir=\fB\fIdirectory\fB]\fB [-o \fB\fIbackend\fB]\fB [--password=\fB\fIsecret\fB]\fB [-r \fB\fIthreshold\fB]\fB [--statistics]\fB [-S \fB\fImode\fB]\fB [-t \fB\fItimeout\fB]\fB [--tolerance=\fB\fIframes\fB]\fB [-- \fB\fIaudio_backend_options\fB]\fB
|
||||
\fBshairport-sync [-djvw]\fB [-a \fB\fIservice-name\fB | --name=\fB\fIservice-name\fB]\fB [-B \fB\fIcommand\fB | --onstart=\fB\fIcommand\fB]\fB [-c \fB\fIconfigurationfile\fB | --configfile=\fB\fIconfigurationfile\fB]\fB [-d | --daemon]\fB [-E \fB\fIcommand\fB | --onstop=\fB\fIcommand\fB]\fB [-g | --get-cover-art]\fB [-j | --justDaemoniseNoPIDFile]\fB [--logOutputLevel]\fB [--log-to-syslog]\fB [-L \fB\fIlatency\fB | --latency=\fB\fIlatency\fB]\fB [-m \fB\fIbackend\fB | --mdns=\fB\fIbackend\fB]\fB [-M | --metadata-enable]\fB [-o \fB\fIbackend\fB | --output=\fB\fIbackend\fB]\fB [-p \fB\fIport\fB | --port=\fB\fIport\fB]\fB [--password=\fB\fIsecret\fB]\fB [-r \fB\fIthreshold\fB | --resync=\fB\fIthreshold\fB]\fB [--statistics]\fB [-S \fB\fImode\fB | --stuffing=\fB\fImode\fB]\fB [-t \fB\fItimeout\fB | --timeout=\fB\fItimeout\fB]\fB [--tolerance=\fB\fIframes\fB]\fB [-v | --verbose]\fB [-w | --wait-cmd]\fB [-- \fB\fIaudio_backend_options\fB]\fB
|
||||
|
||||
shairport-sync -k\fB
|
||||
shairport-sync -X | --displayConfig\fB
|
||||
|
||||
shairport-sync -h\fB
|
||||
|
||||
shairport-sync -k\fB
|
||||
|
||||
shairport-sync -V\fB
|
||||
\f1
|
||||
.SH DESCRIPTION
|
||||
Shairport Sync plays audio streamed from iTunes or from an AirPlay device to an ALSA-compatible audio output device (available on Linux and FreeBSD), to a "sndio" output device (available on OpenBSD, FreeBSD and Linux), to a PulseAudio output stream or to Jack Audio.
|
||||
Shairport Sync plays AirPlay audio. It can be built to stream either from "classic" AirPlay (aka "AirPlay 1") or from AirPlay 2 devices.
|
||||
|
||||
Shairport Sync offers full audio synchronisation. Full audio synchronisation means that audio is played on the output device at exactly the time specified by the audio source. This means that if many devices are playing the same stream at the same time, all the outputs will stay in synchrony with one another. This allows multiple devices to play the same source without getting out of step with one another, enabling, for example, simultaneous multi-room operation.
|
||||
AirPlay 2 support is limited, and AirPlay 2 from iTunes for Windows is not supported. For AirPlay 2 operation, a companion program called \fBnqptp\f1 must be installed.
|
||||
|
||||
Shairport Sync can stream synchronised audio 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.
|
||||
Please see \fBhttps://github.com/mikebrady/shairport-sync\f1 for details.
|
||||
|
||||
Shairport Sync can be compiled to stream metadata, including cover art, to a pipe or socket.
|
||||
|
||||
Shairport Sync can be compiled to offer a standard MPRIS interface, a "native" D-Bus interface and an MQTT client interface. Through these interfaces, it can provide metadata, including cover art, and can offer remote control of the audio source.
|
||||
|
||||
Settings can be made using the configuration file (recommended for all new installations) or by using command-line options.
|
||||
|
||||
The name of the Shairport Sync executable is \fBshairport-sync\f1. Both names are used in these man pages.
|
||||
The name of the Shairport Sync executable is \fBshairport-sync\f1.
|
||||
.SH CONFIGURATION FILE SETTINGS
|
||||
You should use the configuration file for setting up Shairport Sync. This file is usually \fIshairport-sync.conf\f1 and is generally located in the System Configuration Directory, which is normally the \fI/etc\f1 directory in Linux or the \fI/usr/local/etc\f1 directory in BSD unixes. You may need to have root privileges to modify it.
|
||||
You should use the configuration file for setting up Shairport Sync because -- apart from a few special-purpose commands -- it has a much richer set of options than are available on the command line. This file is usually \fIshairport-sync.conf\f1 and is generally located in the System Configuration Directory, which is normally the \fI/etc\f1 directory in Linux or the \fI/usr/local/etc\f1 directory in BSD unixes. You may need to have root privileges to modify it.
|
||||
|
||||
(Note: Shairport Sync may have been compiled to use a different configuration directory. You can determine which by performing the command \fI$ shairport-sync -V\f1. One of the items in the output string is the value of the \fBsysconfdir\f1, i.e. the System Configuration Directory.)
|
||||
(Note: Shairport Sync may have been compiled to use a different configuration directory. You can determine which by performing the command \fI$ shairport-sync -V\f1. The last item in the output string is the value of the \fBsysconfdir\f1, i.e. the System Configuration Directory.)
|
||||
|
||||
Within the configuration file, settings are organised into groups, for example, there is a "general" group of standard settings, and there is an "alsa" group with settings that pertain to the ALSA back end. Here is an example of a typical configuration file:
|
||||
Within the configuration file, settings are organised into groups, for example, there is a \fBgeneral\f1 group of standard settings, and there is an \fBalsa\f1 group with settings that pertain to the \fBALSA\f1 back end. Here is an example of a typical configuration file:
|
||||
|
||||
\fBgeneral = {\f1
|
||||
|
||||
\fBname = "Mike's Boombox";\f1
|
||||
|
||||
\fBpassword = "secret";\f1
|
||||
|
||||
\fBoutput_backend = "alsa";\f1
|
||||
|
||||
\fB};\f1
|
||||
|
||||
\fB\f1
|
||||
@@ -51,293 +43,17 @@ Within the configuration file, settings are organised into groups, for example,
|
||||
|
||||
\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 mixer name should be specified. It is important to do this if the mixer exists. Otherwise, the maximum output from the output device will be whatever setting the mixer happens to have, which will be a matter of chance and which could be very low or even silent.
|
||||
Users generally only need to set (1) the service name and (2) the output device. If the \fBname\f1 setting is omitted, the service name is derived from the system's hostname. By default, the \fBALSA\f1 backend will be chosen if included in the build. If the (alsa) output device has a mixer that can be used for volume control, then (3) the mixer name should be specified. It is important to do this if the mixer exists. Otherwise, the maximum output from the output device will be whatever setting the mixer happens to have, which will be a matter of chance and which could be very low or even silent.
|
||||
|
||||
A sample configuration file with all possible settings, but with all of them commented out, is installed at \fIshairport-sync.conf.sample\f1, within the System Configuration Directory -- \fI/etc\f1 in Linux, \fI/usr/local/etc\f1 in BSD unixes.
|
||||
|
||||
To retain backwards compatibility with previous versions of shairport-sync you can use still use command line options, but any new features, etc. will be available only via configuration file settings.
|
||||
|
||||
The configuration file is processed using the \fIlibconfig\f1 library -- see \fBhttp://www.hyperrealm.com/libconfig/libconfig_manual.html\f1.
|
||||
.TP
|
||||
\fB"GENERAL" SETTINGS\f1
|
||||
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 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. "3.3.6" and \fB%V\f1 for the shairport-sync version string, e.g. "3.3.6-OpenSSL-Avahi-ALSA-soxr-metadata-sysconfdir:/etc".
|
||||
|
||||
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.
|
||||
.TP
|
||||
\fBinterpolation=\f1\fI"mode"\f1\fB;\f1
|
||||
Interpolate, or "stuff", the audio stream using the \fImode\f1. Interpolation here refers to the process of adding or removing frames of audio to or from the stream sent to the output device to keep it exactly synchronised with the player. The "basic" mode is normally almost completely inaudible. The alternative mode, "soxr", is even less obtrusive but requires much more processing power. For this mode, support for libsoxr, the SoX Resampler Library, must be selected when shairport-sync is compiled. The default setting is "auto", which will choose "soxr" if support for it has been compiled into the build of Shairport Synce and if the CPU is fast enough. Otherwise, "basic" stuffing will be chosen.
|
||||
.TP
|
||||
\fBoutput_backend=\f1\fI"backend"\f1\fB;\f1
|
||||
shairport-sync has a number of modules of code ("backends") through which audio is output. Normally, the first audio backend that works is selected. This setting forces the selection of the specific audio \fIbackend\f1. Perform the command \fBshairport-sync -h\f1 to get a list of available audio backends -- the default is the first on this list. Only the "alsa", "sndio" and "pa" backends support synchronisation.
|
||||
.TP
|
||||
\fBmdns_backend=\f1\fI"backend"\f1\fB;\f1
|
||||
shairport-sync has a number of modules of code ("backends") for interacting with the mDNS service to be used to advertise itself. Normally, the first mDNS backend that works is selected. This setting forces the selection of the specific mDNS \fIbackend\f1. The default is "avahi". Perform the command \fBshairport-sync -h\f1 to get a list of available mDNS modules.
|
||||
.TP
|
||||
\fBport=\f1\fIportnumber\f1\fB;\f1
|
||||
Use this to specify the \fIportnumber\f1 shairport-sync uses to listen for service requests from iTunes, etc. The default is port 5000.
|
||||
.TP
|
||||
\fBudp_port_base=\f1\fIportnumber\f1\fB;\f1
|
||||
When shairport-sync starts to play audio, it establises three UDP connections to the audio source. Use this setting to specify the starting \fIportnumber\f1 for these three ports. It will pick the first three unused ports starting from \fIportnumber\f1. The default is port 6001.
|
||||
.TP
|
||||
\fBudp_port_range=\f1\fIrange\f1\fB;\f1
|
||||
Use this in conjunction with the previous setting to specify the \fIrange\f1 of ports that can be checked for availability. Only three ports are needed. The default is 100, thus 100 ports will be checked from port 6001 upwards until three are found.
|
||||
.TP
|
||||
\fBdrift_tolerance_in_seconds=\f1\fIseconds\f1\fB;\f1
|
||||
Allow playback to drift up to \fIseconds\f1 out of exact synchronization before attempting to correct it. The default is 0.002 seconds, i.e. 2 milliseconds. 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 \fBstatistics\f1 setting to monitor correction levels. Corrections should not greatly exceed net corrections. This setting replaces the deprecated \fBdrift\f1 setting.
|
||||
.TP
|
||||
\fBresync_threshold_in_seconds=\f1\fIthreshold\f1\fB;\f1
|
||||
Resynchronise if timings differ by more than \fIthreshold\f1 seconds. 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 0.050 seconds, i.e. 50 milliseconds. Specify 0.0 to disable resynchronisation. This setting replaces the deprecated \fBresync_threshold\f1 setting.
|
||||
.TP
|
||||
\fBignore_volume_control=\f1\fI"choice"\f1\fB;\f1
|
||||
Set this \fIchoice\f1 to \fI"yes"\f1 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 \fI"no"\f1.
|
||||
.TP
|
||||
\fBvolume_range_db=\f1\fIdBvalue\f1\fB;\f1
|
||||
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 30 dB. 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 30. 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 native range of the mixer is used.
|
||||
.TP
|
||||
\fBvolume_max_db=\f1\fIdBvalue\f1\fB;\f1
|
||||
Specify the maximum output level to be used with the hardware mixer, if used. If no hardware mixed is used, this setting specifies the maximum setting permissible in the software mixer, which has an attenuation range from 0.0 dB down to -96.3 dB.
|
||||
.TP
|
||||
\fBvolume_control_profile=\f1\fI"choice"\f1\fB;\f1
|
||||
Use this advanced setting to specify how the airplay volume is transferred to the mixer volume. The \fI"standard"\f1 profile, which is the default, makes the volume change more quickly at lower volumes and slower at higher volumes. Choose the \fI"flat"\f1 profile to makes the volume change at the same rate at all volume levels.
|
||||
.TP
|
||||
\fBvolume_range_combined_hardware_priority=\f1 \fI"choice"\f1\fB;\f1
|
||||
Use this advanced setting to specify how to combine the hardware attenuator with software attenuation to provide a greater attenuation range than the hardware attenuator alone can provide. Choosing \fI"yes"\f1 means that when attenuation is required, the hardware attenuator will be used in preference. If more attenuation than it can provide is needed, the hardware attenuator is set to its greatest attenuation and software attenuation is added.
|
||||
|
||||
For example, if 40 dB of attenuation is required and the hardware attenuator offers a maximum of 30 dB, then the hardware attenuator will be set to give 30 dB attenuation and 10 dB of software attenuation will be added.
|
||||
|
||||
Unfortunately, certain hardware attenuators will mute at their greatest attenuation, so can't be combined with software attenuation in this way. Choosing \fI"no"\f1 means that software attenuation is used to bring the remaining attenuation required into the range offered by the hardware attenuator. This is the default.
|
||||
.TP
|
||||
\fBrun_this_when_volume_is_set=\f1 \fI"/full/path/to/application/and/args"\f1\fB;\f1
|
||||
Here you can specify a program and its arguments that will be run when the volume is set or changed. 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 shebang \fI#!/bin/...\f1 as appropriate.
|
||||
|
||||
The desired AirPlay volume is appended to the end of the command line -- leave a space at the end of the command line you specify here if you want it treated as an extra argument. AirPlay volume goes from 0.0 to -30.0 and -144.0 means "mute".
|
||||
.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 \fI"_raop._tcp"\f1.
|
||||
.TP
|
||||
\fBplayback_mode=\f1\fI"mode"\f1\fB;\f1
|
||||
The \fImode\f1 can be "stereo", "mono", "reverse stereo", "both left" or "both right". Default is "stereo". Note that dither will be added to the signal in the mono mode.
|
||||
.TP
|
||||
\fBalac_decoder=\f1\fI"decodername"\f1\fB;\f1
|
||||
This can be "hammerton" or "apple". This advanced setting allows you to choose the original Shairport decoder by David Hammerton or the Apple Lossless Audio Codec (ALAC) decoder written by Apple. Shairport Sync must have been compiled with the configuration setting "--with-apple-alac" and the Apple ALAC decoder library must be present for this to work.
|
||||
.TP
|
||||
\fBinterface=\f1\fI"name"\f1\fB;\f1
|
||||
Use this advanced setting if you want to confine Shairport Sync to the named interface. Leave it commented out to get the default behaviour.
|
||||
.TP
|
||||
\fBaudio_backend_latency_offset_in_seconds=\f1 \fIoffset_in_seconds\f1\fB;\f1
|
||||
Set this \fIoffset_in_seconds\f1 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.
|
||||
.TP
|
||||
\fBaudio_backend_buffer_desired_length_in_seconds=\f1 \fIlength_in_seconds\f1\fB;\f1
|
||||
Use this \fIlength_in_seconds\f1 to set the desired length of the queue of audio frames in the backend's output buffer.
|
||||
|
||||
The default is 0.15 seconds for the ALSA backend, 0.35 seconds for the PA backend and one second for all other backends.
|
||||
|
||||
If this value is set too small, underflow may occur on low-powered machines. If set too large, the response times to the volume control may become excessive, or it may exceed the backend's buffer size. It may need to be larger on low-powered machines that are also performing other tasks, such as processing metadata.
|
||||
.TP
|
||||
\fBaudio_backend_buffer_interpolation_threshold_in_seconds=\f1 \fItime_in_seconds\f1\fB;\f1
|
||||
This is an advanced feature. If the length of the audio backend buffer size drops below this, it's a sign that shairport sync can not process frames of audio quickly enough. It this threshold is reached, shairport sync will stop using time-consuming interpolation like soxr to avoid underruns.
|
||||
.TP
|
||||
\fBaudio_backend_silent_lead_in_time=\f1 \fIlead_in_time_in_seconds\f1\fB;\f1
|
||||
This is an advanced setting. Use the \fIlead_in_time_in_seconds\f1 to set the desired length of the period of silence (a "silent lead-in") played before a play session begins.
|
||||
|
||||
The purpose of this silent lead-in is to give the backend sufficient time to prepare for operation and to make an estimate (and, importantly, to correct the estimate) of the exact time at which to begin playing audio to achieve initial synchronisation. The value can be from 0.0 up to a maximum of either 4.0 seconds. The actual duration will be close to the setting but can not exceed the latency set by the client, usually 2 seconds or a little more.
|
||||
|
||||
If the value chosen is too short for synchronised backends such as the ALSA, sndio or PA backends, then audio will not be synchronised correctly at the start of play. The default is to have a silent lead-in of approximately the same time as the latency set by the client.
|
||||
.TP
|
||||
\fBdbus_service_bus=\f1 \fI"bus_name"\f1\fB;\f1
|
||||
If shairport sync is compiled with the D-Bus interface, it can offer it on the \fI"system"\f1 or the \fI"session"\f1 D-Bus "bus". Use this to specify which. The default is to use the "system" bus.
|
||||
.TP
|
||||
\fBmpris_service_bus=\f1 \fI"bus_name"\f1\fB;\f1
|
||||
If shairport sync is compiled with the MPRIS interface, it can offer the service on the \fI"system"\f1 or the \fI"session"\f1 D-Bus "bus". Use this to specify which. The default is to use the "system" bus.
|
||||
.TP
|
||||
\fB"SESSIONCONTROL" SETTINGS\f1
|
||||
.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 shebang \fI#!/bin/...\f1 as appropriate.
|
||||
.TP
|
||||
\fBrun_this_after_play_ends=\f1\fI"/path/to/application and args"\f1\fB;\f1
|
||||
Here you can specify a program and its arguments that will be run just after a play session ends. 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 shebang \fI#!/bin/...\f1 as appropriate.
|
||||
.TP
|
||||
\fBrun_this_before_entering_active_state=\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 shairport-sync goes active.
|
||||
|
||||
Shairport Sync goes "active" when a play session starts. When the play session ends, the system will stay active until the time specified in the \fBactive_state_timeout\f1 setting elapses. If a new play session starts before that, the system will remain active. Otherwise, the system will go inactive.
|
||||
|
||||
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 shebang \fI#!/bin/...\f1 as appropriate.
|
||||
.TP
|
||||
\fBrun_this_after_exiting_active_state=\f1\fI"/path/to/application and args"\f1\fB;\f1
|
||||
Here you can specify a program and its arguments that will be run just after shairport-sync goes inactive (see the previous entry for an explanation of the idea). 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 shebang \fI#!/bin/...\f1 as appropriate.
|
||||
.TP
|
||||
\fBactive_state_timeout=\f1\fIseconds\f1\fB;\f1
|
||||
After a play session has ended, the system will remain active for \fIseconds\f1 seconds. If a new play session starts before this time has elapsed, the system will remain active. However, if no new session starts in the interval, the system will go inactive at the end of it. The default is 10 seconds.
|
||||
.TP
|
||||
\fBrun_this_if_an_unfixable_error_is_detected=\f1\fI"/path/to/application and args"\f1\fB;\f1
|
||||
Here you can specify a program and its arguments that will be run if the system detects an unfixable error. At present, there are two types of unfixable errors. One is where a play session cannot be terminated. The second is if an output device has "stalled" -- that is, if an output device refuses to accept any more output frames.
|
||||
|
||||
Although the first problem could, in principle, be fixed by restarting Shairport Sync, it is usually caused by a malfunctioning output device. Typically, the most reliable way to recover from either of these errors is to reboot the entire machine.
|
||||
|
||||
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 shebang \fI#!/bin/...\f1 as appropriate.
|
||||
.TP
|
||||
\fBwait_for_completion=\f1\fI"choice"\f1\fB;\f1
|
||||
Set \fIchoice\f1 to "yes" to make shairport-sync wait until the programs specified in the \fBrun_this_...\f1 settings have completed execution before continuing. The default is "no".
|
||||
.TP
|
||||
\fBallow_session_interruption=\f1\fI"choice"\f1\fB;\f1
|
||||
If \fBchoice\f1 is set to "yes", then another source will be able to interrupt an existing play session and start a new one. When set to "no" (the default), other devices attempting to interrupt a session will fail, receiving a busy signal.
|
||||
.TP
|
||||
\fBsession_timeout=\f1\fIseconds\f1\fB;\f1
|
||||
If a play session has been established and the source disappears without warning (such as a device going out of range of a network) then wait for the number of seconds specified before ending the session. Once the session has terminated, other devices can use it. The default is 120 seconds.
|
||||
.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:
|
||||
.TP
|
||||
\fBoutput_device=\f1\fI"output_device"\f1\fB;\f1
|
||||
Use the output device called \fIoutput_device\f1. The default is the device called \fI"default"\f1.
|
||||
.TP
|
||||
\fBmixer_control_name=\f1\fI"name"\f1\fB;\f1
|
||||
Specify the \fIname\f1 of the mixer control to be used by shairport-sync to control the volume. The mixer control must be on the mixer device, which by default is the output device. If you do not specify a mixer control name, shairport-sync will adjust the volume in software.
|
||||
.TP
|
||||
\fBmixer_device=\f1\fI"mixer_device"\f1\fB;\f1
|
||||
By default, the mixer is assumed to be output_device. Use this setting to specify a device other than the output device.
|
||||
.TP
|
||||
\fBoutput_rate=\f1\fIframe rate\f1\fB;\f1
|
||||
Use this setting to specify the frame rate to output to the ALSA device. Allowable values are "auto" (default), 44100, 88200, 176400 and 352800. The device must have the capability to accept the rate you specify. There is no particular reason to use anything other than 44100 if it is available, and if "auto" is selected, the lowest of these rates available, starting at 44100, will be selected.
|
||||
.TP
|
||||
\fBoutput_format=\f1\fI"format"\f1\fB;\f1
|
||||
Use this setting to specify the format that should be used to send data to the ALSA device. Allowable values are "auto" (default), "U8", "S8", "S16", "S24", "S24_3LE", "S24_3BE" or "S32". The device must have the capability to accept the format you specify.
|
||||
|
||||
"S" means signed; "U" means unsigned; BE means big-endian and LE means little-endian. Except where stated (using *LE or *BE), endianness matches that of the processor. The default is "S16".
|
||||
|
||||
If you are using a hardware mixer, S16 is fine, as audio will pass through Shairport Sync unmodified except for interpolation, but any of the higher-resolution formats are okay too. If you are using the software mixer, use 32- or 24-bit, if your device is capable of it, in order to get the lowest possible levels of dither. The "auto" setting will cause Shairport Sync to choose the highest resolution available.
|
||||
.TP
|
||||
\fBdisable_synchronization=\f1\fI"no"\f1\fB;\f1
|
||||
This is an advanced setting and is for debugging only. Set to \fI"yes"\f1 to disable synchronization. Default is \fI"no"\f1. If you use it to disable synchronisation, then sooner 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
|
||||
\fBuse_mmap_if_available=\f1\fI"yes"\f1\fB;\f1
|
||||
Use this optional advanced setting to control whether MMAP-based output is used to communicate with the DAC. Default is \fI"yes"\f1.
|
||||
.TP
|
||||
\fBmute_using_playback_switch=\f1\fI"no"\f1\fB;\f1
|
||||
This is an advanced setting and the default is \fI"no"\f1. If it is set to \fI"yes"\f1, hardware mute will be used where it is available. Set it to \fI"no"\f1 to prevent the hardware mute being used.
|
||||
|
||||
If Shairport Sync is sharing the output device with other applications, it is best to leave this set to \fI"no"\f1 for compatibility with those applications.
|
||||
|
||||
Another motivation for this is to allow the ALSA function call "snd_mixer_selem_set_playback_switch_all" to be avoided. It is incorrectly implemented on certain soundcards, including the emulated card in VMWare Fusion 8.5.
|
||||
.TP
|
||||
\fBmaximum_stall_time=\f1\fIseconds\f1\fB;\f1
|
||||
If an output device fails to accept any audio frames for more than the time, in seconds, specified here (0.2 seconds by default), it is considered to have malfunctioned. It will result in the \fBrun_this_if_an_unfixable_error_is_detected\f1 program, if any, being called.
|
||||
|
||||
Implemented for the ALSA back end only.
|
||||
.TP
|
||||
\fBdisable_standby_mode=\f1\fI"never"\f1\fB;\f1
|
||||
Shairport Sync has a "Disable Standby" feature to eliminate certain faint-but-annoying audible pops and clicks. When activsted, it prevents an output device from entering standby mode and thus it minimises standby/busy transitions, which can sometimes be heard. Use this setting to control when the Disable Standby feature is active: "never" means it will never be activated, "always" means it will be active as soon as shairport-sync starts running, and "auto" means it will be active while shairport-sync is in the "active" state.
|
||||
|
||||
Shairport Sync goes "active" when a play session starts. When the play session ends, the system will stay active until the time specified in the active_state_timeout setting elapses. If a new play session starts before that, the system will remain active. Otherwise, the system will go inactive.
|
||||
.TP
|
||||
\fB"SNDIO" SETTINGS\f1
|
||||
These settings are for the SNDIO back end, used to communicate with audio output devices in the SNDIO system.
|
||||
.TP
|
||||
\fBdevice=\f1\fI"snd/0"\f1\fB;\f1
|
||||
Use this optional setting to specify the name of the output device, e.g. \fI"snd/0"\f1. The default is to use the SNDIO system's default.
|
||||
.TP
|
||||
\fBrate=\f1\fI44100\f1\fB;\f1
|
||||
Use this optional setting to specify the output rate in frames per second. Valid rates are 44100, 88200, 176400 or 352800. The output device must have the capability to accept data at the specified rate. The default is 44100.
|
||||
.TP
|
||||
\fBformat=\f1\fI"S16"\f1\fB;\f1
|
||||
Use this optional setting to specify the output format. Allowable values are "U8", "S8", "S16", "S24", "S24_3LE", "S24_3BE" or "S32". The device must have the capability to accept the format you specify.
|
||||
|
||||
"S" means signed; "U" means unsigned; BE means big-endian and LE means little-endian. Except where stated (using *LE or *BE), endianness matches that of the processor. The default is "S16".
|
||||
|
||||
Since the SNDIO backend does not use a hardware mixer for volume control, dither will be introduced into the output if it is less than full volume. Thus, (unless you are ignoring the volume control setting), consider using 32- or 24-bit output if your device is capable of it, to get the lowest possible levels of dither.
|
||||
|
||||
Please note that 32- or 24-bit has not been extensively tested on SNDIO.
|
||||
.TP
|
||||
\fBround=\f1\fIvalue\f1\fB;\f1
|
||||
Use this optional advanced setting to specify the period size of the SNDIO channel. If omitted, a SNDIO system default value will be used.
|
||||
.TP
|
||||
\fBbufsiz=\f1\fIvalue\f1\fB;\f1
|
||||
Use this optional advanced setting to specify the buffer size of the SNDIO channel. If omitted, a SNDIO system default value will be used.
|
||||
.TP
|
||||
\fB"PA" SETTINGS\f1
|
||||
These settings are for the new PulseAudio backend.
|
||||
.TP
|
||||
\fBapplication_name=\f1\fI"Shairport Sync"\f1\fB;\f1
|
||||
Use this to set the name to appear in the Sounds "Applications" tab when Shairport Sync is active. The default is the name "Shairport Sync".
|
||||
.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, interleaved stereo.
|
||||
.TP
|
||||
\fBname=\f1\fI"/path/to/pipe"\f1\fB;\f1
|
||||
Use this to specify the name and location of the pipe. The pipe will be created and opened when shairport-sync starts up and will be closed upon shutdown. Frames of audio will be sent to the pipe in packets of 352 frames and will be discarded if the pipe has not have a reader attached. The sender will wait for up to five seconds for a packet to be written before discarding it.
|
||||
.TP
|
||||
\fB"STDOUT" SETTINGS\f1
|
||||
There are no settings for the STDOUT backend.
|
||||
.TP
|
||||
\fB"AO" SETTINGS\f1
|
||||
There are no configuration file settings for the AO backend.
|
||||
.TP
|
||||
\fB"METADATA" SETTINGS\f1
|
||||
shairport-sync can process metadata provided by the source, such as Track Number, Album Name, cover art, etc. and can provide additional metadata such as volume level, pause/resume, etc. It sends the metadata to a pipe, by default \fI/tmp/shairport-sync-metadata\f1. To process metadata, shairport-sync must have been compiled with metadata support included. You can check that this is so by running the command \fB$ shairport-sync -V\f1; the identification string will contain the word \fBmetadata\f1.
|
||||
|
||||
Please note that different sources provide different levels of metadata. Some provide a lot; some provide almost none.
|
||||
|
||||
The \fBmetadata\f1 group of settings allow you to enable metadata handling and to control certain aspects of it:
|
||||
.TP
|
||||
\fBenabled=\f1\fI"choice"\f1\fB;\f1
|
||||
Set the \fIchoice\f1 to "yes" to enable shairport-sync to look for metadata from the audio source and to forward it, along with metadata generated by shairport-sync itself, to the metadata pipe. The default is "no".
|
||||
.TP
|
||||
\fBinclude_cover_art=\f1\fI"choice"\f1\fB;\f1
|
||||
Set the \fIchoice\f1 to "yes" to enable shairport-sync to look for cover art from the audio source and to include it in the feed to the metadata pipe. You must also enable metadata (see above). One reason for not including cover art is that the images can sometimes be very large and may delay transmission of subsequent metadata through the pipe. The default is "no".
|
||||
.TP
|
||||
\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. Additionally, \fIsocket-port\f1 must be non-zero and \fIenabled\f1 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"DIAGNOSTICS" SETTINGS\f1
|
||||
.TP
|
||||
\fBstatistics=\f1\fI"setting"\f1\fB;\f1
|
||||
Use this \fIsetting\f1 to enable ("yes") or disable ("no") the output of some statistical information to the system log (or to \fISTDERR\f1 if the \fB-u\f1 command line option is chosen). The default is to disable statistics.
|
||||
.TP
|
||||
\fBlog_verbosity=\f1\fI0\f1\fB;\f1
|
||||
Use this to specify how much debugging information should sent to the system log (or to \fISTDERR\f1 if the \fB-u\f1 command line option is chosen). The value \fI0\f1 means no debug information, \fI3\f1 means most debug information. The default is \fI0\f1.
|
||||
The sample configuration file includes extensive documentation of the settings. and is also available at \fBhttps://github.com/mikebrady/shairport-sync/blob/master/scripts/shairport-sync.conf\f1. Please refer to it for the most up-to-date information on configuration file settings.
|
||||
.SH OPTIONS
|
||||
This section is about the command-line options available in shairport-sync.
|
||||
|
||||
Note: if you are setting up shairport-sync for the first time or are updating an existing installation, you are encouraged to use the configuration file settings described above. Most of the command-line options described below simply replicate the configuration settings and are retained to provide backward compatibility with older installations of shairport-sync.
|
||||
|
||||
Many command-line options take sensible default values, so you can normally ignore most of them. See the EXAMPLES section for typical usages.
|
||||
|
||||
There are two kinds of command-line options for shairport-sync: regular \fBprogram options\f1 and \fBaudio backend options\f1. Program options are always listed first, followed by any audio backend options, preceded by a \fB--\f1 symbol.
|
||||
|
||||
See the EXAMPLES section for sample usages.
|
||||
.SH PROGRAM OPTIONS
|
||||
These command-line options are used by shairport-sync itself.
|
||||
Program 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.
|
||||
@@ -347,7 +63,7 @@ The following substitutions are allowed: \fB%h\f1 for the computer's hostname, \
|
||||
The default is "%H", which is replaced by the hostname with the first letter capitalised.
|
||||
.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 the appropriate shebang (\fI#!/bin/sh\f1 in the headline.
|
||||
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 the appropriate shebang (\fI#!/bin/sh\f1) in the headline.
|
||||
|
||||
If you want shairport-sync to wait until the command has completed before starting to play, select the \fB-w\f1 option as well.
|
||||
.TP
|
||||
@@ -355,58 +71,64 @@ If you want shairport-sync to wait until the command has completed before starti
|
||||
Read configuration settings from \fIfilename\f1. The default is to read them from the \fIshairport-sync.conf\f1 in the System Configuration Directory -- \fI/etc\f1 in Linux, \fI/usr/local/etc\f1 in BSD unixes. For information about configuration settings, see the "Configuration File Settings" section above.
|
||||
.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/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. See also the \fB-j\f1 option. Only available if shaiport-sync has been compiled with libdaemon support.
|
||||
Instruct shairport-sync to demonise itself. It will write its Process ID (PID) to a file, usually at \fI/var/run/shairport-sync/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. See also the \fB-j\f1 option. Only available if shairport-sync has been compiled with libdaemon support.
|
||||
.TP
|
||||
\fB-E \f1\fIprogram\f1\fB | --on-stop=\f1\fIprogram\f1
|
||||
Execute \fIprogram\f1 when playback has ended. Specify the full path to the program, e.g. \fI/usr/bin/logger\f1. Executable scripts can be used, but they must have the appropriate shebang (\fI#!/bin/sh\f1 in the headline.
|
||||
Execute \fIprogram\f1 when playback has ended. Specify the full path to the program, e.g. \fI/usr/bin/logger\f1. Executable scripts can be used, but they must have the appropriate shebang (\fI#!/bin/sh\f1) in the headline.
|
||||
|
||||
If you want shairport-sync to wait until the command has completed before continuing, select the \fB-w\f1 option as well.
|
||||
.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.
|
||||
|
||||
Please note that cover art data may be very large, and may place too great a burden on your network.
|
||||
\fB-g | --get-coverart\f1
|
||||
This option requires the \fB-M | --metadata-enable\f1 option to be set, and enables shairport-sync to request cover art from the source and to process it as metadata.
|
||||
.TP
|
||||
\fB-h | --help\f1
|
||||
Print brief help message and exit.
|
||||
.TP
|
||||
\fB-j\f1
|
||||
Instruct shairport-sync to demonise itself. Unlike the \fB-d\f1 option, it will not write a Process ID (PID) to a file -- it will just (hence the "j") demonise itself. Only available if shaiport-sync has been compiled with libdaemon support.
|
||||
\fB-j | justDaemoniseNoPIDFile\f1
|
||||
Instruct shairport-sync to demonise itself. Unlike the \fB-d\f1 option, it will not write a Process ID (PID) to a file -- it will just (hence the "j") demonise itself. Only available if shairport-sync has been compiled with libdaemon support.
|
||||
.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. Only available if shaiport-sync has been compiled with libdaemon support.)
|
||||
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. Only available if shairport-sync has been compiled with libdaemon support.)
|
||||
.TP
|
||||
\fB--logOutputLevel\f1
|
||||
Use this to log the volume level when the volume is changed. It may be useful if you are trying to determine a suitable value for the maximum volume level. Not available as a configuration file setting.
|
||||
.TP
|
||||
\fB--log-to-syslog\f1
|
||||
Warnings, error messages and messages are sent, by default, to \fISTDERR\f1. Use this option to route these messages to the \fBsyslog\f1 instead. This is intended for use when Shairport Sync is operating as a daemon.
|
||||
|
||||
See also \fB--displayConfig\f1.
|
||||
.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.
|
||||
\fB-M | --metadata-enable\f1
|
||||
Ask the client to send metadata. It will be sent, along with metadata generated by shairport-sync itself, to a pipe and will also be sent as UDP packets. If you add the \fB-g | --get-cover-art\f1 then cover art included, where available. See \fBhttps://github.com/mikebrady/shairport-sync-metadata-reader\f1 for a sample metadata reader.
|
||||
.TP
|
||||
\fB--metadata-pipename=\f1\fIpathname\f1
|
||||
Specify the path name for the metadata pipe. Note that \fBshairport-sync\f1 will need write permission on that directory and pipe. The default is \fI/tmp/shairport-sync-metadata\f1. If you rename the \fBshairport-sync\f1 executable, the default pipe name will change accordingly.
|
||||
.TP
|
||||
\fB-m \f1\fImdnsbackend\f1\fB | --mdns=\f1\fImdnsbackend\f1
|
||||
Force the use of the specified mDNS backend to advertise the player on the network. The default is to try all mDNS backends until one works.
|
||||
Force the use of the specified mDNS backend to advertise the player on the network. The default is to try all mDNS backends in order until one works.
|
||||
.TP
|
||||
\fB-o \f1\fIoutputbackend\f1\fB | --output=\f1\fIoutputbackend\f1
|
||||
Force the use of the specified output backend to play the audio. The default is to try the first one.
|
||||
.TP
|
||||
\fB-p \f1\fIport\f1\fB | --port=\f1\fIport\f1
|
||||
Listen for play requests on \fIport\f1. The default is to use port 5000.
|
||||
Listen for play requests on \fIport\f1. The default is to use port 5000 for AirPlay and 7000 for AirPlay 2.
|
||||
.TP
|
||||
\fB--password=\f1\fIsecret\f1
|
||||
Require the password \fIsecret\f1 to be able to connect and stream to the service.
|
||||
Require the password \fIsecret\f1 to be able to connect and stream to the service. (This only works for AirPlay and not for AirPlay 2.)
|
||||
.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. This setting is deprecated and will be removed in a future version of shairport-sync.
|
||||
.TP
|
||||
\fB--statistics\f1
|
||||
Print some statistics in the standard output, or in the logfile if in daemon mode.
|
||||
Print some performance information to \fISTDERR\f1, or to \fBsyslog\f1 if the \fB-log-to-syslog\f1 command line option is also chosen.
|
||||
.TP
|
||||
\fB-S \f1\fImode\f1\fB | --stuffing=\f1\fImode\f1
|
||||
Stuff the audio stream using the \fImode\f1. "Stuffing" refers to the process of adding or removing frames of audio to or from the stream sent to the output device to keep it exactly in synchrony with the player. The default mode, \fBbasic\f1, is normally almost completely inaudible. The alternative mode, \fBsoxr\f1, is even less obtrusive but requires much more processing power. For this mode, support for libsoxr, the SoX Resampler Library, must be selected when shairport-sync is compiled.
|
||||
Interpolate ("stuff") the audio stream using the \fImode\f1. "Stuffing" refers to the process of adding or removing frames of audio to or from the stream sent to the output device in order to keep it synchronised with the player. The \fBbasic\f1 mode is normally almost completely inaudible. The alternative mode, \fBsoxr\f1, is even less obtrusive but requires much more processing power. For this mode, support for \fBlibsoxr\f1, the SoX Resampler Library, must be selected when \fBshairport-sync\f1 is built. The default setting, \fBauto\f1, allows Shairport Sync to choose \fBsoxr\f1 mode if the system is powerful enough.
|
||||
.TP
|
||||
\fB-t \f1\fItimeout\f1\fB | --timeout=\f1\fItimeout\f1
|
||||
Exit play mode if the stream disappears for more than \fItimeout\f1 seconds.
|
||||
@@ -416,48 +138,34 @@ When shairport-sync plays an audio stream, it starts a play session and will ret
|
||||
\fB--tolerance=\f1\fIframes\f1
|
||||
Allow playback to be up to \fIframes\f1 out of exact synchronization before attempting to correct it. The default is 88 frames, i.e. 2 ms. The smaller the tolerance, the more likely it is that overcorrection will occur. Overcorrection is when more corrections (insertions and deletions) are made than are strictly necessary to keep the stream in sync. Use the \fB--statistics\f1 option to monitor correction levels. Corrections should not greatly exceed net corrections. This setting is deprecated and will be removed in a future version of shairport-sync.
|
||||
.TP
|
||||
\fB-u\f1
|
||||
If you are running shairport-sync from the command line and want logs to appear there, use this option. Otherwise, logs may go to the system log.
|
||||
.TP
|
||||
\fB-V | --version\f1
|
||||
Print version information and exit.
|
||||
.TP
|
||||
\fB-v | --verbose\f1
|
||||
Print debug information to the system log, or or to \fISTDERR\f1 if the \fB-u\f1 command line option is also chosen. Repeat up to three times to get more detail.
|
||||
Print debug information to the \fISTDERR\f1, or to \fBsyslog\f1 if the \fB-log-to-syslog\f1 command line option is also chosen. Repeat up to three times (i.e. \fB-vv\f1 or \fB-vvv\f1) for more detail. You should use \fB-vvv\f1 very sparingly -- it is really noisy.
|
||||
.TP
|
||||
\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 command-line 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.
|
||||
.TP
|
||||
\fB-X | --displayConfig\f1
|
||||
This logs information relating to the configuration of Shairport Sync. It can be very useful for debugging. The information logged is some host OS information, the Shairport Sync version string (which indicates the build options used when \fBshairport-sync\f1 was built), the contents of the command line that invoked Shairport Sync, the name of the configuration file and the active settings therein.
|
||||
|
||||
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.
|
||||
.TP
|
||||
\fB-d \f1\fIdevice\f1
|
||||
Use the specified output \fIdevice\f1. You may specify a card, e.g. \fBhw:0\f1, in which case the default output device on the card will be chosen. Alternatively, you can specify a specific device on a card, e.g. \fBhw:0,0\f1. The default is the device named \fBdefault\f1.
|
||||
.TP
|
||||
\fB-m \f1\fImixer\f1
|
||||
Use the specified hardware \fImixer\f1 for volume control. Use this to specify where the mixer is to be found. For example, if the mixer is associated with a card, as is often the case, specify the card, e.g. \fBhw:0\f1. If (unusually) the mixer is associated with a specific device on a card, specify the device, e.g. \fBhw:0,1\f1. The default is the device named in the \fB-d\f1 option, if given, or the device named \fBdefault\f1.
|
||||
.TP
|
||||
\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.
|
||||
If this is the only option on the command line, \fBshairport-sync\f1 will terminate after displaying the information.
|
||||
.SH AUDIO BACKEND OPTIONS
|
||||
Audio Backend Options are command-line options that are passed to the chosen audio backend. They are always preceded by the \fB--\f1 symbol to introduce them and to separate them from any preceding program options. In this way, option letters can be used as program options and reused as audio backend options without ambiguity.
|
||||
|
||||
Audio backends are listed with their corresponding Audio Backend Options in the help text provided by the help (\fB-h\f1 or \fB--help\f1) option.
|
||||
.SH EXAMPLES
|
||||
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
|
||||
shairport-sync \fB-a "Joe's Stereo"\f1 \fB-o alsa\f1 \fB--\f1 \fB-d hw:1,0\f1 \fB-m hw:1\f1 \fB-c PCM\f1
|
||||
|
||||
The program will run in daemon mode ( \fB-d\f1 ), will be visible as "Joe's Stereo" ( \fB-a "Joe's Stereo"\f1 ) and will use the SoX Resampler Library-based stuffing ( \fB-S soxr\f1 ). The audio backend options following the \fB--\f1 separator specify that the audio will be output on output 0 of soundcard 1 ( \fB-d hw:1,0\f1 ) and will take advantage of the same sound card's mixer ( \fB-m hw:1\f1 ) using the level control named "PCM" ( \fB-c "PCM"\f1 ).
|
||||
The program will be visible as "Joe's Stereo" ( \fB-a "Joe's Stereo"\f1 ). The program option \fB-o alsa\f1 specifies that the \fBalsa\f1 backend be used, thus that audio should be output into the \fBALSA\f1 audio subsystem. The audio backend options following the \fB--\f1 separator are passed to the \fBalsa\f1 backend and specify that the audio will be output on subdevice 0 of soundcard 1 ( \fB-d hw:1,0\f1 ) and will take advantage of the same sound card's mixer ( \fB-m hw:1\f1 ) using the level control named "PCM" ( \fB-c "PCM"\f1 ).
|
||||
|
||||
The example above is slightly contrived in order to show the use of the \fB-m\f1 option. Typically, output 0 is the default output of a card, so the output device could be written \fB-d hw:1\f1 and then the mixer option would be unnecessary, giving the following, simpler, command:
|
||||
The example above is slightly contrived: Firstly, if the \fBalsa\f1 backend has been included in the build, it will be the default, so it doesn't need to be specified and the \fB-o alsa\f1 option could be omitted. Secondly, subdevice 0 is the default for a soundcard, so the output device could simply be written \fB-d hw:1\f1. Thirdly, when a mixer name is given ( \fB-c "PCM"\f1 ), the default is that the mixer is on the output device, so the \fB-m hw:1\f1 is unnecessary here. Using these defaults and simplifications gives the following command:
|
||||
|
||||
shairport-sync \fB-d\f1 \fB-a "Joe's Stereo"\f1 \fB-S soxr\f1 \fB--\f1 \fB-d hw:1\f1 \fB-c PCM\f1
|
||||
shairport-sync \fB-a "Joe's Stereo"\f1 \fB--\f1 \fB-d hw:1\f1 \fB-c PCM\f1
|
||||
.SH CREDITS
|
||||
Mike Brady developed shairport-sync from the original Shairport by James Laird.
|
||||
|
||||
shairport-sync can be found at \fBhttps://github.com/mikebrady/shairport-sync.\f1
|
||||
|
||||
Shairport can be found at \fBhttps://github.com/abrasive/shairport.\f1
|
||||
Mike Brady (\fBhttps://github.com/mikebrady\f1) developed Shairport Sync from Shairport by James Wah (\fBhttps://github.com/abrasive\f1).
|
||||
.SH COMMENTS
|
||||
This man page was written using \fBxml2man(1)\f1 by Oliver Kurth.
|
||||
|
||||
+151
-870
File diff suppressed because it is too large
Load Diff
@@ -1,28 +0,0 @@
|
||||
<body text="#000000" link="#0000ff" bgcolor="#ffffff"><center><table width="80%">
|
||||
<tr><td><h1>shairport-sync</h1>
|
||||
<h2>Synchronised Audio Player for iTunes / AirPlay</h2>
|
||||
<h2>Synopsis</h2>
|
||||
<b><b></b><b></b><em></em><b></b><b></b><em></em><b></b><b></b><em></em><b></b><b></b><em></em><b></b><b></b><em></em><b></b><b></b><b></b><b></b><em></em><b></b><b></b><em></em><b></b><b></b><em></em><b></b><b></b><em></em><b></b><b></b><em></em><b></b><b></b><em></em><b></b><b></b><b></b><em></em><b></b><b></b><em></em><b></b><b></b><em></em><b></b><b></b><em></em><b></b><br>
|
||||
<b></b><br>
|
||||
<b></b><br>
|
||||
<b></b><br>
|
||||
</b>
|
||||
<h2>Description</h2>
|
||||
<p></p><p></p><p></p><p></p><p></p><p></p><p><b></b></p>
|
||||
<h2>Configuration File Settings</h2>
|
||||
<p><em></em><em></em><em></em></p><p><em></em><b></b></p><p></p><p><b></b></p><p><p><b></b></p></p><p><p><b></b></p></p><p><p><b></b></p></p><p><b></b></p><p><b></b></p><p><b></b></p><p><p><b></b></p></p><p><p><b></b></p></p><p><b></b></p><p></p><p><em></em><em></em><em></em></p><p></p><p><em></em><a href = "http://www.hyperrealm.com/libconfig/libconfig_manual.html">http://www.hyperrealm.com/libconfig/libconfig_manual.html</a></p><p><b></b></p><p><b></b></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><b></b><b></b><b></b></p><p></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em><b></b></p><p><b></b><em></em><b></b></p><p><em></em><b></b></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em><em></em></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em><b></b><b></b></p><p><b></b><em></em><b></b></p><p><em></em><b></b></p><p><b></b><em></em><b></b></p><p><em></em><em></em><em></em></p><p><b></b><em></em><b></b></p><p><em></em></p><p></p><p></p><p></p><p></p><p><b></b><em></em><b></b></p><p></p><p><b></b><em></em><b></b></p><p><em></em><em></em></p><p><b></b><em></em><b></b></p><p><em></em></p><p></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em></p><p></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p></p><p><b></b><em></em><b></b></p><p></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em></p><p></p><p></p><p><b></b><em></em><b></b></p><p></p><p><b></b><em></em><b></b></p><p><em></em></p><p></p><p></p><p><b></b><em></em><b></b></p><p><em></em><em></em></p><p><b></b><em></em><b></b></p><p><em></em><em></em></p><p><b></b></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p></p><p><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p></p><p></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em><b></b></p><p><b></b><em></em><b></b></p><p><b></b></p><p><b></b><em></em><b></b></p><p></p><p><b></b></p><p><b></b><b></b><b></b></p><p><b></b><em></em><b></b></p><p><em></em><em></em></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p></p><p><b></b><em></em><b></b></p><p></p><p><b></b><em></em><b></b></p><p></p><p></p><p></p><p><b></b><em></em><b></b></p><p><em></em><em></em></p><p><b></b><em></em><b></b></p><p></p><p><b></b><em></em><b></b></p><p></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em><em></em><em></em></p><p><em></em></p><p></p><p><b></b><em></em><b></b></p><p><b></b></p><p></p><p><b></b><em></em><b></b></p><p></p><p></p><p><b></b></p><p></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p></p><p><b></b><em></em><b></b></p><p></p><p></p><p></p><p></p><p><b></b><em></em><b></b></p><p></p><p><b></b><em></em><b></b></p><p></p><p><b></b></p><p></p><p><b></b><em></em><b></b></p><p></p><p><b></b></p><p></p><p><b></b><em></em><b></b></p><p></p><p><b></b></p><p></p><p><b></b></p><p></p><p><b></b></p><p><em></em><b></b><b></b></p><p></p><p><b></b></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em></p><p><b></b><em></em><b></b></p><p><em></em><em></em><em></em></p><p><b></b><em></em><b></b></p><p><b></b><em></em></p><p><b></b><em></em><b></b></p><p></p><p><b></b></p><p><b></b><em></em><b></b></p><p><em></em><em></em><b></b></p><p><b></b><em></em><b></b></p><p><em></em><b></b><em></em><em></em><em></em></p>
|
||||
<h2>Options</h2>
|
||||
<p></p><p></p><p></p><p><b></b><b></b><b></b></p><h2>Program Options</h2>
|
||||
<p></p>
|
||||
<p><b></b><em></em><b></b><em></em></p><p><em></em></p><p><b></b><b></b><b></b><b></b></p><p></p><p><b></b><em></em><b></b><em></em></p><p><em></em><em></em><em></em></p><p><b></b></p><p><b></b><em></em><b></b><em></em></p><p><em></em><em></em><em></em><em></em></p><p><b></b></p><p><em></em><b></b><b></b><b></b><b></b></p><p><b></b><em></em><b></b><em></em></p><p><em></em><em></em><em></em></p><p><b></b></p><p><b></b></p><p><b></b></p><p></p><p><b></b></p><p></p><p><b></b></p><p><b></b></p><p><b></b></p><p><b></b></p><p><b></b></p><p></p><p><b></b><em></em></p><p><em></em><em></em></p><p></p><p><b></b><em></em></p><p><em></em><em></em><b></b><a href = "https://github.com/mikebrady/shairport-sync-metadata-reader">https://github.com/mikebrady/shairport-sync-metadata-reader</a></p><p><b></b><em></em><b></b><em></em></p><p></p><p><b></b><em></em><b></b><em></em></p><p></p><p><b></b><em></em><b></b><em></em></p><p><em></em></p><p><b></b><em></em></p><p><em></em></p><p><b></b><em></em><b></b><em></em></p><p><em></em><b></b></p><p><b></b></p><p></p><p><b></b><em></em><b></b><em></em></p><p><em></em><b></b><b></b></p><p><b></b><em></em><b></b><em></em></p><p><em></em></p><p><em></em><b></b></p><p><b></b><em></em></p><p><em></em><b></b></p><p><b></b></p><p></p><p><b></b></p><p></p><p><b></b></p><p><em></em><b></b></p><p><b></b></p><p><b></b><b></b></p><h2>Audio Backend Options</h2>
|
||||
<p><b></b></p><p><b></b><b></b><b></b></p>
|
||||
<p><b></b><em></em></p><p><em></em><b></b><b></b></p><p><b></b><em></em></p><p><em></em><b></b><b></b><b></b></p><p><b></b><em></em></p><p><em></em><b></b><b></b><b></b><b></b></p><p><b></b><em></em></p><p></p><h2>Examples</h2>
|
||||
<p></p><b></b><b></b><b></b><b></b><b></b><b></b><b></b><br>
|
||||
<p><b></b><b></b><b></b><b></b><b></b><b></b><b></b></p><p><b></b><b></b></p><b></b><b></b><b></b><b></b><b></b><b></b><br>
|
||||
|
||||
<h2>Credits</h2>
|
||||
<p></p><p><a href = "https://github.com/mikebrady/shairport-sync.">https://github.com/mikebrady/shairport-sync.</a></p><p><a href = "https://github.com/abrasive/shairport.">https://github.com/abrasive/shairport.</a></p>
|
||||
<h2>Comments</h2>
|
||||
<p><a href="http://masqmail.cx/xml2man/">xml2man</a></p>
|
||||
</td></tr></table></center>
|
||||
</body>
|
||||
+2
-1
@@ -229,7 +229,8 @@ void mpris_metadata_watcher(struct metadata_bundle *argc, __attribute__((unused)
|
||||
static gboolean on_handle_quit(MediaPlayer2 *skeleton, GDBusMethodInvocation *invocation,
|
||||
__attribute__((unused)) gpointer user_data) {
|
||||
debug(1, "quit requested (MPRIS interface).");
|
||||
pthread_cancel(main_thread_id);
|
||||
type_of_exit_cleanup = TOE_dbus; // request an exit cleanup that is compatible with dbus
|
||||
exit(EXIT_SUCCESS);
|
||||
media_player2_complete_quit(skeleton, invocation);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -1671,40 +1671,44 @@ int32_t decipher_player_put_packet(uint8_t *ciphered_audio_alt, ssize_t nread,
|
||||
// %u, Csrc Count: %u, Marker: %u, Payload Type: %u, Sequence Number: %u, Timestamp: %u,
|
||||
// SSRC: %u.", version, padding, extension, csrc_count, marker, payload_type,
|
||||
// sequence_number, timestamp, ssrc);
|
||||
|
||||
if (conn->session_key != NULL) {
|
||||
unsigned char nonce[12];
|
||||
memset(nonce, 0, sizeof(nonce));
|
||||
memcpy(nonce + 4, ciphered_audio_alt + nread - 8,
|
||||
8); // front-pad the 8-byte nonce received to get the 12-byte nonce expected
|
||||
|
||||
unsigned char nonce[12];
|
||||
memset(nonce, 0, sizeof(nonce));
|
||||
memcpy(nonce + 4, ciphered_audio_alt + nread - 8,
|
||||
8); // front-pad the 8-byte nonce received to get the 12-byte nonce expected
|
||||
// https://libsodium.gitbook.io/doc/secret-key_cryptography/aead/chacha20-poly1305/ietf_chacha20-poly1305_construction
|
||||
// Note: the eight-byte nonce must be front-padded out to 12 bytes.
|
||||
|
||||
// https://libsodium.gitbook.io/doc/secret-key_cryptography/aead/chacha20-poly1305/ietf_chacha20-poly1305_construction
|
||||
// Note: the eight-byte nonce must be front-padded out to 12 bytes.
|
||||
unsigned char m[4096];
|
||||
unsigned long long new_payload_length = 0;
|
||||
int response = crypto_aead_chacha20poly1305_ietf_decrypt(
|
||||
m, // m
|
||||
&new_payload_length, // mlen_p
|
||||
NULL, // nsec,
|
||||
ciphered_audio_alt +
|
||||
10, // the ciphertext starts 10 bytes in and is followed by the MAC tag,
|
||||
nread - (8 + 10), // clen -- the last 8 bytes are the nonce
|
||||
ciphered_audio_alt + 2, // authenticated additional data
|
||||
8, // authenticated additional data length
|
||||
nonce,
|
||||
conn->session_key); // *k
|
||||
if (response != 0) {
|
||||
debug(1, "Error decrypting an audio packet.");
|
||||
}
|
||||
// now pass it in to the regular processing chain
|
||||
|
||||
unsigned char m[4096];
|
||||
unsigned long long new_payload_length = 0;
|
||||
int response = crypto_aead_chacha20poly1305_ietf_decrypt(
|
||||
m, // m
|
||||
&new_payload_length, // mlen_p
|
||||
NULL, // nsec,
|
||||
ciphered_audio_alt +
|
||||
10, // the ciphertext starts 10 bytes in and is followed by the MAC tag,
|
||||
nread - (8 + 10), // clen -- the last 8 bytes are the nonce
|
||||
ciphered_audio_alt + 2, // authenticated additional data
|
||||
8, // authenticated additional data length
|
||||
nonce,
|
||||
conn->session_key); // *k
|
||||
if (response != 0) {
|
||||
debug(1, "Error decrypting an audio packet.");
|
||||
unsigned long long max_int = INT_MAX; // put in the right format
|
||||
if (new_payload_length > max_int)
|
||||
debug(1, "Madly long payload length!");
|
||||
int plen = new_payload_length; //
|
||||
// debug(1," Write packet to buffer %d, timestamp %u.", sequence_number, timestamp);
|
||||
player_put_packet(1, sequence_number, timestamp, m, plen,
|
||||
conn); // the '1' means is original format
|
||||
} else {
|
||||
debug(2, "No session key, so the audio packet can not be deciphered -- skipped.");
|
||||
}
|
||||
// now pass it in to the regular processing chain
|
||||
|
||||
unsigned long long max_int = INT_MAX; // put in the right format
|
||||
if (new_payload_length > max_int)
|
||||
debug(1, "Madly long payload length!");
|
||||
int plen = new_payload_length; //
|
||||
// debug(1," Write packet to buffer %d, timestamp %u.", sequence_number, timestamp);
|
||||
player_put_packet(1, sequence_number, timestamp, m, plen,
|
||||
conn); // the '1' means is original format
|
||||
return sequence_number;
|
||||
} else {
|
||||
debug(1, "packet was too small -- ignored");
|
||||
@@ -2828,28 +2832,33 @@ void *rtp_buffered_audio_processor(void *arg) {
|
||||
if ((((flush_requested != 0) && (seq_no == flushUntilSeq)) ||
|
||||
((flush_requested == 0) && (new_buffer_needed))) &&
|
||||
(too_soon_after_connection == 0)) {
|
||||
|
||||
unsigned char nonce[12];
|
||||
memset(nonce, 0, sizeof(nonce));
|
||||
memcpy(nonce + 4, packet + nread - 8,
|
||||
8); // front-pad the 8-byte nonce received to get the 12-byte nonce expected
|
||||
|
||||
// https://libsodium.gitbook.io/doc/secret-key_cryptography/aead/chacha20-poly1305/ietf_chacha20-poly1305_construction
|
||||
// Note: the eight-byte nonce must be front-padded out to 12 bytes.
|
||||
unsigned long long new_payload_length = 0;
|
||||
int response = crypto_aead_chacha20poly1305_ietf_decrypt(
|
||||
m + 7, // m
|
||||
&new_payload_length, // mlen_p
|
||||
NULL, // nsec,
|
||||
packet + 12, // the ciphertext starts 12 bytes in and is followed by the MAC tag,
|
||||
nread - (8 + 12), // clen -- the last 8 bytes are the nonce
|
||||
packet + 4, // authenticated additional data
|
||||
8, // authenticated additional data length
|
||||
nonce,
|
||||
conn->session_key); // *k
|
||||
if (response != 0) {
|
||||
debug(1, "Error decrypting audio packet %u -- packet length %d.", seq_no, nread);
|
||||
int response = -1; // guess that there is a problem
|
||||
if (conn->session_key != NULL) {
|
||||
unsigned char nonce[12];
|
||||
memset(nonce, 0, sizeof(nonce));
|
||||
memcpy(nonce + 4, packet + nread - 8,
|
||||
8); // front-pad the 8-byte nonce received to get the 12-byte nonce expected
|
||||
|
||||
// https://libsodium.gitbook.io/doc/secret-key_cryptography/aead/chacha20-poly1305/ietf_chacha20-poly1305_construction
|
||||
// Note: the eight-byte nonce must be front-padded out to 12 bytes.
|
||||
|
||||
response = crypto_aead_chacha20poly1305_ietf_decrypt(
|
||||
m + 7, // m
|
||||
&new_payload_length, // mlen_p
|
||||
NULL, // nsec,
|
||||
packet + 12, // the ciphertext starts 12 bytes in and is followed by the MAC tag,
|
||||
nread - (8 + 12), // clen -- the last 8 bytes are the nonce
|
||||
packet + 4, // authenticated additional data
|
||||
8, // authenticated additional data length
|
||||
nonce,
|
||||
conn->session_key); // *k
|
||||
if (response != 0)
|
||||
debug(1, "Error decrypting audio packet %u -- packet length %d.", seq_no, nread);
|
||||
} else {
|
||||
debug(2, "No session key, so the audio packet can not be deciphered -- skipped.");
|
||||
}
|
||||
if (response == 0) {
|
||||
// now pass it in to the regular processing chain
|
||||
|
||||
unsigned long long max_int = INT_MAX; // put in the right format
|
||||
|
||||
@@ -1501,6 +1501,7 @@ int msg_write_response(rtsp_conn_info *conn, rtsp_message *resp) {
|
||||
{404, "Not Found"},
|
||||
{451, "Unavailable"},
|
||||
{456, "Header Field Not Valid for Resource"},
|
||||
{470, "Connection Authorization Required"},
|
||||
{500, "Internal Server Error"},
|
||||
{501, "Not Implemented"}};
|
||||
// 451 is really "Unavailable For Legal Reasons"!
|
||||
@@ -3148,6 +3149,13 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
|
||||
|
||||
plist_t streams_array = plist_new_array(); // to hold the ports and stuff
|
||||
plist_t stream0dict = plist_new_dict();
|
||||
|
||||
// get the session key -- it must have one
|
||||
|
||||
plist_t item = plist_dict_get_item(stream0, "shk"); // session key
|
||||
uint64_t item_value = 0; // the length
|
||||
plist_get_data_val(item, (char **)&conn->session_key, &item_value);
|
||||
|
||||
// more stuff
|
||||
// set up a UDP control stream and thread and a UDP or TCP audio stream and thread
|
||||
|
||||
@@ -3164,12 +3172,6 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
|
||||
|
||||
pthread_create(&conn->rtp_ap2_control_thread, NULL, &rtp_ap2_control_receiver, (void *)conn);
|
||||
|
||||
// get the session key
|
||||
|
||||
plist_t item = plist_dict_get_item(stream0, "shk"); // session key
|
||||
uint64_t item_value = 0;
|
||||
plist_get_data_val(item, (char **)&conn->session_key, &item_value);
|
||||
|
||||
// get the DACP-ID and Active Remote for remote control stuff
|
||||
|
||||
char *ar = msg_get_header(req, "Active-Remote");
|
||||
@@ -3329,6 +3331,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
|
||||
plist_array_append_item(streams_array, stream0dict);
|
||||
plist_dict_set_item(setupResponsePlist, "streams", streams_array);
|
||||
resp->respcode = 200;
|
||||
|
||||
} else if (conn->airplay_stream_category == remote_control_stream) {
|
||||
debug(2, "Connection %d (RC): SETUP: Remote Control Stream received from %s.",
|
||||
conn->connection_number, conn->client_ip_string);
|
||||
@@ -4303,7 +4306,7 @@ static void handle_get_parameter(__attribute__((unused)) rtsp_conn_info *conn, r
|
||||
|
||||
if ((req->content) && (req->contentlength == strlen("volume\r\n")) &&
|
||||
strstr(req->content, "volume") == req->content) {
|
||||
debug(2, "Connection %d: Current volume (%.6f) requested", conn->connection_number,
|
||||
debug(1, "Connection %d: Current volume (%.6f) requested", conn->connection_number,
|
||||
config.airplay_volume);
|
||||
char *p = malloc(128); // will be automatically deallocated with the response is deleted
|
||||
if (p) {
|
||||
|
||||
+292
-172
@@ -130,11 +130,14 @@ int killOption = 0;
|
||||
int daemonisewith = 0;
|
||||
int daemonisewithout = 0;
|
||||
int log_to_syslog_selected = 0;
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
int log_to_default = 1; // needed if libdaemon used
|
||||
#endif
|
||||
int display_config_selected = 0;
|
||||
int log_to_syslog_select_is_first_command_line_argument = 0;
|
||||
|
||||
// static int shutting_down = 0;
|
||||
char configuration_file_path[4096 + 1];
|
||||
char actual_configuration_file_path[4096 + 1];
|
||||
char *config_file_real_path = NULL;
|
||||
|
||||
char first_backend_name[256];
|
||||
|
||||
@@ -171,6 +174,7 @@ int has_fltp_capable_aac_decoder(void) {
|
||||
|
||||
#ifdef CONFIG_SOXR
|
||||
pthread_t soxr_time_check_thread;
|
||||
int soxr_time_check_thread_started = 0;
|
||||
void *soxr_time_check(__attribute__((unused)) void *arg) {
|
||||
const int buffer_length = 352;
|
||||
int32_t inbuffer[buffer_length * 2];
|
||||
@@ -270,91 +274,62 @@ void usage(char *progname) {
|
||||
|
||||
} else {
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
printf("Please use the configuration file for settings where possible.\n");
|
||||
printf("Many more settings are available in the configuration file.\n");
|
||||
printf("\n");
|
||||
printf("Usage: %s [options...]\n", progname);
|
||||
printf(" or: %s [options...] -- [audio output-specific options]\n", progname);
|
||||
printf("\n");
|
||||
printf("Options:\n");
|
||||
printf(" -h, --help show this help.\n");
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
printf(" -d, --daemon daemonise.\n");
|
||||
printf(" -j, --justDaemoniseNoPIDFile daemonise without a PID file.\n");
|
||||
printf(" -k, --kill kill the existing shairport daemon.\n");
|
||||
#endif
|
||||
printf(" -V, --version show version information.\n");
|
||||
printf(" -c, --configfile=FILE read configuration settings from FILE. Default is "
|
||||
"/etc/shairport-sync.conf.\n");
|
||||
|
||||
printf("\n");
|
||||
printf(
|
||||
"The following general options are for backward compatibility. These and all new options "
|
||||
"have settings in the configuration file, by default /etc/shairport-sync.conf:\n");
|
||||
printf(" -v, --verbose -v print debug information; -vv more; -vvv lots.\n");
|
||||
printf(" -p, --port=PORT set RTSP listening port.\n");
|
||||
printf(" -a, --name=NAME set advertised name.\n");
|
||||
printf(
|
||||
" -L, --latency=FRAMES [Deprecated] Set the latency for audio sent from an unknown "
|
||||
"device.\n");
|
||||
printf(" -h, --help Show this help.\n");
|
||||
printf(" -V, --version Show version information -- the version string.\n");
|
||||
printf(" -X, --displayConfig Output OS information, version string, command line, configuration file and active settings to the log.\n");
|
||||
printf(" --statistics Print some interesting statistics. More will be printed if -v / -vv / -vvv are also chosen.\n");
|
||||
printf(" -v, --verbose Print debug information; -v some; -vv more; -vvv lots -- generally too much.\n");
|
||||
printf(" -c, --configfile=FILE Read configuration settings from FILE. Default is %s.\n", configuration_file_path);
|
||||
printf(" -a, --name=NAME Set service name. Default is the hostname with first letter capitalised.\n");
|
||||
printf(" --password=PASSWORD Require PASSWORD to connect. Default is no password. (Classic AirPlay only.)\n");
|
||||
printf(" -p, --port=PORT Set RTSP listening port. Default 5000; 7000 for AirPlay 2./\n");
|
||||
printf(" -L, --latency=FRAMES [Deprecated] Set the latency for audio sent from an unknown device.\n");
|
||||
printf(" The default is to set it automatically.\n");
|
||||
printf(" -S, --stuffing=MODE set how to adjust current latency to match desired latency, "
|
||||
"where \n");
|
||||
printf(" \"basic\" inserts or deletes audio frames from "
|
||||
"packet frames with low processor overhead, and \n");
|
||||
printf(
|
||||
" \"soxr\" uses libsoxr to minimally resample packet frames -- "
|
||||
"moderate processor overhead.\n");
|
||||
printf(" \"auto\" (default) chooses basic or soxr depending on "
|
||||
"processor capability.\n");
|
||||
printf(
|
||||
" \"soxr\" option only available if built with soxr support.\n");
|
||||
printf(" -B, --on-start=PROGRAM run PROGRAM when playback is about to begin.\n");
|
||||
printf(" -E, --on-stop=PROGRAM run PROGRAM when playback has ended.\n");
|
||||
printf(
|
||||
" For -B and -E options, specify the full path to the program, "
|
||||
"e.g. /usr/bin/logger.\n");
|
||||
printf(" Executable scripts work, but must have the appropriate "
|
||||
"shebang "
|
||||
"(#!/bin/sh) in the headline.\n");
|
||||
printf(
|
||||
" -w, --wait-cmd wait until the -B or -E programs finish before continuing.\n");
|
||||
printf(" -o, --output=BACKEND select audio output method.\n");
|
||||
printf(" -m, --mdns=BACKEND force the use of BACKEND to advertize the service.\n");
|
||||
printf(" if no mdns provider is specified,\n");
|
||||
printf(" shairport tries them all until one works.\n");
|
||||
printf(
|
||||
" -r, --resync=THRESHOLD [Deprecated] resync if error exceeds this number of frames. "
|
||||
"Set to 0 to "
|
||||
"stop resyncing.\n");
|
||||
printf(
|
||||
" -t, --timeout=SECONDS go back to idle mode from play mode after a break in "
|
||||
"communications of this many seconds (default 120). Set to 0 never to exit play mode.\n");
|
||||
printf(" --statistics print some interesting statistics -- output to the logfile "
|
||||
"if running as a daemon.\n");
|
||||
printf(" --tolerance=TOLERANCE [Deprecated] allow a synchronization error of TOLERANCE "
|
||||
"frames (default "
|
||||
"88) before trying to correct it.\n");
|
||||
printf(" --password=PASSWORD require PASSWORD to connect. Default is not to require a "
|
||||
"password.\n");
|
||||
printf(" --logOutputLevel log the output level setting -- useful for setting maximum "
|
||||
"volume.\n");
|
||||
#ifdef CONFIG_METADATA
|
||||
printf(" -M, --metadata-enable ask for metadata from the source and process it.\n");
|
||||
printf(" --metadata-pipename=PIPE send metadata to PIPE, e.g. "
|
||||
"--metadata-pipename=/tmp/%s-metadata.\n",
|
||||
config.appName);
|
||||
printf(" The default is /tmp/%s-metadata.\n", config.appName);
|
||||
printf(
|
||||
" -g, --get-coverart Include cover art in the metadata to be gathered and sent.\n");
|
||||
printf(" -S, --stuffing=MODE Set how to adjust current latency to match desired latency, where:\n");
|
||||
printf(" \"basic\" inserts or deletes audio frames from packet frames with low processor overhead, and\n");
|
||||
printf(" \"soxr\" uses libsoxr to minimally resample packet frames -- moderate processor overhead.\n");
|
||||
printf(" The default \"auto\" setting chooses basic or soxr depending on processor capability.\n");
|
||||
printf(" The \"soxr\" option is only available if built with soxr support.\n");
|
||||
printf(" -B, --on-start=PROGRAM Run PROGRAM when playback is about to begin.\n");
|
||||
printf(" -E, --on-stop=PROGRAM Run PROGRAM when playback has ended.\n");
|
||||
printf(" For -B and -E options, specify the full path to the program and arguments, e.g. \"/usr/bin/logger\".\n");
|
||||
printf(" Executable scripts work, but the file must be marked executable have the appropriate shebang (#!/bin/sh) on the first line.\n");
|
||||
printf(" -w, --wait-cmd Wait until the -B or -E programs finish before continuing.\n");
|
||||
printf(" -o, --output=BACKEND Select audio backend. They are listed at the end of this text. The first one is the default.\n");
|
||||
printf(" -m, --mdns=BACKEND Use the mDNS backend named BACKEND to advertise the AirPlay service through Bonjour/ZeroConf.\n");
|
||||
printf(" They are listed at the end of this text.\n");
|
||||
printf(" If no mdns backend is specified, they are tried in order until one works.\n");
|
||||
printf(" -r, --resync=THRESHOLD [Deprecated] resync if error exceeds this number of frames. Set to 0 to stop resyncing.\n");
|
||||
printf(" -t, --timeout=SECONDS Go back to idle mode from play mode after a break in communications of this many seconds (default 120). Set to 0 never to exit play mode.\n");
|
||||
printf(" --tolerance=TOLERANCE [Deprecated] Allow a synchronization error of TOLERANCE frames (default 88) before trying to correct it.\n");
|
||||
printf(" --logOutputLevel Log the output level setting -- a debugging option, useful for determining the optimum maximum volume.\n");
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
printf(" -d, --daemon Daemonise.\n");
|
||||
printf(" -j, --justDaemoniseNoPIDFile Daemonise without a PID file.\n");
|
||||
printf(" -k, --kill Kill the existing shairport daemon.\n");
|
||||
#endif
|
||||
printf(" --log-to-syslog send debug and statistics information through syslog\n");
|
||||
printf(
|
||||
" If used, this should be the first command line argument.\n");
|
||||
printf(" -u, --use-stderr [Deprecated] This setting is not needed -- stderr is now "
|
||||
"used by default.\n");
|
||||
#ifdef CONFIG_METADATA
|
||||
printf(" -M, --metadata-enable Ask for metadata from the source and process it. Much more flexibility with configuration file settings.\n");
|
||||
printf(" --metadata-pipename=PIPE send metadata to PIPE, e.g. --metadata-pipename=/tmp/%s-metadata.\n", config.appName);
|
||||
printf(" The default is /tmp/%s-metadata.\n", config.appName);
|
||||
printf(" -g, --get-coverart Include cover art in the metadata to be gathered and sent.\n");
|
||||
#endif
|
||||
printf(" --log-to-syslog Send debug and statistics information through syslog\n");
|
||||
printf(" If used, this should be the first command line argument.\n");
|
||||
printf(" -u, --use-stderr [Deprecated] This setting is not needed -- stderr is now used by default and syslog is selected using --log-to-syslog.\n");
|
||||
printf("\n");
|
||||
mdns_ls_backends();
|
||||
printf("\n");
|
||||
audio_ls_outputs();
|
||||
// clang-format on
|
||||
|
||||
#ifdef CONFIG_AIRPLAY_2
|
||||
}
|
||||
@@ -380,6 +355,7 @@ int parse_options(int argc, char **argv) {
|
||||
{"statistics", 0, POPT_ARG_NONE, &config.statistics_requested, 0, NULL, NULL},
|
||||
{"logOutputLevel", 0, POPT_ARG_NONE, &config.logOutputLevel, 0, NULL, NULL},
|
||||
{"version", 'V', POPT_ARG_NONE, NULL, 0, NULL, NULL},
|
||||
{"displayConfig", 'X', POPT_ARG_NONE, &display_config_selected, 0, NULL, NULL},
|
||||
{"port", 'p', POPT_ARG_INT, &config.port, 0, NULL, NULL},
|
||||
{"name", 'a', POPT_ARG_STRING, &raw_service_name, 0, NULL, NULL},
|
||||
{"output", 'o', POPT_ARG_STRING, &config.output_name, 0, NULL, NULL},
|
||||
@@ -469,6 +445,9 @@ int parse_options(int argc, char **argv) {
|
||||
inform("Suggestion: make \"--log-to-syslog\" the first command line argument to ensure "
|
||||
"messages go to the syslog right from the beginning.");
|
||||
}
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
log_to_default = 0; // a specific log output modality has been selected.
|
||||
#endif
|
||||
log_to_syslog();
|
||||
}
|
||||
|
||||
@@ -587,18 +566,18 @@ int parse_options(int argc, char **argv) {
|
||||
|
||||
config_init(&config_file_stuff);
|
||||
|
||||
char *config_file_real_path = realpath(config.configfile, NULL);
|
||||
config_file_real_path = realpath(config.configfile, NULL);
|
||||
if (config_file_real_path == NULL) {
|
||||
debug(2, "can't resolve the configuration file \"%s\".", config.configfile);
|
||||
} else {
|
||||
debug(2, "looking for configuration file at full path \"%s\"", config_file_real_path);
|
||||
/* Read the file. If there is an error, report it and exit. */
|
||||
if (config_read_file(&config_file_stuff, config_file_real_path)) {
|
||||
free(config_file_real_path);
|
||||
config_set_auto_convert(&config_file_stuff,
|
||||
1); // allow autoconversion from int/float to int/float
|
||||
// make config.cfg point to it
|
||||
config.cfg = &config_file_stuff;
|
||||
|
||||
/* Get the Service Name. */
|
||||
if (config_lookup_string(config.cfg, "general.name", &str)) {
|
||||
raw_service_name = (char *)str;
|
||||
@@ -824,6 +803,9 @@ int parse_options(int argc, char **argv) {
|
||||
|
||||
/* Get the diagnostics output default. */
|
||||
if (config_lookup_string(config.cfg, "diagnostics.log_output_to", &str)) {
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
log_to_default = 0; // a specific log output modality has been selected.
|
||||
#endif
|
||||
if (strcasecmp(str, "syslog") == 0)
|
||||
log_to_syslog();
|
||||
else if (strcasecmp(str, "stdout") == 0) {
|
||||
@@ -1498,7 +1480,7 @@ int parse_options(int argc, char **argv) {
|
||||
char temp_pid_dir[4096];
|
||||
strcpy(temp_pid_dir, "/var/run/");
|
||||
strcat(temp_pid_dir, config.appName);
|
||||
debug(1, "default pid filename is \"%s\".", temp_pid_dir);
|
||||
debug(3, "Default PID directory is \"%s\".", temp_pid_dir);
|
||||
char *use_this_pid_dir = temp_pid_dir;
|
||||
#endif
|
||||
// debug(1,"config.piddir \"%s\".",config.piddir);
|
||||
@@ -1528,7 +1510,7 @@ char pid_file_path_string[4096] = "\0";
|
||||
const char *pid_file_proc(void) {
|
||||
snprintf(pid_file_path_string, sizeof(pid_file_path_string), "%s/%s.pid", config.computed_piddir,
|
||||
daemon_pid_file_ident ? daemon_pid_file_ident : "unknown");
|
||||
// debug(1,"pid_file_path_string \"%s\".",pid_file_path_string);
|
||||
debug(1, "PID file: \"%s\".", pid_file_path_string);
|
||||
return pid_file_path_string;
|
||||
}
|
||||
#endif
|
||||
@@ -1569,6 +1551,7 @@ void exit_function() {
|
||||
#ifdef CONFIG_DBUS_INTERFACE
|
||||
debug(2, "Stopping D-Bus service");
|
||||
stop_dbus_service();
|
||||
debug(2, "Stopping D-Bus service done");
|
||||
#endif
|
||||
if (g_main_loop) {
|
||||
debug(2, "Stopping D-Bus Loop Thread");
|
||||
@@ -1579,35 +1562,46 @@ void exit_function() {
|
||||
// so don't wait for it
|
||||
if (type_of_exit_cleanup != TOE_dbus)
|
||||
pthread_join(dbus_thread, NULL);
|
||||
debug(2, "Stopping D-Bus Loop Thread Done");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DACP_CLIENT
|
||||
debug(2, "Stopping DACP Monitor");
|
||||
dacp_monitor_stop();
|
||||
debug(2, "Stopping DACP Monitor Done");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_METADATA_HUB
|
||||
debug(2, "Stopping metadata hub");
|
||||
metadata_hub_stop();
|
||||
debug(2, "Stopping metadata done");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_METADATA
|
||||
debug(2, "Stopping metadata");
|
||||
metadata_stop(); // close down the metadata pipe
|
||||
debug(2, "Stopping metadata done");
|
||||
#endif
|
||||
debug(2, "Stopping the activity monitor.");
|
||||
activity_monitor_stop(0);
|
||||
debug(2, "Stopping the activity monitor done.");
|
||||
|
||||
if ((config.output) && (config.output->deinit)) {
|
||||
debug(2, "Deinitialise the audio backend.");
|
||||
config.output->deinit();
|
||||
debug(2, "Deinitialise the audio backend done.");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SOXR
|
||||
// be careful -- not sure if the thread can be cancelled cleanly, so wait for it to shut down
|
||||
debug(2, "Waiting for SoXr timecheck to terminate...");
|
||||
pthread_join(soxr_time_check_thread, NULL);
|
||||
if (soxr_time_check_thread_started != 0) {
|
||||
debug(1, "Waiting for SoXr timecheck to terminate...");
|
||||
pthread_join(soxr_time_check_thread, NULL);
|
||||
soxr_time_check_thread_started = 0;
|
||||
debug(1, "Waiting for SoXr timecheck to terminate done");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (conns)
|
||||
@@ -1654,6 +1648,8 @@ void exit_function() {
|
||||
#endif
|
||||
if (config.cfg)
|
||||
config_destroy(config.cfg);
|
||||
if (config_file_real_path)
|
||||
free(config_file_real_path);
|
||||
if (config.appName)
|
||||
free(config.appName);
|
||||
|
||||
@@ -1661,12 +1657,12 @@ void exit_function() {
|
||||
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
if (this_is_the_daemon_process) { // this is the daemon that is exiting
|
||||
debug(1, "libdaemon daemon exit");
|
||||
debug(1, "libdaemon daemon process exit");
|
||||
} else {
|
||||
if (config.daemonise)
|
||||
debug(1, "libdaemon parent exit");
|
||||
debug(1, "libdaemon parent process exit");
|
||||
else
|
||||
debug(1, "exit_function libdaemon exit");
|
||||
debug(1, "normal exit");
|
||||
}
|
||||
#else
|
||||
mdns_unregister(); // once the dacp handler is done and all player threrads are done it should
|
||||
@@ -1700,6 +1696,117 @@ void termHandler(__attribute__((unused)) int k) {
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void _display_config(const char *filename, const int linenumber, int argc, char **argv) {
|
||||
_inform(filename, linenumber, ">> Display Config Start.");
|
||||
|
||||
// see the man entry on popen
|
||||
FILE *fp;
|
||||
int status;
|
||||
char result[1024];
|
||||
|
||||
fp = popen("uname -a 2>/dev/null", "r");
|
||||
if (fp != NULL) {
|
||||
if (fgets(result, 1024, fp) != NULL) {
|
||||
_inform(filename, linenumber, "");
|
||||
_inform(filename, linenumber, "From \"uname -a\":");
|
||||
if (result[strlen(result) - 1] <= ' ')
|
||||
result[strlen(result) - 1] = '\0'; // remove the last character if it's not printable
|
||||
_inform(filename, linenumber, " %s", result);
|
||||
}
|
||||
status = pclose(fp);
|
||||
if (status == -1) {
|
||||
debug(1, "Error on pclose");
|
||||
}
|
||||
}
|
||||
|
||||
fp = popen("(cat /etc/os-release | grep PRETTY_NAME | sed 's/PRETTY_NAME=//' | sed 's/\"//g') "
|
||||
"2>/dev/null",
|
||||
"r");
|
||||
if (fp != NULL) {
|
||||
if (fgets(result, 1024, fp) != NULL) {
|
||||
_inform(filename, linenumber, "");
|
||||
_inform(filename, linenumber, "From /etc/os-release:");
|
||||
if (result[strlen(result) - 1] <= ' ')
|
||||
result[strlen(result) - 1] = '\0'; // remove the last character if it's not printable
|
||||
_inform(filename, linenumber, " %s", result);
|
||||
}
|
||||
status = pclose(fp);
|
||||
if (status == -1) {
|
||||
debug(1, "Error on pclose");
|
||||
}
|
||||
}
|
||||
|
||||
fp = popen("cat /sys/firmware/devicetree/base/model 2>/dev/null", "r");
|
||||
if (fp != NULL) {
|
||||
if (fgets(result, 1024, fp) != NULL) {
|
||||
_inform(filename, linenumber, "");
|
||||
_inform(filename, linenumber, "From /sys/firmware/devicetree/base/model:");
|
||||
_inform(filename, linenumber, " %s", result);
|
||||
}
|
||||
status = pclose(fp);
|
||||
if (status == -1) {
|
||||
debug(1, "Error on pclose");
|
||||
}
|
||||
}
|
||||
|
||||
char *version_string = get_version_string();
|
||||
if (version_string) {
|
||||
_inform(filename, linenumber, "");
|
||||
_inform(filename, linenumber, "Shairport Sync Version String:");
|
||||
_inform(filename, linenumber, " %s", version_string);
|
||||
free(version_string);
|
||||
} else {
|
||||
debug(1, "Can't print version string!\n");
|
||||
}
|
||||
if (argc != 0) {
|
||||
char *obfp = result;
|
||||
int i;
|
||||
for (i = 0; i < argc - 1; i++) {
|
||||
snprintf(obfp, strlen(argv[i]) + 2, "%s ", argv[i]);
|
||||
obfp += strlen(argv[i]) + 1;
|
||||
}
|
||||
snprintf(obfp, strlen(argv[i]) + 1, "%s", argv[i]);
|
||||
obfp += strlen(argv[i]);
|
||||
*obfp = 0;
|
||||
|
||||
_inform(filename, linenumber, "");
|
||||
_inform(filename, linenumber, "Command Line:");
|
||||
_inform(filename, linenumber, " %s", result);
|
||||
}
|
||||
|
||||
if (config.cfg == NULL)
|
||||
_inform(filename, linenumber, "No configuration file.");
|
||||
else {
|
||||
int configpipe[2];
|
||||
if (pipe(configpipe) == 0) {
|
||||
FILE *cw;
|
||||
cw = fdopen(configpipe[1], "w");
|
||||
_inform(filename, linenumber, "");
|
||||
_inform(filename, linenumber, "Configuration File:");
|
||||
_inform(filename, linenumber, " %s", config_file_real_path);
|
||||
_inform(filename, linenumber, "");
|
||||
_inform(filename, linenumber, "Configuration File Settings:");
|
||||
config_write(config.cfg, cw);
|
||||
fclose(cw);
|
||||
FILE *cr;
|
||||
cr = fdopen(configpipe[0], "r");
|
||||
while (fgets(result, 1024, cr) != NULL) {
|
||||
// replace funny character at the end, if it's there
|
||||
if (result[strlen(result) - 1] <= ' ')
|
||||
result[strlen(result) - 1] = '\0'; // remove the last character if it's not printable
|
||||
_inform(filename, linenumber, " %s", result);
|
||||
}
|
||||
fclose(cr);
|
||||
} else {
|
||||
debug(1, "Error making pipe.\n");
|
||||
}
|
||||
}
|
||||
_inform(filename, linenumber, "");
|
||||
_inform(filename, linenumber, ">> Display Config End.");
|
||||
}
|
||||
|
||||
#define display_config(argc, argv) _display_config(__FILE__, __LINE__, argc, argv)
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
memset(&config, 0, sizeof(config)); // also clears all strings, BTW
|
||||
/* Check if we are called with -V or --version parameter */
|
||||
@@ -1708,6 +1815,22 @@ int main(int argc, char **argv) {
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// this is a bit weird, but necessary -- basename() may modify the argument passed in
|
||||
char *basec = strdup(argv[0]);
|
||||
char *bname = basename(basec);
|
||||
config.appName = strdup(bname);
|
||||
if (config.appName == NULL)
|
||||
die("can not allocate memory for the app name!");
|
||||
free(basec);
|
||||
|
||||
strcpy(configuration_file_path, SYSCONFDIR);
|
||||
// strcat(configuration_file_path, "/shairport-sync"); // thinking about adding a special
|
||||
// shairport-sync directory
|
||||
strcat(configuration_file_path, "/");
|
||||
strcat(configuration_file_path, config.appName);
|
||||
strcat(configuration_file_path, ".conf");
|
||||
config.configfile = configuration_file_path;
|
||||
|
||||
#ifdef CONFIG_AIRPLAY_2
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 10, 0)
|
||||
avcodec_init();
|
||||
@@ -1734,16 +1857,8 @@ int main(int argc, char **argv) {
|
||||
pid = getpid();
|
||||
config.log_fd = -1;
|
||||
conns = NULL; // no connections active
|
||||
memset((void *)&main_thread_id, 0, sizeof(main_thread_id));
|
||||
ns_time_at_startup = get_absolute_time_in_ns();
|
||||
ns_time_at_last_debug_message = ns_time_at_startup;
|
||||
// this is a bit weird, but necessary -- basename() may modify the argument passed in
|
||||
char *basec = strdup(argv[0]);
|
||||
char *bname = basename(basec);
|
||||
config.appName = strdup(bname);
|
||||
if (config.appName == NULL)
|
||||
die("can not allocate memory for the app name!");
|
||||
free(basec);
|
||||
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
daemon_set_verbosity(LOG_DEBUG);
|
||||
@@ -1791,14 +1906,6 @@ int main(int argc, char **argv) {
|
||||
config.output_name = first_backend_name;
|
||||
}
|
||||
|
||||
strcpy(configuration_file_path, SYSCONFDIR);
|
||||
// strcat(configuration_file_path, "/shairport-sync"); // thinking about adding a special
|
||||
// shairport-sync directory
|
||||
strcat(configuration_file_path, "/");
|
||||
strcat(configuration_file_path, config.appName);
|
||||
strcat(configuration_file_path, ".conf");
|
||||
config.configfile = configuration_file_path;
|
||||
|
||||
// config.statistics_requested = 0; // don't print stats in the log
|
||||
// config.userSuppliedLatency = 0; // zero means none supplied
|
||||
|
||||
@@ -1880,6 +1987,14 @@ int main(int argc, char **argv) {
|
||||
config.service_name[50] = '\0'; // truncate it and carry on...
|
||||
}
|
||||
|
||||
if (display_config_selected != 0) {
|
||||
display_config(argc, argv);
|
||||
if (argc == 2) {
|
||||
inform(">> Goodbye!");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we are called with -k or --kill option */
|
||||
if (killOption != 0) {
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
@@ -1889,23 +2004,18 @@ int main(int argc, char **argv) {
|
||||
/* Check if the new function daemon_pid_file_kill_wait() is available, if it is, use it. */
|
||||
if ((ret = daemon_pid_file_kill_wait(SIGTERM, 5)) < 0) {
|
||||
if (errno == ENOENT)
|
||||
daemon_log(LOG_WARNING, "Failed to kill %s daemon: PID file not found.", config.appName);
|
||||
warn("Failed to kill the %s daemon. The PID file was not found.", config.appName);
|
||||
// daemon_log(LOG_WARNING, "Failed to kill %s daemon: PID file not found.", config.appName);
|
||||
else
|
||||
daemon_log(LOG_WARNING, "Failed to kill %s daemon: \"%s\", errno %u.", config.appName,
|
||||
strerror(errno), errno);
|
||||
} else {
|
||||
// debug(1,"Successfully killed the %s daemon.", config.appName);
|
||||
if (daemon_pid_file_remove() == 0)
|
||||
debug(2, "killed the %s daemon.", config.appName);
|
||||
else
|
||||
daemon_log(LOG_WARNING,
|
||||
"killed the %s daemon, but cannot remove old PID file: \"%s\", errno %u.",
|
||||
config.appName, strerror(errno), errno);
|
||||
warn("Failed to kill the %s daemon. Error: \"%s\", errno %u.", config.appName,
|
||||
strerror(errno), errno);
|
||||
// daemon_log(LOG_WARNING, "Failed to kill %s daemon: \"%s\", errno %u.", config.appName,
|
||||
// strerror(errno), errno);
|
||||
}
|
||||
return ret < 0 ? 1 : 0;
|
||||
#else
|
||||
fprintf(stderr, "%s was built without libdaemon, so does not support the -k or --kill option\n",
|
||||
config.appName);
|
||||
warn("%s was built without libdaemon, so it does not support the -k or --kill option.",
|
||||
config.appName);
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
@@ -1913,7 +2023,8 @@ int main(int argc, char **argv) {
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
/* If we are going to daemonise, check that the daemon is not running already.*/
|
||||
if ((config.daemonise) && ((pid = daemon_pid_file_is_running()) >= 0)) {
|
||||
daemon_log(LOG_ERR, "The %s daemon is already running as PID %u", config.appName, pid);
|
||||
warn("The %s deamon is already running with process ID (PID) %u.", config.appName, pid);
|
||||
// daemon_log(LOG_ERR, "The %s daemon is already running as PID %u", config.appName, pid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1922,8 +2033,7 @@ int main(int argc, char **argv) {
|
||||
if (config.daemonise) {
|
||||
/* Prepare for return value passing from the initialization procedure of the daemon process */
|
||||
if (daemon_retval_init() < 0) {
|
||||
daemon_log(LOG_ERR, "Failed to create pipe.");
|
||||
return 1;
|
||||
die("Failed to create pipe.");
|
||||
}
|
||||
|
||||
/* Do the fork */
|
||||
@@ -1938,43 +2048,38 @@ int main(int argc, char **argv) {
|
||||
|
||||
/* Wait for 20 seconds for the return value passed from the daemon process */
|
||||
if ((ret = daemon_retval_wait(20)) < 0) {
|
||||
daemon_log(LOG_ERR, "Could not receive return value from daemon process: %s",
|
||||
strerror(errno));
|
||||
return 255;
|
||||
die("Could not receive return value from daemon process: %s", strerror(errno));
|
||||
}
|
||||
|
||||
switch (ret) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
daemon_log(
|
||||
LOG_ERR,
|
||||
"the %s daemon failed to launch: could not close open file descriptors after forking.",
|
||||
config.appName);
|
||||
warn("The %s daemon failed to launch: could not close open file descriptors after forking.",
|
||||
config.appName);
|
||||
break;
|
||||
case 2:
|
||||
daemon_log(LOG_ERR, "the %s daemon failed to launch: could not create PID file.",
|
||||
config.appName);
|
||||
warn("The %s daemon failed to launch: could not create PID file.", config.appName);
|
||||
break;
|
||||
case 3:
|
||||
daemon_log(LOG_ERR,
|
||||
"the %s daemon failed to launch: could not create or access PID directory.",
|
||||
config.appName);
|
||||
warn("The %s daemon failed to launch: could not create or access PID directory.",
|
||||
config.appName);
|
||||
break;
|
||||
default:
|
||||
daemon_log(LOG_ERR, "the %s daemon failed to launch, error %i.", config.appName, ret);
|
||||
warn("The %s daemon failed to launch, error %i.", config.appName, ret);
|
||||
}
|
||||
return ret;
|
||||
} else { /* pid == 0 means we are the daemon */
|
||||
|
||||
this_is_the_daemon_process = 1; //
|
||||
this_is_the_daemon_process = 1;
|
||||
if (log_to_default != 0) // if a specific logging mode has not been selected
|
||||
log_to_syslog(); // automatically send logs to the daemon_log
|
||||
|
||||
/* Close FDs */
|
||||
if (daemon_close_all(-1) < 0) {
|
||||
daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));
|
||||
warn("Failed to close all file descriptors while daemonising. Error: %s", strerror(errno));
|
||||
/* Send the error condition to the parent process */
|
||||
daemon_retval_send(1);
|
||||
|
||||
daemon_signal_done();
|
||||
return 0;
|
||||
}
|
||||
@@ -1982,19 +2087,20 @@ int main(int argc, char **argv) {
|
||||
/* Create the PID file if required */
|
||||
if (config.daemonise_store_pid) {
|
||||
/* Create the PID directory if required -- we don't really care about the result */
|
||||
printf("PID directory is \"%s\".", config.computed_piddir);
|
||||
debug(1, "PID directory is \"%s\".", config.computed_piddir);
|
||||
int result = mkpath(config.computed_piddir, 0700);
|
||||
if ((result != 0) && (result != -EEXIST)) {
|
||||
// error creating or accessing the PID file directory
|
||||
warn("Failed to create the directory \"%s\" for the PID file. Error: %s.",
|
||||
config.computed_piddir, strerror(errno));
|
||||
daemon_retval_send(3);
|
||||
|
||||
daemon_signal_done();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (daemon_pid_file_create() < 0) {
|
||||
daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
|
||||
|
||||
// daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
|
||||
warn("Failed to create the PID file. Error: %s.", strerror(errno));
|
||||
daemon_retval_send(2);
|
||||
daemon_signal_done();
|
||||
return 0;
|
||||
@@ -2021,10 +2127,10 @@ int main(int argc, char **argv) {
|
||||
apfh = apfh >> 32;
|
||||
uint32_t apf32 = apf;
|
||||
uint32_t apfh32 = apfh;
|
||||
debug(1, "startup in AirPlay 2 mode, with features 0x%" PRIx32 ",0x%" PRIx32 " on device \"%s\".",
|
||||
debug(1, "Startup in AirPlay 2 mode, with features 0x%" PRIx32 ",0x%" PRIx32 " on device \"%s\".",
|
||||
apf32, apfh32, config.airplay_device_id);
|
||||
#else
|
||||
debug(1, "startup in classic Airplay (aka \"AirPlay 1\") mode.");
|
||||
debug(1, "Startup in classic Airplay (aka \"AirPlay 1\") mode.");
|
||||
#endif
|
||||
|
||||
// control-c (SIGINT) cleanly
|
||||
@@ -2053,10 +2159,6 @@ int main(int argc, char **argv) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
main_thread_id = pthread_self();
|
||||
if (!main_thread_id)
|
||||
debug(1, "Main thread is set up to be NULL!");
|
||||
|
||||
// make sure the program can create files that group and world can read
|
||||
umask(S_IWGRP | S_IWOTH);
|
||||
|
||||
@@ -2064,35 +2166,26 @@ int main(int argc, char **argv) {
|
||||
|
||||
char *version_dbs = get_version_string();
|
||||
if (version_dbs) {
|
||||
debug(1, "software version: \"%s\"", version_dbs);
|
||||
debug(1, "Version String: \"%s\"", version_dbs);
|
||||
free(version_dbs);
|
||||
} else {
|
||||
debug(1, "can't print the version information!");
|
||||
debug(1, "Can't print the version information!");
|
||||
}
|
||||
|
||||
debug(1, "log verbosity is %d.", debuglev);
|
||||
// print command line
|
||||
|
||||
config.output = audio_get_output(config.output_name);
|
||||
if (!config.output) {
|
||||
die("Invalid audio backend \"%s\" selected!",
|
||||
config.output_name == NULL ? "<unspecified>" : config.output_name);
|
||||
}
|
||||
config.output->init(argc - audio_arg, argv + audio_arg);
|
||||
|
||||
// pthread_cleanup_push(main_cleanup_handler, NULL);
|
||||
|
||||
// daemon_log(LOG_NOTICE, "startup");
|
||||
|
||||
switch (config.endianness) {
|
||||
case SS_LITTLE_ENDIAN:
|
||||
debug(2, "The processor is running little-endian.");
|
||||
break;
|
||||
case SS_BIG_ENDIAN:
|
||||
debug(2, "The processor is running big-endian.");
|
||||
break;
|
||||
case SS_PDP_ENDIAN:
|
||||
debug(2, "The processor is running pdp-endian.");
|
||||
break;
|
||||
if (argc != 0) {
|
||||
char result[1024];
|
||||
char *obfp = result;
|
||||
int i;
|
||||
for (i = 0; i < argc - 1; i++) {
|
||||
snprintf(obfp, strlen(argv[i]) + 2, "%s ", argv[i]);
|
||||
obfp += strlen(argv[i]) + 1;
|
||||
}
|
||||
snprintf(obfp, strlen(argv[i]) + 1, "%s", argv[i]);
|
||||
obfp += strlen(argv[i]);
|
||||
*obfp = 0;
|
||||
debug(1, "Command Line: \"%s\".", result);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AIRPLAY_2
|
||||
@@ -2124,8 +2217,35 @@ int main(int argc, char **argv) {
|
||||
/* Tell Libgcrypt that initialization has completed. */
|
||||
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
|
||||
|
||||
debug(1, "libgcrypt initialised.");
|
||||
|
||||
#endif
|
||||
|
||||
debug(1, "Log Verbosity is %d.", debuglev);
|
||||
|
||||
config.output = audio_get_output(config.output_name);
|
||||
if (!config.output) {
|
||||
die("Invalid audio backend \"%s\" selected!",
|
||||
config.output_name == NULL ? "<unspecified>" : config.output_name);
|
||||
}
|
||||
config.output->init(argc - audio_arg, argv + audio_arg);
|
||||
|
||||
// pthread_cleanup_push(main_cleanup_handler, NULL);
|
||||
|
||||
// daemon_log(LOG_NOTICE, "startup");
|
||||
|
||||
switch (config.endianness) {
|
||||
case SS_LITTLE_ENDIAN:
|
||||
debug(2, "The processor is running little-endian.");
|
||||
break;
|
||||
case SS_BIG_ENDIAN:
|
||||
debug(2, "The processor is running big-endian.");
|
||||
break;
|
||||
case SS_PDP_ENDIAN:
|
||||
debug(2, "The processor is running pdp-endian.");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Mess around with the latency options */
|
||||
// Basically, we expect the source to set the latency and add a fixed offset of 11025 frames to
|
||||
// it, which sounds right
|
||||
@@ -2149,7 +2269,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
/* Print out options */
|
||||
debug(1, "disable resend requests is %s.", config.disable_resend_requests ? "on" : "off");
|
||||
debug(1, "disable_resend_requests is %s.", config.disable_resend_requests ? "on" : "off");
|
||||
debug(1,
|
||||
"diagnostic_drop_packet_fraction is %f. A value of 0.0 means no packets will be dropped "
|
||||
"deliberately.",
|
||||
@@ -2178,9 +2298,8 @@ int main(int argc, char **argv) {
|
||||
debug(1, "mdns backend \"%s\".", strnull(config.mdns_name));
|
||||
debug(2, "userSuppliedLatency is %d.", config.userSuppliedLatency);
|
||||
debug(1, "interpolation setting is \"%s\".",
|
||||
config.packet_stuffing == ST_basic ? "basic"
|
||||
: config.packet_stuffing == ST_soxr ? "soxr"
|
||||
: "auto");
|
||||
config.packet_stuffing == ST_basic ? "basic"
|
||||
: config.packet_stuffing == ST_soxr ? "soxr" : "auto");
|
||||
debug(1, "interpolation soxr_delay_threshold is %d.", config.soxr_delay_threshold);
|
||||
debug(1, "resync time is %f seconds.", config.resyncthreshold);
|
||||
debug(1, "allow a session to be interrupted: %d.", config.allow_session_interruption);
|
||||
@@ -2265,6 +2384,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
#ifdef CONFIG_SOXR
|
||||
pthread_create(&soxr_time_check_thread, NULL, &soxr_time_check, NULL);
|
||||
soxr_time_check_thread_started = 1;
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user