Sunday, January 15, 2023

Synchronized Whole-House Audio (Open Source Sonos)

This post is deprecated. See this github repo for a more complete description and helpful scripts.

 

 

 

 

Some years ago our Squeezebox player died. We kept the janky perl daemon and replaced the player with a raspberry pi, using its built-in DAC connected to the same 1980s-era audio amp, driving two sets of speakers. A house renovation demolished the speaker wiring between rooms, and it was finally time to move into the modern era.

Two neat innovations have come along in the two decades since we bought the squeezebox. The first is software: the Snapcast time-synchronized audio player lets you scatter tiny wifi receivers around your house and have them all play music synchronized together. The second is hardware: the HiFiBerry Amp puts a 60W audio amp into a pi-hat form factor powered by a surplus laptop charger.

This whole story hinges on raspberry pis, which have been unobtanium for a couple years, but hopefully the situation returns to normal soon.

This system is exactly the sort of thing that appeals to me: open source everything. But of course that means you get to (have to) choose bits and pieces at each layer. Here are the choices I've put together so far.

  • Music starts in a folder on the filesystem of my home server.
  • mpd, a music daemon on the server, indexes the music folder, accepts playlist requests, and plays the music as an audio stream to a named pipe.
  • Users can control the playlist request using a web browser. Another daemon ampd provides the web UI and issues commands to mpd. (I don't recall the channel that delivers mpc commands.)
  • When new music is installed on the server, I issue an mpc update command line to request mpd to re-index the filesystem.
  • The audio stream from the music player arrives at snapserver, the daemon that coordinates the time-synced players.
  • snapcast clients running on raspberry pis fetch the audio stream over TCP over WiFi from the snapserver. They play the audio back through the Linux alsa audio subsystem.
  • The drivers for the hifiberry hardware intercept the audio stream and convert it using a high-quality 16-bit DAC and send it out to the amp and speakers.

Direct application audio. It's also possible to manually generate streams of audio and shove them into another audio stream on the snapserver. For example, I can pass flags to vlc to deliver the audio to a TCP port. Each player station can be set to listen to different streams. Since I use this feature rarely, I have a single "fallback" stream set up to play the manual stream if it's present, and otherwise play the mpd playlist audio.

This scheme has a multi-second lag. vlc can be configured to delay the video to match, but it's a hassle and controls like pause feel weird with that much delay.

Future ambitions

More players. There's no reason I couldn't run two instances of mpd. This would let family play americana in the kitchen and living room while I'm listening to folk in the basement and shop.

Bluetooth input. I'd like to press the bluetooth hardware of one of the pis into service as a bluetooth endpoint so people can just send music from a phone or tablet directly to the big speakers in the room they're in. Because of the lag in the pipeline, this probably won't work for playing videos.

Better UI. The ampd UI is pretty clunky, slow, and surprising. Search doesn't work. My music collection has nice album art, but mpd ignores it so ampd fills in random searches from the Internet.