,有时会在number数字后附加一些信息。如果向Asterisk发送了无效的命令,信息如下:510
Invalid or unknown command。对应上面的命令,如下所示:
- AGI Rx << SET CONTEXT media_gw1
- AGI Tx >> 200 result=0
当AGI脚本执行时,Asterisk会向脚本发送各种的信息,可以在做其他事情之前通过标准输入获取这些信息,每项数据都是一行,发送完毕Asterisk会发送一个空行,表示结束,如:
- AGI Tx >> agi_request: dial_agi.php
- AGI Tx >> agi_channel: SIP/25946-0821ea88
- AGI Tx >> agi_language: en
- AGI Tx >> agi_type: SIP
- AGI Tx >> agi_uniqueid: 1209093478.477
- AGI Tx >> agi_callerid: 0000123456
- AGI Tx >> agi_calleridname: beigaolin
- AGI Tx >> agi_dnid: 998866015810370728
- AGI Tx >> agi_context: default
- AGI Tx >> agi_extension: 998866015810370728
- AGI Tx >> agi_priority: 1
根据项目需求,如果需要这些数据,就先保存起来,否则不用处理它。保存步骤按如下过程。
1.打开PHP输出文件描述符:
$in = fopen("php://stdin","r");
2.分析从Asterisk传到AGI的头信息,如需要在AGI程序中获取终端用户的ID,那么从“agi_calleridname:
beigaolin”这个头信息可以获取,我们通过分析每一行这样以:分隔的字符串,取到需要后续处理的字符串
while (!feof($stdin)) {
$temp = fgets($stdin);
$temp = str_replace("\n","",$temp);
$s = explode(":",$temp);
$agivar[$s[0]] = trim($s[1]);
if (($temp == "") || ($temp == "\n")) {
break;
}
}
4.使用开源PHP AGI类函数PHPAGI
像上一小节那样先是获取输入流,分析从输入头字符串中获取对应某个输入变量的值,或者获取输出流然后发送各种标准命令执行某些Asterisk内置应用,如果在AGI程序中实现很复杂的业务逻辑,这样的流程会显得有点累赘,所以需要提取某些常用的操作,我们使用的时候不用关心这些操作,直接以调用类似Asterisk内置应用那样的方式。PHPAGI就是这样的一个开源PHP类函数。它封装了对应Asterisk内置应用的常用函数调用接口,比如说从PHP向Asterisk发送Dial命令的操作,可以直接调用PHP
AGI类函数中的exec_dial。使用PHP AGI能够很容易的操作Asterisk AGI常用接口。使用这个类函数也很简单:
- cd /var/lib/asterisk/agi-bin/(也有可能在用户自定义的路径中)
- wget http://nchc.dl.sourceforge.net/sourceforge/phpagi/phpagi-2.14.tgz
- tar zxvf phpagi-2.14.tgz
- include ("phpagi.php");//包含文件
- include ("phpagi-asmanager.php");
- $agi = new AGI;//引用PHPAGI类函数
5.使用AGI实现主叫号码透传功能
在这里以一个例子来说明AGI程序在VoIP开发中的作用以及开发思路。
假设说有个普通电话为02412345678,手机号为15810370728,而网络电话虚拟号码是0000123456,如果想让拨打出去的电话号码在被叫方(手机或者带有来电显示功能的座机)的来电显示为02412345678或者15810370728,那么他们回复电话的时候就可以直接打到这个普通电话上,方便与主叫的业务联系。这个需求就叫主叫号码透传,能不能进行主叫号码的透传,取决于VoIP落地网关运营商,语音网关可以设置IP侧送过来的主叫号码是否透传。在保证号码规范的前提下,透传什么样的主叫号码,则取决于IP-PBX系统,即Asterisk的设计了。
1.增加一个针对终端用户账户ID的绑定管理系统,如图用户在第二项中输入自己的账户ID,然后再输入想要作为来显示的主叫号码完成绑定操作,后台php程序向数据库中插入一条新记录(X-Lite
ID对应电话号码或者手机号码)。
图1AGI后台管理系统页面
2.使用绑定了主叫号码的X-Lite呼叫某个被叫(手机或者座机)
Asterisk的后台PHP AGI程序的详细设计主叫号码透传流程设计如图2所示。
图2Asterisk 主叫号码透传的后台PHP AGI流程图
以下代码片断展示的是PHP AGI中部分代码,并且作了简化。
#!/usr/local/php.5.2.5/bin/php –q
include_once("phpagi.php");//开源PHP类函数
......
//判断当前这个id是否做了主叫号码来电显示的绑定操作
$query_string = "select * from xliteid where xliteid = '{$caller_name}'";
$query_result = mysql_query($query_string, $db_connection);
//如果当前这个id做了绑定操作,调用PHPAGI类函数,设置Asterisk主叫号码
if($query_result && mysql_num_rows($query_result) > 0)
{
caller_phone_display_agi ();
}
//没有做绑定,设置一个随机的号码
else
{
caller_name = $argv[2];
$rand_num1 = rand(0,9);
$rand_num2 = rand(0,9);
$rand_num3 = rand(0,9);
$caller_phone= "024{$rand_num1}{$rand_num2}650{$rand_num3}{$rand_num4}";
land_media_gw1($caller_phone);
exit();
}
/**
*@caller_phone_display_agi 主叫号码特殊显示
*/
function caller_phone_display_agi()
{
global $db_connection, $callee_phone, $caller_name;
$query_string = "select caller_phone from caller_phone_display
_xliteid where skype_id = '{$caller_name}'";
$query_result = mysql_query($query_string, $db_connection);
{
$row = mysql_fetch_array($query_result);
$caller_phone = $row[0];
$callerid_cli = "\"{$caller_name}\"<{$caller_phone}>";
land_media_gw1($callerid_cli);
exit();
}
}
/**
*@ land_media_gw1 VoIP语音网关media_gw1
*/
function land_media_gw1($callerid_num)
{
global $agi, $callee_phone_withpre;
$agi->set_context("media_gw1");
$agi->set_extension($callee_phone_withpre);
$agi->set_priority(1);
//调用phpagi封装的set_callerid方法,向Asterisk传递设置主叫号码的指令
$agi->set_callerid($callerid_num);
}
对X-Lite账户gaolinb作了主叫号码绑定,使用X-Lite软终端呼叫普通的手机,在Asterisk中设置了agi
debug,从Asterisk后台我们可以清晰地看到:
1.AGI Tx >> *CLI>上面部分,全是从Asterisk输入到当前AGI的环境变量信息,它包含了当前这个呼叫的详细信息,如Channel的类型,是SIP还是H.323,calleridname,即终端用户是gaolinb等重要信息。
2.AGI Tx >> *CLI>下面部分,全是在上面调用PHPAGI类函数后将命令传给了AGI程序执行,对于主叫号码来电显示的命令是:
SET CALLERID ‘gaolinb’<15810370728>,Asterisk将15810370728传到能够支持主叫号码透传的VoIP运营商,从而被叫用户在接听电话前能够显示一个有意义的电话号码。
图3 Asterisk服务器上AGI的输入输出信息
贝高林的Blog
相关链接: