FreeSWITCH学习笔记:Local_Extension

第一个例子是Local_Extension。

FreeSWITCH默认的配置提供了1000~1019共20个SIP账号,密码 都是1234。FreeSWITCH通过以下Dialplan可以将来话路由到这些本地的号码。conf/dialplan/default.xml中的 Local_Extension部分如下: -

FreeSWITCH学习笔记:Local_Extension_第1张图片

这个框架说明,用正则表达式(10[01][0-9])$来匹配被叫号码,它匹配所有1000~1019这20个号码。 这里我们假设在SIP客户端上,用1000和1001分别注册到了FreeSWITCH上,则1000呼叫1001时,FreeSWITCH会 建立一个Channel,该Channel构成一次呼叫的a-leg(a腿)。初始化完毕后,Channel进入ROUTING状态,即到达 Dialplan。由于被叫号码1001与这里的正则表达式匹配,所以接下来会执行下面这些Action。另外,由于我们在 正则表达式中使用了“()”,因此匹配结果会放入变量$1中,因此在这里$1=1001。 下面我们再依次来看一下刚才我们省略的“many actions”里面的内容,先从以下两行开始看:

其中,set和export都是设置一个变量,该变量的名字是dialed_extension,值是1001。 关于set和export的区别我们在第5章已经讲过了。这里再重复一次:set是将变量设置到当前的Channel上, 即a-leg。而export则除具备set的功能外,也将变量设置到b-leg上。当然,这时b-leg还不存在。所以在这里它 对该Channel的影响与set其实是一样的。因此,使用set完全是多余的。但是除此之外,export还设置了一个特殊 的变量,叫export_vars,它的值是dialed_extension。所以,实际上面的第二行就等价于下面的两行:

接着往下看:

FreeSWITCH学习笔记:Local_Extension_第2张图片

其中,bind_meta_app的作用是在该Channel上绑定DTMF。上面四行分别绑定了1、2、3、4四个按键,它们都 绑定到了b-leg上。注意,这时候b-leg还不存在。所以请记住这里,后面我们再讲。继续往下看:

此处,设置回铃音是美音(不同国家的回铃音是有区别的),${us-ring}的值是在vars.xml中设置的。接下 来:

以上是设置如果发生呼叫转移时,用户听到的回铃音 [13]。 下面这些变量会影响呼叫流程,关于它们的详细说明参见下文的bridge部分。

call_timeout是设置呼叫超时的变量。 FreeSWITCH学习笔记:Local_Extension_第3张图片

 

继续往下看:

FreeSWITCH学习笔记:Local_Extension_第4张图片hash是内存中的哈希表数据结构。它可以设置一个键-值对(Key-Value Pair)。如上面最后一行向 ${domain_name}-last_dial_ext这个哈希表中插入一个global键,它的值是${uuid},即本Channel的唯一标志 [14]。 不管是上面的set,还是hash,都是保存一些数据为后面做准备的。不同的是set将变量存绑定到Channel上, 以通道变量的形式存在,而hash保存到内存的哈希表数据结构中。 继续往下看,还是设置通道变量:FreeSWITCH学习笔记:Local_Extension_第5张图片

上面最后一行默认是注释掉的,因此不起作用。nolocal的作用我们之前也讲过,它告诉export只将该变量设 置到b-leg上,而不要设置到a-leg上。 下面,还是往哈希表中插入数据:

FreeSWITCH学习笔记:Local_Extension_第6张图片

再往下看,终于到了一个干实事的地方了:

这里,bridge是最关键的部分。其实上面除bridge以外的Action都可以省略,只是会少一些功能而已(如同 组代答、监听等)。 bridge相当于一座桥,它的作用就是把两条腿1000和1001给桥接起来。在这里,为了能连接到 1001,FreeSWITCH作为一个SIP UAC [15],向1001这个SIP UA(UAS)发起一个INVITE请求,并建立一个新 Channel,就是我们的b-leg。1001开始振铃,bridge把回铃音传回到1000,因此1000就能听到回铃音(如果1001 有自己的回铃音,则1000也能听到,否则将会听到默认的回铃音${us-ring})。 当然,实际的情况比我们所说的要复杂,因为在呼叫之前,FreeSWITCH首先要查找1001这个用户是否已经注 册,否则,会直接返回USER_NOT_REGISTERED,而不会建立b-leg。 bridge的参数是一个标准的呼叫字符串(Dial string),以前我们也讲过。domain和domain_name都是预设 的变量,默认就是服务器的IP地址。user是一个特殊的Endpoint,它指本地用户。所以这里的呼叫字符串翻译出 来就是(这里假设IP是192.168.7.2):

