I was given a Raspberry Pi for my birthday last week, and I’ve already got it up and running, doing what I intended it to do: be an audio sink for iPhone and my laptop – which has terrible speakers.
I knew it would be a PulseAudio sink for my laptop. There’s also neat piece of software called shairport that will act as an AirPlay sink – and people are using it on Raspberry Pi’s.
By default, the common Linux Distribution “Raspbian” for this tiny computer uses ALSA for sound. This is fine for basic stuff, but I was reminded that when two things ever try to play sound at the same time, contention issues arise. It reminded me of a earlier day in Linux history, before the advent of PulseAudio and the magic it imparts.
Continue reading →
I made it my mission to set up Pulse as the default audio handler and make sure shairport would still play nicely in this setting. I want to state that despite what I’ve read, the built-in mini-jack on my Raspberry Pi has been working fine (no USB sound needed). Also, many shairport write-ups have wifi configuration sections – but AirPlay has been working fine for me with the Raspberry Pi wired into the same router my iPhone connects to. No need for extra hardware, just some know-how. So far, it’s been a success, so I thought I’d share my configuration.
I’ve used some conventions in this writeup:
- BOLD text where I’ve added or changed something (a new line or configuration setting)
- […] where I’ve omitted the unchanged contents of a file
commands
in code tags-
file contents
in pre tags
- In the case where commands are extraordinarily long or there are several sequential commands, I’ve used pre tags for those as well
Install & Configure PulseAudio
I found there are a few “tricks” to getting Pulse to work the way I wanted. Some of it involved going against conventional wisdom and running Pulse in “system” mode. To me this isn’t an issue at all as the Raspberry Pi sits on my desk to provide audio service to anyone that’s legitimately connected to my network.
Start by installing PulseAudio and its Zeroconf module:
sudo apt-get install pulseaudio pulseaudio-module-zeroconf
Set Pulse to run as a system daemon:
sudo vi /etc/default/pulseaudio
[...] PULSEAUDIO_SYSTEM_START=1 [...] DISALLOW_MODULE_LOADING=0
At this point you can turn on the PulseAudio system service:
sudo /etc/init.d/pulseaudio start
You can test the sound by running:
paplay /usr/share/scratch/Media/Sounds/Vocals/Singer1.wav
However, I was getting strange errors like
pa_context_connect() failed: Connection refused
even though Pulse was up-and-running. I think Pulse on my Raspberry Pi was getting confused because my desktop system also runs PulseAudio as well and some connection info was transferred in my SSH session. To convince Raspberry Pi’s Pulse to play locally, I set the PULSE_SERVER environment variable:
sudo vi /etc/environment
PULSE_SERVER=localhost
Uncomment the following lines and change the resample method and resampling rate. The sample rate was needed to allow playback from my Ubuntu laptop, the resample method was needed to allow playback from iPhone.
sudo vi /etc/pulse/daemon.conf
[...] resample-method = trivial [...] default-sample-rate = 48000
Comment out the suspend-on-idle module to prevent all the clicks & pops. Turn on anonymous network access and publish the configuration using zeroconf. Change “192.168.0.0” if your network uses a different numbering scheme.
If we were running PulseAudio in user mode, these next changes would be the equivalent of running paprefs
visiting the Network tab and checking:
- Enable network access to local sound devices
- Allow other machines on the LAN to discover local sound devices
- Don’t require authentication
sudo vi /etc/pulse/system.pa
[...] #load-module module-suspend-on-idle [...] load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1;192.168.0.0/24 auth-anonymous=1 load-module module-zeroconf-publish
Move your /etc/asound.conf to /etc/asound.old:
sudo mv /etc/asound.conf /etc/asound.old
Then create a new one with PulseAudio as the default:
sudo vi /etc/asound.conf
pcm.pulse { type pulse } ctl.pulse { type pulse } pcm.!default { type pulse } ctl.!default { type pulse }
Tell libao (shairport’s sound library) to use Pulse instead of ALSA directly:
sudo vi /etc/libao.conf
default_driver=pulse quiet
Install & Configure shairport
This is basically a re-hashing of several other useful installs I found. I felt the need to include it here for completeness.
Start by installing the necessary Git & Perl build packages:
sudo apt-get install git libao-dev libssl-dev libcrypt-openssl-rsa-perl libio-socket-inet6-perl libwww-perl avahi-utils libmodule-build-perl
Unlike other shairport write-ups, I installed the Perl module ‘Net::SDP’ (needed for iOS6 support) via CPAN instead of Git. Adding this library supposedly enables shairport to work with iOS6 devices, but my wife’s phone (which is iOS6) doesn’t work, however my iOS5 phone does. Anyway, it doesn’t hurt to install it:
sudo cpan install Net::SDP
Then clone, and build shairport from GitHub:
git clone https://github.com/albertz/shairport.git shairport cd shairport make sudo make install sudo cp shairport.init.sample /etc/init.d/shairport sudo chmod a+x /etc/init.d/shairport sudo update-rc.d shairport defaults
I went an extra step and made the shairport service run as the pulse user, and to write the process ID file to the pulse-owned /var/run/pulse directory:
sudo vi /etc/init.d/shairport
[...] NAME=AirPi USER=pulse DAEMON="/usr/local/bin/shairport.pl" PIDFILE=/var/run/pulse/$NAME.pid DAEMON_ARGS="-w $PIDFILE -a $NAME" [ -x $binary ] || exit 0 RETVAL=0 start() { echo -n "Starting shairport: " start-stop-daemon --start --quiet --pidfile "$PIDFILE" \ --chuid $USER \ --exec "$DAEMON" -b --oknodo -- $DAEMON_ARGS log_end_msg $? } [...]
You can now start shairport like any other service:
sudo /etc/init.d/shairport start
Did I mention you should do some testing after each of these steps? I forgot to mention it, but you probably should just to make sure everything is heading in the right direction. If I’ve forgotten anything, let me know and I’ll post an update.