WebRTC的丟包計算方法
背景
目前WebRTC的版本主要還是基於GCC的擁塞控制,傳送端需要根據丟包率控制傳送位元速率,而丟包率是在接收端計算並通過RR(Receiver Report RTCP)包通知傳送端。
版本
66
問題
重傳包可能會影響丟包率,如果傳送端重傳的包都被接收端收到,並且接收端沒有區分重傳包,那麼丟包率會是0,與實際的網路狀態不符,傳送端也無從控制傳送位元速率。
丟包與NACK、RTX的關係
在使能RTX的情況下,傳送端的重傳包會使用新的SSRC通過RTX傳送,這些包並不會被計入正常的接收包,這樣接收端丟包率的計算是天然正確的。
在沒有使能RTX的情況下,傳送端的重傳包就在原來的SSRC上簡單重傳,接收端沒有辦法通過什麼特殊標識區分是否是重傳包,而是以接收到包的時間戳以及估算的RTT來判斷是否是重傳包。
判斷當前包是否重傳包的演算法
t1=上一個未亂序的包到當前包時間戳的時間間隔
t2=上一個未亂序的包到當前時間的時間間隔
如果t2 > t1 + f(rtt)則認為當前包是重傳包,f(rtt)是rtt的線性函式,目前f(rtt)=rtt/3+1。
直觀解釋就是,當前包的時間戳已經是過去的時間,其加上f(rtt)後仍然是過去的時間,說明可能是接收端通過NACK通知傳送端傳送的重傳包(可能經過了一個rtt),可以認為是重傳包。
丟包的計算
1. 接收端維護兩個計數器,每收到一個RTP包都更新:
- transmitted,接收到的RTP包的總數;
- retransmitted,接收到重傳RTP包的數量;
2.某時刻收到的有序包的數量Count = transmitted-retransmitte ,當前時刻為Count2,上一時刻為Count1;
3.接收端以一定的頻率傳送RTCP包(RR、REMB、NACK等)時,會統計兩次傳送間隔之間(fraction)的接收包資訊:
//兩次傳送間隔之間理論上應該收到的包數量=當前接收到的最大包序號-上個時刻最大有序包序號
uint16_t exp_since_last = (received_seq_max_ - last_report_seq_max_);
//兩次傳送間隔之間實際接收到有序包的數量=當前時刻收到的有序包的數量-上一個時刻收到的有序包的數量
uint32_t rec_since_last = Count2 - Count1
//丟包數=理論上應收的包數-實際收到的包數
int32_t missing = exp_since_last - rec_since_last
missing即為兩次傳送間隔之間的丟包數量,會累加並通過RR包通知傳送端。
RR中的丟包
接收端傳送的RR包中包含兩個丟包,一個是fraction_lost,是兩次統計間隔間的丟包數,一個是cumulative_lost,是總的累積丟包。傳送端收到後在狀態統計Stats中看到的是累積丟包,而在計算髮送位元速率的時候更多的是使用分段丟包fraction_lost,因為其屬於比較實時的引數。