Snapcast

From NixOS Wiki

Snapcast is a multiroom client-server audio player, where all clients are time synchronized with the server to play perfectly synced audio. It's not a standalone player, but an extension that turns your existing audio player into a Sonos-like multiroom solution. Audio is captured by the server and routed to the connected clients. Several players can feed audio to the server in parallel and clients can be grouped to play the same audio stream.

https://github.com/badaix/snapcast

Pipewire Sink

Both pulseaudio and pipewire can create a virtual audio sink that uses a FIFO queue to stream audio data into Snapcast.

First create a local snapserver instance that creates the FIFO queue to stream into.

  services.snapserver = {
    enable = true;
    codec = "flac";
    streams = {
      pipewire  = {
        type = "pipe";
        location = "/run/snapserver/pipewire";
      };
    };
  };

Then create a systemd user unit to attach the pipe-sink after pipewire has started.

  systemd.user.services.snapcast-sink = {
    wantedBy = [
      "pipewire.service"
    ];
    after = [
      "pipewire.service"
    ];
    bindsTo = [
      "pipewire.service"
    ];
    path = with pkgs; [
      gawk
      pulseaudio
    ];
    script = ''
      pactl load-module module-pipe-sink file=/run/snapserver/pipewire sink_name=Snapcast format=s16le rate=48000
    '';
  };


Playback

To have local audio synced up with remote clients it needs to be routed through a local snapclient instance.

  systemd.user.services.snapclient-local = {
    wantedBy = [
      "pipewire.service"
    ];
    after = [
      "pipewire.service"
    ];
    serviceConfig = {
      ExecStart = "${pkgs.snapcast}/bin/snapclient -h ::1";
    };
  };