WHIP/WHEP 丢包了怎么办?从 NACK、RTX 到 PLI,拆解 WebRTC 的低延迟重传机制
一、WHIP/WHEP 到底支不支持数据包重传?
在实现 WHIP 推送和 WHEP 播放之后,一个很自然的问题是:WebRTC 的媒体数据主要跑在 UDP 之上,如果公网环境出现丢包,WHIP/WHEP 能不能像 SRT 一样把数据重新追回来?答案是可以,但这个问题需要稍微换一个角度理解。严格来说,并不是 WHIP 和 WHEP 协议本身负责媒体包重传,而是它们建立起来的 WebRTC 会话继承了 RTP/RTCP 原有的丢包反馈和恢复能力。
WHIP 的核心职责,是通过 HTTP 完成 WebRTC 推流端的 SDP Offer/Answer、ICE、DTLS 等会话建立过程;WHEP 的方向相反,用于标准化 WebRTC 播放端的会话建立。一旦会话建立完成,真正的视频和音频并不是通过 HTTP 持续传输,而是进入 SRTP、RTP 和 RTCP 媒体链路。也就是说,讨论“WHIP 是否支持重传”,本质上是在讨论 WebRTC RTP 会话有没有丢包检测、反馈和重传机制,而答案显然是有的。

很多人习惯把 TCP 和 UDP 简单理解成“TCP 会重传,UDP 不会重传”,其实这只是传输层本身的区别。UDP 不保证可靠传输,并不意味着运行在 UDP 之上的协议不能自己实现可靠性。WebRTC 就是在 RTP/RTCP 这一层完成这件事情。RTP 包本身携带 Sequence Number,如果发送端连续发送 100、101、102、103,而接收端只收到 100、101、103,就可以立即判断 102 丢失,然后通过 RTCP 向发送端反馈这个丢包信息,这就是实时音视频中经常看到的 NACK。
二、NACK、RTX 和 PLI,分别解决什么问题?
NACK 的全称是 Negative Acknowledgement,可以简单理解为“我发现某些 RTP 包没有收到,请重新发送”。需要注意的是,NACK 自己并不携带视频数据,它只是一个反馈请求。发送端收到 NACK 后,如果原始 RTP Packet 仍然保存在发送缓存中,就可以重新发送对应的数据,这个过程通常通过 RTP RTX,也就是 RTP Retransmission 完成。
假设发送端发出了 RTP 100、101、102、103,其中 102 在网络中丢失,接收端检测到 Sequence Number 出现断档后发送 RTCP NACK,请求 102。发送端查询自己的 RTP History Buffer,如果 102 仍然存在,就重新封装成 RTX Packet 发出去。接收端收到 RTX 后,再根据其中携带的原始 Sequence Number,将它恢复成对应的媒体数据,重新进入排序、组帧和解码流程。所以从工程上看,NACK 是“请求重传”,RTX 才是真正执行重传。

在 WHIP/WHEP SDP 中,经常会看到类似这样的内容:
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
这里 nack 表示接收端可以对丢失的 RTP Packet 发起反馈,rtx 表示存在对应的 RTP 重传 Payload Type,apt=96 则说明该 RTX Payload Type 对应原始 PT 96。实际项目中的 Payload Type 不一定是 96 和 97,因此抓包分析时不应该只盯着具体数字,而应该重点观察 rtcp-fb、rtx 和 apt 的关系。
但仅靠 RTX 并不能解决所有问题。H.264/H.265 视频存在明显的参考帧依赖,如果某些关键数据连续丢失,即使持续发送 NACK,也可能因为 RTT 较高、重传数据回来太晚,导致参考链已经无法正常恢复。这时候继续修补某一个 RTP Packet 的意义已经不大,更有效的方法是让编码端尽快产生新的可恢复图像,这就是 PLI 和 FIR 的价值。
可以把它们简单理解成:
NACK + RTX:修数据包
PLI / FIR:修解码状态
少量、随机、短时间的丢包更适合通过 NACK+RTX 恢复;当连续丢包比较严重,或者参考帧链已经损坏时,则需要尽快进入解码恢复流程。
三、WebRTC 真正关心的不是“能不能重传”,而是“还值不值得重传”
理解 WebRTC 重传机制,最重要的其实不是记住 NACK、RTX、PLI 这些术语,而是理解它背后的时间约束。
对于文件下载而言,一个数据包晚到几百毫秒甚至几秒,只要最终完整到达,通常都可以接受;实时音视频则完全不同,一个视频包即使最终成功追回,如果它对应的播放时间已经过去,那么对于低延迟播放器来说,这个包已经失去了价值。
比如播放器只允许 100~200ms 左右的端到端延迟预算,一个 RTP Packet 丢失后,需要经历丢包检测、发送 NACK、网络 RTT、发送端查找缓存、RTX 重传以及接收端重新排序等过程。如果整个恢复过程花费 150ms,而当前帧剩余的播放时间只有几十毫秒,那么即便 RTX 最终成功到达,也可能已经没有继续参与解码的价值。

