2008-01-16

AGI (Asterisk Gateway Interface) 勉強ノート2

Asteriskにもともと付属しているagi-test.agiと呼ばれるAGIスクリプトを細かく解析してみた。
・・・疲れた。

横長になって見づらいので、テキストファイルでほしい人は連絡してください。
コメントアウトのやり方がPHP(//←これ)なのは気にしないでください。

//agi-test.agi (perlも初心者なので一つ一つ解釈していきます)

#!/usr/bin/perl    //perlで書いていると宣言。perlバイナリが/usr/bin/perlにあるよ。
use strict;    //perlに宣言されていない変数などの起こり得るプログラミングのエラーに厳しく対処。

$|=1;    //perlに対して出力をまとめてから出力(バッファリング)せず、どんなデータもすぐに書き出すようにする。

# Setup some variables (変数のセットアップ)
my %AGI; my $tests = 0; my $fail = 0; my $pass = 0;    //AGI:Asteriskがスクリプトに渡す変数を格納するためのハッシュ、他はスカラ値tests:テストの総数、fail:失敗したテストの数、pass:合格したテストの数


//Asteriskが起動時にAGIプログラムに送る変数のグループをSTDINで受け取ってAGIという名前のハッシュに格納する。

while() {
chomp; //行末の改行を削除する(変数は1つごとに改行されているから)
last unless length($_);     //文字列長が0だったらループ終了
if (/^agi_(\w+)\:\s+(.*)$/) {    //送られてくる変数(例、agi_request: test.py)の書式に合わせ正規表現で記述
$AGI{$1} = $2;     //$AGI(agi_request) = test.pyのように読みとった変数を代入
}
}


//AGIハッシュに格納した値をそれぞれSTDERRに書き込む

print STDERR "AGI Enviroment Dump:\n";
foreach my $i (sort keys %AGI) {     //foreach 一時変数 (対象) 対象の内容を順次読み込み一時変数に代入 ※対象:sort keys %AGI keysがよくわからない??
print STDERR " -- $i = $AGI{$i}=\n";    //格納された値をSTDERRに書き込む
}


//AsteriskからAGIコマンドの結果を読み込み、その結果をデコードして、テストが合格か失敗かを判定

sub checkresult {    //サブルーチン checkresultを宣言
my ($res) = @_;    //配列 res?
my $retval;    //変数 retval?使ってない?
$tests++;    //testsを1回実行するのでカウント
chomp $res;    //$res の改行を削除
if ($res =~ /^200/) {     //resの先頭が200であれば真
$res =~ /result=(-?\d+)/;     //resは±数字である?
if (!length($1)) {    //resの値?が0だったら失敗。
print STDERR "FAIL ($res)\n";
$fail++;     //失敗したのでfailをカウント
} else {
print STDERR "PASS ($1)\n";    //成功!!
$pass++;     //合格したのでpassをカウント
}
} else {
print STDERR "FAIL (unexpected result '$res')\n";    //resの先頭が200でなかったので失敗 
$fail++;     //resが失敗だったのでfailをカウント
}
}


////////////////////////////////////ここまでが準備段階。以下からがAGIスクリプトのロジック////////////////////////////////////


//STREAM FILEコマンドの使い方 (PlayBack()アプリケーション)
//呼び出し元にサウンドファイルを再生するように指示

print STDERR "1. Testing 'sendfile'...";    //sendfileをやるとSTDERRに出力
print "STREAM FILE beep \"\"\n";     //『 STREAM FILE beep(.gsmは書かなくてよい) ""\n 』を入力
my $result = ;    //Asteriskに入力内容をSTDINして、結果をresultに代入
$checkresult($result);     //結果をAsteriskがそのファイルを再生できるかどうか、サブルーチンcheckresultで判定

//備考:STREAM FILEなどのAGIコマンドは要求された引数が必ずなければいけない。STREAM FILEは3つ取ることができ、そのうち2つ必要。
//・再生するサウンドファイル名
//・再生を中断する数字
//・サンプルの番号で指定された、サウンドの再生を始める場所(これはオプション)


//SEND TEXTコマンドの呼び出し方 (SendText()アプリケーション)
//呼び出し元のチャネルタイプがテキスト送信をサポートしていれば呼び出し元に対して指定されたテキストを送信する。引数は1必要。

print STDERR "2. Testing 'sendtext'...";    //sendtextをやるとSTDERRに出力
print "SEND TEXT \"hello world\"\n";    //SEND TEXTで「hello world」を送る
my $result = ;     //STDINの結果をresultに代入
$checkresult($result);    //Asteriskがコマンド実行に成功したかcheckresultで判定


//SEND IMAGEコマンドの呼び出し方 (SendImage()アプリケーション)
//SEND TEXTと同様に呼び出し元のチャネルがイメージの受信をサポートしていれば、イメージを送信できる。引数1必要。

print STDERR "3. Testing 'sendimage'...";    //sendimageやるよー
print "SEND IMAGE asterisk-image\n";    //SEND IMAGEで「asterisk-image」というイメージファイルを送るよ
my $result = ;    //STDINの結果をresultに代入
$checkresult($result);     //Asteriskがコマンド実行に成功したかcheckresultで判定


//SAY NUMBERコマンドの送り方 (SayNumber()アプリケーション)
//番号読み上げ。読み上げる番号とコマンドを中断させる数字で引数2必要。ここでも何も渡さない時には空の引用符を渡す。

print STDERR "4. Testing 'saynumber'...";    //saynumberやるよー
print "SAY NUMBER 192837465 \"\"\n";    //SAY NUMBERで「192837465」と読み上げてもらう
my $result = ;    //STDINの結果をresultに代入
$checkresult($result);    //Asteriskがコマンド実行に成功したかcheckresultで判定


//WAIT FOR DIGITコマンド
//呼び出し元がDTMFの数字を入力するまで、指定された数字のミリ秒だけ待ちます。無限に待たせるにはタイムアウトに-1を使う。返り値は押された数字の10進ASCII値。

print STDERR "5. Testing 'waitdtmf'...";    //waitdtmfやるよぉ
print "WAIT FOR DIGIT 1000\n";    //WAIT FOR DIGITでDTMF受信を1000ミリ秒待つよ
my $result = ;     //STDINの結果をresultに代入
$checkresult($result);     //Asteriskがコマンド実行に成功したかcheckresultで判定


//RECORD FILEコマンド (Record()アプリケーション)
//コールオーディオを録音するために使われます。RECORD FILEは引数を7つ取るが、最後の3つはオプション。
//・録音(保存)先ファイル名
//・オーディオを録音するフォーマット
//・録音を中断する数字
//・ミリ秒で示したタイムアウト(最大録音時間)。タイムアウトがない時は、-1
//・録音を開始する前にスキップすべきサンプルの数(オプション)
//・録音を開始する前にAsteriskにビープ音を出してほしい場合、BEEPという単語(オプション)
//・タイムアウトにいたっておらず、DTMF数字が入力されていなくても、Asteriskがそのユーザが録音を終えたと判断して返送するまでの秒数(オプション)。この引数はs=から始まらなければならない


print STDERR "6. Testing 'record'...";     //録音するよー
print "RECORD FILE testagi gsm 1234 3000\n";    //RECORD FILE ファイル名 ファイル形式 1234押すと録音を中断 3000ミリ秒でタイムアウト
my $result = ;     //STDINの結果をresultに代入
$checkresult($result);     //Asteriskがコマンド実行に成功したかcheckresultで判定


//STREAM FILE(上記)を使ってtestagi.gsmを再生

print STDERR "6a. Testing 'record' playback...";
print "STREAM FILE testagi \"\"\n";
my $result = ;
$checkresult($result);


//AGIスクリプトの終りにテストの要約がSTDERRに出力され、Asteriskコンソール上で終了する。

print STDERR "==================== Complete ====================\n";
print STDERR "$tests tests completed, $pass passed, $fail failed\n";
print STDERR "==================================================\n";


まとめ
  • use strictコマンドを使って、厳格な言語チェックをオンにする

  • $|=1とセットして、出力のバッファリングをオンにする

  • Asteriskからのデータは、while()ループを使って受信される

  • printコマンドを使って値を書く

  • Asteriskコンソールにデバッグ情報を書き出すために、print STDERRコマンドを使う






  • 応援クリックお願いします!!人気blogランキングへ

    2 件のコメント:

    hiro さんのコメント...

    Infinitalk を介さずに、asteriskってつかえるんですよね。インストールして、AGIやスクリプトで自分でシステムを構築すれば、かなりおもしろい実験ができそうでいいねすね。

    79 さんのコメント...

    そうですね。InfiniTalkはGUIを使ってAsteriskを簡単に管理できるようになっているものなので、設定ファイルだけのやり取りでいいのならば完全にシステムの自作が可能です。
    ただしそれを使ってやってみたいところですが、今のシステムを完全に再現するまでにはとても時間がかかりそうです。。。
    2,3人では1年くらい開発しなくてはいけない気がします。

    ですが、自宅のサーバにAsteriskを入れていろいろ試したいというのが本音です。陰でひっそりやって、ある日突然研究室に持ち込んでやろうという野望があります(笑)

    abe氏が作ろうとしているシステムでは、AGIをバリバリ使うと思うので、その部分は全部作ってあげてしまうくらい手伝いたいと思っています。