asterisk Chapter 6.Dialplan Basics 学习笔记

好老的一个话题了,单从软件应用上来说已经快淘汰了,不过它所使用的SIP协议和IP通话的原理架构,在现在仍然有广泛的使用,贴上来仅作为一个曾经学习的记录......
关于sip分机的注册是在 Asterisk:The.Definitive.Guide 第五章讲解的,简单说就是在sip.conf文件里面添加一个个形如下面形式的字段:
[分机号]
type=friend ;注册类型,和认证安全级别有关
secret=abcd ;注册密码
host = dynamic ;使用动态还是静态IP注册
context=test ;所属规则上下文,有些叫他拨号计划,可我就喜欢叫它拨号规则,简单直白。
当然他还可以设置很多其他的参数值,不过这份笔记是第六章的,不会再提第五章的内容了。


第六章讨论的只有一个:
context=test 对应的拨号规则的设定规范,仅限呼叫相关,说白了就是打电话。是最基础的也是必不可少的配置。

文件extensions.conf放置的位置一般都是/etc/asterisk/ 下,另外常见的位置还有/usr/local/etc/asterisk和 /opt/etc/asterisk,该文件内容包含所有 context 的集合,或者叫拨号规则的集合,当然一个拨号规则可能另包含多个规则条目,不同的人对它可能有不同的称呼,我需要声明自己表达的意思,延续上面的例子来说:
1、extensions.conf: 配置文件,拨号规则的集合
2、context=test: 拨号规则,会映射到extensions.conf 文件中的一个字段[test],并从该字段开始定义规则条目,可以包含多个规则条目,当然这些内容都是要自己一个个编写的,不是自动生成的。
3、规则条目: 每一个定义的匹配项和本轮对它将要采取的所有操作步骤,我将它称之为一个规则条目
4、操作步骤: 每一行exten=>的操作动作,我将它称之为一个操作步骤

拨号规则是给分机调用的,不同分机可以调用同一个拨号规则,但是同一个分机不能调用多个拨号规则。原因很简单,不同的拨号规则之间可能有重复或冲突的规则条目。

一个拨号规则可以包含其他的拨号规则
虽然一个分机只能从属于一个拨号规则,但可以通过包含关系,将自己的拨号规则传递给其他分机,或者将其他分机的拨号规则传递给自己。

比如一个号码为601的分机,context = context1 ,仅有拨号规则exten=>_1xx,1,dial(SIP/${EXTEN})

另外一个号码为602的分机,context = context2 ,仅有拨号规则exten=>_2xx,1,dial(SIP/${EXTEN})

此时,601无法拨打2xx的号码,602无法拨打1xx的号码

如果想让601可以拨打2xx的号码,有两种方式:
1、在 [context1] 中添加对应的拨号规则即可
2、在 [context1] 中添加一行 include => context2 ,这样 context1 中就能够调用 context2 的拨号规则
[context1]
exten=>_1xx,1,dial(SIP/${EXTEN})
include => context2

但是这种方法一不小心就可能造成规则重复冲突,所以对于少量的规则条目而言,没必要使用。

拨号规则限定的是主叫,不是被叫。
分机既可能成为主叫,也可能成为被叫;当分机是主叫的时候,拨打的号码就必需遵循所属的拨号规则,如果拨打的目标号码在自己的拨号规则中找不到匹配项,服务器就会报错;当分机是被叫的时候,拨号规则对它没有意义(只讨论打电话)。

默认已存在的几个重要的context:
[general]
[default]
[globals]
[public]
An important use of contexts (perhaps the most important use) is to provide security.

拨号规则条目的设定:
exten => name,priority,application() ; exten的三要素,号码,优先级,方法

name
目标号码,可以直接写号码,也可以使用模式匹配;支持数字和字符
Pattern Matching 模式匹配,使用下划线_开始,后面可以接的通配符
_X ; 0-9
_Z ; 1-9
_N ; 2-9
_. ; 这里的 . 表示匹配0个到任意多个的任意字符,包括数字、字母和符号。但是这种写法包含了asterisk内建的i、t参数,有冲突,所以,不要这样写。如果一定要匹配以随意字符开头的字符串,第一个字符最好使用方括号,比如:
_[0-9a-zA-Z].
_X. ; 第一位匹配0-9数字,后面的不限制

示例:exten => _NXX.,1,Playback(silence/1&auth-thankyou)

被叫和主叫可以同时匹配,使用“/”来分割被叫和主叫号码,前面是被叫,后面是主叫:定义extension时的其它选项包括被称为“ex-girlfriend”逻辑的选项。这个逻辑将匹配extension,不管是来自外部还是内部,关键是看拨入人的主叫ID(caller id).例如:

  exten=>123/100,1,Answer()
  exten=>123/100,2,Playback(tt-weasels)
  exten=>123/100,3,Voicemail(123)
  exten=>123/100,4,Hangup()

只有当主叫的ID号为100时,这个extension才被匹配,并且执行接下来的选项。这个也可以通过模式匹配来完成,如下所示:
exten=>1234/_256NXXXXXX,1,Answer()
只有以256开头的Caller Id才会匹配“1234”这个模式。这在保持本地呼叫时是很有用的。
如果要拨符合左边规格的被叫号码,主叫号码必须符合右边的规则,如果主叫号码不符合规则,将被服务器以401拒绝。

通配符遵循最长匹配优先和精确匹配优先的原则:
exten => _555XXXX,1,Playback(silence/1&digits/1)
exten => _55512XX,1,Playback(silence/1&digits/2)
如果目标号码是以55512开头,匹配到的将是第二项

_NXXXXXX ; 使用7位数就可以与北美的本地7位号码兼容
_NXXNXXXXXX ; 10位数号码模式

部分原文内容:
North American Numbering Plan //NANP,北美拨号计划,该规则在北美19个国家中通用,尤其在美国和加拿大技术比较成熟,能够使用该规则拨打大部分的长途电话,但有些小地方规则会不太一样,比如加勒比地区,不熟悉的人容易被坑,拨打到收费很贵的电话线路上去。
Pattern Matches in Other Countries
The examples in this section were NANP-centric, but the basic logic applies in any country. Here are some examples for other countries (note that we were not able to test these, and they are almost certainly incomplete):
; UK, Germany, Italy, China, etc.
_00. ; international dialing code
_0. ; national dialing prefix
; Australia
_0011. ; international dialing code
_0. ; national dialing prefix
This is by no means comprehensive, but it should give you a general idea of the patterns you’ll want to consider for your own country
If you grew up in North America, you may believe that the 1 you dial before a long-distance call is “the longdistance code.” This is incorrect. The number 1 is the international country code for NANP. Keep this in mind if you send your phone number to someone in another country. The recipient may not know your country code, and thus be unable to call you with just your area code and phone number. Your full phone number with country code is +1 NPA NXX XXXX (where NPA is your area code)—e.g., +1 416 555 1212.

一个规则条目可能包含有多个处理步骤,这些步骤的目标号码显然是一样的,简化的写法可以用same, 省略目标号码,更加便于修改和移植,如:

exten => 123,1,Answer()
same => n,do something
same => n,do something else
same => n,do one last thing
same => n,Hangup() 

关于 n 的意思,看下文


priority ; 优先级,代码执行顺序
第一步一定要写成1,否则直接报错。
后面的步骤,可以写2,3,4,5…
也可以写 n 代表下一步,按照代码从上到下的顺序执行即可,不需要精确到第几步,这样有助于循环调用的灵活性。
所以,对于
same => n,do something
意思就是承接本匹配项的上一步,接下来 do something

Priority labels
优先级的符号标签,主要用于定位,因为当使用 n 代表执行步骤的时候,必需另外找一个唯一标签来定位步骤,比如在Goto()的参数中,就可以用label来替换n:

exten => 123,1,Answer()
same => n(label),Playback(audioFile)   ; label的名字可以随便取
same => n,do something
same => n,do something else
same => n,Goto(label)

application()
方法函数,下面是一些常用的方法

Answer() 应用于接听正在响铃的通道,没有参数。

Progress() ; 向主叫方通告呼叫的进程

Playback(audioFile) ; 播放某个语音文件,可带有路径,绝对路径或相对asterisk sounds directory的路径,目前自己测试的结果是不能播放wav文件(可能安装的时候没有安装相应的编解码模块),能播放gsm文件,最后的文件名不能写后缀!Playback()是一定要把音频播放完才会执行下一步的,除非被叫方接听了,中间的任何用户输入都是无效的!

Hangup() ; 从服务器端挂断通道。不需要参数,但可以加一个ISDN原因码

Background() ; 播放音频文件,和Playback()的作用类似,但另外有一个很重要的作用,即可监听用户的二次输入,只要用户开始输入,播放就自动停止了。被广泛用于生成语音菜单。
[TestMenu]
exten => start,1,Answer()
same => n,Background(enter-ext-of-person)

