254 lines
6.3 KiB
Markdown
254 lines
6.3 KiB
Markdown
|
|
# 语音通话 "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`
|
|||
|
|
|
|||
|
|
**修改内容**:
|
|||
|
|
```javascript
|
|||
|
|
// 优化前
|
|||
|
|
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`
|
|||
|
|
|
|||
|
|
**修改内容**:
|
|||
|
|
```bash
|
|||
|
|
# 新增配置
|
|||
|
|
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 服务器才能生效:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 1. 停止旧进程
|
|||
|
|
pkill -f "uvicorn.*main:app"
|
|||
|
|
|
|||
|
|
# 2. 启动新进程
|
|||
|
|
cd /path/to/lover
|
|||
|
|
uvicorn main:app --host 0.0.0.0 --port 30101 --reload
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 客户端重新编译
|
|||
|
|
|
|||
|
|
在 HBuilderX 中重新运行项目到手机或模拟器。
|
|||
|
|
|
|||
|
|
## 📱 测试指南
|
|||
|
|
|
|||
|
|
### 测试步骤
|
|||
|
|
1. 打开 App,进入语音通话页面
|
|||
|
|
2. 按住"按住说话"按钮
|
|||
|
|
3. **清晰地说 3-5 秒的话**(重要!)
|
|||
|
|
4. 松开按钮
|
|||
|
|
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: [识别的文字]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📚 相关文档
|
|||
|
|
|
|||
|
|
已创建的文档:
|
|||
|
|
1. `最新优化说明.md` - 详细的优化说明
|
|||
|
|
2. `测试检查清单.md` - 测试步骤和检查项
|
|||
|
|
3. `语音通话完整流程图.md` - 可视化流程图
|
|||
|
|
4. `官方文档分析和正确实现.md` - 技术分析
|
|||
|
|
5. `问题定位总结.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"
|
|||
|
|
|
|||
|
|
1. **检查服务器是否重启**
|
|||
|
|
```bash
|
|||
|
|
ps aux | grep uvicorn
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **检查配置是否生效**
|
|||
|
|
```bash
|
|||
|
|
cat lover/.env | grep VOICE_CALL_IDLE_TIMEOUT
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
3. **检查录音时长**
|
|||
|
|
- 客户端日志中的 "总大小" 应该 > 96000 bytes(3 秒)
|
|||
|
|
|
|||
|
|
4. **检查服务器日志**
|
|||
|
|
```bash
|
|||
|
|
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 秒是比较合适的长度。
|
|||
|
|
|
|||
|
|
## 🎉 预期成果
|
|||
|
|
|
|||
|
|
优化完成后,语音通话应该能够:
|
|||
|
|
|
|||
|
|
1. ✅ 用户说话 3-5 秒
|
|||
|
|
2. ✅ 客户端分片发送(3200 bytes/片,100ms 间隔)
|
|||
|
|
3. ✅ 服务器 ASR 识别成功
|
|||
|
|
4. ✅ LLM 生成回复
|
|||
|
|
5. ✅ TTS 合成语音
|
|||
|
|
6. ✅ 客户端播放音频
|
|||
|
|
7. ✅ 整个流程在 20-30 秒内完成
|
|||
|
|
8. ✅ 不再出现 "idle timeout" 错误
|
|||
|
|
|
|||
|
|
## 💡 下一步建议
|
|||
|
|
|
|||
|
|
如果基本功能正常,可以考虑:
|
|||
|
|
|
|||
|
|
1. **实时流式录音**: 使用 `onFrameRecorded` 实现真正的实时传输
|
|||
|
|
2. **降低延迟**: 优化 LLM 和 TTS 的响应速度
|
|||
|
|
3. **打断功能**: 允许用户在 AI 说话时打断
|
|||
|
|
4. **多轮对话**: 优化对话历史管理
|
|||
|
|
5. **情感识别**: 根据用户语气调整回复风格
|
|||
|
|
|
|||
|
|
## 📞 需要帮助?
|
|||
|
|
|
|||
|
|
如果测试失败,请提供:
|
|||
|
|
1. 客户端完整日志
|
|||
|
|
2. 服务器日志
|
|||
|
|
3. 录音信息(大小、时长)
|
|||
|
|
4. 错误信息
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**优化完成时间**: 2026-02-28
|
|||
|
|
**优化人员**: Kiro AI Assistant
|
|||
|
|
**状态**: ✅ 已完成,待测试
|