AirPi: DIY Airplay Speakers using Shairport and a Raspberry Pi
We have speakers in all the ground floor rooms of our house, all driven from the same amp. It’s neat but controlling the input requires going back to the amp.
Surrounded by iDevices too and with apps like iPlayer, Spotify and home share on iTunes, being able to throw audio to the speaker system had to be done. Que Airplay, however, this requires a nice Airplay amp or getting an AirPort. I then found out about Shairport, a program that emulates an AirPort’s Airplay function. With a Raspberry Pi kicking around, I had just found its new job.
Quite a lot has changed in the year since I did this and rather than try and add more updates to this, I have run through the process again and created a new tutorial.
Setting Up Arch ARM
I opted for the Arch Pi distribution for this, simply because it is my Linux of the moment and with no window manager, is perfect for a standalone device. The first thing you’re going to want to do is a system update with pacman (you’ll probably need to update pacman on first run so need to do this twice).
pacman -Syu
Next you’ll need to install the tools required to compile in Arch.
pacman -S kernel26-headers file base-devel abs
Then git to clone the Shairport repo.
pacman -S git
Shairport has a number of dependencies so we’ll install them and there dependencies too.
pacman -S avahi libao openssl perl-crypt-openssl-rsa perl-io-socket-inet6 perl-libwww
Finally, alsa is required to get sound output in Arch on the RPi. Install this and then load the sound driver using modprobe
.
pacman -S alsa-utils alsa-oss modprobe snd-bcm2835
Alsa mutes the channels by default so open the mixer and raise the volume to 0dB gain. Test the output using speaker-test
.
alsamixer speaker-test -c 2
I’m using the 3.5mm jack as an audio output and at this stage I failed to get audio. I realised that with the HDMI plugged in, audio was going through that and not through the jack (it doesn’t seem to do both at once). You need to disconnect the HDMI and reboot the RPi. If you’re connected via monitor and want 3.5mm jack, there is no option but to continue via ssh
or use the phono. I was doing it all via ssh
so it didn’t really matter. If you do reboot, don’t forget to reload drivers using modprobe
before testing again.
[ update: you can change output with using amixer cset numid=3 1
– tomsolari.id.au ]
If all is good, save the alsa levels.
alsactl store
And set the sound modules and new daemons to load at startup by editing /etc/rc.conf
vi /etc/rc.conf MODULES=(.. snd-bcm2835 ..) DAEMONS=(.. dbus avahi-daemon alsa ..)
Probably a good idea to reboot at this stage.
shutdown -r now
Make Shairport
Make a directory called Shairport in the home folder.
mkdir shairport
Now clone the repo, cd
into it and make
.
git clone https://github.com/albertz/shairport.git shairport cd shairport make
All being well, Shairport should have built and you can now run it with the name ‘AirPi’.
./shairport.pl -a AirPi
Create daemon
18/12/12 – This may not work now due to Arch builds now using systemd
. If it doesn’t, this comment thread has a solution.
Install the new build
make install
Shairport includes a sample init
file but it is not designed for Arch. Arch includes a template for creating new daemons in /usr/share/pacman/rc-script.proto, first copy to /etc/rc.d
cp /usr/share/pacman/rc-script.proto /etc/rc.d/shairport
Now edit the file using vi as mine below
#!/bin/bash daemon=shairport daemon_name=shairport.pl . /etc/rc.conf . /etc/rc.d/functions get_pid() { pidof -o %PPID $daemon_name } case "$1" in start) stat_busy "Starting $daemon" PID=$(get_pid) if [[ -z $PID ]]; then [[ -f /var/run/$daemon_name.pid ]] && rm -f /var/run/$daemon_name.pid # RUN $daemon_name -d -a AirPi # if [[ $? -gt 0 ]]; then stat_fail exit 1 else echo $(get_pid) > /var/run/$daemon_name.pid add_daemon $daemon_name stat_done fi else stat_fail exit 1 fi ;; stop) stat_busy "Stopping $daemon_name daemon" PID=$(get_pid) # KILL [[ -n $PID ]] && kill $PID &> /dev/null # if [[ $? -gt 0 ]]; then stat_fail exit 1 else rm -f /var/run/$daemon_name.pid &> /dev/null rm_daemon $daemon_name stat_done fi ;; restart) $0 stop sleep 3 $0 start ;; status) stat_busy "Checking $daemon_name status"; ck_status $daemon_name ;; *) echo "usage: $0 {start|stop|restart|status}" esac exit 0 # vim:set ts=2 sw=2 et:
Add shairport to the list of daemons in etc/rc.conf and you’re all good to go.
UPDATE 2:
I’ve since found a command to redistribute the Pi’s memory, providing less dropped audio (it doesn’t happen much anyway). By default, a certain amount is allocated to the GPU, since this is headless, we can remove that.
cd /boot mv start.elf orig-start.elf cp arm224_start.elf start.elf
UPDATE 3:
Shairport has been updated to support iOS and with it now depends on perl-net-sdp. This can be installed from the AUR using these instructions