asteriskでIVR(自動音声応答)を構築する

今年に入ってから国信大の事務室の電話がIP化したそうです。(新しい国信大の電話番号は050-5438-6933)
IP化により、ただ電話機で受けるだけではない高度な電話サービスを簡単に実現することができます。自動音声応答もその一つですよね。
そこで、久々にちょっと電話ハックということ自動音声応答(Interactive Voice Response, IVR)を自作してみようと思います。

IVRの構築に必要なものは3つあります。1つは当然ですが電話回線が必要ですよね。2つ目も当然ですが自動音声応答で流れる音声です。そして3つ目がIVRを実装するPBXサーバーです。(PBXっていうのは構内交換機のことです。)

電話回線についてはSIPでレジストできる回線が必要です。NTTのひかり電話は固定電話の番号のままIP化(VoIP)できるので有名ですね。また、050番号のIP電話は多数の会社が提供していると思います。個人趣味でちょっと電話回線が欲しい場合は楽天コミュニケーションズか提供しているFUSION IP-Phone SMARTとかいいんじゃないかと思います。スマホの通話料金を節約するのに便利なサービスですが、番号が月額無料で発行できるのでありがたいです。無料で050番号が持てるサービスは他には050 Freeとかもあります。

自動音声応答で流す音声ですが、21世紀ですから声優やアナウンサーの友達がいなくても適当な方法で音声合成すればいいですよね。ゆっくりに喋らせてもいいですし、Google翻訳の読み上げ機能を使うこともできます。AWSの音声合成サービスのPollyなんかは完全ではないですが自然に近い音声を合成できるのでおすすめです。

そして本題のIVRを構築する方法ですが世の中にはTwillioなど便利なサービスがありますが有償で企業向けだったりするので個人では使いにくいです。無料で済ませるには自前のサーバーでオープンソースのIP-PBXであるAsteriskを動かすのが鉄板です。

Asteriskの導入

まず、サーバーにAsteriskを導入します。debianなら# apt-get install asteriskで一発でインスコできると思います。

次にSIPの設定です。/etc/asterisk/sip.confを編集します。INFファイルの要領で設定を書き換えます。

まず、忘れずに行いたいのは外部から勝手に発信されないようゲスト発信を許可しないことです。[general]セクションにallowguest=noを追加しましょう。

次にSIPアカウントの設定をします。SIPアカウントのログイン情報を用意して[general]セクションに以下を追記します。
register => ユーザー:パスワード@ドメイン
次にsip.confの末尾にもアカウント情報を記載します。

[適当なセクション名]
type=friend
username=ユーザー
fromuser=ユーザー
secret=パスワード
host=ドメイン
fromdomain=ドメイン
context=default
insecure=port,invite
canreinvite=no
disallow=all
allow=ulaw
allow=alaw
dtmfmode=inband
nat=yes

こんな感じで記載します。これでSIPアカウントの設定ができました。
次はいよいよ着信後の動作の設定をします。ここでIVRを組み立てます。/etc/asterisk/extensions.confを編集します。
IVR用のセクションの名前を仮にmy-ivrとでもしておきましょう。
まず、[default]セクションに着信したらmy-ivrセクションに飛ぶように以下の記述をします。
exten => SIPのユーザー,1,Goto(my-ivr,s,1)
これは(SIPのユーザー)への着信は1番目にmy-ivrセクションのsコンテキストの1番目に飛ぶという意味です。

my-ivrセクションを書いていきます。
IVRの流れは例として以下の流れで構築するとします。

  • 音声ファイルの場所は/home/asteriskとする
  • 着信したら5秒間呼び出し音を鳴らした後応答する
  • 最初に音声ファイルhelloを流す
  • 次に音声ファイルmenuを流すと同時に数字入力を受け付ける
  • 1の場合、message1-1、message1-2を流して終了
  • 2の場合、message2-1、message2-2を流して最初の選択に戻る
  • 3の場合、message3を流して1の場合に続ける
  • 無操作は1の場合に続ける
  • 誤った番号は音声ファイルinvalidを流して選択に戻る

上記のIVRの流れの設定をコメント付きで載せてみますのでこれを参考にいじれば自分だけの独自のIVRが構築できると思います。基本的に「exten => コンテキスト,順番,コマンド」を並べて記述します。コンテキストは最初はs、番号別の場合はその番号です。順番は同一コンテキスト内でのコマンドの実行順です。1からスタートして2,3,4…と続いていきますが番号を決め打ちすると後から編集する時に番号の振り直しが発生して大変なので2番目以降はnと書くことで前のコマンドの次と扱われます。

[my-ivr]
;exten => コンテキスト,順番,コマンド
;コンテキストsからスタートします
exten => s,1,Set(dir=/home/asterisk/) ;変数定義(音声ファイルのディレクトリ)
exten => s,n,Ringing() ;呼び出し中であることを明示する
exten => s,n,Wait(3) ;3秒待つ
exten => s,n,Answer() ;応答する
exten => s,n,Playback(${dir}hello) ;音声ファイル/home/asterisk/helloを再生
exten => s,n(menu),Background(${dir}menu) ;音声ファイルmenuを再生しつつ番号入力を受け付ける 後でここに飛べるようにn(名前)という感じで順番に名前をつけることができます。
exten => s,n,WaitExten(10) ;番号が入力されるまで待つ
exten => s,n,Goto(1,1) ;番号が入力され無かった場合コンテキスト1の1番に飛ぶ
;誤った番号(その番号のコンテキストが定義されてない)が入力されるとコンテキストiに飛びます。
exten => i,1,Playback(${dir}invalid) ;音声ファイルinvalidを再生
exten => i,2,Goto(s,menu) ;コンテキストsの順番n(menu)に飛ぶ
;番号選択で1が押されたらコンテキスト1に飛びます
exten => 1,1,Playback(${dir}message1-1)
exten => 1,n,Playback(${dir}message1-2)
;番号選択で2が押されたらコンテキスト2に飛びます
exten => 2,1,Playback(${dir}message2-1&${dir}message2-2) ; &で挟んで複数のファイルを指定できます
exten => 2,n,Goto(s,menu)
;番号選択で3がry)
exten => 3,1,Playback(${dir}message3)
exten => 3,n,Goto(1,1) ;コンテキスト1の順番1に飛ぶ

上記で音声ファイルを指定しましたが、音声ファイルはmp3とかはそのまま使えずgsmやulawでエンコードしたものを用意する必要があります。基本gsm形式で用意して、余裕があったらulawでも用意しておくのが良いと思います。(gsm形式だけでも十分です。)
音声ファイルの変換はsoxコマンドが使えます。
gsm形式に変換(拡張子は.gsm)
$ sox sound.mp3 -r 8000 -c 1 sound.gsm
ulawに変換(拡張子は.ulaw)
$ sox sound.mp3 -r 8000 -c 1 -e u-law -t wav sound.ulaw
extensions.confで音声ファイルを指定するときは拡張子を除いたファイル名を指定します。(sound.gsmファイルを再生したいときはPlayback(sound)って感じ)

設定ができたらasteriskを再読み込みすれば反映されます。(# systemctl reload asterisk)
asteriskが起動していなければ起動します。(# systemctl start asterisk)

# asterisk -vvvcrでasteriskのcliを起動できます。cliを起動後に表示されるログを見ながら電話をかけて動作を確認すればデバッグしやすいと思います。

いかがでしたか?
asteriskにはたくさんの機能がありますので色々組み合わせたら結構高度なことができるんじゃないかと思います。
21世紀は電話も情報化している時代です。ご家庭にある自宅サーバーにasteriskを導入すれば誰でも企業レベルの電話システムをおうちで実現することできます。
くれぐれもセキュリティには十分注意しましょう。勝手に発信されて国際電話されまくって高額な電話代を請求される被害が多いです。(僕も高校生の時、家電をasteriskにつなげて遊んでたら中東方面に国際電話されまくって涙目になったことがあります。数日で気がついたので諭吉数人の被害で済みました。諭吉数人が「これくらいで済んで良かった」と思うくらい国際電話の被害は恐ろしいです。昔のダイヤルQ2みたいな感じで途上国に国際電話して現地の電話会社からキックバックをもらうという手口らしいです。)
被害にあったからと言って電話会社は一切電話代を免除してくれないと思います。
asteriskに収容する電話回線は国際電話できない設定にする、サーバーのファイヤーウォールで外部からSIP接続は遮断するくらいは必要です。allowguest=noの設定も絶対に忘れないでください。