1. 程式人生 > >[轉載]如何解決直播中的播放雜音、噪音、回聲問題 | 直播疑難雜症排查

[轉載]如何解決直播中的播放雜音、噪音、回聲問題 | 直播疑難雜症排查

《直播技術詳解》系列文章之後,我們推出了這個新的系列《直播疑難雜症排查》,把解決直播問題的經驗逐步分享出來,同時也會穿插一些音視訊開發的基礎知識和優化經驗,希望能夠幫助到直播領域的開發者們。


本系列會涵蓋的內容包括但不限於如下一些主題: 
播放失敗 
直播卡頓 
首開慢 
延時高 
音畫不同步 
馬賽克嚴重 
播放黑屏、花屏、綠屏 
- 播放雜音、噪音、回聲 
- 點播拖動不準 
- 直播發熱問題 
- 其他問題(待續)

本文為 《直播疑難雜症排查》系列的第八篇文章,我們重點看看直播過程中出現的雜音、噪音和回聲等問題。

相比於視訊而言,音訊要敏感得多,視訊畫面有噪點、馬賽克都還是可以勉強被接受,而聲音一旦有任何瑕疵,人耳都會特別容易感覺到,而且難以忍受。

問題現象

常見的音訊問題現象描述如下: 
- 電流音,爆音,滋滋聲或者嘟嘟聲 
- 聲音斷斷續續,聽不清楚 
- 回聲,能聽到自己說話的聲音

問題排查

1.引數配置問題

上面也有提到,音訊是一個特別敏感的東西,涉及到許多引數配置,一旦配置不太匹配,就會導致聲音聽起來非常詭異(比如:取樣率是 32000Hz 的音訊,給播放器配置為 8000Hz 或者 44100Hz,就明顯會出現音訊慢放或者快放的效果)。

常見的音訊引數和基本原理,可以參考文章:《Android音訊開發(1):基礎知識》

我們只需要注意的是,無論是採集和播放,都要給系統的 API 以及第三方的庫配置正確的引數,如:取樣率、位寬、聲道數等等。

2.程式碼層面的原因

常見的程式碼層面的問題有如下幾種: 
- 音訊 buffer 大小不匹配,一段 1024 bytes 的音訊,放到了 2048 bytes 的陣列,導致尾部有隨機數 
- 音訊 resample 重取樣的演算法問題,導致取樣出來的資料出了問題 
- Android 的 ByteBuffer 取出陣列,是不能直接用 .array() 方法的,而需要用 .get() 方法 
- iOS 系統,其他 app 通過系統 API 更改了 AudioSession 取樣率的配置

3.網路波動

視訊是一幀一幀連續的影象構成的,在播放過程中,如果無法按時渲染,則會出現卡頓的效果;如果丟失幾幀畫面,則會出現快進效果。

而音訊是流式的,雖然也被切分為了一個個音訊幀,但如果無法按時播放或者連續丟失較多的音訊幀,則會明顯聽到斷斷續續的聲音出現。特別是在弱網、丟包率高等不穩定網路環境下,很容易出現這種情況。

4.回聲消除

回聲一般出現在同時有音訊的採集和播放的場景,比如:連麥互動、混音返聽等等,採集到的音訊通過揚聲器又播放出來了,同時又被採集了進去,從而產生了回聲或者嘯叫聲。

這樣的場景下,一般需要通過系統的回聲消除 API,或者第三方回聲消除庫(如:speexdsp,webrtc 等)進行處理。

注意:很多 Android 機型硬體自帶的回聲消除效果並不是很好。

5.混音越界

音訊的 PCM 資料,通常用 short 陣列來存放,當我們做一些多路音訊的混音功能的時候,如果不注意處理 short 型別的大小越界,則往往帶來爆音的問題。下面是一段參考 webrtc 的混音程式碼,專門針對混音越界做了簡單處理,可以參考參考: