This is a (personal) playbook to configure my multi-room radio/Spotify HiFi system. Running on MPD, Snapcast, librespot-java and lirc. Built over frustration of missing features or configurability in the existing pre-built systems such as RuneAudio, Volumio, Pi MusicBox or Moode.
At some point I realised, it was quicker to just build the system myself. Using Ansible I can easily reproduce such a configuration and keep it manageable.
Hopefully these playbooks can also offer some inspiration to you.
I like to play internet radio and Spotify (Connect) in a multi-room setup. The radio part I'm mostly controlling via a traditional remote control, connected via a simple infrared eye on one of the Pi's.
For spotify librespot is the obvious choice.- For Spotify, I've switched to librespot-java
- Only reason is the built-in API, which can easily be called from irexec for remote control
- The librespot-java API also can pass through requests to the Spotify API. Also useful
- For internet radio classic MPD is being used
- I started with Mopidy, but run into issues with a very slow startup (10 s) to start an internet stream.
- Also
mpc
commands were relatively slow (2 s) to execute. - For my usecase I didn't need the Mopidy features, so I switched to the simpler MPD.
- I kept the Ansible playbook task file, in case I want to switch back
- Also
- Using mpdbear for Android to control MPD from my phone.
- Volume control is entirely in Snapcast. I don't touch the MPD (or librespot) volume.
- I started with Mopidy, but run into issues with a very slow startup (10 s) to start an internet stream.
- Multi-room is achieved using Snapcast
- Using the software mixer on all systems, and then fine-tuning the hardware (ALSA) mixers to a nice level gave me the best equal response in volume.
- The
snap_default.py
script is being run to reset the Snapcast volume on every (nightly) reboot for all clients (no surprises in the morning)- Added as
ExecStartPost
to the Systemd service file
- Added as
- Both MPD and librespot pipe their output into the same named pipe. This makes the setup easier to understand.
- This does mean that MPD and librespot should not play at the same time.
- Librespot executes the
mpc_stop.sh
script using the--onevent
handler - The other way around, I've not found a good way to stop librespot when MPD starts.
- I did include a simple
sudo service librespot-java restart
to execute on the remote control power button
- I did include a simple
- Using Snapdroid for Android to control Snapcast
- Using lirc to have my simple remote control working
- The infrared eye has been connected on 3 GPIO pins (add
dtoverlay=gpio-ir,gpio_pin=17
to/boot/config.txt
) - Getting the remote to work using
irrecord
can be a bit of a pain. - I looked at using
uevent
for processing events, but in the end defaulted to the simplerirexec
for sending commands - Most of the command magic is in
irexec.lircrc
.- Using
python-snapcast
to control the Snapcast volume - Created simple scripts
snap_mute.py
andsnap_volume.py
to control the muting and volume of the Snapcast clients
- Using
- The infrared eye has been connected on 3 GPIO pins (add
Running on Raspberry Pi OS Lite (Raspbian 11 (bullseye)).
touch /boot/ssh
/boot/wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=NL
network={
ssid="<SSID>"
psk="<PASSWORD>"
scan_ssid=1
}
Run sudo raspi-config
. Enable:
- Wait for network to boot
- Install nl_NL.UTF8 locale
- Expand SD card
Disable most of the HMDI options.
For kitchen (a Raspberry Pi Zero 2 W with HifiBerry Zero AMP)
dtparam=act_led_trigger=actpwr
hdmi_blanking=2
dtoverlay=hifiberry-dac
For living (a Raspberry Pi 3 with HifiBerry MiniAMP)
dtoverlay=hifiberry-amp
dtoverlay=gpio-ir,gpio_pin=17
dtoverlay=disable-wifi
dtoverlay=disable-bt
- Change default password.
- Add personal SSH key
- Maybe include PiHole to set persistent hostnames, and not having to use IPs.
- Why-o-why is zeroconf/avahi still so unreliable, and not enabled on Android??