···22# virtual "hub" sink, whose monitor is linked to the ROC sinks of the rooms
33# selected with `audio-room` or from Home Assistant (MQTT). Senders: any LAN
44# machine via ROC (while `gg23-audio` from tools/gg23-audio runs), barnacle
55-# via AirPlay (shairport-sync). Rooms run ./room.nix.
55+# via AirPlay 2 (shairport-sync + nqptp). Rooms run ./room.nix.
66{
77 self,
88 config,
···114114 };
115115 };
116116117117+ # AirPlay 2: macOS drives classic AirPlay 1 receivers through a legacy path
118118+ # that can wedge (endpoint stays half-active after switching outputs, and
119119+ # re-picking it fails with -16727 until AirPlayXPCHelper restarts).
117120 services.shairport-sync = {
118121 enable = true;
119119- # AirPlay 1: the default package has no AirPlay 2 (no nqptp needed)
122122+ package = pkgs.shairport-sync-airplay2;
120123 settings = {
121124 general = {
122125 name = "gg23";
···129132 };
130133 };
131134 users.users.shairport.extraGroups = [ "pipewire" ];
135135+136136+ # PTP timing companion AirPlay 2 needs (UDP 319/320; int0 is trusted, et0
137137+ # stays closed). The unit comes from the package.
138138+ systemd.packages = [ pkgs.nqptp ];
139139+ systemd.services.nqptp.wantedBy = [ "multi-user.target" ];
140140+ systemd.services.shairport-sync = {
141141+ wants = [ "nqptp.service" ];
142142+ after = [ "nqptp.service" ];
143143+ };
132144133145 # mDNS for AirPlay on the LAN only; int0 is trusted, et0 must stay closed
134146 services.avahi = {