跳到主要内容

8. SSRC 标识符的分配与使用 (SSRC Identifier Allocation and Use)

承载于 RTP 头部以及 RTCP 包的各个字段中的 SSRC 标识符, 是一个随机的 32 位数, 要求在单个 RTP 会话内全局唯一。至关重要的是, 必须谨慎地选择这个数, 以使在同一网络上或同时启动的参与者不太可能选择相同的数。

仅仅使用本地网络地址 (如一个 IPv4 地址) 作为标识符是不够的, 因为该地址可能并不唯一。由于 RTP 转换器和混合器使得具有不同地址空间的多个网络之间能够互操作, 两个空间内地址的分配模式可能导致比随机分配高得多的冲突率。

在同一主机上运行的多个源也会发生冲突。

仅仅通过调用 random() 而不仔细初始化其状态来获取一个 SSRC 标识符, 也是不够的。如何生成一个随机标识符的示例见附录 A.6。

8.1 冲突概率 (Probability of Collision)​

由于标识符是随机选取的, 两个或多个源选取相同数字是有可能的。当所有源同时启动时 (例如由某个会话管理事件自动触发), 冲突以最高概率发生。如果 N 是源的数量, L 是标识符的长度 (此处为 32 位), 那么两个源独立选取相同值的概率, 对于较大的 N 可近似 [26] 为 1 - exp(-N2 / 2(L+1))。当 N=1000 时, 概率大约为 10**-4。

典型的冲突概率远低于上述最坏情况。当一个新源加入到一个所有其他源都已拥有唯一标识符的 RTP 会话时, 冲突的概率仅等于该空间中被使用的数字的比例。再次地, 如果 N 是源的数量, L 是标识符的长度, 冲突概率为 N / 2L。当 N=1000 时, 概率大约为 2*10-7。

冲突的概率还会进一步降低, 因为一个新源在发送它的第一个包 (数据或控制) 之前, 有机会从其他参与者那里接收包。如果新源跟踪其他参与者 (通过 SSRC 标识符), 那么

在发送它的第一个包之前, 新源可以验证它的标识符不与任何已接收到的标识符冲突, 否则就重新选择。

8.2 冲突解决与环路检测 (Collision Resolution and Loop Detection)​

尽管 SSRC 标识符冲突的概率很低, 但所有 RTP 实现 MUST 准备好检测冲突, 并采取恰当的动作来解决它们。如果一个源在任何时候发现另一个源正在使用与它自己的 SSRC 标识符相同的标识符, 它 MUST 为旧标识符发送一个 RTCP BYE 包, 并选择另一个随机的标识符。(如下文所解释的, 在环路情形下, 这一步仅执行一次。) 如果一个接收方发现另外两个源正在冲突, 当这可以通过不同的源传输地址或 CNAME 检测到时, 它 MAY 保留来自其中一个源的包, 而丢弃来自另一个源的包。这两个源被期望解决该冲突, 以使这种情况不会持续。

由于随机 SSRC 标识符在每个 RTP 会话内保持全局唯一, 它们也可以被用来检测可能由混合器或转换器引入的环路。一个环路导致数据和控制信息的重复, 这些重复可能是未经修改的, 也可能是被混合过的, 如以下示例:

o 一个转换器可能不正确地将一个包转发到它从中接收到该包的同一个多播组, 无论是直接地, 还是经由一条转换器链。在这种情况下, 同一个包出现多次, 源自不同的网络源。

o 两个错误地并联配置的转换器 (即两侧具有相同的多播组) 会将包从一个多播组转发到另一个。单向转换器会产生两个副本; 双向转换器会形成环路。

o 一个混合器可以通过直接地, 或经由另一个混合器或转换器, 向它接收包的同一个传输目的地发送包, 从而闭合一个环路。在这种情况下, 一个源可能既作为一个数据包上的 SSRC, 又作为一个混合数据包中的 CSRC 出现。

一个源可能发现它自己的包正在被环回, 或者来自另一个源的包正在被环回 (第三方环路)。在随机选取源标识符时的环路和冲突, 都会导致包以相同的 SSRC 标识符但不同的源传输地址到达, 该地址可能是发出该包的端系统的地址, 也可能是某个中间系统的地址。

