前言介紹
RTP/RTCP協(xié)議是流媒體通信的基石唐瀑。
- RTP協(xié)議定義流媒體數(shù)據(jù)在互聯(lián)網(wǎng)上傳輸?shù)臄?shù)據(jù)包格式
- RTCP協(xié)議則負(fù)責(zé)可靠傳輸群凶、流量控制和擁塞控制等服務(wù)質(zhì)量保證。
在WebRTC項目中介褥,RTP/RTCP模塊作為傳輸模塊的一部分
發(fā)送端采集到的媒體數(shù)據(jù)進(jìn)行進(jìn)行封包座掘,然后交給上層網(wǎng)絡(luò)模塊發(fā)送递惋;
接收端RTP/RTCP模塊收到上層模塊的數(shù)據(jù)包后柔滔,進(jìn)行解包操作,最后把負(fù)載發(fā)送到解碼模塊萍虽。
因此睛廊,RTP/RTCP 模塊在WebRTC通信中發(fā)揮非常重要的作用。
RTP/RTCP協(xié)議概述
RTP協(xié)議是Internet上針對流媒體傳輸?shù)幕A(chǔ)協(xié)議杉编,該協(xié)議詳細(xì)說明在互聯(lián)網(wǎng)上傳輸音視頻的標(biāo)準(zhǔn)數(shù)據(jù)包格式超全。
RTP協(xié)議本身只保證實時數(shù)據(jù)的傳輸,RTCP協(xié)議則負(fù)責(zé)流媒體的傳輸質(zhì)量保證邓馒,提供流量控制和擁塞控制等服務(wù)嘶朱。
RTP會話期間,各參與者周期性彼此發(fā)送RTCP報文光酣。報文中包含各參與者數(shù)據(jù)發(fā)送和接收等統(tǒng)計信息疏遏,參與者可以據(jù)此動態(tài)控制流媒體傳輸質(zhì)量。
RFC3550 定義RTP/RTCP協(xié)議的基本內(nèi)容救军,包括報文格式财异、傳輸規(guī)則等。除此之外唱遭,IETF還定義一系列擴(kuò)展協(xié)議戳寸,包括RTP協(xié)議基于檔次的擴(kuò)展,和RTCP協(xié)議基于報文類型的擴(kuò)展拷泽,等等疫鹊。
WebRTC的數(shù)據(jù)處理和傳輸過程
WebRTC對外提供兩個線程:Signal和Worker,前者負(fù)責(zé)信令數(shù)據(jù)的處理和傳輸司致,后者負(fù)責(zé)媒體數(shù)據(jù)的處理和傳輸拆吆。
WebRTC線程關(guān)系和數(shù)據(jù)Pipline
Capture線程從攝像頭采集原始數(shù)據(jù),得到VideoFrame蚌吸;
Capture線程是系統(tǒng)相關(guān)的锈拨,在Linux系統(tǒng)上可能是調(diào)用V4L2接口的線程,而在Mac系統(tǒng)上可能是調(diào)用AVFoundation框架的接口羹唠。
接下來原始數(shù)據(jù)VideoFrame從Capture線程到達(dá)Worker線程奕枢,Worker線程起搬運工的作用娄昆,沒有對數(shù)據(jù)做特別處理,而是轉(zhuǎn)發(fā)到Encoder線程缝彬。
Encoder線程調(diào)用具體的編碼器(如VP8, H264)對原始數(shù)據(jù)VideoFrame進(jìn)行編碼萌焰,編碼后的輸出進(jìn)一步進(jìn)行RTP封包形成RTP數(shù)據(jù)包。
然后RTP數(shù)據(jù)包發(fā)送到Pacer線程進(jìn)行平滑發(fā)送谷浅,Pacer線程會把RTP數(shù)據(jù)包推送到Network線程扒俯。最終Network線程調(diào)用傳輸層系統(tǒng)函數(shù)把數(shù)據(jù)發(fā)送到網(wǎng)絡(luò)。
在接收端一疯,Network線程從網(wǎng)絡(luò)接收字節(jié)流撼玄,接著Worker線程反序列化為RTP數(shù)據(jù)包,并在VCM模塊進(jìn)行組幀操作墩邀。
Decoder線程對組幀完成的數(shù)據(jù)幀進(jìn)行解碼操作掌猛,解碼后的原始數(shù)據(jù)VideoFrame會推送到IncomingVideoStream線程,該線程把VideoStream投放到render進(jìn)行渲染顯示眉睹。至此荔茬,一幀視頻數(shù)據(jù)完成從采集到顯示的完整過程。
在上述過程中竹海,RTP數(shù)據(jù)包產(chǎn)生在發(fā)送端編碼完成后慕蔚,其編碼輸出被封裝為RTP報文,然后經(jīng)序列化發(fā)送到網(wǎng)絡(luò)斋配。
在接收端由網(wǎng)絡(luò)線程收到網(wǎng)絡(luò)數(shù)據(jù)包后孔飒,經(jīng)過反序列化還原成RTP報文,然后經(jīng)過解包得到媒體數(shù)據(jù)負(fù)載许起,供解碼器進(jìn)行解碼十偶。
RTP報文在發(fā)送和接收過程中,會執(zhí)行一系列統(tǒng)計操作园细,統(tǒng)計結(jié)果作為數(shù)據(jù)源供構(gòu)造RTCP報文之用惦积。
RTP報文構(gòu)造、發(fā)送/接收統(tǒng)計和RTCP報文構(gòu)造猛频、解析反饋狮崩,是接下來分析的重點。
RTP報文發(fā)送和接收
RTP報文的構(gòu)造和發(fā)送發(fā)生在編碼器編碼之后鹿寻、網(wǎng)絡(luò)層發(fā)送數(shù)據(jù)包之前睦柴,而接收和解包發(fā)生在網(wǎng)絡(luò)層接收數(shù)據(jù)之后、解碼器編碼之前毡熏。本節(jié)詳細(xì)分析這兩部分的內(nèi)容坦敌。
RTP報文構(gòu)造和發(fā)送
發(fā)送端編碼之后RTP報文的構(gòu)造和發(fā)送過程,涉及三個線程:Encoder、Pacer和Network狱窘,分別負(fù)責(zé)編碼和構(gòu)造RTP報文杜顺,平滑發(fā)送和傳輸層發(fā)送。下面詳細(xì)描述這三個線程的協(xié)同工作過程蘸炸。
RTP報文構(gòu)造和發(fā)送
開源實時音視頻技術(shù)WebRTC中RTP/RTCP數(shù)據(jù)傳輸協(xié)議的應(yīng)用
Encode線程調(diào)用編碼器(比如VP8)對采集到的Raw VideoFrame進(jìn)行編碼躬络,編碼完成以后,其輸出EncodedImage通過回調(diào)到達(dá)VideoSendStream::Encoded()函數(shù)搭儒,進(jìn)而通過PayloadRouter路由到ModuleRtpRtcpImpl::SendOutgoingData()穷当。
-
該函數(shù)向下調(diào)用RtpSender::SendOutgoingData(),進(jìn)而調(diào)用RtpSenderVideo::SendVideo()淹禾。
- 該函數(shù)對EncodedImage進(jìn)行打包馁菜,然后填充RTP頭部構(gòu)造RTP報文;如果配置了FEC稀拐,則進(jìn)一步封裝為FEC報文火邓。最后返回RtpSender::SendToNetwork()進(jìn)行下一步發(fā)送丹弱。
RtpSender::SendToNetwork()函數(shù)把報文存儲到RTPPacketHistory結(jié)構(gòu)中進(jìn)行緩存德撬。
接下來如果開啟PacedSending,則構(gòu)造Packet發(fā)送到PacedSender進(jìn)行排隊躲胳,否則直接發(fā)送到網(wǎng)絡(luò)層蜓洪。
Pacer線程周期性從隊列中獲取Packet,然后調(diào)用PacedSender::SendPacket()進(jìn)行發(fā)送坯苹,
接下來經(jīng)過ModuleRtpRtcpImpl到達(dá)RtpSender::TimeToSendPacket()隆檀。
該函數(shù)首先從RtpPacketHistory緩存中拿到Packet的負(fù)載,然后調(diào)用PrepareAndSendPacket()函數(shù):更新RtpHeader的相關(guān)域粹湃,統(tǒng)計延遲和數(shù)據(jù)包恐仑,調(diào)用SendPacketToNetwork()把報文發(fā)送到傳輸模塊。
Network線程則調(diào)用傳輸層套接字執(zhí)行數(shù)據(jù)發(fā)送操作为鳄。至此裳仆,發(fā)送端的RTP構(gòu)造和發(fā)送流程完成。需要注意的是孤钦,在RtpSender中進(jìn)行Rtp發(fā)送后歧斟,會統(tǒng)計RTP報文相關(guān)信息。這些信息作為RTCP構(gòu)造SR/RR報文的數(shù)據(jù)來源偏形,因此非常重要静袖。
RTP報文接收和解析
在接收端,RTP報文的接收和解包操作主要在Worker線程中執(zhí)行俊扭,RTP報文從Network線程拿到后队橙,進(jìn)入Worker線程,經(jīng)過解包操作,進(jìn)入VCM模塊捐康,由Decode線程進(jìn)行解碼畅姊,最終由Render線程進(jìn)行渲染。
RTP報文接收和解析
RTP數(shù)據(jù)包經(jīng)網(wǎng)絡(luò)層到達(dá)Call對象吹由,根據(jù)其SSRC找到對應(yīng)的VideoReceiveStream若未,通過調(diào)用其DeliverRtp()函數(shù)到RtpStreamReceiver:eliverRtp()。
該函數(shù)首先解析數(shù)據(jù)包得到RTP頭部信息倾鲫,接下來執(zhí)行三個操作:1.碼率估計粗合;2.繼續(xù)發(fā)送數(shù)據(jù)包;3.接收統(tǒng)計乌昔。碼率估計模塊使用GCC算法估計碼率隙疚,構(gòu)造REMB報文,交給RtpRtcp模塊發(fā)送回發(fā)送端磕道。
而接收統(tǒng)計則統(tǒng)計RTP接收信息供屉,這些信息作為RTCP RR報文的數(shù)據(jù)來源。下面重點分析接下來的數(shù)據(jù)包發(fā)送流程溺蕉。
RtpStreamReceiver::ReceivePacket()首先判斷數(shù)據(jù)包是否是FEC報文伶丐,如果是則調(diào)用FecReceiver進(jìn)行解包,否則直接調(diào)用RtpReceiver::IncomingRtpPacket()疯特。
該函數(shù)分析RTP報文得到通用的RTP頭部描述結(jié)構(gòu)哗魂,然后調(diào)用RtpReceiverVideo:arseRtpPacket()進(jìn)一步得到Video相關(guān)信息和負(fù)載,接著經(jīng)過回調(diào)返回RtpStreamReceiver對象漓雅。該對象把Rtp描述信息和負(fù)載發(fā)送到VCM模塊录别,繼續(xù)接下來的JitterBuffer緩存和解碼渲染操作。
RTP報文解包過程是封包的逆過程邻吞,重要的輸出信息是RTP頭部描述和媒體負(fù)載组题,這些信息是下一步JitterBuffer緩存和解碼的基礎(chǔ)。另外對RTP報文進(jìn)行統(tǒng)計得到的信息則是RTCP RR報文的數(shù)據(jù)來源抱冷。
RTCP報文發(fā)送和接收
RTCP協(xié)議是RTP協(xié)議的控制下可以崔列,負(fù)責(zé)流媒體的服務(wù)質(zhì)量保證。比較常用的RTCP報文由發(fā)送端報告SR和接收端報告RR徘层,分別包含數(shù)據(jù)發(fā)送統(tǒng)計信息和數(shù)據(jù)接收信息峻呕。這些信息對于流媒體質(zhì)量保證非常重要,比如碼率控制趣效、負(fù)載反饋瘦癌,等等。其他RTCP報文還有諸如SDES跷敬、BYE讯私、SDES等,RFC3550對此有詳細(xì)定義。
本節(jié)重點分析WebRTC內(nèi)部RTCP報文的構(gòu)造斤寇、發(fā)送桶癣、接收、解析娘锁、反饋等流程牙寞。需要再次強(qiáng)調(diào)的是,RTCP報文的數(shù)據(jù)源來自RTP報文發(fā)送和接收時的統(tǒng)計信息莫秆。在WebRTC內(nèi)部间雀,RTCP報文的發(fā)送采取周期性發(fā)送和及時發(fā)送相結(jié)合的策略:ModuleProcess線程周期性發(fā)送RTCP報文;而RtpSender則在每次發(fā)送RTP報文之前都判斷是否需要發(fā)送RTCP報文镊屎;另外在接收端碼率估計模塊構(gòu)造出REMB報文后惹挟,通過設(shè)置超時讓ModuleProcess模塊立即發(fā)送RTCP報文。
RTCP報文構(gòu)造和發(fā)送
在發(fā)送端缝驳,RTCP以周期性發(fā)送為基準(zhǔn)欣除,輔以RTP報文發(fā)送時的及時發(fā)送和REMB報文的立即發(fā)送宛蚓。發(fā)送過程主要包括Feedback信息獲取守问、RTCP報文構(gòu)造悠夯、序列化和發(fā)送刘离。下圖描述了RTCP報文的構(gòu)造和發(fā)送過程线衫。
RTCP報文構(gòu)造和發(fā)送:
開源實時音視頻技術(shù)WebRTC中RTP/RTCP數(shù)據(jù)傳輸協(xié)議的應(yīng)用_4.png
ModuleProcess線程周期性調(diào)用ModuleRtpRtcpImpl:rocess()函數(shù)步鉴,該函數(shù)通過RTCPSender::TimeToSendRtcpReport()函數(shù)確定當(dāng)前是否需要立即發(fā)送RTCP報文孩等。若是,則首先從RTPSender::GetDataCounters()獲取RTP發(fā)送統(tǒng)計信息署海,然后調(diào)用RTCPSender::SendRTCP(),接著是SendCompoundRTCP()發(fā)送RTCP組合報文医男。
在SendCompoundRTCP()函數(shù)中砸狞,首先通過PrepareReport()確定將要發(fā)送何種類型的RTCP報文。然后針對每一種報文镀梭,調(diào)用其構(gòu)造函數(shù)(如構(gòu)造SR報文為BuildSR()函數(shù))刀森,構(gòu)造好的報文存儲在PacketContainer容器中。最后調(diào)用SendPackets()進(jìn)行發(fā)送报账。
接下來每種RTCP報文都會調(diào)用各自的序列化函數(shù)研底,把報文序列化為網(wǎng)絡(luò)字節(jié)流。最后通過回調(diào)到達(dá)PacketContainer::OnPacketReady()透罢,最終把字節(jié)流發(fā)送到傳輸層模塊:即通過TransportAdapter到達(dá)BaseChannel榜晦,Network線程調(diào)用傳輸層套接字API發(fā)送數(shù)據(jù)到網(wǎng)絡(luò)。
RTCP報文的構(gòu)造和發(fā)送過程總體不是很復(fù)雜羽圃,最核心的操作就是獲取數(shù)據(jù)源乾胶、構(gòu)造報文、序列化和發(fā)送。相對來說構(gòu)造報文和序列化比較繁瑣识窿,基于RFC定義的細(xì)節(jié)進(jìn)行斩郎。
RTCP報文接收和解析
在接收端,RTCP報文的接收流程和RTP一樣喻频,經(jīng)過網(wǎng)絡(luò)接收之后到達(dá)Call對象缩宜,進(jìn)而通過SSRC找到VideoReceiveStream,繼而到達(dá)RtpStreamReceiver甥温。接下來RTCP報文的解析和反饋操作都在ModuleRtpRtcpImpl::IncomingRtcpPacket()函數(shù)中完成脓恕。
該函數(shù)首先調(diào)用RTCPReceiver::IncomingRtcpPacket()解析RTCP報文,得到RTCPPacketInformation對象窿侈,然后調(diào)用 TriggerCallbacksFromRTCPPacket()炼幔,觸發(fā)注冊在此處的各路觀察者執(zhí)行回調(diào)操作。
RTCPReceiver::IncomingRtcpPacket()使用RTCPParser解析組合報文史简,針對每一種報文類型乃秀,調(diào)用對應(yīng)的處理函數(shù)(如處理SDES的HandleSDES函數(shù)),反序列化后拿到報文的描述結(jié)構(gòu)圆兵。最后所有報文綜合在一起形成RTCPPacketInformation對象跺讯。該對象接下來作為參數(shù)調(diào)用TriggerCallbacksFromRTCPPacket()函數(shù)觸發(fā)回調(diào)操作,如處理NACK的回調(diào)殉农,處理SLI的回調(diào)刀脏,處理REMB的回調(diào),等等超凳。這些回調(diào)在各自模塊控制流媒體數(shù)據(jù)的編碼愈污、發(fā)送、碼率等服務(wù)質(zhì)量保證轮傍,這也是RTCP報文最終起作用的地方暂雹。
至此,我們分析了RTCP報文發(fā)送和接收的整個流程创夜。
小結(jié)
本文在深入分析WebRTC源代碼的基礎(chǔ)上杭跪,描述出RTP/RTCP模塊的實現(xiàn)流程,在關(guān)鍵問題上(如RTCP報文的數(shù)據(jù)來源)進(jìn)行深入細(xì)致的研究驰吓。為進(jìn)一步深入掌握WebRTC的實現(xiàn)原理和細(xì)節(jié)打下良好基礎(chǔ)涧尿。