音频网络传输 3
11|網絡差怎么辦?音頻網絡傳輸與抗弱網策略
上次了如何挑選一個編解碼器。其實編解碼器就是把音頻信息拆解、包裝成一個個的數據包,然后通過網絡傳輸到遠端。在遠端打開數據包,再組裝成音頻播放出去。
如果把一個個數據包比喻成一輛輛運送音頻貨物的小車,而網絡則是運輸的道路。那么會發現:有的時候經過的是高速公路,物流十分流暢;但有的時候經過的卻是崎嶇蜿蜒的山路,甚至有的小車在山路上,摔下了懸崖,丟掉了包裹,或者趕上交通高峰期道路十分擁堵,從而小車超過了規定的物流時間,這些情況就是我們說的弱網。
一般在弱網情況下,音頻的體驗可能表現為卡頓、雜音。如果情況嚴重可能會直接導致無法正常通話。現在來看看音頻鏈路中弱網是怎么形成的,以及如何通過抗弱網策略來解決弱網問題。
實時音頻傳輸
在介紹弱網之前先來看看音頻是怎么傳輸的。在實時音頻交互的場景中,為了保證傳輸的實時性,一般使用基于 UDP 協議的 RTP 協議來傳輸音頻數據。相較于 TCP 協議,UDP 提供了一種無需建立連接,就可以發送封裝的 IP 數據包的方法。所以它的優點是延遲低、速度快,但丟包了、包損壞了的時候也沒有重傳機制等做保護,可以說它是一種“盡力而為”的協議機制。
而 RTP 定義了音視頻的數據包格式,其中包含了 RTP 版本號、包順序編號等信息。而音頻編碼得到的壓縮后的音頻信息,就對應了數據包最后的 Audio Payload,也就是音頻負載部分。可以通過圖 1 來看看一個完整的音頻數據包的組成形式。
圖1 音頻數據包的組成弱網是如何形成的弱網是如何形成的
現在了解了音頻是怎么傳輸的,接下來來看看弱網是如何形成的。其實弱網狀態中有三個常見的問題:丟包(Packet Loss)、延遲(Latency)和抖動(Jitter)。挨個來看看它們分別是怎么產生的。
丟包
還是以物流小車為例。“丟包”指的是有的車無法在有效時間內到達終點,甚至可能永遠也到不了終點。比如有的小車發生了車禍,或者小車司機罷工了。如果 100 輛車里有 10 輛無法到達終點,那么就把它叫做丟包率為 10%。在網絡傳輸中,數據包會經過很多復雜的路徑,有的是在物理傳輸中發生了丟失,有的是在服務器、路由轉發時由于擁堵或等待時間過長被拋棄。可以說,互聯網傳輸并不是百分百可靠的,總有數據無法按時傳輸到目的地。
延遲和抖動
在網絡這條公路上,從起點到終點有很多不同的路徑可以選擇。可以選擇走高速但也可能走了鄉村小道,這樣就會導致包裹到達終點所經歷的時間發生變化。而這個從發送到接收經過的時間把它叫做延遲。
那么很顯然,音頻在發送的時候是按照時間順序等間隔發送的,但是由于每個數據包經過的路徑不同,從而到達目的地的延遲也不一樣。這就導致有的時候很長時間都沒有一個數據包到達,而有的時候幾乎是同時來了好幾個數據包。這就是常說的抖動。如果按照數據包到達的順序去播放音頻,那么音頻播放可能是亂序的而發生雜音,也可能是沒有數據可以播放,導致卡頓。
實際上,全球的網絡傳輸環境隨區域、時段的不同而不斷變化,并且時好時壞。所以丟包、延時和抖動,是基于互聯網進行實時傳輸不可避免的三個問題,不論是在局域網、單一國家地區內傳輸,還是跨國、跨地區傳輸,我們都可能會遇到這些問題。
從聲網 Agora 監控的網絡實況來看,以網絡相對較好的中國為例,99% 的音頻互動需要處理丟包、抖動和網絡延時等。在這些音頻會話中,20% 由于網絡問題會有超過 3% 的丟包,10% 的會話有超過 8% 的丟包。
抗弱網策略
既然弱網狀態是互聯網傳輸中不可避免的,那么有什么辦法來解決或者說對抗弱網?主要有網絡丟包控制這一網絡傳輸條件下的通用解決方法,和 NetEQ 這種音頻獨有的抗弱網策略這兩塊來解決弱網問題。接下來逐一看一下。
網絡丟包控制
先來看看怎么對抗丟包的。其實抗丟包背后的邏輯比較簡單。簡單地說,就是同一個包一次多發幾個,只要不是都丟了就能至少收到一個包;又或者丟了包就再重傳一個,只要速度夠快還能趕上正常的播放時間就可以。這兩種思想對應通常使用的前向糾錯 FEC(Forward Error Correction)和自動重傳請求 ARQ(Automatic Repeat-reQuest)這兩個糾錯算法。
FEC 是發送端通過信道編碼和發送冗余信息,而接收端檢測丟包,并且在不需要重傳的前提下根據冗余信息恢復丟失的大部分數據包。即以更高的信道帶寬作為恢復丟包的開銷。
這里需要注意的是:音頻前向糾錯遵循 RFC-2198 標準;而視頻前向糾錯遵循 RFC-5109 標準。音頻由于數據包相比視頻要小的多,可以直接用完整的音頻包做冗余,而不是像視頻用一個分辨率比較差的小數據包做冗余。如圖 2 所示這就是 Simple-FEC 的原理。
圖2 正常發包(上)Simple-FEC(下)看圖 2 中的 FEC 就是每次發一個當前時間的數據包和一個上一時刻的冗余包,當其中一個數據包丟失時,我們可以用下一時刻的冗余包把數據恢復起來。顯而易見的是,如果同時丟兩個包,那么就無法恢復數據了。可以看到,在這種多發一倍流量的情況下,連續丟兩個包就無法還原了。那么有沒有什么辦法可以改進這種 Simple-FEC 呢?
再看看另一種 FEC 的方法:RS-FEC,RS 碼即里德 - 所羅門碼(Reed-solomon Code)。這里結合圖 3 來看一下。
圖3 RS-FEC抗丟包原理假設每 m 個包(紅色方塊)進行一次 RS-FEC 編碼得到 n 個冗余包(綠色方塊)。冗余包加上原來的包,也就是我們在 m 個包的間隔時間里要發送 m+n 個包。RS-FEC 的特點是,我們只需要得到 m+n 個包中的任意 m 個包就可以把音頻還原出來。在圖 3 中,m=4,n=4,這樣即使這 8 個包里連續丟了 4 個,也就是丟包率是 50%,都可以保證音頻的流暢播放。
介紹了 FEC,再來看看另一個常用的防丟包策略:ARQ 。其實 ARQ 的原理非常簡單。它就是采用使用確認信息(Acknowledgements Signal,ack),也就是接收端發回的確認信息,表征已正確接收數據包和超時時間。如果發送方在超時前沒有收到確認信息 ack,那么發送端就會重傳數據包,直到發送方收到確認信息 ack 或直到超過預先定義的重傳次數。
可以看到相比 ARQ 的丟包恢復,由于 FEC 是連續發送的,且無需等待接受端回應,所以 FEC 在體驗上的延時更小。但由于不管有沒有丟包 FEC 都發送了冗余的數據包,所以它對信道帶寬消耗較多。而相比 FEC 的丟包恢復,ARQ 因為要等待 ack 或者需要多次重傳。因此,ARQ 延時較大,帶寬利用率不高。
可以看到,這兩種算法都增加了網絡所需要傳輸的帶寬。那么如果網絡帶寬本就不夠而導致丟包,這時 FEC 和 ARQ 不但沒能起到抗丟包的作用,而且還可能導致網絡堵塞導致丟包更嚴重。那么除了 FEC 和 ARQ 這兩種抗丟包手段外,還有沒有什么其它的方法可以解決弱網問題?
NetEQ
其實為了解決弱網問題,在接收端音頻解碼時通常都有一套比較完整的抗丟包策略。實際上,很多音頻編解碼器或者開源實時音頻框架中都自帶了抗丟包策略,其中比較典型的是在 WebRTC 框架中的 NetEQ 模塊。可以通過圖 4 來了解一下。
圖4 NetEQ處理流程由圖 4可以看到,NetEQ 主要包括兩個模塊:MCU(Micro Control Unit,微控制單元)和 DSP(Digital Signal Prcessing,信號處理單元)。我們知道由于網絡傳輸的不穩定性,雖然我們有 FEC 和 ARQ,但由于延遲或者嚴重丟包導致的數據包亂序,或者數據包丟失,還是會經常發生的。
在 MCU 里的 Jitter Buffer(抖動緩存區)或者說 Pactet Buffer(數據包緩存區)就是通過開辟一個比較大的緩沖區域,讓一段時間內到來的數據包在 Jitter Buffer 里存儲、排序。然后按照播放順序把數據包交給 DSP 中的解碼器進行解碼。
在 DSP 模塊中,由解碼緩沖區得到的音頻信號并不是直接交給播放設備播放的。而是需要根據網絡狀態、緩沖區未處理的數據包長度,以及等待播放的音頻長度等參數,來決定使用 DSP 處理中的五種決策方法中的哪一種來處理音頻數據。接下來我們就來看看這五種策略:加速、慢速、正常、融合和丟包補償背后決策的原理、實現方法和實際聽感的效果是什么樣的。
其實 NetEQ 中主要定義了四種收包的情況:
1. 過去幀和當前幀都正確收到
如果過去幀和當前幀都正確接收到了,那么這種情況下只需要考慮網路抖動帶來的數據包堆積和數據包接收不足的問題。
所謂數據包堆積,就是同一時間到達了多個數據包都在等待播放,而這個時候需要使用加速策略(accelerate),即對音頻信號采用變速不變調的算法來縮短解碼后音頻的長度,從而實現快速播放。相反的,如果在緩存中的數據就快播放完了但新包還未送達,那么這時候就需要慢速的方法來把音頻時長拉長。這里用到的同樣是變速不變調的算法,即只改變音頻的播放速度而不改變音頻的音調。
WebRTC 中使用的是一種叫 WSOLA 的算法來實現的,這其實是音效算法中變調不變速算法的一種反向應用,更具體地會在以后詳細解讀。
那快慢放的聽感是什么樣的呢?在網絡有抖動的時候,你可能會感覺對面說話,有的時候會快一點,有的時候會慢一點。這種快慢感在語音的時候可能不是那么容易察覺,這是因為人說話本來就有快有慢。但是在音樂的場景下,因為你對一首歌比較熟悉,所以快慢放就會更容易被察覺。
2. 當前幀發生丟包或者延遲
如果當前幀發生了丟包或者延遲導致當前沒有音頻數據可以播放,這個時候就需要額外的PLC(Package Loss Compensation,丟包補償)模塊來重建音頻。在編解碼器中講過?LPC 算法,其實常見的 PLC 算法就是通過重建或者復用上一幀的 LPC 系數和殘差來還原這一幀的音頻數據,從而實現丟包隱藏的。
這里需要注意和前面的慢放相區分。慢放雖然也可以增加音頻的長度但一個慢放系數比例確定后,慢放所能增加的音頻長度也就固定了,所以一般慢放用于解決需預測時間比較短的音頻的拉長。而 PLC 具有可擴展性,所以一般負責整個一幀或者多幀的,長時間的丟包補償。
3. 連續多幀丟包
那么在連續多幀丟包的情況下依靠 PLC 是不是就可以了呢?答案是否定的,因為 PLC 補出來的音頻很大程度上是上一幀音頻的延長。如果長時間使用 PLC,聲音就會變得失真,從而影響聽感。所以如果出現連續多幀丟包,我們就會逐幀遞減 PLC 補出音頻的能量增益。這也就是為什么,長時間的丟包后的聽感是聲音逐漸變小直至沒有聲音,而不是有一個奇怪的聲音一直在延續。
4. 前一幀丟失,當前幀正常
最后這種情況前一幀可能存在 PLC 的補幀操作,那么新來的音頻數據和上一幀就會出現不連續的情況,這里就會用到融合的操作。操作也比較簡單,就是把當前幀的新數據和之前幀的音頻做交叉淡化,讓它們的連接處能平穩過度。
交叉淡化的步驟如圖 5 所示,其實就是前一幀信號的末尾取一段逐步衰減至 0,然后讓后一幀的前端數據從 0 開始逐步提升。然后把這兩幀重疊部分相加就可以實現比較平滑的拼接了。
圖5 交叉淡化的過程圖 5 中橙色虛線表示交叉淡化用的淡化增益,第一第二行分別表示原始數據和交差淡化衰減后的曲線,最后一行是兩幀重疊部分相加、拼接后得到的數據。
總結
弱網的情況在實時音頻領域中是不可避免的一類問題。它主要表現為丟包、延遲和抖動這三個常見現象。為了能在弱網情況下繼續保持音頻的流暢播放,分別從網絡丟包控制這一網絡傳輸條件下的通用解決方法,和 NetEQ 這種音頻獨有的抗弱網策略這兩塊來解決弱網問題。
其中,網絡丟包控制比較常見的方法有前向糾錯 FEC 和自動重傳請求 ARQ 這兩種。需要注意的是,這兩種方法都是以增加網絡帶寬消耗的方式來提升弱網的能力的。因此,如果在網絡帶寬本身比較差的情況下,就可能導致適得其反。而 NetEQ 則是通過一些音頻處理方法,比如快慢放、PLC 等方法來解決抖動和丟包的問題。
可以看到,NetEQ 中通過多個 Buffer 緩存以及快慢放的形式引入了延遲,從而提升了抗網絡抖動的能力。然后通過 PLC 的方式解決丟包帶來的音頻卡頓。這與 FEC 和 ARQ 相比無需額外的帶寬消耗,但是卻增加了延遲。
實際上抗弱網也叫作音頻的“最后一公里”(Last-mile),并且它是保證音頻傳遞的重要組成部分。其實在實際使用中可能需要針對自己的場景進行一些調整,比如說對于流暢通話比較重要的會議等場景,可以把 NetEQ 中的緩沖 Buffer 適量增大,這樣可以進一步提升抗網絡丟包的能力。但是 Buffer 也不能太大,這樣會導致過多的延遲,從而影響通話效果。
也可以在 NetEQ 中引入網絡抖動情況的估計,比如在網絡抖動嚴重的時候,動態增加 NetEQ 的 Jitter Buffer 的大小,而網絡情況較好的時候減少一些 Jitter Buffer 的大小,從而降低延遲,這些都是可以改進的策略。
總結
- 上一篇: 使用ffmpeg将h264视频文件转Mp
- 下一篇: [css] 你有用过IE css的ex