Spotifyd + RaspberryPi = ❤️

Posted on 09 Jun 2017 - filed under: server, spotify

In the forever quest for the perfect <INSERT THING HERE> setup, I’ve recently installed spotifyd on my Raspberry Pi so that I can casually switch from my phone’s headphones to my HiFi system when I come home, sit back, relax & enjoy my sweet streamed tunes.

So after this, you’ll have your RaspberryPi hooked up to your HiFi system, which you’ll be able to control via your smartphone, or any Spotify app instance. This will only work if you have a spotify premium account.

Spotifyd - The Spotify Daemon

Spotifyd is a neat little daemon written in Rust. It implements the Spotify connect protocol which allows you to control one instance of spotify from another (ie. control your PC’s spotify with your smartphone).

Building Spotifyd on RaspberryPi

As my RaspberryPi’s primary function is a media center, I’m runnig OSMC (a linux distribution forked from debian) on it. So your mileage may vary, as you may have a different setup.

First you need to install Rust, refer to this page for the latest instructions on how to install Rust.

Once this is done, you should be able to invoke cargo build --release (cargo being Rust’s package manager), this should install the dependencies needed by Spotifyd. This can a while on a RaspberryPi so be patient…

Once it is done, you will need a configuration file for spotifyd, go ahead and issue the following command mkdir -p ~/.config/spotifyd/, in that folder create a config file that looks something like:

[global]
username = YOUR_USER_NAME
password = YOUR_PASSWORD
backend = alsa
device = hw:0
onstart = /usr/bin/amixer cset numid=3 1
onstop = /usr/bin/amixer cset numid=3 0
device_name = videodrome
bitrate = 320
cache = /home/osmc/.cache/spotifyd/

You might also want to create the ~/.cache/spotifyd folder.

This is pretty straightforward for the most part, the tricky part being things related to the audio backend, namely backend, device, onstart and onstop.

The RaspberryPi has two audio outputs, one for HDMI (through the TV speakers) and one for the analog jack plug (for the HiFi). In this setup, both outputs will be used thanks to some wizardry.

Identifying your audio output

Running aplay -L (you can sudo apt-get install alsa-utils if theaplay is not available) will list all the audio devices you have. The output is pretty cryptic, here’s mine:

osmc@Videodrome:~$ aplay -L
null
    Discard all samples (playback) or generate zero samples (capture)
default:CARD=ALSA
    bcm2835 ALSA, bcm2835 ALSA
    Default Audio Device
sysdefault:CARD=ALSA
    bcm2835 ALSA, bcm2835 ALSA
    Default Audio Device
dmix:CARD=ALSA,DEV=0
    bcm2835 ALSA, bcm2835 ALSA
    Direct sample mixing device
dmix:CARD=ALSA,DEV=1
    bcm2835 ALSA, bcm2835 IEC958/HDMI
    Direct sample mixing device
dsnoop:CARD=ALSA,DEV=0
    bcm2835 ALSA, bcm2835 ALSA
    Direct sample snooping device
dsnoop:CARD=ALSA,DEV=1
    bcm2835 ALSA, bcm2835 IEC958/HDMI
    Direct sample snooping device
hw:CARD=ALSA,DEV=0
    bcm2835 ALSA, bcm2835 ALSA
    Direct hardware device without any conversions
hw:CARD=ALSA,DEV=1
    bcm2835 ALSA, bcm2835 IEC958/HDMI
    Direct hardware device without any conversions
plughw:CARD=ALSA,DEV=0
    bcm2835 ALSA, bcm2835 ALSA
    Hardware device with all software conversions
plughw:CARD=ALSA,DEV=1
    bcm2835 ALSA, bcm2835 IEC958/HDMI
    Hardware device with all software conversions

Well I will save you the trouble of googling for hours. Although the RaspberryPi has two audio outputs, they’re both handled by the same hardware device (sound card).

Since you only have 1, the device is hw:0, that’s the device = hw:0 line in your config file.

Now that’s where it gets tricky, according to this page from the Pi’s website

The Raspberry Pi has two audio output modes: HDMI and headphone jack. You can switch between these modes at any time.

If your HDMI monitor or TV has built-in speakers, the audio can be played over the HDMI cable, but you can switch it to a set of headphones or other speakers plugged into the headphone jack. If your display claims to have speakers, sound is output via HDMI by default; if not, it is output via the headphone jack. This may not be the desired output setup, or the auto-detection is inaccurate, in which case you can manually switch the output.

I did not succeed in specifying the Jack device directly in the spotifyd.conf file. But as the RaspberryPi document states, you can invoke amixer cset numid=3 1 to set the audio output to the headphone jack. That why we have the onstart = amixer cset numid=3 1 in the configuration file. I’m not sure how this works, but this seems “session specific” as only spotifyd’s audio output is directed to the jack (the media center continues to output to HDMI). But hey, it works ! :P

The alsa-utils package also comes with a player called aplay, you can go ahead and test your audio output by typing:

$> amixer cset numid=3 1
$> aplay whatever.wav

If you hear a sound, you’re all set !

Create a Service

It’s nice to have that daemon running and all, but things crash, and having a way to have it relaunched automatically is always a plus. OSMC uses systemd to manage services (which is subject to heated debates).

Create the /lib/systemd/system/spotifyd.service file with the following content:

[Unit]
Description=Spotifyd

[Service]
ExecStart=/home/osmc/spotifyd/target/release/spotifyd --no-daemon --config /home/osmc/.config/spotifyd/spotifyd.conf
Restart=always

[Install]
WantedBy=multi-user.target

Then issue the following commands:

$> sudo chmod 644 /lib/systemd/system/spotifyd.service
$> sudo systemctl daemon-reload
$> sudo systemctl enable spotifyd.service
$> sudo systemctl start spotifyd.service

Now run this, and if you have a similar output, everything is setup !

osmc@Videodrome:~$ systemctl status spotifyd.service
● spotifyd.service - Spotifyd
   Loaded: loaded (/lib/systemd/system/spotifyd.service; enabled)
   Active: active (running) since ven. 2017-06-09 16:43:47 CEST; 5h 54min ago
 Main PID: 27502 (spotifyd)
   CGroup: /system.slice/spotifyd.service
           └─27502 /home/osmc/spotifyd/target/release/spotifyd --no-daemon --config /home/osmc/.config/spotifyd/spotifyd.conf

Systemd will now make sure that this service is running, and relaunch it in the event of a crash !

What does not work

Volume cannot be adjusted
The feature is not implemented yet in spotifyd This github issue talks about it.
Repeat/Shuffle toggles don’t work
librespot does not implement this yet, this issue talks about it.

Enjoy your setup !