本日の資料
以下にアップされています(限定公開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
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>動詞で生成する(転送する)
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial callerId="発信者番号">
<Number url="http://demo.twilio.com/docs/voice.xml">
発信先番号
</Number>
</Dial>
</Response>
コールの状態
-
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がどのタイミングで発行されるかを確認してみましょう。
- サーバーにSSHでログインします。
- 実習の準備をします。
% 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 ./
#!/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をリアルタイムで監視します。
% cd
% tail -f status.txt
次に、管理コンソールから次の作業を行います。
1.TwiML Binsで以下の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(コールの強制終了)
- 050番号に着信したら、<Play>動詞で音を再生
- 同時に、非同期で10秒待ってから切断するRestAPIを実行
手順
- サーバーにSSHでログインします。
- 以下のコマンドで準備をします。
% cd
% cp hands_on_2016_vol2/practice002/*.php ./html/
% chmod 705 html/*.php
% vi html/callDisconnect.php
$sidと$tokenに、ご自分のAccountSidとAuthTokenを記入します。
:wq で保存
実習で利用するのは以下の2つの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>
#!/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件ずつ)
- 課金情報の更新には少し時間が必要
コールログの構成
- コールログのプロパティ
- https://jp.twilio.com/docs/api/rest/call#instance-properties
- 親コールと子コール
コールログを取得する
- コンソールから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)
- 待機呼はメンバーとして管理
- 平均待ち時間や待機呼の数を取得可能
キューのしくみ
- <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(キューイング)
- 050-XXXX-XXXXに、キューに格納する処理を定義します(ただし、TwiML Appsを使うので、電話番号を用意する必要はありません)。
- キューに入った通話には、enqueue.phpが繰り返し呼ばれ、現在の待ち位置が応答されます。
- 050-YYYY-YYYYに、キューから取り出す処理を定義します。
手順1. 以下のTwiML BinsをEnqueue という名前で作成します。
<?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という名前で作成します。
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say language="ja-JP" voice="alice">
お待ちどうさまでした。お繋ぎいたします。</Say>
</Response>
※作成したTwiML BinsのURLをコピーしておきます。
手順3. 以下のTwiML BinsをDialQueueという名前で作成します。
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial callerId="購入済み050番号">
<Queue url="手順2.で作成したTwiML BinsのURL">
testQueue</Queue>
</Dial>
</Response>
手順4. サーバーに接続し、enqueue.phpを準備します。
% cd
% cp hands_on_2016_vol2/practice003/enqueue.php ./html/
% chmod 705 html/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、オレンジは着信
匿名通話
- (着信転送の場合)着信したコールをキューに入れる
- (V字発信の場合)一人目にRestAPIで発信し、相手が応答したらキューに入れる
- キューに入ったコールは呼び出し中のガイダンスがループする
- キューに入った後で、裏側でRestAPIで相手先を呼び出す
- 相手先が応答すると、転送しますのガイダンスを流して、キューから呼を取り出す
- 相手先が応答しなかった(できなかった)場合は、waitUrlでLeaveを返すようにすることで、キューに入っていたコールを戻し、お繋ぎできませんでしたとガイダンスを流して終話
####### デザインのポイント
- 単純に転送させるだけなら、着信時のurl、もしくはV字発信でDial動詞を呼び出せば良い
- キューを活用するメリット
- 相手先が応答しなかった場合に、何度かリトライする
- 相手先の状況に応じて、メッセージを変更する
択一同報発信
同時に複数の人に発信を行い、最初に取った人だけにガイダンスを流す
- RestAPIで050番号に発信させる
- 着信設定で、<Dial>動詞を呼び出す(この時点で<Number>名詞を最大10まで指定)
- 最初に応答した相手に<Say>動詞でガイダンスを流す
####### デザインのポイント
- <Number>名詞は10までしか設定できない
- RestAPIではtoを複数指定できないので、050番号を中継している
- 留守番電話などが応答してしまう可能性もある
- 対応策としては、<Gather>を入れて、人が応答するまで何度か繰り返す必要あり
- <Dial>動詞に、sequential属性(非公開)があり、false(デフォルト)に設定すると一斉発信、trueに設定すると順次発信(上から1件ずつ発信)
一斉同報発信
同時に複数の人に発信を行い、応答した人すべてにガイダンスを流す
- RestAPIで発信する
- 相手が応答したら、<Say>動詞でガイダンスを流す
- statusCallbackのcompletedイベントを拾って、failedかbusyかno-answerだったら、再度RestAPIでコールする
####### デザインのポイント
- 1CPSの制限あり
- statusCallbackのCallStatusを判定してリカバリ
順序発信
- RestAPIでコールする
- 相手が応答したら、<Say>動詞でガイダンスを流す
- 応答できる時だけキー入力をしてもらう
- キー入力があれば、終了
- キー入力がなければ、<Redirect>でRestAPIで次のコール先に発信
- 同時に<Hangup>を返すことで通話を切断
####### デザインのポイント
- 留守番電話対策、および対応できない人対策として、キー入力を利用
- キー入力がされなかった場合に、<Redirect>を使って次のコール先を呼び出し
- <Redirect>の次には制御が来ないので、<Redirect>先で<Hangup>する
まとめ
- コールをデザインするには図を書くのが良い
- actionとurlの違い、どの動詞がどのフロー制御が可能かを理解
- RestAPIとTwiMLではできることが違うことがあることを意識する
- キューをうまく利用すると、コールの制御がスマートになる
事後アンケート
お手数ですが、以下のURLよりアンケートにご協力ください。
https://goo.gl/UYDgzt