diff --git a/openless-all/app/src-tauri/src/coordinator.rs b/openless-all/app/src-tauri/src/coordinator.rs index 98c25487..ad3e16f8 100644 --- a/openless-all/app/src-tauri/src/coordinator.rs +++ b/openless-all/app/src-tauri/src/coordinator.rs @@ -1039,6 +1039,33 @@ fn spawn_recorder_error_monitor(inner: &Arc, rx: mpsc::Receiver, rx: mpsc::Receiver) { + let captured_session_id = inner.qa_state.lock().session_id; + let inner = Arc::clone(inner); + std::thread::Builder::new() + .name("openless-qa-recorder-error-monitor".into()) + .spawn(move || { + if let Ok(err) = rx.recv() { + let current_session_id = inner.qa_state.lock().session_id; + if captured_session_id != current_session_id { + log::warn!( + "[coord] QA recorder error from stale session {} dropped (current={}, err={})", + captured_session_id, + current_session_id, + err + ); + return; + } + log::error!("[coord] QA recorder runtime error: {err}"); + finish_qa_with_error(&inner, format!("录音设备异常: {err}")); + } + }) + .ok(); +} + fn abort_recording_with_error(inner: &Arc, message: String) { let elapsed = { let mut state = inner.state.lock(); @@ -1754,8 +1781,11 @@ async fn begin_qa_session(inner: &Arc) -> Result<(), String> { }); match Recorder::start(consumer, level_handler) { - Ok((rec, _runtime_errors)) => { + Ok((rec, runtime_errors)) => { *inner.qa_recorder.lock() = Some(rec); + // QA 也跟主听写一样监听 cpal runtime error。设备中途消失 / panic 时 + // 不能让 QA 永远卡在 Recording 没反馈。详见 issue #168。 + spawn_qa_recorder_error_monitor(inner, runtime_errors); } Err(e) => { log::error!("[coord] QA recorder start failed: {e}");