https://d226lax1qjow5r.cloudfront.net/blog/blogposts/streaming-calls-to-a-browser-with-voice-websockets-dr/audio-websockets.png

VoiceWebSocketによるブラウザへのストリーミングコール

最終更新日 November 5, 2020

所要時間:1 分

我々は最近 WebSocketのサポートのサポートを発表しました。この最初のユースケースは、Vonage Voice APIとIBM WatsonやAmazon Alexaのような音声AIプラットフォーム間のサーバー間通信です。しかし、AWS ReInventの我々のブースのために作った小さなデモをお見せしたい。これは、電話会議の音声をウェブブラウザにストリーミングし、それを Web Audio API.

なぜこんなことをしたいのか?まず第一に、WebSocketの新機能をアピールするいい方法なんだけど、開発を始めているうちに、大勢の人を "聞くだけ "モードで通話させたいようなケースに最適だと気づいたんだ。典型的な大企業の "全員参加 "の電話会議を例にとってみよう。5~10人以上が話していると、カオスになります。このような大規模な通話では、参加者のほとんどは受動的なリスナーで、(できれば)無言のままでいる。しかし、これはかなり非効率的でコストがかかる。特にスケールも良くない。通常の参加者は電話会議に参加しているわけではなく、彼らの参加はトークラジオ局を聞いているようなものなのだ。それなら、もっとブロードキャストに近い技術で参加者をつないでみてはどうだろう?

新しい Vonage WebSocket Voice APIはこのユースケースに最適なソリューションだ。接続された多くのブラウザに通話音声をブロードキャストするアプリの作り方を説明しよう。

技術的な詳細

この機能についての技術的な詳細を説明し、Voice WebSocketの機能を理解していただきたいと思います。この機能は、WebアプリケーションとVoiceを統合するための可能性を広げるもので、私はとても楽しみにしています。

これが、この組み合わせの図である:

architecturearchitecture

電話会議

2つの "ドメイン "がある。 Voice APIにホストされた典型的な電話会議があり、話し手はそこにダイヤルする。このコードは非常にシンプルで、新しいVonageアプリケーションを作成し、そのアプリケーションを answer_url会議.これをウェブ・アプリケーション・サーバーから提供します。

NCCOはこうだ:

[
{
"action": "talk",
"text": "Connecting to Audio Socket Conf"
},
{
"action": "conversation",
"name": "audiosocket",
"eventUrl" : ["http://example.com/event"]
}
]

そのため、ユーザーがアプリケーションにリンクされた番号に電話をかけると、非常に基本的な会議に参加することになります。さらに、電話会議のステータスに関するイベントをウェブアプリサーバーに送信します。もちろん、モデレーションやPINなど、より高度な機能を追加することもできます。

ウェブソケット参加者

ここからが(少し)複雑な部分です。Vonage WebSocket APIとやりとりする場合、アプリケーションはWebSocketクライアント(ブラウザなど)ではありません。アプリケーションはWebSocketサーバーです。そのため、アプリケーション・サーバは Vonage REST APIにリクエストを送信し、あなたのアプリケーションを会議の参加者にするように音声プラットフォームに伝える必要があります。そのために、アウトバウンドコールの answer_urlを、電話に使用したのと同じ NCCO に指定します。

ウェブソケットに発信するリクエストは次のようになる:

POST /v1/calls
Host: api.nexmo.com
Authorization: Bearer [YOUR_JWT_TOKEN]

{ "to": [{
"type": "websocket",
"uri": "ws://example.com/socket",
"content-type": "audio/l16;rate=16000",
"headers": {
"app": "audiosocket"
}
}],
"from": {
"type": "phone",
"number": "442037831800"
},
"answer_url": ["http://example.com/ncco"]
}

このシーケンス図はその流れを示している:

sequence diagramsequence diagram

Vonageからアプリ・サーバーへのWebソケット接続が1つだけ確立されるようにするには、アプリケーション内でこの呼び出しの状態と呼び出し識別子(callid).私は確立されたクライアント接続の数をチェックします。ゼロになったら、REST API経由でWebSocketコールを再び閉じます。最初のクライアント接続だけがVonageからの接続を開始します。

インバウンドWebSocketデータの処理

Vonageとアプリサーバ間でWebSocket接続が確立されたら、何を送信するかを理解する必要がある。最初の接続で、Voice APIはいくつかのJSONデータを含む単一のテキスト "メッセージ "を送信します。これは主に、接続が作成されたときに NCCO 経由でアプリケーションから渡された追加値(この場合は app : audiosocket)と共に、音声フォーマットを記述したものです。

