WebRTC的体系结构概述—用于实现视频会议的协议

自从新冠开始,远程工作就变得十分常见了。尽管已经有了疫苗,但许多公司和团队已经完全习惯了在线工作的模式,因此,人们对在线协​​作工具的需求正不断增长,特别是视频会议解决方案。

1_DA9dBeXpIFyWf7VVsIEfIA
Source: Google
资料来源:谷歌

相应地,为实现自己的视频会议方案,并贡献出自己的一份力量,我想到了一个CLI工具,它可以同时分享你的屏幕和代码,这样在你项目中的每一个变化都会实时反映在通话中。


参见Git Streamer(Alpha)通讯的协议(又叫RTC)。

开始时,我对视频会议了解得不太多,经过彻底的研究后,我接触到了WebRTC - 一个用来进行实时通讯的协议(又叫RTC)。

WebRTC不一定是专门为视频会议而设计的,但肯定考虑到了这一点。按照如今的标准,实时的定义就是延迟时间小于一秒钟。WebRTC是目前最快的解决方案,最重要的是,它是开源的,这意味着这项技术是免费的。任何其他解决方案在延迟方面都会束手无策,但请记住,它们并不是为了给我们提供实时性能而创建的,它们的目的也各不相同。下面是一张延迟对比图,只是为了让你了解WebRTC到底有多快:


资料来源:Wowza

当我开始使用WebRTC时,我意识到它的架构十分复杂。为了让它正常运行,我需要安装几个应用程序。它不像REST或web sockets那样用单一的方法集成起来,而需要让很多部件共同参与。我紧跟着教程操作,但很快意识到哪里好像不对。当我试图在系统中做一些调整,如增加超过2人通话的功能,结果就有些跑偏了。据我现在的了解,我得到了一个非常重要的结论: 你必须了解WebRTC在架构上是如何运行的,而不是API

因此,在这篇文章中,我想谈论的是WebRTC是如何工作的、对涉及组件的概述,以及它们彼此的通信方式。因为有很多关于API的教程(虽然关于它架构的好文章只有少数),所以对此我不会再进行深入的讨论。

WebRTC概述

WebRTC是旨在使浏览器之间直接通讯的协议。它包括一组类和方法以规范过程,它从Chrome 23开始时就可以使用:


请参阅:RTCPeerConnection,最原始的WebRTC类

除了标准化通信流程,浏览器还让你可以轻松、安全地访问硬件,这是对WebRTC的补充。你可以流式传输屏幕、麦克风和相机,考虑到每个操作系统和硬件都需要不同(且复杂!)的配置,通常这将需要安装外部插件或二进制文件,并且这可能变得更加复杂。最初,我试图与ffmpeg进行屏幕共享;我设法让它工作,但是遇到了许多兼容性问题。

开箱即用,我们真的很幸运,但我可能应该在另一篇文章中谈谈媒体部分。

对等连接

WebRTC基于p2p架构(点对点);通话的参与者负责将数据从一端传输到另一端,而无需依赖中间人(大部分情况下,我会在后面介绍)。如果一个参与者出于任何原因断开连接,则其他参与者将继续传输数据;与传统通讯不同,在传统通讯中,如果与服务器的连接丢失,数据将不再流式传输。此外,对等点在地理位置上彼此更近,因此数据之间的距离不远。

因此,当我进入对话时,我必须用专门的实例代表每个对等方。因此,假设我在对话中共有4个对等体(包括我自己),那么我将有3个对等体实例,每个实例都直接链接到不同的浏览器。这是网格的样子:

1_pnj8W4d8LFihZXblgAR3yA
4对等系统

信令服务器

随着通话的进行,必须要跟踪加入或退出对话的人员,并分别创建或处理连接。为了跟踪这些事件,我们需要有一个 信令服务器

信令服务器专用于在两个或两个以上想要通信的对等点之间建立初始连接。建立连接后,你不需要用它进行持续的通信。但如果你想发信号通知其他事件,例如对等方已断开连接,则可以使用它,这一切由你决定。

信令服务器可以通过多种方式实现,你需要做的只是搭建对等体A和对等体B之间的桥梁。你可以使用从REST到从理论上的通过电子邮件进行复制粘贴的任何方式,但通常情况下,你会想使用Web sockets场景,因为可以随时自发启动通信:

1_L8JiTFIaH3C12gx1xlVzQg
加入对话后,我会与信令服务器进行广播,以便所有人都可以知道

SDP

一旦我们知道有人加入了对话,就需要交换有关彼此系统的信息以建立连接。此信息是基于 SDP (会话描述协议)协议上的,并且包含有关其所属对等方的详细信息,例如,它使用的代理,支持的硬件,理想交换的媒体类型等。SDP config是一个简单的键值对象:

