Asterisk
Asterisk1 はオープンソースの電話通信アプリケーションであり、GPLv2 で配布されています。短くまとめてしまえば、Asterisk とは通話の発信、受信、およびその他のカスタムされた処理を行うためのアプリケーションです。
Asterisk プロジェクトは Mark Spencer によって 1999 年に開始されました。Mark は当時 Linux Support Services という会社を経営しており、ビジネスを管理するための電話システムが必要だったのです。他の会社からシステムを買うだけの大金を持っていなかったので、彼は自分で作ってしまいました。Asterisk が成長するにしたがって Linux Support Services は事業を Asterisk に集中し、社名は Digium, Inc. に変更されました。
Asterisk という名前は Unix のワイルドカード文字 * (asterisk, アスタリスク) から来ています。Asterisk プロジェクトの目標は、その名前の通り、電話に関係するあらゆることを行うことです。この目標を追求してきた結果として、現在 Asterisk は通話の発信と受け取りのためのテクノロジを大量にサポートしています。旧来の電話ネットワーク PSTN (Public Switched Telephone Network, 公衆交換電話網) はアナログとデジタルの両方がサポートされるのはもちろん、様々な VoIP (Voice over IP) プロトコルもサポートされます。システムを通すことで様々な種類の通話が可能になるというのが、Asterisk の一番の強みです。
Asterisk システムを通じて通話を行うと、通話に対する様々な追加機能を利用できます。ボイスメールのようにそれ自身でたくさんの機能を持つアプリケーションとなっている機能もありますし、他にも音楽ファイルの再生、数字の読み上げ、音声認識など、音声アプリケーションを作るときのパーツとして利用できる小さな機能もあります。
中心的なアーキテクチャのコンセプト
この節では Asterisk アーキテクチャの基礎となるコンセプトをいくつかを説明します。どれも Asterisk の全ての部分において重要な役割を果たします。
チャネル
Asterisk におけるチャネル (channel) とは、Asterisk システムと通話エンドポイントとの接続のことです (図 1.1)。この接続の最も典型的な例は、ある電話が Asterisk システムを使った通話を行う場合です。この場合、Asterisk コードにおける ast_channel
データ構造のインスタンスが作成されます。例えば通話者がボイスメールを使うときなどにこのような通話が作成されます。
チャネルのブリッジ
もっと身近な例としては、次に示す二つの電話の間の通信があります。電話 phone A
が電話 phone B
に電話を掛ける次のシナリオでは、Asterisk システムに接続する二つの通話エンドポイントに対応する二つのチャネルが作成されます (図 1.2)。
このように接続されている Asterisk チャネルのことをチャネルブリッジ (channel bridge) と言います。またチャネルをブリッジするとは、二つのチャネルを繋いでその間でメディアをやり取りできるようにすることを言います。チャネルを通してやり取りされるメディアは通常オーディオのストリームですが、ボイスやテキストのストリームもやり取りできます。複数のメディア (オーディオとビデオなど) を同時にやり取りする場合でも、そのやり取りは単一の Asterisk のチャネルによって処理されます。図 1.2 では phone A
と phone B
に対するチャネルが一つずつあり、その間のブリッジが A から B へ向かうメディアおよび B から A に向かうメディアの管理を受け持ちます。二つのデバイスの間のメディアストリームは全て Asterisk を通して行われ、Asterisk が理解できない、あるいは Asterisk に完全な制御を許さない通信方式は使うことができません。こうすることで Asterisk は、オーディオを録音したり、改変したり、異なるテクノロジの間で変換したりできるようになっています。
二つのチャネルをブリッジする方法は二つあります。つまり、ジェネリックブリッジ (generic bridge) と ネイティブブリッジ (native bridge) です。一つ目のジェネリックブリッジはチャネルで使われているテクノロジに関係なく動作するブリッジであり、ジェネリックブリッジを通してオーディオやシグナルをやり取りすると、そのデータは Asterisk の抽象的なチャネルインターフェースを通してやり取りされます。この抽象化があるおかげでジェネリックブリッジは最も柔軟な方式となっていますが、抽象レイヤーが必要となるために最も効率の悪い方式でもあります。図 1.2 に示したのはジェネリックブリッジの例です。
二つ目のネイティブブリッジはテクノロジに特有な方法で作成されるチャネル間の接続です。二つのチャネルが同じメディア転送テクノロジを使って Asterisk に接続している場合、Asterisk の抽象レイヤーを通して行う任意のテクノロジに対応した通信よりも効率的な通信が存在することがあります。例えば専用のハードウェアと電話網を使って通信を行う場合、メディアは Asterisk を経由する必要が全くありません。また VoIP プロトコルでは、エンドポイント同士がメディアストリームをお互いに直接送り合うことで、サーバーに渡す情報をシグナルだけにできます。
ジェネリックブリッジとネイティブブリッジのどちらを使うかの判断は、ブリッジを作成するときに二つのチャネルを比べることで行われます。二つのチャネルが同じ方式のネイティブブリッジをサポートしている場合にはネイティブブリッジが使われ、そうでない場合にはジェネリックブリッジが使われるということです。二つのチャネルが同じネイティブブリッジをサポートしているかどうかの判定には、C の関数ポインタの比較という単純な方法が使われます。もちろんこれは最もエレガントな方法ではありませんが、これを使うと私たちがやりたいことができないというケースに出くわしたことはこれまでにありません。チャネルに対するネイティブブリッジ用の関数を作る方法は 1.2 節で扱います。図 1.3 にネイティブブリッジの例を示します。
フレーム
通話を処理している間、Asterisk 内部の通信はフレーム (frame) を使って行われます。フレームは ast_frame
データ構造のインスタンスであり、メディアフレームとシグナルフレームという二つの種類があります。通常の通話を行うと、オーディオを含んだメディアフレームのストリームがシステムの中でやり取りされます。シグナルフレームが伝達するのは通話イベントに関するメッセージ、例えば押された数字の桁、通話が保留状態になったという情報、通話が切られたという情報などです。
利用可能なフレームは静的に定義されます。フレームの種類はタイプとサブタイプで表され、数値によってエンコードされます。フレームのリストは /include/asterisk/frame.h
で確認できます。いくつか例を示します:
-
VOICE
: オーディオストリームの一部を伝達するフレーム。 -
VIDEO
: ビデオストリームの一部を伝達するフレーム。 -
MODEM
: T.38 やファックスなどの、IP を通してやり取りされるデータを含んだフレーム。このフレームタイプは主にファックスの送受信に使われる。重要なこととして、このタイプのフレームに含まれるデータを少しでも変更すると、相手のデバイスは正しくデータをデコードできなくなる。これはAUDIO
フレームなどの、データを変換することでクオリティを犠牲にして帯域を節約できるフレームとは異なる。 -
CONTROL
: シグナルメッセージを伝達するフレーム。通話が返答を受けた、切られた、保留になったなどのイベントを表す。 -
DTMF_BEGIN
: 最初に押された数字の桁を表すフレーム。このフレームは通話を発信するデバイスで DTMF のキー2が押されたときに送られる。 -
DTMF_END
: 最後に押された数字の桁を表すフレーム。このフレームは通話を発信するデバイスで DTMF のキーが押されなくなったときに送られる。
Asterisk の抽象コンポーネント
Asterisk は高度に抽象化されたアプリケーションです。Asterisk のコアのアプリケーションはソースコードツリーの asterisk/main
ディレクトリにあるソースコードからビルドできますが、これ自体が何か機能を持っているというわけではありません。コアのアプリケーションはモジュールの登録場所であり、モジュールの抽象的なインターフェースを組み合わせて実際に通話を行うためのプログラムとなっています。インターフェースの実装はモジュールとして実行時に読み込まれます。
Asterisk に組み込まれている全てのモジュールはメインアプリケーションが開始されたときに読み込まれ、デフォルトでは Asterisk のモジュールディレクトリから読み込みます。私たちがこの動作を選択した理由はその単純性です。これに対してどのモジュールをどの順番で読み込むかを指定するための設定ファイルも存在します。このファイルを使うと設定が多少複雑になりますが、必要にならないモジュールを読み込まないようにできます。こうする一番の理由はメモリの節約ですが、セキュリティ的にも利点があります。例えばアプリケーションが通信を行わないなら、通信を行うモジュールは読み込まないのが一番です。
モジュールを読み込むと、モジュールに含まれる全ての抽象コンポーネントの実装が Asterisk のコアアプリケーションに登録されます。Asterisk のコアとして実装・登録できるモジュールのインターフェースにはたくさんの種類があり、一つのモジュールはそのインターフェースに対する実装をいくつでも持つことができます。通常は似た機能に対する実装が一つのモジュールにまとめられます。
チャネルドライバ
Asterisk のインターフェースの中で最も複雑で最も重要なのは、チャネルドライバ (channel driver) です。Asterisk チャネル API は通話プロトコルを抽象化し、これによって Asterisk の他の機能が使われている通話プロトコルに関係なく動くようになります。チャネルドライバは、この抽象化された Asterisk のチャネルと通話テクノロジの詳細との間の変換を行います。
Asterisk のチャネルドライバインターフェースは ast_channel_tech
構造体で定義され、この構造体はチャネルドライバが実装すべきメソッドをいくつか定義しています。そのようなメソッドの中で一つ目にあるのが requester
であり、これは ast_channel
のファクトリメソッドです。通話の発信または受信によって Asterisk のチャネルが作られるとき、 ast_channel_tech
に含まれるその通話に応じた種類の requester
の実装が ast_channel
のインスタンス化と初期化を行います。
初期化以外にもテクノロジごとに異なる方法で行わなければならない処理はたくさんあるので、 ast_channel
には作成時に使われた ast_channel_tech
への ポインタが含まれます。テクノロジによって異なる処理が必要になると、 ast_channel
はその処理を ast_channel_tech
に委譲します。図 1.2 ではブリッジされた二つの Asterisk チャネルを示しましたが、ブリッジされている二つのチャネルのテクノロジの実装をこの図につけ足したものを 図 1.4 に示します。
ast_channel_tech
の中で重要なメソッドをいくつかあげます:
-
requester
:ast_channel
オブジェクトのインスタンス化とチャネルの種類に応じた初期化をチャネルドライバに要請する。 -
call
:ast_channel
で表されるエンドポイントからの通話の発信を行う。 -
answer
:ast_channel
からの通話を受理し、返答を行う。 -
hangup
: 通話を切断する。チャネルドライバはプロトコルに応じた方法を使って通話が終了したことをエンドポイントに伝える。 -
indicate
: エンドポイントにイベントが起きたことを伝える。伝えられるイベントは例えば相手のデバイスが保留になったことなどである。この関数によって保留になったことを示すシグナルがプロトコルに特有の方法でエンドポイントに送られる場合もあるし、保留状態用の音声の再生が始まる場合もある。 -
send_digit_begin
: デバイスに数字の桁 (DTMF) の始まりが送られていることを伝える。 -
send_digit_end
: デバイスに数字の桁 (DTMF) の終わりが送られていることを伝える。 -
read
: エンドポイントからのast_frame
を読む。上述の通り、ast_frame
とは (オーディオやビデオなどの) メディアやシグナルイベントを表すために Asterisk が使う抽象オブジェクトである。 -
write
: デバイスへast_frame
を送る。チャネルドライバは受け取ったデータを実装されている通話プロトコルを使ってパケット化し、エンドポイントへ送る。 -
bridge
: チャネルタイプに対応するネイティブブリッジのコールバック。上述の通り、ネイティブリッジが作成されるのは同じ種類の二つのチャネルの間を結ぶ効率の良いブリッジをチャネルドライバが実装できるときである。この場合にはシグナルとメディアのストリームが抽象レイヤーを通り抜け無くなるので、ネイティブブリッジは効率のために非常に重要である。
通話が終わると、抽象レイヤーのチャネルを管理する Asterisk コードは hangup
コールバックを呼び出し、 ast_channel
を破棄します。
ダイヤルプランのアプリケーション
Asterisk の管理者は、 /etc/asterisk/extensions.conf
にあるダイヤルプラン (dialplan) を使ってルーティングを設定します。ダイヤルプランはエクステンション (extension) と呼ばれる通話のための規則がいくつか集まって出来ています。呼び出しがシステムに到着すると、Asterisk はダイヤル番号を使ってダイヤルプランの中から通話処理を行うエクステンションを検索します。エクステンションにはそのチャネルに対して実行するダイヤルプランアプリケーションのリストが含まれます。ダイヤルプランが含むことができるアプリケーションの一覧はレジストリで管理され、このレジストリは実行時にモジュールが読み込まれるのと同じタイミングで作られます。
Asterisk には 200 近い組み込みのアプリケーションがあります。ただし“アプリケーション”の定義はかなりゆるいです。発信者にオーディオファイルを再生するプレイバックのように一つのタスクだけを行うアプリケーションもありますし、ボイスメールのようにはるかに規模の大きい複雑な処理が絡むアプリケーションもあります。アプリケーションはチャネルとのやり取りに Asterisk の内部 API を全て利用できます。
Asterisk のダイヤルプランを使うと、通話の制御に複数のアプリケーションを使えるようになります。ダイヤルプランでは不可能なさらに詳細な制御が必要になる場合には、任意のプログラミング言語で書くことができるスクリプトインターフェースも利用できます。ただし他のプログラミング言語によるスクリプトインターフェースを使う場合でも、チャネルとやり取りのときにはダイヤルプランのアプリケーションが使われます。
例を見ていく前に、まずは Asterisk のダイヤルプランのシンタックスを見てみましょう。次に示すのは、 1234
という番号に対する発信を制御するダイヤルプランです。誰かがこの番号に電話を掛けると、二つのアプリケーションが起動されます。つまり通話を受理し、オーディオファイルを再生し、通話を切るという処理が行われます。ここで 1234
という数字の選択は恣意的なことに注意してください。
; 誰かが 1234 という番号にかけてきたときの規則を定義する。
;
exten => 1234,1,Answer()
same => n,Playback(demo-congrats)
same => n,Hangup()
ここで exten
はエクステンションの定義の始まりを表す予約語です。 exten
の右側にある 1234
は、今定義しているエクステンションが 1234
という番号への発信に対する規則であることを表します。次の 1
は、この規則がこの番号に対して行われる最初の規則であることを表し、最後の Answer
は、発信を受理するという処理を表します。次の二行の行頭にある same
は、その行の規則が一行目で作られるエクステンションに対するものであること、つまりここでは 1234
に対する規則であることを表します。 n
は“次にこれをする”を表し、最後の部分が行う処理を表します。
Asterisk のダイヤルプランの例をもう一つ示します。ここでは受け取った通話に答え、ビープ音を再生し、4 桁の数字を相手から読み、数字を DIGITS
変数に格納し、数字を音声で読み上げ、通話を切ります。
exten => 5678,1,Answer()
same => n,Read(DIGITS,beep,4)
same => n,SayDigits(${DIGITS})
same => n,Hangup()
前述の通り“アプリケーション”の定義はとてもゆるく、実際の関数のプロトタイプもとても単純です:
int (*execute)(struct ast_channel *chan, const char *args);
しかしそれでも、アプリケーションの実装は include/asterisk
にある API のほとんど全てを利用できます。
ダイヤルプランの関数
ほとんどのダイヤルプランアプリケーションは文字列を引数として受け取ります。文字列の値のハードコードもできますが、変数を使って動的な動作をさせることもできます。次に示すコードでは変数に値を設定し、その値を Verbose
アプリケーションを使って Asterisk のコマンドラインインターフェースに出力しています。
exten => 1234,1,Set(MY_VARIABLE=foo)
same => n,Verbose(MY_VARIABLE is ${MY_VARIABLE})
ダイヤルプランの関数はアプリケーションと同じシンタックスで呼び出されます。関数は Asterisk のモジュールによって登録されます。関数はダイヤルプランからデータを受け取って、加工したデータを返したり、何らかの処理を行ったりします。通常関数はチャネルのメタデータを読み書きするだけで、通話の発信やメディアの処理を行うことはありません。そのようなことを行うのはダイヤルプランアプリケーションです。
関数の使用例を次に示します。まずチャネルの呼び出し ID を Asterisk のコマンドラインインターフェースに出力し、それから呼び出し ID の値を Set
アプリケーションを使って変更しています。この例では Verbose
と Set
がアプリケーションであり、 CALLERID
が関数です。
exten => 1234,1,Verbose(The current CallerID is ${CALLERID(num)})
same => n,Set(CALLERID(num)=<256>555-1212)
ここで変数ではなくて関数が必要になるのは、呼び出し ID が ast_channel
データ構造のインスタンスの中に入っているからです。関数のコードにはデータ構造から情報をどう取り出すか、およびどう変更するかが書かれています。
別の関数の使用例として、通話履歴 (Call Detail Records, CDR) に好きな情報を追加する処理を示します。 CDR
関数が通話履歴に含まれる情報の読み書きを行っています。
exten => 555,1,Verbose(Time this call started: ${CDR(start)})
same => n,Set(CDR(mycustomfield)=snickerdoodle)
コーデックの変換
VoIP においては、メディアをネットワークを通して送るときに様々なコーデックが使用され、コーデックによってメディアの質、CPU の使用量、要求される帯域の間にトレードオフがあります。Asterisk はたくさんのコーデックをサポートしており、必要になった場合にはコーデックの間で変換を行います。
通話を始めるにあたって、Asterisk は二つのエンドポイントの間で共通して利用可能なメディアコーデックを検索し、変換処理を省略できないかを調べます。しかしそのようなコーデックが存在するとは限りませんし、仮にあったとしても変換が必要になることもあります。例えば Asterisk がシステムを通り抜ける信号に対して何らかの処理 (ボリュームを上下させるなど) を行うように設定されていた場合、オーディオは一度非圧縮な状態に変換されるでしょう。また Asterisk が通話を録音するように設定されていて、保存される通話データのコーデックが通話で使われるものと違う場合にも、変換が必要になります。
メディアストリームで使用するコーデックの調整に使われる方法は、Asterisk への接続に使われているテクノロジによって異なります。従来の電話網 (PSTN) などケースでは、調整が全く必要ないでしょう。しかし IP プロトコルを使うようなケースでは、対応可能なコーデックとその優先順位を双方が提示し、その中から一番良いコーデックを決められた方法によって選択します。
例えば SIP (最も良く使われる VoIP プロトコル) では、Asterisk を使った通話が開始されるときのコーデックの調整は次のように行われます
-
エンドポイントが Asterisk に新しい通話リクエストを送る。そのとき、使いたいコーデックのリストも送る。
-
Asterisk には管理者によって設定される利用可能なコーデックとその優先順位のリストがあるので、双方が利用可能なコーデックの中で一番優先度の高いものを見つける。
コーデックの調整はこれまでの十年間で複雑になってきましたが、特にビデオなどの複雑なコーデックは Asterisk が上手く扱うことができません。これからの開発では新しいオーディオコーデックのサポートの追加や、ビデオコーデックに対するより良いサポートを行っていきます。これらは Asterisk の次のメジャーリリースに向けた開発において一番優先度の高い課題です。
コーデック変換モジュールは ast_translator
インターフェースを実装します。変換モジュールには変換元と変換先のフォーマットというフィールドがあることを確認してください。またメディアのチャンクのフォーマットを変換するメソッドもあります。この実装は通話に関することを何も知らず、フォーマットの変換だけを行います。
変換 API についてのより詳細な情報は include/asterisk/translate.h
と main/translate.h
を参照してください。コーデック変換の実装は codecs
ディレクトリにあります。
スレッド
Asterisk は徹底的にマルチスレッド化されたアプリケーションです。スレッドの管理には POSIX スレッド API のロックなどが使われます。デバッグを簡単にするために、Asterisk とスレッドの間のやり取りはラッパー関数を通して行われます。Asterisk のほとんどのスレッドはネットワークモニタースレッドかチャネルスレッドです (チャネルスレッドの目的は PBX のことが多いので、PBX スレッドと呼ばれることもあります)。
ネットワークモニタースレッド
ネットワークモニタースレッドは Asterisk の主要なチャネルドライバごとに作成されます。このスレッドはチャネルに接続されたネットワーク (IP ネットワークや PSTN など)、およびそこからやってくる通話やリクエストを監視します。このスレッドは他にも認証やダイヤル番号の確認などの接続の初期化処理も行います。接続の初期化が完了すると、モニタースレッドは Asterisk チャネル (ast_channel
) のインスタンスを作成し、このインスタンスに関する処理を行うチャネルスレッドを作成します。
チャネルスレッド
前述したように、チャネルは Asterisk の基礎となるコンセプトです。チャネルには外向きのものと内向きのものがあります。内向きのチャネルは Asterisk システムへの発信が行われたときに作成されます。Asterisk のダイヤルプランを実行するのもこのチャネルです。ダイヤルプランを実行する内向きのチャネルごとにスレッドが作成され、このスレッドのことがチャネルスレッドと呼ばれます。
ダイヤルプランアプリケーションは必ずチャネルスレッドのコンテキストで実行されなければなりません。ダイヤルプランの関数はそうでなくても構いませんが、ほとんど常にチャネルスレッドのコンテキストで実行されます。Asterisk CLI などの非同期インターフェースを使ってダイヤルプランの関数を読み書きすることが可能ですが、その場合でもチャネルスレッドが ast_channel
データ構造を所有し、オブジェクトの生存期間を管理します。
通話シナリオ
これまでの二つの節で、Asterisk のコンポーネントの重要なインターフェースを二つ紹介し、さらにスレッドについても説明しました。この節では Asterisk のコンポーネント同士が通話処理においてどのように協調するのかを、よく見られる通話シナリオを使って解説します。
ボイスメールの確認
一つ目のシナリオは、誰かが通話システムに電話をかけてボイスメールを確認するというものです。このシナリオにおいて最初に登場するのはチャネルドライバであり、電話からやってきた通話リクエストをチャネルドライバのモニタースレッドが感知し、初期化処理が行われます。使われている通話テクノロジに応じて、通話の初期化に調整処理が必要になる場合もあります。また通話の初期化するときには通話相手の識別も行われます。普通はダイヤルされた番号によって通話相手が指定されますが、アナログ電話のようにテクノロジによってはダイヤル番号を伝える手段が存在しないことがあります。
Asterisk の設定ファイルで定義されるダイヤルプランの中に、ダイヤルされた番号に対するエクステンションがあることをチャネルドライバが確認すると、Asterisk のチャネルオブジェクト (ast_channel
) が作成され、チャネルスレッドが起動されます。このチャネルスレッドが通話に関する以降の処理を行います (図 1.5)。
チャネルスレッドのメインループがダイヤルプランの実行を制御します。つまり、このスレッドはダイヤルされた番号に対するエクステンションを探し、定義されたステップに沿って実行していきます。次に示すのは extensions.conf
で定義されるエクステンションの例です。このエクステンションでは、 *123
というダイヤルがかかってきたときに VoicemailMain
アプリケーションを実行します。このアプリケーションを使うと、発信者のメールボックスに未読メッセージがあるかどうかを確認できます。
exten => *123,1,Answer()
same => n,VoicemailMain()
チャネルスレッドが Answer
アプリケーションを実行すると、Asterisk は発信に応答します。発信への応答はテクノロジごとに異なる処理なので、共通の処理に加えて ast_channel_tech
構造にある answer
コールバックも呼び出されます。このコールバックで行われる処理の例としては、IP ネットワークを通じた特殊なパケットの送信、あるいはアナログの電話網におけるオフフック処理があります。
チャネルスレッドの次の処理は VoicemailMain
の実行です (図 1.6)。このアプリケーションは app_voicemail
モジュールによって提供されます。ここで重要なこととして、ボイスメールのコードはあらゆる種類の通話を処理できる一方で、このコードは Asterisk システムとエンドポイントの間の通話に使われているテクノロジについて何も知らないということがあります。Asterisk のチャネルという抽象化によって、使われているテクノロジについての詳細が隠蔽され、ボイスメールの実装はテクノロジの詳細を考慮する必要がなくなるのです。
ボイスメールには様々な機能がありますが、突き詰めてしまえばどの機能も発信者から受け取った入力に応じてオーディオファイルを読み書きしているだけです。発信者からの入力は数字のボタンを押すことで与えられますが、そのときの詳細な処理はチャネルドライバが行います。押されたボタンの情報は Asterisk に届いた後に一般的なボタン押下イベントに変換され、それがボイスメールのコードに渡されます。
前にコーデック変換モジュールについて説明しましたが、この通話シナリオではこのモジュールの実装がとても重要になります。ボイスメールのコードが再生するオーディオファイルのフォーマットは通話者と Asterisk システムの間の通信で使われるフォーマットと同じであるとは限らないので、そのような場合にはコーデックの変換するパスが作成されます。
しばらくすると通話者はボイスメールシステムとのやり取りを終えて電話を切ります。チャネルドライバはこのことを検知し、Asterisk システムにチャネルシグナルイベントを通知します。ボイスメールのプログラムはこのイベントを受け取り、実行を終了します。その後制御はチャネルスレッドのメインループに戻り、ダイヤルプランの実行が続けられます。このシナリオではボイスメールの後には処理が無いことから、チャネルドライバにテクノロジごとに異なる通話終了処理をする指示が出され、その後 ast_channel
オブジェクトが破棄されます。
ブリッジされた通話
Asterisk でよくあるシナリオとして次に考えるのは、二つのチャネルがブリッジされた通話です。これは通話者が Asterisk システムを使って他のデバイスに通話を行ったときのシナリオです。初期化処理はボイスメールの例と全く同じです。通話が初期化され、チャネルスレッドがダイヤルプランの実行を始めたときから異なる動作が行われます。
次の単純なダイヤルプランを使うとブリッジされた通話を行うことができます。このエクステンションでは、1234
への通話は外向きの通話を開始するときに使われる Dial
アプリケーションを起動します。
exten => 1234,1,Dial(SIP/bob)
Dial
アプリケーションの引数は、 SIP/bob
というデバイスへの外向きの通話を行うことを示しています。 SIP
という部分は通話で SIP プロトコルを使うことを表し、 bob
という部分は SIP プロトコルを実装するチャネルドライバ chan_sip
への引数です。チャネルドライバに bob
というアカウントがあるとすれば、このエクステンションは Bob への通話を開始します。
Dial
アプリケーションは SIP/bob という識別子を持った新しいチャネルを作成するよう Asterisk コアに指示を出し、コアはテクノロジ固有の初期化処理を行うよう SIP チャネルドライバに指示を出します。チャネルドライバは指定されたデバイスへ通話を行うプロセスを作成します。このプロセスはリクエストを処理する間にいくつかのイベントを Asterisk コアに送ります。例えば、通話が応答された、通話先は話し中である、ネットワークが混雑している、何らかの理由で通話が拒否された、などのイベントです。全てが上手く行けば通話は応答を受け、その情報が通話元のチャネルに伝えられます。Asterisk は外向きの通話が応答を受けるまでシステムにかかってくる発信の一部に答えることができなくなります。両方のチャネルが応答を受けて初めて、チャネル間のブリッジが始まります (図 1.7)。
チャネルがブリッジされている間、一方のチャネルからのオーディオイベントとシグナルイベントはもう一方のチャネルに伝えられ、このやり取りはどちらかが通話を切るなどのブリッジを停止させるイベントが起こるまで続けられます。ブリッジを使った通話においてオーディオフレームに対して行われる主要な操作を 図 1.8 に示します。
通話が終了した後の処理はボイスメールの例とほとんど同じです。一番の違いは二つのチャネルが存在することであり、チャネルスレッドはテクノロジごとに異なる終了処理をそれぞれのチャネルに対して行ってから停止します。
最後に
Asterisk のアーキテクチャが誕生してから十年以上が経過していますが、チャネルという基礎的なコンセプトとダイヤルプランを使った柔軟な通話制御は変化しておらず、進化を続ける産業における複雑な通話システムの開発をサポートし続けています。Asterisk のアーキテクチャが上手く扱えない問題としては、複数のサーバーを使ったときのスケーリングがあります。Asterisk の開発コミュニティは現在 Asterisk SCF (Scalable Communications Framework) という補助プロジェクトに取り組んでおり、これはスケーラビリティの問題を改善することを目的としています。今後数年の間に、Asterisk SCF が加わった Asterisk が通話マーケットの大部分を勝ち取り、はるかに多いインストール数を達成するでしょう。
-
DTMF は Dual-Tone Multi-Frequency の略であり、受話器で数字キーを押すと流れる“ピ・ポ・パ”というトーンのことです。[return]