4. 发送初始 Offer (Sending the Initial Offer)
为了在 offer/answer 交换中发送 initial offer, agent 必须执行以下步骤: (1) 收集 candidates, (2) 对其排序并赋予优先级, (3) 消除冗余 candidates, (4) 选择 default candidates, 然后 (5) 构造并发送 SDP offer. 这五个步骤中除最后一步外, full implementation 与 lite implementation 的处理均不同.
4.1. Full Implementation 需求 (Full Implementation Requirements)
4.1.1. 收集 Candidates (Gathering Candidates)
当 agent 认为通信即将发生时, 它会收集 candidates. Offerer 可以基于用户界面提示或基于发起会话的显式请求来执行此操作. 每个 candidate 都是一个 transport address. 它还具有 type 和 base. 本规范定义并收集四种类型: host candidates, server reflexive candidates, peer reflexive candidates 和 relayed candidates. Server reflexive candidates 使用 STUN 或 TURN 收集, relayed candidates 通过 TURN 获得. Peer reflexive candidates 在 ICE 后续阶段作为 connectivity checks 的结果获得. Candidate 的 base 是 agent 在使用该 candidate 时必须从其发送的 candidate.
4.1.1.1. Host Candidates (主机候选)
第一步是收集 host candidates. Host candidates 通过在主机上某个接口, 物理或虚拟接口, 包括 VPN 接口, 所附着的 IP 地址上绑定端口, 通常是临时端口, 而获得.
对于 agent 希望使用的每个 UDP media stream, agent 应该在主机拥有的每个 IP 地址上为该 media stream 的每个 component 获得一个 candidate. 它通过在特定 IP 地址上绑定 UDP 端口来获得每个 candidate. Host candidate, 事实上每个 candidate, 始终与其作为 candidate 的特定 component 关联. 每个 component 都有一个分配给它的 ID, 称为 component ID. 对基于 RTP 的 media streams, RTP 本身的 component ID 为 1, RTCP 的 component ID 为 2. 如果 agent 使用 RTCP, 它 必须为 RTCP 获得 candidate. 如果 agent 同时使用 RTP 和 RTCP, 且 agent 有 K 个 IP 地址, 它最终会有 2*K 个 host candidates.
每个 host candidate 的 base 设置为该 candidate 本身.
4.1.1.2. Server Reflexive 和 Relayed Candidates
Agents 应该获得 relayed candidates, 并且 应该获得 server reflexive candidates. 这些要求使用 应该强度, 是为了允许提供商差异. 在封闭网络中, 如果 agents 从不连接到公共 Internet, 也不连接到封闭网络外部端点, 使用 STUN 和 TURN servers 可能并非必要. 在这类情况下, 对于双栈或多宿主 agents, 将使用 full implementation 来选择 host candidate. TURN servers 的使用成本较高, 且在使用 ICE 时, 只有当两个端点都位于执行地址和端口依赖映射的 NAT 后面时才会用到它们. 因此, 某些部署可能认为此使用场景较边缘, 并选择不使用 TURN servers. 如果 agent 不收集 server reflexive 或 relayed candidates, 则 推荐实现该功能并仅通过配置禁用, 以便在未来条件变化时可通过配置重新启用.
如果 agent 同时收集 relayed 和 server reflexive candidates, 它使用 TURN server. 如果只收集 server reflexive candidates, 它使用 STUN server.
Agent 接下来将每个 host candidate 与其已配置或通过某种方式发现的 STUN 或 TURN server 配对. 如果配置了 STUN 或 TURN server, 则 推荐配置域名, 并使用 [RFC5389] 中的 DNS 过程, 即使用带有 "stun" service 的 SRV records, 发现 STUN server; 使用 [RFC5766] 中的 DNS 过程, 即使用带有 "turn" service 的 SRV records, 发现 TURN server.
本规范只考虑使用单个 STUN 或 TURN server. 当该单个 STUN 或 TURN server 有多个选择时, 例如通过 DNS records 学到且返回多个结果, agent 应该对特定会话的所有 candidates 使用同一个 STUN 或 TURN server, 按 IP 地址区分. 这会提高 ICE 性能. 结果是一组 host candidates 与 STUN 或 TURN servers 的 pairs. 然后 agent 选择一个 pair, 并从该 host candidate 向 server 发送 Binding 或 Allocate request. 发送到 STUN server 的 Binding requests 不进行认证, 响应中的任何 ALTERNATE-SERVER 属性都会被忽略. Agents 必须支持 [RFC5389] 中为 Binding request 定义的向后兼容模式. Allocate requests 应该使用 client 通过其他方式获得的长期凭据进行认证.
此后每隔 Ta 毫秒, agent 可以生成另一个新的 STUN 或 TURN transaction. 该 transaction 可以是先前因可恢复错误, 例如认证失败, 而失败的 transaction 的重试, 也可以是针对新的 host candidate 和 STUN 或 TURN server pair 的 transaction. Agent 不应该以高于每 Ta 毫秒一次的频率生成 transactions. 关于如何设置 Ta 和 STUN retransmit timer RTO, 见第 16 节.
Agent 会收到 Binding 或 Allocate response. 成功的 Allocate response 会向 agent 提供一个 server reflexive candidate, 从 mapped address 获得, 以及 XOR-RELAYED-ADDRESS 属性中的 relayed candidate. 如果 Allocate request 因 server 缺少资源无法满足而被拒绝, agent 应该改为发送 Binding request 以获得 server reflexive candidate. Binding response 只会向 agent 提供 server reflexive candidate, 同样从 mapped address 获得. Server reflexive candidate 的 base 是发送 Allocate 或 Binding request 的 host candidate. Relayed candidate 的 base 是该 candidate 本身. 如果 relayed candidate 与 host candidate 相同, 这在罕见情况下可能发生, 则该 relayed candidate 必须被丢弃.
4.1.1.3. 计算 Foundations (Computing Foundations)
最后, agent 为每个 candidate 分配 foundation. Foundation 是一个在会话范围内的标识符. 当以下所有条件为真时, 两个 candidates 必须具有相同 foundation ID:
- 它们类型相同, 即 host, relayed, server reflexive 或 peer reflexive.
- 它们的 bases 具有相同 IP 地址, 端口可以不同.
- 对 reflexive 和 relayed candidates, 用于获得它们的 STUN 或 TURN servers 具有相同 IP 地址.
- 它们使用相同传输协议获得, 例如 TCP, UDP 等.
类似地, 如果两个 candidates 类型不同, bases 具有不同 IP 地址, 用于获得它们的 STUN 或 TURN servers 具有不同 IP 地址, 或传输协议不同, 则它们 必须具有不同 foundations.
4.1.1.4. 保持 Candidates 存活 (Keeping Candidates Alive)
一旦 server reflexive 和 relayed candidates 已分配, 它们 必须按第 8.3 节所述保持存活, 直到 ICE processing 完成. 对通过 Binding request 学到的 server reflexive candidates, 绑定 必须通过向 server 发送附加 Binding requests 来保持存活. Allocation 的刷新使用 Refresh transaction 完成, 如 [RFC5766] 所述. Refresh requests 也会刷新 server reflexive candidate.
4.1.2. 确定 Candidates 优先级 (Prioritizing Candidates)
Prioritization 过程会为每个 candidate 分配 priority. 媒体流中的每个 candidate 必须具有唯一 priority, 且该 priority 必须是 1 到 (2**31 - 1) 之间的正整数. ICE 将使用该 priority 确定 connectivity checks 的顺序以及 candidates 的相对偏好.
Agent 应该使用第 4.1.2.1 节中的公式计算该 priority, 并使用第 4.1.2.2 节中的指导选择参数. 如果 agent 选择使用不同公式, ICE 将需要更长时间收敛, 因为两个 agents 的 checks 不会协调一致.
4.1.2.1. 推荐公式 (Recommended Formula)
使用该公式时, agent 通过确定每类 candidate, 即 server reflexive, peer reflexive, relayed 和 host, 的 preference, 并在 agent 多宿主时选择其 IP 地址的 preference, 来计算 priority. 这两个 preference 随后组合起来计算 candidate 的 priority. 该 priority 使用以下公式计算:
priority = (2^24)*(type preference) +
(2^8)*(local preference) +
(2^0)*(256 - component ID)
Type preference 必须是 0 到 126, 含边界, 之间的整数, 表示 candidate 类型的偏好, 这些类型包括 local, server reflexive, peer reflexive 和 relayed. 126 是最高偏好, 0 是最低偏好. 将值设为 0 表示此类型的 candidates 只会作为最后手段使用. 同一类型所有 candidates 的 type preference 必须相同, 不同类型 candidates 的 type preference 必须不同. Peer reflexive candidates 的 type preference 必须高于 server reflexive candidates. 注意, 基于第 4.1.1 节过程收集的 candidates 永远不会是 peer reflexive candidates; 此类型 candidates 是从 ICE 执行的 connectivity checks 中学到的.
Local preference 必须是 0 到 65535, 含边界, 之间的整数. 在 agent 多宿主的情况下, 它表示对获得该 candidate 的特定 IP 地址的偏好. 65535 表示最高偏好, 0 表示最低偏好. 当只有单个 IP 地址时, 该值 应该设置为 65535. 更一般地, 如果某个媒体流的特定 component 有多个同类型 candidates, local preference 必须对每个 candidate 唯一. 在本规范中, 这只会发生在多宿主主机上. 如果主机因双栈而多宿主, local preference 应该设置为 RFC 3484 [RFC3484] 中描述的 IP 地址 precedence value.
Component ID 是该 candidate 的 component ID, 必须在 1 到 256, 含边界, 之间.
4.1.2.2. 选择 Type 和 Local Preferences 的指导 (Guidelines for Choosing Type and Local Preferences)
选择 type 和 local preference 值的一个准则是是否使用媒体中介, 例如 TURN server, VPN server 或 NAT. 使用媒体中介时, 如果媒体发送到该 candidate, 它在被接收前会先经过该媒体中介. Relayed candidates 是涉及媒体中介的一类 candidate. 另一类是从 VPN interface 获得的 host candidates. 当媒体经过媒体中介传输时, 可能增加发送与接收之间的时延. 它也可能增加丢包, 因为可能经过额外的路由跳数. 它还可能增加提供服务的成本, 因为媒体会进入并立即离开由 provider 运行的媒体中介. 如果这些顾虑很重要, relayed candidates 的 type preference 应该低于 host candidates. 推荐值为: host candidates 126, server reflexive candidates 100, peer reflexive candidates 110, relayed candidates 0. 此外, 如果 agent 多宿主且有多个 IP 地址, 来自 VPN interface 的 host candidates 的 local preference 应该具有 0 priority.
选择 preferences 的另一个准则是 IP 地址族. ICE 同时适用于 IPv4 和 IPv6. 因此它提供了一种过渡机制, 允许双栈主机优先使用 IPv6 连通性, 但在 v6 网络断开时, 例如由于 6to4 relay 失败 [RFC3056], 回退到 IPv4. 它也可以帮助同时具有 native IPv6 地址和 6to4 地址的主机. 在这种情况下, 可以为 v6 地址分配较高 local preferences, 随后是 6to4 地址, 再随后是 v4 地址. 这允许站点立即获得并开始使用 native v6 地址, 同时在与尚不具备 native v6 连通性的其他站点中的 agents 通信时仍可回退到 6to4 地址.
选择 preferences 的另一个准则是安全性. 如果用户是远程办公者, 因此同时连接到企业网络和本地家庭网络, 则在企业内部通信时, 用户可能希望语音流量经由 VPN 路由以保持在企业网络内; 而在与企业外用户通信时使用本地网络. 在这种情况下, VPN 地址会具有高于任何其他地址的 local preference.
选择 preferences 的另一个准则是拓扑感知. 这对使用中介的 candidates 最有用. 在这些情况下, 如果 agent 预配置或动态发现了中介相对于自身的拓扑接近程度, 它可以利用该信息为从较近中介获得的 candidates 分配更高 local preferences.
4.1.3. 消除冗余 Candidates (Eliminating Redundant Candidates)
接下来, agent 消除冗余 candidates. 如果一个 candidate 的 transport address 等于另一个 candidate, 且其 base 等于另一个 candidate 的 base, 则该 candidate 是冗余的. 注意, 两个 candidates 可以具有相同 transport address 但具有不同 bases, 这种情况不被认为冗余. 当 agent 不在 NAT 后面时, server reflexive candidate 和 host candidate 经常会冗余. Agent 应该消除 priority 较低的冗余 candidate.
4.1.4. 选择 Default Candidates (Choosing Default Candidates)
如果某个 candidate 会成为来自非 ICE peer 的媒体目标, 则称其为 default; 该目标称为 DEFAULT DESTINATION. 当与 ICE-aware peer 通信时, 如果 default candidates 未被 ICE algorithm 选中, 则 ICE processing 完成后需要 updated offer/answer 来 "fix up" SDP, 使媒体的 default destination 与 ICE 选中的 candidates 匹配. 如果 ICE 恰好选中了 default candidates, 则不需要 updated offer/answer.
Agent 必须选择一组 candidates 作为 default, 对每个正在使用的 media stream 的每个 component 选择一个. 如果 media stream 的端口不是零, 则它正在使用; 端口零在 RFC 3264 中用于拒绝 media stream. 因此, 即使 media stream 被标记为 a=inactive [RFC4566] 或带宽值为零, 它仍被认为正在使用.
推荐基于这些 candidates 与正在联系的 peer 一起工作的可能性来选择 default candidates. 推荐的 default candidates 顺序为: relayed candidates, 如果有 relayed candidates; server reflexive candidates, 如果有 server reflexive candidates; 最后是 host candidates.
4.2. Lite Implementation 需求 (Lite Implementation Requirements)
Lite implementations 只使用 host candidates. Lite implementation 必须为每个 media stream 的每个 component 分配零个或一个 IPv4 candidates. 它 可以分配零个或多个 IPv6 candidates, 但对 host 使用的每个 IPv6 地址, 每个地址不得超过一个. 由于每个 media stream 的每个 component 最多只能有一个 IPv4 candidate, 如果 agent 有多个 IPv4 地址, 它 必须选择其中一个用于分配 candidate. 如果 host 是双栈, 推荐分配一个 IPv4 candidate 和一个 global IPv6 address. 对 lite implementation, ICE 不能用于在 candidates 之间动态选择. 因此, 不 推荐包含来自特定 scope 的多个 candidate, 因为只有 connectivity check 才能真正确定应使用一个地址还是另一个地址.
每个 component 都有一个分配给它的 ID, 称为 component ID. 对基于 RTP 的 media streams, RTP 本身的 component ID 为 1, RTCP 的 component ID 为 2. 如果 agent 使用 RTCP, 它 必须为其获得 candidates.
每个 candidate 被分配一个 foundation. 对从不同 IP 地址分配的两个 candidates, foundation 必须不同; 否则 foundation 必须相同. 对每个 IP 地址递增的简单整数即可满足要求. 此外, 每个 candidate 必须在同一 media stream 的所有 candidates 中被分配唯一 priority. 该 priority 应该等于:
priority = (2^24)*(126) +
(2^8)*(IP precedence) +
(2^0)*(256 - component ID)
如果 host 仅支持 v4, 它 应该将 IP precedence 设置为 65535. 如果 host 支持 v6 或双栈, IP precedence 应该是 RFC 3484 [RFC3484] 中描述的 IP 地址 precedence value.
接下来, agent 为每个 media stream 的每个 component 选择 default candidate. 如果 host 仅支持 IPv4, 每个 media stream 的每个 component 只有一个 candidate, 因而该 candidate 就是 default. 如果 host 支持 IPv6 或双栈, default 的选择属于本地策略事项. 该 default 应该被选择为最可能与 peer 一起使用的 candidate. 对仅 IPv6 的 hosts, 这通常是 globally scoped IPv6 address. 对双栈 hosts, 推荐使用 IPv4 address.
4.3. 编码 SDP (Encoding the SDP)
SDP 编码过程在 full 和 lite implementations 之间相同.
Agent 将为其希望使用的每个 media stream 包含一条 m line. SDP 中 media streams 的顺序对 ICE 有意义. ICE 会先对第一条 m line 执行 connectivity checks, 因此该 stream 的媒体将最先能够流动. Agents 应该将最重要的 media stream, 如果存在, 放在 SDP 的最前面.
对特定 media stream 的每个 candidate, 都会有一个 candidate attribute. 第 15 节提供了构造该属性的详细规则. 该属性携带 candidate 的 IP 地址, 端口和传输协议, 以及为了让 ICE 工作而需要向 peer 发信令的 candidate 属性: priority, foundation 和 component ID. Candidate attribute 还携带对诊断和其他功能有用的 candidate 信息: 其 type 和 related transport addresses.
Agents 之间的 STUN connectivity checks 使用 STUN [RFC5389] 定义的 short-term credential mechanism 进行认证. 该机制依赖通过 client 和 server 之间的协议机制交换的 username 和 password. 在 ICE 中, offer/answer 交换用于交换它们. 此 credential 的 username 部分由每个 agent 的 username fragment 拼接形成, 中间用冒号分隔. 每个 agent 还提供 password, 用于计算其收到 requests 的 message integrity. Username fragment 和 password 分别在 ice-ufrag 和 ice-pwd 属性中交换. 除了提供安全性外, username 还为 checks 与 media streams 的消歧和关联提供支持. 动机见 Appendix B.4.
如果 agent 是 lite implementation, 它 必须在其 SDP 中包含一个 "a=ice-lite" session-level attribute. 如果 agent 是 full implementation, 它 不得包含该属性.
Default candidates 作为媒体的 default destination 加入 SDP. 对基于 RTP 的 streams, 这是通过分别将 RTP candidate 的 IP 地址和端口放入 c 和 m lines 完成的. 如果 agent 使用 RTCP, 它 必须使用 RFC 3605 [RFC3605] 中定义的 a=rtcp 属性编码 RTCP candidate. 如果不使用 RTCP, agent 必须使用 RFC 3556 [RFC3556] 中定义的 b=RS:0 和 b=RR:0 发信令说明.
与非 ICE peers 通信时将作为媒体 default destination 的 transport addresses 必须也作为 candidates 出现在一个或多个 a=candidate lines 中.
ICE 通过允许 offer 或 answer 包含一系列 tokens 来提供可扩展性, 这些 tokens 标识该 agent 使用的 ICE extensions. 如果 agent 支持某个 ICE extension, 它 必须在 ice-options 属性中包含为该 extension 定义的 token.
以下是包含 ICE 属性的 SDP message 示例, 为便于阅读折行:
v=0
o=jdoe 2890844526 2890842807 IN IP4 10.0.1.1
s=
c=IN IP4 192.0.2.3
t=0 0
a=ice-pwd:asd88fgpdd777uzjYhagZg
a=ice-ufrag:8hhY
m=audio 45664 RTP/AVP 0
b=RS:0
b=RR:0
a=rtpmap:0 PCMU/8000
a=candidate:1 1 UDP 2130706431 10.0.1.1 8998 typ host
a=candidate:2 1 UDP 1694498815 192.0.2.3 45664 typ srflx raddr
10.0.1.1 rport 8998
一旦 agent 发送其 offer 或 answer, 该 agent 必须准备在每个 candidate 上接收 STUN 和 media packets. 如第 11.1 节所述, media packets 可以在 candidate 作为媒体 default destination 出现在 offer 或 answer 中之前发送到该 candidate.