跳转到内容

WebRTC

简介

WebRTC(Web Real-Time Communication,网页实时通信)是一项使网页应用和站点能够在不借助中间件的情况下,直接在浏览器之间捕获和可选择性地传输音频、视频和任意数据的技术。它提供了一系列标准API,使得无需插件或第三方软件即可实现点对点的数据共享和视频通话。

WebRTC 包含多个相互关联的 API 和协议,它们协同工作以实现多媒体通信功能,包括音频和视频会议、文件交换、屏幕共享、身份管理以及与传统电话系统的接口等。

核心概念

RTCPeerConnection

RTCPeerConnection 接口表示本地计算机与远程对等方之间的 WebRTC 连接。它用于处理两个对等方之间的数据流式传输。

js
// 创建一个新的 RTCPeerConnection 实例
const pc = new RTCPeerConnection({
  iceServers: [
    {
      urls: 'stun:stun.example.com'
    }
  ]
});

// 监听连接状态变化
pc.onconnectionstatechange = event => {
  switch(pc.connectionState) {
    case "connected":
      // 连接已建立
      break;
    case "disconnected":
    case "failed":
      // 连接断开或失败
      break;
    case "closed":
      // 连接已关闭
      break;
  }
};

RTCDataChannel

RTCDataChannel 接口表示连接的两个对等方之间的双向数据通道,可用于传输任意数据。

js
// 创建数据通道
const dataChannel = pc.createDataChannel("my channel");

// 监听数据通道事件
dataChannel.onopen = event => {
  console.log("数据通道已打开");
  dataChannel.send("Hello, WebRTC!");
};

dataChannel.onmessage = event => {
  console.log("收到消息: " + event.data);
};

dataChannel.onclose = event => {
  console.log("数据通道已关闭");
};

媒体流和轨道

WebRTC 与媒体捕捉和媒体流 API 结合使用时,可以实现强大的多媒体功能。媒体流可以由任意数量的媒体轨道组成,包括音频、视频和文本轨道。

js
// 获取本地媒体流
const localStream = await navigator.mediaDevices.getUserMedia({ 
  video: true, 
  audio: true 
});

// 将媒体轨道添加到连接中
localStream.getTracks().forEach(track => {
  pc.addTrack(track, localStream);
});

// 监听远程媒体流
pc.ontrack = event => {
  const remoteStream = event.streams[0];
  // 将远程流连接到页面中的 video 元素
  document.getElementById('remoteVideo').srcObject = remoteStream;
};

WebRTC 协议

ICE(Interactive Connectivity Establishment)

ICE 是一个允许浏览器和对端浏览器建立连接的协议框架。在网络中,由于防火墙、NAT 等因素,简单的端到端连接往往无法建立,ICE 通过使用 STUN 和 TURN 等技术来解决这些问题。

STUN(Session Traversal Utilities for NAT)

STUN 允许位于 NAT 后的客户端找出自己的公网地址,并判断出路由器阻止直连的限制方法。

js
const configuration = {
  iceServers: [
    {
      urls: 'stun:stun.l.google.com:19302'
    }
  ]
};

const pc = new RTCPeerConnection(configuration);

TURN(Traversal Using Relays around NAT)

TURN 通过 TURN 服务器中继所有数据的方式来绕过对称型 NAT,是开销较大的解决方案,通常在 STUN 无法工作时使用。

js
const configuration = {
  iceServers: [
    {
      urls: 'turn:turn.example.com',
      username: 'username',
      credential: 'password'
    }
  ]
};

SDP(Session Description Protocol)

SDP 是一个描述多媒体连接内容的协议,包括分辨率、格式、编码、加密算法等。在 WebRTC 中,SDP 用于描述连接的媒体能力和配置。

实际应用

建立连接的基本流程

js
async function startConnection() {
  const pc = new RTCPeerConnection(configuration);
  
  // 获取本地媒体流
  const localStream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
  document.getElementById('localVideo').srcObject = localStream;
  
  // 添加本地轨道到连接
  localStream.getTracks().forEach(track => {
    pc.addTrack(track, localStream);
  });
  
  // 创建提议
  const offer = await pc.createOffer();
  await pc.setLocalDescription(offer);
  
  // 通过信令服务器发送 offer 给对端
  signaling.send({type: 'offer', sdp: offer.sdp});
}

// 处理收到的提议
async function handleOffer(offer) {
  const pc = new RTCPeerConnection(configuration);
  
  // 设置远程描述
  await pc.setRemoteDescription(offer);
  
  // 创建应答
  const answer = await pc.createAnswer();
  await pc.setLocalDescription(answer);
  
  // 通过信令服务器发送应答给对端
  signaling.send({type: 'answer', sdp: answer.sdp});
}

处理 ICE 候选

js
// 发送 ICE 候选
pc.onicecandidate = event => {
  if (event.candidate) {
    signaling.send({
      type: 'candidate',
      candidate: event.candidate
    });
  }
};

// 添加收到的 ICE 候选
function handleCandidate(candidate) {
  pc.addIceCandidate(candidate);
}

配置选项

RTCPeerConnection 配置

js
const configuration = {
  // ICE 服务器配置
  iceServers: [
    {
      urls: ['stun:stun.example.com']
    },
    {
      urls: ['turn:turn.example.com'],
      username: 'username',
      credential: 'password'
    }
  ],
  
  // ICE 传输策略
  iceTransportPolicy: 'all', // 'relay' | 'all'
  
  // 捆绑策略
  bundlePolicy: 'balanced', // 'balanced' | 'max-compat' | 'max-bundle'
  
  // RTCP 复用策略
  rtcpMuxPolicy: 'require' // 'negotiate' | 'require'
};

实例属性和方法

RTCPeerConnection 主要属性

属性描述
connectionState连接状态(new, connecting, connected, disconnected, failed, closed)
iceConnectionStateICE 连接状态(new, checking, connected, completed, failed, disconnected, closed)
iceGatheringStateICE 收集状态(new, gathering, complete)
signalingState信令状态(stable, have-local-offer, have-remote-offer, have-local-pranswer, have-remote-pranswer, closed)
localDescription本地会话描述
remoteDescription远程会话描述

RTCPeerConnection 主要方法

方法描述
createOffer()创建 SDP 提议
createAnswer()创建 SDP 应答
setLocalDescription()设置本地会话描述
setRemoteDescription()设置远程会话描述
addIceCandidate()添加 ICE 候选
createDataChannel()创建数据通道
addTrack()添加媒体轨道
removeTrack()移除媒体轨道
close()关闭连接

RTCDataChannel 主要属性

属性描述
label数据通道标签
ordered是否保证传输顺序
readyState通道状态(connecting, open, closing, closed)
bufferedAmount缓冲区中等待发送的字节数
binaryType二进制数据类型(blob, arraybuffer)

RTCDataChannel 主要方法

方法描述
send()发送数据
close()关闭数据通道

浏览器兼容性

WebRTC 在现代浏览器中有良好的支持:

js
// 检查浏览器支持
if (typeof RTCPeerConnection !== 'undefined') {
  // 支持 RTCPeerConnection
  console.log('浏览器支持 RTCPeerConnection');
}

if (typeof RTCDataChannel !== 'undefined') {
  // 支持 RTCDataChannel
  console.log('浏览器支持 RTCDataChannel');
}

// 检查媒体设备支持
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
  console.log('浏览器支持 getUserMedia');
}

安全考虑

  1. HTTPS 要求:WebRTC 需要在安全上下文(HTTPS)中使用
  2. 权限管理:访问摄像头和麦克风需要用户授权
  3. 数据加密:媒体和数据传输默认使用加密
js
// 检查是否在安全上下文
if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
  console.warn('WebRTC 需要 HTTPS 环境');
}

相关资源