f52b5ea64e5e811fd2cb32d579969de350177133
Addresses Codex's xhigh RT-audio audit of the new Windows cpal path (review 2026-06-19; all Windows-only, no Linux-path change): - W1 (P1): start_capture/start_playback reported Ok as soon as cpal's play() returned, but cpal's WASAPI play() only QUEUES IAudioClient::Start(); a later Start failure left the UI joined-but-silent. Readiness is now driven by the stream actually proving itself: the first RT data callback sets a started flag (or the error callback sets an error code), and the owner thread waits (bounded by STREAM_START_TIMEOUT) before reporting Ok. - W2: both RT error callbacks ran format!+log_msg on the time-critical stream thread. They now store a category in an AtomicU8 only; the owner / health logger translate + log off the RT path. - W3: the playback ring was published one interleaved sample at a time, letting the RT consumer read a half-written L/R pair and letting a raced fetch_sub wrap ring_fill to usize::MAX (wedging mixer pacing). Now reserves occupancy before publishing and writes the whole frame with a single push_slice. - W6: finish_start did an unbounded recv() while holding the slot mutex, so a wedged driver hung start_* and any concurrent stop. Now recv_timeout with a FINISH_START_TIMEOUT backstop; on timeout it signals + detaches (never joins). - W7: OS-reported device geometry is validated in resolve() (channels>0, rate in 8k-384k) so 0 channels can't panic chunks_exact(0) and a 0/absurd rate can't make an infinite/huge resample ratio. resample.rs constructors also clamp rates >=1 (release-safe; +2 tests) instead of a debug-only assert. - W4 (diagnostic half): the playout-health logger compared raw device samples against the internal-stereo prefill target. The callback now records demand in internal 48 kHz-stereo units (internal_demand) so the comparison is correct for remapped/non-48k devices. The dynamic-target restructure stays deferred. Deferred (logged in review-2026-06-19-cpal-rt-audit.md): W5 (bounded mixer-> worker channel) touches the shared Linux audio path and wants its own design + regression pass; the W2 dynamic-target sizing needs a real WASAPI callback. Verified: Linux cargo test --lib 326/0, clippy --all-targets clean; windows-gnu cargo check --lib --tests --bins clean; windows-gnu release peerspeak.exe builds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>