My music streaming solution is based on Mopidy, which has a spotify plugin and can run on a Raspberry PI.
After some fiddling with Mopidy and Icecast 2, I realized that Icecast can't satisfy my requirement of synchronous streaming: While moving from one room to another, I don't want the audio to skip back or forward.
So I finally choose pulseaudio as the streaming companion for mopidy, because it supports the Real-time Transport Protocol (RTP), which is exactly made for carrying multimedia streams through the network. This method is also more gentle to the network, because it uses UDP broadcasts and therefore has to send the data only once, no matter how many clients are listening to the stream.
However, my FritzBox did not like this and decided to kill the WiFi after a few minutes streaming. Because the WiFi had quirks before, I upgraded my home network with an TP Link Archer C7, which can handle the traffic without any problem.
The second requirement I have is, to be able to mute and unmute each client quickly from my home automation. To achive this, the client runs a very simple python HTTP server, which can control the output of pulseaudio.
Another challenge was that I am running Libreelec on the Raspberry PI in my bedroom and it has no support for installing additional software. I also want to use PI zeros in the other rooms, so the software must work on both without changes. Because of this, I decided to use Docker, which is fortunately preinstalled on Libreelec and also has with Hypriot a great image for the Raspberry PI.
Getting the audio output and RTP broadcast to work in docker felt quite tricky, but with a few parameters (--net=host and --privileged) it was dead simple. The net=host parameter lets the container use the host network, so you don't have to configure anything. Also it is the only method I know to enable sending and receiving udp broadcasts, without having to configure the host. The privileged option allows the container to access the host devices, especially the audio devices.
I created an docker image for the server, which contains mopidy and pulseaudio and a second image for the client, which contains pulseaudio alongside the control server. Both can be downloaded from Docker Hub and run by a single command.