最近研究了幾個人工智慧的開源專案,漸漸有了想把它們兜起來的想法。一個當然是利用文字輸入,另一個就是語音了。當然文字是簡單點,但是語音就更人性化了,所以研究了一下怎麼在 web 上錄音傳都後端去。做法有2種,首先是一邊錄一邊送,第二種就是錄完再一起送。這邊就選擇比較簡單的第2種開始。
原本參考的原始碼在這,它的做法是在本地端錄音、播放、存檔。
使用麥克風的限制
從很早開始(至少 Firefox 60),要錄制麥克風就有一些限制。
- 要使用 https 連線的錄音,限制才最少
- 若是連到 local 端,也可以沒限制
- 若是要連到 http 錄音,預設是不允許的,要透過 about:config 來開始 insecure.enable 類的選項。但每次還是會問允不允許,不能儲存。
試了很多下,最後還是沒辦法,只能透過 https 來做這些測試。我的方法是透過 stunnel 這個工具來做代理,轉接到 busybox 的 httpd,這樣就可以使用我最熟悉的工具,做簡單的測試就好。
busybox + stunnel 網頁伺服器架設
一般我是習慣用 busybox 的 http server,但大部份 Linux 內建的並不包含 CGI 的支援,需要自己編譯時開啟。如果你有自己慣用的 https server 可以略過我這邊的做法。
首先建立一個 web/ 資料夾,接下來的操做皆在才下進行
安裝設定 stunnel 套件
1 |
apt-get install stunnel |
然後建立憑証檔案
1 2 3 |
openssl genrsa -out key.pem 2048 openssl req -new -x509 -key key.pem -out cert.pem -days 1095 cat * > stunnel.pem |
產生 stunnel 設定檔
1 2 3 4 5 6 7 8 |
client = no #debug = 7 #foreground = yes pid = /tmp/sutnnel.pid [web] accept = 8887 connect = 127.0.0.1:8888 cert = stunnel.pem |
建立 http 檔案
建立 public_html/index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
<body> <div> <h2>Audio record and playback</h2> <p> <button id=startRecord>start</button> <button id=stopRecord disabled>stop</button> </p> <p> <audio id=recordedAudio></audio> <a id=audioDownload></a> </p> </div> <script> var audioChunks; startRecord.onclick = e => { startRecord.disabled = true; stopRecord.disabled = false; // This will prompt for permission if not allowed earlier navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => { audioChunks = []; let order = 0; rec = new MediaRecorder(stream); rec.ondataavailable = e => { audioChunks.push(e.data); if (rec.state == "inactive") { const req = new XMLHttpRequest(); req.open("POST", "cgi-bin/run.sh", false); let blob = new Blob(audioChunks, { type: 'audio/ogg' }); req.send(blob); } } order += 1; rec.start(); }).catch(e => console.log(e)); } stopRecord.onclick = e => { startRecord.disabled = false; stopRecord.disabled = true; rec.stop(); } </script> </body> |
建立 public_html/cgi-bin/run.sh
1 2 3 4 5 6 7 8 |
#!/bin/bash printf '%s\n\n' 'Content-type: text/html' echo "" FN=a rm -f /tmp/$FN.ogg cat > /tmp/$FN.ogg #ffmpeg -i /tmp/$FN.ogg /tmp/$FN.wav opusdec --force-wav /tmp/$FN.ogg - > /tmp/$FN.wav |
建立啟動腳本
編輯 myweb.sh
1 2 3 4 5 6 |
#!/bin/bash chmod a+x public_html/cgi-bin/run.sh killall stunnel killall busybox stunnel tunnel.conf ./busybox httpd -h public_html -p 8888 |
然後啟動該 myweb.sh ,就可以建立一個 listen 在 port 8887 https server 了。再次強調一下,這邊的 busybox 請使用有支援 cgi 的版本 (大部份需要自己編)
執行畫面與結果
最後開啟網頁,可以看到如下的畫面。
當 start / stop 後,檔案就會傳至 cgi-bin/run.sh 來做處理。從 cgi script 可以看到,我僅是將其存檔轉換成 wav 檔而已。這也僅是方便將來利用做準備。