WebRTC技术解析

WebRTC技术解析

一个无需插件、开箱即用的 P2P 音视频传输方案

什么是 WebRTC

WebRTC(Web Real-Time Communication)是 Google 开源的一项实时通信技术,直接内置于浏览器,无需安装任何插件或第三方软件,就能实现浏览器之间的音视频通话、数据传输和屏幕共享。

核心指标 :端到端延迟可控制在 200ms 以内 ,相比传统基于服务器的轮询方案延迟降低 90% ,且服务器带宽成本可减少 70% 以上(因为媒体流不经过服务器中转)。

解决了什么问题

传统网页实现视频通话需要:

  • 浏览器插件(Flash、Silverlight)→ 用户需手动安装,已淘汰

  • RTMP + Flash 流媒体服务器 → 延迟高、维护复杂

  • Socket.io + 服务端转发 → 服务器压力大,无法承载大规模并发

WebRTC 的核心突破:

  1. NAT 穿透 :通过 ICE(交互式连接建立)协议自动尝试 STUN/TURN 服务器,成功率可达 95% 以上

  2. 端到端加密:基于 DTLS 和 SRTP,媒体流传输过程全程加密

  3. 自适应码率:根据网络状况动态调整视频分辨率、帧率和码率,弱网下仍能保持通话

  4. 直接 P2P 传输 :媒体流不经过服务器,降低服务端带宽消耗 80% 以上

最简单的使用流程

WebRTC 连接建立需要信令服务器 (可用 Socket.io 实现)来交换连接信息,但实际媒体流是 P2P 的。

1. 获取本地媒体流

javascript 复制代码
// 获取摄像头和麦克风
const localStream = await navigator.mediaDevices.getUserMedia({
  video: true,
  audio: true
});
// 将流绑定到 video 元素
document.getElementById('localVideo').srcObject = localStream;

2. 创建 RTCPeerConnection 并添加流

javascript 复制代码
// 配置 STUN 服务器(用于 NAT 穿透)
const configuration = {
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
};
const peerConnection = new RTCPeerConnection(configuration);
// 将本地流的所有 track 添加到连接中
localStream.getTracks().forEach(track => {
  peerConnection.addTrack(track, localStream);
});
// 监听远程流并播放
peerConnection.ontrack = (event) => {
  document.getElementById('remoteVideo').srcObject = event.streams[0];
};

3. 创建 Offer 并交换 SDP

发起方(Caller)

javascript 复制代码
// 创建 offer(包含本地媒体能力描述)
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);
// 通过信令服务器发送 offer 给对端
signalingSocket.emit('offer', { offer });

接收方(Callee)

javascript 复制代码
// 收到 offer 后设置远程描述,并创建 answer
await peerConnection.setRemoteDescription(offer);
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);
// 发送 answer 回对端
signalingSocket.emit('answer', { answer });

发起方收到 answer

javascript 复制代码
await peerConnection.setRemoteDescription(answer);
// 此时连接建立完成,ontrack 会触发

4. ICE 候选交换

连接过程中,浏览器会自动收集 ICE 候选(即可能的网络路径),双方需互相交换:

javascript

javascript 复制代码
// 监听本地 ICE 候选
peerConnection.onicecandidate = (event) => {
  if (event.candidate) {
    signalingSocket.emit('ice-candidate', { candidate: event.candidate });
  }
};
// 收到对端候选时添加
signalingSocket.on('ice-candidate', async ({ candidate }) => {
  await peerConnection.addIceCandidate(candidate);
});

完整的最小 Demo(配合 Socket.io 信令)

服务端(server.js)

javascript 复制代码
const io = require('socket.io')(3000);
io.on('connection', (socket) => {
  socket.on('offer', (data) => socket.broadcast.emit('offer', data));
  socket.on('answer', (data) => socket.broadcast.emit('answer', data));
  socket.on('ice-candidate', (data) => socket.broadcast.emit('ice-candidate', data));
});

客户端核心代码(省略 HTML 元素绑定)

javascript 复制代码
// 统一封装信令处理
const socket = io('http://localhost:3000');
let pc = null;
async function startCall(isInitiator) {
 const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
 document.getElementById('localVideo').srcObject = stream;

const config = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] };
 pc = new RTCPeerConnection(config);

stream.getTracks().forEach(t => pc.addTrack(t, stream));
 pc.ontrack = e => document.getElementById('remoteVideo').srcObject = e.streams[0];
 pc.onicecandidate = e => e.candidate && socket.emit('ice-candidate', e.candidate);

if (isInitiator) {
 const offer = await pc.createOffer();
 await pc.setLocalDescription(offer);
 socket.emit('offer', { offer });
 }

socket.on('offer', async ({ offer }) => {
 await pc.setRemoteDescription(offer);
 const answer = await pc.createAnswer();
 await pc.setLocalDescription(answer);
 socket.emit('answer', { answer });
 });

socket.on('answer', async ({ answer }) => {
 await pc.setRemoteDescription(answer);
 });

socket.on('ice-candidate', async ({ candidate }) => {
 await pc.addIceCandidate(candidate);
 });
}
// 页面加载后决定是否作为发起方(例如通过 URL 参数)
startCall(window.location.search.includes('initiator=true'));
相关推荐
EasyGBS8 天前
RTSP、RTMP、HLS、FLV、WebRTC……国标GB28181视频平台EasyGBS五大流媒体协议,你的场景该用哪个?
音视频·webrtc
REDcker9 天前
libdatachannel 快速入门
c++·webrtc·datachannel
冯程12 天前
WebRTC 之 AllocationSequence 详解
webrtc·音视频开发
阿拉斯攀登14 天前
售货柜实战:IPC 拉流 → 抽帧 → YOLO 识别完整流水线
yolo·ffmpeg·音视频·webrtc·视频编解码
阿拉斯攀登14 天前
RTSP 拉流与录制:IPC 摄像头本地录像完整方案
ffmpeg·音视频·webrtc·实时音视频·视频编解码
阿拉斯攀登15 天前
数据通道:RTCDataChannel 可靠与不可靠传输
音视频·webrtc·实时音视频·媒体·视频编解码
REDcker15 天前
腾讯TRRO SDK深度剖析
音视频·webrtc·实时音视频·直播·rtc·腾讯
阿拉斯攀登15 天前
FFmpeg 转码详解:封装格式、编码器、码率控制
ffmpeg·音视频·webrtc·实时音视频·视频编解码
阿拉斯攀登15 天前
FFmpeg 入门:命令行的 20 个常用场景
ffmpeg·音视频·webrtc·视频编解码
阿拉斯攀登16 天前
媒体流与轨道:MediaStream 与 MediaStreamTrack
嵌入式硬件·webrtc·实时音视频·媒体·视频编解码