プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

Twilio 電話を受けたら録音して、メールを飛ばす

以前、こちらの記事で、 Twilio を使って受付用留守番電話を作るというのを試しました。 せっかく受付用留守電を作っても、このままだといちいち Twilio のコンソールを見ないとわからないので現実的ではないです。

ということで、こちらの記事で試したFAX受信時のメール送信と同様に、留守電に録音されたらメールを飛ばすようにしたいと思います。

留守番電話が録音されたら、メールを飛ばす

基本的な考え方は、FAXを受信したらメールを飛ばすのと同じです。

メール送信用 Function の作成

まずは、留守電があったら呼び出される Functions を作成しておきます。 内容的には、FAX送信時と大して変わりませんが、メールの添付ファイルとして指定するのが、FAXの文面ではなく、録音した音声データになります。

サンプルコードは、こちらのGist, 下記修正前のリビジョン を参照してください。

メール送信用 Function の呼び出し設定

Functions を作成したら、次は、メール送信 Function の呼び出し設定を行います。

これは、TwiML の Record 動詞recordingStatusCallback 属性を使えば、録音が利用可能となったタイミングで指定されたURLを呼び出すことで実現できます。

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say language="ja-JP">録音します。録音が終了したらシャープを押してください。</Say>
  <Record action="https://handler.twilio.com/twiml/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 
          recordingStatusCallback="https://xxxxxxxxxxxxxxxxxx.twil.io/function名" />
</Response>

こうすることで、録音が終わり、そのデータが利用可能になった時点で、recordingStatusCallback で指定されたURLが呼び出されます。 なお、以前の記事と同様に、actionで指定されたURLは録音後間違いなく電話が切れるように、hugup動詞のみのTwiMLを指定します。

テスト

さあ、試しましょう。 電話をかけて、適当に録音して、メールが来ているか確認します。

メールを確認すると、

f:id:junichim:20190221145307p:plain

問題なく受信できてました。と思いきや、電話をかけてきた相手の電話番号が表示されていません。

あれ?どうなっているんや?

ということで、リファレンスを調べてみると、どうも recordingStatusCallback で送る時は、発信元の電話番号とかの情報は送られていないようです。

これってどうしたらいいんだろうか?としばし考えたのですが、よくわからなかったので、Twilio のサポートに聞いてみると、CallSid を使って通話の情報を取得してください、とのことでした。 ま、考えてみりゃそういうことか。

発信元電話番号の取得

ということで、メール送信前に、発信元電話番号を取得して、それをメールのタイトルに入れるようにします。

まず、Function が呼ばれた時に、どういう情報が送られているのかを確認します。

debug:context: {
     "ACCOUNT_SID":"ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ,"DOMAIN_NAME":"yyyyyyyy-yyyyyyyy-yyyyyyyyy.twil.io"
}
debug:event: {
     "RecordingSource":"RecordVerb"
    ,"RecordingSid":"RExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ,"RecordingUrl":"https://api.twilio.com/2010-04-01/Accounts/ACxxxxxxxxxxxxxxxxxxxxxxx/Recordings/RExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ,"RecordingStatus":"completed"
    ,"RecordingChannels":"1"
    ,"ErrorCode":"0"
    ,"CallSid":"CAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ,"RecordingStartTime":"Sat, 16 Feb 2019 07:42:24 +0000"
    ,"AccountSid":"ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ,"RecordingDuration":"3"
}

(頭の debug:event 等はconsole.logに埋め込んだ文字です) 引数の event の中身を確認すろと、先ほど見た、 recordingStatusCallback のリファレンスの通りになっています。 そこで、この CallSid が通話を識別するSidなので、これを使って Call Resource を取得して、表示させれば良さそうです。

具体的には、Fetch a Call Resource APIを呼びます。

このAPIのリファレンスのサンプル(例えば、node.js)を見るとわかるように、このAPIを呼ぶためには、Twilio client が必要なのですが、Twilio client を生成するには AUTH_TOKEN が必要です。 なお、先ほど Function が呼ばれた際のパラメータを見てもわかるように AUTH_TOKEN は返してくれません。

そこで、 Function の引数にAUTH_TOKEN を渡すようにするために、Functions の設定を変更して、 AUTH_TOKEN を渡すようにします。

f:id:junichim:20190221150452p:plain

設定変更後、渡されたパラメータを確認すると、

debug:context:{
     "AUTH_TOKEN":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ,"ACCOUNT_SID":"ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ,"DOMAIN_NAME":"xxxxxxxxxxxxxxxxxxxxx"
}

のように AUTH_TOKENが渡ってきているのが確認できました。

ただし、この設定は、そのアカウント(上記の場合はサブアカウント)で管理しているすべての Function について共通のようなので、その点は少し注意が必要かもしれません。

AUTH_TOKEN が取得できるようになったので、リファレンスと同様に電話番号を取得します。 あとは、これとメール送信を Promise でつなげれば終わりです。

最終的に こちらのGist のようにして、発信元の電話番号を取得します。

確認

もう一度試します。 電話をかけて、適当に録音して、メールを確認すると、

f:id:junichim:20190221151611p:plain

こんどは、電話をかけてきた相手の電話番号も無事表示されています。

さいごに

基本的な動作は FAX の時と同じでしたが、処理の呼び出し時に受け取れるパラメータの内容が微妙に異なっているのに少しはまりました。 でも、これで、留守電も使えるようになったので、とりあえずは満足です。