Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package shairport-sync for
openSUSE:Leap:16.0 checked in at 2025-06-02 11:53:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Leap:16.0/shairport-sync (Old)
and /work/SRC/openSUSE:Leap:16.0/.shairport-sync.new.16005 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "shairport-sync"
Mon Jun 2 11:53:00 2025 rev:2 rq:1281802 version:4.3.7
Changes:
--------
--- /work/SRC/openSUSE:Leap:16.0/shairport-sync/shairport-sync.changes
2025-03-19 11:57:37.085152259 +0100
+++
/work/SRC/openSUSE:Leap:16.0/.shairport-sync.new.16005/shairport-sync.changes
2025-06-02 11:53:00.921167157 +0200
@@ -1,0 +2,45 @@
+Tue May 6 08:43:38 UTC 2025 - Bjørn Lie <[email protected]>
+
+- Replace obsolete gnome-common with libtool BuildRequires.
+
+-------------------------------------------------------------------
+Mon Feb 3 12:34:25 UTC 2025 - Wolfgang Frisch <[email protected]>
+
+- Update version to 4.3.7
+ - This update comprises updates to GitHub Actions used for testing and for
+ building Docker.
+
+- Update version to 4.3.6
+ - Bug fixes
+ - Fix a potential bug (no issues reported) by checking that a buffer is not
+ zero before attempting to deallocate it.
+ - Documentation updates
+ - Show how to use MQTTThing with Homebridge to represent Shairport Sync’s
+ active status.
+ - Correct and clarify the statistics documentation.
+ - Fix a typo in the configuration file.
+
+-------------------------------------------------------------------
+Mon Dec 2 15:04:13 UTC 2024 - Wolfgang Frisch <[email protected]>
+
+- Update version to 4.3.5
+ * https://github.com/mikebrady/shairport-sync/releases/tag/4.3.5
+ * Add Home Assistant MQTT Auto-Discovery and active/playing State Messages.
+ Thanks to aaronk6 for their considerable work and code -- see this PR.
+ * Send pvol metadata on mute, thanks to Tucker Kern.
+ * Ensure the PipeWire backend is initially inactive and that it goes active at
+ the start of a play session and inactive at the end. This is to facilitate
+ external activity-monitoring software. Thanks to Nemo157. 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.
+ * Fix a bug in the Jack Audio backend. If the system's Jack Audio 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.
+ * Fix an incompatibility with the recently-introduced FFmpeg version 7. Thanks
+ to Deyan Dragov.
+ * Stop advertising the SFTP and SSH services on Bonjour. Thanks to
+ Jean-Philippe Baril.
+
+-------------------------------------------------------------------
Old:
----
shairport-sync-4.3.4.tar.gz
New:
----
shairport-sync-4.3.7.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ shairport-sync.spec ++++++
--- /var/tmp/diff_new_pack.dBUyJx/_old 2025-06-02 11:53:01.209179112 +0200
+++ /var/tmp/diff_new_pack.dBUyJx/_new 2025-06-02 11:53:01.209179112 +0200
@@ -1,7 +1,7 @@
#
# spec file for package shairport-sync
#
-# Copyright (c) 2024 SUSE LLC
+# Copyright (c) 2025 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
Name: shairport-sync
-Version: 4.3.4
+Version: 4.3.7
Release: 0
Summary: An AirPlay audio player
License: GPL-3.0-only
@@ -30,7 +30,7 @@
BuildRequires: fdupes
BuildRequires: firewall-macros
BuildRequires: gcc-c++
-BuildRequires: gnome-common
+BuildRequires: libtool
BuildRequires: pkgconfig
BuildRequires: systemd-rpm-macros
BuildRequires: xxd
++++++ shairport-sync-4.3.4.tar.gz -> shairport-sync-4.3.7.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/shairport-sync-4.3.4/.github/workflows/check_ap2_systemd_basic.yml
new/shairport-sync-4.3.7/.github/workflows/check_ap2_systemd_basic.yml
--- old/shairport-sync-4.3.4/.github/workflows/check_ap2_systemd_basic.yml
2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/.github/workflows/check_ap2_systemd_basic.yml
2025-01-31 15:57:31.000000000 +0100
@@ -13,9 +13,9 @@
runs-on: ubuntu-22.04
steps:
- - uses: actions/[email protected]
+ - uses: actions/[email protected]
- name: Install Dependencies
- run: sudo apt-get -y --no-install-recommends install build-essential git
xmltoman autoconf automake libtool libpopt-dev libconfig-dev libasound2-dev
avahi-daemon libavahi-client-dev libssl-dev libsoxr-dev libplist-dev
libsodium-dev libavutil-dev libavcodec-dev libavformat-dev uuid-dev
libgcrypt-dev xxd
+ run: sudo apt-get -y --no-install-recommends install xmltoman
libpopt-dev libconfig-dev libasound2-dev avahi-daemon libavahi-client-dev
libsoxr-dev libplist-dev libsodium-dev libavutil-dev libavcodec-dev
libavformat-dev
- name: Configure
run: |
mkdir build
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/shairport-sync-4.3.4/.github/workflows/check_ap2_systemd_full.yml
new/shairport-sync-4.3.7/.github/workflows/check_ap2_systemd_full.yml
--- old/shairport-sync-4.3.4/.github/workflows/check_ap2_systemd_full.yml
2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/.github/workflows/check_ap2_systemd_full.yml
2025-01-31 15:57:31.000000000 +0100
@@ -3,7 +3,7 @@
on:
workflow_dispatch:
push:
- branches: [ "development", "danger" ]
+ branches: [ "development" ]
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
@@ -13,13 +13,13 @@
runs-on: ubuntu-22.04
steps:
- - uses: actions/[email protected]
+ - uses: actions/[email protected]
- name: Install Dependencies
- run: sudo apt-get -y --no-install-recommends install build-essential git
xmltoman autoconf automake libtool libpopt-dev libconfig-dev libasound2-dev
libao-dev libjack-dev libsndio-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 xxd
+ run: sudo apt-get -y --no-install-recommends install 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
- name: Configure
run: |
- autoreconf -i
- ./configure --sysconfdir=/etc --with-alsa --with-ao --with-dummy
--with-jack --with-pipe --with-sndio --with-stdout --with-soxr --with-avahi
--with-ssl=openssl --with-systemd --with-dbus-interface --with-mpris-interface
--with-mqtt-client --with-airplay-2
+ 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 --with-dbus-interface --with-mpris-interface
--with-mqtt-client --with-airplay-2
- name: Make
run: |
make -j
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/shairport-sync-4.3.4/.github/workflows/check_ap2_systemd_full_build_folder.yml
new/shairport-sync-4.3.7/.github/workflows/check_ap2_systemd_full_build_folder.yml
---
old/shairport-sync-4.3.4/.github/workflows/check_ap2_systemd_full_build_folder.yml
2024-07-06 12:56:10.000000000 +0200
+++
new/shairport-sync-4.3.7/.github/workflows/check_ap2_systemd_full_build_folder.yml
2025-01-31 15:57:31.000000000 +0100
@@ -13,15 +13,15 @@
runs-on: ubuntu-22.04
steps:
- - uses: actions/[email protected]
+ - uses: actions/[email protected]
- name: Install Dependencies
- run: sudo apt-get -y --no-install-recommends install build-essential git
xmltoman autoconf automake libtool libpopt-dev libconfig-dev libasound2-dev
libao-dev libjack-dev libsndio-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 xxd
+ run: sudo apt-get -y --no-install-recommends install 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
- name: Configure
run: |
mkdir build
cd build
autoreconf -i ..
- ../configure --sysconfdir=/etc --with-alsa --with-ao --with-dummy
--with-jack --with-pipe --with-sndio --with-stdout --with-soxr --with-avahi
--with-ssl=openssl --with-systemd --with-dbus-interface --with-mpris-interface
--with-mqtt-client --with-airplay-2
+ ../configure --sysconfdir=/etc --with-alsa --with-ao --with-dummy
--with-jack --with-pipe --with-stdout --with-soxr --with-avahi
--with-ssl=openssl --with-systemd --with-dbus-interface --with-mpris-interface
--with-mqtt-client --with-airplay-2
- name: Make
run: |
cd build
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/shairport-sync-4.3.4/.github/workflows/check_ap2_systemv_full.yml
new/shairport-sync-4.3.7/.github/workflows/check_ap2_systemv_full.yml
--- old/shairport-sync-4.3.4/.github/workflows/check_ap2_systemv_full.yml
2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/.github/workflows/check_ap2_systemv_full.yml
2025-01-31 15:57:31.000000000 +0100
@@ -13,13 +13,13 @@
runs-on: ubuntu-22.04
steps:
- - uses: actions/[email protected]
+ - uses: actions/[email protected]
- name: Install Dependencies
- run: sudo apt-get -y --no-install-recommends install build-essential git
xmltoman autoconf automake libtool libpopt-dev libdaemon-dev libconfig-dev
libasound2-dev libao-dev libjack-dev libsndio-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 xxd
+ run: sudo apt-get -y --no-install-recommends install 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-ao --with-dummy
--with-libdaemon --with-jack --with-pipe --with-sndio --with-stdout --with-soxr
--with-avahi --with-ssl=openssl --with-systemv --with-dbus-interface
--with-mpris-interface --with-mqtt-client --with-airplay-2
+ ./configure --sysconfdir=/etc --with-alsa --with-ao --with-dummy
--with-libdaemon --with-jack --with-pipe --with-stdout --with-soxr --with-avahi
--with-ssl=openssl --with-systemv --with-dbus-interface --with-mpris-interface
--with-mqtt-client --with-airplay-2
- name: Make
run: |
make -j
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/shairport-sync-4.3.4/.github/workflows/check_classic_mac_basic.yml
new/shairport-sync-4.3.7/.github/workflows/check_classic_mac_basic.yml
--- old/shairport-sync-4.3.4/.github/workflows/check_classic_mac_basic.yml
2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/.github/workflows/check_classic_mac_basic.yml
2025-01-31 15:57:31.000000000 +0100
@@ -3,7 +3,7 @@
on:
workflow_dispatch:
push:
- branches: [ "development", "danger" ]
+ branches: [ "development" ]
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
@@ -13,7 +13,7 @@
runs-on: macos-13
steps:
- - uses: actions/checkout@v4
+ - uses: actions/[email protected]
- name: Install Dependencies
run: |
brew install automake
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/shairport-sync-4.3.4/.github/workflows/check_classic_systemd_basic.yml
new/shairport-sync-4.3.7/.github/workflows/check_classic_systemd_basic.yml
--- old/shairport-sync-4.3.4/.github/workflows/check_classic_systemd_basic.yml
2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/.github/workflows/check_classic_systemd_basic.yml
2025-01-31 15:57:31.000000000 +0100
@@ -13,9 +13,9 @@
runs-on: ubuntu-22.04
steps:
- - uses: actions/[email protected]
+ - uses: actions/[email protected]
- name: Install Dependencies
- run: sudo apt-get -y --no-install-recommends install build-essential git
xmltoman autoconf automake libtool libpopt-dev libconfig-dev libasound2-dev
avahi-daemon libavahi-client-dev libssl-dev libsoxr-dev
+ 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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/shairport-sync-4.3.4/.github/workflows/check_classic_systemd_full.yml
new/shairport-sync-4.3.7/.github/workflows/check_classic_systemd_full.yml
--- old/shairport-sync-4.3.4/.github/workflows/check_classic_systemd_full.yml
2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/.github/workflows/check_classic_systemd_full.yml
2025-01-31 15:57:31.000000000 +0100
@@ -3,7 +3,7 @@
on:
workflow_dispatch:
push:
- branches: [ "development", "danger" ]
+ branches: [ "development" ]
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
@@ -13,9 +13,9 @@
runs-on: ubuntu-22.04
steps:
- - uses: actions/[email protected]
+ - uses: actions/[email protected]
- name: Install Dependencies
- run: sudo apt-get -y --no-install-recommends install build-essential git
xmltoman autoconf automake libtool libpopt-dev libconfig-dev libasound2-dev
libao-dev libjack-dev libsndio-dev libglib2.0-dev libmosquitto-dev avahi-daemon
libavahi-client-dev libssl-dev libsoxr-dev
+ run: sudo apt-get -y --no-install-recommends install 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
- name: Configure
run: |
mkdir build
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/shairport-sync-4.3.4/.github/workflows/docker-build-on-push_and_pull_request.yaml
new/shairport-sync-4.3.7/.github/workflows/docker-build-on-push_and_pull_request.yaml
---
old/shairport-sync-4.3.4/.github/workflows/docker-build-on-push_and_pull_request.yaml
2024-07-06 12:56:10.000000000 +0200
+++
new/shairport-sync-4.3.7/.github/workflows/docker-build-on-push_and_pull_request.yaml
2025-01-31 15:57:31.000000000 +0100
@@ -22,10 +22,10 @@
jobs:
test-build-on-pull-request:
if: github.event_name == 'pull_request'
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
steps:
- name: Checkout Repo
- uses: actions/checkout@v3
+ uses: actions/[email protected]
with:
fetch-depth: 0
ref: ${{github.event.pull_request.head.ref}}
@@ -38,13 +38,13 @@
echo "SHAIRPORT_SYNC_BRANCH=${SHAIRPORT_SYNC_BRANCH}" >> $GITHUB_ENV
- name: Set up QEMU
- uses: docker/[email protected]
+ uses: docker/[email protected]
- name: Set up Docker Buildx
- uses: docker/[email protected]
+ uses: docker/[email protected]
- name: Build (classic)
- uses: docker/[email protected]
+ uses: docker/[email protected]
with:
context: ./
file: ./docker/classic/Dockerfile
@@ -53,7 +53,7 @@
SHAIRPORT_SYNC_BRANCH=${{ env.SHAIRPORT_SYNC_BRANCH }}
- name: Build
- uses: docker/[email protected]
+ uses: docker/[email protected]
with:
context: ./
file: ./docker/Dockerfile
@@ -64,10 +64,10 @@
build-and-publish:
if: github.event_name != 'pull_request'
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
steps:
- name: Checkout
- uses: actions/[email protected]
+ uses: actions/[email protected]
with:
fetch-depth: 0
@@ -86,20 +86,20 @@
echo "IMAGE_TAG_BASE=development" >> $GITHUB_ENV
- name: Set up QEMU
- uses: docker/[email protected]
+ uses: docker/[email protected]
- name: Set up Docker Buildx
- uses: docker/[email protected]
+ uses: docker/[email protected]
- name: Login to Docker Registry
- uses: docker/[email protected]
+ uses: docker/[email protected]
with:
registry: ${{ secrets.DOCKER_REGISTRY }}
username: ${{ secrets.DOCKER_REGISTRY_USER }}
password: ${{ secrets.DOCKER_REGISTRY_TOKEN }}
- name: Build and push (classic)
- uses: docker/[email protected]
+ uses: docker/[email protected]
with:
context: ./
file: ./docker/classic/Dockerfile
@@ -110,7 +110,7 @@
SHAIRPORT_SYNC_BRANCH=${{ env.SHAIRPORT_SYNC_BRANCH }}
- name: Build and push
- uses: docker/[email protected]
+ uses: docker/[email protected]
with:
context: ./
file: ./docker/Dockerfile
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/shairport-sync-4.3.4/.github/workflows/docker-build-on-tag.yaml
new/shairport-sync-4.3.7/.github/workflows/docker-build-on-tag.yaml
--- old/shairport-sync-4.3.4/.github/workflows/docker-build-on-tag.yaml
2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/.github/workflows/docker-build-on-tag.yaml
2025-01-31 15:57:31.000000000 +0100
@@ -1,9 +1,9 @@
-# Builds & pushes a docker image when a tag is created.
+# Builds & pushes a docker image when a tag is created.
# Tag pattern: '[tag]' & '[tag]-classic'
# 'latest' & 'classic' also, when master tagged.
# Only pushes the tag when it matches one of the following patterns:
-# X, X.Y or X.Y.Z
+# X, X.Y or X.Y.Z
name: Build and push docker (tag)
@@ -21,10 +21,10 @@
jobs:
main:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
steps:
- name: Checkout
- uses: actions/[email protected]
+ uses: actions/[email protected]
with:
fetch-depth: 0
@@ -47,20 +47,20 @@
echo "NQPTP_BRANCH=development" >> $GITHUB_ENV
- name: Set up QEMU
- uses: docker/[email protected]
+ uses: docker/[email protected]
- name: Set up Docker Buildx
- uses: docker/[email protected]
+ uses: docker/[email protected]
- name: Login to Docker Registry
- uses: docker/[email protected]
+ uses: docker/[email protected]
with:
registry: ${{ secrets.DOCKER_REGISTRY }}
username: ${{ secrets.DOCKER_REGISTRY_USER }}
password: ${{ secrets.DOCKER_REGISTRY_TOKEN }}
- name: Build and push (classic)
- uses: docker/[email protected]
+ uses: docker/[email protected]
with:
context: ./
file: ./docker/classic/Dockerfile
@@ -73,7 +73,7 @@
SHAIRPORT_SYNC_BRANCH=${{ env.SHAIRPORT_SYNC_BRANCH }}
- name: Build and push
- uses: docker/[email protected]
+ uses: docker/[email protected]
with:
context: ./
file: ./docker/Dockerfile
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/.github/workflows/stale.yaml
new/shairport-sync-4.3.7/.github/workflows/stale.yaml
--- old/shairport-sync-4.3.4/.github/workflows/stale.yaml 2024-07-06
12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/.github/workflows/stale.yaml 2025-01-31
15:57:31.000000000 +0100
@@ -11,7 +11,7 @@
stale:
runs-on: ubuntu-latest
steps:
- - uses: actions/[email protected]
+ - uses: actions/[email protected]
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.'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' "old/shairport-sync-4.3.4/ADVANCED TOPICS/Statistics.md"
"new/shairport-sync-4.3.7/ADVANCED TOPICS/Statistics.md"
--- "old/shairport-sync-4.3.4/ADVANCED TOPICS/Statistics.md" 2024-07-06
12:56:10.000000000 +0200
+++ "new/shairport-sync-4.3.7/ADVANCED TOPICS/Statistics.md" 2025-01-31
15:57:31.000000000 +0100
@@ -2,7 +2,7 @@
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. The number
represents is the ratio of frames added and removed from the audio stream
relative to all the frames output in the last interval, 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.
+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.
@@ -16,9 +16,9 @@
##### 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 total amount of interpolation done by Shairport Sync to keep the
audio stream in sync. The number represents is the total number of frames added
and removed from the audio stream, expressed in parts per million (PPM) in the
last interval. For reference, adding or removing one frame per second into a
44,100 frames per second stream is 22.68 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 net amount of interpolation done by Shairport Sync to keep the
audio stream in sync. The number represents is the number of frames added plus
the number removed from the audio stream, expressed in parts per million (PPM)
in the last interval. 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.
+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.
##### 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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/BUILD.md
new/shairport-sync-4.3.7/BUILD.md
--- old/shairport-sync-4.3.4/BUILD.md 2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/BUILD.md 2025-01-31 15:57:31.000000000 +0100
@@ -107,12 +107,12 @@
Next, install the packages that are needed for Shairport Sync and NQPTP:
```
-# pkg install git autotools pkgconf popt libconfig openssl alsa-utils \
+# pkg install git autotools pkgconf popt libconfig openssl alsa-utils libsoxr \
libplist libsodium ffmpeg e2fsprogs-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
+# pkg install git autotools pkgconf popt libconfig openssl alsa-utils libsoxr
```
## 3. Build
### NQPTP
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' "old/shairport-sync-4.3.4/MAKING PULL REQUESTS.md"
"new/shairport-sync-4.3.7/MAKING PULL REQUESTS.md"
--- "old/shairport-sync-4.3.4/MAKING PULL REQUESTS.md" 1970-01-01
01:00:00.000000000 +0100
+++ "new/shairport-sync-4.3.7/MAKING PULL REQUESTS.md" 2025-01-31
15:57:31.000000000 +0100
@@ -0,0 +1,6 @@
+Making Pull Requests
+====
+
+If you would like to make pull requests (PRs) to Shairport Sync, please base
them on the `development` branch.
+
+Changes and additions in the `development` branch make their way eventually to
the `master` branch.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/MQTT.md
new/shairport-sync-4.3.7/MQTT.md
--- old/shairport-sync-4.3.4/MQTT.md 2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/MQTT.md 2025-01-31 15:57:31.000000000 +0100
@@ -199,3 +199,36 @@
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.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/RELEASENOTES.md
new/shairport-sync-4.3.7/RELEASENOTES.md
--- old/shairport-sync-4.3.4/RELEASENOTES.md 2024-07-06 12:56:10.000000000
+0200
+++ new/shairport-sync-4.3.7/RELEASENOTES.md 2025-01-31 15:57:31.000000000
+0100
@@ -1,6 +1,6 @@
Minor Release Notes
====
-Minor release notes are attached to the release themselves.
+Minor release notes are attached to the releases themselves.
Version 4.3 -- Security Updates, Bug Fixes and Enhancements
====
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/audio.h
new/shairport-sync-4.3.7/audio.h
--- old/shairport-sync-4.3.4/audio.h 2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/audio.h 2025-01-31 15:57:31.000000000 +0100
@@ -31,6 +31,7 @@
int (*init)(int argc, char **argv);
// at end of program
void (*deinit)(void);
+ void (*prepare_to_play)(void); // sent when audio is received for the first
time -- advance warning.
int (*prepare)(void); // looks and sets stuff in the config data structure
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/audio_jack.c
new/shairport-sync-4.3.7/audio_jack.c
--- old/shairport-sync-4.3.4/audio_jack.c 2024-07-06 12:56:10.000000000
+0200
+++ new/shairport-sync-4.3.7/audio_jack.c 2025-01-31 15:57:31.000000000
+0100
@@ -1,6 +1,6 @@
/*
* jack output driver. This file is part of Shairport Sync.
- * Copyright (c) 2019 -- 2022 Mike Brady
<[email protected]>,
+ * Copyright (c) 2019 -- 2024 Mike Brady
<[email protected]>,
* Jörn Nettingsmeier <[email protected]>
*
* All rights reserved.
@@ -50,8 +50,11 @@
jack_port_t *port[NPORTS];
const char *port_name[NPORTS] = {"out_L", "out_R"};
+
+int sps_sample_rate;
+
jack_client_t *client;
-jack_nframes_t sample_rate;
+jack_nframes_t jack_sample_rate;
jack_nframes_t jack_latency;
jack_ringbuffer_t *jackbuf;
@@ -85,12 +88,7 @@
#endif
static inline sample_t sample_conv(short sample) {
- // It sounds correct, but I don't understand it.
- // Zero int needs to be zero float. Check.
- // Plus 32767 int is 1.0. Check.
- // Minus 32767 int is -0.99997. And here my brain shuts down.
- // In my head, it should be 1.0, and we should tolerate an overflow
- // at minus 32768. But I'm sure there's a textbook explanation somewhere.
+ // signed 16-bit int to float
return ((sample < 0) ? (-1.0 * sample / SHRT_MIN) : (1.0 * sample /
SHRT_MAX));
}
@@ -235,17 +233,17 @@
if (!client) {
die("Could not start JACK server. JackStatus is %x", status);
}
- sample_rate = jack_get_sample_rate(client);
+ jack_sample_rate = jack_get_sample_rate(client);
#ifdef CONFIG_SOXR
if (config.jack_soxr_resample_quality >= SOXR_QQ) {
quality_spec = soxr_quality_spec(config.jack_soxr_resample_quality, 0);
io_spec = soxr_io_spec(SOXR_INT16_I, SOXR_FLOAT32_I);
} else
#endif
- if (sample_rate != 44100) {
+ if (jack_sample_rate != 44100) {
die("The JACK server is running at the wrong sample rate (%d) for
Shairport Sync."
" Must be 44100 Hz.",
- sample_rate);
+ jack_sample_rate);
}
jack_set_process_callback(client, &process, NULL);
jack_set_graph_order_callback(client, &graph, NULL);
@@ -329,6 +327,7 @@
// Nothing to do, JACK client has already been set up at jack_init().
// Also, we have no say over the sample rate or sample format of JACK,
// We convert the 16bit samples to float, and die if the sample rate is !=
44k1 without soxr.
+ sps_sample_rate = i_sample_rate;
#ifdef CONFIG_SOXR
if (config.jack_soxr_resample_quality >= SOXR_QQ) {
// we might improve a bit with soxr_clear if the sample_rate doesn't change
@@ -336,7 +335,7 @@
soxr_delete(soxr);
}
soxr_error_t e = NULL;
- soxr = soxr_create(i_sample_rate, sample_rate, NPORTS, &e, &io_spec,
&quality_spec, NULL);
+ soxr = soxr_create(sps_sample_rate, jack_sample_rate, NPORTS, &e,
&io_spec, &quality_spec, NULL);
if (!soxr) {
die("Unable to create soxr resampler for JACK: %s", e);
}
@@ -366,13 +365,15 @@
debug(2, "audio_occupancy_now is %d.", audio_occupancy_now);
pthread_mutex_unlock(&buffer_mutex);
- int64_t frames_processed_since_latest_latency_check = (delta * sample_rate)
/ 1000000000;
+ int64_t frames_processed_since_latest_latency_check = (delta *
jack_sample_rate) / 1000000000;
// debug(1,"delta: %" PRId64 "
frames.",frames_processed_since_latest_latency_check);
// jack_latency is set by the graph() callback, it's the average of the
maximum
// latencies of all our output ports. Adjust this constant baseline delay
according
// to the buffer fill level:
- *the_delay = jack_latency + audio_occupancy_now -
frames_processed_since_latest_latency_check;
- // debug(1,"reporting a delay of %d frames",*the_delay);
+ int64_t the_delay_in_jack_frames = jack_latency + audio_occupancy_now -
frames_processed_since_latest_latency_check;
+ int64_t the_delay_in_sps_frames = (the_delay_in_jack_frames *
sps_sample_rate) / jack_sample_rate;
+ *the_delay = the_delay_in_sps_frames;
+ // debug(2, "reporting a delay of %ld frames at Shairport Sync's rate of %d
FPS.",*the_delay, sps_sample_rate);
return 0;
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/audio_pa.c
new/shairport-sync-4.3.7/audio_pa.c
--- old/shairport-sync-4.3.4/audio_pa.c 2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/audio_pa.c 2025-01-31 15:57:31.000000000 +0100
@@ -377,7 +377,7 @@
__attribute__((unused)) void *userdata) {
check_pa_stream_status(stream, "audio_pa stream_write_cb.");
int bytes_to_transfer = requested_bytes;
- int bytes_transferred = 0;
+ // int bytes_transferred = 0;
uint8_t *buffer = NULL;
int ret = 0;
pthread_mutex_lock(&buffer_mutex);
@@ -413,7 +413,7 @@
ret = pa_stream_write(stream, buffer, bytes_we_can_transfer, NULL,
0LL, PA_SEEK_RELATIVE);
audio_toq = audio_lmb + bytes_we_can_transfer - first_portion_to_write;
}
- bytes_transferred += bytes_we_can_transfer;
+ // bytes_transferred += bytes_we_can_transfer;
audio_occupancy -= bytes_we_can_transfer;
bytes_to_transfer -= bytes_we_can_transfer;
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/audio_pw.c
new/shairport-sync-4.3.7/audio_pw.c
--- old/shairport-sync-4.3.4/audio_pw.c 2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/audio_pw.c 2025-01-31 15:57:31.000000000 +0100
@@ -56,6 +56,7 @@
static size_t audio_size = buffer_allocation;
static size_t audio_occupancy;
static int enable_fill;
+static int stream_is_active;
struct timing_data {
int pw_time_is_valid; // set when the pw_time has been set
@@ -268,9 +269,9 @@
// called in a realtime thread.
pw_stream_connect(data.stream, PW_DIRECTION_OUTPUT, PW_ID_ANY,
PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS |
- PW_STREAM_FLAG_RT_PROCESS,
+ PW_STREAM_FLAG_RT_PROCESS | PW_STREAM_FLAG_INACTIVE,
params, 1);
-
+ stream_is_active = 0;
pw_thread_loop_unlock(data.loop);
return 0;
}
@@ -279,9 +280,27 @@
__attribute__((unused)) int sample_format) {
}
+static void prepare_to_play() {
+ // debug(1, "prepare to play");
+ if (stream_is_active == 0) {
+ pw_thread_loop_lock(data.loop);
+ pw_stream_set_active(data.stream, true);
+ pw_thread_loop_unlock(data.loop);
+ stream_is_active = 1;
+ debug(3, "prepare to play activating stream");
+ }
+}
+
static int play(__attribute__((unused)) void *buf, int samples,
__attribute__((unused)) int sample_type,
__attribute__((unused)) uint32_t timestamp,
__attribute__((unused)) uint64_t playtime) {
+ if (stream_is_active == 0) {
+ pw_thread_loop_lock(data.loop);
+ pw_stream_set_active(data.stream, true);
+ pw_thread_loop_unlock(data.loop);
+ stream_is_active = 1;
+ debug(3, "set stream active");
+ }
// copy the samples into the queue
debug(3, "play %u samples; %u bytes already in the buffer.", samples,
audio_occupancy);
size_t bytes_to_transfer = samples * DEFAULT_CHANNELS *
DEFAULT_BYTES_PER_SAMPLE;
@@ -382,8 +401,15 @@
// if (enable_fill == 0) {
// debug(1, "stop enable_fill");
// }
- enable_fill = 1;
pthread_mutex_unlock(&buffer_mutex);
+ if (stream_is_active == 1) {
+ pw_thread_loop_lock(data.loop);
+ // pw_stream_flush(data.stream, true);
+ pw_stream_set_active(data.stream, false);
+ pw_thread_loop_unlock(data.loop);
+ stream_is_active = 0;
+ debug(3, "set stream inactive");
+ }
}
audio_output audio_pw = {.name = "pw",
@@ -398,6 +424,7 @@
.delay = &delay,
.stats = NULL,
.play = &play,
+ .prepare_to_play = &prepare_to_play,
.volume = NULL,
.parameters = NULL,
.mute = NULL};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/audio_sndio.c
new/shairport-sync-4.3.7/audio_sndio.c
--- old/shairport-sync-4.3.4/audio_sndio.c 2024-07-06 12:56:10.000000000
+0200
+++ new/shairport-sync-4.3.7/audio_sndio.c 2025-01-31 15:57:31.000000000
+0100
@@ -4,7 +4,7 @@
* Copyright (c) 2017 Tobias Kortkamp <[email protected]>
*
* Modifications for audio synchronisation
- * and related work, copyright (c) Mike Brady 2014 -- 2022
+ * and related work, copyright (c) Mike Brady 2014 -- 2024
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
@@ -30,6 +30,7 @@
static pthread_mutex_t sndio_mutex = PTHREAD_MUTEX_INITIALIZER;
static struct sio_hdl *hdl;
+static int is_running;
static int framesize;
static size_t played;
static size_t written;
@@ -58,7 +59,9 @@
{"S24_3BE", SPS_FORMAT_S24_3BE,
44100, 24, 3, 1, 0},
{"S32", SPS_FORMAT_S32, 44100, 32, 4,
1, SIO_LE_NATIVE}};
-static void help() { printf(" -d output-device set the output device
[default*|...]\n"); }
+static void help() {
+ printf(" -d output-device set the output device
[default|rsnd/0|rsnd/1...]\n");
+}
void onmove_cb(__attribute__((unused)) void *arg, int delta) {
time_of_last_onmove_cb = get_absolute_time_in_ns();
@@ -155,6 +158,7 @@
debug(1, "sndio: rate: %u.", par.rate);
debug(1, "sndio: bits: %u.", par.bits);
+ is_running = 0;
hdl = sio_open(devname, SIO_PLAY, 0);
if (!hdl)
die("sndio: cannot open audio device");
@@ -206,26 +210,15 @@
}
static void deinit() {
- // pthread_mutex_lock(&sndio_mutex);
- pthread_cleanup_debug_mutex_lock(&sndio_mutex, 1000, 1);
- sio_close(hdl);
- // pthread_mutex_unlock(&sndio_mutex);
- pthread_cleanup_pop(1); // unlock the mutex
-}
-
-static void start(__attribute__((unused)) int sample_rate,
- __attribute__((unused)) int sample_format) {
- // pthread_mutex_lock(&sndio_mutex);
pthread_cleanup_debug_mutex_lock(&sndio_mutex, 1000, 1);
- at_least_one_onmove_cb_seen = 0;
- // any previously-reported frame count
-
- if (!sio_start(hdl))
- die("sndio: unable to start");
- written = played = 0;
- time_of_last_onmove_cb = 0;
- at_least_one_onmove_cb_seen = 0;
- // pthread_mutex_unlock(&sndio_mutex);
+ if (hdl != NULL) {
+ if (is_running != 0) {
+ sio_flush(hdl);
+ is_running = 0;
+ }
+ sio_close(hdl);
+ hdl = NULL;
+ }
pthread_cleanup_pop(1); // unlock the mutex
}
@@ -233,10 +226,20 @@
__attribute__((unused)) uint32_t timestamp,
__attribute__((unused)) uint64_t playtime) {
if (frames > 0) {
- // pthread_mutex_lock(&sndio_mutex);
pthread_cleanup_debug_mutex_lock(&sndio_mutex, 1000, 1);
+ if (is_running == 0) {
+ if (hdl != NULL) {
+ if (sio_start(hdl) != 1)
+ debug(1, "sndio: unable to start");
+ is_running = 1;
+ written = played = 0;
+ time_of_last_onmove_cb = 0;
+ at_least_one_onmove_cb_seen = 0;
+ } else {
+ debug(1, "sndio: output device is not open for play!");
+ }
+ }
written += sio_write(hdl, buf, frames * framesize);
- // pthread_mutex_unlock(&sndio_mutex);
pthread_cleanup_pop(1); // unlock the mutex
}
return 0;
@@ -244,10 +247,17 @@
static void stop() {
pthread_cleanup_debug_mutex_lock(&sndio_mutex, 1000, 1);
-
- if (!sio_stop(hdl))
- die("sndio: unable to stop");
- written = played = 0;
+ if (hdl != NULL) {
+ if (is_running != 0) {
+ if (sio_flush(hdl) != 1)
+ debug(1, "sndio: unable to stop");
+ written = played = is_running = 0;
+ } else {
+ debug(1, "sndio: stop: not running.");
+ }
+ } else {
+ debug(1, "sndio: output device is not open for stop!");
+ }
pthread_cleanup_pop(1); // unlock the mutex
}
@@ -276,18 +286,34 @@
static int delay(long *delay) {
int result = 0;
pthread_cleanup_debug_mutex_lock(&sndio_mutex, 1000, 1);
- result = get_delay(delay);
+ if (hdl != NULL) {
+ if (is_running != 0) {
+ result = get_delay(delay);
+ } else {
+ debug(1, "sndio: output device is not open for delay!");
+ if (delay != NULL)
+ *delay = 0;
+ }
+ } else {
+ debug(1, "sndio: output device is not open for delay!");
+ }
pthread_cleanup_pop(1); // unlock the mutex
return result;
}
static void flush() {
- // pthread_mutex_lock(&sndio_mutex);
pthread_cleanup_debug_mutex_lock(&sndio_mutex, 1000, 1);
- if (!sio_stop(hdl) || !sio_start(hdl))
- die("sndio: unable to flush");
- written = played = 0;
- // pthread_mutex_unlock(&sndio_mutex);
+ if (hdl != NULL) {
+ if (is_running != 0) {
+ if (sio_flush(hdl) != 1)
+ debug(1, "sndio: unable to flush");
+ written = played = is_running = 0;
+ } else {
+ debug(1, "sndio: flush: not running.");
+ }
+ } else {
+ debug(1, "sndio: output device is not open for flush!");
+ }
pthread_cleanup_pop(1); // unlock the mutex
}
@@ -296,7 +322,7 @@
.init = &init,
.deinit = &deinit,
.prepare = NULL,
- .start = &start,
+ .start = NULL,
.stop = &stop,
.is_running = NULL,
.flush = &flush,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/common.c
new/shairport-sync-4.3.7/common.c
--- old/shairport-sync-4.3.4/common.c 2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/common.c 2025-01-31 15:57:31.000000000 +0100
@@ -574,6 +574,38 @@
pthread_setcancelstate(oldState, NULL);
}
+void _debug_print_buffer(const char *thefilename, const int linenumber, int
level, void *vbuf,
+ size_t buf_len) {
+ if (level > debuglev)
+ return;
+ char *buf = (char *)vbuf;
+ char *obf =
+ malloc(buf_len * 4 + 1); // to be on the safe side -- 4 characters on
average for each byte
+ if (obf != NULL) {
+ char *obfp = obf;
+ unsigned int obfc;
+ for (obfc = 0; obfc < buf_len; obfc++) {
+ snprintf(obfp, 3, "%02X", buf[obfc]);
+ obfp += 2;
+ if (obfc != buf_len - 1) {
+ if (obfc % 32 == 31) {
+ snprintf(obfp, 5, " || ");
+ obfp += 4;
+ } else if (obfc % 16 == 15) {
+ snprintf(obfp, 4, " | ");
+ obfp += 3;
+ } else if (obfc % 4 == 3) {
+ snprintf(obfp, 2, " ");
+ obfp += 1;
+ }
+ }
+ };
+ *obfp = 0;
+ _debug(thefilename, linenumber, level, "%s", obf);
+ free(obf);
+ }
+}
+
// The following two functions are adapted slightly and with thanks from
Jonathan Leffler's sample
// code at
//
https://stackoverflow.com/questions/675039/how-can-i-create-directory-tree-in-c-linux
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/common.h
new/shairport-sync-4.3.7/common.h
--- old/shairport-sync-4.3.4/common.h 2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/common.h 2025-01-31 15:57:31.000000000 +0100
@@ -175,6 +175,8 @@
int mqtt_publish_parsed;
int mqtt_publish_cover;
int mqtt_enable_remote;
+ int mqtt_enable_autodiscovery;
+ char *mqtt_autodiscovery_prefix;
char *mqtt_empty_payload_substitute;
#endif
uint8_t ap1_prefix[6];
@@ -382,11 +384,14 @@
void _warn(const char *filename, const int linenumber, const char *format,
...);
void _inform(const char *filename, const int linenumber, const char *format,
...);
void _debug(const char *filename, const int linenumber, int level, const char
*format, ...);
+void _debug_print_buffer(const char *thefilename, const int linenumber, int
level, void *buf,
+ size_t buf_len);
#define die(...) _die(__FILE__, __LINE__, __VA_ARGS__)
#define debug(...) _debug(__FILE__, __LINE__, __VA_ARGS__)
#define warn(...) _warn(__FILE__, __LINE__, __VA_ARGS__)
#define inform(...) _inform(__FILE__, __LINE__, __VA_ARGS__)
+#define debug_print_buffer(...) _debug_print_buffer(__FILE__, __LINE__,
__VA_ARGS__)
uint8_t *base64_dec(char *input, int *outlen);
char *base64_enc(uint8_t *input, int length);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/configure.ac
new/shairport-sync-4.3.7/configure.ac
--- old/shairport-sync-4.3.4/configure.ac 2024-07-06 12:56:10.000000000
+0200
+++ new/shairport-sync-4.3.7/configure.ac 2025-01-31 15:57:31.000000000
+0100
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.50])
-AC_INIT([shairport-sync], [4.3.4],
[[email protected]])
+AC_INIT([shairport-sync], [4.3.7],
[[email protected]])
AM_INIT_AUTOMAKE([subdir-objects])
AC_CONFIG_SRCDIR([shairport.c])
AC_CONFIG_HEADERS([config.h])
@@ -300,8 +300,9 @@
# Look for Soundio flag
AC_ARG_WITH(soundio, [AS_HELP_STRING([--with-soundio],[choose soundio API
support.])])
if test "x$with_soundio" = "xyes" ; then
- AC_DEFINE([CONFIG_SOUNDIO], 1, [Include SoundIO Support.])
- AC_CHECK_LIB([soundio], [soundio_create], , AC_MSG_ERROR(soundio support
requires the soundio library -- libsoundio-dev suggested))
+ AC_DEFINE([CONFIG_SOUNDIO], 1, [Include the SoundIO (libsoundio) backend.])
+ AC_CHECK_LIB([soundio], [soundio_create], , AC_MSG_ERROR(soundio support
requires the libsoundio library -- libsoundio-dev suggested (note: the soundio
backend is deprecated and will be removed in a future update)))
+ AC_MSG_WARN([The soundio (libsoundio) backend is deprecated and will be
removed in a future update.])
fi
AM_CONDITIONAL([USE_SOUNDIO], [test "x$with_soundio" = "xyes"])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/docker/Dockerfile
new/shairport-sync-4.3.7/docker/Dockerfile
--- old/shairport-sync-4.3.4/docker/Dockerfile 2024-07-06 12:56:10.000000000
+0200
+++ new/shairport-sync-4.3.7/docker/Dockerfile 2025-01-31 15:57:31.000000000
+0100
@@ -1,11 +1,7 @@
-FROM alpine:3.17 AS builder
+ARG NQPTP_BRANCH=main
+ARG SHAIRPORT_SYNC_BRANCH=.
-# Check required arguments exist. These will be provided by the Github Action
-# Workflow and are required to ensure the correct branches are being used.
-ARG SHAIRPORT_SYNC_BRANCH
-RUN test -n "$SHAIRPORT_SYNC_BRANCH"
-ARG NQPTP_BRANCH
-RUN test -n "$NQPTP_BRANCH"
+FROM alpine:3.20 AS builder
RUN apk -U add \
alsa-lib-dev \
@@ -23,6 +19,7 @@
libsndfile-dev \
libsodium-dev \
libtool \
+ pipewire-dev \
mosquitto-dev \
popt-dev \
pulseaudio-dev \
@@ -30,26 +27,32 @@
xxd
##### ALAC #####
-RUN git clone https://github.com/mikebrady/alac
+FROM builder AS alac
+RUN git clone --depth=1 https://github.com/mikebrady/alac
WORKDIR /alac
RUN autoreconf -i
RUN ./configure
-RUN make
+RUN make -j $(nproc)
RUN make install
WORKDIR /
##### ALAC END #####
##### NQPTP #####
-RUN git clone https://github.com/mikebrady/nqptp
+FROM builder AS nqptp
+ARG NQPTP_BRANCH
+RUN git clone --depth=1 -b "$NQPTP_BRANCH" https://github.com/mikebrady/nqptp
WORKDIR /nqptp
-RUN git checkout "$NQPTP_BRANCH"
RUN autoreconf -i
RUN ./configure
-RUN make
+RUN make -j $(nproc)
WORKDIR /
##### NQPTP END #####
##### SPS #####
+# Note: apple-alac requires alac build first.
+FROM alac AS shairport-sync
+ARG SHAIRPORT_SYNC_BRANCH
+
WORKDIR /shairport-sync
COPY . .
RUN git checkout "$SHAIRPORT_SYNC_BRANCH"
@@ -58,14 +61,36 @@
RUN CFLAGS="-O3" CXXFLAGS="-O3" ../configure --sysconfdir=/etc --with-alsa
--with-pa --with-soxr --with-avahi --with-ssl=openssl \
--with-airplay-2 --with-metadata --with-dummy --with-pipe
--with-dbus-interface \
--with-stdout --with-mpris-interface --with-mqtt-client \
- --with-apple-alac --with-convolution
+ --with-apple-alac --with-convolution --with-pw
RUN make -j $(nproc)
RUN DESTDIR=install make install
WORKDIR /
##### SPS END #####
+##### STATIC FILES #####
+FROM scratch AS files
+
+# Add run script that will start SPS
+COPY --chmod=755 ./docker/run.sh ./run.sh
+COPY ./docker/etc/s6-overlay/s6-rc.d /etc/s6-overlay/s6-rc.d
+COPY ./docker/etc/pulse /etc/pulse
+##### END STATIC FILES #####
+
+##### BUILD FILES #####
+FROM scratch AS build-files
+
+COPY --from=shairport-sync
/shairport-sync/build/install/usr/local/bin/shairport-sync
/usr/local/bin/shairport-sync
+COPY --from=shairport-sync
/shairport-sync/build/install/usr/local/share/man/man1 /usr/share/man/man1
+COPY --from=nqptp /nqptp/nqptp /usr/local/bin/nqptp
+COPY --from=alac /usr/local/lib/libalac.* /usr/local/lib/
+COPY --from=shairport-sync
/shairport-sync/build/install/etc/shairport-sync.conf /etc/
+COPY --from=shairport-sync
/shairport-sync/build/install/etc/shairport-sync.conf.sample /etc/
+COPY --from=shairport-sync
/shairport-sync/build/install/etc/dbus-1/system.d/shairport-sync-dbus.conf
/etc/dbus-1/system.d/
+COPY --from=shairport-sync
/shairport-sync/build/install/etc/dbus-1/system.d/shairport-sync-mpris.conf
/etc/dbus-1/system.d/
+##### END BUILD FILES #####
+
# Shairport Sync Runtime System
-FROM crazymax/alpine-s6:3.17-3.1.1.2
+FROM crazymax/alpine-s6:3.20-3.2.0.2
ENV S6_CMD_WAIT_FOR_SERVICES=1
ENV S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0
@@ -83,44 +108,35 @@
libgcrypt \
libplist \
libpulse \
- libressl3.6-libcrypto \
+ libressl3.8-libcrypto \
libsndfile \
libsodium \
libuuid \
+ pipewire \
man-pages \
mandoc \
mosquitto \
popt \
- soxr
+ soxr \
+ curl
-# Copy build files.
-COPY --from=builder /shairport-sync/build/install/usr/local/bin/shairport-sync
/usr/local/bin/shairport-sync
-COPY --from=builder /shairport-sync/build/install/usr/local/share/man/man1
/usr/share/man/man1
-COPY --from=builder /nqptp/nqptp /usr/local/bin/nqptp
-COPY --from=builder /usr/local/lib/libalac.* /usr/local/lib/
-COPY --from=builder /shairport-sync/build/install/etc/shairport-sync.conf /etc/
-COPY --from=builder
/shairport-sync/build/install/etc/shairport-sync.conf.sample /etc/
-COPY --from=builder
/shairport-sync/build/install/etc/dbus-1/system.d/shairport-sync-dbus.conf
/etc/dbus-1/system.d/
-COPY --from=builder
/shairport-sync/build/install/etc/dbus-1/system.d/shairport-sync-mpris.conf
/etc/dbus-1/system.d/
+RUN rm -rfv /lib/apk/db/* && \
+ rm -rfv /etc/avahi/services/*.service && \
+ addgroup shairport-sync && \
+ adduser -D shairport-sync -G shairport-sync && \
+ addgroup -g 29 docker_audio && \
+ addgroup shairport-sync docker_audio && \
+ addgroup shairport-sync audio && \
+ mkdir -p /run/dbus
-COPY ./docker/etc/s6-overlay/s6-rc.d /etc/s6-overlay/s6-rc.d
-COPY ./docker/etc/pulse /etc/pulse
-RUN chmod +x /etc/s6-overlay/s6-rc.d/01-startup/script.sh
+# Remove anything we don't need.
+# Remove any statically-defined Avahi services, e.g. SSH and SFTP
# Create non-root user for running the container -- running as the user
'shairport-sync' also allows
# Shairport Sync to provide the D-Bus and MPRIS interfaces within the container
-
-RUN addgroup shairport-sync
-RUN adduser -D shairport-sync -G shairport-sync
-
# Add the shairport-sync user to the pre-existing audio group, which has ID
29, for access to the ALSA stuff
-RUN addgroup -g 29 docker_audio && addgroup shairport-sync docker_audio &&
addgroup shairport-sync audio
-# Remove anything we don't need.
-RUN rm -rf /lib/apk/db/*
-
-# Add run script that will start SPS
-COPY ./docker/run.sh ./run.sh
-RUN chmod +x /run.sh
+COPY --from=files / /
+COPY --from=build-files / /
-Entrypoint ["/init","./run.sh"]
+ENTRYPOINT ["/init","./run.sh"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/docker/classic/Dockerfile
new/shairport-sync-4.3.7/docker/classic/Dockerfile
--- old/shairport-sync-4.3.4/docker/classic/Dockerfile 2024-07-06
12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/docker/classic/Dockerfile 2025-01-31
15:57:31.000000000 +0100
@@ -1,4 +1,6 @@
-FROM alpine:3.17 AS builder
+ARG SHAIRPORT_SYNC_BRANCH=.
+
+FROM alpine:3.20 AS builder
# Classic (aka AirPlay 1) Build
@@ -18,7 +20,7 @@
libconfig-dev \
libsndfile-dev \
libtool \
- mbedtls-dev \
+ openssl-dev \
mosquitto-dev \
popt-dev \
pulseaudio-dev \
@@ -29,7 +31,7 @@
WORKDIR /alac
RUN autoreconf -i
RUN ./configure
-RUN make
+RUN make -j $(nproc)
RUN make install
WORKDIR /
##### ALAC END #####
@@ -40,7 +42,7 @@
RUN git checkout "$SHAIRPORT_SYNC_BRANCH"
WORKDIR /shairport-sync/build
RUN autoreconf -i ../
-RUN CFLAGS="-O3" CXXFLAGS="-O3" ../configure --sysconfdir=/etc --with-alsa
--with-pa --with-soxr --with-avahi --with-ssl=mbedtls \
+RUN CFLAGS="-O3" CXXFLAGS="-O3" ../configure --sysconfdir=/etc --with-alsa
--with-pa --with-soxr --with-avahi --with-ssl=openssl \
--with-metadata --with-dummy --with-pipe --with-dbus-interface \
--with-stdout --with-mpris-interface --with-mqtt-client \
--with-apple-alac --with-convolution
@@ -50,7 +52,7 @@
##### SPS END #####
# Shairport Sync Runtime System
-FROM crazymax/alpine-s6:3.17-3.1.1.2
+FROM crazymax/alpine-s6:3.20-3.2.0.2
ENV S6_CMD_WAIT_FOR_SERVICES=1
ENV S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0
@@ -68,10 +70,11 @@
libpulse \
man-pages \
mandoc \
- mbedtls \
+ libcrypto3 \
mosquitto \
popt \
- soxr
+ soxr \
+ curl
# Copy build files.
COPY --from=builder /shairport-sync/build/install/usr/local/bin/shairport-sync
/usr/local/bin/shairport-sync
@@ -97,8 +100,14 @@
# Remove anything we don't need.
RUN rm -rf /lib/apk/db/*
+# Remove any statically-defined Avahi services, e.g. SSH and SFTP
+RUN rm -rf /etc/avahi/services/*.service
+
# Add run script that will start SPS
COPY ./docker/run.sh ./run.sh
RUN chmod +x /run.sh
-Entrypoint ["/init","./run.sh"]
+# D-Bus might need this directory
+RUN mkdir -p /run/dbus
+
+ENTRYPOINT ["/init","./run.sh"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/docker/docker-compose.yaml
new/shairport-sync-4.3.7/docker/docker-compose.yaml
--- old/shairport-sync-4.3.4/docker/docker-compose.yaml 2024-07-06
12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/docker/docker-compose.yaml 2025-01-31
15:57:31.000000000 +0100
@@ -9,11 +9,14 @@
# S6_KEEP_ENV: 1 # Allow S6 to pass environment variables from compose
file
# PULSE_SERVER: unix:/tmp/pulseaudio.socket # Path for PulseAudio socket
# PULSE_COOKIE: /tmp/pulseaudio.cookie # Path for PulseAudio cookie
+ # XDG_RUNTIME_DIR: /tmp # Path for pipewire
devices:
- "/dev/snd" # ALSA device, omit if using PulseAudio
# volumes:
# -
./volumes/shairport-sync/shairport-sync.conf:/etc/shairport-sync.conf #
Customised Shairport Sync configuration file.
# - /run/user/1000/pulse/native:/tmp/pulseaudio.socket # PulseAudio
socket when using that backend
+ # - /run/user/1000/pipewire-0:/tmp/pipewire-0 # Pipewire socket when
using pipewire
+ # command: -o pw # You can specify the desired output with command:
logging:
options:
max-size: "200k"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/mqtt.c
new/shairport-sync-4.3.7/mqtt.c
--- old/shairport-sync-4.3.4/mqtt.c 2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/mqtt.c 2025-01-31 15:57:31.000000000 +0100
@@ -90,6 +90,135 @@
snprintf(remotetopic, strlen(config.mqtt_topic) + 8, "%s/remote",
config.mqtt_topic);
mosquitto_subscribe(mosq, NULL, remotetopic, 0);
}
+
+ // send autodiscovery messages if enabled
+ if (config.mqtt_enable_autodiscovery && config.mqtt_publish_parsed) {
+ send_autodiscovery_messages(mosq);
+ }
+}
+
+// function to send autodiscovery messages for Home Assistant
+void send_autodiscovery_messages(struct mosquitto *mosq) {
+ const char *device_name = config.service_name;
+#ifdef CONFIG_AIRPLAY_2
+ const char *device_id = config.airplay_device_id ?
config.airplay_device_id : config.service_name;
+#else
+ const char *device_id = config.service_name;
+#endif
+ const char *device_id_no_colons = str_replace(device_id, ":", "");
+ const char *sw_version = get_version_string();
+ const char *model = "shairport-sync";
+ const char *model_friendly = "Shairport Sync";
+ const char *manufacturer = "Mike Brady";
+ const char *autodiscovery_prefix = (config.mqtt_autodiscovery_prefix !=
NULL) ?
+ config.mqtt_autodiscovery_prefix : "homeassistant";
+
+ char topic[512];
+ char payload[1280];
+ char device_payload[512];
+ char id_string[128];
+
+ snprintf(device_payload, sizeof(device_payload),
+ "\"device\": {"
+ "\"identifiers\": [\"%s\"],"
+ "\"name\": \"%s\","
+ "\"model\": \"%s\","
+ "\"sw_version\": \"%s\","
+ "\"manufacturer\": \"%s\""
+ "}",
+ device_id, device_name, model_friendly, sw_version, manufacturer);
+
+ // when adding sensors here, be sure to also update sensor_names and icons
below!
+ const char *sensors[] = {
+ "artist",
+ "album",
+ "title",
+ "genre",
+ "format",
+ "output_format",
+ "output_frame_rate",
+ "track_id",
+ "client_ip",
+ "client_mac_address",
+ "client_name",
+ "client_model",
+ "client_device_id",
+ "server_ip",
+ "volume",
+ "active",
+ "playing",
+ NULL
+ };
+
+ const char *sensor_names[] = {
+ "Artist",
+ "Album",
+ "Title",
+ "Genre",
+ "Format",
+ "Output Format",
+ "Output Frame Rate",
+ "Track ID",
+ "Client IP",
+ "Client MAC Address",
+ "Client Name",
+ "Client Model",
+ "Client Device ID",
+ "Server IP",
+ "Volume",
+ "Active Session",
+ "Playing"
+ };
+
+ const char *icons[] = {
+ "mdi:account-music", // artist
+ "mdi:album", // album
+ "mdi:music", // title
+ "mdi:music-box-multiple", // genre
+ "mdi:file", // format
+ "mdi:file", // output format
+ "mdi:file-chart", // output frame rate
+ "mdi:identifier", // track ID
+ "mdi:ip", // client IP
+ "mdi:hexadecimal", // client MAC address
+ "mdi:cellphone-text", // client name
+ "mdi:cellphone-text", // client model
+ "mdi:hexadecimal", // client device ID
+ "mdi:ip-network", // server IP
+ "mdi:volume-high", // volume
+ "mdi:play-box-multiple", // active
+ "mdi:play-box-multiple-outline" // playing
+ };
+
+ for (int i = 0; sensors[i] != NULL; i++) {
+ bool is_binary_sensor = (strcmp(sensors[i], "active") == 0 ||
strcmp(sensors[i], "playing") == 0);
+ bool is_volume_sensor = strcmp(sensors[i], "volume") == 0;
+
+ snprintf(topic, sizeof(topic), "%s/%ssensor/%s_%s/%s/config",
+ autodiscovery_prefix, is_binary_sensor ? "binary_" : "",
+ model, device_id_no_colons, sensors[i]);
+
+ snprintf(id_string, sizeof(id_string), "%s_%s_%s", model, device_name,
sensors[i]);
+
+ snprintf(payload, sizeof(payload),
+ "{"
+ "\"name\": \"%s\","
+ "\"state_topic\": \"%s/%s\","
+ "\"icon\": \"%s\","
+ "\"unique_id\": \"%s\","
+ "\"object_id\": \"%s\","
+ "%s%s%s"
+ "}",
+ sensor_names[i], config.mqtt_topic, sensors[i], icons[i],
id_string, id_string,
+ is_binary_sensor ? "\"payload_on\": \"1\",\"payload_off\": \"0\","
: "",
+ is_volume_sensor ? "\"value_template\": \"{{ ((value |
regex_findall_index("
+ "find='^(.+?),', index=0, ignorecase=False) | float / 30 + 1)
* 100) | round(0) }}\","
+ "\"unit_of_measurement\": \"%\"," : "",
+ device_payload);
+
+ mosquitto_publish(mosq, NULL, topic, strlen(payload), payload, 0,
true);
+ debug(2, "[MQTT]: published autodiscovery for %s", id_string);
+ }
}
// helper function to publish under a topic and automatically append the main
topic
@@ -167,12 +296,14 @@
} else if (type == 'ssnc') {
switch (code) {
case 'abeg':
+ mqtt_publish("active", "1", 1);
mqtt_publish("active_start", data, length);
break;
case 'acre':
mqtt_publish("active_remote_id", data, length);
break;
case 'aend':
+ mqtt_publish("active", "0", 1);
mqtt_publish("active_end", data, length);
break;
case 'asal':
@@ -210,9 +341,11 @@
mqtt_publish("output_frame_rate", data, length);
break;
case 'pbeg':
+ mqtt_publish("playing", "1", 1);
mqtt_publish("play_start", data, length);
break;
case 'pend':
+ mqtt_publish("playing", "0", 1);
mqtt_publish("play_end", data, length);
break;
case 'pfls':
@@ -224,6 +357,7 @@
}
break;
case 'prsm':
+ mqtt_publish("playing", "1", 1);
mqtt_publish("play_resume", data, length);
break;
case 'pvol':
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/mqtt.h
new/shairport-sync-4.3.7/mqtt.h
--- old/shairport-sync-4.3.4/mqtt.h 2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/mqtt.h 2025-01-31 15:57:31.000000000 +0100
@@ -7,6 +7,7 @@
void mqtt_process_metadata(uint32_t type, uint32_t code, char *data, uint32_t
length);
void mqtt_publish(char *topic, char *data, uint32_t length);
void mqtt_setup();
+void send_autodiscovery_messages(struct mosquitto *mosq);
void on_connect(struct mosquitto *mosq, void *userdata, int rc);
void on_disconnect(struct mosquitto *mosq, void *userdata, int rc);
void on_message(struct mosquitto *mosq, void *userdata, const struct
mosquitto_message *msg);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/player.c
new/shairport-sync-4.3.7/player.c
--- old/shairport-sync-4.3.4/player.c 2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/player.c 2025-01-31 15:57:31.000000000 +0100
@@ -1179,6 +1179,10 @@
if (conn->ab_buffering) { // if we are getting packets but not yet
forwarding them to the
// player
if (conn->first_packet_timestamp == 0) { // if this is the very
first packet
+
+ if (config.output->prepare_to_play) // tell the player to get
ready
+ config.output->prepare_to_play(); // there could be more than
one of these sent
+
conn->first_packet_timestamp =
curframe->given_timestamp; // we will keep buffering until
we are
// supposed to start playing this
@@ -2141,9 +2145,10 @@
if ((config.output->parameters == NULL) || (conn->input_bit_depth >
output_bit_depth) ||
(config.playback_mode == ST_mono))
conn->enable_dither = 1;
-
- // remember, the output device may never have been initialised prior to this
call
- config.output->start(config.output_rate, config.output_format); // will need
a corresponding stop
+
+ // call the backend's start() function if it exists.
+ if (config.output->start != NULL)
+ config.output->start(config.output_rate, config.output_format);
// we need an intermediate "transition" buffer
@@ -3291,6 +3296,37 @@
pthread_exit(NULL);
}
+static void player_send_volume_metadata(uint8_t vol_mode_both, double
airplay_volume, double scaled_attenuation, int32_t max_db, int32_t min_db,
int32_t hw_max_db)
+{
+#ifdef CONFIG_METADATA
+ // here, send the 'pvol' metadata message when the airplay volume
information
+ // is being used by shairport sync to control the output volume
+ char dv[128];
+ memset(dv, 0, 128);
+ if (config.ignore_volume_control == 0) {
+ if (vol_mode_both == 1) {
+ // normalise the maximum output to the hardware device's max output
+ snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume,
+ (scaled_attenuation - max_db + hw_max_db) / 100.0,
+ (min_db - max_db + hw_max_db) / 100.0, (max_db - max_db +
hw_max_db) / 100.0);
+ } else {
+ snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume,
scaled_attenuation / 100.0,
+ min_db / 100.0, max_db / 100.0);
+ }
+ } else {
+ snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, 0.0, 0.0, 0.0);
+ }
+ send_ssnc_metadata('pvol', dv, strlen(dv), 1);
+#else
+ (void)vol_mode_both;
+ (void)airplay_volume;
+ (void)scaled_attenuation;
+ (void)max_db;
+ (void)min_db;
+ (void)hw_max_db;
+#endif
+}
+
void player_volume_without_notification(double airplay_volume, rtsp_conn_info
*conn) {
debug_mutex_lock(&conn->volume_control_mutex, 5000, 1);
// first, see if we are hw only, sw only, both with hw attenuation on the
top or both with sw
@@ -3379,6 +3415,9 @@
volume_mode, airplay_volume);
}
}
+
+ uint8_t vol_mode_both = (volume_mode == vol_both) ? 1 : 0;
+ player_send_volume_metadata(vol_mode_both, airplay_volume, 0, 0, 0, 0);
} else {
int32_t max_db = 0, min_db = 0;
switch (volume_mode) {
@@ -3489,26 +3528,8 @@
inform("Output Level set to: %.2f dB.", scaled_attenuation / 100.0);
}
-#ifdef CONFIG_METADATA
- // here, send the 'pvol' metadata message when the airplay volume
information
- // is being used by shairport sync to control the output volume
- char dv[128];
- memset(dv, 0, 128);
- if (config.ignore_volume_control == 0) {
- if (volume_mode == vol_both) {
- // normalise the maximum output to the hardware device's max output
- snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume,
- (scaled_attenuation - max_db + hw_max_db) / 100.0,
- (min_db - max_db + hw_max_db) / 100.0, (max_db - max_db +
hw_max_db) / 100.0);
- } else {
- snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume,
scaled_attenuation / 100.0,
- min_db / 100.0, max_db / 100.0);
- }
- } else {
- snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, 0.0, 0.0, 0.0);
- }
- send_ssnc_metadata('pvol', dv, strlen(dv), 1);
-#endif
+ uint8_t vol_mode_both = (volume_mode == vol_both) ? 1 : 0;
+ player_send_volume_metadata(vol_mode_both, airplay_volume,
scaled_attenuation, max_db, min_db, hw_max_db);
if (config.output->mute)
config.output->mute(0);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/rtp.c
new/shairport-sync-4.3.7/rtp.c
--- old/shairport-sync-4.3.4/rtp.c 2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/rtp.c 2025-01-31 15:57:31.000000000 +0100
@@ -2094,10 +2094,10 @@
av_free(codec_context);
}
-void avcodec_open2_cleanup_handler(void *arg) {
- debug(3, "avcodec_open2_cleanup_handler");
- AVCodecContext *codec_context = arg;
- avcodec_close(codec_context);
+void avcodec_open2_cleanup_handler(__attribute__((unused)) void *arg) {
+ debug(3, "avcodec_open2_cleanup_handler -- does nothing right now");
+ // AVCodecContext *codec_context = arg;
+ // avcodec_free_context(&codec_context);
}
void av_parser_init_cleanup_handler(void *arg) {
@@ -2313,8 +2313,15 @@
// push a deallocator -- av_packet_free(pkt);
pthread_cleanup_push(swr_alloc_cleanup_handler, &swr);
+
+// FFmpeg 5.1 or later...
+#if LIBAVUTIL_VERSION_MAJOR >= 57
+ av_opt_set_chlayout(swr, "in_chlayout",
&(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO, 0);
+ av_opt_set_chlayout(swr, "out_chlayout",
&(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO, 0);
+#else
av_opt_set_int(swr, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
+#endif
av_opt_set_int(swr, "in_sample_rate", conn->input_rate, 0);
av_opt_set_int(swr, "out_sample_rate", conn->input_rate,
0); // must match or the timing will be wrong`
@@ -2357,7 +2364,11 @@
};
av_opt_set_sample_fmt(swr, "out_sample_fmt", av_format, 0);
- swr_init(swr);
+ int swr_err = swr_init(swr);
+ if (swr_err !=0){
+ die("FFMpeg swr_init() failed Error %d (%s)",
+ swr_err, av_err2str(swr_err));
+ }
uint8_t packet[16 * 1024];
unsigned char m[16 * 1024]; // leave the first 7 bytes blank to make room
for the ADTS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/rtsp.c
new/shairport-sync-4.3.7/rtsp.c
--- old/shairport-sync-4.3.4/rtsp.c 2024-07-06 12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/rtsp.c 2025-01-31 15:57:31.000000000 +0100
@@ -1179,15 +1179,29 @@
read_encrypted(conn->fd,
&conn->ap2_pairing_context.control_cipher_bundle, buf, count);
} else {
result = read(conn->fd, buf, count);
+ if (result == 0) {
+ debug(3, "AP2 read result 0, for a request count of %u.", count);
+ }
}
#else
result = read(conn->fd, buf, count);
+ if (result == 0) {
+ debug(3, "AP1 read result 0, for a request count of %u.", count);
+
+ }
#endif
+ if ((result == 0) && (errno != 0)) {
+ char errorstring[1024];
+ strerror_r(errno, (char *)errorstring, sizeof(errorstring));
+ debug(2, "Connection %d: read result 0, error %d: \"%s\".",
+ conn->connection_number, errno, (char *)errorstring);
+ }
+
if (wait_time != 0)
remaining_time = time_to_wait_to - get_absolute_time_in_ns();
- if (((result == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) &&
(remaining_time > 0))
+ if ((((result == -1) || (result == 0)) && ((errno == EAGAIN) || (errno
== EWOULDBLOCK))) && (remaining_time > 0))
debug(1, "remaining time on a timed read is %" PRId64 " ns.",
remaining_time);
- } while (((result == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
&&
+ } while ((((result == -1) || (result == 0)) && ((errno == EAGAIN) ||
(errno == EWOULDBLOCK))) &&
(remaining_time > 0));
} else {
@@ -1425,7 +1439,10 @@
*the_packet = msg;
shutdown:
if (reply != rtsp_read_request_response_ok) {
- msg_free(the_packet);
+ if (*the_packet != NULL) {
+ debug(3, "Freeing the_packet");
+ msg_free(the_packet);
+ }
release_buffer = 1; // allow the buffer to be released
}
pthread_cleanup_pop(release_buffer);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/scripts/shairport-sync.conf
new/shairport-sync-4.3.7/scripts/shairport-sync.conf
--- old/shairport-sync-4.3.4/scripts/shairport-sync.conf 2024-07-06
12:56:10.000000000 +0200
+++ new/shairport-sync-4.3.7/scripts/shairport-sync.conf 2025-01-31
15:57:31.000000000 +0100
@@ -128,7 +128,7 @@
// output_rate = "auto"; // can be "auto", 44100, 88200, 176400 or 352800,
but the device must have the capability.
// output_format = "auto"; // can be "auto", "U8", "S8", "S16", "S16_LE",
"S16_BE", "S24", "S24_LE", "S24_BE", "S24_3LE", "S24_3BE", "S32", "S32_LE" or
"S32_BE" but the device must have the capability. Except where stated using
(*LE or *BE), endianness matches that of the processor.
-// disable_synchronization = "no"; // Set to "yes" to disable
synchronization. Default is "no" This is really meant for troubleshootingG.
+// disable_synchronization = "no"; // Set to "yes" to disable
synchronization. Default is "no" This is really meant for troubleshooting.
// period_size = <number>; // Use this optional advanced setting to set
the alsa period size near to this value
// buffer_size = <number>; // Use this optional advanced setting to set
the alsa buffer size near to this value
@@ -157,7 +157,7 @@
// --with-sndio
sndio =
{
-// device = "snd/0"; // optional setting to set the name of the output
device. Default is the sndio system default.
+// device = "default"; // optional setting to set the name of the output
device, e.g. "rsnd/0", "rsnd/1", etc.
// rate = 44100; // optional setting which can be 44100, 88200, 176400 or
352800, but the device must have the capability. Default is 44100.
// format = "S16"; // optional setting which can be "U8", "S8", "S16",
"S24", "S24_3LE", "S24_3BE" or "S32", but the device must have the capability.
Except where stated using (*LE or *BE), endianness matches that of the
processor.
// round = <number>; // advanced optional setting to set the period size
near to this value
@@ -285,6 +285,8 @@
// Currently published
topics:artist,album,title,genre,format,songalbum,volume,client_ip,
// Additionally, messages at the topics
play_start,play_end,play_flush,play_resume are published
// publish_cover = "no"; //whether to publish the cover over mqtt in
binary form. This may lead to a bit of load on the broker
+// enable_autodiscovery = "no"; //whether to publish an autodiscovery message
to automatically appear in Home Assistant
+// autodiscovery_prefix = "homeassistant"; //string to prepend to
autodiscovery topic
// enable_remote = "no"; //whether to remote control via MQTT. RC is
available under `topic`/remote.
// Available commands are "command", "beginff", "beginrew", "mutetoggle",
"nextitem", "previtem", "pause", "playpause", "play", "stop", "playresume",
"shuffle_songs", "volumedown", "volumeup"
};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shairport-sync-4.3.4/shairport.c
new/shairport-sync-4.3.7/shairport.c
--- old/shairport-sync-4.3.4/shairport.c 2024-07-06 12:56:10.000000000
+0200
+++ new/shairport-sync-4.3.7/shairport.c 2025-01-31 15:57:31.000000000
+0100
@@ -1300,6 +1300,10 @@
if (config.mqtt_publish_cover && !config.get_coverart) {
die("You need to have metadata.include_cover_art enabled in order to use
mqtt.publish_cover");
}
+ config_set_lookup_bool(config.cfg, "mqtt.enable_autodiscovery",
&config.mqtt_enable_autodiscovery);
+ if (config_lookup_string(config.cfg, "mqtt.autodiscovery_prefix", &str)) {
+ config.mqtt_autodiscovery_prefix = (char *)str;
+ }
config_set_lookup_bool(config.cfg, "mqtt.enable_remote",
&config.mqtt_enable_remote);
if (config_lookup_string(config.cfg, "mqtt.empty_payload_substitute",
&str)) {
if (strlen(str) == 0)
@@ -2550,6 +2554,7 @@
debug(1, "mqtt will%s publish parsed metadata.", config.mqtt_publish_parsed
? "" : " not");
debug(1, "mqtt will%s publish cover Art.", config.mqtt_publish_cover ? "" :
" not");
debug(1, "mqtt remote control is %sabled.", config.mqtt_enable_remote ? "en"
: "dis");
+ debug(1, "mqtt autodiscovery is %sabled.", config.mqtt_enable_autodiscovery
? "en" : "dis");
#endif
#ifdef CONFIG_CONVOLUTION