在WebRTC中,前向糾錯(cuò)(FEC)和丟包重傳(NACK)是抵抗網(wǎng)絡(luò)錯(cuò)誤的重要手段。FEC在發(fā)送端將數(shù)據(jù)包添加冗余糾錯(cuò)碼,糾錯(cuò)碼連同數(shù)據(jù)包一起發(fā)送到接收端;接收端根據(jù)糾錯(cuò)碼對(duì)數(shù)據(jù)進(jìn)行檢查和糾正。RFC5109[1]定義FEC數(shù)據(jù)包的格式。NACK則在接收端檢測(cè)到數(shù)據(jù)丟包后,發(fā)送NACK報(bào)文到發(fā)送端;發(fā)送端根據(jù)NACK報(bào)文中的序列號(hào),在發(fā)送緩沖區(qū)找到對(duì)應(yīng)的數(shù)據(jù)包,重新發(fā)送到接收端。NACK需要發(fā)送端發(fā)送緩沖區(qū)的支持,RFC5104[2]定義NACK數(shù)據(jù)包的格式。</br>
本文在研究WebRTC源代碼的基礎(chǔ)上,以Video數(shù)據(jù)包的發(fā)送和接收為例,深入分析ANCK丟包重傳機(jī)制的實(shí)現(xiàn)。主要內(nèi)容包括:SDP協(xié)商N(yùn)ACK,接收端丟包判定,NACK報(bào)文構(gòu)造、發(fā)送、接收和解析,RTP數(shù)據(jù)包重傳。下面分別詳細(xì)論述之。</br>
1 SDP協(xié)商N(yùn)ACK
</br>
NACK作為RTP層反饋參數(shù),和Video Codec聯(lián)系在一起。WebRTC在初始化階段,創(chuàng)建PeerConnectionFactory對(duì)象,在該對(duì)象中創(chuàng)建MediaEngine,其中的VideoEngine為WebRtcVideoEngine2。該對(duì)象在構(gòu)造時(shí),會(huì)收集本端支持的所有Video Codec,NACK作為Codec的屬性被一起收集。在接下來(lái)的SDP協(xié)商過(guò)程中,NACK屬性被協(xié)商到Offer/Answer中,如圖1所示。</br>
PeerConnection在CreateOffer時(shí),收集本端的會(huì)話控制信息、音視頻Codec信息和網(wǎng)絡(luò)信息等內(nèi)容。視頻Codec信息從WebRtcVideoEngine2中獲取。最后本端Offer形成SDP報(bào)文,經(jīng)過(guò)PeerConnection對(duì)象發(fā)送到網(wǎng)絡(luò)。</br>
接收端在收到Offer之后,首先調(diào)用SetRemoteDescription,根據(jù)本地配置信息向下創(chuàng)建VideoReceiveStream對(duì)象,本地NACK配置信息會(huì)最終到達(dá)VCMJitterBuffer。接著PeerConnection調(diào)用CreateAnswer,生成Answer;根據(jù)Offer中的Codec信息和本端支持的Codec信息,最終選定雙方都支持的Codec集合。最后用生成的Answer作為參數(shù)調(diào)用SetLocalDescription,根據(jù)Answer中的Video Codec信息向下重新創(chuàng)建VideoReceiveStream對(duì)象。NACK信息向下傳遞最終到達(dá)VCMJitterBuffer,在這里設(shè)置NACK相關(guān)參數(shù)。這些參數(shù)在接收RTP數(shù)據(jù)包過(guò)程中發(fā)揮作用,比如判斷丟包、是否發(fā)送NACK報(bào)文等。Answer發(fā)回發(fā)送端時(shí),發(fā)送端調(diào)用SetRemoteDescription執(zhí)行同樣的設(shè)置流程。</br>
2 接收端丟包判定
</br>
Video接收端丟包判定在Worker線程中進(jìn)行。RTP數(shù)據(jù)包到達(dá)接收端后,經(jīng)過(guò)RTP模塊到達(dá)VCM模塊的JitterBuffer對(duì)象,最終調(diào)用VCMJitterBuffer的InsertPacket函數(shù)對(duì)數(shù)據(jù)包進(jìn)行緩存和重排。</br>
VCMJitterBuffer把丟失RTP數(shù)據(jù)包的序列號(hào)存儲(chǔ)在集合missing_seq_nums中。對(duì)于本次從RTP模塊到來(lái)的數(shù)據(jù)包,標(biāo)記其序列號(hào)為seq1,而上次到達(dá)數(shù)據(jù)包的序列號(hào)為seq2。如果seq1 > seq2,則表示seq1順序到達(dá),標(biāo)記(seqnum2, seqnum1)區(qū)間內(nèi)的數(shù)據(jù)包為丟失狀態(tài),將其存儲(chǔ)到missing_seq_nums集合中。注意這里的丟失狀態(tài)是暫時(shí)的,如果下個(gè)數(shù)據(jù)包到達(dá)時(shí)有seq1 < seq2,則表示數(shù)據(jù)包亂序到達(dá),則把missing_seq_nums中小于seq1的序列號(hào)都刪除掉。</br>
在更新missing_seq_nums集合時(shí),如果集合中存儲(chǔ)的序列號(hào)超過(guò)預(yù)設(shè)的容量,則通過(guò)調(diào)用RecycleFramesUntilKeyFrame()不斷丟包來(lái)減少集合中的序列號(hào),直到集合中的序列號(hào)總數(shù)低于預(yù)設(shè)容量值。</br>
3 NACK報(bào)文發(fā)送和接收
</br>
接收端的NACK報(bào)文構(gòu)造和發(fā)送工作在ModuleProcessThread線程中周期性完成。過(guò)程如圖2所示。</br>
ModuleProcessThread線程周期性調(diào)用VideoReceiver::process函數(shù),該函數(shù)通過(guò)VCMReceiver調(diào)用VCMJitterBuffer::GetNackList,從missing_seq_nums集合中得到過(guò)去一段時(shí)間內(nèi)丟失RTP數(shù)據(jù)包的序列號(hào)。然后調(diào)用RtpStreamReceiver::ResendPackets函數(shù)。調(diào)用流程最終會(huì)到達(dá)RTCPSender::SendRTCP,發(fā)送類型為NACK的RTCP報(bào)文。</br>
NACK報(bào)文是類型為205的RTCP 擴(kuò)展反饋報(bào)文,在RFC4585中定義[4]。具體格式如圖3所示:</br>
其中PT = 205,F(xiàn)MT = 1,Packet identifier(PID)即為丟失RTP數(shù)據(jù)包的序列號(hào),Bitmao of Lost Packets(BLP)指示從PID開始接下來(lái)16個(gè)RTP數(shù)據(jù)包的丟失情況。一個(gè)NACK報(bào)文可以攜帶多個(gè)RTP序列號(hào),NACK接收端對(duì)這些序列號(hào)逐個(gè)處理。</br>
NACK報(bào)文構(gòu)造完成以后,發(fā)送到網(wǎng)絡(luò)層。NACK報(bào)文是RTCP報(bào)文的一種,因此其發(fā)送、接收和分析遵循RTCP報(bào)文處理的一般流程。這部分內(nèi)容可參考文檔[3]。</br>
4 RTP數(shù)據(jù)包重傳
</br>
接收端在接收和解析NACK報(bào)文后,通過(guò)回調(diào)機(jī)制處理各種類型的RTCP報(bào)文,對(duì)于NACK報(bào)文,會(huì)調(diào)用RTPSender重新發(fā)送RTP數(shù)據(jù)包,如圖4所示:</br>
RTCPReceiver在解析RTCP之后,得到RTCP報(bào)文的描述結(jié)構(gòu),然后通過(guò)回調(diào)進(jìn)行報(bào)文語(yǔ)義處理。NACK報(bào)文會(huì)被發(fā)送到RTPSender進(jìn)行處理。RTPSender根據(jù)NACK報(bào)文中包含的序列號(hào),到RTPPacketHistory緩存中查找對(duì)應(yīng)的RTP數(shù)據(jù)包。如果找到,則把數(shù)據(jù)包發(fā)送到網(wǎng)絡(luò)。</br>
至此,一個(gè)完整的NACK報(bào)文回路完成,丟失的RTP數(shù)據(jù)包會(huì)重新發(fā)送到接收端。</br>
5 總結(jié)
</br>
本文深入分析了WebRTC內(nèi)部關(guān)于丟包重傳(NACK)的實(shí)現(xiàn)細(xì)節(jié),對(duì)NACK的SDP協(xié)商、丟包判定和重傳進(jìn)行深入研究,為繼續(xù)學(xué)習(xí)掌握WebRTC的QoS機(jī)制奠定基礎(chǔ)。</br>
</br>
參考文獻(xiàn)
[1] RFC5109 - RTP Payload Format for Generic Forward Error Correction.</br>
[2] RFC5104 - RFC 5104 - Codec Control Messages in the RTP Audio-Visual Profile with Feedback (AVPF) </br>
[3] WebRTC中RTP/RTCP協(xié)議實(shí)現(xiàn)分析 - http://www.lxweimin.com/p/c84be6f3ddf3 </br>
[4] RFC4585 - Extended RTP Profile for Real-time Transport Control Protocol (RTCP)-Based Feedback (RTP/AVPF)