This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 5 years have passed since last update.

Twilioハンズオン Vol.2

Last updated at Posted at 2016-07-10
1 / 38

本日の資料

以下にアップされています(限定公開URL)
http://goo.gl/q2HXW6


Vol.2の目的

音声通話のノウハウを習得しよう

  • コール(呼)とは何かを理解します
  • キューやカンファレンスなどの機能を理解します
  • コールがデザインできるようになります
参考
  • Vol.1 Twilioのことをよく知ろう(終了)
  • Vol.3 TwilioベースにクラウドPBXを作ろう

プロモーションアカウントについて

  • トライアルアカウントではありません
  • 一定額のポイントがチャージされています
  • 利用規約に同意していただく必要があります
  • ハンズオン終了後も使い続けられます
  • メールアドレスとパスワードを変更してください
  • vol.3でも引き続き使います

CPIサーバーアカウントについて

  • SSH秘密鍵のセットアップが必要です
  • 各自の仮想環境が提供されています
  • ユーザ名、ドメイン名を忘れないようにしてください
  • 8月末まで使うことができます
  • vol.3でも引き続き使います

アジェンダ

  • コール(呼)の基本
  • コールの状態を変更する
  • コールログ
  • キュー
  • カンファレンス
  • コールをデザインする

自己紹介

髙橋克己(たかはしかつみ)

(株)KDDIウェブコミュニケーションズ
Twilio事業部 ソリューションアーキテクト

katsumi.takahashi@kddi-web.com

CPIサーバーのセットアップ

  • 秘密鍵のダウンロード(ダウンロード先は講師の指示に従ってください)
  • 秘密鍵のセットアップ http://goo.gl/64pg0F
  • SSH接続の確認

コール(呼)の基本

  • Twilioにおける通話の単位
  • 状態を持つ
  • コール単位にログが記録される

コールの生成方法

  • RestAPIのCalls.POSTで作成する
php
<?php
require_once('./twilio-php/Services/Twilio.php');

$sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; 
$token = "your_auth_token"; 
$client = new Services_Twilio($sid, $token);

$call = $client->account->calls->create(
"発信元番号", "発信先番号", 
"http://demo.twilio.com/docs/voice.xml", array());
echo $call->sid;
  • <Dial>動詞で生成する(転送する)
TwiML
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial callerId="発信者番号">
    <Number url="http://demo.twilio.com/docs/voice.xml">
      発信先番号
    </Number>
  </Dial>
</Response>

コールの状態

  • コールには以下の状態が存在します
    スクリーンショット 2016-07-10 15.57.31.png

  • queued: Twilioの発信キューに入っている状態

  • initiated: キャリアに向けて発信作業中

  • ringing: 相手先を呼出中

  • in-progress: 相手が応答している状態

  • completed: 通話が終了している状態


コールの状態を取得する

  • statusCallbackというWebHookを利用
  • 取得したいイベント(Initiated/Ringing/Answed/Completed)を指定
  • Completedイベント以外は有料(0.015円/イベント)
  • statusCallbackを持つもの
    • <Dial><Number>
    • <Dial><Client>
    • <Dial><Conference>
    • <Dial><Sip>
    • <Sms>
    • RestAPIのCalls.POST
    • RestAPIのCalls.CallSid.POST

コールの結果

  • コールのCallStatusパラメータ
  • <Dial>のactionUrlで取得
  • statusCallbackのcompletedイベントで取得
  • 代表的なコールの結果には以下の5つがあります。
    • completed: 相手が応答し、通話が正常に終了
    • busy: 相手からビジー信号を受信
    • failed: 通話を接続できませんでした
    • no-answer: 相手が応答せず、通話が終了
    • canceled: queued または ringing 中に、通話がキャンセル

実習1(statusCallback)

statusCallbackがどのタイミングで発行されるかを確認してみましょう。

  1. サーバーにSSHでログインします。
  2. 実習の準備をします。
sh
% cd
% git clone https://github.com/twilio/twilio-php.git
% git clone https://github.com/twilioforkwc/hands_on_2016_vol2.git
% cp hands_on_2016_vol2/practice001/statusCallback.php ./html/
% chmod 705 html/statusCallback.php
% cp hands_on_2016_vol2/status.txt ./

