使用WebRTC的FEC抗丢包
解读
在国内实时互动场景(云游戏、XR 远程渲染、元宇宙会议)中,Unity 客户端常把渲染帧或音视频流通过 WebRTC 推到浏览器或 App。面试问“怎么用 WebRTC 的 FEC 抗丢包”,表面看是网络知识点,实质考察三点:
- 是否理解 WebRTC 在 Unity 中的集成链路(libwebrtc 插件 → C# 回调 →渲染/音频管线);
- 能否把 FEC 算法参数与带宽、延迟、画质做权衡,而不是“打开开关”了事;
- 是否具备 端到端验证与调优 的能力(丢包模拟、GCC 拥塞控制、Metrics 上报)。
答得太浅(“把 fec 打开”)会被追问“冗余度多少、怎么动态调整”,答得太深(“自己改 opus 源码”)又容易被判“过度设计”。因此要把 Unity 侧可控的配置点、WebRTC 内核的算法逻辑、国内网络特征 三条线讲清。
知识点
- WebRTC FEC 类型
- Opus in-band FEC:语音帧内部带冗余,只抗 1 个包丢失,码率增加≈20%。
- ULPFEC (Uneven Level Protection):RFC 5109,在视频 RTP 层外加冗余包,可设 mask 表控制保护级别;冗余度 10%–50%。
- FlexFEC:RFC 8627,支持 1-D/2-D 行列异或,抗突发丢包更好,Chrome≥90 默认开。
- Unity 集成点
- 国内主流方案:
– Unity-WebRTC 插件(Unity 官方维护,基于 m94 libwebrtc);
– 声网/即构/腾讯云 GME 的私有 SDK,内部已封装 FEC; - 若自研插件,需在 CreatePeerConnectionFactory 时把 flexfec_enabled 置 true,并通过 RtpParameters.encodings[].fec 结构体把 payload type 映射到 96~127 动态段。
- 国内主流方案:
- 参数调优
- 丢包率 <3%:Opus in-band 足够;
- 3%–8%:视频开 ULPFEC,冗余度 15%,保护距离 L0=1、L1=2;
- >8% 或 200 ms 突发:FlexFEC 2-D,行列比 5×9,冗余度 25%,同时把 NACK RTT 阈值从默认 40 ms 提到 80 ms,避免重传风暴。
- 与带宽估计联动
WebRTC 的 GCC 会把 FEC 冗余量算进 available bitrate;若 FEC 占比过高,GCC 会压视频码率,导致画质糊。需把 maxPaddingBitrate 提高 10% 给冗余包留带宽。 - Unity 侧验证
- 用 Clumsy/NetLimiter 在 PC 端注入 5% 随机丢包,看 VideoReceiveStream::OnRecoverablePacketLoss 回调;
- Android 端用 tc qdisc 加 100 ms 抖动 + 3% 丢包,观察 webrtc::Stats 中的 packetsRecovered 计数是否上涨;
- 把 Stats 上报到 Grafana,红线 packetsLost、绿线 packetsRecovered,面试时直接拿图讲效果,国内面试官认可度极高。
答案
“我们在 Unity 2021 LTS 里用官方 Unity-WebRTC 插件,版本 2.4.0-exp.6,基于 Chromium M94。打开 FEC 分三步:
- Factory 层开启
在WebRTC.Initialize()后,把webrtc::PeerConnectionFactoryInterface::Options的flexfec_enabled置 true; - SDP 协商
在OnNegotiationNeeded回调里,对视频 transceiver 的RtpParameters.encodings[0]添加fec = { ssrc: 0xFEC0, payloadType: 96 },并在 SDP 里插入a=rtpmap:96 flexfec-03; - 冗余度动态调整
每 5 s 读取RTCPeerConnection.GetStats()中的inbound-rtp.packetsLost与packetsRecovered,丢包率 <3% 时把flexfec.params[k] = 0(关冗余),>8% 时把行列 2-D 冗余度调到 25%。
实测在 2.5 Mbps 码率、5% 随机丢包、RTT 60 ms 的弱网环境下,PSNR 提升 1.8 dB,卡顿率从 4.7% 降到 1.2%,同时 GCC 带宽估计只下降 6%,满足云游戏 720p60 的体验红线。”
拓展思考
- FEC 与 ARQ 混合策略
国内 4G/5G 切换时常出现 200 ms 突发丢包,可先做 FEC 抗 80 ms,剩余丢包用 NACK+RTX 重传;把nack_max_packets从默认 250 提到 500,防止重传窗口打满。 - Unity 渲染管线与 FEC 带宽抢占
如果同时推多路纹理流(Color + Depth for AR),可把 Depth 流设成 ULPFEC 10%,Color 流 FlexFEC 25%,并在编码端用 Unity RenderTexture.GetNativeTexturePtr() 直接送硬编,减少 GPU→CPU 回读,给冗余包留 CPU 预算。 - 国产化合规
信创环境下需替换 libwebrtc 的 BoringSSL 为国密 TLS 1.3,FEC 算法本身只涉及异或运算,不含加密,可直接复用;但动态 payload type 96~127 需避开 GB/T 28181 已占用的 100-103,否则与公安内网平台对接会冲突。