WebRTC 的平滑發(fā)送

平滑的發(fā)送

Paced sender今豆,也常常被稱為 “pacer”,它是 WebRTC RTP 棧的一部分亚斋,主要用于平緩發(fā)送到網(wǎng)絡(luò)的數(shù)據(jù)包流隙弛。

背景

考慮一個(gè)碼率為 5Mbps 幀率為 30fps 的視頻流饱溢。理想情況下喧伞,這個(gè)視頻流的每個(gè)幀的大小大約 21kB,每個(gè)幀被打包成大約 18 個(gè) RTP 數(shù)據(jù)包绩郎。雖然說(shuō)每秒中滑動(dòng)窗口的平均比特率是正確的 5Mbps潘鲫,但在更短的時(shí)間尺度上,它可以被視為每隔 33 毫秒 167 Mbps 的突發(fā)傳輸肋杖,然后是 32 毫秒的靜默期溉仑。此外,相當(dāng)常見(jiàn)的是状植,在突然移動(dòng)的情況下浊竟,尤其是在處理屏幕共享時(shí),視頻編碼器會(huì)超出目標(biāo)幀大小津畸。比理想大小大 10 倍甚至 100 倍的幀是一個(gè)非常真實(shí)的場(chǎng)景振定。這些數(shù)據(jù)包突發(fā)可能會(huì)導(dǎo)致一些問(wèn)題,例如網(wǎng)絡(luò)擁塞和緩沖區(qū)膨脹肉拓,甚至是數(shù)據(jù)包丟失后频。大多數(shù)會(huì)話都有多個(gè)媒體流,比如一個(gè)視頻軌道和一個(gè)音頻軌道暖途。如果你一次將一個(gè)視頻幀發(fā)送到網(wǎng)絡(luò)上卑惜,并且這些數(shù)據(jù)包需要 100 毫秒到達(dá)對(duì)端 —— 這意味著你現(xiàn)在也阻塞了任何音頻數(shù)據(jù)包及時(shí)到達(dá)遠(yuǎn)端。

Paced sender 通過(guò)使用一個(gè)緩沖區(qū)來(lái)解決這個(gè)問(wèn)題驻售,媒體數(shù)據(jù)包先在這個(gè)緩沖區(qū)里排隊(duì)露久,然后使用一個(gè) 漏桶 算法將它們平緩地發(fā)送到網(wǎng)絡(luò)上。緩沖區(qū)中包含所有媒體軌道的單獨(dú)的 fifo 流欺栗,以便實(shí)現(xiàn)抱环,比如音頻可以優(yōu)先于視頻 - 并且可以以循環(huán)方式發(fā)送優(yōu)先級(jí)相等的流,以避免任何一個(gè)流阻塞其它流纸巷。

由于 pacer 控制在網(wǎng)絡(luò)上發(fā)送的比特率镇草,因此它還用于在需要最小發(fā)送速率的情況下生成填充 - 如果使用比特率探測(cè),則生成數(shù)據(jù)包序列瘤旨。

數(shù)據(jù)包的生命周期

當(dāng)使用 paced sender 時(shí)梯啤,媒體數(shù)據(jù)包的典型路徑看起來(lái)就像這樣:

  1. RTPSenderVideoRTPSenderAudio 將媒體數(shù)據(jù)打包成 RTP 數(shù)據(jù)包。

  2. 數(shù)據(jù)包被發(fā)送給 [RTPSender] 類進(jìn)行傳輸存哲。

  3. pacer 通過(guò) [RtpPacketSender] 接口被調(diào)用以將數(shù)據(jù)包批量入隊(duì)因宇。

  4. 數(shù)據(jù)包被放進(jìn) pacer 內(nèi)的隊(duì)列中七婴,等待適當(dāng)?shù)臅r(shí)機(jī)發(fā)送它們。

  5. 在計(jì)算好的時(shí)間察滑,pacer 調(diào)用 PacingController::PacketSender() 回調(diào)方法打厘,通常由 [PacketRouter] 類實(shí)現(xiàn)。

  6. router 基于數(shù)據(jù)包的 SSRC 將數(shù)據(jù)包轉(zhuǎn)發(fā)到正確的 RTP 模塊贺辰,并在其中的 RTPSenderEgress 類中打上最后的時(shí)間戳户盯,可能會(huì)保存它以進(jìn)行重傳等。

  7. 數(shù)據(jù)包被發(fā)送到底層的 Transport 接口饲化,之后它現(xiàn)在超出了范圍莽鸭。

與此異步進(jìn)行的是確定估計(jì)的可用發(fā)送帶寬 - 并通過(guò) void SetPacingRates(DataRate pacing_rate, DataRate padding_rate) 方法對(duì) RtpPacketPacker 設(shè)置目標(biāo)發(fā)送速率。

