一、项目背景

我们正在开发一个面向老年用户的健康管理系统,语音通话是核心功能之一。系统包含两个前端项目:fronted(微信小程序)和 fronted-user-web(Vue3 Web 应用)。两个平台需要实现相同的语音通话体验,但底层技术栈完全不同。

本文从两个项目的实现对比出发,分析跨平台语音功能开发的异同。

二、整体架构对比

微信小程序语音通话

小程序使用微信原生 API 实现录音和播放。RecorderManager 负责录音,InnerAudioContext 负责播放。网络通信使用微信的 WebSocket API(wx.connectSocket)。语音识别和 AI 对话依赖后端服务。

Vue Web 语音通话

Web 端使用 Web Audio API 进行音频处理。getUserMedia 获取麦克风权限,AudioContext 管理音频节点。网络通信使用标准 WebSocket。同样依赖后端进行语音识别和 AI 对话。

共同点是:两个平台都采用前后端分离架构,录音在客户端完成,音频数据发送到后端处理。

三、录音实现对比

微信小程序的录音实现相对简单,因为微信封装了底层细节:

const recorderManager = wx.getRecorderManager()

recorderManager.start({

  format: 'pcm',

  sampleRate: 16000,

  numberOfChannels: 1

})

recorderManager.onFrameRecorded((res) => {

  // 实时发送音频帧到后端

  socket.send({ event: 'audio_chunk', audioBase64: ... })

})

Web 端的实现则复杂得多,需要手动处理音频链路:

1. 通过 getUserMedia 获取 MediaStream

2. 创建 AudioContext 和 MediaStreamSource

3. 使用 AudioWorkletNode 处理 PCM 数据

4. 手动将 Float32 转换为 Int16

5. 降采样到 16kHz

四、AudioWorklet 取代 ScriptProcessorNode

Web 端最初使用了已被废弃的 ScriptProcessorNode,控制台会打印 Deprecation 警告。迁移到 AudioWorklet 后,音频处理移至独立线程,性能更好且没有废弃风险。

AudioWorklet 需要一个独立的处理器文件(pcm-processor.js),在主线程通过 audioWorklet.addModule 加载。处理器在 process 方法中接收音频数据,完成降采样和格式转换后通过 postMessage 传回主线程。

class PcmProcessor extends AudioWorkletProcessor {

  process(inputs, outputs, parameters) {

    const input = inputs[0]

    if (!input || !input[0]) return true

    // 降采样到 16kHz

    // Float32 转 Int16

    this.port.postMessage({ pcm: pcm.buffer }, [pcm.buffer])

    return true

  }

}

五、VAD 语音检测的差异

小程序端可以直接使用录音的音量回调判断用户是否在说话,而 Web 端需要自行实现 VAD。

Web 端通过 AnalyserNode 分析频域数据,计算平均能量值来判断语音活动。这个过程中遇到的关键问题如下:

1. requestAnimationFrame 自调度循环必须在条件判断之前调用,否则 VAD 循环永远不会启动

2. 阈值需要根据实际环境调整,静默能量值在不同设备上差异很大

3. 静默超时时间影响用户体验,从 1.5 秒改为 0.5 秒后响应更及时

六、通信方式对比

小程序使用 wx.connectSocket 建立 WebSocket 连接,Web 端使用标准 WebSocket API。两个平台都需要处理重连、心跳、异常恢复等逻辑。

在开发模式下,Web 端还需要处理 Vite 代理的问题。后端 WebSocket 运行在 9527 端口,而 Vite 开发服务器在 5173 端口。需要在 vite.config.js 中配置 ws: true 来启用 WebSocket 代理。

七、TTS 播报的降级策略

小程序端直接使用微信的 InnerAudioContext 播放后端返回的音频数据。Web 端除了播放后端音频外,还实现了浏览器端 TTS 降级方案。

当后端 TTS 服务不可用时,Web 端自动切换到 Web Speech API 进行文字播报。具体策略如下:

1. 收到 AI 回答文字后立即启动浏览器播报

2. 如果随后收到后端 TTS 音频,取消浏览器播报,使用后端音频

3. 浏览器播报按句子分段,句间插入自然停顿

八、技术理解

Web Audio API 的设计思路是音频处理管道化。开发者可以将不同的音频节点像管道一样连接起来,每个节点负责一个特定的处理任务。这种设计使音频处理逻辑清晰、可组合。

AudioWorklet 相比 ScriptProcessorNode 的优势在于运行在独立线程。音频数据处理是计算密集型任务,如果在主线程运行会导致界面卡顿。AudioWorklet 将处理逻辑移到音频渲染线程,既保证了性能,又避免了被废弃的风险。

VAD 的阈值设定需要经验。AnalyserNode 的 getByteFrequencyData 返回 0-255 的值,理论上阈值设在 10-20 之间比较合理。但实际测试发现,不同麦克风、不同环境下的基线值差异很大。建议的做法是在用户开始说话前采集几秒的环境噪声,动态计算阈值。

九、技术进度

当前功能完成状态如下:

录音采集:已完成

支持 getUserMedia 获取音频流,AudioWorklet 处理 PCM 数据,降采样到 16kHz

VAD 语音检测:已完成

基于 AnalyserNode 频域分析,阈值可配置,支持 0.5s 静默超时判定

WebSocket 实时通信:已完成

支持快速模式的实时语音对话,自动重连和心跳保持

浏览器 TTS 播报:已完成

Web Speech API 实现,支持句子分段、语音优选、语速调节

打断机制:已完成

用户说话时自动停止 AI 播报,快速模式同时通知后端

专家模式音频上传:已完成

PCM 转 WAV 后上传,后端转写和 AI 对话

自动降级:已完成

快速模式不可用时自动切换到专家模式,TTS 失败时降级到浏览器播报

后续计划:自适应 VAD 阈值、噪声环境优化、更丰富的声音提示。

十、总结

跨平台语音功能开发中,微信小程序因其封装完善的 API,实现相对简单直接。Web 端虽然 API 更底层、实现更复杂,但带来了更高的灵活性,可以实现自定义的音频处理逻辑。

两个平台的核心差异不在于功能,而在于 API 的抽象层级。理解这些差异有助于在不同平台间复用架构设计,同时针对各平台特点进行针对性优化。

更多推荐