WebRTC 连接
本文介绍了各种 WebRTC 相关协议如何相互作用,以创建连接并在对等方之间传输数据和/或媒体。
注意: 本页面需要大量重写以确保结构完整性和内容完整性。这里有很多很好的信息,但由于目前这里有点像一个垃圾场,所以组织方式一团糟。
信令
不幸的是,WebRTC 无法在没有中间服务器的情况下创建连接。我们称之为 信令通道 或 信令服务。它是在建立连接之前用于交换信息的任何通信通道,无论是通过电子邮件、明信片还是信鸽。这由您决定。
我们需要交换的信息是 Offer(提议)和 Answer(应答),其中只包含下面提到的 SDP。
作为连接发起方的对等方 A 将创建一个 Offer。然后,他们将使用所选的信令通道将此 Offer 发送给对等方 B。对等方 B 将从信令通道接收 Offer 并创建一个 Answer。然后,他们将通过信令通道将其发送回对等方 A。
会话描述
WebRTC 连接上端点的配置称为 会话描述。该描述包括有关正在发送的媒体类型、其格式、正在使用的传输协议、端点的 IP 地址和端口以及描述媒体传输端点所需的其他信息。此信息使用 会话描述协议 (SDP) 进行交换和存储;如果您想了解 SDP 数据的格式详细信息,可以在 RFC 8866 中找到。
当用户向另一个用户发起 WebRTC 呼叫时,会创建一个特殊描述,称为 提议 (offer)。此描述包括有关呼叫方提议的呼叫配置的所有信息。接收方然后用 应答 (answer) 进行响应,这是对其呼叫端点的描述。通过这种方式,两台设备相互共享交换媒体数据所需的信息。这种交换使用交互式连接建立 (ICE) 进行处理,该协议允许两台设备使用中介来交换提议和应答,即使两台设备被网络地址转换 (NAT) 分隔。
因此,每个对等方都保留两个描述:本地描述 (local description),描述自身;以及 远程描述 (remote description),描述呼叫的另一端。
提议/应答过程不仅在首次建立呼叫时执行,而且在呼叫的格式或其它配置需要更改的任何时候也执行。无论是新呼叫还是重新配置现有呼叫,以下是交换提议和应答必须发生的基本步骤,暂时不考虑 ICE 层
- 呼叫者通过
MediaDevices.getUserMedia捕获本地媒体 - 呼叫者创建
RTCPeerConnection并调用RTCPeerConnection.addTrack()(因为addStream已弃用) - 呼叫者调用
RTCPeerConnection.createOffer()创建一个提议。 - 呼叫者调用
RTCPeerConnection.setLocalDescription()将该提议设置为 本地描述 (即连接本地端的描述)。 - 在 setLocalDescription() 之后,呼叫者要求 STUN 服务器生成 ICE 候选。
- 呼叫者使用信令服务器将提议传输给预期的呼叫接收者。
- 接收者收到提议并调用
RTCPeerConnection.setRemoteDescription()将其记录为 远程描述 (连接另一端的描述)。 - 接收者执行其呼叫端所需的任何设置:捕获其本地媒体,并通过
RTCPeerConnection.addTrack()将每个媒体轨道附加到对等连接。 - 接收者然后通过调用
RTCPeerConnection.createAnswer()创建一个应答。 - 接收者调用
RTCPeerConnection.setLocalDescription(),传入创建的应答,以将该应答设置为其本地描述。接收者现在知道连接两端的配置。 - 接收者使用信令服务器将应答发送给呼叫者。
- 呼叫者收到应答。
- 呼叫者调用
RTCPeerConnection.setRemoteDescription()将应答设置为其呼叫端的远程描述。它现在知道两个对等方的配置。媒体开始按配置流动。
待处理和当前描述
更深入地了解该过程,我们发现 localDescription 和 remoteDescription(返回这两个描述的属性)并不像它们看起来那么简单。因为在重新协商期间,一个提议可能因其提出了不兼容的格式而被拒绝,所以每个端点都需要能够提出新格式,但在被另一个对等方接受之前不能实际切换到该格式。因此,WebRTC 使用 待处理 和 当前 描述。
当前描述(由 RTCPeerConnection.currentLocalDescription 和 RTCPeerConnection.currentRemoteDescription 属性返回)表示连接当前实际使用的描述。这是双方完全同意使用的最新连接。
待处理描述(由 RTCPeerConnection.pendingLocalDescription 和 RTCPeerConnection.pendingRemoteDescription 返回)表示在分别调用 setLocalDescription() 或 setRemoteDescription() 后正在考虑的描述。
当读取描述(由 RTCPeerConnection.localDescription 和 RTCPeerConnection.remoteDescription 返回)时,如果存在待处理描述(即,待处理描述不为 null),则返回 pendingLocalDescription/pendingRemoteDescription 的值;否则,返回当前描述(currentLocalDescription/currentRemoteDescription)。
当通过调用 setLocalDescription() 或 setRemoteDescription() 更改描述时,指定的描述被设置为待处理描述,WebRTC 层开始评估它是否可接受。一旦提议的描述达成一致,currentLocalDescription 或 currentRemoteDescription 的值将更改为待处理描述,并且待处理描述再次设置为 null,表示没有待处理描述。
注意: pendingLocalDescription 不仅包含正在考虑的提议或应答,还包含自提议或应答创建以来已经收集到的任何本地 ICE 候选。同样,pendingRemoteDescription 包含通过调用 RTCPeerConnection.addIceCandidate() 提供的任何远程 ICE 候选。
有关这些属性和方法的更多具体信息,请参阅各个文章;有关 WebRTC 支持的编解码器以及与哪些浏览器兼容的信息,请参阅 WebRTC 使用的编解码器。编解码器指南还提供了帮助您选择最适合您需求的编解码器的指导。
ICE 候选
除了交换媒体信息(上面在提议/应答和 SDP 中讨论)之外,对等方还必须交换有关网络连接的信息。这被称为 ICE 候选,并详细说明了对等方能够通信的可用方法(直接或通过 TURN 服务器)。通常,每个对等方会首先提出其最佳候选,然后向下推迟到较差的候选。理想情况下,候选是 UDP(因为它更快,并且媒体流能够相对容易地从中断中恢复),但 ICE 标准也允许 TCP 候选。
注意: 通常,使用 TCP 的 ICE 候选仅在 UDP 不可用或受限制(使其不适合媒体流)时才会使用。但是,并非所有浏览器都支持 ICE over TCP。
ICE 允许候选者表示通过 TCP 或 UDP 的连接,通常更倾向于 UDP(并且得到更广泛的支持)。每个协议都支持几种类型的候选者,候选者类型定义了数据如何从对等点传输到对等点。
UDP 候选类型
UDP 候选(protocol 设置为 udp 的候选)可以是以下类型之一:
TCP 候选类型
TCP 候选(即 protocol 为 tcp 的候选)可以是以下类型:
选择候选对
ICE 层选择两个对等体之一作为 控制代理。这是 ICE 代理,它将对用于连接的候选对做出最终决定。另一个对等体称为 受控代理。您可以通过检查 RTCIceCandidate.transport.role 的值来识别您的连接端是哪个,尽管通常哪个是哪个并不重要。
控制代理不仅负责对使用哪个候选对做出最终决定,而且还负责在必要时使用 STUN 和更新的提议向受控代理发送该选择的信号。受控代理只是等待被告知要使用哪个候选对。
重要的是要记住,一个 ICE 会话可能会导致控制代理选择多个候选对。每次它这样做并将该信息与受控代理共享时,两个对等方都会重新配置其连接以使用新候选对描述的新配置。
一旦 ICE 会话完成,当前生效的配置就是最终配置,除非发生 ICE 重置。
在每代候选者结束后,会以 RTCIceCandidate 的形式发送一个候选者结束通知,其 candidate 属性是一个空字符串。此候选者仍应使用 addIceCandidate() 方法照常添加到连接中,以便将该通知传递给远程对等方。
当当前协商交换中不再有任何候选者时,会通过发送一个 RTCIceCandidate 来发送候选者结束通知,其 candidate 属性为 null。此消息 不需要 发送给远程对等方。它是状态的遗留通知,可以通过观察 iceGatheringState 变为 complete,或者通过观察 icegatheringstatechange 事件来检测。
当出现问题时
在协商过程中,总会有事情不如意的时候。例如,在重新协商一个已经激活的连接时——例如,为了适应不断变化的硬件或网络配置——协商可能会陷入僵局,或者发生某种形式的错误,从而完全阻止协商。此外,还可能存在权限问题或其他问题。
ICE 回滚
当重新协商一个已经激活的连接,并且出现协商失败的情况时,您并不希望终止正在运行的通话。毕竟,您很可能只是试图升级或降级连接,或者对正在进行的会话进行其他调整。在这种情况下,终止通话将是过度的反应。
相反,您可以启动 ICE 回滚。回滚将 SDP 提议(以及由此推断的连接配置)恢复到连接的 signalingState 为 stable 时的配置。
要以编程方式发起回滚,请发送一个 type 为 rollback 的描述。描述对象中的任何其他属性都将被忽略。
此外,当曾经创建过提议的对等方收到远程对等方的提议时,ICE 代理将自动发起回滚。换句话说,如果本地对等方处于 have-local-offer 状态,表示本地对等方之前 发送 了一个提议,那么使用 收到的 提议调用 setRemoteDescription() 将触发回滚,以便协商从远程对等方作为呼叫方切换到本地对等方作为呼叫方。
ICE 重启
了解 ICE 重启 过程。
复杂图表中的整个交换过程
