Intro: Play the Same Music in Multiple Rooms
I don't know about you but I like to have the same music across all my apartment without turning the sound too loud. So after a bit of research about this problem, I decided to construct several speakers all connected by wifi to the same music server in order to play the same music simultaneously in several rooms and in particular in the bathroom.
The system is based on the GStreamer technology which is the base of some awesome software like VLC and on speaker with wifi capability using a Raspberry Pi.
Step 1: Building a Speaker for the Bathroom
- a bathroom proof speaker
- a 2W amplifier (working on 12v)
- a Raspberry Pi Zero (working on 5v)
- a Pimoroni Phat DAC
- an SD card
- an ON/OFF button
- a 12v power adaptor + a compatible plug
- a DC/DC step-down (12v->5v)
- an electrical box
- some cables
The construction is pretty straightforward.
On the electronic side, follow this ASCII diagram.
- DC plug --> ON/OFF button --> amplifier
- ON/OFF button --> DC/DC step-down --> Raspberry Pi
- Raspberry Pi --> Phat DAC --> amplifier --> speaker
On the mechanical side, cut all the holes needed in the electrical box, put everything inside and that's all.
Using this technique, you can create all kind of speakers you want.
Step 2: The Software Side
All the software side is based on the open source multimedia framework, GStreamer. I used only Linux but it exists on different OS, so I imagine that all can be adapted for other OS.
For starter, you have to install Raspbian Lite on the Pi, the PHAT DAC and the GStreamer 1.0 with the "good" plugins. On the computer used as the music server, you need the same GStreamer. I will not detail those parts because others have done this better than me. The last thing needed is that the Pi and the music server have to be connected to the same network by cable or wifi.
In order to test if GStreamer is correctly installed, you can use those command lines.
On the speaker:
$gst-launch-1.0 udpsrc port=5000 caps='application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)L16, encoding-params=(string)1, channels=(int)1, payload=(int)96' ! rtpL16depay ! audioconvert ! autoaudiosink
On the PC:
$gst-launch-1.0 audiotestsrc ! audioconvert ! audio/x-raw, format="(string)S16BE", layout="(string)interleaved", channels=1,rate=44100 ! rtpL16pay ! udpsink host=RASPBERRYPI_IP port=5000
After you put the good IP address instead of "RASPBERRYPI_IP", you should hear a sinusoidal sound on the speaker. That's not something you will like to hear for a long time, so don't put the volume too loud.
Some explanation: the PC produces the sinusoidal sound using "audiotestsrc", "audioconvert ! audio/x-raw, format="(string)S16BE", layout="(string)interleaved", channels=1,rate=44100" convert the sound in the good format understood by "rtpL16pay" that creates the audio packets and finally "udpsink" sends the packets using the UDP protocol. On the speaker, it is the same but inverted, "udpsrc" recovers the audio flux, "rtpL16depay" de-packets and "audioconvert ! autoaudiosink" converts the sound to match the format of the automatic sound card and of course, plays it.
So now that the basic stuff works, it is time to go further. The goal is to intercept the sound of an application in order to send it through the network.
- We create a fake output
$pactl load-module module-null-sink sink_name=multiHP
- We connect an input to the fake output (silence the selected application (input))
$pacmd list-sinks (outputs list)
$pacmd list-sink-inputs (inputs list)
$pacmd move-sink-input %input %output (replace %input and %output by one of the corresponding lists)
- We put the sound card at maximum
$pactl set-sink-volume 0 100%
- We test on the PC the way to recover the fake output (recover the sound)
$gst-launch-1.0 pulsesrc device=multiHP.monitor ! audioconvert ! autoaudiosink
You should hear again the sound of the application that you have selected.
Great! Now it is time to go for the final command lines. Here are the command lines in the case of 2 speakers with the sound also played by the PC.
On each Speakers:
$gst-launch-1.0 udpsrc port=5000 caps='application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)L16, encoding-params=(string)2, payload=(int)96' ! rtpL16depay ! audioconvert ! autoaudiosink
On the PC:
$gst-launch-1.0 pulsesrc device=multiHP.monitor ! audioconvert ! audio/x-raw, format="(string)S16BE", layout="(string)interleaved", channels=2,rate=44100 ! rtpL16pay ! tee name=t t. ! queue ! udpsink host=%addrpi1 port=5000 t. ! queue ! udpsink host=%addrpi2 port=5000 t. ! queue ! audioconvert ! autoaudiosink
Step 3: Conclusion
This instructable is just the first step to a complete project. It was only to explain the principle. Now you can automatize by making some script on the Raspberry Pi boot and on the PC. You can adapt the GStreamer command depending on your need. I personally modified my previous instructable (BRAND NEW OLD RADIO) in order to use it as a speaker. There is an infinite number of things to do to improve this multi-room sound system. In particular, all the speakers are not synchronized, so you have some variation when you change from a room to another.
I hope that you will try and improve this instructable.
Don't hesitate to ask questions if you need details.