Introducing Bark! Low-latency multi-receiver live-sync lossless audio streaming for local networks. It's like Sonos, but open source, so nobody can brick your devices remotely. It's also written in Rust :)

https://github.com/haileys/bark

It sends 48khz uncompressed float32 data over UDP multicast. It can achieve playback sync to within hundreds of microseconds in ideal conditions, and usually to within a millisecond.

I've been working on it in my spare time over the past week, and I'm pretty happy with how it's shaped up. I have three receivers setup and it works remarkably well at keeping everything in sync as I walk around my house. For now it only really works on Linux, and supports Pipewire (and Pulse in theory), but there's no huge impediment to making it truly cross-platform.

It also features a fancy live stats subcommand, which can used on any computer in the same multicast domain to watch the status of the stream cluster:

GitHub - haileys/bark: live sync audio streaming for local networks

live sync audio streaming for local networks. Contribute to haileys/bark development by creating an account on GitHub.

GitHub

@hailey this looks interesting.

How do you deal with long-term clock drift between your receivers? Is there some logic to resample the audio to match the clocks or do you wait until the buffer over/underflows and then jump?

@electronic_eel yes it uses the speex-dsp resampler and it will slew to resync for small offsets, and jump for large discontinuous offsets!

@hailey nice!

do you have plans on integrating it somehow with mpd?

I'd be especially interested in a way to use mpd to select on which devices I want to output audio. mpd has the concept of "audio_output" and most mpd clients allow you to control them.

@electronic_eel no special integration needed! You can create a virtual duplex device in both Pipewire and Pulse, configure mpd to play to that device, and bark to capture from that device - see the readme for more info

@hailey yeah, but the issue is the multi-room control via mpd audio_outputs if I'm not mistaken.

To control which rooms should be enabled from within mpd, I need multiple audio_outputs in mpd, some are enabled and some disabled. Now these should integrate again into one bark stream to allow it to do it's multiroom magic. Or maybe some other logic to check which rooms are enabled in mpd.

This would allow me to use the many different mpd clients to control the whole stack: playlist, song, volume and rooms.

@electronic_eel I see! You could achieve this by creating separate virtual devices and running multiple bark stream processes using separate multicast groups for each speaker. You'd lose the benefit of multicast, since you'd essentially be unicasting to each speaker (but in a roundabout way via multicast), but the actual synchronisation runs according to CLOCK_BOOTTIME on the source host, so provided all stream sources are running on the same machine the sync would work.

@hailey ah, cool!

I don't care about network bandwidth as all sinks have direct ethernet cables to one switch. So unicast or multicast doesn't matter for my application.

I think I will give bark a try soon.