これは2017年WebRTCアドベントカレンダーの23日目の記事です。
はじめに
最近、話題のスマートスピーカーGoogle HomeのCMようなことブラウザでもやりたい。
ということで
いろいろ調べてみると最もお手軽なのはWeb_Speech_APIしたが、ブラウザ互換性を見ると
Safari未サポートということなのでcloud speech API用の音声ファイルを作ってみます。
ちなみにGoogle Cloud Speech APIはLINEAR16 または MULAW でエンコードされたwavファイルも対応
しているのでブラウザでマイク音声からwavファイルを生成する手引 1
こちらで十分なのですが
今回は違う形式の音声ファイル(flac)をブラウザで作成したいので
ライブラリないかなと探していた所、いいのありました!
ライブラリ
Flacエンコード用
https://github.com/mmig/libflac.js
MIT License
Blob保存
https://github.com/eligrey/FileSaver.js
MIT License
WebWorkerを使ったDemoも用意されてます
https://mmig.github.io/speech-to-flac/
実装方法
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>flac recorder</title>
</head>
<body>
<input type="button" id="start-button" onclick="startRecording();" value="Rec"></input>
<input type="button" id="stop-button" onclick="stopRecording();" value="Stop"></input>
<script type="text/javascript" src="libflac3-1.3.2.min.js" /></script>
<script type="text/javascript" src="FileSaver.min.js" /></script>
<script type="text/javascript">
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || window.navigator.mozGetUserMedia;
window.URL = window.URL || window.webkitURL;
var encoder = null;
var recording = false;
var localStream = null;
var audio_context = null;
var source = null;
var node = null;
function startRecording() {
//worker開始
encoder = new Worker('encoder.js');
encoder.onmessage = function(evt) {
if (evt.data.cmd == 'end') {
//flac保存処理
saveAs(evt.data.buf, 'output.flac');
//worker破棄
encoder.terminate();
encoder = null;
}
};
navigator.getUserMedia({ video: false, audio: true },
function(stream) { // for success case
localStream = stream;
gotStream(localStream);
},
function(err) { // for error case
console.log(err);
}
);
}
function gotStream(stream) {
console.log('start recording');
recording = true;
var audio_context;
if (typeof webkitAudioContext !== 'undefined') {
audio_context = new webkitAudioContext;
} else if (typeof AudioContext !== 'undefined') {
audio_context = new AudioContext;
}
source = audio_context.createMediaStreamSource(stream);
if (source.context.createJavaScriptNode) {
node = source.context.createJavaScriptNode(4096, 1, 1);
} else if (source.context.createScriptProcessor) {
node = source.context.createScriptProcessor(4096, 1, 1);
}
var samplerate = audio_context.sampleRate; //44100 または 48000
//flac初期処理
encoder.postMessage({ cmd: 'init', config: { samplerate: samplerate, bps: 16, channels: 1, compression: 5 } });
node.onaudioprocess = function(evt) {
if (!recording) {
return;
}
var channel = evt.inputBuffer.getChannelData(0);
//flacエンコード
encoder.postMessage({ cmd: 'encode', buf: channel });
};
source.connect(node);
node.connect(audio_context.destination);
}
function stopRecording() {
if (!recording) {
return;
}
console.log('stop recording');
var tracks = localStream.getAudioTracks()
for (var i = tracks.length - 1; i >= 0; --i) {
tracks[i].stop();
}
recording = false;
//worker終了
encoder.postMessage({ cmd: 'finish' });
source.disconnect();
node.disconnect();
source = node = null;
};
</script>
</body>
</html>
おわりに
そのうちMediaRecorderのmimeTypeにflacが追加されるのを期待しますw!