Asterisk 20 サンプル設定ファイル 解説

2024年7月24日 (水) 12:10時点におけるTakahashi (トーク | 投稿記録)による版

Asterisk 20以降用のサンプル設定ファイルの内容を解説します。Asteriskの勉強用に読んでください。
『読み物』になっています。地道に読んでください。Asteriskの基本知識はある程度必要です。

目次

extensions.conf

globals

;
; グローバル設定(変数類)
;
[globals]
;外線発信時の自局番号
MYNUMBER=0312345678
;外線発信時のトランク名
MYTRUNK=outbound-trunk
;PPIセット時のドメイン
PPIDOMAIN=ntt-east.ne.jp
;外線着信させる内線番号(カンマ区切り)
RINGPHONES=201,202

最初のセクション "globals" ではグローバル変数を定義します。Asteriskの変数は明示的にグローバルと宣言されない限り、チャネル依存です。チャネルは呼が発生してから破棄されるまでAsteriskの内部に存在するのでチャネル変数はその呼内だけの "ローカル" となります。言い換えると、ある通話内で使っているローカル変数は別な通話から参照することはできません。
これに対してグローバル変数はAsterisk全体で設定/参照することができます。
グローバル変数を予め定義しておくには "globals" というセクション(コンテキスト)に書いておきます。

default

defaultコンテキストはみなさん無意識にdefaultを使っていますが、defaultである必要はなく、エンドポイントcontext=で定義するものです。これはそのエンドポイントが発信等を行う際にどのコンテキストで処理するかを指定します。つまりエンドポイントでcontext=defaultと設定されていると発信処理はこのコンテキストを使用するということになります。

内線処理部

[default]
;
;内線処理(1~9から始まる番号)
;
;内線はDBで抽象化されているので内線番号はDBに設定する
;例: database put MYPBX/EXT 201 phone1
;この設定では内線201はエンドポイントphone1となる
exten => _Z.,1,NoOp(内線)
;SIPメッセージングの場合の処理
exten => _X.,n,Set(MTARGET=${EXTEN})
exten => _X.,n,GotoIf($["${CHANNEL(name)}"="Message/ast_msg_queue"]?sipmsg,s,1)
;自局情報を取得してセット
exten => _Z.,n,Gosub(sub-whoami,s,1)
;内線番号が割り当たってなければ発信させない
exten => _Z.,n,GotoIf($["${MY_EXTEN}"=""]?nogo)
;内線番号に対応するエンドポイントをDBから取得
exten => _Z.,n,Set(TARGET=${DB(MYPBX/EXT/${EXTEN})})
;PJSIPのdial contactsに変換
;注意:ダイヤル先がREGISTERされていない場合でもCONTACTSは空になる
;(pjsip show contactsの結果を参照)
exten => _Z.,n,NoOp(${PJSIP_DIAL_CONTACTS(${TARGET})})
exten => _Z.,n,Set(TARGET=${PJSIP_DIAL_CONTACTS(${TARGET})})
;ターゲットが空(Dial先のエンドポイントがない)なら終了
exten => _Z.,n,GotoIf($["${TARGET}"=""]?nogo)
;Dialを実行
exten => _Z.,n,Dial(${TARGET})
exten => _Z.,n(nogo),Hangup

まず内線間の通話を行うための処理が書かれています。このダイヤルプランでは『内線はゼロ以外の数字から始まる』番号と定義しています。

exten => _Z.

おっといけません。extenの書き方を説明していませんでした。extenはAsteriskにおけるダイヤルプランそのもののことでエンドポイント、つまりは電話機等からダイヤルされた番号をどう処理するかを書きます。書き方にはいくつかあるのですが筆者はこの書き方が好きです。

exten => 123,1,NoOp(123)
exten => 123,n,Dial(PJSIP/123)

このような書き方をします。123の部分はexten、sまたはnの部分はpriority、NoOpやDialが書かれている部分にはAsteriskのアプリケーションあるはファンクションと呼ばれる処理を書きます。一般的な書式は以下のようになります。

exten => exten,priority,app

extenは同じ処理は同じextenを書きます。priorityは必ず"1"から始めなくてはいけません。そしてその次のpriorityは2,3,4...とひとつづつ増やしますが、"n"を書くと勝手に前のpriority +1と解釈されます。つまり先ほどの例は

exten => 123,1,NoOp(123)
exten => 123,2,Dial(PJSIP/123)

と同じことになっていたわけです。
さてそれでは実際のサンプル設定ファイルに戻りましょう。extenが何やら呪文めいています。

exten => _Z.1,NoOp