从 SmartMediaKit 这类强调低延迟播放的 SDK 角度看,这个问题尤其重要。低延迟并不是简单地把 Jitter Buffer 调到最小。Buffer 太大,网络抖动和 RTX 有更充分的恢复空间,但整体延迟会增加;Buffer 太小,虽然实验室里看起来延迟非常漂亮,但到了真实 4G、5G、Wi-Fi 或跨公网环境中,稍微出现一点 RTT 波动,RTX 还没回来,当前帧就已经超时。
因此可以把重传是否有价值简单抽象成:
丢包检测时间
+ NACK反馈时间
+ 网络RTT
+ RTX回传时间
+ 重排序时间
<
当前帧剩余的播放时间预算
只有满足这个条件,重传才真正值得做。
这也是 WebRTC 和 TCP 很本质的区别。TCP 更关心的是数据最终是否完整、有序到达,而实时媒体系统必须不断判断:这个数据现在回来,还有没有价值?
四、从 SmartMediaKit 的 WHIP 推送和 WHEP 播放实现看弱网处理
如果从实际 SDK 的角度来看,支持 WHIP/WHEP 远不止“把 WebRTC 跑通”这么简单。
以 WHIP 推送为例,完整的数据路径大致可以理解为:
Encoder
|
RTP Packetizer
|
RTP Sender
|
Internet
|
WHIP Server
但如果真正考虑 NACK/RTX,那么发送模块实际上还需要维护一个有限大小的 RTP History Buffer。已经发出去的 RTP Packet 不能立即彻底释放,而是要保存一段时间。当服务端检测到 RTP Sequence Number 缺失,通过 RTCP NACK 请求重传时,Publisher 需要根据 Sequence Number 从缓存中找到原始 Packet,再生成 RTX Packet 重新发送。

因此对于 SmartMediaKit 的 WHIP 推送端来说,真正需要关注的并不只是“能不能把 H.264/H.265 推到服务器”,还包括 RTP 缓存窗口、NACK 去重、RTX 映射、RTT、重传次数以及过期 Packet 的处理。如果缓存太短,NACK 回来时原始 Packet 已经被删除;缓存太长,则会增加资源占用,而且很多过旧数据已经没有继续重传的意义。
WHEP 播放端则是另外一个方向。Player 根据 RTP Sequence Number 检测丢包,必要时向 WHEP Server 发送 NACK;收到 RTX 之后,需要识别 RTX Payload Type、还原原始 Sequence Number,再进入 RTP Reorder、Jitter Buffer、Frame Assemble,最后交给 Decoder。
对于 SmartMediaKit 这样的低延迟播放器来说,这里还有一个很关键的处理:不能因为 RTX 成功收到,就无条件把它交给解码器。如果某个 Packet 已经超过 Frame Deadline,那么直接丢弃可能比继续等待更合理,否则系统很容易出现一种典型问题:网络已经恢复了,但播放器为了等待过去的数据,端到端延迟反而越积越高。
这也是为什么商业级 WHEP 播放实现需要关注的不只是 WebRTC API,而是 RTP Loss Detection、NACK、RTX、Jitter、Packet Reorder、Late Packet Drop、PLI/FIR、Decoder Recovery,以及最终的延迟回收策略。
五、WHIP/WHEP 和 SRT 都能重传,但设计思路明显不同
最近在 SmartMediaKit 中同时测试 SRT 推送、SRT 播放以及 WHIP/WHEP 后,一个很明显的感受是:虽然这些协议都大量建立在 UDP 之上,也都具备丢包恢复机制,但在弱网中的表现并不是一个“性格”。
SRT 的核心机制之一是 ARQ,它通常会在设定的 Latency Window 内尽可能把丢失的数据重新追回来,所以在公网存在一定丢包率时,SRT 经常能够表现出非常不错的稳定性。WebRTC 同样可以通过 NACK 和 RTX 重传,但它的实时性约束更强,它会不断权衡 RTT、Jitter、播放 Deadline、拥塞状况以及当前解码状态,一个 Packet 如果已经来不及使用,系统完全可能放弃继续恢复,转而通过 PLI/FIR 尽快恢复新的解码参考点。

