In my last post I outlined my intention to make a Sonos-like audio streaming system. Today I managed to get a single Raspberry Pi playing music from a Spotify through a server on my home network. I’ll explain how I did it, and what I’m going to do next.
As I hinted at in my previous post, I don’t particularly fancy playing about with a Perl behemoth like Logitech Media Server. It also just seems a bit of a dead end to me – the server’s code is open source, but it’s hosted by Logitech, and it was open-sourced after they mothballed their Squeezebox range. Who can say how long Logitech will keep hosting and maintaining the code? Surely they will lose interest, without a product range to back up their investment of time and money. Additionally, the software seems so featureful that the community aren’t forking it and actively adding new features or refactoring the code. This state of play led me to try to find another solution, and it seems I have found it in Mopidy.
Mopidy is a Music Player Daemon (MPD) service, hence the name. It supports a subset of the standard features of MPD, but most of the important ones. Staying close to MPD means that Mopidy can be controlled with one of the many MPD clients available. For instance, during my testing I was using ncmpcpp, a terminal client.
The feature I love about Mopidy is that it is written in Python. I can open it up and work out what’s going on, with enough effort, and I can add extensions if I am so inclined. It also supports PulseAudio, which brings me on to the next part of the setup…
PulseAudio is a piece of software that acts as an interface between audio sources (programs, games, microphones, etc.) and audio ‘sinks’. A ‘sink’ is a place where audio goes, be it a sound card, an audio editor or a network stream. PulseAudio supports streaming via RTP, which brings me on to the next part…
Real-time Transport Protocol
Real-time Transport Protocol, or RTP, is a method of transport on networks which tries to make sure that data is sent in a timely fashion. It is intended for use with audio, and often forms part of VoIP packages a la Skype. We can tolerate packet loss with audio, in favour of keeping everything timely.
Since I currently only have two Raspberry Pis, and one is spending its life forwarding electricity and temperature data to another server, I can only set up one Pi as a receiver. This is a good opportunity to test the concept of the Mopidy-PulseAudio-RTP audio stack.
In terms of hardware…
- I need a server to host Mopidy and stream its audio via PulseAudio-RTP. I have a Philips Living Room PC Core 2 Duo server that’s about 5 years old that I use for this kind of thing, running, as of yesterday, Ubuntu 14.04 LTS Server Edition.
- I have a Raspberry Pi, of course, with a 16 GB memory card with Raspbian. The 16 GB is only there because I don’t have any other SD cards larger than 2 GB (standard install Raspbian needs about 3 GB). Mopidy and PulseAudio won’t need anywhere near 16 GB of storage, and I’ll probably eventually strip out all the extra stuff in Raspbian I don’t use and copy the whole card to a 2 GB one. I am using headphones on the Pi to listen to music. The output jack won’t drive anything more powerful, so you’ll need an amplifier if you want to play music through speakers. It’s also possible to output audio via the HDMI port, so that might work for others.
- A laptop to control what’s playing. Not strictly necessary, if the server is also a useable desktop computer. You can also use one of the many MPD clients available for Android and iOS to control Mopidy, if you want.
- A router running DHCP or similar, with every device connected to it. Again, strictly, the DHCP server can be the same as the music server, but I use my home router as the DHCP server so I’m using that. The Raspberry Pi and server are connected via wire to a switch which in turn is connected to the router. The room I’ve got this stuff set up in has only one ethernet wired connection, and I split it into two with the switch. The laptop is connected wirelessly.
In terms of software, this is what I’ve used:
- Server: Ubuntu 14.04, PulseAudio, Mopidy
- Raspberry Pi: Raspbian, PulseAudio
- Laptop: Ubuntu 12.04, ncmpcpp terminal client
Here’s how to do it:
PulseAudio setup on both the server and the Pi
server~$ sudo apt-get install pulseaudio
pi~$ sudo apt-get install pulseaudio
That should work for both Ubuntu and Raspbian.
Next, set up an RTP sink on the server. Change directory and edit
server~$ cd /etc/pulse/
server~$ sudo nano default.pa
Fill it with the following content:
#! /usr/bin/pulseaudio -nF load-module module-native-protocol-unix auth-anonymous=1 load-module module-suspend-on-idle timeout=1 load-module module-null-sink sink_name=rtp format=s16be channels=2 rate=16000 load-module module-rtp-send source=rtp.monitor
This will set the audio sample rate to 16 kHz. This is low, but I found that setting it to 44.1 kHz or 48 kHz would congest the network to the extent it is unusable. I need to tweak this later and get it to work, perhaps using a separate network altogether.
server~$ sudo nano daemon.conf
Leave everything in there, but uncomment and edit the line
exit-idle-time to be:
exit-idle-time = -1
And uncomment and edit the line
default-sample-format = s16le
On the Raspberry Pi, configure the
pi~$ cd /etc/pulse
pi~$ sudo nano default.pa
Uncomment the line that says
#load-module module-rtp-recv .
daemon.conf on the Pi:
pi~$ sudo nano daemon.conf
Add at the bottom:
default-sample-rate = 16000 resample-method = src-sinc-fastest default-fragments = 10 default-fragment-size-msec = 10
Mopidy and Spotify on the Server
Following the installation instructions from Mopidy, on the server, add the repository key:
server~$ wget -q -O - http://apt.mopidy.com/mopidy.gpg | sudo apt-key add -
Add the repository sources as a file:
server~$ cd /etc/apt/sources.list.d/
server~$ sudo nano mopidy.list
Add to the file:
# Mopidy APT archive deb http://apt.mopidy.com/ stable main contrib non-free deb-src http://apt.mopidy.com/ stable main contrib non-free
Update the repositories and download the packages:
server~$ sudo apt-get update
server~$ sudo apt-get install mopidy mopidy-spotify
Run Mopidy once to make it generate the configuration file:
Ctrl+C to kill the server. Edit the file
server~$ sudo nano ~/.config/mopidy/mopidy.conf
Edit the configuration options under
[mpd] to look like this (you can leave the commented values already there):
[audio] output = pulsesink device=rtp
[mpd] enabled = true hostname = :: port = 9999
Set the port in
[mpd] to whatever you want. I found the default Mopidy port was already used, even on the default Ubuntu 14.04 install, so I set it to
For Spotify, edit the values under
[spotify] enabled = true username = [username] password = [password]
Obviously setting [username] and [password] as appropriate. I found that this pair was all I needed to get Mopidy to access my playlists successfully. It’s also possible to specify bitrates and timeouts, but I left these commented.
(Optional) ncmpcpp on Controller
Follow the instructions on the ncmpcpp website. I didn’t want to add the unstable Debian repository so I compiled it from source, but there are alternatives.
Getting it to Work
Everything is configured, so it should then be possible to start everything up and play music on the Pi. On the server, start PulseAudio as a daemon and Mopidy in userspace:
server~$ pulseaudio -D
server~$ mopidy &
Pay attention to
/var/log/syslog if you have any trouble.
On the Pi, start PulseAudio:
pi~$ pulseaudio -D
Again, any trouble and check the syslog.
Now, play something on the server using the laptop or other controller:
laptop~$ ncmpcpp -h 192.168.1.10 -p 9999
The IP address
192.168.1.10 corresponded to my server. The port is set to the one I specified in the configuration.
In ncmpcpp, I can look at my Spotify playlists and play them, and I hear the tunes through my Raspberry Pi’s headphones. The music quality isn’t great, because I set the sample rate quite low. I will need to investigate network issues to see how to improve audio quality while keeping network congestion minimal. PulseAudio’s RTP uses multicast, and this in general is a heavy protocol. For instance, reports all over the web say it can floor a WiFi connection with ease. Sonos uses a separate wireless network, and presumably this is because quality and throughput can’t be guaranteed on a regular network.
So, I have the ability to play music across the network. Next up, I will get another Raspberry Pi and set it up to listen to the same stream, to test how multicast works with two clients. Hopefully the timing provided by RTP will mean the music steams will be in sync.