HTML5 錄音的踩坑之旅

發表於2017-12-25

開篇閒扯

前一段時間的一個案子是開發一個有聲課件,大致就是通過匯入文件、圖片等資源後,頁面變為類似 PPT 的佈局,然後選中一張圖片,可以插入音訊,有單頁編輯和全域性編輯兩種模式。其中音訊的匯入方式有兩種,一種是從資源庫中匯入,還有一種就是要提到的錄音。
說實話,一開始都沒接觸過 HTML5 的 Audio API,而且要基於在我們接手前的程式碼中進行優化。當然其中也踩了不少坑,這次也會圍繞這幾個坑來說說感受(會省略一些基本物件的初始化和獲取,因為這些內容不是這次的重點,有興趣的同學可以自行查詢 MDN 上的文件):

  • 呼叫 Audio API 的相容性寫法
  • 獲取錄音聲音的大小(應該是頻率)
  • 暫停錄音的相容性寫法
  • 獲取當前錄音時間

 

錄音前的準備

開始錄音前,要先獲取當前裝置是否支援 Audio API。早期的方法 navigator.getUserMedia 已經被 navigator.mediaDevices.getUserMedia 所代替。正常來說現在大部分的現代瀏覽器都已經支援navigator.mediaDevices.getUserMedia 的用法了,當然MDN上也給出了相容性的寫法

因為這個方法是非同步的,所以我們可以對無法相容的裝置進行友好的提示

一切順利的話,我們就可以進入下一步了。
(這裡有對獲取上下文的方法進行了省略,因為這不是這次的重點)

開始錄音、暫停錄音

這裡有個比較特別的點,就是需要新增一箇中間變數來標識是否當前是否在錄音。因為在火狐瀏覽器上,我們發現一個問題,錄音的流程都是正常的,但是點選暫停時卻發現怎麼也暫停不了,我們當時是使用 disconnect 方法。這種方式是不行的,這種方法是需要斷開所有的連線才可以。後來發現,應該增加一箇中間變數 this.isRecording 來判斷當前是否正在錄音,當點選開始時,將其設定為true,暫停時將其設定為false
當我們開始錄音時,會有一個錄音監聽的事件 onaudioprocess ,如果返回 true 則會將流寫入,如果返回 false 則不會將其寫入。因此判斷this.isRecording,如果為 false 則直接 return

當然這裡也會有個坑,就是無法再使用,自帶獲取當前錄音時長的方法了,因為實際上並不是真正的暫停,而是沒有將流寫入罷了。於是我們還需要獲取一下當前錄音的時長,需要通過一個公式進行獲取

這樣就能夠獲取正確的錄音時長了。

結束錄音

結束錄音的方式,我採用的是先暫停,之後需要試聽或者其它的操作先執行,然後再將儲存流的陣列長度置為 0。

獲取頻率

具體可以參考https://developer.mozilla.org/zh-CN/docs/Web/API/AnalyserNode/frequencyBinCount

其它

  • HTTPS:在 chrome 下需要全站有 HTTPS 才允許使用
  • 微信:在微信內建的瀏覽器需要呼叫 JSSDK 才能使用
  • 音訊格式轉換:音訊格式的方式也有很多了,能查到的大部分資料,大家基本上是互相 copy,當然還有一個音訊質量的問題,這裡就不贅述了。

結語

這次遇到的大部分問題都是相容性的問題,因此在上面踩了不少坑,尤其是移動端的問題,一開始還有出現因為獲取錄音時長寫法錯誤的問題,導致直接卡死的情況。這次的經歷也彌補了 HTML5 API 上的一些空白,當然最重要的還是要提醒一下大家,這種原生的 API 文件還是直接檢視 MDN 來的簡單粗暴!

相關文章