白話解讀 WebRTC 音頻 NetEQ 及優(yōu)化實(shí)踐,webrtc 人聲優(yōu)化白話解讀 WebRTC 音頻 NetEQ 及優(yōu)化實(shí)踐NetEQ 是 WebRTC 音視頻核心技術(shù)之一,對于提高 VoIP 質(zhì)量有明顯的效果,本文將從更為宏觀的視角,用通俗白話介紹 WebRTC 中音頻 NetEQ 的相關(guān)概念背景和框架原理,以及......
NetEQ 是 WebRTC 音視頻核心技術(shù)之一,對于提高 VoIP 質(zhì)量有明顯的效果,本文將從更為宏觀的視角,用通俗白話介紹 WebRTC 中音頻 NetEQ 的相關(guān)概念背景和框架原理,以及相關(guān)的優(yōu)化實(shí)踐。
作者| 良逸審校| 泰一
為什么要 “白話” NetEQ
隨便搜索一下,我們就能在網(wǎng)上找到很多關(guān)于 WebRTC 中音頻 NetEQ 的文章,比如下面的幾篇文章都是非常不錯(cuò)的學(xué)習(xí)資料和參考。特別是西安電子科技大學(xué) 2013 年吳江銳的碩士論文《WebRTC 語音引擎中 NetEQ 技術(shù)的研究》,非常詳盡地介紹了 NetEQ 實(shí)現(xiàn)細(xì)節(jié),也被引用到了很多很多的文章中。
《WebRTC 語音引擎中 NetEQ 技術(shù)的研究》
NetEQ 算法
WebRTC 中音頻相關(guān)的 NetEQ
這些文章大部分從比較 “學(xué)術(shù)” 的或 “算法” 的角度,對 NetEQ 的細(xì)節(jié)做了非常透徹的分析,所以這里我想從更宏觀一些的角度,說一下我個(gè)人的理解。白話更容易被大家接受,爭取一個(gè)數(shù)學(xué)公式都不用,一行代碼都不上就把思路說清楚,有理解不對的地方,還請大家不吝賜教。
丟包、抖動(dòng)和優(yōu)化的理解
在音視頻實(shí)時(shí)通信領(lǐng)域,特別是移動(dòng)辦公(4G),疫情下的居家辦公和在線課堂 (WIFI),網(wǎng)絡(luò)環(huán)境成了影響音視頻質(zhì)量最關(guān)鍵的因素,在差的網(wǎng)絡(luò)質(zhì)量面前,再好的音視頻算法都顯得有些杯水車薪。網(wǎng)絡(luò)質(zhì)量差的表現(xiàn)主要有延時(shí)、亂序、丟包、抖動(dòng),誰能處理和平衡好這幾類問題,誰就能獲得更好的音視頻體驗(yàn)。由于網(wǎng)絡(luò)的基礎(chǔ)延時(shí)是鏈路的選擇決定的,需優(yōu)化鏈路調(diào)度層來解決;而亂序在大部分網(wǎng)絡(luò)條件下并不是很多,而且亂序的程度也不是很嚴(yán)重,所以接下來我們主要會(huì)討論丟包和抖動(dòng)。
抖動(dòng)是數(shù)據(jù)在網(wǎng)絡(luò)上的傳輸忽快忽慢,丟包是數(shù)據(jù)包經(jīng)過網(wǎng)絡(luò)傳輸,因?yàn)楦鞣N原因被丟掉了,經(jīng)過幾次重傳后被成功收到是恢復(fù)包,重傳也失敗的或者恢復(fù)包過時(shí)的,都會(huì)形成真正的丟包,需要丟包恢復(fù) PLC 算法來無中生有的產(chǎn)生一些假數(shù)據(jù)來補(bǔ)償。丟包和抖動(dòng)從時(shí)間維度上又是統(tǒng)一的,等一會(huì)來了的是抖動(dòng),遲到很久才來的是重傳包,等一輩子也不來的就是 “真丟包”,我們的目標(biāo)就是要盡量降低數(shù)據(jù)包變成 “真丟包” 的概率。
優(yōu)化,直觀來講就是某個(gè)數(shù)據(jù)指標(biāo),經(jīng)過一頓猛如虎的操作之后,從 xxx 提升到了 xxx。但我覺得,評判優(yōu)化好壞不能僅僅停留在這個(gè)維度,優(yōu)化是要 “知己知彼”,己是自己的產(chǎn)品需求,彼是現(xiàn)有算法的能力,己彼合一才是最好的優(yōu)化,不管算法是簡單還是復(fù)雜,只要能完美的匹配自己的產(chǎn)品需求,就是最好的算法,“能捉到老鼠的就是好貓”。
NetEQ 及相關(guān)模塊
NetEQ 的出處
《GIPS NetEQ 原始文檔》,這是由 GIPS 公司提供的最原始的 NetEQ 的說明文檔(中文翻譯),里面介紹了什么是 NetEQ 以及對其性能的簡單說明。NetEQ 本質(zhì)上就是一個(gè)音頻的 JitterBuffer(抖動(dòng)緩沖器),名字起的非常貼切,Network Equalizer(網(wǎng)絡(luò)均衡器)。大家都知道 Audio Equalizer 是用來均衡聲音的效果器,而這里的 NetEQ 是用來均衡網(wǎng)絡(luò)抖動(dòng)的效果器。而且 GIPS 還給這個(gè)名字注冊了商標(biāo),所以很多地方看到的是 NetEQ (TM) 。上面的官方文檔中,有一條很重要信息,“最小化抖動(dòng)緩沖帶來的延時(shí)影響”,這說明 NetEQ 的設(shè)計(jì)目標(biāo)之一就是:“追求極低延時(shí)”。這個(gè)信息很關(guān)鍵,為我們后續(xù)的優(yōu)化提供了重要線索。
NetEQ 在音視頻通訊 QoS 流程中的位置
音視頻通訊對于普通用戶來說,只要網(wǎng)絡(luò)是通的,WIFI 和 4G 都可以,一個(gè)呼叫過去,看到人且聽到聲音,就 OK 了,很簡單的事情,但對于底層的實(shí)現(xiàn)卻沒有看起來那么簡單。單 WebRTC 開源引擎的相關(guān)代碼文件數(shù)量就有 20 萬個(gè)左右,代碼行數(shù)不知道有沒有人具體算過,應(yīng)該也是千萬數(shù)量級的了。不知道多少碼農(nóng)為此掉光了頭發(fā) :)。
下面這張圖,是對實(shí)際上更復(fù)雜的音視頻通訊流程的抽象和簡化。左邊是發(fā)快遞 (推流) 側(cè):經(jīng)過采集、編碼、封裝、發(fā)快遞;中間經(jīng)過網(wǎng)絡(luò)傳輸;右邊是接收 (拉流) 側(cè):接收、解包、解碼、播放;這里重點(diǎn)體現(xiàn)了 QoS(Quality of Service,服務(wù)質(zhì)量)的幾個(gè)大的功能,以及跟推拉流數(shù)據(jù)主要流程的關(guān)系。可以看到 QoS 功能分散在音視頻通訊流程中的各個(gè)位置,導(dǎo)致要了解整個(gè)流程之后才能對 QoS 有比較全面的理解。圖上看起來左邊發(fā)快遞側(cè)的 QoS 功能要多一些,這是因?yàn)?QoS 的目的就是要解決通訊過程中的用戶體驗(yàn)問題,要解決問題,最好就是找到問題的源頭,能從源頭解決的,都是比較好的解決方式。但總有一部分問題是不能從源頭來解決的,比如在多人會(huì)議的場景,一個(gè)人的收流側(cè)網(wǎng)絡(luò)壞了,不能影響其它人的開會(huì)體驗(yàn),不能出現(xiàn) “一顆老鼠屎壞掉一鍋粥” 的情況,不能污染源頭。所以收流也要做 QoS 的功能,目前收流側(cè)的必備功能就是 JitterBuffer,包括視頻的和音頻的,本文重點(diǎn)分析音頻的 JitterBuffer NetEQ。
上面這張圖是對 NetEQ 及其相關(guān)模塊工作流程的抽象,主要包含 4 個(gè)部分,NetEQ 的輸入、NetEQ 的輸出、音頻重傳 Nack 請求模塊、音視頻同步模塊。為什么要把 Nack 請求模塊和音視頻同步模塊也放進(jìn) NetEQ 的分析中因?yàn)檫@兩個(gè)模塊都直接跟 NetEQ 有依賴,相互影響。圖里面的虛線,標(biāo)識每個(gè)模塊依賴的其它模塊的信息,以及這些信息的來源。接下來介紹一下整個(gè)流程。
1. 首先是 NetEQ 的輸入部分:
底層 Socket 收到一個(gè) UDP 包后,觸發(fā)從 UDP 包到 RTP 包的解析,經(jīng)過對 ***C 和 PayloadType 的匹配,找到對應(yīng)的音頻流接收的 Channel,然后從InsertPacketInternal輸入到 NetEQ 的接收模塊中。
收到的音頻 RTP 包很可能會(huì)帶有 RED 冗余包(redundance),按照 RFC2198 的標(biāo)準(zhǔn)或者一些私有的封裝格式,對其進(jìn)行解包,還原出原始包,重復(fù)的原始包將會(huì)被忽略掉。解出來的原始 RTP 數(shù)據(jù)包會(huì)被按一定的算法插入到 packet buffer 緩存里面去。之后會(huì)將收到的每一個(gè)原始包的序列號,通過UpdateLastReceivedPacket函數(shù)更新到 Nack 重傳請求模塊,Nack 模塊會(huì)通過 RTP 收包或定時(shí)器觸發(fā)兩種模式,調(diào)用GetNackList函數(shù)來生成重傳請求,以 NACK RTCP 包的格式發(fā)快遞給推流側(cè)。
同時(shí),解完的每一個(gè)原始包,得到了時(shí)間軸上唯一的一個(gè)接收時(shí)刻,包和包之間的接收時(shí)間差也能算出來了,這個(gè)接收時(shí)間差除以每個(gè)包的打包時(shí)長就是 NetEQ 內(nèi)部用來做抖動(dòng)估計(jì)的 IAT(interarrival time),比如,兩個(gè)包時(shí)間差是 120ms,而打包時(shí)長是 20ms,則當(dāng)前包的 IAT 值就是 120/20=6。之后每個(gè)包的 IAT 值經(jīng)過核心的網(wǎng)絡(luò)抖動(dòng)估計(jì)模塊(DelayManager)處理之后,得到最終的目標(biāo)水位(TargetLevel),到此 NetEQ 的輸入處理部分就結(jié)束了。
2. 其次是 NetEQ 的輸出部分:
輸出是由音頻硬件播放設(shè)備的播放線程定時(shí)觸發(fā)的,播放設(shè)備會(huì)每 10ms 通過GetAudioInternal接口從 NetEQ 里面取 10ms 長度的數(shù)據(jù)來播放。
進(jìn)入GetAudioInternal的函數(shù)之后,第一步要決策如何應(yīng)對當(dāng)前數(shù)據(jù)請求,這個(gè)任務(wù)交給操作決策模塊來完成,決策模塊根據(jù)之前的和當(dāng)前的數(shù)據(jù)和操作的狀態(tài),給出最終的操作類型判斷。NetEQ 里面定義了幾種操作類型:正常、加速、減速、融合、拉伸(丟包補(bǔ)償)、靜音,這幾種操作的意義,后面再詳細(xì)的說。有了決策的操作類型,再從輸入部分的包緩存(packet buffer)里面取出一個(gè) RTP 包,快遞給抽象的解碼器,抽象的解碼器通過DecodeLoop函數(shù)層層調(diào)用到真正的解碼器進(jìn)行解碼,并把解碼后的 PCM 音頻數(shù)據(jù)放到DecodedBuffer里面去。然后就是開始執(zhí)行不同的操作了,NetEQ 里面為每一種操作都實(shí)現(xiàn)了不同的音頻數(shù)字信號處理算法(DSP),除了 “正?!?操作會(huì)直接使用DecodedBuffer里的解碼數(shù)據(jù),其它操作都會(huì)結(jié)合解碼的數(shù)據(jù)進(jìn)行二次 DSP 處理,處理結(jié)果會(huì)先被放到算法緩存(Algorithm Buffer)里面去,然后再插入到 Sync Buffer 里面。Sync Buffer 是一個(gè)循環(huán) buffer,設(shè)計(jì)的比較巧妙,存放了已經(jīng)播放過的數(shù)據(jù)、解碼后未播放的數(shù)據(jù),剛剛從算法緩存里插入的數(shù)據(jù)放在 Sync Buffer 的末尾,如上圖所示。最后就是從 Sync Buffer 取出最早解碼后的數(shù)據(jù),快遞出去給外部的混音模塊,混音之后再國際快遞音頻硬件來播放。
另外,從圖上可以看出決策模塊(BufferLevelFilter)會(huì)結(jié)合當(dāng)前包緩存 packet buffer 里緩存的時(shí)長,和 Sync Buffer 里緩存的數(shù)據(jù)時(shí)長,經(jīng)過算法過濾后得到音頻當(dāng)前的緩存水位。音視頻同步模塊會(huì)使用當(dāng)前音頻緩存水位,和視頻當(dāng)前緩存水位,結(jié)合最新 RTP 包的時(shí)間戳和音視頻的 SR 包獲得的時(shí)間戳,計(jì)算出音視頻的不同步程度,再通過 SetMinimumPlayoutDelay 最終設(shè)置到 NetEQ 里面的最小目標(biāo)水位,來控制 TargetLevel,實(shí)現(xiàn)音視頻同步。
NetEQ 內(nèi)部模塊
NetEQ 抖動(dòng)估計(jì)模塊(DelayManager)
1. 平穩(wěn)抖動(dòng)估計(jì)部分:
將每個(gè)包的 IAT 值,按照一定的比例(取多少比例是由下面的遺忘因子部分的計(jì)算決定的),累加到下面的 IAT 統(tǒng)計(jì)的直方圖里面,最后計(jì)算從左往右累加值的 0.95 位置,此位置的 IAT 值作為最后的抖動(dòng) IAT 估計(jì)值。例如下圖,假定目標(biāo)水位 TargetLevel 是 9,意味著目標(biāo)緩存數(shù)據(jù)時(shí)長將會(huì)是 180ms(假定打包時(shí)長 20ms)。
2. 平穩(wěn)抖動(dòng)遺忘因子計(jì)算:
遺忘因子是用來控制當(dāng)前包的 IAT 值取多少比例累加到上面的直方圖里面去的系數(shù),計(jì)算過程用了一個(gè)看起來比較復(fù)雜的公式,經(jīng)過分析,其本質(zhì)就是下面的黃色曲線,意思是開始的時(shí)候遺忘因子小,會(huì)取更多的當(dāng)前包的 IAT 值來累加,隨著時(shí)間推移,遺忘因子逐漸變大,會(huì)取更少的當(dāng)前包 IAT 值來累加。這個(gè)過程搞的有點(diǎn)復(fù)雜,從工程角度看完全可以簡化成直線之類的,因?yàn)闇y試下來 5s 左右的時(shí)間,基本就收斂到目標(biāo)值 0.9993 了,其實(shí)這個(gè) 0.9993 才是影響抖動(dòng)估計(jì)的最主要的因素,很多優(yōu)化也是直接修改這個(gè)系數(shù)來調(diào)節(jié)估計(jì)的靈敏度。
3. 峰值抖動(dòng)估計(jì):
DelayManager 中有一個(gè)峰值檢測器 PeakDetector 用來識別峰值,如果頻繁檢測到峰值,會(huì)進(jìn)入峰值抖動(dòng)的估計(jì)狀態(tài),取最大的峰值作為最終估計(jì)結(jié)果,而且一旦進(jìn)入這個(gè)狀態(tài)會(huì)一直維持 20s 時(shí)間,不管當(dāng)前抖動(dòng)是否已經(jīng)恢復(fù)正常了。下面是一個(gè)示意圖。
NetEQ 操作決策模塊(DecisionLogic)
決策模塊的簡化后的基本判定邏輯,如下圖所示,比較簡潔不用解釋。這里解釋一下下面這幾個(gè)操作類型的意義:
ComfortNoise:是用來產(chǎn)生舒適噪聲的,比單純的靜音包聽起來會(huì)更舒服的靜音狀態(tài);
Expand(PLC):丟包補(bǔ)償,最重要的無中生有算法模塊,解決 “真丟包” 時(shí)沒數(shù)據(jù)的問題,造假專業(yè)戶 ;
Merge:如果上一次是 Expand 造假出來的數(shù)據(jù),那為了聽起來更舒服一些,會(huì)跟正常數(shù)據(jù)包做一次融合算法;
Accelerate:變聲不變調(diào)的加速播放算法;
PreemptiveExpand:變聲不變調(diào)的減速播放算法;
Normal:正常的解碼播放,不額外引入假數(shù)據(jù);
NetEQ 相關(guān)模塊優(yōu)化點(diǎn)
NetEQ 抗抖動(dòng)優(yōu)化
由于 NetEQ 的設(shè)計(jì)目標(biāo)是 “極低延時(shí)”,不能很好的匹配,視頻會(huì)議,在線課堂,直播連麥等非極低延時(shí)場景,需要對其敏感度進(jìn)行調(diào)整,主要調(diào)整抖動(dòng)估計(jì)模塊相關(guān)的靈敏度;
直播場景,由于對于延時(shí)敏感度可以到秒級以上,所以需要啟用 StreamMode 的功能(新版本中好像去掉了),而且也需要對其中參數(shù)進(jìn)行適配;
服務(wù)于極低延時(shí)目標(biāo),原始的包緩存 packetbuffer 太小,容易造成 flush,需要按業(yè)務(wù)需要調(diào)大一些;
還有一些業(yè)務(wù)會(huì)根據(jù)自己的業(yè)務(wù)場景主動(dòng)識別網(wǎng)絡(luò)狀況,然后直接設(shè)置最小 TargetLevel,簡單粗暴的控制 NetEQ 的水位。
NetEQ 抗丟包優(yōu)化:
原始的 WebRTC 的 Nack 丟包請求的觸發(fā)機(jī)制是用包觸發(fā)的,在弱網(wǎng)下會(huì)惡化重傳效果,可以改為定時(shí)觸發(fā)來解決;
丟包場景會(huì)有重傳,但如果 buffer 太小,重傳也會(huì)被丟棄,所以為了提高重傳效率,增加 ARQ 延時(shí)預(yù)留功能,可明顯降低拉伸率;
比較算法級的優(yōu)化是對丟包補(bǔ)償 PLC 算法的優(yōu)化,調(diào)整現(xiàn)有 NetEQ 的拉伸機(jī)制,優(yōu)化聽感效果;
開啟 Opus 的 Dtx 功能之后,在丟包場景會(huì)導(dǎo)致音頻 Buffer 變大,需要單獨(dú)優(yōu)化 Dtx 相關(guān)處理邏輯。
下面是 ARQ 延時(shí)預(yù)留功能開啟后的效果對比,平均拉伸率降低 50%,延時(shí)也會(huì)相應(yīng)增加:
音視頻同步優(yōu)化:
原始的 WebRTC 的 P2P 音視頻同步算法是沒有問題的,但是目前架構(gòu)上面一般都有媒體轉(zhuǎn)發(fā)服務(wù)器(SFU),而服務(wù)器的 SR 包生成算法可能會(huì)由于某些限制或者錯(cuò)誤會(huì)不完全正確,導(dǎo)致無法正常同步,為規(guī)避 SR 包生成錯(cuò)誤,需要優(yōu)化音視頻同步模塊的計(jì)算方式,使用水位為主要參考來同步,即在接收端保證音視頻的緩存時(shí)間是差不多大小的。下面是優(yōu)化效果的對比:
還有一種音視頻同步的問題,其實(shí)不是音視頻同步機(jī)制導(dǎo)致的,而是設(shè)備性能有問題,不能及時(shí)處理視頻的解碼和渲染,導(dǎo)致視頻數(shù)據(jù)累積,從而形成的音視頻不同步。這種問題可以通過對比不同步時(shí)長的趨勢,跟視頻解碼和渲染時(shí)長的趨勢,兩者匹配度會(huì)很高,如下圖所示:
總結(jié)
NetEQ 作為音頻接收側(cè)的核心功能,基本上包含了各個(gè)方面,所以很多很多音視頻通訊的技術(shù)實(shí)現(xiàn)里都會(huì)有它的蹤跡,乘著 WebRTC 開源快 10 年的東風(fēng),NetEQ 也變的非常普及,希望這篇白話文章能幫大家更好的理解 NetEQ。
作者最后的話:需求不停歇,優(yōu)化無止境
特別聲明:以上文章內(nèi)容僅代表作者本人觀點(diǎn),不代表ESG跨境電商觀點(diǎn)或立場。如有關(guān)于作品內(nèi)容、版權(quán)或其它問題請于作品發(fā)表后的30日內(nèi)與ESG跨境電商聯(lián)系。
二維碼加載中...
使用微信掃一掃登錄
使用賬號密碼登錄
平臺顧問
微信掃一掃
馬上聯(lián)系在線顧問
小程序
ESG跨境小程序
手機(jī)入駐更便捷
返回頂部