pax_global_header00006660000000000000000000000064152025557440014523gustar00rootroot0000000000000052 comment=efd93c5a54c8ee06a2e186c90ee618d7e9e24b2a shairport-sync-5.1-dev/000077500000000000000000000000001520255574400151315ustar00rootroot00000000000000shairport-sync-5.1-dev/.dockerignore000066400000000000000000000000751520255574400176070ustar00rootroot00000000000000.github documents docker/Dockerfile docker/classic/Dockerfileshairport-sync-5.1-dev/.github/000077500000000000000000000000001520255574400164715ustar00rootroot00000000000000shairport-sync-5.1-dev/.github/FUNDING.yml000066400000000000000000000000531520255574400203040ustar00rootroot00000000000000github: mikebrady custom: [paypal.me/UMBr] shairport-sync-5.1-dev/.github/ISSUE_TEMPLATE/000077500000000000000000000000001520255574400206545ustar00rootroot00000000000000shairport-sync-5.1-dev/.github/ISSUE_TEMPLATE/Bug Report.yaml000066400000000000000000000046111520255574400235130ustar00rootroot00000000000000name: Issue Report description: Questions about installing or configuring Shairport Sync? Please check through Issues (including closed issues) or create a new Issue here. title: "[Problem]: " labels: ["new issue"] body: - type: markdown attributes: value: | Thanks for taking the time to fill out this 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: system attributes: label: System Information. description: Please give some information about the system hardware -- make and model would be useful, e.g. Raspberry Pi 4 (4 GB). Also, the make and model of the output DAC, if known. validations: required: true - type: textarea id: version attributes: label: Configuration Information. description: Please paste the results of `shairport-sync --displayConfig` here, if available. This gives useful information about the environment Shairport Sync is running in and also displays the command line options and configuration settings. If `shairport-sync --displayConfig` is not available, please paste the results of two commands `uname -a` and `shairport-sync -V`. render: shell validations: required: true - type: checkboxes id: check-papw attributes: label: PulseAudio or PipeWire installed? description: Does your system use a sound server like PulseAudio or PipeWire? (If it has a GUI, it probably does...) options: - label: Check if your system uses a Sound Server. - type: dropdown id: install attributes: label: How did you install Shairport Sync? options: - Homebrew for Mac - Docker - A package manager (apt, apt install, yum, pkg, etc.) - Built from source 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 shairport-sync-5.1-dev/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000010401520255574400226370ustar00rootroot00000000000000blank_issues_enabled: false contact_links: - name: Questions? url: https://github.com/mikebrady/shairport-sync/discussions/categories/q-a about: If you have questions about installing or configuring Shairport Sync, please check through Issues (including closed issues) or raise a new Issue. Got more general questions? If so, 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. shairport-sync-5.1-dev/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000034161520255574400222760ustar00rootroot00000000000000## Pull Requests Thanks for helping to improve Shairport Sync. This template is an effort to make a Pull Request as trouble-free and useful as possible. ## ⚠️ Important: Target Branch **Please ensure your pull request targets the `development` branch, not `master`.** Contributions should be submitted against the `development` branch for review and testing before they are merged into the main release branch. --- ## Description Please provide a brief description of your changes: ## Type of Change Please delete options that are not relevant: - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [ ] Build/CI configuration change ## Related Issue If this PR addresses an existing issue, please link it here: Fixes #(issue number) ## Testing Please describe the tests you ran to verify your changes: - [ ] Tested on Linux - [ ] Tested on FreeBSD - [ ] Tested on OpenBSD - [ ] Tested with AirPlay 2 - [ ] Tested with classic AirPlay **Test Configuration:** * Hardware/Platform: * OS Version: * Build flags used: ## Checklist - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation (if applicable) - [ ] My changes generate no new warnings - [ ] I have tested my changes and verified they work as expected - [ ] I have checked that my PR targets the `development` branch ## Additional Notes Any additional information, context, or screenshots that would help reviewers understand your changes: shairport-sync-5.1-dev/.github/dependabot.yml000066400000000000000000000003101520255574400213130ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: github-actions directory: "/" schedule: interval: weekly day: sunday time: "10:00" open-pull-requests-limit: 10 target-branch: development shairport-sync-5.1-dev/.github/workflows/000077500000000000000000000000001520255574400205265ustar00rootroot00000000000000shairport-sync-5.1-dev/.github/workflows/check_ap2_systemd_basic.yml000066400000000000000000000021631520255574400260030ustar00rootroot00000000000000name: systemd, alsa, pipewire, build folder. on: workflow_dispatch: push: branches: [ "development" ] pull_request: types: [opened, synchronize, reopened, ready_for_review] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6.0.2 - name: Install Dependencies run: sudo apt-get -y --no-install-recommends install libpipewire-0.3-dev libplist-utils xmltoman libpopt-dev libconfig-dev libasound2-dev avahi-daemon libavahi-client-dev libsoxr-dev libplist-dev libsodium-dev libavutil-dev libavcodec-dev libavformat-dev libgcrypt-dev uuid-dev - name: Configure run: | mkdir build cd build autoreconf -i .. ../configure --sysconfdir=/etc --with-alsa --with-soxr --with-avahi --with-ssl=openssl --with-systemd-startup --with-airplay-2 --with-pipewire - name: Make run: | cd build make -j - name: Install run: | cd build sudo make install - name: Invoke run: | sudo systemctl start shairport-sync - name: Terminate run: | sudo systemctl stop shairport-sync shairport-sync-5.1-dev/.github/workflows/check_ap2_systemd_full.yml000066400000000000000000000022711520255574400256640ustar00rootroot00000000000000name: systemd, alsa, ao, dummy, jack, pipe, stdout on: workflow_dispatch: push: branches: [ "development" ] pull_request: types: [opened, synchronize, reopened, ready_for_review] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6.0.2 - name: Install Dependencies run: sudo apt-get -y --no-install-recommends install libglib2.0-dev libplist-utils xmltoman libpopt-dev libconfig-dev libasound2-dev libao-dev libjack-dev libmosquitto-dev avahi-daemon libavahi-client-dev libsoxr-dev libplist-dev libsodium-dev libavutil-dev libavcodec-dev libavformat-dev libgcrypt-dev - name: Configure run: | autoreconf -fi ./configure --sysconfdir=/etc --with-alsa --with-ao --with-dummy --with-jack --with-pipe --with-stdout --with-soxr --with-avahi --with-ssl=openssl --with-systemd-startup --with-dbus-interface --with-mpris-interface --with-mqtt-client --with-airplay-2 - name: Make run: | make -j - name: Install run: | sudo make install - name: Invoke run: | sudo systemctl start shairport-sync - name: Terminate run: | sudo systemctl stop shairport-sync shairport-sync-5.1-dev/.github/workflows/check_ap2_systemd_full_build_folder.yml000066400000000000000000000025161520255574400304000ustar00rootroot00000000000000name: systemd, alsa, pipewire, ao, dummy, jack, pipe, stdout,using a build folder. on: workflow_dispatch: push: branches: [ "development" ] pull_request: types: [opened, synchronize, reopened, ready_for_review] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6.0.2 - name: Install Dependencies run: sudo apt-get -y --no-install-recommends install libpipewire-0.3-dev libplist-utils xmltoman libpopt-dev libconfig-dev libasound2-dev libao-dev libjack-dev libglib2.0-dev libmosquitto-dev avahi-daemon libavahi-client-dev libssl-dev libsoxr-dev libplist-dev libsodium-dev libavutil-dev libavcodec-dev libavformat-dev libgcrypt-dev - name: Configure run: | mkdir build cd build autoreconf -i .. ../configure --sysconfdir=/etc --with-alsa --with-pipewire --with-ao --with-dummy --with-jack --with-pipe --with-stdout --with-soxr --with-avahi --with-ssl=openssl --with-systemd-startup --with-dbus-interface --with-mpris-interface --with-mqtt-client --with-airplay-2 - name: Make run: | cd build make -j - name: Install run: | cd build sudo make install - name: Invoke run: | sudo systemctl start shairport-sync - name: Terminate run: | sudo systemctl stop shairport-sync shairport-sync-5.1-dev/.github/workflows/check_ap2_systemv_full.yml000066400000000000000000000024611520255574400257070ustar00rootroot00000000000000name: systemv, alsa, pipewire, ao, dummy, jack, pipe, stdout on: workflow_dispatch: push: branches: [ "development" ] pull_request: types: [opened, synchronize, reopened, ready_for_review] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6.0.2 - name: Install Dependencies run: sudo apt-get -y --no-install-recommends install libpipewire-0.3-dev libplist-utils xmltoman libpopt-dev libdaemon-dev libconfig-dev libasound2-dev libao-dev libjack-dev libglib2.0-dev libmosquitto-dev avahi-daemon libavahi-client-dev libssl-dev libsoxr-dev libplist-dev libsodium-dev libavutil-dev libavcodec-dev libavformat-dev uuid-dev libgcrypt-dev - name: Configure run: | autoreconf -i ./configure --sysconfdir=/etc --with-alsa --with-pipewire --with-ao --with-dummy --with-libdaemon --with-jack --with-pipe --with-stdout --with-soxr --with-avahi --with-ssl=openssl --with-systemv-startup --with-dbus-interface --with-mpris-interface --with-mqtt-client --with-airplay-2 - name: Make run: | make -j - name: Install run: | sudo make install - name: Invoke run: | sudo /etc/init.d/shairport-sync start sleep 2 - name: Terminate run: | sudo /etc/init.d/shairport-sync stop shairport-sync-5.1-dev/.github/workflows/check_classic_mac_basic.yml000066400000000000000000000012471520255574400260140ustar00rootroot00000000000000name: macos classic, libao, BREW -- classic only, because macOS can't host NQPTP. on: workflow_dispatch: push: branches: [ "development" ] pull_request: types: [opened, synchronize, reopened, ready_for_review] jobs: build: runs-on: macos-latest steps: - uses: actions/checkout@v6.0.2 - name: Install Dependencies run: | brew install automake brew install popt brew install libconfig brew install libao - name: Configure run: | autoreconf -fi ./configure --with-os=darwin --with-ao --with-stdout --with-dns_sd --with-ssl=openssl - name: Make run: | make shairport-sync-5.1-dev/.github/workflows/check_classic_systemd_basic.yml000066400000000000000000000017501520255574400267430ustar00rootroot00000000000000name: systemd classic, alsa, using a build folder. on: workflow_dispatch: push: branches: [ "development" ] pull_request: types: [opened, synchronize, reopened, ready_for_review] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6.0.2 - name: Install Dependencies run: sudo apt-get -y --no-install-recommends install xmltoman libpopt-dev libconfig-dev libasound2-dev avahi-daemon libavahi-client-dev libssl-dev libsoxr-dev - name: Configure run: | mkdir build cd build autoreconf -i .. ../configure --sysconfdir=/etc --with-alsa --with-soxr --with-avahi --with-ssl=openssl --with-systemd-startup - name: Make run: | cd build make -j - name: Install run: | cd build sudo make install - name: Invoke run: | sudo systemctl start shairport-sync - name: Terminate run: | sudo systemctl stop shairport-sync shairport-sync-5.1-dev/.github/workflows/check_classic_systemd_full.yml000066400000000000000000000023611520255574400266230ustar00rootroot00000000000000name: systemd classic, ffmpeg, alsa, pipewire, build folder. on: workflow_dispatch: push: branches: [ "development" ] pull_request: types: [opened, synchronize, reopened, ready_for_review] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6.0.2 - name: Install Dependencies run: sudo apt-get -y --no-install-recommends install xmltoman libpipewire-0.3-dev libpopt-dev libconfig-dev libasound2-dev libao-dev libjack-dev libglib2.0-dev libmosquitto-dev avahi-daemon libavahi-client-dev libssl-dev libsoxr-dev libavutil-dev libavcodec-dev libavformat-dev - name: Configure run: | mkdir build cd build autoreconf -i .. ../configure --sysconfdir=/etc --with-ffmpeg --with-alsa --with-pipewire --with-ao --with-dummy --with-pipe --with-stdout --with-soxr --with-avahi --with-ssl=openssl --with-dbus-interface --with-mpris-interface --with-mqtt-client --with-systemd-startup - name: Make run: | cd build make -j - name: Install run: | cd build sudo make install - name: Invoke run: | sudo systemctl start shairport-sync - name: Terminate run: | sudo systemctl stop shairport-sync shairport-sync-5.1-dev/.github/workflows/docker-on-push-tag-or-pr.yaml000066400000000000000000000121111520255574400260520ustar00rootroot00000000000000# Builds and pushes a docker image in the following scenarios: # When a commit is made to 'master' or 'development'. # Tag pattern # 'master' branch - rolling, rolling-classic (for commits) # - [tag], [tag]-classic, latest, classic (for tags) # 'development' branch - development, development-classic (for all pushes including tags) # Builds but does not push a docker image for PRs. name: Build and conditionally push docker image on: workflow_dispatch: push: branches: - master - development tags: - "*" pull_request: types: [opened, synchronize, reopened, ready_for_review] jobs: docker-vars: uses: ./.github/workflows/docker-vars.yaml build-docker-image-and-publish: name: Build and conditionally push docker image needs: - docker-vars runs-on: ubuntu-22.04 strategy: matrix: include: - name: classic dockerfile: ./docker/classic/Dockerfile build_args: | SHAIRPORT_SYNC_BRANCH=. - name: main dockerfile: ./docker/Dockerfile build_args: | SHAIRPORT_SYNC_BRANCH=. NQPTP_BRANCH=${{ needs.docker-vars.outputs.nqptp_branch }} steps: - name: Checkout shairport sync repo uses: actions/checkout@v6.0.2 with: fetch-depth: 0 - name: Determine which branch the tag belongs to id: determine_branch if: github.ref_type == 'tag' run: | # Check which branch contains this tag if git branch -r --contains ${{ github.sha }} | grep -q 'origin/master'; then echo "branch=master" >> $GITHUB_OUTPUT echo "Tag ${{ github.ref_name }} is on master branch" elif git branch -r --contains ${{ github.sha }} | grep -q 'origin/development'; then echo "branch=development" >> $GITHUB_OUTPUT echo "Tag ${{ github.ref_name }} is on development branch" else echo "branch=unknown" >> $GITHUB_OUTPUT echo "Warning: Tag ${{ github.ref_name }} is not on master or development branch" fi - name: Login to Docker Registry uses: docker/login-action@v4.1.0 with: registry: ${{ secrets.DOCKER_REGISTRY }} username: ${{ secrets.DOCKER_REGISTRY_USER }} password: ${{ secrets.DOCKER_REGISTRY_TOKEN }} if: needs.docker-vars.outputs.push_docker_image == 'true' - name: Set up QEMU uses: docker/setup-qemu-action@v4.0.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4.0.0 - name: Build and push ${{ matrix.name }} uses: docker/build-push-action@v7.1.0 env: registry_and_name: ${{ secrets.DOCKER_REGISTRY }}/${{ secrets.DOCKER_IMAGE_NAME }} with: context: ./ file: ${{ matrix.dockerfile }} platforms: ${{ needs.docker-vars.outputs.docker_platforms }} push: ${{ needs.docker-vars.outputs.push_docker_image == 'true' }} # Assign tags based on branch or tag type for clarity tags: | ${{ github.ref_type == 'branch' && github.ref_name == 'development' && matrix.name == 'main' && format('{0}:development', env.registry_and_name) || '' }} ${{ github.ref_type == 'branch' && github.ref_name == 'development' && matrix.name == 'classic' && format('{0}:development-classic', env.registry_and_name) || '' }} ${{ github.ref_type == 'tag' && steps.determine_branch.outputs.branch == 'development' && matrix.name == 'main' && format('{0}:development', env.registry_and_name) || '' }} ${{ github.ref_type == 'tag' && steps.determine_branch.outputs.branch == 'development' && matrix.name == 'classic' && format('{0}:development-classic', env.registry_and_name) || '' }} ${{ github.ref_type == 'branch' && github.ref_name == 'master' && matrix.name == 'main' && format('{0}:rolling', env.registry_and_name) || '' }} ${{ github.ref_type == 'branch' && github.ref_name == 'master' && matrix.name == 'classic' && format('{0}:rolling-classic', env.registry_and_name) || '' }} ${{ github.ref_type == 'tag' && steps.determine_branch.outputs.branch == 'master' && matrix.name == 'main' && format('{0}:{1}', env.registry_and_name, github.ref_name) || '' }} ${{ github.ref_type == 'tag' && steps.determine_branch.outputs.branch == 'master' && matrix.name == 'classic' && format('{0}:{1}-classic', env.registry_and_name, github.ref_name) || '' }} ${{ github.ref_type == 'tag' && steps.determine_branch.outputs.branch == 'master' && matrix.name == 'main' && format('{0}:latest', env.registry_and_name) || '' }} ${{ github.ref_type == 'tag' && steps.determine_branch.outputs.branch == 'master' && matrix.name == 'classic' && format('{0}:classic', env.registry_and_name) || '' }} build-args: | ${{ matrix.build_args }} shairport-sync-5.1-dev/.github/workflows/docker-vars.yaml000066400000000000000000000031021520255574400236260ustar00rootroot00000000000000name: Set variables for a Docker build (used by another workflow). on: workflow_call: outputs: docker_platforms: description: "The docker platforms to build for." value: ${{ jobs.docker-vars.outputs.docker_platforms }} nqptp_branch: description: "The NQPTP branch." value: ${{ jobs.docker-vars.outputs.nqptp_branch }} push_docker_image: description: "Whether to push the docker image." value: ${{ jobs.docker-vars.outputs.push_docker_image }} jobs: docker-vars: name: Set variables required for docker build. runs-on: ubuntu-22.04 env: NQPTP_BRANCH: main PUSH_DOCKER_IMAGE: "false" outputs: nqptp_branch: ${{ env.NQPTP_BRANCH }} push_docker_image: ${{ env.PUSH_DOCKER_IMAGE }} docker_platforms: linux/386,linux/amd64,linux/arm/v7,linux/arm64 steps: - name: Push docker image if this is a tag. if: github.ref_type == 'tag' run: | echo "PUSH_DOCKER_IMAGE=true" >> "$GITHUB_ENV" - name: Push docker image if this is the "master" or "development" branch. if: | github.ref_type == 'branch' && ( github.ref_name == 'master' || github.ref_name == 'development' ) run: | echo "PUSH_DOCKER_IMAGE=true" >> "$GITHUB_ENV" - name: If 'development' branch, set NQPTP_BRANCH to 'development'. if: | github.ref_type == 'branch' && github.ref_name == 'development' run: | echo "NQPTP_BRANCH=development" >> "$GITHUB_ENV" shairport-sync-5.1-dev/.github/workflows/stale.yaml000066400000000000000000000014401520255574400225210ustar00rootroot00000000000000name: 'Close stale issues and PRs' on: schedule: - cron: '0 0 * * *' permissions: issues: write pull-requests: write jobs: stale: runs-on: ubuntu-latest steps: - uses: actions/stale@v10.2.0 with: stale-issue-message: 'This issue has been inactive for 28 days so will be closed 7 days from now. To prevent this, please remove the "stale" label or post a comment.' stale-pr-message: 'This PR has been inactive for 28 days so will be closed 7 days from now. To prevent this, please remove the "stale" label or post a comment.' operations-per-run: 100 # These are the defaults at the time of writing. https://github.com/marketplace/actions/close-stale-issues # days-before-stale: 28 # days-before-close: 7 shairport-sync-5.1-dev/.gitignore000066400000000000000000000014061520255574400171220ustar00rootroot00000000000000/INSTALL /shairport-sync /shairport-sync.exe /shairport-sync-dbus-test-client /shairport-sync-mpris-test-client *.o /*~ *.xml~ /config.mk /config.h Makefile Makefile.in aclocal.m4 autom4te.cache compile /config.* configure depcomp install-sh missing stamp-h1 .dirstamp .deps man/Makefile man/Makefile.in scripts/shairport-sync.service scripts/shairport-sync shairport-sync.core gitversion-stamp gitversion.* plist_xml_strings.* plists/*.c plists/*.h plists/*.x #Some dbus files that are automatically generated /org.gnome.ShairportSync.service /dbus-interface.* /mpris-interface.* /lib_*.* # Some eclipse project files .cproject .project # macOS stuff .DS_Store shairport-sync.xcodeproj # separate build directories build # vscode .vscode # IntelliJ/JetBrains .idea/ shairport-sync-5.1-dev/.gitmodules000066400000000000000000000000001520255574400172740ustar00rootroot00000000000000shairport-sync-5.1-dev/.travis.yml000066400000000000000000000023211520255574400172400ustar00rootroot00000000000000language: c sudo: required dist: trusty env: matrix: - CFG="--with-alsa --with-avahi --with-ssl=openssl --with-soxr --with-metadata --with-systemv" - CFG="--with-alsa --with-avahi --with-ssl=polarssl --with-soxr --with-metadata --with-systemv" - CFG="--with-alsa --with-avahi --with-ssl=openssl --with-soxr --with-metadata --with-systemd" - CFG="--with-alsa --with-avahi --with-ssl=polarssl --with-soxr --with-metadata --with-systemd" - CFG="--with-alsa --with-tinysvcmdns --with-ssl=openssl --with-soxr --with-metadata --with-systemv" - CFG="--with-alsa --with-tinysvcmdns --with-ssl=polarssl --with-soxr --with-metadata --with-systemv" - CFG="--with-alsa --with-tinysvcmdns --with-ssl=openssl --with-soxr --with-metadata --with-systemd" - CFG="--with-alsa --with-tinysvcmdns --with-ssl=polarssl --with-soxr --with-metadata --with-systemd" script: - autoreconf -fi - ./configure $CFG - make before_install: - sudo apt-get -qq update - sudo apt-get install -y libdaemon-dev avahi-daemon libavahi-client-dev addons: apt: packages: - libasound2-dev - libsoxr-dev - libpopt-dev - libssl-dev - libpolarssl-dev - libconfig-dev - xmltoman - libao-dev shairport-sync-5.1-dev/ADDINGTOHOME.md000066400000000000000000000021721520255574400173170ustar00rootroot00000000000000Here is how to add a Shairport Sync device to the Apple Home application on iOS 15.3.1. Note that Shairport Sync has to be built with AirPlay 2 support. *** Step 0: Speaker & TV access. --- In the Home app > Home settings "Allow Speaker & TV access", select the option "Anyone On the Same Network". If a "require password" option below the "anyone on same network" is available, make sure it is unchecked. Step 1: Open the "Home" app --- Tap the `Add Accessory` panel or choose "Add Accessory" from the `+` symbol in the top right: ![IMG_3678](https://user-images.githubusercontent.com/4265913/157615721-e42a07e3-f93e-49d0-9233-e7b92a577459.jpg) *** Step 2: "More options..." --- Step 2: Tap `More options...` ![IMG_3679](https://user-images.githubusercontent.com/4265913/157616118-79c6d494-ce6e-4666-a6de-53cb40d0e751.jpg) *** Step 3: Select your Shairport Sync device: --- Your Shairport Sync device should appear here, though you may have to scroll. Tap the appropriate icon and follow the remaining instructions. ![IMG_3680](https://user-images.githubusercontent.com/4265913/157616475-22ee2eb6-56f4-4368-a1ed-d925f9984f1e.jpg) shairport-sync-5.1-dev/ADVANCED TOPICS/000077500000000000000000000000001520255574400172605ustar00rootroot00000000000000shairport-sync-5.1-dev/ADVANCED TOPICS/AdjustingSync.md000066400000000000000000000043421520255574400223720ustar00rootroot00000000000000# Adjusting Synchronisation with Shairport Sync Sometimes, a timing difference can be heard, where the audio coming from the Shairport-Sync-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 Shairport Sync 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 Shairport Sync 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 Shairport Sync 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 Shairport Sync 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. shairport-sync-5.1-dev/ADVANCED TOPICS/Events.md000066400000000000000000000075651520255574400210630ustar00rootroot00000000000000# Events Shairport Sync can run programs when certain _events_ occur. The events are: 1. When Shairport Sync goes _active_ or _inactive,_ 3. When audio play starts or stops, 5. When the volume is set or changed. ### Active / Inactive Events Shairport Sync is normally in the `inactive` state when no audio is being played. When audio is sent to Shairport Sync, it will transition from `inactive` to `active`. When the audio stops, Shairport Sync will start a timer. If audio restarts before the timer reaches the value of the `active_state_timeout` setting (10 seconds by default), Shairport Sync will stay `active`. However, if no more audio is received before the timer reaches the `active_state_timeout` value, Shairport Sync will transition to `inactive`. The overall effect of this is that Shairport Sync will go `active` when a track starts and stays active in the interval between tracks, so long as the interval is less than the `active_state_timeout`. When the sequence of tracks ends, Shairport Sync will go `inactive`. * Set the `run_this_before_entering_active_state` setting to the full path name to the program to run before Shairport Sync goes `active`. * Set the `run_this_after_exiting_active_state` setting to the full path name to the program to run after Shairport Sync goes `inactive`. * Set the `active_state_timeout` setting to the maximum amount of time to wait for play to resume before going `inactive`. ### Play Start / Play Stop **Note:** Play events have been superceded by Active/Inactive events, which works better in AirPlay 2 operation. When audio starts, the `play begins` event occurs. When it stops, the `play ends` event occurs. * Set the `run_this_before_play_begins` setting to the full path name to the program to run just before Shairport Sync starts playing. * Set the `run_this_after_play_ends` setting to the full path name to the program to run after Shairport Sync stops playing. ### Volume Adjustment Shairport Sync can run a program whenever the volume is set or changed. * Set `run_this_when_volume_changes` to the full path name to the program to run using the `general` group setting `run_this_when_volume_changes` _but also_ add a space character to the end of the name. This is because when a volume event occurs, Shairport Sync will append the new volume to the text you have specified in `run_this_when_volume_changes` and will then try to execute it. For example, to use the `echo` command to log the volume setting, let's say that you have found that the full path name for `echo` is `/usr/bin/echo`, then you would specify `run_this_when_volume_is_set` as follows: ``` run_this_when_volume_is_set = "/usr/bin/echo "; ``` (Note the extra space at the end of the path name.) Suppose the volume is set or changed to `-24.6`, then Shairport Sync will execute the command `/usr/bin/echo -24.6`. (Without that extra space, it would try to execute `/usr/bin/echo24.6`.) ### Waiting for Completion Set the `wait_for_completion` value to `"yes"` for Shairport Sync to wait until the respective commands have been completed before continuing. ### Program The environment in which the program you specify will be very different to a login environment. In particular, the `PATH` variable will be different. This means that you can't assume that the system will look in the right directories for programs or documents. Therefore, it is _vital_ that you specify everything using a _full path name_. For example, to get the `logger` command to log `Active Start` when Shairport Sync goes active, set `run_this_before_entering_active_state` as follows: ``` run_this_before_entering_active_state = "/usr/bin/logger \"Active Start\""; ``` You can specify a program to be executed or you can specify a script. Make sure the script file is marked as executable and has the appropriate shebang `#!/bin/...` as the first line. Within the script, make sure all references to files are full path names. shairport-sync-5.1-dev/ADVANCED TOPICS/GetTheBest.md000066400000000000000000000131411520255574400216000ustar00rootroot00000000000000# Get The Best from Shairport Sync Shairport Sync was designed to run best on dedicated stand-alone low-power "headless" Linux/FreeBSD systems with ALSA as the audio system and with a decent CD-quality Digital to Analog Converter (DAC). ## CPU Power and Memory Computer power and memory requirements are modest – a Raspberry Pi B or better, including the Pi Zero W, is fine. ## CPU Clock For best performance, Shairport Sync requires a stable and accurate system clock. This is because the output DAC's output rate is normally determined by the system clock (exceptionally, some very high-end USB streamers use their own built-in clocks). If the clock drifts, or if its actual frequency is far from its nominal frequency, Shairport Sync will have to do more interpolation, which inevitably must degrade the audio fidelity, even if it is very hard to hear. Some very old laptops are known to have inaccurate clocks and and some embedded systems can suffer from temperature-related clock drift. Recent Raspberry Pis seem to have very accurate clocks with low drift. ## Linux The best kind of Linux for Shairport Sync is a "bare" or "headless" Linux, that is, a Linux without a graphical user interface (GUI). Raspberry Pi OS Lite, Debian Minimal Server, Ubuntu Server, Fedora Server and Arch Linux (Minimal Configuration) are good examples of suitable Linux distributions. Shairport Sync will also runs on "desktop" Linuxes such as Ubuntu Desktop, Fedora Workstation, Raspberry Pi OS with desktop and Debian. However, Linuxes with a GUI are less suitable because they almost always use a sound server like PipeWire or PulseAudio. These can interfere with Shairport Sync, which prefers direct and exclusive access to the audio hardware. ## DAC A good Digital to Analog Converter (DAC) will have a huge influence on the quality of the audio. Shairport Sync runs at the frame rate of the input audio 44,100 or 48,000 frames per second (44,100 only if built for classic AirPlay without FFmpeg support.). It will automatically output in a wide range of formats and will try to match the output rate and channel count to that of the input. If not, it can transcode and mixdown automatically. Output rates, formats and channel counts can be restricted if necessary. Good DACs are available at a very wide range of prices, from low-cost USB "Sound Cards" to very high-end HiFi streaming DACs. In the Raspberry Pi world, many very good low-cost I2S DACs, some with integrated amplifiers, are available. The DAC powering the Pi's built-in audio jack is not great, however. While it may be good enough for trying out Shairport Sync or for casual listening, it has a very limited frequency response and can generate very large transients when it starts up. A separate DAC will transform the output quality. **Note** If you are building for classic AirPlay and do not wish to use the FFmpeg library, input and output is restricted to 44,100 frames per second. Make sure that the DAC is capable of 44,100 FPS operation. Most recent DACs are okay, but some older DACs will only run at 48,000 FPS or multiples of it. ## Maximum Output Level The `volume_max_db` setting allows you to reduce the maximum level of DAC output to prevent possible overloading of the amplifier or premplifier it feeds. ## Volume Range The volume range is the difference (technically the ratio, expressed in dB) between the highest and lowest level of the volume control. Ideally, this should give the highest volume at the high end and a barely audible sound at the lowest level. Typical volume ranges are 60 dB to 85dB. If the range is much less than this, the difference between high and low volume won't seem large enough to the listener. If the range is much more, much of the low end of the volume control range will be inaudible. (The built-in DAC of the Raspberry Pi has this problem.) Use the `volume_range_db` setting to set the volume range. If the range you request is greater than the range available in the hardware mixer, the built-in attenuator will be used to make up the difference. ## Volume Control Audio is sent at full volume in AirPlay and AirPlay 2 with separate information being sent to set the actual volume. This volume information can be used in four ways: * It can be used to control a built-in attenuator. This is the default. * It can be used to control a mixer built in to the DAC. To use a mixer, set the `mixer_control_name` in the configuration file to the name of the mixer you wish to use. * It can be ignored by Shairport Sync. This may be appropriate when you want the volume to be controlled by just one control, typically an audio system's volume control knob or the volume control of a car radio. To make Shairport Sync ignore the volume information, set `ignore_volume_control` to `"yes"`. * AirPlay volume changes cause events when an executable – a program or executable script – can be called. So, you could get Shairport Sync to ignore volume control information but call an executable to control an external volume control. ## Other Settings * The `disable_standby_mode` setting can be used to prevent the DAC from transitioning between active and standby states, which can sometimes cause a faint popping noise. If activated, Shairport Sync sends frames of silence to keep the DAC busy, preventing it from entering standby mode. * The `disable_synchronisation` setting can be used to prevent Shairport Sync from doing any interpolation whatever. Normally, this would lead to a problem when the DAC's buffer either overflowed or underflowed, but some very high-end streamers adjust the rate at which their DACs run to match the exact rate at which audio arrives, thus preventing underflow or overflow. shairport-sync-5.1-dev/ADVANCED TOPICS/InitialConfiguration.md000066400000000000000000000313631520255574400237310ustar00rootroot00000000000000# Finish Setting Up When you complete the instructions in [BUILD.md](../BUILD.md), you have a basic functioning Shairport Sync installation. If you want more control – for example, if you want to use a specific DAC, or if you want AirPlay to control the DAC's volume control – you can use settings in the configuration file (recommended) or you can use command-line options. ## The Configuration File Shairport Sync reads settings from a configuration file at `/etc/shairport-sync.conf` (in FreeBSD it will be at `/usr/local/etc/shairport-sync.conf`). When you run `$sudo make install`, a sample configuration file called `shairport-sync.conf.sample` is always installed or updated. This contains all the setting groups and all the settings available, but they all are commented out (comments begin with `//`) so that default values are used. The file contains explanations of the settings, useful hints and suggestions. ## Specifying the Output Device and Mixer Control If you have followed the [BUILD.md](../BUILD.md) instructions, audio received by Shairport Sync will be sent to the `default` device. Depending on the configuration of your system, you may be able to specify a specific hardware output DAC and use its built-in mixer to control volume levels. This would be desirable because (1) the `default` device may be doing further processing on the audio before sending it to the hardware output device, degrading its fidelity, and (2) using the real device's hardware mixer to control volume would give Shairport Sync complete control of the volume range. To get a list of the hardware DACs on your system, refer to the output of `$ shairport-sync -h`. Here is a sample from a Raspberry Pi 3B system: ``` Usage: shairport-sync [options...] or: shairport-sync [options...] -- [audio output-specific options] ... [snip] ... Settings and options for the audio backend "alsa": -d output-device set the output device, default is "default". -c mixer-control set the mixer control name, default is to use no mixer. -m mixer-device set the mixer device, default is the output device. -i mixer-index set the mixer index, default is 0. hardware output devices: "hw:Headphones" "hw:sndrpihifiberry" "hw:vc4hdmi" ... [snip] ... ``` In this system, you can see that there are three hardware output devices, `"hw:Headphones"`, `"hw:sndrpihifiberry"` and `"hw:vc4hdmi"`. Using a tool like [`dacquery`](https://github.com/mikebrady/dacquery) or `alsamixer`, an output device can be checked to find the name of the volume control mixer. For the first device, the name of the mixer is `"Headphone"`. These setting can be entered into the configuration file, in the `alsa` section, as follows: ``` ... alsa = { output_device = "hw:Headphones"; // 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. ... } ``` Make sure to uncomment entries you wish to make active, and restart Shairport Sync after you have made changes. If you make a syntax error, Shairport Sync will not start and will leave a message in the log. See more details below and in the comments in the configuration file. Please note that if your system has a sound server such as PipeWire or PulseAudio (most desktop Linuxes have one of these), you may not be able to access the sound hardware directly, so you may only be able to use the `default` output. ## More about Configuration Settings Settings in the configuration file are grouped. For instance, there is a `general` group within which you can use the `name` tag to set the service name. Suppose you wanted to set the name of the service to `Front Room` and give the service the password `secret`, then you should do the following: ``` general = { name = "Front Room"; password = "secret"; // ... other general settings }; ``` The password setting is only valid for classic Shairport Sync. (Remember, anything preceded by `//` is a comment and will have no effect on the setting of Shairport Sync.) **Important:** You should *never* use an important password as the AirPlay password for a Shairport Sync player – the password is stored in Shairport Sync's configuration file in plain text and is thus completely vulnerable. No backend is specified here, so it will default to the `alsa` backend if more than one back end has been compiled. To route the output to PipeWire, set: ``` output_backend = "pipewire"; ``` in the `general` group. The `alsa` group is used to specify properties of the output device. The most obvious setting is the name of the output device which you can set using the `output_device` tag. The following `alsa` group settings are very important for maximum performance. If your audio device has a mixer that can be use to control the volume, then Shairport Sync can use it to give instant response to volume and mute commands and it can offload some work from the processor. * The `mixer_control_name` tag allows you to specify the name of the mixer volume control. * The `mixer_device` tag allows you specify where the mixer is. By default, the mixer is on the `output_device`, so you only need to use the `mixer_device` tag if the mixer is elsewhere. This can happen if you specify a *device* rather than a *card* with the `output_device` tag, because normally a mixer is associated with a *card* rather than a device. Suppose you wish to use the output device `5` of card `hw:0` and the mixer volume-control named `PCM`: ``` alsa = { output_device = "hw:0,5"; mixer_device = "hw:0"; mixer_control_name = "PCM"; // ... other alsa settings }; ``` The `pipewire` group is used to specify settings relevant to the PipeWire backend. You can set the "Application Name" that will appear in the "Sound" control panel. Note: Shairport Sync can take configuration settings from command line options. This is mainly for backward compatibility, but sometimes still useful. Where possible, it is recommended that you use the configuration file method. ### Raspberry Pi To make Shairport Sync output to the built-in audio DAC and use its hardware mixer, in the `alsa` section of the configuration file, set the output device and mixer as follows: ``` alsa = { output_device = "hw:Headphones"; // the name of the alsa output device. 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. // ... other alsa settings ``` (Remember to uncomment the lines by removing the `//` at the start of each.) When these changes have been made, restart Shairport Sync or simply reboot the system. A problem with the built-in DAC that it declares itself to have a very large mixer volume control range – all the way from -102.38dB up to +4dB, a range of 106.38 dB. In reality, only the top 60 dB or so is in any way usable. To help get the most from it, consider using the `volume_range_db` setting in the `general` group to instruct Shairport Sync to use the top of the DAC mixer's declared range. For example, if you set the `volume_range_db` figure to 60, the top 60 dB of the range will the used. With this setting on the Raspberry Pi, maximum volume will be +4dB and minimum volume will be -56dB, below which muting will occur. From a user's point of view, the effect of using this setting is to move the minimum usable volume all the way down to the bottom of the user's volume control, rather than have the minimum usable volume concentrated very close to the maximum volume. ### Examples Here are some examples of complete configuration files. ``` general = { name = "Joe's Stereo"; }; alsa = { output_device = "hw:0"; }; ``` This gives the service the name "Joe's Stereo" and specifies that audio device `hw:0` be used. For best results with the `alsa` backend — including getting true mute and instant response to volume control and pause commands — you should access the hardware volume controls. Use [`dacquery`](https://github.com/mikebrady/dacquery)`amixer` or `alsamixer` or similar to discover the name of the mixer control to be used as the `mixer_control_name`. Here is an example for for a Raspberry Pi using its internal soundcard — device hw:0 — that drives the headphone jack: ``` general = { name = "Mike's Boombox"; }; alsa = { output_device = "hw:0"; mixer_control_name = "Headphone"; }; ``` Here is an example of driving a Topping TP30 Digital Amplifier, which has an integrated USB DAC and which is connected as audio device `hw:1`: ``` general = { name = "Kitchen"; }; alsa = { output_device = "hw:1"; mixer_control_name = "PCM"; }; ``` For a cheapo "3D Sound" USB card (Stereo output and input only) on a Raspberry Pi: ``` general = { name = "Front Room"; }; alsa = { output_device = "hw:1"; mixer_control_name = "Speaker"; }; ``` For a first generation Griffin iMic on a Raspberry Pi: ``` general = { name = "Attic"; }; alsa = { output_device = "hw:1"; mixer_control_name = "PCM"; }; ``` On an NSLU2, to drive a first generation Griffin iMic: ``` general = { name = "Den"; }; alsa = { mixer_control_name = "PCM"; }; ``` On an NSLU2, to drive the "3D Sound" USB card: ``` general = { name = "TV Room"; }; alsa = { mixer_control_name = "Speaker"; }; ``` Finally, here is an example of using the PulseAudio backend: ``` general = { name = "Zoe's Computer"; output_backend = "pa"; }; ``` ### Latency Latency is the exact time from a sound signal's original timestamp until that signal actually "appears" on the output of the audio output device, usually a Digital to Audio Converter (DAC), irrespective of any internal delays, processing times, etc. in the computer. Shairport Sync uses latencies supplied by the source, typically either 2 seconds or just over 2.25 seconds. You shouldn't need to change them. Problems can arise when you are trying to synchronise with speaker systems — typically surround-sound home theatre systems — that have their own inherent delays. You can compensate for an inherent delay using the appropriate backend (typically `alsa`) `audio_backend_latency_offset_in_seconds`. Set this offset (in frames) to compensate for a fixed delay in the audio back end; for example, if the output device delays by 100 ms, set this to -0.1. ### Resynchronisation Shairport Sync actively maintains synchronisation with the source. If synchronisation is lost — say due to a busy source or a congested network — Shairport Sync will mute its output and resynchronise. The loss-of-sync threshold is a very conservative 0.050 seconds — i.e. the actual time and the expected time must differ by more than 50 ms to trigger a resynchronisation. Smaller disparities are corrected by insertions or deletions, as described above. * You can vary the resync threshold, or turn resync off completely, with the `general` `resync_threshold_in_seconds` setting. ### Tolerance Playback synchronisation is allowed to wander — to "drift" — a small amount before attempting to correct it. The default is 0.002 seconds, i.e. 2 ms. The smaller the tolerance, the more likely it is that overcorrection will occur. Overcorrection is when more corrections (insertions and deletions) are made than are strictly necessary to keep the stream in sync. Use the `statistics` setting to monitor correction levels. Corrections should not greatly exceed net corrections. * You can vary the tolerance with the `general` `drift_tolerance_in_seconds` setting. ## Command Line Arguments You can use command line arguments to provide settings to Shairport Sync, though newer settings will only be available via the configuration file. For full information, please read the Shairport Sync `man` page, also available at http://htmlpreview.github.io/?https://github.com/mikebrady/shairport-sync/blob/master/man/shairport-sync.html. Apart from the following options, all command line options can be replaced by settings in the configuration file. Here is a brief description of command line options that are not replicated by settings in the settings file. * The `-c` option allows you to specify the location of the configuration file. * The `-V` option gives you version information about Shairport Sync and then quits. * The `-d` option causes Shairport Sync to properly daemonise itself, that is, to run in the background. You may need sudo privileges for this. * The `-k` option causes Shairport Sync to kill an existing Shairport Sync daemon. You may need to have sudo privileges for this. The System V init script at `/etc/init.d/shairport-sync` has a bare minimum : `-d`. Basically all it does is put the program in daemon mode. The program will read its settings from the configuration file. shairport-sync-5.1-dev/ADVANCED TOPICS/Metadata.md000066400000000000000000000032421520255574400213230ustar00rootroot00000000000000# Metadata Shairport Sync can deliver metadata supplied by the source, such as Album Name, Artist Name, Cover Art, etc. through a pipe or UDP socket to a recipient application program — see https://github.com/mikebrady/shairport-sync-metadata-reader for a sample recipient. Sources that supply metadata include iTunes and the Music app in macOS and iOS. ## Metadata over UDP As an alternative to sending metadata to a pipe, the `socket_address` and `socket_port` tags may be set in the metadata group to cause Shairport Sync to broadcast UDP packets containing the track metadata. The advantage of UDP is that packets can be sent to a single listener or, if a multicast address is used, to multiple listeners. It also allows metadata to be routed to a different host. However UDP has a maximum packet size of about 65000 bytes; while large enough for most data, Cover Art will often exceed this value. Any metadata exceeding this limit will not be sent over the socket interface. The maximum packet size may be set with the `socket_msglength` tag to any value between 500 and 65000 to control this - lower values may be used to ensure that each UDP packet is sent in a single network frame. The default is 500. Other than this restriction, metadata sent over the socket interface is identical to metadata sent over the pipe interface. The UDP metadata format is very simple - the first four bytes are the metadata *type*, and the next four bytes are the metadata *code* (both are sent in network byte order - see https://github.com/mikebrady/shairport-sync-metadata-reader for a definition of those terms). The remaining bytes of the packet, if any, make up the raw value of the metadata. shairport-sync-5.1-dev/ADVANCED TOPICS/PulseAudioAndPipeWire.md000066400000000000000000000040731520255574400237500ustar00rootroot00000000000000# Working with PulseAudio or PipeWire Many Linux systems, especially desktop Linuxes with a GUI, have [PipeWire](https://pipewire.org) or [PulseAudio](https://www.freedesktop.org/wiki/Software/PulseAudio/) installed as [sound servers](https://en.wikipedia.org/wiki/Sound_server). PipeWire and PulseAudio are widely used and have the great advantage of being easily able to mix audio from multiple sources. However, the main thing to remember about PipeWire and PulseAudio sound servers is they only become available when a user logs in -- that is, they are set up as _user services_. Shairport Sync relies on them and therefore it must also be set up as a user service. Shairport Sync can not be set up as a system service because the PipeWire or PulseAudio services are not available when system services are launched just after system startup. To use PipeWire or PulseAudio-based systems, Shairport Sync must be set up as a user service. ### Considerations 1. Shairport Sync will work without modification in a PipeWire- or PulseAudio-based system if built with the default ALSA backend. This is because PipeWire and PulseAudio both provide a default ALSA pseudo-device to receive and play audio from ALSA-compatible programs. 2. Shairport Sync can be built with "native" PipeWire or PulseAudio backends by adding the `--with-pipewire` or `--with-pulseaudio` configuration flags when it is being built. This has the advantage of bypassing the ALSA compatability layer. 3. To check if PipeWire support is built into Shairport Sync, check that the string `PipeWire` is included in the version string. (Enter `$ shairport-sync -V` to get the version string.) Similarly, the version string will include `PulseAudio` if the PulseAudio backend is built in. 4. Remember to specify which backend Shairport Sync should use in the configuration file or on the command line. ## Starting Shairport Sync as a User Service Please refer to [this](https://github.com/mikebrady/shairport-sync/blob/development/BUILD.md#5-enable-and-start-service) section to discover how to start Shairport Sync as a user service. shairport-sync-5.1-dev/ADVANCED TOPICS/README.md000066400000000000000000000022461520255574400205430ustar00rootroot00000000000000# Advanced Topics Here you will find links to some advanced features and things you can do with Shairport Sync. * [Working with PulseAudio or PipeWire](PulseAudioAndPipeWire.md). * [Adjusting Sync](AdjustingSync.md) – advance or delay the timing of the output from Shairport Sync to compensate for amplifier delays. * [Metadata](Metadata.md). * [Events](Events.md). * [Statistics](Statistics.md). * Setting up an [MQTT](../MQTT.md) system. * [Digital Signal Processing](https://github.com/mikebrady/shairport-sync/wiki/Digital-Signal-Processing-with-Shairport-Sync). * [Car Installation](../CAR%20INSTALL.md) – build an isolated WiFi network containing a Shairport Sync player on a Raspberry Pi. Suitable for a car radio with an `aux` input or for the stereo in that broadband-free holiday cottage. The configuration file – which contains lots of documentation – is on your system. By default, the sample configuration file is placed at `/etc/shairport-sync.conf.sample` (`/usr/local/etc/shairport-sync.conf.sample` on FreeBSD). You can also view an online version [here](../scripts/shairport-sync.conf). Build configuration flags are discussed [here](CONFIGURATION%20FLAGS.md). shairport-sync-5.1-dev/ADVANCED TOPICS/Statistics.md000066400000000000000000000401611520255574400217360ustar00rootroot00000000000000# Statistics If you set the `statistics` setting in the `diagnostics` section of the configuration file to `"YES"`, some statistics will be logged at regular intervals. The items logged will depend on the type of stream being processed: classic AirPlay, AirPlay 2 Buffered Audio or AirPlay 2 Realtime Audio. If the `log_verbosity` is set to 1, 2 or 3, additional items will be logged. From an audio enthusiast's point of view, the most important figure is possibly the `All Sync PPM` figure. This is the total amount of interpolation needed by Shairport Sync to keep the audio stream in sync in the last interval, i.e. the number of frames added plus the number of frames removed from the audio stream, relative to the total number of frames output, expressed in parts per million (PPM). For reference, adding or removing one frame per second into a 44,100 frames per second stream is ± 22.68 PPM. The lower this number number is, the higher the fidelity of the audio signal passed to the output device. On a well sorted system, this figure can be 0.0 for considerable periods, but it can't really be zero forever unless the output device is adapting to the true data rate (some very high-end streamers seem to do so). You may also find that the number might be higher at the start while the system settles down. The second most important figure is possibly the `Sync Error ms`. This is the average synchronisation error in milliseconds in the last interval. Ideally it should be 0.0. By default, Shairport Sync has a tolerance of a sync error of ± 2.0 milliseconds without triggering interpolation. Two other interesting measurements of the output rate may be available – `Output FPS (r)` and `Output FPS (c)`, where `(r)` means "raw" and the `(c)` means "corrected". The "raw" figure is the rate at which the output device (typically a DAC) accepts data measured relative to the computer's own system clock (specifically the `CLOCK_MONOTONIC_RAW` clock). The accuracy of the number depends on the accuracy of the clock, which will typically be accurate to within anything from 20 to 100 ppm. The "corrected" figure is the rate at which the output device accepts data relative to the computer's network-time-disciplined clock (specifically the `CLOCK_MONOTONIC` clock). This clock is normally adjusted ("disciplined") to keep time with network time and should be accurate to with a few tens of milliseconds over a _long_ period. So (1) if you could run a play session for a long period – say a day – and (2) if network time synchronisation is enabled and (3) if the network connection to the network time service is fast and stable, then you should get an accurate absolute measure of exact frame rate of the output device. If your internet connection is not good, the corrected figure will be very inaccurate indeed. Here is a brief description of the figures that might be provided. ##### Sync Error ms Average playback synchronisation error in milliseconds in the last interval. By default, Shairport Sync will allow a sync error of ± 2.0 milliseconds without any interpolation. Positive means late, negative means early. ##### Net Sync PPM This is the net amount of interpolation done by Shairport Sync to keep the audio stream in sync in the last interval, i.e. the number of frames added **minus** the number of frames removed from the audio stream, relative to the total number of frames output, expressed in parts per million (PPM). For reference, adding or removing one frame per second into a 44,100 frames per second stream is 22.68 ppm. ##### All Sync PPM This is the total amount of interpolation done by Shairport Sync to keep the audio stream in sync in the last interval, i.e. the number of frames added **plus** the number of frames removed from the audio stream, relative to the total number of frames output, expressed in parts per million (PPM). The magnitude of this should be the same as the `Net Sync PPM`. If it is much larger it means that Shairport Sync is overcorrecting for sync errors – try increasing the drift tolerance to reduce it. ##### Av Sync Window (ms) This is an estimate, in milliseconds, of how often the audio system updates the latency data it provides. ##### Packets This is the number of packets of audio frames received since the start of the session. A packet normally contains 352 ± 1 audio frames. ##### Missing This is the number of packets of audio frames that were expected but not received in the last interval. It should be zero, and if not it usually indicates a significant problem with the network. classic AirPlay and AirPlay 2 Realtime Streams only. ##### Late This is the number of packets of audio frames that were received late – but still in time to be used – in the last interval. Classic AirPlay and AirPlay 2 Realtime Streams only. ##### Too Late This is the number of packets of audio frames that were received too late to be used in the last interval. It is possible that these packets were already received, so those frames might not actually be missing when the time comes to play them. Classic AirPlay and AirPlay 2 Realtime Streams only. ##### Resend Reqs This is the number of times Shairport Sync requests the resending of missing frames. Requests can be for one or more frames. Classic AirPlay and AirPlay 2 Realtime Streams only. ##### Min DAC Queue The is the smallest number of frames of audio in the DAC's hardware queue. If it goes too low, the DAC may begin to underrun. ##### Min Buffers The is the smallest number of packets of audio in the queue to be processed in the last interval. It is related to the overall latency in Classic AirPlay and AirPlay 2 Realtime Streams. If it comes close to zero it's often a sign that the network is poor. ##### Max Buffers The is the largest number of packets of audio in the queue to be processed in the last interval. ##### Min Buffer Size The is smallest remaining number of bytes in the Buffered Audio buffer in the last interval. It can legitimately be zero when a track ends or begins. If it reaches zero while a track is playing, it means that audio data is not arriving at Shairport Sync quickly enough and may indicate network problems. AirPlay 2 Buffered Audio streams only. ##### Nominal FPS This is the rate specified in the AirPlay stream itself. Classic AirPlay only. ##### Received FPS This is the rate at which frames are received from the network averaged since the start of the play session. Classic AirPlay only. ##### Output FPS (r) Output rate measured relative to the computer system's clock since the start of the play session. See above for a discussion. ##### Output FPS (c) Output rate measured relative to the network-clock-disciplined computer system's clock since the start of the play session. See above for a discussion. ##### Source Drift PPM This is a measure of the difference between the source clock and Shairport Sync's clock expressed in parts per million. Only valid when 10 or more drift samples have been received. Classic AirPlay only. ##### Drift Samples This is the number drift samples have been accepted for calculating the source drift. Classic AirPlay only. #### Example The following example is of an AirPlay 2 Buffered Audio Stream from a HomePod mini to a WiFi-connected Raspberry Pi 3 equipped with a Pimoroni "Audio DAC SHIM (Line-Out)" with `log_verbosity` set to `1` after 3 hours and 37 minutes of operation. The audio is from a radio station accessed through Apple Music: ``` 5.292055362 "rtsp.c:3112" Connection 1. AP2 Buffered Audio Stream. 1.382815677 "player.c:2650" Connection 1: Playback Started -- AirPlay 2 Buffered. 7.899808955 "player.c:2491" Sync Error ms | Net Sync PPM | All Sync PPM | Min DAC Queue | Min Buffer Size | Output FPS (r) | Output FPS (c) ... 8.014025361 "player.c:2491" -1.69 2.8 2.8 7341 198k 44100.04 44100.35 7.992082237 "player.c:2491" -1.70 2.8 2.8 7332 188k 44100.04 44100.34 8.015987549 "player.c:2491" -1.68 0.0 0.0 7334 186k 44100.04 44100.35 8.010537393 "player.c:2491" -1.68 2.8 2.8 7335 187k 44100.04 44100.36 7.993940934 "player.c:2491" -1.85 0.0 0.0 7329 198k 44100.04 44100.37 8.015796195 "player.c:2491" -1.87 5.7 5.7 7325 194k 44100.04 44100.37 8.021665934 "player.c:2491" -1.92 5.7 5.7 7329 190k 44100.04 44100.37 7.990409477 "player.c:2491" -1.85 2.8 2.8 7347 201k 44100.04 44100.37 8.001858278 "player.c:2491" -1.96 17.0 17.0 7332 204k 44100.04 44100.37 8.007150986 "player.c:2491" -1.89 2.8 2.8 7327 195k 44100.04 44100.36 7.998612862 "player.c:2491" -1.87 2.8 2.8 7317 199k 44100.04 44100.36 8.020592653 "player.c:2491" -1.89 11.3 11.3 7323 203k 44100.04 44100.35 8.003245674 "player.c:2491" -1.89 8.5 8.5 7325 198k 44100.04 44100.35 7.990874789 "player.c:2491" -1.98 19.8 19.8 7103 197k 44100.04 44100.34 8.010600257 "player.c:2491" -1.85 2.8 2.8 7327 187k 44100.04 44100.33 8.004573122 "player.c:2491" -1.89 5.7 5.7 7327 187k 44100.04 44100.33 8.012853278 "player.c:2491" -1.89 5.7 5.7 7326 190k 44100.04 44100.32 8.005596664 "player.c:2491" -1.95 22.7 22.7 7322 165k 44100.04 44100.31 8.019198695 "player.c:2491" -1.85 5.7 5.7 7333 166k 44100.04 44100.31 7.999363382 "player.c:2491" -1.79 2.8 2.8 7349 153k 44100.04 44100.30 7.990332549 "player.c:2491" -1.87 5.7 5.7 7328 155k 44100.04 44100.29 8.012287445 "player.c:2491" -1.84 2.8 2.8 7352 185k 44100.04 44100.28 7.998929528 "player.c:2491" -1.94 14.2 14.2 7331 171k 44100.04 44100.28 8.008170622 "player.c:2491" -1.88 5.7 5.7 7327 188k 44100.04 44100.27 8.012935257 "player.c:2491" -1.87 19.8 19.8 7270 205k 44100.04 44100.26 8.006337966 "player.c:2491" -1.86 0.0 0.0 7334 199k 44100.04 44100.25 8.004206612 "player.c:2491" -1.76 2.8 2.8 7331 204k 44100.04 44100.25 7.998495257 "player.c:2491" -1.82 2.8 2.8 7329 204k 44100.04 44100.24 8.016859059 "player.c:2491" -1.88 2.8 2.8 7335 201k 44100.04 44100.23 7.993529320 "player.c:2491" -1.92 14.2 14.2 7329 205k 44100.04 44100.22 8.021956820 "player.c:2491" -1.96 11.3 11.3 7322 206k 44100.04 44100.21 8.006401820 "player.c:2491" -1.93 11.3 11.3 7322 199k 44100.04 44100.21 8.001469111 "player.c:2491" -1.89 5.7 5.7 7336 204k 44100.04 44100.20 7.995194320 "player.c:2491" -1.86 5.7 5.7 7330 202k 44100.04 44100.19 8.017805206 "player.c:2491" -1.99 22.7 22.7 7322 201k 44100.04 44100.18 7.995541038 "player.c:2491" -1.95 22.7 22.7 7331 203k 44100.04 44100.18 8.011463643 "player.c:2491" -1.87 0.0 0.0 7331 207k 44100.04 44100.17 7.995941403 "player.c:2491" -1.85 2.8 2.8 7331 206k 44100.04 44100.16 8.013330570 "player.c:2491" -1.71 2.8 2.8 7344 212k 44100.04 44100.15 8.012214580 "player.c:2491" -1.82 0.0 0.0 7333 203k 44100.04 44100.15 7.998585049 "player.c:2491" -1.85 8.5 8.5 7332 207k 44100.04 44100.14 8.023448799 "player.c:2491" -1.86 5.7 5.7 7328 206k 44100.04 44100.13 7.984586612 "player.c:2491" -1.87 8.5 8.5 7277 205k 44100.04 44100.12 8.017339372 "player.c:2491" -1.91 17.0 17.0 7327 207k 44100.04 44100.12 8.007090309 "player.c:2491" -1.94 17.0 17.0 7286 199k 44100.04 44100.11 8.007894164 "player.c:2491" -1.87 2.8 2.8 7334 201k 44100.04 44100.10 7.991787497 "player.c:2491" -1.89 2.8 2.8 7327 194k 44100.04 44100.09 8.019011611 "player.c:2491" -1.94 5.7 5.7 7323 185k 44100.04 44100.09 7.994695362 "player.c:2491" -1.99 14.2 14.2 7321 199k 44100.04 44100.08 8.010284632 "player.c:2491" -1.93 11.3 11.3 7325 191k 44100.04 44100.07 8.011451612 "player.c:2491" -1.87 8.5 8.5 7329 156k 44100.04 44100.09 7.993112549 "player.c:2491" -1.84 2.8 2.8 7330 150k 44100.04 44100.13 8.004971455 "player.c:2491" -1.77 11.3 11.3 7325 157k 44100.04 44100.16 8.010517133 "player.c:2491" -1.85 0.0 0.0 7322 182k 44100.04 44100.19 8.005598851 "player.c:2491" -2.00 39.7 39.7 7207 180k 44100.04 44100.22 8.006777965 "player.c:2491" -1.99 39.7 39.7 7320 183k 44100.04 44100.24 7.115508696 "player.c:1643" Connection 1: Playback Stopped. Total playing time 03:37:20. Output: 44100.04 (raw), 44100.24 (corrected) frames per second. ``` For reference, a drift of one second per day is approximately 11.57 ppm. Left uncorrected, even a drift this small between two audio outputs will be audible after a short time. shairport-sync-5.1-dev/AIRPLAY2.md000066400000000000000000000133541520255574400166440ustar00rootroot00000000000000# AirPlay 2 Please be aware that an official specification of AirPlay 2 has not been made public. What follows is based on what has been discovered so far. ### Streams AirPlay 2 supports two stream types -- "Realtime Audio" and "Buffered Audio". - Realtime audio is played after a short delay. The delay is usually around two seconds. (This is similar to the older Classic AirPlay format.) - Buffered audio starts playing after a very short delay. Audio can arrive faster than it is played and is buffered locally in the Shairport Sync device. ### Formats AirPlay 2 supports a variety of audio formats. This is a summary of what is known to work so far. - Compression - ALAC (Apple Lossless Advanced Codec) encoding is used for lossless streaming, - AAC (Advanced Audio Coding) is used for lossy streaming. - (BTW you can check your perception of lossy and lossless formats [here](http://abx.digitalfeed.net).) - Encoding - Signed 16- and 24-bit signed linear PCM samples ("S16" and "S24"), - 24-bit floating point PCM samples ("F24"). - Rates - Sample rates of 44,100 and 48,000 frames per second (fps). - Channels - Stereo, 5.1 and 7.1 Surround Sound. # Shairport Sync This information relates to Shairport Sync Version 5.0 onwards. Shairport Sync offers AirPlay 2 support for audio sources on: - iOS devices, - Macs from macOS 10.15 (Catalina) onwards, - HomePod minis, - Apple TVs. ## What Works - Audio synchronised with other AirPlay 2 devices. - AirPlay 2 audio playback: - Basic - ALAC/S16/44100/2 realtime audio (stereo), - AAC/F24/44100/2 buffered audio (stereo). - Better - AAC/F24/48000/2 buffered audio (stereo). - Lossless - ALAC/S24/48000/2 buffered audio (stereo). - Surround - AAC/F24/48000/5.1 and AAC/F24/48000/7.1 buffered audio (surround sound). - Transcoding: the output will be transcoded if necessary (e.g. from 44,100 to 48,000 fps) to match the output device's rate. - Mixdown: mixdown to fewer output channels (e.g. 5.1 to stereo) is automatic but can be controlled. - Shairport Sync can revert to "classic" AirPlay if necessary. - Devices running Shairport Sync in AirPlay 2 mode can be [added](https://github.com/mikebrady/shairport-sync/blob/development/ADDINGTOHOME.md) to the Home app. - Shairport Sync can be built to support classic AirPlay (aka "AirPlay 1") only. Classic Airplay offers only one format, ALAC/S16/44100/2, but output transcoding is available to, for example, 48000 fps. ## What Does Not Work - High-Definition Lossless -- 96,000 and 192,000 fps material -- is not supported. - Dolby Atmos is not supported. - AirPlay 2 for Windows iTunes is not supported. - Remote control facilities are not implemented. - AirPlay 2 from macOS prior to 10.15 (Catalina) is not supported. - Multiple instances of the AirPlay 2 version of Shairport Sync can not be hosted on the same system. It seems that AirPlay 2 clients are confused by having multiple AirPlay 2 players at the same IP addresses. ## General Shairport Sync uses a companion application called [NQPTP](https://github.com/mikebrady/nqptp) ("Not Quite PTP") for timing and synchronisation in AirPlay 2. NQPTP must have exclusive access to ports `319` and `320`. ## What You Need For AirPlay 2, a system with the power of a Raspberry Pi B, or better, is recommended. Here are some guidelines: * Full access, including low-port-number network access or `root` privileges, to a system at least as powerful as a Raspberry Pi B. * Ports 319 and 320 must be free to use (i.e. they must not be in use by another service such as a PTP service) and must not be blocked by a firewall. * An up-to-date Linux, FreeBSD or OpenBSD system. This is important, as some of the libraries must be the latest available. * Due to realtime timing requirements, Shairport Sync does not work well on virtual machines outputting to ALSA, PipeWire or PulseAudio. For the same reason, Shairport Sync does not work very well with with Bluetooth. YMMV of course, and you can have success where timing is not crucial, such as outputting to `stdout` or to a unix pipe. * Shairport Sync can not run in AirPlay 2 mode on a Mac because NQPTP, on which it relies, needs ports 319 and 320, which are already used by macOS. * A version of the [FFmpeg](https://www.ffmpeg.org) library with an AAC decoder capable of decoding Floating Planar -- `fltp` -- material must be in your system. There is a guide [here](TROUBLESHOOTING.md#aac-decoder-issues-airplay-2-only) to help you find out if your system has it. * An audio output. For preference, the output device should be capable of accepting stereo or multichannel at 44,100 and 48,000 frames per second. With FFmpeg support, audio will be transcoded and mixed to match output device capabilities as necessary. * You can use [`dacquery`](https://github.com/mikebrady/dacquery) to test the suitability of hardware ALSA audio devices on your system. #### An Ideal System For the highest quality audio with the highest fidelty and a minimum of audio processing, an ideal system would be a bare Linux system without a GUI and without PipeWire or PulseAudio, such as Raspberry Pi OS (Lite) or similar. In this case, Shairport Sync connects directly to the ALSA output DAC. For testing, the build-in DAC or a low-cost USB DAC is usually sufficient. A problem with this setup is that Shairport Sync expects exclusive access to the audio device. If you have other audio sources, this can be problematic. In such a situation, an otherwise-bare system as described above, but with PipeWire added, can be used, so that all audio sources output to the PipeWire system, which takes care of mixing. Take care to ensure that the Unix users running the audio applications that use PipeWire are members of the `pipewire` group. ## Guides * A building guide is available at [BUILD.md](BUILD.md). shairport-sync-5.1-dev/AUTHORS000066400000000000000000000000001520255574400161670ustar00rootroot00000000000000shairport-sync-5.1-dev/BUILD.md000066400000000000000000000431241520255574400163160ustar00rootroot00000000000000# Build and Install Shairport Sync This guide is for a basic installation of Shairport Sync in a recent (2018 onwards) Linux or FreeBSD. ## Important Note – Upgrading to Version 5! If you have been using Shairport Sync prior to Version 5.0 and are rebuilding or reinstalling Shairport Sync, be aware that a few important things have changed. While the overall operation of Shairport Sync has not changed much, it is really important to fully remove existing startup scripts and to check and update configuration files. Some important changes are highlighted here: 1. The default sample rate has changed from 44,100 to 48,000 for buffered audio. Real-time audio streams remain at 44,100. 2. Shairport Sync will also play surround sound (5.1 and 7.1) and lossless (48k) audio. 3. Shairport Sync will automatically switch output rates and formats to correspond to input rates and formats. This can be controlled. 4. Many build flags have changed: for example `--with-systemd` is now `--with-systemd-startup`. 5. Many configuration settings names and facilities have changed. For example `convolution` is now `convolution_enabled`. Another example is that convolution is now multi-threaded, so a new `convolution_thread_pool_size` setting is available. 7. Installation has changed: when Shairport Sync and NQPTP are installed, their startup scripts have changed to provide them with more suitable privileges. You must remove any existing startup scripts. 8. Jack Audio is deprecated and will be removed in a future update. Consider using PipeWire instead. A useful guide to Version 5 Configuration File Changes is available [here](CONFIGURATIONFILECHANGES5.md). ## 0. General Shairport Sync can be built as an AirPlay 2 player (with [some limitations](AIRPLAY2.md#features-and-limitations)) or as classic Shairport Sync – a player for the older, but still supported, "classic" AirPlay (aka "AirPlay 1") protocol. Check ["What You Need"](AIRPLAY2.md#what-you-need) for some basic system requirements. Note that Shairport Sync does not work well in virtual machines – YMMV. Overall, you'll be building and installing two programs – Shairport Sync itself and [NQPTP](https://github.com/mikebrady/nqptp), a companion app that Shairport Sync uses for AirPlay 2 timing. If you are building classic Shairport Sync, NQPTP is unnecessary and can be omitted. In the commands below, note the convention that a `#` prompt means you are in superuser mode and a `$` prompt means you are in a regular unprivileged user mode. You can use `sudo` *("SUperuser DO")* to temporarily promote yourself from user to superuser, if permitted. For example, if you want to execute `apt-get update` in superuser mode and you are in user mode, enter `sudo apt-get update`. ## 1. Prepare #### Remove Old Copies of Shairport Sync Before you begin building Shairport Sync, it's best to remove any existing copies of the application, called `shairport-sync`. Use the command `$ which shairport-sync` to find them. For example, if `shairport-sync` has been installed previously, this might happen: ``` $ which shairport-sync /usr/local/bin/shairport-sync ``` Remove it as follows: ``` # rm /usr/local/bin/shairport-sync ``` Do this until no more copies of `shairport-sync` are found. Shairport Sync could also be found in `/usr/bin/shairport-sync` or elsewhere. #### Remove Old Configuration Files If you want to preserve any configuration settings you have made, you should make a note of them and then delete the configuration file. This is suggested because there may be new configuration options available, which will be present but disabled in the updated configuration file that will be installed. You can then apply your previous settings to the updated configuration file. The configuration file is typically at `/etc/shairport-sync.conf` or `/usr/local/etc/shairport-sync.conf`. #### Remove Old Service Files You should also remove any of the following service files that may be present: * `/etc/systemd/system/shairport-sync.service` * `/etc/systemd/user/shairport-sync.service` * `/lib/systemd/system/shairport-sync.service` * `/lib/systemd/user/shairport-sync.service` * `/etc/dbus-1/system.d/shairport-sync-dbus.conf` * `/etc/dbus-1/system.d/shairport-sync-mpris.conf` * `/etc/init.d/shairport-sync` * `~/.config/systemd/user/shairport-sync.service` New service files will be installed if necessary at the `# make install` stage. (In FreeBSD, there is no need to remove the file at `/usr/local/etc/rc.d/shairport-sync` – it's always replaced in the `make install` step.) #### Reboot after Cleaning Up If you removed any installations of Shairport Sync or any of its service or configuration files in the last three steps, you should reboot. ## 2. Get Tools and Libraries Okay, now let's get the tools and libraries for building and installing Shairport Sync (and NQPTP). ### Debian / Raspberry Pi OS / Ubuntu ``` # apt update # apt upgrade # this is optional but recommended # 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 uuid-dev libgcrypt-dev xxd libplist-utils \ libavutil-dev libavcodec-dev libavformat-dev ``` 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 autoconf automake libtool \ libpopt-dev libconfig-dev libasound2-dev avahi-daemon libavahi-client-dev libssl-dev libsoxr-dev \ libavutil-dev libavcodec-dev libavformat-dev ``` Building on Ubuntu 24.10 or Debian 13 ("Trixie") and later – and possibly on other distributions – requires `systemd-dev`. Be very careful here if you are using backports -- there is a [report](https://github.com/mikebrady/shairport-sync/issues/2195#issuecomment-4325326002) that installing `systemd-dev` on a backported system can severely damage it. ``` $ apt install --dry-run --no-install-recommends systemd-dev ``` Only if that looks okay, proceed to: ``` # apt install --no-install-recommends systemd-dev ``` ### Fedora (Fedora 40) Important: to get the correct version of FFmpeg, _before you install the libraries_, please ensure the you have [enabled](https://docs.fedoraproject.org/en-US/quick-docs/rpmfusion-setup) RPM Fusion software repositories to the "Nonfree" level. If this is not done, the FFmpeg libraries will lack a suitable AAC decoder, preventing Shairport Sync from working in AirPlay 2 mode. ``` # yum update # yum install --allowerasing make automake gcc gcc-c++ \ git autoconf automake avahi-devel libconfig-devel openssl-devel popt-devel soxr-devel \ ffmpeg ffmpeg-devel libplist-devel libsodium-devel libgcrypt-devel libuuid-devel vim-common \ alsa-lib-devel ``` If you are building classic Shairport Sync, the list of packages is shorter: ``` # yum update # yum install make automake gcc gcc-c++ \ git autoconf automake avahi-devel libconfig-devel openssl-devel popt-devel soxr-devel \ ffmpeg ffmpeg-devel alsa-lib-devel ``` ### Arch Linux After you have installed the libraries, note that you should enable and start the `avahi-daemon` service. ``` # pacman -Syu # pacman -Sy git base-devel alsa-lib popt libsoxr avahi libconfig \ libsndfile libsodium ffmpeg vim libplist ``` If you are building classic Shairport Sync, the list of packages is shorter: ``` # pacman -Syu # pacman -Sy git base-devel alsa-lib popt libsoxr avahi libconfig ffmpeg ``` Enable and start the `avahi-daemon` service. ``` # systemctl enable avahi-daemon # systemctl start avahi-daemon ``` ### FreeBSD This is for FreeBSD 14.3. First, update everything: ``` # freebsd-update fetch # freebsd-update install # pkg update # pkg upgrade ``` Next, install the Avahi subsystem. FYI, `avahi-app` is chosen because it doesn’t require X11. If you are using a GUI with your FreeBSD system, select `avahi` rather than `avahi-app`. `nss_mdns` is included to allow FreeBSD to resolve mDNS-originated addresses – it's not actually needed by Shairport Sync. Thanks to [reidransom](https://gist.github.com/reidransom/6033227) for this. ``` # pkg install avahi-app nss_mdns ``` Add these lines to `/etc/rc.conf`: ``` dbus_enable="YES" avahi_daemon_enable="YES" ``` Next, change the `hosts:` line in `/etc/nsswitch.conf` to ``` hosts: files dns mdns ``` Reboot for these changes to take effect. Next, install the packages that are needed for Shairport Sync and NQPTP. If you will be using using `--with-sndio` instead of `--with-alsa` – see below – you can omit the `alsa-utils` package. If you are building Shairport Sync for AirPlay 2, install the following packages: ``` # pkg install git autotools pkgconf popt libconfig openssl alsa-utils libsoxr \ libplist libsodium ffmpeg libuuid vim ``` If you are building classic Shairport Sync, the list of packages is shorter: ``` # pkg install git autotools pkgconf popt libconfig openssl alsa-utils ffmpeg ``` ## 3. Build ### NQPTP Skip this section if you are building classic Shairport Sync – NQPTP is not needed for classic Shairport Sync. Download, install, enable and start NQPTP from [here](https://github.com/mikebrady/nqptp). ### Shairport Sync #### Build and Install Download Shairport Sync and configure, compile and install it. Before executing the commands, please note the following: ##### Build Options * **FreeBSD:** For FreeBSD, replace `--with-systemd-startup` with `--with-os=freebsd --with-freebsd-startup`. * Optionally, replace `--with-alsa` with the backend for FreeBSD's native audio system `--with-sndio`. * If you omit the `--sysconfdir=/etc` entry, `/usr/local/etc` will be used as the `sysconfdir`, which is conventionally used in FreeBSD. * **Classic Shairport Sync:** For classic Shairport Sync, replace `--with-airplay-2` with `--with-ffmpeg`. * You can actually omit `--with-ffmpeg` when building classic Shairport Sync, but it is not recommended. While you'll save space (you can omit the FFMpeg libraries in the build and run-time environments), transcoding, e.g. from 44,100 to 48,000 frames per second, will not be available and less well-maintained and less secure decoders will be used. * **Extra Features:** If you wish to add extra features, for example an extra audio backend, take a look at the [configuration flags](CONFIGURATION%20FLAGS.md). For this walkthrough, though, please do not change too much! ``` $ git clone https://github.com/mikebrady/shairport-sync.git $ cd shairport-sync $ autoreconf -fi # about 1.5 minutes on a Raspberry Pi B $ ./configure --sysconfdir=/etc --with-alsa \ --with-soxr --with-avahi --with-ssl=openssl --with-systemd-startup --with-airplay-2 $ make # just over 7 minutes on a Raspberry Pi B # make install ``` ## 4. Test At this point, Shairport Sync should be built and installed but not running. Now you can test it out from the command line. Before you start testing, though, if you have built Shairport Sync for AirPlay 2 operation, ensure `NQPTP` is running. To check the installation, enter: ``` $ shairport-sync ``` * Add the `-v` command line option to get some diagnostics. * Add the `--statistics` option to get some infomation about the audio received. The AirPlay service should appear on the network and the audio you play should come through to the default audio output device. You can use the AirPlay volume control or the system's volume controls or a command-line tool like `alsamixer` to adjust levels. If you have problems, please check the hints in Final Notes below, or in the [TROUBLESHOOTING.md](TROUBLESHOOTING.md) guide. When you are finished running Shairport Sync, use Control-C it to stop it. ## 5. Enable and Start Service ### Linux If your system uses either PipeWire or PulseAudio as sound servers (most "desktop" Linuxes use one or the other), Shairport Sync must be started as a user service. This is because the PipeWire or PulseAudio services – needed by Shairport Sync – are user services themselves, and they must be running before Shairport Sync starts. That implies that Shairport Sync must be started as a user service. #### Checking for PipeWire or PulseAudio If PipeWire is installed and running, the following command should return status information, as follows: ``` $ systemctl --user status pipewire ● pipewire.service - PipeWire Multimedia Service Loaded: loaded (/usr/lib/systemd/user/pipewire.service; enabled; preset: enabled) ... ``` If not, it will return something like this: ``` $ systemctl --user status pipewire Unit pipewire.service could not be found. ``` Similarly, if PulseAudio is installed, the following command return status information: ``` $ systemctl --user status pulseaudio ``` If PipeWire or PulseAudio is installed, you must enable Shairport Sync as a _user service_ only. #### Enable Shairport Sync as a User Service To enable Shairport Sync as a user service that starts automatically when the user logs in, reboot, ensure you are logged in as that user and then run the following convenience script: ``` $ sh user-service-install.sh ``` This will run a few checks, install a user startup script and start Shairport Sync immediately. (Run `$ sh user-service-install.sh --dry-run` initially if you prefer...) ##### User Service Limitations. 1. If Shairport Sync is installed as a user service, it is activated when that user logs in and deactivated when the user logs out. On an unattended system, this difficulty can be overcome by using automatic user login. 2. If your system has a GUI (that is, if it's a "desktop Linux"), then audio will only be routed to the speakers when the user is logged in through the GUI. #### Enable Shairport Sync as a System Service If your system does not have either PipeWire or PulseAudio installed (see how to check above), then you can enable Shairport Sync as a system service that starts automatically when the system boots up. To do so – assuming you have followed the build guide successfully – enter the following command: ``` # systemctl enable shairport-sync ``` This enables Shairport Sync to start automatically when the system boots up. Please remember, this will not work if PipeWire or PulseAudio are installed on your system. You should not enable Shairport Sync as a user service and a system service at the same time! ### FreeBSD To make the `shairport-sync` daemon load at startup, add the following line to `/etc/rc.conf`: ``` shairport_sync_enable="YES" ``` ## 6. Check Reboot the machine. The AirPlay service should once again be visible on the network and audio will be sent to the default audio output. ## 7. Final Notes A number of system settings can affect Shairport Sync. Please review them as follows: ### ALSA Output Devices If your system is _not_ using PipeWire or PulseAudio (see [above](#checking-for-pipewire-or-pulseaudio)), it probably uses ALSA directly. The following hints might be useful: 1. To access ALSA output devices, a user must be in the `audio` group. To add the current user to the `audio` group, enter: ``` $ sudo usermod -aG audio $USER ``` 2. Ensure that the ALSA default output device is not muted and has the volume turned up – `alsamixer` is very useful for this. 3. To explore the ALSA output devices on your system, consider using the [dacquery](https://github.com/mikebrady/dacquery) tool. ### Power Saving If your computer has an `Automatic Suspend` Power Saving Option, you should experiment with disabling it, because your computer has to be available for AirPlay service at all times. ### WiFi Power Management – Linux If you are using WiFi, you should turn off WiFi Power Management. On a Raspberry Pi, for example, you can use the following commands: ``` # iwconfig wlan0 power off ``` or ``` # iw dev wlan0 set power_save off ``` The motivation for this is that WiFi Power Management will put the WiFi system in low-power mode when the WiFi system is considered inactive. In this mode, the system may not respond to events initiated from the network, such as AirPlay requests. Hence, WiFi Power Management should be turned off. See [TROUBLESHOOTING.md](https://github.com/mikebrady/shairport-sync/blob/master/TROUBLESHOOTING.md#wifi-adapter-running-in-power-saving--low-power-mode) for more details. (You can find WiFi device names (e.g. `wlan0`) with `$ ifconfig`.) ### Firewall If a firewall is running (some systems, e.g. Fedora, run a firewall by default), ensure it is not blocking ports needed by Shairport Sync and [NQPTP](https://github.com/mikebrady/nqptp/blob/main/README.md#firewall). ## 8. Connect and enjoy... ### Add to Home With AirPlay 2, you can follow the steps in [ADDINGTOHOME.md](ADDINGTOHOME.md) to add your device to the Apple Home system. ### Wait, there's more... At this point, you should have a basic functioning Shairport Sync installation. If you want more control – for example, using the ALSA backend, if you want to use a specific DAC, or if you want AirPlay to control the DAC's volume control – you can use settings in the configuration file or you can use command-line options. #### Configuration Sample File When you run `# make install`, a configuration file is installed if one doesn't already exist. Additionally, a sample configuration file called `shairport-sync.conf.sample` is _always_ installed. This contains all the setting groups and all the settings available, commented out so that default values are used. The file contains explanations of the settings, useful hints and suggestions. The configuration file and the sample configuration file are installed in the `sysconfdir` you specified at the `./configure...` step above. 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. shairport-sync-5.1-dev/CAR INSTALL.md000066400000000000000000000413321520255574400171520ustar00rootroot00000000000000# Shairport Sync for Cars If your car audio has an AUX input, you can get AirPlay in your car using Shairport Sync. Together, Shairport Sync and an iPhone or an iPad with cellular capability can give you access to internet radio, YouTube, Apple Music, Spotify, etc. on the move. While Shairport Sync is no substitute for CarPlay, the audio quality is often much better than Bluetooth. ## The Basic Idea The basic idea is to use a small Linux computer to create an isolated WiFi network (a "Car WiFi Network") and run Shairport Sync on it to provide an AirPlay service. An iPhone or an iPad with cellular capability can simultaneously connect to internet radio, YouTube, Apple Music, Spotify, etc. over its cellular network connection and send AirPlay audio through the Car WiFi Network to the AirPlay service provided by Shairport Sync. This sends the audio to the computer's sound card or DAC, which is connected to the AUX input of your car audio. Please note that Android phones and tablets can not, so far, do this trick of using the two networks simultaneously. ## Example This example is based on Raspberry Pi OS Lite (Trixie). Note that some of the details will vary if you are using a different version of Linux. If you are updating an existing installation, please refer to the [updating](#updating) section below. In this example, a Raspberry Pi Zero W and a Pimoroni PHAT DAC are used. Shairport Sync will be built for AirPlay 2 operation. You can build classic Shairport Sync to support only the original "classic" AirPlay (aka AirPlay 1) if you prefer. ### Prepare the initial SD Image * Download Raspberry Pi OS Lite (Trixie) and install it onto an SD Card using `Raspberry Pi Imager`. The Lite version is preferable to the Desktop version as it doesn't include a sound server like PulseAudio or PipeWire that is not needed in this case. * Before writing the image to the card, use the Settings control on `Raspberry Pi Imager` to set hostname, enable SSH and provide a username and password to use while building the system. Similarly, you can specify a wireless network the Pi will connect to while building the system. Later on, the Pi will be configured to start its own isolated network. * The next few steps are to add the overlay needed for the sound card. This may not be necessary in your case, but in this example a Pimoroni PHAT is being used. If you do not need to add an overlay, skip these steps. * Mount the card on a Linux machine. Two drives should appear – a `boot` drive and a `rootfs` drive. * `cd` to the `boot` drive (since my username is `mike`, it will be `$ cd /media/mike/boot`). * From there, cd to the `firmware` subdirectory, i.e. `/boot/firmware`. * Edit the `config.txt` file to add the overlay needed for the sound card. This may not be necessary in your case, but in this example a Pimoroni PHAT is being used and it needs the following entry to be added: ``` dtoverlay=hifiberry-dac ``` * Close the file and carefully dismount and eject the two drives. *Be sure to dismount and eject the drives properly; otherwise they may be corrupted.* * Remove the SD card from the Linux machine, insert it into the Pi and reboot. After a short time, the Pi should appear on your network – it may take a couple of minutes. To check, try to `ping` it at the `.local`, e.g. if the hostname is `bmw` then use `$ ping bmw.local`. Once it has appeared, you can SSH into it and configure it. ### Boot, Configure, Update The first thing to do on a Pi would be to do the usual update and upgrade: ``` # apt-get update # apt-get upgrade ``` ### Build and Install Let's get the tools and libraries for building and installing Shairport Sync (and NQPTP). ``` # apt update # apt upgrade # this is optional but recommended # 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 uuid-dev libgcrypt-dev xxd libplist-utils \ libavutil-dev libavcodec-dev libavformat-dev systemd-dev ``` 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 autoconf automake libtool \ libpopt-dev libconfig-dev libasound2-dev avahi-daemon libavahi-client-dev libssl-dev libsoxr-dev \ libavutil-dev libavcodec-dev libavformat-dev systemd-dev ``` Note: older versions of the Raspberry Pi OS don't have -- and don't need -- the `systemd-dev` package. If it is reported as unknown, omit if from the installation. #### NQPTP Skip this step if you are building classic Shairport Sync – NQPTP is not needed for classic Shairport Sync. Download, install, enable and start NQPTP from [here](https://github.com/mikebrady/nqptp/tree/development) following the guide for Linux. #### Shairport Sync Download Shairport Sync, configure, compile and install it. * Replace `--with-airplay-2` from the `./configure` options with `--with-ffmpeg` if you are building classic Shairport Sync. ``` $ git clone https://github.com/mikebrady/shairport-sync.git $ cd shairport-sync $ git checkout development $ autoreconf -fi $ ./configure --sysconfdir=/etc --with-alsa \ --with-soxr --with-avahi --with-ssl=openssl --with-systemd-startup --with-airplay-2 $ make # make install # systemctl enable shairport-sync ``` The `autoreconf` step may take quite a while – please be patient! ### Configure Shairport Sync Here are the important options for the Shairport Sync configuration file at `/etc/shairport-sync.conf`: ``` // Sample Configuration File for Shairport Sync for Car Audio with a Pimoroni PHAT general = { name = "BMW Radio"; ignore_volume_control = "yes"; volume_max_db = -3.00; }; alsa = { output_device = "hw:1"; // the name of the alsa output device. Use "alsamixer" or "aplay" to find out the names of devices, mixers, etc. }; ``` Two `general` settings are worth noting. 1. First, the option to ignore the sending device's volume control is enabled. This means that the car audio's volume control is the only one that affects the audio volume. This is a matter of personal preference. 2. Second, the maximum output offered by the DAC to the AUX port of the car audio can be reduced if it is overloading the car audio's input circuits and causing distortion. Again, that's a matter for personal selection and adjustment. The `alsa` settings are for the Pimoroni PHAT – it does not have a hardware mixer, so no `mixer_control_name` is given. The DAC's 32-bit capability is automatically selected if available, so there is no need to set it here. Similarly, since `soxr` support is included in the build, `soxr` interpolation will be automatically enabled if the device is fast enough. ### Extra Packages A number of packages to enable the Pi to work as a WiFi base station are needed: ``` # apt install --no-install-recommends hostapd isc-dhcp-server ``` (The installer will get errors trying to set up both of these services; the errors can be ignored.) Disable both of these services from starting at boot time (this is because we will launch them sequentially later on): ``` # systemctl unmask hostapd # systemctl disable hostapd # systemctl disable isc-dhcp-server ``` #### Configure HostAPD Configure `hostapd` by creating `/etc/hostapd/hostapd.conf` with the following contents which will set up an open network with the name BMW. You might wish to change the name: ``` # Thanks to https://wiki.gentoo.org/wiki/Hostapd#802.11b.2Fg.2Fn_triple_AP # The interface used by the AP interface=wlan0 # This is the name of the network -- yours may be different ssid=BMW # "g" simply means 2.4GHz band hw_mode=g # Channel to use channel=11 # Limit the frequencies used to those allowed in the country ieee80211d=1 # The country code country_code=IE # Enable 802.11n support ieee80211n=1 # QoS support, also required for full speed on 802.11n/ac/ax wmm_enabled=1 ``` Note that, since the car network is isolated from the Internet, you don't really need to secure it with a password. #### Configure DHCP server First, replace the contents of `/etc/dhcp/dhcpd.conf` with this: ``` subnet 10.0.10.0 netmask 255.255.255.0 { range 10.0.10.5 10.0.10.150; #option routers ; #option broadcast-address ; } ``` Second, modify the `INTERFACESv4` entry at the end of the file `/etc/default/isc-dhcp-server` to look as follows: ``` INTERFACESv4="wlan0" INTERFACESv6="" ``` ### Set up the Startup Sequence Configure the startup sequence by adding commands to `/etc/rc.local`. If `/etc/rc.local` does not already exist, create it with owner and group `root` and permissons `755`. The commands will start the necessary services automatically after startup, depending on the `MODE` -- `DEC` for develoment mode, and `RUN` for normal operating mode. The contents of `/etc/rc.local` should look like this: ``` #!/bin/sh -e # # rc.local # # Shairport Sync is automatically started as a service on startup. # If MODE is set to RUN, the system will start the WiFi access point. # If MODE is set to anything else, e.g. DEV, the system will not start the WiFi access point. # Instead, you can connect the system to a network. # If it still has the WiFi credentials of the last WiFi network it connected to, # it can connect to it automatically. MODE=RUN /bin/sleep 2 # may be necessary while wlan0 becomes available /sbin/iw dev wlan0 set power_save off # always do this if test $MODE = RUN ; then # If script execution gets in here, it starts the WiFi access point. /usr/sbin/hostapd -B -P /run/hostapd.pid /etc/hostapd/hostapd.conf /sbin/ip addr add 10.0.10.1/24 dev wlan0 /bin/systemctl start isc-dhcp-server else # If script execution gets in here, it starts services needed for normal operation. /bin/systemctl start dhcpcd || /bin/systemctl start NetworkManager || : /bin/sleep 2 # may be necessary while the network becomes available /bin/systemctl start systemd-timesyncd || : fi exit 0 # normal exit here ``` #### Disable Services - Mandatory You now need to disable some services; that is, you need to stop them starting automatically on power-up. This is because they interfere with the system's operation in WiFi Access Point mode, or because they don't work when the system isn't connected to the Internet. A further possibility if that they will be started by the script in `/etc/rc.local` when appropriate. Only one of the `NetworkManager` and the `dhcpcd` service will be present in your system, but it's no harm to try to disable both. ``` # systemctl disable dhcpcd # systemctl disable NetworkManager # systemctl disable wpa_supplicant # systemctl disable systemd-timesyncd ``` #### Disable Unused Services - Optional These optional steps have been tested on a Raspberry Pi Lite (Trixie) only -- they have not been tested on other systems. Some services are not necessary for this setup and can be disabled as follows: ``` # systemctl disable keyboard-setup ``` #### Security Note The WiFi credentials you used initially to connect to your network (e.g. your home network) will have been stored in the system. This is convenient for when you want to reconnect to update (see later), but if you prefer to delete them, use `nmtui` or `nmcli` to remove them. #### Optional: Read-only mode – Raspberry Pi Specific This optional step is applicable to a Raspberry Pi only. Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem` and choose to enable the overlay filesystem, and to set the boot partition to be write-protected. (The idea here is that this offers more protection against files being corrupted by the sudden removal of power.) Note that some packages may be installed to enable read-only mode, so the Pi needs to be connected to the internet for this step. Thus, if may be necessary to temporarily enable and disable read-only mode while connected to your network before re-enabling it after restarting in its final `RUN` mode as a stand-alone AirPlay receiver. ### Final Step When you are finished, carefully power down the machine before unplugging it from power: ``` # poweroff ``` Note: doing a `reboot` here doesn't seem to work properly -- it really does seem necessary to power off. ### Ready Install the Raspberry Pi in your car. It should be powered from a source that is switched off when you leave the car, otherwise the slight current drain will eventually flatten the car's battery. When the power source is switched on -- typically when you start the car -- it will take around 75 seconds for the system to become available using a Raspberry Pi Zero W, about 35 seconds with a Pi Zero 2 W. ### Enjoy! --- ## Updating From time to time, you may wish to update this installation. Assuming you haven't deleted your original WiFi network credentials, the easiest thing is to temporarily reconnect to the network you used when you created the system. You can then update the operating system and libraries in the normal way and then update Shairport Sync. However, if you're *upgrading* the operating system to e.g. from Bullseye to Bookworm, the names and index numbers of the output devices may change, and the names of the mixer controls may also change. You can use [`dacquery`](https://github.com/mikebrady/dacquery) to discover device names and mixer names. #### Exit Raspberry Pi Read-Only Mode If it's a Raspberry Pi and you have optionally enabled the read-only mode, you must take the device out of Read-only mode: Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem` and choose to disable the overlay filesystem and to set the boot partition not to be write-protected. This is so that changes can be written to the file system; you can make the filesystem read-only again later. Save the changes and reboot the system. #### Undo Optimisations If you have disabled any of the services listed in the [Disable Unused Services - Optional](#disable-unused-services---optional) section, you should re-enable them. (But *do not* re-eneable `NetworkManager`, `dhcpcd`, `wpa_supplicant` or `systemd-timesyncd` -- they are handled specially by the startup script.) #### Perform Legacy Updates Over time, the arrangements by which the system is prepared for operation has changed to make it easier to revert to normal operation when necessary for maintenance, updates, etc. A small number of the old settings need to be changed to bring them up to date with the present arrangements. Once the required changes have been made, your system will be ready for the update process detailed below. Here are those legacy changes you need to make, just once: 1. If there is a file called `/etc/dhcpcd.conf` and if the first line reads: ``` denyinterfaces wlan0 ``` then delete that line -- it is no longer needed and will cause problems in future if it remains there. If the file `/etc/dhcpcd.conf` doesn't exist, or if the first line is not `denyinterfaces wlan0`, then you don't need to do anything. 2. Replace the contents of the file `/etc/rc.local` with the new contents given [above](#set-up-the-startup-sequence). 3. Disable a number of services as follows. Only one of the `NetworkManager` and the `dhcpcd` service will be present in your system, but it's no harm to try to disable both. ``` # systemctl disable dhcpcd # systemctl disable NetworkManager # systemctl disable wpa_supplicant # systemctl disable systemd-timesyncd ``` 4. Enable the `shairport-sync` service itself: ``` # systemctl enable shairport-sync ``` Once you have made these one-off legacy updates, you can proceed to the next stage -- performing the update. ### Performing the Update To update, take the following steps: #### Temporarily reconnect to a network and update 1. Edit the startup script in `/etc/rc.local` to so that the system is no longer in the RUN mode. To do that, change line 15 so that it goes from this: ``` MODE=RUN ``` to this: ``` MODE=DEV ``` Do not be tempted to insert any spaces anywhere -- Unix scripting syntax is very strict! 2. Save and close the file and reboot. From this point on, the system will start normally and can be connected to a network. If it still has the WiFi credentials of the last network it was connected to, then it could automatically reconnect. The system is now ready for updating in the normal way. #### Revert to normal operation When you are finished updating, you need to put the system back into its RUN mode, as follows: 1. Edit the startup script in `/etc/rc.local` to so that the MODE variable is set to RUN. To do that, change line 15 so that it goes from this: ``` MODE=DEV ``` to this: ``` MODE=RUN ``` Once again, do insert any spaces anywhere. 2. Save and close the file and reboot. The system should start as it would if it was in the car. shairport-sync-5.1-dev/CONFIGURATION FLAGS.md000066400000000000000000000317541520255574400203110ustar00rootroot00000000000000# Configuration Flags When the application is being built, these flags determine what capabilities are included in Shairport Sync. For example, to include DSP capabilities – needed for a loudness filter – you would include the `--with-convolution` flag in the list of options at the `./configure ...` stage when building the application. In the following sections, Shairport Sync's compilation configuration options are detailed by catgegory. ## AirPlay 2 or AirPlay | Flag | | ---- | | `--with-airplay-2` | _AirPlay 2_ is the current version of the AirPlay protocol. It offers multi-room operation and integration with the Home application. However, the Shairport Sync implementation is doesn't support iTunes on Windows, and its integration with the Home app and support for remote control is incomplete. Additionally, it requires a fairly recent (2018 or later) version of a Debian-like Linux, Alpine Linux or FreeBSD. It has not been tested on other Linux distributions such as OpenWrt. Finally, AirPlay 2 can be lossy – in one mode of operation, audio is encoded in 256kbps AAC. _AirPlay_ (without the "2", aka "classic AirPlay" or "AirPlay 1") is an older version of the AirPlay protocol. If offers multi-room operation to iTunes on macOS or Windows, the Music app on macOS and some third-party computer applications such as [OwnTone](https://owntone.github.io/owntone-server/). It will run on lower powered machines, including many embedded devices. This version of AirPlay is lossless – audio is received in 44,100 frames per second 16-bit interleaved stereo ALAC format. It is compatible with a wider range of Linux distributions, back to around 2012. However, support for this version of AirPlay seems to be gradually waning. It does not offer multi-room operation to iOS, iPadOS or AppleTV and is incompatible with HomePod. It is not integrated with the Home app. To build Shairport Sync for AirPlay 2, include the `--with-airplay-2` option in the `./configure ...` options. You will also have to include extra libraries. Omitting this option will cause Shairport Sync to be built for the older AirPlay protocol. Include the `--with-ffmpeg` to build for classic AirPlay but using the FFmpeg libraries for decoding and for transcoding. This is recommended for classic AirPlay because it is better maintained and more flexible. Unfortunately, the FFmpeg library is very bulky and so many embedded devices simply don't have space for it. ## Audio Output | Flags | | ----- | | `--with-alsa` | | `--with-sndio` | | `--with-pipewire` | | `--with-pulseaudio` | | `--with-jack` | | `--with-ao` | | `--with-stdout` | | `--with-pipe` | Shairport Sync has a number of different "backends" that send audio to an onward destination, e.g. an audio subsystem for output to a Digital to Audio Converter and thence to loudspeakers, or to a pipe for further processing. You can use configuration options to include support for multiple backends at build time and select one of them at runtime. Here are the audio backend configuration options: - `--with-alsa` Output to the Advanced Linux Sound Architecture ([ALSA](https://www.alsa-project.org/wiki/Main_Page)) system. This is recommended for highest quality. - `--with-sndio` Output to the FreeBSD-native [sndio](https://sndio.org) system. - `--with-pipewire` Output to the [PipeWire](https://pipewire.org) sound server. - `--with-pulseaudio` Include the [PulseAudio](https://www.freedesktop.org/wiki/Software/PulseAudio) sound server. - `--with-jack` Output to the [Jack Audio](https://jackaudio.org) system. - `--with-ao` Output to the [libao](https://xiph.org/ao/) system. No synchronisation. - `--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. ### PulseAudio and PipeWire If your system uses either PipeWire or PulseAudio as sound servers, Shairport Sync must be started as a user service. This is because the PipeWire or PulseAudio services -- needed by Shairport Sync -- are user services themselves, and they must be running before Shairport Sync starts. That implies that Shairport Sync must be started as a user service. PipeWire and PulseAudio provide a default ALSA pseudo device, so that Shairport Sync can therefore use the ALSA backend with PipeWire- or PulseAudio-based systems. ## Audio Options | Flags | | ----- | | `--with-soxr` | | `--with-apple-alac` | | `--with-convolution` | | `--with-ffmpeg` | - `--with-soxr` Enables Shairport Sync to use [libsoxr](https://sourceforge.net/p/soxr/wiki/Home/)-based resampling for improved interpolation. Recommended. - `--with-apple-alac` Enables Shairport Sync to use the Apple ALAC Decoder. Requires [`libalac`](https://github.com/mikebrady/alac). Deprecated due to security issues. - `--with-convolution` Includes a convolution filter that can be used to apply effects such as frequency and phase correction, and a loudness filter that compensates for the non-linearity of the human auditory system. Requires `libsndfile`. Note that this is only available with audio at 44100 frames per second at present. - `--with-ffmpeg` Enables classic Shairport Sync to use the [FFmpeg](https://ffmpeg.org) ALAC decoder and the FFmpeg software resampler to transcode, e.g. from 44100 to 48000 frames per second. Requires FFmpeg libraries. (Note: this is for Classic AirPlay only -- `--with-ffmpeg` is automatically enabled for AirPlay 2.) ## Metadata | Flags | | ----- | | `--with-metadata` | Metadata such as track name, artist name, album name, cover art and more can be requested from the player and passed to other applications. - `--with-metadata` Adds support for Shairport Sync to request metadata and to pipe it to a compatible application. See https://github.com/mikebrady/shairport-sync-metadata-reader for a sample metadata reader. ## Inter Process Communication | Flags | | ----- | | `--with-mqtt-client` | | `--with-dbus-interface` | | `--with-dbus-test-client` | | `--with-mpris-interface` | | `--with-mpris-test-client` | Shairport Sync offers three Inter Process Communication (IPC) interfaces: an [MQTT](https://mqtt.org) interface, an [MPRIS](https://specifications.freedesktop.org/mpris-spec/latest/)-like interface and a Shairport Sync specific "native" D-Bus interface loosely based on MPRIS. The options are as follows: - `--with-mqtt-client` Includes a client for [MQTT](https://mqtt.org), - `--with-dbus-interface` Includes support for the native Shairport Sync D-Bus interface, - `--with-dbus-test-client` Compiles a D-Bus test client application, - `--with-mpris-interface` Includes support for a D-Bus interface conforming as far as possible with the MPRIS standard, - `--with-mpris-test-client` Compiles an MPRIS test client application. D-Bus and MPRIS commands and properties can be viewed using utilities such as [D-Feet](https://wiki.gnome.org/Apps/DFeet). ##### MPRIS The MPRIS interface has to depart somewhat from full MPRIS compatibility due to logical differences between Shairport Sync and a full standalone audio player such as Rhythmbox. Basically there are some things that Shairport Sync itself can not control that a standalone player can control. A good example is volume control. MPRIS has a read-write `Volume` property, so the volume can be read or set. However, all Shairport Sync can do is *request* the player to change the volume control. This request may or may not be carried out, and it may or may not be done accurately. So, in Shairport Sync's MPRIS interface, `Volume` is a read-only property, and an extra command called `SetVolume` is provided. ## Other Configuration Options ### Configuration Files | Flags | | ----- | | `--sysconfdir=` | Shairport Sync will look for a configuration file – `shairport-sync.conf` by default – when it starts up. By default, it will look in the directory specified by the `sysconfdir` configuration variable, which defaults to `/usr/local/etc`. This is normal in BSD Unixes, but is unusual in Linux. Hence, for Linux installations, you need to set the `sysconfdir` variable to `/etc` using the configuration setting `--sysconfdir=/etc`. ### Daemonisation | Flags | | ----- | | `--with-libdaemon` | | `--with-piddir=` | A [daemon](https://en.wikipedia.org/wiki/Daemon_(computing)) is a computer program that runs as a background process, rather than being under the direct control of an interactive user. Shairport Sync is designed to run as a daemon. FreeBSD and most recent Linux distributions can run an application as a daemon without special modifications. However, in certain older distributions and in special cases it may be necessary to enable Shairport Sync to daemonise itself. Use the `--with-libdaemon` configuration option: - `--with-libdaemon` Includes a demonising library needed if you want Shairport Sync to demonise itself with the `-d` option. Not needed for `systemd`-based systems which demonise programs differently. - `--with-piddir=` Specifies a pathname to a directory in which to write the PID file which is created when Shairport Sync daemonises itself and used to locate the daemon process to be killed with the `-k` command line option. ### Automatic Start | Flags | | ----- | | `--with-systemd-startup` | | `--with-systemdsystemunitdir=` | | `--with-systemv-startup` | | `--with-freebsd-startup` | | `--with-cygwin-service` | Daemon programs such as Shairport Sync should be started automatically so that the service they provide becomes available without further intervention. Typically this is done using startup scripts. Four options are provided – two for Linux, one for FreeBSD and one for CYGWIN. In Linux, the choice depends on whether [systemd](https://en.wikipedia.org/wiki/Systemd) is used or not. If `systemd` is installed, then the `--with-systemd-startup` option is suggested. If not, the `--with-systemv-startup` option is suggested. - `--with-systemd-startup` Includes scripts to create a Shairport Sync service that can optionally launch automatically at startup or at user login on `systemd`-based Linuxes. Default is not to to install. Note: an associated special-purpose option allows you to specify where the `systemd` system startup file will be placed: - `--with-systemdsystemunitdir=` Specifies the directory for `systemd` service files. - `--with-systemv-startup` Includes a script to create a Shairport Sync service that can optionally launch automatically at startup on System V based Linuxes. Default is not to to install. - `--with-freebsd-startup` Includes a script to create a Shairport Sync service that can optionally launch automatically at startup on FreeBSD. Default is not to to install. - `--with-cygwin-service` Includes a script to create a Shairport Sync service that can optionally launch automatically at startup on CYGWIN. Default is not to to install. ### Cryptography | Flags | | ----- | | `--with-ssl=openssl` | | `--with-ssl=mbedtls` | | `--with-ssl=polarssl` | AirPlay 2 operation requires the OpenSSL libraries, so the option `--with-ssl=openssl` is mandatory. For classic Shairport Sync, the options are as follows: - `--with-ssl=openssl` Uses the [OpenSSL](https://www.openssl.org) cryptography toolkit. This is mandatory for AirPlay 2 operation. - `--with-ssl=mbedtls` Uses the [Mbed TLS](https://github.com/Mbed-TLS/mbedtls) cryptography library. Only suitable for classic AirPlay operation – do not include it in an AirPlay 2 configuration. - `--with-ssl=polarssl` Uses the PolarSSL cryptography library. This is deprecated – PolarSSL has been replaced by Mbed TLS. Only suitable for classic AirPlay operation – do not include it in an AirPlay 2 configuration. ### Zeroconf/Bonjour | Flags | | ----- | | `--with-avahi` | | `--with-tinysvcmdns` | | `--with-external-mdns` | | `--with-dns_sd` | AirPlay devices advertise their existence and status using [Zeroconf](http://www.zeroconf.org) (aka [Bonjour](https://en.wikipedia.org/wiki/Bonjour_(software))). AirPlay 2 operation requires the [Avahi](https://www.avahi.org) libraries, so the option `--with-avahi` is mandatory. For classic Shairport Sync, the options are as follows: The Zeroconf-related options are as follows: - `--with-avahi` Chooses [Avahi](https://www.avahi.org)-based Zeroconf support. This is mandatory for AirPlay 2 operation. - `--with-tinysvcmdns` Chooses [tinysvcmdns](https://github.com/philippe44/TinySVCmDNS)-based Zeroconf support (deprecated). - `--with-external-mdns` Supports the use of ['avahi-publish-service'](https://linux.die.net/man/1/avahi-publish-service) or 'mDNSPublish' to advertise the service on Bonjour/ZeroConf. - `--with-dns_sd` Chooses `dns-sd` Zeroconf support. ### Miscellaneous | Flag | Significance | | -------------------- | ---- | | `--with-os=` | Specifies the Operating System to target: One of `linux` (default), `freebsd`, `openbsd` or `darwin`. | | `--with-configfiles` | Installs configuration files (including a sample configuration file) during `make install`. | | `--with-pkg-config` | Specifies the use of `pkg-config` to find libraries. (Obselete for AirPlay 2. Special purpose use only.) | shairport-sync-5.1-dev/CONFIGURATIONFILECHANGES5.md000066400000000000000000000147451520255574400212130ustar00rootroot00000000000000# Configuration File Changes in Version 5.0 This document summarizes the important changes to the `shairport-sync.conf` configuration file for normal users upgrading to Version 5.0. ## Multi-Channel Audio Support (NEW!) Version 5.0 adds support for multi-channel audio (up to 8 channels), including surround sound formats like 5.1 and 7.1. **New Settings in `general` section (showing defaults):** * `eight_channel_mode = "on"` - Enable 8-channel (7.1 surround) audio reception. * `six_channel_mode = "on"` - Enable 6-channel (5.1 surround) audio reception. * `mixdown = "auto"` - Control how multi-channel audio is mixed down to fewer channels. * `output_channel_mapping = "auto"` - Control how audio channels map to your output device. **What this means for you:** If you have a surround sound system, you can now receive and play multi-channel audio directly. Most users can leave these at their defaults. ## Audio Format and Rate Settings **Enhanced Interpolation Options:** The `interpolation` setting now supports a new `"vernier"` mode especially intended for low-power devices: * `"auto"` (default, recommended) - Automatically chooses the best method for your processor. * `"vernier"` (new!) - Optimized for low-power devices like Raspberry Pi. * `"soxr"` - High quality, needs fast processor. * `"basic"` - No longer recommended. **New FFmpeg Decoder:** The `alac_decoder` setting has changed: * Default is now `"ffmpeg"` (if built with FFmpeg support). * Old `"hammerton"` and `"apple"` decoders are deprecated for security reasons. **New Buffer Setting:** * `audio_decoded_buffer_desired_length_in_seconds = 1.0` - (Advanced.) Controls the internal audio buffer size (AirPlay 2 only). ## Backend-Specific Changes ### ALSA Backend **New format/rate/channel settings** - You can now specify multiple options and let Shairport Sync auto-select: * `output_rate = "auto"` - Can be "auto", a single rate like `48000`, or a list like `(44100, 48000)`. * `output_format = "auto"` - Can be "auto", a format like `"S32_LE"`, or a list. * `output_channels = "auto"` - Can be "auto", a number like `2`, or a list like `(2, 6, 8)`. **What this means:** Shairport Sync can now automatically switch between different audio formats and rates to match your source, or you can lock it to specific settings. **Other ALSA changes:** * `use_mmap_if_available` default changed from `"yes"` to `"no"`. * `disable_standby_mode_silence_scan_interval` default changed from `0.004` to `0.030`. * New: `disable_standby_mode_default_channels = 2` - Initial channel setting when standby mode is disabled. * New: `disable_standby_mode_default_rate` - Initial sample rate when standby mode is disabled. ### PipeWire Backend **Renamed section:** The `pw` section is now called `pipewire`. **New settings:** * `output_rate = "auto"`. * `output_format = "auto"`. * `output_channels = "auto"`. **What this means:** PipeWire now has the same flexible format/rate/channel options as ALSA. ### PulseAudio Backend **Renamed section:** The `pa` section is now called `pulseaudio`. **New settings:** * `output_rate = "auto"`. * `output_format = "auto"`. * `output_channels = "auto"`. * `default_channel_layouts = "alsa"` - Use ALSA-compatible channel layouts (default) or PulseAudio's own layouts. ### Other Backends `sndio`, `pipe`, `stdout`, and `ao` backends have all gained the new `output_rate`, `output_format`, and `output_channels` settings with similar functionality. ## DSP (Convolution and Loudness) Changes **Convolution Filter:** Settings have been renamed for clarity: * `convolution` → `convolution_enabled`. * `convolution_ir_file` → `convolution_ir_files`. * `convolution_max_length` → `convolution_max_length_in_seconds`. **New convolution setting:** * `convolution_thread_pool_size = 1` - Number of CPU threads for convolution processing. **What this means:** - You can now specify multiple impulse response files for different sample rates. - The convolution filter works with both stereo and multi-channel audio. - You can use multiple CPU cores for faster processing (but core management by the OS may cause power supply noise on some systems). **Loudness Filter:** * `loudness` → `loudness_enabled`. * The loudness filter now works with stereo and multi-channel audio at both 44.1k and 48k. ## MQTT Changes **New setting:** * `publish_retain = "no"` - Set to `"yes"` to make the MQTT broker store the last message for each topic. **What this means:** When enabled, new MQTT subscribers will immediately receive the most recent values instead of having to wait for the next update. ## Session Control Changes **Default timeout changed:** * `session_timeout` default changed from `120` seconds to `60` seconds. **What this means:** Shairport Sync will now become available again 60 seconds (instead of 120) after a source disappears. ## Removed Settings The following old settings have been removed: * `resync_recovery_time_in_seconds` - No longer needed with improved synchronization. ## What Should You Do? **For most users:** Your existing configuration file will continue to work, though you might have to make some minimal changes. **Must Do** * If you use PipeWire or PulseAudio, please change over to the new configuration file settings and backend names immediately. **Should Do** * If you are using ALSA plugins, e.g. `plughw:1` to transcode from 44.1k to 48k, consider outputing directly to the underlying hardware device -- `hw:1` in this example -- allowing Shairport Sync to transcode if needed. **If you want to use new features:** 1. **Multi-channel audio:** Leave `eight_channel_mode` and `six_channel_mode` settings at default, or set them to `"on"` if you have a surround sound system. 2. **Better performance on low-power devices:** Leave the `interpolation` setting at default, or set it to `"vernier"`. 3. **MQTT retain:** Set `publish_retain = "yes"` if you want MQTT clients to receive the last known state immediately. 4. **Convolution improvements:** Update your `convolution_ir_file` to `convolution_ir_files` and add multiple impulse response files for different sample rates. 5. **Backend-specific formats:** Specify exact rates/formats/channels if you want to lock Shairport Sync to specific settings, or use "auto" to let it adapt. **To prepare for the future:** Consider updating deprecated setting names to their new equivalents: - `convolution` → `convolution_enabled`. - `convolution_ir_file` → `convolution_ir_files`. - `convolution_max_length` → `convolution_max_length_in_seconds`. - `loudness` → `loudness_enabled`. shairport-sync-5.1-dev/COPYING000066400000000000000000000000721520255574400161630ustar00rootroot00000000000000Please refer to the individual source files for licenses. shairport-sync-5.1-dev/CYGWIN.md000066400000000000000000000120551520255574400164560ustar00rootroot00000000000000Installing Shairport Sync into Cygwin [Airplay 2 Not Supported] ==== This guide is based on installing onto a fresh installation of Cygwin 2.895 (64-bit installation) running in Windows 10 inside VMWare Fusion on a Mac. The end result is a new Windows Service called `CYGWIN Shairport Sync`, providing an AirPlay service by which iOS devices or other AirPlay sources on the network can play audio through the Windows device. Windows Firewall ---- While getting everything working, it is suggested that you temporarily disable the Windows Firewall. Shairport Sync uses port 5000 for TCP and uses three ports for UDP, so you should leave a minimum of three, and preferably at least 10, open from 6001 upwards. The Bonjour Service, used in conjunction with the Avahi daemon, advertises Shairport Sync over a number of further ports. Once everything is working, the firewall can be re-enabled gradually. Setting up Windows ---- Set up Windows 10 and install all updates. Install the `Bonjour Service`, available from Apple in an installer called "Bonjour Print Services for Windows v2.0.2". * Download and run `Bonjour Print Services for Windows v2.0.2` * After accepting conditions and clicking the `Install` button, the installer will do a preliminary installation, installing just the Bonjour Service. It will then pause, inviting you to install Bonjour Print Services. You can decline this, as the Bonjour Service will have been installed during the first part of the installation. * Check Bonjour Service is running. In Windows, open the `Services` desktop application and ensure that you can see `Bonjour Service` running. Setting up Cygwin ---- * Download the Cygwin installer from the [official website](https://cygwin.com/install.html). Save the installer in the Downloads folder. * Open a Windows `Command Prompt` window and enter the following multi-line command, omitting the `C:\Users\mike>` prompt: ``` C:\Users\mike> Downloads\setup-x86_64.exe -P cygrunsrv,dbus,avahi,avahi-tools,gnome-keyring,libavahi-client-devel,^ libglib2.0-devel,openssl,pkg-config,autoconf,automake,clang,libdaemon-devel,popt-devel,^ make,libao-devel,openssl-devel,libtool,git,wget,flex,bison ``` This will do a complete installation of Cygwin and all necessary packages. * Set up the D-Bus and Avahi Services: Open a `Cygwin64 Terminal` window in Administrator mode. Enter the following command: ``` $ messagebus-config ``` Answer `yes` to all queries. Open the Windows `Services` desktop application (if it's already open, refresh the screen contents: `Actions > Refresh`) and look for the `CYGWIN D-Bus system service`. Open it and start it. Next, open (or return to) a `Cygwin64 Terminal` window in Administrator mode. Enter the following command: ``` $ /usr/sbin/avahi-daemon-config ``` Answer `yes` to all queries. Open the Windows `Services` desktop application (if it's already open, refresh the screen contents: `Actions > Refresh`) and look for the `CYGWIN Avahi service`. Open it and start it. The `libconfig` Library ---- Shairport Sync relies on a library – `libconfig` – that is not a Cygwin package, so it must be downloaded, compiled and installed: * Download, configure, compile and install `libconfig`: ``` $ git clone https://github.com/hyperrealm/libconfig.git $ cd libconfig $ autoreconf -fi $ ./configure $ make $ make install $ cd .. ``` Shairport Sync ---- * Download, configure and compile Shairport Sync: ``` $ git clone https://github.com/mikebrady/shairport-sync.git $ cd shairport-sync $ git checkout development // this is temporary $ autoreconf -fi $ PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./configure --with-ao --with-ssl=openssl \ --with-avahi --with-dbus-interface --with-libdaemon --sysconfdir=/etc --with-cygwin-service $ make $ make install ``` * The last step above installs the `shairport-sync` application into `/usr/local/bin` and also installs a configuration file, a service configuration script and two D-Bus policy files. Shairport Sync Service ---- * To install Shairport Sync as a Cygwin Service, open (or return to) a `Cygwin64 Terminal` window in Administrator mode. Enter the following command: ``` $ shairport-sync-config ``` Answer `yes` to all queries. Open the Windows `Services` desktop application (if it's already open, refresh the screen contents: `Actions > Refresh`) and look for the `CYGWIN Shairport Sync` service. Open it and start it. An AirPlay player on the local network should now be able to see an AirPlay output device bearing the computer's Device Name, e.g. `DESKTOP-0RHGN0`. You can set a different name by changing the settings in the Shairport Sync configuration file, installed at `/etc/shairport-sync.conf`. Since Shairport Sync is now a Cygwin Service, you do not need to open Cygwin to launch it – it should launch automatically when Windows is booted up. Known Issues ---- * Shairport Sync cannot access the D-Bus system bus to make its D-Bus interface available. The cause of this problem is unknown. (While the Avahi daemon can access the D-Bus system bus, Shairport Sync can not. The two applications use different D-Bus libraries, so perhaps the issue lies there.) shairport-sync-5.1-dev/ChangeLog000066400000000000000000000000001520255574400166710ustar00rootroot00000000000000shairport-sync-5.1-dev/FFTConvolver/000077500000000000000000000000001520255574400174465ustar00rootroot00000000000000shairport-sync-5.1-dev/FFTConvolver/AudioFFT.cpp000066400000000000000000000612031520255574400215550ustar00rootroot00000000000000// ================================================================================== // Copyright (c) 2017 HiFi-LoFi // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is furnished // to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ================================================================================== #include "AudioFFT.h" #include #include #include #if defined(AUDIOFFT_APPLE_ACCELERATE) #define AUDIOFFT_APPLE_ACCELERATE_USED #include #include #elif defined(AUDIOFFT_FFTW3) #define AUDIOFFT_FFTW3_USED #include #else #if !defined(AUDIOFFT_OOURA) #define AUDIOFFT_OOURA #endif #define AUDIOFFT_OOURA_USED #include #endif namespace audiofft { namespace detail { class AudioFFTImpl { public: AudioFFTImpl() = default; AudioFFTImpl(const AudioFFTImpl &) = delete; AudioFFTImpl &operator=(const AudioFFTImpl &) = delete; virtual ~AudioFFTImpl() = default; virtual void init(size_t size) = 0; virtual void fft(const float *data, float *re, float *im) = 0; virtual void ifft(float *data, const float *re, const float *im) = 0; }; constexpr bool IsPowerOf2(size_t val) { return (val == 1 || (val & (val - 1)) == 0); } template void ConvertBuffer(TypeDest *dest, const TypeSrc *src, size_t len) { for (size_t i = 0; i < len; ++i) { dest[i] = static_cast(src[i]); } } template void ScaleBuffer(TypeDest *dest, const TypeSrc *src, const TypeFactor factor, size_t len) { for (size_t i = 0; i < len; ++i) { dest[i] = static_cast(static_cast(src[i]) * factor); } } } // End of namespace detail // ================================================================ #ifdef AUDIOFFT_OOURA_USED /** * @internal * @class OouraFFT * @brief FFT implementation based on the great radix-4 routines by Takuya Ooura */ class OouraFFT : public detail::AudioFFTImpl { public: OouraFFT() : detail::AudioFFTImpl(), _size(0), _ip(), _w(), _buffer() {} OouraFFT(const OouraFFT &) = delete; OouraFFT &operator=(const OouraFFT &) = delete; virtual void init(size_t size) override { if (_size != size) { _ip.resize(2 + static_cast(std::sqrt(static_cast(size)))); _w.resize(size / 2); _buffer.resize(size); _size = size; const int size4 = static_cast(_size) / 4; makewt(size4, _ip.data(), _w.data()); makect(size4, _ip.data(), _w.data() + size4); } } virtual void fft(const float *data, float *re, float *im) override { // Convert into the format as required by the Ooura FFT detail::ConvertBuffer(_buffer.data(), data, _size); rdft(static_cast(_size), +1, _buffer.data(), _ip.data(), _w.data()); // Convert back to split-complex { double *b = _buffer.data(); double *bEnd = b + _size; float *r = re; float *i = im; while (b != bEnd) { *(r++) = static_cast(*(b++)); *(i++) = static_cast(-(*(b++))); } } const size_t size2 = _size / 2; re[size2] = -im[0]; im[0] = 0.0; im[size2] = 0.0; } virtual void ifft(float *data, const float *re, const float *im) override { // Convert into the format as required by the Ooura FFT { double *b = _buffer.data(); double *bEnd = b + _size; const float *r = re; const float *i = im; while (b != bEnd) { *(b++) = static_cast(*(r++)); *(b++) = -static_cast(*(i++)); } _buffer[1] = re[_size / 2]; } rdft(static_cast(_size), -1, _buffer.data(), _ip.data(), _w.data()); // Convert back to split-complex detail::ScaleBuffer(data, _buffer.data(), 2.0 / static_cast(_size), _size); } private: size_t _size; std::vector _ip; std::vector _w; std::vector _buffer; void rdft(int n, int isgn, double *a, int *ip, double *w) { int nw = ip[0]; int nc = ip[1]; if (isgn >= 0) { if (n > 4) { bitrv2(n, ip + 2, a); cftfsub(n, a, w); rftfsub(n, a, nc, w + nw); } else if (n == 4) { cftfsub(n, a, w); } double xi = a[0] - a[1]; a[0] += a[1]; a[1] = xi; } else { a[1] = 0.5 * (a[0] - a[1]); a[0] -= a[1]; if (n > 4) { rftbsub(n, a, nc, w + nw); bitrv2(n, ip + 2, a); cftbsub(n, a, w); } else if (n == 4) { cftfsub(n, a, w); } } } /* -------- initializing routines -------- */ void makewt(int nw, int *ip, double *w) { int j, nwh; double delta, x, y; ip[0] = nw; ip[1] = 1; if (nw > 2) { nwh = nw >> 1; delta = atan(1.0) / nwh; w[0] = 1; w[1] = 0; w[nwh] = cos(delta * nwh); w[nwh + 1] = w[nwh]; if (nwh > 2) { for (j = 2; j < nwh; j += 2) { x = cos(delta * j); y = sin(delta * j); w[j] = x; w[j + 1] = y; w[nw - j] = y; w[nw - j + 1] = x; } bitrv2(nw, ip + 2, w); } } } void makect(int nc, int *ip, double *c) { int j, nch; double delta; ip[1] = nc; if (nc > 1) { nch = nc >> 1; delta = atan(1.0) / nch; c[0] = cos(delta * nch); c[nch] = 0.5 * c[0]; for (j = 1; j < nch; j++) { c[j] = 0.5 * cos(delta * j); c[nc - j] = 0.5 * sin(delta * j); } } } /* -------- child routines -------- */ void bitrv2(int n, int *ip, double *a) { int j, j1, k, k1, l, m, m2; double xr, xi, yr, yi; ip[0] = 0; l = n; m = 1; while ((m << 3) < l) { l >>= 1; for (j = 0; j < m; j++) { ip[m + j] = ip[j] + l; } m <<= 1; } m2 = 2 * m; if ((m << 3) == l) { for (k = 0; k < m; k++) { for (j = 0; j < k; j++) { j1 = 2 * j + ip[k]; k1 = 2 * k + ip[j]; xr = a[j1]; xi = a[j1 + 1]; yr = a[k1]; yi = a[k1 + 1]; a[j1] = yr; a[j1 + 1] = yi; a[k1] = xr; a[k1 + 1] = xi; j1 += m2; k1 += 2 * m2; xr = a[j1]; xi = a[j1 + 1]; yr = a[k1]; yi = a[k1 + 1]; a[j1] = yr; a[j1 + 1] = yi; a[k1] = xr; a[k1 + 1] = xi; j1 += m2; k1 -= m2; xr = a[j1]; xi = a[j1 + 1]; yr = a[k1]; yi = a[k1 + 1]; a[j1] = yr; a[j1 + 1] = yi; a[k1] = xr; a[k1 + 1] = xi; j1 += m2; k1 += 2 * m2; xr = a[j1]; xi = a[j1 + 1]; yr = a[k1]; yi = a[k1 + 1]; a[j1] = yr; a[j1 + 1] = yi; a[k1] = xr; a[k1 + 1] = xi; } j1 = 2 * k + m2 + ip[k]; k1 = j1 + m2; xr = a[j1]; xi = a[j1 + 1]; yr = a[k1]; yi = a[k1 + 1]; a[j1] = yr; a[j1 + 1] = yi; a[k1] = xr; a[k1 + 1] = xi; } } else { for (k = 1; k < m; k++) { for (j = 0; j < k; j++) { j1 = 2 * j + ip[k]; k1 = 2 * k + ip[j]; xr = a[j1]; xi = a[j1 + 1]; yr = a[k1]; yi = a[k1 + 1]; a[j1] = yr; a[j1 + 1] = yi; a[k1] = xr; a[k1 + 1] = xi; j1 += m2; k1 += m2; xr = a[j1]; xi = a[j1 + 1]; yr = a[k1]; yi = a[k1 + 1]; a[j1] = yr; a[j1 + 1] = yi; a[k1] = xr; a[k1 + 1] = xi; } } } } void cftfsub(int n, double *a, double *w) { int j, j1, j2, j3, l; double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; l = 2; if (n > 8) { cft1st(n, a, w); l = 8; while ((l << 2) < n) { cftmdl(n, l, a, w); l <<= 2; } } if ((l << 2) == n) { for (j = 0; j < l; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = a[j + 1] + a[j1 + 1]; x1r = a[j] - a[j1]; x1i = a[j + 1] - a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; a[j2] = x0r - x2r; a[j2 + 1] = x0i - x2i; a[j1] = x1r - x3i; a[j1 + 1] = x1i + x3r; a[j3] = x1r + x3i; a[j3 + 1] = x1i - x3r; } } else { for (j = 0; j < l; j += 2) { j1 = j + l; x0r = a[j] - a[j1]; x0i = a[j + 1] - a[j1 + 1]; a[j] += a[j1]; a[j + 1] += a[j1 + 1]; a[j1] = x0r; a[j1 + 1] = x0i; } } } void cftbsub(int n, double *a, double *w) { int j, j1, j2, j3, l; double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; l = 2; if (n > 8) { cft1st(n, a, w); l = 8; while ((l << 2) < n) { cftmdl(n, l, a, w); l <<= 2; } } if ((l << 2) == n) { for (j = 0; j < l; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = -a[j + 1] - a[j1 + 1]; x1r = a[j] - a[j1]; x1i = -a[j + 1] + a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i - x2i; a[j2] = x0r - x2r; a[j2 + 1] = x0i + x2i; a[j1] = x1r - x3i; a[j1 + 1] = x1i - x3r; a[j3] = x1r + x3i; a[j3 + 1] = x1i + x3r; } } else { for (j = 0; j < l; j += 2) { j1 = j + l; x0r = a[j] - a[j1]; x0i = -a[j + 1] + a[j1 + 1]; a[j] += a[j1]; a[j + 1] = -a[j + 1] - a[j1 + 1]; a[j1] = x0r; a[j1 + 1] = x0i; } } } void cft1st(int n, double *a, double *w) { int j, k1, k2; double wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; x0r = a[0] + a[2]; x0i = a[1] + a[3]; x1r = a[0] - a[2]; x1i = a[1] - a[3]; x2r = a[4] + a[6]; x2i = a[5] + a[7]; x3r = a[4] - a[6]; x3i = a[5] - a[7]; a[0] = x0r + x2r; a[1] = x0i + x2i; a[4] = x0r - x2r; a[5] = x0i - x2i; a[2] = x1r - x3i; a[3] = x1i + x3r; a[6] = x1r + x3i; a[7] = x1i - x3r; wk1r = w[2]; x0r = a[8] + a[10]; x0i = a[9] + a[11]; x1r = a[8] - a[10]; x1i = a[9] - a[11]; x2r = a[12] + a[14]; x2i = a[13] + a[15]; x3r = a[12] - a[14]; x3i = a[13] - a[15]; a[8] = x0r + x2r; a[9] = x0i + x2i; a[12] = x2i - x0i; a[13] = x0r - x2r; x0r = x1r - x3i; x0i = x1i + x3r; a[10] = wk1r * (x0r - x0i); a[11] = wk1r * (x0r + x0i); x0r = x3i + x1r; x0i = x3r - x1i; a[14] = wk1r * (x0i - x0r); a[15] = wk1r * (x0i + x0r); k1 = 0; for (j = 16; j < n; j += 16) { k1 += 2; k2 = 2 * k1; wk2r = w[k1]; wk2i = w[k1 + 1]; wk1r = w[k2]; wk1i = w[k2 + 1]; wk3r = wk1r - 2 * wk2i * wk1i; wk3i = 2 * wk2i * wk1r - wk1i; x0r = a[j] + a[j + 2]; x0i = a[j + 1] + a[j + 3]; x1r = a[j] - a[j + 2]; x1i = a[j + 1] - a[j + 3]; x2r = a[j + 4] + a[j + 6]; x2i = a[j + 5] + a[j + 7]; x3r = a[j + 4] - a[j + 6]; x3i = a[j + 5] - a[j + 7]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; x0r -= x2r; x0i -= x2i; a[j + 4] = wk2r * x0r - wk2i * x0i; a[j + 5] = wk2r * x0i + wk2i * x0r; x0r = x1r - x3i; x0i = x1i + x3r; a[j + 2] = wk1r * x0r - wk1i * x0i; a[j + 3] = wk1r * x0i + wk1i * x0r; x0r = x1r + x3i; x0i = x1i - x3r; a[j + 6] = wk3r * x0r - wk3i * x0i; a[j + 7] = wk3r * x0i + wk3i * x0r; wk1r = w[k2 + 2]; wk1i = w[k2 + 3]; wk3r = wk1r - 2 * wk2r * wk1i; wk3i = 2 * wk2r * wk1r - wk1i; x0r = a[j + 8] + a[j + 10]; x0i = a[j + 9] + a[j + 11]; x1r = a[j + 8] - a[j + 10]; x1i = a[j + 9] - a[j + 11]; x2r = a[j + 12] + a[j + 14]; x2i = a[j + 13] + a[j + 15]; x3r = a[j + 12] - a[j + 14]; x3i = a[j + 13] - a[j + 15]; a[j + 8] = x0r + x2r; a[j + 9] = x0i + x2i; x0r -= x2r; x0i -= x2i; a[j + 12] = -wk2i * x0r - wk2r * x0i; a[j + 13] = -wk2i * x0i + wk2r * x0r; x0r = x1r - x3i; x0i = x1i + x3r; a[j + 10] = wk1r * x0r - wk1i * x0i; a[j + 11] = wk1r * x0i + wk1i * x0r; x0r = x1r + x3i; x0i = x1i - x3r; a[j + 14] = wk3r * x0r - wk3i * x0i; a[j + 15] = wk3r * x0i + wk3i * x0r; } } void cftmdl(int n, int l, double *a, double *w) { int j, j1, j2, j3, k, k1, k2, m, m2; double wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; m = l << 2; for (j = 0; j < l; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = a[j + 1] + a[j1 + 1]; x1r = a[j] - a[j1]; x1i = a[j + 1] - a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; a[j2] = x0r - x2r; a[j2 + 1] = x0i - x2i; a[j1] = x1r - x3i; a[j1 + 1] = x1i + x3r; a[j3] = x1r + x3i; a[j3 + 1] = x1i - x3r; } wk1r = w[2]; for (j = m; j < l + m; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = a[j + 1] + a[j1 + 1]; x1r = a[j] - a[j1]; x1i = a[j + 1] - a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; a[j2] = x2i - x0i; a[j2 + 1] = x0r - x2r; x0r = x1r - x3i; x0i = x1i + x3r; a[j1] = wk1r * (x0r - x0i); a[j1 + 1] = wk1r * (x0r + x0i); x0r = x3i + x1r; x0i = x3r - x1i; a[j3] = wk1r * (x0i - x0r); a[j3 + 1] = wk1r * (x0i + x0r); } k1 = 0; m2 = 2 * m; for (k = m2; k < n; k += m2) { k1 += 2; k2 = 2 * k1; wk2r = w[k1]; wk2i = w[k1 + 1]; wk1r = w[k2]; wk1i = w[k2 + 1]; wk3r = wk1r - 2 * wk2i * wk1i; wk3i = 2 * wk2i * wk1r - wk1i; for (j = k; j < l + k; j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = a[j + 1] + a[j1 + 1]; x1r = a[j] - a[j1]; x1i = a[j + 1] - a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; x0r -= x2r; x0i -= x2i; a[j2] = wk2r * x0r - wk2i * x0i; a[j2 + 1] = wk2r * x0i + wk2i * x0r; x0r = x1r - x3i; x0i = x1i + x3r; a[j1] = wk1r * x0r - wk1i * x0i; a[j1 + 1] = wk1r * x0i + wk1i * x0r; x0r = x1r + x3i; x0i = x1i - x3r; a[j3] = wk3r * x0r - wk3i * x0i; a[j3 + 1] = wk3r * x0i + wk3i * x0r; } wk1r = w[k2 + 2]; wk1i = w[k2 + 3]; wk3r = wk1r - 2 * wk2r * wk1i; wk3i = 2 * wk2r * wk1r - wk1i; for (j = k + m; j < l + (k + m); j += 2) { j1 = j + l; j2 = j1 + l; j3 = j2 + l; x0r = a[j] + a[j1]; x0i = a[j + 1] + a[j1 + 1]; x1r = a[j] - a[j1]; x1i = a[j + 1] - a[j1 + 1]; x2r = a[j2] + a[j3]; x2i = a[j2 + 1] + a[j3 + 1]; x3r = a[j2] - a[j3]; x3i = a[j2 + 1] - a[j3 + 1]; a[j] = x0r + x2r; a[j + 1] = x0i + x2i; x0r -= x2r; x0i -= x2i; a[j2] = -wk2i * x0r - wk2r * x0i; a[j2 + 1] = -wk2i * x0i + wk2r * x0r; x0r = x1r - x3i; x0i = x1i + x3r; a[j1] = wk1r * x0r - wk1i * x0i; a[j1 + 1] = wk1r * x0i + wk1i * x0r; x0r = x1r + x3i; x0i = x1i - x3r; a[j3] = wk3r * x0r - wk3i * x0i; a[j3 + 1] = wk3r * x0i + wk3i * x0r; } } } void rftfsub(int n, double *a, int nc, double *c) { int j, k, kk, ks, m; double wkr, wki, xr, xi, yr, yi; m = n >> 1; ks = 2 * nc / m; kk = 0; for (j = 2; j < m; j += 2) { k = n - j; kk += ks; wkr = 0.5 - c[nc - kk]; wki = c[kk]; xr = a[j] - a[k]; xi = a[j + 1] + a[k + 1]; yr = wkr * xr - wki * xi; yi = wkr * xi + wki * xr; a[j] -= yr; a[j + 1] -= yi; a[k] += yr; a[k + 1] -= yi; } } void rftbsub(int n, double *a, int nc, double *c) { int j, k, kk, ks, m; double wkr, wki, xr, xi, yr, yi; a[1] = -a[1]; m = n >> 1; ks = 2 * nc / m; kk = 0; for (j = 2; j < m; j += 2) { k = n - j; kk += ks; wkr = 0.5 - c[nc - kk]; wki = c[kk]; xr = a[j] - a[k]; xi = a[j + 1] + a[k + 1]; yr = wkr * xr + wki * xi; yi = wkr * xi - wki * xr; a[j] -= yr; a[j + 1] = yi - a[j + 1]; a[k] += yr; a[k + 1] = yi - a[k + 1]; } a[m + 1] = -a[m + 1]; } }; /** * @internal * @brief Concrete FFT implementation */ typedef OouraFFT AudioFFTImplementation; #endif // AUDIOFFT_OOURA_USED // ================================================================ #ifdef AUDIOFFT_APPLE_ACCELERATE_USED /** * @internal * @class AppleAccelerateFFT * @brief FFT implementation using the Apple Accelerate framework internally */ class AppleAccelerateFFT : public detail::AudioFFTImpl { public: AppleAccelerateFFT() : detail::AudioFFTImpl(), _size(0), _powerOf2(0), _fftSetup(0), _re(), _im() {} AppleAccelerateFFT(const AppleAccelerateFFT &) = delete; AppleAccelerateFFT &operator=(const AppleAccelerateFFT &) = delete; virtual ~AppleAccelerateFFT() { init(0); } virtual void init(size_t size) override { if (_fftSetup) { vDSP_destroy_fftsetup(_fftSetup); _size = 0; _powerOf2 = 0; _fftSetup = 0; _re.clear(); _im.clear(); } if (size > 0) { _size = size; _powerOf2 = 0; while ((1 << _powerOf2) < _size) { ++_powerOf2; } _fftSetup = vDSP_create_fftsetup(_powerOf2, FFT_RADIX2); _re.resize(_size / 2); _im.resize(_size / 2); } } virtual void fft(const float *data, float *re, float *im) override { const size_t size2 = _size / 2; DSPSplitComplex splitComplex; splitComplex.realp = re; splitComplex.imagp = im; vDSP_ctoz(reinterpret_cast(data), 2, &splitComplex, 1, size2); vDSP_fft_zrip(_fftSetup, &splitComplex, 1, _powerOf2, FFT_FORWARD); const float factor = 0.5f; vDSP_vsmul(re, 1, &factor, re, 1, size2); vDSP_vsmul(im, 1, &factor, im, 1, size2); re[size2] = im[0]; im[0] = 0.0f; im[size2] = 0.0f; } virtual void ifft(float *data, const float *re, const float *im) override { const size_t size2 = _size / 2; ::memcpy(_re.data(), re, size2 * sizeof(float)); ::memcpy(_im.data(), im, size2 * sizeof(float)); _im[0] = re[size2]; DSPSplitComplex splitComplex; splitComplex.realp = _re.data(); splitComplex.imagp = _im.data(); vDSP_fft_zrip(_fftSetup, &splitComplex, 1, _powerOf2, FFT_INVERSE); vDSP_ztoc(&splitComplex, 1, reinterpret_cast(data), 2, size2); const float factor = 1.0f / static_cast(_size); vDSP_vsmul(data, 1, &factor, data, 1, _size); } private: size_t _size; size_t _powerOf2; FFTSetup _fftSetup; std::vector _re; std::vector _im; }; /** * @internal * @brief Concrete FFT implementation */ typedef AppleAccelerateFFT AudioFFTImplementation; #endif // AUDIOFFT_APPLE_ACCELERATE_USED // ================================================================ #ifdef AUDIOFFT_FFTW3_USED /** * @internal * @class FFTW3FFT * @brief FFT implementation using FFTW3 internally (see fftw.org) */ class FFTW3FFT : public detail::AudioFFTImpl { public: FFTW3FFT() : detail::AudioFFTImpl(), _size(0), _complexSize(0), _planForward(0), _planBackward(0), _data(0), _re(0), _im(0) {} FFTW3FFT(const FFTW3FFT &) = delete; FFTW3FFT &operator=(const FFTW3FFT &) = delete; virtual ~FFTW3FFT() { init(0); } virtual void init(size_t size) override { if (_size != size) { if (_size > 0) { fftwf_destroy_plan(_planForward); fftwf_destroy_plan(_planBackward); _planForward = 0; _planBackward = 0; _size = 0; _complexSize = 0; if (_data) { fftwf_free(_data); _data = 0; } if (_re) { fftwf_free(_re); _re = 0; } if (_im) { fftwf_free(_im); _im = 0; } } if (size > 0) { _size = size; _complexSize = AudioFFT::ComplexSize(_size); const size_t complexSize = AudioFFT::ComplexSize(_size); _data = reinterpret_cast(fftwf_malloc(_size * sizeof(float))); _re = reinterpret_cast(fftwf_malloc(complexSize * sizeof(float))); _im = reinterpret_cast(fftwf_malloc(complexSize * sizeof(float))); fftwf_set_timelimit(0.01); fftw_iodim dim; dim.n = static_cast(size); dim.is = 1; dim.os = 1; _planForward = fftwf_plan_guru_split_dft_r2c(1, &dim, 0, 0, _data, _re, _im, FFTW_MEASURE); _planBackward = fftwf_plan_guru_split_dft_c2r(1, &dim, 0, 0, _re, _im, _data, FFTW_MEASURE); } } } virtual void fft(const float *data, float *re, float *im) override { ::memcpy(_data, data, _size * sizeof(float)); fftwf_execute_split_dft_r2c(_planForward, _data, _re, _im); ::memcpy(re, _re, _complexSize * sizeof(float)); ::memcpy(im, _im, _complexSize * sizeof(float)); } virtual void ifft(float *data, const float *re, const float *im) override { ::memcpy(_re, re, _complexSize * sizeof(float)); ::memcpy(_im, im, _complexSize * sizeof(float)); fftwf_execute_split_dft_c2r(_planBackward, _re, _im, _data); detail::ScaleBuffer(data, _data, 1.0f / static_cast(_size), _size); } private: size_t _size; size_t _complexSize; fftwf_plan _planForward; fftwf_plan _planBackward; float *_data; float *_re; float *_im; }; /** * @internal * @brief Concrete FFT implementation */ typedef FFTW3FFT AudioFFTImplementation; #endif // AUDIOFFT_FFTW3_USED // ============================================================= AudioFFT::AudioFFT() : _impl(new AudioFFTImplementation()) {} AudioFFT::~AudioFFT() {} void AudioFFT::init(size_t size) { assert(detail::IsPowerOf2(size)); _impl->init(size); } void AudioFFT::fft(const float *data, float *re, float *im) { _impl->fft(data, re, im); } void AudioFFT::ifft(float *data, const float *re, const float *im) { _impl->ifft(data, re, im); } size_t AudioFFT::ComplexSize(size_t size) { return (size / 2) + 1; } } // namespace audiofft shairport-sync-5.1-dev/FFTConvolver/AudioFFT.h000066400000000000000000000126001520255574400212170ustar00rootroot00000000000000// ================================================================================== // Copyright (c) 2017 HiFi-LoFi // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is furnished // to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ================================================================================== #ifndef _AUDIOFFT_H #define _AUDIOFFT_H /** * AudioFFT provides real-to-complex/complex-to-real FFT routines. * * Features: * * - Real-complex FFT and complex-real inverse FFT for power-of-2-sized real data. * * - Uniform interface to different FFT implementations (currently Ooura, FFTW3 and Apple * Accelerate). * * - Complex data is handled in "split-complex" format, i.e. there are separate * arrays for the real and imaginary parts which can be useful for SIMD optimizations * (split-complex arrays have to be of length (size/2+1) representing bins from DC * to Nyquist frequency). * * - Output is "ready to use" (all scaling etc. is already handled internally). * * - No allocations/deallocations after the initialization which makes it usable * for real-time audio applications (that's what I wrote it for and using it). * * * How to use it in your project: * * - Add the .h and .cpp file to your project - that's all. * * - To get extra speed, you can link FFTW3 to your project and define * AUDIOFFT_FFTW3 (however, please check whether your project suits the * according license). * * - To get the best speed on Apple platforms, you can link the Apple * Accelerate framework to your project and define * AUDIOFFT_APPLE_ACCELERATE (however, please check whether your * project suits the according license). * * * Remarks: * * - AudioFFT is not intended to be the fastest FFT, but to be a fast-enough * FFT suitable for most audio applications. * * - AudioFFT uses the quite liberal MIT license. * * * Example usage: * @code * #include "AudioFFT.h" * * void Example() * { * const size_t fftSize = 1024; // Needs to be power of 2! * * std::vector input(fftSize, 0.0f); * std::vector re(audiofft::AudioFFT::ComplexSize(fftSize)); * std::vector im(audiofft::AudioFFT::ComplexSize(fftSize)); * std::vector output(fftSize); * * audiofft::AudioFFT fft; * fft.init(1024); * fft.fft(input.data(), re.data(), im.data()); * fft.ifft(output.data(), re.data(), im.data()); * } * @endcode */ #include #include namespace audiofft { namespace detail { class AudioFFTImpl; } // ============================================================= /** * @class AudioFFT * @brief Performs 1D FFTs */ class AudioFFT { public: /** * @brief Constructor */ AudioFFT(); AudioFFT(const AudioFFT &) = delete; AudioFFT &operator=(const AudioFFT &) = delete; /** * @brief Destructor */ ~AudioFFT(); /** * @brief Initializes the FFT object * @param size Size of the real input (must be power 2) */ void init(size_t size); /** * @brief Performs the forward FFT * @param data The real input data (has to be of the length as specified in init()) * @param re The real part of the complex output (has to be of length as returned by * ComplexSize()) * @param im The imaginary part of the complex output (has to be of length as returned by * ComplexSize()) */ void fft(const float *data, float *re, float *im); /** * @brief Performs the inverse FFT * @param data The real output data (has to be of the length as specified in init()) * @param re The real part of the complex input (has to be of length as returned by ComplexSize()) * @param im The imaginary part of the complex input (has to be of length as returned by * ComplexSize()) */ void ifft(float *data, const float *re, const float *im); /** * @brief Calculates the necessary size of the real/imaginary complex arrays * @param size The size of the real data * @return The size of the real/imaginary complex arrays */ static size_t ComplexSize(size_t size); private: std::unique_ptr _impl; }; /** * @deprecated * @brief Let's keep an AudioFFTBase type around for now because it has been here already in the 1st * version in order to avoid breaking existing code. */ typedef AudioFFT AudioFFTBase; } // namespace audiofft #endif // Header guard shairport-sync-5.1-dev/FFTConvolver/ConvolverThreadPool.cpp000066400000000000000000000143271520255574400241200ustar00rootroot00000000000000/* * Convolver Thread Pool. This file is part of Shairport Sync * Copyright (c) Mike Brady 2026 * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "ConvolverThreadPool.h" #include "FFTConvolver.h" #include "config.h" extern "C" void _debug(const char *filename, const int linenumber, int level, const char *format, ...); #define debug(...) _debug(__FILE__, __LINE__, __VA_ARGS__) ConvolverThreadPool::ConvolverThreadPool() : _convolvers(), _threads(), _taskQueue(), _queueMutex(), _condition(), _completionCV(), _stop(false), _activeTasks(0) {} ConvolverThreadPool::~ConvolverThreadPool() { shutdown(); // Delete all convolver instances for (size_t i = 0; i < _convolvers.size(); ++i) { delete _convolvers[i]; } _convolvers.clear(); } bool ConvolverThreadPool::init(size_t numThreads, size_t numConvolvers) { // Clean up any existing threads first shutdown(); // Validate parameters if (numThreads == 0 || numConvolvers == 0) { return false; } // Delete any existing convolvers for (size_t i = 0; i < _convolvers.size(); ++i) { delete _convolvers[i]; } _convolvers.clear(); // Reset state _stop = false; _activeTasks = 0; // Create convolver instances (but don't initialize them yet) _convolvers.resize(numConvolvers); for (size_t i = 0; i < numConvolvers; ++i) { _convolvers[i] = new FFTConvolver(); } // Create worker threads _threads.reserve(numThreads); for (size_t i = 0; i < numThreads; i++) { #ifndef COMPILE_FOR_OSX pthread_setname_np(pthread_self(), "convolver"); #endif _threads.emplace_back([this]() { workerThread(); }); } return true; } // Mutex to protect FFTW plan creation (required) std::mutex fftwMutex; bool ConvolverThreadPool::initConvolver(size_t convolverId, size_t blockSize, const Sample *ir, size_t irLen) { if (convolverId >= _convolvers.size()) { return false; } // Make sure no tasks are using this convolver waitForAll(); std::lock_guard lock(fftwMutex); return _convolvers[convolverId]->init(blockSize, ir, irLen); } bool ConvolverThreadPool::initAllConvolvers(size_t blockSize, const Sample *ir, size_t irLen) { // Make sure no tasks are running waitForAll(); for (size_t i = 0; i < _convolvers.size(); ++i) { if (!_convolvers[i]->init(blockSize, ir, irLen)) { return false; } } return true; } void ConvolverThreadPool::processAsync(size_t convolverId, const Sample *input, Sample *output, size_t len) { assert(convolverId < _convolvers.size()); { std::lock_guard lock(_queueMutex); // Create the task _taskQueue.push([this, convolverId, input, output, len]() { _convolvers[convolverId]->process(input, output, len); }); ++_activeTasks; } // Wake up one worker thread _condition.notify_one(); } void ConvolverThreadPool::waitForAll() { std::unique_lock lock(_queueMutex); _completionCV.wait(lock, [this]() { return _taskQueue.empty() && _activeTasks == 0; }); } void ConvolverThreadPool::clearState(size_t convolverId) { // Do the replacement assertion check first, and then wait for all tasks to stop if (convolverId < _convolvers.size()) { waitForAll(); } else { debug(1, "assert(convolverId < _convolvers.size()) failed, with convolverId: %u and " "_convolvers.size(): %u.", convolverId, _convolvers.size()); } } /* this is the old version void ConvolverThreadPool::clearState(size_t convolverId) { assert(convolverId < _convolvers.size()); // Make sure no tasks are running before clearing state waitForAll(); // _convolvers[convolverId]->clearState(); } */ void ConvolverThreadPool::clearAllStates() { // Make sure no tasks are running before clearing state waitForAll(); for (size_t i = 0; i < _convolvers.size(); ++i) { _convolvers[i]->clearState(); } } void ConvolverThreadPool::workerThread() { while (true) { std::function task; // Wait for a task or stop signal { std::unique_lock lock(_queueMutex); _condition.wait(lock, [this]() { return _stop || !_taskQueue.empty(); }); // Exit if stopping and no more tasks if (_stop && _taskQueue.empty()) { return; } // Get the next task task = std::move(_taskQueue.front()); _taskQueue.pop(); } // Execute the task (outside the lock for better parallelism) task(); // Mark task as complete { std::lock_guard lock(_queueMutex); --_activeTasks; _completionCV.notify_all(); } } } void ConvolverThreadPool::shutdown() { // Signal threads to stop { std::lock_guard lock(_queueMutex); _stop = true; } _condition.notify_all(); // Wait for all threads to finish for (auto &thread : _threads) { if (thread.joinable()) { thread.join(); } } // Clear thread vector _threads.clear(); // Clear remaining tasks - properly this time { std::lock_guard lock(_queueMutex); while (!_taskQueue.empty()) { _taskQueue.pop(); } } // Reset state _activeTasks = 0; _stop = false; }shairport-sync-5.1-dev/FFTConvolver/ConvolverThreadPool.h000066400000000000000000000037771520255574400235740ustar00rootroot00000000000000#ifndef CONVOLVER_THREAD_POOL_H #define CONVOLVER_THREAD_POOL_H #include "FFTConvolver.h" #include #include #include #include #include #include #include // Use the fftconvolver namespace using fftconvolver::FFTConvolver; using fftconvolver::Sample; class ConvolverThreadPool { private: std::vector _convolvers; std::vector _threads; std::queue> _taskQueue; std::mutex _queueMutex; std::condition_variable _condition; std::condition_variable _completionCV; bool _stop; size_t _activeTasks; public: ConvolverThreadPool(); ~ConvolverThreadPool(); // Initialize the thread pool (creates convolvers but doesn't initialize them) // numThreads: number of worker threads (level of parallelism) // numConvolvers: total number of convolver instances bool init(size_t numThreads, size_t numConvolvers); // Initialize a specific convolver with its IR // convolverId: which convolver to initialize // blockSize: block size for convolution // ir: impulse response data // irLen: length of impulse response bool initConvolver(size_t convolverId, size_t blockSize, const Sample *ir, size_t irLen); // Initialize all convolvers with the same IR bool initAllConvolvers(size_t blockSize, const Sample *ir, size_t irLen); // Queue a convolution task (non-blocking) void processAsync(size_t convolverId, const Sample *input, Sample *output, size_t len); // Wait for all queued tasks to complete (blocking) void waitForAll(); // Clear the state of a specific convolver void clearState(size_t convolverId); // Clear the state of all convolvers void clearAllStates(); // Get the number of convolvers size_t getNumConvolvers() const { return _convolvers.size(); } // Get the number of threads size_t getNumThreads() const { return _threads.size(); } void shutdown(); private: void workerThread(); // void shutdown(); }; #endif // CONVOLVER_THREAD_POOL_Hshairport-sync-5.1-dev/FFTConvolver/FFTConvolver.cpp000066400000000000000000000124241520255574400224720ustar00rootroot00000000000000// ================================================================================== // Copyright (c) 2012 HiFi-LoFi // // This is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // ================================================================================== #include "FFTConvolver.h" #include #include #if defined(FFTCONVOLVER_USE_SSE) #include #endif namespace fftconvolver { FFTConvolver::FFTConvolver() : _blockSize(0), _segSize(0), _segCount(0), _fftComplexSize(0), _segments(), _segmentsIR(), _fftBuffer(), _fft(), _preMultiplied(), _conv(), _overlap(), _current(0), _inputBuffer(), _inputBufferFill(0) {} FFTConvolver::~FFTConvolver() { reset(); } void FFTConvolver::reset() { for (size_t i = 0; i < _segCount; ++i) { delete _segments[i]; delete _segmentsIR[i]; } _blockSize = 0; _segSize = 0; _segCount = 0; _fftComplexSize = 0; _segments.clear(); _segmentsIR.clear(); _fftBuffer.clear(); _fft.init(0); _preMultiplied.clear(); _conv.clear(); _overlap.clear(); _current = 0; _inputBuffer.clear(); _inputBufferFill = 0; } void FFTConvolver::clearState() { if (_segCount == 0) { return; // Not initialized } _inputBuffer.setZero(); _inputBufferFill = 0; _overlap.setZero(); for (size_t i = 0; i < _segCount; ++i) { _segments[i]->setZero(); } _preMultiplied.setZero(); _conv.setZero(); _current = 0; } bool FFTConvolver::init(size_t blockSize, const Sample *ir, size_t irLen) { reset(); if (blockSize == 0) { return false; } // Ignore zeros at the end of the impulse response because they only waste computation time while (irLen > 0 && ::fabs(ir[irLen - 1]) < 0.000001f) { --irLen; } if (irLen == 0) { return true; } _blockSize = NextPowerOf2(blockSize); _segSize = 2 * _blockSize; _segCount = static_cast(::ceil(static_cast(irLen) / static_cast(_blockSize))); _fftComplexSize = audiofft::AudioFFT::ComplexSize(_segSize); // FFT _fft.init(_segSize); _fftBuffer.resize(_segSize); // Prepare segments for (size_t i = 0; i < _segCount; ++i) { _segments.push_back(new SplitComplex(_fftComplexSize)); } // Prepare IR for (size_t i = 0; i < _segCount; ++i) { SplitComplex *segment = new SplitComplex(_fftComplexSize); const size_t remaining = irLen - (i * _blockSize); const size_t sizeCopy = (remaining >= _blockSize) ? _blockSize : remaining; CopyAndPad(_fftBuffer, &ir[i * _blockSize], sizeCopy); _fft.fft(_fftBuffer.data(), segment->re(), segment->im()); _segmentsIR.push_back(segment); } // Prepare convolution buffers _preMultiplied.resize(_fftComplexSize); _conv.resize(_fftComplexSize); _overlap.resize(_blockSize); // Prepare input buffer _inputBuffer.resize(_blockSize); _inputBufferFill = 0; // Reset current position _current = 0; return true; } void FFTConvolver::process(const Sample *input, Sample *output, size_t len) { if (_segCount == 0) { ::memset(output, 0, len * sizeof(Sample)); return; } size_t processed = 0; while (processed < len) { const bool inputBufferWasEmpty = (_inputBufferFill == 0); const size_t processing = std::min(len - processed, _blockSize - _inputBufferFill); const size_t inputBufferPos = _inputBufferFill; ::memcpy(_inputBuffer.data() + inputBufferPos, input + processed, processing * sizeof(Sample)); // Forward FFT CopyAndPad(_fftBuffer, &_inputBuffer[0], _blockSize); _fft.fft(_fftBuffer.data(), _segments[_current]->re(), _segments[_current]->im()); // Complex multiplication if (inputBufferWasEmpty) { _preMultiplied.setZero(); for (size_t i = 1; i < _segCount; ++i) { const size_t indexIr = i; const size_t indexAudio = (_current + i) % _segCount; ComplexMultiplyAccumulate(_preMultiplied, *_segmentsIR[indexIr], *_segments[indexAudio]); } } _conv.copyFrom(_preMultiplied); ComplexMultiplyAccumulate(_conv, *_segments[_current], *_segmentsIR[0]); // Backward FFT _fft.ifft(_fftBuffer.data(), _conv.re(), _conv.im()); // Add overlap Sum(output + processed, _fftBuffer.data() + inputBufferPos, _overlap.data() + inputBufferPos, processing); // Input buffer full => Next block _inputBufferFill += processing; if (_inputBufferFill == _blockSize) { // Input buffer is empty again now _inputBuffer.setZero(); _inputBufferFill = 0; // Save the overlap ::memcpy(_overlap.data(), _fftBuffer.data() + _blockSize, _blockSize * sizeof(Sample)); // Update current segment _current = (_current > 0) ? (_current - 1) : (_segCount - 1); } processed += processing; } } } // End of namespace fftconvolver shairport-sync-5.1-dev/FFTConvolver/FFTConvolver.h000066400000000000000000000071441520255574400221420ustar00rootroot00000000000000// ================================================================================== // Copyright (c) 2017 HiFi-LoFi // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is furnished // to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ================================================================================== #ifndef _FFTCONVOLVER_FFTCONVOLVER_H #define _FFTCONVOLVER_FFTCONVOLVER_H #include "AudioFFT.h" #include "Utilities.h" #include namespace fftconvolver { /** * @class FFTConvolver * @brief Implementation of a partitioned FFT convolution algorithm with uniform block size * * Some notes on how to use it: * * - After initialization with an impulse response, subsequent data portions of * arbitrary length can be convolved. The convolver internally can handle * this by using appropriate buffering. * * - The convolver works without "latency" (except for the required * processing time, of course), i.e. the output always is the convolved * input for each processing call. * * - The convolver is suitable for real-time processing which means that no * "unpredictable" operations like allocations, locking, API calls, etc. are * performed during processing (all necessary allocations and preparations take * place during initialization). */ class FFTConvolver { public: FFTConvolver(); virtual ~FFTConvolver(); /** * @brief Initializes the convolver * @param blockSize Block size internally used by the convolver (partition size) * @param ir The impulse response * @param irLen Length of the impulse response * @return true: Success - false: Failed */ bool init(size_t blockSize, const Sample *ir, size_t irLen); /** * @brief Convolves the the given input samples and immediately outputs the result * @param input The input samples * @param output The convolution result * @param len Number of input/output samples */ void process(const Sample *input, Sample *output, size_t len); /** * @brief Resets the convolver and discards the set impulse response */ void reset(); /** * @brief Clears audio history */ void clearState(); private: size_t _blockSize; size_t _segSize; size_t _segCount; size_t _fftComplexSize; std::vector _segments; std::vector _segmentsIR; SampleBuffer _fftBuffer; audiofft::AudioFFT _fft; SplitComplex _preMultiplied; SplitComplex _conv; SampleBuffer _overlap; size_t _current; SampleBuffer _inputBuffer; size_t _inputBufferFill; // Prevent uncontrolled usage FFTConvolver(const FFTConvolver &); FFTConvolver &operator=(const FFTConvolver &); }; } // End of namespace fftconvolver #endif // Header guard shairport-sync-5.1-dev/FFTConvolver/Utilities.cpp000066400000000000000000000101501520255574400221220ustar00rootroot00000000000000// ================================================================================== // Copyright (c) 2017 HiFi-LoFi // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is furnished // to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ================================================================================== #include "Utilities.h" namespace fftconvolver { bool SSEEnabled() { #if defined(FFTCONVOLVER_USE_SSE) return true; #else return false; #endif } void Sum(Sample *FFTCONVOLVER_RESTRICT result, const Sample *FFTCONVOLVER_RESTRICT a, const Sample *FFTCONVOLVER_RESTRICT b, size_t len) { const size_t end4 = 4 * (len / 4); for (size_t i = 0; i < end4; i += 4) { result[i + 0] = a[i + 0] + b[i + 0]; result[i + 1] = a[i + 1] + b[i + 1]; result[i + 2] = a[i + 2] + b[i + 2]; result[i + 3] = a[i + 3] + b[i + 3]; } for (size_t i = end4; i < len; ++i) { result[i] = a[i] + b[i]; } } void ComplexMultiplyAccumulate(SplitComplex &result, const SplitComplex &a, const SplitComplex &b) { assert(result.size() == a.size()); assert(result.size() == b.size()); ComplexMultiplyAccumulate(result.re(), result.im(), a.re(), a.im(), b.re(), b.im(), result.size()); } void ComplexMultiplyAccumulate(Sample *FFTCONVOLVER_RESTRICT re, Sample *FFTCONVOLVER_RESTRICT im, const Sample *FFTCONVOLVER_RESTRICT reA, const Sample *FFTCONVOLVER_RESTRICT imA, const Sample *FFTCONVOLVER_RESTRICT reB, const Sample *FFTCONVOLVER_RESTRICT imB, const size_t len) { #if defined(FFTCONVOLVER_USE_SSE) const size_t end4 = 4 * (len / 4); for (size_t i = 0; i < end4; i += 4) { const __m128 ra = _mm_load_ps(&reA[i]); const __m128 rb = _mm_load_ps(&reB[i]); const __m128 ia = _mm_load_ps(&imA[i]); const __m128 ib = _mm_load_ps(&imB[i]); __m128 real = _mm_load_ps(&re[i]); __m128 imag = _mm_load_ps(&im[i]); real = _mm_add_ps(real, _mm_mul_ps(ra, rb)); real = _mm_sub_ps(real, _mm_mul_ps(ia, ib)); _mm_store_ps(&re[i], real); imag = _mm_add_ps(imag, _mm_mul_ps(ra, ib)); imag = _mm_add_ps(imag, _mm_mul_ps(ia, rb)); _mm_store_ps(&im[i], imag); } for (size_t i = end4; i < len; ++i) { re[i] += reA[i] * reB[i] - imA[i] * imB[i]; im[i] += reA[i] * imB[i] + imA[i] * reB[i]; } #else const size_t end4 = 4 * (len / 4); for (size_t i = 0; i < end4; i += 4) { re[i + 0] += reA[i + 0] * reB[i + 0] - imA[i + 0] * imB[i + 0]; re[i + 1] += reA[i + 1] * reB[i + 1] - imA[i + 1] * imB[i + 1]; re[i + 2] += reA[i + 2] * reB[i + 2] - imA[i + 2] * imB[i + 2]; re[i + 3] += reA[i + 3] * reB[i + 3] - imA[i + 3] * imB[i + 3]; im[i + 0] += reA[i + 0] * imB[i + 0] + imA[i + 0] * reB[i + 0]; im[i + 1] += reA[i + 1] * imB[i + 1] + imA[i + 1] * reB[i + 1]; im[i + 2] += reA[i + 2] * imB[i + 2] + imA[i + 2] * reB[i + 2]; im[i + 3] += reA[i + 3] * imB[i + 3] + imA[i + 3] * reB[i + 3]; } for (size_t i = end4; i < len; ++i) { re[i] += reA[i] * reB[i] - imA[i] * imB[i]; im[i] += reA[i] * imB[i] + imA[i] * reB[i]; } #endif } } // End of namespace fftconvolver shairport-sync-5.1-dev/FFTConvolver/Utilities.h000066400000000000000000000163121520255574400215750ustar00rootroot00000000000000// ================================================================================== // Copyright (c) 2017 HiFi-LoFi // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is furnished // to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ================================================================================== #ifndef _FFTCONVOLVER_UTILITIES_H #define _FFTCONVOLVER_UTILITIES_H #include #include #include #include #include namespace fftconvolver { #if defined(__SSE__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2) #if !defined(FFTCONVOLVER_USE_SSE) && !defined(FFTCONVOLVER_DONT_USE_SSE) #define FFTCONVOLVER_USE_SSE #endif #endif #if defined(FFTCONVOLVER_USE_SSE) #include #endif #if defined(__GNUC__) #define FFTCONVOLVER_RESTRICT __restrict__ #else #define FFTCONVOLVER_RESTRICT #endif /** * @brief Returns whether SSE optimization for the convolver is enabled * @return true: Enabled - false: Disabled */ bool SSEEnabled(); /** * @class Buffer * @brief Simple buffer implementation (uses 16-byte alignment if SSE optimization is enabled) */ template class Buffer { public: explicit Buffer(size_t initialSize = 0) : _data(0), _size(0) { resize(initialSize); } virtual ~Buffer() { clear(); } void clear() { deallocate(_data); _data = 0; _size = 0; } void resize(size_t size) { if (_size != size) { clear(); if (size > 0) { assert(!_data && _size == 0); _data = allocate(size); _size = size; } } setZero(); } size_t size() const { return _size; } void setZero() { ::memset(_data, 0, _size * sizeof(T)); } void copyFrom(const Buffer &other) { assert(_size == other._size); if (this != &other) { ::memcpy(_data, other._data, _size * sizeof(T)); } } T &operator[](size_t index) { assert(_data && index < _size); return _data[index]; } const T &operator[](size_t index) const { assert(_data && index < _size); return _data[index]; } operator bool() const { return (_data != 0 && _size > 0); } T *data() { return _data; } const T *data() const { return _data; } static void Swap(Buffer &a, Buffer &b) { std::swap(a._data, b._data); std::swap(a._size, b._size); } private: T *allocate(size_t size) { #if defined(FFTCONVOLVER_USE_SSE) return static_cast(_mm_malloc(size * sizeof(T), 16)); #else return new T[size]; #endif } void deallocate(T *ptr) { #if defined(FFTCONVOLVER_USE_SSE) _mm_free(ptr); #else delete[] ptr; #endif } T *_data; size_t _size; // Prevent uncontrolled usage Buffer(const Buffer &); Buffer &operator=(const Buffer &); }; /** * @brief Type of one sample */ typedef float Sample; /** * @brief Buffer for samples */ typedef Buffer SampleBuffer; /** * @class SplitComplex * @brief Buffer for split-complex representation of FFT results * * The split-complex representation stores the real and imaginary parts * of FFT results in two different memory buffers which is useful e.g. for * SIMD optimizations. */ class SplitComplex { public: explicit SplitComplex(size_t initialSize = 0) : _size(0), _re(), _im() { resize(initialSize); } ~SplitComplex() { clear(); } void clear() { _re.clear(); _im.clear(); _size = 0; } void resize(size_t newSize) { _re.resize(newSize); _im.resize(newSize); _size = newSize; } void setZero() { _re.setZero(); _im.setZero(); } void copyFrom(const SplitComplex &other) { _re.copyFrom(other._re); _im.copyFrom(other._im); } Sample *re() { return _re.data(); } const Sample *re() const { return _re.data(); } Sample *im() { return _im.data(); } const Sample *im() const { return _im.data(); } size_t size() const { return _size; } private: size_t _size; SampleBuffer _re; SampleBuffer _im; // Prevent uncontrolled usage SplitComplex(const SplitComplex &); SplitComplex &operator=(const SplitComplex &); }; /** * @brief Returns the next power of 2 of a given number * @param val The number * @return The next power of 2 */ template T NextPowerOf2(const T &val) { T nextPowerOf2 = 1; while (nextPowerOf2 < val) { nextPowerOf2 *= 2; } return nextPowerOf2; } /** * @brief Sums two given sample arrays * @param result The result array * @param a The 1st array * @param b The 2nd array * @param len The length of the arrays */ void Sum(Sample *FFTCONVOLVER_RESTRICT result, const Sample *FFTCONVOLVER_RESTRICT a, const Sample *FFTCONVOLVER_RESTRICT b, size_t len); /** * @brief Copies a source array into a destination buffer and pads the destination buffer with zeros * @param dest The destination buffer * @param src The source array * @param srcSize The size of the source array */ template void CopyAndPad(Buffer &dest, const T *src, size_t srcSize) { assert(dest.size() >= srcSize); ::memcpy(dest.data(), src, srcSize * sizeof(T)); ::memset(dest.data() + srcSize, 0, (dest.size() - srcSize) * sizeof(T)); } /** * @brief Adds the complex product of two split-complex buffers to a result buffer * @param result The result buffer * @param a The 1st factor of the complex product * @param b The 2nd factor of the complex product */ void ComplexMultiplyAccumulate(SplitComplex &result, const SplitComplex &a, const SplitComplex &b); /** * @brief Adds the complex product of two split-complex arrays to a result array * @param re The real part of the result buffer * @param im The imaginary part of the result buffer * @param reA The real part of the 1st factor of the complex product * @param imA The imaginary part of the 1st factor of the complex product * @param reB The real part of the 2nd factor of the complex product * @param imB The imaginary part of the 2nd factor of the complex product */ void ComplexMultiplyAccumulate(Sample *FFTCONVOLVER_RESTRICT re, Sample *FFTCONVOLVER_RESTRICT im, const Sample *FFTCONVOLVER_RESTRICT reA, const Sample *FFTCONVOLVER_RESTRICT imA, const Sample *FFTCONVOLVER_RESTRICT reB, const Sample *FFTCONVOLVER_RESTRICT imB, const size_t len); } // End of namespace fftconvolver #endif // Header guard shairport-sync-5.1-dev/FFTConvolver/convolver.cpp000066400000000000000000000210171520255574400221700ustar00rootroot00000000000000/* * Convolver. This file is part of Shairport Sync * Copyright (c) Mike Brady 2026 * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "convolver.h" #include "ConvolverThreadPool.h" #include "FFTConvolver.h" #include "Utilities.h" #include #include #include extern "C" void _warn(const char *filename, const int linenumber, const char *format, ...); extern "C" void _debug(const char *filename, const int linenumber, int level, const char *format, ...); #define warn(...) _warn(__FILE__, __LINE__, __VA_ARGS__) #define debug(...) _debug(__FILE__, __LINE__, __VA_ARGS__) // Create and initialize the thread pool ConvolverThreadPool pool; void convolver_pool_init(size_t numThreads, size_t numConvolvers) { if (!pool.init(numThreads, numConvolvers)) { debug(1, "failed to initialize thread pool!"); } else { debug(1, "thread pool initialized with %u thread%s and %u convolver%s.", numThreads, numThreads == 1 ? "" : "s", numConvolvers, numConvolvers == 1 ? "" : "s"); } } void convolver_pool_closedown() { pool.shutdown(); // Just shutdown, don't delete debug(3, "thread pool shut down"); } int convolver_init(const char *filename, unsigned char channel_count, double max_length_in_seconds, size_t block_size) { debug(3, "convolver_init"); int success = 0; SF_INFO info = {}; // Zero everything, including format if (filename) { SNDFILE *file = sf_open(filename, SFM_READ, &info); if (file) { size_t max_length = (size_t)(max_length_in_seconds * info.samplerate); const size_t size = (unsigned int)info.frames > max_length ? max_length : (unsigned int)info.frames; float *buffer = (float *)malloc(sizeof(float) * size * info.channels); if (buffer != NULL) { // float buffer[size * info.channels]; float *abuffer = (float *)malloc(sizeof(float) * size); if (abuffer != NULL) { size_t l = sf_readf_float(file, buffer, size); if (l != 0) { unsigned int cc; if (info.channels == 1) { for (cc = 0; cc < channel_count; cc++) { if (!pool.initConvolver(cc, block_size, buffer, size)) { debug(1, "new convolver failed to initialize convolver %u ", cc); } } } else if (info.channels == channel_count) { // we have to deinterleave the ir file channels for each convolver // float abuffer[size]; for (cc = 0; cc < channel_count; cc++) { unsigned int i; for (i = 0; i < size; ++i) { abuffer[i] = buffer[channel_count * i + cc]; } if (!pool.initConvolver(cc, block_size, abuffer, size)) { debug(1, "new convolver failed to initialize convolver %u ", cc); } } } success = 1; } debug(2, "convolution impulse response filter initialized from \"%s\" with %d channel%s and " "%d samples", filename, info.channels, info.channels == 1 ? "" : "s", size); sf_close(file); free((void *)abuffer); } else { debug(1, "failed to init convolvers because insufficient memory was available"); } free((void *)buffer); } else { warn("failed to init convolvers because insufficient memory was available"); } } else { warn("Convolution impulse response filter file \"%s\" can not be opened. Please check that " "it exists, is a valid sound file and has appropriate access permissions.", filename); } } return success; } void convolver_process(unsigned int channel, float *data, int length) { pool.processAsync(channel, data, data, length); } void convolver_wait_for_all() { pool.waitForAll(); } void convolver_clear_state() { pool.clearAllStates(); } const unsigned int max_channels = 8; fftconvolver::FFTConvolver convolvers[max_channels]; // fftconvolver::FFTConvolver convolver_l; // fftconvolver::FFTConvolver convolver_r; // always lock use this when accessing the playing conn value /* pthread_mutex_t convolver_lock = PTHREAD_MUTEX_INITIALIZER; int convolver_init(const char *filename, unsigned char channel_count, double max_length_in_seconds, size_t block_size) { debug(1, "convolver_init"); int success = 0; SF_INFO info; if (filename) { SNDFILE *file = sf_open(filename, SFM_READ, &info); if (file) { size_t max_length = (size_t)(max_length_in_seconds * info.samplerate); const size_t size = (unsigned int)info.frames > max_length ? max_length : (unsigned int)info.frames; float buffer[size * info.channels]; size_t l = sf_readf_float(file, buffer, size); if (l != 0) { pthread_mutex_lock(&convolver_lock); unsigned int cc; for (cc = 0; cc < channel_count; cc++) { convolvers[cc].reset(); } if (info.channels == 1) { for (cc = 0; cc < channel_count; cc++) { convolvers[cc].init(block_size, buffer, size); } } else if (info.channels == channel_count) { // we have to deinterleave the ir file channels for each convolver for (cc = 0; cc < channel_count; cc++) { float abuffer[size]; unsigned int i; for (i = 0; i < size; ++i) { abuffer[i] = buffer[channel_count * i + cc]; } convolvers[cc].init(block_size, abuffer, size); } } pthread_mutex_unlock(&convolver_lock); success = 1; } debug(2, "convolution impulse response filter initialized from \"%s\" with %d channel%s and " "%d samples", filename, info.channels, info.channels == 1 ? "" : "s", size); sf_close(file); } else { warn("Convolution impulse response filter file \"%s\" can not be opened. Please check that " "it exists, is a valid sound file and has appropriate access permissions.", filename); } } return success; } void convolver_reset() { debug(1, "convolver_reset"); pthread_mutex_lock(&convolver_lock); unsigned int cc; for (cc = 0; cc < max_channels; cc++) { convolvers[cc].reset(); } // convolver_l.reset(); // it is possible that init could be called more than once // convolver_r.reset(); // so it could be necessary to remove all previous settings pthread_mutex_unlock(&convolver_lock); } void convolver_clear_state() { debug(1, "convolver_clear_state"); pthread_mutex_lock(&convolver_lock); unsigned int cc; for (cc = 0; cc < max_channels; cc++) { convolvers[cc].clearState(); } // convolver_l.reset(); // it is possible that init could be called more than once // convolver_r.reset(); // so it could be necessary to remove all previous settings pthread_mutex_unlock(&convolver_lock); } void convolver_process(unsigned int channel, float *data, int length) { pthread_mutex_lock(&convolver_lock); convolvers[channel].process(data, data, length); pthread_mutex_unlock(&convolver_lock); usleep(100); } void convolver_process_l(float *data, int length) { pthread_mutex_lock(&convolver_lock); convolver_l.process(data, data, length); pthread_mutex_unlock(&convolver_lock); } void convolver_process_r(float *data, int length) { pthread_mutex_lock(&convolver_lock); convolver_r.process(data, data, length); pthread_mutex_unlock(&convolver_lock); } */shairport-sync-5.1-dev/FFTConvolver/convolver.h000066400000000000000000000015451520255574400216410ustar00rootroot00000000000000// C wrapper to C++ FFTConvolver #pragma once #ifdef __cplusplus extern "C" { #endif #include // int convolver_init(const char* file, unsigned char channel_count, double max_length_in_seconds, // size_t block_size); void convolver_reset(); // void convolver_clear_state(); // void convolver_process(unsigned int channel, float *data, int length); // void convolver_process_l(float* data, int length); // void convolver_process_r(float* data, int length); void convolver_pool_init(size_t numThreads, size_t numConvolvers); void convolver_pool_closedown(); int convolver_init(const char *file, unsigned char channel_count, double max_length_in_seconds, size_t block_size); void convolver_process(unsigned int channel, float *data, int length); void convolver_clear_state(); void convolver_wait_for_all(); #ifdef __cplusplus } #endif shairport-sync-5.1-dev/LIBSOXR.md000066400000000000000000000030051520255574400165730ustar00rootroot00000000000000 The Raspbian image at the time of writing is the `May 2016` version, with the release date of `2016-05-10`. It does not include `libsoxr`, but it is available as a package via `apt-get`. Alternatively, `libsoxr` is very easy to compile. Here are very brief instructions to download, compile and install it: * Install `cmake`. This is used in the building of libsoxr. On Linuxes such as Debian/Ubuntu/Raspbian: ``` # apt-get install cmake ``` On FreeBSD: ``` # pkg install cmake ``` * Download the `libsoxr source`: ``` $ git clone git://git.code.sf.net/p/soxr/code libsoxr ``` * `cd` into the `libsoxr` directory and start the build process: ``` $ cd libsoxr $ ./go ``` Be patient! This takes a long time on a Raspberry Pi -- it looks like it gets stuck around 40% or 50%, but it will finish if you let it. Having compiled `libsoxr`, it must now must be installed: ``` $ cd Release # make install ``` Finally, for Shairport Sync to be able to locate `libsoxr` during compilation, you need to tell `ld` about it. Be careful here if you are on FreeBSD -- the following instructions for Linux would mess up your FreeBSD system. On Linuxes such as Debian/Ubuntu/Raspbian: ``` # ldconfig -v ``` On FreeBSD you must add the location of the `soxr.pc` file to the `PKG_CONFIG_PATH`, if it exists, and define it otherwise. Here is what you do if it doesn't already exist: ``` $ PKG_CONFIG_PATH="/usr/local/lib/pkgconfig" $ export PKG_CONFIG_PATH ``` That's it. Now you can select the `--with-soxr` option when you're building Shairport Sync. shairport-sync-5.1-dev/LICENSES000066400000000000000000000030131520255574400162560ustar00rootroot00000000000000alac.c: Copyright (c) 2005, David Hammerton All rights reserved. see alac.c for full license text tinysvcmdns.c, tinysvcmdns.h: Copyright (C) 2011 Darell Tan All rights reserved. see tinysvcmdns.[ch] for full license text tinyhttp Copyright 2012 Matthew Endsley All rights reserved see the tinyhttp/LICENSE for full license text Shairport: Copyright (c) 2011-2013 James Laird Shairport Sync: Copyright (c) 2014–2017 Mike Brady Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. shairport-sync-5.1-dev/MQTT.md000066400000000000000000000304571520255574400162510ustar00rootroot00000000000000# MQTT in Shairport Sync To enable Shairport Sync to act as an MQTT publisher, you need to: 1. Install the mosquitto library: ``` # apt install libmosquitto-dev ``` 2. Add the configuration flag `--with-mqtt-client` to the list of parameters to the `./configure...` command. For example: ``` $ ./configure --with-mqtt-client --sysconfdir=/etc --with-alsa --with-avahi --with-ssl=openssl --with-systemd ``` If Shairport Sync has MQTT support, it will have the string `mqtt` in its configuration string. For example: ``` $ shairport-sync -V 3.3.8-OpenSSL-Avahi-ALSA-metadata-mqtt-sysconfdir:/etc ``` **Note:** [The Docker image](https://hub.docker.com/r/mikebrady/shairport-sync) will have MQTT support enabled by default. ## Setting Up MQTT Publishing This is a rough guide on the setup of MQTT publishing in ShairPort Sync. The MQTT service listens for and publishes metadata generated by the AirPlay source and Shairport Sync. ### Example Configuration In the following example, Shairport Sync is configured to publish parsed metadata information and album-art to a MQTT server under the topic "shairport". ```xml metadata = { enabled = "yes"; // Set this to yes to get Shairport Sync to solicit metadata from the source and to pass it on via a pipe. include_cover_art = "yes"; // Set to "yes" to get Shairport Sync to solicit cover art from the source and pass it via the pipe. You must also set "enabled" to "yes". cover_art_cache_directory = "/tmp/shairport-sync/.cache/coverart"; // Artwork will be stored in this directory if the dbus or MPRIS interfaces are enabled or if the MQTT client is in use. Set it to "" to prevent caching, which may be useful on some systems. pipe_name = "/tmp/shairport-sync-metadata"; pipe_timeout = 5000; // Wait for this number of milliseconds for a blocked pipe to unblock before giving up. }; mqtt = { enabled = "yes"; // Set this to yes to enable the mqtt-metadata-service. hostname = "192.168.1.111"; // Hostname of the MQTT Broker. port = 1883; // Port on the MQTT Broker to connect to. username = "username"; // Set this to your MQTT user's username in order to enable username authentication. password = "password"; // Set this to your MQTT user's password in order to enable username & password authentication. topic = "shairport"; // MQTT topic where this instance of Shairport Sync should publish. If not set, the general.name value is used. // publish_raw = "no"; // Whether to publish all available metadata under the codes given in the 'metadata' docs. publish_parsed = "yes"; // Whether to publish a small (but useful) subset of metadata under human-understandable topics. publish_cover = "yes"; // Whether to publish the cover over MQTT in binary form. This may lead to a bit of load on the broker. // publish_retain = "no"; // Whether to set the retain flag on published MQTT messages. When enabled, the broker stores the last message for each topic so new subscribers receive the most recent value immediately. // enable_remote = "no"; // Whether to remote control via MQTT. RC is available under `topic`/remote. }; ``` **Important:** Either `publish_raw`, `publish_parsed`, or `publish_cover` need to be set in the MQTT configuration. Otherwise, no messages will be published. ## Overall Active States `active_start` and `active_end` represent a stable on/off flag for the current AirPlay session. `active_start` is plublished when any new AirPlay session begins. `active_end` will fire after a configured timeout period unless the AirPlay stream is resumed. ```xml sessioncontrol = { // "active" state starts when play begins, and ends when the active_state_timeout has elapsed after play ends, unless another play session starts before the timeout has fully elapsed. active_state_timeout = 30.0; }; ``` ## Metadata Parsing Additional details regarding the metadata can be found at https://github.com/mikebrady/shairport-sync-metadata-reader. Metadata is generated by both the stream source (iOS, iTunes, etc.) and by Shairport Sync itself. This data is coded as two 4-character codes to identify each piece of data, the `type` and the `code`. The first 4-character code, called the `type`, is either: * `core` for all the regular metadadata coming from iTunes, etc., or * `ssnc` (for 'shairport-sync') for all metadata coming from Shairport Sync itself, such as start/end delimiters, etc. Additionally: * For `core` metadata, the second 4-character code is the 4-character metadata code that comes from iTunes, etc. See, for example, https://code.google.com/p/ytrack/wiki/DMAP for information about the significance of the codes. The original data supplied by the source, if any, follows, and is encoded in base64 format. The length of the data is also provided. * For `ssnc` metadata, the second 4-character code is used to distinguish the messages. Cover art, coming from the source, is not tagged in the same way as other metadata, it seems, so is sent as an `ssnc` type metadata message with the code `PICT`. Progress information, similarly, is not tagged like other source-originated metadata, so it is sent as an `ssnc` type with the code `prgr`. Here are some of the `core` codes commonly passed from the source: * `asal` -- album * `asar` -- artist * `ascp` -- composer * `asgn` -- genre * `astm` -- song time * `caps` -- play status (stopped, paused, playing) * `minm` -- title * `mper` -- track persistent id Here are the 'ssnc' codes defined so far: * `PICT` -- the payload is a picture, either a JPEG or a PNG. Check the first few bytes to see which. * `acre` -- Active Remote * `cdid` -- Client advertised Device ID * `clip` -- the payload is the IP address of the client, i.e. the sender of audio. Can be an IPv4 or an IPv6 address. * `cmac` -- Client advertised MAC address * `cmod` -- Client advertised model ("iPhone14,2") * `daid` -- DACP ID * `dapo` -- DACP Port * `mden` -- a sequence of metadata has ended. The RTP timestamp associated with the metadata sequence is included as data, if available. * `mdst` -- a sequence of metadata is about to start. The RTP timestamp associated with the metadata sequence is included as data, if available. * `pbeg` -- play stream begin. No arguments * `pcen` -- a picture has been sent. The RTP timestamp associated with it is included as data, if available. * `pcst` -- a picture is about to be sent. The RTP timestamp associated with it is included as data, if available. * `pend` -- play stream end. No arguments * `pfls` -- play stream flush. No arguments * `prsm` -- play stream resume. No arguments * `prgr` -- progress -- this is metadata from AirPlay consisting of RTP timestamps for the start of the current play sequence, the current play point and the end of the play sequence. * `pvol` -- play volume. The volume is sent as a string -- "airplay_volume,volume,lowest_volume,highest_volume", where "volume", "lowest_volume" and "highest_volume" are given in dB. The "airplay_volume" is what's sent by the source (e.g. iTunes) to the player, and is from 0.00 down to -30.00, with -144.00 meaning "mute". This is linear on the volume control slider of iTunes or iOS AirPlay. If the volume setting is being ignored by Shairport Sync itself, the volume, lowest_volume and highest_volume values are zero. * `snam` -- a device e.g. "Joe's iPhone" has started a play session. Specifically, it's the "X-Apple-Client-Name" string for AP1, or direct from the configuration Plist for AP2. * `snua` -- a "user agent" e.g. "iTunes/12..." has started a play session. Specifically, it's the "User-Agent" string. * `stal` -- this is an error message meaning that reception of a large piece of metadata, usually a large picture, has stalled; bad things may happen. * `svip` -- the payload is the IP address of the server, i.e. shairport-sync. Can be an IPv4 or an IPv6 address. ### Parsed Messages The MQTT service can parse the above raw messages into a subset of human-readable topics that include: * `active_remote_id` -- Active Remote ID * `artist` -- text of artist name * `album` -- text of album name * `client_ip` -- IP address of the connected client * `client_device_id` -- Client advertised Device ID * `client_mac_address` -- Client advertised MAC address * `client_model` -- Client advertised model ("iPhone14,2") * `client_name` -- Client advertised name ("Joe's iPhone") * `dacp_id` -- DACP ID * `format` -- ?? * `genre` -- text of genre * `server_ip` -- IP address of Shairport Sync that the client is connected to * `songalbum` -- * `title` -- text of song title * `volume` -- The volume is sent as a string -- "airplay_volume,volume,lowest_volume,highest_volume", where "volume", "lowest_volume" and "highest_volume" are given in dB. (see above) Additionally, empty messages (`--`) at the following topics are published. * `play_start` -- fired at the begining of every song * `play_end` -- fired at the end of every song * `play_flush` -- fired when song is skipped or on positional change * `play_resume` -- fired when song play resumes from pause * `active_start` -- fired when a new active AirPlay session begins * `active_end` -- fired after a configured timeout period after the stream ends (unless a new stream begins) ## Consuming MQTT Data MQTT provides users with the flexibility to consume the MQTT data in various home automation projects. If you have an interesting use, please raise a new issue to suggest adding it to the guide, or simply fork the development branch and create a pull request. ### [Home Assistant](https://www.home-assistant.io/) Examples The `active_start` and `active_end` have good potential use as triggers to turn on and off various connected receivers/zones. Note that `payload_off` is set to prevent accidental triggering. ```yml mqtt: - binary_sensor: name: "shairport active start" state_topic: "shairport/active_start" payload_on: "--" payload_off: "OFF" off_delay: 300 - binary_sensor: name: "shairport active end" state_topic: "shairport/active_end" payload_on: "--" payload_off: "OFF" off_delay: 300 ``` In the below example, the parsed data is saved into the Home Assistant database as sensor data. Please note the conversion of the volume from dB to percentage. ```yml mqtt: sensor: - name: "shairport album" state_topic: "shairport/album" expire_after: 600 - name: "shairport artist" state_topic: "shairport/artist" expire_after: 600 - name: "shairport title" state_topic: "shairport/title" expire_after: 600 - name: "shairport genre" state_topic: "shairport/genre" expire_after: 600 - name: "shairport volume (dB)" state_topic: "shairport/volume" - name: "shairport volume (PCT)" state_topic: "shairport/volume" value_template: "{{ value | regex_findall_index(find='^(.+?),', index=0, ignorecase=False) | float / 30 + 1 }}" unit_of_measurement: 'percent' ``` ### [Homebridge](https://homebridge.io/) [MQTTThing](https://github.com/arachnetech/homebridge-mqttthing#readme) Examples **Homebridge** is a lightweight Node.js server that brings non-HomeKit devices to Apple’s Home app, and **MQTTThing** is a versatile Homebridge plugin that integrates MQTT-enabled devices with HomeKit. While MQTTThing offers a speaker characteristic, it does not seem to be recognized by HomeKit. Instead, the **contact sensor** characteristic can effectively represent Shairport Sync’s `active` status within HomeKit, enabling users to trigger automations based on this status. Below is an example configuration for Homebridge's JSON Config to represent Shairport Sync's `active` status: ```json "accessories": [ { "type": "contactSensor", "name": "Shairport", "url": "hostname:1883", "username": "user", "password": "password", "topics": { "getContactSensorState": "shairport/active" }, "onValue": "1", "offValue": "0", "otherValueOff": false, "accessory": "mqttthing" } ] ``` * Replace hostname:1883, user, and password with the details of your MQTT broker. * The topic shairport/active should match the one configured in Shairport Sync’s MQTT settings. * The onValue and offValue correspond to the MQTT messages indicating whether Shairport Sync is active (1) or inactive (0). MQTTThing supports a wide range of characteristics, allowing additional topics from Shairport Sync or other devices to be represented in HomeKit as different accessory types (e.g., switches, lights, or sensors) in a similar manner. shairport-sync-5.1-dev/Makefile.am000066400000000000000000000266371520255574400172030ustar00rootroot00000000000000ARFLAGS = cr # To be able to ref to the user's own home directory: homedir = @HOME@ # Note that xmlmantohtml isn't producing correct HTML. # Uncomment the if/else and SUBDIR lines in this stanza to make xmltoman build shairport-sync.1 if USE_XMLTOMAN SUBDIRS = man else man_MANS = $(top_srcdir)/man/shairport-sync.1 endif lib_pair_ap_a_CFLAGS = -Wall -g -DCONFIG_GCRYPT -pthread --include=utilities/debug.h lib_tinyhttp_a_CFLAGS = -pthread lib_dbus_interface_a_CFLAGS = -pthread lib_mpris_interface_a_CFLAGS = -pthread bin_PROGRAMS = shairport-sync # BUILT_SOURCES get built before anything else (?) BUILT_SOURCES = CLEANFILES = shairport_sync_LDADD = noinst_LIBRARIES = # See below for the flags for the test client program shairport_sync_SOURCES = shairport.c bonjour_strings.c mdns.c common.c rtp.c \ player.c audio.c loudness.c activity_monitor.c \ rtsp.c \ utilities/debug.c utilities/network_utilities.c utilities/rtsp_message_utilities.c \ utilities/string_utilities.c if BUILD_FOR_DARWIN AM_CXXFLAGS = -I/usr/local/include -Wno-multichar -Wall -Wextra -Wno-deprecated-declarations -pthread -DSYSCONFDIR=\"$(sysconfdir)\" AM_CFLAGS = --include=utilities/debug.h -Wno-multichar -Wall -Wextra -Wno-deprecated-declarations -pthread -DSYSCONFDIR=\"$(sysconfdir)\" else if BUILD_FOR_FREEBSD AM_CXXFLAGS = -I/usr/local/include -Wno-multichar -Wall -Wextra -pthread -DSYSCONFDIR=\"$(sysconfdir)\" AM_CFLAGS = --include=utilities/debug.h -Wno-multichar -Wall -Wextra -pthread -DSYSCONFDIR=\"$(sysconfdir)\" else if BUILD_FOR_OPENBSD AM_CXXFLAGS = -I/usr/local/include -Wno-multichar -Wall -Wextra -Wno-clobbered -Wno-psabi -pthread -DSYSCONFDIR=\"$(sysconfdir)\" AM_CFLAGS = --include=utilities/debug.h -Wno-multichar -Wall -Wextra -pthread -DSYSCONFDIR=\"$(sysconfdir)\" else AM_CXXFLAGS = -Wshadow -fno-common -Wno-multichar -Wall -Wextra -Wformat -Wformat=2 -Wno-clobbered -Wno-psabi -pthread -DSYSCONFDIR=\"$(sysconfdir)\" AM_CFLAGS = --include=utilities/debug.h -Wshadow -fno-common -Wno-multichar -Wall -Wextra -Wformat -Wformat=2 -Wno-clobbered -Wno-psabi -pthread -DSYSCONFDIR=\"$(sysconfdir)\" endif endif endif # include version information from git if available if USE_GIT_VERSION ## Check if the git version information has changed and rebuild gitversion.h if so .PHONY: gitversion-check gitversion-check: $(top_srcdir)/verify-gitversion BUILT_SOURCES += gitversion-check CLEANFILES += gitversion-stamp gitversion.h endif if USE_HAMMERTON shairport_sync_SOURCES += alac.c endif if USE_APPLE_ALAC shairport_sync_SOURCES += apple_alac.cpp endif if USE_CUSTOMPIDDIR AM_CFLAGS+= \ -DPIDDIR=\"$(CUSTOM_PID_DIR)\" endif if USE_AVAHI shairport_sync_SOURCES += mdns_avahi.c endif if USE_TINYSVCMDNS shairport_sync_SOURCES += mdns_tinysvcmdns.c tinysvcmdns.c endif if USE_EXTERNAL_MDNS shairport_sync_SOURCES += mdns_external.c endif if USE_ALSA shairport_sync_SOURCES += audio_alsa.c endif if USE_JACK shairport_sync_SOURCES += audio_jack.c endif if USE_SNDIO shairport_sync_SOURCES += audio_sndio.c endif if USE_STDOUT shairport_sync_SOURCES += audio_stdout.c endif if USE_PIPE shairport_sync_SOURCES += audio_pipe.c endif if USE_DUMMY shairport_sync_SOURCES += audio_dummy.c endif if USE_AO shairport_sync_SOURCES += audio_ao.c endif if USE_SOUNDIO shairport_sync_SOURCES += audio_soundio.c endif if USE_PULSEAUDIO shairport_sync_SOURCES += audio_pa.c endif if USE_PIPEWIRE shairport_sync_SOURCES += audio_pw.c endif if USE_CONVOLUTION shairport_sync_SOURCES += FFTConvolver/AudioFFT.cpp FFTConvolver/FFTConvolver.cpp FFTConvolver/Utilities.cpp FFTConvolver/convolver.cpp FFTConvolver/ConvolverThreadPool.cpp AM_CXXFLAGS += -std=c++11 endif if USE_DNS_SD shairport_sync_SOURCES += mdns_dns_sd.c endif if USE_METADATA shairport_sync_SOURCES += metadata/pc_queue.c metadata/core.c endif if USE_METADATA_PIPE shairport_sync_SOURCES += metadata/pipe.c endif if USE_METADATA_MULTICAST shairport_sync_SOURCES += metadata/multicast.c endif if USE_METADATA_HUB shairport_sync_SOURCES += metadata/hub.c endif if USE_MQTT shairport_sync_SOURCES += mqtt.c endif if USE_DACP_CLIENT shairport_sync_SOURCES += dacp.c shairport_sync_LDADD += lib_tinyhttp.a noinst_LIBRARIES += lib_tinyhttp.a lib_tinyhttp_a_SOURCES = tinyhttp/chunk.c tinyhttp/header.c tinyhttp/http.c endif if USE_AIRPLAY_2 shairport_sync_SOURCES += ap2_buffered_audio_processor.c ap2_event_receiver.c \ ap2_event_message_handler.c ptp-utilities.c \ utilities/buffered_read.c utilities/structured_buffer.c utilities/mod23.c \ utilities/generate_random_uuid.c utilities/generate_device_uuid.c \ plists/get_info_response.c shairport_sync_LDADD += lib_pair_ap.a lib_pair_ap_a_SOURCES = pair_ap/pair.c pair_ap/pair_fruit.c pair_ap/pair_homekit.c pair_ap/pair-tlv.c noinst_LIBRARIES += lib_pair_ap.a plists/get_info_response.h: plists/get_info_response.xml sh $(top_srcdir)/xml_plist_codegen.sh $(top_srcdir)/plists/get_info_response.xml $(abs_builddir)/plists plists/get_info_response.c: plists/get_info_response.h touch plists/get_info_response.c BUILT_SOURCES += plists/get_info_response.h plists/get_info_response.c CLEANFILES +=plists/get_info_response.h plists/get_info_response.c endif if USE_DBUS shairport_sync_LDADD += lib_dbus_interface.a noinst_LIBRARIES += lib_dbus_interface.a lib_dbus_interface_a_SOURCES = dbus-interface.c shairport_sync_SOURCES += dbus-service.c BUILT_SOURCES += dbus-interface.h dbus-interface.c CLEANFILES += dbus-interface.h dbus-interface.c dbus-interface.c: org.gnome.ShairportSync.xml gdbus-codegen --interface-prefix org.gnome --generate-c-code dbus-interface $(top_srcdir)/org.gnome.ShairportSync.xml dbus-interface.h: dbus-interface.c touch dbus-interface.h endif if USE_MPRIS shairport_sync_LDADD += lib_mpris_interface.a noinst_LIBRARIES += lib_mpris_interface.a lib_mpris_interface_a_SOURCES = mpris-interface.c shairport_sync_SOURCES += mpris-service.c BUILT_SOURCES += mpris-interface.h mpris-interface.c CLEANFILES += mpris-interface.h mpris-interface.c mpris-interface.c: org.mpris.MediaPlayer2.xml gdbus-codegen --interface-prefix org.mpris --generate-c-code mpris-interface $(top_srcdir)/org.mpris.MediaPlayer2.xml mpris-interface.h: mpris-interface.c touch mpris-interface.h endif noinst_PROGRAMS = if USE_DBUS_CLIENT #Make it, but don't install it anywhere noinst_PROGRAMS += shairport-sync-dbus-test-client shairport_sync_dbus_test_client_SOURCES = shairport-sync-dbus-test-client.c shairport_sync_dbus_test_client_LDADD = lib_dbus_interface.a endif if USE_MPRIS_CLIENT #Make it, but don't install it anywhere noinst_PROGRAMS += shairport-sync-mpris-test-client shairport_sync_mpris_test_client_SOURCES = shairport-sync-mpris-test-client.c shairport_sync_mpris_test_client_LDADD = lib_mpris_interface.a endif CONFIG_FILE_INSTALL_TARGET = config-file-install-local $(CONFIG_FILE_INSTALL_TARGET): scripts/shairport-sync.conf install -d $(DESTDIR)$(sysconfdir) install -m 0644 $(top_srcdir)/scripts/shairport-sync.conf $(DESTDIR)$(sysconfdir)/shairport-sync.conf.sample [ -f $(DESTDIR)$(sysconfdir)/shairport-sync.conf ] || cp $(top_srcdir)/scripts/shairport-sync.conf $(DESTDIR)$(sysconfdir)/shairport-sync.conf if BUILD_FOR_LINUX DBUS_POLICY_DIR = /etc/dbus-1/system.d else DBUS_POLICY_DIR = $(sysconfdir)/dbus-1/system.d endif if USE_DBUS if INSTALL_CYGWIN_STARTUP DBUS_POLICY_FILE = scripts/shairport-sync-dbus-policy-cygwin.conf else DBUS_POLICY_FILE = scripts/shairport-sync-dbus-policy.conf endif # INSTALL_CYGWIN_STARTUP DBUS_POLICY_INSTALL_TARGET = dbus-policy-install-local $(DBUS_POLICY_INSTALL_TARGET): $(DBUS_POLICY_FILE) install -d $(DESTDIR)$(DBUS_POLICY_DIR) install -m 0644 $(top_srcdir)/$(DBUS_POLICY_FILE) $(DESTDIR)$(DBUS_POLICY_DIR)/shairport-sync-dbus.conf endif # USE_DBUS if USE_MPRIS if INSTALL_CYGWIN_STARTUP MPRIS_POLICY_FILE = scripts/shairport-sync-mpris-policy-cygwin.conf else MPRIS_POLICY_FILE = scripts/shairport-sync-mpris-policy.conf endif # INSTALL_CYGWIN_STARTUP MPRIS_POLICY_INSTALL_TARGET = mpris-policy-install-local $(MPRIS_POLICY_INSTALL_TARGET): $(MPRIS_POLICY_FILE) install -d $(DESTDIR)$(DBUS_POLICY_DIR) install -m 0644 $(top_srcdir)/$(MPRIS_POLICY_FILE) $(DESTDIR)$(DBUS_POLICY_DIR)/shairport-sync-mpris.conf endif # USE_MPRIS INSTALL_GROUP_TARGET = install-group-local $(INSTALL_GROUP_TARGET): getent group shairport-sync &>/dev/null || groupadd -r shairport-sync &>/dev/null INSTALL_USER_TARGET = install-user-local $(INSTALL_USER_TARGET): $(INSTALL_GROUP_TARGET) getent passwd shairport-sync &> /dev/null || useradd -r -M -g shairport-sync -s /usr/sbin/nologin -G audio shairport-sync &>/dev/null if INSTALL_SYSTEMV_STARTUP INSTALL_SYSTEMV_TARGET = install-systemv-local # watch out -- shairport-sync is created during the ./configure step and # will be stored in a scripts folder in the _build_ folder # which will be the source folder if you're not using a separate build folder $(INSTALL_SYSTEMV_TARGET): scripts/shairport-sync $(INSTALL_USER_TARGET) install -d $(DESTDIR)$(sysconfdir)/init.d [ -e $(DESTDIR)$(sysconfdir)/init.d/shairport-sync ] || install -m 0755 scripts/shairport-sync $(DESTDIR)$(sysconfdir)/init.d endif # INSTALL_SYSTEMV_STARTUP if INSTALL_SYSTEMD_STARTUP SYSTEMD_SERVICE = shairport-sync.service INSTALL_SYSTEMD_TARGET = install-systemd-local # watch out -- shairport-sync.service is created during the ./configure step and # will be stored in a scripts folder in the _build_ folder # which will be the source folder if you're not using a separate build folder # Install a system service script, but don't replace an existing script $(INSTALL_SYSTEMD_TARGET): scripts/$(SYSTEMD_SERVICE) $(INSTALL_USER_TARGET) install -d $(DESTDIR)$(systemdsystemunitdir) [ -e $(DESTDIR)$(systemdsystemunitdir)/shairport-sync.service ] || install -m 0644 scripts/$(SYSTEMD_SERVICE) $(DESTDIR)$(systemdsystemunitdir)/shairport-sync.service endif # INSTALL_SYSTEMD_STARTUP if INSTALL_FREEBSD_STARTUP # Choose a uid and gid of 801 completely arbitrarity, except that it should be below 1000. FreeBSD doesn't seem to allow you to say "an ID in the range of..." install-freebsd-user-local: pw showgroup shairport-sync > /dev/null 2>&1 || pw addgroup -n shairport-sync -g 801 > /dev/null 2>&1 pw showuser shairport-sync > /dev/null 2>&1 || pw adduser -c "shairport-sync unprivileged user" -n shairport-sync -u 801 -s /usr/sbin/nologin -d /nonexistent > /dev/null 2>&1 INSTALL_FREEBSD_TARGET = install-freebsd-local $(INSTALL_FREEBSD_TARGET): scripts/shairport-sync.freebsd install-freebsd-user-local install -d -o shairport-sync -g shairport-sync $(DESTDIR)/var/run/shairport-sync install -d $(DESTDIR)/usr/local/etc/rc.d/ install -m 0555 $(top_srcdir)/scripts/shairport-sync.freebsd $(DESTDIR)/usr/local/etc/rc.d/shairport_sync endif # INSTALL_FREEBSD_STARTUP if INSTALL_CYGWIN_STARTUP INSTALL_CYGWIN_TARGET = install-cygwin-local $(INSTALL_CYGWIN_TARGET): scripts/shairport-sync-config install -d $(DESTDIR)/usr/local/bin [ -e $(DESTDIR)/usr/local/bin/shairport-sync-config ] || install -m 0755 $(top_srcdir)/scripts/shairport-sync-config $(DESTDIR)/usr/local/bin/ endif # INSTALL_CYGWIN_STARTUP install-config-files: $(CONFIG_FILE_INSTALL_TARGET) \ $(DBUS_POLICY_INSTALL_TARGET) \ $(MPRIS_POLICY_INSTALL_TARGET) \ $(INSTALL_SYSTEMV_TARGET) \ $(INSTALL_SYSTEMD_TARGET) \ $(INSTALL_SYSTEMD_USER_TARGET) \ $(INSTALL_FREEBSD_TARGET) \ $(INSTALL_CYGWIN_TARGET) if INSTALL_CONFIG_FILES install-exec-hook: install-config-files endif shairport-sync-5.1-dev/NEWS000066400000000000000000000000701520255574400156250ustar00rootroot00000000000000Please refer to RELEASENOTES.md and README.md for news. shairport-sync-5.1-dev/OPENBSD.md000066400000000000000000000057231520255574400165540ustar00rootroot00000000000000Shairport Sync on OpenBSD [AirPlay 2 Not Supported] ---- This is a note about installing Shairport Sync on OpenBSD. Shairport Sync compiles and runs natively on OpenBSD using the `sndio` back end. For general information on `sndio` please follow [this link](http://www.sndio.org). Unlike FreeBSD, it seems that OpenBSD does not use the directory `/usr/local/etc` as a system configuration directory ("`sysconfdir`") but follows the same practice as Linux in using `/etc` as the default `sysconfdir`. General ---- This build was done on a default build of `OpenBSD 6.6 GENERIC.MP#5 amd64`. Following [this guide](https://www.openbsd.org/faq/faq15.html), `/etc/installurl` was created with the to refer to the standard repository: ``` https://ftp.openbsd.org/pub/OpenBSD ``` You might have a [closer or faster](https://www.openbsd.org/ftp.html) repository to use instead. Next, although it may not always be necessary, apply any outstanding system updates and [update the packages](https://unix.stackexchange.com/questions/23579/how-to-apply-updates-on-openbsd-netbsd-and-freebsd). First, update the system: ``` # syspatch ``` Now update the packages: ``` # pkg_add -Uu ``` Install the Avahi subsystem ([search](https://www.openbsd.org/faq/faq15.html) using, for example, `# pkg_info -Q avahi`). ``` # pkg_add avahi ``` A number of libraries will be installed to support Avahi, including the D-Bus system. Enable the D-Bus and Avahi subsystems to [start automatically](http://openbsd-archive.7691.n7.nabble.com/starting-avahi-the-proper-way-td311612.html): ``` # rcctl enable messagebus avahi_daemon # rcctl start messagebus avahi_daemon ``` Building ---- Install the following packages (e.g. using `pkg_add` in superuser mode) needed to download and build Shairport Sync: ``` # pkg_add autoconf automake popt libconfig git ``` Note the versions of `autoconf` and `automake` you choose (`2.69` and `1.16` at the time of writing) and add them as shell variable definitions for -- they could be placed in the user's `.profile` file to be automatically executed at login: ``` export AUTOCONF_VERSION=2.69 export AUTOMAKE_VERSION=1.16 ``` Now, download Shairport Sync from GitHub: ``` $ git clone https://github.com/mikebrady/shairport-sync.git $ cd shairport-sync ``` Next, configure and compile shairport-sync: ``` $ autoreconf -fi $ ./configure --sysconfdir=/etc --with-avahi --with-ssl=openssl --with-libdaemon \ --with-sndio --with-os=openbsd $ make ``` The application is called `shairport-sync`. Check that it's running correctly by executing the following command: ``` $ ./shairport-sync -V ``` This will execute the application and it will return its version information and terminate, for example: ``` 3.3.6-libdaemon-OpenSSL-Avahi-sndio-sysconfdir:/etc ``` There is no make install yet -- you're on your own. Using the `sndio` backend ---- The `sndio` back end does not yet have a hardware volume control facility. You should set the volume to maximum before use, using, for example, the `mixerctl` command. shairport-sync-5.1-dev/README000066400000000000000000000000001520255574400157770ustar00rootroot00000000000000shairport-sync-5.1-dev/README.md000066400000000000000000000257561520255574400164270ustar00rootroot00000000000000# Shairport Sync Shairport Sync is an [AirPlay](https://www.pocket-lint.com/speakers/news/apple/144646-apple-airplay-2-vs-airplay-what-s-the-difference) audio player for Linux, FreeBSD and OpenBSD. It plays audio streamed from Apple devices and from AirPlay sources such as [OwnTone](https://github.com/owntone/owntone-server) (formerly `forked-daapd`). Shairport Sync can be built as an AirPlay 2 player (with [some limitations](AIRPLAY2.md#features-and-limitations)) or as "classic" Shairport Sync – a player for the older, but still supported, AirPlay (aka "AirPlay 1") protocol. When built for AirPlay 2, Shairport Sync can play stereo and multichannel (5.1 and 7.1) audio, including lossless 24-bit stereo at 48,000 frames per second. Metadata such as artist information and cover art can be requested and provided to other applications. Shairport Sync can interface with other applications through MQTT, an MPRIS-like interface and D-Bus. Shairport Sync does not support AirPlay video or photo streaming. # Quick Start * If you are updating from a previous version of Shairport Sync, please visit the [release notes](RELEASENOTES.md) for possible breaking changes. * A building guide is available [here](BUILD.md). * A Docker image is available on the [Docker Hub](https://hub.docker.com/r/mikebrady/shairport-sync). Also see [docker/README.md](docker/README.md). * Next Steps and Advanced Topics are [here](ADVANCED%20TOPICS/README.md). * Runtime settings are documented [here](scripts/shairport-sync.conf). * Build configuration options are detailed in [CONFIGURATION FLAGS.md](CONFIGURATION%20FLAGS.md). * The `man` page, detailing command line options, is [here](https://raw.githack.com/mikebrady/shairport-sync/development/man/shairport-sync.1.xml). * Some advanced topics and developed in [ADVANCED TOPICS](https://github.com/mikebrady/shairport-sync/tree/master/ADVANCED%20TOPICS). # Features * Outputs AirPlay audio to [ALSA](https://www.alsa-project.org/wiki/Main_Page), [sndio](http://www.sndio.org), [PipeWire](https://pipewire.org), [PulseAudio](https://www.freedesktop.org/wiki/Software/PulseAudio/), to a unix pipe or to `STDOUT`. It also has limited support for [libao](https://xiph.org/ao/). * Metadata — Shairport Sync can deliver metadata supplied by the source, such as Album Name, Artist Name, Cover Art, etc. through a pipe or UDP socket to a recipient application program — see https://github.com/mikebrady/shairport-sync-metadata-reader for a sample recipient. Sources that supply metadata include iTunes and the Music app in macOS and iOS. * An interface to [MQTT](https://en.wikipedia.org/wiki/MQTT), a popular protocol for Inter Process Communication, Machine-to-Machine, Internet of Things and Home Automation projects. The interface provides access to metadata and artwork, with remote control for Classic AirPlay clients. * Digital Signal Processing facilities – please see the [DSP Wiki Page Guide](https://github.com/mikebrady/shairport-sync/wiki/Digital-Signal-Processing-with-Shairport-Sync). (Thanks to [Yann Pomarède](https://github.com/yannpom) for the code and to [Paul Wieland](https://github.com/PaulWieland) for the guide.) * An [MPRIS](https://specifications.freedesktop.org/mpris-spec/2.2/)-like interface, partially complete and very functional, including access to metadata and artwork, and partial remote control for Classic AirPlay clients. * A native D-Bus interface, including access to metadata, artwork and system settings. Remote control is also available for Classic AirPlay clients. * Better Volume Control — Shairport Sync offers finer control at very top and very bottom of the volume range. See http://tangentsoft.net/audio/atten.html for a good discussion of audio "attenuators", upon which volume control in Shairport Sync is modelled. See also the diagram of the volume transfer function in the documents folder. In addition, Shairport Sync can offer an extended volume control range on devices with a restricted range. * Flexible output rates, formats and channels with built-in transcoding. * Remote Control (Classic AirPLay only) – Remote control commands -- such as `play`, `pause`, and volume-setting commands -- can be sent to Classic AirPlay clients via the D-Bus, MPRIS and MQTT interfaces. Remote Control is unfortunately not available for AirPlay 2 clients, as the system used has not been discovered. Some features require configuration at build time – see [CONFIGURATION FLAGS.md](CONFIGURATION%20FLAGS.md). # Status Shairport Sync was designed to [run best](ADVANCED%20TOPICS/GetTheBest.md) on stable, dedicated, stand-alone low-power "headless" systems with ALSA as the audio system and with a decent CD-quality Digital to Analog Converter (DAC). Shairport Sync runs on recent (2018 onwards) Linux systems, FreeBSD from 12.1 onwards and OpenBSD. It requires a system with the power of a Raspberry Pi B or better. Classic Shairport Sync runs on a wider variety of Linux sytems, including OpenWrt and Cygwin and it also runs on OpenBSD. Many embedded devices are powerful enough to power classic Shairport Sync. # Heritage and Acknowledgements The functionality offered by Shairport Sync is the result of study and analysis of the AirPlay and AirPlay 2 protocols by many people over the years. These protocols have not been officially published, and there is no assurance that Shairport Sync will continue to work in future. Shairport Sync is a substantial rewrite of the fantastic work done in Shairport 1.0 by James Wah (aka [abrasive](https://github.com/abrasive)), James Laird and others — please see [this list](https://github.com/abrasive/shairport/blob/master/README.md#contributors-to-version-1x) of the contributors to Shairport 1.x and Shairport 0.x. From a "heritage" point of view, Shairport Sync is a fork of Shairport 1.0. For the development of AirPlay 2 support in Version 4.x, special thanks are due to: * [JD Smith](https://github.com/jdtsmith) for really thorough testing, support and encouragement. * [ejurgensen](https://github.com/ejurgensen) for advice and [code to deal with pairing and encryption](https://github.com/ejurgensen/pair_ap). * [ckdo](https://github.com/ckdo) for pointing the way, particularly with pairing and encryption protocols, with a [functional Python implementation](https://github.com/ckdo/airplay2-receiver) of AirPlay 2. * [invano](https://github.com/invano) for showing what might be possible and for initial Python development. * [Charles Omer](https://github.com/charlesomer) for Docker automation, repository management automation, testing, encouragement, enthusiasm. Much of Shairport Sync's AirPlay 2 functionality is based on ideas developed at the [openairplay airplay2-receiver]( https://github.com/openairplay/airplay2-receiver) repository. It is a pleasure to acknowledge the work of the contributors there. Thanks to everyone who has supported and improved Shairport Sync over the years. # More about Shairport Sync The audio that Shairport Sync receives is sent to the computer's sound system, to a named unix pipe or to `STDOUT`. By far the best sound system to use is ALSA. This is because ALSA can give direct access to the Digital to Analog Converter (DAC) hardware of the machine. Audio samples can be sent through ALSA directly to the DAC, maximising fidelity, and accurate timing information can be obtained from the DAC, maximising synchronisation. ## Synchronised Audio 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. To accomplish this, Shairport Sync needs access to audio systems – such as ALSA on Linux and `sndio` on FreeBSD and OpenBSD – that provide very accurate timing information about audio being streamed to output devices. Ideally, Shairport Sync should have direct access to the output device used, which should be a real sound card capable of working with 44,100 or 48,000 samples ("frames") per second, interleaved PCM stereo of 8, 16, 24 or 32 bits. Shairport Sync will choose a suitable output rate, format and channel count. This can be done manually or automatically. Shairport Sync works well with sound servers such as PipeWire and PulseAudio, widely used sound servers found on many desktop Linuxes. While the timing information is not as accurate as that of ALSA or `sndio`, it is often impractical to bypass these systems. For other use cases, Shairport Sync can provide synchronised audio output to a unix pipe or to `STDOUT`, 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. ## Latency, "Stuffing", Timing AirPlay protocols use an agreed *latency* – a time lag or delay – between the time represented by a sound sample's `timestamp` and the time it is actually played by the audio output device, typically a Digital to Audio Converter (DAC). Latency gives players time to compensate for network delays, processing time variations and so on. The latency is specified by the audio source when it negotiates with Shairport Sync. AirPlay sources set a latency of around 2.0 to 2.25 seconds. AirPlay 2 can use shorter latencies, around half a second. As mentioned previously, Shairport Sync implements full audio synchronisation when used with ALSA, `sndio`, PipeWire or PulseAudio audio systems. This is done by monitoring the timestamps present in data coming from the audio source and the timing information coming back from the audio system itself. To maintain the latency required for exact synchronisation, Shairport Sync will perform interpolation -- effectively shortening or lengthening the stream of audio to exactly match the output rate to the input rate. If the output device is running too slow or too fast relative to the source, Shairport Sync will resample sequences of audio frames to add or remove frames as needed. Higher quality resampling can be achieved with `libsoxr` support, but this requires a good deal of processing power — most embedded devices probably can't support it. If your computer is fast enough, Shairport Sync will automatically choose this method. Interpolation is not done for partial audio synchronisation – the audio samples are simply presented at exactly the right time to the next stage in the processing chain. Timestamps are referenced relative to the source computer's clock – the "source clock", but timing must be done relative to the clock of the computer running Shairport Sync – the "local clock". So, Shairport Sync synchronises the source clock and the local clock, usually to within a fraction of a millisecond. In AirPlay 2, this is done with the assistance of a companion application called [NQPTP](https://github.com/mikebrady/nqptp) using a [PTP](https://en.wikipedia.org/wiki/Precision_Time_Protocol)-based timing protocol. In classic AirPlay, a variant of [NTP](https://en.wikipedia.org/wiki/Network_Time_Protocol) synchronisation protocols is used. shairport-sync-5.1-dev/RELEASENOTES-DEVELOPMENT.md000066400000000000000000007654361520255574400211510ustar00rootroot00000000000000Version 5.0.5-dev-15-g3cbc4b18 == **Bug Fixes – Classic AirPlay Remote Control (Updated)** * A significant Classic AirPlay Remote Control bug was found: in Classic AirPlay mode, the DACP command port was being incorrectly reported to the Remote Control system, causing it not to function! This has been fixed, and remote control has been restored for Classic AirPlay. Please check the D-Bus interface for the [`RemoteControl`](org.gnome.ShairportSync.xml#L44) suite -- most all of these now work. The [`AdvancedRemoteControl`](org.gnome.ShairportSync.xml#L72) suite also works with the macOS Music App but only in Classic AirPlay. [MQTT remote control commands](mqtt.c#L68) and some [MPRIS commands](org.mpris.MediaPlayer2.xml#L16) should now also work, although the MPRIS interface is quite incomplete. * The `dapo` metadata token now correctly reports the DACP port as a character string, and reports a DACP port of `"0"` when the DACP port is or becomes invalid. Version 5.0.5-dev-12-g9d102497 == **Enhancements** * Setting a password now works with AirPlay 2 as well as Classic AirPlay. Use the `password` setting in the `general` section of the configuration file or the `--password=""` command line option to set a password. * Update information about the password and interpolation (aka "stuffing") command line settings. Version 5.0.5-dev-10-g4b020a6b == **Enhancements** * Experimentally allow up to 31 audio channels. This is up from a previous maximum of eight. The ALSA system allows up to 32 channels, one more than Shairport Sync can handle, so let's see... Unfortunately, this can not be tested due to a lack of suitable output devices, so if anyone can test it out, it would be appreciated. Thanks to [24fpsDaVinci](https://github.com/24fpsDaVinci) for the [issue](https://github.com/mikebrady/shairport-sync/issues/2199). **Upmixing** * "Upmixing" adds channels to an audio stream, e.g. you could upmix stereo (two channels) to 5.1 surround sound (six channels) by copying and blending the stereo channels to drive the extra surround channels. The FFmpeg resampler used by Shairport Sync does implement upmixing, but by default it just copies the source channels to their equivalent channels in the output, leaving the extra channels silent. So, while Shairport Sync does technically implement upmixing, it makes no audible difference. Maybe in the future, upmixing matrices will be added, but it is not a priority just now. Thanks to [iliaspapan](https://github.com/iliaspapan) for [enquiring](https://github.com/mikebrady/shairport-sync/issues/2194) about this. Version 5.0.5-dev-7-g3a1bfd71 == **Docker Updates** * Update Docker images to use Alpine 3.23.4 (up from build 20250108). * Update Docker images to use FFmpeg 8.1 (up from 7.1). **Other Updates** * Fix some benign compiler warnings coming from the updated compiler in Ubuntu 26.04. Version 5.0.5-dev-2-g2400aae4 == This is effectively 5.0.4-dev-9-g68b6d4df. Version 5.0.4-dev-9-g68b6d4df == **Bug Fix** * Fixed missing configuration mapping parameter in PulseAudio backend initialisation. This bug would prevent the PulseAudio backend from initialising, preventing Shairport Sync from working. Version 5.0.4-dev-5-g936b8387 == **New Features** * AirPlay 2 Passwords. Until now, you could set a password only for Classic AirPlay. Now, setting a password is effective for both AirPlay 2 and Classic AirPlay. * Metadata multicast is now optional, so can, in principle, be omitted. This is still experimental. * DACP support is optional and can, in principle, be omitted. This is still experimental. **Bug Fixes and Stability Improvements** * Calls to some libraries have been made uncancellable in order to improve application stability when terminating or when pre-empting an active play session. These changes are not yet complete. **Other Changes** * Some rationalisation of source files is being undertaken. Version 5.0.3-dev-4-g07ca1891 == **Release** * This is effectively release 5.0.3 **Bug Fix** * Make code using `getifaddrs()` uncancellable to prevent a mysterious `Unexpected error 9 on netlink descriptor` error. Thanks to [microfx](https://github.com/microfx) for reporting the [issue](https://github.com/mikebrady/shairport-sync/issues/2184). Version 5.0.3-dev == **Small Changes** * Add warnings if string or boolean configuration parameters were present but not strings. * Improve behaviour when there is a large timing uncertainty/granularity and a large audio buffer. e.g. on some virtual machines. * Make the SoxR delay checker thread behave better when being cancelled. * Remove some debug messages, quieten some others, add a few. Version 5.0.1+-38-gf784e463 == **Build Update** * The Apple ALAC Decoder can no longer be included in an AirPlay 2 build. The reason is that FFmpeg -- used instead -- deals comprehensively with ALAC, AAC, multichannel, mixdown and rate transcoding and is well maintained. The Apple ALAC Decoder is known to have security issues and is no longer maintained. This update prevents it from being included in Shairport Sync for AirPlay 2. Version 5.0.1+-36-g6729802d == **Update** * The Shairport Sync `systemd` service file has been updated as follows: * It uses POSIX shell parameter expansion functionality to prevent adding leading space in option values. * It adds `nqptp.service` to the `After` and `Requires` options when building for Airplay 2. Many thanks to [mikelei8291](https://github.com/mikelei8291) for the [PR](https://github.com/mikebrady/shairport-sync/pull/2174). Version 5.0.1+-32-g20a87fef == **Build Bugfix** * Fix a bug at the `.configure...` stage of a build of Classic Shairport Sync whereby the UUID library was incorrectly required if the FFmpeg library was being used. (The wording on a few associated warning messages was also fixed.) Thanks to [phexian](https://github.com/phexian) for the [report](https://github.com/mikebrady/shairport-sync/issues/2177). **Dependabot Update** * A Dependabot update to a building tool was added. Version 5.0.1+-23-g7fb3506e == **Documentation Update** * Fixed dead link to the online [`man`](https://raw.githack.com/mikebrady/shairport-sync/development/man/shairport-sync.1.xml) page. Thanks to [CornelisJ](https://github.com/CornelisJ) for the [report](https://github.com/mikebrady/shairport-sync/issues/2158). Version 5.0.1+-13-ga14517d7 == **Change** * When built for AirPlay 2, add `pw=true` to the Bonjour raop properties if the classic AirPlay password is set. This might help with Owntone compatibility. Version 5.0.1+-11-g07546c35 == **Changes** * Turn off yet more currently-irrelevant debug messages by setting their level to 4, meaning they will never be displayed. * Use `NULL` instead of `0` to check for the presence of a classic AirPlay password. Makes no difference, but type-wise it is less misleading. Version 5.0.1+-8-gb09fd400 == **Bug Fix** * Defer rather than delete blocks of audio that are too far into the future, and also check for a valid clock when checking the timing of blocks. This is to attempt to deal with an unexpected situation where the timing of blocks of incoming audio seems to suddenly jump into the distant future, as if audio from the skipped-over interval has been dropped. Can this be classified as a bug fix? Who knows! **Changes** * Turn off some more currently-irrelevant debug messages by setting their level to 4, meaning they will never be displayed. Version 5.0.1+-2-g22f283fe == **Bug Fix** * Update the D-Bus test client to refer to `shairport_sync_get_loudness_enabled` rather than `shairport_sync_get_loudness`. thankt to [flatsiedatsie](https://github.com/flatsiedatsie) for the [bug report](https://github.com/mikebrady/shairport-sync/issues/2155). **Other Changes** * Turn off many currently-irrelevant debug messages by setting their level to 4, meaning they will never be displayed. Version 5.0-post-dev-13-g5893eabf == * The MQTT client in Shairport Sync has a Home-Assistant-specific configuration key called `object_id` used to define the entity's unique ID for HA. The term `object_id` has been deprecated by HA in favour of a new term: `defauly_entity_id`. This has now been added to Shairport Sync's MQTT client. The deprecated `object_id` term will be removed in a future release. Thanks to [Markus Reiter](https://github.com/reitermarkus) for the [PR](https://github.com/mikebrady/shairport-sync/pull/2148). Version 5.0-post-dev-10-g3888999d == * Remove requirement for the `mosquitto` service to be running when Shairport Sync is built with the `--with-mqtt-client` configuration flag. The service does not, in fact, need to be running in every case. This reverses a change made in [PR](https://github.com/mikebrady/shairport-sync/pull/2137) at [Version 5.0-dev-161](https://github.com/mikebrady/shairport-sync/blob/development/RELEASENOTES-DEVELOPMENT.md#version-50-dev-161-g5b3659c2). Thanks to [David Crook](https://github.com/idcrook) for the [bug report](https://github.com/mikebrady/shairport-sync/issues/2150). Version 5.0-post-dev-6-gd32d5cb9 == * Fix handling of missing `const` type qualifier and some follow-on warnings. Thanks to [Rudi Heitbaum](https://github.com/heitbaum) for the [PR](https://github.com/mikebrady/shairport-sync/pull/2146). Version 5.0-post-dev-1-g963380a8 == * This is essentially release Version 5.0 or 5.0.0. Version 5.0-dev-168-g846e0e3d == **MQTT Enhancement** * Add a new `publish_retain` boolean option to the MQTT section of the configuration file (normally `/etc/shairport-sync.conf`). When enabled, published MQTT messages will have the `retain` flag set, so that the MQTT broker stores the last message per topic and new subscribers receive the most recent value immediately. Thanks to [lululombard](https://github.com/lululombard) for the [PR](https://github.com/mikebrady/shairport-sync/pull/2142). **Dependabot Update** * A Dependabot update to some image building tools was added. Version 5.0-dev-161-g5b3659c2 == **Bug Fix** * Fix an MQTT warning and simplify building the `systemd` startup script. The warning occured if Shairport Sync was built with MQTT support. For that case, the startup script omitted stating that the `mosquitto` service was required and had to be active before starting Shairport Sync. Thanks to [hvilleneuve29](https://github.com/hvilleneuve29) for the [PR](https://github.com/mikebrady/shairport-sync/pull/2137). **Dependabot Update** * A Dependabot update to some image building tools was added. Version 5.0-dev-155-g45063d10 == **Bug Fix** * Finally! Add [Carl Johnson](https://github.com/SoarVermont)'s [suggestion](https://github.com/mikebrady/shairport-sync/issues/1996) to only consider interfaces that are up, running and not loopback interfaces for a valid MAC address. Thanks to Carl for his suggestion and for his gentle reminder. Versions 5.0-dev-153-g525e49cd, 5.0-dev-151-g16b6534a and 5.0-dev-146-g691d71f3 == **Updates** * Tighten up the checking of arguments given to `debug()`, `inform()`, `warn()` and `die()` to avoid silly errors. No known issues, but better sure than sorry. Thanks to [ejurgensen](https://github.com/ejurgensen) for the [PR](https://github.com/mikebrady/shairport-sync/pull/2124) which prompted the review. Version 5.0-dev-142-gfcacc4e5 == **Updates** * Continuing to address some issues with AutoMix on AirPlay, skipping tracks, and other unreported issues, this update represents some "housekeeping" -- cleaning up some old code based on a better (?) understanding of protocols. Your bug reports are welcome. Here are some of the details: * Cleaned up `get_play_lock()` and `release_play_lock()` stuff and placed them in the right places for AP2, AP1 compatibiity and Classic AP. * Fixed the setting of flags and GID in Bonjour. * The `principal_conn` is correctly released when terminating a listener loop. * The `airplay_stream_type` is correctly set for a classic airplay session. * Moved NQPTP clock setup and start from Setup Phase 1 to Setup Phase 2. * Stopped a player thread from resetting the NTPTP client clock when it finishes. * Modified and greatly simplified the `TEARDOWN` handling in AP2 mode. * Allowed threads to 'naturally' terminate when ports are closed by the client. * Improved clearing of flush requests in new play sessions. * Added, but disabled, code to remove previously decoded buffers of data from the player if replacement buffers come in later. (This happens when input changes from AAC to ALAC on the fly, and it's unclear whether this is an AirPlay 2 implementation bug or not.) It's unclear which buffers should have primacy -- the older ones or the newer ones -- so for simplicity new buffers that would replace buffers that are already decoded are simply dropped. Version 5.0-dev-106-gec0016fb == **Bug Fix** * Fix a bug in the PulseAudio backend so that `PA_ERR_NODATA` returns "No latency data yet". Thanks to [Vladimir Shakov](https://github.com/bogdad) for the [report and fix](https://github.com/mikebrady/shairport-sync/pull/2119). Version 5.0-dev-100-ga1238882 == **Bug Fix** * Fixed a bug whereby Shairport Sync would not work with `mbedtls` library from version 3.4 (present on recent versions of Linux, e.g. Debian 13...). Many thanks to [Christian Beier](https://github.com/bk138) for [finding the bug](https://github.com/mikebrady/shairport-sync/issues/2115) and for [fixing it](https://github.com/mikebrady/shairport-sync/pull/2118). Version 5.0-dev-93-g1417cd6f == **Bug Fix** * Ensure old flush requests are deleted when a new play session starts. Thanks to [saujanyashah](https://github.com/saujanyashah) for the [report](https://github.com/mikebrady/shairport-sync/issues/2107). Version 5.0-dev-87-ge12a3ed7 == **Updates -- This is Significant** * To address some issues around AutoMix on AirPlay, a long-overdue rebuild of the buffered audio processor and been done, using everything we have figured out until now. It implements a cleaner method to handle both immediate and deferred flush requests. Lots of old flags and redundant code have been removed. Some diagnostics have been left in the code. The changes are pretty far-reaching, and it is possible that new issues have been inadventently introduced and old ones revived. Please let us know if you discover any issue, especially if you can readily cause the issue to occur. As you may know, it can be difficult to determine if an issue is caused by AirPlay 2 itself or by Shairport Sync. Version 5.0-dev-83-g38592252 == **Enhancements** * _Convolution Update._ The convolution system is now multithreaded and works on stereo and multichannel audio at 48k and 44.1k. * Multiple impulse response (IR) files can now be provided to the convolution system through a new setting: `convolution_ir_files` (the old setting: `convolution_ir_file` is now deprecated). When convolution starts, Shairport Sync will look for an IR file with a sample rate matching the input (44.1k or 48k) and channel count. If an exact match can not be found, it will start again and look for a single-channel IR file with the matching rate. It will always choose the first match in the file list supplied with the `convolution_ir_files` setting or the `D-Bus` method. * Multithreading of convolution processing is now possible -- use the `convolution_thread_pool_size` setting to set the number of threads to use during convolution. (Note: high levels of multicore operation can cause audible power supply noise on some systems, due to rapid power switching or frequency-ramping of CPU cores.) * The [HiFi-LoFi FFT convolver](https://github.com/HiFi-LoFi/FFTConvolver) has been updated to the latest available. * _Loudness Update._ The loudness code now works with stereo and multichannel audio at 48k and 44.1k. **Deprecations** * The Jack audio backend is deprecated and will be removed in the future. It seems to be very little used, and most of its functionality is now available through PipeWire. **Configuration File and D-Bus Changes** * A new `convolution_thread_pool_size` configuration file setting has been added, defaulting to 1. This is not available in the `D-Bus` interface. * The `convolution` setting is deprecated -- use `convolution_enabled` instead. * The `convolution_max_length` setting is deprecated -- use `convolution_max_length_in_seconds` instead. * The `convolution_ir_file` setting is deprecated -- use `convolution_ir_files` (i.e. plural!) instead. * The `loudness` setting is deprecated -- use `loudness_enabled` instead. * Corresponding `D-Bus` methods and properties have been updated. **Bug Fix** * Fix an FFmpeg deprecation warning. Version 5.0-dev-65-g8545938d == **Enhancement** * Add a new command-line argument `dbus_default_message_bus` which can be `system` or `session`. This becomes the default message bus used both by the D-Bus native service and the MPRIS service. In its absence, the default is to use the `system` message bus. Example of use: ``` $ shairport-sync ... --dbus_default_message_bus=session .... ``` * Add a warning if a convolution impulse response file can not be read, e.g. due to a bad path name or a permissions error. **Bug fix** * If the native D-Bus interface is active and a convolution impulse response file is specified, don't open it a second time on startup. (BTW, this is not known to have caused any problems.) Version 5.0-dev-50-g10700356 == **Docker Update** * Add an `ENABLE_AVAHI` environment variable to enable or disable `avahi` and `dbus` processes in the Docker image. The default is to enable both, an has always been the case. Thanks to [Adam Oleksy](https://github.com/admo) for the [PR](https://github.com/mikebrady/shairport-sync/pull/2071). Version 5.0-dev-47-g03fb1d69 === **Tiny Update** * Remove a redundant `s6-overlay` directory from the `docker` `etc` subdirectory. The directory was obsolete and wasn't copied into Docker images anyway... * Various Dependabot updates. Version 5.0-dev-39-g77d0deec == **Dependabot Updates** * A number of deferred Dependabot-originated updates have been accepted. They all relate to (limited) automated testing and Docker image creation. Version 5.0-dev-34-ga5a54621 == **Bug Fix** * Fixed a bug whereby the volume setting was ignored if the input was not at 44100 FPS and the loudness DSP setting was enabled. Thanks to [microfx](https://github.com/microfx) for the [report](https://github.com/mikebrady/shairport-sync/issues/2039) and for helping to track down the issue. Version 5.0-dev-25-ge05448ae == **Bug Fixes and Enhancements** * A convenience script [`user-service-install.sh`](user-service-install.sh) has been added to install a `systemd` user service startup script. * Associated with this, a user service startup script is no longer installed at the `# make install` step in a `systemd` based Linux. This is because: * The user service startup script would be owned by `root` and therefore would not be editable or removable by the user, * The user service startup script would be only be installed correctly if the command was `$ sudo make install` and would not work properly if the command was `# make install` because the script would be installed in the wrong place. * Update the [BUILD.md](BUILD.md) guide to reflect the introduction of the new script. * Thanks to [petcol](https://github.com/petcol) for their [help and persistence](https://github.com/mikebrady/shairport-sync/issues/2003) in identifying and resolving this problem. * Ignore empty configuration setting strings. Specifically, log a warning and behave as if the configuration setting was not given. Thanks to [mantheman](https://github.com/mantheman) for the initial report. * Add a `disconnect` command to the MQTT interface. Thanks to [Jordan Zucker](https://github.com/jzucker2) for the [PR](https://github.com/mikebrady/shairport-sync/pull/2001). * In the Docker images, remove any left-over `pid` files before starting the D-Bus and Avahi services. Thanks to [Kir Belevich](https://github.com/deepsweet) for the [report](https://github.com/mikebrady/shairport-sync/issues/2009). Version 5.0-dev == This is a major update adding exciting new features and improvements to Shairport Sync: * 48k operation; * 48k lossless stereo from Apple devices e.g. Homepod mini, Apple TV 4K; * 48k 5.1 and 7.1 surround sound from Apple devices e.g. Homepod mini, Apple TV 4K; * Full FFmpeg integration for flexibility and security; * Multichannel ALSA, PipeWire, PulseAudio, FreeBSD, stdout and unix pipe output backends; * Flexible, controllable, automatic matching of output format to input format; * Improved synchronization; * A new "vernier" resampling and interpolation method for low-power CPUs; * Lower powered devices operation, including the original Raspberry Pi B; * Reduced Docker image sizes; * A `systemd` user startup script. * Many bug fixes. 44.1k operation is retained. **Deprecation Note** The stand-alone ALAC decoder by John Hammerton, used in all versions of Shairport Sync until now, and Apple's own ALAC decoder, optional for Shairport Sync, are now deprecated due to maintainance and security issues. You may find it be necessary to use one of them (for classic AirPlay reception only) in devices with very restricted storage, but security considerations mean that these decoders will be fully dropped in future. **Warning:** This is a breaking update. That means you probably can not simply update an existing installation of Shairport Sync without a little bit of work. To update correctly you must: * Remove the Shairport Sync device from Apple Home -- you can add it back later; * Review the list of libraries needed for building Shairport Sync, as there are some extras -- see the updated [BUILD.md](BUILD.md) guide; * Review configuration flags when building Shairport Sync -- some names have changed, e.g. `--with-systemd` becomes `--with-systemd-startup`; * Fully delete and reinstall Shairport Sync and NQPTP, along with all their service files; * Review and update settings: * Some of the names of the setting sections have changed, e.g. the `pa` section becomes the `pulseaudio` section; * The behaviour of Shairport Sync backends has changed, e.g. rates and channel counts can change dynamically. Version 4.3.7-dev-24-gbc5001eb == This is effectively release 4.3.7. **Dependabot Updates** * A number of deferred Dependabot-originated updates have been accepted. They all relate to (limited) automated testing and Docker image creation. Version 4.3.7-dev-11-g7367d042 == **Automated Docker Build Fixes** * Thanks to [Charles Omer](https://github.com/charlesomer) for [fixes](https://github.com/mikebrady/shairport-sync/pull/1961) to the Github Action scripts for building and pushing Docker images. Version 4.3.7-dev-3-g802058fe == **Docker Enhancement** * Add `curl` to the Docker images to facilitate automations. Thanks to [ironcrafter54](https://github.com/ironcrafter54) for the [suggestion](https://github.com/mikebrady/shairport-sync/discussions/1960). Version 4.3.7-dev == * This is effectively Version 4.3.6-dev-24-g015a5829, which is also effectively Version 4.3.6. Version 4.3.6-dev-24-g015a5829 == **MQTT Documentation Addition** Show how to use [MQTTThing](https://github.com/arachnetech/homebridge-mqttthing#readme) with [Homebridge](https://homebridge.io/) to represent Shairport Sync’s `active` status. Thanks to [keefar](https://github.com/keefar) for the [PR](https://github.com/mikebrady/shairport-sync/pull/1955). Version 4.3.6-dev-19-g39781ece == **Documentation Fix** Fix a typo in the configuration file. Many thanks to [Justin](https://github.com/OptimoSupreme). Version 4.3.6-dev-17-gce73230e == **Documentation Fix** Correct and clarify the [statistics documentation](https://github.com/mikebrady/shairport-sync/blob/master/ADVANCED%20TOPICS/Statistics.md). 1. The descriptions of Net Sync PPM and All Sync PPM were partly swapped -- this has been corrected. 2. Generally clarify the language and harmonize the wording with the introduction. Many thanks to [willmo](https://github.com/willmo) for the [PR](https://github.com/mikebrady/shairport-sync/pull/1950). Version 4.3.6-dev-13-g00e595ce == **Docker Build Optimistion** Ensure the `/run/dbus` directory, needed for dbus to start, is defined. Version 4.3.6-dev-9-gf7401ec7 == **Docker Build Optimisation** Improve the Dockerfile build sequences as follows: 1. Build each dependency in a separate stage, facilitating parallel builds. 2. Define default value for ARGS, permitting easier local docker builds. 3. Clone the specified branch only, and to a depth of 1, thus getting relevant data faster. 4. Copy files in a one-off command, reducing the amount of Docker layers created. Many thanks to [David Girón](https://github.com/duhow) for the [PR](https://github.com/mikebrady/shairport-sync/pull/1945). Version 4.3.6-dev-3-ge4d3c6f7 == **Bug Fix** * Fix a potential bug by checking that a buffer is not zero before attempting to deallocate it. Version 4.3.6-dev-1-g409397d3 == This is effectively the same as the release version 4.3.5. Version 4.3.5-dev-56-g758648a5 == **Deprecation Note** * The `soundio` backend is being deprecated and will be removed in a future update. It seems that nobody is using it, and as it stands it is very inflexible. _"If this be error and upon me proved,"_ -- as [Shakespeare wrote](https://www.poetryfoundation.org/poems/45106/sonnet-116-let-me-not-to-the-marriage-of-true-minds) -- please let us know... Version 4.3.5-dev-53-gaa3af3b3 == **Bug Fix** * Fix a problem in the Jack Audio backend `audio_jack.c`. The problem was that if the system's jack server was running at anything other than 44,100 frames per second, the delay information being returned by the backend was incorrect. Thanks to [lucianoiam](https://github.com/lucianoiam) for [reporting the problem](https://github.com/mikebrady/shairport-sync/issues/1926) and for checking the proposed solution. Version 4.3.5-dev-48-gfe743fdf == **Docker Bug Fixes** * Stop advertising the SFTP and SSH services on Bonjour. Thanks to [https://github.com/jpbaril](https://github.com/jpbaril) for bringing this to notice. **Bug Fix** * Due to recent changes in the MQTT client, a compilation error occured when building for Classic Airplay only. Fixed. Version 4.3.5-dev-44-ge4c2ce4a == **Enhancements** * Add Home Assistant MQTT Auto-Discovery and active/playing State Messages, thanks to [aaronk6](https://github.com/aaronk6). * Send `pvol` metadata on mute, thanks to [Tucker Kern](https://github.com/mill1000). **Bug Fix** * Check `swr_init()` and exit if error code found, thanks to [Andrew May](https://github.com/acmay). Version 4.3.5-dev-29-g17b134b0 == **PipeWire Enhancement** * Initialise the PipeWire backend so that the PipeWire stream is initially inactive. Version 4.3.5-dev-27-g8e6bd06c == **PipeWire Enhancement** * Until now, the stream in the PipeWire backend remained permanently active. This meant that external programs could not tell when audio was really playing or not. Now the stream will go inactive (i.e. "paused") when play is stopped and active when play resumes. Note that in AirPlay 2, play often stops momentarily between tracks, and so there will be momentary changes from active to inactive and back to active again in the PipeWire backend. This may change as the backend improves. Thanks to [Nemo157](https://github.com/Nemo157) for the Idea: https://github.com/mikebrady/shairport-sync/discussions/1889. Version 4.3.5-dev-23-g1687b2a4 == **Docker Enhancement** * The AirPlay 2 Docker image now incorporates the PipeWire backend. Thanks to [Maxim](https://github.com/irdkwmnsb) for the PR: https://github.com/mikebrady/shairport-sync/pull/1880. Version 4.3.5-dev-6-g597aba0c == **FreeBSD Bug Fix** * Modify the `sndio` backend (native to OpenBSD, also used in FreeBSD) to deal with an intermittent bug. Specifically, use an explicit `is_running` flag to keep track of the playing status of the backend. Thanks to [Jan Przybylak](https://github.com/janprzy), [Klemens Nanni](https://github.com/klemensn) and [Amanda Stjerna](https://github.com/amandasystems) for their help and persistence tracking down this problem. Resolves Issue: https://github.com/mikebrady/shairport-sync/issues/1765. **Configuration Comment Update** * Update comments in the `sndio` section of the sample configuration file. Version 4.3.5-dev-3-ge28c566a == **Bug Fix** * Fix a double-free fault introduced by replacing `avcodec_close` with `avcodec_free_context`. It seems as if the context is freed by a subsequent `av_free` anyway... Sigh. Version 4.3.5-dev-1-g9909bc21 == **Bug Fix** * Use `(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO` now in place of bit-mapped `AV_CH_LAYOUT_STEREO` when setting up the FFmpeg software resampler with `swr_init()`. It was possible to do this starting at FFmpeg 5.1, but is mandatory in FFmpeg 7. Also remove now-deprecated `avcodec_close`. Thanks to [Deyan Dragov](https://github.com/itsdeyan) for the report: https://github.com/mikebrady/shairport-sync/issues/1876. Version 4.3.4-dev-25-g15a7090a == **Change** * Revert the `session_timeout` to two minutes (120 seconds). In other words, if a player becomes disconnected for more than two minutes while playing, the session is terminated. **Bug Fixes** * Enable the disconnected session timeout for AirPlay 2 operation -- it had been disabled by default. * Fix a bug that prevented a fatal error that occured while directly accessing the alsa output device from terminating the application cleanly. Version 4.3.4-dev-21-g105299a7 == **Bug Fix** * Fixed a bug that prevented Shairport Sync from recovering cleanly if a player disconnected without warning. The problem was that the player thread would not respond to cancel request. Fixed by moving a `pthreadtestcancel()` call to the innermost loop. Associated with this, some obsolete watchdog code has been removed. Also, the `session_timeout` default has been changed from 120 seconds to 60 seconds. Thanks to [Tobias Huttinger](https://github.com/tobiashuttinger) for the bug report -- Issue [#1870](https://github.com/mikebrady/shairport-sync/issues/1870). Version 4.3.4-dev-13-gc064b8ba == **Bug Fixes** * Reorder some of the files to be included in `shairport.c` to fix compilation errors in old versions of Mac OS X. * Avoid using `TCP_KEEPINTVL` and `TCP_KEEPCNT` if they are not defined (they are not defined in older versions of Mac OS X). Thanks to [Sergey Federov](https://github.com/barracuda156) for raising these [issues](https://github.com/mikebrady/shairport-sync/issues/1860) and pointing at a potential solution. * Fix a race condition with the metadata queues. The problem was that the queues were being initialised by threads launched by the main thread which, having started the threads, proceeded to use the queues. But if the threads were late in starting, the queues might not be initialised by the time the main thread tried to use them. Fixed by initialising the queues in the main thread. Version 4.3.4-dev-10-gaade1b39 == **Docker Enhancement -- Continued** * Move the `ulimit -n ...` command to set the maximum file limit from the `01-startup/script.sh` (where it didn't seem to have any effect) to the `02-dbus/run`. Thanks to [rp86](https://github.com/rp86) for the feedback. Version 4.3.4-dev-8-g111e247b == **Docker Enhancement** * Limit maximum open file handles in Docker images. Thanks to [Florian Wallner](https://github.com/powerflo) for [Issue #1756](https://github.com/mikebrady/shairport-sync/issues/1756), [iVolt1](https://github.com/iVolt1) for pointing to a fix and [rp86](https://github.com/rp86) for the reminder! * Increase the level of optimisation while building the Shairport Sync application itself. Version 4.3.4-dev-6-g5f64722a == **Enhancement -- HDMI Ports** * As a further enhancement for HDMI, enable access to mixers on a HDMI output device. The issue appears to be that a mixer can not be "attached" to a device whose name begins with `hdmi:`, so it must be attached to the same device, but with the `hdmi:` prefix replaced by `hw:`. Version 4.3.4-dev-3-g238e4bbf == **Enhancement -- HDMI Ports** * If your device has HDMI ports, the Shairport Sync help command has previously listed them with a `hw:` prefix, e.g. `hw:vc4hdmi0`. Unfortunately, if you use a name like that as an `output_device` name for a HDMI device in Shairport Sync, the device may not be usable. But if you use the `hdmi:` prefix, e.g. `hdmi:vc4hdmi0`, it _may_ work: something capable of receiving audio must be connected to the HDMI port and it must be powered on _when your device boots up_. The enhancement is to update the help text for the ALSA backend to denote HDMI devices using the `hdmi:` prefix rather than `hw:`. Now, for example, on a Raspberry Pi 4, the output is: ``` Settings and options for the audio backend "alsa": -d output-device set the output device, default is "default". -c mixer-control set the mixer control name, default is to use no mixer. -m mixer-device set the mixer device, default is the output device. -i mixer-index set the mixer index, default is 0. hardware output devices: "hdmi:vc4hdmi0" "hdmi:vc4hdmi1" ``` Previously it was: ``` Settings and options for the audio backend "alsa": -d output-device set the output device, default is "default". -c mixer-control set the mixer control name, default is to use no mixer. -m mixer-device set the mixer device, default is the output device. -i mixer-index set the mixer index, default is 0. hardware output devices: "hw:vc4hdmi0" "hw:vc4hdmi1" ``` ...which is technically correct but unfortunately not very useful. Get more information about the hardware output devices using [sps-alsa-explore](https://github.com/mikebrady/sps-alsa-explore) (also available as a Docker image). Version 4.3.4-dev-1-gc945f3a9 == This is effectively release version 4.3.3 -- the starting point for 4.3.4. Version 4.3.3-dev-81-ge0b13829 == **Bug Fix** * Undo the changes made in Version 4.3.3-dev-46. Unfortunately, the changes in [PR 1831](https://github.com/mikebrady/shairport-sync/pull/1831) make the Classic Airplay build of Shairport Sync invisible to iOS 17.5 and iPadOS 17.5. Thanks to [poker335](https://github.com/poker335) for identifying the issue and suggesting the fix. Version 4.3.3-dev-79-gf8e8550e == **Enhancements** * A number of minor documentation updates. Thanks to [Ambrose Li](https://github.com/acli) for their [PR](https://github.com/mikebrady/shairport-sync/pull/1851). Version 4.3.3-dev-73-g8d678c43 == **Enhancement** * Add support for the `mdebtls3` library. (Note: `mdebtls3` is optional for Classic Airplay builds; it is not used in AirPlay 2 builds). Many thanks to [orangepizza](https://github.com/orangepizza) for the [PR](https://github.com/mikebrady/shairport-sync/pull/1846). Version 4.3.3-dev-66-gb054c004 == **Enhancement** * Simplify the macOS build check. * Add some extra `CFLAG` settings to `configure.ac` for `libconfig`, `libpopt`, `openssl` and `libcrypto` to enable compilation on macOS without extra flag settings. Version 4.3.3-dev-61-gcc963bf0 == **Enhancement** * Use `macos-13` instead of `macos-latest` as the `github` runner for the Mac-compatible build check. Version 4.3.3-dev-58-g85f8ea12 == **Enhancement** * Use `PKG_CHECK_MODULES`, if it's available, to find the `ao` lib. Version 4.3.3-dev-53-gc0f5112b === **Bug Fix** * Remove some almost-never-used and therefore untested code, and remove a potentially misleading comment from the ALSA backend. Version 4.3.3-dev-49-gb5ea2b10 === **MQTT Documentation Updates** * Thanks to [Craig Lockwood](https://github.com/1ockwood) for [improvements](https://github.com/mikebrady/shairport-sync/pull/1838) to the [MQTT](MQTT.md) document. The `binary_sensor` example has been updated and the rest of the document has been edited for clarity, length and consistency. Version 4.3.3-dev-46-g6eba4fd8 === **Enhancement** * This enhancement modifies the AirPlay attributes advertised by Shairport Sync to allow AirPlay clients to see only the player of the appropriate protocol -- Classic Airplay ("AirPlay 1") or AirPlay 2. For example, if you run two instances of Shairport Sync, one built for Classic Airplay and the other for AirPlay 2, MacOS and iOS will recognize only the AirPlay 2 instance. Without the enhancement, MacOS and iOS will detect both Classic AirPlay and AirPlay 2 devices at the same time. (TuneBlade recognised only the Classic Airplay device, since it is not compatible with AirPlay 2.) Thanks to [Oleh Kuzhylnyi](https://github.com/kuzhylol) for the [PR](https://github.com/mikebrady/shairport-sync/pull/1831). Version 4.3.3-dev-43-g5922f9d1 === **Enhancement** * If a network interface is specified in the configuration file, limit the addresses used for PTP to that network interface only. Thanks to [Ryan Mounce](https://github.com/rmounce) for the [PR](https://github.com/mikebrady/shairport-sync/pull/1813). Version 4.3.3-dev-41-g0f07107c === **Enhancment** * Look for `DACP-ID` and `Active-Remote` in the `GET /info` request, where it sometimes appears in an AirPlay 2 session originating from an Intel Mac. Version 4.3.3-dev-40-g98627932 === **Enhancement** * Add a configuration option `--without-create-user-group` to optionally disable the creation of the `shairport-sync` user and group during a `make install`. This makes packaging easier for some systems, e.g. Yocto. Thanks to [hvilleneuve29](https://github.com/hvilleneuve29) for the [PR](https://github.com/mikebrady/shairport-sync/pull/1820). Version 4.3.3-dev-38-gab59f201 === **Docker Compose Enhancement** * Set `S6_KEEP_ENV = 1` to enable the passing of environment variables from the docker compose file into the image. Thanks to [HNKNTA](https://github.com/HNKNTA) for the [PR](https://github.com/mikebrady/shairport-sync/pull/1812). Version 4.3.3-dev-35-gd6ad6da1 === **Documentation Update** * The introduction paragraph now more clearly mentions the hard facts/requirements with "as of v4.1 and newer" and the supported devices are displayed in bullet list format for better readabilty. Thanks to [porg](https://github.com/porg) for the [PR](https://github.com/mikebrady/shairport-sync/pull/1818). Version 4.3.3-dev-32-gcf10ff9d === **Enhancement** * Implements the idea in [Issue 1808](https://github.com/mikebrady/shairport-sync/issues/1808) to make Fedora package-building easier. Thanks to [Bill Peck](https://github.com/p3ck) for the suggestion and continued support for Fedora. Version 4.3.3-dev-30-g4aee4ec8 === **Enhancements** * Start using the `pledge(2)` facilities in OpenBSD. In OpenBSD, limit the set of system calls Shairport Sync is allowed to make, most importantly, permit `fork(2)`/`execve(2)` if and only if user defined commands are run. [PR 1803](https://github.com/mikebrady/shairport-sync/pull/1803). **Bug Fixes** * Do not print the password in debug logs. [PR 1811](https://github.com/mikebrady/shairport-sync/pull/1811). * If a string argument is a NULL in some debug messages, output the string `(null)`. [PR 1810](https://github.com/mikebrady/shairport-sync/pull/1810). Thanks again to [Klemens Nanni](https://github.com/klemensn) for these PRs. Version 4.3.3-dev-21-g926cd56e === **Enhancements** * Updates to documentation regarding OpenBSD -- [PR 1797](https://github.com/mikebrady/shairport-sync/pull/1797). **Bug Fixes** * Fix an OpenBSD compilation warning -- [PR 1797](https://github.com/mikebrady/shairport-sync/pull/1797). * Terminate Shairport Sync if the configuration file exists but can not be opened -- [PR 1798](https://github.com/mikebrady/shairport-sync/pull/1798). Thanks to [Klemens Nanni](https://github.com/klemensn) for these PRs. Version 4.3.3-dev-14-gf37d1b8e === ***Pesky Changes You Can't Ignore*** * The `man` entry for Shairport Sync has moved from Section 7 ("Miscellaneous information") to Section 1 ("General commands (tools and utilities)"). For this reason, you should delete the file `/usr/local/share/man/man7/shairport-sync.7` if it exists. FYI, the `man` entry will now be placed at `/usr/local/share/man/man1/shairport-sync.1` at the `make install` step. Thanks to [Klemens Nanni](https://github.com/klemensn) for noticing this and for providing [PR 1795](https://github.com/mikebrady/shairport-sync/pull/1795) to deal with it. **Bug Fixes** * A number of OpenBSD-specific issues have been discovered and fixed by [Klemens Nanni](https://github.com/klemensn). Thanks to them for [PR 1794](https://github.com/mikebrady/shairport-sync/pull/1794) and [PR 1793](https://github.com/mikebrady/shairport-sync/pull/1793). **Enhancement** * Add a separate `install-config-files` Makefile target to selectively enable or disable the installation of configuration files at `make install`. Thanks to [Zane van Iperen](https://github.com/vs49688) for [PR 1782](https://github.com/mikebrady/shairport-sync/pull/1782). Version 4.3.3-dev-4-g7e741465 === * A slight change to [CAR INSTALL](https://github.com/mikebrady/shairport-sync/blob/development/CAR%20INSTALL.md), to add a two-second delay when accessing the WiFi device for the first time. It may be necessary in some cases, e.g. the Pi 3B. **Bug Fix** * Use `pthread_rwlock_wrlock` instead of the incorrect use of `pthread_rdlock_wrlock` when tearing down a connection. (This didn't seem to cause any problems, but it was definitely a bug, now fixed.) Version 4.3.3-dev-1-g9ab85989 === * Forgot to push tag 4.3.3-dev, so "back" to 4.3.3-dev-1. Apologies for the confusion. The commit hash is good. * Further updates to [CAR INSTALL](https://github.com/mikebrady/shairport-sync/blob/development/CAR%20INSTALL.md), hopefully to make updates a bit simpler. Version 4.3.3-dev-7-ga7603893 === * Remove the a few compilation warnings during a Docker build -- the warnings were that some variables possibly being used uninitialised. Version 4.3.3-dev-3-g2a5c49d3 === * Update [CAR INSTALL](https://github.com/mikebrady/shairport-sync/blob/development/CAR%20INSTALL.md) for Bookworm, which uses `NetworkManager` and does not use `dhcpcd`. * Changes to the car installation setup may result in more stable WiFi operation. Version 4.3.2-dev-58-gb70dd463 === This became Release 4.3.2, approximately. **Investigation -- continued** * Return `501` ("Not Implemented") instead of `200` ("OK") in response to a `POST` message with the argument `/feedback` on a Classic AirPlay connection. Version 4.3.2-dev-56-g4cd3c1da === **Investigation** * Return `200` -- "OK" in response to a `POST` message with the argument `/feedback` on a Classic AirPlay connection. Continue to return `500` -- "Internal Server Error" for all other `POST` messages. This is part of an investigation into [Issue #1745](https://github.com/mikebrady/shairport-sync/issues/1745). Version 4.3.2-dev-51-g98679bbb === **Enhancement** * Add a new `pw` (PipeWire) backend setting -- `sink_target`. Leave the setting commented out to use the sink target already selected by the PipeWire system. **Bug Fixes** * Fix a bug in picking up the PipeWire `node_name` -- it was being sought in the `pa` stanza instead of the `pw` stanza of the configuration file. * Fix memory management bugs in the PipeWire backend -- settings strings were being deallocated twice on exit. * Fix memory management bugs in the PulseAudio backend -- settings strings were being deallocated twice on exit. Version 4.3.2-dev-47-g288e5eb6 === * In the PipeWire backend, change the default for `node_name` from "shairport-sync" to "Shairport Sync". Version 4.3.2-dev-45-g3763b321 === **Enhancement** * Add two `pw` (PipeWire) backend settings -- `application_name` (default: "Shairport Sync") and `node_name` (default: "shairport-sync"). The `application_name` is used when referring to Shairport Sync in the GUI and the `node_name` is used in, for example, output from `pw-link`. Thanks to [alexsarmiento](https://github.com/alexsarmiento) for the [suggestion](https://github.com/mikebrady/shairport-sync/issues/1742). **Bug Fixes** * Minor bug fixes to the PulseAudio backend. Version 4.3.2-dev-41-gdc197ae7 === **Bug Fix** * Fix underrun ("xrun") errors in the new PipeWire backend. These errors seem harmless, and the only place they were noticed was in the listing from `pw-top` on recent versions of PipeWire (e.g. PipeWire 0.3.80 in Fedora 38). Anyway, they are gone now. Version 4.3.2-dev-38-gbde2bcc8 === **Enhancement** * The PipeWire backend (`pw`) has been completely rewritten and now provides full sychronisation. **Bug Fixes** * Stability improvements to the PulseAudio (`pa`) backend. some bugs with the use of mutexes and the treatment of a full FIFO buffer were identified and fixed. Version 4.3.2-dev-30-gc36d322a === **Bug Fix** * If the volume control was at its absolute minimum (-144.0), audio would be muted even if `ignore_volume_control` was enabled in the configuration file. The fix was to mute only if `ignore_volume_control` is not enabled. Thanks to [mc510](https://github.com/mc510) for reporting the [issue](https://github.com/mikebrady/shairport-sync/issues/1737). Version 4.3.2-dev-27-g04e3f891 === **Bug Fixes** * Fix bugs in the handling of an Avahi client disconnection event. Due to its rarity, Shairport Sync was not handling Avahi client disconnection events correctly. Specificially, it was not cleaning up before deleting the disconnected Avahi client and attempting to create a new one. This has now been fixed. It is worth noting that these disconnection events are very rare and often indicate that there is something wrong with the computer as a whole. Version 4.3.2-dev-25-gc0467468 === * Make the latency in the PipeWire backend 200,000 instead of 20,000. Should help with DAC underrun. Version 4.3.2-dev-23-gc4975d5c === * Fixed some debug messages that were missing arguments. In principle, these could cause crashes just when you need them to work properly, sigh. As far as is known, however, they did not cause problems. Many thanks to [Nathan Gray](https://github.com/n8gray) for the [report](https://github.com/mikebrady/shairport-sync/issues/1734). Version 4.3.2-dev-21-ga3f12d68 === * When a connection terminates abruptly while is it the `principal_conn`, make sure it sets the `principal_conn` to `NULL` and cleans up the Bonjour flags, if appropriate. Version 4.3.2-dev-19-g91c0803d === * Lock access to the `principal_conn` (i.e. the connection that may be playing) using a read-write lock rather than a mutex. Use read locking when checking that a connection is currently the principal connection before altering any system-wide values such as mDNS flags. This eliminates a number of data race conditions. * As soon as it has been decided that the current playing session (as specified in the `principal conn`) is to be preempted, demote it from `principal_conn` status before stopping play, closing the connection, etc. * Set the status flags correctly for a Classic Airplay session on an AirPlay 2 system. Version 4.3.2-dev-4-g20a45def === * Bump version information. Version 4.3.1-dev-3-g2fb81ca9 === **Exploration** * Add some slightly noisy diagnostics to try to locate a fault. Version 4.3.1d-2-ge6a2a429 === **Bug Fix** * Fix a recently-introduced bug that prevented Shairport Sync being added to Home. Version 4.2.1d0-67-gef14cace === **IMPORTANT Bug Fixes** * A recent security audit has identified a number of issues with NQPTP that have been fixed in the latest update to NQPTP and in this corresponding update to Shairport Sync. * Please update to the latest `development` branch version of NQPTP before updating Shairport Sync. (Shairport Sync now requires the Shared Memory Interface version 10, i.e. `smi10`.) * When updating NQPTP on Linux, ensure you remove the old service file as directed in the README. * Having completed both updates and installations, remember to restart NQPTP first and then restart Shairport Sync. Version 4.2.1d0-62-g556419e8 ==== **Bug Fix** * Fix a bug introducted in the last `development` push, 4.2.1d0-60-g702e8285, whereby volume control changes would be ignored after a pause in playing of longer than about 8 minutes. Version 4.2.1d0-60-g702e8285 ==== **Bug Fix** * Fixes a bug that causes the Docker image to crash occasionally when OwnTone attempts to interrupt an existing iOS session. Thanks to [aaronk6](https://github.com/aaronk6) for the report. Version 4.2.1d0-56-ga9000de6 ==== **Bug Fixes** * The `active_end` enhancement in 4.2.1d0-23 didn't work and has been rewritten here. * A crashing bug in NQPTP has been fixed in the `development` version -- please update. (The updated version will be incorporated automatically in the `development` version of the Docker image.) Version 4.2.1d0-51-gbc2fda52 ==== **Enhancement** * Modify the new `dasl_tapered` volume control profile to work better with mixers with a restricted attenuation range. This volume control profile has the property that halving the AirPlay volume reduces the output level by 10 dB, which corresponds to roughly halving the perceived volume. For example, if the AirPlay volume goes from 0.0 to -15.0, the output level will decrease by 10 dB. Halving the AirPlay volume again, from -15 to -22.5, will decrease output by another 10 dB. Halving the AirPlay volume once more, from -22.5 to -25.25, decreases the output by a further 10 dB, meaning that at AirPlay volume -25.25, the volume is decreased by 30 dB relative to the level at AirPlay volume 0.0. Now, if the attenuation range of the mixer is only 30 dB, then changing the AirPlay volume in the range from -25.25 down to -30.0 would have no further effect on the output level, since it's already at the lowest possible level permitted by the attenuator. This "dead zone" is about one sixth of the full range of the AirPlay volume control. To work around this, the "flat" output level is used if it gives a higher output dB value than the calculation described above. It means that changing the AirPlay volume, even at low levels, will always change the output level, while the original advantage of the `dasl_tapered` profile is retained at higher AirPlay volumes. In practice, if the device's attenuation range is over about 50 dB, the flat output level will hardly be needed at all. Version 4.2.1d0-46-g57061dfb ==== **Enhancement** * Add a new volume control profile called `dasl-tapered`. Shairport Sync already has two volume control profiles -- the `standard` profile -- which is the default -- and a `flat` profile. A feature of the `dasl-tapered` profile is that halving the volume control setting (e.g. moving the volume slider from full to half, or from half to a quarter) reduces the output level by 10dB, which roughly corresponds with a perceived halving of the audio volume level. Many thanks to David Leibovic, aka [dasl-](https://github.com/dasl-), for this. To activate the `dasl-tapered` profile, set the `volume_control_profile` to `"dasl_tapered"` in the configuration file and restart Shairport Sync. There may be some more minor adjustments to this profile for devices with a restricted attenuation range... Version 4.2.1d0-40-g9ef4e351 ==== **Bug Fix** * Fix a cross-compliation error caused by not looking for the correct version of the `ar` tool. The fix was to substitute the correct version during the `autoreconf` phase. Thanks to [sternenseemann](https://github.com/sternenseemann) for raising the [issue](https://github.com/mikebrady/shairport-sync/issues/1705) and the [PR](https://github.com/mikebrady/shairport-sync/pull/1706) containing the fix. Version 4.2.1d0-37-g9a8f1ba1 ==== **Bug Fix** * Update the mDNS strings for the Classic AirPlay feature of AP2, so that it does not appear to provide MFi authentication. Addresses [this discussion](https://github.com/mikebrady/shairport-sync/discussions/1691). Version 4.2.1d0-35-g6acd73da ==== **Update** * Confirm the bug fix made in [4.2.1d0-26](#version-421d0-26-g716aa051) to Classic Airplay Remote Control: always use a revision number of 1 when looking for status updates on the DACP remote control port. Version 4.2.1d0-33-gd4e00380 ==== **Bug Fix** * If an `active_end` signal is generated when the system is shutdown gracefully, ensure it is sent before shutting down the metadata transmission system, duh. Version 4.2.1d0-31-gb0f2fb9a ==== **Bug Fix** * Fix a bug that could ocassionally cause a crash if `allow_session_interruption` is set to `"yes"` and a Classic AirPlay session is interrupted by a play session request from another device. Version 4.2.1d0-28-g0ca5fd3c ==== **Tiny Bug Fix** * Fix a `statistics` bug (the minimum buffer size was incorrectly logged) and also tidy up the statistics logging interval logic for resetting min and max counters. Version 4.2.1d0-26-g716aa051 ==== **Bug Fix** * Classic Airplay Remote Control. Always use a revision number of 1 when looking for status updates on the DACP remote control port. This is ia quick-and-dirty change to try out a (good) suggestion in [Issue #1658](https://github.com/mikebrady/shairport-sync/issues/1658) -- if it works change will be made permanent. Thanks to [ejurgensen](https://github.com/ejurgensen), as ever, for the report and the suggested fix. Version 4.2.1d0-23-g46a215b6 ==== **Enhancement** * On graceful shutdown, an `active_end` signal should now be generated if the system was in the active state. Addresses issue [#1647](https://github.com/mikebrady/shairport-sync/issues/1647). Thanks to [Tucker Kern](https://github.com/mill1000) for raising the issue. Version 4.2.1d0-21-g2f52e699 ==== **Bug Fix** * Add an important missing format string argument to a call in the Jack Audio backend. Many thanks to [michieldwitte](https://github.com/michieldwitte) for their [PR](https://github.com/mikebrady/shairport-sync/pull/1693). Version 4.2.1d0-17-g17414f57 ==== **Enhancements** * Stop using a deprecated FFmpeg data structure reference. * Stop using deprecated OpenSSL calls. Thanks to [yubiuser](https://github.com/yubiuser) for their [PR](https://github.com/mikebrady/shairport-sync/pull/1684) -- which did some of the updating -- and for their guidance. * Run workflow-based tests on PRs automatically. Thanks to [yubiuser](https://github.com/yubiuser) for their [PR](https://github.com/mikebrady/shairport-sync/pull/1687). Version 4.2.1d0-5-gc3d99f96 ==== **Enhancement** * Increase the level of detail in the debug log at verbosity level 2 (i.e. `-vv`). Version 4.1-dev-922-gffeeacc4 ==== This is (approximately) Version 4.2 release. **Enhancement** * When built for AirPlay 2, include the Shared Memory Interface (SMI) version number in the version string, in the form: `smi*` where `*` is the version number, e.g. `smi9`. This must be same as the SMI version number of NQPTP, which can be listed by entering `$ nqptp -V`. Version 4.1-dev-919-gbd068fb6 ==== **Enhancements** * Allow compilation with `libplist` 2.3.0. Thanks to [Markus Reiter](https://github.com/reitermarkus) for the update. * Updates to GitHub Action Workflows -- many thanks to [yubiuser](https://github.com/yubiuser) for this detailed work. * Include PulseAudio support in the Shairport Sync builds within the Docker images. Thanks to [Ferdynand Naczynski](https://github.com/nipsufn) and thanks also to [Noel Hibbard](https://github.com/noelhibbard) for championing this idea for a long time. * Documentation Updates. Version 4.1-dev-896-g03961830 ==== **Bug Fix** * In some situations, the Device ID generated by Shairport Sync was all zeros, and so was invalid, causing connectivity problems. The cause of the problem was that `get_device_id` was not interpreting `getaddrinfo` information correctly. Thanks to [Carl Johnson](https://github.com/ridgelift) for [reporting](https://github.com/mikebrady/shairport-sync/issues/1657) the issue, finding the (rather obscure) cause of the problem and for providing [code](https://github.com/mikebrady/shairport-sync/issues/1657#issuecomment-1493423175) to fix it. Version 4.1-dev-886-ge74300d7 ==== **Updates and Enhancements** * Merge [Pull Request #1635](https://github.com/mikebrady/shairport-sync/pull/1635) and [Pull Request #1636](https://github.com/mikebrady/shairport-sync/pull/1636) . The PRs update the MQTT documentation to correspond to updates in [Home Assistant](https://www.home-assistant.io/blog/2022/06/01/release-20226/#breaking-changes). Thanks to [hunhejj](https://github.com/hunhejj) for these. * Merge [Pull Request #1624](https://github.com/mikebrady/shairport-sync/pull/1624). The PR updates the Docker images to use Alpine 3.17 and ensure services such as Avahi and D-Bus start in the correct order. Thanks to [yubiuser](https://github.com/yubiuser) for their work on this. Version 4.1-dev-876-g29ca3225 ==== **Bug Fix** * Fix a bug reported in Issue [#1633](https://github.com/mikebrady/shairport-sync/issues/1633). The bug was that when a Realtime Audio stream (e.g. playing from Spotify on iOS or using Shairport Sync as the Sound Output on a Mac) was played, it was fine, but when a second stream was started, it could not be heard. The problem was that the PTP clock was not being correctly revalidated for second and subsequent Realtime Audio streams. The fix was to ensure that the PTP clock is revalidated on second and subsequent plays on the same connection. Thanks again to [David Leibovic](https://github.com/dasl-) for finding the problem. Version 4.1-dev-874-g551734b3 ==== **Bug Fix** * Use TCP keepalive a little more generally -- treat it the same as a client closing the link rather than just an error. Version 4.1-dev-872-g65c6975e ==== **Bug Fix** * Remove three potential race conditions between Shairport Sync opening a TCP connection and the client checking that the connections are open. The problem was that the connections were being opened in threads that were created just before the client was given the connection information. If the threads were delayed (e.g. on a slow or busy processor), the client could use the connection information to check the connections, but find that they were not (yet) open. This could cause the client to terminate the session immediately with a `TEARDOWN`. The fix was to open the connections before creating those threads and before sending the connection information back to the client. In this way, the connections are guaranteed to be open before the client has the information it needs to try to open them, even if the threads ared delayed in starting. This bug would manifest itself by allowing play to proceed but not play anything. Version 4.1-dev-870-gc924387a ==== **Bug Fix** * When built for AirPlay 2, ensure the hexadecimal string that prefixes the AirPlay 1 Service Name in the Bonjour text strings matches the AirPlay 2 Device ID. For example, if the Service Name is `Kitchen` and the AirPlay 2 Device ID is `b8:2f:eb:d7:85:df`, the AirPlay 1 Service Name should be `B82FEBD785DF@Kitchen`. (When built for AirPlay 1, the hexadecimal prefix is simply a hash of the Service Name.) Thanks to [Casper](https://github.com/casperghst42) for raising the [issue](https://github.com/owntone/owntone-server/issues/1578) and to [ejurgensen](https://github.com/ejurgensen) for identifying the cause of the problem. Version 4.1-dev-862-g6eb70eee ==== ***Pesky Changes You Can't Ignore*** * **Important**. Please update and re-start NQPTP. The Shared Memory Interface protocol that Shairport Sync and NQPTP use to communicate with one another has been updated to version 9 to reflect changes in NQPTP's operation. **Enhancements** * A new "high volume check" attempts to prevent the unpleasant surprise of a new session playing at the same very high volume as the previous session if that previous session was some time, e.g. some hours, ago. How it works is that if a timeout period has elapsed since the last play session and the last play session was very loud, a lower volume will be suggested for new play sessions. Most iOS and iPadOS apps accept the suggestion as the new volume. However, Macs, HomePods and AppleTVs use the suggested volume only when connecting the first time. The timeout, loudness threshold and suggested volume are all settable in the configuration file. Please refer to the sample configuration file for more details. The feature is disabled by default. * The PulseAudio backend has been reworked to simplify the code and to remove a number of issues. Hopefully nothing has been broken. Version 4.1-dev-846-gb5bb2fef ==== * Improvements to the detection of a missing or non-existent output device. Look for `ENODEV` and `ENOENT` errors when opening or playing to an output device. Version 4.1-dev-843-gae5910e2 ==== **Bug Fix** * Stop endless error messages from the `stdout` backend. **Enhancements** * Call the unfixable error handler if the output device can't be opened or generates errors while being used. If no program is attached to the `run_this_if_an_unfixable_error_is_detected` hook in the `sessioncontrol` section of the configuration file, the program will exit instead. * Shorten the amount of time to wait after a client disappears before terminating a play session. Version 4.1-dev-824-g8e5393ec ==== **Enhancements** * Add `man` page and `man` utilities to the Docker images. * Enable the MQTT client to parse the `phbt` and `phb0` Playing HeartBeaT metadata tokens. Version 4.1-dev-818-gf15c3255 ==== **Enhancement** * Add a configuration check for the `xxd` program when building for AirPlay 2. Cleans up an annoying problem mentioned in Issue [#1341](https://github.com/mikebrady/shairport-sync/issues/1341). Thanks to [David Girón](https://github.com/duhow) for the reminder. Version 4.1-dev-815-gcb097034 ==== **Enhancement** * Use [TCP `keepalive`](https://en.wikipedia.org/wiki/Keepalive) to close down a play session when the client disappears, e.g. when the player goes out of range of WiFi. A play session is now terminated after a break in connection lasting more than approximately one minute. Addresses the problem reported in Issue [#1584](https://github.com/mikebrady/shairport-sync/issues/1584). Thanks to [JanLp](https://github.com/JanLp) for the report. Version 4.1-dev-809-g8a69f5ea ==== **Enhancements** * Add another item of metadata with the code `phb0` and the DBus property name `FirstFramePosition`. This is similar to the `phbt` and `FramePosition` metadata, except that it is updated for the first frame of a play session. It can be ignored, as a `phbt` token is also sent when the first frame is output. Version 4.1-dev-805-g50738c36 ==== **Enhancements** * Very provisional additions to the metadata -- add some functionality for Shairport Sync to send information about what frame of audio is being played at a particular time. It can be set up to periodically generate a `phbt` (a Playing HeartBeaT) item comprising the RTP frame number of the audio being played at a particular instant -- the computer's system time in nanoseconds. The two numbers are presented as a string, e.g. `595422363/4697675115573193`. Set the interval in seconds with the new `metadata` setting `progress_interval` – 0.0 means no heartbeat is generated. * Equivalent additions have been made to the native `DBus` interface: the `phbt` information appears as a `FramePosition` property and the update interval can be set using the `SetFramePositionUpdateInterval(Seconds)` method. Please note that this might all disappear or change radically. Version 4.1-dev-798-g803eddbd ==== **Docker** * Within the Docker container, launch Shairport Sync as `root` user rather than as the user `shairport-sync`. This is experimental, to investigate possible device access issues. Version 4.1-dev-795-g7f279efa ==== **Bug Fix** * Fix a bug if the ALSA device name isn't available. (Happens in Fedora 37 on Arm in VMWare Fusion on an Apple Silicon Mac.) Version 4.1-dev-790-g03d291f4 ==== **Bug Fix -- Second Attempt!** * Second attempt to fix a bug caused in the transition to version 4.1, where a change was made to how the 12-hex-digit prefix to the classic AirPlay service name was derived. Previously it was a hash of the service name, and in 4.1 this was changed to deriving it from one of the device's MAC addresses. This seems to cause problems with multiple instances of classic Shairport Sync running on the same system, as they would all get the same prefix. The fix was to generate the prefix from a hash of the service name and the device's MAC address, which should be unique for every instance. Addresses issue [#1581](https://github.com/mikebrady/shairport-sync/issues/1581). Thanks to [Christoph Bloemer (?)](https://github.com/chbloemer) for the report. The first attempt failed because not all the changes needed were done. Version 4.1-dev-789-g75aa150e ==== **Oops** * Reverted the fix below. Something still to be done... Version 4.1-dev-786-gfc117e73 ==== **Bug Fix** * Fix a bug caused in the transition to version 4.1, where a change was made to how the 12-hex-digit prefix to the classic AirPlay service name was derived. Previously it was a hash of the service name, and in 4.1 this was changed to deriving it from one of the device's MAC addresses. This seems to cause problems with multiple instances of classic Shairport Sync running on the same system, as they would all get the same prefix. The fix was to generate the prefix from a hash of the service name and the device's MAC address, which should be unique for every instance. Addresses issue [#1581](https://github.com/mikebrady/shairport-sync/issues/1581). Thanks to [Christoph Bloemer (?)](https://github.com/chbloemer) for the report. Version 4.1-dev-784-g60e913dd ==== **Bug Fix** * In the PulseAudio backend, Whenever a play or latency request is made, reopen the stream if it is closed. Addresses issue [#1580](https://github.com/mikebrady/shairport-sync/issues/1580). Thanks, as ever, to [Noel Hibbard](https://github.com/noelhibbard) for the report. Version 4.1-dev-781-g9af924dd ==== **Metadata Enhancements** The following new metadata items have been added to the metadata pipe, MQTT and the native D-Bus interface. 1. `core`/`asdk`. This is [glossed](https://github.com/tchapi/shairport-sync-ui/blob/master/DMAP_DAAP_Codes.md) as `daap.songdatakind`. It seems to indicate whether the audio is timed or not, e.g. a track or album has the value `0`, and a continuous untimed stream such as a radio station is `1`, so it is potentially very useful for remote control displays, as it seems to indicate whether a progress bar, etc. could be used or not. The value is included, if available, in the native DBus interface in the metadata bundle with the tag `sps:songdatakind`. 2. `ssnc`/`styp`. This is the type of data stream currently being received by Shairport Sync. Values are `Classic`, `Buffered` or `Realtime`. Included in the native D-Bus interface as `StreamType` in the `org.gnome.ShairportSync.RemoteControl` interface. 3. `ssnc`/`ofmt`. This is the output format of audio going to the output device. Values are `S32`, `S24` and so on. S=signed, U=unsigned, 32/24/16/8 is the bit depth, BE/LE is Big-Endian or Little-Endian. Note that `S24` means signed 24 bits in a 32-bit space; `S24_3LE` means Signed 24 bits in a 3-byte little-endian form, etc. Each frame is always a stereo pair. Included in the native D-Bus interface as `OutputFormat` in the `org.gnome.ShairportSync` interface. 4. `ssnc`/`ofps`. This is the output rate in frames per second, usually `44100`. Included in the native D-Bus interface as `OutputRate` in the `org.gnome.ShairportSync` interface. Version 4.1-dev-776-g27754a62 ==== **Docker Enhancements** * Place the configuration file and the sample configuration file in the Docker image at `/etc/shairport-sync.conf` and `/etc/shairport-sync.conf.sample`. Thanks to [inDomus](https://github.com/KC-inDomus) and [tamasfodor1988](https://github.com/tamasfodor1988) for the report, Issue [#1575](https://github.com/mikebrady/shairport-sync/issues/1575). Version 4.1-dev-774-g3e4b67e9 ==== **Metadata Enhancements** * Add the service name, e.g. `"Den Speakers"` as metadata. This has the code `"svna"` in the metadata pipe and the name `"service_name"` in the MQTT interface. * Add two properties to the D-Bus metadata interface: 1. `ServiceName` -- see above. 2. `ClientName` -- the name of the current client, e.g. `"Joes's iPad"`. Version 4.1-dev-772-g085bf128 ==== **Bug Fix** * Fix a long-standing bug whereby the socket used for the RTSP connection wasn't closed when the connection was closed by the client, potentially exhausting the sockets available. Many thanks to [Lars Strojny](https://github.com/lstrojny) for the report: [#1567](https://github.com/mikebrady/shairport-sync/issues/1567). **Enhancements** * Small documentation updates. * More use of GitHub actions to check standard builds. Version 4.1-dev-756-g0a8b1231 ==== **Docker Updates** * Move to using `latest` tags for the latest release and `rolling` for intermediate (non-release) updates on the master branch. Pushes to the `development` branch will result in Docker images with the `development` tag. **Enhancement** * Tidy up `--display_config` output to skip empty configuration file stanzas and to note when there are no active settings whatever in the file. Version 4.1-dev-747-ga4da36b4 ==== **Docker Updates** * Extra command-line arguments passed when the Docker image is launched are passed to the `shairport-sync` instance as described on Docker Hub. * The `shairport-sync` instance runs as `user` and `group` `shairport-sync`, which has reduced privileges. * The "classic" docker image now uses the `s6-overlay` to manage processes, the same way as the standard (AirPlay 2) docker image. It does makes the image bigger, so takes a little longer to download. Version 4.1-dev-745-gbb4e9078 ==== **Bug Fix** * Fix a bug that caused new metadata not to be passed on immediately to the D-Bus, MPRIS and MQTT interfaces. Thanks to [phelbas](https://github.com/phelbas) for finding the bug and the fix in Issue [#1560](https://github.com/mikebrady/shairport-sync/issues/1560). **Enhancement** * Add two new metadata tokens for AirPlay 2 buffered audio streams only, which can be paused for a period of about five minutes before the session is ended. They are for Pause (`paus`) and Resume (`pres`). * Clean up the generation of `MPRIS` and D-Bus `PlayerStatus` values. Until now, Shairport Sync used extra information to try to determine the state a session was in -- `Playing`, `Paused` or `Stopped`. The extra information used what (1) when the first frame was played, (2) when a flush was requested and when (3) frame play was resumed. Unfortunately, these are noisy signals and are unreliable for this purpose, so they are now no longer used. The situation now is that `PlayerStatus` becomes `Playing` when a play session begins and becomes `Stopped` when a play session ends, unless it is an AirPlay 2 buffered audio session. In the case of a AirPlay 2 buffered audio session, a play session will be `Paused` when play stops (but the play session is not ended). If play resumes within a period determined by the client (about five minutes), `PlayerStatus` will return to `Playing`. Otherwise, the play session is ended by the client and `PlayerStatus` will transition to `Stopped`. Version 4.1-dev-738-g9f7584eb ==== **Enhancement** * It seems that this missing session key issue discovered and discussed below is a transient problem: some client apps omit the session key occasionally but include it the rest of the time. So, to make the problem a bit less intrusive for users, the way a missing session key is dealt with has been changed. The new arrangement is that instead of dropping the AirPlay connection completely as noted below, the audio is simply skipped. From the user's perspective, the music simply won't play, but the AirPlay connection won't be dropped. When they start it again, the session key will hopefully be present and the audio will play. Let's hope that this will be less disruptive for users and that this issue goes away as clients are updated. Thanks again to [Mike](https://github.com/xska2) for his help with this in [#1551](https://github.com/mikebrady/shairport-sync/issues/1551). Version 4.1-dev-735-g6a55774f ==== **Bug Fix** * Very occasionally, and for as-yet unknown reasons, an AirPlay 2 session may not include an important parameter called a "session key". This was causing Shairport Sync to crash. With this update, Shairport Sync will now simply drop the entire connection if a session doesn't include a "session key". Addresses the crashing issue reported in [#1551](https://github.com/mikebrady/shairport-sync/issues/1551). Big thanks to [Mike](https://github.com/xska2) for his huge assistance in tracking this down. Version 4.1-dev-730-g63e0dfda ==== **Minor Debugging Enhancements** * Improve debugging of a Shairport Sync daemon process created with `libdaemon`. * List the command line when Shairport Sync starts with a verbosity of 1 or more. Version 4.1-dev-726-g5e6e6344 ==== **Enhancement** * Enhance `--displayConfig` to log information about the OS as well as about Shairport Sync itself, and use Shairport Sync's standard logging -- it's not stuck on `STDERR` anymore. Version 4.1-dev-721-g93c1f1ae ==== **Pesky Things You Can't Ignore** If you are updating from a previous version, after you have pulled the update, please redo the `autoreconf -fi` and the `./configure...` steps (and the do a `make clean` for good measure) before `make`ing the executable -- there have been many changes to the build process. **Bug Fix** * Correction to `Makefile.am` to make it work both on FreeBSD and Linux both in the source directory and in a subsidiary build directory. Version 4.1-dev-717-g86539bc5 ==== **Pesky Things You Can't Ignore** If you are updating from a previous version, after you have pulled the update, please redo the `autoreconf -fi` and the `./configure...` steps (and the do a `make clean` for good measure) before `make`ing the executable -- there have been many changes to the build process. **Enhancements** * A new command-line-only option is included: `--displayConfig`. This prints configuration information to `STDERR` and should be useful when debugging issues. * Help text is reordered and updated. * The `man` page is updated. * The `man` contents are no longer automatically built when Shairport Sync is built. This is okay because the contents are normally static. The `man` folder has a new `Makefile`. * The `xmltoman` application is not now needed when building Shairport Sync. * When updating the `man` page, `xsltproc` is now used instead of `xmlmantohtml`. Version 4.1-dev-701-g65daef30 ==== **Bug Fix** * Fix a bug in the generation of version information from git tags. The fix is to use lightweight tags as well as annotated tags. GitHub marks releases with lightweight tags, so this should make version and release information correspond better. **Enhancement** * Add an new Advanced Topic -- [Adjusting Sync](ADVANCED%20TOPICS/AdjustingSync.md) explaining how to compensate for amplifier delays such as might be found on TVs or AVRs. Version 4.1-dev-694-g234c00ad ==== **Bug Fix** * Fixed a memory allocation (`malloc`) bug caused by allocating on byte too few for a character string -- yep, the trailing `NUL`. Special thanks to [ageorgios](https://github.com/ageorgios) for their help in locating and fixing the bug! Thanks also to [MTxx87](https://github.com/MTxx87) and [Mike](https://github.com/xska2) for reporting what seems to be the same bug. Version 4.1-dev-688-g7dcad083 ==== **Bug Fixes** * Fixed two memory leaks in Shairport Sync. * Reinstate the use of `libcrypt` again with the `pair_ap` library to avoid an apparent memory leak in `libcrypto`. * Quieten a noisy debug message in the `dummy` backend. Version 4.1-dev-604-gf96fa2f7 ==== **Bug Fix** * If the D-Bus interface was enabled, each change in volume control was calling the volume event hook twice. Fixed. Version 4.1-dev-601-g98744211 ==== **Bug Fix** * Recent versions of Shairport Sync have a "heartbeat" checker, to try to determine when the client has stopped running without warning -- typically when it has gone to sleep. Unfortunately, it interferes with some non-Apple clients, so it has been disabled in this update. Version 4.1-dev-599-g2bc62c7d ==== **Enhancements** * Added some GitHub Actions to test different combinations of builds -- hopefully the result will be fewer bugs. Thanks to [Charles Omer](https://github.com/charlesomer) for the inspiration to try these in the first place. **Bug Fixes** * Fixed a bug where the DAC was not closed after the active timeout when the `alsa` `disable_standby_mode` was set to `"auto"`. Thanks to [Tim Curtis](https://github.com/moodeaudio) for an exemplary [bug report](https://github.com/mikebrady/shairport-sync/issues/1546). * Fixed a couple of bugs (found with GitHub Actions) in the installers on both `systemd` and System V systems. Version 4.1-dev-551-g30aaabc4 ==== **Update** * Updated to the latest version of the [`pair_ap`](https://github.com/ejurgensen/pair_ap) library. Thanks again to [ejurgensen](https://github.com/ejurgensen/pair_ap/commits?author=ejurgensen) for this invaluable resource. **Enhancement** * Removed the requirement for the [`libgcrypt`](https://gnupg.org/software/libgcrypt/index.html) library. OpenSSL is mandatory for other parts of Shairport Sync when operating in the AirPlay 2 mode and is now used in place of `libgcrypt`. Version 4.1-dev-548-g7dc077e2 ==== * Removed the workaround for the apparent bug in AirPlay 2 Buffered Streams in iOS 16.0. A number of approaches were tried. The most aurally successful is left in the code but is disabled. Basically, it delays the timing of the frames following the 2,112 frame discontinuity by 2,112 frames. This eliminates the timing discontinuity but delays the AirPlay stream by 47.9 ms, and this can be heard in some situations. So it looks as if the bug -- if that's what it is -- can't easily be worked around. It has not been fixed by iOS 16.0.2, unfortunately. Version 4.1-dev-543-g24f06b81 ==== **Enhancements** * Add a workaround for an apparent bug in AirPlay 2 Buffered Streams in iOS 16.0. After playing exactly 22,528 frames of audio, iOS 16.0 sends 2,112 frames of audio with the same timestamps as the previous 2,112 frames. This makes the frames that follow 47.9 ms (2112/44100 seconds) late. The workaround is to drop these extra 2,112 frames. * If an AirPlay 2 Buffered Streams is being skipped or scrubbed, the audio that follows will generate an audible click due to an AAC decoding transient because preceding audio frames are missing. Shairport Sync now mutes the first 2,048 frames, down from 3,072 frames before. **Bug Fix** * Give the RTSP idle checker a longer timeout -- 10 seconds -- and confine its operation to AirPlay 2 Runtime Streams and classic AirPlay only. This is to stop an occasional RTSP idle timeout silencing an AirPlay 2 Buffered Audio session. Version 4.1-dev-532-g8dfebea2 ==== **Enhancements** * Improve the response of Shairport Sync when a Mac is woken up from sleep and continues playing e.g. a YouTube video. Shairport Sync should resume play in most circumstances. (BTW, the HomePod mini does not resume in these circumstances.) **Bug Fix** * Make the RTSP idle checker a bit more resilient -- wait for the full timeout even if interrupted by e.g. `SIGINT`. Also signal to NQPTP when to stop listening when a session goes idle or stops. Version 4.1-dev-526-gfd880056 ==== ***Pesky Changes You Can't Ignore*** * **Important**. Please update and re-enable NQPTP. The Shared Memory Interface protocol that Shairport Sync and NQPTP use to communicate with one another has been updated to reflect changes in NQPTP's operation. Apart from moving to the new SMI interface for NQPTP, this update consists of many small enhancements and bug fixes. (Yeah, and the build number really did go backwards...) Version 4.1-dev-535-gdafd1726 ==== **Bug Fix** * Fix yet another bug in the Makefile.am. Thanks to [Isioma Nnodum](https://github.com/mikebrady/shairport-sync/issues?q=is%3Apr+author%3Aicompuiz) for finding and [fixing](https://github.com/mikebrady/shairport-sync/pull/1536) it. Version 4.1-dev-520-g1092a8c1 ==== **Enhancements** * It is now possible to build Shairport Sync in a separate directory, thanks mainly to the work [#1493](https://github.com/mikebrady/shairport-sync/pull/1493) and [#1500](https://github.com/mikebrady/shairport-sync/pull/1500) of [Lukas Rusak](https://github.com/lrusak). A number of subsequent changes were necessary to make it work for FreeBSD. * Shairport Sync should build on piCore. Thanks to [jackaroo](https://github.com/94jackaroo) for [reporting](https://github.com/mikebrady/shairport-sync/pull/1528) and checking. Version 4.1-dev-516-ga617e607 ==== **Updates and Enhancements** * The Docker image has been enhanced. Thanks, as always, to [Charles Omer](https://github.com/charlesomer). More changes are on the way here. **Bug Fixes** * With Realtime Streams, if even one timing control packet was missing, Shairport Sync would work as if the sender had disappeared and cause a playback interruption. This has been modified so that it takes at least three missing control packets in a row to conclude that the sender was gone. Thanks to [Devid Leibovic](https://github.com/dasl-) for a [very thorough investigation](https://github.com/mikebrady/shairport-sync/issues/1515) of this issue. Version 4.1-dev-494-gd34db2a4 ==== * The [CAR INSTALL.md](https://github.com/mikebrady/shairport-sync/blob/development/CAR%20INSTALL.md) guide has been updated for AirPlay 2 and for Raspberry Pi OS (Bullseye). * A few noisy debug messages have been removed or quietened. Thanks to [David Leibovic](https://github.com/dasl-) for [the report](https://github.com/mikebrady/shairport-sync/issues/1513). Version 4.1-dev-468-gcb03d5c6 ==== **Updates and Enhancements** * The `development` branch now builds again on macOS with [brew](https://brew.sh). (Remember, though, that Shairport Sync [will not function in AirPlay 2 mode on a Mac](https://github.com/mikebrady/shairport-sync/blob/development/AIRPLAY2.md)). * The `libao` backend has been updated to address an issue with the system becoming unavailable. The biggest change was to close the driver as soon as playing stops, reopening it when playing restarts. * The `libao` drivers are now listed in the help text. If available, it is suggested that the `alsa` driver be used in preference to the `pulseaudio` driver. **Bug Fixes** * The classic AirPlay build now works properly again with `tinysvcmdns` and `dns_sd`. Version 4.1-dev-466-g05dfcdfd ==== **Enhancements** These are for advanced users. * Add a new `Protocol` property to the D-Bus interface. Values: `AirPlay` if built for AirPlay and `AirPlay 2` if build for AirPlay 2. * Add a new `Volume` property to the D-Bus interface. This enables you to get and set the volume _locally_. Use this carefully: it means that you can set the volume of the player without changing it at the source (e.g. iTunes / Music). The source will not be informed of the change, so the volume it sets and and the actual volume may become different. It is preferable to use remote control (if available) to "ask" the player to change the volume. * Add a new `DropSession` method. This will immediately and forcibly terminate a playing session without informing the source. Use it carefully. It is preferable to use remote control (if available) to "ask" the player to stop playing. Version 4.1-dev-454-ga774a6fc ==== **Enhancement** * Strip the trailing dot and everything after it in the hostname when using it as the basis for a service name. E.g. `freebsd.local` becomes `freebsd`. **Bug Fixes** * Fix a few compilation bugs and portability issues, and turn off deprecation warnings when compiling for Mac OS. **Note:** After this update, you'll need to run `autoreconf -fi` and the `./configure...` steps again. Version 4.1-dev-439-gb7a11cae ==== Documentation update. Comments, corrections and suggestions welcome. Version 4.1-dev-429-g449e024c ==== **Enhancement** * With the ALSA backend, if the `default` device isn't available, Shairport Sync will now try to use `"hw:0"` instead. Background: the default ALSA device is sometimes a pseudo device provided by a sound server such as PipeWire or PulseAudio to play audio from ALSA-compatible programs. But it's not always available to all users, especially daemons like Shairport Sync. This simple change will try to use the first ALSA hardware device -- card 0 -- if the default output device is inaccessible with error code `EHOSTDOWN`. It allows Shairport Sync to work on default settings with Fedora 36. Version 4.1-dev-424-g4729e325 ==== **Enhancements** * Shairport Sync should no longer terminate if its ALSA output device is busy. This is useful when using ALSA devices in systems with sound servers such as PulseAudio or PipeWire. Shairport Sync now simply waits until the device becomes available. Shairport Sync retains exclusive access to the device (and so the sound server can not use it) until it is finished playing. * Wait up to ten seconds (was two seconds) for NQPTP to come online when starting up -- AirPlay 2 only. Version 4.1-dev-420-g23d0502f ==== **Bug Fix** * This commit reverses the enhancement in Version 4.1-dev-418-g5011dc09 because it doesn't work properly. Specifically, some service files are not being renamed and installed correctly. Apologies for the inconvenience. **Note** After pulling this update, you should rerun the `$ autotools -fi` and `$ ./configure...` steps. Version 4.1-dev-418-g5011dc09 ==== **Enhancement** * The `Makefile.am` file has been updated to allow allow building and installing from a separate build directory. Thanks to [Lukas Rusak](https://github.com/lrusak) for the [contribution](https://github.com/mikebrady/shairport-sync/pull/1493). **Note** After pulling this update, you should rerun the `$ autotools -fi` and `$ ./configure...` steps. Version 4.1-dev-412-gf218a4d4 ==== **Note** -- A bug has been fixed in NQPTP -- please update it. **Reversion** * The change to the allowed settling time mentioned below has been reverted back to 5.0 seconds – the issue this was meant to address turned out to be a bug in NQPTP. Version 4.1-dev-409-g6bfeb49f ==== **Bug Fix** * Shorten the settling time (from 5.0 seconds to 0.75 seconds) allowed when a new AirPlay 2 player, with its own clock, is added or removed from the devices currently playing. The problem was that if something else happens during the settling time, the changeover to the new clock may fail. This doesn't eliminate the issue, but hopefully it stops it being a problem for the user. Version 4.1-dev-376-gca6e768f ==== **Bug Fix** * Fix a bug that permitted clipping to occur when the `playback_mode` as set to `mono`. Thanks to [xStatts](https://github.com/xStatts) for the [report](https://github.com/mikebrady/shairport-sync/issues/1491) and for checking the fix. Version 4.1-dev-357-gf551274a ==== Explore remote control a bit more. No progress to report... Version 4.1-dev-352-g4d608216 ==== **Bug Fix** * Fix a bug in the activity monitor that could potentially allow the `run_this_before_entering_active_state` hook to be called more than once when the player was going active. It could also potentially allow the `run_this_after_exiting_active_state` hook to be called more than once when the player was leaving the idle state, but only if the `active_state_timeout` was set to 0. Thanks to [Ben Willmore](https://github.com/ben-willmore) for the [report](https://github.com/mikebrady/shairport-sync/issues/1440). **Enhancement** * Allow procedures hooked to `run_this_before_entering_active_state` and `run_this_after_exiting_active_state` to run without the `activity_monitor_mutex` in the locked state. Version 4.1-dev-350-g82849e0d ==== **Change** * Return 501 instead of 404 for unimplemented GETs in AirPlay 2 mode. Version 4.1-dev-347-g6556a79d ==== **Bug Fix** * If a speaker with its own master clock (e.g. a HomePod mini) was added and then removed from the group of output speakers in AirPlay 2 mode, Shairport Sync would stop working. **Note** -- there is an important update to NQPTP out as well. Version 4.1-dev-340-g4705be9b ==== **Enhancement** * Improve the AAC decoder check by iterating through all formats the AAC decoder supports. Version 4.1-dev-332-g38c43f07 ==== **Bug Fixes** * Fixed a bug where the AAC decoder check would not recognise the AAC decoder in `ffmpeg` version 3. Thanks to [GXJ0102](https://github.com/GXJ0102) for help with this. * Fixed a bug where, on a very fast CPU, `"basic"` interpolation would be chosen instead of `"soxr"` interpolation. **Enhancement** * Relax the "fully-up-to-date" system requirement slighty -- Shairport Sync will build and run on Ubuntu 18.04 LTS. Version 4.1-dev-317-g0dc34a46 ==== ***Pesky Changes You Can't Ignore*** A change has been made the `shairport-sync`service/startup files, so before updating, please rerun the `./configure...` step and (Linux only) remove the existing service file as follows: ``` $ ./configure ... # whatever your preferred options are... # rm /lib/systemd/system/shairport-sync.service # Linux only -- no need for this in FreeBSD ``` **Enhancements** * The AAC decoder check for AirPlay 2 operation was temporarily removed but has now been reinstated and is working again. If it is causing problems, please let us know. A section has been added to the [TROUBLESHOOTING.md](https://github.com/mikebrady/shairport-sync/blob/development/TROUBLESHOOTING.md#aac-decoder-issues-airplay-2-only) document. * Debugging and statistical information now outputs to `STDERR` by default, so the rather confusing `-u` command line option is no longer needed. This has the following implications: * If Shairport Sync is run from a terminal window, then messages, warnings, debug and statistical information will appear on the terminal window. * If Shairport Sync is run as a daemon, then `STDERR` will be redirected to the system log. * If you wish to use [syslog](https://en.wikipedia.org/wiki/Syslog) (e.g. you might wish to see the different levels of highlighting of different categories of information), there is a new command line option `--log-to-syslog`. (This is used by the modified startup scripts.) * The `-u` option is now redundant and is deprecated (see above). * A new command line option `--log-to-syslog` allows you to direct messages, warnings, debug and statistical information to [syslog](https://en.wikipedia.org/wiki/Syslog). For full effect, it should be the first argument in your list of command line arguments. It is really intended for when Shairport Sync is run as a daemon. Version 4.1-dev-283-ga62e4b0b ==== **Enhancements** * FreeBSD compatibility. Shairport Sync (and NQPTP) can now work in AirPlay 2 mode on a FreeBSD system. Note that the build instructions and the configuration parameters have changed -- `libdaemon` is no longer needed and should not be included. * Certain Linux distributions -- notably Fedora 36 -- do not include a suitable AAC decoder for decoding AirPlay 2 Buffered Audio streams. Shairport Sync now includes a check to ensure that the AAC decoder can decode the stream, which seems to be encoded in Floating Point Linear Planar AAC ("`fltp`") format. (The AAC decoder is provided by the [`libavcodec`](https://www.ffmpeg.org/libavcodec.html) library, part of the [`ffmpeg`](https://www.ffmpeg.org) multimedia framework. For troubleshooting, the [`ffmpeg`](https://www.ffmpeg.org/ffmpeg.html) command line tool is very useful.) Version-4.1-dev-266-g1d228870 ==== **Minor Changes** * Cosmetic changes -- some debug and informational messages altered. Version-4.1-dev-255-g8a2756b7 ==== **Bug Fix** * Fix an audible interruption that could happen in certain circumstances when an output device was added or removed to a group of output devices. The "certain circumstances" are when the following two conditions are true: 1. An AirPlay 2 Realtime Stream is playing, 2. The new output device's clock takes or relinquishes control of output timing. For example, (i) when playing Spotify on an iOS device (this currently uses an AirPlay 2 Realtime Stream) to a Shairport Sync device and (ii) adding or removing a HomePod mini as an output device (the HomePod mini's clock will take or relinquish control of output timing). **Enhancement** * When a Shairport Sync device is added as an output device to a stream that is already playing, it now mutes for two seconds to improve synchronisation when it joins in and actually starts producing audio. The previous slight lack of synchronisation was inaudible, but would require some interpolation before settling down. Version-4.1-dev-249-g38bbad6f ==== **Bug Fix** * Fix a bug in the `systemd` startup file. The bug was that even when Shairport Sync was built without Avahi support, Shairport Sync would not launch until the Avahi service was available. Thanks to [klslz](https://github.com/klslz) for reporting the problem in issue [#1454](https://github.com/mikebrady/shairport-sync/issues/1454). Version-4.1-dev-247-ga295c2a2 ==== **Bug Fix** * Fix a bug in the logic for suppressing clicks when the `alsa` `disable_standby_mode` is active. Version-4.1-dev-245-gf34a69fa ==== **Enhancement** * AirPlay 2 only. Two new metadata messages have been added. They might be useful for amplifier switching, etc. 1. The `conn` message signifies "AirPlay 2 connect" and is sent when an AirPlay 2 device selects this player. It is sent _before_ killing any current play session. (Note: in AirPlay 2 operation, the existing `clip` message is identical, but it is sent _after_ any existing play session has been terminated.) 2. The `disc` message signifies "AirPlay 2 disconnect". Version-4.1-dev-242-g3877acc7 ==== **Bug Fix** * Fix a crash that would occur after days of continuous play. The issue was that each time a cover art file was created (and previous cover art deleted) the coverart directory was opened with `open()`, but was not closed with `close()`. Version-4.1-dev-238-g1dc481c3 ==== **Enhancement** * Add some extra diagnostic information when large sync errors occur: if available, add the total number of frames sent to the output device and also, if available, add th e current delay, in frames, in the output device. Version-4.1-dev-234-ge8721889 ==== **Bug Fix** * Fixed a bug using HomePod Software 15.4. The bug was that when a Shairport Sync device was added as a HomePod output device, visually it didn't appear to join the group of output devices and additionally its volume control could not be accessed. The bug was fixed by increasing the maximum permissible length of ID strings in Shairport Sync. Version-4.1-dev-229-g08afa822 ==== **Enhancement** * Add _Minimum Buffer Size_ to statistcs information for a Buffered Audio stream (and remove the minimum and maximum number of decoded buffers -- they are not too interesting). The Minimum Buffer Size gives the smallest size, in bytes of kilibytes, of the buffer of audio that has yet to be decoded during the last statistics interval. The larger it is, the longer Shairport Sync can play while a network outage is occuring. It can legitimately be zero at the start of a track, and obviously it can reach zero at the end of a track, but if it is zero while a track is playing, it may indicate problems with the network. Version-4.1-dev-224-g29d2155e ==== ***Pesky Change You Can't Ignore*** A change has been made the `shairport-sync` `systemd` service file, so before updating, please remove the existing service file with the following command: ``` # rm /lib/systemd/system/shairport-sync.service ``` **Bug Fixes** * Interpret `disable_standby_mode` to determine if a flush should also close an `alsa` device as follows: 1. If `disable_standby_mode` is set to `"no"` (default) or `"never"`, then a flush will immediately close the `alsa` device. 2. If `disable_standby_mode` is `"auto"`, a flush will not close the `alsa` device. The device will be closed at the end of the active timeout. 3. If `disable_standby_mode` is `"yes"` or `"always"`, a flush will not close the `alsa` device. The device will never be closed. * Remove the invalid `Provides` entry from the `systemd` service file. Thanks to [David Crook](https://github.com/idcrook) for reporting Issue [#1448](https://github.com/mikebrady/shairport-sync/issues/1448). Version-4.1-dev-214-gadf0845e ==== **Enhancement** * Check to see if the alsa_handle is NULL in `precision_delay_and_status`. Version-4.1-dev-211-g9bac04e2 ==== **Bug Fix** * Check for `NULL` pointers before dereferencing delay and state variable pointers in `audio_alsa.c`'s `delay` and `*-delay_and_status` functions. Thanks to [leirace](https://github.com/leirace) for the report, Issue [#1441](https://github.com/mikebrady/shairport-sync/issues/1441). Version-4.1-dev-209-gb4cd4fbc ==== ***Pesky Change You Can't Ignore*** A change has been made the `shairport-sync` `systemd` service file, so before updating, please remove the existing service file with the following command: ``` # rm /lib/systemd/system/shairport-sync.service ``` **Enhancements** * Improve the timing service interface: Instead of opening and closing a Shared Memory Interface (SMI) whenever timing information was needed from NQPTP, the SMI is now opened only once, at startup. Overall, this reduces overhead at critical times and seems to improve the initial accuracy of synchronisation. It also requires the NQPTP service to be available and accessible at startup. * Improve `alsa` flush performance: Add new code to better handle a flush request in the `alsa` backend. This new code results in smoother operation and timing accuracy is improved when continuing after a flush. * Define the Shairport Sync service in the `systemd` service file. **Bug Fix** * Fix a bug that caused a crash if an incorrect `wait_for_completion` option was chosen. Fixed a few similar bugs too. Thanks to [HiFiBerry](https://github.com/hifiberry) for reporting the issue at [#1431](https://github.com/mikebrady/shairport-sync/issues/1431). Version-4.1-dev-193-g4848608d ==== * Don't try to decode commands at debug level 2 -- leave it to level 3. Version-4.1-dev-191-ge07c202b ==== #### Enhancement * This enhancement relates to MQTT with empty payloads. Many MQTT brokers and clients treat messages with empty payloads in a special way. For instance, [MQTT Explorer](http://mqtt-explorer.com) hides messages with empty payloads and [Node-RED](https://nodered.org) seems to use them to release and garbage-collect data received previously. Many Shairport Sync messages contain no extra data and so would naturally have empty payloads. This is causing problems -- see [#1425](https://github.com/mikebrady/shairport-sync/issues/1425) and [#1375](https://github.com/mikebrady/shairport-sync/issues/1375). To avoid these problems, a short "dummy" payload consisting of the character string "--" is now added to MQTT messages that contain no extra data. This can be changed with a new MQTT option in the configuration file: `empty_payload_substitute`. Thanks to [DOCaCola](https://github.com/DOCaCola) and [UMB8998](https://github.com/UMB8998) for reporting on this. Version-4.1-dev-188-gf135d857 ==== #### Bugfixes * Ensure that when `ignore_volume_control` is true, the volume metadata has the current, max and min values of the [now ignored] attenuator set to 0.0. Thanks to [Michael Daley](https://github.com/greend139) for reporting in Issue [#1417](https://github.com/mikebrady/shairport-sync/issues/1417). * Add a fix for v3 of s6 overlay and other improvements to the Docker image. Thanks to [Charles Omer](https://github.com/charlesomer) for the fix and the improvements and thanks to [rdrdog](https://github.com/rdrdog) for reporting the issue. #### Other Changes * Add code to check certain 32-bit and 64-bit conversions. Version-4.1-dev-173-gdeb11654 ==== #### Enhancements * Add some sanity checking of the latency offset and buffer size to check if they can be accommodated. * Discard non-sentinel UDP timing packets that are received just when a timing thread starts -- they may relate to a prior session. Version-4.1-dev-171-g703717a5 ==== #### Bugfix * Clear PTP clock information when a Realtime stream stops playing. This _may_ address one of the issues reported in [#1404](https://github.com/mikebrady/shairport-sync/issues/1404). Version-4.1-dev-169-g6ced6bc6 ==== #### Enhancement * Add a new `mixer_control_index` setting to the `alsa` section of the configuration file. A mixer is fully identified by a name and index. The index defaults to zero, and, until now, it could only be set using the `alsa` command-line argument `-i`. Thanks to [flipoidix](https://github.com/flipoidix) for bringing this issue to notice. Version-4.1-dev-164-gf79222f7 ==== #### Bugfix * Fix a crashing bug in AirPlay 2 mode which occurs if no configuration file is found. This particularly affects the Docker image, as it contains no configuration file. Thanks to [Charles Omer](https://github.com/charlesomer) for reporting. Version-4.1-dev-160-g9c2f9f7a ==== #### Bugfix * Fix a crashing bug in AirPlay 1 ("Classic") mode, whereby if a session was abruptly interrupted, e.g. by the sudden loss of a network, Shairport Sync would crash. The problem was that the interrupted session was not correctly terminated. Thanks to [th0u](https://github.com/th0u) for reporting issue [#1398](https://github.com/mikebrady/shairport-sync/issues/1398). Version-4.1-dev-158-gb5860fc4 ==== #### Enhancements The following enhancements are mainly experimental, for advanced users only, and are intended to enable multiple instances of Shairport Sync (SPS) to run in one computer and provide multiple AirPlay 2 endpoints. At this point, multiple instances of SPS can indeed run on one machine and provide multiple AirPlay 2 endpoints, but unfortunately the presence of multiple services at the same address seems to confuse AirPlay 2 clients. So, it seems that while multiple instances of SPS can now run successfully on one device, they can't be used on the same network. * Use a uniquely-named named SMI interface to get dedicated access to NQPTP. * Simplify validation of the mDNS interface setting, if given. * Exit with a warning if the player is using a name that already exists. * Stop storing the timing peer list. * Generate an initial timing list during setup — don’t wait for the first timing peer list message. May gain around 50 ms. * Fix a bug and clean up generation of device's timing addresses. * Add some control to the generation of the Device ID: 1. Revise how the Device ID is generated from the device’s MAC addresses 2. Add a setting to add a fixed offset to the automatically-generated Device ID. 3. Add a setting to specify a complete Device ID, replacing the automatically-generated Device ID. * Be more careful to create default file names based on the name of the app. Version-4.1-dev-146-g42e508b4 ==== #### Enhancements * Extract several very useful extra pieces of client metadata for AP2. Many thanks to [Cody Cutrer](https://github.com/ccutrer). * Enable a cleaner restart of the D-Bus daemon in a Docker image. Thanks again to [Charles Omer](https://github.com/charlesomer). Version-4.1-dev-138-g5617f40e ==== #### Minor Internal Changes * A small number of internal chages made. Version-4.1-dev-127-g4d0460b9 ==== #### Enhancement * Update the Docker workflow to automatically do Docker tagging and to use an s6-overlay implementation. Thanks to [Charles Omer](https://github.com/charlesomer) for all this work, and to [Robert Casties](https://github.com/robcast) for his s6-overlay Pull Request [#1349](https://github.com/mikebrady/shairport-sync/pull/1349) which formed the basis of the s6-overlay work. * Slight documentation update, thanks to [michaeldeborst](https://github.com/michaeldeborst). Version-4.1-dev-115-g8656149d ==== * Simplify and improve timing when a play session from a new device is started. Version-4.1-dev-106-ge98111fb ==== #### Enhancement * Try to improve the reliability of restarting a "silent clock" device. Version-4.1-dev-104-g84dd2dc4 ==== * Begin to explore some more connection types. Version-4.1-dev-102-g9bf45574 ==== #### Enhancement * Make debug messages in the system log easier to see on macOS Terminal (!) by outputting them at LOG_INFO level rather than LOG_DEBUG level. Version-4.1-dev-100-g8330f30b ==== #### Enhancement * Updated information on the statistics provided -- see [MOREINFO.md](https://github.com/mikebrady/shairport-sync/blob/development/MOREINFO.md#statistics). (Note: this has moved to [STATISTICS.md](ADVANCED%20TOPICS/Statistics.md).) Version 4.1-dev-95-ga7a02083 ==== #### Bug Fix * Fixed a compilation bug that occurs if metadata support is not included in the build configuration. The fix was to add the appropriate conditional code statements. Thanks to [Daniel Gooß](https://github.com/Dangoo) and [winstonsetiawan](https://github.com/winstonsetiawan) for reporting. Version 4.1-dev-92-g3ab16b5d ==== #### Enhancement * Thanks to [Anton Lindqvist](https://github.com/mptre) for updates and bug fixes to building for OpenBSD. #### Other Updates * Thanks to [tekdude](https://github.com/tecdude) for a documentation update. * Various documentation updates. Version 4.1-dev-81-g24a5bbbe ==== This is a pretty big under-the-hood update. #### Significant Changes * Change clock base to improve stability. You need to use the updated `nqptp` that has also been changed. If you forget, Shairport Sync will not work properly and will leave a message in the log. * Avoid skipping the first 100 milliseconds or so of a newly-selected track. * Clean up the output of statistics — shorter when log verbosity is zero. * Change behaviour after an unrecoverable error -- if not handled, exit Shairport Sync. * Add client and server ip metadata for AP2 Buffered Audio Stream. #### Changes * Add client and server ip metadata for AP2. Remove timing peer list and DACP code only for a full AP2 teardown. * Fix a few memory leaks. Add bogus exits to allow SPS to quit at the end of a play session, to make it easier to use `valgrind`. * Stop checking that the timing peers are within the same subnet. * Look for at least 0.1 seconds of leadtime, ensure a master clock is at least 0.275 seconds old before use, quieten a few debug messages. * Add txtAirPlay data to the get info response. * Don't pause reception of long RTSP messages. * Don't ask for cover art if not asking for metadata too, duh. * Skip some types of invalid AAC packets. * Don't decode outdated frames. * Wait for timing information to be valid in AP2 Buffered Audio Streams processing. * Set the timing peer list as soon as a SETPEERS message is received -- don't wait until play is about to begin. Not sure if it works universally yet. * Tidy up the statistics printout table and stop outputting (non existent) nominal fps for AP2 Realtime Streams. * Use PKG_CHECK_MODULES to find libavcodec, to make it work with Fedora 35 (?) * Change behaviour after an unrecoverable error -- if not handled, exit Shairport Sync. * log statistics headers whenever verbosity goes on or off or whenever statistics are requested * Clean up statistics. * Stop watchdog timing out AP2 sessions. * Remove the commas in the statistics logs -- easier to get into a spreadsheet. * Don't overwrite service files if they already exist. * Try finding libplist as libplist-2.0 on Linux too. * Move to using CLOCK_MONOLITHIC_RAW to avoid NTP effects. Bump interface version. * Add code to check divisions and mods for a potential divide by zero problem. This may cause SPS to terminate but it will leave a log message. * Add a 'stats' function to the audio back ends to replace the 'rate_info' function. Zero all except the alsa back end. * Attempt to increase the precision of the FPS timing * Update to the latest version of ejurgensen's pair_ap library. With thanks. #### Bug Fix - This fixes [#1345](https://github.com/mikebrady/shairport-sync/issues/1345) by checking for the `libplist` library both under the name `libplist` and `libplist-2.0` using the fallback strategy [as described in the autotools docs](https://autotools.io/pkgconfig/pkg_check_modules.html). Since we now try both names, we no longer need the FreeBSD/Linux check. Many thanks to [FW](https://github.com/fwcd) for the bug report, the fix and this documentation! Version 4.1-dev-21-g1032cad6 === #### Enhancement - Update the `pair_ap` library to the [latest version](https://github.com/ejurgensen/pair_ap). Thanks again to [ejurgensen](https://github.com/ejurgensen). Addresses Issue [#1334](https://github.com/mikebrady/shairport-sync/issues/1334). Thanks to [iChUdY](https://github.com/iChUdY) for reporting the issue. Version 4.1-dev-19-g3f6f0932 === #### Bug fix - Fix a bug that would occasionally mute Shairport Sync when using it with AppleTV. Combined with the [recent update](https://github.com/mikebrady/nqptp/blob/development/RELEASE_NOTES.md) of `nqptp`, this makes using Shairport Sync much more useful with an AppleTV 4K. Version 4.1-dev-15-gf4115c45 ==== #### Bug Fix - Fix the following [buildroot](https://buildroot.org) build failure when the `--with convolution` flag is included. The issue is due to a change in the behaviour of automake 1.16.5 -- see [`https://git.savannah.gnu.org/cgit/automake.git/commit/?id=f4a3a70f69e1dbccb6578f39ef47835098a04624`](https://git.savannah.gnu.org/cgit/automake.git/commit/?id=f4a3a70f69e1dbccb6578f39ef47835098a04624): ``` configure.ac:305: error: AM_INIT_AUTOMAKE expanded multiple times /home/giuliobenetti/autobuild/run/instance-1/output-1/host/share/aclocal-1.16/init.m4:29: AM_INIT_AUTOMAKE is expanded from... configure.ac:6: the top level /home/giuliobenetti/autobuild/run/instance-1/output-1/host/share/aclocal-1.16/init.m4:29: AM_INIT_AUTOMAKE is expanded from... configure.ac:305: the top level ``` Fixes: [`http://autobuild.buildroot.org/results/464148bdccb705d8992dc860262bfdeb01b7e2a1`](http://autobuild.buildroot.org/results/464148bdccb705d8992dc860262bfdeb01b7e2a1). Thanks to [Fabrice Fontaine](https://github.com/ffontaine) for [Pull Request #1314](https://github.com/mikebrady/shairport-sync/pull/1314). Version 4.1-dev-9-gd2e35fc0 ==== #### Bug Fix - Fix an incompatibility with iOS 15.1 betas and release candidates. The problem was this: if an unknown RTSP command was received, Shairport Sync would return a HTTP error response code of 400 ("Bad Request") but the player would not continue. After some experimentation, it was discovered that a HTTP error response code of 501 ("Not Implemented") would allow the player to continue. Thanks to [corrpel](https://github.com/corrpel) and [bloomkd46](https://github.com/bloomkd46) for reporting the issue. Version 4.1-dev-4-g0fe21f3a ==== #### Bug Fixes - Fix a bug whereby the `volume_range_db` setting would be ignored if it was less than the range of the hardware mixer. - Fix a bug that prevented an AirPlay 2 build if metadata was not enabled, either directly or indirectly, at the `./configure...` step. Version 4.1-dev ==== #### Enhancement - **Better Siri, HomePod mini and Home Integration** An AirPlay 2 build of Shairport Sync now provides a visible volume control when used by a HomePod mini. This should work for other devices too -- reports welcome. You can use the Home app and Siri to set and adjust the volume when used to play from the HomePod mini. Version 4.0-dev-308-g23da206 ==== #### Bug Fixes - Restore logging to `syslog`. Version 4.0-dev-303-g9074069 ==== #### New Features - An initial [PipeWire](https://pipewire.org) backend, with thanks to [Lukas Rusak](https://github.com/lrusak). Use the `--with-pw` configuration flag at the `./configure...` stage to include support. #### Bug Fixes - Fix a bug when using the `tinysvcmdns` mDNS implementation, with thanks to [fesc2000](https://github.com/fesc2000). - When an unrecognised SETUP message is received, just ignore it and put a warning in the log. Remove a redundant `client_setup_plist` data item from the `conn` data structure. #### Enhancements - Shairport Sync no longer needs to be in the same directory as NQPTP during compilation. - Add Docker automations -- thanks to [Charles Omer](https://github.com/charlesomer). - Add Issue management automations -- thanks to [Charles Omer](https://github.com/charlesomer). - Reconnect the DACP scanner for AirPlay 2. (It still isn't useful, unfortunately.) - Add initial support to allow dynamic modification of Rendezvous advertisements. - Simplify some UFW suggestions in the Troubleshooting Guide. - Merge some documentation changes from the `master` branch. - Add information to the Car Install Guide about improving boot times, thanks to [vasilisvg](https://github.com/vasilisvg) Version 4.0-dev-185-g0c02ee2 ==== #### New Features - **Home App Integration** An AirPlay 2 build of Shairport Sync now offers limited integration with the Home app. Specifically, a Shairport Sync AirPlay 2 instance can now be added as a speaker to the Home app. Thanks to [ckdo](https://github.com/ckdo) and [ejurgensen](https://github.com/ejurgensen) for figuring this out and for coding it up. It means that some Siri interaction is possible. - **Automated Docker Builds** Thanks to the work of [Charles Omer](https://github.com/charlesomer), Docker builds on the `development` branch should appear from time to time on the [Docker Hub](https://hub.docker.com/r/mikebrady/shairport-sync). #### Bug Fixes - [Crashing bug fix](https://github.com/mikebrady/nqptp/blob/main/RELEASE_NOTES.md) in `nqptp` -- thanks to [ste94pz](https://github.com/ste94pz). - Honour the `max_volume_db` setting even when `ignore_volume_control` is true. Note that dithering is enabled if software attenuation is needed. #### Other Changes - Spell out `Shairport Sync` instead of `SPS` in a few places. - Clang format some source files. Version 4.0-dev-153-g9ccde50 ==== Big Update ---- Version 4 brings [limited AirPlay 2 functionality](https://github.com/mikebrady/shairport-sync/blob/development/AIRPLAY2.md) to Shairport Sync. For information about AirPlay 2, including acknowledgements, please visit [AIRPLAY2.md](https://github.com/mikebrady/shairport-sync/blob/development/AIRPLAY2.md). #### Known Issues - In the AirPlay 2 build, a crash can occur occasionally when the player is being selected. If you can get this to happen reliably, please let us know. #### Warning 1. Big changes have been made to the codebase to enable it to be used to build either as the "classic" AirPlay 1 player or as a new AirPlay 2 player. These changes have probably introduced bugs into the classic AirPlay 1 build. 2. There is lots we don't know about AirPlay 2. This can result in incorrect behaviour. Watch out for very high volume levels, especially if you have a powerful audio system. 3. This is a `development` branch and is probably more buggy than usual. Normal support will not be provided -- instead, we will be interested in bug reports that help improve the program. You need to be adept with Linux or FreeBSD to get involved. Version 3.3.8d7 ==== **Bug Fix** * Fix a bug in the `alsa` back end. In the interval between checking to see if the alsa device handle was NULL and actually using it, the handle could be set to NULL. The interval between check and usage is now protected. Version 3.3.8d6 ==== **Bug Fix** * Fix a bug in the `alsa` precision timing code. Thanks to [durwin99](https://github.com/durwin99), [Nicolas Da Mutten](https://github.com/cleverer), [mistakenideas](https://github.com/mistakenideas), [Ben Willmore](https://github.com/ben-willmore) and [giggywithit](https://github.com/giggywithit) for the [report](https://github.com/mikebrady/shairport-sync/issues/1158). Version 3.3.8d5 ==== **Bug Fixes** * Fix a fault in the configuration script `configure.ac` that caused the `libdaemon` library to be omitted even when requested. Thanks to [aleszczynskig](https://github.com/aleszczynskig) and [xska2](https://github.com/xska2) for the [report](https://github.com/mikebrady/shairport-sync/issues/1137). Version 3.3.8d4 ==== **Bug Fixes** * Fix a fault in the configuration script `configure.ac`. The fault was that a `--without-*` configuration argument was being misunderstood and interpreted partly as a `--with-*` argument. Thanks to [David Racine](https://github.com/bassdr) for the [report](https://github.com/mikebrady/shairport-sync/issues/1123). Version 3.3.8d3 ==== **Enhancements** * Documentation for the MQTT interface. Many thanks to [minix1234](https://github.com/minix1234)! **Bug Fixes** * Fix a bug that caused Shairport Sync to hang, but not actually crash, if an on-play or any on-*** script failed. * Fix a crash that occurred if metadata support is enabled during compilation but turned off in the configuration file. Thanks to [Tim Curtis](https://github.com/moodeaudio) for the report. * Fix a crash that occurred playing from AirPower on Android. Thanks to [Ircama](https://github.com/Ircama) for the report. Version 3.3.8d2 -- 3.3.8d0 ==== There are absent from the repository -- see `3.3.8rc0` and `rc1` in the `master` branch. Version 3.3.7d19 ==== **Bug Fix** * Ensure the metadata pipe is created, if necessary, when the `--with-metadata` configuration option is chosen without the `--with-dbus-interface`, `--with-mpris-interface` or the `--with-mqtt-client` options. Super thanks to [Philip Howard](https://github.com/Gadgetoid) for finding this and for developing a possible solution. **Enhancements** * Add a default name for the `pipe` backend. If you don't specify a name for the `pipe` backend's named pipe, it will be `/tmp/shairport-sync-audio`. Note that Shairport Sync will need to have write permission to `/tmp` to create the pipe. Version 3.3.7d18 ==== **Bug Fix** * Make the first output backend in the list of backends the default, and make its name the default output_name. Clang-format everything. Thanks again to [kiwi-ed](https://github.com/kiwi-ed) for bringing this issue to light. Version 3.3.7d17 ==== **Bug Fix** * Include the word `jack` in the version string if support for [Jack Audio](https://jackaudio.org) is included. Thanks to [kiwi-ed](https://github.com/kiwi-ed) for bringing this issue to light. Version 3.3.7d16 ==== **Bug Fix** * Fix potential inability to restore synchronisation quickly in certain situations. Version 3.3.7d15 ==== **Enhancements** * Changed permissions when creating the metadata pipe (and the audio pipe in the `pipe` backend) to `rw-rw-rw-` for compatibility with `snapserver`. Version 3.3.7d14 ==== **Enhancements** * Fixed a situation where a misleading error message was given if a configuration file cound not be located and `get_coverart` was selected as a command line option. Apart from a misleading message, `get_coverart` and `enable_metadata` should have been enabled automatically where metadata support is included in the build configuration. Thanks to [Craig Fletcher](https://github.com/leakypixel) for the bug report. Version 3.3.7d13 ==== This is 3.3.7rc1 **Enhancements** * Fixed another bug, related to the bug fixed in 3.3.7d4, where leading zeros were not removed from the DACP ID. Thanks again to [julianc1969](https://github.com/juliandc1969). Version 3.3.7d12 ==== This is 3.3.7rc0 **Enhancements** * Added the the string `-alac` to the the version string in '-V' if Apple ALAC decoder support is included. Version 3.3.7d11 ==== **Bug Fixes** * Fixed a number of bugs that prevented Shairport Sync from terminating cleanly in response to the `MPRIS` interface's `Quit()` command. Thanks to [João Gabriel](https://github.com/jgabriel98) for reporting this issue. * Related to the above, the code used to terminate the application after a fatal error has been cleaned up. It now uses the correct `exit()` call rather than the rather hacky `abort()` call, returning the value of the constant `EXIT_FAILURE` (typically `1`) to the caller . Version 3.3.7d10 ==== **Bug Fix** * Fixed a bug whereby the start and end of active mode tokens `abeg` and `aend` where not generated or published -- `pend` tokens were being generated instead. Thanks to [minix1234](https://github.com/minix1234) for the bug report and [fix](https://github.com/mikebrady/shairport-sync/pull/1023). **Enhancements** * Cleaned up and simplified the code that handles `FLUSH` requests coming from the player. (Debug messages are still a little verbose.) Version 3.3.7d9 ==== **Enhancements** * Improved timing estimation. Shairport Sync has been using linear least-squares regression to estimate timing drift between the (remote) source clock and the local clock. This technique is now extended to provide an estimate of the remote-to-local clock difference itself. (The remote-to-local clock difference is used to remap the timing of audio frames from the remote device's clock to the local clock.) Timing drift estimates are now saved when a sessions ends, keyed to the client IP number. When a new session starts from that IP number, the stored estimate is used until a new estimate can be generated from the new session. In practice, the timing techniques in use up to now have been very accurate, but this should result in slightly smoother rates of correction. Version 3.3.7d8 ==== **Enhancements** * Tidied up the creation and initial opening of pipes. Suppress repeated pipe-opening error messages. * Tidied up warnings and fatal error messages when log verbosity is zero. * Cleaned up the code that provides a silent lead-in to play on a back end without synchronisation, e.g. a pipe or `stdout`. * Added in commented-out code to check the timeliness of the release of audio to a back end without synchronisation, e.g. a pipe or `stdout`. TL;DR – so long as the back end does not block, frames will be released to it not more than one packet (352 frames) late. Version 3.3.7d7 ==== **Enhancements** * Logs and statistics can now be directed to the system log (default), `stdout`, `stderr` or to a file or pipe of your choice using a new setting, `log_output_to` in the `diagnostics` section of the configuration file. This is very useful when the system log is disabled or diverted. * Audio data from the `pipe` back end and metadata from the metadata pipe are now written using standard blocking `write` commands rather than a slightly complex non-blocking write function. Pipes are now opened in non-blocking mode and changed to blocking mode when successfully opened. * Separate threads are now used for each metadata subsystem. Until now, all metadata was processed on a single thread. This included writing to the metadata pipe and the multicast stream and supplying metadata for the `mqtt` interface and for the `dbus` and `MPRIS` interfaces. Unfortunately, that meant that a problem with any one of these subsystems could propagate into the others. Now they all run on separate threads. If one thread blocks, it will not interfere with the other subsystems. Version 3.3.7d6 ==== **Bug Fixes and Enhancements** * Fixed a bug calculating the instantaneous synchronisation error. This bug could occasionally cause Shairport Sync to lose synchronisation and maybe even to mute for a few seconds before resynchronising. It was caused doing modulo arithmetic incorrectly and it's been there for a while. * Cleaned up and improved the code to synchronise the first frame of audio. This should result in more accurate and reliable initial synchronisation, usually to under a millisecond, and often to within 20 or 30 microseconds. Syncronisation should improve even when the silent lead-in time is as short as 0.3 seconds or when the `audio_backend_latency_offset_in_seconds` is as much as -1.7 seconds, i.e. when only 0.3 seconds of latency are left when the latency would normally be 2.0 seconds. * Removed a bug which would affect initial synchronisation if a `FLUSH` command was received from the player at an inopportune time. * Cleaned up some confused uses of modulo arithmetic. * Cleaned up the allocation of memory for gathering running statistics – the heap is now used instead of the stack. * Cleaned up the display of statistics for backends that do not implement active synchronisation, e.g. the `pipe` and `STDOUT` back ends. Version 3.3.7d5 ==== **Bug Fixes and Enhancements** * Added code to do calculations involving the `audio_backend_latency_offset_in_seconds` and `audio_backend_silent_lead_in_time` settings correctly. Many thanks to [Tucker Kern](https://github.com/mill1000) for discovering a number of bugs associated with this and for [proposing a solution](https://github.com/mikebrady/shairport-sync/pull/1001). This prompted a closer investigation and a number of further improvements were made, and a few "hostages to fortune" removed. * Cleaned up the `audio_backend_silent_lead_in_time` setting by adding an `"auto"` setting. * Improved synchronisation accuracy with short silence lead-ins. **New Feature** * For the PulseAudio backend `pa`, added a new `server` entry to the `pa` section of the configuration file, allowing you to specify a connection to a remote or a local system PulseAudio instance instead of letting PulseAudio choose. Thanks to [Guillaume Revaillot](https://github.com/grevaillot) for this new feature. Version 3.3.7d4 ==== **Bug Fix** * The DACP ID looks like a 64-bit number expressed in hexadecimal. It is normally quoted with leading zeroes removed, but in the `_dacp._tcp` service string, leading zeros are not removed from the DACP ID. The bug fix removes those leading zeroes. Thanks to [julianc1969](https://github.com/juliandc1969) for tracking down this bug so tenaciously! Version 3.3.7d3 ==== **Enhancement** * While a player is active, the DACP port number to which to send remote commands should be broadcast over ZEROCONF/Bonjour. However, if that information is not available, Shairport Sync will now check for it every two seconds. Version 3.3.7d2 ==== **Pesky Changes** * The underlying timing system has been moved from 64-bit fixed-point time representation (like NTP) to a 64-bit unsigned nanoseconds representation. This should make precisely no difference to the functionality of Shairport Sync but the transition might inadvertently have introduced bugs. Problem reports gratefully received. **Enhancement** * The timing software in the `sndio` backend does some extra sanity checking on certain time estimates, it may help a little when running on virtual machines. Version 3.3.7d1 ==== This is 3.3.6 with some documentation updates. Version 3.3.6d11 = Version 3.3.6 ==== **Bug Fix** * Avoid using `strndup` as it seems older versions of OpenWrt do not recognise it. Version 3.3.6d10 ==== **Bug Fix** * Brown-bag fix -- do what 3.3.6d9 was supposed to do! Version 3.3.6d9 ==== **Bug Fix** * Fix a bug in the provision of metadata which would on occasion cause metadata from the previous track to be provided. Thanks to [Tuomas Hämäläinen](https://github.com/tuomashamalainen) and [HiFiBerry](https://github.com/hifiberry) for reporting. This bugfix addresses issue [#972](https://github.com/mikebrady/shairport-sync/issues/972). Version 3.3.6d8 ==== **Bug Fixes** * Tidy up compilation of the `audio-dummy` and `audio-soundio` back ends when the `-fno-common` flag is used. * Remove a superflous extra definition of a variable which would cause it to be used uninitialised. Version 3.3.6d7 ==== **Bug Fix** * Treat the `mper` (Persistent ID of a track) metadata attribute as the 64-bit item that it really is rather than a 32-bit item as hithereto. Output it as a hexadecimal number on the MPRIS and D-Bus interfaces to correspond with the format of the persistent id obtained from AppleScript. E.g: ``` tell application "Music" get the {persistent ID} of the current track end tell ``` resulting in: ``` {"FD84B4B40FA33A85"} ``` The MPRIS `trackid` corresponding to this would be `/org/gnome/ShairportSync/FD84B4B40FA33A85`. Thanks to to [Scott Simon](https://github.com/zutroy97) for finding a related bug in the [shairport-sync-metadata-reader](https://github.com/mikebrady/shairport-sync-metadata-reader). **Other Changes** * Include the `-fno-common` flag in the compilation options to detect incorrect definitions of global variables and multiple definitions of `enum` data types. Version 3.3.6d7 ==== **Bug Fix** * Make Shairport Sync compile in the forthcoming Fedora 32. Fedora 32 uses GCC-10 which [defaults to `-fno-common`](https://gcc.gnu.org/gcc-10/porting_to.html) exposing a number of issues with Shairport Sync – multiple definitions of some `enum`s and failure to define certain variables as `extern`. Version 3.3.6d7 is an attempt to clear up all these errors. Many thanks to [Bill Peck](https://github.com/p3ck) for his ongoing support, for bringing this issue to notice and for developing a workaround. Address issue [#973](https://github.com/mikebrady/shairport-sync/issues/973). Version 3.3.6d6 ==== **Bug Fix** * Add a `SIGCHLD` handler to remove completed processes that were used to perform and program "hooks" without waiting for completion and thus prevent them from becoming zombie processes. Thanks to [patrickjane](https://github.com/patrickjane) for reporting the bug and for suggesting a solution. Addresses issue [#968](https://github.com/mikebrady/shairport-sync/issues/968). Version 3.3.6d5 ==== **Bug Fix** * Fix an incompatibilty with Forked Daapd that was causing Forked Daapd to lock up. Thanks to [@tomgadow](https://github.com/tomgadow) and [@ejurgensen](https://github.com/ejurgensen) for their help in finding and (hopefully) fixing this issue. Addresses issue [#953](https://github.com/mikebrady/shairport-sync/issues/953) and [Forked Daapd Issue #870](https://github.com/ejurgensen/forked-daapd/issues/870). **Enhancements** * Add some extra examples of using the RemoteControl interface's SetAirplayVolume feature to the shairport-sync-dbus-test-client source. **Pesky Changes You May Not Be Able To Ignore** * Renamed the `Server` property in the D-Bus interface to `Client`. The rather strange language in use has it that a player like iTunes is a "client" of the AirPlay device like Shairport Sync, which is therefore considered the "server". The newly-renamed "Client" property is the IP number of the player. Version 3.3.6d4 ==== A fix for issue #953 that wouldn't work. Version 3.3.6d3 ==== **New Features** * Add `SetAirplayVolume` to the native D-Bus `RemoteControl` interface. * Add `SetVolume` to the `MPRIS` interface. **Bug Fixes** * Hook up the `Volume` property in the `MPRIS` interface. **Enhancements** * Modify `RemoteCommand` in the D-Bus interface to return the HTTP status and response in hex. * Add a few sample commands, including `MPRIS` commands, to the [Sample D-Bus Commands](https://github.com/mikebrady/shairport-sync/blob/development/documents/sample%20dbus%20commands) document. Version 3.3.6d2 ==== **New Features** * Resampling has been added for the [Jack Audio](http://jackaudio.org) backend. This can be used to up-sample to 192kHz. Thanks to [Pieter De Gendt](https://github.com/pdgendt) for this addition. Version 3.3.6d1 ==== This is release version 3.3.5. Version 3.3.5d1 ==== **Pesky Changes You May Not Be Able To Ignore** * Renamed the `LoudnessFilterActive` property in the D-Bus interface to `Loudness`. Updated [shairport-sync-dbus-test-client.c](https://github.com/mikebrady/shairport-sync/blob/development/shairport-sync-dbus-test-client.c) accordingly. **New Features** * Added to the D-Bus interface the ability to turn on and off convolution, to set the convolution gain and to change the convolution impulse response files. See examples in [sample dbus commands](https://github.com/mikebrady/shairport-sync/blob/development/documents/sample%20dbus%20commands). Note: for these commands to make sense, Shairport Sync must be built with support for convolution and the native D-Bus interface (`--with-convolution` and `--with-dbus-interface`) and fully installed. **Bug Fix** * Fixed a bug whereby if you enabled the Loudness filter via the D-Bus interface, the output disappeared until you changed the volume. Version 3.3.5d0 ==== **Bug Fix** * Fixed a crashing bug when output format `"S24"` was chosen. Fixes the issue reported by [artenverho](https://github.com/artenverho) in [#927](https://github.com/mikebrady/shairport-sync/issues/927). Version 3.3.4 ==== This version did not appear on the `development` branch -- it fixed a small compilation error. Version 3.3.3d11 ==== **Bug Fix** * Fixed a crashing bug -- if a plain HTTP packet (in fact, any packet that didn't have an RTSP-style header) was sent to the TCP session port (usually port 5000), Shairport Sync would crash! Thanks to @[dubo-dubon-duponey](https://github.com/dubo-dubon-duponey) for reporting. Fixes [#921](https://github.com/mikebrady/shairport-sync/issues/921). **Pesky Change** * The setting `retain_cover_art` is now part of the `diagnostics` group. Set it to `"yes"` to retain cover art cached by the D-Bus, MPRIS or `mqtt` interfaces. Your directory may fill up if you leave it set! Version 3.3.3d9 ==== **Enhancements** * Expose a `metadata` setting related to handling cover art: * The setting `cover_art_cache_directory` allows you to specify where cover art files will be cached if Shairport Sync has been built with native D-Bus, MPRIS or MQTT support. The default is `/tmp/shairport-sync/.cache/coverart`. If you set it to an empty list: `""`, caching is disabled. This might be useful in, say, an embedded device, or wherever you want to minimise file writing. Version 3.3.3d8 ==== **Bug Fix** * Fix a bug in the resend request logic. **Enhancement** * Expose the settings controlling the resend request logic. The new settings are in the `general` section: * `resend_control_first_check_time` is the time allowed to elapse before a packet is considered missing, defaulting to 0.1 sec. UDP packets don't always arrive in order and they don't need to be re-requested just because they arrive out of sequence. Essentially, therefore, this parameter is to prevent needless resend requests for packets that are already in transit. * `resend_control_check_interval_time` is the interval between repeated requests for a missing packet, defaulting to 0.25 seconds. * `resend_control_last_check_time` is the time by which the last check should be done before the estimated time of a missing packet's transfer to the output buffer, defaulting to 0.1 seconds. In other words, if a packet is still missing 0.1 seconds before it is due to be transferred to the DAC's output buffer, don't bother asking for a resend. Version 3.3.3d7 ==== **Duh** * Versions 3.3.2d3 to 3.3.2d6 should have been labelled 3.3.3d\. **Enhancement** * Rewrite the logic for identifying missing packets of audio and for asking for resends. It seems more robust -- there was a suspicion of the previous logic that resend requests were not made for some missing packets. In addition, requests for resends of continuous sequences of packets are rolled into one. Version 3.3.2d6 ==== **Enhancements** * Normalise the `'pvol`' volume outputs so that when both the software and hardware attenuators are in use to extend the overall attenuation range, the maximum output level corresponds to the maximum output level of the hardware mixer. * Add the option of including the file and line number of each log entry's source. The option is on by default and is settable in the configuration file and in the `dbus` interface. **Bug Fixes** * Fixes an error whereby the `'pvol'`volume metadata was no longer sent if Shairport Sync was configured to ignore volume control information coming from the audio source. Addresses issue [#903](https://github.com/mikebrady/shairport-sync/issues/903). Thanks to [Jordan Bass](https://github.com/jorbas) for reporting the regression and for identifying the commit and code in which the regression occurred. * Fixes a compilation error if including the MQTT client -- thanks to [exoqrtx](https://github.com/exoqrtx) for reporting. * Fixes a compilation error if including the MPRIS interface. * Ensure the hardware mixer of an `alsa` device is detected and initialised before responding to the first volume setting. Version 3.3.2d5 ==== **Enhancement** * Improves the detection of the remote services available when an audio source is playing. If the source is minimally compatible, e.g. iOS, Shairport Sync's `org.gnome.ShairportSync.RemoteControl` native `dbus` interface becomes "`available`". If the source is iTunes, then the `org.gnome.ShairportSync.AdvancedRemoteControl` interface also becomes `available`. Artwork, metadata, status and limited remote control facilities are accessible through these interfaces when they are in the `available` state. Follows on from issues raised in [#890](https://github.com/mikebrady/shairport-sync/issues/890). Thanks again to [exoqrtx](https://github.com/exoqrtx) for bringing these issues to light and for testing. **Bug Fix** * Fixes an issue that occured in Ubuntu 14.04 – the `shairport-sync` daemon would silently die after a fairly long period. It typically happened just after a DHCP address was renewed. The problem seemed to be related to having more than one `avahi` threaded polling loop (though this isn't documented anywhere). The fix was to consolidate the `avahi` stuff down to one threaded polling loop. Addresses issue [#895](https://github.com/mikebrady/shairport-sync/issues/895). Thanks to [Hans (the) MCUdude](https://github.com/MCUdude) for reporting and for initial troubleshooting. Version 3.3.2d4 ==== **Bug Fixes and Enhancements** * Fixes and enhancements to the MPRIS and native D-Bus interfaces. In particular, situations where artwork is absent are better handled, and the remote interface and advanced remote interface `availability` properties should be more resilient in the face of network problems. Addresses issue [#890](https://github.com/mikebrady/shairport-sync/issues/890). Thanks to [exoqrtx](https://github.com/exoqrtx) for bringing these issues to light and for testing. Version 3.3.2d3 ==== **Bug Fix** * Fixes a potential crash when an incomplete `fmtp` parameter set is sent by the requesting client. Thanks to [Angus71](https://github.com/Angus71) for the fault report and for the repair. **Enhancement** * Instead of returning `EXIT_FAILURE`, return `EXIT_WITH_SUCCESS` on early exit with either "version" (`–version` or `-V`) or "help" (`–help` or `-h`) arguments. Thanks to [Henrik Nilsson](https://github.com/henriknil) for the patch. Version 3.3.2d2 ==== **Bug Fix** * Fix a double-free memory bug. Thanks to [Chris Boot](https://github.com/bootc) for reporting this bug, which came through the Debian BTS: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=925577. The fix is different from the suggested patch. Version 3.3.2d1 ==== **Enhancements** * Allow `disable_standby_mode` to operate on any output device, not just real hardware devices. If there are too many underruns while outputting silence, the disable standby mode will be turned off. The Inevitable Version 3.3.1rc1 ==== **Bug Fixes** * Fix a bug in the MQTT documentation and add sanity checking for the port chosen -- thanks to [David Crook](https://github.com/idcrook). * Fix a bug that caused manual format and rate setting to be ignored -- thanks to [Jörg Krause](https://github.com/joerg-krause). * Add missing support for format settings S24_LE, S24_BE, S32_LE and S32_BE. * Fix a bug that caused dither to be too loud. * Fix error message for invalid `disable_standby_mode` choice -- thanks to [Tim Curtis](https://github.com/moodeaudio) at [Moode Audio](https://moodeaudio.org). Version 3.3rc8 ==== **Enhancements** * Add a list of alsa hardware devices found to the alsa backend help section in the `shairport-sync -h` text. (Doesn't work for alsa on FreeBSD/OpenBSD.) * Always place D-Bus access policy documents in `/etc/dbus-1/system.d` in Linux, but adhere to the standard for FreeBSD/OpenBSD. Version 3.3rc7 ==== **Enhancements** * Improvements to the `MQTT` client -- extra diagnostic messages at run time and at configuration time. Version 3.3rc6 ==== **Pesky Change You Can't Ignore** * The `while_active` setting in the new `disable_standby_mode` has been renamed to `auto`. **Enhancements** * Automatic bit-depth and speed selection for `alsa` output devices has been added and is the default. The greatest bit depth available is selected, and the lowest multiple of 44,100 frames per second is chosen. * Improve support for big-endian devices by adding support for `S16_LE`, `S16_BE`, `S24_LE`, `S24_BE`, `S32_LE` and `S32_BE` formats. Version 3.3rc5 ==== * Had a bug, sorry -- please go to 3.3rc6 or later. Version 3.3rc4 ==== **New Feature** * Support is now included for the automatic selection of the interpolation method. If support for `soxr` interpolation is included at configuration time (using the `--with-soxr` at the `./configuration...` step), then `auto` interpolation is made the default interpolation mode. During startup, the time it takes to do two `soxr` interpolations is calculated -- this, in milliseconds, becomes the `soxr_delay_index`. If the `soxr_delay_index` is less than or equal to a new `general` group setting called `soxr_delay_threshold` (default 30), then `soxr` interpolation will be chosen in `auto` mode; otherwise, `basic` interpolation will be chosen. Version 3.3rc3 ==== **Minor Enhancement** * Calculate the length of the first sequence of frames of silence preceding the audio at the start of a play session a little more carefully to make it somewhat longer. This should make output devices that operate with a fairly large buffer a little less likely to underrun at the start of a session. Version 3.3rc2 ==== **New Feature** * Shairport Sync can now accept AirPlay streams containing uncompressed PCM -- specifically, 16-bit network-endian interleaved stereo, 44,100 frames per second. There is a restricton -- the packets of audio must be 352 frames long. **Bug Fix** * Compatibility has been restored with virtual ALSA devices. Sometimes, an ALSA output device isn't actually a real hardware device -- for example, if PulseAudio is installed in your system, the "default" ALSA output device may in fact a virtual device that provides a route into the PulseAudio sound server for audio from ALSA-compatible applications. Such virtual devices don't always provide the precise delay timing that Shairport Sync uses. The bug fix is to fall back to the standard calls when precise delay timing is not available. * If precise delay timing data is not available, the `disable_standby_mode` is turned off, as it relies on high precision timing. Version 3.3rc1 ==== **New Feature** * If support for `soxr` interpolation is included at configuration time, then `soxr` interpolation is made the default at run time. (This was later changed -- see 3.3rc4.) * If support for the Apple ALAC decoder is included at configuration time, then the Apple ALAC decoder is made the default at run time. * If support for metadata is included at configuration, then metadata and cover art are both enabled by default at run time. (Metadata is enabled if you configure support for metadata, the dbus interface, the MPRIS interface or the MQTT client.) **Enhancements** * MQTT publishes `active_start` and `active_end` events when the active state is entered and exited. * Add correction to fix for tinysvcmdns CVE-2017-12130. * Partly update man pages. Version 3.3rc0 ==== Version 3.3rc0 is 3.3d56 Version 3.3d56 to Version 3.3d40 ==== **New Features** * Two new external program/script hooks – `run_this_before_entering_active_state` and `run_this_after_exiting_active_state` are provided for when the system goes active or inactive. Background: Many users use the `run_this_before_play_begins` program hook to turn on an amplifier and the `run_this_after_play_ends` hook to turn it off. A big problem is when another play session starts immediately after a play session ends, causing the amplifier to be switched off and then on again very quickly. This happens, for example, when a YouTube clip ends and the next one begins. To get around this, the concept of an *active state* covering a sequence of play sessions is introduced. When a play session starts, the system goes active, i.e. it enters the active state. When the play session ends, the system remains active for a period determined by the `active_state_timeout` setting, 10 seconds by default. If another play session starts before the period elapses, the system stays active; otherwise the system goes inactive -- it leaves the active state. The two new hooks mentioned above can be used to execute programs/scripts when the system goes active or inactive. * A new `alsa`-only `disable_standby_mode` setting, for controlling the Disable Standby feature, can be set to `always`, `while_active` or `never`. The `always` setting is recommended for systems where the output device is dedicated to Shairport Sync. The "Disable Standby" state iself can be set or cleared via the D-Bus interface `DisableStandby` property. * A new command-line option, `-u`, directs logging to STDERR rather than the system log. Useful when you compile Shairport Sync without `libdaemon` using the `--without-libdaemon` configuration option. **Enhancements** * Changes to the Jack Audio back end. The back end for Jack Audio, `audio_jack.c`, has been extensively rewritten by [Jörn Nettingsmeier](https://github.com/nettings) in a way that is more in keeping with the Jack Audio style. It uses native Jack Audio lockless buffers and offers autoconnect facilities that the previous version didn't have. Many thanks to him. * The volume-control software has been completely rewritten. From a user's point of view, the result should be a much smoother response to volume control changes, free from artefacts. It is now also possible to combine the hardware mixer and the software attenuator in two ways -- giving priority to the software mixer or giving priority to the hardware mixer. see the new `volume_range_combined_hardware_priority` setting in the `general` section opf the configuration file. * The muting/unmuting code has been rewritten to be simpler and more consistent. * In the `alsa` backend, new `play()` and `delay()` functions minimise the use of `snd_pcm_recover()` to prevent unnecessary resets of the output DACs. * In the `alsa` backend driver, hardware isn't accessed until the first time it is needed. That is, when Shairport Sync starts up, it no longer needs to access the device momentarily. Instead, it waits for the first use. * The `libdaemon` library is now an optional build. It is not necessary for `systemd` systems and can be omitted. Use the `--without-libdaemon` configuration option to leave it out. **Bug Fixes** * The `mdns-external` method used to advertise the Shairport Sync AirPlay service on ZeroConf is now an optional build and is omitted by default. Previously it was included with `--with-avahi` and could not be included on its own. * A number of memory leaks associated with the use of OpenSSL have been fixed. * Use CLOCK_RUNTIME in place of CLOCK_MONOTONIC when doing synchronisation timing using the alsa library prior to 1.0.28. Necessary for compabibility with OpenWRT Barrier Breaker. Version 3.3d39 to Version 3.3d38 ==== **New Feature** A new feature called *Disable Standby* keeps the output DAC in the play state all the time and helps to remove some annoying clicking / popping noises. It is really pretty impressive, especially combined with fixes to the dithering code described below. If you can enable 24- or 32-bit audio output to your output device, you can get even better results. This is an ALSA-specific attempt to remove the annoying low-level clicking sounds that some output devices make just when they start processing audio and sometimes when they stop. Typically a faint click might be heard just before a play session starts or just before audio resumes after a pause. Similarly, a faint click can sometimes be heard just after a play session ends. It is extremely difficult to remove these clicks completely from the hardware, so this new feature ensures that the output device avoids situations where these clicks might be generated by *always* playing audio. To accomplish this, if Shairport Sync isn't actually playing anything, audio frames consisting of silence are sent to the output device, keeping it playing. Apart from the initial startup transition, the output device never stops playing and thus never transitions to and from standby mode, avoiding the possibility of generating associated audio disturbances. To enable this feature, a new `alsa` group setting with the name `disable_standby_mode` is available. (If you do a full `$ sudo make install`, a new sample configuration file with this setting in it is installed at `/etc/shairport-sync.conf.sample` or `/usr/local/etc/shairport-sync.conf.sample`.) A downside to this feature is that the output device totally dedicated to Shairport Sync. For this reason, this new feature is disabled by default. Note -- this setting is likely to change. It will probably be necessary to modify it somehow to enable it to be used in integrated systems. Your feedback would be welcome. **Enhancements and Bug Fixes** * At present, Shairport Sync adds dither to the audio (a) if the built-in software-based volume control is used, (b) if the audio is mixed to mono or (3) if there is a reduction in sample size, say from 16- to 8-bit. The code for generating dither has been much improved. Due to a poor pseudo-random number arrangement, the dither noise didn't sound like white noise -- now it does. In addition, if dither is to be added, it is also added to the silence inserted just prior to the start of play, and is also added to the silent frames used to prevent the output device from going into standby mode, if selected. Version 3.3d37 to Version 3.3d22 ==== These updates are about stability. **Enhancements and Bug Fixes** With great help from [gibman](https://github.com/gibman) — see [#772](https://github.com/mikebrady/shairport-sync/issues/772) for the gory details — a myriad of issues have been identified and fixed. In particular, [gibman](https://github.com/gibman) shared an automated way of stress-testing Shairport Sync, and this has resulted in the detection of many bugs. And so, with apologies to Shakespeare, we have taken up arms against a sea of troubles, and by opposing we have ended them. It is hoped that the result is considerably more stable and can better withstand the, uh, slings and arrows of outrageous fortune. Here is a flavour of some of the issues addressed: * Replace the existing watchdog, which only offered partial coverage, with a much more robust thread-based watchdog. * Allow a reported remote processing time of zero. * Fix a logical error that could cause an endless loop during a flush. * Ensure a player thread is correctly initialised before allowing it to be cancelled cleanly. * Ensure the player thread always has a cancellation point so that it should always be possible to ask it to terminate. * If a play session is interrupted, wait for it to terminate for up to three seconds. * If a play session is interrupted, ensure the new session uses a different set of UDP ports. This is to ensure that data from the interrupted session – which might be still in transit – doesn't enter the new session. * Make all ALSA command sequences un-cancellable. This is to ensure that ALSA subsystem will not be left in a partially-initialised state if Shairport Sync terminates abruptly. * When a connection is terminated abruptly, ensure that all the UDP ports is use are closed properly. * Impose timeouts on both reading and writing to the supervisory RTSP connection governing a session. * When closing the RTSP connection due to an error, close it immediately, without waiting for a full TCP handshake, because, if the other end has erred, the handshake may never come. * Fix a parameter initialisation error in a situation where there is no hardware mixer. * Fix an MQTT-related crash by ignoring unrecognised commands. * Fix a compilation error and a warning when using the `--with-convolution` configuration option. **New Feature** * A new `run_this_if_an_unfixable_error_is_detected` (in the `sessioncontrol` group of settings) program hook is provided. At the moment, two conditions can trigger this. The first is if the watchdog is unable to terminate a play session. The second is if the output device stalls for a long period. Both conditions can be caused by malfunctioning DACs. The external program could, for example, reboot the device. Version 3.3d21 ==== **Enhancements** * Use `/dev/urandom` rather than `/dev/random` as a source of some kind of randomness for the cryptographic "nonce" used in AirPlay password exchange, as `/dev/random` blocks occasionally. Please see [here](https://unix.stackexchange.com/questions/324209/when-to-use-dev-random-vs-dev-urandom) for a discussion of the merits of both. The effect of `/dev/random`'s blocking on Shairport Sync was to make the source of randomness somewhat less random. (By the way, you should never use an important password as an AirPlay password for Shairport Sync -- it is stored in Shairport Sync's configuration file in plain text.) Version 3.3d20 ==== **Enhancements** * The code that deals with packet loss resulting from network problems has been completely rewritten. The reason is that, while the old code worked quite well, it could be overwhelmed if the network problems were very serious. The new code is simpler and more robust in testing so far. This code interacts with the code for flushing audio before and after a play session, so it may have introduced regressions. * The build instructions have been changed to avoid compiler warnings coming from automatically-generated code produced for the D-Bus-based interfaces. * Warnings are now logged if the ALSA subsystem fails to recover properly after an error has been cleared. **Bug Fix** * A compilation problem in OpenBSD has been fixed by changing the order of some include files. Version 3.3d16 ==== **Enhancement** * Extend the range of `audio_backend_latency_offset_in_seconds` to ± 1.75 seconds. Note that no sanity checking of any kind is done on this – if it is too large the program may simply crash. * Pay more attention to errors that may occur when asking for the DAC delay just before play starts. For diagnostic use. * Formatting of the settings file `shairport-sync.conf` has been fixed, thanks to the work of [roblan](https://github.com/roblan). Version 3.3d15 ==== **Enhancement** * Adjust the latency calculation to accommodate changes in iOS 12 and AirPlay connections from macOS Mojave. Thanks to [artenverho](https://github.com/artenverho) who first reported the issue. Version 3.3d14 ==== **Bug Fix** * Fix a problem when calling the program to be run when the volume control is changed. Thanks to [shaven](https://github.com/shaven) for the report. Version 3.3d13 ==== Reverted to 3.3d11 -- the modification in 3.3d12 was not needed and has been removed. Version 3.3d11 ==== **Enhancement** * Add a configuration option to specify the PulseAudio output sink. An extra option for the `pa` backend to allow the specification of the audio sink. Thanks to [Maciej Wilczyński](https://github.com/mLupine) for his work on this. **Bug Fix** * Remove unrecognised options from FreeBSD and OpenBSD compilation instructions. Version 3.3d10 ==== Modify the `jack` interface to ignore the latencies of any ports connected to the `jack` end. This is because it does not seem appropriate to try to compensate for the delays in the `jack` system. Not sure if this is the correct approach... Maybe it's better to allow the user to select no compensation, compensate for the lowest latency or compensate for the highest latency; it seems unnecessarily complex, not really the business of Shairport Sync. Version 3.3d9 ==== Many changes to compilation and linking flags. Stop using `HAVE_*` flags except where necessary, use `CONFIG_*` for optional stuff, use `HAS_*` for immediate definitions to be used during configuration, use `USE_*` for Automake definitions. Probably introduced bugs, sigh. Version 3.3d8 ==== **Bug Fix** * Ensure the compiler flag `HAVE_LIBSOXR` is defined if the `--with-soxr` configuration flag is used and `pkg-config` is in use. Version 3.3d7 ==== * Remove the "rolling" requirement for Jack output to be sent. * Set the default buffer size for Jack to 0.5 seconds. This may be temporary! Version 3.3d6 ==== An improved [Jack Audio](http://jackaudio.org) backend. Testing notes: * At the `./configure` step, include `--with-jack`. This should not require any extra packages or libraries when it is being compiled on an AVLinux machine. No need for any other backend to be included, so you can omit `--with-alsa`, etc. * Tested on the latest AVLinux only. * Jack Audio will not run correctly on a virtual machine; it will only work properly on a real device. * A new set of configuration options is present in the configuration file. * The Shairport Sync backend will attempt, every second, to open a client on the Jack server until it succeeds. This behaviour can be stopped or the interval extended with the `jack` `auto_client_open_interval` configuration option. * Once a Jack client has been opened by the Shairport Sync backend, it will remain open. This behaviour can be changed with the `jack` `auto_client_disconnect` configuration option. * Other Jack congfiguration options include the ability to change the name of the client – `client_name` – and the names of the channels – `left_channel_name` and `right_channel_name`. Testing needed -- these arrangements may not conform to the norms of the Jack community, so all feedback gratefully received. Some information, e.g. the true output rate, not implemented yet. Version 3.3d5 ==== * Introducing a very rough implementation of a Jack Audio backend. The JACK Audio Connection Kit "provides a basic infrastructure for audio applications to communicate with each other and with audio hardware. Through JACK, users are enabled to build powerful systems for signal processing and music production." Version 3.3d4 ==== * Sometimes `libsoxr` is built to rely on `libavutil`. With the present changes to `configure.ac`, if `libavutil` is present, link to it when linking to `libsoxr`, but if it's not present, don't link to it when linking to `libsoxr`. * Add `pgk-config` support to `libsoxr` selection. Thanks to [Jörg Krause](https://github.com/joerg-krause) for identifying these issues and proposing fixes. Version 3.3d3 ==== * Modify the code that synchronises the Shairport Sync system's clock with the source clock to try to take account of the sources's nominal rate, which (oddly, e.g. iTunes on a Mac) might not be exactly 44,100 fps. There may be a 32-bit unsigned overflow error here somewhere! * Try to interpolate for the measured drift between the standard three-second timing snapshots. These changes make a very slight difference from time to time, of the order of microseconds, and it's not clear yet how reliable the drift interpolation is. * Add some extra fields to the `statistics` output, including nominal source rate, actual input rate, actual output rate, source clock drift, calculated correction needed in ppm. All these numbers agree to a high degree, but the generation of them is fragile and susceptible to errors when there are problems like underrun, and they are not actually running averages, which would be genuinely useful. But they show promise! **Bug Fixes** * Fix a bug in the `dbus` native interface which would silently switch `soxr` interpolation to `basic`. * Fix a mutex lock bug in the metadata hub. No known effects. Version 3.3d1 ==== Internal changes are being made for version 3.3 to avoid using `SIGUSR1` and `pthread_kill` to stop threads; the standard `pthread_cancel` and friends are being used instead. This should lead to more reliable and orderly cancellation of sessions and threads. However, it is quite a complex change, so bugs may have been introduced or reactivated. Lots of testing needed. **Bug Fix** * Fix an arithmetic overflow in frame rate calculations that could occur after 2^32 frames – approximately 27 hours at 44,100 frames per second. Version 3.3d0 ==== **New Features** * Frame rates! Exact input and output frame rates are now included in the `statistics` output. The figures generated are averaged over the entire play session since the last pause/resume, if any, so they should settle down and become more accurate over a long play session, say a couple of hours. Timing is relative to `CLOCK_MONOTONIC`. When your system is connected for an appreciable period to network time, e.g. using an NTP client, `CLOCK_MONOTONIC` is adjusted ("conditioned") to keep time extremely accurately. The calculated output frame rate should be very accurate. The calculated input frame rate will vary considerably over short intervals due to network conditions, but over a long play session it should also become very accurate. Timing is done from the start of the play session, or from the resumption of play following a pause. Note that while some audio sources pause and resume between tracks, both iTunes on the Mac and the Music app on iOS play all the tracks on a playlist without pause (so long as the tracks are downloaded and present in the device in time). * Add the command `quit` to the MPRIS and the D-Bus interfaces. The main motivation for this is that it makes it easier to search for memory leaks. **Bug Fixes** * A number of memory leaks have been identified and removed. * A bogus warning about using the deprecated `general` `statistics` options has been fixed. Version 3.2d67 ==== This is equivalent to 3.2.1. **Bug Fix** * Fix a bug causing a crash when `soxr` interpolation was enabled and a play session was stopped. This bug overwrote incorrect memory locations, so depending on what it overwrote, may have been responsible for other inexplicable crashes. Thanks are due to [hanaguro](https://github.com/hanaguro), [FnasBas](https://github.com/FnasBas), [priitohlo](https://github.com/priitohlo), [David Krmpotić](https://github.com/davidhq) and [artenverho](https://github.com/artenverho). Version 3.2.d66 ==== This is equivalent to 3.2. Version 3.2.d65 ==== **Modification** * The algorithm for generating resend requests has been made somewhat more gentle -- a little less insistent. **Bug Chasing** * Some very elementary bounds checking on the ANNOUNCE packet is performed: that it is 1024 bytes or less in size and that line lengths remaining after parsing do not turn negative when they should remain positive or be exactly zero. Version 3.2.d64 ==== **Enhancement** * An extra property has been added to the RemoteControl section of the native Shairport Sync D-Bus interface. It is the "progress" metadata emitted from time to time by the AirPlay source and consisting of RTP timestamps for the start of the current play sequence, the current play point and the end of the play sequence. **Bug Fix** * Code to monitor the amount of time a mutex lock request took is improved. Version 3.2.d63 ==== **Enhancement** * An [MQTT](https://en.wikipedia.org/wiki/MQTT) client interface is introduced, with support for metadata and for some remote control commands, thanks to the work of [Till Zimmermann](https://github.com/tillz). MQTT is a fairly often used protocol in FOSS home-automation projects (as well as in commercial ones), and as Shairport Sync is often used in these setups, this adds client support for this protocol. Version 3.2d62 ==== **Bug Fix** * Restore compatibility with Synology AudioStation/5.2. Thanks to [Jörg Krause](https://github.com/joerg-krause) for identifying both the issue itself and the likely location of the fix needed. It's not clear if the problem lies with Shairport Sync or Synology – the fix was to ensure that an RTSP reply was sent in one `SEND` call, which shouldn't be important. Version 3.2d61 ==== **Bug Fix** * Add a pthread_cancel cleanup routine to put_packet to unlock the player rw mutex when cancelled. Sincere thanks to [David Krmpotić](https://github.com/davidhq) for help investigating this. Version 3.2d57, 3.2d58, 3.2d59, 3.2d60 ==== **Bug Chasing** * Debug messaging has been enhanced when a `TEARDOWN` message is received. * Check both timed and untimed mutex locks and give estimates of how long to wait. Generate debug messages when appropriate. * Unlock the `ab_mutex` when sending a resend request. Version 3.2d56 ==== **Enhancement** * The `mute_using_playback_switch` setting in the `alsa` group has been replaced by a `use_hardware_mute_if_available`, which defaults to `"no"`. This new setting controls both the playback switch method and the magic volume level method for doing hardware-supported muting. If hardware muting is used, the output device will be muted when Shairport Sync releases it, potentially causing problems for other audio programs using the device. To avoid this, `use_hardware_mute_if_available` is disabled by default. **Bug Chasing** * A debug message has been enhanced when a `TEARDOWN` message is received. Version 3.2d55 ==== **Bug Fix** * Flush requests that are received while the player is being initialised or deleted are now ignored. This should prevents two potential (but never seen) lock possibilities. Version 3.2d54 ==== **Bug Fix** * Prevent packets of audio being added when the play session has ended and the player is being deleted. They are now simply dropped. Version 3.2d53 ==== **Bug Fix** * Fix an incompatibility with Cygwin 64. It seems that the handling of signals in Cygwin is different to regular "native" Unix/Linux platforms. So, this is an attempt to use `pthread_cancel` calls where possible. In principle it should simplify thread management considerably, so let's see how it goes. * Fix an off-by-one error that was generating excessive resend requests. Version 3.2d51 ==== * Fix a small bug locking and unlocking the read-write mutex. It might (and in principle, it could) cause a crash. Version 3.2d50 ==== * Add a read-write mutex lock to the player thread so that it can't be accessed while it's being created and initialised or while it's being torn down and destroyed. Make external accessor functions acquire a read lock for access. It's "A Good Thing" and it might help the seg fault problem, which I'm afraid still can't reproduce... Version 3.2d49 ==== * A few extra debugging messages to try to locate where a segfault is occurring. Version 3.2d48 ==== **Bug Fix** * A seg fault possibly caused by a dangling pointer has been addressed by making the UDP sockets blocking rather than non-blocking. A two millisecond limit has been put on the sendto calls. Version 3.2d47 ==== **Bug Fix** * A very subtle bug that would occasionally cause a loud 80 millisecond buzz when a new track was selected has been located and fixed. Thanks to [mistipen](https://github.com/mistepien) and [artenverho](https://github.com/artenverho) for help with this. Version 3.2d46 ==== Update [TROUBLESHOOTING.md](https://github.com/mikebrady/shairport-sync/blob/development/TROUBLESHOOTING.md) to correspond to 3.2RC6. Version 3.2d45 ==== **Enhancement** * Restore the old method for calculating latency for older AirPlay sources: an AirPlay source displaying an AirPlay User Agent string version of 353 or older -- corresponding to iOS 11.1.2 or older -- will add an extra 0.25 seconds to the latency requested. This seems to be right. Version 3.2d44 ==== **Bug Fixes** * When errors occur sending resend requests, back off for 0.5 seconds, rather than 10 seconds, and make the code actually work. * Make the configuration options for including the dbus interface and the mpris interface be `--with-dbus-interface` and `--with-mpris-interface` as expected, not `--with-dbus` and `--with-mpris` as they actually were. Version 3.2d42 ==== This version just brings some small changes made to the Release Candidates back into the `development` branch. Version 3.2d41 ==== **Bug Fixes** * Fixed a hitherto-silent bug that prevented Shairport Sync working properly with AirAudio. According to the [unofficial standard](https://nto.github.io/AirPlay.html), requests for resending missing packets come from the control port; however, up until now, Shairport Sync sent them on the audio port. All AirPlay sources responded to these improperly-delivered requests except AirAudio, which discards requests that do not come from the correct source. Fixed now, with many thanks to [funtax](https://github.com/funtax) and to [Janusz Kowalczyk](https://github.com/kowalcj0) for bringing the issue to the fore. Version 3.2d40 ==== **Bug Fixes** * A number of serious and long-standing bugs have been identified and fixed in the threads that handle audio, control and timing packets. Specifically, if UDP reception or transmission errors occurred (a rare occurrence on a good network, but possible on noisy or congested networks), the threads would quit. In this way, an error on the reception of the first control packet could mute an entire play session. **Enhancements** * The code used to request the retransmission of missing audio packets has been significantly improved. Version 3.2d39 ==== **Enhancements** * An extra diagnostic to artificially drop UDP packets to simulate a noisy network has been added. Set the proportion of packets to be dropped in the `diagnostics` section of the configuration file using the tag `drop_this_fraction_of_audio_packets`. The value should be between 0.0 and 1.0. E.g. a value of 0.001 would mean one packet in a thousand would be dropped, on average. Look in the sample configuration file `/etc/shairport-sync.conf.sample` for the added entry. * Minimal compatibility with AirAudio has been added / restored. There remains a question about error correction for handling UDP packet loss. Thanks to [Janusz Kowalczyk](https://github.com/kowalcj0) for reporting the issues. Version 3.2d35 ==== **Enhancements** * More cleaning up of the D-Bus and MPRIS interface messages -- they are quieter now. **Bug Fix** * Thanks are due to [yejun](https://github.com/yejun) for noticing and proposing a fix for the bug that dithering is left on when the volume control is ignored. Audio samples should pass through without alteration. (The fix was already in the `development` branch though.) Version 3.2d34 ==== **Enhancements** * Better compatibility with TuneBlade -- Shairport Sync honours the latency settings properly now. * Big cleanup of D-Bus and MPRIS interface messages -- it's a lot less noisy. More to be done here. * The brokey YouTube iOS app, which generates a great deal of invalid metadata (do they even know?), is handled a bit better. If valid metadata is there, Shairport Sync can process it. * `clip` and `svip` messages are now only emitted for a play connection, not for all connections (e.g. connections that just enquire if the service is present). * `pfls` and `prsm` messages are less frequent, especially when a play session starts. **Other Developments** * Shairport Sync now uses about an extra half megabyte of RAM for compatibility with TuneBlade's option to have a very long latency -- up to five seconds. Version 3.2d33 ==== A new metadata token -- `'pffr'` -- is emitted when the First Frame of a play session has been Received. Not sure we'll keep it... Version 3.2d30 ==== **Enhancements** * A "native" D-Bus Remote Control permits remote control of the current AirPlay or iTunes client. It includes status information about whether the remote control connection is viable or not, i.e. whether it can still be used to control the client. A remote control connection to the audio client becomes valid when the client starts AirPlaying to Shairport Sync. The connections remains valid until the audio source deselects Shairport Sync for AirPlay, or until the client disappears, or until another client starts AirPlaying to Shairport Sync. It is likely that a time limit will be put on this, so that after, say, 30 minutes of inactivity, the remote control connection will be dropped. Version 3.2d29 ==== **Enhancements** * CAR INSTALL and OPENBSD notes added. * A barebones "native" D-Bus interface for Shairport Sync permitting control of some diagnostic settings. To be expanded... * A partly implemented MPRIS control interface including play/pause/next/previous/volume and some metadata. * Remote control of an iTunes source including play/pause/next/previous/volume. * Remote control of an AirPlay source including play/pause/next/previous. Version 3.2d28 ==== Continuing the experiments with D-Bus and related DACP support. In this revision, an attempt is made to control the amount of scanning the system does to maintain up-to-date information about a DACP source. As before, please note that the implementation is likely to change greatly or be removed at any time. **Enhancements** * Barebones support added for OpenBSD compilation. * Only ask for missing packets to be resent once, and if any error occurs making the request, stop for 10 seconds. * Include the `-pthread` flag -- including the pthread library with `-lpthread` isn't always enough. Version 3.2d26 ==== **Enhancements** * Improvements in the documentation relating to scripts -- thanks to [Niklas Janz](https://github.com/Alphakilo). * Add optional timing annotations to debug messages -- see the new settings in the diagnostic stanza of the configuration file. **Bug Fixes** * Ensure the TEARDOWN of a play session is not delayed by a long sleep timer. * Allow more than one ANNOUNCE packet for the same play session. Honour the settings in the most recent one. * Move the creation and calling of a player thread from the SETUP handler to the RECORD handler. * When closing an ALSA sound device, don't wait for any remaining audio to be output with `snd_pcm_drain`; instead, just drop all remaining frame using `snd_pcm_drop`. * TEARDOWN should complete in less than 50 ms. Version 3.2d25 ==== **Enhancement** * Better handling of missing timing packets. * Improved resnchronisation logic should improve performance with slow-to-download YouTube videos. * Shairport Sync will now log an unexpectedy dropped or faulty RTSP connection. This might be useful on noisy networks. Version 3.2d24 ==== **New Feature** * A new `general` option `volume_control_profile`, for advanced use only, with two options: `"standard"` which uses the standard volume control profile -- this has a higher transfer profile at low volumes and a lower transfer profile at high volumes -- or `"flat"` which uses a uniform transfer profile to linearly scale the output mixer's dB according to the AirPlay volume. Version 3.2d23 ==== Continuing the experiments with D-Bus and related DACP support. **Enhancement** * Some DACs have a feature that the lowest permissible "attenuation" value that the built-in hardware mixer can be set to is not an attenuation value at all – it is in fact a command to mute the output completely. Shairport Sync has always checked for this feature, basically in order to ignore it when getting the true range of attenuation values offered by the mixer. However, with this enhancement, Shairport Sync can actually use this feature to mute the output where appropriate. Version 3.2d22 ==== Continuing the experiments with D-Bus and related DACP support. **Bug Fix** * Fix timing error when using Airfoil as a source. Version 3.2d21 ==== Continuing the experiments with D-Bus and related DACP support. In this revision, [tinyhttp](https://github.com/mendsley/tinyhttp) is now used for sending and retrieving DACP information. Many thanks to [Matthew Endsley](https://github.com/mendsley) for this work on tinyhttp. As before, please note that the implementation is likely to change greatly or be removed at any time. Version 3.2d20 ==== **Bug Fix** * Fix silly seg-fault bug in 3.2d19, activated when a DACP record was withdrawn. Version 3.2d19 ==== **Enhancement** * Add compatibility with [Swinsian](https://swinsian.com), a Mac music player. Version 3.2d18 ==== **Bug Fix** * In recent versions of iOS (11.2) and mac OS (10.13.2), when play is resumed after a pause, the volume level is not always restored, and, if software volume control is being used, Shairport Sync plays at full volume. This issue has been addressed by storing the last airplay volume setting when a play session ends and using it as a default when a new play session begins. (This is a more generalised solution than in 3.2d16.) * Better AirPlay synchronisation. Older versions of Shairport Sync added an 11,025 frame (0.25 seconds) offset to all the latencies agreed with the sender. This seems now only to be correct for iTunes and ForkedDaapd sources, but incorrect for AirPlay sources. Accordingly, the offset is only added for iTunes and ForkedDaapd. The result is better sync with videos, e.g, YouTube, etc. while iTunes and ForkedDaapd synchronisation is unaffected. Version 3.2d16 ==== **Bug Fix** * In recent versions of iOS (11.2) and mac OS (10.13.2), when play is resumed after a pause, the volume level is not always restored, and, if software volume control is being used, Shairport Sync plays at full volume. This issue has been addressed by storing the last software volume setting when a play session ends and using it as a default when a new play session begins. Version 3.2d15 ==== **Bug Fix, kind of...** * Shairport Sync crashes on Arch Linux with with pulseaudio backend enabled. The cause appears to be a pulseaudio configuration issue, but of course, Shairport Sync shouldn't crash. For the present, the bug fix merely adds an error message before terminating Shairport Sync. **Enhancements** * Still lots of changes and experiments with D-Bus and DACP. As before, please note that the implementation is likely to change greatly or to be removed at any time. Version 3.2d13 ==== **Security Update** The version of `tinysvcmdns` bundled in Shairport Sync has a buffer overflow bug: *"An exploitable heap overflow vulnerability exists in the tinysvcmdns library version 2016-07-18. A specially crafted packet can make the library overwrite an arbitrary amount of data on the heap with attacker controlled values. An attacker needs send a dns packet to trigger this vulnerability."* The vulnerability is addressed by additional checking on packet sizes. See also [CVE-2017-12087](https://bugs.launchpad.net/bugs/cve/2017-12087) and [Vulnerability in tinysvcmdns](https://bugs.launchpad.net/ubuntu/+source/shairport-sync/+bug/1729668). Thanks and [Chris Boot](https://github.com/bootc) for fixing this bug. Version 3.2d12 ==== Experimenting with an [MPRIS](https://specifications.freedesktop.org/mpris-spec/latest/)-compatible D-Bus interface. A very small number of features have a tentative implementation. As with the Shairport Sync D-Bus interface, please note that the implementation is likely to change greatly or be removed at any time. Continuing the experiments with D-Bus support, Shairport Sync can now be compiled to have a D-Bus presence on the D-Bus system bus. It presents a small number of properties and can execute a method call which sends a command string to the audio source's DACP port. As before, please note that the implementation is likely to change greatly or be removed at any time. **Enhancement** * The metadata output stream can include a `dapo` message carrying the DACP port number to be used when communicating with the DACP remote control. This might be useful because the port number is actually pretty hard to find and requires the use of asynchronous mdns operations. You must be using the Avahi mdns back end. **Bug Fix** * A bug in the hardware volume control affects output devices that have hardware mixers but that do not allow the volume to be set in dB. One example is the Softvol plugin in ALSA. Shairport Sync fails silently when presented with such a device when hardware volume control is enabled: the volume events have no effect. The bug has been fixed by adding two missing lines of code to the `init()` function in `audio_alsa.c`. Thanks to [Jakub Nabaglo](https://github.com/nbgl) for finding and fixing the bug. * A number of bug fixes due to [belboj](https://github.com/belboj). Many thanks for these! * Enhancements to the handling of quit requests by threads, thanks(again) to [belboj](https://github.com/belboj)! **Other Stuff** * The directory structure has been rearranged somewhat. Probably will change again... * Typo fix! Thanks to [corbinsantin](https://github.com/corbinsantin). Version 3.2d8 ==== **Bug Fix** * Fixed a bug that prevented Shairport Sync from starting automatically on systems using the System V startup system (e.g. Ubuntu 14.04). The problem was that the directory to be used – `/var/run/shairport-sync/` – was deleted on power down and needed to be recreated on startup. In it's absence, Shairport Sync would not start and would report a mysterious daemon error \#2. Version 3.2d7 ==== This introduces a very experimental [D-Bus](https://en.wikipedia.org/wiki/D-Bus) interface to Shairport Sync. At present, in a very ad-hoc trial arrangement, Shairport Sync provides a system bus D-Bus service enabling a program to get and set Volume, to enable and disable the Loundness Filter and to get and set the Loundness Filter threshold (remember, BTW, the Loudness filter only works with software-based volume control). The implementation is likely to change greatly or be removed at any time. Tested on Ubuntu 16.04 and on Raspbian Stretch. Two extra configuration options are provided: `--with-dbus` and `--with-dbus-test-client`. (BTW, the test client is never installed, merely compiled.) Version 3.1.2 ==== Shairport Sync is more stable playing audio from YouTube and SoundCloud on the Mac. **Pesky Changes You Should Not Ignore** * When you update from a previous version of Shairport Sync, your output device may have been left in a muted state. You should use a command line tool like `alsamixer` or `amixer` to unmute the output device before further use. **Change of Default** * The default value for the `alsa` setting `mute_using_playback_switch` has been changed to `"no"` for compatibility with other audio players on the same machine. The reason is that when this setting is set to `"yes"`, the output device will be muted when Shairport Sync releases it. Unfortunately, other audio players using the output device expect it to be unmuted, causing problems. Thanks to [Tim Curtis](https://github.com/moodeaudio) at [Moode Audio](http://moodeaudio.org) and [Peter Pablo](https://github.com/PeterPablo) for clarifying the issue. **Bug Fixes** * Fixed bugs that made Shairport Sync drop out or become unavailable when playing YouTube videos, SoundCloud streams etc. from the Mac. Background: there has been a persistent problem with Shairport Sync becoming unavailable after playing, say, a YouTube clip in a browser on the Mac. Shairport Sync 3.1.2 incorporates a change to how certain AirPlay messages are handled. Introduced in nascent form in 3.1.1, further follow-on changes have improved the handling of player lock and have simplified and improved the handling of unexpected loss of connection. Shairport Sync also now works properly with SoundCloud clips played in a browser on the Mac. * Using [infer](https://github.com/facebook/infer/blob/master/README.md), a number of silent issues have been detected, such as not checking some calls to `malloc` to ensure the response is not NULL. Most of these have been addressed by additional checks. Version 3.1.1 ==== **Bug Fixes** * A bug in the `sndio` backend has been fixed that caused problems on some versions of Linux. * A change has been made to how Shairport Sync responds to a `TEARDOWN` request, which should make it respond better to sequences of rapid termination and restarting of play sessions. This can happen, for example, playing YouTube videos in Safari or Chrome on a Mac. * Choosing `soxr` interpolation in the configuration file will now cause Shairport Sync to terminate with a message if Shairport Sync has not been compiled with SoX support. * Other small changes. Version 3.1 ==== Version 3.1 brings two new backends, optional loudness and convolution filters, improvements in non-synchronised backends, enhancements, stability improvements and bug fixes. **New Features** * A `sndio` backend gives Shairport Sync native fully synchronised output on OpenBSD and FreeBSD, thanks to the work of [Tobias Kortkamp (t6)](https://github.com/t6). * A `pa` backend now allows Shairport Sync to provide synchronised output on PulseAudio-equipped systems -- many desktop Linuxes use PulseAudio as their sound manager. * Optional loudness and convolution filters can be incorporated in the audio processing chain, thanks to the fantastic work of [yannpom](https://github.com/yannpom). * A volume-change program hook `run_this_when_volume_is_set` has been added to the `general` settings stanza to execute an application whenever the volume is changed. **Pesky Changes You Should Know About** * The `audio_backend_buffer_desired_length_in_seconds` and `audio_backend_latency_offset_in_seconds` settings have been moved from individual backend stanzas to the `general` stanza. They now have an effect on every type of backend. * If you are using a System V (aka `systemv`) installation, please note that the default location for PID file has moved -- it is now stored at `/var/run/shairport-sync/shairport-sync.pid`. This change is needed to improve security a little and to improve compatibility across platforms. If you're not doing anything strange, this should make no difference. **Enhancements** * Resynchronisation, which happens when the synchronisation is incorrect by more than 50 ms by default, should be a lot less intrusive when it occurs – it should now either insert silence or skip frames, as appropriate. * The Linux installer has been improved and simplified and a FreeBSD installer introduced. * A new setting, `audio_backend_silent_lead_in_time`, allows you to set the duration of the period of silence played (the "silent lead-in") before a play session starts. * A new command-line option, `--logOutputLevel`, allows you to output the volume levels to the log whenever they are changed. This may be useful during setup. * Improvements have been made to the handling of large items of metadata over UDP. * A new command line option, `-j`, demonizes Shairport Sync without creating a PID file. * A new `alsa`-only setting, `mute_using_playback_switch`, is available for advanced use. * Other minor enhancements. **Bug Fixes** * Stability improvements. More care has been taken (!) to make code thread-safe, resulting in improved stability. * Conversion from stereo to mono has been fixed to avoid clipping while preserving full resolution. Thanks to [Robert Jones (RobDeBagel)](https://github.com/RobDeBagel) for bringing this to notice. * Short intrusions of audio at the start of a new session from the end of the previous session have been eliminated. * Many (many!) miscellaneous bugs fixed. Version 3.0.2 ==== **Bug Fixes** * Fixed bugs in the `ao`, `pulseaudio` and `sndio` back ends. Basically they were expecting default sample rate and depth information, and were terminating when they saw explicit rate and depth data. Version 3.0.1 ==== This update fixes one alarming and potentially very noisy bug and restores the identification of Shairport Sync as "ShairportSync" so that TuneBlade recognises it as an open source application. **Bug Fixes** * Fixed a bug that was causing Shairport Sync to possibly make a very loud and alarming noise whenever an audio frame was missing. * In 2.8.6, a change was made to the way Shairport Sync identified itself, so that it could be recognised by TuneBlade as an open source application and treated preferentially. That change was inadventently lost in the transition from 2.8.6 to 3.0. Now it's restored. Version 3.0 ==== Big Update ---- Version 3 brings in support for 24-bit and 32-bit (and 8 bit!) DACs and for DACs running at multiples of 44,100 samples per second. The most obvious audible change is if you are using software volume control and can take advantage of 32- or 24-bit DACs. Dithering can now occur on a 32-bit or 24-bit sample rather than on a 16-bit sample, making the noise floor very much lower. This is the case, for example, with a Pimoroni PHAT DAC. Here is the list of new features: **New Features** * 8-bit, 16-bit, 24-bit, 24-bit three-byte (S24_3LE and S24_3BE) and 32-bit output to ALSA devices. * 44,100, 88,200, 176,400 and 352,800 sample per second output. This is done using simple upsampling. It's only worth doing if 44,100 samples per second output is not available. * Internal processing including software volume control and interpolation is done after sample size and rate conversion. * Apple ALAC decoder support. This needs the `libalac` library, available at [ALAC](https://github.com/mikebrady/alac), to be installed. Add the flag `--with-apple-alac` to the `./configure` arguments. Then you can choose the Apple ALAC decoder in the configuration file. * Support for `mbed TLS` has been added and the use of `PolarSSL` is deprecated, as `mbed TLS` is a development of `PolarSSL` and `PolarSSL` itself is not being developed further. * Choose Network Interface. Add a new setting, for advanced users only, in the `general` section. Use the `interface` setting to allow you to specify the interface on which to provide the AirPlay service. Omit the setting to get the default, which is to choose the interfaces automatically. * Set Max Volume. Add a new setting, for advanced users only, in the `general` section. Use the `volume_max_db` setting to allow you to specify the maximum level to set on the hardware mixer (if chosen) or the built-in software mixer otherwise. The software mixer's range is 0.0 dB to -96.1 dB. The setting must be a number with a decimal point, e.g. 21.3. * An experimental new back end for `libsoundio`, a C library for cross-platform real-time audio input and output. Many thanks to [Serg Podtynnyi](https://github.com/shtirlic). Please see https://github.com/mikebrady/shairport-sync/pull/433 for more details. Pesky Changes You Cannot Ignore ---- * Processor load is up by about 11%. * Settings have changed -- basically, any timings that were denominated in frames are now in seconds. Please refer to the shairport-sync.conf.sample file for details. * Sox-based interpolation at higher sample rates may overload your CPU -- you might have to choose between higher sample rates and sox-based interpolation. Version 3.0rc0 – Release Candidate 0 ---- Note: all Version 3 changes are summarized above. **New Feature** * An experimental new back end for `libsoundio`, a C library for cross-platform real-time audio input and output. Many thanks to [Serg Podtynnyi](https://github.com/shtirlic). Please see https://github.com/mikebrady/shairport-sync/pull/433 for more details. **Other changes** * Updates to `man` page and [README](https://github.com/mikebrady/shairport-sync/blob/development/README.md). Reports of typos or suggestions for improvement are welcome! Version 3.0d24 – Development Version ---- Note: all Version 3 changes are summarized above. **New Feature** * Set Max Volume. Add a new setting, for advanced users only, in the `general` section. Use the `volume_max_db` setting to allow you to specify the maximum level to set on the hardware mixer (if chosen) or the built-in software mixer otherwise. The software mixer's range is 0.0 dB to -96.1 dB. The setting must be a number with a decimal point, e.g. 21.3. Version 3.0d23 – Development Version ---- Note: all Version 3 changes are summarized above. **New Feature** * Choose Interface. Add a new setting, for advanced users only, in the `general` section. Use the `interface` setting to allow you to specify the interface on which to provide the AirPlay service. Omit the setting to get the default, which is to choose the interfaces automatically. Version 3.0d22 – Development Version ---- Note: all Version 3 changes are summarized above. **Bug Fix** * Fixed a bug which prevented successful building in the OpenWrt build system. The problem was caused by an `#include apple_alac.h` in `player.c` which was actioned even if the apple alac decoder was not selected. This caused the OpenWrt build system to expect the standard C++ library – required by the apple alac code – to be referenced, but it was not specified on the build manifest and therefore stopped the build. The solution was to make the `#include` conditional on selecting the apple alac decoder. Version 3.0d21 – Development Version ---- Note: all Version 3 changes are summarized above. **Bug Fix** * Fixed a bug which turned off resync by default. Duh. Version 3.0d20 – Development Version ---- Note: all Version 3 changes are summarized above. **Bug Fix** * Fix a small and generally silent error in configure.ac so that it only looks for the systemd directory if systemd has been chosen. It caused a warning when cross-compiling. Version 3.0d19 – Development Version ---- Note: all Version 3 changes are summarized above. **New Feature** * Reduces processor load back to V2.X levels by using a precalculated array of pseudorandom numbers to do dithering. Doesn't seem to make any audible difference. Version 3.0d18 – Development Version ---- Note: all Version 3 changes are summarized above. **New Features** * 8-bit, 16-bit, 24-bit, 24-bit three-byte (S24_3LE and S24_3BE) and 32-bit output to ALSA devices. (Other back ends are not updated yet.) * 44,100, 88,200, 176,400 and 352,800 sample per second output. This is done using simple upsampling. * Internal processing including software volume control and interpolation is done after sample size and rate conversion. * Apple ALAC decoder support. This needs the `libalac` library, available at [ALAC](https://github.com/mikebrady/alac). Add the flag `--with-apple-alac` to the `./configure` arguments. Then you can choose the Apple ALAC decoder in the configuration file. * Support for `mbed TLS` has been added and the use of `PolarSSL` is deprecated, as `mbed TLS` is a development of `PolarSSL` and `PolarSSL` itself is not being developed further. * Settings that were denominated in frames are now deprecated but still honoured. Deprecation warnings are issued. Pesky Changes You Cannot Ignore ==== * Settings have changed -- basically, any timings that were denominated in frames are now in seconds. Please refer to the shairport-sync.conf.sample file for details. * Sox-based interpolation at higher sample rates may overload your CPU -- yopu might have to choose between higher sample rates and sox-based interpolation. **Bugs** * Documentation is not updated. Version 2.8.6 – Stable Candidate ---- **Enhancements** * This release contains a small change – it identifies itself as a ShairportSync device rather than an AirPort device. This should make it possible for Tuneblade, and possibly other players, to recognise it correctly. Version 2.8.5 – Stable Version ---- This release includes bug fixes and minor enhancements and is recommended for all users. Note: if you're upgrading, there is a new `./configure` option: ==== The build process now uses the directory path `sysconfdir` to determine where to place the configuration file `shairport-sync.conf`. The default value for `sysconfdir` is `/usr/local/etc` which is used in the BSD family, whereas `/etc` is normally used in Linux. To retain the present behaviour of Shairport Sync, *you must add an extra parameter to the `./configure... ` command.* The parameter you must add is `--sysconfdir=/etc`. (This has been added to the sample configuration command line in README.md.) The enhancements and bug fixes in 2.8.5 were made in versions 2.8.4.1 to 2.8.4.8 inclusive. Please read below for the full list. Version 2.8.4.8 – Development Version ---- **Enhancements** * Add a new metadata item `clip` (for `CL`ient `IP`). This item is a string comprising the IP number of the "client", and is sent when a play session is starting. The "client" is the sender of the audio stream, e.g. iTunes on a Mac, or the Music player in iOS. * When synchronisation has been disabled on the ALSA device (you should only do this for testing), Shairport Sync now refrains from asking for buffer length information from the device. Version 2.8.4.7 – Development Version ---- * This update means the build process now uses the directory path `sysconfdir` to determine where to place the configuration file `shairport-sync.conf`. The default value for `sysconfdir` is `/usr/local/etc` which is used in the BSD family, whereas `/etc` is normally used in Linux. So, to retain the present behaviour of Shairport Sync, you must add an extra parameter to the `./configure... ` command. The parameter you must add is `--sysconfdir=/etc`. (This has been added to the sample configuration command line in README.md.) * Shairport Sync has been updated to use the value of `sysconfdir` to determine where to look for the configuration file. If `sysconfdir` has been left with its default value of `/usr/local/etc`, then Shairport Sync will look for `/usr/local/etc/shairport-sync.conf`. If, as recommended for Linux, `sysconfdir` has been set to `/etc`, then Shairport Sync will look, as before, for `/etc/shairport-sync.conf`. **Enhancement** * The version string output when you use the command-line option `-V` now includes the value of the `sysconfdir`, e.g. `2.8.4.7-OpenSSL-Avahi-ALSA-soxr-sysconfdir:/etc`. Version 2.8.4.6 – Development Version ---- **Enhancement** * Add a new `alsa` configuration setting: `use_mmap_if_available` to control the use of mmap. The default is `"yes"` -- see [#351](https://github.com/mikebrady/shairport-sync/issues/351). Version 2.8.4.5 – Development Version ---- **Enhancement** * Handle varying packet lengths -- this makes it compatible with the HTC Connect, HTCs AirPlay implementation. Thanks to [Jörg Krause](https://github.com/joerg-krause) for his detective work, and see [#338](https://github.com/mikebrady/shairport-sync/issues/338). Version 2.8.4.4 – Development Version ---- **Enhancement** * Use alsa direct access (mmap) feature to improve performance if mmap is supported. Thanks to [Yihui Xiong](https://github.com/xiongyihui). Version 2.8.4.3 – Development Version ---- **Bug Fix** * Set the RTSP socket to close on `exec()` of child processes; otherwise, background `run_this_before_play_begins` or `run_this_after_play_ends` commands that are sleeping prevent the daemon from being restarted because the listening RTSP port is still in use. Fixes [#329](https://github.com/mikebrady/shairport-sync/issues/329). Version 2.8.4.2 – Development Version ---- **Bug Fixes** * Fixed an issue where you could not compile the audio_pipe back end without enabling metadata support (thanks to [busa-projects](https://github.com/busa-projects) for reporting the issue). * Fixed a few small issues causing compiler warnings in `mdns_dns_sd.c`. **Other** * Removed the INSTALL file – it's generated automatically by `autoreconf -fi` anyway – added it to the files to be ignored in `.gitignore` and added a simple `INSTALL.md` file. Version 2.8.4.1 – Development Version ---- **Bug Fixes** * Fixed two issues when including support for `pulseaudio`. * Corrected two small errors in sample parameters for the UDP metadata stream settings, thanks to [rkam](https://github.com/rkam). Version 2.8.4 – Stable Version ---- The following is a summary of the bug fixes and enhancements since version 2.8.3. **Bug Fixes** * Checks have been added for empty or NULL audio buffers that were causing assertion violations and subsequent abnormal program termination. * An IPv6 bug has been fixed — a bug in the networking software would not allow an IPv6 link-local connection to be made from a client if Shairport Sync was running on a device with more than one network interface. The solution was to take account of the `config_id` information. * Some problems have been fixed with the non-blocking write function used to write metadata. * A bug in the volume control transfer function has been fixed, thanks to [Jörg Krause](https://github.com/joerg-krause). **Enhancements** * Shairport Sync now works with [AllConnect/Streambels](http://allconnectapp.com) on Android with password protection. (As with all Android clients, you should set the `drift` to something large, like 500 or 1,000, as the timekeeping of these clients isn't as accurate as that of iTunes, etc.) * The networking subsystem has been modified to always use the same IP number during a session. Background: the computer Shairport Sync is running on can have many IP numbers active at the same time – various IPv6 numbers and also various IPv4 numbers. During a play session, when Shairport Sync has to create connections back to the source, it would use an automatically-assigned IP number for itself, but that number might not be same as the the number used earlier in the session. From now on, it will always use the same IP number it used when the connection was first established. Thanks to [ejurgensen](https://github.com/ejurgensen) for help with this. * Experimental support has been added for a softvol plugin, thanks to the work of [Jörg Krause](https://github.com/joerg-krause) -- see [#293](https://github.com/mikebrady/shairport-sync/pull/293). * A `playback_mode` setting has been added to allow the selection of `stereo` (default) or `mono` playback -- thanks to [faceless2](https://github.com/faceless2). * The new default service name is now the device's `hostname`, with its first character capitalised (ASCII only). * Substitutions can now be made in the service name. The following substitutions can be used in the service name: `%h` for the `hostname`, `%H` for the `hostname` with the first letter capitalised, `%v` for the version number and `%V` for the full version string. Maximum length is 50 characters. * An existing `shairport-sync.service` file will not be overwritten by `sudo make install`. * The text strings advertising the capabilities of Shairport Sync over Bonjour/Zeroconf/Avahi have been changed and now more closely match those of an AirPort Express Base Station (First Generation). * It is now possible to set the amount of time to wait for the metadata pipe to become ready for writing. The setting is called `pipe_timeout` in the `metadata` section. Default is 5,000 milliseconds. * Metadata can now be provided via UDP -- thanks to [faceless2](https://github.com/faceless2). * Statistics output is more machine readable -- thanks to [Jörg Krause](https://github.com/joerg-krause) * The `shairport-sync.spec` file has been updated for compatibility with building Debian packages using `checkinstall` -- thanks to [vru1](https://github.com/vru1). Version 2.8.3.11 – Development Version ---- **Bug Fix** Fixed some problems with the non-blocking write function used to write to the metadata pipe. **Enhancement** It is now possible to set the amount of time to wait for the metadata pipe to become ready for writing. The setting is called `pipe_timeout` in the `metadata` section. Default is 5,000 milliseconds. Version 2.8.3.10 – Development Version ---- **Bug Fix** * Restored metadata feed lost in 2.8.3.7. Version 2.8.3.9 – Development Version ---- **Enhancements** * Substitutions can now be made in the service name, i.e. the name that appears in iTunes, etc. The following substitutions can be used in the service name you specify: `%h` for the hostname, `%H` for the hostname with the first letter capitalised, `%v` for the version number and `%V` for the full version string. Maximum length is 50 characters. * The new default service name is simply the hostname, with its first character capitalised. * An existing `shairport-sync.service` file will not be overwritten by `sudo make install`. Version 2.8.3.7 – Development Version ---- **Enhancements** * Shairport Sync now works with AllConnect/Streambels on Android with password protection. (As with all Android clients, you should set the `drift` to something large, like 500 or 1,000, as the timekeeping of these clients isn't as accurate as that of iTunes, etc.) * The text strings advertising the capabilities of Shairport Sync over Bonjour/Zeroconf/Avahi have been changed and now more closely match those of an AirPort Express Base Station (First Generation). Version 2.8.3.6 – Development Version ---- **Bug fix** An IPv6 link-local connection issue was fixed. A bug in the networking software would not allow an IPv6 link-local connection to be made from a client if Shairport Sync was running on a device with more than one network interface. The solution was to take account of the `config_id` information. Version 2.8.3.5 – Development Version ---- **Enhancement** Experimental support for a softvol plugin, thanks to the work of [Jörg Krause](https://github.com/joerg-krause) -- see [#293](https://github.com/mikebrady/shairport-sync/pull/293). **Bug fix** Add checks for empty or NULL audio buffers that seem to be causing assertion violations and subsequent abnormal program termination. Version 2.8.3.4 – Development Version ---- **Bug Fix** The networking subsystem has been modified to always use the same IP number during a session. Background: the computer Shairport Sync is running on can have many IP numbers active at the same time – various IPv6 numbers and also various IPv4 numbers. During a play session, when Shairport Sync has to create connections back to the source, it would use an automatically-assigned IP number for itself, but that number might not be same as the the number used earlier in the session. From now on, it will always use the same IP number it used when the connection was first established. Thanks to [ejurgensen](https://github.com/ejurgensen) for help with this. Changed the `mono` setting for a `playback_mode` setting with two possible values: `stereo` (default) and `mono`. Version 2.8.3.3 – Deleted ---- Version 2.8.3.2 – Deleted ---- Version 2.8.3.1 – Development Version ---- Added a new `mono` setting -- thanks to [faceless2](https://github.com/faceless2). Documentation to follow. Version 2.8.3 – Stable Version ---- A bug in 2.8.2 caused Avahi to fail at startup under some circumstances with older installations. The problem was that sometimes the `regtype` setting would not be initialised properly. Version 2.8.2 – Stable Version ---- Version 2.8.2 is derived from development version 2.9.5.7 and has stability improvements, bug fixes and a few special-purpose enhancements. For full details, please refer to the release notes here, back as far as 2.8.1. Version 2.9.5.7 – Development Version ---- Version 2.9.5.7 contains general bug fixes and enhancements for some special situations. **Bug Fixes** * Getting delay and latency information from the `alsa` subsystem has been improved -- bugs fixed, error codes handled better, arithmetic handling (hopefully) better. * If latency information is temporarily unavailable from the `alsa` subsystem, skip trying to synchronise until the next time. * Some condition variables and a mutex were uninitialised, yikes! Fixed. * A bug that set the output volume to maximum at the same time as muting the output has been fixed. AFAIK, this was inaudible, but it was scary looking. * Recover from name collisions in Avahi. * Detect and handle empty buffers better. **Enhancements** * Turn off synchronisation. This is an advanced feature and generally leads to buffer underrun or overrun. * Set `alsa` buffer size and `alsa` period size. There are advanced features, mainly for debugging. They may be removed. * Change the Zeroconf/Bonjour `regtype` to enable Shairport Sync to continue to run but to be invisible to AirPlay clients. Special purpose usage only. * Output total number of packets and the play time of a session when statistics are enabled. Version 2.9.4 – Development Version ---- Version 2.9.4 corrects some bugs in how Avahi error conditions are handled. **Bug Fix** * During operation, if the network disappeared, Avahi would occasionally report an error. This would cause Shairport Sync to attempt to terminate gracefully (which is the wrong thing to do in the circumstances). However, the termination attempt was actually causing an assertion violation crash. These errors are now simply logged. Version 2.9.3 – Development Version ---- Version 2.9.3 is 2.8.1 with documentation and version changes to indicate that it's in the development branch. Version 2.8.1 – Stable Version ---- Version 2.8.1 is derived from development version 2.9.2 and has stability improvements and important bug fixes. For full details, please refer to the release notes here, back as far as 2.9.1. Version 2.9.2 – Development Version ---- Version 2.9.2 focuses on further bug fixes and stability improvements. * Enhanced stability: an important bug has been fixed in the handling of missing audio frames – i.e. what happens when a frame of audio is truly missing, after all attempts to fetch it have been unsuccessful. The bug would cause Shairport Sync to do an unnecessary resynchronisation, or, if resync was turned off, to jump out of sync. This is a long-standing bug – thanks to [Jörg Krause](https://github.com/joerg-krause) for identifying it. * An extra diagnostic has been added which gives the mean, standard deviation and maximum values for inter-packet reception time on the audio port. It may be useful for exploring line quality. Version 2.9.1 – Development Version ---- Version 2.9.1 focuses on bug fixes and stability improvements. * Stability improvements are concentrated on what happens when a play sessions ends and is followed immediately by a new session. This happens in iOS 9.2 when you click to the next track or to the previous track. It also happens playing YouTube videos when a Mac's System Audio is routed through AirPlay. Thanks to [Tim Curtis](https://github.com/moodeaudio) for help with these issues. * A workaround for an apparent flushing issue in TuneBlade has been included. Thanks to [gibman](https://github.com/gibman) for reporting this issue. * A number of bug fixes have been made to `configure.ac` – thanks to [Jörg Krause](https://github.com/joerg-krause). Version 2.8 – Stable Version ---- Version 2.8 is derived from version 2.7.10 with slight documentation updates. Here is a summary of changes between the last stable version – 2.6 – and this version. For full details, refer to the release notes here, back as far as 2.7. **New Feature** * For hardware mixers with a restricted range (including many cheaper USB DACS), the general `volume_range_db` can be used to specify a wider range than the hardware provides – the extra range is provided by software. **Enhancements** * The `man` manual and the html version of it are automagically rebuilt if `xml2man` and friends are available. * Volume-setting metadata is now sent even when the volume level is to be ignored by Shairport Sync itself. * Shairport Sync waits a little longer before asking for missing packets to be resent. Sometimes packets are just arriving slightly out of order and don't need to be asked for again. * The build scripts have been modified to be a little more compatible with standard practice. * A Continuous Integration (CI) system – Travis CI – is now used to do some limited build checking (thanks guys!). * Support added for compiling on Cygwin. * Added `rtptime` tags to metadata and picture metadata. * Replaced and improved the dither algorithm used with the software volume control. The new dither code gives a two bit peak-to-peak dither based on a Triangular Probability Distribution Function (TPDF). * Disabled picture sending if pictures haven’t been asked for. **Bug fixes** * Fixed a bug that prevented Shairport Sync from correctly setting the hardware mixer volume if it had been altered externally. Thanks to [Tim Curtis](https://github.com/moodeaudio) for help with these issues. * Modified the shutdown behaviour so that a shutdown followed immediately by a play request is handled better. This was causing iOS 9.2 sometimes to drop the Airplay link between tunes. * Fixed a data-alignment bug that would cause a crash in certain circumstances on ARM processors with metadata enabled. * Corrected the names for a few settings tags. * Fixed some typos and misspellings. * Miscellaneous small bug fixes. Version 2.7.10 -- Development Version ---- **New Feature** * If the `ignore_volume_control` setting was `yes`, Shairport Sync really did ignore volume control settings and did not send any volume metadata (i.e. `pvol` coded metadata). Now, while continuing to ignore volume control settings, it sends a `pvol` token where the first number is the AirPlay volume, as before, but the remaining three parameters are set to zero. Version 2.7.9 -- Development Version ---- **Bug Fix** * Oops – brown-bag update. Fixed a crashing bug introduced in the last release, caused by not checking for a hardware mixer before trying to access it, duh. Version 2.7.8 -- Development Version ---- **Bug Fix** * Fixed an issue whereby Shairport Sync did not reset the hardware mixer volume level before resuming playing. The issue was caused by not releasing and later reaquiring the mixer when pausing and resuming. Thanks to [Tim Curtis](https://github.com/moodeaudio) for reporting the issue. Version 2.7.7 -- Development Version ---- **Enhancements** * Add note about the Arch Linux Community repository package `shairport-sync`. Thanks to [Anatol Pomozov](https://github.com/anatol). * Shairport Sync doesn't ask for packets to be resent quite so quickly -- it waits about half a second now before asking for missing packets to be resent. **Bug Fixes** * Improved Shairport Sync's behaviour when it's asked to stop a play session and immediately start another. The signalling system used to stop threads was sometimes stopping threads belonging to the new session. This affected iOS 9.2 users going to the next track -- sometimes the player would become unavailable for an instant and disconnect the session. Th problem still happens occasionally. * Removed code favouring the use of "public" IPv6 addresses as source addresses when connecting to a distant IPv6 port – Neither OpenWrt nor FreeBSD can use it at present. Also, it's not clear if any problems are being caused by not favouring public IPv6 addresses. Version 2.7.6 -- Development Version ---- **Bug Fixes** * Look for the correct tag name for desired `ao` buffer length: `audio_backend_buffer_desired_length` rather than `audio_backend_buffer_desired_length_software`. * Fix a few FreeBSD compilation bugs. * Fix a few documentation issues and typos. Thanks to [Chris Boot](https://github.com/bootc). **Enhancements** * Add note about installing to Mac OS X. Thanks to [Serg Podtynnyi](https://github.com/shtirlic). * Add automatic rebuild of manpage and html documentation when `xmltoman` and friends are available. Thanks to [Chris Boot](https://github.com/bootc). * Favour the use of "public" IPv6 addresses as source addresses when connecting to a distant IPv6 port. Version 2.7.5 -- Development Version ---- **New Features** * Ubuntu PPA files now available at https://launchpad.net/~dantheperson. **Enhancements** * Broaden the use of the value `$PREFIX` instead of the path `/usr/local/bin` during configuration. Thanks to [dantheperson](https://github.com/dantheperson). Version 2.7.4 -- Development Version ---- **Enhancements** * Use the correct method for finding the `systemd` unit path, as recommended by Debian maintainers and http://www.freedesktop.org/software/systemd/man/daemon.html#Installing%20Systemd%20Service%20Files. Thanks to [dantheperson](https://github.com/dantheperson). * Rather than hardwire the path `/usr/local/bin` as the path to the shairport-sync executable, the value of `$PREFIX` is now used during configuration. Thanks to [Nick Steel](https://github.com/kingosticks). * Add some extra diagnostic messages if the hardware buffer in the DAC is smaller than desired. * If metadata has been enabled, but if picture sending has not been requested and the source sends pictures anyway, omit them from the metadata feed. Thanks to [Jörg Krause](https://github.com/joerg-krause). **Bug Fixes** * Fixed a data alignment issue in the handling of metadata on some processors. Thanks to [Jörg Krause](https://github.com/joerg-krause). * Removed an `assert` which would terminate the program if a malformed packet of data was received. * Look for the correct tag name for desired alsa buffer length: `audio_backend_buffer_desired_length` rather than `audio_backend_buffer_desired_length_software`. Version 2.7.3 -- Development Version ---- **Bug Fix** * The dither code was broken in Shairport Sync and also less than ideal anyway. Fixed and improved. Dither is added whenever you use the software volume control at less than full volume. See http://www.ece.rochester.edu/courses/ECE472/resources/Papers/Lipshitz_1992.pdf for a very influential paper by Lipshitz, Wannamaker and Vanderkooy, 1992. The dither code in Shairport Sync was inherited from Shairport and does not conform to the recommendations in the paper -- specifically the implementation would give one bit of dither where the paper recommends two bits peak-to-peak. The other thing is that the inherited dither code was actually broken in Shairport Sync. So, the new dither code gives a two bit peak-to-peak dither based on a Triangular Probability Distribution Function (TPDF). It sounds like a very low-level white noise, unmodulated by the audio material. It would be nice if it was even lower, but it's better than listening to the artifacts present when dithering is disabled. Version 2.7.2 -- Development Version ---- **Bug Fix** * Fix a bug that suppressed output of the `rtptime` associated with metadata and with picture information coming from the audio source and passed on via the metadata pipe. **Other Changes** * Added some more information to the log whenever problems are detected with the proposed alsa device. Version 2.7.1 -- Development Version ---- **Bug Fix** * The new volume-extension code was not correctly setting the volume after a pause / resume. Fixed. Version 2.7 -- Development Version ---- **New Features** * Extend the volume range for some DACs. Background: some of the cheaper DACS have a very small volume range (that is, the ratio of the highest to the lowest volume, expressed in decibels, is very small). In some really cheap DACs it's only around 30 dB. That means that the difference between the lowest and highest volume settings isn't large enough. With the new feature, if you set the `general` `volume_range_db` to more than the hardware mixer's range, Shairport Sync will combine the hardware mixer's range with a software attenuator to give the desired range. For example, suppose you want a volume range of 70 dB and the hardware mixer offers only 30 dB, then Shairport Sync will make up the other 40 dB with a software attenuator. One drawback is that, when the volume is being changed, there may be a slight delay (0.15 seconds by default) as the audio, whose volume may have been adjusted in software, propagates through the system. Another slight possible drawback is a slightly heavier load on the processor. * Check for underflow a little better when buffer aliasing occurs on very bad connections... * Add extra debug messages to the alsa back end to diagnose strange DACs. * Add configuration file for the `libao` back end -- to change the buffer size and the latency offset, same as for stdout. * Add `shairport-sync.exe` to `.gitignore`. * Add a check to support compilation on a CYGWIN platform. * Add `rtptime` tags to metadata and picture information and add two new metadata items to precede and follow the transmission of a picture. Background: it seems that metadata and picture information for the same item, e.g. a track, are normally tagged with a timestamp called the `rtptime`; if they refer to the same item, they will have the same `rtptime` tags. The update here is to add the `rtptime` value, if available, as data to the `mdst` and `mden` metadata items, which are sent before ("MetaData STart") and after ("MetaData ENd") a metadata sequence. In addition, similar tags -- `pcst` ("PiCture STart") and `pcen` ("PiCture ENd") are now sent before and after a picture with the `rtptime` value, if available, sent as data. By the way, the progress metadata (`prgr` for "PRoGRess"), which is sent just when a track starts, contains the same `rtptime` as its middle element. Version 2.6 -- Stable Version ---- This is basically version 2.4.2 with two small fixes. It's been bumped to 2.6 because (1) the new features added between 2.4.1 and 2.4.2 deserve more than just a bug-fix increment and (2) the development versions (2.5.x) should have lower numbers than the release versions, so that releases are always seen as upgrades. For example: 2.5.0.9 --> 2.6 looks like an upgrade, whereas 2.5.0.9 --> 2.4.2 looks like a downgrade. **Fixes** * For `systemd` users, the `shairport-sync.service` file is updated to point to the correct location of the shairport-sync application. * For Fedora users, the `shairport-sync.spec` file is updated to refer to 2.6. Version 2.4.2 ---- This release has important enhancements, bug fixes and documentation updates. It also appears to bring compatibility with Synology NAS devices. **New Features** * Source-specified Latencies. Shairport Sync now uses the latencies specified by the audio source. Background: the AirPlay protocol used by Shairport Sync allows the audio source to specify the exact delay or latency that should be applied to the audio stream. Until now, Shairport Sync ignored this information and used fixed preset latencies that were selected on the basis of the "User-Agent" setting. Using source-specified latencies means that Shairport Sync is able adapt automatically to different sources. Using source-specified latencies is now automatic unless non-standard static latencies have been specified in the configuration file or command line. Using non-standard latencies is usually done to compensate for delays in the back end of the system. For example, if the audio amplifier being driven by Shairport Sync has an inherent delay of its own -- as happens with many home theatre and surround sound systems -- then some users have reduced the latencies used by Shairport Sync to compensate. This usage is discouraged -- the `audio_backend_latency_offset` in the appropriate backend stanza (e.g. in the "alsa" stanza) should be used for this. Static latency settings are now deprecated, and will be removed in a future version of Shairport Sync. * Set Volume Range. This is a new setting that allows you to use just a portion of the full range of attenuation offered by a mixer. For example, if a mixer has a minimum volume of -80 dB and a maximum of +20 dB, you might wish to use only 60 dB of the 100 dB available. This might be because the sound becomes inaudible at the lowest setting and unbearably loud at the highest setting. It is for this reason that many domestic HiFi systems have a volume control range of only 60 to 80 dB. Another possible reason to use this setting might be because the range specified by the mixer does not match the actual capabilities of the device. For example, the Raspberry Pi's DAC that feeds the built-in audio jack claims a range of 106 dB but has a useful range of only about 35dB. The new `volume_range_db` setting in the `general` stanza allows you to specify the maximum range from highest to lowest. The range suggested for the Raspberry Pi's built-in audio DAC, which feeds the headphone jack, is 35. Using it in this case gives the volume control a much more useful range of settings. **Bug fixes** * Sometimes, especially when using Shairport Sync as a system output, it would not play the audio stream. This was caused by an improperly initialised variable. Fixed. Synology NAS devices now seem to be working with Shairport Sync. * Fix in the `shairport.c`: the USE_CUSTOM_LOCAL_STATE_DIR macro was still being used when it should have been USE_CUSTOM_PID_DIR. * Fix a crashing bug -- if metadata was enabled but a pipename was not supplied, boom. **Other Changes** * Initial timing accuracy improved. The estimate of when to play the starting frame of the audio sequence has improved significantly. This leads to fewer corrections being needed at the start. * Volume ratios expressed in decibels are now consistently denominated in voltage decibels rather than power decibels. The rationale is that the levels refer to voltage levels, and power is proportional to the square of voltage. Thus a ratio of levels of 65535 to 1 is 96.3 dB rather than the 48.15 dB used before. * The latency figure returned to the source as part of the response to an rtsp request packet is 11,025, which may (?) be meant to indicate the minimum latency the device is capable of. * An experimental handler for a GET_PARAMETER rtsp request has been added. It does nothing except log the occurrence. * The RTSP request dispatcher now logs an event whenever an unrecognised rtsp has been made. Version 2.4.1 ---- This release has three small bug fixes and some small documentation updates. **Bug Fixes** Changes from the previous stable version -- 2.4 -- are summarised here: * The USE_CUSTOM_LOCAL_STATE_DIR macro was still being used when it should have been USE_CUSTOM_PID_DIR. This could affect users using a custom location for the PID directory. * A compiler error has been fixed that occurred if metadata was enabled and tinysvcmdns was included. * A crash has been fixed that occurred if metadata was enabled and a metadata pipe name was not specified. (Thanks to the contributors who reported bugs.) **Small Changes** * If a mixer being used to control volume does not have a control denominated in dB, a warning is logged and the mixer is not used. * Slight revisions have been made to the configuration file `configure.ac` to make compilation on FreeBSD a little easier. Version 2.4 ---- **Stable release** This stable release is the culmination of the 2.3.X sequence of development releases. **Change Summary** Changes from the previous stable version -- 2.2.5 -- are summarised here: * Settings are now read from a configuration file. Command-line settings are supported but discouraged. * Metadata is now supported -- it can be delivered to a unix pipe for processing by a helper application. See https://github.com/mikebrady/shairport-sync-metadata-reader for a sample metadata reader. * Raw PCM audio can be delivered to standard output ("stdout") or to a unix pipe. The internal architecture has changed considerably to support this. * Support for compilation on OpenWrt back to Attitude Adjustment. * Can play unencrypted audio streams -- complatible with, e.g. Whaale. * Uses the libconfig library. * Runs on a wider range of platforms, including Arch Linux and Fedora. * Bug fixes. Please note that building instructions have changed slightly from the previous version. Also, the `-t hardware/software` option has been deprecated in the alsa back end. Version 2.3.13 ---- **Note** * We're getting ready to release the development branch as the new, stable, master branch at 2.4. If you're packaging Shairport Sync, you might prefer to wait a short while as we add a little polish before the release. **Changes** * Harmonise version numbers on the release and on the `shairport.spec` file used in Fedora. Version 2.3.12 ---- **Note** * We're getting ready to release the development branch as the new, stable, master branch at 2.4. If you're packaging Shairport Sync, you might prefer to wait a short while as we add a little polish before the release. **Changes** * `update-rc.d` has been removed from the installation script for System V because it causes problems for package makers. It's now noted in the user installation instructions. * The `alsa` group `mixer_type` setting is deprecated and you should stop using it. Its functionality has been subsumed into `mixer_name` – when you specify a `mixer_name` it automatically chooses the `hardware` mixer type. **Enhancements** * Larger range of interpolation. Shairport Sync was previously constrained not to make interpolations ("corrections") of more than about 1 per 1000 frames. This constraint has been relaxed, and it is now able to make corrections of up to 1 in 352 frames. This might result in a faster and undesirably sudden correction early during a play session, so a number of further changes have been made. The full set of these changes is as follows: * No corrections happen for the first five seconds. * Corrections of up to about 1 in 1000 for the next 25 seconds. * Corrections of up to 1 in 352 thereafter. **Documentation Update** * Nearly there with updates concerning the configuration file. Version 2.3.11 ---- Documentation Update * Beginning to update the `man` document to include information about the configuration file. It's pretty sparse, but it's a start. Version 2.3.10 ---- Bug fix * The "pipe" backend used output code that would block if the pipe didn't have a reader. This has been replaced by non-blocking code. Here are some implications: * When the pipe is created, Shairport Sync will not block if a reader isn't present. * If the pipe doesn't have a reader when Shairport Sync wants to output to it, the output will be discarded. * If a reader disappears while writing is occurring, the write will time out after five seconds. * Shairport Sync will only close the pipe on termination. Version 2.3.9 ---- * Bug fix * Specifying the configuration file using a *relative* file path now works properly. * The debug verbosity requested with `-v`, `-vv`, etc. is now honoured before the configuration file is read. It is read and honoured from when the command line arguments are scanned the first time to get a possible configuration file path. Version 2.3.8 ---- * Annoying changes you must make * You probably need to change your `./configure` arguments. The flag `with-initscript` has changed to `with-systemv`. It was previously enabled by default; now you must enable it explicitly. * Changes * Added limited support for installing into `systemd` and Fedora systems. For `systemd` support, use the configuration flag `--with-systemd` in place of `--with-systemv`. The installation does not do everything needed, such as defining special users and groups. * Renamed `with-initscript` configuration flag to `with-systemv` to describe its role more accurately. * A System V startup script is no longer installed by default; if you want it, ask for it with the `--with-systemv` configuration flag. * Added limited support for FreeBSD. You must specify `LDFLAGS='-I/usr/local/lib'` and `CPPFLAGS='-L/usr/local/include'` before running `./configure --with-foo etc.` * Removed the `-configfile` annotation from the version string because it's no longer optional; it's always there. * Removed the `dummy`, `pipe` and `stdout` backends from the standard build – they are now optional and are no longer automatically included in the build. * Bug fixes * Allow more stack space to prevent a segfault in certain configurations (thanks to https://github.com/joerg-krause). * Add missing header files(thanks to https://github.com/joerg-krause). * Removed some (hopefully) mostly silent bugs from the configure.ac file. Version 2.3.7 ---- * Changes * Removed the two different buffer lengths for the alsa back end that made a brief appearance in 2.3.5. * Enhancements * Command line arguments are now given precedence over config file settings. This conforms to standard unix practice. * A `–without-pkg-config` configuration argument now allows for build systems, e.g. for older OpenWrt builds, that haven't fully implemented it. There is still some unhappiness in arch linux builds. * More * Quite a bit of extra diagnostic code was written to investigate clock drift, DAC timings and so on. It was useful but has been commented out. If might be useful in the future. Version 2.3.5 ---- * Changes * The metadata item 'sndr' is no longer sent in metadata. It's been replaced by 'snam' and 'snua' -- see below. * Enhancements * When a play session is initiated by a source, it attempts to reserve the player by sending an "ANNOUNCE" packet. Typically, a source device name and/or a source "user agent" is sent as part of the packet. The "user agent" is usually the name of the sending application along with some more information. If metadata is enabled, the source name, if provided, is emitted as a metadata item with the type `ssnc` and code `snam` and similarly the user agent, if provided, is sent with the type `ssnc` and code `snua`. * Two default buffer lengths for ALSA -- default 6615 frames if a software volume control is used, to minimise the response time to pause and volume control changes; default 22050 frames if a hardware volume control is used, to give more resilience to timing problems, sudden processor loading, etc. This is especially useful if you are processing metadata and artwork on the same machine. * Extra metadata: when a play session starts, the "Active-Remote" and "DACP-ID" fields -- information that can be used to identify the source -- are provided as metadata, with the type `ssnc` and the codes `acre` and `daid` respectively. The IDs are provided as strings. * Unencrypted audio data. The iOS player "Whaale" attempts to send unencrypted audio, presumably to save processing effort; if unsuccessful, it will send encrypted audio as normal. Shairport Sync now recognises and handles unencrypted audio data. (Apparently it always advertised that it could process unencrypted audio!) * Handle retransmitted audio in the control channel. When a packet of audio is missed, Shairport Sync will ask for it to be retransmitted. Normally the retransmitted audio comes back the audio channel, but "Whaale" sends it back in the control channel. (I think this is a bug in "Whaale".) Shairport Sync will now correctly handle retransmitted audio packets coming back in the control channel. * Bugfixes * Generate properly-formed `..` items of information. Version 2.3.4 ---- * Enhancement * When a play session starts, Shairport Sync opens three UDP ports to communicate with the source. Until now, those ports could be any high numbered port. Now, they are located within a range of 100 port locations starting at port 6001. The starting port and the port range are settable by two new general settings in `/etc/shairport-sync.conf` -- `udp_port_base` (default 6001) and `udp_port_range` (default 100). To retain the previous behaviour, set the `udp_port_base` to `0`. * Bugfixes * Fix an out-of-stack-space error that can occur in certain cases (thanks to https://github.com/joerg-krause). * Fix a couple of compiler warnings (thanks to https://github.com/joerg-krause). * Tidy up a couple of debug messages that were emitting misleading information. Version 2.3.3.2 ---- * Bugfix -- fixed an error in the sample configuration file. Version 2.3.3.1 ---- * Enhancement * Metadata format has changed slightly -- the format of each item is now `........`, where the `..` part is present if the length is non-zero. The change is that everything is now enclosed in an `..` pair. Version 2.3.2 and 2.3.3 ---- These releases were faulty and have been deleted. Version 2.3.1 ----- Some big changes "under the hood" have been made, leading to limited support for unsynchronised output to `stdout` or to a named pipe and continuation of defacto support for unsynchronised PulseAudio. Also, support for a configuration file in preference to command line options, an option to ignore volume control and other improvements are provided. In this release, Shairport Sync gains the ability to read settings from `/etc/shairport-sync.conf`. This gives more flexibility in adding features gives better compatibility across different versions of Linux. Existing command-line options continue to work, but some will be deprecated and may disappear in a future version of Shairport Sync. New settings will only be available via the configuration file. Note that, for the present, settings in the configuration will have priority over command line options for Shairport Sync itself, in contravention of the normal unix convention. Audio back end command line options, i.e. those after the `--`, have priority over configuration file settings for the audio backends. In moving to the the use of a configuration file, some "housekeeping" is being done -- some logical corrections and other small changes are being made to option names and modes of operations, so the settings in the configuration file do not exactly match command line options. When `make install` is executed, a sample configuration is installed or updated at `/etc/shairport-sync.conf.sample`. The same file is also installed as `/etc/shairport-sync.conf` if that file doesn't already exist. To prevent the configuration files being installed, use the configuration option `--without-configfiles`. * Pesky Change You Must Do Something About If you are using metadata, please note that the option has changed somewhat. The option `-M` has a new long name equivalent: `--metadata-pipename` and the argument you provide must now be the full name of the metadata pipe, e.g. `-M /tmp/shairport-sync-metadata`. * Enhancements * Shairport Sync now reads settings from the configuration file `/etc/shairport-sync.conf`. This has settings for most command-line options and it's where any new settings will go. A default configuration file will be installed if one doesn't exist, and a sample file configuration file is always installed or updated. Details of settings are provided in the sample file. Shairport Sync relies on the `libconfig` library to read configuration files. For the present, you can disable the new feature (and save the space taken up by `libconfig`) by using the configure option `--without-configfile-support`. * New command-line option `-c ` or `--configfile=` allows you to specify a configuration file other than `/etc/shairport-sync.conf`. * Session Timeout and Allow Session Interruption can now be set independently. This is really some "housekeeping" as referred to above -- it's a kind of a bug fix, where the bug in question is an inappropriate connection of the setting of two parameters. To explain: (1) By default, when a source such as iTunes starts playing to the Shairport Sync device, any other source attempting to start a play session receives a "busy" signal. If a source disappears without warning, Shairport Sync will wait for 120 seconds before dropping the session and allowing another source to start a play session. (2) The command-line option `-t` or `--timeout` allows you to set the wait time before dropping the session. If you set this parameter to `0`, Shairport Sync will not send a "busy" signal, thus allowing another source to interrupt an existing one. (3) The problem is that if you set the parameter to `0`, a session will never be dropped if the source disappears without warning. The (obvious) fix for this is to separate the setting of the two parameters, and this is now done in the configuration file `/etc/shairport-sync.conf` -- please see the settings `allow_session_interruption` and `session_timeout`. The behaviour of the `-t` and `--timeout` command-line options is unchanged but deprecated. * New Option -- "Ignore Volume Control" ('ignore_volume_control'). If you set this to "yes", the output from Shairport Sync is always set at 100%. This is useful when you want to set the volume locally. Available via the settings file only. * Statistics option correctly reports when no frames are received in a sampling interval and when output is not being synchronised. * A new, supported audio back end called `stdout` provides raw 16-bit 44.1kHz stereo PCM output. To activate, set `output_backend = "stdout"` in the general section of the configuration file. Output is provided synchronously with the source feed. No stuffing or stripping is done. If you are feeding it to an output device that runs slower or faster, you'll eventually get buffer overflow or underflow in that device. To include support for this back end, use the configuration option `--with-stdout`. * Support for the `pipe` back end has been enhanced to provide raw 16-bit 44.1kHz stereo PCM output to a named pipe. To activate, set `output_backend = "pipe"` in the general section of the configuration and give the fully-specified pathname to the pipe in the pipe section of the configuration file -- see `etc/shairport-sync.conf.sample` for an example. No stuffing or stripping is done. If you are feeding it to an output device that runs slower or faster, you'll eventually get buffer overflow or underflow in that device. To include support for this back end, use the configuration option `--with-pipe`. * Support for the `dummy` audio backend device continues. To activate, set `output_backend = "dummy"` in in the general section of the configuration. To include support for this back end, use the configuration option `--with-dummy`. * Limited support for the PulseAudio audio backend continues. To activate, set `output_backend = "pulse"` in in the general section of the configuration. You must still enter its settings via the command line, after the `--` as before. Note that no stuffing or stripping is done: if the PulseAudio sink runs slower or faster, you'll eventually get buffer overflow or underflow. * New backend-specific settings are provided for setting the size of the backend's buffer and for adding or removing a fixed offset to the overall latency. The `audio_backend_buffer_desired_length` default is 6615 frames, or 0.15 seconds. On some slower machines, particularly with metadata processing going on, the DAC buffer can underflow on this setting, so it might be worth making the buffer larger. A problem on software mixers only is that changes to volume control settings have to propagate through the buffer to be heard, so the larger the buffer, the longer the response time. If you're using an alsa back end and are using a hardware mixers, this isn't a problem. The `audio_backend_latency_offset` allows you emit frames to the audio back end some time before or after the synchronised time. This would be useful, for example, if you are outputting to a device that takes 20 ms to process audio; yoou would specify a `audio_backend_latency_offset = -882`, where 882 is the number of frames in 20 ms, to compensate for the device delay. Version 2.3 ----- * Enhancements * Adding the System V startup script (the "initscript") is now a configuration option. The default is to include it, so if you want to omit the installation of the initscript, add the configuration option `--without-initscript`. * Metadata support is now a compile-time option: `--with-metadata`. * A metadata feed has been added. Use the option `-M `, e.g. `-M /tmp`. Shairport Sync will provide metadata in a pipe called `/shairport-sync-metadata`. (This is changed in 2.3.1.) There's a sample metadata reader at https://github.com/mikebrady/shairport-sync-metadata-reader. The format of the metadata is a mixture of XML-style tags, 4-character codes and base64 data. Please look at `rtsp.c` and `player.c` for examples. Please note that the format of the metadata may change. Beware: there appears to be a serious bug in iTunes before 12.1.2, such that it may stall for a long period when sending large (more than a few hundred kilobytes) coverart images. * Bugfix * Fix a bug when compiling for Arch Linux on Raspberry Pi 2 (thanks to https://github.com/joaodriessen). * Fix a bug whereby if the ANNOUNCE and/or SETUP method fails, the play_lock mutex is never unlocked, thus blocking other clients from connecting. This can affect all types of users, but particularly Pulseaudio users. (Thanks to https://github.com/jclehner.) * Modify the init script to start after all services are ready. Add in a commented-out sleep command if users find it necessary (thanks to https://github.com/BNoiZe). * Two memory leaks fixed (thanks to https://github.com/pdgendt). * An error handling time specifications for flushes was causing an audible glitch when pausing and resuming some tracks. This has been fixed (thanks to https://github.com/Hamster128). Version 2.2.5 ----- * Bugfixes * Fix a segfault error that can occur in certain cases (thanks again to https://github.com/joerg-krause). * Include header files in common.c (thanks again to https://github.com/joerg-krause). Version 2.2.4 ----- * Bugfixes * Fix an out-of-stack-space error that can occur in certain cases (thanks to https://github.com/joerg-krause). * Fix a couple of compiler warnings (thanks to https://github.com/joerg-krause). Version 2.2.3 ----- * NOTE: all the metadata stuff has been moved to the "development" branch. This will become the stable branch henceforward, with just bug fixes or minor enhancements. Apologies for the inconvenience. * Bugfixes * Fix a bug when compiling for Arch Linux on Raspberry Pi 2 (thanks to https://github.com/joaodriessen). * Fix a compiler warning (thanks to https://github.com/sdigit). Version 2.2.2 ----- * Enhancement * An extra latency setting for forked-daapd sources -- 99,400 frames, settable via a new option `--forkedDaapdLatency`. Version 2.2.1 ----- * Bugfixes: * If certain kinds of malformed RTSP packets were received, Shairport Sync would stop streaming. Now, it generally ignores faulty RTSP packets. * The `with-pulseaudio` compile option wasn't including a required library. This is fixed. Note that the PulseAudio back end doesn't work properly and is just included in the application because it was there in the original shairport. Play with it for experimentation only. * Fix typo in init.d script: "Headphones" -> "Headphone". * Extra documentation * A brief note on how to compile `libsoxr` from source is included for the Raspberry Pi. Version 2.2 ----- * Enhancements: * New password option: `--password=SECRET` * New tolerance option: `--tolerance=FRAMES`. Use this option to specify the largest synchronisation error to allow before making corrections. The default is 88 frames, i.e. 2 milliseconds. The default tolerance is fine for streaming over wired ethernet; however, if some of the stream's path is via WiFi, or if the source is a third-party product, it may lead to much overcorrection -- i.e. the difference between "corrections" and "net correction" in the `--statistics` option. Increasing the tolerance may reduce the amount of overcorrection. Version 2.1.15 ----- * Changes to latency calculations: * The default latency is now 88,200 frames, exactly 2 seconds. It was 99,400 frames. As before, the `-L` option allows you to set the default latency. * The `-L` option is no longer deprecated. * The `-L` option no longer overrides the `-A` or `-i` options. * The default latency for iTunes is now 99,400 frames for iTunes 10 or later and 88,200 for earlier versions. * The `-i` or `--iTunesLatency` option only applies to iTunes 10 or later sources. Version 2.1.14 ----- * Documentation update: add information about the `-m` audio backend option. The `-m` audio backend option allows you to specify the hardware mixer you are using. Not previously documented. Functionality of shairport-sync is unchanged. Version 2.1.13 ----- * Compilation change: Begin to use PKG_CHECK_MODULES (in configure.ac) to statically link some of the libraries used by shairport-sync. It is intended to make it easier to build in the buildroot system. While sufficient for that purpose, note that PKG_CHECK_MODULES is not used for checking all the libraries yet. Functionality of shairport-sync is unchanged. Version 2.1.12 ----- * Enhancement: `--statistics` Statistics are periodically written to the console (or the logfile) if this command-line option is included. They are no longer produced in verbose (`-v`) mode. * Bugfixes for `tinysvcmdns` * A bug that prevented the device's IP number(s) and port numbers being advertised when using `tinysvcmdns` has been fixed. (Cause: name needed to have a `.local` suffix.) * Bugs causing the shairport service to semi-randomly disappear and reappear seem to be fixed. (Possible cause: incorrect timing settings when using `tinysvcmdns`.) Version 2.1.11 ----- * Enhancement * A man page is now installed -- do `man shairport-sync` or see it here: http://htmlpreview.github.io/?https://github.com/mikebrady/shairport-sync/blob/2.1/man/shairport-sync.html. Version 2.1.10 ----- * Bugfix * A bug that caused the `-t` timeout value to be incorrectly assigned has been fixed. (Cause: `config.timeout` defined as `int64_t` instead on `int`.) Version 2.1.9 ----- * Bugfixes * A bug that sometimes caused the initial volume setting to be ignored has been fixed. (Cause: setting volume before opening device.) * a bug that caused shairport-sync to become unresponsive or unavailable has been fixed. (Cause: draining rather than flushing the alsa device before stopping.) Version 2.1.8: ----- * Enhancements * (This feature is intended to be useful to integrators.) Shairport Sync now the ability to immediately disconnect and reconnect to the sound output device while continuing to stream audio data from its client. Send a `SIGUSR2` to the shairport-sync process to disconnect or send it a `SIGHUP` to reconnect. If shairport-sync has been started as a daemon using `shairport-sync -d`, then executing `shairport-sync -D` or `--disconnectFromOutput` will request the daemon to disconnect, and executing `shairport-sync -R` or `--reconnectToOutput` will request it to reconnect. With this feature, you can allow Shairport Sync always to advertise and provide the streaming service, but still be able to disconnect it locally to enable other audio services to access the output device. * Annoying things you should know about if you're updating from a previous version: * Options `--with-openssl`, `--with-polarssl` have been replaced with a new option `--with-ssl=