首頁(yè)>>>技術(shù)>>>VoIP

基于A(yíng)sterisk的VoIP開(kāi)發(fā)指南——(2)Asterisk AGI程序編寫(xiě)指南

2008/06/12

1.概述

  很多時(shí)候,我們需要在撥號方案中做某些業(yè)務(wù)邏輯的判斷或者外部數據庫的查詢(xún),根據具體地需要,有幾種做法:

  使用Asterisk的通道變量、Goto函數、Gotoif函數等實(shí)現某些簡(jiǎn)單跳轉,通過(guò)幾個(gè)這樣的函數的組合,實(shí)現簡(jiǎn)單的業(yè)務(wù)。

  對終端接入用戶(hù)的呼叫請求中的某些屬性,進(jìn)行簡(jiǎn)單的數據庫增刪改查,在A(yíng)sterisk官方發(fā)布的asterisk-addons開(kāi)發(fā)包中安裝MYSQL模塊,具體地方法在這不細述。使用類(lèi)似下面的方式:   如果碰到了結合了1、2的業(yè)務(wù)需求,這時(shí)候撥號方案配置文件中就會(huì )出現大量地與業(yè)務(wù)邏輯有關(guān)的復雜代碼,造成技術(shù)人員閱讀上不方便,并且代碼也不好維護,如下面這段配置文件:

  ……   ……   ……

  上面綜合了通道變量、Goto、Gotoif、MYSQL數據查詢(xún)等操作,其實(shí)如果配置文件中只是幾行這樣的操作閱讀起來(lái)沒(méi)問(wèn)題,但業(yè)務(wù)需求具有可變性,代碼維護起來(lái)就比較麻煩。所以,我們就尋找另外一種方案,即在配置文件中不進(jìn)行數據庫查詢(xún)等重量級的操作,而是將它交到一個(gè)外部應用程序或者腳本中,即封裝到Asterisk的AGI后臺中,可以實(shí)現各種復雜的業(yè)務(wù)需求。使用類(lèi)似PHP、JAVA、C等編程語(yǔ)言?xún)戎玫呐袛嗾Z(yǔ)句,而不是Asterisk封裝的類(lèi)似Goto、Gotoif等函數,會(huì )更加快地實(shí)現業(yè)務(wù)需求,代碼也更好維護。下面先看看如何在撥號方案中使用AGI程序。

2.使用AGI腳本

  執行AGI腳本時(shí),Application應用就是'agi',參數是腳本的文件名,同時(shí)腳本需要滿(mǎn)足以下條件:   比如說(shuō)執行一個(gè)用PHP語(yǔ)言實(shí)現的AGI程序,有可能就是這樣:

  exten => 1,2,AGI(test.php, ${CALLERID(name)})

  腳本執行時(shí),可以從控制臺上得到不同基本的詳細信息,例如,文件不能被執行,或者找不到文件等等。

  通過(guò)向Asterisk控制臺信息輸出,可以得到AGI腳本的執行信息,至少在開(kāi)發(fā)初期中,控制臺信息輸出是個(gè)好辦法。

  通過(guò)agi VERBOSE命令,可以將信息發(fā)送到asterisk控制臺上,并且而通過(guò)verbosity設置可以關(guān)閉開(kāi)啟這個(gè)功能。

  如果直接,可以采用各種語(yǔ)言很方便的通過(guò)AGI接口編寫(xiě)實(shí)施腳本。腳本和Asterisk之間通過(guò)標準的輸入輸出進(jìn)行交互。

3.AGI(Asterisk Gateway Interface)技術(shù)實(shí)現原理   在腳本名稱(chēng)后緊跟以英文半角狀態(tài)下的逗號,分隔的字符串,就可以把需要的參數傳入腳本:AGI(dial_agi.php,${EXTEN:11},${CALLERID(name)}),AGI腳本總是接收2種參數,1是腳本的完整路徑,2是撥號方案中'Exten'傳遞的參數,其中第1種參數,如果AGI程序放在了Asterisk默認路徑,可以省略,只寫(xiě)AGI程序名。第2種參數是AGI程序需要撥號方案中'Exten'傳遞進(jìn)來(lái)的參數,比如說(shuō)本文中${EXTEN:11},${CALLERID(name)},一個(gè)是被叫的電話(huà)號碼,一個(gè)是主叫的賬號ID。   我們可以在A(yíng)GI腳本程序中向Asterisk發(fā)送各種命令從而調用Asterisk的某些應用程序,如Dial、Goto、Monitor等,也可以直接發(fā)送命令獲得或者設置某些Asterisk通道變量的值。對于基于PHP的AGI腳本程序,可以按照如下步驟:

  (1).打開(kāi)PHP輸出文件描述符:

  $stdout = fopen('php://stdout', 'w');

  (2).向Asterisk發(fā)送命令:

  fputs($stdout," SET CONTEXT media_gw1\n"); ");
fflush($stdout);

  上述步驟是對于SET 或者 GET Asterisk的某些通道變量時(shí)的使用方法,如果需要調用Asterisk內置的應用,如執行跳轉到某個(gè)context下的某個(gè)priority的Goto應用函數,可以調用EXEC命令后面緊跟Asterisk,如:fputs($stdout," EXEC Goto media_gw1|s|2\n"); ");命令必須以換行符結束,AGI命令返回文本字符串,如下格式:200 Result=,有時(shí)會(huì )在number數字后附加一些信息。如果向Asterisk發(fā)送了無(wú)效的命令,信息如下:510 Invalid or unknown command。對應上面的命令,如下所示:      當AGI腳本執行時(shí),Asterisk會(huì )向腳本發(fā)送各種的信息,可以在做其他事情之前通過(guò)標準輸入獲取這些信息,每項數據都是一行,發(fā)送完畢Asterisk會(huì )發(fā)送一個(gè)空行,表示結束,如:   根據項目需求,如果需要這些數據,就先保存起來(lái),否則不用處理它。保存步驟按如下過(guò)程。

  1.打開(kāi)PHP輸出文件描述符:

  $in = fopen("php://stdin","r");

  2.分析從Asterisk傳到AGI的頭信息,如需要在A(yíng)GI程序中獲取終端用戶(hù)的ID,那么從“agi_calleridname: beigaolin”這個(gè)頭信息可以獲取,我們通過(guò)分析每一行這樣以:分隔的字符串,取到需要后續處理的字符串
  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.使用開(kāi)源PHP AGI類(lèi)函數PHPAGI

  像上一小節那樣先是獲取輸入流,分析從輸入頭字符串中獲取對應某個(gè)輸入變量的值,或者獲取輸出流然后發(fā)送各種標準命令執行某些Asterisk內置應用,如果在A(yíng)GI程序中實(shí)現很復雜的業(yè)務(wù)邏輯,這樣的流程會(huì )顯得有點(diǎn)累贅,所以需要提取某些常用的操作,我們使用的時(shí)候不用關(guān)心這些操作,直接以調用類(lèi)似Asterisk內置應用那樣的方式。PHPAGI就是這樣的一個(gè)開(kāi)源PHP類(lèi)函數。它封裝了對應Asterisk內置應用的常用函數調用接口,比如說(shuō)從PHP向Asterisk發(fā)送Dial命令的操作,可以直接調用PHP AGI類(lèi)函數中的exec_dial。使用PHP AGI能夠很容易的操作Asterisk AGI常用接口。使用這個(gè)類(lèi)函數也很簡(jiǎn)單: 5.使用AGI實(shí)現主叫號碼透傳功能

  在這里以一個(gè)例子來(lái)說(shuō)明AGI程序在VoIP開(kāi)發(fā)中的作用以及開(kāi)發(fā)思路。

  假設說(shuō)有個(gè)普通電話(huà)為02412345678,手機號為15810370728,而網(wǎng)絡(luò )電話(huà)虛擬號碼是0000123456,如果想讓撥打出去的電話(huà)號碼在被叫方(手機或者帶有來(lái)電顯示功能的座機)的來(lái)電顯示為02412345678或者15810370728,那么他們回復電話(huà)的時(shí)候就可以直接打到這個(gè)普通電話(huà)上,方便與主叫的業(yè)務(wù)聯(lián)系。這個(gè)需求就叫主叫號碼透傳,能不能進(jìn)行主叫號碼的透傳,取決于VoIP落地網(wǎng)關(guān)運營(yíng)商,語(yǔ)音網(wǎng)關(guān)可以設置IP側送過(guò)來(lái)的主叫號碼是否透傳。在保證號碼規范的前提下,透傳什么樣的主叫號碼,則取決于IP-PBX系統,即Asterisk的設計了。   1.增加一個(gè)針對終端用戶(hù)賬戶(hù)ID的綁定管理系統,如圖用戶(hù)在第二項中輸入自己的賬戶(hù)ID,然后再輸入想要作為來(lái)顯示的主叫號碼完成綁定操作,后臺php程序向數據庫中插入一條新記錄(X-Lite ID對應電話(huà)號碼或者手機號碼)。

