2015/12/10

Twilioで無応答転送


こんにちは、maru-kouです。

この記事はTwilio Advent Calendar 2015の12日目の記事です。
http://qiita.com/advent-calendar/2015/twilio

#Advent Calenderについてはこちら


概要


Twilioの着信時に呼出中のまま一定時間内に応答しなかった場合に、他の電話番号に自動転送(無応答転送)するケースについて考えてみたいと思います。




Twilioとは


下記を参照ください。



処理の流れ





実装


・呼出用TwiML生成


図の処理No.2の個所です。
発信時、Twilioからのリクエストにて呼出用のTwiMLを返却します。
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Dial action="http://XXX.XXX.XXX.XXX/action" callerId="+8150XXXXXXXX" timeout="10">
      <Number>電話番号B</Number>
    </Dial>
</Response>

Dial動詞のtimeout属性を指定することで、指定された秒数分、応答が無ければ通話が切断されます。
今回は10秒を指定しました。
Dial動詞のaction属性は通話切断後に発行されるリクエストURLです。
ここに転送用TwiML生成のURLを指定しています。

このTwiMLにより、電話番号Bを呼出し、10秒間応答がなければタイムアウトとなり、Bの呼出しを終了します。
タイムアウト後は転送用TwiML生成が実行されます。
なお、action属性はタイムアウトだけでなく、応答後の切断やタイムアウト前の切断など全ての通話切断後に実行されるので注意が必要です。


・転送用TwiML生成


図の処理No.4の個所です。
タイムアウト後に転送先へダイアルするTwiMLの生成を行います
#Node.jsで処理しています。
var http = require('http');
var qs = require('querystring');
var fs = require('fs');

http.createServer(function (req, res) {

  if (req.url == "/action") {
    //転送用TwiML生成

    if(req.method=='POST') {

      var body='';

      req.on('data', function (data) {
        body +=data;
      });

      req.on('end',function(){               
        var reqParam =  qs.parse(body);

        if (reqParam.CallStatus == "in-progress" 
          && reqParam.DialCallStatus == "no-answer") {
          //タイムアウト

          var strm = fs.createReadStream('twiml-transfer.xml');   //転送用TwiML
          strm.pipe(res);
          res.writeHead(200, {'Content-Type': 'application/xml'});

        } else {
          //タイムアウト以外

          var strm = fs.createReadStream('twiml-hangup.xml');    //通話終了用TwiML
          strm.pipe(res);
          res.writeHead(200, {'Content-Type': 'application/xml'});

        }
      });
      
    }
  }

}).listen(80);
21行目でタイムアウトかどうか判定しています。
リクエストパラメータのCallStatusとDialCallStatusで判定が可能です。

#CallStatusは通話の状態を示す値
https://jp.twilio.com/docs/api/twiml/twilio_request#request-parameters-call-status
#DialCallStatusはDialタグの結果を示す値
https://jp.twilio.com/docs/api/twiml/dial#attributes-action-dial-call-status-values

この二つの値は操作状況によって以下のような値が入ります

No操作状況CallStatusDialCallStatus
1呼出中に発信者が切断completedno-answer
2呼出中に受信者が切断in-progressbusy
3呼出中にタイムアウト発生in-progressno-answer
4通話して発信者が切断completedcompleted
5通話して受信者が切断in-progresscompleted

転送を行うのはタイムアウトの時だけなので、3の場合に処理を分岐させています。


twiml-transfer.xml
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Dial callerId="+8150XXXXXXXX">電話番号C</Dial>
</Response>

転送用のTwiMLです。電話番号Cを呼び出しています。


twiml-hangup.xml
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Hangup/>
</Response>

通話終了用のTwiMLです。Hangup動詞で終了しています。


以上です。
これで無応答時の自動転送が実現できました。

3 件のコメント:

  1. Advent Calendarにご参加、有難うございます!
    CallStatusを判定して処理を分けているのですね〜。
    ちなみに、呼び出し用のTwiMLの動詞の後に、別の動詞を書くことで、タイムアウト時の処理ができたかと思います。この場合、最初の動詞でactionを指定しないことが条件になります。
    具体的には、



    電話番号B


    転送先電話番号


    という感じです。

    返信削除
  2. あー、タグがエスケープされちゃいましたね。
    すみません。

    返信削除
  3. 高橋様
    コメントありがとうございます。
    タグは取り除かれるようですね・・・残念です。

    TwiMLの動詞の後に別の動詞を書くということは以下のようなTwiMLでしょうか。

    <?xml version="1.0" encoding="UTF-8"?>
    <Response>
        <Dial callerId="+8150XXXXXXXX" timeout="10">
          <Number>電話番号B</Number>
        </Dial>
        <Dial callerId="+8150XXXXXXXX"
          <Number>転送先電話番号</Number>
        </Dial>
    </Response>

    このTwiMLだと確かにタイムアウト時に転送先電話番号にダイアルしますが、タイムアウト以外の切断時もダイアルされてしまうと思います。

    上記のようなTwiMLではなく、別の書き方があるのでしょうか。
    タイムアウトによる処理の分岐がTwiMLで制御できれば実装がもっと簡潔になるので、ぜひ取り入れたいところです。

    返信削除