5.3.1. Initial Answers (初始应答)
5.3.1. Initial Answers (初始应答)
在已提供远程描述之后首次调用 createAnswer 时, 其结果称为初始应答。若尚未安装远程描述, 则无法生成应答, 且必须返回错误。
请注意, 远程描述 SDP 可能并非由 JSEP 端点创建, 也可能不符合第 5.2 节列出的全部要求。在许多情况下, 这没有问题。但是, 若缺少任何强制性 SDP 属性, 或上文列为强制使用的功能不存在, 则必须将其视为错误, 并必须导致受影响的 "m=" 段被标记为拒绝。
生成初始应答的第一步是生成会话级属性。此处的流程与上文第 5.2.1 节所示相同, 但 "a=ice-options" 行 (其中包含 [RFC8840] 第 4.1.3 节规定的 "trickle" 选项以及 [RFC8445] 第 10 节规定的 "ice2" 选项) 仅当报价中存在相应选项时才包含。
下一步是按 [RFC5888] 第 7 节的定义生成会话级唇音同步 (LS) 组。对于报价中出现的每个类型为 "LS" 的组, 选取 MID 值在所指定组中引用的本地 RtpTransceiver, 并确定其中哪些要么引用共同的本地 MediaStream (由创建它们时调用的 addTrack/addTransceiver 指定), 要么因并非由 addTrack/addTransceiver 创建而没有可引用的 MediaStream。若至少存在两个这样的 RtpTransceiver, 则必须添加一个类型为 "LS" 的组, 其 MID 值为这些 RtpTransceiver 的 MID。否则, 必须忽略报价中的 "LS" 组, 且不在应答中生成对应组。
举一个简单的例子, 考虑以下在同一 MediaStream 中包含单条音频与单条视频轨道的报价。为清晰起见, 已省略与本例无关的 SDP 行。如第 5.2 节所述, 已添加类型为 "LS" 的组, 引用每条轨道的 RtpTransceiver。
a=group:LS a1 v1
m=audio 10000 UDP/TLS/RTP/SAVPF 0
a=mid:a1
a=msid:ms1
m=video 10001 UDP/TLS/RTP/SAVPF 96
a=mid:v1
a=msid:ms1
若应答方在添加其轨道时使用单个 MediaStream, 则其两个收发器都将引用该流, 因此后续应答将包含与报价中相同的 "LS" 组, 如下所示:
a=group:LS a1 v1
m=audio 20000 UDP/TLS/RTP/SAVPF 0
a=mid:a1
a=msid:ms2
m=video 20001 UDP/TLS/RTP/SAVPF 96
a=mid:v1
a=msid:ms2
但是, 若应答方将其轨道划分到不同的 MediaStream, 则其收发器将引用不同的流, 因此后续应答将不包含 "LS" 组。
m=audio 20000 UDP/TLS/RTP/SAVPF 0
a=mid:a1
a=msid:ms2a
m=video 20001 UDP/TLS/RTP/SAVPF 96
a=mid:v1
a=msid:ms2b
最后, 若应答方未添加任何轨道, 则其收发器不会引用任何 MediaStream, 从而维持报价方的偏好, 因此后续应答将包含相同的 "LS" 组。
a=group:LS a1 v1
m=audio 20000 UDP/TLS/RTP/SAVPF 0
a=mid:a1
a=recvonly
m=video 20001 UDP/TLS/RTP/SAVPF 96
a=mid:v1
a=recvonly
第 7.2 节的示例展示了更复杂的 "LS" 组生成情形。
下一步是为远程报价中出现的每个 "m=" 段生成一个 "m=" 段, 如 [RFC3264] 第 6 节所述。就本讨论而言, 报价中凡可作为媒体级属性的会话级属性, 均视为存在于每个 "m=" 段中。每个被报价的 "m=" 段将有一个关联的 RtpTransceiver, 如第 5.10 节所述。若 RtpTransceiver 数量多于 "m=" 段数量, 则未匹配的 RtpTransceiver 需要在后续报价中关联。
对于每个被报价的 "m=" 段, 若以下任一条件成立, 则应答中对应的 "m=" 段必须通过将 "m=" 行中的 <port> 置零来标记为拒绝, 如 [RFC3264] 第 6 节所示, 并可跳过对该 "m=" 段的进一步处理:
-
关联的 RtpTransceiver 已停止。
-
不存在既受支持又 (若适用) 符合编解码器偏好所允许的报价媒体格式。
-
捆绑策略为 "max-bundle", 且该段不是第一个 "m=" 段, 也不与第一个 "m=" 段处于同一捆绑组。
-
捆绑策略为 "balanced", 且该段不是该媒体类型的第一个 "m=" 段, 也不与该媒体类型的第一个 "m=" 段处于同一捆绑组。
-
该 "m=" 段位于捆绑组中, 且该组的报价方标记 "m=" 段因上述原因之一正被拒绝。这要求捆绑组内所有 "m=" 段均被拒绝, 如 [RFC8843] 第 7.3.3 节所述。
否则, 应答中的每个 "m=" 段必须随后按 [RFC3264] 第 6.1 节生成。对于 "m=" 行本身, 必须遵循以下规则:
-
<port> 通常应设为此 "m=" 段的默认 ICE 候选的端口, 但鉴于尚无可用候选, 必须使用默认 <port> 值 9 (Discard), 如 [RFC8840] 第 4.1.1 节所示。
-
<proto> 字段必须设置为与报价中对应 "m=" 行的 <proto> 字段完全一致。
-
若已为关联收发器设置编解码器偏好, 则必须按相应顺序生成媒体格式, 无论报价顺序如何, 且必须排除偏好中未列出的任何编解码器。
-
否则, "m=" 行上的媒体格式必须按当前远程描述中的报价顺序生成, 排除当前不支持的格式。当前可用但不在当前远程描述中的任何媒体格式必须在所有已有格式之后添加。
-
无论哪种情况, 应答中的媒体格式必须至少包含报价中存在的一种格式, 但也可以包含本地支持但报价中未列出的格式, 如 [RFC3264] 第 6.1 节所述。若不存在共同格式, 则按上文所述拒绝该 "m=" 段。
"m=" 行之后必须立即跟 "c=" 行, 如 [RFC4566] 第 5.7 节所述。同样, 由于尚无候选, "c=" 行必须包含默认值 "IN IP4 0.0.0.0", 如 [RFC8840] 第 4.1.3 节所定义。
若报价支持捆绑, 所有待捆绑的 "m=" 段必须使用相同的 ICE 凭证与候选;所有不捆绑的 "m=" 段必须使用互不相同的 ICE 凭证与候选。每个 "m=" 段必须包含以下属性 (其类型既非 IDENTICAL 也非 TRANSPORT):
-
当且仅当报价中存在时, 添加 "a=mid" 行, 如 [RFC5888] 第 9.1 节所述。MID 值必须与报价中指定的一致。
-
方向属性, 通过应用 [RFC3264] 第 6.1 节关于报价方向的规则, 再与关联 RtpTransceiver 的方向求交确定。例如, 若 "m=" 段报价为 "sendonly" 而本地收发器设为 "sendrecv", 则应答中的结果为 "recvonly"。
-
对 "m=" 行上的每种媒体格式, 添加 "a=rtpmap" 与 "a=fmtp" 行, 如 [RFC4566] 第 6 节与 [RFC3264] 第 6.1 节所述。
-
若报价中存在 "rtx", 对于应使用 RTP 重传的每个主码, 添加相应的 "a=rtpmap" 行指明 "rtx" 及主码的时钟速率, 以及引用主码负载类型的 "a=fmtp" 行, 如 [RFC4588] 第 8.1 节所述。
-
对于每种受支持的 FEC 机制, 添加 "a=rtpmap" 与 "a=fmtp" 行, 如 [RFC4566] 第 6 节所述。必须支持的 FEC 机制见 [RFC8854] 第 7 节, 各媒体类型的具体用法见第 4 与第 5 节。
-
若此 "m=" 段用于每包媒体时长可配置的媒体 (例如音频), 添加 "a=maxptime" 行, 如第 5.2 节所述。
-
若此 "m=" 段用于视频媒体且已知可解码图像尺寸存在限制, 添加 "a=imageattr" 行, 如第 3.6 节所述。
-
对于报价中出现的每种受支持 RTP 头扩展, 添加 "a=extmap" 行, 如 [RFC5285] 第 5 节所述。应当/必须支持的头扩展列表见 [RFC8834] 第 5.2 节。需要加密的头扩展必须按 [RFC6904] 第 4 节指明。
-
对于报价中出现的每种受支持 RTCP 反馈机制, 添加 "a=rtcp-fb" 行, 如 [RFC4585] 第 4.2 节所述。应当/必须支持的 RTCP 反馈机制列表见 [RFC8834] 第 5.1 节。
-
若 RtpTransceiver 的方向为 sendrecv 或 sendonly:
- 对于在通过 addTrack 或 addTransceiver 创建收发器时与该收发器关联的每个 MediaStream, 添加 "a=msid" 行, 如 [RFC8830] 第 2 节所述, 但省略 "appdata" 字段。
每个未捆绑进另一 "m=" 段的 "m=" 段必须包含以下属性 (类别为 IDENTICAL 或 TRANSPORT):
-
"a=ice-ufrag" 与 "a=ice-pwd" 行, 如 [RFC8839] 第 5.4 节所述。
-
对每个所需的摘要算法, 为端点每个证书添加一条或多条 "a=fingerprint" 行, 如 [RFC8122] 第 5 节所述。
-
"a=setup" 行, 如 [RFC4145] 第 4 节所述, 并在 [RFC5763] 第 5 节中澄清用于 DTLS-SRTP。应答中的角色值必须为 "active" 或 "passive"。当报价包含 "actpass" 值时 (对 JSEP 端点总是如此), 应答方应当使用 "active" 角色。来自非 JSEP 端点的报价可以为 "a=setup" 发送其他值, 此时应答必须使用与报价一致的值。
-
"a=tls-id" 行, 如 [RFC8842] 第 5.3 节所述。
-
若报价中存在, 添加 "a=rtcp-mux" 行, 如 [RFC5761] 第 5.1.3 节所述。否则, 添加 "a=rtcp" 行, 如 [RFC3605] 第 2.1 节所述, 内容为默认值 "9 IN IP4 0.0.0.0" (因为尚未收集候选)。
-
若报价中存在, 添加 "a=rtcp-rsize" 行, 如 [RFC5506] 第 5 节所述。
若已报价数据信道 "m=" 段, 还必须为数据生成 "m=" 段。<media> 字段必须设为 "application", <proto> 与 <fmt> 字段必须与报价中的字段完全一致。
在数据 "m=" 段内, 必须按上文生成并包含 "a=mid" 行, 以及引用 SCTP 端口号的 "a=sctp-port" 行, 如 [RFC8841] 第 5.1 节所定义;并在适当时包含 "a=max-message-size" 行, 如 [RFC8841] 第 6.1 节所定义。
如上所述, 以下 IDENTICAL 或 TRANSPORT 类别的属性仅当数据 "m=" 段未捆绑进另一 "m=" 段时才包含:
-
"a=ice-ufrag"
-
"a=ice-pwd"
-
"a=fingerprint"
-
"a=setup"
-
"a=tls-id"
请注意, 若媒体 "m=" 段被捆绑进数据 "m=" 段, 则某些 TRANSPORT 与 IDENTICAL 属性也可能出现在数据 "m=" 段中, 即使它们否则仅适用于媒体 "m=" 段 (例如 "a=rtcp-mux")。
若报价了语义为 "BUNDLE" 的 "a=group" 属性, 必须按 [RFC5888] 添加相应的会话级 "a=group" 属性。这些属性的语义必须为 "BUNDLE", 且必须包含未被拒绝的报价捆绑组中的所有 mid 标识符。请注意, 无论报价中是否存在 "a=bundle-only", 应答中的所有 "m=" 段都不得包含 "a=bundle-only" 行。
若明确定义可在会话级有效, 则所有 "m=" 段之间共有的属性可以移到会话级。
创建报价时禁止出现的属性, 在创建应答时同样禁止。