~/html/statusCallback.php
#!/usr/local/bin/php-cgi-7.0
<?php
  $param = $_POST["CallStatus"] . "\n";
  $file = '../status.txt';
  file_put_contents($file, $param, FILE_APPEND);
?>
<!DOCTYPE html>
<html><body>OK</body></html>

status.txtをリアルタイムで監視します。

sh
% cd
% tail -f status.txt

次に、管理コンソールから次の作業を行います。

1.TwiML Binsで以下のTwiMLを作ります。
TwiML
<Response>
  <Dial callerId="購入済み番号">
    <Number 
statusCallbackEvent="initiated ringing answered completed" 
statusCallback="http://twilio:twilio@ドメイン名.secure.ne.jp/statusCallback.php" 
statusCallbackMethod="POST">ご自分の電話番号</Number>
  </Dial>
</Response>
2.TwiML Appsを作成します。

上で作成したTwiML BinsのURLを呼び出すTwiML Appsを適当な名前で作成します。

3.テスト

TwiML Appsを保存して、再度開くと、管理コンソール上から発信テストができます。
サーバー上のstatus.txtに、statusCallbackEventで指定したタイミングでWebHookが来ることを確認します。


コールの状態を変更する

  • 通話中のコールに別のTwiMLを実行する
  • RestAPI経由でコールを制御する
  • Calls.CallSid.POST
  • 利用シーン
    • 通話中の呼を強制切断
    • 通話中の呼に割り込み

実習2(コールの強制終了)

通話中のコールを強制的に切断してみます。
デザインパターン(強制終話) (1).png

  • 050番号に着信したら、<Play>動詞で音を再生
  • 同時に、非同期で10秒待ってから切断するRestAPIを実行

手順
1. サーバーにSSHでログインします。
2. 以下のコマンドで準備をします。

