クラウドPBX、twilio で 050番号から外線発信
前回は、twilio で電話をクラウド化という記事の中で、twilio の Programmable Voice に SIP Domain を作成し、SIPクライアントを登録(SIP REGISTER)するところまでを一気に駆け抜けて説明しました。
今回は、前回の記事で作った SIPクライアントから、050番号を使って外部の電話へ発信してみます。他者の電話との接続には PSTN網を使います。内部で使ってるのが SIP、外部との接続が PSTN網です。PSTN網との接続では、指定の利用料金が掛かります。(ネガティブな話、この利用料金 = 通話料がかなり高いです。固定電話宛でも 5.5円/1分ほど掛かるので、他者の 050IP電話のような、通話料削減を目的とした使用にはオススメしません)
なお、PSTN網では発信、着信とも PSTN網で使う世界でユニークな電話番号が必要です。twilio では日本の電話番号として 050番号が取得できます。twilio では条件さえ満たせば、他国の電話番号も取得でき、カンタンに使える番号としては米国の電話番号が使えます。
2022-06-17追記:
050番号ではなく、03、06、052 といったいわゆる 0AB~J番号も自身で引いている回線を使えば、Twilio からの発着信も可能です。回線を接続するための機器と設定が必要です。設定方法は以下の記事で書きました。
アナログ電話回線を FXO ATA、Grandstream HT813 を使って Twilio に収容
0AB~J電話回線を Yeastar TA410 FXO ATA を使って Twilio に収容
追記終わり
050番号は、050-CDEF-GHIJ という形式の番号です。(CDEF-GHIJ には数字が入ります)
これは日本国内のドメスティックな表現で、電話番号の国際規格である ITU-T の E.164 では + から始まり、識別用の国・地域番号を含めた形式が使われます。先ほどの、050-CDEF-GHIJ を E.164形式で表すと、
+8150CDEFGHIJ
になります。+81 は日本を識別する国番号です。50CDEFGHIJ がユーザを識別する番号(ドメスティック表現の先頭にあった 0 は、日本国内の市外局番からの電話であることを識別するためのコードで、正確には電話番号の一部ではありません)です。今後、twilio の内部ではすべてこの E.164形式の番号を使う必要があるので注意が必要です。
この先の説明は、twilio で 050番号(もしくはどこかの国の番号)を取得済みという前提で行います。同じアカウント内で取得した 050番号は、用途に関係なく発信元として使えますが、それ以外の番号は自社で所有しているものであっても発信元としては使えません。(twilio が発信元の偽装を禁止している)
SIPクライアントから、PSTN網への接続の最初のインタフェイスは、Programmable Voice の SIP Domain で設定した、A CALL COMES IN です。comes in というと、外から入ってくるイメージになりますが、これは twilio から見て、SIPクライアントは外部なので、SIPクライアントから入り込んでくるコールという意味です。
A CALL COMES IN には Webhook、TwiML Bin、Function、Studio などが指定できるので他システムとの連携を行って高度なことを行うこともできますが、単純に外部へ発信するだけなら twilio でホストしてくれるアプリだけで可能です。細かい制御をやろうと思うと、JavaScript で記述できる Function を使いたいのですが、ここでは Studio を使ったルーティングを紹介します。
twilio console の左のメニューの中から、Studio を選びます。

Studio Dashboard が開いて作成済みの Studio の一覧が表示されます。リストの左上の「+」をクリックして、新しい Studio を作ります。

外部への発信なので、Outgoing という名前にしました。ここはわかりやすければ何でも良いです。

いくつかのテンプレートから作ることができますが、今回は空からスクラッチに書いていくので、Start from scratch. を選んで「Next」をクリックします。

Studio ではマウスで必要な機能を追加、接続していくことで視覚的にフローを作ることができます。
はじめ、Trigger が一つだけ置かれています。ここが起点になります。
右の一覧から、Connect Call To をドラッグして配置します。自動的に connect_call_1 という名前が付いたオブジェクトが配置されます。
Trigger の Incoming Call の左の丸をドラッグして、connect_call_1 の左上の丸へ接続します。

