ULP Fec 与 Flex FEC 概述
一,对抗网络丢包的主要技术
在介绍 fec 之前我先根据个人经验介绍下对抗网络丢包的一些技术,如有错误欢迎指正。
多路传输
同一份数据使用多个传输通道进行传输,当数据包在某个传输通道丢失,接收端可以从其他通道接收数据,有些 sd-wan 用到了该技术。
FEC
前向纠错,发送端根据配置的冗余度将源数据包通过异或(XOR)生成对应数量的冗余包连同源数据包一起发送出去,接收端根据冗余包和源数据包通过再通过异或(XOR)恢复丢失的包,基础原理参考这篇文章
ARQ
维基百科解释的非常明白,链接
NACK
后向纠错,当接收端检查到报文丢失,发送 rtcp nack 请求源端重新发送丢失的包。
......
二,FEC 介绍
1. Fec VS Nack
webrtc 对抗网络丢包主要使用了两种技术 fec 和 nack,两者使用的场景如下
当 rtt <= 20ms ,fec 功能是不启用。我们对 gcc 稍作修改,视频大概可以支持 30%的丢包。
当 rtt >20ms,fec 功能开启,webrtc 维护了一个 FEC Rate 一维的冗余表,其实相当一个二维表 kFecRateTable[rate_i][loss_j], 行代表单帧码率, 列代表丢包率 loss_ratio * 256, 理论上丢包率是能支持的最大值 50%,效果我后面测试再给。
当 rtt 过大,使用 nack 势必会引入延时,如果使用 fec,通过冗余包+源数据包能恢复丢失的包,延时问题是可以解决的。俗话说天下没有免费的午餐,当带宽受限 fec 包会挤占大量的带宽,这势必会导致发送端降帧率,码率或者分辨率。
2. Ulp FEC
ULP(RFC5109)是 Uneven Level Protection 的缩写,不均等保护,根据数据包重要程度使用不同级别的保护策略,webrtc 针对 I 帧和 P 帧有两个冗余度,这个冗余度是根据上述 kFecRateTable 表查询得到。
2.1) fec 包结构
FEC Header 固定为 10 个字节,FEC Header 后面可以跟着多个 Level,每个 Level 保护着不同的数据。
2.2) FEC Header 格式
E: 保留的扩展标位,默认为 0
L:长掩码标志位。当 L 等于 0 时,ulp Level header 的 mask 长度为 16bits,当 L 设置为 1 时,ulp Level header 的 mask 长度为 48bits。
P、X、CC、PT:由所保护的 RTP 包的对应值通过 XOR 运算得到。
SN base: fec 包所保护的 RTP 包中的最小序列号。
TS recovery: 所保护的 RTP 包的 timestamps XOR 运算得到。
Length recovery:所保护的 RTP 包的长度通过 XOR 运算得到。
2.3) Ulp Level header 格式
Protection Length:所保护的数据的长度
mask:根据 FEC Header 标志位 L 取值不同而改变,当 L 等于 0 时,ulp Level header 的 mask 长度为 16bits,当 L 设置为 1 时,ulp Level header 的 mask 长度为 48bits,举个例子:当 FEC Header SN base 为 100,mask 值为 0x5A(01011010), 得知该 fec 包保护的 rtp 包的序列号有 101,103,104,106.
备注:89 版本 ulp 和 red 包是绑定到一起的,必须同时启用或者不启用,58 版本 red 包可以单独存在。
3. Flex fec
Flexible Forward Error Correction 目前还在草案阶段(RFC),相对 ULP 它有两个优势
自由选择对行,还是列来生成 fec 包
去除了 Ulp Level header 对 mask 的限制,ULP 最大支持 48bit
3.1) Flex fec header
R: 1 重传包,0 修复包,目前 webrtc89 版本不支持重传包
F: 1 packets indicated by offset M and N ;0: 变长 mask
当 F 为 0,使用 flexible mask(可变长度 mask),结构如下
当 F 为 1 ,使用 packets indicated by offset M and N(固定长度 mask),结构:
M/N 含义
If M>0, N=0, is Row FEC, and no column FEC will follow
Hence, FEC = SN, SN+1, SN+2, ... , SN+(M-1), SN+M.
If M>0, N=1, is Row FEC, and column FEC will follow.
Hence, FEC = SN, SN+1, SN+2, ... , SN+(M-1), SN+M.
and more to come
If M>0, N>1, indicates column FEC of every M packet
in a group of N packets starting at SN base.
Hence, FEC = SN+(Mx0), SN+(Mx1), ... , SN+(MxN).
P/X/CC/M/PT/Length recovery/TS recovery/SSRC_i/Base_i: 参考 上述 ulp 的介绍
SSRC count: 被保护的 SSRC 数量,0:非法,目前 webrtc89 版本只支持一个。
Reserved: 保留的扩展标位,默认为 0
flex fec sdp 示例
FEC-FR: 源视频流与 FEC 修复流 ssrc 绑一起。
repair-window: “The time that spans the source packets and the corresponding repair packets. The size of the repair window is specified in microseconds.”摘自rfc 5.1.1节我的理解是
源数据包与 fec 包的时间跨度,webrtc 注释必须要有,但是它还没有实现相关的代码。见函数:
flex fec 测试结果记录
由于目前 89 版本的 webrtc flex fec 看起来还不是很完整,不能自由选择行/列来生成 fec 包的模式,只能使用 flexible mask, 而且我测试发现在 25ms + 30%丢包效果很差,个人觉得这一块还有很长的路要走。
参考:
https://zhuanlan.zhihu.com/p/143077304
https://datatracker.ietf.org/doc/html/draft-ietf-payload-flexible-fec-scheme-03
https://datatracker.ietf.org/doc/html/rfc5109
评论