數(shù)據(jù)包優(yōu)先級(jí)

pacer 基于兩個(gè)標(biāo)準(zhǔn)對(duì)數(shù)據(jù)包進(jìn)行優(yōu)先級(jí)排序:

  • 數(shù)據(jù)包類型吃靠,優(yōu)先級(jí)從高到低如下:

    1. 音頻
    2. 重傳
    3. 視頻和 FEC
    4. 填充
  • 入隊(duì)的順序

入隊(duì)順序是在每個(gè)流 (SSRC) 的基礎(chǔ)上執(zhí)行的硫眨。給定相同的優(yōu)先級(jí),[RoundRobinPacketQueue] 在媒體流之間交替巢块,以確保沒(méi)有流不必要地阻塞其它流礁阁。

實(shí)現(xiàn)

當(dāng)前 paced sender 有兩個(gè)實(shí)現(xiàn)(盡管它們通過(guò) PacingController 類共享大量的邏輯)。 傳統(tǒng)的 [PacedSender] 使用專門的線程以 5ms 的間隔輪詢 pacing 控制器族奢,并具有保護(hù)內(nèi)部狀態(tài)的鎖氮兵。顧名思義,更新的 [TaskQueuePacedSender] 使用 [TaskQueue] 來(lái)保護(hù)狀態(tài)歹鱼,并調(diào)度數(shù)據(jù)包處理泣栈,后者動(dòng)態(tài)地基于實(shí)際的發(fā)送速率和約束。避免在新的應(yīng)用中使用傳統(tǒng)的 PacedSender弥姻,我們已經(jīng)在計(jì)劃移除它了南片。

數(shù)據(jù)包路由器

一個(gè)稱為 [PacketRouter] 的相鄰組件用于路由從 pacer 出來(lái)的數(shù)據(jù)包,并進(jìn)入正確的 RTP 模塊庭敦。它具有以下功能:

  • SendPacket 方法查找具有對(duì)應(yīng)于數(shù)據(jù)包的 SSRC 的 RTP 模塊疼进,以進(jìn)一步路由到網(wǎng)絡(luò)。秧廉。
  • 如果使用了發(fā)送端帶寬估計(jì)伞广,它會(huì)填充傳輸范圍內(nèi)的序列號(hào)擴(kuò)展。
  • 生成填充疼电。支持基于負(fù)載的填充的模塊被優(yōu)先考慮嚼锄,最后一個(gè)發(fā)送媒體的模塊始終是第一選擇。
  • 發(fā)送媒體之后返回任何生成的 FEC蔽豺。
  • 轉(zhuǎn)發(fā) REMB 和/或 TransportFeedback 消息給適當(dāng)?shù)?RTP 模塊区丑。

目前 FEC 是基于每個(gè) SSRC 生成的,因此總是在發(fā)送媒體后從 RTP 模塊返回。希望有一天沧侥,我們將支持使用單個(gè) FlexFEC 流覆蓋多個(gè)流 - 則數(shù)據(jù)包路由器是這種 FEC 生成器可能存在的地方可霎。它甚至可以用于 FEC 填充,作為 RTX 的替代方案宴杀。

API

這一節(jié)概述了與 pacer 的幾個(gè)不同用例相關(guān)的類和方法

數(shù)據(jù)包發(fā)送

要發(fā)送數(shù)據(jù)包癣朗,可以使用 RtpPacketSender::EnqueuePackets(std::vector<std::unique_ptr<RtpPacketToSend>> packets)。pacer 接收一個(gè) PacingController::PacketSender 對(duì)象作為構(gòu)造函數(shù)的參數(shù)旺罢,當(dāng)需要實(shí)際發(fā)送數(shù)據(jù)包時(shí)使用這個(gè)回調(diào)旷余。

發(fā)送速率

要控制發(fā)送速率,則使用 void SetPacingRates(DataRate pacing_rate, DataRate padding_rate)主经。如果數(shù)據(jù)包隊(duì)列變?yōu)榭杖倌海野l(fā)送速率掉到 padding_rate 以下庭惜,則 pacer 將從 PacketRouter 請(qǐng)求填充包罩驻。

要完全掛起/恢復(fù)發(fā)送數(shù)據(jù)(比如,由于網(wǎng)絡(luò)可用性)护赊,則使用 Pause()Resume() 方法惠遏。

