Repository navigation
[audio][ASR] 激活后应立即打开麦克风,避免等待建连导致丢失开头语音 #1081
Description
Summary
在 Android 悬浮球和 Windows 桌面版上,点击/激活录音后,麦克风并不是立即进入可用状态,而是要先等待一段时间。用户通常会在点击后马上说话,不会等录音动画完全亮起,因此开头几个字经常丢失。
另外,目前实时 ASR 的中间结果并不会在录音过程中流式显示出来。既然当前 streaming path 没有提供可见的实时文字,我建议评估将传统听写改为「先完整录音,再把录音文件交给 ASR 转写」的非流式方案,或至少提供这一方案作为稳定模式。
Reproduction
- 配置云端 ASR(当前测试日志使用 Bailian ASR)。
- Android 点击悬浮球,或在 Windows 桌面版激活听写。
- 点击后立即开始说话,不等待胶囊/录音动画完全亮起。
- 观察启动等待、开头语音丢失,以及录音期间没有实时原文显示。
Observed behavior
-
Android 和 Windows 都能复现,说明问题很可能位于跨平台 Core 录音管线,而不是单一平台的麦克风权限或驱动。
-
Windows 日志中的一次启动:
03:32:32.368 [cli] dispatching intent=ToggleDictation 03:32:32.798 [recorder] inputDevice=麦克风 ... 03:32:33.398 [recorder] cb#1 ...另一段启动中,
dispatch到inputDevice约 0.8 秒,首个音频回调又晚约 0.6 秒。 -
Android 日志中,
inputDevice到首个 cpal 回调通常还需要约 0.3–0.5 秒。 -
两端随后都能持续收到非零 PCM,说明麦克风本身可以正常工作。
-
当前实时 ASR 的 partial/interim 结果没有显示在胶囊或输入目标中,因此用户无法确认刚才说的内容是否已经被接收。
Technical findings
在当前 Core 2.0 管线中,启动顺序是:
TranscriptionEngine::start()
└─ 云端 ASR open_session()(DNS/TCP/TLS/WebSocket 建连)
└─ AudioRecorder::start()
└─ 第一个 PCM 回调
PipelineDictationEngine::start_voice_capture / start 会先等待 transcription_engine.start(...).await,之后才调用 recorder.start(...).await。Bailian 的 build_cloud_transcription_session 每次会话都会创建新的实时 ASR 实例并等待 open_session();当前 WebSocket 建连超时上限为 5 秒。
这与 fc38edd1(2026-09-06,Core 2.0 consolidation)之前的行为不同:旧协调器先启动 Recorder,再通过 deferred PCM bridge 缓冲等待 ASR 建连的音频。因此旧流程不会把云端网络等待放在“麦克风尚未启动”的前面。
Expected behavior
- 激活录音后应立即请求并打开系统麦克风。
- 用户点击后马上说话时,首个 PCM 不应因为 ASR 建连而丢失。
- 如果 ASR 尚未准备好,应在内存中缓冲已经采集到的 PCM,待 ASR 可用后再发送。
- 录音期间应显示实时原文;如果当前 streaming path 无法稳定提供 partial 结果,应明确提供非流式模式,而不是让用户误以为实时转写已经在工作。
Proposal
请评估以下方案之一:
- 恢复「Recorder first + deferred PCM bridge」:先开麦、立即采集 PCM,同时异步建立实时 ASR;
- 对传统听写提供「录音文件 ASR」模式:点击后只负责稳定录音,停止后将 WAV/PCM 文件提交给支持批量转写的 ASR;
- 将实时流式 ASR 保留为可选模式,并在 partial 结果不可用时自动回退到文件式转写。
文件式方案未必对每个 provider 都能降低总转写耗时,但它应能显著改善录音启动体验、首字保留和网络抖动下的稳定性;建议在 Android/Windows 上实测端到端耗时后决定默认模式。
Related issues
- Keep provider connections alive: TLS handshake costs 4.2s and is paid twice per dictation #998 — Keep provider connections alive: TLS handshake costs 4.2s and is paid twice per dictation
- Feature(StreamInput): 输入过程中将实时文字插入输入框 #1004 — Feature(StreamInput): 输入当中看不到实时的文字转换和显示
- 热键 bridge 串行阻塞:一次慢 IO 就能让热键彻底失灵(已为此挖了三条旁路) #872 — 热键 bridge 串行阻塞:一次慢 IO 就能让热键彻底失灵
Environment
- OpenLess Android floating overlay
- OpenLess Windows desktop
- Logs captured on 2026-09-17
- Current Core 2.0 branch after
fc38edd1
Activity
H-Chris233 commentedon Sep 17, 2026
受理
feat(dictation): 恢复录音优先并增加稳定模式 (#1082)