上篇(webRTC中音頻相關的netEQ(四):控制命令決策)講了MCU模塊是怎麼根據網絡延時、抖動緩衝延時和反饋報告等來決定給DSP模塊發什麼控制命令的。DSP模塊根據收到的命令進行相關處理,處理簡要流程圖以下。html
從上圖看出若是有語音包從packet buffer裏取出來先要作解碼獲得PCM數據,沒有就不用作解碼了。編解碼也是數字信號處理算法的一種,是個至關大的topic,不是本文所關注的,本文關注的是對解碼後的PCM數據作數字信號處理,如加減速。若是命令是非Normal命令,就要根據命令作DSP處理,是Normal命令就不用作了。最後取出一幀數據用於播放。web
MCU發給DSP的主要的控制命令有正常播放(normal)、加速播放(accelerate)、減速播放(preemptive expand)、丟包補償(PLC,代碼中叫expand)、融合(merge)等。正常播放就是不須要作額外的DSP處理。加減速也就是改變語音時長,即在不改變語音的音調並保證良好音質的狀況下使語音在時間軸上壓縮或者拉伸,或者叫變速不變調。語音時長調整算法可分爲時域調整和頻域調整,時域調整以重疊區波形類似性(WSOLA)算法爲表明,一般用在語音通訊中。頻域調整一般音樂數據中。丟包補償就是基於先前的語音數據生成當前丟掉的語音數據。融合處理髮生在上一播放的幀與當前解碼的幀不是連續的狀況下,須要來銜接和平滑一下。這些都是很是專業的算法,本文不會涉及,本文是講工程上的一些實現,主要是buffer的處理。算法
在講這些處理以前先看netEQ裏相關的幾塊buffer,分別是decodedBuffer(用於放解碼後的語音數據)、algorithmBuffer(用於放DSP算法處理後的語音數據)、speechBuffer(用於放將要播放的語音數據,這個在前面的文章(webRTC中音頻相關的netEQ(二):數據結構)中講過)和speechHistoryBuffer(用於放丟包補償的歷史語音數據,即靠這些數據來產生補償的語音數據)。網絡
先看加速處理。它主要用於加速播放,是抖動延遲過大時在不丟包的狀況下儘可能減小抖動延遲的關鍵措施。它的處理流程以下:數據結構
1,看decodedBuffer裏是否有30Ms的語音數據(語音數據量要大於等於30Ms才能作加速處理),若是沒有就須要向speechBuffer裏未播放的語音數據借,使知足大於等於30Ms的條件。下圖示意了借的步驟:post
先算出decodedBuffer裏缺的樣本數(記爲nsamples, 等於30Ms的樣本數減去buffer裏已有的樣本數),即須要向speechBuffer借的樣本數。而後在decodedBuffer裏將已有的樣本數右移nsamples,同時從speechBuffer裏end處開始取出nsamples個樣本,將其放在decodedBuffer裏開始處空出來的地方。url
2,作加速算法處理,輸入是decodedBuffer裏的30Ms語音數據,輸出放在algorithmBuffer裏。若是壓縮後的樣本數小於向speechBuffer借的樣本個數nsamples(假設小msamples),不只要把這些壓縮後的樣本拷進speechBuffer裏(從end位置處向前放),同時還要把從cur到pos處的樣本數向後移msamples,cur指針也向後移msamples個數。下圖給出了示意:3d
若是壓縮後的樣本數大於向speechBuffer借的樣本個數(假設大qsamples),先要把從cur到pos處的樣本數向前移qsamples(cur和pos指針都要向前移qsamples個數),而後把這些壓縮後的樣本拷進speechBuffer裏(從pos位置處向後放)。下圖給出了示意:指針
3,從speechBuffer裏取出一幀語音數據播放,同時把cur指針向後移一幀的位置。調試
減速處理的流程跟加速是相似的, 這裏就不詳細講了。下面開始講丟包補償,它的處理流程以下:
1,基於speechHistoryBuffer利用丟包補償算法生成補償的語音數據(記樣本數爲nsamples)放在algorithmBuffer裏,同時還要更新speechHistoryBuffer裏的數據爲下次作丟包補償作準備。示意圖以下:
先把speechHistoryBuffer裏的數據左移nsamples,而後把algorithmBuffer裏的nsamples個樣本放在speechHistoryBuffer的尾部。
2,把algorithmBuffer裏生成的數據放到speechBuffer裏。示意圖以下:
先將speechBuffer裏的數據左移nsamples,而後把algorithmBuffer裏的nsamples個樣本放在speechBuffer的尾部,同時cur指針也要左移nsamples。
3,從speechBuffer裏取出一幀語音數據播放,同時把cur指針向後移一幀的位置。
至於merge中buffer的處理,相對簡單,這裏就不講了。至此我以爲netEQ的主要核心點都講完了,共5篇,算一個系列吧。理解了這些核心點後要想對netEQ有更深的認識就得去實際的調試了,把一些細節搞得更清楚。netEQ裏面的細節特別多,要想所有搞清楚是要花很多時間的。要是所有搞清楚了對語音接收側處理的認識會有一個質的提高。