This commit is contained in:
Mike Brady
2026-02-27 14:57:28 +00:00
10 changed files with 199 additions and 101 deletions
@@ -73,7 +73,7 @@ jobs:
uses: docker/setup-buildx-action@v3.12.0
- name: Build and push ${{ matrix.name }}
uses: docker/build-push-action@v6.18.0
uses: docker/build-push-action@v6.19.2
env:
registry_and_name: ${{ secrets.DOCKER_REGISTRY }}/${{ secrets.DOCKER_IMAGE_NAME }}
with:
-89
View File
@@ -1,89 +0,0 @@
# 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
name: Build and push Docker images...
on:
workflow_dispatch:
push:
tags:
- '[0-9]+' # X
- '[0-9]+\.[0-9]+' # X.Y
- '[0-9]+\.[0-9]+\.[0-9]+' # X.Y.Z
env:
DOCKER_PLATFORMS: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64
NQPTP_BRANCH: main
LATEST_TAG: false
jobs:
main:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
- name: Set SHAIRPORT_SYNC_BRANCH env.
run: |
raw=$(git branch -r --contains ${{ github.ref }})
branch=${raw##*/}
echo "SHAIRPORT_SYNC_BRANCH=${branch}" >> $GITHUB_ENV
- name: Set tag env
run: echo "GIT_TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Is branch "development"?
if: ${{ env.SHAIRPORT_SYNC_BRANCH == 'development' }}
run: |
echo "NQPTP_BRANCH=development" >> $GITHUB_ENV
- name: Is branch "danger-2301"?
if: ${{ env.SHAIRPORT_SYNC_BRANCH == 'danger-2301' }}
run: |
echo "NQPTP_BRANCH=development" >> $GITHUB_ENV
- name: Set up QEMU
uses: docker/setup-qemu-action@v3.6.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.10.0
- name: Login to Docker Registry
uses: docker/login-action@v3.4.0
with:
# registry: docker.io # default
username: ${{ secrets.DOCKER_REGISTRY_USER }}
password: ${{ secrets.DOCKER_REGISTRY_TOKEN }}
- name: Build and push (classic)
uses: docker/build-push-action@v6.15.0
with:
context: ./
file: ./docker/classic/Dockerfile
platforms: ${{ env.DOCKER_PLATFORMS }}
push: true
tags: |
${{ secrets.DOCKER_IMAGE_NAME }}:${{ env.GIT_TAG }}-classic
${{ env.LATEST_TAG == 'true' && format('{0}:classic', secrets.DOCKER_IMAGE_NAME) || '' }}
build-args: |
SHAIRPORT_SYNC_BRANCH=${{ env.SHAIRPORT_SYNC_BRANCH }}
- name: Build and Push AirPlay 2 Version
uses: docker/build-push-action@v6.15.0
with:
context: ./
file: ./docker/Dockerfile
platforms: ${{ env.DOCKER_PLATFORMS }}
push: true
tags: |
mikebrady/sps-private:${{ env.GIT_TAG }}
mikebrady/sps-private:latest
build-args: |
SHAIRPORT_SYNC_BRANCH=${{ env.SHAIRPORT_SYNC_BRANCH }}
NQPTP_BRANCH=${{ env.NQPTP_BRANCH }}
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v10.1.1
- uses: actions/stale@v10.2.0
with:
stale-issue-message: 'This issue has been inactive for 28 days so will be closed 7 days from now. To prevent this, please remove the "stale" label or post a comment.'
stale-pr-message: 'This PR has been inactive for 28 days so will be closed 7 days from now. To prevent this, please remove the "stale" label or post a comment.'
+1 -3
View File
@@ -1,7 +1,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.50])
AC_INIT([shairport-sync], [5.0rc0], [4265913+mikebrady@users.noreply.github.com])
AC_INIT([shairport-sync], [5.0-post-dev], [4265913+mikebrady@users.noreply.github.com])
: ${CFLAGS="-O3"}
: ${CXXFLAGS="-O3"}
AM_INIT_AUTOMAKE([subdir-objects])
@@ -389,8 +389,6 @@ AC_ARG_WITH(mqtt-client, [AS_HELP_STRING([--with-mqtt-client],[include a client
if test "x$with_mqtt_client" = "xyes" ; then
AC_DEFINE([CONFIG_MQTT], 1, [Include a client for MQTT, the Message Queuing Telemetry Transport protocol])
AC_CHECK_LIB([mosquitto], [mosquitto_lib_init], , AC_MSG_ERROR(MQTT support requires the mosquitto library -- libmosquitto-dev suggested!))
systemd_after_args="${systemd_after_args} mosquitto.service"
systemd_requires_args="${systemd_requires_args} mosquitto.service"
fi
AM_CONDITIONAL([USE_MQTT], [test "x$with_mqtt_client" = "xyes"])
+1 -1
View File
@@ -474,7 +474,7 @@ void set_dacp_server_information(rtsp_conn_info *conn) {
debug_mutex_unlock(&dacp_server_information_lock, 3);
}
void dacp_monitor_port_update_callback(char *dacp_id, uint16_t port) {
void dacp_monitor_port_update_callback(const char *dacp_id, uint16_t port) {
debug_mutex_lock(&dacp_server_information_lock, 500000, 2);
debug(3,
"dacp_monitor_port_update_callback with Remote ID \"%s\", target ID \"%s\" and port "
+1 -1
View File
@@ -31,7 +31,7 @@ void relinquish_dacp_server_information(rtsp_conn_info *conn); // tell the DACP
// that the player thread is no
// longer associated with it.
void dacp_monitor_port_update_callback(
char *dacp_id, uint16_t port); // a callback to say the port is no longer in use
const char *dacp_id, uint16_t port); // a callback to say the port is no longer in use
int dacp_send_command(const char *command, char **body, ssize_t *bodysize);
int send_simple_dacp_command(const char *command);
+174
View File
@@ -0,0 +1,174 @@
## Shairport Sync D-Bus Interface
Shairport Sync can have a D-Bus interface, which can be used to control aspects of its operation and get status information from it.
To include the D-Bus interface at build time, add the `--with-dbus-interface` flag at the `./configure…` stage. When the D-Bus interface is included in Shairport Sync, its Version String will include the term `dbus`, for instance:
```
$ shairport-sync -V
5.0.0-1-gc956d763-AirPlay2-smi10-OpenSSL-Avahi-ALSA-soxr-metadata-dbus-sysconfdir:/etc
```
Once Shairport Sync has been built with the D-Bus interface, it must then be installed correctly to provide a Shairport Sync service either on the D-Bus `system` bus or the D Bus `session` bus.
To become available as a system-wide service on the D-Bus `system` bus, it must be installed as a system service using the `# make install` step of the build process. This installs the appropriate service files and sets required permissions.
Remember to enable Shairport Sync to start as a system service. You may also need to restart the entire system to allow the service to be seen.
If Shairport Sync is installed as a user service, it will not be able to become a service on the D-Bus `system` bus, but it can be added to the D-Bus `session` bus. Edit the configuration file to select the `session` bus, or add the option `--dbus_default_message_bus=session` to the command line.
### D-Feet
On desktop Linuxes with a GUI, e.g. Ubuntu, D-Feet is a great tool for examining a D-Bus service:
![Shairport Sync and DFeet](https://github.com/user-attachments/assets/613dab83-9b02-4312-9ad1-c94db1d0ef49)
### Sample Test Client
A simple test client, written in C, can be built when you are building Shairport Sync itself. To build it, simply add the `--with-dbus-test-client` flag at the `./configure…` stage. Along with the `shairport-sync` executable application, you'll get another executable called `shairport-sync-dbus-test-client` which you can run from the command line.
After attempting to send some commands, it will listen for property changes on the D-Bus interface and report them on the console.
### Command Line Examples
The examples below are based on Shairport Sync running as a `system` service and use the standard CLI tool `dbus-send`:
* Get `Active` Status -- `true` when Shairport Sync is playing (and for a short time later); `false` otherwise.
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:Active
```
* Get Log Verbosity
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync.Diagnostics string:Verbosity
```
* Return Log Verbosity
```
$ echo `dbus-send --print-reply=literal --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync.Diagnostics string:Verbosity`
```
* Set Log Verbosity to 2
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync.Diagnostics string:Verbosity variant:int32:2
```
* Get Statistics-Requested Status
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync.Diagnostics string:Statistics
```
* Set Statistics-Requested Status to `true`
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync.Diagnostics string:Statistics variant:boolean:true
```
* Are File Name and Line Number included in Log Entries?
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync.Diagnostics string:FileAndLine
```
* Include File Name and Line Number in Log Entries
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync.Diagnostics string:FileAndLine variant:boolean:true
```
* Is Elapsed Time included in Log Entries?
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync.Diagnostics string:ElapsedTime
```
* Include Elapsed Time in Log Entries
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync.Diagnostics string:ElapsedTime variant:boolean:true
```
* Get Drift Tolerance
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:DriftTolerance
```
* Set Drift Tolerance to 1 millisecond
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync string:DriftTolerance variant:double:0.001
```
* Is Loudness enabled:
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:LoudnessEnabled
```
* Enable Loudness Filter
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync string:LoudnessEnabled variant:boolean:true
```
* Get Loudness Threshold
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:LoudnessThreshold
```
* Set Loudness Threshold
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync string:LoudnessThreshold variant:double:-15.0
```
* Is Convolution enabled:
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:ConvolutionEnabled
```
* Enable Convolution
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync string:ConvolutionEnabled variant:boolean:true
```
* Get Convolution Gain:
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:ConvolutionGain
```
* Set Convolution Gain -- the gain applied after convolution is applied -- to -10.0 dB
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync string:ConvolutionGain variant:double:-10
```
* Get Convolution Impulse Response Files:
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:ConvolutionImpulseResponseFiles
```
* Set Convolution Impulse Response Files:
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync string:ConvolutionImpulseResponseFiles variant:string:"'/home/pi/filters/Sennheiser HD 205 minimum phase 48000Hz.wav', '/home/pi/filters/Sennheiser HD 205 minimum phase 44100Hz.wav'"
```
* Get Convolution Impulse Response File Maximum Length:
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:ConvolutionMaximumLengthInSeconds
```
* Set Convolution Impulse Response File Maximum Length:
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync string:ConvolutionMaximumLengthInSeconds variant:double:1
```
* Get the Protocol that Shairport Sync was built for -- AirPlay or AirPlay 2:
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:Protocol
```
* Get the current volume level. This returns a value between -30.0 and 0.0, which is linear on the UI volume control. It can also return -144.0 to indicate mute.
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:Volume
```
* Set the current volume level. This should be a value between -30.0 and 0.0. Set a value of -144.0 to mute. Note that all this is done locally on the Shairport Sync device itself. The volume control of audio source (e.g. iTunes / macOS Music / iOS) is not updated to reflect any changes.
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync string:Volume variant:double:-10.0
```
* Drop the current session immediately. Shairport Sync will immediately stop playing and drop the connection from the audio source. This may show up as an error at the source.
```
$ dbus-send --system --print-reply --type=method_call --dest=org.gnome.ShairportSync '/org/gnome/ShairportSync' org.gnome.ShairportSync.DropSession
```
#### Remote Control
Remote Control commands are sent as requests to the player (iOS, iTunes, macOS Music, etc.). Different versions of the players implement different subsets of the following commands.
**Note:** Unfortunately, at this time -- early 2026 -- these requests are ignored, so remote control doesn't work.
* Check if Remote Control is available:
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync.RemoteControl string:Available
```
* Send the `play` command to the player:
```
$ dbus-send --system --print-reply --type=method_call --dest=org.gnome.ShairportSync '/org/gnome/ShairportSync' org.gnome.ShairportSync.RemoteControl.Play
```
Remote Control commands include: `Play`, `Pause`, `PlayPause`, `Resume`, `Stop`, `Next`, `Previous`, `VolumeUp`, `VolumeDown`, `ToggleMute`, `FastForward`, `Rewind`, `ShuffleSongs`.
* Set Airplay Volume using Remote Control. Airplay Volume is between -30.0 and 0.0 and maps linearly onto the slider, with -30.0 being lowest and 0.0 being highest.
```
$ dbus-send --system --print-reply --type=method_call --dest=org.gnome.ShairportSync '/org/gnome/ShairportSync' org.gnome.ShairportSync.RemoteControl.SetAirplayVolume double:-10.0
```
#### Advanced Remote Control
Some commands and properties are accessible only through the `AdvancedRemoteControl` interface.
**Note:** Unfortunately, at this time -- early 2026 -- these requests are ignored, so advanced remote control doesn't work.
* Check if Advanced Remote Control is available:
```
$ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync.AdvancedRemoteControl string:Available
```
* Set Volume using Advanced Remote Control:
```
$ dbus-send --system --print-reply --type=method_call --dest=org.gnome.ShairportSync '/org/gnome/ShairportSync' org.gnome.ShairportSync.AdvancedRemoteControl.SetVolume int32:50
```
+5 -1
View File
@@ -1,10 +1,14 @@
# For the "Native" Shairport Sync D-Bus Interface support, Shairport Sync must be built with the D-Bus interface support. Add the '--with-dbus-interface' flag at the ./configure stage.
# For the "Native" Shairport Sync D-Bus Interface support, Shairport Sync must be built with the D-Bus interface support -- to do this, add the '--with-dbus-interface' flag at the ./configure stage.
# Secondly, for the Shairport Sync interface to become available on the D-Bus system bus, Shairport Sync must be installed and running as a system service. The example below assume that it is installed and running as a system service.
# There is a simple test client that you can build -- add the '--with-dbus-test-client' flag at the ./configure stage. You'll get an executable called shairport-sync-dbus-test-client
# After attempting to send some commands, it will listen for property changes on the D-Bus interface and report them on the console.
# Additionally, the following are examples of using the CLI command "dbus-send" to send D-Bus commands to Shairport Sync:
# Get "Active" Status -- true when Shairport Sync is playing (and for a short time later); false otherwise.
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:Active
# Get Log Verbosity
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync.Diagnostics string:Verbosity
# Return Log Verbosity
+1 -1
View File
@@ -109,7 +109,7 @@ static void resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIn
// char a[AVAHI_ADDRESS_STR_MAX], *t;
debug(3, "resolve_callback: Service '%s' of type '%s' in domain '%s':", name, type, domain);
if (dbs->dacp_id) {
char *dacpid = strstr(name, "iTunes_Ctrl_");
const char *dacpid = strstr(name, "iTunes_Ctrl_");
if (dacpid) {
dacpid += strlen("iTunes_Ctrl_");
while (*dacpid == '0')
+14 -3
View File
@@ -198,8 +198,10 @@ void send_autodiscovery_messages(struct mosquitto *mosq) {
(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]);
const char* entity_type = is_binary_sensor ? "binary_sensor" : "sensor";
snprintf(topic, sizeof(topic), "%s/%s/%s_%s/%s/config", autodiscovery_prefix,
entity_type, model, device_id_no_colons, sensors[i]);
snprintf(id_string, sizeof(id_string), "%s_%s_%s", model, device_name, sensors[i]);
@@ -211,9 +213,18 @@ void send_autodiscovery_messages(struct mosquitto *mosq) {
"\"icon\": \"%s\","
"\"unique_id\": \"%s\","
"\"object_id\": \"%s\","
// As of Home Assistant 2025.10, `default_entity_id` replaces `object_id`.
// Home Assistant 2026.4 will remove support for `object_id`,
// so we add both for backward compatibility.
"\"default_entity_id\": \"%s.%s\","
"%s%s%s"
"}",
sensor_names[i], config.mqtt_topic, sensors[i], icons[i], id_string, id_string,
sensor_names[i], // name
config.mqtt_topic, sensors[i], //state_topic
icons[i], // icon
id_string, // unique_id
id_string, // object_id
entity_type, id_string, // default_entity_id
is_binary_sensor ? "\"payload_on\": \"1\",\"payload_off\": \"0\"," : "",
is_volume_sensor
? "\"value_template\": \"{{ ((value | regex_findall_index("