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

Reply via email to