问题现象
Windows 平台录音时,如果录音器异常停止,超过 8 秒没有音频数据上传,会触发 ASR 服务超时机制,导致胶囊卡在 processing 状态无响应。
用户界面表现
- 胶囊显示蓝色加载点点(processing 状态)
- ✕ 和 ✓ 按钮显示但无响应
- 无错误提示,用户不知道发生了什么
- 需要手动取消或重启应用才能恢复
错误日志
2026-05-04T08:01:31.974029Z [ERROR] [asr] error frame code=45000081
body={"error":"[Timeout waiting next packet] waiting next packet timeout: 8.000000 seconds, session has ended"}
复现步骤
- 启动 OpenLess
- 按录音键开始录音
- 录音器异常停止(麦克风被占用、设备断开、CPAL 崩溃等)
- ASR 服务等待 8 秒后超时
- 观察胶囊状态:卡在 processing,无法恢复
时间线分析
08:01:21 - 用户按下录音键,开始录音
08:01:22 - ASR 连接成功,开始发送音频
08:01:22 - 录音回调 #1(第一个回调)
08:01:23 - 录音回调 #50(最后一个回调,仅 0.5 秒)
- 录音器异常停止,无更多回调
08:01:31 - ASR 超时错误(8 秒无数据后)
之后 - 无任何日志,胶囊卡在 processing 状态
根因分析
1. 录音器异常停止(根本原因)
- 录音开始后只有 50 个回调(约 0.5 秒)
- 之后录音器完全停止,没有任何回调或错误日志
- 这不是用户闭麦,而是录音器静默失败
可能的原因:
- 麦克风设备被其他应用占用
- 音频设备断开或驱动问题
- CPAL 音频库回调线程崩溃
- Windows 音频服务中断
- 麦克风权限被撤销
2. ASR 服务超时机制(触发因素)
- Volcengine ASR 是流式识别,要求持续的音频流
- 如果 8 秒内没有收到新的音频包,服务端认为会话结束
- 发送错误帧
code=45000081 并关闭连接
- 这是 ASR provider 的正常机制,不是 bug
3. 错误处理机制缺失(导致无响应)
- ASR 错误通过
signal_error() 发送到 final_tx
- 但 coordinator 没有正确处理这个错误
- 胶囊状态机没有错误恢复分支
- 前端没有收到状态更新,继续显示 processing
- 结果:胶囊卡住,用户界面无响应
因果链
录音器异常停止 (0.5秒后)
↓
没有音频数据发送到 ASR
↓
ASR 等待 8 秒无数据
↓
ASR 超时并结束会话
↓
错误处理机制缺失
↓
胶囊卡在 processing 状态
技术细节
录音器停止的证据
08:01:22.801 - cb#1 (第一个回调)
08:01:23.291 - cb#50 (第 50 个回调,最后一个)
之后无任何回调
当前错误处理流程
// src-tauri/src/asr/volcengine.rs:436
self.signal_error(VolcengineASRError::ConnectionFailed(...));
self.state.lock().is_connected = false;
*self.audio_tx.lock() = None;
// 但没有通知 coordinator 恢复状态
缺失的保护机制
- ❌ 没有检测录音器是否还在运行
- ❌ 没有录音器健康检查(如 2 秒无回调则报警)
- ❌ 没有客户端超时保护(不依赖 ASR 服务端)
- ❌ 没有错误恢复机制(自动回到 idle)
影响范围
- 用户体验:严重影响,用户不知道发生了什么,只能重启
- 平台:Windows 平台(macOS/Linux 可能也有类似问题)
- 频率:偶发,但一旦发生就无法自动恢复
- 触发条件:任何导致录音器停止的情况
建议修复
1. 录音器健康检查
// 检测录音回调是否停止
let last_callback_time = Arc::new(Mutex::new(Instant::now()));
// 在回调中更新时间
*last_callback_time.lock() = Instant::now();
// 定期检查(每 2 秒)
tokio::spawn(async move {
loop {
tokio::time::sleep(Duration::from_secs(2)).await;
if last_callback_time.lock().elapsed() > Duration::from_secs(2) {
log::error!("录音器停止响应,自动取消");
// 取消录音,恢复到 idle
}
}
});
2. 客户端超时保护
// 不依赖 ASR 服务端超时,客户端主动检测
const RECORDING_TIMEOUT: Duration = Duration::from_secs(60);
const PROCESSING_TIMEOUT: Duration = Duration::from_secs(30);
const RECORDER_HEALTH_CHECK: Duration = Duration::from_secs(2);
3. 完善错误处理
// ASR 错误后自动恢复到 idle 状态
match asr_result {
Err(e) => {
log::error!("ASR error: {}", e);
// 清理状态
self.stop_recording();
// 通知前端显示错误
self.emit_capsule_state(CapsuleState::Error {
message: "识别超时,请重试".to_string()
});
// 3 秒后自动恢复到 idle
tokio::time::sleep(Duration::from_secs(3)).await;
self.emit_capsule_state(CapsuleState::Idle);
}
}
4. 录音器错误捕获
// 在 CPAL 回调中捕获错误
let error_callback = move |err| {
log::error!("录音器错误: {}", err);
// 通知 coordinator
};
临时解决方案
用户遇到此问题时:
- 点击 ✕ 按钮尝试取消(可能无效)
- 重启应用
- 检查麦克风是否被其他应用占用
- 检查麦克风权限设置
相关代码
src-tauri/src/recorder.rs - 录音器实现
src-tauri/src/asr/volcengine.rs:428-442 - ASR 错误处理
src-tauri/src/coordinator.rs - 录音状态管理
src/components/Capsule.tsx - 胶囊状态显示
环境
- 平台:Windows 11
- 版本:1.2.13
- ASR 服务:Volcengine
Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
问题现象
Windows 平台录音时,如果录音器异常停止,超过 8 秒没有音频数据上传,会触发 ASR 服务超时机制,导致胶囊卡在 processing 状态无响应。
用户界面表现
错误日志
复现步骤
时间线分析
根因分析
1. 录音器异常停止(根本原因)
可能的原因:
2. ASR 服务超时机制(触发因素)
code=45000081并关闭连接3. 错误处理机制缺失(导致无响应)
signal_error()发送到final_tx因果链
技术细节
录音器停止的证据
当前错误处理流程
缺失的保护机制
影响范围
建议修复
1. 录音器健康检查
2. 客户端超时保护
3. 完善错误处理
4. 录音器错误捕获
临时解决方案
用户遇到此问题时:
相关代码
src-tauri/src/recorder.rs- 录音器实现src-tauri/src/asr/volcengine.rs:428-442- ASR 错误处理src-tauri/src/coordinator.rs- 录音状态管理src/components/Capsule.tsx- 胶囊状态显示环境
Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com