使用WebRTC的FEC抗丢包

解读

在国内实时互动场景(云游戏、XR 远程渲染、元宇宙会议)中,Unity 客户端常把渲染帧或音视频流通过 WebRTC 推到浏览器或 App。面试问“怎么用 WebRTC 的 FEC 抗丢包”,表面看是网络知识点,实质考察三点:

  1. 是否理解 WebRTC 在 Unity 中的集成链路(libwebrtc 插件 → C# 回调 →渲染/音频管线);
  2. 能否把 FEC 算法参数与带宽、延迟、画质做权衡,而不是“打开开关”了事;
  3. 是否具备 端到端验证与调优 的能力(丢包模拟、GCC 拥塞控制、Metrics 上报)。
    答得太浅(“把 fec 打开”)会被追问“冗余度多少、怎么动态调整”,答得太深(“自己改 opus 源码”)又容易被判“过度设计”。因此要把 Unity 侧可控的配置点、WebRTC 内核的算法逻辑、国内网络特征 三条线讲清。

知识点

  1. 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 默认开。
  2. Unity 集成点
    • 国内主流方案:
      Unity-WebRTC 插件(Unity 官方维护,基于 m94 libwebrtc);
      声网/即构/腾讯云 GME 的私有 SDK,内部已封装 FEC;
    • 若自研插件,需在 CreatePeerConnectionFactory 时把 flexfec_enabled 置 true,并通过 RtpParameters.encodings[].fec 结构体把 payload type 映射到 96~127 动态段。
  3. 参数调优
    • 丢包率 <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,避免重传风暴。
  4. 与带宽估计联动
    WebRTC 的 GCC 会把 FEC 冗余量算进 available bitrate;若 FEC 占比过高,GCC 会压视频码率,导致画质糊。需把 maxPaddingBitrate 提高 10% 给冗余包留带宽。
  5. 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 分三步:

  1. Factory 层开启
    WebRTC.Initialize() 后,把 webrtc::PeerConnectionFactoryInterface::Optionsflexfec_enabled 置 true;
  2. SDP 协商
    OnNegotiationNeeded 回调里,对视频 transceiver 的 RtpParameters.encodings[0] 添加 fec = { ssrc: 0xFEC0, payloadType: 96 },并在 SDP 里插入 a=rtpmap:96 flexfec-03
  3. 冗余度动态调整
    每 5 s 读取 RTCPeerConnection.GetStats() 中的 inbound-rtp.packetsLostpacketsRecovered,丢包率 <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 的体验红线。”

拓展思考

  1. FEC 与 ARQ 混合策略
    国内 4G/5G 切换时常出现 200 ms 突发丢包,可先做 FEC 抗 80 ms,剩余丢包用 NACK+RTX 重传;把 nack_max_packets 从默认 250 提到 500,防止重传窗口打满。
  2. Unity 渲染管线与 FEC 带宽抢占
    如果同时推多路纹理流(Color + Depth for AR),可把 Depth 流设成 ULPFEC 10%,Color 流 FlexFEC 25%,并在编码端用 Unity RenderTexture.GetNativeTexturePtr() 直接送硬编,减少 GPU→CPU 回读,给冗余包留 CPU 预算。
  3. 国产化合规
    信创环境下需替换 libwebrtc 的 BoringSSL 为国密 TLS 1.3,FEC 算法本身只涉及异或运算,不含加密,可直接复用;但动态 payload type 96~127 需避开 GB/T 28181 已占用的 100-103,否则与公安内网平台对接会冲突。