The Snapcast project provides an Open Source client (Snapclient) and server (Snapserver) that distributes audio over a digital network to multiple audio output devices while ensuring synchronization. This enables listening to an audio stream over an extended area, even if that area consists of multiple isolated spaces.
What Snapcast does is simple. But it does it very well, and the pervasive access to music that Snapcast enables has contributed significantly to my quality of life over the last several years.
With a little effort Snapcast makes it possible to implement a whole house audio system that rivals six figure professional installations but which, if implemented with at hand or second hand hardware, costs very little.
Many thanks to the contributors who make Snapcast possible.
Collecting and listening to music has always been a priority for me, and I like to make music part of my everyday experience.
For me the best way to achieve this is to distribute the audio I am listenting to throughout my home, so I can listen uninterrupted as I move about.
I have used several methods to accomplish this over the years.
When my living arrangements did not accommodate installing the necessary cables to achieve whole house audio, my solution was a short range FM transmitter. This solution was simple to set up, but offered limited range and mediocre sound quality.
Once I had the means, I installed analog cabling from the analog line output on my server to my receiver/amplifier. This provided quality sound in the space where the stereo system resided, but other parts of the house were still dependent on the FM transmitter and it’s limited range and sound quality.
I had the good fortune to design and build my own house. This allow me to place architectural speakers in the main living space, driven by a stereo receiver receiving the analog feed from my server.
Definitely a step forward. But quality listening was still restricted to the one space, and managing content through the server independent from setting volume and speaker selection at the stereo receiver complicated operation.
With the new house came a new problem. The house was in a rural area, in a sheltered location, and had a steel roof. FM radio, the primary source of much of what I liked to listen to, was unusable.
The other feature incorporated in the house was extensive Cat 5e cabling. There had to be a way to distribute quality audio throughout the house without having to run parallel analog audio cabling to every room.
At this point, everyone in the audience is screaming “Sonos”. Yes, Sonos does this; distributed, synchronized audio over a digital network.
However, with a proprietary solution:
you are often dependent on a cloud service, so your system becomes electronic waste at the whim of the market
your choice of audio sources is constrained by the profit motive of your product’s manufacturer
you are dependent on the diligence of your provider to maintain access to existing services when they make changes, and to keep up to date with new service offerings
you have to buy all new, often expensive, hardware
With an Open solution, there is more work up front. But you secure a solution that:
is sustainable in the long term
is customizable to your specific requirements
uses audio equipment already at hand
can be implemented on existing multi-purpose hosts, saving space and power
are componentized; parts of the system can be replaced or upgraded without impact to the remainder of the system
allows your audio amplifiers and speakers to serve multiple use. They can provide high quality output from your PC when watching a movie, then distribute your whole house audio the remainder of the time.
Google has a campaign underway for Nest devices that highlights whole house audio as the key feature. If you are happy revealing intimate personal information in exchange for convenience of installation you are welcome to your choice. But this is not a solution that works for me.
Sonos appears to only stream synchronized audio sourced from a phone. Why should my home audio system fail just because I am using my phone away from home? Which, last time I checked, was the primary use of a mobile phone.
Snapserver can stream synchronized audio from your phone, but can be configured to do much more.
Finally, there is a lot of high quality audio equipment being disposed of because it is not easily integrated with digital audio sources. Snapcast let’s you redeploy these components into an easy to use, high functionality, and future proof whole house audio system.
The authoritative repository for Snapcast is on Github. The software is available there, as well as extensive and high quality documentation.
Snapcast has been packaged for most linux distributions. Most of my systems are based on Debian Linux, so both the client and server was available via apt-get.
Instructions are available to build Snapcast for:
I successfully built Snapclient on piCore; a Linux distribution for Raspberry Pi.
Native Snapclient apps are available for iOS and Android
There are two components to Snapcast:
A single server instance (Snapserver) accepts streams of audio from multiple sources, and makes them available to multiple clients
The server also provides a web interace which controls the stream played by, and volume, of each Snapclient.
Multiple clients (Snapclient) receive a stream from the server, and outputs synchronized audio to an amplifier and speaker
Configuration of the system is done at the server, through editing the file snapserver.conf.
I am not going repeat the documentation for the configuration file here. Rather, I am going to share the architecture I use, solutions to the challenges I ran into, and provide some shortcuts that are of particular value to an Alberta audience.
Snapserver can receive multiple audio sources. In a typical installation, there are multiple sources being processed and made available simultaneously by the Snapserver. This allows individual Snapclients to chose the audio source desired at each location.
The Snapserver primarily accepts audio in the form of a bit stream, either piped through STDOUT, or through a FIFO queue.
Making an audio source available through your Snapcast system is a matter of finding and configuring software that can handle the source files or stream, and output it as a stream of PCM audio.
The documentation provides extensive examples for this, including integration with common media hub systems.
But for my application I ended up using four source types:
My audio library is old and simple. It consists of a simple hierarchy of mp3 files in directories of the form:
genre 1 artist 1 album 1 track 1.mp3 track 2.mp3 track 3.mp3 ... track n.mp3 album 2 track 1.mp3 ... album 3 ... ... album n artist 2 album 1 album 2 ... genre 2 ...
. ├── Christmas │ ├── Academy and Chorus of St. Martin-in-the-Fields │ │ └── Christmas with the Academy │ │ ├── Away in a Manger.mp3 │ │ ├── Christmas Oratorio: Sinfonia.mp3 │ │ └── Tomorrow Shall Be My Dancing Day.mp3 │ ├── Allison Brown │ │ └── Evergreen │ │ ├── Carol And The Kings.mp3 │ │ ├── Christmas Don't Be Late.mp3 │ │ └── Two Santas.mp3 │ ├── Allison Young ├── Music │ ├── Alison Krauss │ │ ├── A Hundred Miles Or More - A Collection │ │ │ ├── Away Down The River.mp3 │ │ │ ├── Baby Mine.mp3 │ │ │ ├── Down To The River To Pray.mp3 │ │ │ ├── Get Me Through December.mp3
Play lists are handled through directories containing soft links to the songs that I want included in the list. Each mp3 file is fully tagged.
The oldest file in the hierarchy is from 1998. That is 24 years of continuous use without having to re-encode or reorganize.
The following BASH code snippet starts from a directory and assembles a play list of the mp3 files in the hierarchy of directories:
cd /home/shared/served_files/Audio/Music sudo rm -f /tmp/SnapList sudo find ~+ -type f -follow -name *.mp3 > /tmp/SnapList sudo chown Snapserver /tmp/SnapList sudo chgrp Snapserver /tmp/SnapList
and then this line in snapserver.conf shuffle plays the list with mplayer:
source = process:///usr/bin/mplayer?name=All¶ms=-vo null -really-quiet -srate 48000 -nolirc -volume 100 -playlist /tmp/SnapList -ao pcm:file=/dev/stdout
In my system I have two instances of mplayer feeding streams to Snapserver all the time, each defined by a directory containing soft links to a collection of tracks suitable for daytime (lively) or evening (more subdued) listening.
A third mplayer instance is enabled automatically December 1, and disabled December 26. It serves Christmas music.
Most of the audio I listen to is sourced from internet audio streams. Specifically, I am a fan of, and donor to, CKUA.
While content providers really, really, really want you to listen through their phone App, most of them provide an http based audio stream that can be accessed directly. They streams are necessary if a content creator wants to be available through music player applications, or smart speakers like Nest or HomePod.
To listen to one of these streams through Snapcast you need to find the URL. The best source I have found for this is fmstream.org.
Accessing CKUA is a challenge. They have multiple streams, which tend to be inconsistent in quality, availability and stability. The MP3 streams were the best to use for several years, but recently started dropping and skipping. I am now using the AAC stream (which disappeared for a while for some reason) and as of Q3 2022 they are good quality and reliable.
CBC also likes to mess around and change their streams on a regular basis. The URL’s is use for accessing CBC changed three times during the preparation of this article.
Secondly, you need to select the audio player client software to use. Initially, I mostly used mplayer. However, I now find I get more reliable results from cvlc, which is the command line invocation for Video Lan Client.
The final challenge is setting the “sampleformat” configuration value in relevant line in snapserver.conf correctly. One way to determine the correct settings is to use VLC (Video Lan Client) to listen to the stream; the “Media information” page then provides as starting point for the values you need to provide to Snapserver.
If a stream makes noise, but it sounds like the Chipmunks, you need to mess around with the rate component of the “sampleformat” configuration attribute.
Here are the lines from my snapserver.conf file that provide access to BBC Radio 1 (This is the BBC’s modern popular music and current chart hits broadcast, not the BBC World Service), CKUA, Radio Caroline (the original pirate radio station out of England), CBC Radio 1 and 2, and Jazz FM 91 out of Toronto:
source = process:///usr/bin/cvlc?name=BBC_1&sampleformat=48000:16:2¶ms=--no-video --aout afile --audiofile-file - http://stream.live.vc.bbcmedia.co.uk/bbc_radio_one source = process:///usr/bin/cvlc?name=CKUA&sampleformat=44100:16:2¶ms=--no-video --aout afile --audiofile-file - http://ais-sa1.streamon.fm/7000_48k.aac source = process:///usr/bin/cvlc?name=CAROLINE&sampleformat=44100:16:2¶ms=--no-video --aout afile --audiofile-file - http://sc3.radiocaroline.net:8030/listen.pls source = process:///usr/bin/cvlc?name=CBC_1&sampleformat=44100:16:2¶ms=--no-video --aout afile --audiofile-file - http://cbcmp3.ic.llnwd.net/stream/cbcmp3_cbc_r1_cgy source = process:///usr/bin/cvlc?name=CBC_2&sampleformat=44100:16:2¶ms=--no-video --aout afile --audiofile-file - http://cbcmp3.ic.llnwd.net/stream/cbcmp3_cbc_r2_edm source = process:///usr/bin/mplayer?name=Jazz.FM91¶ms=-vo null -cache 100 -cache-min 50 -really-quiet -srate 48000 -nolirc -volume 100 -ao pcm:file=/dev/stdout https://jazzfm91.streambb.live/SB00009
Yes, I know. I am a nerd.
The shairport program allows linux hosts to receive Airplay streams from iOS (Apple) devices. It can be used as a source for Snapcast.
Be aware that shairport imparts a significant delay to the audio stream. This means you get poor results if you try to distribute the audio stream from a video; the video and audio track end up out of sync. However, the solution is great for listening to podcasts.
The required line in snapserver.conf:
source = process:////usr/bin/shairport-sync?name=Airplay¶ms=-o stdout&sampleformat=44100:16:2
Complete details are provided in the documentation.
You can direct the output from the Pulse audio daemon on a linux desktop instance to Snapserver.
I use this is to direct the audio from web seminars into Snapcast. I can then move about the house doing other tasks while still listening.
I initially had problems getting pulse redirection to start reliably; every time I went to use it a lot of fiddling and restarting was required to get it to work. But I eventually resolved the issue.
The Snapclient documentation suggests creating the fifo queue that carries the bitstream from the pulseaudio daemon to snapserver in /tmp, i.e /tmp/snapfifo.
It turns out that “sticky” directories like /tmp have obscure usage restrictions that prevent processes that do not share a user id from opening a common file.
After creating the fifo in /run (i.e. /run/snapfifo), changing snapserver.conf, and directing the pulseaudio server to the new fifo, everything starts reliably.
The required line in snapserver.conf:
source = pipe:///run/snapfifo?name=Pulse&mode=read
Some configuration of your desktop is also required; the documentation provides the details.
One final point; the “&mode=read” argument in the snapserver.conf line is important. Otherwise the Snapserver recreates the fifo every time it starts, which causes the connection from the pulseaudio daemon to be lost.
Once you have your Snapserver instance up and running, multiple instances of Snapclient are used to listen to the audio streams.
Snapclient hosts can include:
application software running on a multi-use host, i.e. a workstation
a web browser
dedicated apps for iOS and Android
dedicated hardware (e.g. a Raspberry Pi)
I have up to fourteen instances of Snapclient running on my network.
Here is what my Snapserver control page looks like when they are all running:
Click to view full size
Snapclient runs on each of my three Linux desktops/laptop (one desktop
runs two instances) and the Linux based server.
Two dedicated Raspberry Pi’s with IQaudio DigiAMP+ boards drive the
architectural speakers in the great room.
Two dedicated Raspberry Pi’s drive Ikea Eneby speakers in the bed rooms.
A Raspberry Pi Model A powered by a USB power bank drive an Ikea Eneby
speaker equipped with a battery. This used to take audio out to the
Snaplient running on a Raspberry Pi with another IQaudio DigiAMP+ board in an outbuilding. This Pi also provides a WiFi access point and security camera.
The Snapclient App running on my Macbook.
The Snapclient App running on my iPhone and iPad.
I highly recommend Ikea Eneby speakers; I have four of them. They are affordable, simple and easy to use, look good, and have great sound quality.
Unfortunately, Ikea is discontinuing the Eneby and replacing it with the Sonos based Symfonisk line. Which are three times the cost and don’t have an analog input; they only play audio from a phone.
Isn’t capitalisim grand!
Things I learned setting up my clients:
The four Raspberry Pi’s dedicated to hosting Snapclient use piCore; this ensures resiliency to power loss.
The fifth Pi hosted Snapclient instance uses Raspberry Pi OS Lite because Motion is not packaged for piCore. This is acceptable, because this Pi is protected by a UPS.
I try to keep fixed devices off my wireless network. This makes Raspberry Pi model B’s ideal Snapclient hosts; they have low power consumption, Ethernet, and analog audio. That being said, several of my Snapclients are older Pi’s that, while are not the best choice for demanding deployments, are more than sufficient for the task.
The IQaudio DigiAMP+ hats work well, and are an official supported product of the Raspberry Pi foundation. They have excellent sound quality and provide sufficient wattage for most applications.
Be aware that the usb power supplies used for Pi’s are not sufficient to drive these boards. You must provide a DC power supply that delivers 60 watts at 12 to 24 DC through a 5.5mm x 2.5mm barrel connector. This is the only power supply you need; the Pi is fed off of the hat.
Two dedicated Pi’s with IQaudio DigiAMP+ hats replace a stereo receiver that drove the built in speakers in the great room, but died of old age. The advantage of the Pi’s is that speaker selection and volume are now controlled through Snapserver.
The only configuration I have found necessary for Snapclient is specifying the output audio device if the host has more than one audio output. This occurs more often than you might think; if you have an HDMI TV attached, or a monitor with speakers connected by HDMI, it turns up as a sound device.
I will not get into the details of how to do this here; running “snapclient -h” provides you the commands you need. Just be aware that if everything appears to be working, but you are not hearing any sound, this is likely the issue.
Unfortunately, there can be up to four places where volume can be set between the source and the final output:
This means there can be a lot of messing around adjusting settings until you get the desired results.
My advice is to follow the same principle used in professional audio; keep the signal as powerful as you can as late in the chain as you can, as long you do not cause distortion from over driving.
When using the Safari browser from Mac and iOS devices you can control Snapcast, but playing audio through the browser does not work (the issue is with Safari, not with Snapcast). The web client is fully functional with alternate browsers (e.g. Chrome) on Mac’s, and a dedicated App is available for both Mac’s and iOS.
The connection between the host running Snapclient and the amplifier needs to be hardwired. Bluetooth imposes latency that Snapclient cannot accommodate for, so the output from a Bluetooth connected speaker will be out of sync with the output from the other Snapclient instances.
Be aware that Snapcast does not use TCP/IP multicasting; each client makes an independent connection to the server. Yet another reason to keep Snapclient instances off your wireless network.
Snapcast only deals with synchronized distribution of audio. You need to decide how you want to control your audio system and manage your media.
A control system is not strictly necessary. My play lists are directories of soft links to the directories of mp3 files I want in the playlist. I could configure Snapserver to run an mplayer instance that shuffle plays each playlist (as per example above), and a vlc instances for every audio streams I am interested in, and select which stream I wanted listen to with snapclient. I would start and stop the server by logging into the console and issuing commands.
In my case, I use a custom built web site hosted on my home server. I am not going to share this code; it is implemented with CGI scripts that were built piecemeal over the years, some functionality is currently broken, and it is thoroughly obsolete.
There is a snapcast component for Home Assistant.
Here are some considerations to keep in mind when planning your system:
You need to have some method to manually restart Snapserver. The culprit is not Snapserver; it is very stable. The culprit is audio stream sources or Internet access that are short of capacity, causing the audio player providing a stream to exit because it’s cache is exhausted.
Snapserver, when invoked, will start up a process for each source, and make them all available for selection via Snapclient.
This may be acceptable if you have fast internet. I have have crappy rural internet, so I avoid traffic that is not of immediate value.
The way I achieve this is bash scripting that comments out the lines in snapclient.conf related to streams I am not listening to, and uncomments the line for the stream I am going to listen to. This is done before invoking Snapserver.
These bash script snippets:
Uncomment every line in snapserver.conf related to an internet audio stream:
sudo sed -i '/CBC_1/s/^#//' /etc/snapserver.conf sudo sed -i '/CBC_2/s/^#//' /etc/snapserver.conf sudo sed -i '/CKUA/s/^#//' /etc/snapserver.conf sudo sed -i '/Jazz.FM91/s/^#//' /etc/snapserver.conf sudo sed -i '/BBC_1/s/^#//' /etc/snapserver.conf sudo sed -i '/CAROLINE/s/^#//' /etc/snapserver.conf
Comment out every line in snapserver.conf related to an internet audio stream:
sudo sed -i '/CBC_1/s/^/#/' /etc/snapserver.conf sudo sed -i '/CBC_2/s/^/#/' /etc/snapserver.conf sudo sed -i '/CKUA/s/^/#/' /etc/snapserver.conf sudo sed -i '/Jazz.FM91/s/^/#/' /etc/snapserver.conf sudo sed -i '/BBC_1/s/^/#/' /etc/snapserver.conf sudo sed -i '/CAROLINE/s/^/#/' /etc/snapserver.conf
Uncomment the line related to the stream that is going to be listened to:
if [ "$QUERY_STRING" == "CBC1" ] then sudo sed -i '/CBC_1/s/^#//' /etc/snapserver.conf fi if [ "$QUERY_STRING" == "CBC2" ] then sudo sed -i '/CBC_2/s/^#//' /etc/snapserver.conf fi if [ "$QUERY_STRING" == "CKUA" ] then sudo sed -i '/CKUA/s/^#//' /etc/snapserver.conf fi if [ "$QUERY_STRING" == "JAZZFM91" ] then sudo sed -i '/Jazz.FM91/s/^#//' /etc/snapserver.conf fi if [ "$QUERY_STRING" == "BBC1" ] then sudo sed -i '/BBC_1/s/^#//' /etc/snapserver.conf fi if [ "$QUERY_STRING" == "CAROLINE" ] then sudo sed -i '/CAROLINE/s/^#//' /etc/snapserver.conf fi
All this is run just before snapserver is started.
For me, Snapcast was the archetypical Open Software experience.
My journey began with “Gee, it would be nice to be able do that.”, progressed to, “This looks interesting. Since it is free and simple to install, let’s give a try.“, and concluded with “How did I live without this?“.
And because I built my system myself, and have permanent access to all of the required components (and could hack the source if I really had to) I know that rather than having to throw away and replace everything in a few years, I have another item in my my Open Source toolkit that can be adapted and sustained as long as I require it.