fix(recorder): watchdog 在 sleep 醒来后重检 stop_flag,消除停采误报
当用户松开 hotkey 进入 Listening → Processing 转移时,coordinator 调
rec.stop() 设置 stop_flag 并 pause cpal Stream。但 watchdog 线程此时
可能正卡在 1 秒的 sleep 里:sleep 结束后旧逻辑直接读 last_callback_time,
看到"已 >3 秒未更新"就触发 EngineFailed("录音回调静默停止 N 秒"),
让 coordinator 把正常停采当成引擎崩溃,胶囊弹出 "audio engine failed"。
复现日志(~/Library/Logs/OpenLess/openless.log):
27.011 [recorder] cb#4250 ... <- 最后一次回调
27.054 [asr] server JSON ... <- ASR 仍在收尾
~27.5 end_session 调 rec.stop() 设置 stop_flag + pause cpal
31.667 [ERROR] [recorder] watchdog: 录音回调已停止 4 秒,触发错误恢复
31.667 [ERROR] [coord] recorder runtime error: audio engine failed
修复:watchdog sleep 醒来后立即再 load 一次 stop_flag,flag 已置位则
直接 break 退出,不再做 elapsed 判定。这样:
- 主动停采路径(hotkey-release / cancel):watchdog 静默退出,无误报
- 真故障路径(CoreAudio 设备掉线、OS 音频复位):stop_flag 仍为 false,
watchdog 照常按 3 秒静默阈值触发 EngineFailed,行为不变
附 18 行注释解释 race,避免后续重构时被无意识回退。
This commit is contained in:
1 parent
15442b5aad
commit
1bb38ef0f7
1 file changed
+17
@@ -192,6 +192,23 @@ fn run_audio_thread(
|
||||
while !stop_flag_for_watchdog.load(Ordering::SeqCst) {
|
||||
thread::sleep(std::time::Duration::from_millis(WATCHDOG_CHECK_INTERVAL_MS));
|
||||
|
||||
// 关键:sleep 醒来后必须重新检查 stop_flag,再去看 elapsed。
|
||||
//
|
||||
// 否则会与 hotkey-release 停采路径产生竞态:
|
||||
// 1. 用户松开 hotkey → end_session 调 rec.stop() → 设置 stop_flag
|
||||
// → audio 线程 pause 了 cpal Stream → 回调真的静默
|
||||
// 2. 但 watchdog 此时正卡在上面的 1 秒 sleep 里
|
||||
// 3. sleep 结束后,若不重新检查 stop_flag,
|
||||
// 就会读到 last_callback_time 已经"老 4 秒",
|
||||
// 把"我们主动停掉的录音"错报成 EngineFailed("录音回调静默停止 N 秒"),
|
||||
// coordinator 收到错误后会终止 session、胶囊弹错。
|
||||
//
|
||||
// 修复方式是 sleep 后立即再 load 一次:进入 stop 流程后 watchdog 静默退出,
|
||||
// 不影响 watchdog 在真正活动期捕获 CoreAudio 设备掉线等真故障。
|
||||
if stop_flag_for_watchdog.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
|
||||
let last_callback = *state_for_watchdog.last_callback_time.lock();
|
||||
match last_callback {
|
||||
Some(last_time) => {
|
||||
|
||||
Reference in new issue
Block a user