html5素材网站,一家企业如何做网站推广,洛阳网站制作建设,成都网站建设哪儿济南兴田德润怎么联系5. Asterisk AGI程序编写指南 5.1概述 很多时候#xff0c;我们需要在拨号方案中做某些业务逻辑的判断或者外部数据库的查询#xff0c;根据具体地需要#xff0c;有几种做法#xff1a; 1#xff0e;使用Asterisk的通道变量、Goto函数、Gotoif函数等实现某些简单跳转… 5. Asterisk AGI程序编写指南 5.1概述 很多时候我们需要在拨号方案中做某些业务逻辑的判断或者外部数据库的查询根据具体地需要有几种做法 1使用Asterisk的通道变量、Goto函数、Gotoif函数等实现某些简单跳转通过几个这样的函数的组合实现简单的业务。 2对终端接入用户的呼叫请求中的某些属性进行简单的数据库增删改查在Asterisk官方发布的asterisk-addons开发包中安装MYSQL模块具体地方法在这不细述。使用类似下面的方式 exten _0[0-9].,1, MYSQL(Connect connid dhhost dbuser dbpass dbname) exten _0[0-9].,2., MYSQL(Query resultid ${connid} query-string) exten _0[0-9].,3MYSQL(Fetch fetchid ${resultid} var1\ var2\ ...\ varN) exten _0[0-9].,4MYSQL(Disconnect ${connid}) 3如果碰到了结合了1、2的业务需求这时候拨号方案配置文件中就会出现大量地与业务逻辑有关的复杂代码造成技术人员阅读上不方便并且代码也不好维护如下面这段配置文件 …… exten 888,1,MYSQL(Connect connid localhost ipcontact passwd ipcontact) exten 888,n,GotoIf($[${connid} ]?error,1) exten 888,n,MYSQL(Query resultid ${connid} SELECT\ number\ FROM\ phones\ WHERE\ channel\${chan}\) …… exten 888,n,GotoIf($[${foundRow} 1]?done) ; leave loop if no row found exten 888,n,NoOp(${number}) exten 888,n,Goto(fetchrow) ; continue loop if row found exten 888,n(done),MYSQL(Clear ${resultid}) exten 888,n,MYSQL(Disconnect ${connid}) …… 上面综合了通道变量、Goto、Gotoif、MYSQL数据查询等操作其实如果配置文件中只是几行这样的操作阅读起来没问题但业务需求具有可变性代码维护起来就比较麻烦。所以我们就寻找另外一种方案即在配置文件中不进行数据库查询等重量级的操作而是将它交到一个外部应用程序或者脚本中即封装到Asterisk的AGI后台中可以实现各种复杂的业务需求。使用类似PHP、JAVA、C等编程语言内置的判断语句而不是Asterisk封装的类似Goto、Gotoif等函数会更加快地实现业务需求代码也更好维护。下面先看看如何在拨号方案中使用AGI程序。 5.2 使用AGI脚本 执行AGI脚本时Application应用就是agi参数是脚本的文件名同时脚本需要满足以下条件 l 必须可执行chomd 755 l 必须放置在指定目录如标准目录/var/lib/asterisk/agi-bin l 必须指定完整的extension信息 比如说执行一个用PHP语言实现的AGI程序有可能就是这样 exten 1,2,AGI(test.php, ${CALLERID(name)}) 脚本执行时可以从控制台上得到不同基本的详细信息例如文件不能被执行或者找不到文件等等。 通过向Asterisk控制台信息输出可以得到AGI脚本的执行信息至少在开发初期中控制台信息输出是个好办法。 通过agi VERBOSE命令可以将信息发送到asterisk控制台上并且而通过verbosity设置可以关闭开启这个功能。 如果直接可以采用各种语言很方便的通过AGI接口编写实施脚本。脚本和Asterisk之间通过标准的输入输出进行交互。 5.3 AGI(Asterisk Gateway Interface)技术实现原理 l 传递参数到AGI脚本 在脚本名称后紧跟以英文半角状态下的逗号,分隔的字符串就可以把需要的参数传入脚本AGI(dial_agi.php,${EXTEN:11},${CALLERID(name)})AGI脚本总是接收2种参数1是脚本的完整路径2是拨号方案中Exten传递的参数其中第1种参数如果AGI程序放在了Asterisk默认路径可以省略只写AGI程序名。第2种参数是AGI程序需要拨号方案中Exten传递进来的参数比如说本文中${EXTEN:11},${CALLERID(name)}一个是被叫的电话号码一个是主叫的账号ID。 l 通过标准的输出发送命令到Asterisk 我们可以在AGI脚本程序中向Asterisk发送各种命令从而调用Asterisk的某些应用程序如Dial、Goto、Monitor等也可以直接发送命令获得或者设置某些Asterisk通道变量的值。对于基于PHP的AGI脚本程序可以按照如下步骤 1打开PHP输出文件描述符 $stdout fopen(php://stdout, w); 2向Asterisk发送命令 fputs($stdout, SET CONTEXT media_gw1\n); ); fflush($stdout); 上述步骤是对于SET 或者 GET Asterisk的某些通道变量时的使用方法如果需要调用Asterisk内置的应用如执行跳转到某个context下的某个priority的Goto应用函数可以调用EXEC命令后面紧跟Asterisk如fputs($stdout, EXEC Goto media_gw1|s|2\n); );命令必须以换行符结束AGI命令返回文本字符串如下格式200 Resultnumber有时会在number数字后附加一些信息。如果向Asterisk发送了无效的命令信息如下510 Invalid or unknown command。对应上面的命令如下所示 AGI Rx SET CONTEXT media_gw1 AGI Tx 200 result0 l 通过标准的输入从Asterisk接收信息 当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; } } 5.4 使用开源PHP AGI类函数PHPAGI 像上一小节那样先是获取输入流分析从输入头字符串中获取对应某个输入变量的值或者获取输出流然后发送各种标准命令执行某些Asterisk内置应用如果在AGI程序中实现很复杂的业务逻辑这样的流程会显得有点累赘所以需要提取某些常用的操作我们使用的时候不用关心这些操作直接以调用类似Asterisk内置应用那样的方式。PHPAGI就是这样的一个开源PHP类函数。它封装了对应Asterisk内置应用的常用函数调用接口比如说从PHP向Asterisk发送Dial命令的操作可以直接调用PHP AGI类函数中的exec_dial。使用PHP AGI能够很容易的操作Asterisk AGI常用接口。使用这个类函数也很简单 l 下载准备phpagi 函数文件 cd /var/lib/asterisk/agi-bin/(也有可能在用户自定义的路径中) wget http://nchc.dl.sourceforge.net/sourceforge/phpagi/phpagi-2.14.tgz tar zxvf phpagi-2.14.tgz l 在代码中使用 include (phpagi.php);//包含文件 include (phpagi-asmanager.php); $agi new AGI;//引用PHPAGI类函数 5.5 使用AGI实现主叫号码透传功能 在这里以一个例子来说明AGI程序在VoIP开发中的作用以及开发思路。 假设说有个普通电话为02412345678手机号为15810370728而网络电话虚拟号码是0000123456如果想让拨打出去的电话号码在被叫方(手机或者带有来电显示功能的座机)的来电显示为02412345678或者15810370728那么他们回复电话的时候就可以直接打到这个普通电话上方便与主叫的业务联系。这个需求就叫主叫号码透传能不能进行主叫号码的透传取决于VoIP落地网关运营商语音网关可以设置IP侧送过来的主叫号码是否透传。在保证号码规范的前提下透传什么样的主叫号码则取决于IP-PBX系统即Asterisk的设计了。 l 设计思路 1.增加一个针对终端用户账户ID的绑定管理系统如图用户在第二项中输入自己的账户ID然后再输入想要作为来显示的主叫号码完成绑定操作后台php程序向数据库中插入一条新记录(X-Lite ID对应电话号码或者手机号码)。 图5-2 AGI后台管理系统页面 2.使用绑定了主叫号码的X-Lite呼叫某个被叫(手机或者座机) Asterisk的后台PHP AGI程序的详细设计主叫号码透传流程设计如图4-4所示。 图5-3 Asterisk 主叫号码透传的后台PHP AGI流程图 l 代码实现 以下代码片断展示的是PHP AGI中部分代码并且作了简化。 #!/usr/local/php.5.2.5/bin/php –q ?php 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(); } /** 主叫号码特殊显示 */ 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); if($query_result mysql_num_rows($query_result) 0) { $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后台我们可以清晰地看到 1AGI Tx *CLI上面部分全是从Asterisk输入到当前AGI的环境变量信息它包含了当前这个呼叫的详细信息如Channel的类型是SIP还是H.323calleridname即终端用户是gaolinb等重要信息。 2AGI Tx *CLI下面部分全是在上面调用PHPAGI类函数后将命令传给了AGI程序执行对于主叫号码来电显示的命令是 SET CALLERID ‘gaolinb’15810370728Asterisk将15810370728传到能够支持主叫号码透传的VoIP运营商从而被叫用户在接听电话前能够显示一个有意义的电话号码。 图5-4 Asterisk服务器上AGI的输入输出信息