因此, 如果一个源改变了它的源传输地址, 它 MAY 也选择一个新的 SSRC 标识符, 以避免被解释为一个被环回的源。(这不是 MUST, 因为在 RTP 的某些应用中, 源可能在会话期间预期会更改地址。) 注意, 如果一个转换器重启并因而改变了它转发包所使用的源传输地址 (例如改变了 UDP 源端口号), 那么所有这些包在接收方看来都像是被环回了, 因为 SSRC 标识符是由原始源施加的, 并不会改变。这个问题可以通过在重启期间保持源传输地址固定来避免, 但无论如何, 它都会在接收方处超时之后被解决。

发生在转换器或混合器远端的环路或冲突, 如果包的所有副本都经过该转换器或混合器, 则无法使用源传输地址检测到; 然而, 当两个 RTCP SDES 包中的块包含相同的 SSRC 标识符但不同的 CNAME 时, 冲突仍可能被检测到。

为了检测和解决这些冲突, 一个 RTP 实现 MUST 包含一种类似于下文所描述的算法, 尽管实现 MAY 为保留来自冲突的第三方源的哪些包选择不同的策略。下文描述的算法会忽略来自与一个已建立源冲突的新源或环路的包。它通过为旧标识符发送一个 RTCP BYE 包并选择一个新的标识符, 来解决与参与者自己 SSRC 标识符的冲突。然而, 当冲突是由参与者自己的包的环路所诱发时, 该算法将只选择一次新标识符, 此后忽略来自该环路源传输地址的包。这是为了避免 BYE 包的洪泛。

该算法需要维护一个以源标识符为索引的表, 其中包含在以该标识符接收到的第一个 RTP 包和第一个 RTCP 包中的源传输地址, 以及该源的其他状态。需要两个源传输地址, 因为例如 RTP 和 RTCP 包上的 UDP 源端口号可能不同。然而, 可以假定两个源传输地址中的网络地址是相同的。

在 RTP 或 RTCP 包中接收到的每个 SSRC 或 CSRC 标识符, 都会在源标识符表中查找, 以便处理该数据或控制信息。包中的源传输地址会与表中该标识符对应的源传输地址进行比较, 若不匹配则检测到一个环路或冲突。对于控制包, 每个带有它自己 SSRC 标识符的元素 (例如一个 SDES 块) 都需要单独的查找。(接收报告块中的 SSRC 标识符是一个例外, 因为它标识的是报告方所听到的源, 而该 SSRC 标识符与报告方所发送 RTCP 包的源传输地址无关。) 如果未找到 SSRC 或 CSRC, 则创建一个新的条目。当接收到带有相应 SSRC 标识符、且由匹配的源传输地址验证通过的 RTCP BYE 包时, 或者当在相对较长的时间内 (见第 6.2.1 节) 没有包到达时, 这些表条目会被移除。

注意, 如果在接收方开始运作时, 同一主机上的两个源正以相同的源标识符进行传输, 有可能第一个接收到的 RTP 包来自其中一个源, 而第一个接收到的 RTCP 包来自另一个源。这会导致错误的 RTCP 信息与 RTP 数据相关联, 但这种情况应当足够罕见且无害, 因而可以忽略。

为了跟踪参与者自己数据包的环路, 实现 MUST 还维护一个单独的、被发现存在冲突的源传输地址 (而非标识符) 列表。如同源标识符表一样, MUST 保持两个源传输地址, 以分别跟踪冲突的 RTP 和 RTCP 包。注意, 冲突地址列表应当很短, 通常为空。该列表中的每个元素存储源地址, 以及最近一次接收到冲突包的时间。当一个源在大约 10 个 RTCP 报告间隔 (见第 6.2 节) 的时间内没有从该源到达冲突包时, 该元素 MAY 被从列表中移除。