1_7FYyYs-INH5q8cvPFiisCg
资料来源:researchgate.net

SDP配置既可以代表 回应 ,也可以代表 提议 。每当我们想建立连接时,我们都会进行提议,与此对应,我们应该得到回应。提议与回应是双向的,我的意思是,无论哪一方发起连接,结果都将是相同的。

但是,重要的是要跟踪有问题的SDP配置代表了哪一端:我们,还是另一端。初始化对等实例时,我们需要做两件事:本地描述和远程描述。本地描述代表我们,远程描述代表另一端,合在一起,我们就可以成功建立连接:

1_D0OSxkLJAPZXnmja2Fvq3A
将2个对等方与其SDP连接起来

ICE候选对象

一个对等方可能有很多通信传输。某个用户可能有多个私有IP /端口,和/或多个公共IP /端口,和/或各种协议,和/或一个或多个反向代理等等。一旦我们创建了SDP产品,WebRTC就会尝试查找每个可能的通信传输到浏览器,这被称为 ICE 候选 对象( 交互式连接建立):

1_bum1MRdIK6Wkbu_WJ2uSIA
实际的RTCIceCandidate实例

ICE候选对象仅仅是应该添加到SDP中的另一个键值组。我们可以等待WebRTC找到每个可能的候选者并发送完整的SDP,或者我们可以与信令服务器一起发送每个检测到的ICE候选对象并逐步扩展SDP;或者这两个选项均有效。WebRTC应该知道如何在ICE之间轮换并选择最可行的选项。

默认情况下,WebRTC将优先基于 UDP (用户数据报协议)的ICE 。与 TCP (传输控制协议,HTTP所使用的传统协议)不同,在TCP中,除非先发送100%的数据包,否则不对数据包进行流传输,而UDP会保持与先前数据包状态无关的流数据包的状态,从而使通信速度更快。

1_jqBn8HdZFK19wNY2PrpaHA
创建SDP后,WebRTC便开始寻找ICE候选对象

NAT

如今,大多数计算机都没有直接连接到全球网络,它们很可能经过 NAT 层(网络地址转换)。通过路由器进行传输时,机器的专用IP /端口实际上将转换为其他公用IP /端口。

由于WebRTC努力在两端之间建立尽可能直接的联系,因此任何一方通过代理过程时都会带来一些复杂性。让我们看一下不同的NAT配置,并看看如何使用它们建立直接连接(因为自己说得不够好,所以我直接从dh2i.com上获得了定义):

普通(完全Cone)NAT

完全Cone NAT是一种将来自同一内部IP地址和端口的所有请求都映射到同一外部IP地址和端口的NAT。此外,通过将数据包发送到映射的外部地址,任何外部主机都可以将数据包发送到内部主机。

1_hgb0TD9gEoVd9P3vuMqvvA
插图:具有目标IP /端口的对等方尝试通过向路由器的公共IP /端口之一发出请求来与我们建立连接,然后将其转换为我们机器的专用IP /端口。

受限Cone NAT

受限Cone NAT是一种将来自相同内部IP地址和端口的所有请求都映射到相同外部IP地址和端口的NAT。与完全锥形NAT不同,外部主机(具有IP地址X)仅在内部主机以前将数据包发送到IP地址X时才可以将数据包发送到内部主机。

1_y0D0aHURSaRQI_scH0RA6A

端口受限Cone NAT

端口受限Cone NAT类似于受限Cone NAT,但是限制包括端口号,特别的是,只有内部主机先前已将数据包发送到IP地址X和端口P时,外部主机才能将具有源IP地址X和源端口P的数据包发送到内部主机。

1_qrd3mZ6RTyzPuAzowWCugQ
对称NAT

对称NAT是其请求都来自同一内部IP地址和端口到特定目标IP地址和端口,并都映射到相同的外部IP地址和端口的对称NAT。如果同一主机将具有相同源地址和端口的数据包发送到另一目的地,则使用不同的映射。此外,只有接收到数据包的外部主机才能将UDP数据包发送回内部主机。

1_pZM6EHpC8c027idJ6tKmxw

我想在这些定义中添加一点内容。路由器将使用NAT表管理其状态,该表将包含其所有交易的历史记录;每当我们提出请求时,都会创建一个条目并将其添加到表中。该条目通常将包含以下信息:

  • 专用IP /端口
  • 公共IP /端口
  • 目的IP /端口

这些信息至关重要,我们可以通过它们更好地了解即将到来的原则。

STUN

如果我们的计算机连接到NAT层,则我们需要公共IP /端口来创建ICE候选对象。因此,WebRTC使我们能够在初始化WebRTC连接时指定 STUN 服务器URL(用于NAT的会话遍历工具)。

STUN是一套标准化的方法,包括网络协议,用于穿越实时语音、视频、消息和其他交互式通信应用中的网络地址转换器(NAT)。—维基百科

实际上,它所做的只是返回公共IP /端口。因此,当我们尝试在两个对等点之间建立连接时,将发生以下情况:

  • 使对等方A和对等方B具有完整的锥形NAT。
  • 对等方A将使用STUN服务器获取有关其公共IP /端口的信息。
  • 对等方A将使用信令服务器将该信息发送给对等方B。
  • 对等B将获得该信息,并尝试与对等A建立连接。
  • 反之亦然。

1_80Z67TRcEZnqHj3dWSi2cg
资料来源:MDN

由于STUN服务器的功能不多,因此价格便宜。他们不需要任何身份验证,通常是免费提供的。

如果2个对等点在完整的Cone NAT上运行,则仅需要公共IP /端口即可建立连接。路由器将查看附加到传入请求的公共IP /端口,如果可以将其与专用IP /端口匹配,它将接受连接。

打孔

其他2个受限Cone NAT与对等体的连接方式与完整锥形NAT类似,但是它们有一个小的限制。他们需要知道其公共IP /端口,并且还需要确保NAT表中存在传入请求的目标IP /端口。与完全Cone NAT基本不同,在完全锥形NAT中,路由器基本信任所有人,而受限制的Cone 仅信任尝试与之建立连接的人员。

这产生了一个悖论。如果有两个对等的人以前从未建立过连接,那么他们如何才能建立连接?

为了克服此问题,我们使用了一种称为 打孔 (也称为穿孔)的技术。基本上是这样的:

  • 使对等方A具有受限的Cone NAT,对等体B具有完整的Cone NAT。
  • 对等方A将使用STUN服务器获取有关其公共IP /端口的信息。
  • 对等方A将使用信令服务器将该信息发送给对等方B。
  • 对等B将获得该信息,并尝试与对等A建立连接。
  • 对等B将无法建立连接,但会将对等A的公共信息存储在其NAT表中。
  • 对等体A将尝试与对等体B建立连接。由于对等体A在对等体B NAT表中已经存在,因此该连接被接受。
  • 对等体A将存储有关对等体B的公共信息。
  • 对等体B现在可以与对等体A建立连接。

TURN

当我们处理对称NAT时,我们可以完全抛出p2p并将浏览器通信直接移到垃圾桶。让我们首先观察连接过程:

  • 使对等体A具有对称NAT,对等体B具有完整的Cone NAT。
  • 对等方A将使用STUN服务器获取有关其公共IP /端口的信息。
  • 对等方A将使用信令服务器将该信息发送给对等方B。
  • 对等B将获得该信息,并尝试与对等A建立连接。
  • 对等B将无法建立连接,但会将对等A的公共信息存储在其NAT表中。
  • 对等体A将尝试与对等体B建立连接。但是,因为存储在其NAT表中的公共信息实际上不同于它实际接收到的公共信息,所以对等体B将拒绝对等体A。

你会看到,当一个对等方的公共IP /端口不是静态的时,我们将无法实现直接的浏览器通信。这就是为什么WebRTC使我们能够指定 TURN 服务器URL(使用围绕NAT的中继的遍历)的原因。

使用围绕NAT的中继进行遍历(TURN)是一种协议,可帮助遍历用于多媒体应用程序的网络地址转换器(NAT)或防火墙。—维基百科

TURN实际上只是为了避免直接沟通。它使用反向代理,这样公共IP /端口就保持不变,我们可以建立连接,这不仅会使连接变慢且效率降低,而且会使连接成本大大提高。因此,TURN ICE将始终被列为最低优先级。

想象一下与数十个对等方进行呼叫,其中每个对等方都通过TURN发送数据包。你将不得不为所有正在传输的数据付费,这可能会造成很高的成本,尤其是如果服务器不在最近的区域中时。这就是为什么TURN服务器永远不会免费提供的原因,并且始终在身份验证机制之后对其进行保护。

1_WSa3buqCC42Jc4Qygi9jXw%20(1)
资料来源:MDN

圆是封闭的。现在,两个或更多对等方就可以建立连接并彼此通信了。

我希望你能喜欢这篇文章,如果你正寻找一种快速简便的方法来同时共享屏幕和代码,我建议你看一下Git Streamer

原文作者 Eytan Manor
原文链接 https://eytanmanor.medium.com/an-architectural-overview-for-web-rtc-a-protocol-for-implementing-video-conferencing-e2a914628d0e

推荐阅读
作者信息
AgoraTechnicalTeam
TA 暂未填写个人简介
文章
153
相关专栏
开源技术
63 文章
本专栏仅用于分享音视频相关的技术文章,与其他开发者和 Agora 研发团队交流、分享行业前沿技术、资讯。发帖前,请参考「社区发帖指南」,方便您更好的展示所发表的文章和内容。