From a7fdc96e7bf133d67195211be916933cdaca3a0e Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 25 Apr 2026 09:37:51 +0000 Subject: [PATCH] fix(audio): log dropped capture errors instead of silently discarding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cpal stream-error closure used `let _ = err_tx.try_send(...)` against a bounded sync_channel(16). If the live session's listener stalled or the frontend disconnected, runtime stream errors were silently dropped — the diagnostic bundle showed nothing for a session that mysteriously stopped working. - Bump the error channel capacity 16 → 32 (matches AUDIO_CHANNEL_CAPACITY). - On try_send failure, log to stderr with the device name + a per-session drop counter so the symptom is visible in the diagnostic bundle even when the typed event never reached the frontend. - Plumb a new `dropped_errors: Arc` through `build_input_stream` alongside the existing `dropped_chunks`, mirroring the same pattern. (kon-audio doesn't build in the audit sandbox: it links against ALSA which the sandbox lacks. CI cross-platform compiles it.) https://claude.ai/code/session_0189xUb6ie6t9qHkzatGZ9Rb --- crates/audio/src/capture.rs | 40 ++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/crates/audio/src/capture.rs b/crates/audio/src/capture.rs index 7fbbed2..7dde529 100644 --- a/crates/audio/src/capture.rs +++ b/crates/audio/src/capture.rs @@ -370,11 +370,15 @@ fn open_and_validate( let (tx, rx) = mpsc::sync_channel::(AUDIO_CHANNEL_CAPACITY); let requeue_tx = tx.clone(); let dropped_chunks = Arc::new(AtomicU64::new(0)); - // Bounded channel for runtime stream errors. Capacity 16 = plenty for - // the rare error case; if it ever fills, we drop newer errors silently - // because they would be redundant noise in a stream that is already - // failing. (Codex review 2026/04/17 M2) - let (err_tx, err_rx) = mpsc::sync_channel::(16); + // Bounded channel for runtime stream errors. Capacity 32 = plenty for + // the rare error case; if it ever fills, drops are reported via stderr + // and counted in `dropped_errors` so the symptom is visible in the + // diagnostic bundle even when the listener has gone away. Errors + // beyond the cap are by definition redundant noise in a stream that + // is already failing. (Codex review 2026/04/17 M2; capacity bump and + // drop logging added 2026/04/25 audit pass.) + let (err_tx, err_rx) = mpsc::sync_channel::(32); + let dropped_errors = Arc::new(AtomicU64::new(0)); let stream = match format { SampleFormat::F32 => build_input_stream::( @@ -385,6 +389,7 @@ fn open_and_validate( tx, dropped_chunks.clone(), err_tx.clone(), + dropped_errors.clone(), name.to_string(), ), SampleFormat::I16 => build_input_stream::( @@ -395,6 +400,7 @@ fn open_and_validate( tx, dropped_chunks.clone(), err_tx.clone(), + dropped_errors.clone(), name.to_string(), ), SampleFormat::U16 => build_input_stream::( @@ -405,6 +411,7 @@ fn open_and_validate( tx, dropped_chunks.clone(), err_tx.clone(), + dropped_errors.clone(), name.to_string(), ), other => { @@ -503,6 +510,7 @@ fn build_input_stream( tx: mpsc::SyncSender, dropped_chunks: Arc, err_tx: mpsc::SyncSender, + dropped_errors: Arc, device_name: String, ) -> std::result::Result where @@ -532,10 +540,24 @@ where // frontend can show a toast. Also keep the eprintln for ops // logs. (Codex review 2026/04/17 M2) eprintln!("[kon-audio] capture error: {err}"); - let _ = err_tx.try_send(CaptureRuntimeError { - device_name: err_device_name.clone(), - message: err.to_string(), - }); + if err_tx + .try_send(CaptureRuntimeError { + device_name: err_device_name.clone(), + message: err.to_string(), + }) + .is_err() + { + // Channel full — listener has stalled or detached. Note + // it in stderr and the dropped-errors counter so the + // diagnostic bundle still shows the symptom even if the + // frontend never received the typed event. + let prior = dropped_errors.fetch_add(1, Ordering::Relaxed); + eprintln!( + "[kon-audio] capture error channel full; dropped error #{} for device '{}'", + prior + 1, + err_device_name, + ); + } }, None, )