如何使用socket.io发送MediaStream音频数据实现实时语音通话
实时语音通话功能优化实现方案
现有方案问题分析
- 第一版方案问题:
- 每2秒重复调用
getUserMedia申请麦克风权限,重复创建媒体流和录制实例,资源消耗高,还可能触发重复权限校验 - 2秒的大切片导致端到端延迟至少2s以上,多段音频拼接时容易出现帧错位、间隙,直接导致播放卡顿
- 每2秒重复调用
- 第二版方案问题:
- 使用了已废弃的
navigator.getUserMediaAPI,兼容性差,是直接报错的主要原因 - 提取的是Analyser节点的频域特征数据,不是可播放的原始音频编码数据,传输到对端后无法还原为语音,必然出现播放失败
- 用
requestAnimationFrame每秒发送60次数据,带宽占用极高,完全没有必要
- 使用了已废弃的
可行优化方案(基于Socket.IO传输)
发送端实现
核心逻辑:仅申请一次麦克风权限,复用媒体流,设置小切片实时发送
// 全局保存实例,避免重复创建 let mediaRecorder = null; let audioStream = null; // 仅初始化一次麦克风 async function initAudioCapture() { try { // 统一用标准API申请权限,开启音频预处理优化通话质量 audioStream = await navigator.mediaDevices.getUserMedia({ audio: { echoCancellation: true, noiseSuppression: true, autoGainControl: true } }); // 使用opus编码,适配语音场景,低延迟高压缩率 mediaRecorder = new MediaRecorder(audioStream, { mimeType: 'audio/webm;codecs=opus' }); // 每100ms输出一次切片,平衡延迟和带宽 mediaRecorder.ondataavailable = (e) => { if (e.data.size > 0) { socket.emit('liveAudioToServer', e.data); } }; mediaRecorder.start(100); // 传入timeslice参数,每100ms触发一次dataavailable } catch (err) { console.log('音频采集初始化失败', err); } } // 通话开始时调用一次即可 initAudioCapture();
接收端实现
核心逻辑:用MediaSource实时拼接音频片段,流式播放,避免拼接间隙
const audio = document.createElement('audio'); audio.autoplay = true; const mediaSource = new MediaSource(); audio.src = URL.createObjectURL(mediaSource); let sourceBuffer = null; // 缓存待播放的切片队列,避免网络波动导致的播放卡顿 const bufferQueue = []; mediaSource.addEventListener('sourceopen', () => { sourceBuffer = mediaSource.addSourceBuffer('audio/webm;codecs=opus'); sourceBuffer.mode = 'sequence'; // 缓存队列有数据就追加到缓冲区 sourceBuffer.addEventListener('updateend', () => { if (bufferQueue.length > 0 && !sourceBuffer.updating) { const chunk = bufferQueue.shift(); sourceBuffer.appendBuffer(chunk); } }); }); // 接收服务端转发的音频切片 socket.on('liveAudioFromServer', (chunk) => { const uint8Chunk = new Uint8Array(chunk); if (sourceBuffer && !sourceBuffer.updating) { sourceBuffer.appendBuffer(uint8Chunk); } else { bufferQueue.push(uint8Chunk); } });
额外优化建议
- 多人通话场景如果对延迟要求更高,优先使用WebRTC方案,可直接实现端到端或经SFU中转的实时音视频传输,不需要自行处理音频切片、编码、丢包补偿等逻辑,端到端延迟可控制在200ms以内
- 可根据网络抖动情况动态调整切片大小,网络差的时候适当增大切片,避免丢包导致卡顿
- 服务端仅需按房间ID做广播转发即可,不需要额外处理音频数据
内容的提问来源于stack exchange,提问作者sponge bobo
相关产品推荐
相关产品推荐

