WebRTC技術(shù)專題(3)【更進(jìn)一步,核心組件RTP/RTCP數(shù)據(jù)傳輸協(xié)議】

前言介紹

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

  1. Capture線程從攝像頭采集原始數(shù)據(jù),得到VideoFrame蚌吸;

  2. Capture線程是系統(tǒng)相關(guān)的锈拨,在Linux系統(tǒng)上可能是調(diào)用V4L2接口的線程,而在Mac系統(tǒng)上可能是調(diào)用AVFoundation框架的接口羹唠。

  3. 接下來原始數(shù)據(jù)VideoFrame從Capture線程到達(dá)Worker線程奕枢,Worker線程起搬運工的作用娄昆,沒有對數(shù)據(jù)做特別處理,而是轉(zhuǎn)發(fā)到Encoder線程缝彬。

  4. Encoder線程調(diào)用具體的編碼器(如VP8, H264)對原始數(shù)據(jù)VideoFrame進(jìn)行編碼萌焰,編碼后的輸出進(jìn)一步進(jìn)行RTP封包形成RTP數(shù)據(jù)包。

  5. 然后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ò)。

  6. 在接收端一疯,Network線程從網(wǎng)絡(luò)接收字節(jié)流撼玄,接著Worker線程反序列化為RTP數(shù)據(jù)包,并在VCM模塊進(jìn)行組幀操作墩邀。

  7. 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ǔ)涧尿。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市檬贰,隨后出現(xiàn)的幾起案子姑廉,更是在濱河造成了極大的恐慌,老刑警劉巖偎蘸,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件庄蹋,死亡現(xiàn)場離奇詭異瞬内,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)限书,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門虫蝶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人倦西,你說我怎么就攤上這事能真。” “怎么了扰柠?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵粉铐,是天一觀的道長。 經(jīng)常有香客問我卤档,道長蝙泼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任劝枣,我火速辦了婚禮汤踏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘舔腾。我一直安慰自己溪胶,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布稳诚。 她就那樣靜靜地躺著哗脖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪扳还。 梳的紋絲不亂的頭發(fā)上才避,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機(jī)與錄音普办,去河邊找鬼工扎。 笑死,一個胖子當(dāng)著我的面吹牛衔蹲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播呈础,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼舆驶,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了而钞?” 一聲冷哼從身側(cè)響起沙廉,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎臼节,沒想到半個月后撬陵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體珊皿,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年巨税,在試婚紗的時候發(fā)現(xiàn)自己被綠了蟋定。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡草添,死狀恐怖驶兜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情远寸,我是刑警寧澤抄淑,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站驰后,受9級特大地震影響肆资,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜灶芝,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一郑原、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧监署,春花似錦颤专、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晓避,卻和暖如春簇捍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背俏拱。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工暑塑, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人锅必。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓事格,卻偏偏與公主長得像,于是被迫代替她去往敵國和親搞隐。 傳聞我的和親對象是個殘疾皇子驹愚,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容