リアルタイム音声認識サービス
近年、様々な音声認識サービスが世の中には展開されてます。
音声認識サービスのシステム構成は様々な形態があり、特にリアルタイム音声認識を行うサービスでは
- 「専用のアプリケーションをPC/スマホにインストールして、サーバ側で音声認識」
- 「専用のアプリケーションをPC/スマホにインストールして、エッジ側で音声認識」
- 「専用のデバイス端末で録音した音声をサーバ側で音声認識」
- 「Webブラウザからマイク入力した音声をサーバ側で音声認識」
などといったような形態のものが存在します。すべてを調査したわけではないですが、やはりサービス形態として最も多いのは「Webブラウザからマイク入力した音声をサーバ側で音声認識する」という形態でしょう。
そこで、今回はブラウザ上でマイクからの入力をリアルタイムでサーバに送信する部分をどのように作るか検討していきます。
ブラウザ上でマイクを扱う
ブラウザ上でJavascriptからマイクを利用するには、Web Audio APIが利用できそうです。
どうやら、ScriptProcessorNode はすでに非推奨になっており、AudioWorkletを利用する必要がありそうですが、まだまだ現役っぽいので一旦今回はそちらで進めていきます。
ドキュメントを読み進めてみると、まずはAudioContextと呼ばれるオブジェクトを生成します。
audioContext = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: 16000 });
window.AudioContext || window.webkitAudioContext
はブラウザによって名称が異なるため、その対応となります。
ここで、AudioContextのコンストラクタの仕様を確認してみると、いくつかオプションを指定できるようです。
サンプリングレートを利用する音声認識エンジンの入力に合わせておきましょう。(大体8k or 16kかと思われますが)
※指定しなかった場合、デバイスの規定値が利用されるようです
audioContext = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: 16000 });
以下のコードにおいてscriptProcessor.onaudioprocess = onAudioProcess;
の部分で指定した関数(onAudioProcess)が実際にリアルタイムに音声を処理する関数となります。録音中に繰り返し何度も呼び出されます。
navigator.getUserMedia({ audio: true }, function (stream) {
// 録音関連
localMediaStream = stream;
var scriptProcessor = audioContext.createScriptProcessor(bufferSize, 2, 1);
localScriptProcessor = scriptProcessor;
var mediastreamsource = audioContext.createMediaStreamSource(stream);
mediastreamsource.connect(scriptProcessor);
scriptProcessor.onaudioprocess = onAudioProcess;
scriptProcessor.connect(audioContext.destination);
},
function (e) {
console.log(e);
}
);
では、実際に音声を処理する部分を作成していきます。
// 録音中繰り返し呼び出されます
var onAudioProcess = function (e) {
// 音声のバッファを作成
var input = e.inputBuffer.getChannelData(0);
var bufferData = new Float32Array(bufferSize);
for (var i = 0; i < bufferSize; i++) {
bufferData[i] = input[i];
}
//!!!ここでデータをサーバーに送信したりする処理を記述!!!
};
これで、フロントエンド側で音声データを逐次マイクから取得することができました。
ここで取得した音声データを音声認識サーバに送信することでリアルタイムに音声認識が可能となります。
リアルタイム音声認識システムでは、HTTP/Websocket/gRPC/ソケット通信など様々な種類のインタフェースが定義されます。
!!!ここでデータをサーバーに送信したりする処理を記述!!!
という部分には各IFに応じた、送信処理を記述します。