Here’s how to setup Raspberry Pi as AirPlay audio player, so we can stream music to it from Apple devices (macOS, iOS, etc.). This is possible thanks to amazing work from many different developers over the years, going back to original Shairport, which successfully reversed engineered first version of AirPlay. Shairport Sync is a fork of that project, building on the legacy.
Info
This only works as an audio player (target). Unfortunately it’s not possible to use Shairport Sync as a source and use it to stream audio to other AirPlay compatible speakers. AFAIK this can only be done from Apple systems, like iOS and macOS. I haven’t found a workaround to this yet, although PulseAudio network streams (and its modern implementation in PipeWire) look like an interesting alternative to Apple AirPlay as a whole that I may explore in the future. Building a complete FOSS multi-room audio system is a bit daunting, but I can’t resist to try.
I’m using Raspberry Pi OS Lite x64 (without desktop environment) and the same Pi I used in my earlier post.
Setting up Shairport Sync
First, let’s make sure all packages are up to date:
sudo apt update && apt list --upgradable
sudo apt upgrade -y
Now let’s install packages required to build and run Shairport Sync:
sudo apt install autoconf libtool libdaemon-dev libasound2-dev libpopt-dev libconfig-dev avahi-daemon libavahi-client-dev libssl-dev git
We can now clone the repo:
git clone https://github.com/mikebrady/shairport-sync.git
Now we can configure it with these three commands:
cd shairport-sync
autoreconf -i -f
./configure --with-alsa --with-avahi --with-ssl=openssl --with-systemd --with-metadata --sysconfdir=/etc
The flags we are using are:
Flag | Description |
---|---|
--with-alsa | Output to the Advanced Linux Sound Architecture (ALSA) system. This is recommended for highest quality. |
--with-avahi | Chooses Avahi-based Zeroconf support. This is mandatory for AirPlay 2 operation. |
--with-ssl=openssl | Uses the OpenSSL cryptography toolkit. This is mandatory for AirPlay 2 operation. |
--with-systemd | Includes a script to create a Shairport Sync service that can optionally launch automatically at startup on systemd-based Linux. |
--with-metadata | Adds support for Shairport Sync to request metadata (track name, artist name, album name, cover art and more) and to pipe it to a compatible application. |
--sysconfdir=/etc | Shairport Sync will look for a configuration file – shairport-sync.conf by default – when it starts up. sysconfdir defaults to /usr/local/etc directory. I prefer /etc . |
Note
We need to talk about sound in Linux. Like many other aspects, this part of the system is modular and comprises of several different components that work in tandem. There is a plethora of options and possible configurations out there, but most distros nowadays ship with PipeWire.
Here’s a simplified explanation how sound is handled in Linux:
--with-alsa
flag instructs Shairport Sync to use plain ALSA (Advanced Linux Sound Architecture), rather than the middleware. This setup is simple, minimal, and fitting for a headless streamer. ALSA is an integral part of Linux kernel on any distro, as it provides audio device drivers and facilitates direct access to the hardware.
On a system with a desktop environment, you probably shouldn’t use ALSA but rather your sound server (middleware). This is most likely PipeWire, but can also be PulseAudio depending on the Linux distro (or one of the more obscure options - if you are using a distro that ships them as default, then you surely must know what you’re doing). Check which one is installed on your system, then use --with-pipewire
or --with-pa
flags respectively.
Optionally you could add below flag to enable AirPlay version 2 support. I am going to omit it however and use version 1:
Flag | Description |
---|---|
--with-airplay-2 | Enables support for AirPlay 2, newer version of the protocol that offers better multi-room compatibility with Apple devices and integrates with Apple Home app. |
Info
Why am I not using version 2 of the protocol? Not all of its features are currently supported by Shairport Sync (for example smart control when integrated with Apple Home app). Also, the implementation of v2 operates with 256Kbps AAC streams in certain scenarios, while v1 is lossless. Since I’m going to be actively listening on headphones most of the time, audio quality takes priority for me. You can find detailed explanation and also all other possible configuration flags here.
Finally we can build it and install it with these two commands:
make
sudo make install
We should be able to start the service now and enable it to start automatically on future boots:
sudo systemctl enable shairport-sync --now
Let’s check the status with:
luk@officepi:~ $ sudo systemctl status shairport-sync.service
● shairport-sync.service - Shairport Sync - AirPlay Audio Receiver
Loaded: loaded (/lib/systemd/system/shairport-sync.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2023-09-16 12:51:07 BST; 33s ago
Main PID: 608 (shairport-sync)
Tasks: 7 (limit: 779)
CPU: 350ms
CGroup: /system.slice/shairport-sync.service
└─608 /usr/local/bin/shairport-sync --log-to-syslog
Sep 16 12:51:07 officepi systemd[1]: Started Shairport Sync - AirPlay Audio Receiver.
Raspberry Pi should appear now on the list of AirPlay devices. Here’s an example from iOS:
Changing audio output
By default Raspberry Pi should output audio via integrated headphone jack. If you have access to the desktop environment with a sound server (like PipeWire), then you can easily change the output device via GUI. Here’s how to change it on a headless system in ALSA, without a sound server.
Option 1: Modify default ALSA audio device
This is the option I chose, since I’m using the Raspberry Pi as a headless streamer and I’m going to use only one audio output for Sharepoint Sync and any other software that I may add in the future.
First, let’s check all available devices:
luk@officepi:~ $ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: Headphones [bcm2835 Headphones], device 0: bcm2835 Headphones [bcm2835 Headphones]
Subdevices: 8/8
Subdevice #0: subdevice #0
Subdevice #1: subdevice #1
Subdevice #2: subdevice #2
Subdevice #3: subdevice #3
Subdevice #4: subdevice #4
Subdevice #5: subdevice #5
Subdevice #6: subdevice #6
Subdevice #7: subdevice #7
card 1: S3E [Schiit Modi 3E], device 0: USB Audio [USB Audio]
Subdevices: 0/1
Subdevice #0: subdevice #0
card 2: vc4hdmi [vc4-hdmi], device 0: MAI PCM i2s-hifi-0 [MAI PCM i2s-hifi-0]
Subdevices: 1/1
Subdevice #0: subdevice #0
In my case, I have a USB audio DAC that I’d like to use as a default output. That’s card number 1. Unfortunately those numbers don’t mean much, as they can change on reboots, especially when certain devices are not present at boot time and are plugged in later (like a USB DAC might be). We can work around that by using device names instead. They are in the output above, but Arch wiki also has a nice one liner to query them:
luk@officepi:~ $ aplay -l | awk -F \: '/,/{print $2}' | awk '{print $1}' | uniq
Headphones
S3E
vc4hdmi
We can now set a system-wide default by creating /etc/asound.conf
:
sudo nano /etc/asound.conf
And pasting below config. Make sure to change the card name to your preferred one, in my case it’s S3E
:
pcm.!default {
type hw
card S3E
}
ctl.!default {
type hw
card S3E
}
Finally, let’s reboot to apply the changes:
sudo shutdown -r now
That’s it! Shairport Sync should now play audio via your preferred device.
Option 2: Specify output device in shairport-sync.conf
It is also possible to specify output device in the config file for Shairport Sync, independently of system-wide default. This will only work if you also used --with-alsa
flag earlier. If you are using PulseWire or other middleware, then Shairport Sync can’t access the hardware directly. Instead you should be able to manage the output sink in that middleware.
First we need to list all PCM interfaces. Note that we are using capital -L
this time. -l
lists physical devices. I’ll truncate the output to show only couple devices as an example:
luk@officepi:~ $ aplay -L
[...]
front:CARD=S3E,DEV=0
Schiit Modi 3E, USB Audio
Front output / input
[...]
hdmi:CARD=vc4hdmi,DEV=0
vc4-hdmi, MAI PCM i2s-hifi-0
HDMI Audio Output
We need to grab the card name of our preferred interface. In examples above that’s S3E
from front:CARD=S3E,DEV=0
line and vc4hdmi
from hdmi:CARD=vc4hdmi,DEV=0
.
Tip
You can also use shairport-sync -h
to list available devices. At the end of the output you should see:
luk@officepi:~ $ shairport-sync -h
[...]
Settings and options for the audio backend "alsa":
-d output-device set the output device, default is "default".
-c mixer-control set the mixer control name, default is to use no mixer.
-m mixer-device set the mixer device, default is the output device.
-i mixer-index set the mixer index, default is 0.
hardware output devices:
"hw:Headphones"
"hw:S3E"
"hw:vc4hdmi"
We can now specify output device in the config file, which should be located in /etc/shairport-sync.conf
if you used the same configuration flags I mentioned earlier. Otherwise, by default it’s located in /usr/local/etc/shairport-sync.conf
Look for the “Back End Settings” section that mentions ALSA:
// Back End Settings
// These are parameters for the "alsa" audio back end.
// For this section to be operative, Shairport Sync must be built with the following configuration flag:
// --with-alsa
alsa =
{
// output_device = "default";
Remove //
to uncomment output_device
line, and change it to hw:
followed by your interface card:
alsa =
{
output_device = "hw:S3E";
There’s no need to close the bracket. };
should already be at the end of ALSA section below all the comments.
Now restart the service:
sudo systemctl restart shairport-sync.service
That’s it!
Controlling volume levels
Two options again:
Option 1: Shairport Sync and its own software volume control
In its current configuration, volume changes made on the source device while streaming audio are managed in software by Shairport Sync. You can separately adjust master volume for the audio card by using alsamixer
utility if it’s too low or too high. You may need to install alsa-utils
package first if it’s not already installed (sudo apt install alsa-utils
on Debian based distros).
Running alsamixer
should then let you control volume levels for different cards and their outputs:
Option 2: Shairport Sync can control device volume directly
Output device must be capable of volume control for this to work. Not all devices support this, e.g. standalone DACs.
If you defined output_device
in the config file for Shairport Sync, you can also add mixer_control_name = "PCM"
right below it. You may need to change PCM
to your output name, like Headphone
or Front
(without adding hw:
this time). It depends on the hardware, but it should correspond to the output name shown by alsamixer
. This way Shairport Sync will directly set device master volume based on your input from the streaming source.