LoginSignup
9
4

More than 5 years have passed since last update.

仕組みから理解するTwilio #2 - 通信フロー・データ構造

Last updated at Posted at 2016-10-15

この記事は下記記事の続きです。一連の記事で独自に定義している用語等がありますので、先にこちらを読むことを推奨いたします。
仕組みから理解するTwilio #1 - はじめに

ここでは、Twilioを利用する際の通信フローや、授受されるデータ構造について説明します。

  • 1. はじめに
    • 1. Twilio利用時の基本構成・用語の定義
    • 2. 今回検証した環境
  • 2. 通信フロー・データ構造 ←いまココ
    • 1. 認証・CapabilityToken授受
    • 2. 外部電話からTwilioクライアントへのCall(IncomingCall)
    • 3. Twilioクライアントから外部電話へのCall(OutgoingCall)
  • 3-1. AWS API Gateway+Lambda実装Walkthrough(前編)
    • 1. API Serverの処理の実装(Python on AWS Lambda)
    • 2. API Gatewayの設定
  • 3-2. AWS API Gateway+Lambda実装Walkthrough(後編)
    • 3. Twilio Clientの実装とデプロイ
    • 4. 動作確認!

今回実現するTwilio Clientは、まずは通常の電話と同じことができることを目指しました。
具体的な仕様は以下となります。

  • 出来ること
    • Twilio Clientから、任意の番号を指定して一般の電話にかけることができる(アウトバウンド通話)
    • 一般の電話からTwilio Clientに電話をかけることができる(インバウンド通話)
  • Twilio Clientの仕様
    • 自身を識別する値として、Twilio電話番号のみ保持する。自身のClient Nameは保持しない。
    • HTML/JavaScriptで実装され、S3上に配置される。

電話番号等のパラメータは下記であると仮定します。

パラメータ 説明・備考
Twilio電話番号 050-3123-4567 Twilio Clientに割り当てた電話番号。Twilioコンソールから事前に購入しておいて下さい。
Client Name DeviceId_0001 Twilio Server内で当該Twilio Clientを識別・制御するための名前。
外部の電話 090-5987-6543 Twilio外の電話。ご自身の携帯電話等を利用してください。

認証・CapabilityToken授受

処理フロー

まず、下記の図をご覧ください。
TwilioDiagrams_Fig2-1.png

処理のフローは下記のようになります。

  • 1-1. Capability Tokenの取得リクエスト
    • Twilio ClientはAPI Serverに対し、Capability Tokenを取得するためのリクエストを行います。
    • API ServerはTwilio Clientから送信された情報をもとに、必要に応じて認証・認可を行います。
  • 1-2. Capability Tokenの返却
    • API Serverは、Capability Tokenを生成し、Twilio Clientに返却します。
    • この際、当該Capability Tokenを利用して何ができるか(電話をかけることができる/受けることができる)、Twilio ClientのClient Name、有効期限といった情報が付与されます。
  • 1-3.Twilio Clientのセットアップ

1-1及び1-2の間の通信方式の実装は、完全にユーザに任されています。通信にHTTP/HTTPS及びそれ以外のプロトコルを使うことも可能です。

データ構造も完全に任意です。
Twilio Clientから送信する情報には、Twilio Clientを識別するための情報として、ユーザー名やパスワードやその他情報を利用することができます。任意の認証・認可を実現することも可能です。
API Serverから返却される情報としてCapability Tokenは必須ですが、他にも任意の情報を返却することが可能です。

今回の検証では、リクエスト・レスポンスともJSONで実装しました。具体的なデータ構造は下記のとおりです。

リクエストはシンプルに、Twilio電話番号のみとしました。指定されたTwilio電話番号が取得済みのものであれば認証成功とします。
{"twilioPhoneNumber": "+81-50-1234-9876"}

レスポンスは、Capability Token及び処理の成否としました。
{"capabilityToken": capabilityToken, "success": True}

1-3の通信については未検証です。詳細は不明です。JavaScriptクライアントの場合はWebSocketを利用し、CapabilityToken等の情報をTwilio Serverに送信しているようです。
Twilioが提供する各種SDKから初期セットアップが行われるため、通常はユーザーが意識する必要はありません。
# ただし、トラブルシュート時にはこの情報が必要になるケースはあり得ると思いますが。

Capability Tokenの作成・データ構造

API Serverでは、TwilioのHelperライブラリを利用してCapability Tokenを生成します。

Python2.7での実装をもとに説明します。必要なライブラリ類は既にインストール済みで、利用できるものとします。
https://www.twilio.com/docs/libraries/python#help
また、Twilioアカウントを開設済みでありAccount SID及びAuth Tokenは確認済みであること、TwiML Appを作成しApp SIDを確認済みであることとします。

    from twilio.util import TwilioCapability
    import json

    def generate_capability_token(twilio_phone_number):

        # 必要なパラメータを設定します。
        twilio_account_sid = "{{twilio_accound_sid}}"  # TwilioアカウントのSIDを指定します。
        twilio_auth_token = "{{twilio_account_auth_token}}" # Twilioアカウントに紐付くAuth Tokenを指定します。
        twilio_app_sid = "{{twilio_app_sid}}"  # 事前に作成したApp Sidを指定します。
        expiration_time_for_capability_token = 3600  # Capability Tokenの有効期限を指定します。

        # Capability Tokenを生成し、必要な権限を付与します。
        capability = TwilioCapability(twilio_account_sid, twilio_auth_token)
        capability.allow_client_incoming(get_client_name_by_phone_number(twilio_phone_number)) # 指定されたTwilio電話番号をもとに、Twilio Client Nameを取得します。get_client_name_by_phone_numberは自分で個別に実装した関数です。
        capability.allow_client_outgoing(twilio_app_sid)
        capabilityToken = capability.generate(expiration_time_for_capability_token)

        # 既定の構造に変換し、返却します。
        res = {"capabilityToken": capabilityToken, "success": True}
        return json.dumps(res)

基本的には下記ドキュメントに従った実装となります。
Generate Capability Tokens
http://twilio-python.readthedocs.io/en/latest/usage/token-generation.html

TwilioアカウントSIDとAuth TokenをもとにTwilioCapabilityを生成した後、allow_client_incoming及びallow_client_outgoingメソッドで権限を付与していきます。
最後にTwilioCapabilityのgenerateメソッドを実行することで、Capability Tokenを生成することができます。引数には有効期限を秒単位で指定することができます。

Capability Tokenの詳細は下記ドキュメントにあります。

Twilio Client: Capability Tokens
https://www.twilio.com/docs/api/client/capability-tokens

Capbility TokenはJWT(Json Web Token)形式です。生成の際にはTwilio Serverとの通信は必要としません。
未検証ですが、恐らく必要な情報をJSON化し、Auth Tokenで電子署名を生成して付与したのち、Base64デコードしているものと推測されます。

ここで重要なポイントは下記のとおりです。
- Twilio Clientから電話をかけるための権限と、Twilio Clientで電話を受けるための権限が違うこと
- Twilio Clientから電話をかけるための権限は、TwiML appのApp sidで指定すること
- Twilio Clientで電話を受けるための権限は、Client Nameで指定すること

次から、Twilio Clientと他の電話との通話の仕組みを見ていきます。

外部電話からTwilioクライアントへのCall(IncomingCall)

処理フロー

まず、下記の図をご覧ください。
TwilioDiagrams_Fig2-2.png

また、Twilioアカウントをセットアップし電話番号を取得した際に設定したURLを思い出してください。
「A CALL COMES IN」で指定したURLは、電話を受ける際に利用されます。
2016-10-16_03h52_20.png

