Drew Lustro  ·  bootleg hypertext

Hi-Fi Audio via AirPlay on Raspberry Pi

![KRK Rokit with Raspberry Pi and turntable](/images/blog/legacy/rivington-turntable.jpg) > Originally published **January 29, 2013**. Now updated with latest Shairport libs, depedencies, and installation instructions. After getting my Raspberry Pi last week, I set out to make it do something useful in the interim before a more compelling creative lightning bolt hits me. Luckily, nerds & neckbeards with smarts beyond the scope of my own ability have done the heavily lifting necessary to turn a Raspberry Pi into a cheap AirPlay receiver. In the footnotes of Jordan Burgess' fantastic piece on the topic, he writes that sound quality out of the Pi's 3.5mm stereo jack suffers because the Pi's hardware uses pulse wave modulation to output a signal to the jack. He was right. The sound quality is far from Hi-Fi and is shameful to run through my KRK monitors. To add insult to injury, the stereo jack would often output deafeningly-loud white noise if you were unlucky when stopping a track. I suspected the software at fault was shairport, an open-source reverse engineering of Apple's AirPlay codec. I would venture to guess that shairport doesn't clean up and silence the audio signal when playback is interrupted because the authors didn't care to accomodate a shitty PWM-based DAC. I cannot point the finger at the amazing contributors to shairport though, as they've reverse-engineered something that I would take me weeks to wrap my brain around.

Since the culprit is suspected to be a "dirty" PWM, I thought that the option of using an external USB sound card would amend the white noise problem and offer me CD-quality audio to boot. I had an M-Audio Mobile Pre laying around that was acting as a dummy mixer for the KRK's anyway, so I decided to dive in and setup wireless Hi-Fi audio on my Raspberry Pi. #### Assumptions * You have a Raspberry Pi and compatible USB soundcard * Networking is setup and working fine on your Pi * You're comfortable opening up a terminal shell on your Raspberry Pi via ssh #### What I'll Be Covering * Setup Shairport on your Raspberry Pi as a daemon * Get linux to recognize, prefer, and use the USB sound card ### Shairport Daemon Setup This section is a blend of Trouch & Burgess' write-ups. #### Make sure your Raspberry Pi is up-to-date This is always smart to run with new linux systems.
pi@raspberrypi ~ $ sudo apt-get update
pi@raspberrypi ~ $ sudo apt-get upgrade
#### Install Shairport prerequisites Shairport requires perl and a handful of other packages from the repo in order to install successfully.
pi@raspberrypi ~ $ sudo apt-get install git libao-dev libssl-dev libcrypt-openssl-rsa-perl libio-socket-inet6-perl libwww-perl avahi-utils libmodule-build-perl libasound2-dev libpulse-dev
#### Install Perl Net-SDP Apparently a change in IOS 6 requires this module to be installed or else shairport will crash.
pi@raspberrypi ~ $ git clone https://github.com/njh/perl-net-sdp.git perl-net-sdp
pi@raspberrypi ~ $ cd perl-net-sdp
pi@raspberrypi ~/perl-net-sdp $ perl Build.PL
pi@raspberrypi ~/perl-net-sdp $ sudo ./Build
pi@raspberrypi ~/perl-net-sdp $ sudo ./Build test
pi@raspberrypi ~/perl-net-sdp $ sudo ./Build install
pi@raspberrypi ~/perl-net-sdp $ cd ..
#### Build & install Shairport "as root" and have it launch on system startup This will install shairport into /usr/sbin and make it available to the system / root user.
pi@raspberrypi ~ $ git clone https://github.com/abrasive/shairport.git
pi@raspberrypi ~ $ cd shairport
pi@raspberrypi ~ $ ./configure
Configuring Shairport
OpenSSL found
libao found
PulseAudio found
ALSA found
Avahi client found
getopt.h found
LDFLAGS: -lm -lpthread -lssl -lcrypto -lao -lpulse-simple -lpulse -lasound -lavahi-common -lavahi-client
Configure successful. You may now build with 'make'
pi@raspberrypi ~/shairport $ make
pi@raspberrypi ~/shairport $ sudo make install
pi@raspberrypi ~/shairport $ sudo cp scripts/debian/init.d/shairport /etc/init.d/shairport
pi@raspberrypi ~/shairport $ cd /etc/init.d
pi@raspberrypi ~/shairport $ sudo chmod a+x shairport
pi@raspberrypi ~/shairport $ sudo update-rc.d shairport defaults
pi@raspberrypi ~/shairport $ sudo useradd -g audio shairport # add shairport user, then add user to audio group
For instance, if we wanted to name it HiFiPi, we'd make the AP_NAME line look like this (by default, it's set to the Raspberry Pi's hostname):
pi@raspberrypi ~/shairport $ sudo nano /etc/init.d/shairport
AP_NAME=HiFiPi # look for this line, and set to "HiFiPi" or whatever you want shairport to advertise
AP_NAME=$(hostname) # OR, use this to make the AirPlay name default to the Raspberry Pi's hostname
Make sure that the installation was successful by starting shairport
pi@raspberrypi ~/shairport $ sudo /etc/init.d/shairport start
Ok, so now we've basically installed shairport and it will launch everytime your Raspberry Pi boots. ### USB Soundcard Setup USB audio card next to Raspberry Pi #### Check to see if linux recognizes your USB sound card Make sure your soundcard is plugged in before booting up the Raspberry Pi. You can check to see if your system detects it with aplay -l
pi@raspberrypi ~ $ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA]
  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: MobilePre [MobilePre], device 0: USB Audio [USB Audio]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
#### Make the Raspberry Pi prefer the USB sound card Your Pi will prefer it's own hardware audio on boot-up, we need to change this by editing alsa-base.conf
pi@raspberrypi ~ $ sudo nano /etc/modprobe.d/alsa-base.conf
Find the following line:
options snd-usb-audio index=-2
Comment out the line and add the following after:
#options snd-usb-audio index=-2
options snd-usb-audio nrpacks=1
Find your sound card's alias by listing them with aplay -L (note the capital L)
pi@raspberrypi ~ $ aplay -L
    Discard all samples (playback) or generate zero samples (capture)
    Playback/recording through the PulseAudio sound server
    bcm2835 ALSA, bcm2835 ALSA
    Default Audio Device
    MobilePre, USB Audio
    Front speakers
    MobilePre, USB Audio
    IEC958 (S/PDIF) Digital Audio Output
    bcm2835 ALSA, bcm2835 ALSA
    Default Audio Device
According to the output above, it's called front:MobilePre, yours may be different. #### Tell ALSA to use the USB hardware as it's default sound device. Edit /etc/asound.conf to look like the following with front:MobilePre replaced with your own device identifier.
pi@raspberrypi ~ $ sudo nano /etc/asound.conf
It should look something like the following:
pcm.mmap0 {
    type mmap_emul;
    slave {
      pcm "hw:0,0";

pcm.!default front:MobilePre
Reboot your Pi.
pi@raspberrypi ~ $ sudo reboot
#### Test an audio file After restarting the machine, try playing an audio file out of it. mpg123 can play any mp3 stored on the machine. Lets transfer an mp3 over scp to the Pi:
drew@mymachine~ $ scp Cake.mp3 pi@
Install *mpg123* and see if the audio file plays:
pi@raspberrypi ~ $ sudo apt-get install mpg123
pi@raspberrypi ~ $ mpg123 Cake.mp3
Hear something? Awesome. #### Test Shairport via an Apple Device Connect headphones to your USB sound card and make sure the shairport streaming works. If it's all good, then we're done! No clicks, no pops, just delicious hi-fi audio. Shairport device on AirPlay chooser ### Troubleshooting Don't hear anything? Let's try to debug this. See what hardware device and subdevice the USB soundcard is listed at. At this point, it should be card 0, subdevice 0 as it is the default device.
pi@raspberrypi ~ $ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: MobilePre [MobilePre], device 0: USB Audio [USB Audio]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
card 1: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA]
  Subdevices: 7/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
Turn the mp3 into a wav file and force a test on the hardware where the 0,0 corresponds to *<card device number>,<subdevice number>*
pi@raspberrypi ~ $ mpg123 -w test.wav Cake.mp3
pi@raspberrypi ~ $ sudo aplay -Dhw:0,0 test.wav
If you hear nothing, perhaps your USB sound card is not compatible with the Pi. If you hear something, then the sound card simply is not being properly set as the default audio device. Double-check your *alsa-base.conf* and *asound.conf* files to try to spot a typo. ### Extra #### Bumping up the volume The 'max volume' for your USB sound card is often fixed to some value. You can control the volume dynamically via anything that can stream to AirPlay, but the volume will still be capped at a limit. Let's change this. Start playing audio on your Raspberry Pi. Use alsamixer to pull up a GUI for editing sound device volume. Press F6 and select your device. Edit the levels and then hit ESC when you're ready to exit.
pi@raspberrypi ~ $ alsamixer
After hitting F6 and selecting my device, it looks like this: alsamixer TERM control
Store those values as defaults.
pi@raspberrypi ~ $ sudo alsactl store 0
#### References * http://alsa.opensrc.org/.asoundrc * http://jordanburgess.com/post/38986434391/raspberry-pi-airplay * http://trouch.com/2012/08/03/airpi-airplay-audio-with-raspberry/ * http://www.jackenhack.com/raspberry-pi-usb-audio-quality-problems/