headroom/crates
atagen 04a005e1cd F4: real-sink discovery fallback closes the cold-boot race
Codex flagged a real-but-rare race in `try_bind_default_metadata`:
the daemon installs the metadata listener then immediately writes
`default.audio.sink = headroom-processed`, relying on PipeWire to
deliver the prior value to the listener before our write. In
practice this works (pw-metadata replays current state to a
freshly-installed listener), but two failure modes leak through:

  1. **Prior daemon left the world dirty.** If a previous daemon
     run set default to `headroom-processed` and didn't restore
     before exiting, the listener replays "headroom-processed" —
     `on_metadata_property` recognises that as our own promotion
     and returns early. `real_sink.name` is never captured.
     Bypass routes log "no real sink known" forever.
  2. **No replay event.** If the listener doesn't fire for any
     reason — broken PipeWire, an event-bus hiccup,
     pipewire-rs's `add_listener_local` racing with our write —
     same outcome.

Fix: instead of trying to win the listener race
(pipewire-rs has no synchronous metadata getter, and `Core::sync`
needs an async done-callback we don't have plumbing for), make
`try_capture_real_sink` self-heal. When `real_sink.name` is still
`None` and we see *any* non-processed `Audio/Sink` on the registry,
adopt it as the fallback real sink. A subsequent
`default.audio.sink` event will refine the choice via the existing
`adopt_new_real_sink` path if WP picks something else.

This is a belt-and-braces patch — the listener path stays the
primary mechanism, the fallback only kicks in when that path
hasn't produced a name. In steady-state (the common case where
listener replay works) it changes nothing.

Verified

  Cold start with PipeWire's `default.audio.sink` set to the
  Mbox: daemon logs `preferred_real_sink updated sink=Mbox`
  via the listener path; the fallback's
  `adopting first available Audio/Sink as fallback` log does
  not fire. No regression for the steady state.

  188 tests pass; clippy clean at -D warnings --all-targets.
2026-05-21 18:43:02 +10:00
..
headroom-cli 8e: playback callback timing instrumentation + spike investigation 2026-05-21 16:42:46 +10:00
headroom-client stage 2 2026-05-19 16:33:09 +10:00
headroom-core F4: real-sink discovery fallback closes the cold-boot race 2026-05-21 18:43:02 +10:00
headroom-dsp F6: honour compressor.enabled in the DSP 2026-05-21 18:19:32 +10:00
headroom-ipc 5: monitor TUI + wire fill-ins 2026-05-21 13:35:27 +10:00