asterisk撥號規則


一、前言
    本文檔以asterisk-1.4.32為基礎寫作而成,可能和其他版本有些區別。其中參考了一些別的書籍和文章。因為寫的比較倉促,而且基本都是晚上寫的,里面的內容邏輯性和語句沒有仔細斟酌,就是想到什么寫什么,難免有什么遺漏和錯誤的地方,大家發現請及時通知我修改。另外這是我第一次寫技術性的文章還很嫩澀,算是一個開始,希望大家多多支持。

二、Asterisk dialplan 基本結構
    Asterisk dialplan 的語法可以分為四個關鍵點,也就是語法結構的四個組成部分,四個部分分別context ,extensionnum ,priority 和 action。由這四個組成部分dialplan的結構為:
  [context]
   exten => extensionnum,priority,action
    1、context
    context是指dialplan的流程塊,整個dialplan就是由每個context的內容組成,他們協作完成整個asterisk命令邏輯的運轉。context的名字必須放在中括號之中,比如PSTN外線打進系統所執行的流程我們都習慣叫from-pstn,在語法里面就寫做"[from-pstn]"。所有屬於這個流程的內容都寫在這個下面。每一個命令都由換行符來隔開,也就是說每一行就是一個命令,每一行命令都必須由"exten => "(這個里面的空格可以沒有)開頭。流程的結尾就是遇到到下一個流程標識截止。
    2、extensionnum
    extensionnum是指流程塊里面的流程匹配標識(也就是asterisk里面說的extension),這個匹配標識其實通常就是我們要撥的號碼(當然這個匹配標識不光是數字也可以是字母或者一些特殊字符)。比如你撥分機101,而你設置的撥分機的流程塊是dial-ext,那么asterisk就會在dial-ext流程塊里面尋找能匹配101的流程,找到了就會執行。說到匹配大家就會想到通配符吧,哈哈,asterisk里面也有類似的通配符,下面我就介紹一下asterisk里面關於extension的通配符。
     X和x表示單個0-9的數字
     N和n表示單個1-9的數字
     Z和z表示單個2-9的數字
     .表示單個的任何字符和數字
     []中括號里面可以是你想任意的匹配的數字或者字母,比如你想匹配1、3或者6,那么你就可以這樣[136]或者[1,3,6],在中括號里面還支持這樣[1-8]是指匹配1到8的任意一個數字。
     當你的extensionnum中含有任何通配符的時候你就要用一個短的下划線"_"來作為extensionnum的開頭除了這些以外asterisk還有一些特殊意義的匹配字符,
     s :是指Start extension,也就是當沒有extension的時候就會執行這個流程(例如在模擬外線進線沒有收到callerID的情況下就會轉到這個extension來執行),另外在zapata.conf的channels段里面如果設定了immediate=yes程序就會自動找到s這流程來執行。
     t :是指timeout extension,也就是說如果等待用戶輸入超時后就會轉到t這個流程來執行,在這里你可以設置一些提示音來告訴客戶超時了。
     i :是指invalid extension,也就是說如果客戶輸入無效的時候會轉到i這個流程來執行
     fax :是指fax calls,也就是說如果asterisk檢測到傳真信號的時候就會自動轉到這個流程里面來執行。
     h :是指hangup extension,就是說呼叫終止后執行的流程,在這里通道已經終止,放音、發送DTMF等命令都不可用了,只能做一些呼叫結束后處理的一些工作。
     需要注意的是,不管你設置的流程是什么都是屬於某個流程塊的,在不相互包含的情況下,流程塊與流程塊之間是相互獨立的,流程或者變量是不會沖突的。
    3、priority
    priority是指流程里面的命令的執行優先級,除了跳轉的情況,都是按照priority值的之從小到大執行的。在流程里面你會經常看見"n"這個priority,它是指next也就是上一個priority+1.我們通常還會給某個priority取個名字,來方便我們流程跳轉,也方便流程的閱讀。語法是這樣的 exten => extensionnum,priority(name),action ,name就是這個priority的名字。
     exten => _123409XX,1,GotoIf($[${EXTEN}=12340910]?ivr1:normal) 
     exten => _123409XX,n(normal),Dial(SIP/101)
     exten => _123409XX,n,Goto(end)
     exten => _123409XX,n(ivr1),BackGround(MyVox/Greeting)
     exten => _123409XX,n(end),Hangup
    上面這段代碼就是當匹配的號碼是12340901時就跳轉到ivr1這個priority上否則就跳轉到normal這個priority上。上面這段流程也可以寫成:
     exten => _123409XX,1,GotoIf($[${EXTEN}=12340910]?4:2) 
     exten => _123409XX,2,Dial(SIP/101)
     exten => _123409XX,3,Goto(5)
     exten => _123409XX,4,BackGround(MyVox/Greeting)
     exten => _123409XX,5,Hangup
   4、action
    action就相對好理解多了就是流程里面你要執行的命令,asterisk支持的命令很多,我就介紹幾個比較常用的。所有命令的規則里中括號里面是可選的部分,沒有中括號的必須填加的。參數之間的分隔符是"|",其實","來分隔也可以,但是1.6版本的asterisk不行,1.6的只能用"|"。還應該注意的是action的命令名有大小寫之分,寫錯將會出現錯誤,當命令沒有參數時可以不用寫小括號。
    1)、Answer
    語法:Answer([delay])
    應答一個振鈴的Channel。如果呼叫沒有被應答此方法將應答這個呼叫,如果delay這個參數指定那么應答成功后將等待delay秒后再返回執行下條命令,應答不成功就會直接返回錯誤返回值而不執行delay延遲。這個命令用於呼入的情況,呼出的時候不會真正執行answer操作但是會執行delay延遲。
    2)、Playback
    語法:Playback(filename[&filename2...][|option])
    給當前Channel播放語音文件。第一個參數是語音文件,語音文件的格式asterisk默認的是gsm,其他wav、sln、vox、pcm等也都支持,但是最好用gsm格式的文件,如果沒有gsm格式的可以用sox這個工具把格式變為gsm的,一般變成gsm格式的語音播放起來就不會有什么問題了。播放的語音文件也可以是多個,每個之間用"&"來分隔,語音文件的擴展名不用寫,語音文件中不能有空格,最好就是字母和數字的組合,為了語義的需要可以用下划線來分隔。當一個語音文件出現問題時命令就會停止,后面的語音文件就不會再被播放了。語音文件是相對地址也可以是絕對地址,相對地址的默認路徑是/var/lib/asterisk/sounds/。
     第二個參數是一些控制變量,這個參數是可選的:
     skip :如果這個變量設置,而且當前通道沒有UP,命令就會立刻結束,不播放任何語音。
     noanswer :如果設置這個變量,在當前通道沒有UP的時候,就不會執行anwser來UP這個通道。
     say :如果設置這個變量,在播放語音之前會把要播放的語音文件名都出來。
     j :如果設置這個變量,當語音文件播放出現問題的時候,流程就會跳轉到priority+101這個priority繼續執行。
     通道變量PLAYBACKSTATUS,通道變量的值通常都是一個字符串,當語音播放成功后PLAYBACKSTATUS為SUCCESS,否則為FAILED。當播放多個文件時只要有一個文件播放失敗PLAYBACKSTATUS即為FAILED。
     3)、BackGround
     語法:Background(filename1[&filename2...][|options[|langoverride][|context]])
     給當前Channel播放語音文件,並等待客戶輸入,來執行相應的extension。第一個參數是語音文件,這個參數的用法跟Playbcak的第一參數用法一樣。
     第二個參數是一些控制變量,這個參數是可選的:
      s :如果這個變量設置,而且當前通道沒有UP,命令就會立刻結束,不播放任何語音。
      n :播放語音前不用answer這個通道
      m :只有當用戶輸入的能和參數context中的流程匹配才結束。
      p :只播放不接受用戶輸入。
     第三個參數是指播放聲音的語言,這個參數是可選的。
     第四個參數是指當用戶輸入后要去尋找匹配並執行的context,在多層的IVR中這個參數是關鍵,這個參數是可選的。
    4)、Dial
    語法:Dial(Technology/resource[&Tech2/resource2...][|timeout][|options][|URL])
    這個命令會是當前通道呼叫一個或多個Channel,其中有一個Channel應答,當前通道就會和這個Channel橋接在一起,其他Channel就會掛斷。
    第一個參數是要呼叫的通道可以是多個每個之間用"&"來分隔。
    第二個參數是超時時間,單位為秒,如果不設置超時時間,呼叫就會一直等到對方應答為止。
    第三個參數是一些控制變量:
     A(x) :當被叫方應答的時候給被叫方播放一段語音,x為要播放的語音文件
     C :重新設置CDR
     d :允許主叫方在等待被叫方應答的時候,按一個數字鍵跳轉到這個數字所能匹配的流程中,新的流程是指定在EXITCONTEXT變量中設置的流程,如果EXITCONTEXT沒有被指定那么就在當前context中尋找。
     D([called][:calling]) :發送DTMF到主叫方或者被叫方,當被叫應答但是通道還沒有橋接的時候。
     f :強制為被叫方Channel設置CallerID,用當前的extension
     g :當對方掛機的后,接着當前的context執行
     G(context^exten^pri) :當呼叫被應答之后,將主叫方跳轉到指定的priority中執行,被叫跳轉到指定的priority+1中執行,指定的priority由G的參數指定。
     h :允許被叫方按"*"結束會話
     H :允許主叫方按"*"結束會話
     i :忽略任何forwarding請求
     j :當所有呼叫請求都忙的時候跳轉到當前priority+101處
     k :允許被叫使用parking功能
     K :允許主叫使用parking功能
     L(x[:y][:z]) :限定呼叫'x'ms,當剩下'y'ms時播放一個警告,重復這個警告每隔'z'ms。下面這些變量是用於這個操作:
            LIMIT_PLAYAUDIO_CALLER    yes|no (default yes) 對主叫播放語音
            LIMIT_PLAYAUDIO_CALLEE    yes|no     對被叫播放語音
            LIMIT_TIMEOUT_FILE     時間到的時候播放的語音
            LIMIT_CONNECT_FILE     呼叫開始時播放的語音
            LIMIT_WARNING_FILE     y定義的那個警告的語音,一般都是播放還剩多少時間
     m([class]) :為主叫提供hold music在Channel應答之前。
     M(x[^arg]) :為被叫Channel執行指定的宏,在還未和主叫橋接之前。被指定的參數可以用"^"來分隔。宏執行完后后會返回一個變量MACRO_RESULT來指示接下來要執行的命令:
            ABORT    通話兩端都掛斷
            CONGESTION 當線路催掛的時候執行,也就是設置完CONGESTION狀態,然后繼續執行流程
            BUSY    當線路忙的時候執行,如果j這個參數被設置則,跳轉到priority+101處執行
            CONTINUE  掛斷被叫,主叫繼續執行流程
            GOTO:<context>^<exten>^<priority>   跳轉到指定的流程處繼續執行
          注意:TIMEOUT()函數不能用在宏中
     n([x])和N :修改screen/privacy模式. ;screen/privacy就是在被叫應答后還沒有橋接之前給被叫播放一段IVR來讓它做一些操作,其中就有選擇是否願意接受這個呼叫
     p和P([x]) :設置screen/privacy模式.
     o :指定主叫Channel的callerID為被叫Channel的CallerID。
     O([x]) :設置Operator Services模式,只對zaptel和dahdi通道有效
     r :主叫等待應答是為主叫播放回鈴音
     S(x) :應答后x秒掛斷通話
     t :允許被叫發送DTMF實現transfer主叫  詳細信息在features.conf中設置
     T :允許主叫發送DTMF實現transfer被叫 詳細信息在features.conf中設置
     w :允許被叫發送DTMF為通話錄音    詳細信息在features.conf中設置
     W :允許主叫發送DTMF為通話錄音    詳細信息在features.conf中設置
   第四個參數是一個url地址,如果通道支持這個url將發送給被叫
   通道變量:
    DIALEDTIME      這個變量是指從呼叫開始到會話結束的時間
    ANSWEREDTIME    這個變量是指應答開始到會話結束的時間
    DIALSTATUS     這個變量顯示的是呼叫的結果狀態有以下一些值CHANUNAVAIL | CONGESTION | NOANSWER | BUSY | ANSWER | CANCEL | DONTCALL | TORTURE | INVALIDARGS ,在Privacy和Screening模式中,被叫選擇發送主叫到'Go Away'腳本時狀態變為DONTCALL;發送到'torture'腳本時狀態變為TORTURE。
    5)、Hangup
    語法:Hangup([causecode])
    這個命令是掛斷一個Channel。可選的參數是指定掛機的原因。
    6)、Goto
    語法:Goto([[context|]extension|]priority)
    這個命令是跳轉到指定priority處執行,默認是當前的context和extension。當輸入的context直接掛機,當輸入的extension和priority錯誤會在當前context尋找i流程來執行,如果i不存在就尋找h流程來執行,如果連h也不存在,就掛機。當沒有任何參數的時候該通道也會掛機。
    7)、GotoIf
    語法:GotoIf(condition?[labeliftrue]:[labeliffalse])
    這個命令是有條件的跳轉,跟c語言中的?:語句有點類似,當condition的條件為1時跳轉到labeliftrue處,否則跳轉到labeliffalse處。label的格式為[[context|]extension|]priority。其他就跟Goto命令一樣。
    就先介紹這幾個常用的,別的一些會在下一篇中介紹。
三、Dialplan中的變量和邏輯表達
   a、Dialplan中的變量通過${變量名}來引用和標識,變量名不一定要大些,但是大些可有助於閱讀。
    1)、全局變量
     全局變量適用於所有的Context所有的extension。全局變量可以在[globals]段中定義,也可以通過SetGlobalVar()來定義。下面舉個例子。
     [globals]
     OUTLINE=Zap/g1
     或
     [from-ext]
     exten => _9XXXXXXX.,1,SetGlobalVar(OUTLINE=Zap/g1)
    2)、通道變量
    通道變量是特定的呼叫相關的變量,與全局變量不同,通道變量只能在當前呼叫存在期間定義,並只能用於參與該呼叫的通道。有很多預先定義的通道變來那個可以用於Dialplan,在asterisk源程序中的doc子目錄下channelvariables.txt文件中有詳細的介紹。通道變量可以通過Set()來設置。例如:
    exten => _123409XX,1,Set(INCOMING=${EXTEN})
    EXTEN就是一個asterisk已經預先定義的變量,他表示的就是當前的extension。既然提到了EXTEN變量在這里順便就說一下變量的截取,語法是這樣的:${variable_name[:offset[:length]]}。舉個例子倆說明一下:
    exten => 12340900,1,Set(INCOMING=${EXTEN})
    這個里面${EXTEN}就是12340900,如果我只想要后四位那怎么辦那?${EXTEN:4}就表示0900了,也就是去掉了${EXTEN}的前四位;那要是想要前四位怎么辦那?很簡單${EXTEN:0:4}就表示1234了。offset和length也可以是負數,offset是負數表示要的是從后面數|offset|個數,length是負數表示要的是除了從后面數的|length|個數。哈哈,說的不太明白舉個例子吧。${EXTEN:-4}也表示0900,${EXTEN:-2}就表示00,${EXTEN:2:4}表示3409,${EXTEN:2:-2}也表示3409,${EXTEN:-6:-2}也表示3409.
    3)、環境變量
     環境變量是一種在asterisk里面訪問操作系統環境變量的一種方法。這些變量以${ENV(var)}的形式引用,其中var就是要引用的操作系統環境變量。
    b、邏輯表達式,你應該沒有忘記${var}表示變量,邏輯表達式和這個差不多$[expression].$[1 + 2]就表示1+2的結果3.中括號中運算符和變量之間最好用空格分開,否則可能會出現錯誤的結果。當然中括號里面可以是任意運算符。這些預算符包括:
    1)、邏輯運算符
    expr1 | expr2     當expr1為真,賦值為expr1的值,否則為expr2的值
    expr1 & expr2   當expr1和expr2的值都為真時,賦值為expr1的值,否則賦值為0
    expr1 {=, >, >=, <, <=, !=} expr2    如果自變量都是整數,將得到一個整數的比較結果;否則他們將得到字符串的結果,如果給定的關系是正確的,這個結果是1,否則就是0.
    ! expr1      取反,當expr1是NULL、0、一個空字符串、或者一個字符串"0",返回1;否則返回0.
    2)、數學運算符
    expr1 {+, -, *, /, %} expr2   加減乘除余數
    - expr1             取負
    3)、正則表達式運算符
    expr1 : expr2    這個運算符expr2匹配到expr1,expr2必須是個表達式,如果匹配成功,被匹配的表達式包括了至少一個正則表達式的字表達式,整個表達式對應返回(1 or \1);另外,匹配操作符返回字符匹配上的數量。如果匹配失敗,返回空值。其他情況返回0.
    expr1 =~ expr2   這個運算符和:很像,唯一區別就是這個可以不從字符串的開始匹配。
   4)、三態運算符
    expr1 ? expr2 : expr3    這個用法就不用說了,說說expr1的否的條件就行了,數字的話是0,字符串時""(空串)。
  c、運算符優先級
   1)、(,)
   2)、!,-
   3)、:,=~
   4)、*,/,%
   5)、+,-
   6)、=,!=,<,>,<=,>=
   7)、|,&
   8)、?:
四、撥號方案函數
  撥號方案函數可以增加更多功能到你的表達式中,你可以想象他們運行起來和操作符類似,但是更高級一些。
  語法:FUNCTION_NAME(argument)
  非常像變量,你可以引用函數名,但是你如果要引用函數的值,就要用美元"$"放在前面,用花括號"{}"括起函數表達式。就像這樣:
   ${FUNCTION_NAME(argument)}
  函數也可以嵌套封裝其他的函數,如下:
   ${FUNCTION_NAME(${FUNCTION_NAME(argument)})}
  舉個例子吧:
   exten => 123,1,Set(TEST=example)
   exten => 123,2,SayNumber(${LEN(${TEST})})
   上面這個例子能算出字符串example有7個字符,將字符串的數量賦值給變量長度,然后將數量送給SayNumber().
五、Include
  Asterisk允許在一個context中使用另一個context,通過include指令來實現。這用來授予訪問權給不同的撥號方案段。介紹一下語法:
  語法:include => context
  在當前context包含另外的context時,必須注意包含順序。Asterisk首先試圖在當前context中匹配extension。如果不成功,會試圖嘗試第一個包含進來的context,然后按照包含順序再去嘗試其他的context。就跟把包含的contex拷貝到當前context的后面有點類似。另外還有一種include的應用就是一個dialplan文件包含另一個dialplan文件,意思和上面說的include用法差不多,只不過這回是文件。
  語法:#include FILENAME
  這個在elastrix中應用的比較多,差不多每個關鍵的配置文件都包含另一個附加的配置文件。舉個在elastrix里面的例子,在extensions.conf
 文件中你會發現這樣的語句:
  #include extensions_additional.conf
  #include extensions_custom.conf
