语音系统专家Skill voice-system-expert

Quetrex语音系统专家技能专注于Web语音交互架构的实现与维护,特别擅长OpenAI实时API集成、WebRTC音频流处理、浏览器原生回声消除(AEC)技术。该技能确保语音系统稳定运行,防止音频反馈循环,遵循行业最佳实践,适用于实时语音对话、智能语音助手、在线会议系统等场景。关键词:语音系统架构、WebRTC音频、回声消除、OpenAI实时API、语音交互、浏览器AEC、语音活动检测、音频流水线。

前端开发 0 次安装 0 次浏览 更新于 3/2/2026

名称:语音系统专家 描述:当处理Quetrex的语音界面、OpenAI实时API、WebRTC或回声消除时使用。了解Quetrex特定的语音架构决策和模式。关键 - 防止破坏正常工作的语音系统。 允许工具:读取

Quetrex语音系统专家

关键:首先阅读此内容

Quetrex的语音系统架构经过充分文档记录和实战测试。在对语音相关代码进行任何更改之前,您必须阅读:

  1. ADR-001-VOICE-ECHO-CANCELLATION.md(权威架构决策)
  2. docs/architecture/VOICE-SYSTEM.md(技术实现)
  3. docs/features/voice-interface.md(面向用户的功能)

位置: src/lib/openai-realtime.ts

核心架构决策

始终开启的麦克风 + 浏览器AEC

这是VOICE-SYSTEM.md中的决策4,也是ADR-001中记录的权威方法。

// ✅ 正确:始终开启的麦克风
const mediaStream = await navigator.mediaDevices.getUserMedia({
  audio: {
    echoCancellation: true,  // 关键 - 浏览器处理回声消除
    noiseSuppression: true,
    autoGainControl: true,
  },
})

// 麦克风轨道在整个对话期间保持启用状态
// 浏览器的原生AEC防止反馈循环
// 服务器端VAD(语音活动检测)处理轮次检测

工作原理

音频流水线

用户说话
    ↓
麦克风(始终启用,echoCancellation: true)
    ↓
WebRTC → OpenAI实时API
    ↓
服务器端VAD检测语音
    ↓
OpenAI处理并响应
    ↓
通过WebRTC的音频响应
    ↓
HTMLAudioElement播放(保持在浏览器流水线中)
    ↓
浏览器AEC比较麦克风输入 + 扬声器输出
    ↓
回声自动消除(无反馈循环)

为什么这有效

浏览器回声消除要求:

  1. 麦克风输入和扬声器输出都必须在浏览器的音频图中
  2. 音频必须流经浏览器的WebRTC堆栈
  3. 无需手动干预(浏览器处理)

这是行业标准:

  • ChatGPT语音模式
  • Google Meet
  • Zoom
  • Discord
  • Microsoft Teams

它们都使用始终开启的麦克风 + 浏览器AEC。

不要做这些事情

❌ 不要:切换麦克风轨道

// ❌ 错误 - 这会破坏回声消除
async function pauseRecording() {
  microphone.enabled = false // 不要这样做
}

async function resumeRecording() {
  microphone.enabled = true // 不要这样做
}

为什么失败:

  • 不是行业标准
  • 导致音频故障
  • 可能破坏回声消除
  • 增加人为延迟
  • 更复杂的状态管理
  • 没有实际好处

❌ 不要:将音频路由到浏览器外部

// ❌ 错误 - AudioWorklet旁路到原生音频
const workletNode = new AudioWorkletNode(audioContext, 'bypass-processor')
workletNode.port.postMessage({ cmd: 'route-to-native' })

为什么失败:

  • 破坏浏览器AEC(音频离开浏览器流水线)
  • 导致回声/反馈循环
  • 需要复杂的原生音频处理
  • 平台特定的实现
  • 已经尝试并失败(参见abandoned-approaches/)

❌ 不要:实现自定义回声消除

// ❌ 错误 - 自定义AEC实现
class CustomEchoCanceller {
  cancelEcho(input: AudioBuffer, output: AudioBuffer) {
    // 复杂的DSP代码...
  }
}

为什么失败:

  • 重复造轮子
  • 浏览器AEC经过数十亿用户实战测试
  • 正确实现极其复杂
  • 需要深厚的DSP知识
  • 性能问题
  • 需要平台特定的调优

❌ 不要:添加人为延迟

// ❌ 错误 - 用于回声预防的延迟
await new Promise(resolve => setTimeout(resolve, 500))
await playAudio()
await new Promise(resolve => setTimeout(resolve, 500))
resumeRecording()

为什么失败:

  • 不必要(浏览器AEC处理)
  • 降低用户体验
  • 增加延迟
  • 如果实现错误,仍然无法防止回声

您可以更改什么

✅ 可以:调整音频设置

// ✅ 可以调整这些设置
const constraints = {
  audio: {
    echoCancellation: true,      // 必须为true
    noiseSuppression: true,       // 可以调整
    autoGainControl: true,        // 可以调整
    sampleRate: 24000,            // 可以更改以提高质量
    channelCount: 1,              // 单声道适合语音
  },
}

✅ 可以:处理连接状态

// ✅ 可以管理连接生命周期
async function connectVoice() {
  // 设置WebRTC连接
  // 开始流式传输
  // 处理连接事件
}

async function disconnectVoice() {
  // 清理WebRTC连接
  // 停止流式传输
  // 释放麦克风
}

✅ 可以:添加UI反馈

// ✅ 可以添加视觉指示器
function onVoiceActivity(active: boolean) {
  if (active) {
    // 显示“正在聆听”指示器
    // 动画麦克风图标
  } else {
    // 显示“空闲”指示器
  }
}

✅ 可以:处理错误

// ✅ 可以改进错误处理
try {
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
} catch (error) {
  if (error.name === 'NotAllowedError') {
    // 显示权限请求UI
  } else if (error.name === 'NotFoundError') {
    // 显示“未找到麦克风”错误
  }
}

实现位置

主要文件: src/lib/openai-realtime.ts

关键函数:

  • setupMediaStream() - 使用正确的约束初始化麦克风
  • connectToOpenAI() - 建立WebRTC连接
  • handleAudioResponse() - 通过HTMLAudioElement播放AI响应

不要修改:

  • 麦克风启用/禁用逻辑(应保持始终开启)
  • 回声消除设置(必须为true)
  • 音频路由(必须保持在浏览器流水线中)

可以修改:

  • UI反馈和视觉指示器
  • 错误处理和用户消息
  • 连接重试逻辑
  • 音频质量设置(采样率等)

为什么选择此架构

来自ADR-001:

选项A:信任行业模式(已选择)

  • ✅ ChatGPT、Google Meet、Zoom、Discord使用
  • ✅ 浏览器供应商为此模式优化
  • ✅ 在所有平台上工作(macOS、Windows、Linux、移动设备)
  • ✅ 无需自定义实现
  • ✅ 经过验证的可靠性

已拒绝的选项:

  • ❌ 手动麦克风切换(不是行业标准)
  • ❌ AudioWorklet原生旁路(破坏AEC)
  • ❌ 自定义回声消除(重复造轮子)
  • ❌ 原生Rust WebRTC(2-4周工作,无好处)

平台上下文:Web应用程序

重要: Quetrex现在是一个纯Web应用程序,不是Tauri桌面应用程序。

这对语音的重要性:

  • 浏览器回声消除在所有浏览器中完美工作
  • 没有WKWebView限制(那是Tauri问题)
  • 通用兼容性(Chrome、Safari、Firefox、Edge)
  • 无需平台特定的音频处理
  • 直接工作™️

WKWebView问题(历史): Quetrex最初是Tauri桌面应用程序。在macOS上,Tauri使用WKWebView,它有一个错误:WebRTC音频播放不起作用。这迫使我们尝试变通方法(AudioWorklet旁路、原生音频路由),这些方法都破坏了回声消除。

解决方案: 转换为Web应用程序。现在回声消除在任何地方都完美工作。

测试语音更改

如果您必须修改语音代码:

  1. 在真实浏览器上测试(不仅仅是开发工具)
  2. 测试回声场景:
    • 调高扬声器音量
    • 开始语音对话
    • 验证无反馈循环/回声
  3. 跨平台测试:
    • Chrome(最常见)
    • Safari(macOS、iOS)
    • Firefox
    • Edge
  4. 测试边缘情况:
    • 网络连接不良
    • 麦克风权限被拒绝
    • 对话中断开连接

何时查阅文档

在进行任何语音更改之前,请阅读:

  1. docs/decisions/ADR-001-VOICE-ECHO-CANCELLATION.md
  2. docs/architecture/VOICE-SYSTEM.md
  3. docs/development/abandoned-approaches/

如果您看到提及:

  • Tauri → 忽略(Quetrex现在是Web应用程序)
  • WKWebView → 忽略(不再相关)
  • AudioWorklet旁路 → 不要实现(已经尝试,失败)
  • 手动麦克风切换 → 不要实现(不是行业标准)

总结

黄金法则: 信任浏览器回声消除。始终开启的麦克风 + echoCancellation: true + 音频在浏览器流水线中 = 完美的回声消除。

应该做:

  • 在整个对话期间保持麦克风启用
  • 使用 echoCancellation: true
  • 保持音频在浏览器中(HTMLAudioElement)
  • 让OpenAI实时API处理VAD
  • 信任行业模式

不应该做:

  • 切换麦克风轨道
  • 将音频路由到浏览器外部
  • 实现自定义回声消除
  • 添加人为延迟
  • 尝试“改进”已经有效的东西

如果有疑问: 阅读ADR-001和VOICE-SYSTEM.md。架构经过充分文档记录是有原因的。