webRTC中音頻相關的netEQ(一):概述


上篇文章(語音通信中終端上的時延(latency)及減小方法)說從本篇開始會切入webRTC中的netEQ主題,netEQ是webRTC中音頻技術方面的兩大核心技術之一(另一核心技術是音頻的前后處理,包括AEC、ANS、AGC等,俗稱3A算法)。webRTC是Google收購GIPS重新包裝后開源出來的,目前已是有巨大影響力的實時音視頻通信解決方案。國內的互聯網公司,要做實時音視頻通信產品,絕大多數都是基於webRTC來做的,有的是直接用webRTC的解決方案,有的是用webRTC里的核心技術,比如3A算法。不僅互聯網公司,其他類型公司(比如通信公司),也會把webRTC里的精華用到自己的產品中。我剛開始做voice engine時,webRTC還未開源,但那時就知道了GIPS是一家做實時語音通信的頂級公司。webRTC開源后,一開始沒機會用,后來做OTT語音(APP語音)時用了webRTC里的3A算法。在做了Android手機平台上的音頻開發后,用了webRTC上的netEQ,不過用的是較早的C語言版本,不是C++版本,並且只涉及了netEQ中的DSP模塊(netEQ有兩大模塊,MCU(micro control unit, 微控制單元)和DSP(digital signal processing, 信號處理單元),MCU負責控制從網絡收到的語音包在jitter  buffer里的插入和提取,同時控制DSP模塊用哪種算法處理解碼后的PCM數據,DSP負責解碼以及解碼后的PCM信號處理,主要PCM信號處理算法有加速、減速、丟包補償、融合等),MCU模塊在CP (communication processor, 通訊處理器)上做,兩個模塊之間通過消息交互。DSP模塊經過調試,基本上掌握了機制。MCU模塊由於在CP上做,沒有source code,我就從網上找來了我們用的版本相對應的webRTC的開源版本,經過了一段時間的理解后,也基本上搞清楚了機制。從本篇開始,我將花幾篇講netEQ(基於我用的早期C語言版本)。這里需要說明的是每個產品在使用webRTC上的代碼時都會根據自己產品的特點做一定的修改,我做的產品也不例外。我在講時一些細節不會涉及,主要講機制。本篇先對netEQ做一個概述。

 

實時IP語音通信的軟件架構框圖通常如下圖:

 

上圖中發送方(或叫上行、TX)將從MIC采集到的語音數據先做前處理,然后編碼得到碼流,再用RTP打包通過UDP socket發送到網絡中給對方。接收方(或叫下行、RX)通過UDP socket收語音包,解析RTP包后放入jitter buffer中,要播放時每隔一定時間從jitter buffer中取出包並解碼得到PCM數據,做后處理后送給播放器播放出來。

 

netEQ模塊在接收側,它是把jitter buffer和decoder綜合起來並加入解碼后的PCM信號處理形成,即netEQ = jitter buffer + decoder + PCM信號處理。這樣上圖中的軟件架構框圖就變成下圖:

  

上文說過netEQ模塊主要包括MCU和DSP兩大單元。它的軟件框圖如下圖:

 

從上兩圖看出,jitter buffer(也就是packet  buffer,后面就跟netEQ一致,表述成packet buffer,用於去除網絡抖動)模塊在MCU單元內,decoder和PCM信號處理模塊在DSP單元內。MCU單元主要負責把從網絡側收到的語音包經過RTP解析后往packet  buffer里插入(insert),以及從packet buffer 里提取(extract)語音包給DSP單元做解碼、信號處理等,同時也算網絡延時(optBufLevel)和抖動緩沖延時(buffLevelFilt),根據網絡延時和抖動緩沖延時以及其他因素(上一幀的處理方式等)決定給DSP單元發什么信號處理命令。主要的信號處理命令有5種,一是正常播放,即不需要做信號處理。二是加速播放,用於通話延時較大的情況,通過加速算法使語音信息不丟而減少語音時長,從而減少延時。三是減速播放,用於語音斷續情況,通過減速算法使語音信息不丟而增加語音時長,從而減少語音斷續。四是丟包補償,用於丟包情況,通過丟包補償算法把丟掉的語音補償回來。五是融合(merge),用於前一幀丟包而當前包正常收到的情況,由於前一包丟失用丟包補償算法補回了語音,與當前包之間需要做融合處理來平滑上一補償的包和當前正常收到的語音包。以上幾種信號處理提高了在惡劣網絡環境下的語音質量,增強了用戶體驗。可以說是在目前公開的處理語音的網絡丟包、延時和抖動的方案中是最佳的了。

 

DSP單元主要負責解碼和PCM信號處理。從packet buffer提取出來的碼流解碼成PCM數據放進decoded_buffer中,然后根據MCU給出的命令做信號處理,處理結果放在algorithm_buffer中,最后將algorithm_buffer中的數據放進speech_buffer待取走播放。Speech_buffer中數據分兩塊,一塊是已播放過的數據(playedOut),另一塊是未播放的數據(sampleLeft), curPosition就是這兩種數據的分割點。另外還有一個變量endTimestamps用於記錄最后一個樣本的時間戳,並報告給MCU,讓MCU根據endTimestamps和packet buffer里包的timestamp決定是否要能取出包以及是否要取出包。

 

這里先簡要介紹一下netEQ的處理過程,后面文章中會詳細講。處理過程主要分兩部分,一是把RTP語音包插入packet packet的過程,二是從packet buffer中提取語音包解碼和PCM信號處理的過程。先看把RTP語音包插入packet packet的過程,主要有三步:

1,在收到第一個RTP語音包后初始化netEQ。

2,解析RTP語音包,將其插入到packet buffer中。在插入時根據收到包的順序依次插入,到尾部后再從頭上繼續插入。這是一種簡單的插入方法。

3,計算網絡延時optBufLevel。

再看怎么提取語音包並解碼和PCM信號處理,主要有六步:

1,將DSP模塊的endTimeStamp賦給playedOutTS,和sampleLeft(語音緩沖區中未播放的樣本數)一同傳給MCU,告訴MCU當前DSP模塊的播放狀況。

2,看是否要從packet buffer里取出語音包,以及是否能取出語音包。取出包時用的是遍歷整個packet buffer的方法,根據playedOutTS找到最小的大於等於playedOutTS的時間戳,記為availableTS,將其取出來。如果包丟了就取不到包。

3,算抖動緩沖延時buffLevelFilt。

4,根據網絡延時抖動緩沖延時以及上一幀的處理方式等決定本次的MCU控制命令。

5,如果有從packet buffer里提取到包就解碼,否則不解碼。

6,根據MCU給的控制命令對解碼后的以及語音緩沖區里的數據做信號處理。

 

在我個人看來,netEQ有兩大核心技術點。一是計算當前網絡延時和抖動緩沖延時的算法。要根據網絡延時、抖動緩沖延時和其他因素決定信號處理命令,信號處理命令對了能提高音質,相反則會降低音質,所以說信號處理命令的決策非常關鍵。二是各種信號處理算法,主要有加速(accelerate)、減速(preemptive expand)、丟包補償(PLC)、融合(merge)和背景噪聲生成(BNG),這些都是非常專業的算法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM