這次客戶有個需求需要做即時語音辨識,這個現在其實要做到很容易,像是 Google 、 Azure 都有提供相關的服務,而且整包 SDK 寫好給你,只要呼叫函式就可以使用了。但這次客戶要配合的語音辨識服務,僅提供 API 使用,沒有整包 SDK 可以用,而且僅支援 pcm-16,16kHz 格式的音訊,所以得自己從麥克風接音訊進來、轉檔、發送後端並取回資料。今天這篇就來講講要怎麼在前端透過 WebRTC 來取得麥克風音訊及處理的過程。
#取得麥克風音訊
首先我們得先確定使用者用的瀏覽器有沒有支援 WebRTC ,若有才可以繼續進行後續動作,否則可能就得請使用者換個瀏覽器了。
接著就可以利用 WebRTC 的 getUserMedia 來取得麥克風音訊:
在使用 getUserMedia 的時候可以指定要回傳的音訊格式,但這個設定好像沒什麼用,因為我把接到的 stream 直接丟到後端後會出錯,但用後面的方式轉過格式後就過了,十分奇妙...
如果一切順利,應該可以在 console 看到,有回傳了一個 MediaStream。
#利用 AudioContext 處理音訊
AudioContext 可以理解成一個乘載音訊的容器,我們會利用他的 ScriptProcessorNode 來對音訊進行處理,包含了 onaudioprocess 的 callback。
為了獲取錄音的的數據,我們要把他 connect 到 ScriptProcessorNode,因此我們要先建立一個 ScriptProcessorNode 的實體:
這邊利用 createScriptProcessor 來建立實體,需要傳入幾個參數
- BUFFER_SIZE
緩衝區大小,通常是 4 KB - INPUT_CHANNEL_COUNT
輸入的聲道數量 - OUTPUT_CHANNEL_COUNT
輸出的聲道數量
在之後的 onAudioProcess 裡面可以透過下面的程式碼取得左右聲道的資料:
因為最後會把音訊轉為 wav 格式,而 wav 在儲存的時候會左右聲道的數據交叉存放:
最後要來建立 wav 檔案,先建立 header 部分,接著要來把音訊的資料寫入,因為要使用16位二進制,而16位的範圍是 -32768 ~ +32767 ,最大值的 32767 轉換成 16進制則是0x7FFF,把音量乘以這個數值就是實際要儲存下來的值:
上面的函式都完成後,就可以在 onAudioProcess 裡面來使用,先取得左右聲道的陰鬼資料,將其合併起來後建立 wav 檔案,就可以利用 FormData 來傳送給後端了。
最後把剛剛 audioContext 的後半段給補上,先建立 ScriptProcessorNode,並指定 onAudioProcess 的處理函式即完成了。
若要停止錄音,則利用下方程式碼即可: