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.
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.
Thanks! I have an ultrabook (Ubuntu) with bad speakers and an unused rasppi and this made my day 🙂
Thanks Radu – keep in mind there’s a audible delay once you add the network into the mix. So using pulse is good for listening to music, but far less so for watching videos.
Thank you for the guide! This is exactly what I have been looking for.
I have tried your guide and it works! Thank you!
‘
Unfortunately I do get constant buffer underruns after a few minutes streaming from my Ubuntu laptop.
Have you experienced similar problems? I have not yet experienced same issue playing locally on the raspberry.
I haven’t experienced buffer underruns. Is your Pi using a wired or wireless connection? It sounds like either the network buffer or Pulse’s buffer just needs to be increased, especially if it plays for a while without issues.
Let me know if you find a fix, it would be useful to have with this guide.
Thank you for a quick reply!
The Pi is wired the laptop is not. I have tried with the additional “load-module module-alsa-card device_id=0 tsched=true tsched_buffer_size=2048576 tsched_buffer_watermark=962144” setting in /etc/pulse/system.pa
But it does no change really. – I was able to reproduce same symptom locally also.
I posted here (http://www.raspberrypi.org/phpBB3/viewtopic.php?f=28&t=62763) to get more insight.
Do you think an upgrad to Pulseaudio 4.0 would help?
I’m not sure if Pulse 4.0 will help or not. My Raspbian has me running Pulse Audio 2.0, but admittedly I haven’t done any upgrades since I did this write up.
Pingback: Coding a morse code translator
thank you so much, i searched already 4 years ago for a solution and finally found one 😀
No problem Kaito. Let me know if you had to do anything differently as I published this over a year ago.
Hey!
Thanks for this great How2, i was looking for this solution very desperately 🙂
I only got one minor Problem, i’m using an usb DAC as output device. It is recognized by pulse and i’m able to use it as pa network sink. But when i stream music to the Shairport, the music is not played via the DAC. I think it’s just a configuration problem, but i’m not entirely sure how to select a default sound device in pa.
Thanks for the comment! I think you can set the default card in your /etc/pulse/default.pa file. Here’s a little write-up on how to figure out which one you want to be default: https://bbs.archlinux.org/viewtopic.php?pid=1287356#p1287356