導讀:2020年,新冠疫情爆發並席卷全球,對包括中國在內的全球經濟造成了巨大的沖擊,同時深刻影響了社會生活。在這一背景下,以消費市場上轟轟烈烈的直播電商為引爆點,直播行業再次掀起熱潮。在中國企業數字化轉型的浪潮中發展了十年之久的企業直播服務市場,也順勢進入高速發展階段。
文|洪順迪
網易雲信流媒體 Server 端研發工程師
典型的直播架構
在典型的直播架構中,左邊是推流客戶端,協議上才采用 RTMP 上行;右邊是拉流客戶端,支持不同的拉流協議拉流,比較常見的是:RTMP、FLV、HLS
現有架構的優點
這套框架很好的利用了 CDN 廠商或者說雲廠商的能力。盡管拉流協議沒有統一,rtmp/flv/hls 等拉流協議作為比較成熟的流媒體協議,經過多年的發展,得到了各 CDN 廠商廣泛支持。在雲端能力的支持下,服務端並發能力和拉流端加速能力大大增加了,直播行業蓬勃發展。
低延遲直播的現狀
在直播領域中卡頓和延遲就像是天平的兩端。延遲做的越短,則卡頓越高;延遲越長,卡頓就越少。
一般場景下都是客戶端用更大的 buffer 時長,犧牲延時來滿足流暢性。隨着行業的發展,某一些應用場景對延時時間的要求越來越苛刻,比如體育比賽直播,教育場景下老師與學生間的互動等,這些場景下常見的直播流媒體協議的缺點就體現出來了。
一般 rtmp 協議直播延時在 3-10s,如果經過層層 CDN 的緩存和轉發,超過10秒也是常有的事,flv 和 hls 協議的延時更高。就拉流端來說,延遲的很大一部分源自網絡傳輸:rtmp 在傳輸媒體前的 tcp 3次握手和 c0/c1/c2 握手協議,無端引入了好幾個 RTT 的延遲;由於 rtmp/flv/hls 的傳輸層都是基於 tcp 協議,在網絡不穩定的情況下,受限於 tcp 協議的擁塞控制不能充分利用網絡帶寬,客戶端為了保持流暢性,只能加大緩存時間,因此更進一步加大了延遲。
在認識到現有流媒體直播協議的局限性后,各大友商也紛紛推出了自己的低延時直播,較好的起到了對抗弱網和加快首屏的作用。但目前大都基於私有的信令協議和私有的 UDP 流媒體傳輸協議,各大雲廠商無法互相兼容,這就限制了低延遲直播的大規模發展。
基於標准 WebRTC 的低延遲直播的開源實踐
網易雲信一直在探索如何做一個開放的低延時直播方案,將來各家雲廠商也能夠比較方便的實現,就像現有的 rtmp/hls 協議一樣,推動整個直播行業低延遲化。要實現這種方案需要做以下兩件事情。
-
開放的信令協議:信令協議需要滿足絕大多數廠商的媒體協商需求,同時又能盡可能的簡潔。
-
開放的媒體協議:媒體傳輸協議需要滿足在各大廠商間能夠通用,在這之上的 QoS 能力也需要開放,不能是私有的。
依據上面的要求我們選擇了 RTC 領域成熟的解決方案——WebRTC。下圖是我們現在的實踐架構。
上圖中
邊緣媒體服務器從 CDN 拉流到 WE-CAN 大網邊緣節點,再從 WE-CAN 大網邊緣節點發送給客戶端。
開源的信令協議實現
信令協議上采用 HTTP+SDP 的方式,即客戶端 POST 一個 SDP Offer。
{ ... "pull_stream": "nertc://your.domain.com/live/testname" "sdp": "v=0\r\no=4611731400430051336 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0 1\r\n......", "type": "offer" }
然后媒體服務器經過協商返回 SDP Answer。
標准的 WebRTC 媒體協議
客戶端拿到 SDP Answer 后,就是標准的 WebRTC 媒體交互流程:ICE、 DTLS 加密連接,接收 RTP 流媒體。
下面是一個基本的 Web 端的拉流代碼 Demo:
self.pc = new RTCPeerConnection(null); self.pc.addTransceiver("audio", {direction: "recvonly"}); self.pc.addTransceiver("video", {direction: "recvonly"}); var offer = await self.pc.createOffer(); await self.pc.setLocalDescription(offer); var session = await new Promise(function(resolve, reject) { var data = { pull_stream: streamId, type: "offer", sdp: offer.sdp }; $.ajax({ type: "POST", url: apiUrl, data: JSON.stringify(data), contentType:'application/json', dataType: 'json' }).done(function(data) { resolve(data); }); }); await self.pc.setRemoteDescription( new RTCSessionDescription({type: 'answer', sdp: session.sdp}) ); 點擊並拖拽以移動
開源的 Native 媒體播放器
為了讓 Native 客戶端能夠更方便的接入 WebRTC,我們同樣開源了一個集成了標准 WebRTC 的低延遲直播播放器:We-Can-Player,只要輸入流地址,就能實現接收 WebRTC 流播放。
客戶端的架構:
只要廠商實現了類似的協議,用這個播放器稍作修改就可以拉到 WebRTC 的流。從架構上可以看出媒體服務器和拉流客戶端之間的交互大都是基於標准的 WebRTC,沒有私有的 RTP 擴展和私有的 QoS 協議, CDN 廠商甚至可以沒有自己的 RTC 大網,只需在 CDN 邊緣節點實現標准的 WebRTC 網關+一個簡單的 HTTP Server 就可以擁有同樣的能力。
為了優化直播體驗,我們還在 Server 端做了大量的優化。
優化直播體驗
首屏優化
-
GOP 緩存首屏優化
直播領域有兩大指標:首屏和流暢性。假設用戶推流端的 GOP 的是5秒,在某些情況下,拉流端要等接近5秒才能收到第一個 I 幀,首屏才能渲染。這對直播來說是不可接受的。
解決方案是在媒體服務器里做 Gop 緩存,緩存最近1-2個 Gop 的媒體包在 Server 端,當客戶端和媒體器媒體連接成功以后,先發送 Gop 緩存里面的媒體包,再發送當前的媒體數據。客戶端收到媒體包后,需要根據一定的策略對齊音視頻包,再加速追幀。
在具體的實踐過程中,要注意 Gop 緩存大小、客戶端的 Jitter buffer 大小的配合、Gop 緩存里音視頻的對齊、不同的推流端不同的 Gop 長度的適配等情況。
-
Pacer 平滑發送
如果推流端設置的 Gop 比較大,當拉流客戶端媒體連接成功后,會一股腦的給客戶端發送全部的 Gop 里數據,可能造成客戶端緩沖溢出以及其他問題。這時候就需要 Server 的 Pacer 平滑發送發揮作用了。
在具體的實踐過程中,要注意 Pacer 的追幀速率與客戶端追幀速率的配合。
延遲優化
-
WE-CAN 大網
前文提到了直播行業之所以能蓬勃發展,在技術方面 CDN 廠商的雲端能力起到了很大的推動作用。CDN 加快了邊緣節點的回源速度,邊緣節點又加快了拉流終端的接入速度。
從上面的架構圖可以看到,為了加快回源速度,回源媒體服務的選擇會盡可能的接近 CDN 的區域中心節點;為了優化客戶端的接入性能,拉流媒體服務器也要盡可能的接近拉流客戶端,因此媒體如何迅速地從回源媒體服務傳輸給拉流媒體服務就至關重要。
而 WE-CAN 就承當了這個職責,他是雲信內部開發的一套高效全球傳輸大網,能加速全球任何兩個媒體服務器之間的網絡傳輸。從某種意義上來說,他起到了推動 CDN 加速傳輸的作用,不過 CDN 的原理是層層 cache,WE-CAN 靠的是路徑優化。
-
全 SFU 架構的媒體服務器
設想兩個主播的互動,如果我們加入 MCU 的話必然會引入緩存,導致首屏和延遲都加大,所以 RTC 大網內部都是基於 SFU 架構做的布局。
全鏈路延時監控
如何全鏈路的監控拉流測引入的延遲?媒體流在 WE-CAN 大網里經過層層轉發,如果任何一段路由引入不必要的延遲,就會影響最終的低延遲效果。我們的做法是在 RTP 頭里加上一個 extension,記錄 RTP 包到達每個機器的毫秒級的 NTP 時間后,在轉發給客戶端的最后一個媒體服務器上匯報每跳路由的時間消耗以及邊緣服務器與客戶端之間的 RTT 時間,在最終發給客戶端的客戶端 RTP 中再剝離這個 extension。盡管各機器的 NTP 時間沒有絕對對齊,但依賴 WE-CAN 大網的全局 NTP 時間同步功能,差距能夠控制在 1ms,這個精度足夠在工程實踐中發揮監控作用。
效果和后續工作
第一階段在網絡 QoS 方面暫時只支持 ARQ 和 Opus 的 inband-FEC 能力。由於 WebRTC 原生支持基於 XOR 的 FEC 能力,在抗連續丟包方面很弱,所以暫時沒有開啟 FEC,但較 RTMP 有了巨大的改進。實現了在 50% 丟包條件下,控制在2秒左右的延遲,200~400ms的首屏。
我們后面的計划包括:加入更多的 WebRTC 標准 Qos 能力(包括 FEC 在內);推流側的 WebRTC 改造能力等,具體的開源內容可以持續關注【智企技術+】公眾號,后續我們會持續更新開源相關內容及開源地址。
作者介紹
洪順迪 ,網易雲信流媒體 Server 端研發工程師,負責網易雲信流媒體 Server 端的開發工作。