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.

9 thoughts on “Raspberry Pulse: Raspberry Pi + PulseAudio + Shairport

    • 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.

      Reply
  1. 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.

    Reply
    • 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.

      Reply
      • 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?

        Reply
        • 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.

          Reply
  2. Pingback: Coding a morse code translator

Leave a Reply