sh
% cd
% cp hands_on_2016_vol2/practice002/*.php ./html/
% chmod 705 html/*.php
% vi html/callDisconnect.php

$sidと$tokenに、ご自分のAccountSidとAuthTokenを記入します。
:wq で保存

実習で利用するのは以下の2つのphp

playMusic.php
#!/usr/local/bin/php-cgi-7.0
<?php
    header("content-type: text/xml");
    echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    $callSid = $_POST["CallSid"];
    exec("nohup php-7.0 -c '' 'callDisconnect.php' $callSid > /dev/null &");
?>
<Response>
    <Play loop="0">https://api.twilio.com/cowbell.mp3</Play>
</Response>
callDisconnect.php
#!/usr/local/bin/php-cgi-7.0
<?php
  require_once('../twilio-php/Services/Twilio.php');
  # Todo: Replace XXX... to your AccountSID and token
  $sid = "ACXXXXXXXXXXXX";
  $token = "XXXXXXXXXXXXXXX";
  $client = new Services_Twilio($sid, $token);
  sleep(10);
  $callSid = $argv[1];
  $call = $client->account->calls->get($callSid);
  $call->hangup();
?>

3.着信URLを設定する

保有している050番号に着信WebHookの設定を行います。
http://twilio:twilio@ドメイン名.secure.ne.jp/playMusic.php

4.テスト

050番号に電話をかけると、カウベルの音がなり、10秒経つと電話が強制的に切れることを確認します。


コールログ

  • コールを記録しているログ
  • ログは削除しないかぎり永久に残る
  • 削除するにはRestAPI(1件ずつ)
  • 課金情報の更新には少し時間が必要

コールログの構成


コールログを取得する

  • コンソールからCSV形式でダウンロード
    • 抽出できる項目(Sid,AccountSid,StartTime,EndTime,Duration,From,To,Direction,Status,ApiVersion,Price,PriceUnit)
  • RestAPI経由でダウンロード
    • すべての項目(ドキュメントに書かれていない項目も含めて)が取得可能
ログサンプル
{ sid: 'CAf3f2e82e5b414881be5090e4ddb69dc2',
  date_created: 'Sat, 25 Jun 2016 10:51:37 +0000',
  date_updated: 'Sat, 25 Jun 2016 10:52:09 +0000',
  parent_call_sid: 'CA4b793333626b46e8ca0451a831baa727',
  account_sid: 'AC16fbca5fa1ee7376ac748c2e737f3547',
  to: '+81904532XXXX',
  to_formatted: '+81904532XXXX',
  from: '+81503188XXXX',
  from_formatted: '+81503188XXXX',
  phone_number_sid: 'PN226b1dca9d40f7a290bed7592e1eca75',
  status: 'completed',
  start_time: 'Sat, 25 Jun 2016 10:51:48 +0000',
  end_time: 'Sat, 25 Jun 2016 10:52:09 +0000',
  duration: '21',
  price: '-16.20000',
  price_unit: 'JPY',
  direction: 'outbound-dial',
  answered_by: null,
  api_version: '2010-04-01',
  annotation: null,
  forwarded_from: '0503188XXXX',
  group_sid: null,
  caller_name: null,
  uri: '/2010-04-01/Accounts/AC**********/Calls/CAf3f2e82e5b414881be5090e4ddb69dc2.json',
  subresource_uris:
   { notifications: '/2010-04-01/Accounts/AC**********/Calls/CAf3f2e82e5b414881be5090e4ddb69dc2/Notifications.json',
     recordings: '/2010-04-01/Accounts/AC**********/Calls/CAf3f2e82e5b414881be5090e4ddb69dc2/Recordings.json' },
  dateCreated: Sat Jun 25 2016 19:51:37 GMT+0900 (JST),
  dateUpdated: Sat Jun 25 2016 19:52:09 GMT+0900 (JST),
  parentCallSid: 'CA4b793333626b46e8ca0451a831baa727',
  accountSid: 'AC**********',
  toFormatted: '+81904532XXXX',
  fromFormatted: '+81503188XXXX',
  phoneNumberSid: 'PN226b1dca9d40f7a290bed7592e1eca75',
  startTime: Sat Jun 25 2016 19:51:48 GMT+0900 (JST),
  endTime: Sat Jun 25 2016 19:52:09 GMT+0900 (JST),
  priceUnit: 'JPY',
  answeredBy: null,
  apiVersion: '2010-04-01',
  forwardedFrom: '0503188XXXX',
  groupSid: null,
  callerName: null,
  subresourceUris:
   { notifications: '/2010-04-01/Accounts/AC**********/Calls/CAf3f2e82e5b414881be5090e4ddb69dc2/Notifications.json',
     recordings: '/2010-04-01/Accounts/AC**********/Calls/CAf3f2e82e5b414881be5090e4ddb69dc2/Recordings.json' } }

キュー


キューとは

  • コールを一時的に待機させておく領域
  • キューの利用料は無料
  • 待機呼には上限あり(初期値は100、Maxで1,000)
  • 待機呼はメンバーとして管理
  • 平均待ち時間や待機呼の数を取得可能

キューのしくみ

キューのしくみ.png

  • <Enqueue>動詞でキューに入れます。
  • <Dial>でキューから取り出します(FIFO)。
  • <Leave>動詞でキューを<Enqueue>の直後に戻します。

キューに入れる

  • <Enqueue>動詞でキューに入る
  • キュー名を指定可能(なければ自動作成)
  • WaitUrlでキューに入った時の動作を定義可能
  • WaitUrlで指定できるのは、<Play>, <Say>, <Pause>, <Hangup>, <Redirect>, <Leave>, <Gather>
  • WaitUrlはキューにいる間は繰り返し呼ばれる(コール単位)

WaitUrlで状態を把握する

  • WaitUrlで渡されるパラメータ
    • QueuePosition: 現在のキューの位置(1〜)
    • QueueSid: キューのSid
    • QueueTime: キューに入っている時間(秒)
    • AveQueueTime: キューの平均待ち時間(秒)
    • CurrentQueueSize: キューに入っている通話の数

キューから取り出す

  • <Dial><Queue>
    • キューが空の場合、次の人がキューに入るのを待つか、タイムアウト(最大60秒)になるのを待ちます。
  • <Leave>
    • <Enqueue>動詞の次の動詞に制御を戻します。
  • RestAPI
    • Queues.QueueSid.Members.CallSid
    • Queues.QueueSid.Members.Front
  • キューから外れた理由は、<Enqueue>動詞のactionで取得できます。
    • bridged: 通話がキューから外れ、相手にブリッジされた
    • bridging-in-progress: 通話がキューから外れ、相手と通話中
    • error: エラー(waitUrlのエラーも含む)
    • hangup: 待機中の発信者が切断
    • leave: <Leave>動詞によりキューを外れた
    • redirected: RestAPIによりリダイレクトされた
    • redirected-from-bridged:
    • queue-full: キューがいっぱいで入れなかった
    • system-error: Twilio上でエラーが発生した

メンバーを管理する

RestAPIでメンバーの一覧を取得する
RestAPIでメンバーを取り出す


実習3(キューイング)

デザインパターン(キュー).png

  • 050-XXXX-XXXXに、キューに格納する処理を定義します(ただし、TwiML Appsを使うので、電話番号を用意する必要はありません)。
  • キューに入った通話には、enqueue.phpが繰り返し呼ばれ、現在の待ち位置が応答されます。
  • 050-YYYY-YYYYに、キューから取り出す処理を定義します。
手順1. 以下のTwiML BinsをEnqueue という名前で作成します。
TwiML
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Enqueue 
waitUrl="http://twilio:twilio@ドメイン名.secure.ne.jp/enqueue.php">
    testQueue
  </Enqueue>
</Response>
手順2. 以下のTwiML BinsをDequeueという名前で作成します。
TwiML
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say language="ja-JP" voice="alice">
お待ちどうさまでした。お繋ぎいたします。</Say>
</Response>

※作成したTwiML BinsのURLをコピーしておきます。

手順3. 以下のTwiML BinsをDialQueueという名前で作成します。
TwiML
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial callerId="購入済み050番号">
    <Queue url="手順2.で作成したTwiML BinsのURL">
testQueue</Queue>
  </Dial>
</Response>
手順4. サーバーに接続し、enqueue.phpを準備します。
sh
% cd
% cp hands_on_2016_vol2/practice003/enqueue.php ./html/
% chmod 705 html/enqueue.php
enqueue.php
#!/usr/local/bin/php-cgi-7.0
<?php
  header("content-type: text/xml");
  echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";

  $queuePosition = $_POST["QueuePosition"];
  $talk = "お待たせしております。現在のあなたの順番は" . $queuePosition . "番目です。";
?>
<Response>
  <Say language="ja-JP" voice="alice">
    <?php
      echo($talk);
    ?>
  </Say>
</Response>
手順5. 050番号の着信設定を行います。

購入した電話番号の着信設定で、手順3.で作成したTwiML BinsのURLを設定します。

テスト
  • 適当な名前でTwiML Appsを新規で作成し、手順1.で作成したTwiML BinsのURLを指定します。
  • 作成したTwiML Appsを開き、「発信」を押します。
  • 通話がキューに入り、現在の待ち位置が音声として流れます。
  • 手順5.で設定した050番号に電話をかけ、キューに入っているコールがブリッジされることを確認します。

カンファレンス

  • 2名以上の複数のユーザで会話をする機能
  • BasicカンファレンスとGlobalカンファレンスの2種類が存在
    • Basic: 無料、最大40名、US経由で通話
    • Global: 有料(東京0.6円/分/参加者)、最大250名、JP経由で通話
    • 切り替えはアカウント単位
  • 電話会議、コールセンターのモニターなどで利用

カンファレンスへの参加方法

  • <Dial><Conference>
  • RestAPIから直接カンファレンスには参加できない
  • 主要な属性
    • muted: 参加者の声を拾わない
    • beep: 参加者が参加、退出した際に音をならすか
    • startConferenceOnEnter: 参加した時点でカンファレンスが始まる
    • endConferenceOnExit: 退出した時点でカンファレンスが終了する
    • waitUrl: カンファレンスが始まる前に流す音楽のURL
    • maxParticipants: 参加者の上限を設定
    • statusCallback: カンファレンスに関するイベント(start/end/join/leave/mute/hold)が発生した際にWebHook

