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

固定发送端场景下,WebRTC接收端(用户B)连接音频流步骤问询

固定发送端的WebRTC音频单向收发实现步骤

一、核心简化思路

因为发送端(用户A)固定,不需要复杂的呼叫协商逻辑,只需把发送端的SDP Offer和ICE候选持久化,接收端(用户B)直接拉取并应答即可。以下是分角色的具体实现步骤:


二、发送端(用户A)操作流程

  1. 获取麦克风媒体流
    请求用户授权麦克风权限,获取音频流:

    const localStream = await navigator.mediaDevices.getUserMedia({ audio: true });
    
  2. 初始化RTCPeerConnection
    配置STUN服务器(用于NAT穿透),创建连接实例:

    const pcConfig = {
      iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
    };
    const senderPc = new RTCPeerConnection(pcConfig);
    
  3. 添加音频轨道到连接
    将麦克风流的音频轨道加入PeerConnection:

    localStream.getAudioTracks().forEach(track => {
      senderPc.addTrack(track, localStream);
    });
    
  4. 生成并存储Offer SDP
    创建Offer并设置本地描述,同时收集ICE候选:

    let storedOffer = null;
    let iceCandidates = [];
    
    // 收集ICE候选
    senderPc.onicecandidate = (e) => {
      if (e.candidate) {
        iceCandidates.push(e.candidate);
      } else {
        // 候选收集完成,将Offer和候选存入信令存储(比如后端接口)
        fetch('/api/save-sender-data', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            offer: storedOffer,
            iceCandidates
          })
        });
      }
    };
    
    // 创建Offer
    const offer = await senderPc.createOffer();
    await senderPc.setLocalDescription(offer);
    storedOffer = offer;
    
  5. 监听接收端的Answer
    轮询或通过WebSocket接收接收端的Answer SDP,设置为远程描述:

    setInterval(async () => {
      const res = await fetch('/api/get-receiver-answer');
      const answer = await res.json();
      if (answer && !senderPc.currentRemoteDescription) {
        await senderPc.setRemoteDescription(answer);
      }
    }, 1000);
    

三、接收端(用户B)操作流程

  1. 初始化RTCPeerConnection
    同样配置STUN服务器,创建连接实例:

    const pcConfig = {
      iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
    };
    const receiverPc = new RTCPeerConnection(pcConfig);
    
  2. 监听音频流并播放
    收到发送端的音频轨道时,创建Audio元素播放:

    receiverPc.ontrack = (e) => {
      const audioEl = document.createElement('audio');
      audioEl.srcObject = e.streams[0];
      audioEl.play();
      document.body.appendChild(audioEl);
    };
    
  3. 拉取发送端的Offer和ICE候选
    从信令存储获取发送端的预存数据:

    const res = await fetch('/api/get-sender-data');
    const { offer, iceCandidates } = await res.json();
    
  4. 生成并发送Answer SDP
    设置远程描述为发送端的Offer,创建Answer并发送到信令存储:

    await receiverPc.setRemoteDescription(offer);
    const answer = await receiverPc.createAnswer();
    await receiverPc.setLocalDescription(answer);
    
    // 发送Answer到后端
    fetch('/api/save-receiver-answer', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(answer)
    });
    
  5. 添加发送端的ICE候选
    将收集到的ICE候选逐个添加到本地连接:

    for (const candidate of iceCandidates) {
      await receiverPc.addIceCandidate(candidate);
    }
    

四、轻量信令后端(Node.js + Express示例)

用简单接口实现数据存储,替代复杂的Firestore逻辑:

const express = require('express');
const app = express();
app.use(express.json());

// 存储发送端数据
let senderData = null;
// 存储接收端Answer
let receiverAnswer = null;

app.post('/api/save-sender-data', (req, res) => {
  senderData = req.body;
  res.sendStatus(200);
});

app.get('/api/get-sender-data', (req, res) => {
  res.json(senderData);
});

app.post('/api/save-receiver-answer', (req, res) => {
  receiverAnswer = req.body;
  res.sendStatus(200);
});

app.get('/api/get-receiver-answer', (req, res) => {
  res.json(receiverAnswer);
});

app.listen(3000, () => console.log('信令服务器运行在3000端口'));

五、关键注意事项

  • HTTPS环境:getUserMedia仅在HTTPS或localhost环境下生效,部署时需配置SSL。
  • ICE候选完整性:必须等发送端的ICE候选全部收集完成后,再让接收端拉取,否则可能导致连接失败。
  • 浏览器兼容性:主流浏览器(Chrome、Firefox、Edge)均支持标准WebRTC API,无需前缀。
  • 测试顺序:先启动发送端并完成授权、Offer存储,再启动接收端拉取数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 23:57:27