语音输入 VoiceInput 实现链路
大约 2 分钟
语音输入 VoiceInput 实现链路
源码:VoiceInput.vue;输入条封装:ChatInput.vue(voiceMode)。
事件协议:ASR流式协议.md(阿里/腾讯共用)
总览:../README.md · 阿里 ../aliyun/ASR语音识别集成.md · 腾讯 ../tencent/ASR语音识别集成.md
约定
- H5 只认原生下发的
event:asr_interim、asr_session_complete、asr_error等(常量与AsrStreamProtocol.java一致)。 TERMINAL_ASR_EVENTS:asr_session_complete、asr_error。- 不传、不解析 JSON 字段
isEnd。
核心分支(_onStreamResult)
event | H5 |
|---|---|
asr_interim | _applyInterim;已接受的 interim 会重置静音 3s 计时 |
asr_sentence_end | _sealSentence(进 committed)+ 启动 3s |
asr_vad_end | 启动 3s |
asr_session_complete | _finishVoiceRecognition(立即收尾) |
asr_error | _finishVoiceRecognition |
静音自动停录:silenceTimeout > 0 时,句末/VAD/有效 interim 后 3s 无新活动 → _stopRecording()。asr_session_complete 不再多等 3s。
展示与防回退
display = merge( merge(anchor, committed), interim )
interim:整段覆盖,非 diff。_shouldAcceptInterimPartial:拒绝同长或更短的「回退」包(如「你好」→「你,」)。
streamToInput === true(默认)时 emit('update:text', display);hold-send 为 false,按住过程不写输入框、不 emit 预览。
发送竞态
ChatInput.onSend 最先调用 voiceInput.abortStreamSync():
- 递增世代,丢弃后续迟到回调;
- 若在录则停原生(type 31)。
避免「已点发送清空框 → 迟到 asr_interim 又写回」。
hold-send(豆包式)
由 ChatInput 驱动 VoiceInput 的 hold API,智能填单:voice-mode="hold-send"。
| 步骤 | 行为 |
|---|---|
| 点麦克风 | 输入区切为「按住 说话」条(hideTrigger + 独立 voiceInputHold 实例) |
touchstart | beginHold() → 拉 token、开流式 ASR |
| 按住中 | 不展示识别字、不 update:text |
touchend(未上滑取消) | endHold() → 等终稿 → done → ChatInput emit('send') |
| 上滑 ≥ 72px | cancelHold() → _holdDiscardResult=true,终稿在 _finishVoiceRecognition 入口丢弃 |
cancelHold 内部也会 abortStreamSync()。
与 ChatInput 分工
| 模式 | VoiceInput | ChatInput |
|---|---|---|
text | 侧边麦点击录音,silence-timeout=3000,流式写框 | 多行输入 + 发送 |
hold-send | stream-to-input=false,hold API | 按住条 UI、上滑取消、松手 send |
调试
- H5:
[ASR] event displayMode text(cordovaPluginonNative已统一 parse 对象)。 - 原生:
adb logcat -s ALI_ASR,对照vendorEvent。