To enable Shairport Sync to act as an MQTT publisher, you need to:
- Install the mosquitto library:
# apt install libmosquitto-dev
- Add the configuration flag
--with-mqtt-client
to the list of parameters to the./configure...
command. For example:
$ ./configure --with-mqtt-client --sysconfdir=/etc --with-alsa --with-avahi --with-ssl=openssl --with-systemd
If Shairport Sync has MQTT support, it will have the string mqtt
in its configuration string. For example:
$ shairport-sync -V
3.3.8-OpenSSL-Avahi-ALSA-metadata-mqtt-sysconfdir:/etc
Note: The Docker image will have MQTT support enabled by default.
This is a rough guide on the setup of MQTT publishing in ShairPort Sync. The MQTT service listens for and publishes metadata generated by the AirPlay source and Shairport Sync.
In the following example, Shairport Sync is configured to publish parsed metadata information and album-art to a MQTT server under the topic "shairport".
metadata =
{
enabled = "yes"; // Set this to yes to get Shairport Sync to solicit metadata from the source and to pass it on via a pipe.
include_cover_art = "yes"; // Set to "yes" to get Shairport Sync to solicit cover art from the source and pass it via the pipe. You must also set "enabled" to "yes".
cover_art_cache_directory = "/tmp/shairport-sync/.cache/coverart"; // Artwork will be stored in this directory if the dbus or MPRIS interfaces are enabled or if the MQTT client is in use. Set it to "" to prevent caching, which may be useful on some systems.
pipe_name = "/tmp/shairport-sync-metadata";
pipe_timeout = 5000; // Wait for this number of milliseconds for a blocked pipe to unblock before giving up.
};
mqtt =
{
enabled = "yes"; // Set this to yes to enable the mqtt-metadata-service.
hostname = "192.168.1.111"; // Hostname of the MQTT Broker.
port = 1883; // Port on the MQTT Broker to connect to.
username = "username"; // Set this to your MQTT user's username in order to enable username authentication.
password = "password"; // Set this to your MQTT user's password in order to enable username & password authentication.
topic = "shairport"; // MQTT topic where this instance of Shairport Sync should publish. If not set, the general.name value is used.
// publish_raw = "no"; // Whether to publish all available metadata under the codes given in the 'metadata' docs.
publish_parsed = "yes"; // Whether to publish a small (but useful) subset of metadata under human-understandable topics.
publish_cover = "yes"; // Whether to publish the cover over MQTT in binary form. This may lead to a bit of load on the broker.
// enable_remote = "no"; // Whether to remote control via MQTT. RC is available under `topic`/remote.
};
Important: Either publish_raw
, publish_parsed
, or publish_cover
need to be set in the MQTT configuration. Otherwise, no messages will be published.
active_start
and active_end
represent a stable on/off flag for the current AirPlay session.
active_start
is plublished when any new AirPlay session begins.
active_end
will fire after a configured timeout period unless the AirPlay stream is resumed.
sessioncontrol =
{
// "active" state starts when play begins, and ends when the active_state_timeout has elapsed after play ends, unless another play session starts before the timeout has fully elapsed.
active_state_timeout = 30.0;
};
Additional details regarding the metadata can be found at https://github.com/mikebrady/shairport-sync-metadata-reader.
Metadata is generated by both the stream source (iOS, iTunes, etc.) and by Shairport Sync itself. This data is coded as two 4-character codes to identify each piece of data, the type
and the code
.
The first 4-character code, called the type
, is either:
core
for all the regular metadadata coming from iTunes, etc., orssnc
(for 'shairport-sync') for all metadata coming from Shairport Sync itself, such as start/end delimiters, etc.
Additionally:
- For
core
metadata, the second 4-character code is the 4-character metadata code that comes from iTunes, etc. See, for example, https://code.google.com/p/ytrack/wiki/DMAP for information about the significance of the codes. The original data supplied by the source, if any, follows, and is encoded in base64 format. The length of the data is also provided. - For
ssnc
metadata, the second 4-character code is used to distinguish the messages. Cover art, coming from the source, is not tagged in the same way as other metadata, it seems, so is sent as anssnc
type metadata message with the codePICT
. Progress information, similarly, is not tagged like other source-originated metadata, so it is sent as anssnc
type with the codeprgr
.
Here are some of the core
codes commonly passed from the source:
asal
-- albumasar
-- artistascp
-- composerasgn
-- genreastm
-- song timecaps
-- play status (stopped, paused, playing)minm
-- titlemper
-- track persistent id
Here are the 'ssnc' codes defined so far:
PICT
-- the payload is a picture, either a JPEG or a PNG. Check the first few bytes to see which.acre
-- Active Remotecdid
-- Client advertised Device IDclip
-- the payload is the IP address of the client, i.e. the sender of audio. Can be an IPv4 or an IPv6 address.cmac
-- Client advertised MAC addresscmod
-- Client advertised model ("iPhone14,2")daid
-- DACP IDdapo
-- DACP Portmden
-- a sequence of metadata has ended. The RTP timestamp associated with the metadata sequence is included as data, if available.mdst
-- a sequence of metadata is about to start. The RTP timestamp associated with the metadata sequence is included as data, if available.pbeg
-- play stream begin. No argumentspcen
-- a picture has been sent. The RTP timestamp associated with it is included as data, if available.pcst
-- a picture is about to be sent. The RTP timestamp associated with it is included as data, if available.pend
-- play stream end. No argumentspfls
-- play stream flush. No argumentsprsm
-- play stream resume. No argumentsprgr
-- progress -- this is metadata from AirPlay consisting of RTP timestamps for the start of the current play sequence, the current play point and the end of the play sequence.pvol
-- play volume. The volume is sent as a string -- "airplay_volume,volume,lowest_volume,highest_volume", where "volume", "lowest_volume" and "highest_volume" are given in dB. The "airplay_volume" is what's sent by the source (e.g. iTunes) to the player, and is from 0.00 down to -30.00, with -144.00 meaning "mute". This is linear on the volume control slider of iTunes or iOS AirPlay. If the volume setting is being ignored by Shairport Sync itself, the volume, lowest_volume and highest_volume values are zero.snam
-- a device e.g. "Joe's iPhone" has started a play session. Specifically, it's the "X-Apple-Client-Name" string for AP1, or direct from the configuration Plist for AP2.snua
-- a "user agent" e.g. "iTunes/12..." has started a play session. Specifically, it's the "User-Agent" string.stal
-- this is an error message meaning that reception of a large piece of metadata, usually a large picture, has stalled; bad things may happen.svip
-- the payload is the IP address of the server, i.e. shairport-sync. Can be an IPv4 or an IPv6 address.
The MQTT service can parse the above raw messages into a subset of human-readable topics that include:
active_remote_id
-- Active Remote IDartist
-- text of artist namealbum
-- text of album nameclient_ip
-- IP address of the connected clientclient_device_id
-- Client advertised Device IDclient_mac_address
-- Client advertised MAC addressclient_model
-- Client advertised model ("iPhone14,2")client_name
-- Client advertised name ("Joe's iPhone")dacp_id
-- DACP IDformat
-- ??genre
-- text of genreserver_ip
-- IP address of Shairport Sync that the client is connected tosongalbum
--title
-- text of song titlevolume
-- The volume is sent as a string -- "airplay_volume,volume,lowest_volume,highest_volume", where "volume", "lowest_volume" and "highest_volume" are given in dB. (see above)
Additionally, empty messages (--
) at the following topics are published.
play_start
-- fired at the begining of every songplay_end
-- fired at the end of every songplay_flush
-- fired when song is skipped or on positional changeplay_resume
-- fired when song play resumes from pauseactive_start
-- fired when a new active AirPlay session beginsactive_end
-- fired after a configured timeout period after the stream ends (unless a new stream begins)
MQTT provides users with the flexibility to consume the MQTT data in various home automation projects. If you have an interesting use, please raise a new issue to suggest adding it to the guide, or simply fork the development branch and create a pull request.
Home Assistant Examples
The active_start
and active_end
have good potential use as triggers to turn on and off various connected receivers/zones. Note that payload_off
is set to prevent accidental triggering.
mqtt:
- binary_sensor:
name: "shairport active start"
state_topic: "shairport/active_start"
payload_on: "--"
payload_off: "OFF"
off_delay: 300
- binary_sensor:
name: "shairport active end"
state_topic: "shairport/active_end"
payload_on: "--"
payload_off: "OFF"
off_delay: 300
In the below example, the parsed data is saved into the Home Assistant database as sensor data. Please note the conversion of the volume from dB to percentage.
mqtt:
sensor:
- name: "shairport album"
state_topic: "shairport/album"
expire_after: 600
- name: "shairport artist"
state_topic: "shairport/artist"
expire_after: 600
- name: "shairport title"
state_topic: "shairport/title"
expire_after: 600
- name: "shairport genre"
state_topic: "shairport/genre"
expire_after: 600
- name: "shairport volume (dB)"
state_topic: "shairport/volume"
- name: "shairport volume (PCT)"
state_topic: "shairport/volume"
value_template: "{{ value | regex_findall_index(find='^(.+?),', index=0, ignorecase=False) | float / 30 + 1 }}"
unit_of_measurement: 'percent'