6.2 丢包恢复三件套


文档摘要

6.2 丢包恢复三件套 本节摘要:丢包是实时通信逃不掉的宿主,问题只在于丢了之后怎么办。WebRTC 的答案有三件:nack 点名重传(丢了补发)、FEC 前向纠错(预先备份)、pli 关键帧请求(断了重来)。三件套各管一段、各有代价,用错场景会把网络越救越挤。本节讲清每件的触发逻辑、带宽成本与配置决策,并回答「为什么我的通话偶尔定格两秒」这类现象级问题。 学习目标 阅读完本节,你应当能够: 说清 nack 重传的触发条件,以及「重传迟到」时它为何主动放弃; 解释 FEC 的两种形态(包级冗余与带内冗余)与各自的带宽代价; 描述 pli 关键帧请求的触发场景与它造成的画面定格代价; 按丢包特征(随机散点还是连续突发、RTT 高低)在重传与纠错间做配置取舍;

6.2 丢包恢复三件套

本节摘要:丢包是实时通信逃不掉的宿主,问题只在于丢了之后怎么办。WebRTC 的答案有三件:nack 点名重传(丢了补发)、FEC 前向纠错(预先备份)、pli 关键帧请求(断了重来)。三件套各管一段、各有代价,用错场景会把网络越救越挤。本节讲清每件的触发逻辑、带宽成本与配置决策,并回答「为什么我的通话偶尔定格两秒」这类现象级问题。

学习目标

阅读完本节,你应当能够:

  1. 说清 nack 重传的触发条件,以及「重传迟到」时它为何主动放弃;
  2. 解释 FEC 的两种形态(包级冗余与带内冗余)与各自的带宽代价;
  3. 描述 pli 关键帧请求的触发场景与它造成的画面定格代价;
  4. 按丢包特征(随机散点还是连续突发、RTT 高低)在重传与纠错间做配置取舍;
  5. 用统计接口读出重传包数、FEC 包数与关键帧请求数,判断恢复机制是否健康。

一、问题与直觉:补救的三种哲学

对「包丢了」这个事件,工程上有三种反应哲学。要回来:接收端点名,发送端重发——精准,但来回一趟的延迟决定了它只适合丢包少、往返短的场景。预先备份:发正包时捎带冗余数据,丢了用冗余算回来——即时,但不管丢不丢都在付冗余带宽。从头再来:视频编码是前后依赖的(后一帧参考前一帧),依赖链断了就修不动,只能请求一个新的关键帧——代价最大,画面定格等关键帧到达。三件套就是这三种哲学的实现:nack 重传、FEC 纠错、pli 关键帧。

它们的协作关系不是三选一,而是分层兜底:小丢小乱交给重传,持续丢包靠纠错硬扛,解码链崩溃时才动用关键帧这张贵牌。理解「贵牌最后打」,就理解了全部配置逻辑。

二、核心原理:三件套的触发与代价

nack 重传。接收端发现序号缺口(5.2 节的序号字段在此发力),立刻发 nack 点名。发送端从重传缓存里找出对应包重发。它有一个聪明的自我克制:重传包到达时如果已经晚于播放时刻,就不再有用——发送端会比对「预计到达时间与该包的时限」,过期就不重发了,把带宽留给新包。这就是为什么高 RTT 链路上 nack 效果衰减:来回一趟的时间超过了几帧的播放窗口,重传就变成了无效功。

FEC 前向纠错。WebRTC 里有两种形态:包级 FEC(ulpfec/red)把若干 RTP 包的冗余打包成一个纠错包,组内丢一个可恢复;带内 FEC(Opus 的 inbandfec)把前一帧的冗余编进当前音频帧,对音频的散点丢包极其有效。代价是恒定的额外带宽——典型配置两成左右。FEC 的正确适用场景是「丢包连续不断且 RTT 大」:重传追不上,纠错就地生效。

pli 关键帧请求。接收端解码器报错(参考帧缺失),发 pli;发送端编码器生成关键帧。贵在两处:关键帧比普通帧大数倍到数十倍,瞬时挤占带宽;关键帧到达前的画面只能定格。所以pli 是最后手段,频繁pli 通常意味着前两件套失灵或丢包已严重到连锁崩溃。

