Diagnose the audio-unhealthy banner
A red audio unhealthy banner appeared in BanterLab. The test loop has paused. This guide explains what triggered it and how to recover.
What it means
The AudioDeviceWatchdog has been in "giving up" state for at least 5 minutes with no sample-counter advancement between any of its post-give-up retry attempts. In plain language: the audio device disappeared, the OS audio server (PipeWire / PulseAudio) has not re-enumerated it, and our normal recovery loop has been retrying once a minute for at least 5 minutes without success.
BanterAutoTest reacts to this signal by setting mAudioPaused and suspending the iter scheduler. Iters do not silently freeze any more — they're explicitly paused, the banner tells you so, and they resume the moment the audio device comes back.
The escalation tiers
| Tier | Trigger | Banner | Iter scheduler |
|---|---|---|---|
| 1. Active rebuild | sample counter frozen ≥ 3 s | (none) | running, may stall briefly |
| 2. Post-give-up retry | 20 rebuilds without progress | yellow (existing) | running |
| 3. Audio unhealthy | tier 2 persists ≥ 5 min | red (new) | paused |
Recovery is automatic at any tier when the sample counter advances.
What triggered it
The most common cause (observed 2026-06-20) is a USB hot-plug glitch:
- A USB audio device is unplugged.
- The kernel correctly re-enumerates it when re-plugged (
lsusbshows it). - PipeWire / WirePlumber does NOT pick it up —
pactl list short sinksdoes not contain the device any more. - Our
findAudioOutputresolves to the staleQAudioDevicedescriptor — Qt accepts it, reportsActiveState, but no samples ever leave. - The watchdog correctly detects the silent stall and rebuilds repeatedly.
- After ~20 rebuilds → yellow
givingUp(tier 2). Retries continue at 1/minute. - After 5 minutes of fruitless retries → red
audioUnhealthy(tier 3). Scheduler pauses.
Recovery steps
Try in order. Each step is non-destructive; stop as soon as the banner clears.
-
Wait briefly. If the cause was transient (CPU contention, brief OS audio glitch), the watchdog's per-minute retry probe may already be about to succeed. Watch the banner for 60 s.
-
Check the device is present. Run:
pactl list short sinks pactl list short sourcesConfirm your expected device is in the output. If it's missing, the audio server has not re-detected it.
-
Replug the device. Physically unplug the USB audio adapter, wait 2 s, replug. Watch
pactl listagain. Some PipeWire builds need a manual nudge here. -
Restart the audio server. As your user (NOT root):
systemctl --user restart pipewire pipewire-pulse wireplumberThis briefly silences all audio on the system. After it returns,
pactl list short sinksshould re-discover the device. Within ~60 s the BanterLab banner should clear (the next post-give-up retry probes the device and gets samples flowing). -
Relaunch the hub. If the banner still does not clear after a successful PipeWire restart, the binding in BanterLab is stuck. Stop the hub and start it again — the test set resumes from the last checkpoint (per the audio-recovery-watchdog spec).
What does NOT trigger the banner
- Brief CPU contention. The pinned scheduler thread is invariant to GUI-thread starvation.
- Compositor pacing. Same reason.
- A single failed iter. The banner only fires after a full 5 min of post-give-up retries — the threshold is intentionally conservative.
- A transient PipeWire reconnect that succeeds within 5 min.
If you see the banner triggering on shorter outages, the setAudioUnhealthyAfterMs knob may have been tuned down — check the spec or your config.
Reference
- Spec:
content/doc/internal/specs/audio-compositor-decoupling/architecture.md§AR-10 - Related: diagnose-audio-stall, diagnose-iter-cadence-stutter