処理のフローは下記のようになります。TwiMLの取得は受信先のTwilio電話番号に設定されたURLが利用されます。

  • 2-1. 実際の電話からTwilio Clientへ電話をかける
    • 実際の電話から、Twilio Clientに紐付けられたTwilio電話番号に対し、電話をかけます。
    • 当然ですが、電話をかける際にTwilio ClientのClient Nameを指定することはできません。
  • 2-2. Twilio ServerからAPI ServerへのTwiML取得リクエスト
    • Twilio Serverは、call対象となった電話番号の「A CALL COMES IN」に指定された通りにHTTPリクエストを発行します。
    • 渡されるパラメータとして重要なものは、発信元の電話番号と受信先のTwilio電話番号です。
  • 2-3. API ServerからTwilio ServerへTwiMLを返却する
    • API Serverは、パラメータとして渡されたTwilio電話番号をもとに、これに紐付くClient Nameを取得する必要があります。
    • Client Nameが取得でき次第、TwiMLを生成して返却します。
  • 2-4. Twilio ServerはTwiMLに書かれた内容を実行する。
    • TwiMLには、指定されたClient Nameに電話をつなげるよう指示があります。
    • 発信元の電話をTwilio Clientにつなぎます。

API Serverから返却するべきTwiML

項番2-3で、API Serverから返却されるTwiMLは下記のようになります。
このTwiMLは、指定されたTwilio Clientに電話をかけることを意味しています。

<?xml version="1.0\" encoding="UTF-8"?>
<Response>
  <Dial timeout="60">
    <Client>DeviceId_0001</Client>
  </Dial>
</Response>

<Client/>エレメントには、Twilio電話番号そのものを指定することができません。
Twilio電話番号に紐付くTwilio Clientの、Client Nameを入れる必要があります。
# ここでは仮に「DeviceId_0001」としています。

従ってAPI Serverは、項番2-3において、受信先のTwilio電話番号情報をもとに、Client Nameを取得する必要があります。予めDBなどに紐付け情報を保存しておき、TwiML生成時に取得するのが良いでしょう。

なお、TwiMLでは様々な制御を行うことが可能です。詳細は公式ドキュメントを参照してください。

https://www.twilio.com/docs/api/twiml/dial
https://www.twilio.com/docs/api/twiml/client

Twilio ServerからのHTTP POSTリクエスト

Twilio ServerからAPI Serverへのリクエストは少し特殊です。
また、公式ドキュメントには詳しい情報が見当たりませんでした。以下はパケットキャプチャした情報をもとに説明します。

2016-10-16_04h19_49.png

上図はTwilio ServerからのHTTP POSTリクエストをパケットキャプチャしたものです。
ポイントは下記のとおりです。

  • Content-Type:はapplication/x-www-form-urlencodedであること
  • パラメータは、HTTPリクエストBodyに「&」で連結されたKey Valueペアで、1行で指定されること(GETパラメータのような形式)
  • HTTPリクエストBody内の各パラメータはURLエンコードされていること

各パラメータの詳細を見ていきましょう。
発信元の電話番号を「090-5987-6543」、受信先のTwilio電話番号を「050-3123-4567」としています。

パラメータ 説明(推測ベース)
AccountSid=AC3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx TwilioアカウントのSID。
ApiVersion=2010-04-01 TwilioのAPIのバージョンか?
Called=%2B815031234567 受信先のTwilio電話番号。E.164形式。Toと同一の値が入る模様。
CalledCity=
CalledCountry=JP
CalledState=
CalledVia=05031234567 不明。Twilio内で電話転送された場合に利用されるものか?
CalledZip=
Caller=%2B819059876543 発信元の電話の電話番号。Fromと同一の値が入る模様。
CallerCity=
CallerCountry=JP
CallerState=
CallerZip=
CallSid=CA86nnnnnnnnnnnnnnnnnnnnnnnnnnnnnn 当該通話に付与されるUniqueなIDか?
CallStatus=ringing
Direction=inbound 通話の方向か?
ForwardedFrom=05031234567 不明。Twilio内で電話転送された場合に利用されるものか?
From=%2B819059876543 発信元の電話の電話番号。E.164形式。Callerと同一の値が入る模様。
FromCity=
FromCountry=JP
FromState=
FromZip=
To=%2B815031234567 受信先のTwilio電話番号。Calledと同一の値が入る模様。
ToCity=
ToCountry=JP
ToState=
ToZip=

ここで重要なパラメータは、Caller/From/Called/Toの4つと考えられます。
API Server内で、この情報をもとにTwiMLを生成します。

