深入理解 WebRTC:实时音视频通信的原理与实现全流程

深入理解 WebRTC:实时音视频通信的原理与实现全流程

一、引言

如果你使用过 视频会议(腾讯会议、Zoom)、语音聊天室、远程协作工具,那么你已经悄悄地使用了 WebRTC —— 浏览器原生支持的实时通信技术。

但写过 WebRTC 的人都知道:
👉 文档看似很多,但真正从原理到实现的体系化内容却不多。
👉 尤其是「信令怎么写?」「ICE 是啥?」「打洞是什么?」这些概念经常让初学者抓狂。

这篇文章,我会用开发者的视角,带你 从 0 到 1 掌握 WebRTC 的核心原理,并给出 可直接运行的代码模版,帮你快速构建属于自己的实时音视频 DEMO。


二、WebRTC 是什么?(What)

WebRTC(Web Real-Time Communication)是一套让浏览器直接进行实时音视频通信的技术标准。

其目标很简单:

让浏览器之间可以 P2P 传输音视频、文本、文件,且不依赖插件。

核心提供三个能力:

能力API
获取摄像头、麦克风getUserMedia()
P2P 数据传输RTCPeerConnection
任意数据通道RTCDataChannel

WebRTC 的杀手级特性:

  • 低延迟(几十毫秒)
  • 端到端加密
  • 浏览器原生支持
  • 可穿透绝大多数 NAT
  • 无需依赖中心服务器进行媒体转发(纯 P2P)

三、需求背景(Why)

现代实时应用对通信有越来越高的要求:

  • 远程会议
  • 在线教育
  • 实时客服系统
  • 多人语音房/直播互动
  • 浏览器游戏同步
  • 远程桌面 / 协同办公

它们共同需求:

通信方式延迟是否能满足实时
HTTP 轮询200ms+
WebSocket20–100ms❌(不能传音视频)
WebRTC< 50ms✔✔✔

所以在「实时音视频」场景里,WebRTC 是唯一的正解。


四、WebRTC 工作原理(How)

从工程的角度看,WebRTC 全流程可以分为 5 个关键步骤


1. 获取本地媒体流(摄像头/麦克风)

浏览器向用户请求权限:

const localStream =await navigator.mediaDevices.getUserMedia({ video:true, audio:true});

2. 创建 PeerConnection

这是 WebRTC 最核心的对象:

const pc =newRTCPeerConnection({ iceServers:[{ urls:"stun:stun.l.google.com:19302"}// 用于 NAT 打洞]});

3. 将本地媒体轨道加入连接

localStream.getTracks().forEach(track=>{ pc.addTrack(track, localStream);});

4. 信令交换(SDP + ICE)

注意:信令服务器不是 WebRTC 的一部分,需要你自行实现(WebSocket 通常即可)

信令的作用:
👉 只是“帮两台浏览器交换必要信息”,不负责媒体传输。

两个核心内容:

类型用途
SDP(会话描述)告诉对方我的音视频能力、编码类型等
ICE Candidate(网络候选地址)告诉对方我可连接的网络地址

这部分流程如下:

  1. A 创建 offer → 发送给 B
  2. B 创建 answer → 回给 A
  3. 双方持续交换 ICE Candidate

5. 建立 P2P 通道并传输音视频

完成 SDP + ICE 交换后,两端会尝试直连(NAT 穿透),连上后即可流式传输音视频。


五、代码实现(可直接运行)

下面提供一个最简版的 WebRTC 点对点视频通话 Demo
信令使用 WebSocket,可自行换成自己的服务器。


1. 信令服务器(Node.js)

使用 ws 创建一个最简单的信令服务:

// server.jsconst WebSocket =require('ws');const wss =newWebSocket.Server({ port:8080}); wss.on('connection',ws=>{ ws.on('message',msg=>{// 广播给所有客户端 wss.clients.forEach(client=>{if(client !== ws && client.readyState === WebSocket.OPEN){ client.send(msg);}});});}); console.log('Signaling server listening on ws://localhost:8080');

运行:

node server.js 

2. 前端 WebRTC Demo(HTML + JavaScript)

// index.jsconst localVideo = document.getElementById("localVideo");const remoteVideo = document.getElementById("remoteVideo");const ws =newWebSocket("ws://localhost:8080");const pc =newRTCPeerConnection({ iceServers:[{ urls:"stun:stun.l.google.com:19302"}]});// 接收远端流 pc.ontrack=event=>{ remoteVideo.srcObject = event.streams[0];};// 发送 candidate pc.onicecandidate=event=>{if(event.candidate){ ws.send(JSON.stringify({ type:"candidate", candidate: event.candidate }));}};// 处理信令消息 ws.onmessage=asyncevent=>{const data =JSON.parse(event.data);if(data.type ==="offer"){await pc.setRemoteDescription(data.offer);const answer =await pc.createAnswer();await pc.setLocalDescription(answer); ws.send(JSON.stringify({ type:"answer", answer }));}if(data.type ==="answer"){await pc.setRemoteDescription(data.answer);}if(data.type ==="candidate"){await pc.addIceCandidate(data.candidate);}};// 获取本地流并加入 PeerConnectionasyncfunctionstart(){const stream =await navigator.mediaDevices.getUserMedia({ video:true, audio:true}); localVideo.srcObject = stream; stream.getTracks().forEach(track=> pc.addTrack(track, stream));}// 主动发起呼叫asyncfunctioncall(){const offer =await pc.createOffer();await pc.setLocalDescription(offer); ws.send(JSON.stringify({ type:"offer", offer }));}start();

3. Demo 页面结构(index.html)

<!DOCTYPE html><html lang="zh"><body><h2>WebRTC 简易视频通话 DEMO</h2><video id="localVideo" autoplay muted></video><video id="remoteVideo" autoplay></video><button onclick="call()">发起通话</button><script src="index.js"></script></body></html>

六、运行效果截图

当你打开两个浏览器并连接同一个信令服务器时,将看到:

  • 左侧:本地摄像头画面(localVideo)
  • 右侧:来自另一台浏览器的远端视频(remoteVideo)
  • 点击“发起通话”后,远端浏览器自动响应该呼叫,连接成功后双方即可互相看到视频画面

最终效果示意:

在这里插入图片描述

如果两个设备在不同网络,只要 STUN 可用,依然能成功 P2P 通话。

下面是 重新改写后的总结部分,更偏向收尾与个人感悟,语气更像真实开发者分享:


七、总结

写 WebRTC 是一种很特别的体验:它不像写普通前端逻辑,可以在控制台里一路 console.log;也不像写接口,有报错就能立刻定位。
它更像是在 与浏览器、网络环境、对端应用一起协作完成一件事——稍微一个环节出了问题,你就会陷入「为什么连不上?」的灵魂拷问。

从本地媒体采集、RTCPeerConnection 建立,到 SDP/ICE 的信令交换,再到最终建立真正的 P2P 通道,其实每一步都有很多值得学习的细节。但当你真的跑通一次之后,你会发现:

WebRTC 本身并没有想象中那么神秘,它只是在帮你做正确且安全的“实时通信”。

我个人非常喜欢 WebRTC 的原因是,它让浏览器变得像“一个可以实时沟通的实时终端”。
当你第一次看到远端的视频画面在自己的浏览器中出现时,那种“我真的让两个浏览器直接连上了!”的感觉,是很有成就感的。

希望这篇文章能帮助你建立 WebRTC 的整体认知,为你后续开发实时音视频相关项目打下一个扎实、可落地的基础。


作者: 王新焱
博客: https://blog.ZEEKLOG.net/qq_34402069
时间: 2025年12月5日


Read more

copilot在wsl中无法工作

copilot在wsl中无法工作

copilot 在 wsl 中无法工作——vscode remote develop 代理设置 通过本文,你可以了解: 1. 如何解决 copilot 在 wsl 中无法使用的问题 2. wsl和宿主机之间的网络通信 3. vscode 的 remote develop 代理设置 问题表现 如果你有以下问题之一: 1. 对话没有输出 2. 显示 fetch failed 3. 模型名称不显示 问题分析 查看 copilot chat 的 output 显示: 如果显示 proxies 相关问题,可以确定是 WSL 中运行的 vscode 调用了宿主机的 proxy

埃斯顿机器人快速入门

埃斯顿机器人快速入门

本文章适合有一定基础的人学习如:abb,发那科,库卡等这些主流的机器人,一些通用的知识点就不在这里过多描述,只讲一下不同的地方以便快速入门接手项目。 有一定基础!!! 有一定基础!!! 有一定基础!!! 目录 * 1.仿真软件Editor * 1.1下载Editor2.6.05 * 1.2官方最新版下载 * 2.界面介绍 * 3.IO配置 * 4.程序变量与语法 * 5.程序下载 1.仿真软件Editor 1.1下载Editor2.6.05 这个软件是埃斯顿机器人的仿真软件,适合在没有机器人前期准备程序及配置的时候使用。入门学习也非常合适,毕竟也不是一直有都有机会拿实机去练习的。 仿真软件可以选择在官网下载,但是在官网下载有点问题一开始我都找不到,使用我这里先给一个截止到这一篇文章发布前最新版的连接。点🐔下载!!! 1.2官方最新版下载 进入埃斯顿官网点击资料下载见面,你会发现哎嘿!你要搜索相关的手册或者安装包的名称才能下载,输错了就找不到了! 可以跟着我输入关键字:Editor 2.

Kimi vs 豆包学术助手:AI写作降AI谁更适合中国学生?

Kimi vs 豆包学术助手:AI写作降AI谁更适合中国学生?

Kimi vs 豆包学术助手:AI写作降AI谁更适合中国学生? TL;DR Kimi和豆包都是国产AI的代表,用来辅助论文写作或降AI各有优势:Kimi擅长长文本处理和学术场景,豆包日常对话更自然。但用它们降AI效果有限,本质上还是AI生成AI。真正靠谱的降AI方案是用专业工具,推荐嘎嘎降AI(达标率99.26%)或比话降AI(不达标全额退款)。 国产AI双雄:学生党的新选择 这两年国产AI发展特别快,Kimi和豆包是最被学生群体熟知的两个名字。Kimi是月之暗面开发的,主打长文本处理能力,据说一次能处理20万字;豆包是字节跳动出品的,更像一个全能型AI助手,什么都能聊。作为即将毕业的学生,我一直在思考:这两个工具用来写论文和降AI,到底哪个更靠谱? 于是我做了一次实测对比。测试用的是一篇10000字的课程论文,知网AIGC检测原始AI率是65%。我分别用Kimi和豆包尝试降AI,同时也用嘎嘎降AI和比话降AI作为对照,看看国产通用AI和专业降AI工具之间的差距到底有多大。 Kimi降AI实测 Kimi最大的优势是长文本处理能力。一般的AI处理几千字就要分段,Kim