Skip to content

Make the audio stack reliable on headless boots - #79

Open
olaservo wants to merge 1 commit into
pollen-robotics:developfrom
olaservo:fix/headless-boot-audio-stack
Open

Make the audio stack reliable on headless boots#79
olaservo wants to merge 1 commit into
pollen-robotics:developfrom
olaservo:fix/headless-boot-audio-stack

Conversation

@olaservo

Copy link
Copy Markdown

This addresses an issue I ran into while testing Bluetooth on a Reachy Mini Wireless:

  • PipeWire and WirePlumber are user services and the image does not enable lingering for pollen, so user@1000 runs only while a login session exists.
  • Bluetooth audio is PipeWire-only, so it can't work on a headless boot. The image's 40-force-monitor-bluez.conf never loads, because WirePlumber is not running to read it.
  • Daemon audio falls back to pulsesink when ~/.asoundrc does not resolve, and then blocks on a pulse socket that never appears. That starved the 50 Hz control loop and ended in an fd leak and a SIGABRT restart loop.

Three changes in stage2/05-reachy-mini:

  • Enable lingering for pollen.
  • 41-force-monitor-alsa.conf: the ALSA-side equivalent of the Add support for connecting bluetooth devices #55 bluez fix, for a related failure where WirePlumber stays active with an empty device graph while aplay -l sees every card. In some cases this turns a silent failure into an exit.
  • wireplumber-alsa-watchdog.{timer,service}: restarts the audio stack 45 s after startup if the graph holds no ALSA device. Healthy boots are untouched.

Tested on a Reachy Mini Wireless (v0.2.7, trixie, wireplumber 0.5.8-2).

PipeWire and WirePlumber are user services and the image does not enable
lingering for pollen, so user@1000 runs only while a login session
exists. A headless boot has no audio server, and the stack is torn down
on SSH disconnect. Daemon audio falls back to pulsesink whenever
~/.asoundrc does not resolve, and then blocks on a pulse socket that
never appears.

Bluetooth audio is PipeWire-only, so it cannot work on a headless boot
at all. The image's own 40-force-monitor-bluez.conf never loads, because
WirePlumber is not running to read it.

Observed on a Reachy Mini Wireless: this starved the 50 Hz control loop
and ended in an fd leak and a SIGABRT restart loop.

Three changes in stage2/05-reachy-mini:

* Enable lingering for pollen, so user@1000 starts at boot.

* 41-force-monitor-alsa.conf is the ALSA-side equivalent of the pollen-robotics#55
  bluez fix. monitor.alsa sits behind an optional reserve-device ->
  support.dbus chain that can drop the monitor at a session-less
  startup, leaving WirePlumber active with an empty device graph while
  aplay -l sees every card. Disable reserve-device and mark monitor.alsa
  required. In some cases this turns a silent failure into an exit: if
  the monitor cannot load, WirePlumber stops instead of running
  device-less, so systemd restarts it rather than leaving an empty
  graph.

* wireplumber-alsa-watchdog.{timer,service}: 45 s after the user manager
  starts, restart the audio stack if the graph holds no ALSA device. The
  check greps for ALSA because v4l2 and Bluetooth objects can populate
  the graph while the cards are missing. Healthy boots are untouched.

The delay is in the timer rather than an ExecStartPre sleep: a sleeping
oneshot wanted by default.target holds user@1000 in activating for the
whole delay on every boot.

Tested on a Reachy Mini Wireless (v0.2.7, trixie, wireplumber 0.5.8-2).
Headless power-cycles bring up a full graph and the watchdog no-ops.
Disabling monitor.alsa reproduces the empty graph, and the watchdog
detects and recovers it.

Assisted-by: Claude:claude-fable-5
@olaservo
olaservo force-pushed the fix/headless-boot-audio-stack branch from f852cbb to 5ad4a1c Compare August 15, 2026 01:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant