自前でサーバーを建てずに、順次発信をTwiML Binsだけで構築する！

:::note alert
2023年5月1日を持ちまして、株式会社KDDIウェブコミュニケーションズのTwilioリセール事業が終了したため、本記事に記載されている内容は正確ではないことを予めご了承ください。
:::

# 追記
2017/7/20 5月に発表されたTwilio Functionsを使うことで、TwiML Binsより安全に高度な連続架電が可能になりました。
独自サーバーを立てずに順次発信を実現したい方は、ぜひFunctionsをご活用ください。

# はじめに

電話APIであるTwilioには、非常に多くの利用方法がありますが、その中でも代表的な使い方に「異常を電話で通報する」というものがあります。その名の通り、例えばサーバーに異常が発生したり、夜間にドアが空いたことを検知したりした場合に、自動的に電話をかけるソリューションです。

## 自動で電話をかけるにはどうするか

Twilioが用意している[RestAPI](https://jp.twilio.com/docs/api/rest)を利用します。
例えば、以下のPHPコードを実行するとTwilio経由で電話がかけられます（予め[PHPヘルパーライブラリ](https://jp.twilio.com/docs/libraries/php)をダウンロードしておく必要があります）。

```PHP5.x
<?php
// Get the PHP helper library from twilio.com/docs/php/install
require_once '/path/to/vendor/autoload.php'; // Loads the library
use Twilio\Rest\Client;

// Your Account Sid and Auth Token from twilio.com/user/account
$sid = "TwilioのAccountSID";
$token = "TwilioのAuthToken";
$client = new Client($sid, $token);

$call = $client->calls->create(
    "Twilioで購入した発信元電話番号", "発信先電話電話番号",
    array("url" => "http://demo.twilio.com/docs/voice.xml")
);

echo $call->sid;
```

# 本記事で紹介すること

上記コードのように、Twilioを使うとプログラムから簡単に電話をかけることができます。
しかし、異常通報では次のような要件が課せられることがあります。

- 通報先が一人ではない
- 誰かが出るまで電話をし続けたい

このようなニーズには、上記のような単純なしくみでは上手く行きません。
一般的には、上記のようなコードをループさせるプログラムを作り、自前のサーバー上で実行する必要があります。
これは正しいアプローチであり、Twilioとしても推奨する手法です。
一方で、通報のためだけに自前のサーバーを立てるのは難しいとか、自前のサーバーに異常が発生した場合にどうするかという問題もあります。
そこで本記事では、自前でサーバーを建てずに、しかも複数人に対して、誰かが電話にでるまで架電するしくみを紹介します。そのために、Twilioの管理コンソール内に用意されている「TwiML Bins」を利用します。

#### 注意事項

- 本記事で紹介する方法は、かなりトリッキーであり、Twilioとしても想定していない使い方になります。
- ログが正しくとれなかったり、実際の通話した分よりも少しだけ通話料金が高くなります。
- この記事に記載した方法で想定されない動作をした場合に、その責任は一切負いませんので、予めご了承ください。

# 準備

本記事を実行するために必要なものは以下の通りです。

- Twilioのアップグレードアカウント（トライアルアカウントでは、発信先には認証済み電話番号しか指定できません）
- Twilioで購入した050番号を１つ
- RestAPIを呼び出すためのしくみ（上記で紹介したコードなどが実行できるパソコンなど）

# しくみを理解する

本記事で作成するしくみをコールダイアログを使って表現したのが次の図です。
![TwiML Binsによる順次着信（ループ対応） (1).png](https://qiita-image-store.s3.amazonaws.com/0/86046/edd68794-6df3-cbff-b384-5297af1a18d7.png)


左上のCalls.POSTとかかれたダイアログが起点になります。
RestAPIを使って050番号に発信すると、Twilioは自動的に着信状態となり（PSTN着信ダイアログ）、urlで指定されたTwiML①（SayとPauseとHangupが組み合わされたもの）を実行します。このTwiMLは電話を一定時間後に切断するための重要な役割をもっています。ここで指定したPause動詞の秒数が経過すると、この着信に関するコールは切断されます。たとえば、5人に通知をしたいと考えている時に、ここの秒数が短すぎると5人目まで辿り着く前に切断されてしまうことになります。
Calls.POSTのダイアログのurl（RestAPIで発信した際に、相手先が応答したときに実行されます）には、連続架電をするためのTwiML③（Dial動詞が書かれているTwiML）が指定されています。今回は050番号に発信しているため、Twilioが自動着信をすることを利用して、連続架電を実行しています。
Dial動詞のダイアログでは、図では複数のDial動詞が列挙されているようになっていますが、実際には１つのDial動詞の中に、Number名詞を複数記述することで連続架電を実行しています。それぞれのNumber名詞には、通知先を一つづつ指定するとともに、urlには電話に出た時に通知したいメッセージを記したTwiML②を指定します。
ループさせるために、最後のNumber名詞には、今回RestAPIで架電した050番号を再度指定し、さらにurlには自分自身のTwiML③を再帰的に呼び出しています。

# TwiMLを作成する

本記事では、図を見てもわかるように3つのTwiMLを作成する必要があります。

## ダミーの応答メッセージTwiMLを作成する

図の中のTwiML①を作成します。

1. 管理コンソールのデベロッパーセンターを開きます。
2. TwiML Binsを選択して、赤い+アイコンをクリックして以下のTwiMLを作成してください。
3. 「FRIENDLY NAME」には、「ダミー応答メッセージ」、「TWIML」には以下のコードを入力します。

```lang:TwiML①
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say>dummy</Say>
  <Pause length="60" />　<!-- デフォルトで60秒を指定 --> 
  <Hangup />
</Response>
```

架電の途中で呼び出しが止まってしまうようなら、60秒を長くします。

1. Valid Voice TwiMLが表示されているのを確認し、「Create」ボタンを押します。
2. 作成されたTwiMLの「URL」フィールドをメモ帳にコピーしておきます。

## 応答メッセージのTwiMLを作成する

図の中のTwiML②を作成します。

1. 再度TwiML Binsを選択し、赤い+アイコンをクリックして以下のTwiMLを作成してください。
2. 「FRIENDLY NAME」には、「応答メッセージ」、「TWIML」には以下のコードを入力します。

```lang:TwiML②
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say language="ja-JP">緊急事態が発生しました。至急確認が必要です。</Say>
  <Hangup/>
</Response>
```

メッセージは自由に変更して構いません。

1. Valid Voice TwiMLが表示されているのを確認し、「Create」ボタンを押します。
2. 作成されたTwiMLの「URL」フィールドをメモ帳にコピーしておきます。

## 連続架電のTwiMLを作成する

図の中のTwiML③を作成します。

1. 再度TwiML Binsを選択し、赤い+アイコンをクリックして以下のTwiMLを作成してください。
2. 「FRIENDLY NAME」には、「連続架電」、「TWIML」には以下のコードを入力します。

```lang:TwiML③
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial callerId="購入した050番号" timeout="10" sequential="true">
    <Number url="TwiML②でコピーしておいたURL" >発信先電話番号１</Number>
    <Number url="TwiML②でコピーしておいたURL" >発信先電話番号２</Number>
    <Number url="TwiML②でコピーしておいたURL" >発信先電話番号n</Number>
    <Number url="">購入した050番号</Number>
  </Dial>
</Response>
```

- Dial動詞にかかれている`timeout`は、呼び出し秒数となります。
- Dial動詞にかかれている`sequential="true"`は順次着信を意味します（ドキュメントには記載がありません）。
- 購入した050番号、発信先電話番号はすべてE.164形式（+81から始まる書式）で指定してください。
- 発信先電話番号は最大９つまで指定ができ、上から順番に架電されます。

1. Valid Voice TwiMLが表示されているのを確認し、「Create」ボタンを押します。
2. 作成されたTwiMLの「URL」フィールドをメモ帳にコピーしておきます。
3. 最後のNumber動詞のurl欄に、今コピーしたURLを指定し、「Save」ボタンを押します。

# 購入した050番号の設定

購入した050番号に着信時の設定を行います。

1. 管理コンソールから電話番号を開きます。
2. 購入した050番号（今回利用する番号）を選択し、「A CALL COMES IN」を「TwiML」に切り替え、先程作成したTwiML①の「ダミー応答メッセージ」を選択します。
3. 「保存」ボタンを押します。

# テスト

一連の設定が正しく動作するかをテストしてみましょう。

1. 管理コンソールのデベロッパーセンターを開きます。
2. API Explorerを選択します。
3. 「プログラマブルVoice」が選択されている状態で、「通話」を展開します。
4. 「通話を発信する」とかかれたPOSTを展開します。
5. 「TO」と「FROM」に、購入した050番号を入力、もしくは選択します。
6. 「URL」に、先程作成したTwiML③のURLを入力します。
7. 右側の「Request」ウィンドウ内にある「Show your Auth Token」にチェックを入れます。
8. 作成されたCurlのスクリプトをコピーし、ターミナルなどから実行します。

#### 実行時の注意
- 現在、API Explorerにはバグがあり、curlの一行目にある`/Call.`を`/Call.json`に書き換える必要があります。
- 万が一、ループが止まらなくなった場合（電話が永遠にかかってきてしまうような場合）は、先程作成したTwiML③の最後のNumberを削除してセーブし直すか、TwiML③自体を削除してください。

# 本番環境に適用する

テストがうまくいったら、あとは本番環境に適用しましょう。
この記事の先頭で説明したように、RestAPIを使って今回購入した050番号に発信するようにします。その際の発信元番号も同じ050番号で構いません。また、RestAPIのurlで、TwiML③のURLを指定することを忘れないようにしてください。

例えば、PHP５．ｘであれば以下のようなコードになるはずです。

```PHP5.x
<?php
require_once '/path/to/vendor/autoload.php';
use Twilio\Rest\Client;

// Your Account Sid and Auth Token from twilio.com/user/account
$sid = "TwilioのAccountSID";
$token = "TwilioのAuthToken";
$client = new Client($sid, $token);

$call = $client->calls->create(
    "購入した050番号", "購入した050番号",
    array("url" => "TwiML③のURL")
);

echo $call->sid;
```