如何利用JavaScript的WebRTC实现实时通信?

答案是利用WebRTC实现通信需四步:获取本地媒体流,创建RTCPeerConnection连接,通过信令交换offer/answer和ICE候选,最后处理连接状态;核心为P2P传输,依赖STUN/TURN穿透NAT,信令可自定义。

要利用JavaScript的WebRTC实现实时通信,核心在于建立点对点连接,传输音视频流或任意数据。整个过程不依赖中间服务器转发媒体内容,但需要信令机制协调连接信息。下面介绍关键步骤和实现方式。

1. 获取本地媒体流

使用 getUserMedia() 获取用户的摄像头和麦克风权限,获取音视频流。

  • 调用 navigator.mediaDevices.getUserMedia() 请求音视频权限
  • 将获取的流绑定到 元素进行预览
  • 处理权限拒绝等异常情况

示例代码:

navigator.mediaDevices.getUserMedia({ video: true, audio: true })
  .then(stream => {
    localVideo.srcObject = stream;
    localStream = stream;
  })
  .catch(err => console.error('无法获取媒体流:', err));

2. 创建RTCPeerConnection连接

RTCPeerConnection 是WebRTC的核心API,负责建立P2P连接并传输数据。

  • 初始化 new RTCPeerConnection(),可配置STUN/TURN服务器以穿透NAT
  • 将本地流添加到连接:peerConnection.addStream(localStream)
  • 监听远程流事件:onaddstream 或现代的 ontrack

示例配置:

const peerConnection = new RTCPeerConnection({
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
});
peerConnection.addStream(localStream);
peerConnection.ontrack = event => {
  remoteVideo.srcObject = event.streams[0];
};

3. 交换信令(Signaling)

WebRTC本身不规定信令传输方式,需通过WebSocket、HTTP等自定义通道交换连接信息。

  • 生成本地offer:createOffer()setLocalDescription()
  • 发送offer给对方,对方设置为远程描述:setRemoteDescription()
  • 对方创建answer并返回,本地设置answer为远程描述
  • ICE候选者通过 onicecandidate 收集并发送给对方

信令流程示例:

// 发起方
peerConnection.createOffer()
  .then(offer => peerConnection.setLocalDescription(offer))
  .then(() => sendToPeer('offer', peerConnection.localDescription));

// 接收方
peerConnection.setRemoteDescription(new RTCSessionDescription(offer))
  .then(() => peerConnection.createAnswer())
  .then(answer => peerConnection.setLocalDescription(answer))
  .then(() => sendToPeer('answer', answer));

// 双方监听ICE候选
peerConnection.onicecandidate = event => {
  if (event.candidate) sendToPeer('candidate', event.candidate);
};

4. 处理ICE候选与连接状态

ICE(Interactive Connectivity Establishment)用于发现最优网络路径。

  • 收到对方发来的candidate时,调用 addIceCandidate()
  • 监听连接状态变化:iceconnectionstatechangeconnectionstatechange
  • 处理断线重连或关闭连接

示例处理:

socket.on('message', message => {
  if (message.type === 'candidate') {
    peerConnection.addIceCandidate(new RTCIceCandidate(message.candidate));
  }
});

基本上就这些。只要完成媒体获取、连接建立、信令交换和ICE处理,就能实现浏览器间的实时音视频通信。实际项目中还需考虑兼容性、错误处理和网络波动等问题,但核心流程不变。