Ai_GirlFriend/xuniYou/NO_VALID_AUDIO_ERROR问题修复.md
2026-02-28 18:41:16 +08:00

251 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# NO_VALID_AUDIO_ERROR 问题修复
## 🎯 问题描述
服务器日志显示:
```
2026-02-28 18:24:53.660 - voice_call - INFO - ASR connection opened
2026-02-28 18:25:16.706 - voice_call - ERROR - ASR error: NO_VALID_AUDIO_ERROR
```
阿里云 ASR 报错:`NO_VALID_AUDIO_ERROR` - 音频数据无效
## 🔍 根本原因
### 问题代码
```javascript
fs.readFile({
filePath: res.tempFilePath,
encoding: 'binary', // ❌ 错误!这会返回字符串,不是 ArrayBuffer
success: (fileRes) => {
this.sendAudioInChunks(fileRes.data) // fileRes.data 是字符串!
}
})
```
### 为什么会出错?
1. **`encoding: 'binary'` 返回的是字符串**
- uni-app 的 `readFile` 指定 encoding 后返回字符串
- 不是 ArrayBuffer
2. **字符串的 `slice()` 方法返回的还是字符串**
- `audioData.slice(offset, end)` 返回字符串片段
- 不是二进制数据
3. **WebSocket 发送字符串时会被当作文本消息**
- 服务器收到的不是二进制音频数据
- 而是文本字符串
- ASR 无法识别,报错 `NO_VALID_AUDIO_ERROR`
## ✅ 修复方案
### 修复后的代码
```javascript
fs.readFile({
filePath: res.tempFilePath,
// ✅ 不指定 encoding返回 ArrayBuffer
success: (fileRes) => {
// 验证数据类型
if (!(fileRes.data instanceof ArrayBuffer)) {
console.error('❌ 数据不是 ArrayBuffer')
return
}
this.sendAudioInChunks(fileRes.data) // fileRes.data 是 ArrayBuffer ✅
}
})
```
### sendAudioInChunks 也增加了验证
```javascript
async sendAudioInChunks(audioData) {
// 确保 audioData 是 ArrayBuffer
if (!(audioData instanceof ArrayBuffer)) {
console.error('❌ audioData 不是 ArrayBuffer')
return
}
const totalSize = audioData.byteLength // 使用 byteLength
// ArrayBuffer.slice() 返回新的 ArrayBuffer
const chunk = audioData.slice(offset, end) // ✅ 正确的二进制切片
// WebSocket 发送 ArrayBuffer
this.socketTask.send({
data: chunk // ✅ 发送二进制数据
})
}
```
## 📊 数据类型对比
### 错误的方式encoding: 'binary'
```javascript
typeof fileRes.data // "string"
fileRes.data instanceof ArrayBuffer // false
fileRes.data.length // 字符串长度(可能不等于字节数)
fileRes.data.slice(0, 10) // 返回字符串片段
```
### 正确的方式(不指定 encoding
```javascript
typeof fileRes.data // "object"
fileRes.data instanceof ArrayBuffer // true
fileRes.data.byteLength // 字节数
fileRes.data.slice(0, 10) // 返回 ArrayBuffer 片段
```
## 🔧 如何测试
### 1. 重新编译客户端
在 HBuilderX 中重新运行项目到手机/模拟器
### 2. 测试步骤
1. 打开 App进入语音通话页面
2. 按住"按住说话"按钮
3. 说话 3-5 秒
4. 松开按钮
5. 观察日志
### 3. 预期日志
#### 客户端日志
```
✅ 文件读取成功
📊 数据类型: object
📊 是否为 ArrayBuffer: true
📊 数据大小: 160000 bytes
📦 开始分片发送(官方推荐参数)
📊 总大小: 160000 bytes
📊 预计录音时长: 5.00 秒
📤 发送第 1 片,大小: 3200 bytes
✅ 第 1 片发送成功
...
```
#### 服务器日志
```
✅ 应该看到:
ASR connection opened
ASR event end=False sentence=...
ASR event end=True sentence=[识别的文字]
Handle sentence: [识别的文字]
❌ 不应该再看到:
ASR error: NO_VALID_AUDIO_ERROR
```
## 📚 技术要点
### uni-app readFile 的 encoding 参数
| encoding 值 | 返回类型 | 用途 |
|------------|---------|------|
| 不指定 | ArrayBuffer | 二进制文件(音频、图片、视频) |
| 'utf8' | String | 文本文件 |
| 'base64' | String | Base64 编码 |
| 'binary' | String | ❌ 不要用于音频!返回字符串 |
### WebSocket send() 方法
```javascript
// 发送文本
websocket.send({ data: "hello" }) // 文本消息
// 发送二进制
websocket.send({ data: arrayBuffer }) // 二进制消息
```
服务器端会根据数据类型自动判断:
- 字符串 → `msg["text"]`
- ArrayBuffer → `msg["bytes"]`
## 🎓 经验总结
### 关键教训
1. **不要对二进制文件使用 encoding 参数**
- 音频、图片、视频等二进制文件
- 不指定 encoding让它返回 ArrayBuffer
2. **验证数据类型**
- 使用 `instanceof ArrayBuffer` 验证
- 使用 `byteLength` 而不是 `length`
3. **理解 WebSocket 的数据类型**
- 字符串和二进制数据的处理方式不同
- 服务器端会根据类型分别处理
### 最佳实践
```javascript
// ✅ 读取二进制文件的正确方式
fs.readFile({
filePath: path,
// 不指定 encoding
success: (res) => {
if (res.data instanceof ArrayBuffer) {
// 处理二进制数据
}
}
})
// ✅ 读取文本文件的正确方式
fs.readFile({
filePath: path,
encoding: 'utf8',
success: (res) => {
if (typeof res.data === 'string') {
// 处理文本数据
}
}
})
```
## 🎉 预期结果
修复后,应该能够:
1. ✅ 正确读取 PCM 音频文件为 ArrayBuffer
2. ✅ 正确切片 ArrayBuffer
3. ✅ 正确发送二进制数据到服务器
4. ✅ 服务器 ASR 正确识别音频
5. ✅ 不再出现 `NO_VALID_AUDIO_ERROR` 错误
6. ✅ 完整的对话流程ASR → LLM → TTS
## 📞 如果还有问题
如果修复后还是出现 `NO_VALID_AUDIO_ERROR`,可能的原因:
1. **音频格式不对**
- 确认录音格式为 PCM
- 确认采样率为 16000Hz
- 确认单声道
2. **音频太短**
- 至少录音 3 秒
- 查看日志中的 "预计录音时长"
3. **音频质量差**
- 在安静环境测试
- 清晰发音
- 避免背景噪音
---
**修复时间**: 2026-02-28
**问题**: NO_VALID_AUDIO_ERROR
**原因**: 使用 `encoding: 'binary'` 导致发送字符串而不是二进制数据
**解决**: 不指定 encoding让 readFile 返回 ArrayBuffer
**状态**: ✅ 已修复,待测试