priorityは理解してもらえたと思います。extenが謎ですね。これはパターンマッチといって番号の規則に一致するようにextenを書いています。先頭のアンダーバー(_)はパターンマッチを使う、Zは1~9の数字、ドット(.)はそれに続く任意のものという意味です。つまりこのextenは111であれ123であれ2001であれ201であっても一致するパターンということになります。ただし0123にはマッチしません。
内線番号として1~9で始まる番号はすべて内線として扱うという意味になります。
_Z.は1~9で始まるどんな番号にでもマッチするのでダイヤル先として例えば2001を実行すると当然マッチします。このときAsteriskの組み込み変数、EXTENは2001となります。

続いて以下の処理

;SIPメッセージングの場合の処理
exten => _X.,n,Set(MTARGET=${EXTEN})
exten => _X.,n,GotoIf($["${CHANNEL(name)}"="Message/ast_msg_queue"]?sipmsg,s,1)

この部分はSIPを使ったメッセージング用です。SIPのメッセージを受け取った場合にはファンクション、CHANNEL()の'name'エントリが Message/ast_msg_queueになるので、もしその文字列であったならばGoto(GotoIf)でコンテキストがsipmsg、extenがs、プライオリティが1の場所にジャンプします。メッセージング処理については後で解説します。

次の部分はちょっとしたポイントです。

exten => _Z.,n,Gosub(sub-whoami,s,1)
;内線番号が割り当たってなければ発信させない
exten => _Z.,n,GotoIf($["${MY_EXTEN}"=""]?nogo)

このダイヤルプランでの設計は『内線を抽象化』することにあります。Asteriskのサンプル設定でよくあるのはエンドポイントと内線番号をイコールにするものですがこの方法は処理が簡単になる反面、内線番号の付けなおしなどが面倒になります。ある電話機の設定が例えばエンドポイント名2001で内線2001だった場合にこの内線を2010にしたいといった場合にはエンドポイントの設定を2010に修正、つまりは電話機の設定を変更しなくてはいけなくなります。
これに対して抽象化されている内線ではエンドポイント名(設定)は常に同じものとし、内線番号とエンドポイントは『別な』方法で紐付けを行います。
さて、本題に戻りましょう。上記の処理が何をしているかというとGosubによってサブルーチンsub-whoamiを呼び出しています。ここでお気付きかもしれませんが、AsteriskにおけるGotoやGosubは常にAsteriskのextenの書式で行われるため、Gosub(context,exten,priority)のかたちで記述します。要するにプログラミング言語の一種なのですがAsteriskの書式ではジャンプしたり呼び出すにはcontext,exten,priorityのかたちとなるわけです。
sub-whoamiは後で説明しますが、内線が抽象化されていることにより電話機自体は自分の番号を「知りません」このためAsteriskに登録されているエンドポイントと内線番号を参照してエンドポイント名から内線番号を求めるという処理をsub-whoamiが行っています。
sub-whoamiは内線が登録されているとMY_EXTENという変数に内線番号をセットします。もしエンドポイントに対応する内線が登録されていない場合には値はありません。内線番号が登録されていない電話機からは発信させないようにMY_EXTENが空ならば"nogo"にジャンプします。"nogo"って何?と思われたでしょう。この"nogo"は内線処理部の最後の個所

exten => _Z.,n(nogo),Hangup

ここです。プライオリティの個所にカッコ書きで書かれているのはラベルで同一context、exten内であればそのラベルが設定されているpriorityにジャンプします。コンテキストをまたいでジャンプする場合には先ほどのGotoのようにcontext,exten,prioritのかたちでジャンプさせます。


発信側の情報が取得できたので相手先(着信側)にダイヤルさせるようになるのですが、内線を抽象化しているため、内線番号からエンドポイントに変換しなくてはなりません。

;内線番号に対応するエンドポイントをDBから取得
exten => _Z.,n,Set(TARGET=${DB(MYPBX/EXT/${EXTEN})})

内線番号とエンドポイントの紐付けはAstDBで行っています。DBのファミリ MYPBX/EXTのキーが内線番号、値がエンドポイントです。DBファンクションでエンドポイント名を求めます。

;PJSIPのdial contactsに変換
;注意:ダイヤル先がREGISTERされていない場合でもCONTACTSは空になる
;(pjsip show contactsの結果を参照)
exten => _Z.,n,NoOp(${PJSIP_DIAL_CONTACTS(${TARGET})})
exten => _Z.,n,Set(TARGET=${PJSIP_DIAL_CONTACTS(${TARGET})})
;ターゲットが空(Dial先のエンドポイントがない)なら終了
exten => _Z.,n,GotoIf($["${TARGET}"=""]?nogo)

エンドポイントを取得した後はPJSIPの"contacts"を取得します。これはPJSIPでは同一エンドポイントに複数のエンティティ、つまりは電話機がレジストすることができるためで、親子電話のように複数の電話機をひとつのエンドポイントとして扱うことができるためです。エンドポイントがレジストしてきていない場合にはこの結果は空になります。
これでようやくダイヤルすることができます。

exten => _Z.,n,Dial(${TARGET})

内線の処理は以上です。

WIP