上篇(webRTC中音頻相關的netEQ(三):存取包和延時計算)講了語音包的存取以及網絡延時和抖動緩衝延時的計算,MCU也收到了DSP模塊發來的反饋報告。本文講MCU模塊如何根據網絡延時、抖動緩衝延時和反饋報告等決定發給DSP模塊的控制命令, 好讓DSP模塊先對取出的語音包作解碼處理(若是有的話)以及根據這些命令作信號處理。html
MCU模塊給DSP模塊發的控制命令主要有正常播放(normal)、加速播放(accelerate)、減速播放(preemptive expand)、丟包補償(PLC,代碼中叫expand)、融合(merge),還有些次要的,如解碼器從新初始化(decoder re-init)、packet buffer 重置(packet buffer reset)等。這裏講主要的控制命令是怎麼決策的,次要的相對簡單就略去不講了,有興趣的能夠本身去看相關代碼。DSP模塊收到這些命令後會轉化爲本身的處理命令,下表列出了主要的控制命令和處理命令的映射關係。web
MCU模塊給DSP模塊發什麼樣的控制命令首先取決於當前幀和前一幀的接收狀況。當前幀和前一幀的接收狀況主要分如下四種(對當前幀和前一幀作排列組合獲得四種狀況):網絡
1,當前幀和前一幀都接收正常,數據包會進入正常的解碼流程。MCU模塊會發正常播放、加速播放、減速播放三種控制命令中的一個給DSP,解碼後的數據會根據命令作相應的處理。post
2,當前幀接收正常,但前一幀丟失。若是前一幀丟失,但當前幀接收正常,說明前一幀是經過丟包補償生成的。爲了使前一幀由丟包補償生成的數據和當前沒有丟包的幀的數據保持語音連續,須要根據先後幀的相關性作平滑處理。這種狀況下MCU模塊會發正常播放、融合兩種控制命令中的一個給DSP。DSP模塊先對當前幀解碼,而後解碼後的數據會根據命令作相應的處理。url
3,僅當前幀發生丟包或延遲,這時就不須要解碼了。MCU模塊會發丟包補償命令給DSP,DSP模塊會進入丟包補償單元來生成補償數據。spa
4,當前幀丟失或延遲,前一幀一樣丟失或延遲。MCU模塊會連續的發丟包補償命令給DSP,DSP模塊也會連續的進入丟包補償單元來生成補償數據。不過越到後面生成的補償數據效果越差。code
在上面的四種狀況中,有些狀況下MCU模塊只會發一種命令給DSP模塊,好比當前幀丟失,只會發丟包補償控制命令給DSP。但有些狀況下MCU模塊可能會發幾種命令中的一種給DSP模塊,好比當前幀和前一幀都接收正常,MCU模塊會發正常播放、加速播放、減速播放三種控制命令中的一個給DSP。到底發哪一種命令呢,這就取決於網絡延時、抖動緩衝延時以及DSP發給MCU的反饋報告等因素了。這是本文的重點,下面具體講。orm
在DSP發給MCU的反饋報告中有個變量playedOutTS,它表示已經播放到的PCM數據的時間戳。同時MCU中還有個變量availableTS,它表示packet buffer中能得到的有效包的起始時間戳,顯然若是availableTS等於0表示packet buffer爲空。若是playedOutTS等於availableTS,它說明語音包正常接收;若是playedOutTS小於availableTS,它說明有語音包的丟失或者延時,須要作丟包補償(PLC)。上篇文章(webRTC中音頻相關的netEQ(三):存取包和延時計算)中講了網絡延時值(optBufLevel)和抖動緩衝延時值(buffLevelFilt)的計算,MCU就是要根據時間戳(playedOutTS & availableTS)的關係和延時(optBufLevel & buffLevelFilt)的關係以及上一幀的播放模式等來決定發什麼樣的控制命令給DSP。先舉個簡單的例子,若是playedOutTS = availableTS而且buffLevelFilt > optBufLevel,這說明當前包正常接收,可是抖動緩衝延時大於網絡延時,即緩衝的包多了增長了時延,須要作加速播放處理,因此MCU會發加速處理命令給DSP。下面給出各個控制命令的條件,即知足所列條件時MCU就會發相應的控制命令給DSP。htm
1,正常播放控制命令 / 加速播放控制命令 / 減速播放控制命令的條件blog
正常播放控制命令爲BUFSTATS_DO_NORMAL。加速播放控制命令爲BUFSTATS_DO_ACCELERATE,加速播放的緣由是要播放的數據正常到達,可是抖動緩衝延時大於網絡延時,增長了時延,所以要加速播放。減速播放控制命令爲BUFSTATS_DO_PREEMPTIVE_EXPAND,又稱爲優先擴展控制命令。減速播放的緣由是要播放的數據正常到達,可是抖動緩衝延時小於網絡延時,會引發播放時聲音的斷續,下降音質,所以要減速播放,拉長時間,使不會出現斷續。這三種控制命令都有一個必要條件,那就是playedOutTS = availableTS, 因此把這三種控制命令放在一塊兒講。在「playedOutTS = availableTS」條件下,只有三種控制命令可供選擇,要麼正常播放,要麼加速播放,要麼減速播放。把加速播放和減速播放的條件搞清楚了,剩下的就是正常播放條件了。下圖更直觀的說明了正常播放、加速播放和減速播放的關係,去掉加速和減速的就是正常播放的了。
先看加速播放的條件。它的第二個條件是上一幀播放模式不爲丟包補償(第一個條件爲playedOutTS = availableTS),第三個條件是下列兩個之一:
1) 加速播放第三個條件之一
其中sample_rate爲採樣率,如8000/16000。samples_per_packet爲每一個包的採樣點數,以16KHZ/每包20ms爲例,samples_per_packet就爲320。 timescaleHoldOff初始化爲32,且每發生一次加速或減速播放就右移一位。此參數是爲了防止連續的加速或減速播放惡化人耳的聽覺感覺。
2)加速播放第三個條件之二
再看減速播放的條件。它的第一個條件與第二個條件與加速播放同樣,第三個條件以下:
說實話我沒有徹底理解上面三個加減速的數學表達式的判據,尤爲是係數值的選取。我知道不能簡單的認爲「buffLevelFilt > optBufLevel"就加速「buffLevelFilt < optBufLevel"就減速,要真的這麼判斷的話效果確定是很差的。若是哪位朋友理解了,麻煩給講講,先謝謝了!
除加減速播放這些條件外,剩下的就是正常播放了。能夠寫成以下的僞代碼:
If(playedOutTS == availableTS)
{
If(上一幀播放模式不爲丟包補償)
{
If(加速播放第三個條件是下列之一 || 加速播放第三個條件是下列之二)
return 加速播放;
If(減速播放第三個條件)
return 減速播放;
}
return 正常播放;
}
2,丟包隱藏控制命令的條件
丟包隱藏控制命令爲BUFSTATS_DO_EXPAND,又稱爲擴展控制命令。丟包隱藏的緣由是要播放的包已丟失或者還沒到(延時)。發生丟包隱藏的場景有:
1)availableTS = 0,即packet buffer爲空,顯然這時須要作丟包補償。
2)playedOutTS < availableTS,即要播放的包丟失或者延時到,可是packet buffer裏有緩衝包,須要知足下面兩個條件之一便可:
a) 上一幀播放模式不爲丟包補償
b) 上一幀播放模式爲丟包補償,且前面幾幀均爲丟包補償,這是連續丟包的場景,這時要看連續丟包補償的次數。netEQ設定最多能夠補償100ms的數據,以每包20ms爲例,最多能夠補償5個包,其實100ms後的補償效果也很差了。因此連續丟包補償的次數小於5的話,還會繼續丟包補償,不然就不作丟包補償了。
3,融合控制命令的條件
融合控制命令爲BUFSTATS_DO_MERGE,主要用於丟包隱藏後產生的PCM數據與從packet buffer裏取出的數據的銜接過程。因此產生融合控制命令的條件是:
1)playedOutTS < availableTS (此式也表示packet buffer不爲空,爲空時availableTS = 0)
2)上一幀的處理模式爲丟包補償
以上就是主要的控制命令的條件。可能不一樣版本之間可能有差別,我是根據我用的版原本講的。就像上面我說的,有些我也沒有徹底理解,只是把它照本宣科的講出來。苦於沒有文檔呀,網上也沒有相關的論述,目前只能先這樣了,後面若是徹底理解了再補充。