6.3 KiB
6.3 KiB
语音通话 "idle timeout" 问题 - 优化总结
📅 日期
2026-02-28
🎯 问题描述
用户在使用语音通话功能时,录音后总是收到 "idle timeout" 错误,无法完成完整的对话流程(ASR → LLM → TTS)。
🔍 问题根因
1. 客户端发送参数不符合官方推荐
- 问题: 每片 8KB,间隔 50ms,发送速度是实际音频速度的 5 倍
- 影响: 虽然在官方范围内(1KB-16KB),但不是最优参数
2. 服务器超时时间不足
- 问题: 默认 60 秒超时,但 ASR + LLM + TTS 可能需要更长时间
- 影响: 在处理完成前就超时断开
3. 测试音频太短
- 问题: 之前测试只有 9KB(约 0.3 秒)
- 影响: ASR 无法识别太短的音频
✅ 已实施的优化
优化1: 调整客户端分片参数(符合官方推荐)
文件: xuniYou/pages/chat/phone.vue
修改内容:
// 优化前
const chunkSize = 8192 // 8KB
const chunkDelay = 50 // 50ms
// 优化后
const chunkSize = 3200 // 3.2KB(官方推荐)
const chunkDelay = 100 // 100ms(官方推荐)
理由:
- PCM 16kHz 单声道: 32000 bytes/秒
- 100ms 音频 = 32000 × 0.1 = 3200 bytes
- 完美匹配实时音频流速度
优化2: 增加服务器超时时间
文件: lover/.env
修改内容:
# 新增配置
VOICE_CALL_IDLE_TIMEOUT=120
理由:
- 从 60 秒增加到 120 秒
- 给 ASR + LLM + TTS 留出足够处理时间
- 避免在处理过程中超时
📊 优化效果对比
发送速度对比
| 参数 | 优化前 | 优化后 |
|---|---|---|
| 每片大小 | 8192 bytes | 3200 bytes |
| 发送间隔 | 50ms | 100ms |
| 发送速率 | 163840 bytes/s | 32000 bytes/s |
| 音频速率 | 32000 bytes/s | 32000 bytes/s |
| 速率比 | 5.12 倍 | 1 倍 ✅ |
时间线对比
优化前:
0s - 用户说话 1 秒
1s - 一次性发送 32KB
1s - ASR 无法处理
60s - 超时断开 ❌
优化后:
0s - 用户说话 5 秒
5s - 开始分片发送(3200 bytes/片,100ms 间隔)
10s - 发送完成,ASR 识别
11s - LLM 生成回复
13s - TTS 合成语音
15s - 客户端播放音频 ✅
🔧 需要执行的操作
⚠️ 重要:必须重启服务器
修改 .env 文件后,必须重启 FastAPI 服务器才能生效:
# 1. 停止旧进程
pkill -f "uvicorn.*main:app"
# 2. 启动新进程
cd /path/to/lover
uvicorn main:app --host 0.0.0.0 --port 30101 --reload
客户端重新编译
在 HBuilderX 中重新运行项目到手机或模拟器。
📱 测试指南
测试步骤
- 打开 App,进入语音通话页面
- 按住"按住说话"按钮
- 清晰地说 3-5 秒的话(重要!)
- 松开按钮
- 等待响应(应该在 20 秒内完成)
预期结果
- ✅ 看到"发送中..."提示
- ✅ 看到"识别中..."提示
- ✅ 收到文字回复
- ✅ 听到语音回复
- ✅ 没有 "idle timeout" 错误
关键日志
客户端应该看到:
📦 开始分片发送(官方推荐参数)
📊 总大小: 160000 bytes
📊 每片大小: 3200 bytes
📊 发送间隔: 100 ms
✅ 所有音频片段发送完成,共 50 片
✅ 结束标记发送成功
📋 收到控制消息, type: reply_text
🎵 收到音频数据流
📋 收到控制消息, type: reply_end
服务器应该看到:
ASR connection opened
ASR event end=True sentence=[识别的文字]
Handle sentence: [识别的文字]
📚 相关文档
已创建的文档:
最新优化说明.md- 详细的优化说明测试检查清单.md- 测试步骤和检查项语音通话完整流程图.md- 可视化流程图官方文档分析和正确实现.md- 技术分析问题定位总结.md- 问题诊断过程
🎓 技术要点总结
1. Paraformer-realtime-v2 的正确用法
- 必须流式发送音频数据
- 每包 1KB-16KB,建议 3200 bytes
- 发送间隔建议 100ms
- 发送完成后必须发送 "end" 标记
2. PCM 音频参数
- 采样率: 16000 Hz
- 位深度: 16 bit (2 bytes)
- 声道数: 1(单声道)
- 数据速率: 32000 bytes/秒
3. 超时设置
- 空闲超时: 120 秒(从 60 秒增加)
- 静默超时: 60 秒(无语音活动)
- 给 ASR + LLM + TTS 留出足够时间
4. 录音要求
- 最少 2-3 秒
- 建议 3-5 秒
- 清晰发音,避免噪音
🐛 故障排查
如果还是出现 "idle timeout"
-
检查服务器是否重启
ps aux | grep uvicorn -
检查配置是否生效
cat lover/.env | grep VOICE_CALL_IDLE_TIMEOUT -
检查录音时长
- 客户端日志中的 "总大小" 应该 > 96000 bytes(3 秒)
-
检查服务器日志
tail -f lover/logs/app.log
常见问题
Q: 为什么要用 3200 bytes? A: 因为 PCM 16kHz 单声道每秒 32000 bytes,100ms 就是 3200 bytes,这是官方推荐的参数。
Q: 为什么要延迟 100ms? A: 模拟实时音频流的速度,让 ASR 能够边收边识别,而不是一次性收到大块数据。
Q: 为什么要发送 "end" 标记? A: 告诉服务器音频发送完毕,触发 ASR 的最终识别,否则 ASR 会一直等待更多数据。
Q: 为什么要说 3-5 秒? A: 太短的音频(< 1 秒)ASR 可能无法识别,3-5 秒是比较合适的长度。
🎉 预期成果
优化完成后,语音通话应该能够:
- ✅ 用户说话 3-5 秒
- ✅ 客户端分片发送(3200 bytes/片,100ms 间隔)
- ✅ 服务器 ASR 识别成功
- ✅ LLM 生成回复
- ✅ TTS 合成语音
- ✅ 客户端播放音频
- ✅ 整个流程在 20-30 秒内完成
- ✅ 不再出现 "idle timeout" 错误
💡 下一步建议
如果基本功能正常,可以考虑:
- 实时流式录音: 使用
onFrameRecorded实现真正的实时传输 - 降低延迟: 优化 LLM 和 TTS 的响应速度
- 打断功能: 允许用户在 AI 说话时打断
- 多轮对话: 优化对话历史管理
- 情感识别: 根据用户语气调整回复风格
📞 需要帮助?
如果测试失败,请提供:
- 客户端完整日志
- 服务器日志
- 录音信息(大小、时长)
- 错误信息
优化完成时间: 2026-02-28
优化人员: Kiro AI Assistant
状态: ✅ 已完成,待测试