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作一個概述。html

 

實時IP語音通訊的軟件架構框圖一般以下圖:git

 

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

 

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決定是否要能取出包以及是否要取出包。socket

 

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

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

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

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),這些都是很是專業的算法。

相關文章
相關標籤/搜索