接入与协议适配
1. 职责与边界
本模块负责连接与消息处理,将两种 WebSocket 协议转换为统一内部配置,组织音频收发、正常结束与异常退出,并提供 HTTP 路由。它调用缓冲、会话和转换模块,不实现模型算法。
主要源码:ws.py、protocol_detector.py、protocol_adapter.py、base.py、tools.py。完整消息与字段由语音转换 API 中文 / English维护。
2. 输入与输出
| 边界 | 输入 | 输出 |
|---|---|---|
| WebSocket 初始化 | 首条 JSON 配置消息 | 统一配置、Session、Buffer 和协议适配器;标准协议另发 ready |
| 音频收发 | 二进制 PCM 数据或原始 Opus 包 | 转换后的单声道 int16 PCM 字节,无 WAV 头 |
| 连接结束 | 协议结束消息、断联或超时 | 正常路径发完成消息,退出路径执行清理 |
| HTTP | 健康、版本或会话数据请求 | 状态、版本或已保存会话数据;合同见系统 API与会话数据 API |
3. 关键流程
3.1 协议归一化与初始化
/ 和 /ws 使用同一 WebSocket 处理函数。接受连接后,路由读取首条 JSON,由 ProtocolDetector 识别协议并创建适配器。
| 协议 | 识别依据 | 内部处理 |
|---|---|---|
| 简单协议 | signal = start | 将 stream_id、sample_bit 等映射到统一字段,使用内部 api_key 占位值,不发送 ready |
| 标准协议 | type = config | 保留初始化字段,完成初始化后发送 ready |
识别器对其他消息也返回标准适配器,路由随后检查归一化结果是否为配置消息。适配器还负责识别结束消息、格式化完成和错误消息。
路由校验配置类型、api_key 和单声道要求,随后从转换实例创建 Session,再按编码选择 PCM 或 Opus Buffer,并将 Session 绑定到 Buffer 用于事件记录。ready 按协议需要发送,连接计数在初始化末尾登记。
3.2 音频收发
收到非空二进制消息后,路由调用 buffer.add_chunk(),再通过 has_complete_chunk() 循环消费可用的完整块。每次 process_chunk() 执行:
- 从 Buffer 取得浮点音频块。
- 调用
chunk_vc(numpy_chunk, session),从session.out_data取得结果。 - 将结果乘以 32768 并转换为 int16 字节,发送给客户端。
- 记录处理耗时和输出事件。
因此网络包边界与推理块边界不同。输入格式与块长度由音频缓冲解释,逐块算法由转换流水线解释。
3.3 正常结束与异常退出
初始化后的每次 websocket.receive() 使用 app.receive_timeout;首条配置的 receive_json() 不在该超时包装内。
收到适配器识别的正常结束消息时,路由循环处理剩余缓冲,不足一块时由 Buffer 补齐,再发送该协议的完成消息并退出。完成响应当前不填充实际统计数据。
超时、断联和接收异常会退出收包流程,不执行上述正常结束的尾块处理。finally 尝试关闭连接、移除已登记连接、清空 Buffer,并为路由已持有的 Session 创建后台保存与清理任务。状态及资源释放见会话与状态管理。
3.4 HTTP 入口
/health 返回固定健康状态,/version 返回包版本与构建日期。健康接口没有逐请求试运行模型的检查。
/tools/session/{session_id} 调用 App 中的 SessionDataManager 读取已落盘会话文件;它不查询活跃 Session,也不触发推理或等待后台保存完成。文件组织与编码流程见数据记录与可观测性。
4. 约束与关联文档
标准协议的 api_key 校验只检查非空,简单协议使用内部占位值;HTTP 工具接口没有访问鉴权。这是当前实现边界,部署侧访问控制见配置与部署。
部分处理异常仅写日志并返回,Opus 解码失败可能补静音,协议未保证每次内部失败都返回结构化错误。完成消息表示正常结束分支走到响应步骤,不证明每块转换成功、音质合格或录音已经保存。持久化完成语义见数据记录。