WaitExten() ; 号里面可以写数值,单位为秒,即等待用户输入的最大时间,二次拨号用的。
The WaitExten() application waits for the caller to enter DTMF digits and is used directly following the Background() application, like this:
[TestMenu]
exten => start,1,Answer()
same => n,Background(enter-ext-of-person)
same => n,WaitExten()

Background()和WaitExten() Playback() 典型的组合使用方式:
[TestMenu]
exten => start,1,Answer()
same => n,Background(enter-ext-of-person)
same => n,WaitExten(5)
exten => 1,1,Playback(digits/1)
exten => 2,1,Playback(digits/2)

Goto() ; 可以有1-3个参数
只有1个参数时,它是priority参数;暗含了作用域为本 context 和本条 exten 规则
只有2个参数时,它是 exten 和 priority 参数,暗含了作用域为本 context .
有3个参数时,它分别是 context, exten, priority 参数

[TestMenu]
exten => start,1,Answer()
same => n,Background(enter-ext-of-person)
same => n,WaitExten(5)

exten => 1,1,Playback(digits/1)
same => n,Goto(TestMenu,start,1)

exten => 2,1,Playback(digits/2)
same => n,Goto(TestMenu,start,1)

exten => i,1,Playback(pbx-invalid)
same => n,Goto(TestMenu,start,1)

exten => t,1,Playback(vm-goodbye)
same => n,Hangup() 

以上示例,展示了
如果用户按了没有定义的字符,将转到关于i的动作
如果用户输入超时,将转到关于t的动作

Dial(destination, timeout, option, URI)
四个参数,后三个都是可选参数,中间留空的要用逗号声明,比如:
exten => 1,1,Dial(DAHDI/1,,m) //只有第1个和第3个参数,第2个和第4个参数留空

1.destination
Dial(technology/user[:password]@remote_host[:port][/remote_extension])
常用的技术类型包括 DAHDI(for analog and T1/E1/J1 channels),SIP,and IAX2.

(1) technology: 表示用到的协议技术
(2) user…: 表示该请求转交给某个中间设备,对于register模式,直接使用注册ID即可,如果是内部呼叫,不需要中间设备,这一项就不需要写。
(3) remote_extension: invite 对象

可以在示范服务器上做如下实验
exten => 500,1,Dial(IAX2/guest@misery.digium.com/s)
The full syntax for the Dial() application is slightly different for DAHDI channels:
Dial(DAHDI/[gGrR]channel_or_group[/remote_extension])
For example, here is how you would dial 1-800-555-1212 on DAHDI channel number
4:13
exten => 501,1,Dial(DAHDI/4/18005551212)

2.timeout 可选的,单位为秒,如果没有定义timeout,会一直尝试拨打目标分机不会停止,直到对方接通,或者主叫方主动挂断。
exten => 502,1,Dial(DAHDI/1,10)

Let’s put what we’ve learned so far into another example:
exten => 502,1,Dial(DAHDI/1,10)
same => n,Playback(vm-nobodyavail)
same => n,Hangup()
As you can see, this example will play the vm-nobodyavail.gsm sound file if the call goes unanswered.

3.option 可选的,参数很多,比如t T m, 可以多个参数一起写,常用的如 m ,主叫方将听到一段服务器内置的铃音,但这未必是个好选择,因为会导致主叫无法接听到远端的回铃音,进而无法判断被叫方是否接收到了呼叫请求。
exten => 502,1,Dial(DAHDI/1,10,m)
same => n,Playback(vm-nobodyavail)
same => n,Hangup()

4.URI 可选的
If the destination channel supports receiving a URI at the time of the call, the specified URI will be sent

一个完整的演示

[TestMenu]
exten => start,1,Answer()
same => n,Background(enter-ext-of-person)
same => n,WaitExten(5)
exten => 1,1,Dial(SIP/0000FFFF0001,10) ; Replace 0000FFFF0001 with your device name
same => n,Playback(vm-nobodyavail)
same => n,Hangup()
exten => 2,1,Dial(SIP/0000FFFF0002,10) ; Replace 0000FFFF0002 with your device name
same => n,Playback(vm-nobodyavail)
same => n,Hangup()
exten => i,1,Playback(pbx-invalid)
same => n,Goto(TestMenu,start,1)
exten => t,1,Playback(vm-goodbye)
same => n,Hangup() 


变量和表达式

一般都是用在方法函数中的

