会话与状态管理
1. 职责与边界
本模块维护单个连接连续转换所需的状态,包括音频窗口、VAD 缓存、音高统计、SOLA 拼接缓冲和当前输出。模型与参考条件归 Worker 所有,会话只在调用时使用这些共享资源。
主要源码:session.py、realtime_vc.py 的 create_session()、ws.py 的初始化与退出路径。Session 当前也实现音频记录和保存,相关职责单独由数据记录与可观测性维护。
2. 输入与输出
| 项目 | 内容 |
|---|---|
| 创建输入 | 会话 ID、输入与模型输出采样率、协议输出采样率、窗口及输出长度、设备与保存配置 |
| 流水线输入 | Buffer 提供的新音频块,加上会话中已保留的上下文 |
| 逐块结果 | 更新后的上下文、session.out_data 和各阶段耗时 |
| 退出结果 | 已记录数据的保存任务,以及会话内存状态的清理 |
协议输出采样率由接入层传入。create_session() 在需要时向 Worker 的缓存添加对应输出重采样器,然后为该连接分配独立 Session。
3. 状态归属与更新
| 状态 | 创建与更新方式 | 使用者 |
|---|---|---|
input_wav | 初始化为零,随后按 VAD 状态滚动并填入新块 | 内容编码、音高、RMS 等阶段 |
vad_cache 与语音标记 | 每次 VAD 调用更新,语音结束标记在块处理末尾应用 | 窗口更新、音高与转换分支 |
F0 样本、块计数、中位数与 shifted_f0_alt | 开启音高且检测到语音时更新 | 音高调整和推理条件 |
sola_buffer | 初始为零,每次拼接保存下一块需要的重叠区 | SOLA 对齐与交叉淡化 |
infer_wav_zero | 按模型输出区域长度分配 | 无语音且非首块时的静音输出 |
out_data | 按协议输出块长分配,逐块原位覆盖 | 路由发送与输出记录 |
is_first_chunk、chunk_time_records | 首块完成后更新标记,每块重新记录耗时 | 首块推理分支与日志 |
| 音频记录、时间线、累计时长 | 在输入、输出和事件记录点追加 | 保存与离线分析,详见数据记录专题 |
RMS 包络在当前块计算,使用会话音频窗口和本块推理结果;窗口更新和拼接算法由流式转换流水线说明。Buffer 的原始字节缓存独立于 Session 的模型上下文,二者生命周期都跟随连接。
4. 生命周期
4.1 创建与运行
初始化消息通过接入层校验后,RealtimeVoiceConversion.create_session() 使用 Worker 已计算的流式参数创建 Session。Buffer 随后绑定该 Session,路由持有两者并逐块调用转换。
各连接持有独立的窗口、缓存和输出数组;同一 Worker 复用模型、参考条件和按采样率缓存的输出重采样器。当前没有以会话 ID 查询、恢复或迁移活跃 Session 的管理接口,HTTP 会话工具查询的是已落盘文件。
4.2 结束与清理
触发结束的协议规则由接入与协议适配维护。正常结束先处理尾块,再发完成响应;断联和超时直接进入退出流程。
路由在 finally 中尝试移除连接计数、清空 Buffer,并对其持有的 Session 调用 asyncio.create_task(session.async_save_and_cleanup())。后台协程在线程中执行 save_and_cleanup(),先尝试保存,再在 finally 中调用 cleanup()。
清理方法置空主要音频窗口、拼接缓冲和输出数组,清空 VAD 缓存、录音列表和时间线,并调用 CUDA 缓存清理。对象析构时还会尝试清理。该流程没有卸载 Worker 共享的模型和参考条件。
5. 约束与关联文档
会话 ID 用于连接计数、日志和文件命名。客户端应提供唯一、适合文件名的标识;当前没有租户命名空间或完整标识校验,也没有保证重复 ID 会被拒绝。
完成响应与后台保存是不同阶段。异常退出会尝试保存已经记录的部分,进程强制终止可能中断任务;持久化边界见完成与保存时序。音频记录会在会话内累计,资源评估需同时考虑模型驻留、上下文和记录数据。