两者可以这样理解:
| 对比项 | WHIP/WHEP / WebRTC | SRT |
|---|---|---|
| 媒体体系 | RTP/RTCP | SRT Packet |
| 丢包反馈 | RTCP NACK | ACK/NAK/Loss Report |
| 重传机制 | RTP RTX | ARQ |
| 恢复目标 | Deadline 内尽量恢复 | Latency Window 内尽量恢复 |
| 解码恢复 | PLI/FIR 等 | 更多依赖数据恢复及编码层 |
| 实时性倾向 | 更激进 | 更强调稳定恢复 |
| 浏览器生态 | 很强 | 较弱 |
| 典型应用 | RTC、超低延迟直播、Web 播放 | 公网贡献链路、稳定传输 |
所以说“WebRTC 不可靠、SRT 可靠”其实并不准确。更合理的理解是:SRT 愿意预留一定时间窗口,把更多数据追回来;WebRTC 则更加关注,这个包追回来的时候是不是还赶得上实时播放。
从 SmartMediaKit 当前协议能力的演进来看,这两者其实并不是简单的替代关系。WHIP/WHEP 更适合极低延迟、Web 生态和 RTC 化的实时链路;SRT 则在弱网、公网传输和对稳定性要求较高的场景中有明显优势。对于一个面向工业、机器人、无人机、远程操控、安防等场景的实时音视频 SDK 来说,这两类协议更适合形成互补。
六、从“协议支持”走向商业级实现,真正难的是弱网
实现 WHIP Publisher 或 WHEP Player 的 Demo,并不是整个问题最难的部分。完成 HTTP、SDP Offer/Answer、ICE、DTLS、SRTP,只能说明协议链路已经跑通。真正决定产品质量的,是网络开始变差以后系统还能不能保持合理的延迟、画面完整性和恢复速度。
因此在 SmartMediaKit 后续的 WHIP/WHEP 优化中,比“是否支持某个协议”更值得关注的,是 RTT、Packet Loss、Jitter、NACK Sent/Received、RTX Sent/Received、RTX Recovered、RTX Too Late、PLI/FIR、Frames Dropped、Decoder Recovery Time、Current Bitrate 等指标。

其中有一个数据我认为尤其值得关注:有效 RTX 恢复率。
例如一段时间内一共请求重传 1000 个 RTP Packet,其中 920 个最终成功回来,表面看 RTX Recovery Rate 达到了 92%。但如果其中真正赶在 Frame Deadline 之前进入解码流程的只有 750 个,那么对于低延迟播放器而言,真正有效的恢复率实际上只有 75%。那些已经成功传到终端、但因为来得太晚而被丢弃的数据,从实时播放的角度看并没有真正产生价值。
因此评价一个 WHIP/WHEP 实现的弱网能力,不能只看“丢包率是多少”,而应该继续追问:5% 随机丢包下画面是否稳定?连续 Burst Loss 后多久恢复?RTT 从 30ms 增长到 150ms 时 RTX 还有多少有效价值?PLI 会不会过于频繁?网络恢复以后累计延迟能不能快速降回来?RTX 是否会反过来放大已经存在的网络拥塞?
把这些问题处理好,才真正意味着一个实时音视频 SDK 从“协议能跑”进入了“商业级实现”。
归根结底,研究 WHIP/WHEP 的 NACK、RTX 和 PLI 后会发现,实时音视频真正稀缺的资源并不只是带宽,而是时间。RTX 需要时间,Jitter Buffer 需要时间,等待新的恢复帧需要时间,网络抖动吸收同样需要时间。一旦恢复所消耗的时间超过了业务允许的 Latency Budget,再完整的数据也已经失去了实时价值。
所以,回到最开始的问题:WHIP 推送和 WHEP 播放支持数据包重传吗?答案当然是支持。但更准确地说,WHIP/WHEP 建立的 WebRTC 媒体会话可以通过 RTCP NACK、RTP RTX、PLI、FIR、FEC、Jitter Buffer 以及拥塞控制共同对抗网络丢包。
而它与 TCP、SRT 最大的区别,并不只是“有没有重传”,而是:
为了追回一个已经丢掉的数据包,系统愿意付出多少延迟。
对于 SmartMediaKit 这样的低延迟实时音视频 SDK 来说,真正需要解决的也不是简单做到“支持 WHIP、支持 WHEP”,而是让这些协议进入真实公网、弱网和复杂设备环境以后,仍然能够在延迟、稳定性和数据恢复之间找到合适的平衡。
这才是 WHIP/WHEP 从协议能力走向真正工程价值的关键。
📎 CSDN官方博客:音视频牛哥-CSDN博客
更多推荐
所有评论(0)