Twilioの留守番電話検知機能（AMD）を使ってみた（PHP）

#はじめに
株式会社じげんの山形です。
主にバックエンドとフロントエンドの実装を担当してます。

Twilioではプログラムからユーザーに対して自動電話をかける事ができます。
実装していて困ったのが、人が電話に出ても、留守電が起動しても、自動電話が指定したメッセージを流し続けてしまう事でした。その時に役立ったのがTwilioのAnswering Machine Detection（以後AMDと呼称）の機能でした。今回その機能を色々試して分かったことを書いていきます。


#環境

・PHP7.2以上
・Twilio Sdk をインストール済み(twilio/sdk: 6.31)
※筆者はLaravel5系を使用しております

#前提

・Twilioのアカウントを所有
・（電話可能な）電話番号を取得済み
・PHPで通話を発信する方法を知っていること（ご存知ない方は[公式のドキュメント](https://jp.twilio.com/docs/voice/tutorials/how-to-make-outbound-phone-calls-php)を参照してください）


#目次

1. AMDを使用してみる（PHP）
2. AMDを非同期で使用する
3. おまけ


#本編

AMDの公式ドキュメントは下記です。
[Answering Machine Detection - Twilio](https://www.twilio.com/docs/voice/answering-machine-detection)

AMDの使用には1callあたり$.0075かかるようなので、こちらは注意してください（公式ドキュメントより引用）。
>Answering Machine Detection will be charged at $.0075 per call where enabled and the called party picks up. Busy or Failed calls may engage our AMD system but will not be charged.

##1.AMDを使用してみる（PHP）

AMDを使用するのはcallするときに``machineDetection: Enable``を追加すれば使用できます。

```php:
use Twilio\Rest\Client;

=========
$client = new Client($sid, $token); //自身のアカウントのsidとtoken
$calls = $client->calls
                ->create(
                    $toNumber, //宛先の電話番号
                    $fromNumber, 　//通話元の電話番号
                    [
                        "url" => $callUrl,　       // ユーザーが受電した直後にリクエストが行くURLを指定
                        "timeout" => 30,
                        "machineDetection" => "Enable", 　// AMDを使用するためのパラメータ
                    ]
                );
```

上記のように指定することで、$callUrlのリクエストに``AnweredBy``というパラメータが返ってきます。
人の場合は``AnsweredBy:human``
留守電の場合は``AnsweredBy:machine_start``
と返ってきました。
この値によって、$callUrl内の処理を分岐させることが可能です。

ただし、注意点としてAMDが判断するまでに時間が少々かかります。
$callUrlが実行されるまで大体7秒程度かかってしまいました。

##2. AMDを非同期で使用する

AMDの監視を非同期で行う事ができます。

```php:
use Twilio\Rest\Client;

=========
$client = new Client($sid, $token); //自身のアカウントのsidとtoken
$calls = $client->calls
                ->create(
                    $toNumber, //宛先の電話番号
                    $fromNumber, 　//通話元の電話番号
                    [
                        "url" => $callUrl,　       // ユーザーが受電した直後にリクエストが行くURLを指定
                        "timeout" => 30,
                        "machineDetection" => "Enable", 　// AMDを使用するパラメータ
                        "asyncAmd" => true,        // AMDを非同期で使用
                        'asyncAmdStatusCallback' => $checkAmdUrl,　　// AMDの結果を返すURL
                        'asyncAmdStatusCallbackMethod' => "POST", // 上記URLのHTTPメソッド
                    ]
                );
```

上記のように
``asyncAmd:true``、``asyncAmdStatusCallback``に監視する用のURL（今回の場合は``$checkAmdUrl``としてます）を指定、``asyncAmdStatusCallbackMethod:POST``（こちらはデフォルトでPOSTが指定される為省略可）を設定することで、``$checkAmdUrl``に結果が返されます。

こちらを使用すれば``$callUrl``の実行が待たされることはありませんが、当然``$callUrl``内で``AnsweredBy``による分岐は不可能となります。



##3. おまけ

1のように単純にAMDを使用すると、"url"に指定したURL実行まで数秒の待ち時間が発生します。
2のように非同期でAMDを使用すると、待ち時間は無くなりますが、"url"に指定したURLにおけるAMDの判定結果による分岐ができなくなります。

そこで個人的に便利だと思ったのが通話の上書きです。つまり、実行中の自動電話を停止し、新しいメッセージを流す事ができます。
例えば下記のように指定することで通話の上書きが実行できます。

```php:
use Twilio\Rest\Client;

=========
$client = new Client($sid, $token); //自身のアカウントのsidとtoken
$calls = $client->calls($callSid) // request内のCallSidを指定
                ->update(
                    [
                        "url" => $updateCallUrl,　       // URLを指定
                        "method" => "POST",
                    ]
                );
```

どういう場面で使用できるかというと、
2で記述したように、AMDを非同期で使用し、``asyncAmdStatusCallback``に指定したURL内で留守電検知が完了したタイミングで通話の上書きを行えば、待ち時間をほとんど与えることなく通話を続ける事が可能となります。

#最後に
TwilioのAMDはアメリカの電話文化に合わせた実装になっているとのことで、実装前は日本でこの機能が正常に使用できるとは思ってませんでした。（ラグが発生することを除けば）AMDの機能を試してみて、使用にそこまで問題がなかった事は驚きでした。
（参照：[Twilio で相手が人間か機械かを判別することはできますか？ &ndash; Twilio - KDDI Web Communications](https://cloudapi.zendesk.com/hc/ja/articles/206427321-Twilio-%E3%81%A7%E7%9B%B8%E6%89%8B%E3%81%8C%E4%BA%BA%E9%96%93%E3%81%8B%E6%A9%9F%E6%A2%B0%E3%81%8B%E3%82%92%E5%88%A4%E5%88%A5%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AF%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%81%8B-)）
Twilioには便利機能たくさんあるようですが、英語のドキュメントも多いので（英語苦手ですが）勉強続けていきたいです。

#関連
・[Twilio - KDDI Web Communications｜コミュニケーションAPI](https://cloudapi.kddi-web.com/)
・[Answering Machine Detection - Twilio](https://www.twilio.com/docs/voice/answering-machine-detection)