WebRTC 系列之视频辅流
導(dǎo)讀:近幾年,實(shí)時(shí)音視頻領(lǐng)域越來越熱,業(yè)界很多音視頻引擎都是基于 WebRTC 進(jìn)行實(shí)現(xiàn)的。本文主要介紹 WebRTC 在視頻輔流上的需求背景以及相關(guān)技術(shù)實(shí)現(xiàn)。
文|陶金亮
網(wǎng)易云信資深客戶端開發(fā)工程師
WebRTC 中的 SDP 支持兩種方案:PlanB 方案 和 Unified Plan 方案。早期我們使用多PeerConnection的 Plan B 方案中只支持一條視頻流發(fā)送,這條視頻流,我們稱之為”主流”。目前我們使用單 PeerConnection 的 Unified Plan 方案,新增一條視頻輔流,何為視頻”輔流”?視頻輔流是指第二條視頻流,一般用于屏幕共享。
需求背景
隨著業(yè)務(wù)的發(fā)展,一路視頻流滿足不了更多實(shí)際業(yè)務(wù)場(chǎng)景的需求,例如在多人視頻聊天、網(wǎng)易會(huì)議以及其他在線教育場(chǎng)景下,需要同時(shí)發(fā)送兩路視頻流:一路是攝像頭流,另一路是屏幕共享流。
但是,目前使用 SDK 分享屏幕時(shí),采用的是從攝像頭采集通道進(jìn)行屏幕分享。在該方案下,分享者只有一路上行視頻流,該場(chǎng)景中要么上行攝像頭畫面,要么上行屏幕畫面,兩者是互斥的。
除非實(shí)例一個(gè)新的 SDK 專門采集并發(fā)送屏幕畫面,但實(shí)例兩個(gè) SDK 的方案在業(yè)務(wù)層處理起來十分麻煩且會(huì)存在許多問題,例如如何處理兩個(gè)流間的關(guān)系等。
在 WebRTC 場(chǎng)景中,還存在一種可以單獨(dú)為屏幕分享開啟一路上行視頻流的方案,并稱之為“輔流(Substream)”。輔流分享即共享者同時(shí)發(fā)布攝像頭畫面和屏幕畫面兩路畫面。
另外,有了這個(gè)輔流的通道,當(dāng)設(shè)備為新版本 iPhone(新版本 iPhone 具有同時(shí)開啟前后攝像頭的能力)時(shí),也為支持前后2路攝像頭發(fā)送視頻數(shù)據(jù)奠定了基礎(chǔ)。
?技術(shù)背景
前期 SDK 的架構(gòu)設(shè)計(jì)是一個(gè)多 PeerConnection 的模型,即:一個(gè) PeerConnection 對(duì)應(yīng)一路音視頻流。隨著新的 SDP(Session Description Protocol)格式(UnifyPlan)的推出和支持,一個(gè) PeerConnection 可以對(duì)應(yīng)多路音視頻流,即單 PeerConnection 模型,即基于單 PC 的架構(gòu),允許創(chuàng)建多個(gè) Transceiver,用于發(fā)送多條視頻流。
技術(shù)實(shí)現(xiàn)
目前視頻流主要分為三類:Camera 流、屏幕共享流、自定義輸入視頻流,分別有不同屬性:
將 Camera 流作為主流,支持 Simulcast;
將自定義視頻輸入(非屏幕共享)作為主流,不支持 Simulcast;
將屏幕共享作為輔流,不支持 Simulcast,有單獨(dú)的屏幕共享編碼策略;
由于 iOS 屏幕共享的特殊性,其需要通過自定義視頻輸入的方式來獲取視頻數(shù)據(jù),因此存在如下圖所示的流程圖:
綜上所述:iOS 的自定義輸入既可以使用主流的通道發(fā)送視頻(非屏幕共享),也可以使用輔流的通道發(fā)送視頻(屏幕共享)。
如果是其他平臺(tái),例如 Mac、Win、Aos 等,則會(huì)相對(duì)簡(jiǎn)單,攝像頭數(shù)據(jù)和屏幕共享的數(shù)據(jù)都來自于 SDK 內(nèi)部,外部自定義視頻輸入的數(shù)據(jù)才來自于外部。
?關(guān)鍵類圖?
上述提到的單 PC 架構(gòu),目前會(huì)有2個(gè) RtpTransceiver,一個(gè)是 AudioTransceiver,一個(gè)是 VideoTransceiver,而輔流的屏幕共享會(huì)在新增一個(gè) RtpTransceiver。一個(gè) VideoRtpSender 會(huì)包含一個(gè) VideoMediaChannel。
?輔流改動(dòng)?
實(shí)現(xiàn)輔流需要對(duì)不同層面都做一些調(diào)整以及重構(gòu),具體如下:
信令層面需要支持多路視頻流,使用 mediaType 用于區(qū)分上述的 Camera 流(Video)、屏幕共享流(ScreenShare)、自定義視頻輸入流(externalVideo);
重構(gòu)跨平臺(tái)層的 Capture 和 Source 的管理;
重構(gòu)用戶和渲染畫布的管理,從一個(gè) UID 對(duì)應(yīng)一個(gè) render,過渡到一個(gè) UID 的 sourceId 對(duì)應(yīng)一個(gè) render,每個(gè) UID 可能會(huì)包含2個(gè) sourceId;
互動(dòng)直播的服務(wù)器推流和錄制需要支持主流和輔流的合流錄制;
主流和輔流的擁塞控制方案的落地;
主流和輔流的碼率分配方案的落地;
主流和輔流的編碼器性能優(yōu)化;
PacedSender 發(fā)送策略、音畫同步等方案的調(diào)整;
服務(wù)器 Qos 下行碼率的分配方案的調(diào)整;
輔流相關(guān)的統(tǒng)計(jì)數(shù)據(jù)的匯總;
下面介紹在整個(gè)過程中,比較重要的幾個(gè)技術(shù)點(diǎn)的實(shí)現(xiàn)。
?帶寬分配?
在弱網(wǎng)情況下,需要視頻輔流的時(shí)候,我們會(huì)優(yōu)先把碼率分配給音頻流,其次是輔流,最后再分配給主流,整體策略為保輔流。
帶寬分配的主要流程如下:
WebRTC 的擁塞控制算法 GCC(下文簡(jiǎn)稱 CC) 評(píng)估出來的總帶寬分配會(huì)分給音頻流、主流、輔流;
主流內(nèi)部再由 Simulcast 模塊分配大小流的碼率,不開 Simulcast 時(shí)就直接給大流;
具體過程如圖所示:
輔流會(huì)在上圖的基礎(chǔ)上再新增一個(gè) VideoSendStream。
?碼率分配?
目前關(guān)于碼率分配的流程如下圖所示,概括起來有一下幾步:
CC 的碼率通過 transport controller 傳遞到 Call 中;
然后經(jīng)過 BitrateAllocator 分配到各個(gè)注冊(cè)的流中 (目前就是視頻模塊);
視頻模塊拿到分配的碼率,分配給 fec 和重傳,剩下來的分配給 video encoder bitrate;
視頻編碼器模塊拿到 video encoder bitrate,按照我們的策略,分配給大流、小流使用;
?擁塞控制?
為了實(shí)現(xiàn)視頻輔流的功能,我們需要對(duì)擁塞控制進(jìn)行相關(guān)的改動(dòng),主要通過以下四個(gè)方面的改動(dòng)來實(shí)現(xiàn):
SDP 信令改動(dòng)
按照 RFC 2327,使用 "b=<modifier>:<bandwidth-value>" 的方式來指定建議帶寬,有兩種 modifier(修飾符):
AS:單一媒體帶寬;
CT:會(huì)話總帶寬,表示所有媒體的總帶寬;
(RFC 2327:https://tools.ietf.org/html/rfc2327)
目前 SDK 使用 b=AS: 的方式指定攝像頭碼流或屏幕共享碼流的建議帶寬,并把這個(gè)值作為 CC 模塊的估計(jì)值上限。
新的需求要求在同一會(huì)話中,可同時(shí)發(fā)送攝像頭碼流和屏幕共享碼流,因此應(yīng)把兩路媒體的建議帶寬值相加得到整個(gè)會(huì)話的建議帶寬值,作為 CC 模塊的估計(jì)值上限。
WebRTC 支持 b=AS: 方式(單路媒體),在 WebRTC 內(nèi)部對(duì)多路媒體進(jìn)行相加處理即可滿足需求,而 WebRTC 目前不支持 b=CT: 方式,所以建議使用 b=AS: 方式,改動(dòng)相對(duì)較少。
CC 總碼率更新策略
Pub 碼流能力更新,通過 SDP 方式 (b=AS:) 同步設(shè)置"最大帶寬"到 CC 模塊,當(dāng)新增一路媒體流時(shí),通過啟動(dòng) probe 快速探測(cè)的方式,迅速上探到可用帶寬:
?快速帶寬評(píng)估?
突然增加一路媒體流時(shí),需要能夠很快上探到真實(shí)帶寬值,使用 probe 快速探測(cè)算法實(shí)現(xiàn)這一目標(biāo):
如果探測(cè)成功,CC 估計(jì)值迅速收斂,在帶寬充足場(chǎng)景中收斂為 CC 上限,帶寬受限場(chǎng)景中為真實(shí)帶寬;
如果探測(cè)失敗(如高丟包率場(chǎng)景),CC 估計(jì)值緩慢收斂,在帶寬充足場(chǎng)景中最終收斂為 CC 上限, 帶寬受限場(chǎng)景中為真實(shí)帶寬;
Paced Sender 處理
輔流與主流的視頻大小流的發(fā)送優(yōu)先級(jí)一致,所有視頻媒體數(shù)據(jù),使用預(yù)算和 pacing multiplier 的方式做平滑發(fā)送處理;
增加一個(gè)視頻碼流類型,kVideoSubStream = 3,與主流的大小流視頻數(shù)據(jù)區(qū)分開來;
Probe 快速探測(cè)期間,當(dāng)編碼數(shù)據(jù)不足的情況下,發(fā)送 padding 數(shù)據(jù)彌補(bǔ),以保證發(fā)送碼率滿足要求;
下圖為實(shí)際進(jìn)行碼率分配測(cè)試的結(jié)果展示:
?統(tǒng)計(jì)上報(bào)?
帶寬的統(tǒng)計(jì)上報(bào)分為兩個(gè)部分,分別是從 MediaInfo 獲取以及 Bweinfo 獲取。
1、發(fā)送端和接收端 MediaInfo 獲取
當(dāng)前 SDK 的帶寬估計(jì)從 MediaInfo 獲取邏輯為:
遍歷當(dāng)前所有 transceiver,獲取每個(gè) transceiver 的 video_channel 和 voice_channel,從而獲取到 video_media_channel 和 voice_media_channel;
根據(jù) media_channel 的 getstats 獲取當(dāng)前 channel 的 MediaInfo;
將獲取的 MediaInfo 放在 vertor media_infos 中,便于上報(bào);
主流和輔流同時(shí)發(fā)送場(chǎng)景,只是增加了一個(gè) transceiver,因此此邏輯適用于主流和輔流同時(shí)發(fā)送的場(chǎng)景,如下圖:
2、帶寬估計(jì)信息獲取
當(dāng)前 SDK 的帶寬估計(jì)從 Bweinfo 獲取邏輯:
獲取 gcc、probe 探測(cè)等表示總體帶寬信息;
獲取每個(gè) transceiver 的 voiceChanel 和 videoChannel 相關(guān)的帶寬估計(jì)信息(類似于 MediaInfo 的獲取);
主流和輔流同時(shí)發(fā)送的場(chǎng)景只是增加了 transceiver,因此此邏輯適用主流加輔流同時(shí)發(fā)送場(chǎng)景,如下圖:
總結(jié)
以上就是關(guān)于 WebRTC 中視頻輔流的分享,主要從業(yè)務(wù)需求出發(fā),通過技術(shù)背景以及關(guān)鍵技術(shù)類圖,詳細(xì)分享了關(guān)于視頻輔流的技術(shù)實(shí)現(xiàn)。也歡迎留言與我們交流關(guān)于 WebRTC 以及音視頻相關(guān)技術(shù)。
推薦閱讀
WebRTC 系列之音頻的那些事
從入門到進(jìn)階|如何基于WebRTC搭建一個(gè)視頻會(huì)議
WebRTC 之ICE淺談
【入門】WebRTC知識(shí)點(diǎn)概覽 | 內(nèi)有技術(shù)干貨免費(fèi)下載
總結(jié)
以上是生活随笔為你收集整理的WebRTC 系列之视频辅流的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网络QoS的平衡之道——音视频弱网对抗策
- 下一篇: 2020 年值得再读一遍的网易云信技术干