近来一直在研究asterisk的dialplan。本文是全部的例子均来自“未来之路”。希望能给和我一样在刚刚开始学习asterisk的人有所帮助。当然在网上还有很多这样的文档。不过我想对于初学者来说还是自己动手写一下会比较好。
拨号方案的语法
拨号方案由四部分组成:
contexts(分组),
extensions(asterisk要执行的命令),
priorities(步骤),
applications(应用)
在与电话系统打交道的时候我们把extension看作是呼叫另一部电话所播的号码。
Dialplans被分为几个段,这些段为ceontext。context用来分组
当然在你定义context的名字的时候是取决于你freePBX的(他们两个要相互对应)。
Extension
每一个eontext内都有一个或多个extension。extension是asterisk要执行的命令,有来电或者通道上所比的数字来触发
一个完整的extension包含三部分:
Extension的名字或者号码,
Priority(每个extension可以有多个步骤,步骤的编号称作(Priority),
应用或者命令,针对呼叫完成一些动作。
例:exten => name,priority,application()
[from-incoming]
exten => name,priority,application()
exten => 123,1,Answer() ;应答
exten => 123,2,Playback(hello-world);播放语音文件在Playback括号内可以些完整的路径但文件不能带文件名
exten => 123,2,Hangup() ;挂断
Priority
每个extension都可以有多个步骤,称作Priorities。每个Priority都按顺序编号,从1开始。在asterisk1.2版本里出现了Priority编号有了新的变化引入n Priority。n表示下一个的意思。每次一道"n"就取前一个Priority的编号加上1。
在拨号方案中加入逻辑
Background()和Goto()应用
Background:构建交互式Asterisk系统的关键是Background()的应用。与Playback()相同的是,他也播放事先录制好的语音文件;与Playback不同的是,当主角方案下电话键的时候会中断播放转到所按的数字对应的extension。
语法为:exten => 123,2,Background(hello-world)
Goto:用于把呼叫发送到另一个context,extension,以及priority。Goto应用是的在拨号方案的不同部分有序的转移非常容易。
语法是通过对吧context,extension和priorty作为目的地路径来执行如下:
exten => 123,1,Goto(context,extension,priority)
现将Background和Goto 写在一个拨号规则里如下:
[from-incoming]
exten => s,1,Answer()
exten => s,2,Background(exter-ext-of-person)
exten => 1,1,Playback(digits/1)
exten => 1,2,Goto(incoming,s,1)
exten => 2,1,Playback(digits/2)
exten => 2,2,Goto(incoming,s,1) ;负责在回放选择的数字之后,把呼叫控制发送给s extension
加入非法输入和超时的处理
[from-incoming]
exten => 302,1,Answer()
exten => 302,2,Background(exter-ext-of-person)
exten => 1,1,Playback(digits/1)
exten => 1,2,Goto(incoming,s,1)
exten => 2,1,Playback(digits/2)
exten => 2,2,Goto(incoming,s,1)
exten => i,1,Playback(pbx-invalid) ;i 无效按键
exten => i,2,Goto(incoming,s,1) ;t 超时
exten => t,1,Playback(vm-goodbye)
exten => t,2,Hangup()
i和t的应用使拨号规则更加健壮和有好一些但是因为主叫无法和实际的人联系需要了解另外一个应用为Dial()
使用Dial()应用
Dial():作用是分配通道。
Dial()有四个参量
第一个是呼叫的被较地,由呼叫所采用的技术,反斜线,远地资源等组成。
exten => 123,1,Dial(Zap/1)
同时连接多个通道使用"&"连接
exten => 123,1,Dial(Zap/1&Zap/2&Zap/3&Zap/4)
第二个是超时单位为秒。如果给懂了超时参量,Dial()会一直对被叫进行呼叫,知道指定超时时间。
exten => 123,1,Dial(Zap/1,10)
如果呼叫在超时之前被接通通道就被桥接,拨号方案完成。如果没有应答Dial()会继续道该extension的下一个priority。但是如果通道忙Dial()将会转到priotity+101,如果气存在的话(其中的n是Dial()会被调用的priority)如下:
[from-incoming]
exten => 123,1,Dial(Zap/1,10)
exten => 123,n,Playback(vm-nobodyavail)
exten => 123,n,Hangup()
exten => 123,102,Playback(tt-allbusy)
exten => 123,n,Hangup
第三个是可选的字符串。包含一个或多个能够影响Dial()应用行为的字符。最常用的是r(非必填项)。
[from-incoming]
exten => 302,1,Answer()
exten => 302,n,Background(enter-ext-of-person)
exten => 101,1,Dial(Zap/1,10)
exten => 101,n,Playback(vm-nobodyavail)
exten => 101,n,Hangup()
exten => 101,102,Playback(tt-allbusy)
exten => 101,n,Hangup()
exten => 102,1,Dial(SIP/6650,10)
exten => 102,n,Playback(vm-nobodyavail)
exten => 102,n,Hangup()
exten => 102,102,Playback(tt-allbusy)
exten => 102,n,Hangup()
exten => i,1,Playback(pbx-invalid)
exten => i,n,Goto(incoming,s,1)
exten => t,1,Playback(vm-goodbye)
exten => t,n,Hangup()
给内部呼叫增加Context
1.首先配置通道
拨号规则为:
[from-incoming]
exten => 302,1,Answer()
exten => 302,n,Background(enter-ext-of-person)
exten => 101,1,Dial(Zap/1,10)
exten => 101,n,Playback(vm-nobodyavail)
exten => 101,n,Hangup()
exten => 101,102,Playback(tt-allbusy)
exten => 101,n,Hangup()
exten => 102,1,Dial(SIP/6650,10)
exten => 102,n,Playback(vm-nobodyacail)
exten => 102,n,Hangup()
exten => 102,102,Playback(tt-allbusy)
exten => 102,n,Hangup()
exten => i,1,Playback(pbx-invalid)
ecten => i,n,Goto(incoming,s,1)
ecten => t,1,Playback(vm-goodbye)
exten => t,n,Hangup()
[from-internal]
exten => 101,1,Dial(zap/1,,r)
exten => 102,1,Dial(SIP/302,,r)
或者可已使用名字,但是需要用户可能通过支持名字的VoIP传输来拨号
[from-internal]
exten => 101,1,Dial(zap/1,,r)
exten => 102,1,Dial(SIP/302,,r)
下面在拨号方案里使用变量,在拨号方案里有三种变量:全局变量、通道变量和环境变量
全局变量
如名字所说全局变量使用于所有的context里的所有extensions。全局变量的好处在于可以用在拨号发难的任意地方
定义全局变量的两种方法 SetGlobalVar
[globals]
JOHN =Zap/1
[from-internal]
exten => 123,1,SetGlobalVar(JOHN =Zap/1)
通道变量
通道变量是特定的呼叫相关的变量(如 Caller *IDnumber),与全局变量不同通道变量只能在当前呼叫存在期间定义并只能用于参与该呼叫的通道。 通道变量使用set来设置。
如下例:
exten =>123,1,Set(MAGICUNMBER=42)
环境变量
环境变量是一中在Asterisk中访问操作系统环境变量的方法这些变量以${ENV(var)}形式引用的中的var是所有引用的操作系统环境变量
在拨号方案中加入变量及区别权限
[globals]
JOHN = Zap/1
JANE = SIP/302
[incoming]
exten => 302,1,Answer()
exten => 302,2,Background(enter-ext-of-person)
exten => 101,1,Dial(${JOHN},10)
exten => 101,n,Playback(vm-nobodyavail)
exten => 101,n,Hangup()
exten => 101,102,Playback(tt-allbusy)
exten => 101,n,Hangup()
exten => 102,1,Dial(${JANE},10)
exten => 102,n,Playback(vm-nobodyavail)
exten => 102,n,Hangup()
exten => 102,102,playback(pbx-invalid)
exten => 102,n,Hangup
exten => 102,102,Playback(tt-allbusy)
exten => 102,n,Hangup
exten => i,1,Playback(pbx-invalid)
exten => i,n,Goto(incoming,s,1)
exten => t,1,Playback(vm-goodbye)
exten => t,n,Hangup()
[internal]
exten => 101,1,Dial(${JOHN},,r)
exten => 102,1,DIAL(${JANE},,r)
模式匹配:总是以一个(_)开始
在下划线之后可以使用一个或多个下面列出来的字符
X:匹配0-9的任意数字
Z:匹配1-9的任意数字
N:匹配2-9的任意数字
[15-7]:匹配任何数字或者指定的数字范围。这个表示匹配1,5,6,或7
。(句号):通配符,匹配一个或多个字符
例拨打(匹配三位的extension)从200到999:
exten => _NXX,1,Playback(auth-thankyou)
需要注意的是在Asterisk中多个模式与所播的extension匹配他会使用最接近的一个模式。通常我们把extension的前几位去掉处理${EXTEN:x}其中的x是要去掉的位数。如exten的值为95551212那么${exten:1}取出的值就为5551212拨号规则如下:
exten => _XXX,1,SayDigits(${exten:1})
如果只读出最后一位:exten => _XXX,1,SayDigits(${exten:-1})
开启去话拨号
首先要走的事情是给[globals]context加一个变量(当然单独建一个context这样做的目的是能够规定和空值谁可以拨打去话以及拨打什么样的去话),用于定义一个通道可以用来向外拨打电话:
[globals]
JOHN = Zap/1
JANE = SIP/302
OUTBOUNDTRUNK = Zap/4
建立本地电话的context,为了和传统电话交换机保持一直,我们在模式之前放上9因此用户在呼叫外部号码之前先拨9
[outbound-local]
exten => _9NXXXXXX,1,Dial(${OUTBOUNDTRUNK}/${EXTEN:1})
exten => _9NXXXXXX,n,Congestion()
ecten => _9NXXXXXX,102,Congestion()
需要注意的是拨9并没有立即给你外线,这和传统的PBX系统不同。一旦在FXS线路上拨9,拨号音会停止。如果在拨9之后还希望有拨号音没加入下面一行(就在context定义之后):
ignorepat => 9
建立一个长途电话的context
[outbound-long-distance]
exten => _91NXXNXXXXXX,1,Dial(${OUTBOUNDTRUNK}/${EXTEN:1})
exten => _91NXXNXXXXXX,2Congestion()
exten => _91NXXNXXXXXX,102,Congestion()
现在有了连哥哥新的context,如何允许内部用户利用他们?我们需要一种办法来世的一个context能够使用另一个context。
Incaludes
Asterisk允许在一个context中使用一个context,通过include指令来实现。这用来授予访问权给不同的拨号方案。我们使用include功能来让[internal],context中的用户能够拨打去话。语法如下:
include => context
到目前为止拨号方案中有两个context用于去话但是[internal]context中的人好不能够使用他们。我们用在 [internal]context包含这两个去话context来实现使用,如下:
[globale]
JOHN =Zap/1
JANE = SIP/6650
OUTOUNDTRUNK = Zap/4
[from-incoming]
exten => 600,1,Answer()
exten => 600,n,Background(exter-est-of-person)
exten => 101,1,Dial(${JOHN},10)
exten => 101,n,Playback(vm-noboduavail)
exten => 101,n,Hangup()
exten => 102,1,Dial(${JANE},10)
exten => 102,n,Playback(vm-nobodyavail)
exten => 102,n,Hangup()
exten => 102,102,Playback(tt-allbusy)
exten => 102,n,Hangup()
exten => i,1,Playback(pbx-invalid)
exten => i,n,Goto(incoming,s,1)
exten => t,1,Playback(vm-goodbye)
exten => t,n,Hangup()
[from-internal]
include => ourbound-local
include => outbound-long-distance
exten => 101,1,Dial(${JANE},,r)
exten => 102,1,Dial(${HANE},,r)
[outbound-local]
exten => _9NXXXXXX,1,Dial(${OUTBOUNDTRUNK}/${EXTEN:1})
exten => _9NXXXXXX,n,Congestion()
exten => _9NXXXXXX,102,Congestion()
exten => 112,1,Dial(${OUTBOUNDTRUNK}/112)
exten => 9112,1,Dial(${OUTBOUNDTRUNK}/112)
[outbound-long-distance]
exten => _91NXXNXXXXXX,1,Dial(${OUTBOUNDTRUNK}/${EXTEN:1})
exten => _91NXXNXXXXXX,2,Congestion()
exten => _91NXXNXXXXXX,102,Congestion()
在两个include语句让[internal]context内的主叫方可以拨打去话。