适用版本:tcpv2.3+
mode:vad:{JWT_TOKEN}##mode:vad##input_audio_format:pcm{
"taskid": "abc12345",
"type": "listen",
"state": "start"
}{
"taskid": "abc12345",
"type": "listen",
"state": "detecting",
"mode": "vad"
}{
"taskid": "abc12345",
"type": "listen",
"state": "stop",
"mode": "vad"
}[##START][MessageType:8][task_id:8字节][seq:0000][JSON消息体][##END]{
"taskid": "abc12345",
"type": "listen",
"state": "start",
"interrupt": false // 可选,默认 false
}interrupt(可选):是否同时打断当前 TTS 下发false(默认):只更新输入侧 task_id,不打断 TTS(适用于 realtime 正常流程)true:同时更新 TTS task_id,立即停止旧音频下发(适用于 auto 模式按键打断)interrupt=true,同时打断正在进行的 TTS 输出注意:正常流程中客户端不需要发送此消息。VAD 模式下,语音结束的判定由服务端完成。
此消息仅用于客户 端主动取消录音的特殊场景(如用户点击"取消"按钮)。
{
"taskid": "abc12345",
"type": "listen",
"state": "stop"
}| 发送方 | 触发条件 | 后续行为 |
|---|---|---|
| 客户端 | 用户主动取消 | 丢弃数据,不处理,不回复 |
| 服务端 | VAD检测到语音结束 | 通知客户端,开始STT/LLM/TTS处理 |
{
"taskid": "abc12345",
"type": "listen",
"state": "detecting",
"mode": "vad"
}reason 字段区分原因:{
"taskid": "abc12345",
"type": "listen",
"state": "stop",
"mode": "vad"
}VAD_MAX_FRAMES > 0):{
"taskid": "abc12345",
"type": "listen",
"state": "stop",
"mode": "vad",
"reason": "timeout"
}reason 或 reason 非 "timeout":正常流程,等待接收回复reason: "timeout":超时取消,不会有回复,可发送新的 LISTEN start 开始新会话VAD_MAX_FRAMES 配置值1. 发送 LISTEN start (taskid: A)
2. 上传音频帧
3. 收到 LISTEN stop (taskid: A)
↓
4. 立即发送 LISTEN start (taskid: B) ← 关键:立即开始
5. 继续上传音频帧(taskid: B)
6. 同时接收并播放 taskid A 的音频回复1. 发送 LISTEN start (taskid: A)
2. 上传音频帧
3. 收到 LISTEN stop (taskid: A)
↓
4. 停止上传音频
5. 接收并播放 taskid A 的音频回复
6. 播放完成
↓
7. 发送 LISTEN start (taskid: B) ← 关键:播放完成后
8. 开始上传音频帧(taskid: B)时间轴 客户端 服务端
│
│ 生成 taskid: A
│ │
├─────────────────┼──── LISTEN start (A) ──────────────>│ 重置 VAD
│ │ │ 清空缓冲区
│ │<──── STATUS: 开始监听 ────────────────│
│ │ │
│ 开始录音 │
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:1) ───────────>│
├─────────────────┼──── AUDIO_FRAME (seq:2) ───────────>│ VAD 检测中
├─────────────────┼──── AUDIO_FRAME (seq:3) ───────────>│ 检测到语音
│ │ │
│ 用户说完,停止说话 │ VAD 触发
│ 继续录音(背景音) │
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:4) ───────────>│
│ │<──── LISTEN stop (A) ─────────────────│ 语音结束
│ │ │
│ 停止录音 │ 模型处理中
│ 等待播放 │ (生成回复)
│ │ │
│ │<──── AUDIO (seq:1) ────────────────────│
│ │<──── AUDIO (seq:2) ────────────────────│
│ 播放中... │
│ │<──── AUDIO (seq:3) ────────────────────│
│ │<──── END_FRAME ────────────────────────│
│ │ │
│ 播放完成 │
│ 生成新 taskid: B │
│ │ │
├─────────────────┼──── LISTEN start (B) ──────────────>│ 重置 VAD
│ │<──── STATUS: 开始监听 ────────────────│
│ │ │
│ 开始新一轮录音 │
▼ ▼ ▼时间轴 客户端 服务端
│
│ 生成 taskid: A
│ │
├─────────────────┼──── LISTEN start (A) ──────────────>│ 重置 VAD
│ │ │ 清空缓冲区
│ │<──── STATUS: 开始监听 ────────────────│
│ │ │
│ 开始录音 │
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:1) ───────────>│
├─────────────────┼──── AUDIO_FRAME (seq:2) ───────────>│ VAD 检测中
├─────────────────┼──── AUDIO_FRAME (seq:3) ───────────>│ 检测到语音
│ │ │
│ 用户说完,停止说话 │ VAD 触发
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:4) ───────────>│
│ │<──── LISTEN stop (A) ─────────────────│ 语音结束
│ │ │
│ 生成新 taskid: B(立即!) │ 模型处理 A
│ │ │ (生成回复)
├─────────────────┼──── LISTEN start (B) ──────────────>│ 重置 VAD
│ │<──── STATUS: 开始监听 ────────────────│
│ │ │
│ 继续录音(taskid: B) │
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:1, tid:B) ────>│
│ │<──── AUDIO (seq:1, tid:A) ─────────────│ 返回 A 的回复
│ │ │
│ 同时: │
│ - 播放 A 的回复 │
│ - 录音并上传 B 的音频 │
│ (AEC 消除回声) │
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:2, tid:B) ────>│
│ │<──── AUDIO (seq:2, tid:A) ─────────────│
├─────────────────┼──── AUDIO_FRAME (seq:3, tid:B) ────>│
│ │<──── AUDIO (seq:3, tid:A) ─────────────│
│ │<──── END_FRAME (tid:A) ────────────────│
│ │ │
│ A 播放完成,B 继续录音 │
▼ ▼ ▼时间轴 客户端 服务端
│
│ [taskid: A 正在处理中] │
│ │ │
│ 录音中(taskid: B) │ 生成 A 的回复
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:5, tid:B) ────>│
├─────────────────┼──── AUDIO_FRAME (seq:6, tid:B) ────>│
│ │<──── AUDIO (seq:1, tid:A) ─────────────│ 返回 A
│ │ │
│ 播放 A + 录音 B │ VAD 检测 B
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:7, tid:B) ────>│
│ │ │ B 触发 VAD!
│ │<──── LISTEN stop (B) ─────────────────│
│ │ │
│ 生成新 taskid: C(立即!) │ 打断 A
│ │ │ 开始处理 B
├─────────────────┼──── LISTEN start (C) ──────────────>│
│ │<──── STATUS: 开始监听 ────────────────│
│ │ │
│ 停止播放 A 的回复 │ A 停止发送
│ 继续录音(taskid: C) │ 模型处理 B
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:1, tid:C) ────>│
│ │ │ 生成 B 的回复
│ │<──── AUDIO (seq:1, tid:B) ─────────────│ 返回 B
│ │ │
│ 播放 B + 录音 C │
▼ ▼ ▼时间轴 客户端 服务端
│
│ [taskid: A 正在处理中] │
│ │ │
│ 录音中(taskid: B) │ 生成 A 的回复
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:5, tid:B) ────>│
├─────────────────┼──── AUDIO_FRAME (seq:6, tid:B) ────>│
│ │<──── AUDIO (seq:1, tid:A) ─────────────│ 返回 A
│ │ │
│ 播放 A + 录音 B │ VAD 检测 B
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:7, tid:B) ────>│ 检测到人声!
│ │<──── LISTEN detecting (B) ─────────────│ 200ms后触发
│ │ │
│ 立即停止播放 A │ 继续接收 B
│ 继续录音(taskid: B) │
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:8, tid:B) ────>│
├─────────────────┼──── AUDIO_FRAME (seq:9, tid:B) ────>│
│ │ │ B 语音结束
│ │<──── LISTEN stop (B) ─────────────────│
│ │ │
│ 生成新 taskid: C │ 开始处理 B
│ │ │
├─────────────────┼──── LISTEN start (C) ──────────────>│
│ │<──── STATUS: 开始监听 ────────────────│
│ │ │
│ 继续录音(taskid: C) │ 模型处理 B
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:1, tid:C) ────>│
│ │ │ 生成 B 的回复
│ │<──── AUDIO (seq:1, tid:B) ─────────────│ 返回 B
│ │ │
│ 播放 B + 录音 C │
▼ ▼ ▼时间轴 客户端 服务端
│
│ 录音中(taskid: A) │
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:1, tid:A) ────>│
├─────────────────┼──── AUDIO_FRAME (seq:2, tid:A) ────>│
│ │ │
│ 用户点击"取消"按钮 │
│ │ │
├─────────────────┼──── LISTEN stop (A) ───────────────>│ 抛弃所有音频
│ │<──── STATUS: 已停止并清空 ───────────│ 重置 VAD
│ │ │
│ 生成新 taskid: B │
│ │ │
├─────────────────┼──── LISTEN start (B) ──────────────>│ 开始新会话
│ │<──── STATUS: 开始监听 ────────────────│
│ │ │
│ 开始新录音 │
▼ ▼ ▼时间轴 客户端 服务端
│
│ [taskid: A 正在播放回复] │ 正在发送 A 的音频
│ │ │
│ │<──── AUDIO (seq:1, tid:A) ─────────────│
│ │<──── AUDIO (seq:2, tid:A) ─────────────│
│ 播放中... │
│ │ │
│ 用户按下"打断"按钮 │
│ 停止播放 A │
│ 生成新 taskid: B │
│ │ │
├─────────────────┼──── LISTEN start (B, interrupt:true)>│ 打断 TTS!
│ │ │ 停止发送 A
│ │<──── STATUS: 开始监听 ────────────────│
│ │ │
│ 开始录音(taskid: B) │
│ │ │
├─────────────────┼──── AUDIO_FRAME (seq:1, tid:B) ────>│
├─────────────────┼──── AUDIO_FRAME (seq:2, tid:B) ────>│ VAD 检测 B
│ │ │
▼ ▼ ▼interrupt: true 参数,通知服务端同时打断 TTS