圖1AGI后臺管理系統頁(yè)面


  2.使用綁定了主叫號碼的X-Lite呼叫某個(gè)被叫(手機或者座機)

  Asterisk的后臺PHP AGI程序的詳細設計主叫號碼透傳流程設計如圖2所示。

圖2Asterisk 主叫號碼透傳的后臺PHP AGI流程圖

  以下代碼片斷展示的是PHP AGI中部分代碼,并且作了簡(jiǎn)化。

  #!/usr/local/php.5.2.5/bin/php –q
  include_once("phpagi.php");//開(kāi)源PHP類(lèi)函數
  ......
  //判斷當前這個(gè)id是否做了主叫號碼來(lái)電顯示的綁定操作
  $query_string = "select * from xliteid where xliteid = '{$caller_name}'";
  $query_result = mysql_query($query_string, $db_connection);

  //如果當前這個(gè)id做了綁定操作,調用PHPAGI類(lèi)函數,設置Asterisk主叫號碼

  if($query_result && mysql_num_rows($query_result) > 0)
  {
  caller_phone_display_agi ();
  }
  //沒(méi)有做綁定,設置一個(gè)隨機的號碼
  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語(yǔ)音網(wǎng)關(guān)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賬戶(hù)gaolinb作了主叫號碼綁定,使用X-Lite軟終端呼叫普通的手機,在A(yíng)sterisk中設置了agi debug,從Asterisk后臺我們可以清晰地看到:

  1.AGI Tx >> *CLI>上面部分,全是從Asterisk輸入到當前AGI的環(huán)境變量信息,它包含了當前這個(gè)呼叫的詳細信息,如Channel的類(lèi)型,是SIP還是H.323,calleridname,即終端用戶(hù)是gaolinb等重要信息。

  2.AGI Tx >> *CLI>下面部分,全是在上面調用PHPAGI類(lèi)函數后將命令傳給了AGI程序執行,對于主叫號碼來(lái)電顯示的命令是:

  SET CALLERID ‘gaolinb’<15810370728>,Asterisk將15810370728傳到能夠支持主叫號碼透傳的VoIP運營(yíng)商,從而被叫用戶(hù)在接聽(tīng)電話(huà)前能夠顯示一個(gè)有意義的電話(huà)號碼。


圖3 Asterisk服務(wù)器上AGI的輸入輸出信息

貝高林的Blog



相關(guān)鏈接:
基于A(yíng)sterisk的VoIP開(kāi)發(fā)指南—Asterisk模塊編寫(xiě)指南 2008-06-12
基于A(yíng)sterisk的VoIP開(kāi)發(fā)指南—實(shí)現基本呼叫功能 2008-06-12
無(wú)線(xiàn)IPPBX系統的設計與實(shí)現 2008-06-12
淺論美國寬帶電話(huà)(VOIP)監管的新動(dòng)向 2008-06-11
網(wǎng)絡(luò )電話(huà)(VoIP)成功應用美軍軍事系統 2008-06-06

分類(lèi)信息:        
亚洲精品网站在线观看不卡无广告,国产a不卡片精品免费观看,欧美亚洲一区二区三区在线,国产一区二区三区日韩 濮阳市| 离岛区| 竹北市| 霍州市| 桦川县| 安国市| 博白县| 宾阳县| 准格尔旗| 涞水县| 新乡县| 安乡县| 甘孜县| 三穗县| 河北省| 钟祥市| 庐江县| 三穗县| 信阳市| 屏南县| 滕州市| 赤壁市| 阿拉善盟| 栾城县| 玉树县| 德保县| 明溪县| 梧州市| 大名县| 汉川市| 方山县| 云阳县| 新巴尔虎右旗| 四平市| 华容县| 托克托县| 合山市| 蒙城县| 丰都县| 丰镇市| 湖口县| http://444 http://444 http://444 http://444 http://444 http://444