
シェア:
ベンはセカンドキャリアの開発者で、以前は成人教育、コミュニティ組織化、非営利団体運営の分野で10年を過ごした。彼はVonageの開発者支援者として働いていた。コミュニティ開発とテクノロジーの交差点について定期的に執筆している。南カリフォルニア出身で、長年ニューヨークに住んでいたが、現在はイスラエルのテルアビブ近郊に在住。
Vonage Voice API WebSocketを使ってRubyで通話を録音する
所要時間:2 分
Vonage音声API Vonage Voice API ウェブソケット機能は最近ベータ版から一般版になりました。WebSocketsを使用すると、単一の永続的なTCP接続を介して双方向通信を作成することができます。WebSocketでは、複数のHTTPリクエストとレスポンスを処理する必要はありません。1つのWebSocket接続を開くだけで、テキストとバイナリのデータ通信を継続的に行うことができます。
WebSocketはHTTPレスポンスとリクエストのサイクルを簡素化できるが、アプリケーションを構築するには異なるパラダイムだ。ありがたいことに、一般的に使用されているプログラミング言語にはWebSocketツールがあり、プロセスの複雑さを軽減してくれる。
このチュートリアルでは、RubyでWebSocketを扱う小さなWebサーバーを構築します。このサーバーは、着信する音声通話、WebSocket接続を処理し、HTMLをレンダリングします。使用するのは Rackをウェブインターフェースとして使用し Thinを使用します。このチュートリアルでは、WebSocket の扱いに関する既存の知識は必要ありませんが、Ruby で Web サーバーを扱った軽い経験があることを前提としています。
tl;dr もしスキップしてアプリだけを実行したいのであれば、完全に動作するバージョンを GitHub.
前提条件
このチュートリアルでは、Ruby v2.7以上がマシンにインストールされている必要があります。また、このアプリケーションではいくつかのgemが使用されます。それぞれは後で作成する Gemfileに記載されており、コマンドラインから bundle installを実行することでインストールされます:
これでアプリケーションの実装に取りかかることができる。
Vonage API アカウント
このチュートリアルではバーチャル電話番号も使用します。購入するには 電話番号 > 電話番号の購入 番号を購入するにアクセスし、ニーズに合ったものを検索してください。
APIアカウントを設定する最後のステップは、Voice API Applicationを作成することです。プロビジョニングしたバーチャル電話番号をこのアプリケーションにリンクし、WebhookのURLを設定する。
Vonage API Dashboardから次の場所に移動します。 アプリケーションをクリックし 新しいアプリケーションを作成する.次のページが表示されます:
Dashboard Create Application
アプリケーションを作成するために重視すべき点は、紫色で強調表示されています:
名前アプリケーションに任意の名前を付けることができます。
公開鍵と秘密鍵:認証用の公開鍵と秘密鍵のペアを生成します。秘密鍵ファイルがあなたのマシンにダウンロードされます。私たちのアプリケーションは着信音声通話を処理するだけなので、この鍵で何かをする必要はありません。
機能:各アプリケーションは複数の機能を扱うことができる。今回の目的では、以下の機能をオンにするだけです。 Voice.
オプションの入力が終わったら 新規アプリケーションの作成ボタンを押して終了します。
アプリケーションが作成されたので、それを新しくプロビジョニングされた電話番号にリンクし、ウェブフックURLを設定しましょう。
前と同じように アプリケーションに移動し、アプリケーション名の横の楕円をクリックして 編集リンクをクリックします。
社内 機能セクションに以下のオプションが表示されます:
Application Webhook URL settings
を記入する必要があります。 イベントURLと 回答URL.前者は、Vonageが音声通話のすべてのイベントライフサイクルデータを送信する場所です。後者は、Vonageが新しい音声通話を開始するたびに送信する場所です。ここで提供されるURLは、Vonageが到達できるように、外部からアクセスできる必要があります。つまり localhostを使用することはできません。一般的な開発オプションはngrokで、以下のチュートリアルに従ってください。 チュートリアルを参照してください。
イベントURLとアンサーURLの末尾に /webhooks/eventと /webhooks/answerで終わることを確認してください。
また、Vonageの電話番号をこのアプリケーションに接続する必要があります。そのためには 番号>自分の番号に移動し、電話番号の横にある鉛筆のアイコンをクリックします。そしてオプションから新しいアプリケーションを選択し、電話番号をリンクさせます。保存 保存をクリックすると、この番号への着信はすべてあなたのアプリケーションに転送されます。
フォルダ構造の作成
Vonage APIアカウントと設定の準備ができたので、アプリケーションのフォルダ構造を作成しましょう。最終的には以下のようになります:
.
+-- recordings/
+-- views/
| +-- index.html.erb
+-- app.rb
+-- Gemfileアプリケーションのルートフォルダには app.rbが含まれ、これが音声通話の着信とWebSocket接続を処理するWebサーバーになります。また Gemfileここには依存関係を定義します。さらに2つのフォルダがあります: recordings/と views/.と. recordings/フォルダには Voice API WebSockets 接続からの通話記録が保存されます。.フォルダは、アプリケーションの1つのビューを保存する場所です。 views/フォルダは、アプリケーションの1つのビューを保存する場所です。
依存関係の定義
の中に Gemfileに、アプリケーションで使用する以下のgemを追加する:
source 'https://rubygems.org'
gem 'wavefile'
gem 'faye-websocket'
gem 'json'
gem 'rack'
gem 'thin'それぞれの宝石は特定の機能を果たす:
Wavefile:このgemを使って、生のオーディオデータをWAVファイルに変換します。
Faye: このgemを使ってWebSockets接続を処理します。
JSON: このgemは、Vonage Voice APIに送り返す通話命令をJSONに変換するために使用されます。
Rack: ウェブ・フレームワークとして Rack を使用します。
薄い:このgemは、Rackの上にWebサーバを提供します。
コマンドラインから bundle installをコマンドラインから実行することで、これらのgemをすべてアプリケーションで利用できるようになります。
サーバーの構築
依存関係と変数の定義
これでウェブ・サーバーを構築する準備が整った。サーバーの構築で最初にすることは、いくつかの requireと includeステートメントを追加することです:
require 'rack'
require 'erb'
require 'faye/websocket'
require 'json'
require "wavefile"
include Rack
include WaveFileこの時点で、WebSockets接続リクエストの外部アクセス可能なURLと等しい定数変数も定義します。このURLは、Vonage Voice APIに新しいコールを受信したときに送り返す命令で使用します:
EXTERNAL_WS_URL = 'ws://example.com/cable'上記のスニペットの example.comを外部からアクセス可能なURLに置き換えてください。
ヘルパーメソッド
このアプリケーションでは、2つのヘルパー・メソッドを利用する。今すぐ作成して、定数変数宣言の後に追加すればいい。
最初の方法です、 #create_wav_fileは、WebSocketを通じて受信したバイナリオーディオデータをWAVファイルに変換するプロセスを支援します。Wavefile gemの機能を利用してWAVファイルを作成し、後でアプリケーションで使用するファイル名を返します:
def create_wav_file(data, file_name)
buffer = Buffer.new(data, Format.new(:mono, :pcm_16, 16000))
puts "Audio Buffer Created..."
writer = Writer.new(file_name, Format.new(:mono, :pcm_16, 16000))
puts "New Audio File Created..."
puts "Writing to the Buffer..."
writer.write(buffer)
puts "Closing Buffer Writing..."
writer.close
puts "WAV File Created..."
file_name
end上記のメソッドは、入力される音声が monoソースではなく stereoソースからのものであることを指定します。違いは、データの配列の配列ではなく、バイナリデータのフラットな配列で定義された単一のオーディオトラックがあることです。オーディオは pcm_16これはソースがリニアPCM 16ビットであることを意味する。最後に、ソースは 16000これはサンプルレートが16KHzであることを意味する。新しいWAVファイルは、オーディオ・バイナリ・ソース・データと同じオーディオ設定で作成されます。
番目のメソッド、 #erbは、ERBテンプレート・ファイルをユーザーにレンダリングするために使う短いメソッドである:
def erb(template)
path = File.expand_path("#{template}")
ERB.new(File.read(path)).result(binding)
end残りのコードは、一連の mapステートメントで構成される。 Rack::Handlerミドルウェアにラップされます。
ルートの定義
アプリケーションのルートは、RackとThinをつなぐRackミドルウェアの内部で定義する必要があります。また Rack::Staticミドルウェアを使います。Faye WebSocketハンドラもここで初期化します:
Rack::Handler::Thin.run(Rack::Builder.new {
Faye::WebSocket.load_adapter('thin')
use(Rack::Static, urls: ["/recording"], root: 'recording')次の4つのルートを構築する必要がある。 mapステートメントを構築する必要があります: /cable, /, /webhooks/answerそして /webhooks/answer.では、それをやってみよう。
最初のルートはWebSocket接続を処理する:
map('/cable') do
run(->env{
if Faye::WebSocket.websocket?(env)
puts "WebSockets connection opened..."
@call_data = []
ws = Faye::WebSocket.new(env)
ws.on :message do |event|
if event.data.is_a?(Array)
@call_data.append(event.data.pack('c*').unpack('s*'))
else
puts event.data
end
end
ws.on :close do |event|
puts 'WebSocket connection closed...'
create_wav_file(@call_data.flatten, 'recording/recording.wav')
end
ws.rack_response
end
})
end
上記のルートでは、接続リクエストがWebSocketリクエストかどうかをチェックする。もしそうであれば、新しい Faye::WebSocket.WebSocketに送信されるデータには、テキストデータとバイナリデータの2種類があります。後者は常にバイトサイズの整数を配列にした形で送信されます。
このように event.dataが配列オブジェクトかどうかをチェックすることができる。配列であれば、WAVファイルの作成に使用するバイナリ音声データであることがわかる。そうでない場合は、Vonage Voice API からのステータス更新である。この場合は、コンソールにログを記録します。
重要な注意点があります:Faye WebSockets gemは、上で述べたようにバイナリデータをバイトサイズの整数に変換します。しかしこれは、正確に1バイトまたは8ビットサイズの整数に変換することを意味します。Vonage Voice APIは音声のバイナリデータを16ビット整数で送信する。つまり、アプリケーションは8ビットのバイナリ・データを16ビットに変換する必要がある。Ruby標準ライブラリの #packと #unpackインスタンス変数 @call_dataインスタンス変数に追加します。これは、理解しやすい音声を生成するために必要なステップです。
次のルートは indexビューを提供します。ファイルがあるかどうかをチェックし、ファイルがあればインスタンス変数でそれをビューに渡します:
map('/') do
if File.exist?('recording.wav')
@call_status = 'Audio Loaded!'
@file = 'recording.wav'
end
run(->env{
[200, { 'Content-Type' => 'text/html'}, [erb("views/index.html.erb")]]})
end
この /webhooks/answerルートは Vonage Voice API に特化した NCCO (Nexmo Call Control Object) と呼ばれる命令を返します。 NCCO (Nexmo Call Control Object)と呼ばれる特別な命令を返します。JSONとして送り返す命令は、Voice APIにWebSocket接続を開きたいことを伝え、接続を開始するためのWebSocket URLを提供します。また、Voice API には、発信者に短いメッセージを話し、まもなく通話がストリーミングされることを知らせたいことも伝えます:
map('/webhooks/answer') do
run(->env{
ncco = [
{
"action": "talk",
"text": "You will be streaming momentarily."
},
{
"action": "connect",
"endpoint": [
{
"type": "websocket",
"uri": "#{EXTERNAL_WS_URL}",
"content-type": "audio/l16;rate=16000",
}
]
}
].to_json
[200, { 'Content-Type' => 'application/json' }, [ncco]]
})
end
最後に作成するルートは、Voice APIがアプリケーションに送信するコールのイベントライフサイクルデータを処理します。私たちはこのデータに対して何もしたくありません。 200ステータスコード
map('/webhooks/event') do
run(->env{
[200, { 'Content-Type' => 'text/html'}, ['']]
})
end
最後に Rack::Builderブロックを閉じる:
}, Port: 9292)アプリケーションを実行する前に作成しなければならない最後の項目は、ビューです。
ビューの作成
このアプリケーションには1つのビューしかありません。このビューにはアプリケーションのルートURL、つまり localhost:9292もしくは 127.0.0.1:9292.このビューは、再生するオーディオを <audio>要素で表示します:
<html>
<head>
<title>Ruby Vonage WebSockets Demo</title>
</head>
<body>
<h1>Vonage WebSockets + Ruby == ♥</h1>
<p>Welcome to the Vonage WebSockets demo in Ruby</p>
<h2>Your Audio To Playback</h2>
<p>Once you have finished your call, your audio will be available to playback from here.</p>
<div id="audio-status">
<%= @call_status %>
<br />
<% if @file %>
<audio
controls
src="recording/<%= @file %>">
Your browser does not support the
<code>audio</code> element.
</audio>
<% end %>
</div>
</body>
</html>
ビューはルートで作成したインスタンス変数を使って <audio>要素を表示するかどうかを決定します。
これでアプリケーションを実行する準備ができた!
アプリケーションの実行
これでアプリケーションを実行する準備が整いました。実行するには、アプリのルート・フォルダーでコマンドラインから以下を実行する:
また、ngrokや同様のツールを使って、ウェブサーバーが外部からアクセス可能であることを確認することも忘れずに。
この時点で、Vonageバーチャル電話番号に電話をかけて、アプリケーションに電話をかけます。話し終わったら、電話を切ることができます。ウェブブラウザでアプリにアクセスすると、オーディオプレーヤーが表示され、録音した音声が再生されます。おめでとうございます!
さらに読む
このチュートリアルでは、Vonage Voice API の WebSockets 機能を Ruby で使えるようにするための基本的な機能を紹介しました。この機能でできることはまだまだたくさんあります。Vonage Voice API WebSockets についてもっと知りたい方は、以下をご覧ください: