Node.js客户端-服务端WebRTC P2P模式下媒体流传输实现咨询
实现客户端-服务端WebRTC媒体流传输方案
以下方案基于你当前使用的simple-peer对等连接库、Node端wrtcWebRTC适配包实现,包含流上传、合流、下发全流程逻辑:
一、服务端(backend/server.js)改造
首先需要完成客户端流接收、多路音频合流、混合流下发三个核心逻辑,修改后代码如下:
const Peer = require('simple-peer'); const wrtc = require('wrtc'); const AudioMixer = require('audio-mixer'); // 需提前npm安装,用于多音频流合并 // 全局存储所有客户端连接实例、音频轨道 const allConnectedPeers = new Map(); const clientAudioTracks = new Map(); // 每个新客户端接入时初始化对应peer实例 function createClientPeer(clientId) { const clientPeer = new Peer({ initiator: true, wrtc }); clientPeer.on('connect', () => { allConnectedPeers.set(clientId, clientPeer); console.log('客户端连接成功:', clientId); }); // 监听客户端上传的音频流 clientPeer.on('stream', (clientStream) => { const audioTrack = clientStream.getAudioTracks()[0]; clientAudioTracks.set(clientId, audioTrack); // 触发合流后推送给所有在线客户端 broadcastMixedStream(); }); // 客户端断开时清理资源 clientPeer.on('close', () => { allConnectedPeers.delete(clientId); clientAudioTracks.delete(clientId); broadcastMixedStream(); }); clientPeer.on('error', (err) => console.error('连接错误:', err)); return clientPeer; } // 多路音频合并为单流+全量下发 function broadcastMixedStream() { const trackList = Array.from(clientAudioTracks.values()); if (trackList.length === 0) return; // 初始化混音器,输出单路音频流 const mixer = new AudioMixer({ channels: 2, sampleRate: 48000, bitDepth: 16 }); trackList.forEach(track => { const input = mixer.input(); // 将音频轨道数据写入混音器输入 track.on('data', (chunk) => input.write(chunk)); }); // 生成混合后的单路音频流 const mixedStream = new wrtc.MediaStream(); const mixedTrack = mixer.output().createTrack(); mixedStream.addTrack(mixedTrack); // 推送给所有在线客户端 allConnectedPeers.forEach(peer => { // 先移除旧的混合流避免重复 if (peer._streams.length) peer.removeStream(peer._streams[0]); peer.addStream(mixedStream); }); }
注意:如果不需要专业混音效果,也可以直接把所有音频轨加入同一个MediaStream下发,但客户端会同时解码多轨,性能消耗更高。
二、客户端(frontend/index.js)改造
需要补充本地音频采集、流上传、信令交互三个逻辑,修改后代码如下:
import Peer from 'simple-peer'; // 初始化信令WebSocket(需自行搭建简单WebSocket服务交换SDP/ICE候选) const ws = new WebSocket('ws://你的服务端地址/ws'); // 获取本地麦克风音频流 async function getLocalAudio() { return await navigator.mediaDevices.getUserMedia({ audio: true, video: false }); } // 初始化与服务端的WebRTC连接 async function initRTCConnection() { const localStream = await getLocalAudio(); const serverPeer = new Peer({ initiator: false }); // 把本地音频流推送给服务端 serverPeer.addStream(localStream); // 信令交换:本地生成SDP/ICE时发送给服务端 serverPeer.on('signal', (data) => { ws.send(JSON.stringify({ type: 'signal', payload: data })); }); // 信令交换:接收服务端发过来的SDP/ICE完成握手 ws.onmessage = (msg) => { const { type, payload } = JSON.parse(msg.data); if (type === 'signal') serverPeer.signal(payload); }; // 接收服务端下发的混合流并播放 serverPeer.on('stream', async (stream) => { const audioEl = document.createElement('audio'); audioEl.autoplay = true; if ('srcObject' in audioEl) { audioEl.srcObject = stream; } else { audioEl.src = window.URL.createObjectURL(stream); } document.body.appendChild(audioEl); // 兼容浏览器自动播放限制,建议在用户点击事件回调中执行该初始化逻辑 try { await audioEl.play(); } catch (e) { console.warn('自动播放失败,请点击页面任意位置触发播放', e); } }); serverPeer.on('connect', () => console.log('与服务端RTC连接成功')); serverPeer.on('error', (err) => console.error('连接错误:', err)); }
三、必填补充说明
- 信令服务是WebRTC连接的前置条件,必须通过WebSocket/HTTP传递两端的
signal事件数据,否则无法完成握手建立连接 - 若需要支持多人语音,混音逻辑建议做回声消除、噪声抑制处理,可引入
webrtc-audio-processing类库实现 - 服务端部署时需要开放UDP端口,或者配置STUN/TURN服务器解决跨网穿透问题
内容的提问来源于stack exchange,提问作者ADAMJR
相关产品推荐
相关产品推荐

