--- /dev/null
+name: Bug Report
+description: File a bug report
+title: "[Bug]: "
+labels: ["bug"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for taking the time to fill out this bug report!
+ - type: textarea
+ id: what-happened
+ attributes:
+ label: What happened?
+ description: Also, what did you expect to happen?
+ validations:
+ required: true
+ - type: textarea
+ id: logs
+ attributes:
+ label: Relevant log output
+ description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
+ render: shell
+ - type: textarea
+ id: version
+ attributes:
+ label: Version?
+ description: What version of Shairport Sync are you running? (`shairport-sync -V`)
+ validations:
+ required: true
+ - type: checkboxes
+ id: checked-current-issues
+ attributes:
+ label: Check previous issues
+ description: Please check previous issues (including closed ones) for duplicates.
+ options:
+ - label: Confirm
+ required: true
\ No newline at end of file
--- /dev/null
+blank_issues_enabled: false
+contact_links:
+ - name: Questions?
+ url: https://github.com/mikebrady/shairport-sync/discussions/categories/q-a
+ about: Please ask and answer questions here.
+ - name: Feature Requests
+ url: https://github.com/mikebrady/shairport-sync/discussions/categories/ideas
+ about: Please submit feature requests/enhancements here.
\ No newline at end of file
--- /dev/null
+# Builds & pushes a docker image when a commit is made to one of the branches specified below.
+# Tag pattern: 'unstable-[BRANCH NAME]'.
+
+name: Build and push docker image based on commit to specified branches.
+
+on:
+ push:
+ branches: [ master ]
+
+env:
+ DOCKER_PLATFORMS: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64
+
+jobs:
+ main:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+
+ - name: Set SHAIRPORT_SYNC_BRANCH env.
+ run: echo "SHAIRPORT_SYNC_BRANCH=${GITHUB_REF##*/}" >> $GITHUB_ENV
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v1
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v1
+
+ - name: Login to Docker Registry
+ uses: docker/login-action@v1
+ with:
+ registry: ${{ secrets.DOCKER_REGISTRY }}
+ username: ${{ secrets.DOCKER_REGISTRY_USER }}
+ password: ${{ secrets.DOCKER_REGISTRY_TOKEN }}
+
+ - name: Build and push
+ uses: docker/build-push-action@v2
+ with:
+ context: ./
+ file: ./docker/airplay1/Dockerfile
+ platforms: ${{ env.DOCKER_PLATFORMS }}
+ push: true
+ tags: ${{ secrets.DOCKER_IMAGE_NAME }}:unstable-${{ env.SHAIRPORT_SYNC_BRANCH }}
+ build-args: |
+ SHAIRPORT_SYNC_BRANCH=${{ env.SHAIRPORT_SYNC_BRANCH }}
\ No newline at end of file
--- /dev/null
+# Builds & pushes a docker image when a tag occurs.
+# It seems this yaml has to exist on the branch the tag refers to.
+
+# The following tags are created & pushed:
+# [RELEASE TAG] and latest
+
+name: Build and push docker images on releases.
+
+on:
+ push:
+ tags:
+ - '*' # Push events to every tag (not containing '/')
+
+env:
+ DOCKER_PLATFORMS: linux/386,linux/amd64,linux/arm/v6,linux/arm64,linux/arm/v7
+
+jobs:
+ main:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+
+ - name: Set SHAIRPORT_SYNC_BRANCH env.
+ run: |
+ raw=$(git branch -r --contains ${{ github.ref }})
+ branch=${raw##*/}
+ echo "SHAIRPORT_SYNC_BRANCH=${branch}" >> $GITHUB_ENV
+
+ - name: Set tag env
+ run: echo "GIT_TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v1
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v1
+
+ - name: Login to Docker Registry
+ uses: docker/login-action@v1
+ with:
+ registry: ${{ secrets.DOCKER_REGISTRY }}
+ username: ${{ secrets.DOCKER_REGISTRY_USER }}
+ password: ${{ secrets.DOCKER_REGISTRY_TOKEN }}
+
+ - name: Build and push
+ uses: docker/build-push-action@v2
+ with:
+ context: ./
+ file: ./docker/airplay1/Dockerfile
+ platforms: ${{ env.DOCKER_PLATFORMS }}
+ push: true
+ tags: ${{ secrets.DOCKER_IMAGE_NAME }}:latest, ${{ secrets.DOCKER_IMAGE_NAME }}:${{ env.GIT_TAG }}
+ build-args: |
+ SHAIRPORT_SYNC_BRANCH=${{ env.SHAIRPORT_SYNC_BRANCH }}
\ No newline at end of file
aclocal.m4
autom4te.cache
compile
-config.*
+/config.*
configure
depcomp
install-sh
```
By the way, the `autoreconf` step may take quite a while on a Raspberry Pi -- be patient!
-Now to configure Shairport Sync. Here are the important options for the Shairport Sync configuration file at `/etc/shairport-sync.conf`:
+### Configure
+If you don't set any configuration parameters, Shairport Sync will use the default `alsa` output device.
+
+If you wish to configure Shairport Sync to use a specific output device (recommended), an experimental tool called [sps-alsa-explore](https://github.com/mikebrady/sps-alsa-explore) is available to search for all `alsa` hardware output devices that can be used by Shairport Sync. Here is the tool's output for a Raspberry Pi 4 running Buster:
+
+```
+> Device: "hw:Headphones"
+ Short Name: "hw:0"
+ This device seems suitable for use with Shairport Sync.
+ Possible mixers: "Headphone"
+ Suggested rate and format:
+ Rate Format
+ 44100 S16_LE
+
+> Device: "hw:vc4hdmi0"
+ Short Name: "hw:2"
+ This device can not be accessed and so can not be checked.
+ (Does it need to be configured or connected?)
+
+> Device: "hw:vc4hdmi1"
+ Short Name: "hw:3"
+ This device can not be accessed and so can not be checked.
+ (Does it need to be configured or connected?)
+
+```
+
+To use the "Headphones" device, here are the options for the Shairport Sync configuration file at `/etc/shairport-sync.conf`:
```
// Sample Configuration File for Shairport Sync on a Raspberry Pi using the built-in audio DAC
general =
alsa =
{
- output_device = "hw:0";
- mixer_control_name = "PCM";
+ output_device = "hw:Headphones";
+ mixer_control_name = "Headphone";
};
```
The `volume_range_db = 60;` setting makes Shairport Sync use only the usable part of the built-in audio card mixer's attenuation range.
+(BTW, Shairport Sync will choose the suggested speed and format automatically.)
+
The next step is to enable Shairport Sync to start automatically on boot up:
```
# systemctl enable shairport-sync
**Cygwin:** Please see the guide at [CYGWIN.md](https://github.com/mikebrady/shairport-sync/blob/master/CYGWIN.md).
+**OpenBSD:** A port exists for Shairport Sync. Packages are available for users of -current OpenBSD, the first release to include this port will be OpenBSD 7.2. To install, simply run
+
+```
+pkg_add shairport_sync
+```
+Configure your system to start the service at boot time with
+```
+rcctl enable messagebus avahi_daemon shairport_sync
+```
+
+Note that the README for this port includes instructions on how to share access to the audio device between Shairport Sync and another user.
+
Sincere thanks to all package contributors!
If you wish to build and install the latest version of Shairport Sync on Debian, Ubuntu, Fedora or Arch platforms, please continue to follow these instructions. When the program has been compiled and installed, refer to the section on Configuring Shairport Sync that follows. To build Shairport Sync from sources on FreeBSD please refer to [FREEBSD.md](https://github.com/mikebrady/shairport-sync/blob/master/FREEBSD.md).
- `--with-stdout` include an optional backend module to enable raw audio to be output through standard output (stdout).
- `--with-pipe` include an optional backend module to enable raw audio to be output through a unix pipe.
- `--with-soundio` include an optional backend module to enable raw audio to be output through the soundio system.
-- `--with-avahi` or `--with-tinysvcmdns` for mdns support. Avahi is a widely-used system-wide zero-configuration networking (zeroconf) service — it may already be in your system. If you don't have Avahi, or similar, then consider including tinysvcmdns, which is a tiny zeroconf service embedded inside the shairport-sync application itself. To enable multicast for `tinysvcmdns`, you may have to add a default route with the following command: `route add -net 224.0.0.0 netmask 224.0.0.0 eth0` (substitute the correct network port for `eth0`). You should not have more than one zeroconf service on the same system — bad things may happen, according to RFC 6762, §15.
+- `--with-avahi` or `--with-tinysvcmdns` for mdns support. Avahi is a widely-used system-wide zero-configuration networking (zeroconf) service — it may already be in your system. If you don't have Avahi, or similar, then consider including tinysvcmdns, which is a tiny zeroconf service embedded inside the shairport-sync application itself. To enable multicast for `tinysvcmdns`, you may have to add a default route with the following command: `route add -net 224.0.0.0 netmask 224.0.0.0 eth0` (substitute the correct network port for `eth0`). You should not have more than one zeroconf service on the same system — bad things may happen, according to RFC 6762, §15. If you need to use an external zeroconf service (`--with-external-mdns`) to avoid this problem, you may need to install avahi-utils or avahi-tools to get the `avahi-publish-service` tool for your system.
- `--with-ssl=openssl`, `--with-ssl=mbedtls` or `--with-ssl=polarssl` (deprecated) for encryption and related utilities using either OpenSSL, mbed TLS or PolarSSL.
- `--with-libdaemon` include a demonising library needed if you want to be able to demonise Shairport Sync with the `-d` option. Not needed for `systemd`-based systems which demonise programs differently.
- `--with-soxr` for libsoxr-based resampling.
2. If you have set `interpolation` in the `general` section of the configuration file to to `soxr`, comment it out or set it to `auto` or `basic` as the `soxr` setting can cause lower-powered devices to bog down at critical times, e.g. see [this report](https://github.com/mikebrady/shairport-sync/issues/631#issuecomment-366305203).
3. Ensure the volume setting of your output device is set to some reasonable value and ensure it is not muted. For ALSA devices, the `alsamixer` command-line tool is very good for this. For other sound systems, please consult the relevant documentation.
+### 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.
+
### WiFi adapter running in power-saving / low-power mode
**Check Throughput**
debug(1, "Failed to load mixer element");
response = -4;
} else {
- debug(3, "Mixer Control name is \"%s\".", alsa_mix_ctrl);
+ debug(3, "Mixer control is \"%s\",%d.", alsa_mix_ctrl, alsa_mix_index);
alsa_mix_elem = snd_mixer_find_selem(alsa_mix_handle, alsa_mix_sid);
if (!alsa_mix_elem) {
- warn("failed to find mixer control \"%s\".", alsa_mix_ctrl);
+ warn("failed to find mixer control \"%s\",%d.", alsa_mix_ctrl, alsa_mix_index);
response = -5;
} else {
response = 1; // we found a hardware mixer and successfully opened it
alsa_mix_ctrl = (char *)str;
}
+
+ // Get the Mixer Control Index
+ if (config_lookup_int(config.cfg, "alsa.mixer_control_index", &value)) {
+ alsa_mix_index = value;
+ }
+
+
+
+
+
/* Get the disable_synchronization setting. */
if (config_lookup_string(config.cfg, "alsa.disable_synchronization", &str)) {
if (strcasecmp(str, "no") == 0)
--- /dev/null
+# Shairport Sync Docker Image
+
+Available at: https://hub.docker.com/r/mikebrady/shairport-sync
+
+## Original AirPlay 1 Image
+Please see: [airplay1/README.md](airplay1/README.md)
+
+## GitHub Action Builds
+Requires the following secrets to be set in the repo:
+- `DOCKER_REGISTRY` - docker.io if using Docker Hub, else set to your registry URL.
+- `DOCKER_REGISTRY_TOKEN` - Access token for your registry.
+- `DOCKER_REGISTRY_USER` - Login user for your registry.
+- `DOCKER_IMAGE_NAME` - The name of the image, for example `your-registry.com/shairport-sync` or just `your-username/shairport-sync` if using Docker Hub.
\ No newline at end of file
--- /dev/null
+FROM alpine:3.12 AS builder-base
+# General Build System:
+RUN apk -U add \
+ git \
+ build-base \
+ autoconf \
+ automake \
+ libtool \
+ dbus \
+ su-exec \
+ alsa-lib-dev \
+ libdaemon-dev \
+ popt-dev \
+ mbedtls-dev \
+ soxr-dev \
+ avahi-dev \
+ libconfig-dev \
+ libsndfile-dev \
+ mosquitto-dev \
+ xmltoman
+
+# ALAC Build System:
+FROM builder-base AS builder-alac
+
+RUN git clone https://github.com/mikebrady/alac
+WORKDIR alac
+RUN autoreconf -fi
+RUN ./configure
+RUN make
+RUN make install
+
+# Shairport Sync Build System:
+FROM builder-base AS builder-sps
+
+# This will be modified by the Github Action Workflow and is required
+# to ensure the correct branch is being used.
+ARG SHAIRPORT_SYNC_BRANCH
+RUN test -n "$SHAIRPORT_SYNC_BRANCH"
+
+COPY --from=builder-alac /usr/local/lib/libalac.* /usr/local/lib/
+COPY --from=builder-alac /usr/local/lib/pkgconfig/alac.pc /usr/local/lib/pkgconfig/alac.pc
+COPY --from=builder-alac /usr/local/include /usr/local/include
+
+WORKDIR shairport-sync
+COPY . .
+RUN git checkout "$SHAIRPORT_SYNC_BRANCH"
+RUN autoreconf -fi
+RUN ./configure \
+ --with-alsa \
+ --with-dummy \
+ --with-pipe \
+ --with-stdout \
+ --with-avahi \
+ --with-ssl=mbedtls \
+ --with-soxr \
+ --sysconfdir=/etc \
+ --with-dbus-interface \
+ --with-mpris-interface \
+ --with-mqtt-client \
+ --with-apple-alac \
+ --with-convolution
+RUN make -j $(nproc)
+RUN make install
+
+# Shairport Sync Runtime System:
+FROM alpine:3.12
+
+RUN apk -U add \
+ alsa-lib \
+ dbus \
+ popt \
+ glib \
+ mbedtls \
+ soxr \
+ avahi \
+ libconfig \
+ libsndfile \
+ mosquitto-libs \
+ su-exec \
+ libgcc \
+ libgc++
+
+RUN rm -rf /lib/apk/db/*
+
+COPY --from=builder-alac /usr/local/lib/libalac.* /usr/local/lib/
+COPY --from=builder-sps /etc/shairport-sync* /etc/
+COPY --from=builder-sps /etc/dbus-1/system.d/shairport-sync-dbus.conf /etc/dbus-1/system.d/
+COPY --from=builder-sps /etc/dbus-1/system.d/shairport-sync-mpris.conf /etc/dbus-1/system.d/
+COPY --from=builder-sps /usr/local/bin/shairport-sync /usr/local/bin/shairport-sync
+
+# Create non-root user for running the container -- running as the user 'shairport-sync' also allows
+# Shairport Sync to provide the D-Bus and MPRIS interfaces within the container
+
+RUN addgroup shairport-sync
+RUN adduser -D shairport-sync -G shairport-sync
+
+# Add the shairport-sync user to the pre-existing audio group, which has ID 29, for access to the ALSA stuff
+RUN addgroup -g 29 docker_audio && addgroup shairport-sync docker_audio
+
+COPY ./docker/airplay1/start.sh /
+RUN chmod +x /start.sh
+
+ENTRYPOINT [ "/start.sh" ]
--- /dev/null
+# Original AirPlay 1 Only Docker Image
+
+## Basic Usage
+
+```
+$ docker run -d --restart unless-stopped --net host --device /dev/snd \
+ mikebrady/shairport-sync
+```
+The above command will run Shairport Sync as a daemon in a Docker container, accessing the computer's ALSA audio infrastructure. It will send audio to the default output device and make no use of any hardware mixers the default device might have. The AirPlay service name will be the host's `hostname` with the first letter capitalised, e.g. `Ubuntu`.
+
+## Options
+
+Any options you add to the command above will be passed to Shairport Sync. Here is an example:
+```
+$ docker run -d --restart unless-stopped --net host --device /dev/snd \
+ mikebrady/shairport-sync -a DenSystem -- -d hw:0 -c PCM
+```
+This will sent audio to alsa hardware device `hw:0` and make use of the that device's mixer control called `PCM`. The service will be visible as `DenSystem` on the network.
+
+## Configuration File
+
+Edit the configuration file `/etc/shairport-sync.conf` in the container (or use the `-v` option to mirror an external copy of `shairport-sync.conf` in to `/etc/shairport-sync.conf`) to get access to the full range of configuration options.
\ No newline at end of file
--- /dev/null
+#!/bin/sh
+
+set -e
+
+rm -rf /var/run/dbus.pid
+#mkdir -p /var/run/dbus
+
+dbus-uuidgen --ensure
+dbus-daemon --system
+
+avahi-daemon --daemonize --no-chroot
+
+su-exec shairport-sync shairport-sync "$@"
\ No newline at end of file
--- /dev/null
+# Example docker compose config.
+
+services:
+ shairport-sync:
+ image: mikebrady/shairport-sync
+ network_mode: host
+ restart: unless-stopped
+ devices:
+ - "/dev/snd"
+ # volumes:
+ # - ./volumes/shairport-sync/shairport-sync.conf:/etc/shairport-sync.conf # Customised Shairport Sync configuration file.
+ logging:
+ options:
+ max-size: "200k"
+ max-file: "10"
\ No newline at end of file
alsa =
{
// output_device = "default"; // the name of the alsa output device. Use "shairport-sync -h" to discover the names of ALSA hardware devices. Use "alsamixer" or "aplay" to find out the names of devices, mixers, etc.
-// mixer_control_name = "PCM"; // the name of the mixer to use to adjust output volume. If not specified, volume in adjusted in software.
+// mixer_control_name = "PCM"; // the name of the mixer to use to adjust output volume. No default. If not specified, no mixer is used and volume in adjusted in software.
+// mixer_control_index = 0; // the index of the mixer to use to adjust output volume. Default is 0. The mixer is fully identified by the combination of the mixer_control_name and the mixer_control_index, e.g. "PCM",0 would be such a specification.
// mixer_device = "default"; // the mixer_device default is whatever the output_device is. Normally you wouldn't have to use this.
// output_rate = "auto"; // can be "auto", 44100, 88200, 176400 or 352800, but the device must have the capability.