${VARIABLENAME} ; 变量,也可以是表达式,区分大小写,习惯上都使用Pascal/Camel规范写法.
使用表达式的结构${EXPRESSION} ,这里表达式可以是常用表达式,比较表达式,加法表达式等等。

exten => 301,1,Set(LEIF=SIP/0000FFFF0001)
same => n,Dial(${LEIF})

有三种变量:global variables,channel variables,environment variables

全局变量在所有通道、所有时间范围里面都有效,它在extensions.conf文件中的起始位置:[globals]context中申明,如:
[globals]
LEIF=SIP/0000FFFF0001

通道变量channel variables只在当前通话的信道有效,be set via the Set() application.
exten => 202,1,Set(MagicNumber=42)
same => n,SayNumber(${MagicNumber})

环境变量,提供了一种从asterisk内部访问Unix环境变量的方式,格式为ENV(),调用格式为${ENV(var)},其中的var可以是任意你想指定的Unix环境变量。

举例:

[globals]
LEIF=SIP/0000FFFF0001
JIM=SIP/0000FFFF0002
RUSSELL=SIP/0000FFFF0003
[LocalSets]
exten => 101,1,Dial(${LEIF})
exten => leif,1,Dial(${LEIF})
exten => 102,1,Dial(${JIM})
exten => jim,1,Dial(${JIM})
exten => 103,1,Dial(${RUSSELL})
exten => russell,1,Dial(${RUSSELL})
exten => 201,1,Goto(TestMenu,start,1) ; access the TestMenu context
[TestMenu]
exten => start,1,Answer()
same => n,Background(enter-ext-of-person) 
same => n,WaitExten()
exten => 1,1,Dial(DAHDI/1,10)
same => n,Playback(vm-nobodyavail)
same => n,Hangup()
exten => 2,1,Dial(SIP/Jane,10)
same => n,Playback(vm-nobodyavail)
same => n,Hangup()
exten => i,1,Playback(pbx-invalid)
same => n,Goto(TestMenu,start,1)
exten => t,1,Playback(vm-goodbye)
same => n,Hangup() 

${EXTEN} ; 该变量表示当前exten=>匹配到的号码

SayDigits(${EXTEN}) //向主叫方读出刚刚输入的分机号
exten => _XXX,1,Answer()
same => n,SayDigits(${EXTEN})

变量切片法则同linux shell,语法如下:
${EXTEN:x:y}

举例:给出一个name: 94169671111,按照要求截取号码:
\${EXTEN:1:3} ; 去掉左边第1个数,取接下来的3个数 结果:416
\${EXTEN:2:-4} ; 去掉左边两个数,再去掉右边4个数(从右往左数4个数),取中间的数 结果:16967
\${EXTEN:-4:4} ; 从右往左数4个数,以此为基点去掉左边所有的数,取接下来的4个数 结果:1111
\${EXTEN:-6:-4} ; 从右往左数6个数,以此为基点去掉左边所有的数,再去掉右边4个数,取中间的数 结果:67
平常使用一般不会搞得那么复杂,最主要的使用还是\${EXTEN}和\${EXTEN:1}


一段原文:
The [globals] section contains two variables, named LOCAL and TOLL.3 The purpose of these variables is to simplify management of your dialplan should you ever need to change carriers. They allow you to make one change to the dialplan that will affect all
places where the specified channel is referenced:

[globals]
LOCAL=DAHDI/G0 ; assuming you have a PSTN card in your system
TOLL=SIP/YourVoipCarrier ; as defined in sip.conf
The [external] section contains the actual dialplan code that will recognize the numbers dialed and pass them to the Dial() application:4
[external]
exten => _NXXNXXXXXX,1,Dial(${LOCAL}/${EXTEN}) ; 10-digit pattern match for NANP
exten => _NXXXXXX,1,Dial(${LOCAL}/${EXTEN}) ; 7-digit pattern match for NANP
exten => _1NXXNXXXXXX,1,Dial(${TOLL}/${EXTEN}) ; Long-distance pattern match for
; NANP
exten => _011.,1,Dial(${TOLL}/${EXTEN}) ; International pattern match for
; calls made from NANP
; This section is functionally the same as the above section.
; It is for people who like to dial '9' before their calls
exten => _9NXXNXXXXXX,1,Dial(${LOCAL}/${EXTEN:1})
exten => _9NXXXXXX,1,Dial(${LOCAL}/${EXTEN:1})
exten => _91NXXNXXXXXX,1,Dial(${TOLL}/${EXTEN:1})
exten => _9011.,1,Dial(${TOLL}/${EXTEN:1})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值