首页 > 新闻 > 专家观点 >

《FreeSWITCH: VoIP实战》:拨号计划- Dialplan

2012-08-17 15:51:59   作者:杜金房   来源:CTI论坛   评论:0  点击:


  拨号计划是 FreeSWITCH 中至关重要的一部分。它的主要作用就是对电话进行路由(从这一点上来说,相当于一个路由表)。说的简明一点,就是当一个用户拨号时,对用户所拨的号码进行分析,进而决定下一步该做什么。当然,实际上,它所能做的比你想象的要强大的多。

  我们在第二章中已经提到过修改过拨号计划,单从配置文件看,还算比较简单直观。实际上,它的概念也不是很复杂。如果你理解正则表达式,那你应该能看懂系统系统自带的大部分的配置。但是,在实际应用中,有许多问题还是常常令初学者感到疑惑。主要的问题是,要理解 Dialplan,还需要了解 FS 是怎样工作的(第五章),API 与 APP 的区别等。

  通过本章,我们除了要了解 Dialplan 的基本概念和运作方式,还要以理论与实践相结合的方式来进行学习,使用初学者能快速上手,有经验的人也能学到新的维护和调试技巧。

  XML Dialplan

  Dialplan 是 FreeSWITCH 中一个抽象的部分,它可以支持多种不同的格式,如类似 Asterisk 的格式(由 mod_dialplan_asterisk提供)。但在实际使用中,用的最多的还是 XML 格式。下面,我们就先讨论这种格式。

  配置文件的结构

  拨号计划的配置文件在 conf/dialplan 中,在前面的章节中我们讲过,它们是在 freeswitch.xml 中,由 <X-PRE-PROCESS cmd="include" data="dialplan/*.xml"/> 装入的。

  拨号计划由多个 Context (上下文/环境)组成。每个 Context 中有多个 Extension (分支,在简单的 PBX 中也可以认为是分机号,但很显然,Extension 涵盖的内容远比分机号多)。所以,Context 就是多个 Extension 的逻辑集合,它相当于一个分组,一个 Context 中的 Extension 与其它 Context 中的 Extension 在逻辑上是隔离的。

  下面是 Dialplan 的完整结构:

<?xml version="1.0"?>
<document type="freeswitch/xml">
  <section name="dialplan" description="Regex/XML Dialplan">
    <context name="default">
         <extension name="Test Extension">
         </extension>
    </context>
  </section>
</document>

  Extension 相当于路由表中的表项,其中,每一个 Extension 都有一个 name 属性。它可以是任何合法的字符串,本身对呼叫流程没有任何影响,但取一个好听的名字,有助于你在查看 Log 时发现它。

  在 Extension 中可以对一些 condition (条件)进行判断,如果满足测试条件所指定的表达式,则执行相对应的 action (动作)。

例如,我们将下列 Extension 配置加入到 conf/dialplan/default.xml 中。并作为第一个 Extension。

<extension name="My Echo Test">
  <condition field="destination_number" expression="^echo|1234$">
    <action application="echo" data=""/>
  </condition>
</extension>

  FreeSWITCH 安装时,提供了很多例子,为了避免与提供的例子冲突,强列建议在学习时把自己写的 Extension 写在最前面。当然我说的最前面并不是 default.xml 的第一行,而是放到第一个 Extension 的位置,就是以下语句的后面(你通常能在第13-14行找到它们):

<include>
  <context name="default">

  用你喜欢的编译器编辑好并存盘后,在 FreeSWITCH 命令行上(Console 或 fs_cli)执行 reloadxml 或按 F6键,使 FreeSWITCH 重新读入你修改过的配置文件。并按 F8 键将 log 级别设置为 DEBUG,以看到详细日志.然后,将软电话注册上,并拨叫 1234 或 echo (大部分软电话都能呼叫字母,如Zoiper,Xlite可以使用空格键切换数字和字母)。

你将会看到很多 Log, 注意如下的行:

