外观
WebSocket 协议
协议
健康检查
text
GET /health成功响应(HTTP 200)
json
{
"ok": true,
"service": "sherpa-asr-online-server",
"activeSessions": 3,
"maxSessions": 16,
"wsPath": "/audio",
"ioWorkers": 4
}- 任何方法 / 路径不在
healthPath、不是 WebSocket 升级到wsPath,一律 返回 404 JSON 体并关闭连接
WebSocket 升级
text
GET /audio HTTP/1.1
Host: <host>:<port>
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: <base64-16>
Sec-WebSocket-Protocol: audio.drachtio.org握手要求:
Sec-WebSocket-Version: 13,否则 400Connection: upgrade且Upgrade: websocket,否则 400- 若
server.wsSubprotocol非空,请求必须在Sec-WebSocket-Protocol中带上 对应 token,否则 400 - 通过
concurrency.maxSessions限流;连接数已满返回 503,并丢弃该连接
成功响应
text
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: <base64-20>
Sec-WebSocket-Protocol: audio.drachtio.org升级成功后,服务端立即把连接挂到一个 ASR session(recognizer + VAD 已就绪), 并打日志 ws-<n> websocket session started on worker=<i>。
客户端消息
1. metadata 文本帧(opcode=0x1)
第一帧通常是任意 JSON 文本,服务端会把整段文本存到会话状态,并尽力解析以下 任一字段作为 channelUuid(用于日志与录音文件名):
text
uuid | channel_uuid | call_uuid | sessionId | session_id可选字段 hotwordProfile 用于选择本 WebSocket session 的 hotword profile:
json
{
"uuid": "fs-channel-uuid",
"hotwordProfile": "sales"
}选择规则:
hotwordProfile命中hotwordProfiles时,本连接以及连接内后续 utterance reset 都使用该 profile 的 hotwords- metadata 未带
hotwordProfile时,如果配置了defaultHotwordProfile,使用 默认 profile;否则不启用 hotwords hotwordProfile未命中、为空或类型不合法时,本连接继续运行但不启用 hotwords,并写入 warning 日志- 只处理第一帧 metadata;后续文本帧不会改变本连接的 hotword profile
示例(mod_audio_fork 默认下发的字段):
json
{
"uuid": "fs-channel-uuid",
"callerId": "10086",
"direction": "inbound"
}后续文本帧默认丢弃,仅在 logging.debugTextFrames=true 时落日志。
2. 二进制音频帧(opcode=0x2)
携带 16kHz / 单声道 / PCM16 little-endian 原始采样数据。
- 帧大小受
socket.maxFrameBytes限制,超过即触发 1002 协议错误并关闭 - 任意时间发送
payload.length == 0的二进制帧,等价于“flush”:服务端 立刻 flush 当前语音段并发出 final(如有未结算文本) - 服务端不会做重采样;如果上游不是 16kHz,partial 将完全错乱
3. 控制帧
0x8Close:服务端先 flush final,再回送1000 byeclose 帧0x9Ping:原样回送 Pong0xAPong:直接忽略- 其它 opcode:发出
error事件后回送1003 unsupported opcode并关闭
不支持分片帧(FIN=0 或 opcode=0x0),收到会以 1002 protocol error 关闭。
服务端事件
服务端通过 WebSocket 文本帧(opcode=0x1)下发 JSON 事件,按 type 分三类。
type=transcription
每次 partial 推送 / final 段完成 / 客户端 flush 都可能发出一条:
json
{
"type": "transcription",
"data": {
"text": "你好世界",
"isFinal": false,
"utteranceIndex": 3,
"speechStarted": true,
"speechActive": true,
"speechSegmentDetected": true,
"speechSegmentCompleted": false,
"serverSessionId": "ws-12",
"channelUuid": "fs-channel-uuid",
"metadataText": "{\"uuid\":\"fs-channel-uuid\",\"direction\":\"inbound\"}",
"finalReason": "segment-completed",
"flushReason": "client-close"
}
}| 字段 | 说明 |
|---|---|
text | 当前识别文本(partial 或 final) |
isFinal | true 表示本句已结算;下一段从 utteranceIndex+1 开始 |
utteranceIndex | 同一连接内的语句序号,从 1 起 |
speechStarted | bridge/VAD 是否真实检测到开始说话 |
speechActive | bridge/VAD 当前是否真实处于说话中 |
speechSegmentDetected | bridge/VAD 是否真实检测到语音段 |
speechSegmentCompleted | bridge/VAD 是否真实检测到段落结算完成(驱动 final) |
serverSessionId | 服务端会话 ID(ws-<n>) |
channelUuid | 从 metadata 解析到的通道 UUID(无则字段缺省) |
metadataText | 原始 metadata 文本(仅有 metadata 时附带) |
finalReason | isFinal=true 时填:segment-completed / final / flush |
flushReason | 由 flush 触发时填:audio-idle / client-close / zero-length-binary / socket-read-end |
partial 节流:同一句话内,partial 文本最快每 asr.partialMinIntervalMs ms 下发 一次(文本未变化的事件不会重发)。partial 携带的是产生该 pending 文本时的真实 bridge/VAD flags,不会为便于消费而硬编码为 true。partial / final 文本会先 trim;纯空格、换行等空白识别结果不会作为文本事件或 idle final 下发。
可在服务启动后运行 node request-asr.js --silence,发送至少 3 秒零 PCM;脚本会在 收到非空 transcription 或任一伪 speech flag 时失败。
type=error
json
{
"type": "error",
"data": {
"message": "ASR accept failed: <reason>"
}
}error 一般紧随其后是连接关闭:
- ASR
AcceptPcm16失败:1011 内部错误 - 识别处理失败:1011 内部错误
- 协议错误(帧过大 / 不支持的 opcode):1002 / 1003
type=disconnect
当服务端因协议错误主动断开时,可能在关闭前先发一条:
json
{
"type": "disconnect",
"data": {
"reason": "<message>"
}
}连接生命周期
text
客户端 服务端
|--- TCP 连接 ------------>|
|--- HTTP GET /audio ----->|
|<-- 101 Switching Proto --|
|--- TEXT metadata ------->| (获取 session;记录 channelUuid)
|--- BIN PCM16 frame ----->| (partial 推送)
|<-- transcription partial-|
|--- BIN PCM16 frame ----->|
|<-- transcription final --| (speech_segment_completed)
|--- BIN PCM16 frame ----->|
|<-- transcription partial-|
|--- BIN zero-length ----->| (flush)
|<-- transcription final --| (flushReason=zero-length-binary)
|--- CLOSE frame --------->|
|<-- CLOSE 1000 bye -------|关闭路径:
| 触发 | 行为 |
|---|---|
| 客户端发 close 帧 | flush final → 回 1000 bye → 关闭 |
| 客户端单方面 TCP 断开 | flush final(flushReason=socket-read-end)→ 释放 session |
| 服务端流式异常 | 发 error 事件 → 关闭码 1011 |
| 协议错误 | 发 error + disconnect → 关闭码 1002 / 1003 |