WebRTC FEC

Abstract

WebRTC FEC

Authors

Walter Fan

Status

WIP

Updated

2024-08-21

简介

FEC 即 Forward Error Correction 前向纠错,如果网络由于拥塞或中断丢失了一些媒体数据包,由于发送端通过 FEC 也发了一些冗余包,这样接收方依然能够正常地恢复和解码

NACK 作为应付丢包的常用手段默认会启用,但是如果延迟较大, NACK 的效果会大打折扣, FEC 会在延迟较大时启用,理论上可以支持 50% 的丢包。但是如果带宽过小,FEC 及 RTX 都会占用带宽,导致需要进一步降低发送码率,也就是降低质量。

目前在 WebRTC 中支持的 FEC 主要有以下两种,原理基本是用 XOR 的方法来进行错误恢复

  • ULP FEC

  • FLEX FEC

奇偶校验 FEC Parity FEC

比较简单的 FEC 是异或 (XOR) 奇偶校验方案。 方案如下:

  • 发送方确定受修复数据包保护的源数据包组(固定大小)。

  • 发送方通过对这些数据包组执行 XOR 操作来生成修复数据包。

  • 发送方将源包和修复包发送给接收方

  • 在接收端,如果数据包丢失,它会尝试恢复数据包。

有几种类型的奇偶校验 FEC 方案:

  • 单维:一个数据包只能用于一组源数据包。 例如,行(非交错)和列(交错)。

  • 多维:一个数据包可以用于多组源数据包。 例如,楼梯图案等。

原理

a xor b = c
a xor c = b
b xor c = a

Python test code:

from operator import xor
a = 3
b = 4
c = xor(a, b)
print(xor(a, c) == b, xor(b, c) == a)
#output: (True, True)

FEC/NAC rate

FEC 的发送速率可以根据如下因素决定

  • 根据 bitrate, packet_loss, reateIndex( width, height, frameRate, bitrate) 来决定 I 帧,P 帧的 fec rate

  • 根据 rtt, 调整 p 帧 fec rate (I 帧不变)

    • rtt < rtt_low(20ms): P帧fec rate=0,只用nack;

    • rtt > rtt_low && rtt < rtt_high: P帧fec rate不变,同时使用nack、fec

    • rtt > rtt_high: P帧fec rate不变,不使用nack 当前rttHigh为-1,表示永远使用nack

ULP FEC

ULP 在 RFC5109 中有详细定义,即 Uneven Level Protection 意为不均等保护,根据数据包重要程度使用不同级别的保护策略, webrtc 针对 I 帧和 P 帧有两个冗余度,这个冗余度是根据上述 kFecRateTable 表查询得到

  • fec_rate_table.h

// Table for Protection factor (code rate) of delta frames, for the XOR FEC.
// Input is the packet loss and an effective rate (bits/frame).
// Output is array kFecRateTable[k], where k = rate_i*129 + loss_j;
// loss_j = 0,1,..128, and rate_i varies over some range.
// TODO(brandtr): Consider replacing this big static table with a closed-form
// expression instead.
static const int kFecRateTableSize = 6450;
static const unsigned char kFecRateTable[kFecRateTableSize] = { ... }

Example

  • Offer SDP

v=0
o=- 4616755491246903017 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1
a=extmap-allow-mixed
a=msid-semantic: WMS stream_id
m=audio 9 RTP/AVPF 111 63 103 104 9 102 0 8 106 105 13 110 112 113 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:xoX+
a=ice-pwd:KTYSyS/M3a+9MltQ9vjeqfGQ
a=ice-options:trickle
a=mid:0
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=sendrecv
a=msid:stream_id audio_label
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:63 red/48000/2
a=fmtp:63 111/111
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:9 G722/8000
a=rtpmap:102 ILBC/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:112 telephone-event/32000
a=rtpmap:113 telephone-event/16000
a=rtpmap:126 telephone-event/8000
a=ssrc:248689302 cname:sKdWEXdSPhisX/aG
a=ssrc:248689302 msid:stream_id audio_label
a=ssrc:248689302 mslabel:stream_id
a=ssrc:248689302 label:audio_label
m=video 9 RTP/AVPF 96 97 98 99 100 101 35 36 124 123 127
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:xoX+
a=ice-pwd:KTYSyS/M3a+9MltQ9vjeqfGQ
a=ice-options:trickle
a=mid:1
a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:13 urn:3gpp:video-orientation
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
a=sendrecv
a=msid:stream_id video_label
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtpmap:98 VP9/90000
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 transport-cc
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=fmtp:98 profile-id=0
a=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=rtpmap:100 VP9/90000
a=rtcp-fb:100 goog-remb
a=rtcp-fb:100 transport-cc
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=fmtp:100 profile-id=2
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtpmap:35 AV1/90000
a=rtcp-fb:35 goog-remb
a=rtcp-fb:35 transport-cc
a=rtcp-fb:35 ccm fir
a=rtcp-fb:35 nack
a=rtcp-fb:35 nack pli
a=rtpmap:36 rtx/90000
a=fmtp:36 apt=35
a=rtpmap:124 red/90000
a=rtpmap:123 rtx/90000
a=fmtp:123 apt=124
a=rtpmap:127 ulpfec/90000
a=ssrc-group:FID 951759562 3406123244
a=ssrc:951759562 cname:sKdWEXdSPhisX/aG
a=ssrc:951759562 msid:stream_id video_label
a=ssrc:951759562 mslabel:stream_id
a=ssrc:951759562 label:video_label
a=ssrc:3406123244 cname:sKdWEXdSPhisX/aG
a=ssrc:3406123244 msid:stream_id video_label
a=ssrc:3406123244 mslabel:stream_id
a=ssrc:3406123244 label:video_label
  • Offer SDP

v=0
o=- 5891415405757292783 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1
a=extmap-allow-mixed
a=msid-semantic: WMS stream_id
m=audio 9 RTP/AVPF 111 63 103 104 9 102 0 8 106 105 13 110 112 113 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:V8Bg
a=ice-pwd:/pGLA/exQ5bdHylEsC6KOZmm
a=ice-options:trickle
a=mid:0
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=sendrecv
a=msid:stream_id audio_label
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:63 red/48000/2
a=fmtp:63 111/111
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:9 G722/8000
a=rtpmap:102 ILBC/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:112 telephone-event/32000
a=rtpmap:113 telephone-event/16000
a=rtpmap:126 telephone-event/8000
a=ssrc:661437280 cname:7HW9LbofrT0Z073x
m=video 9 RTP/AVPF 96 97 98 99 100 101 35 36 124 123 127
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:V8Bg
a=ice-pwd:/pGLA/exQ5bdHylEsC6KOZmm
a=ice-options:trickle
a=mid:1
a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:13 urn:3gpp:video-orientation
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
a=sendrecv
a=msid:stream_id video_label
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtpmap:98 VP9/90000
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 transport-cc
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=fmtp:98 profile-id=0
a=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=rtpmap:100 VP9/90000
a=rtcp-fb:100 goog-remb
a=rtcp-fb:100 transport-cc
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=fmtp:100 profile-id=2
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtpmap:35 AV1/90000
a=rtcp-fb:35 goog-remb
a=rtcp-fb:35 transport-cc
a=rtcp-fb:35 ccm fir
a=rtcp-fb:35 nack
a=rtcp-fb:35 nack pli
a=rtpmap:36 rtx/90000
a=fmtp:36 apt=35
a=rtpmap:124 red/90000
a=rtpmap:123 rtx/90000
a=fmtp:123 apt=124
a=rtpmap:127 ulpfec/90000
a=ssrc-group:FID 1704191852 3785084139
a=ssrc:1704191852 cname:7HW9LbofrT0Z073x
a=ssrc:3785084139 cname:7HW9LbofrT0Z073x

参考资料