Processing Seven <1000>->1234 in context default
parsing [default->My Echo Test] continue=false
Regex (PASS) [Echo Test] destination_number(1234) =~ /^echo|1234$/ break=on-false
Action echo()

  在我的终端上,上面的第一行是以绿色显示的。当然,为了排版方便,我省去了 Log 中的日期以及其它不关键的一些信息。

   第一行,Processing 说明是在处理 Dialplan,Seven 是我的的 SIP 名字,1000 是我的分机号, 1234 是我所拨叫的号码,这里,我直接拨叫了 1234。它完整意思是说,呼叫已经达到路由阶段,要从 XML Dialplan 中查找路由,该呼叫来自 Seven,分机号是1000,它所呼叫的被叫号码是 1234 (或 echo,如果你拨叫 echo 的话)。

   第二行,呼叫进入 parsing (解析XML) 阶段,它首先找到 XML 中的一个 Context,这里是 default(它是在 user directory 中定义的,看第五章。user directory 中有一项 , 说明,如果 1000 这个用户发起呼叫,则它的 context 就是 default,所以要从 XML Dialplan 中的 default 这个 Context 查起)。它首先找到的第一个 Extension 的 name 是 My Echo Test(还记得吧?我们我们把它放到了 Dialplan 的最前面)。continue=false 的意思我们后面再讲。

  第三行,由于该 Extension 中有一个 Condition,它的测试条件是 destination_number,也就是被叫号码,所以, FreeSWITCH 测试被叫号码(这里是 1234)是否与配置文件中的正则表达式相匹配。 ^echo|1234$ 是正则表达式,它匹配 echo 或 1234。所以这里匹配成功,Log 中显示 Regex (PASS)。 当然既然匹配成功了,它就开始执行动作 echo(它是一个 APP),所以你就听到了自己的声音。

   这是最简单的路由查找。前面我已经说了,系统自带了一些 Dialplan 的例子,也许在第二章你已经测试过了。下面,我们试一下系统自带的 echo 的例子。这次,我呼叫的是 9196。在 Log 中,还是从绿色的行开始看:

Processing Seven <1000>->9196 in context default
parsing [default->My Echo Test] continue=false
Regex (FAIL) [Echo Test] destination_number(9196) =~ /^echo|1234$/ break=on-false
parsing [default->unloop] continue=false
Regex (PASS) [unloop] ${unroll_loops}(true) =~ /^true$/ break=on-false
Regex (FAIL) [unloop] ${sip_looped_call}() =~ /^true$/ break=on-false
parsing [default->tod_example] continue=true
Date/Time Match (FAIL) [tod_example] break=on-false
parsing [default->holiday_example] continue=true
Date/Time Match (FAIL) [holiday_example] break=on-false
parsing [default->global-intercept] continue=false
Regex (FAIL) [global-intercept] destination_number(9196) =~ /^886$/ break=on-false
parsing [default->group-intercept] continue=false
Regex (FAIL) [group-intercept] destination_number(9196) =~ /^\*8$/ break=on-false
parsing [default->intercept-ext] continue=false
Regex (FAIL) [intercept-ext] destination_number(9196) =~ /^\*\*(\d+)$/ break=on-false
parsing [default->redial] continue=false
Regex (FAIL) [redial] destination_number(9196) =~ /^(redial|870)$/ break=on-false
parsing [default->global] continue=true
Regex (FAIL) [global] ${call_debug}(false) =~ /^true$/ break=never

parsing [default->fax_receive] continue=false
Regex (FAIL) [fax_receive] destination_number(9196) =~ /^9178$/ break=on-false
parsing [default->fax_transmit] continue=false
Regex (FAIL) [fax_transmit] destination_number(9196) =~ /^9179$/ break=on-false
parsing [default->ringback_180] continue=false
Regex (FAIL) [ringback_180] destination_number(9196) =~ /^9180$/ break=on-false
parsing [default->ringback_183_uk_ring] continue=false
Regex (FAIL) [ringback_183_uk_ring] destination_number(9196) =~ /^9181$/ break=on-false
parsing [default->ringback_183_music_ring] continue=false
Regex (FAIL) [ringback_183_music_ring] destination_number(9196) =~ /^9182$/ break=on-false
parsing [default->ringback_post_answer_uk_ring] continue=false
Regex (FAIL) [ringback_post_answer_uk_ring] destination_number(9196) =~ /^9183$/ break=on-false
parsing [default->ringback_post_answer_music] continue=false
Regex (FAIL) [ringback_post_answer_music] destination_number(9196) =~ /^9184$/ break=on-false
parsing [default->ClueCon] continue=false
Regex (FAIL) [ClueCon] destination_number(9196) =~ /^9191$/ break=on-false
parsing [default->show_info] continue=false
Regex (FAIL) [show_info] destination_number(9196) =~ /^9192$/ break=on-false
parsing [default->video_record] continue=false
Regex (FAIL) [video_record] destination_number(9196) =~ /^9193$/ break=on-false
parsing [default->video_playback] continue=false
Regex (FAIL) [video_playback] destination_number(9196) =~ /^9194$/ break=on-false
parsing [default->delay_echo] continue=false
Regex (FAIL) [delay_echo] destination_number(9196) =~ /^9195$/ break=on-false
parsing [default->echo] continue=false
Regex (PASS) [echo] destination_number(9196) =~ /^9196$/ break=on-false
Action answer()
Action echo()

相关阅读:

分享到: 收藏

专题