六、宏macro
  你如果熟悉計算機編程,那么你對宏就肯定不會陌生,dialplan也支持。你可以定義一個宏指令,它包含多步的指令列表,然后讓電話extension指向這個宏指令。
  語法:[macro-MACRONAME]
     exten => s,1,action
     exten => s,n,action
     exten => s,n,action
  調用語法:exten => Macro(macroname,arg1,arg2...)
  宏指令的名字必須以macro-作為開始。這是他們與常規的context的區別。Dialplan中的宏指令的命令同其他任何命令很相似。唯一的限制因素是宏指令只能用"s"extension。我們先定義一個宏指令:
  [macro-dial]
  exten => s,1,Dial(SIP/101)
  exten => s,n,VoiceMail(101)
  接下來我們看看怎樣調用宏指令:
   exten => _123409XX,1,GotoIf($[${EXTEN}=12340910]?4:2) 
   exten => _123409XX,2,Macro(dial)
   exten => _123409XX,3,Goto(5)
   exten => _123409XX,4,BackGround(MyVox/Greeting)
   exten => _123409XX,5,Hangup
  此外Macro()程序也定義了幾種特別的變量來為我們使用。它們包括:
   ${MACRO_CONTEXT}       這個被調用宏中,初始的context
   ${MACRO_EXTEN}     這個被調用宏中,初始的extension
   ${MACRO_PRIORITY}    這個被調用宏中,初始的priority
   ${MACRO_OFFSET}     宏返回后從${MACRO_OFFSET}+n+1的priority處執行
   ${ARGn}         傳遞到宏指令的第n個變量。例如第一個自變量是${ARG1},第二個是${ARG2}
  為了舉個使用變量的例子,我們把上面例子的宏修改一下:
   [macro-dial]
   exten => s,1,Dial(SIP/1${MACRO_EXTEN:6})
   exten => s,n,VoiceMail(1${MACRO_EXTEN:6})
  這樣當撥的是12340901時宏就執行Dial(SIP/101),並給並留言到101語音信箱里面。
七、結束語
  終於結束了(有遺漏的以后再加吧)。其實這篇文章最初想法是寫給楊兄的,后來想想既然寫了為什么不寫成個類似文章樣式的,放到自己的空間,給一些希望了解asterisk的人一些幫助。中文說asterisk的數很少,據我所和好像只有《asterisk未來電話之路》這本書漢化了,要想讓技術發展就得有自由和寬松的風氣,就像春秋戰國時一樣大家勇於發表自己的見解、勇於討論。我知道國內有很多asterisk的高手,我搞asterisk也才只有兩年,只能算個剛入門的新生,所以我希望能有更多的人,能把自己學到的對於asterisk技術見解和技術思路,都寫出來大家分享。哪怕就像我一樣只是匯集翻譯個文檔。最后希望只要能幫助到大家就好,哈哈,記住轉載一定要保留我的名字和出處,謝謝了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM