摘要

  • RTP 的示例接收算法让未见过的同步源进入试用期:一个看似合理的包不足以成立,短暂的连续序号才提供初步连续性证据。
  • 同一状态机先拒绝异常大跳变、记住它的后继值,只有下一个序号真的到达才重新同步;这保护了丢包核算,却不认证发送者,也不证明媒体成功播放。

报头过关,来源还没有过关

设想接收端第一次看见 SSRC 0x4A17,携带的序号是 41,900。版本字段是 2,负载类型属于本会话,填充和长度也互相吻合。它仍可能是投错地址的流量、使用错误上下文解密后偶然像 RTP 的字节、一次随机碰撞,或者确实是一位新说话者的第一包。

RFC 1889 在 1996 年把这个贫乏的证据条件写进 RTP;2003 年取代它的 RFC 3550 保留了做法并修清细节。对于陌生来源,接收端只能检查一些弱条件:版本、已知负载类型、填充、扩展和长度。它们能排除部分不可能解释,却不能给孤立的包补造一段历史。

于是,时间成为验证的一部分。新 SSRC 先进入 probation。附录 A.1 的示例要求连续收到一小段序号后,才把来源宣布为有效。典型的 MIN_SEQUENTIAL 是 2:41,900 仍是候选,41,901 才提供第一条跨包关系。

这份关系非常有限。两个连续数字不识别人,不认证设备,也不保证负载能够解码。它只令一个运行假设比刚才更可信:这些包似乎来自一条正在维护自身次序的流。

试用期用启动延迟交换少一些误收

规范允许应用丢掉试用期内的包,也允许先缓存,待来源过关后再交付,只要增加的延迟可以接受。要求更长的连续段,会降低偶然报头与序号同时碰对的概率,却也扣住更多开头媒体;在高丢包路径上,真正的来源甚至可能一直无法完成试用。

因此,附录给的是算法和典型参数,不是给所有应用颁发一组永恒常数。若接收端已经拿到有效 RTCP 包,便拥有更强上下文;某些负载格式的时间戳按可预测步长增加,也能加入验证。通话、存档流和高时延组播购买的启动延迟与误接风险,并不相同。

probation 比 authentication 更准确。它是接收端在不确定条件下制定的本地准入政策,不是发送者交付的身份证明。

十六位序号是一只圆环

来源通过试用后,序号也不能按普通整数直接比较。RTP 线上字段只有 16 位,65,535 之后回到零。一个小数跟在大数后面,可能只是健康回绕,而非时间倒退。

示例状态同时保存见过的最高序号和已经跨过的 16 位周期数,由此构造扩展序号,让 RTCP 可以跨回绕计算应收包数,而无需扩大线上报头。

网络还会制造乱序。略低于最大值的包可能只是迟到或重复;适度超前的值可能表示中间有缺口。接收端需要在当前最大值周围划出可接受邻域,而不是只做相等判断。

RFC 3550 示例中的 MAX_MISORDER 是 100,MAX_DROPOUT 是 3,000。它同时交代了背景:每秒 50 包、最大乱序两秒、最大中断一分钟。数字只有连同包率与时间假设才有意义,并非跨越所有媒体与年代的自然常量。

一次不可能的大跳变没有立刻获得身世

假设运行中的来源到达 12,000,下一包却是 50,000。若立刻把差额记成丢包,会生成一份十分精确的灾难报告;若立即宣布来源重启,同样是在用一个异常替历史作传。

示例算法两者都不做。它先拒绝这个大跳变,把“被拒序号加一”存进 bad_seq。如果后来真的收到 50,001,这一对连续值才构成新开端,接收端重新初始化序号状态,把 50,001 当成新时期第一份被接纳的观察。

一个可疑值没有权力改写过去;它的后继值令“发生过未宣告重启或长时间中断”成为可执行判断。

这与初次试用使用相似的两包连续证据,却回答不同问题。初次试用问:一个陌生 SSRC 是否值得长期状态?重启确认问:一个已知 SSRC 的旧序号历史是否已经不再解释眼前的包?两者都依赖连续性,因为系统不能假定一定会收到明确的重启宣告。

重置计数器是在承认不知道

确认新时期后,接收端会重置丢包统计。表面看像删除证据,实际上继续沿用旧基线才会制造不存在的证据。

长时间失联期间可能跨过若干完整的 16 位周期;来源也可能以随机序号重新启动。没有一条被观察到的桥,接收端无法知道旧时期与新时期之间本应有多少包。把两段硬接成一条累计曲线,只会把未知区间伪装成精确损失。

RTP 的损失算法本来就比仪表盘百分数复杂。RFC 3550 用“预期数减实际收到数”定义累计损失,而迟到包与重复包也计入收到数;重复多于缺失时,结果可以为负。RFC 3611 后来增加丢失与重复的事件轨迹,并要求尽量报告观察事实,把解释留给使用报告的人。

时期边界决定分母究竟是什么。重置不等于早期损失不重要,只表示一套可辩护的序号算术不能越过一次无人看见的重生。

RFC 3550 修的是示例,不是中心思想

这套机制在 RFC 1889 已经出现。RFC 3550 的变更记录说明了几个小而关键的修复:base_seq 从收到的序号开始,而不是减一;文字明确保存的是坏序号加一;初始化步骤被拆开,以免实现者误以为调用一个函数已经完成全部准备;RFC 1889 出版加工时丢失的词也得到补回。

这段历史提醒我们:附录示例也会成为基础设施。伪代码常常比解释限制的段落传播更远。起点差一会改变预期包数,bad_seq 的模糊措辞则会改变究竟由哪一包确认新时期。

真正的设计核心不是 2、100 或 3,000,而是把不确定性放进明确状态:候选来源、有效序列、可接受乱序、可疑断裂、得到确认的新开端。

连续性不是密码学权威

有能力伪造连续序号的攻击者可以通过这项测试,真实发送者也可能因丢包而失败;错误配置的端点可以按完美顺序发送毫无意义的内容。RTP 试用期过滤偶然误投和不可信的状态跳跃,不证明来源。

RFC 3711 后来定义 SRTP,在适当密钥管理下提供机密性、消息认证和防重放。这是另一层证据。即便 SRTP 也不证明某个人听到了、媒体清晰可懂,或者一场商业沟通确实完成;它保护的是密码学上下文里的包。

这段历史最耐久的结论很窄:字段要靠解释它的状态才成为证据。第一个序号是没有过去的主张,第二个能建立连续性;大跳变暂停旧账,后继值可以开启新时期。每一步都由接收端作出决定,也必须保留这个决定能说什么、不能说什么。

来源