次に、connect_call_1 をクリックし、右の画面でプロパティを設定します。
CONNECT CALL TO で Single Number を選択し、{{trigger.call.to | replace: 'sip:', ''}} と入力します。この二重括弧で囲まれた表記は変数で、trigger.call.to には発信先の番号が含まれています。後半はフィルタです。replace は文字列置換のフィルタです。発信したい先は SIP ではないので、先頭の sip: を削除するように指定しています。
厳密には、SIP URI の後半の、@以降も削除する必要があるのですが、twilio では E.164形式の後ろに SIP URI のドメイン名が付いたフォーマットの場合、後半を無視して前半部の数字だけを E.164形式として認識するので削除せずに手抜きしています。(今後の仕様変更で、この小技は使えなくなる可能性があります)
CALLER ID は発信元の番号です。デフォルトで {{contact.channel.address}} という変数が入っています。これはこのままだと、発信に使う SIPクライアントの SIP URI(例えば、sip:3002@fugafuga.sip.twilio.com など)が入りますが、これは PSTN網に抜けていくに当たっては使用できないフォーマットなので変更する必要があります。
twilio で取得した 050番号を決め打ちで使う場合はカンタンです。変数にする必要はないので、取得した 050番号を E.164形式で記述してやります。
取得した 050番号が、050-3186-4000 だとすると、E.164形式では +815031864000 になります。
「Save」をクリックして設定を保存し、この Studio をデプロイします。デプロイは右上の、「Publish」をクリックします。

いま作った Studio を SIP Domain に設定します。
Programmable Voice、SIP Domains、該当の Domain まで進みます。
Call Control Configuration の中の、A CALL COMES IN が、発信に使う API の設定です。(twilio から見て、SIPクライアントから送られてくる向きなので、COMES IN になります)
Studio を選択して、さきほど作った Outgoing を指定します。
「Save」をクリックして設定を保存します。
SIPクライアントから発信テスト

MicroSIP から発信してみます。
宛先としては、E.164形式にする必要があるので、自分の携帯電話の番号を E.164形式に変えて「発信」してみます。

ちゃんと、指定の 050番号から発信されました。
自動で日本ローカルフォーマットを E.164形式に変換する
このままでも使えなくはないですが、電話をかけるたびに相手先の番号を E.164形式に変換して入力するのは面倒です。
そこで、Studio の Outgoing を少し編集して、0 が頭についた日本ローカルフォーマットの電話番号を、自動で E.164形式に変換してしまいます。

変更するのは、connect_call_1 の CONNECT CALL TO の欄です。
この欄は定数、変数、その他、Liquid Template Language という独自の言語を使うことができます。詳しい仕様はドキュメントを参照してください。
先ほどは、replace というフィルタを使って頭の sip: という文字列を削除しましたが、これを remove_first で先頭の sip:0 を削除し、prepend で +81 という文字列を書き加える、という処理を行います。
{{trigger.call.To | remove_first: 'sip:0' | prepend: '+81'}}
このまま、コピペして使っていただいて構いません。

これで、日本ローカルフォーマットの電話番号を使っても、自動的に E.164番号を使って接続することができました。
この記事ではデモのため、手抜きで対応させましたがこの実装には問題が残っています。全ての番号が、日本ローカルフォーマットであるという前提で組み立てているので、このままでは海外番号への発信ができません。例えば、米国に電話しようとして +1 920-990-0999 に掛けようとします。本来であれば、この電話番号を入力するだけで発信できるのですが、先頭に +81 を付与されてしまうため、+81sip:+19209900999 という異常な電話番号になってしまうため、エラーとなってしまいます。
他にも、ハイフォンを含んだ電話番号を入力された場合に、自動で除いていやるといったフィルタも考えられます。(通常は、ユーザがハイフンも入力したとしても、SIPクライアントが自動的に削除して発信するはずなので必要ありません)
このあたりの制御は、Liquid Template Language だけで記述することは不可能ではないのですが得策とは言えないので、別の機会に現実的な実装を紹介します。
追記:
さらに追加で remove_first: '+81sip:' を付ければ、いける気もしてきました。(テストしていません)
{{trigger.call.To | remove_first: 'sip:0' | prepend: '+81' | remove_first: '+81sip:'}}

いまの発信の様子はログとして閲覧することができます。
Programmable Voice、Calls、Call Logs と進んでいくとログが表示され、詳細も見ることができます。このようなナマのログに近いものがカンタンに見られるのが、twilio を使う上でのとても大きなメリットです。内部でなにをやっているかも包み隠さず見せてくれるので(なんと、通信のパケットも pcap形式で見ることができます)、デバッグしていく上で大きな味方になります。
SIPクライアントから twilio の向きが Incoming、twilio から PSTN網への発信が Outgoing Dial です。一つの発信には、必ずこの 2つのペアが作られます。
次の記事で、050番号宛の着信を SIPクライアントで受ける設定を紹介します。
目次
クラウドPBX、twilio で 050番号から外線発信 (この記事)
twilio に SIPクライアントを追加するときの注意(特にスマホ)
クラウドPBX、twilio を VoIPフォンで使う(Panasonic KX-UT248)