参加者の操作

  • RestAPIで参加者リストを取得
    • Conferences/{ConferenceSid}/Participants
    • 取得時点の参加者しか取得できない
  • 参加者をホールドする
    • 特定の参加者に音楽を流して、一時的に会議から外す
  • 参加者のミュートする
    • 特定の参加者のマイクをオフにする

コールをデザインする

  • TwiML動詞のフローを理解する
  • 図にして設計することが重要
  • 同期、非同期をイメージしながらデザイン
  • 電話特有の動作(話中、発信キャンセル、応答なし)を考慮

コールダイアログ

  • コールダイアグラムの紹介(https://goo.gl/fiOroP)
  • url: 相手が応答したときにHookされます
  • action: 処理が終了した時にHookされます
  • statusCallback: イベント毎に非同期でHookされます
  • 青い四角がRestAPI、グレーがTwiML、オレンジは着信

匿名通話

お互いが自分の電話番号を伝えずに通話を行う
匿名通話.png

  1. (着信転送の場合)着信したコールをキューに入れる
  2. (V字発信の場合)一人目にRestAPIで発信し、相手が応答したらキューに入れる
  3. キューに入ったコールは呼び出し中のガイダンスがループする
  4. キューに入った後で、裏側でRestAPIで相手先を呼び出す
  5. 相手先が応答すると、転送しますのガイダンスを流して、キューから呼を取り出す
  6. 相手先が応答しなかった(できなかった)場合は、waitUrlでLeaveを返すようにすることで、キューに入っていたコールを戻し、お繋ぎできませんでしたとガイダンスを流して終話
# デザインのポイント
  • 単純に転送させるだけなら、着信時のurl、もしくはV字発信でDial動詞を呼び出せば良い
  • キューを活用するメリット
    • 相手先が応答しなかった場合に、何度かリトライする
    • 相手先の状況に応じて、メッセージを変更する

択一同報発信

同時に複数の人に発信を行い、最初に取った人だけにガイダンスを流す
択一同報発信.png

  1. RestAPIで050番号に発信させる
  2. 着信設定で、<Dial>動詞を呼び出す(この時点で<Number>名詞を最大10まで指定)
  3. 最初に応答した相手に<Say>動詞でガイダンスを流す
# デザインのポイント
  • <Number>名詞は10までしか設定できない
  • RestAPIではtoを複数指定できないので、050番号を中継している
  • 留守番電話などが応答してしまう可能性もある
    • 対応策としては、<Gather>を入れて、人が応答するまで何度か繰り返す必要あり
  • <Dial>動詞に、sequential属性(非公開)があり、false(デフォルト)に設定すると一斉発信、trueに設定すると順次発信(上から1件ずつ発信)

一斉同報発信

同時に複数の人に発信を行い、応答した人すべてにガイダンスを流す
一斉同報発信 (1).png

  1. RestAPIで発信する
  2. 相手が応答したら、<Say>動詞でガイダンスを流す
  3. statusCallbackのcompletedイベントを拾って、failedかbusyかno-answerだったら、再度RestAPIでコールする
# デザインのポイント
  • 1CPSの制限あり
  • statusCallbackのCallStatusを判定してリカバリ

順序発信

複数の人に順番に発信を行い、誰かが応答した時点で終了する
順序発信.png

  1. RestAPIでコールする
  2. 相手が応答したら、<Say>動詞でガイダンスを流す
  3. 応答できる時だけキー入力をしてもらう
  4. キー入力があれば、終了
  5. キー入力がなければ、<Redirect>でRestAPIで次のコール先に発信
  6. 同時に<Hangup>を返すことで通話を切断
# デザインのポイント
  • 留守番電話対策、および対応できない人対策として、キー入力を利用
  • キー入力がされなかった場合に、<Redirect>を使って次のコール先を呼び出し
  • <Redirect>の次には制御が来ないので、<Redirect>先で<Hangup>する

まとめ

  • コールをデザインするには図を書くのが良い
  • actionとurlの違い、どの動詞がどのフロー制御が可能かを理解
  • RestAPIとTwiMLではできることが違うことがあることを意識する
  • キューをうまく利用すると、コールの制御がスマートになる

事後アンケート

お手数ですが、以下のURLよりアンケートにご協力ください。
https://goo.gl/UYDgzt

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