场景
你需要开发 实时视频会议、屏幕共享 或 P2P 文件传输 功能,要求低延迟、高可靠性的端到端通信。
一、核心概念
1. WebRTC 三要素
- MediaStream(媒体流):音视频输入输出(摄像头、麦克风)
- RTCPeerConnection:对等连接管理(NAT 穿透、编解码协商)
- RTCDataChannel:双向数据传输通道
2. 连接建立流程
1. 媒体设备访问 → 2. 信令交换 → 3. ICE 候选收集 → 4. 建立 P2P 连接
二、实战代码示例
步骤 1:获取媒体流
// 获取摄像头和麦克风访问权限
async function getMediaStream() {
try {
return await navigator.mediaDevices.getUserMedia({
video: { width: 1280, height: 720 },
audio: true
});
} catch (err) {
console.error('媒体设备访问失败:', err);
}
}
// 在 video 元素显示本地视频
const localVideo = document.getElementById('localVideo');
const stream = await getMediaStream();
localVideo.srcObject = stream;
步骤 2:建立信令服务器(Node.js 示例)
// 使用 Socket.IO 实现信令服务器
const express = require('express');
const socketIO = require('socket.io');
const app = express();
const server = app.listen(3000);
const io = socketIO(server);
io.on('connection', (socket) => {
socket.on('join', (roomId) => {
socket.join(roomId);
socket.to(roomId).emit('user-connected', socket.id);
});
socket.on('signal', ({ to, data }) => {
socket.to(to).emit('signal', { from: socket.id, data });
});
});
步骤 3:创建对等连接
// 初始化 RTCPeerConnection
const pcConfig = {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }, // 免费 STUN 服务器
// 需要 TURN 服务器可添加 { urls: 'turn:your-turn-server', credential: 'xxx' }
]
};
const pc = new RTCPeerConnection(pcConfig);
// 添加本地媒体流
stream.getTracks().forEach(track => {
pc.addTrack(track, stream);
});
// 处理 ICE 候选
pc.onicecandidate = ({ candidate }) => {
if (candidate) {
socket.emit('signal', { to: remoteUserId, data: { candidate } });
}
};
// 接收远程流
pc.ontrack = (event) => {
const remoteVideo = document.getElementById('remoteVideo');
remoteVideo.srcObject = event.streams[0];
};
步骤 4:发起连接
// 发起方创建 Offer
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
socket.emit('signal', { to: remoteUserId, data: { offer } });
// 接收方处理 Offer
socket.on('signal', async ({ from, data: { offer } }) => {
await pc.setRemoteDescription(offer);
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
socket.emit('signal', { to: from, data: { answer } });
});
// 处理 Answer
socket.on('signal', async ({ data: { answer } }) => {
await pc.setRemoteDescription(answer);
});
三、高级功能实现
1. 屏幕共享
async function shareScreen() {
const stream = await navigator.mediaDevices.getDisplayMedia({
video: { cursor: 'always' },
audio: true
});
const screenTrack = stream.getVideoTracks()[0];
const sender = pc.getSenders().find(s => s.track.kind === 'video');
sender.replaceTrack(screenTrack);
}
2. 文件传输(通过 RTCDataChannel)
// 创建数据通道
const dc = pc.createDataChannel('fileTransfer');
dc.onmessage = (event) => {
const fileChunk = event.data;
// 处理接收的文件块
};
// 发送文件
async function sendFile(file) {
const chunkSize = 16384; // 16KB
const reader = new FileReader();
let offset = 0;
reader.onload = () => {
dc.send(reader.result);
offset += reader.result.byteLength;
if (offset < file.size) readChunk(offset);
};
const readChunk = (o) => {
const slice = file.slice(o, o + chunkSize);
reader.readAsArrayBuffer(slice);
};
readChunk(0);
}
3. 网络质量监控
pc.getStats().then(stats => {
stats.forEach(report => {
if (report.type === 'candidate-pair' && report.selected) {
console.log('当前 RTT:', report.currentRoundTripTime);
}
});
});
四、性能优化技巧
- 编解码选择:优先使用 VP8/VP9 视频编解码
- 带宽自适应:使用
RTCRtpSender.setParameters()
动态调整码率 - ICE 策略优化:设置
iceTransportPolicy: 'relay'
强制使用 TURN 服务器(高防火墙环境)
五、工具与库
工具/库 | 用途 | 特点 |
---|---|---|
Simple-Peer | 简化 WebRTC API | 封装复杂连接逻辑 |
Twilio | 云通信平台 | 提供 TURN 服务和 SDK |
Mediasoup | SFU 媒体服务器 | 适合大规模会议系统 |
WebRTC-internals | 浏览器内置调试工具 | 查看详细连接状态 |
六、注意事项
- HTTPS 要求:生产环境必须使用 HTTPS
- 浏览器兼容性:iOS Safari 对部分功能有限制
- NAT 穿透失败:需配置 TURN 服务器作为中继
- 设备权限:首次访问需用户明确授权
明日预告:WebSocket
—— 如何实现实时双向数据通信?