Twilio で実装する通話状態検知システム - 留守電・電源オフを自動判定

Twilio で実装する通話状態検知システム - 留守電・電源オフを自動判定

Twilio の Call API と StatusCallback を活用して、自動通話発信から留守電検知まで行うシステムを Twilio Functions で実装。人応答・留守電・電源オフなどの状態を自動判定し、監視業務の自動化を実現する方法を詳しく解説します。

はじめに

本記事では、Twilio の Programmable Voice API を活用して、通話の自動発信から状態検知までを行うシステムを実装します。Call API による通話発信と StatusCallback による状態監視の仕組みを、Twilio Functions を使用して構築し、その動作を検証します。

twilio-call-status-demo

Twilio とは

Twilio は、開発者向けのクラウド通信プラットフォームです。REST API を通じて SMS、音声通話、ビデオ通話などの通信機能をアプリケーションに組み込むことができます。特に Programmable Voice では、通話の発信・受信、リアルタイムな状態監視、留守電検知などの機能を提供しています。

対象読者

  • JavaScript (Node.js) の基本的な知識を持つ開発者
  • REST API と HTTP リクエスト・レスポンスを理解している方
  • 電話による連絡業務の自動化を検討している方

参考

構成

system architecture

システムの動作フローは以下のステップで構成されます。

  1. /call エンドポイントへのリクエスト
  2. Twilio Call API の呼び出し
  3. 対象電話番号への発信開始
  4. 通話状態の変化 (initiated → ringing → answered/no-answer/busy)
  5. 各状態変化時に /callback エンドポイントへ StatusCallback 送信
  6. /callback での状態判定と分岐処理
  7. ログ出力と結果の記録

状態遷移時の各状態は以下の通りです。

  • initiated: Twilio がキューから通話を取り出し、ダイヤル開始
  • ringing: 相手先で呼び出し音が鳴っている状態
  • answered: 通話が応答された状態 (人または留守電)
  • completed: 通話が正常に終了
  • no-answer: 応答がない、または通話が拒否された
  • busy: 相手が通話中
  • failed: 通話が失敗 (無効な番号など)

各状態において、Answering Machine Detection (AMD) が有効な場合は、answeredBy パラメータで人 (human) か留守電 (machine) かを判定できます。

実装

環境構築

Twilio アカウントの準備

  1. Twilio Console にログイン
  2. Account SID と Auth Token を確認
  3. 発信用の Twilio 電話番号を取得

Twilio Account Dashboard

Twilio Functions の作成

  1. Twilio Console で Functions and Assets > Services を選択
  2. 新しいサービスを作成 (例: call-status-system)
    Twilio Service call-status-system
  3. 環境変数を設定
    environmental variables
    • TWILIO_PHONE_NUMBER: 発信元の Twilio 購入番号
    • TARGET_PHONE_NUMBER: 発信先の電話番号 (テスト用)

Twilio Function - /call

Add > Add Function で通話を発信する Function /call を追加します。

add function

/call の実装
exports.handler = async function(context, event, callback) {
  const twilioClient = context.getTwilioClient();

  try {
    const toNumber = event.to || context.TARGET_PHONE_NUMBER;
    const fromNumber = context.TWILIO_PHONE_NUMBER;

    // StatusCallback URL の構築
    const callbackUrl = `https://${context.DOMAIN_NAME}/call-status`;

    console.log(`通話開始: ${fromNumber}${toNumber}`);

    // Call API の実行
    const call = await twilioClient.calls.create({
      from: fromNumber,
      to: toNumber,
      twiml: '<Response><Say language="ja-JP">テスト通話です</Say></Response>',

      // StatusCallback の設定
      statusCallback: callbackUrl,
      statusCallbackEvent: ['initiated', 'ringing', 'answered', 'completed'],

      // AMD の有効化
      machineDetection: 'Enable',
      timeout: 30
    });

    console.log(`Call SID: ${call.sid}`);

    return callback(null, {
      statusCode: 200,
      body: JSON.stringify({
        success: true,
        callSid: call.sid,
        status: call.status
      })
    });

  } catch (error) {
    console.error('通話エラー:', error);
    return callback(error);
  }
};

今回は検証のために Visibility を Public に設定します。

visibility

Twilio Function - /call-status

StatusCallback を受信して状態に応じた処理を行う Function /call-status を実装します。

/call-status の実装
exports.handler = function(context, event, callback) {
  const { CallSid, CallStatus, AnsweredBy, Duration, SipResponseCode } = event;

  console.log(`=== StatusCallback: ${CallStatus} ===`);
  console.log(`Call SID: ${CallSid}`);

  // 状態に応じた分岐処理
  switch (CallStatus) {
    case 'initiated':
      console.log(`📞 通話開始`);
      break;

    case 'ringing':
      console.log(`🔔 呼び出し中`);
      break;

    case 'answered':
      console.log(`📱 応答検知`);
      break;

    case 'completed':
      console.log(`✅ 通話完了 (${Duration}秒)`);

      if (AnsweredBy === 'machine') {
        console.log(`🤖 留守電検知`);
        // 留守電用の後処理
      } else if (AnsweredBy === 'human') {
        console.log(`👤 人応答検知`);
        // 人応答用の後処理
      }
      break;

    case 'no-answer':
      console.log(`❌ 応答なし (SIP: ${SipResponseCode})`);
      // 電源オフ・圏外の処理
      break;

    case 'busy':
      console.log(`📵 通話中`);
      break;

    case 'failed':
      console.log(`💥 通話失敗 (SIP: ${SipResponseCode})`);
      break;
  }

  // Twilio への応答
  return callback(null, { statusCode: 200, body: 'OK' });
};

この実装では、主要な通話状態を判定し、特に completed 状態で AMD の結果 (AnsweredBy) を確認して留守電と人応答を区別しています。各状態でのログ出力により、通話の進行状況を追跡できます。

Functions の編集が完了したら、 Save と Deploy All を行うのを忘れないようにしてください。

動作確認

Functions の 「Live logs」 を ON にします。

Live logs toggle

ブラウザまたは curl で /call エンドポイントにアクセスします。

curl -X GET "https://your-service-xxxx.twil.io/call"

Live logs で以下のようなログが出力されることを確認します。

人が応答した場合:

=== StatusCallback: initiated ===
📞 通話開始
=== StatusCallback: ringing ===
🔔 呼び出し中
=== StatusCallback: completed ===
✅ 通話完了 (15秒)
👤 人応答検知

留守電の場合:

=== StatusCallback: completed ===
✅ 通話完了 (8秒)
🤖 留守電検知

応答なしの場合:

=== StatusCallback: no-answer ===
❌ 応答なし (SIP: 487)

これにより、通話状態の自動検知が正常に動作していることを確認できます。

twilio-call-status-demo

まとめ

本記事では、Twilio の Programmable Voice API と Functions を活用して、通話状態検知システムを構築しました。Call API による自動発信から StatusCallback による状態監視まで、サーバーレス環境で一貫したシステムを実装できました。特に Answering Machine Detection 機能により、留守電・人応答・電源オフなどの状態を自動判定し、各状態に応じた分岐処理を実現しています。

このシステムは監視・アラート業務の自動化や顧客への自動連絡など、様々な場面で活用できます。Twilio の豊富な API を活用することで、複雑な通信インフラを構築することなく、短時間で実用的なシステムを開発できる点が大きな利点です。今後はデータベース連携や複数番号への順次発信など、具体的な業務要件に合わせた機能拡張も可能です。

この記事をシェアする

facebookのロゴhatenaのロゴtwitterのロゴ

© Classmethod, Inc. All rights reserved.