I finally got my hands on a Raspberry Pi and my first project has been to make a good quality music player. I've not had a speaker setup to listen to music on for many years - it's almost exclusively been on headpones, mostly on my phone, for far too many years now.

There are a lot of people out there doing similar things, and thanks to all for providing various hints and tips to get me going:

Most of these setups are focussing on a single audio source. I was after a more complex setup.

My goal for this project was to be able to chuck audio at the Raspberry Pi from:

  1. Android phones
  2. iOS devices
  3. MPD for standalone playback

Using PulseAudio has allowed me to achieve all of these goals as well as providing a few additional benefits.

USB Dac

The on-board sound out of the Raspberry Pi is not intended to be high quality and for me wasn't even close to reasonable for a HiFi experience. The Raspberry Pi has two USB ports and Raspbian has USB audio support available in the kernel out of the box.

There are a lot of USB DACs available to suit all budgets and quality requirements. I ended up with a HiFimeDIY Sabre.

I wasn't in the market for something audiophile, but I can certainly hear the difference in audio quality compared to the audio jack on my laptop.

Testing the DAC

The first step after plugging the DAC in is to try and play something. You can list the available audio devices:

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: DAC [HiFimeDIY DAC], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: DAC [HiFimeDIY DAC], device 1: USB Audio [USB Audio #1]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Playing something through the DAC is simply a case of telling aplay which device to use:

aplay -D plughw:1,0 /usr/share/sounds/alsa/Front_Left.wav
aplay -D plughw:1,0 /usr/share/sounds/alsa/Front_Right.wav
aplay -D plughw:1,0 /usr/share/sounds/alsa/Front_Center.wav

Low Latency nrpacks=1

There is a kernel module option to reduce the latency and help increase the quality of the USB audio output. I've enabled it to no noticeable effect other than to remove some error messages that were showing up rather frequently in the kernel log.

The guys over at The Raspyfi Project have made a rather extensive list of optimisations they've made to the stock Raspbian image.

ALSA

Using ALSA directly is nice and simple and should simply work everywhere if aplay worked above.

Unfortunately only a single device can use ALSA at a time, so for the audio nirvana we're aiming for we need to make use of a sound server. There have been a lot of different sound servers over the years in Linux, one of the more recent ones is PulseAudio. It has its fans and detractors, but is generally well supported in modern distributions with Raspbian being no exception.

PulseAudio

PulseAudio as with everything else sound related in Linux seems to be sporadically documented and there is also a lot of out of date information floating around. Thankfully the distribution maintainers do a generally fantastic job of pulling everything together.

System Wide PulseAudio

The only way I could get clean, glitch free playback with PulseAudio with the USB DAC was to run the PulseAudio daemon as root. The documentation for PulseAudio goes to great lengths to explain why you shouldn't run a system wide instance of PulseAudio.

Running PulseAudio as the pi user resulted in continual and very painful to listen to clicking in the output.

For this project I am running the Raspberry Pi headless with no X11 running so this is the only sane way to get PulseAudio up and running and we do fall under the one acceptable use case of running system wide PulseAudio - that of an embedded system with no real users.

Raspbian ships with an init script already supplied and to enable it you need to edit /etc/default/pulseaudio and change the appropriate line:

PULSEAUDIO_SYSTEM_START=1

I also added the pi and mpd users to the pulse-access group to allow them access.

root@raspberrypi:~# adduser pi pulse-access
root@raspberrypi:~# adduser mpd pulse-access
root@raspberrypi:~# groups mpd
mpd : audio pulse-access
root@raspberrypi:~# groups pi
pi : pi adm dialout cdrom sudo audio video plugdev games users netdev input indiecity pulse-access

Pulse Resampling

Older versions of pulse used a fixed sampling rate and would re-sample on the fly. With the release of v2.0 this has been changed. If the output device supports multiple sample rates then they will be switched on the fly.

You can get a list of available sample rates:

pi@raspberrypi ~ $ cat /proc/asound/card1/stream0 
HiFimeDIY Audio HiFimeDIY DAC at usb-bcm2708_usb-1.3, full speed : USB Audio

Playback:
  Status: Stop
  Interface 3
    Altset 1
    Format: S16_LE
    Channels: 2
    Endpoint: 3 OUT (ADAPTIVE)
    Rates: 8000, 16000, 32000, 44100, 48000, 96000
  Interface 3
    Altset 2
    Format: S24_3LE
    Channels: 2
    Endpoint: 3 OUT (ADAPTIVE)
    Rates: 8000, 16000, 32000, 44100, 48000, 96000

...

You can verify that PulseAudio is indeed switching on the fly with a couple of simple steps. Play a file with a sample rate of say 44.1 Khz and whilst it is playing:

pi@raspberrypi ~ $ cat /proc/asound/card1/stream0 
HiFimeDIY Audio HiFimeDIY DAC at usb-bcm2708_usb-1.3, full speed : USB Audio

Playback:
  Status: Running
    Interface = 3
    Altset = 1
    Packet Size = 388
    Momentary freq = 44100 Hz (0x2c.199a)
  Interface 3
    Altset 1
    Format: S16_LE
    Channels: 2
    Endpoint: 3 OUT (ADAPTIVE)
    Rates: 8000, 16000, 32000, 44100, 48000, 96000
  Interface 3
    Altset 2
    Format: S24_3LE
    Channels: 2
    Endpoint: 3 OUT (ADAPTIVE)
    Rates: 8000, 16000, 32000, 44100, 48000, 96000

...

In the first few lines (Momentary freq =) you can see the sample rate that is actually being used by the hardware.

There are almost certainly other ways to verify this and query all the properties of audio devices, but this seems to do the job!

Wireless

To cut down on the wires going to the system I opted to get a WiFi USB dongle. It's a low profile, low power adapter the same size as the micro Bluetooth dongles that have been around for a while now.

The chipset is a RTL8188CUS and with the latest Raspbian image simply worked out of the box.

pi@raspberrypi ~ $ sudo lsusb | grep Real
Bus 001 Device 004: ID 0bda:8176 Realtek Semiconductor Corp. RTL8188CUS 802.11n WLAN Adapter

There are plenty of guides on the web on how to configure wireless USB dongles for the Raspberry Pi.

AutoFS and NFS

My audio is all stored on a NAS which exposes it via Samba and NFS.

I use AutoFS to make mounting the networked filesystem nice and easy. A few packages are needed nfs-common, rpcbind and autofs5.

Edit /etc/audo.master and uncomment the /net line:

/net    -hosts

After starting up the autofs daemon you should be able to simply browse your network shares under /net/machine for example mine is under /net/plug.local.

MPD

MPD was a requirement for this project as it allows music to be queued up from a variety of sources and simply left to play.

Getting MPD up and running was easy and simply a case of telling it to use PulseAudio. Edit /etc/mpd.conf and set your audio_output section like so:

audio_output {
        type            "pulse"
        name            "MPD PulseAudio Output"
}

Setting the music_directory option to point to my AutoFS NAS mount directory was the only other change necessary to /etc/mpd.conf.

UPnP

With the basic audio output working the next step is a UPnP renderer so that I can get my Android phone in on the audio action. There are a few different UPnP renderer options available for Linux, but the easiest to get up and running I found to be gmediarender-ressurect. A few other people have got this up and going on the Raspberry Pi.

I'll hand over to the official documentation:

  1. Installation notes

And a couple of useful posts:

  1. A UPnP renderer for the Raspberry Pi
  2. RASPBERRY PI UPNP MEDIA PLAYER

gmediarender-ressurect uses GStreamer to output it's audio, which doesn't default to using PulseAudio. Thankfully it allows the audio output sink to be controlled from the command line:

/usr/local/bin/gmediarender -f upnp-pi --gstout-audiosink

Automatic Startup of gmediarender-ressurect

UPDATE - solved, see Musical Pi Follow Up

Using PulseAudio made getting automatic startup working a bit tricky. I had a couple of attempts at creating an init.d script, which were partially successful. gmediarender would start successfully, but would insist on routing audio out via the onboard audio of the Raspberry Pi rather than the USB DAC.

My solution was to simply start it up via a line in /etc/rc.local:

su -c "/usr/local/bin/gmediarender -f upnp-pi -d --gstout-audiosink pulsesink" pi

Simply, easy and does the trick.

GStreamer Default Sink

You can set GStreamer to use PulseAudio as its default sink with a quick GConf change:

gconftool-2 -t string --set /system/gstreamer/0.10/default/audiosink pulsesink

As previously mentioned though, this wasn't enough for me to get everything working on boot. The /etc/rc.local approach seems to be the most reliable so far.

AirPlay

As there are also fruity products around in our household AirPlay support was definitely on the list of things to get working. Enter ShairPort!

Again I'll hand over to others at this point:

  1. Official documentation
  2. Turn a Raspberry Pi Into an AirPlay Receiver for Streaming Music in Your Living Room
  3. Hacking a Raspberry Pi into a wireless airplay speaker

Automatic Startup of ShairPort

UPDATE - solved, see Musical Pi Follow Up

Again I had a few problems getting the supplied init.d script to work. It is almost certainly something to do with using PulseAudio, but again a simple one liner in /etc/rc.local does the job:

su -c "/usr/local/bin/shairport.pl --a air-pi -d --ao_driver=pulse" pi

Networked PulseAudio Speakers

One benefit of using PulseAudio is that you can make use of PulseAudio network streaming for next to no effort. This allows me to route all the audio output from my laptop to a decent set of speakers via the Raspberry Pi, great for things like Spotify or anything else that can't be run directly on the Raspberry Pi.

There are a few bits and pieces necessary to get this working.

Enable receiving and advertising networked audio on the Raspberry Pi by adding the following to /etc/pulse/system.pa:

load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1;192.168.0.0/16
load-module module-zeroconf-publish

Obviously change the ip address ranges to suit and you'll need to install pulseaudio-module-zeroconf.

Finally you need to allow PulseAudio to make use of the networked speakers on your other machines. Fire up paprefs on a machine with PulseAudio installed and check the "Make discoverable PulseAudio sound devices available locally". You probably have to log out and back in again to have this option take affect.

I had to install pulseaudio-utils to get the paprefs application.

On my Ubuntu 12.04 laptop in the "Sound Settings" applet I now get the option to choose "HiFimeDIY DAC Analog Stereo on pulse@raspberrypi.local" as a destination for my sound. Lovely!

Issues

I get occasional niggles with the wireless - it feels like the dongle goes to sleep sometimes and takes a while to respond after periods of inactivity. That and occasional signal problems make me think it may be worth considering going down the wired ethernet route. That said the problems seem transient and infrequent enough to be ignored and in general the bandwidth is stable enough to stream FLAC and networked PulseAudio without issue.

Thoughts

One final thing I'd love to get working is getting audio from Windows through to the Raspberry Pi in the same way that PulseAudio lets me do with Linux. There are a few options floating around there on the web including AirFoil which works with the AirPlay protocol, but I've not experimented yet.

All in all though it's been a fun project and I'm enjoying having my music out in the open and not trapped in my headphones!

5 thoughts on “Yet Another Musical (Raspberry) Pi

  1. Pingback: TwoToneDetect on a Raspberry Pi - How To - Page 7 - The RadioReference.com Forums

  2. Pingback: Playing music on a Raspberry Pi using UPnP and DLNA (revisited) | Stephen C Phillips

  3. Hi - any idea if its possible to switch audio devices on the fly with pulse audio? haven't had any luck wi alsa and been trying for ages - idea is to have 1 set of speakers connected via usb and another by hdmi (or 3.5 jack) in a different room and be able to send the audio to either both or just one or the other without having to reboot....
    any ideas??

    Reply
  4. Pingback: Raspberry Pi’yi bir Müzik Merkezi’ne dönüştürmek (MPD Kurulumu) | Raspberry Pi Türkiye Topluluğu

  5. Hi There, I was experiencing random wireless dropouts too especially after idle. I use the RTL8188CUS chipset based wifi dongle. It was so frustrating that I deemed the Raspberry PI project a failure and shelved 4 months ago.

    Today I revisited the project to install shairport and sure enough the same problem returned. I tried to turn off power management for the card to no avail. Then I swapped microcables, swapped powersupply and went all the way to 2A powersupply and still the same issue. Finally it dawned on me that it could be the ondemand governer.

    So changed the governer to performance governer and voila the issue is gone. No more wireless dropouts. Rock solid wireless.

    So to change the governer for current session, under a root prompt do the following:
    List available governers
    #cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
    Change to performance governer for only this session (reverts to on demand governer on reboot)
    # echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

    At this point, repeat the first command to verify current governer has changed to performance. If so, ssh to the pi and leave it idle for a while. Then come back and check if you can continue the session (i.e no dropouts).

    If you are happy with performance governer, you can make the changes permanent by following the debian guide here:

    https://wiki.debian.org/HowTo/CpuFrequencyScaling

    Hope this helps others as this was sooooo frustrating for me.

    Cheers from Australia.

    Reply

Leave a reply

required

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>