1. はじめに
1.1 記事の目的
私はハローでカスタマーサポート向けAIサービス「HelloX」 の開発を担当しています。入社後に電話領域を学び始めましたが、知れば知るほど奥が深く、技術的にも面白い分野だと実感しています。
その電話技術の面白さを紹介するために、この記事では、 Twilio と Asterisk を組み合わせ、いわゆる“固定電話”のように Twilio番号で外線の発着信 と 着信時の同時呼び出し を行える最小構成のIP電話を作ろうと思います。
1.1.1 HelloX とは?
HelloX は、電話の応対から後処理(ACW)までを自動化 するカスタマーサポート向けAIサービスです。既存ツール/社内データと連携し、従来は人手が必要だった後処理まで自動化します。
ユースケースの例としては以下のようなものがあります:
- 未収督促・債権回収:顧客データと同期し、督促プロセスを自動化
- 予約受付:在庫/空室と連動し、受付可否を即判断
1.1.2 開発者視点での面白さ
電話領域の開発で面白いと思う点は、リアルタイム性の高い処理が求められることです。
Web APIでの通常のリクエスト/レスポンスと異なり、電話はストリーミング処理であり、低遅延であることを求められます。
音声AIの処理は、ASR(音声認識)、LLM(言語モデル)、TTS(音声合成)といった重い処理を伴いますが、これを「自然な会話テンポ」の中で行う必要があります。
たとえば、AIの応答までに数秒の「沈黙」が発生すると体験が損なわれるため、人間と同等のテンポを追求することが重要なミッションです。
古くから存在する電話網の制約と、最新のAI技術をいかにシームレスに融合させ、誰も体験したことのない「AIとの自然な会話」を実現することが開発者として最も挑戦的で面白い部分だと感じています。
1.2 前提知識
本記事は、IP電話やVoIP技術に関する前提知識がないWebエンジニアの方でも理解できるよう、基礎用語から丁寧に解説していきます。
まず、本記事で登場する主要な技術について説明します。
1.2.1 IP電話関連の基礎用語
SIP(Session Initiation Protocol)とは
- HTTPやSMTPと同じく、アプリケーション層のプロトコルの一つ
- インターネット上で通話を確立・管理するための通信プロトコル
- 「電話をかける」「電話を受ける」「通話を終了する」といった一連の動作を制御
Twilioとは
- 電話をAPI化したクラウド基盤
- 電話番号の取得、発着信、IVR、録音、SIP接続などを行える
- プログラムから電話・SMS・ビデオ通話などを制御できるAPIを提供
- PSTN(一般的な携帯電話が使用している公衆電話網)とIP電話を仲介する
Asteriskとは
- オープンソースのPBX(Private Branch Exchange:電話交換機)ソフトウェア
- この番号への着信はどのような処理を実行し、どの端末に転送するか等を柔軟にカスタマイズが可能
- Webサーバーで言えばNginxやApacheのような存在で、電話交換の仕組みを提供
1.2.2 実際の通話の流れと各技術の役割
普段使っている携帯電話から、本記事で構築するTwilio番号(050番号)に電話をかけたときの流れを通して、Twilio・Asteriskがそれぞれどのような役割を果たしているのかを説明します。
あなたの友人(携帯電話)とあなた(SIPクライアント)が通話する場合の通話フロー
①友人の携帯電話 -> ②PSTN-> ③Twilio -> ④インターネット -> ⑤Asterisk -> ⑥インターネット -> ⑦SIPクライアント(あなた)
ポイント
- ③でTwilioがPSTN(一般的な携帯電話が使用している公衆電話網)からインターネット上で通信できるSIPプロトコルに変換しています。逆も然りで、SIPクライアントからの通信をPSTNに変換しています。
- ⑤でAsteriskはダイヤルプラン(※)に基づき、通話の割り当て先に振り分けます
- 通話が繋がった以降はAsteriskは音声データを中継し、通話の切断等の通話の制御の役割を果たします。
※ ダイヤルプランとは、受け取った電話を「誰に」「どのように」接続し、「どんな処理を」実行するかを定義する一連のルールのことです。
1.2.3 事前に用意するもの
今回の構築で事前に使うものを以下に記載しておきます
- GCPアカウント
- Twilioアカウント
- Twilioで購入した050番号1つ
- SIPクライアント(iOSだとSoftphoneで動作確認済み)
1.3 シーケンス図
本記事で作成する"固定電話"のシーケンス図を記載します。
1.3.1 受信側

1.3.2 発信側

この前提を踏まえ、次章では使用環境と要件、VM 準備、Asterisk のインストール手順を整理します。
2. 環境構築
この章では必要に応じて静的IPアドレスを予約し、AsteriskサーバーをGCP上に準備します。
また、通信を制御するためファイアーウォールを設定します。
2.0 IPアドレスの作成
とりあえずすぐに試してみたい人は不要です。
作成の際は特に細かい設定は不要で、リージョンだけasia-northeast1にするようにしてください。
ex.
- 内部
- 名前: asterisk-server-dev-private
- リージョン: asia-northeast1
- 外部
- 名前: asterisk-server-dev-public
- リージョン: asia-northeast1
※ IPアドレスは何かに割り当てなければ余計に料金が発生するのでご注意ください
2.1 VMインスタンス作成
インスタンスに入ってAsteriskのインストールを行うことも面倒なので、起動スクリプトに組み込みましょう
※インスタンス自体の立ち上げはすぐ完了しますが、起動スクリプト実行までに2時間かかるので注意してください
ex.(記載内容以外変更なし)
- マシンの構成
- 名前: asterisk-server-dev
- リージョン: asia-northeast1
- マシンタイプ: e2-micro
- OSとストレージ
- オペレーティング システムとストレージ(変更)
- 24.04 LTS Minimal(x86/64)
- オペレーティング システムとストレージ(変更)
- ネットワーキング(2.0でIPアドレス作成した人のみ必要)
- ネットワーク インターフェース
- プライマリ内部IPv4アドレス: asterisk-server-dev-private
- 外部IPv4アドレス
- ネットワークタグ: asterisk-server-dev
- ネットワーク インターフェース
- 詳細
- 起動スクリプト(下記を貼り付け)
▶︎ Asteriskインストールコマンド
```
sudo apt update && sudo apt upgrade -y
sudo apt install -y build-essential wget git subversion uuid-dev libxml2-dev \\
libsqlite3-dev libssl-dev libncurses5-dev libjansson-dev libsrtp2-dev pkg-config libopus-dev vim telnet
cd /usr/src && \\
sudo wget <https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-22.6.0.tar.gz> && \\
sudo tar xvf asterisk-22.6.0.tar.gz && \\
cd asterisk-22.6.0
sudo contrib/scripts/install_prereq install
sudo ./configure
sudo make menuselect.makeopts
sudo make -j$(nproc)
sudo make install
sudo make samples && sudo make config && sudo ldconfig
sudo adduser --system --group --no-create-home asterisk && \\
sudo chown -R asterisk:asterisk /etc/asterisk && \\
sudo chown -R asterisk:asterisk /var/lib/asterisk && \\
sudo chown -R asterisk:asterisk /var/log/asterisk && \\
sudo chown -R asterisk:asterisk /var/spool/asterisk && \\
sudo chown -R asterisk:asterisk /usr/lib/asterisk
sudo systemctl daemon-reload
sudo systemctl start asterisk
sudo systemctl enable asterisk
sudo mv /etc/asterisk/pjsip.conf /etc/asterisk/pjsip.conf.backup && \\
sudo touch /etc/asterisk/pjsip.conf
sudo mv /etc/asterisk/extensions.conf /etc/asterisk/extensions.conf.backup && \\
sudo touch /etc/asterisk/extensions.conf
sudo systemctl daemon-reload
sudo systemctl restart asterisk
```
2.2 firewall設定
内向き、外向きそれぞれのfirewall設定を追加し、VMインスタンスに適用させましょう
2.2.1 内向き
ex.
- 名前: asterisk-server-ingress
- ターゲットタグ: asterisk-server-dev(VMインスタンスで設定したネットワークタグです)
- 送信元IPv4範囲: 0.0.0.0/0
- プロトコルとポート
- UDP: 5060, 10000-20000
2.2.2 外向き
ex.
- 名前: asterisk-server-egress
- ターゲットタグ: asterisk-server-dev(VMインスタンスで設定したネットワークタグです)
- 送信元IPv4範囲: 0.0.0.0/0
- プロトコルとポート
- UDP: 5060, 10000-60000
【ポイント】
5060/UDP: TwilioとAsteriskで使用する5060/UDPを許可します
(内向き)10000–20000/UDP: Asteriskが受信するデフォルトのRTPポート範囲10000–20000/UDPを許可します
(外向き)10000–60000/UDP: TwilioではRTPポート範囲は10000–60000/UDPを使用しています。
3. Twilioの準備
この章では、Twilioの設定を行います。PSTNとSIPの相互変換を行うためにSIPTrunkを作成し、Asteriskサーバーと接続できるようにIPアドレスの許可設定や認証情報を作成します。
購入した050番号を使用するため、このSIP Trunkで利用できるように結びつけます。
3.1 IP Access control listsの作成
Elastic SIP Trunking > Manage > IP Access control lists
この後作成するSIP Trunkでアクセスを許可するIPアドレスを登録する必要があります。
作成したVMインスタンスに割り当てられている外部IPアドレスをコピーし、作成します。
ex.
- Friendly Name: asterisk-server
- CIDR Network Address: {外部IPアドレス}
3.2 Credential listsの作成
Elastic SIP Trunking > Manage > Credential lists
SIP Trunkに接続するための認証情報を作成します。
- Friendly Name: asterisk-server
- Username: {任意のユーザー名}
- Password: {任意のパスワード}
強力なパスワードにすることを強く推奨します
3.3 SIP Trunkの作成
Elastic SIP Trunking > Manage > Trunks
Create new SIP Trunkから作成します
ex. Friendly Name: asterisk-server
3.3.1 General
こちらは特に変更不要ですが、TrunkSIDはコピーしておきましょう
3.3.2 Termination
Twilioで発行される050番号はIP電話と呼ばれており、一般的に使用している080, 090番号等では公衆交換電話網を使用しているため、厳密には異なる回線で通話を行います。
このTerminationではIP電話から公衆交換電話網に繋ぐための設定を行います。
ex.
- Termination SIP URI: {任意の項目だが、TrunkSIDだとわかりやすい}
- Authentication
- IP Access control lists: {作成したIP Access control lists}
- Credential lists: {作成したCredential lists}
これでTerminationの設定は完了です
3.3.3 Origination
Originationでは逆に、公衆交換電話網からIP電話として受けるために必要な設定を行います。
Twilioで受け取った電話をどこに送るかをOrigination URIsに追加しましょう
ex.
- Origination SIP URI: sip:{VMインスタンスの外部IP}:{Asteriskサーバーのポート番号}
Asteriskサーバーのポート番号については後述しますが、デフォルトポートの5060以外で任意のポートを使用しましょう
これでOriginationの設定は完了です
3.3.4 Numbers
SIP Trunkに設定する番号を追加します。事前に購入した番号を追加しましょう。
4. Asteriskの基本設定
この章では、Asteriskの基本的な設定を行います。
スマホの電話アプリなどを「内線1001」「内線1002」として登録するための設定を行い、各内線のダイヤルプランを設定します。
この章では内線通話を実現させて、実際に動かせることをテストします。
※注意事項: Asteriskは攻撃対象になりやすいため、セキュリティには十分注意してください。電話を不正に利用され、課金が発生するほか、詐欺等犯罪に利用される可能性があります。本記事では動作確認のみに留め、実際に使用する場合は安全な運用方法について調査することを強く推奨します。
4.1 必要な設定ファイル
Asterisk で内線通話を実現するために、以下の2つの設定ファイルを最低限編集します。
作成したVMインスタンスにSSHで接続し、各種ファイルを編集します。
設定ファイルは/etc/asterisk/配下に配置されています。
4.1.1 pjsip.conf
SIPチャンネルドライバーであるPJSIPの設定ファイルです。
電話用端末に接続する内線用エンドポイントや認証情報を記述します。
今回は内線番号として 1001, 1002 の2エンドポイントを定義します。
4.1.2 extensions.conf
ダイヤルプラン(発着信時の動作ルール)の設定ファイルです。
電話の発信・着信時にどのような処理を行うかをContextと呼ばれる単位で定義します。
今回は内線用のコンテキストを作成し、1001と1002 を取り扱う発信ルールを設定します。
4.2 pjsip.conf の設定
Asterisk の PJSIP 設定 /etc/asterisk/pjsip.conf を編集し、内線通話に必要な最小限の設定を行います。
▶︎ pjsip.conf
```conf
[transport-udp-nat]
type = transport
protocol = udp
bind = 0.0.0.0:5060
local_net = {VMインスタンスの内部IP}/20
external_signaling_address = {VMインスタンスの外部IP}
external_media_address = {VMインスタンスの外部IP}
[1001]
type = endpoint
transport = transport-udp-nat
context = internal
disallow = all
allow = ulaw,alaw
auth = 1001
aors = 1001
direct_media = no
force_rport = yes
rtp_symmetric = yes
rewrite_contact = yes
[1001]
type = auth
auth_type = userpass
username = 1001
password = {任意の強力なパスワード}
[1001]
type = aor
max_contacts = 1
qualify_frequency = 60
[1002]
type = endpoint
transport = transport-udp-nat
context = internal
disallow = all
allow = ulaw,alaw
auth = 1002
aors = 1002
direct_media = no
force_rport = yes
rtp_symmetric = yes
rewrite_contact = yes
[1002]
type = auth
auth_type = userpass
username = 1002
password = {任意の強力なパスワード}
[1002]
type = aor
max_contacts = 1
qualify_frequency = 60
```
【ポイント】
[transport-udp-nat]: ここでは PJSIP の転送層(待受・NAT・公開IP)を定義しています
[1001] (endpoint): 内線1001のSIPクライアントの定義を行います。
[1001] (auth): 内線1001の認証設定です。
[1001] (aor): 内線1001のAOR(Address Of Record)で、登録Contactの保存や本数制限を制御します。
[1002]の内容については1001と同様なので割愛します
4.3 extensions.conf の設定
ダイヤルプランを設定するファイル、/etc/asterisk/extensions.confに内線用コンテキストとしてinternalを作成し、内線 1001 / 1002 を相互に呼び出せるようにします。
▶︎ extensions.conf
```conf
[internal]
; 1001 に着信があった場合
exten => 1001,1,Dial(PJSIP/1001,15,r)
same => n,Hangup()
; 1002 に着信があった場合
exten => 1002,1,Dial(PJSIP/1002,15,r)
same => n,Hangup()
```
【ポイント】
exten => 1001,1,Dial(PJSIP/1001,15,r): 1001に着信があったら1001で接続しているSIPクライアントに電話を送ることを設定しています。
▶︎ ↓細かい解説を読んだ方が面白いので興味があれば読んでみてください。↓
`exten =>(※1) 1001(※2),1(※3),Dial(※4)(PJSIP/1001(※5),15(※6),r(※7))`
※1... 「どの番号(内線や電話番号)に電話が来たとき、何をするか」を定義する行。
※2... Asteriskが受け取った電話番号。1001に電話があったら、、、という設定内容。
※3... 本設定の優先順位。実行順番に近いイメージ。
※4... 何を行うかを設定する箇所。今回はDialなので、電話を繋ぐ、という設定内容。
※5... Dialの引数。どこにを表しており、今回は1001の内線番号を持つ端末に、という設定内容。
※6... Dialの引数。待機時間を表している。今回は15秒間待機する設定内容。
※7... Dialのオプション。Asteriskが発信者に対して自前の呼び出し音を鳴らす設定内容
この設定により、「1001に電話があったら、1001に接続している端末に電話に出るまで最大15秒間待ちながら、発信者にリングオン(Prrrr...)を流す」設定となっている
なお、Dial() が終了したタイミングで次のステップ(same =>の行)に進む
具体的には、下記のいずれかのタイミング
- 通話がつながりどちらかが切った
- 1001が15秒かけたが出なかった
- 1001にかけたが通話中だった
`same(※1) => n(※2),Hangup()(※3)`
※1... 同じ内線の流れを続けるという内容。続きを記載するイメージ。
※2... 優先順位を自動的に直前の設定の+1で入れる。なので、ここでは2となっている。
※3... 電話を切るという設定内容
これにより、一つ目のダイヤルプラン設定内容は
1. 「1001に電話があったら、1001に接続している端末に電話に出るまで最大15秒間待ちながら、発信者にリングオン(Prrrr...)を流す」
2. Dial処理が完了したら、通話を終了する
4.4 内線通話テスト
Asterisk サービスを再起動するか、Asterisk CLI上で設定を反映します。
# サービス再起動 $ sudo service asterisk restart # AsteriskCLIで設定反映 $ sudo asterisk -rvvvvv *CLI> pjsip reload *CLI> dialplan reload
4.4.1 クライアント登録
iPhone の SIP ソフトフォンに 1001、macOS「Telephone」アプリに 1002 を設定。(逆でも可)
設定方法はそれぞれ設定から(SIP)アカウント追加を行えるので、下記内容で登録してください。
名前: {内線番号 ex. 1001, 1002}
ドメイン: {VMインスタンスの外部IP:{設定したポート番号}}
パスワード: {pjsip.confで設定したパスワード}
登録ステータスが Registered やAvailableになれば成功です。
【Tips】
もしうまく接続できない場合、sudo asterisk -rvvvvvでログを見ながら試してみると良いです
このとき、接続しようとしているのに何もログが出ていない、という事象があれば何かしらのネットワーク設定に誤りがある可能性があります。
特に下記をチェックしてみましょう
- VMインスタンスの外部IP、内部IP(特に静的IPを予約していない場合)
- firewall設定
- VMインスタンス、firewallのネットワークタグ
4.4.2 通話試験
では、実際に内線通話を試してみましょう
内線1001から内線1002に発信し、1002側が着信・応答して通話可能なことを確認します
逆も同様に確認します
なお、登録状況や通話の様子は Asterisk CLI で確認できるので、どんなログが出ているのか見てみると面白いです
$ sudo asterisk -rvvvvv
ちなみに、v(Verbose)の数が多ければ多いほど細かいログが出ます(最大5個)
5. TwilioとAsteriskの連携
この章では、Twilio Elastic SIP TrunkingとAsteriskを接続し、外線の発信・着信を行います。
AsteriskにTwilio SIP Trunkingと接続するための設定を追加します。
最終的にTwilioを経由した外線との発信・着信ができることをテストします。
5.1 Asterisk側のTwilio Elastic SIP Trunkingとの接続設定
/etc/asterisk/pjsip.confに下記を追記します
▶︎ pjsip.conf
```conf
; =====================
; Twilio SIP Trunk (Outbound)
; =====================
[twilio-trunk]
type=endpoint
transport=transport-udp-nat
context=from-twilio
disallow=all
allow=ulaw,alaw
outbound_auth=twilio-auth
aors=twilio-aor
[twilio-auth]
type=auth
auth_type=userpass
username={Twilio SIP Trunk用のUsername}
password={Twilio SIP Trunk用のPassword}
[twilio-aor]
type=aor
contact=sip:{Twilio SIP TrunkのTermination SIP URI}.pstn.tokyo.twilio.com:5060
; =====================
; Twilio SIP Trunk (Inbound)
; =====================
[twilio-inbound]
type=endpoint
transport=transport-udp-nat
context=from-twilio
disallow=all
allow=ulaw,alaw
aors=twilio-inbound-aor
direct_media=no
rtp_symmetric=yes
force_rport=yes
rewrite_contact=yes
[twilio-inbound-aor]
type=aor
max_contacts=1
[twilio-inbound-identify]
type=identify
endpoint=twilio-inbound
match=54.65.63.192/30
```
【ポイント】
[twilio-trunk] (endpoint): Twilioへの発信用エンドポイントで、Termination(外線発信)時の接続先と認証を定義します。
[twilio-auth] (auth): TwilioのTermination向け認証情報です。
[twilio-aor] (aor): Twilioの接続先を示すAORです。
[twilio-inbound] (endpoint): TwilioからのOrigination(着信)を受け付けるエンドポイントを定義します。
[twilio-inbound-aor] (aor): Twilio着信用エンドポイントのAOR設定です。
[twilio-inbound-identify]: Twilioからの通信だけを正しく受け入れられるよう、受け入れる送信元IPアドレスを定義します。
5.2 外線発信・受信ルールの定義
下記の外線発信・受信用の設定をextensions.confに追記して、外線との通話をできるようにしましょう
▶︎ extensions.conf
```conf
include => outbound
[outbound]
exten => _0X.,1,NoOp(外線発信: ${CALLERID(num)} -> ${EXTEN})
same => n,Set(CALLERID(num)={Twilio SIP Trunkに登録したTwilio番号, ex. +8150xxxxxxxx})
same => n,Set(DIALNUM=${EXTEN})
same => n,ExecIf($["${DIALNUM:0:1}"="0"]?Set(DIALNUM=+81${DIALNUM:1}))
same => n,Dial(PJSIP/${DIALNUM}@twilio-trunk,30)
same => n,Hangup()
[from-twilio]
exten => _{Twilio SIP Trunkに登録したTwilio番号, ex. +8150xxxxxxxx},1,NoOp(Twilio着信: ${EXTEN})
same => n,Dial(PJSIP/1002,30)
same => n,Hangup()
```
【ポイント】
include => outbound: [inbound]のダイヤルプランに、[outbound]も含める指示
exten => _0X.,1,NoOp(外線発信: ${CALLERID(num)} -> ${EXTEN}): 0から始まり、次の値が数字(X)で、それ以降に何かしら1文字が入っている(.)番号のダイヤルプランを定義(※)
※ 今回は例のため緩いルールで設定していますが、実際に使用する場合は厳密に電話番号のルールをカスタマイズしたほうが良いでしょう
5.3 外線通話テスト
まず、編集した設定ファイルを反映しましょう
$ sudo asterisk -rvvvvv *CLI> pjsip reload *CLI> dialplan reload
5.3.1 発信テスト
設定ファイル反映後、SIPクライアントから自分の携帯電話等に電話をかけてみましょう
実際に電話がかかってきて、通話することができれば成功です
5.3.2 受信テスト
自分の携帯電話等から、SIP Trunkingに登録されているTwilio番号に電話をかけてみましょう
今回は内線1001に割り当てているので、1001のSIPクライアントに電話がかかってきて、通話することができれば成功です
6. 応用設定
ここまでの内容で内線同士の通話、内線から外線への発信、外線から内線への発信をできるようになりました。
この章では、少し応用の例として、より"固定電話"として運用できるよう、下記を実装してみましょう
6.1 複数端末での同時着信
固定電話といえば子機があることで複数の機器が同時に着信音を鳴らしてくれると思います。
ということで、ここでは複数端末で同時に着信させてみましょう。
extensions.confの外線からの受信部分のダイヤルプラン修正しましょう
6.1.1 before
exten => _{Twilio SIP Trunkに登録したTwilio番号, ex. +8150xxxxxxxx},1,NoOp(Twilio着信: ${EXTEN})
same => n,Dial(PJSIP/1002,30)
same => n,Hangup()
6.1.2 after
exten => _{Twilio SIP Trunkに登録したTwilio番号, ex. +8150xxxxxxxx},1,NoOp(Twilio着信: ${EXTEN})
same => n,Dial(PJSIP/1001&PJSIP/1002,30)
same => n,Hangup()
【ポイント】
修正内容はシンプルです。
same => n,Dial(PJSIP/1001&PJSIP/1002,30)にてDial先を&で並列で指定することができるため、ここで指定を追加しています。
6.2 内線の順次呼出
ここまでの内容で固定電話っぽくなったと思います。
勘の良い方であればAsteriskの便利さ、カスタマイズ性に気付いたと思います。
ということで"固定電話"として運用することを考えた時にせっかくなので従来の"固定電話"をカスタマイズし、内線を同時ではなく順番に呼び出すようにしましょう
6.2.1 before
exten => _{Twilio SIP Trunkに登録したTwilio番号, ex. +8150xxxxxxxx},1,NoOp(Twilio着信: ${EXTEN})
same => n,Dial(PJSIP/1001&PJSIP/1002,30)
same => n,Hangup()
6.2.2 after
exten => _{Twilio SIP Trunkに登録したTwilio番号, ex. +8150xxxxxxxx},1,NoOp(Twilio着信: ${EXTEN})
same => n,Dial(PJSIP/1001,30)
same => n,Dial(PJSIP/1002,30)
same => n,Hangup()
【ポイント】
こちらも修正内容はシンプルです。
same =>の行はその行が完了したら次の優先度の行を実行するため、1001へのDialを実行した後に1002へDialするようにしています。
本章を通してAsteriskの勘所がわかってきたのではないでしょうか
7. まとめと次のステップ
7.1 本記事で構築した内容の整理
本記事では、TwilioとAsteriskを組み合わせて"固定電話"のような通話環境を構築しました。
ざっと本記事で行った内容をまとめると下記のようになります。
- クラウド環境準備: GCP上にAsteriskをインストールしたVMインスタンスを作成し、必要なファイアウォールルールを設定しました。
- Asterisk基本設定: VMにインストールしたAsteriskに対し、
pjsip.confとextensions.confを編集して内線環境を構築しました。内線番号1001と1002のエンドポイントを作成し、内線同士で通話できる最低限のダイヤルプランを設定しました。 - TwilioSIPトランク準備: TwilioコンソールでElastic SIP Trunkingを設定しました。接続を許可するIPアドレスの設定、credential設定を行い、Termination(発信側)とOrigination(受信側)の設定を行い、購入済みの050番号をこのTrunkに割り当てました。
- AsteriskとTwilioの連携設定: Asterisk側でTwilioのSIPトランクに接続するための設定を追記しました。
pjsip.confにはTwilio用の設定を、extensions.confには外線受発信用のダイヤルプランを定義しました。 - 応用設定: 応用例として、複数端末での同時着信を実装しました。また、着信順を指定する従来の固定電話にはないカスタマイズ例も試しました。
以上が本記事で構築・検証した内容の概要です。最後に、完成した Asterisk の設定ファイル全文を示します。
7.1.1 /etc/asterisk/pjsip.conf(最終版):
▶︎ /etc/asterisk/pjsip.conf
```conf
[transport-udp-nat]
type = transport
protocol = udp
bind = 0.0.0.0:5060
local_net = {VMインスタンスの内部IP}/20
external_signaling_address = {VMインスタンスの外部IP}
external_media_address = {VMインスタンスの外部IP}
[1001]
type = endpoint
transport = transport-udp-nat
context = internal
disallow = all
allow = ulaw,alaw
auth = 1001
aors = 1001
direct_media = no
force_rport = yes
rtp_symmetric = yes
rewrite_contact = yes
[1001]
type = auth
auth_type = userpass
username = 1001
password = {任意の強力なパスワード}
[1001]
type = aor
max_contacts = 1
qualify_frequency = 60
[1002]
type = endpoint
transport = transport-udp-nat
context = internal
disallow = all
allow = ulaw,alaw
auth = 1002
aors = 1002
direct_media = no
force_rport = yes
rtp_symmetric = yes
rewrite_contact = yes
[1002]
type = auth
auth_type = userpass
username = 1002
password = {任意の強力なパスワード}
[1002]
type = aor
max_contacts = 1
qualify_frequency = 60
; =====================
; Twilio SIP Trunk (Outbound)
; =====================
[twilio-trunk]
type=endpoint
transport=transport-udp-nat
context=from-twilio
disallow=all
allow=ulaw,alaw
outbound_auth=twilio-auth
aors=twilio-aor
[twilio-auth]
type=auth
auth_type=userpass
username={Twilio SIP Trunk用のUsername}
password={Twilio SIP Trunk用のPassword}
[twilio-aor]
type=aor
contact=sip:{Twilio SIP TrunkのTermination SIP URI}.pstn.tokyo.twilio.com:5060
; =====================
; Twilio SIP Trunk (Inbound)
; =====================
[twilio-inbound]
type=endpoint
transport=transport-udp-nat
context=from-twilio
disallow=all
allow=ulaw,alaw
aors=twilio-inbound-aor
direct_media=no
rtp_symmetric=yes
force_rport=yes
rewrite_contact=yes
[twilio-inbound-aor]
type=aor
max_contacts=1
[twilio-inbound-identify]
type=identify
endpoint=twilio-inbound
match=54.65.63.192/30
```
7.1.2 /etc/asterisk/extensions.conf(最終版):
▶︎ /etc/asterisk/extensions.conf
```conf
[internal]
; 内線 1001 に着信があった場合の処理
exten => 1001,1,Dial(PJSIP/1001,15,r)
same => n,Hangup()
; 内線 1002 に着信があった場合の処理
exten => 1002,1,Dial(PJSIP/1002,15,r)
same => n,Hangup()
include => outbound
[outbound]
exten => _0X.,1,NoOp(外線発信: ${CALLERID(num)} -> ${EXTEN})
same => n,Set(CALLERID(num)={Twilio SIP Trunkに登録したTwilio番号, ex. +8150xxxxxxxx})
same => n,Set(DIALNUM=${EXTEN})
same => n,ExecIf($["${DIALNUM:0:1}"="0"]?Set(DIALNUM=+81${DIALNUM:1}))
same => n,Dial(PJSIP/${DIALNUM}@twilio-trunk,30)
same => n,Hangup()
[from-twilio]
exten => _{Twilio SIP Trunkに登録したTwilio番号, ex. +8150xxxxxxxx},1,NoOp(Twilio着信: ${EXTEN})
same => n,Dial(PJSIP/1001,30)
same => n,Dial(PJSIP/1002,30)
same => n,Hangup()
```
7.2 応用例
前述した通り、Asteriskを使用することでカスタマイズ性の高いPBX機能を独自で設定することが可能です。
Asteriskの柔軟性を活かすことで、例えば下記のような応用が可能です。
- 自動音声ガイダンス: 着信に誰も出られなかった場合に、自動で留守番電話のメッセージを受け取ったり、案内音声を再生することができます。
- API連携: ダイヤルプラン内でAPIを叩くことも可能です。自作したAPIサーバーと連携することでよりカスタマイズ性の高い電話システムになります。
- AIを使った自動応答: WebSocket等を経由してLLMと連携し、AIが電話に出て用件を応対するといった高度な仕組みも実現できます。
このように工夫次第で、"電話"自体をより便利に扱うことができることはAsteriskを用いる最大の魅力だと思います。
7.3 最後に
本記事を通じて、電話システムの奥深さや Asterisk の面白さに少しでも興味を持っていただけたなら幸いです。
私自身、電話技術は一切知らない状態でしたが、ハローについて調べる中で電話 × AIという未知の領域に好奇心がくすぐられ、調べれば調べるほど楽しそうなプロダクトだなというので入社して今に至ります。
「電話にAIをシームレスに接続させたい」というミッションを達成するべく、今もサービス向上に全力で励んでいます。
もし「電話 × AI」の新たな活用にチャレンジしてみたいという思いを持っていただけたなら、ぜひHelloXチームで一緒にハローの未来を創り上げていきましょう!