Running snapclient with pulseaudio on Raspbian

Multi-room audio is one of those things that sounds like it should be simple. You’ve got speakers, you’ve got a network — just pipe audio from A to B, right? Well, not quite. One of our clients wanted whole-house audio using Raspberry Pis as receivers with Snapcast, and while the server side was straightforward, getting snapclient to talk to PulseAudio on a fresh Raspbian Bookworm install turned into a bit of a detour.

The problem

Out of the box, snapclient on Raspbian Bookworm can’t connect to PulseAudio. The service starts, but there’s no sound — and the logs are full of connection refused errors. Since these Pis are headless appliances with no desktop environment, PulseAudio isn’t running in a user session where snapclient can reach it.

Going system-wide

The fix is to run PulseAudio as a system-wide daemon. Not everyone’s favourite approach — the PulseAudio docs will wag a finger at you — but for a headless audio appliance it’s the pragmatic choice.

First, we create a systemd service for PulseAudio:

sudo nano /etc/systemd/system/pulseaudio.service
[Unit]
Description=PulseAudio Daemon

[Install]
WantedBy=multi-user.target

[Service]
Type=simple
ExecStart=/usr/bin/pulseaudio --system --realtime --disallow-exit --no-cpu-limit
Restart=on-failure
LimitRTPRIO=1000
LimitNICE=-20
LimitMEMLOCK=256M

Making snapclient wait its turn

Next, we update the snapclient service to depend on PulseAudio — otherwise it might start before PulseAudio is ready and sulk about it:

sudo nano /etc/systemd/system/multi-user.target.wants/snapclient.service
[Unit]
Description=Snapcast client
Documentation=man:snapclient(1)
Wants=avahi-daemon.service
After=network-online.target time-sync.target sound.target avahi-daemon.service pulseaudio.service

[Service]
EnvironmentFile=-/etc/default/snapclient
ExecStart=/usr/bin/snapclient --logsink=system $SNAPCLIENT_OPTS
User=snapclient
Group=snapclient
Restart=on-failure

[Install]
WantedBy=multi-user.target

Note the pulseaudio.service added to the After= line.

Permissions and config

The snapclient user needs to be in the pulse-access group to talk to the system-wide PulseAudio daemon:

adduser snapclient pulse-access

And finally, we tell snapclient to actually use PulseAudio as its output:

sudo nano /etc/default/snapclient
START_SNAPCLIENT=true
SNAPCLIENT_OPTS="--player pulse"

Reboot the Pi and that’s it — audio sorted.

Leave a Reply