对于如所示的算法, 假定参与者的自己的源标识符和状态包含在源标识符表中。该算法也可以被重构为先针对参与者自己的源标识符进行一次单独的对比。

  if (SSRC 或 CSRC 标识符未在源标识符表中找到) {
创建一个新的条目, 存储数据或控制源传输地址、
SSRC 或 CSRC 以及其他状态;
}

/* 标识符在表中找到 */

else if (表条目是在收到一个控制包时创建的
而这是第一个数据包, 或反之) {
存储来自此包的源传输地址;
}
else if (来自包的源传输地址与表中为该标识符
保存的地址不匹配) {

/* 指示了一个标识符冲突或环路 */

if (源标识符不是参与者自己的) {
/* 可选的错误计数步骤 */
if (源标识符来自一个包含 CNAME 项的 RTCP SDES 块,
且该 CNAME 与表条目中的 CNAME 不同) {
计为一次第三方冲突;
} else {
计为一次第三方环路;
}
中止该数据包或控制元素的处理;
/* MAY 选择不同的策略以保留新源 */
}

/* 参与者自己包的冲突或环路 */

else if (源传输地址在冲突的数据或控制源传输
地址列表中被找到) {
/* 可选的错误计数步骤 */
if (源标识符不是来自一个包含 CNAME 项的 RTCP SDES 块,
或者 CNAME 是参与者自己的) {
计为一次自身流量被环回的发生;
}
在冲突地址列表条目中标记当前时间;
中止该数据包或控制元素的处理;
}

/* 新的冲突, 改变 SSRC 标识符 */

else {
记录一次冲突的发生;
在冲突的数据或控制源传输地址列表中创建一个
新条目并标记当前时间;
发送一个带有旧 SSRC 标识符的 RTCP BYE 包;
选择一个新的 SSRC 标识符;
在源标识符表中创建一个新条目, 包含旧的 SSRC
以及正在处理的数据或控制包的源传输地址;
}
}

在此算法中, 来自一个新冲突源地址的包将被忽略, 而来自原始源地址的包将被保留。如果原始源在较长时间内没有包到达, 该表条目将超时, 新源将能够接管。这可能发生在原始源检测到冲突并移向一个新的源标识符时, 但在通常的情形下, 会从一个原始源接收到 RTCP BYE 包, 从而无需等待超时即可删除状态。

如果原始源地址是经由一个混合器接收到的 (即, 作为 CSRC 了解到), 而后来同一个源被直接接收到, 除非混合中的其他源会丢失, 否则接收方最好切换到新的源地址。此外, 对于诸如电话这样的应用, 其中某些源 (如移动实体) 可能在一个 RTP 会话的过程中更改地址, RTP 实现 SHOULD 修改冲突检测算法, 以接受来自新源传输地址的包。为了防止在真正发生冲突时地址之间来回跳动 (flip-flopping), 该算法 SHOULD 包含某种手段来检测这种情况并避免切换。

当由于冲突而选择一个新的 SSRC 标识符时, 候选标识符 SHOULD 首先在源标识符表中查找, 看它是否已被某个其他源使用。如果是, MUST 生成另一个候选者并重复该过程。

到多播目的地的数据包环路可能导致严重的网络洪泛。所有混合器和转换器 MUST 实现像这里这样的环路检测算法, 以便它们能够打破环路。这应当把过量流量限制在不超过原始流量的一份重复副本, 这可能允许会话继续, 从而可以找到并修复环路的原因。然而, 在混合器或转换器未能正确地打破环路、并导致高流量水平的极端情况下, 端系统可能必须完全停止发送数据或控制包。这个决定可能取决于应用。SHOULD 适当地指示一个错误状况。传输 MAY 在经过一个较长的随机时间 (约为分钟量级) 后周期性地再次尝试。

8.3 与分层编码一起使用 (Use with Layered Encodings)​

对于在独立 RTP 会话上传输的分层编码 (见第 2.4 节), 跨所有层级的会话 SHOULD 使用单一的 SSRC 标识符空间, 并且核心 (基础) 层 SHOULD 用于 SSRC 标识符分配和冲突解决。当一个源发现它发生了冲突时, 它只在基础层上发送一个 RTCP BYE 包, 但在所有层级都将 SSRC 标识符改变为新值。