跳到主要内容

3.2 Session Descriptions and State Machine (会话描述和状态机)

3.2 Session Descriptions and State Machine (会话描述和状态机)

为了建立媒体平面, JSEP 实现需要特定的参数来指示向远程端传输什么, 以及如何处理接收到的媒体。这些参数由 offer 和 answer 中会话描述的交换确定, 并且此过程中有某些必须在 JSEP API 中处理的细节。

会话描述适用于本地端还是远程端会影响该描述的含义。例如, 发送给远程方的编解码器列表表示本地端愿意接收什么, 当与远程端支持的编解码器集相交时, 指定远程端应该发送什么。然而, 并非所有参数都遵循此规则; 某些参数是声明性的, 远程端必须完全接受或拒绝它们。此类参数的一个示例是在 DTLS [RFC6347] 上下文中使用的 TLS 指纹 [RFC8122]; 这些指纹是基于提供的本地证书计算的, 不受协商约束。

此外, 各种 RFC 对 offer 和 answer 的格式设置了不同的条件。例如, offer 可以提议任意数量的 "m=" 部分 (即 [RFC4566] 第 5.14 节中描述的媒体描述), 但 answer 必须包含与 offer 完全相同的数量。

最后, 虽然确切的媒体参数只有在交换了 offer 和 answer 之后才知道, 但 offerer 可能会在收到 answer 之前接收 ICE 检查, 以及可能的媒体 (例如, 在建立连接后重新 offer 的情况下)。为了在这种情况下正确处理传入的媒体, offerer 的媒体处理程序必须在 answer 到达之前了解 offer 的详细信息。

因此, 为了正确处理会话描述, JSEP 实现需要:

  1. 知道会话描述是属于本地端还是远程端。

  2. 知道会话描述是 offer 还是 answer。

  3. 允许独立于 answer 指定 offer。

JSEP 通过添加 setLocalDescription 和 setRemoteDescription 方法并让会话描述对象包含指示所提供的会话描述类型的类型字段来解决此问题。这满足了上面列出的 offerer 的要求, offerer 首先调用 setLocalDescription(sdp [offer]), 然后稍后调用 setRemoteDescription(sdp [answer]), 以及 answerer 的要求, answerer 首先调用 setRemoteDescription(sdp [offer]), 然后稍后调用 setLocalDescription(sdp [answer])。

在 offer/answer 交换期间, 未完成的 offer 在 offerer 和 answerer 处被视为 "pending", 因为它可能被接受或拒绝。如果这是一个 re-offer, 每一方还将拥有 "current" 本地和远程描述, 这些描述反映了上一次 offer/answer 交换的结果。第 4.1.14, 4.1.16, 4.1.13 和 4.1.15 节提供了有关 pending 和 current 描述的更多详细信息。

JSEP 还允许应用程序将 answer 视为临时的 (provisional)。临时 answer 为 answerer 提供了一种向 offerer 传达初始会话参数的方法, 以便允许会话开始, 同时允许稍后指定最终 answer。最终 answer 的概念对于 offer/answer 模型很重要; 当收到这样的 answer 时, 现在知道确切的会话配置, 调用者分配的任何额外资源都可以被释放。这些 "资源" 可以包括诸如额外的 ICE 组件, Traversal Using Relays around NAT (TURN) 候选者或视频解码器之类的东西。另一方面, 临时 answer 不进行这种释放; 因此, 在呼叫建立期间可以接收和应用多个不同的临时 answer, 具有它们自己的编解码器选择, 传输参数等。请注意, 最终 answer 本身可能与任何接收到的临时 answer 不同。

在 [RFC3264] 中, 信令级别的约束是对于给定的会话只能有一个未完成的 offer, 但在 JSEP 级别, 可以在任何时候生成新的 offer。例如, 当使用 SIP 进行信令时, 如果发送了一个 offer 然后使用 SIP CANCEL 取消, 则即使没有收到第一个 offer 的 answer, 也可以生成另一个 offer。为了支持这一点, JSEP 媒体层可以在 JavaScript 应用程序需要用于信令时通过 createOffer 方法提供 offer。answerer 可以发送回零个或多个临时 answer, 然后最终通过发送最终 answer 来结束 offer/answer 交换。其状态机如下:

                    setRemote(OFFER)               setLocal(PRANSWER)
/-----\ /-----\
| | | |
v | v |
+---------------+ | +---------------+ |
| |----/ | |----/
| have- | setLocal(PRANSWER) | have- |
| remote-offer |------------------- >| local-pranswer|
| | | |
| | | |
+---------------+ +---------------+
^ | |
| | setLocal(ANSWER) |
setRemote(OFFER) | |
| V setLocal(ANSWER) |
+---------------+ |
| | |
| |<---------------------------+
| stable |
| |<---------------------------+
| | |
+---------------+ setRemote(ANSWER) |
^ | |
| | setLocal(OFFER) |
setRemote(ANSWER) | |
| V |
+---------------+ +---------------+
| | | |
| have- | setRemote(PRANSWER) |have- |
| local-offer |------------------- >|remote-pranswer|
| | | |
| |----\ | |----\
+---------------+ | +---------------+ |
^ | ^ |
| | | |
\-----/ \-----/
setLocal(OFFER) setRemote(PRANSWER)

Figure 2: JSEP State Machine

除了这些状态转换之外, 临时 ("pranswer") 和最终 ("answer") answer 的处理之间没有其他区别。