{
"app": "audiosocket",
"content-type": "audio/l16;rate=16000"
}

最初のテキストメッセージの後、Vonageはそれぞれ20msのRAWオーディオを含むバイナリメッセージを送信します。(注:RAWオーディオは.wavファイルとは異なります。つまり、あなたのコードでは、受信したメッセージがテキストかバイナリかを判断し、それに応じて処理する必要があります。

オーディオデータをブラウザに送信する

このオーディオをブラウザで再生するには WebAudioで再生するには、RAWオーディオを.wavファイルにする必要がある。これは、ファイルに44バイトの小さなヘッダーを追加することを意味する。しかし、20msのフレームごとにこれを行うのはかなりのオーバーヘッドになりますし、私たちのユースケースを考えると、リスナーに対する多少の遅延は許容できます。これを避けるために、Vonageからのメッセージを10個バッファリングして、それらを連結し、44バイトのヘッダーを一番上に貼り付けます。これで200msの.wavファイルができる。

そして、接続されているクライアント・ウェブソケットのリストを繰り返し、それぞれにファイルをバイナリ・メッセージとして送信することで、これらの.wavファイルをクライアントにブロードキャストすることができる。

ブラウザでオーディオを再生する

ウェブクライアントでは、ウェブソケットサーバーに接続し、受信したオーディオメッセージを処理するためのJavaScriptを作成する必要があります。Vonageから受信するオーディオ・フォーマットは16ビット16Khzで、ほとんどのブラウザのネイティブ・フォーマットは32ビット44.1Khzなので、WebAudioで一定のストリームを再生することはできません。適切な再生レートに音声をトランスコードするようブラウザに要求する必要があります。そのため バッファソースは非常にうまくこれを行い、レイテンシーもほとんど追加しませんが、個別のファイルでのみ動作し、ファイルごとに新しいインスタンスを作成する必要があります。そのため、新しいオーディオファイルがウェブソケットに到着したら、それを関数に渡す必要があります。 bufferSourceを作成し、それをメインの audioContext.

もうひとつ考慮すべき点はタイミングだ。サンプルの数を減らしても長いサンプル(20msに対して200ms)にすることでジッターは改善されますが、それでもメッセージは正確な間隔で届きません。そのため、単純に次々と再生すると不具合が生じます。幸いなことに、WebAudioには非常に正確なタイミングインターフェースがあります。最初のサンプルの時間を T0とし、受信したメッセージの数を数え、それに 0.2を掛けることで、各サンプルを正しい時刻に開始するようにスケジューリングし、実質的にグリッチのないストリームを再構築することができます。

クライアント・コードのこれらの部分については、以下にコメント付きで詳述する:

var startTime; // Make startTime a global var

ws.onmessage = function(event) {
// On the first message set the startTime to the currentTime from the audio context
if (count ==0){
startTime = audioContext.currentTime;
}

audioContext.decodeAudioData(event.data, function(data) {
count ++; // Keep a count of how many messages have been received
var playTime = startTime + (count *0.2) //Play each at file 200ms
playSound(data, playTime); //call the function to play the sample at the appropriate time
});
};

function playSound(buffer, playTime) {
var source = audioContext.createBufferSource(); //Create a new BufferSource fr the
source.buffer = buffer; // Put the sample content into the buffer
source.start(playTime); // Set the starting time of the sample to the scheduled play time
source.connect(analyserNode); //Connect the source to the visualiser
source.connect(audioContext.destination); // Also Connect the source to the audio output
}

もちろん、ファイルの到着が予定開始時刻より遅すぎるというシナリオもあります。しかし、WebAudioはこのように賢く、あたかも最初からそこにあったかのように、正しいポイントから再生が始まるように実際に調整します。ですから 200msサンプルは T 1200msで再生されるはずのサンプルが 1300msまで呼び出されなかった場合、WebAudioは 100msにジャンプして再生を開始します。このため、サンプルの小さな開始が欠落する不具合が発生することがありますが、これは電話形式のオーディオではまったく問題ありません。高音質な音楽ではうまくいかないかもしれません。

コードを取得する

これで、低遅延の一方向オーディオ・ストリームがブラウザで直接再生されることになる。

コードをチェックアウトする VonageコミュニティGitHubオーガニゼーションでコードを確認し Vonage WebSocket Voice API についての詳細は ドキュメント をご覧ください。.

シェア:

https://a.storyblok.com/f/270183/384x384/7fbbc7293b/sammachin.png
Sam Machinヴォネージの卒業生