You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现浏览器WebRTC与Node.js服务器作为对等端的音频流传输

嘿,刚好之前折腾过把Node.js作为WebRTC对等端和浏览器做音频通话的需求,你已经有浏览器自连的基础了,其实核心就是把其中一个浏览器端换成Node.js就行——不过Node本身没有浏览器自带的WebRTC API,得借助第三方库来实现。下面给你一步步拆解具体操作:

1. 给Node.js端补上WebRTC能力

Node.js原生没有RTCPeerConnection、MediaStream这些WebRTC核心API,我们需要用第三方库来模拟浏览器的WebRTC环境,最推荐的是wrtc——它完全实现了标准的浏览器WebRTC API,这样你原来写的浏览器端代码改动极小。

首先安装依赖:

npm install wrtc ws

(顺带装了ws,用来做信令的WebSocket通道,你原来浏览器自连应该也用到了类似的信令机制)

2. 改造信令逻辑:让Node同时做信令服务器+对等端

WebRTC必须通过信令交换SDP(会话描述)和ICE候选(网络地址信息),所以Node.js要同时扮演两个角色:接收浏览器信令的服务器,以及和浏览器对等的WebRTC客户端。

核心流程梳理

  • 浏览器和Node建立WebSocket连接,作为信令通道
  • 浏览器获取本地音频流,创建Offer并通过WebSocket发给Node
  • Node接收Offer后设置为自己的远程描述,生成Answer发回浏览器
  • 双方各自收集ICE候选,通过信令通道发给对方并添加到PeerConnection
  • 连接建立后,双方就能交换音频流了
3. 核心代码示例

Node.js端代码(信令+WebRTC对等端)

const { RTCPeerConnection, MediaRecorder } = require('wrtc');
const WebSocket = require('ws');

// 启动WebSocket信令服务器
const wss = new WebSocket.Server({ port: 8080 });
console.log('信令服务器启动在ws://localhost:8080');

wss.on('connection', async (ws) => {
  // 创建Node端的PeerConnection实例,配置STUN服务器(用于NAT穿透)
  const pc = new RTCPeerConnection({
    iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
  });

  // 监听ICE候选,一旦生成就发给浏览器
  pc.onicecandidate = (event) => {
    if (event.candidate) {
      ws.send(JSON.stringify({
        type: 'iceCandidate',
        candidate: event.candidate
      }));
    }
  };

  // 监听浏览器发来的信令消息
  ws.on('message', async (data) => {
    const message = JSON.parse(data);
    switch (message.type) {
      case 'offer':
        // 接收浏览器的Offer,设置为远程描述
        await pc.setRemoteDescription(new RTCPeerConnection.RTCSessionDescription(message.offer));
        // 生成Answer并发送给浏览器
        const answer = await pc.createAnswer();
        await pc.setLocalDescription(answer);
        ws.send(JSON.stringify({
          type: 'answer',
          answer: answer
        }));
        break;
      case 'iceCandidate':
        // 添加浏览器发来的ICE候选
        await pc.addIceCandidate(new RTCPeerConnection.RTCIceCandidate(message.candidate));
        break;
    }
  });

  // 接收浏览器发来的音频流,这里可以选择录制或者处理
  pc.ontrack = (event) => {
    const remoteAudioStream = event.streams[0];
    console.log('收到浏览器的音频流');
    
    // 示例:把音频流录制为文件
    const recorder = new MediaRecorder(remoteAudioStream);
    recorder.ondataavailable = (e) => {
      require('fs').writeFileSync('browser-audio.wav', e.data);
      console.log('音频已保存到browser-audio.wav');
    };
    recorder.start();
  };

  // 错误处理
  pc.onerror = (err) => {
    console.error('PeerConnection错误:', err);
  };
});

浏览器端代码(改动自你原有的自连代码)

// 连接Node的WebSocket信令服务器
const ws = new WebSocket('ws://localhost:8080');
const pc = new RTCPeerConnection({
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
});

// 获取本地音频流并添加到PeerConnection
navigator.mediaDevices.getUserMedia({ audio: true })
  .then((localStream) => {
    // 本地预览(可选)
    document.getElementById('local-audio').srcObject = localStream;
    // 添加本地音频轨道到PeerConnection
    localStream.getTracks().forEach(track => pc.addTrack(track, localStream));

    // 创建Offer并发送给Node服务器
    pc.createOffer()
      .then(offer => pc.setLocalDescription(offer))
      .then(() => {
        ws.send(JSON.stringify({
          type: 'offer',
          offer: pc.localDescription
        }));
      });
  });

// 发送ICE候选到Node服务器
pc.onicecandidate = (event) => {
  if (event.candidate) {
    ws.send(JSON.stringify({
      type: 'iceCandidate',
      candidate: event.candidate
    }));
  }
};

// 接收Node服务器的信令消息
ws.onmessage = async (event) => {
  const message = JSON.parse(event.data);
  switch (message.type) {
    case 'answer':
      await pc.setRemoteDescription(new RTCSessionDescription(message.answer));
      break;
    case 'iceCandidate':
      await pc.addIceCandidate(new RTCIceCandidate(message.candidate));
      break;
  }
};

// 接收Node服务器发来的音频流并播放
pc.ontrack = (event) => {
  const remoteStream = event.streams[0];
  document.getElementById('remote-audio').srcObject = remoteStream;
};
4. 关键注意事项
  • 公网部署需配置TURN服务器:如果你的服务要部署到公网,仅靠STUN可能无法穿透复杂NAT,需要自己搭建coturn服务器或者使用第三方TURN服务,在PeerConnection的iceServers里添加TURN配置。
  • 安全问题:线上环境一定要用wss://(WebSocket over HTTPS),避免信令被窃听,同时确保服务器的HTTPS证书有效。
  • 音频编码兼容性:默认的opus编码基本能兼容浏览器和Node端,但如果遇到音频无法播放的情况,可以检查双方支持的编码集,手动指定编码。
  • 错误处理:一定要给WebSocket和PeerConnection添加onerror监听,避免因为网络波动或配置错误导致程序崩溃。

内容的提问来源于stack exchange,提问作者moimoi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:35:24