PythonのQuick Startアプリは、発信元の情報としてCallerを、受信先の情報としてToを利用しているようです。そのためIncoming Call用TwiML返却APIの実装も、このパラメータを利用するようにします。

Twilioクライアントから外部電話へのCall(OutgoingCall)

処理フロー

まず、下記の図をご覧ください。
TwilioDiagrams_Fig2-3.png

また、Twilioアカウントをセットアップし、TwiML Appを作成した際に設定したURLを思い出してください。
2016-10-16_05h14_56.png

処理のフローは下記のようになります。TwiMLの取得はTwiML Appに設定されたURLが利用されます。

  • 3-1. Twilio Clientから発信リクエストを行う
  • 3-2. Twilio ServerからAPI ServerへのTwiML取得リクエスト
    • Twilio Serverは、CapabilityTokenに紐付けられたTwiML Appの、「REQUEST URL」に指定された通りにHTTPリクエストを発行します。
    • 渡されるパラメータとして重要なものは、Twilio ClientのClient Name、発信先電話番号、Twilio Clientから渡されたパラメータです。
  • 3-3. API ServerからTwilio ServerへTwiMLを返却する。
    • API Serverは、パラメータとして渡された情報をもとに、発信元となるTwilio電話番号、発信先の電話番号を取得する必要があります。
    • 必要な情報を取得でき次第、TwiMLを生成して返却します。
  • 3-4. Twilio ServerはTwiMLに書かれた内容を実行する。
    • Twilio Clientからの電話を、実際の電話につなぎます。

API Serverから返却するべきTwiML

項番3-3で、API Serverから返却されるTwiMLは下記のようになります。
発信元のTwilio電話番号を「050-3123-4567」、発信先の電話番号を「090-5987-6543」としています。

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial timeout="60" callerId="+81-50-3123-4567">
    <Number>+81-90-5987-6543</Number>
  </Dial>
</Response>

<Number/>エレメントには、発信先の電話番号を指定します。
<Dial/>エレメントのcallerId属性には、必ずTwilio電話番号を指定する必要があります。
https://jp.twilio.com/docs/api/twiml/dial#examples-3

Twilio ServerからのHTTP POSTリクエスト

公式ドキュメントには詳しい情報が見当たりませんでした。以下はパケットキャプチャした情報をもとに説明します。
2016-10-16_05h30_26.png

各パラメータの詳細を見ていきましょう。
なお、Twilio Clientからconnectを実行した際、下記のパラメータを付与しています。

  • callerPhoneNumber: 発信元となる、自分自身に紐付けられた電話番号。
  • callOutgoingPhoneNumber: 発信先となる、実際の電話番号。
パラメータ 説明(推測ベース)
AccountSid=AC3exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx TwilioアカウントのSID。
ApiVersion=2010-04-01 TwilioのAPIのバージョンか?
ApplicationSid=AP75zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz CapabilityTokenに紐付けられたTwiML AppのSID
Called=
Caller=client%3ADeviceId_0001 発信元のTwilio ClientのClient Name。
CallSid=CA06nnnnnnnnnnnnnnnnnnnnnnnnnnnnnn 当該通話に付与されるUniqueなIDか?
CallStatus=ringing
Direction=inbound
From=client%3ADeviceId_0001 発信元のTwilio ClientのClient Name。Callerと同一の値が入る模様。
To=
callerPhoneNumber=%2B81-50-3123-4567 Twilio Clientで指定したカスタムパラメータ
callOutgoingPhoneNumber=%2B81-90-5987-6543 Twilio Clientで指定したカスタムパラメータ

デフォルトで、Caller及びFromにClient Nameが設定されます。
必要に応じて、Twilio Clientの実装の中で必要なパラメータを指定することが可能です。
前述したとおり、Twilio ClientがCapability Tokenを取得する際の通信において、API Serverから任意の値を返すことができますので、ここでconnect時に必要なパラメータを渡しておくこともできます。

最後に

通信フロー・データ構造は以上となります。
次からはいよいよ実装に入っていきます。
AWS API Gateway+Lambda実装Walkthrough(前編)

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4