- Playing the same audio signal in multiple rooms (background music)
- The ability to reproduce its own audio signal in each room
- Possibility of distributed playback of notifications (for example, the doorbell rings not near the door at full volume, but at a low volume through all or through certain speakers).
In this article, I will share an example of building a multi-room system in my own apartment. The original idea was to create background music (the selected radio station) at low volume in all rooms, instead of one point where the volume had to be increased.
The basis for the multi-room system was the free Snapcast solution . The server part is launched on the home server, either Orange PI zero minicomputers with active speakers connected to them, or more powerful Rasberry PI with an installed Kodi media player (distributor Libreelec) act as clients by room.
Key features of the finished system
- Playing an Internet radio station in the background
- The ability to play music on a multi-room (or on a separately selected client) using Airplay, UPnP or through a Plex player. There are plans to add bluetooth support, although this is not particularly relevant to me
- Playing arbitrary content from a computer via a web interface
- Change of the currently playing radio station manually or according to the schedule
- Assignment to each client of any source
- The volume control is individually for each audio device (it works like this: the own audio system control is set to maximum, the volume of each snapclient is adjusted from the server if necessary (usually also set to maximum), and the overall volume level is adjusted from the source from which the playback is going - the phone , computer player or mpd)
On clients now it is done without frills - there is armbian, on which shairport and snapclient are installed, and there are plans to deliver upmpdcli and plexamp, so that each client would act as a universal point that reproduces sound using any possible protocol. The main problem that hinders this so far is that Linux does not allow sharing one ALSA audio device between several programs, and here you have to either turn off others while playing sound through one service, or try to use Pulseaudio, which is impossible in the case of Snapclient (Snapcast works exclusively through ALSA, because it minimizes delays and due to this the sound of all sources is absolutely synchronous.More details can be found in the Snapcast documentation).
The server side is designed as microservices in the form of several docker containers combined into a stack. Initially, there were plans to launch containers in the Swarm cluster (yes, I have two computers at home combined into a Swarm cluster, which runs all the services that I need and do not really need at home), but this idea had to be abandoned, and the stack through docker-compose The .yml file is run on one of the computers. The reliability is of course lame, but enough for the home. The reason for the inability to start in the cluster is that the Snapcast server uses fifo to receive the audio stream (a typical chain works like this - the sound is played using mpd, the fifo is the output device, from which the snapserver reads and transmits the stream to all clients). But due to the fact that the cluster cannot share volume,which hosts a fifo between several nodes (using a fifo on a host and forwarding it using a distributed file system also does not work. Although it may be possible through nfs, I have not tried it yet), and it is also impossible to force the swarm cluster to run all containers on one node, the only way to give all services access to fifo is to run everything on one node (you can, of course, make a virtual machine, or one giant container, where everything that is possible is launched via supervisor, but I decided not to do that).the only way to give all services access to the fifo is to run everything on one node (you can, of course, make a virtual machine, or one gigantic container, where everything is launched through the supervisor, but I decided not to do that).the only way to give all services access to the fifo is to run everything on one node (you can, of course, make a virtual machine, or one gigantic container, where everything is launched through the supervisor, but I decided not to do that).
Stack composition
1) Snapserver. Snapcast server container. It is available on ports 1704, 1705 and in the home network, calls to it go through the dns name snapserver.local. It knows how to announce itself through Avahi, but when working in avahi docker, announcements go through a separate container (it is not included in this stack).
2) Snapcastr. Snapserver web service. Available on port 5011 (available as snapcastr.local via local reverse proxy).
3) Snapchanger. Python script that parses audio sources and switches clients to the highest priority audio source that is currently active. For example, internet radio has the lowest priority and always plays. When playing music from a phone via Airplay, it switches to this stream, and if at this moment there is a signal from a smart home, it will switch to it. When a stream is stopped, it switches back to the active streams with the highest priority. For each client, you can specify your list of threads and priorities for them.
4) Snapcron. A container with cron that can run scripts at a certain time, for example, changing the volume on clients (turn off the music in the bedroom at night completely).
5) mpd. mpd instance for playing internet radio. Forwarded to the home network on a non-standard port 36602.
6) radio. pyhthon scripts that make sure that the radio is always played (there are cases when the connection is interrupted, or the connection seems to be there, but the sound does not play), as well as switching radio stations and volume depending on the time of day.
7-8) mpd.fm and pifi - web shells for playing radio stations. Two pieces of the same type for experiments.
9) mopidy. Another shell (aka a separate mpd server) for playing music. It acts as a separate mpd server and responds to the standard mpd port - 6600. Can be used to listen to music. It uses its own stream and works independently of mpd for radio stations.
10-12) shairport-sync, upmpdcli, plexamp - containers with corresponding clients. Each of the containers uses its own instance of mpd, writing to its own fifo. So each client has its own independent stream.
Thus, the stack now supports:
- Several independent sound sources with arbitrary choice between them - Default, uPnP, Mopidy, Plexamp, AirPlay and Internet radio.
- Managing the Snapcast server itself with Snapcastr.
- A set of scripts to ensure reliable and uninterrupted background radio sound.
- Controlling radio playback using pi-fi or mpd.fm (in addition, I configured control of this mpd instance using the Node-red used in my home automation).
Repository link