三件套的配置决策可以归纳成一张表:

网络特征 重传 nack 纠错 FEC 关键帧 pli
低丢包低 RTT 主力,效果最好 少开省带宽 罕见触发
持续散点丢包 有效 开带内,性价比高 偶发
高 RTT 高丢包 追不上播放时限 主力,包级加码 仍需兜底
突发连续丢包 部分有效 包级组内恢复 突发过长时触发

配置入口有两个层面。SDP 协商层面,rtcp-fb 行声明支持哪些反馈(第 3 章读 SDP 时见过);参数层面通过发送器配置:

// 查看与调整某路视频发送器的 FEC 与重传 const sender = pc.getSenders().find((s) => s.track?.kind === 'video'); const params = sender.getParameters(); console.log(params.encodings[0]); // 编码参数入口(6.3 节展开) // 浏览器通常自动决策 FEC 开关,人工干预多见于服务端转发器与自研端 // 音频的带内 FEC 由编解码参数控制: const audioParams = audioSender.getParameters(); // Opus 的 useinbandfec 在 SDP 的 fmtp 行协商,见第 3 章对账方法

健康检查靠统计接口:出向流的重传包数、FEC 包数,入向流的丢包数与关键帧请求数。健康状态的大致画像:重传数与丢包数同量级(说明 nack 在干活)、pli 请求零星出现(说明解码链稳)、FEC 包占比与配置吻合。

⚠️ 常见坑:看到丢包率高就无脑全开 FEC,结果冗余带宽挤占了正常媒体,丢包率进一步上升——恢复手段本身变成了拥塞源。三件套的开启要跟随目标码率:带宽紧张时先收缩 FEC,保正常媒体。

三、工程实践要点:现象归因

把三件套语义翻译成用户现象。「偶尔定格一秒左右然后跳到最新画面」:一次 pli 往返加编码耗时,正常。「画面持续马赛克但声音正常」:视频流连续丢包且 FEC 没能覆盖,重传又迟到——检查 FEC 是否开启、RTT 是否过高。「声音发闷发飘」:Opus 带内 FEC 在工作的听感(用音质换连续性),说明音频链路在丢包——属正常应对,源头在链路。「每隔固定间隔定格」:多为周期性带宽尖峰触发连续丢包,去查同链路上的其他流量。

完整案例:跨国专线上的「马赛克雨」

背景:某跨境会议客户投诉:固定在每天某个时段,画面持续马赛克,声音尚可;换时段立刻恢复。

操作:接入端统计显示该时段 RTT 从常规水平翻倍,重传包大量「过期放弃」(发送端日志可见放弃计数激增),FEC 当时未开启。时间规律指向跨境链路的晚高峰拥塞。处置:对该客户链路开启包级 FEC 与 Opus 带内 FEC,冗余约两成;同时把视频初始码率下调,给冗余腾出空间;nack 保持开启处理散点丢失。

结果:马赛克现象消失,代价是画质略降与约两成冗余开销,客户接受。后续把「RTT 超阈值自动加 FEC」做成了服务端策略,不再依赖个案配置。

解读:这个案例是决策表的活教材:高 RTT 让重传失效(过期放弃),纠错顶上;「声音正常」恰是带内 FEC 生效的旁证。再看对策的顺序——先诊断(统计与日志)、再对症(按 RTT 选手段)、后固化(做成策略),是质量问题的标准处置链路。

变式:SFU 场景下三件套的执行点变得多元:SFU 可以对上行链路的丢包在服务端就地重传(它缓存了流),对下行链路按各接收端状态分别 nack——同一份流对不同用户可以有不同的恢复强度。理解了三件套的原理,SFU 的这些行为就不再是魔法,第 7 章展开。

本节要点回顾

  • 三种哲学各管一段:重传要回来、纠错预先备份、关键帧从头再来,贵牌最后打。
  • 重传会自我克制:追不上播放时限的包果断放弃,高 RTT 场景效果天然衰减。
  • FEC 是持续丢包的主力:带内护音频、包级护视频,代价是恒定冗余,开启要跟随带宽。
  • pli 是贵牌:定格加大包,频繁出现即前两件失灵的信号。
  • 统计接口验健康:重传数对丢包数、pli 零星、FEC 占比合配置,三条对上即健康。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U