🤖

Raspberry PiでCTI(Computer Telephony Integration)システムを構築する

2021/02/25に公開

はじめに

先日、コンタクトセンターの自動応答をTwilioからAmazon Connectに移行しましたが(記事はこちら)、今度はCTI(Computer Telephony Integration)を再構築する機会があったので、設定方法をご紹介します。

弊社CTIの仕組み

弊社CTIの仕組み

  1. 顧客がコンタクトセンターに電話をかける。
  2. オフィスの電話が鳴り、同時にFreePBXが着信する。
  3. FreePBXが着信電話番号をDBに書き込む。
  4. 電話番号とリレーションした顧客情報がオペレーターの画面に表示される。
  5. オペレーターは顧客情報やコンタクト履歴等を確認しながら、余裕を持って電話対応できる。

電話が鳴ってから顧客情報が表示されるまで1秒以内なので、オペレーターは電話を取る前に様々な情報を知ることができ、よりスムーズに対応することが可能になります。

AsteriskとFreePBXおよびRasPBXの関係

弊社のCTIはFreePBXが中心になっています。FreePBXはオープンソースのIP−PBXソフトウェアですが、同名のLinuxディストリビューションのことを指す場合もあります。FreePBXのコア部分はAsteriskでできています。Asteriskは単体でIP-PBXとしての機能を持っているので、環境構築と設定ファイルの準備さえすれば、FreePBXなしでもIP-PBXの構築は可能です。ただしAsteriskの設定はかなり難しく、私は一度挑戦して諦めたことがあります。下図は/etc/asteriskにあるファイルの例です。

Asterisk設定ファイル群

FreePBXはGUIで設定できるので(下図参照)、Asteriskの設定ファイル群を直接編集するよりは楽です。ある程度は依存関係をチェックしてくれますし、項目名毎にヘルプがあるのもありがたいです。それでもIP-PBXの設定はすごく難しいのですが…。

FreePBX設定の例

FreePBXをRaspberry Piでも動くようにしたのがRasPBXです。弊社のCTIはそこそこ速いマシンにFreePBXディストリビューションをインストールして動かしていますが、今までは予備機がなかったので今回RasPBXを使って予備機の構築に挑戦してみました。

Basix側の準備

PBX設定

brastelに依頼してCTI用のユーザーIDとSIPアカウントを発行してもらいます。CTI用のアカウントができたら、Basixの管理画面でCTIを導入したい外線着信グループに所属させます。BasixではユーザーIDを追加しただけではSIPアカウントは発行されないので、明示的に依頼する必要があります。

FreePBXの設定に必要な情報は以下の4つです。

  • SIPサーバーのドメイン(xxxxx.brastel.ne.jp)
  • Proxy(basix-proxy.brastel.ne.jp)
  • CTI用ユーザーのSIPアカウント
  • CTI用ユーザーのSIPパスワード

ドメイン以外の情報はBasixの管理画面では取得できないので、アカウント発行時に控えておきましょう。

RasPBXのインストール

以下のURLから最新のモジュール(zip形式)をダウンロードし、解凍しておきます。

http://www.raspberry-asterisk.org/downloads/

SDカードのマウント先を確認します。Mac以外の環境の方はこちらを参考にしてください。

$ diskutil list
/dev/disk3 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *7.8 GB     disk3
   1:                 DOS_FAT_32 NO NAME                 7.7 GB     disk3s1

アンマウントします。

$ sudo diskutil unmountDisk /dev/disk3
Unmount of all volumes on disk3 was successful

ddでSDカードに書き込みます。30分ほどかかりました。

$ sudo dd bs=1m if=~/Downloads/raspbx-10-10-2020.img of=/dev/disk3
3836+1 records in
3836+1 records out
4022338560 bytes transferred in 1996.343506 secs (2014853 bytes/sec)

インストール後の各種設定

SSHでログイン

SSHでRasPBXにログインします。初期パスワードはraspberryです。Mac以外の環境の方はraspbx.localraspbxに読み替えてください。

~ $ ssh root@raspbx.local
The authenticity of host 'raspbx.local (fe80::156:3d9:fac2:4daf%en5)' can't be established.
ECDSA key fingerprint is SHA256:vtE5/AgzCttW9heTjeiUdUwACyoanIphwbJhT5OwmDQ.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'raspbx.local,fe80::156:3d9:fac2:4daf%en5' (ECDSA) to the list of known hosts.
root@raspbx.local's password:
Linux raspbx 5.4.51-v7+ #1333 SMP Mon Aug 10 16:45:19 BST 2020 armv7l

Welcome to RasPBX - Asterisk for Raspberry Pi

RasPBX is based on Debian. The programs included with the Debian GNU/Linux
system are free software; the exact distribution terms for each program are
described in the individual files in /usr/share/doc/*/copyright.

RasPBX comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

List of RasPBX specific commands:
-----------------------------------------------------------------------------
raspbx-upgrade      Keep your system up to date with the latest add-ons and
                    security fixes
configure-timezone  Set timezone for both system and PHP
install-fax         Install HylaFAX
add-fax-extension   Add additional fax extension for use with HylaFAX
install-fail2ban    Install Fail2Ban for additional security
install-dongle      Install GSM/3G calling capability with chan_dongle
raspbx-backup       Backup your complete system to an image file

root@raspbx:~#

ファイルシステムの拡張

最初はSDカードのサイズに関わらず4GBのディスクスペースしか使えません。

root@raspbx:~# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root       3.5G  2.4G  952M  72% /
devtmpfs        431M     0  431M   0% /dev
tmpfs           463M     0  463M   0% /dev/shm
tmpfs           463M   13M  450M   3% /run
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           463M     0  463M   0% /sys/fs/cgroup
/dev/mmcblk0p1  253M   55M  198M  22% /boot
tmpfs            93M     0   93M   0% /run/user/0

SDカードの容量をフル活用するにはraspi-configコマンドを実行します。

raspi-config1

raspi-config2

raspi-config3

raspi-config4

画像の通り実行していくとファイルシステムがSDカードの上限まで拡張されます。

root@raspbx:~# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root       6.9G  2.4G  4.3G  36% /
devtmpfs        431M     0  431M   0% /dev
tmpfs           463M     0  463M   0% /dev/shm
tmpfs           463M  7.2M  456M   2% /run
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           463M     0  463M   0% /sys/fs/cgroup
/dev/mmcblk0p1  253M   55M  198M  22% /boot
tmpfs            93M     0   93M   0% /run/user/0

/dev/rootのサイズが3.5GBから6.9GBになりました。

パスワードの変更

root@raspbx:~# passwd
New password:
Retype new password:
passwd: password updated successfully

タイムゾーンの設定

configure-timezoneを実行し、Asia → Tokyoの順に選択します。

root@raspbx:~# configure-timezone

Current default time zone: 'Asia/Tokyo'
Local time is now:      Fri Feb 19 16:21:13 JST 2021.
Universal Time is now:  Fri Feb 19 07:21:13 UTC 2021.

Setting PHP to system timezone: Asia/Tokyo

ロケールの設定

dpkg-reconfigure localesを実行し、ja_JP.UTF-8を追加します。

root@raspbx:~# dpkg-reconfigure locales
Generating locales (this might take a while)...
  en_GB.UTF-8... done
  en_US.UTF-8... done
  ja_JP.UTF-8... done
Generation complete.

OSのアップデート

パッケージリストを更新します。

apt update

インストール済みのパッケージをアップグレードします。

apt full-upgrade

RasPBX独自のアップグレードを行います。

raspbx-upgrade

アップグレード時にできたキャッシュを削除します。

apt clean

再起動します。

reboot

FreePBXの設定

FreePBXの設定項目は多岐にわたります。ここではBasixに接続してCTIを実現するのに必要な設定に絞って説明します。

初期設定

ブラウザで http://raspbx.local/ にアクセスします。Mac以外の環境の方は http://raspbx/ です。

初期設定

図のような初期設定画面へ遷移するので管理者のIDとパスワードを設定します。ちなみにこのキャプチャだけはアップグレード前に撮ったので、最新版ではデザインが変わっていると思います。

トランクの設定

chan_pjsipの追加

「接続」→「トランク」でトランク設定画面を表示し、「トランクを追加」から「SIP(chan_pjsip)トランクを追加」を選択します。

General設定

Generalタブでは「トランク名」と「アウトバウンドCID」を設定します。どちらも任意の値で構いません。

pjsip_general設定

「pjsip設定」タブ内の「General」タブではユーザー名、Secret、SIP Server、SIP Server Portを設定します。SIP Server Portは通常のSIPサーバーでは5060です。

pjsip_高度な設定_1

pjsip_高度な設定_2

pjsip_高度な設定_3

「pjsip設定」タブ内の「高度な設定」ではOutbound Proxy、クライアントURI、Server URI、Message Contextを設定します。

設定項目 設定値
Outbound Proxy sip:basix-proxy.brastel.ne.jp
クライアントURI sip:{ユーザー名}@{SIP Server}
Server URI sip:{SIP Server}
Message Context 任意の値

カスタム宛先の設定

カスタム宛先の追加

「アドミン」→「カスタム宛先」でカスタム宛先設定画面を表示します。

カスタム宛先設定

カスタム宛先ではTargetと説明を設定します。Targetは「コンテキスト,exten,優先度」という形式で記述します。ここではcti,s,1としました。

インバウンドルートの設定

インバウンドルートの追加

「接続」→「インバウンドルート」でインバウンドルート設定画面を表示します。

インバウンドルートを追加

「インバウンドルートを追加」をクリックします。

インバウンドルートの設定

インバウンドルートは「説明」と「宛先をセット」を設定します。「宛先をセット」では先ほど作成したカスタム宛先を選択してください。

extensions_custom.confの編集

最後にブラウザからは設定できない/etc/asterisk/extensions_custom.confを編集します。

extensions_custom.conf
[cti]
exten => s,1,NoOp(${CALLERID(name)})
exten => s,2,Log(NOTICE,${CALLERID(name)})
exten => s,n,AGI(inbound.py)
exten => s,n,Return()

exten => s,n,AGI(inbound.py)が特に重要です。

この設定により、電話がかかってくる度に/var/lib/asterisk/agi-bin/inbound.pyが実行されます。ここではPythonにしましたが、どんな言語でも実行可能です。

設定適用

すべての設定が完了したら「設定適用」をクリックします。

CTI用プログラムの作成

サンプルとしてFirestore上に電話番号を格納するCTIプログラムを作成しました。/var/lib/asterisk/agi-binに配置してください。Firebaseの設定は調べればすぐに分かるので省略します。

inbound.py
#!/usr/bin/python3
import datetime
import firebase_admin
import json
from asterisk.agi import *
from firebase_admin import credentials
from firebase_admin import firestore
from pytz import timezone

now = datetime.datetime.now(timezone('UTC'))    # タイムスタンプ

# firebase初期処理
cred = credentials.Certificate('{Firebase認証用JSONファイルのパス}')
firebase_admin.initialize_app(cred)

# 着信時の情報を取得
agi = AGI()
caller_id = agi.env['agi_callerid'] # 着信電話番号

# Firestoreに書き込み
db = firestore.client()
doc_ref = db.collection('inbound').document()
doc_ref.set({
    'phone_number': caller_id,
    'timestamp': now,
})

モジュールのインストール

pip3をインストールします。

apt install python-pip python3-pip

Firebase Admin SDKをインストールします。

pip3 install firebase-admin

Asterisk用インターフェースをインストールします。

pip3 install pyst2

inbound.pyに実行権限を追加します。

chmod +x inbound.py

動作確認

/var/log/asterisk/fullを表示しながら電話をかけてみます。

tail -f /var/log/asterisk/full

ログに電話番号およびres_agi.c: Launched AGI Script /var/lib/asterisk/agi-bin/inbound.pyという内容が表示されていれば成功です。

Firestore

Firestore上には新たなドキュメントが追加されます。電話番号と顧客情報を紐づけてフロント側を作れば、CTIシステムの完成です。

終わりに

Asteriskの設定ファイルを書くのはかなり難しいですが、FreePBXはブラウザからポチポチ入力すればなんとなく動く設定が作れるので面白いですよ。内線電話網の構築や、通話録音、IVR、FAXの送受信など、およそ電話関連の機能は一通りそろっているので、小規模な事業所ならこれだけで本格的なコールセンターを構築できます。外線接続周りの設定は難しいですが、挑戦してみてはいかがでしょうか。

Discussion