{sip_invite_domain=192.168.7.2}user/[email protected] 其中,“{}”里是设置通道变量。由于bridge在这里要建立b-leg,因此这些变量只会建立在b-leg上。这与 set是不一样的,但它等价于下面的export:

好了,到此为止电话路由基本上就完成了,我们已经建立了1000到1001之间的呼叫,1001已经开始振铃,就 等着有人来接电话了。

接下来可能会有以下几种情况: ·被叫应答 ·被叫忙 ·被叫无应答 ·被叫拒绝 ·其他情况…… 我们先来看一下被叫应答的情况。

1001接电话,与1000畅聊。在这个时候bridge一直是阻塞的,也就是 说,bridge这个App会一直等待b-leg(1001)挂机(或者其他错误)后才返回,这时才有可能继续执行下面的 Action。

好吧,让我们先休息一下,等他们两个聊完吧。

最后,无论哪一方挂机,bridge就算结束了。如果1000(主叫)先挂机,则FreeSWITCH会将挂机原因 (Hangup Cause,一般是NORMAL_RELEASE,即正常释放)发送给1001,同时释放b-leg。由于a-leg已经没 了,Dialplan就再也没有往下执行的必要,因此会产生计费信息,并销毁a-leg。 如果1001先挂机,b-leg就这样消失了。但a-leg依然存在,所以还有戏看。 b-leg会将挂机原因传到a-leg。在a-leg决定是否继续往下执行之前,会检查一些变量,以决定该怎么做。其 中,我们在前面设置了hangup_after_bridge=true。它的意思是,如果bridge正常完成后,就挂机。

因此,a-leg 到这里就释放了,它的挂机原因是参考b-leg得出的。 但由于种种原因1001可能没接电话,如1001可能会拒接(返回CAlL_REJECTED,但某些SIP UA会在用户拒接时 返回USER_BUSY,隐藏真实原因)、忙(USER_BUSY)、无应答(NO_ANSWER或NO_USER_RESPONSE)等。出现这些情 况时,FreeSWITCH认为这是不成功的bridge,因此就不管用hangup_after_bridge变量了(由于没有成功的 bridge,也就也没有“after”一说了)。这时候它会检查另一个变量continue_on_fail。由于我们上面设置的 continue_on_fail=true,因此在bridge失败后会继续(continue)执行下面的Action。 这里值得说明的是,通过给continue_on_fail不同的值,可以决定在什么情况下继续,如下面的设置将只在 用户忙和无应答的情况下才会继续呼叫流程:

其他可能的值有:NORMAL_TEMPORARY_FAILURE(临时故障)、TIMEOUT(超时,一般是SIP超时)、 NO_ROUTE_DESTINATION(呼叫不可达)等。 当然,此处的continue_on_fail=true表示无论什么原因导致bridge失败(我们没法联系上1001),我们都决 定继续执行。言归正传,我们接着往下看:

Dialplan执行到这里,answer App首先会使FreeSWITCH给主叫1000回送应答消息,以建立真正的媒体流,准 备对其播放声音。接下来:

sleep表示暂停,1000表示暂停的毫秒数(即1秒),然后转到1001的语音信箱 [16]。另外,值得注意的 是,FreeSWITCH默认配置文件中是通过transfer加loopback Endpoint的方式转到voicemail的,我们还没有学到 loopback,因为这里我们学到的新东西已经够多了,所以为了方便说明,笔者直接改成了voicemail App的形式, 它们在这里的作用是等价的。

你可能感兴趣的:(freeswitch)