Synchronised Low Latency Multi-Client Network Audio

My flatmates and I have been trying for a long time to set up a synchronised network audio system so that we can listen to music from youtube and other sources together. Many, many avenues have been explored, including clients which just play a file at the same time, webRTC, websockets, netcat and many others. However, these methods proved very difficult to synchronise across an IP based network.

Finally, we have found a solution. It may not be optimum but performs well!

First, a warning

We did notice severe wifi problems when using this kind of multicast streaming. It would cause computers to randomly drop off the wifi and be unable to reconnect. It would also lag out SSH on the network. We're looking into IGMP snooping to sort this, (allows clients to 'subscribe' to multicast streams) and will update this post if we find anything.

The issue is that multicast is very expensive when transmitted over wifi, whereas over ethernet it is actually less expensive than normal unicast packets.

If you're not sure if this is a problem for you, try killing pulse audio and see if the problems stop:

pulseaudio -k

If you were running this on a pure ethernet LAN, however, it works flawlessly with no problems and a very small latency!

The Server

I used a clean Ubuntu Server 16.04 instance to set this up. Your experience with other flavours may vary.

Step 1 - Install required components. mpd, pulseaudio, vlc, nfs (for media access)

sudo apt install mpd pulseaudio vlc nfs-common

Setup pulseaudio.

sudo nano /etc/pulse/default.pa

#Add the following content at the end of the file to rtp stream media to the network
load-module module-null-sink sink_name=rtp format=s16be channels=2 rate=44100
load-module module-rtp-send source=rtp.monitor

Start pulseaudio

pulseaudio -D

Find pulseaudio stream

sudo tcpdump -i eth0 #Your interface here

You'll see a lot of packets like this:

12:06:25.209396 IP 10.0.1.125.32787 > 224.0.0.56.46606: UDP, length 1292
12:06:25.216614 IP 10.0.1.125.32787 > 224.0.0.56.46606: UDP, length 1292
12:06:25.339596 IP 10.0.1.125.32787 > 224.0.0.56.46606: UDP, length 1292
12:06:25.346829 IP 10.0.1.125.32787 > 224.0.0.56.46606: UDP, length 1292
12:06:25.354058 IP 10.0.1.125.32787 > 224.0.0.56.46606: UDP, length 1292
12:06:25.361285 IP 10.0.1.125.32787 > 224.0.0.56.46606: UDP, length 1292
12:06:25.368519 IP 10.0.1.125.32787 > 224.0.0.56.46606: UDP, length 1292
12:06:25.375750 IP 10.0.1.125.32787 > 224.0.0.56.46606: UDP, length 1292
12:06:25.382990 IP 10.0.1.125.32787 > 224.0.0.56.46606: UDP, length 1292

The address and port in this case you would need to make a note of is:
224.0.0.56:46606

Make MPD config

mkdir -p ~/.config/mpd
cp /usr/share/doc/mpd/mpdconf.example ~/.config/mpd/mpd.conf
nano ~/.config/mpd/mpd.conf

(Change the line with the music_directory parameter to suit your music location)

music_directory         "/mnt/josh/"

Start MPD (debug mode)

mpd --no-daemon --verbose --stdout ~/.config/mpd/mpd.conf

Debug mode is helpful to check whether it can find your music library correctly.

Start VLC on server

On the same server, start VLC acting as a netsync master

vlc --control netsync --netsync-master rtp://224.0.0.56:46356

On the clients, synchronise the ntp clocks to a known source

sudo ntpdate 1.uk.pool.ntp.org

On the clients, start VLC in netsync client mode

vlc --control netsync --netsync-master-ip 10.0.1.125 rtp://224.0.0.56:46356

Download an MPD client, e.g. mpc and start playing music.

Now, you should have synchronised music across multiple machines!