How to Set Up Multi-Room Audio with Snapcast (Synchronised Music on Cheap Speakers)

Music in every room, perfectly in sync: Snapcast on the server, a Pi and a speaker per room, any source you like.

Multi-room speaker systems cost hundreds per room and tie you to one app. Snapcast does the hard part — playing the same audio on many devices with sample-accurate sync — in software: a server on your home server takes audio from any source, and a client on each room's device (a Raspberry Pi Zero and a £15 speaker, an old phone, a PC) plays it in time. Navidrome (84), Spotify Connect, AirPlay, Mopidy, a radio stream or a microphone can all be sources, and Home Assistant gets per-room volume.

Quick reference

PieceWhat
Serversnapserver in Docker on the home server, port 1704/1705, web UI on 1780
Sourcesnamed pipes or processes: librespot (Spotify), shairport-sync (AirPlay), MPD/Mopidy, Navidrome via MPD-style player
Clientssnapclient on a Pi (sudo apt install snapclient), or the Snapcast Android app
Controlhttp://server-ip:1780 (Snapweb), or Home Assistant's Snapcast integration
Latency--latency per client to align Bluetooth speakers
Groupsrooms grouped to play the same stream or different ones

1. The server

mkdir -p ~/docker/snapcast/{config,data} && cd ~/docker/snapcast
nano compose.yaml

services:
snapserver:
image: ghcr.io/badaix/snapcast:latest
container_name: snapserver
command: snapserver -c /config/snapserver.conf
ports:
- "1704:1704"
- "1705:1705"
- "1780:1780"
volumes:
- ./config:/config
- ./data:/tmp/snapfifo-dir
restart: unless-stopped

librespot:
image: ghcr.io/badaix/snapcast:latest # same image has librespot; or use a dedicated image
container_name: librespot
command: librespot --name "Home Speakers" --bitrate 320 --backend pipe --device /tmp/snapfifo-dir/spotify --initial-volume 80
volumes:
- ./data:/tmp/snapfifo-dir
restart: unless-stopped

nano config/snapserver.conf

[stream]
source = pipe:///tmp/snapfifo-dir/spotify?name=Spotify&sampleformat=44100:16:2
source = pipe:///tmp/snapfifo-dir/music?name=Music&sampleformat=44100:16:2
source = tcp://0.0.0.0:4953?name=Radio&mode=server
codec = flac
buffer = 1000

[http]
enabled = true
bind_to_address = 0.0.0.0
port = 1780
doc_root = /usr/share/snapserver/snapweb

[stream.music]

Each source is a stream clients can choose. A pipe is a file another program writes raw audio into — librespot for Spotify above; MPD or Mopidy configured with a pipe output into /tmp/snapfifo-dir/music for your Navidrome/local library; shairport-sync for AirPlay the same way. The TCP source lets anything that can send raw PCM (a script with ffmpeg) feed a stream.

docker compose up -d
sudo ufw allow from 192.168.1.0/24 to any port 1704:1705 proto tcp
sudo ufw allow from 192.168.1.0/24 to any port 1780 proto tcp

2. A client in each room

A Raspberry Pi Zero 2 W with a USB DAC or a cheap HAT, into any powered speaker:

sudo apt install snapclient -y
sudo nano /etc/default/snapclient

SNAPCLIENT_OPTS="--host 192.168.1.50 --hostID kitchen --soundcard default"

sudo systemctl enable --now snapclient

snapclient -l lists sound cards if default isn't the DAC. Repeat per room with a different hostID. Old Android phones: the Snapcast app, server address, done — a phone docked on a speaker is a perfectly good room.

A PC or the server itself can be a client too (snapclient on the desktop, plugged into the living-room amp).

3. Control it

Open http://192.168.1.50:1780 (Snapweb): every client with its volume, mute, and which stream its group plays. Drag clients into groups — kitchen and dining on Spotify, bedroom on Radio. The browser can also be a client (play in the tab).

Home Assistant: Settings → Integrations → Snapcast → server address. Each room becomes a media player entity: volume sliders on the dashboard, "mute the kids' room at 9 pm", "play Radio 4 in the kitchen at 7 am". Music Assistant integrates it too, with Navidrome as a library.

4. Sync and Bluetooth

Wired and USB outputs are sample-accurate out of the box. A Bluetooth speaker adds its own delay; set --latency 150 (ms, tune by ear) on that client so it lines up with the others. buffer = 1000 on the server is the global headroom; raise it on flaky Wi-Fi.

5. Sources worth adding

Troubleshooting

Client plays nothing. Wrong --soundcard; snapclient -l. Or the stream's fifo has no writer yet — start Spotify playing.

Rooms drift out of sync. A Bluetooth or HDMI output with variable delay; set --latency. Or Wi-Fi dropouts: buffer up.

Crackling on a Pi Zero. CPU; use codec = pcm or opus instead of flac, and a USB DAC rather than the Pi's own jack.

Spotify device doesn't appear. librespot needs the same LAN as the phone for discovery (mDNS; VLANs again), and a Premium account.

Wrapping up

One server container with a stream per source, a Pi and speaker per room, Snapweb or Home Assistant for control. Spotify, AirPlay, your own library and the radio play in perfect sync across the house, on speakers you already owned, controlled from the dashboard that runs everything else.

Call us