在某些情況下,指定的 pacing 速率可能會(huì)被覆蓋骏啰,例如由于極端的編碼器過(guò)沖节吮。使用 void SetQueueTimeLimit(TimeDelta limit) 來(lái)指定你希望數(shù)據(jù)包在 pacer 的隊(duì)列中等待的最長(zhǎng)時(shí)間(暫停除外)。實(shí)際發(fā)送速率可能會(huì)增加到超過(guò) pacing_rate判耕,以嘗試使 平均 排隊(duì)時(shí)間小于請(qǐng)求的限制透绩。這樣做的理由是,如果發(fā)送隊(duì)列長(zhǎng)于三秒壁熄,最好冒丟包的風(fēng)險(xiǎn)帚豪,然后嘗試使用關(guān)鍵幀進(jìn)行恢復(fù),而不是造成嚴(yán)重的延遲草丧。

帶寬估計(jì)

如果帶寬估計(jì)器支持帶寬探測(cè)狸臣,它可能會(huì)請(qǐng)求以指定速率發(fā)送一組數(shù)據(jù)包,以判斷這是否會(huì)導(dǎo)致網(wǎng)絡(luò)延遲/丟失增加昌执。使用 void CreateProbeCluster(DataRate bitrate, int cluster_id) 方法 - 通過(guò)這個(gè) PacketRouter 發(fā)送的數(shù)據(jù)包將在附加的 PacedPacketInfo 結(jié)構(gòu)中用相應(yīng)的 cluster_id 進(jìn)行標(biāo)記烛亦。

如果使用擁塞窗口 pushback,則可以使用 SetCongestionWindow()UpdateOutstandingData() 更新?tīng)顟B(tài)懂拾。

還有一些方法可以幫我們控制如何 pace:

  • SetAccountForAudioPackets() 確定音頻數(shù)據(jù)包是否計(jì)入帶寬消耗煤禽。
  • SetIncludeOverhead() 確定是否把完整 RTP 數(shù)據(jù)包大小計(jì)入帶寬使用(否則只計(jì)算媒體載荷)。
  • SetTransportOverhead() 設(shè)置每個(gè)數(shù)據(jù)包消耗的額外數(shù)據(jù)大小岖赋,表示比如 UDP/IP 頭部呜师。

統(tǒng)計(jì)數(shù)據(jù)

有幾種方法用于在 pacer 狀態(tài)中收集統(tǒng)計(jì)信息:

  • OldestPacketWaitTime(),自添加進(jìn)隊(duì)列中的最早的數(shù)據(jù)包被添加進(jìn)隊(duì)列以來(lái)的時(shí)間贾节。
  • QueueSizeData()汁汗,當(dāng)前在隊(duì)列中的總字節(jié)數(shù)衷畦。
  • FirstSentPacketTime(),發(fā)送第一個(gè)數(shù)據(jù)包的絕對(duì)時(shí)間知牌。
  • ExpectedQueueTime()祈争,隊(duì)列中的總字節(jié)數(shù)除以發(fā)送速率。

RTPSender
RtpPacketSender
RtpPacketPacer
PacketRouter
PacedSender
TaskQueuePacedSender
RoundRobinPacketQueue

原文

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末角寸,一起剝皮案震驚了整個(gè)濱河市菩混,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扁藕,老刑警劉巖沮峡,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異亿柑,居然都是意外死亡邢疙,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門望薄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)疟游,“玉大人,你說(shuō)我怎么就攤上這事痕支“渑埃” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵卧须,是天一觀的道長(zhǎng)另绩。 經(jīng)常有香客問(wèn)我,道長(zhǎng)花嘶,這世上最難降的妖魔是什么笋籽? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮察绷,結(jié)果婚禮上干签,老公的妹妹穿的比我還像新娘。我一直安慰自己拆撼,他們只是感情好容劳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著闸度,像睡著了一般竭贩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上莺禁,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天留量,我揣著相機(jī)與錄音,去河邊找鬼。 笑死楼熄,一個(gè)胖子當(dāng)著我的面吹牛忆绰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播可岂,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼错敢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了缕粹?” 一聲冷哼從身側(cè)響起稚茅,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎平斩,沒(méi)想到半個(gè)月后亚享,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绘面,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年欺税,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片飒货。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡魄衅,死狀恐怖峭竣,靈堂內(nèi)的尸體忽然破棺而出塘辅,到底是詐尸還是另有隱情,我是刑警寧澤皆撩,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布扣墩,位于F島的核電站,受9級(jí)特大地震影響扛吞,放射性物質(zhì)發(fā)生泄漏呻惕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一滥比、第九天 我趴在偏房一處隱蔽的房頂上張望亚脆。 院中可真熱鬧,春花似錦盲泛、人聲如沸濒持。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)柑营。三九已至,卻和暖如春村视,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工杖小, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人惋嚎。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像站刑,于是被迫代替她去往敵國(guó)和親瘸彤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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