移動端實現HTML5 mp3錄音踩坑指南:系統播放音量變小、一些機型錄音斷斷續續 之 MediaRecorder和AudioWorklet的終極對決

H5錄音見坑填坑

在2022-06-19那天,Recorder H5錄音開源庫(//github.com/xiangyuecn/Recorder)群里有用戶回饋手機上錄音有bug,前後回饋過來幾段測試過程完整錄像;分析後初步發現在他那個手機上表現確實是斷斷續續的,從而音質非常差;此版本的Recorder採用的瀏覽器AudioContext.createScriptProcessorAudioWorklet 介面對getUserMedia返回的音頻流進行音頻採集,在線測試地址://xiangyuecn.gitee.io/recorder/

但用另外一個錄音庫 collab-project/videojs-record 錄製的卻沒有這個問題,當時初步分析了下一,發現collab-project在手機上使用的是MediaStreamRecorder來錄製webm格式音頻,底層使用的是瀏覽器的MediaRecorder介面對getUserMedia返回的音頻流進行音頻採集。

更新後的Recorder錄音在線測試頁

採用MediaRecorder採集音頻

已經知道了瀏覽器的MediaRecorder介面錄製出來的音頻不會有ScriptProcessorAudioWorklet 介面錄製出來的那種斷斷續續現象;並且後面兩個除了在移動端外,在PC端錄製出來的音頻也會有爆音的現象,只不過要間隔比較久才偶爾出現,對音質影響不明顯,這些問題MediaRecorder統統沒有!

因此很有必要使用MediaRecorder來進行錄音,來獲得更好的音質ScriptProcessorAudioWorklet 靠邊站。

音頻格式:WebM和PCM

MediaRecorder一般錄製出來的是WebM格式的音影片文件,可通過MediaRecorder.isTypeSupported方法判斷支援的格式:

[ //胡亂拼接一些類型 不同瀏覽器支援的不同
	'audio/webm; codecs=opus' //都支援的格式
	,'audio/webm; codecs=pcm' //Chrome/Safari支援
	,'audio/pcm'
	,'audio/webm; codecs=wav'
	,'audio/wav'
	,'audio/webm; codecs=ogg'
	,'audio/ogg' //FireFox支援
].forEach(v=>console.log( MediaRecorder.isTypeSupported(v) +" : "+ v ))

可以看到MediaRecorder對opus編碼的WebM格式支援的最好;pcm編碼的WebM在Chrome/Safari里得到了支援;wav、ogg不做參考。

Recorder只想得到瀏覽器採集到的PCM音頻數據(易於轉換成其他格式,比如mp3、wav),或者能簡單的解碼得到PCM也行,opus編碼的WebM對我們需要實現的錄音功能幫助不大;好在還有pcm編碼的WebM支援,簡單的從WebM容器中提取出PCM即可,目前能支援在Chrome/Safari瀏覽器上運行就能解決絕大部分用戶終端的適配。

從WebM封裝容器中提取PCM數據

MediaRecorder錄製了audio/webm; codecs=pcm數據後,會根據設定的時長間隔,將音頻片段通過回調傳給js;好在WebM容器格式簡單,很好的做到實時的提取PCM數據。

WebM格式(.webm.weba)和常見的 .mkv 影片格式都使用的:Matroska開源多媒體容器標準;Matroska封裝格式官方文檔://www.matroska.org/index.html。

學習一下Matroska文檔,就很容易提取出WebM中包含的音頻軌道數據了,PCM編碼的WebM中的音頻軌道中的數據一般為32位浮點數pcm數據。

我寫了一段解析和提取WebM音頻的程式碼,程式碼注釋裡面詳細介紹了WebM格式分解過程,源程式碼在這裡 (可以直接測試運行)。

錄音的兼容性

MediaRecorder只支援在Chrome/Safari里對getUserMedia返回的音頻流錄製成audio/webm; codecs=pcm格式,其他瀏覽器FireFox不支援此編碼的錄製,需要降級使用 ScriptProcessorAudioWorklet 來對getUserMedia音頻流的採集錄製。

好在這些功能在Recorder H5錄音開源庫都是支援的,升級加一個MediaRecorder支援也用不了多少程式碼,不管是MediaRecorder還是ScriptProcessorAudioWorklet,Recorder統統實時的返回16位PCM數據;有了PCM數據後:實時轉碼、實時上傳、語音識別、音頻可視化等等功能均可實現。

所有已正常支援getUserMedia的瀏覽器均能錄音,錄音音質根據瀏覽器支援情況自動優先採用最佳音頻採集方案;支援的包括但不限於:Chrome、Firefox、Safari、iOS 14.3+、Android WebView、騰訊Android X5內核(QQ、微信、小程式WebView)、大部分2021年後更新的Android手機自帶瀏覽器。

困擾已久的H5錄音時系統播放音量變小的問題

從Recorder開源之初就發現了這個問題,手機上只要打開了錄音,同時播放音頻的時候,系統聲音會非常的小,甚至跑到了聽筒播放,但有時又正常 毫無規律,幾年一直束手無策,根本沒有文檔有這方面的描述或文章參考。

在本次Recorder升級支援MediaRecorder的時候,由於需要getUserMedia參數裡面設置audio的取樣率sampleRate,順手就把noiseSuppression降噪、echoCancellation回聲消除都默認設成了false,沒想到測試的時候再也沒有系統播放聲音變小的現象。

降噪、回聲消除這兩個參數很早以前就在測試頁面中提供了設置選項,不過之前默認是未配置狀態,以前也經常設為false進行測試,竟然沒有發現這些參數能解決系統音量變小。

最後經過反覆測試,只有noiseSuppression+echoCancellation同時生效時,打開錄音後再播放音頻,系統音量一定會變小,很慘的是getUserMedia只要你沒有配置這兩個參數,默認就是同時開啟的;只要你給這兩參數任意一個設為false,或者都設為false,就不會影響手機系統音量。

目前Recorder已默認禁用了noiseSuppression和echoCancellation,使用原聲錄製(高音甜、中音準、低音沉,總之一句話就是通透 — 陳永仁(梁朝偉 飾))。


Recorder H5錄音開源庫://github.com/xiangyuecn/Recorder

Recorder H5在線測試頁://xiangyuecn.gitee.io/recorder/
【完】