1、正则表达式
freeswitch> regex 1234 | \d true freeswitch> regex 1234 | \d{4} true freeswitch> regex 1234 | \d{5} false freeswitch> regex 1234 | ^123 true 2、通道变量 在FreeSwitch中,每一次呼叫都由一条或多条“腿(Call Leg)组成,其中的一条腿又成为一个Channel(通道),每一个Channel都由很有属性,用于标识Channel的状态、性能等,这些属性称为Channel Variable(通道变量),可简写为Channel Var、Chan Var或Var。 log的作用就是将信息写到日志中,他的第一个参数是loglevel,就是log的级别,不同的级别在彩色的终端上能以不同的颜色显示,日志的级别有以下几种(数越大显示越详细): 0 - CONSOLE 1 - ALERT 2 - CRIT 3 - ERR 4 - WARNING 5 - NOTICE 6 - INFO 7 - DEBUG 3、测试条件 大部分的测试条件都是针对被叫号码的,但你也可以对其他变量进行测试,如在 Dialplan的default.xml中IP地址就可以这样测试: <condition field="network_addr" expression="^192\.168\.200\.158$"> Dialplan中的测试条件
除此之外,测试还接受用户在用户目录中设置的变量,但必须使用${}对变量进行引用。如下面toll_allow就是在用户目录中设置的: <condition field="${toll_allow}" expressio="internation"> 如果在你的用户目录中设置以下变量,可以在Dialplan中通过condition一行进行相关测试。 用户目录中的设置: <user id="1000"> <variables> <variable name="my_test_var" value="my_test_value"/> </variables> </user> Dialplan中的测试条件: <condition field="${my_test_var}" expressio="my_test_value$"> 测试条件不可以嵌套,但可以迭加。如下: <extension name="Testing"> <condition field="network_addr" expression="^192\.168\.200\.158$"/> <condition field="destination_number" expression="^1234$"> <action application="log" data="INFO , I know you called ${destination_number}"/> </condition> </extension> 两个condition是迭加关系,即只有在IP地址和被叫号码两个条件都匹配的情况下才执行 action,否则就跳过本extension ,继续解析下一项。 迭加的condition还可以构成其他关系,break参数就是用于实现这个功能,它有以下几个值: on-false:第一次匹配失败时停止,但继续处理其他extension ,这个是默认的配置。 on-true:第一次匹配成功时停止,会先完成对应的action,再继续处理其他extension。 always:不管是否匹配,都停止。 never:不管是否匹配,都继续。 假设呼叫1234,如果ip地址是192.168.200.158,就播放早上好,如果ip是192.168.200.159,就播放晚上好,设置如下: <extension name="Testing"> <condition field="destination_number" expression="^1234$"/> <condition field="network_addr" expression="^192\.168\.200\.158$" break="on-true"> <action application="playback" data="good-morning.wav"/> </condition> <condition field="network_addr" expression="^192\.168\.200\.159$"> <action application="playback" data="good-night.wav"/> </condition> </extension> 4、动作与反动作 <extension name="Testing"> <condition field="destination_number" expression="^1234$"/> <condition field="network_addr" expression="^192\.168\.200\.158$" break="on-true"> <action application="playback" data="good-morning.wav"/> <anti-action application="playback" data="good-night.wav"/> </condition> </extension> 如果呼叫ip地址来自192.168.200.158则播放good-morning.wav,否则播放good-night.wav。 5、实例解析 1、Local_Extension Freeswitch默认的配置提供了1000-1019共20个SIP账号,密码都是1234。Freeswtch通过Dialplan可以将来话路由到这些本地的号码。Config/dialplan/default.xml中的Local_Extension部分如下: <extension name="Local_Extension"> <condition field="destination_number" expression="^(10[01][0-9])$"> <! - - 此处省略many actions - -> </condition> </extension> 在SIP客户端上用1000呼叫1001时,FS会建立一个Channel,该Channel构成一次呼叫的a-leg。初始化完毕后,Channel进入ROUTING状态,即到达Dialplan。由于被叫号码1001与这里的正则表达式匹配,所以会执行下面的action。由于在正则表达式中使用个“()”,因此匹配结果会放入$1中,因此在这里$1=1001。 下面分析省略的actions里面的内容: <action application="set" data="dialed_extension=$1"/> <action application="export" data="dialed_extension=$1"/> set和export都是设置一个变量,名字为dialed_extension,值是1001。而set是讲变量设置到当前的Channel上,即a-leg。export除具备set的功能外,将变量设置到b-leg上。当然,这时b-leg还不存在。 接着往下看: <!-- bind_meta_app can have these args <key> [a|b|ab] [a|b|o|s] <app> -->
<action application="bind_meta_app" data="1 b s execute_extension::dx XML features"/>
<action application="bind_meta_app" data="2 b s record_session::$${recordings_dir}/${ caller_id_number}.${strftime(%Y-%m-%d-%H-%M-%S)}.wav"/>
<action application="bind_meta_app" data="3 b s execute_extension::cf XML features"/>
<action application="bind_meta_app" data="4 b s execute_extension::att_xfer XML features"/> bind_meta_app的作用是在该Channel上绑定DTMF。上面四行分别绑定了1、2、3、4四个按键,它们都绑在b-leg上。注意,这时b-leg还不存在。 往下看: <action application="set" data="ringback=${us-ring}"/> 此处,设置回铃音是美音,${us-ring}的值是在vars.xml中设置的。接下来: <action application="set" data="transfer_ringback=$${hold_music}"/> 如果发生呼叫转移,用户听到的回铃音。 <action application="set" data="call_timeout=30"/> call_timeout是设置呼叫超时的变量。 继续看: <action application="set" data="hangup_after_bridge=true"/> <!--<action application="set" data="continue_on_fail=NORMAL_TEMPORARY_FAILURE,USER_BUSY,NO_ANSWER,TIMEOUT,NO_ROUTE_DESTINATION"/> --> <action application="set" data="continue_on_fail=true"/> <action application="hash" data="insert/${domain_name}-call_return/${dialed_extension}/${caller_id_number}"/> <action application="hash" data="insert/${domain_name}-last_dial_ext/${dialed_extension}/${uuid}"/> <action application="hash" data="insert/${domain_name}-last_dial_ext/${called_party_callgroup}/${uuid}"/> <action application="hash" data="insert/${domain_name}-last_dial_ext/global/${uuid}"/> hash是内存中的哈希表数据结构。他可以设置一个键-值对。例如最后一行${domain_name}-last_dial_ext这个哈希表中插入一个global键,它的值是${uuid},即本Channel的唯一标志。 不管是set,还是hash,都是保存数据为后面做准备。不同的是set将变量绑定到Channel上,以通道变量的形式存在,而hash保存到内存的哈希表数据结构中。 往下看,是设置通道变量: <action application="set" data="called_party_callgroup=${user_data(${dialed_extension}@${domain_name} var callgroup)}"/> <!--<action application="export" data="nolocal:rtp_secure_media=${user_data(${dialed_extension}@${domain_name} var rtp_secure_media)}"/>--> 最后一行默认是注释掉的,nolocal的作用是告诉export只将该变量设置到b-leg上,而不要设置到a-leg上。 下面还是往哈希表中插入数据: <action application="hash" data="insert/${domain_name}-last_dial/${called_party_callgroup}/${uuid}"/> 再往下看: <action application="bridge" data="user/${dialed_extension}@${domain_name}"/> bridge是最关键的部分。bridge相当于一座桥,它的作用是把两条腿1000和1001给桥接起来。为了能连接到1001,Freeswitch作为SIP UAC,向1001这个SIP UA发起INVITE请求,并建立一个新的Channel,就是我们的b-leg。1001开始振铃,bridge把回铃音传回1000,因此1000就能听见回铃音。 当然,在呼叫之前首先要查找1001这个用户是否已经注册,否则会直接返回USER_NOT_REGISTERED,就不会建立b-leg。 domain和domain_name都是预设的变量,默认的是服务器的IP地址。user是一个特殊的 Endpoint,它指的是本地用户。这里呼叫字符串翻译出来就是 {sip_invite_domain=192.168.200.158}user/1001@192.168.200.158 其中,{}里是设置通道变量,这些变量只会建立在b-leg上。 以上电话路由基本上就完成了,我们已经建立了1000到1001之间的呼叫,1001已经开始振铃,接下来会有以下几种情况: 1.被叫应答 2.被叫忙 3.被叫无应答 4.被叫拒绝 5.其他情况 第一种情况:1000与1001畅聊,这个时候bridge一直是阻塞的,也就是说,bridge会一直等待b-leg(1001)挂机后才返回,这时才有可能继续执行下面的action。无论哪一方挂机,bridge就算结束了。 如果1000(主叫)先挂机,Freeswitch会将挂机原因(一般是NORMAL_RELEASE)发送给1001,同时释放b-leg,由于a-leg已经没有了,Dialplan就没有往下执行的必要了,因此会产生计费信息,并销毁a-leg。 如果1001先挂机,b-leg就没有了,但b-leg会将挂机原因传到a-leg。在a-leg决定是否继续往下执行之前,会检查一些变量,以决定该怎么做。hangup_after_bridge=true的意思是,如果bridge正常完成后,就挂机,到这里a-leg就释放了。 如果1001没接电话,如1001拒接(返回CALL_REJECTED,有些会返回USER_BUSY,隐藏真实原因)、忙(USER_BUSY)、无应答(NO_ANSWER或NO_USER_RESPONSE)等。出现这些情况Freeswitch会认为是不成功的bridge,就不管hangup_after_bridge的变量了。这时候会检查另一个变量continue_on_fail。设置的continue_on_fail=true,在bridge失败后会继续执行下面的action。 通过给continue_on_fail不同的值,可以决定在什么情况下继续,比如下面的设置将只在用户忙和无应答的情况下才会继续呼叫流程: <action application="set" data="continue_on_fail=USER_BUSY,NO_ANSWER”/> 其他可能的值有:NORMAL_TEMPORARY_FAILURE(临时故障),TIMEOUT(超时),NO_ROUTE_DESTINATION(呼叫不可达)。 接着往下看: <action application="answer"/> Dialplan执行到这里,Freeswitch会给主叫1000回送应答消息,以建立真正的媒体流,准备对其播放声音。接下来: <action application="sleep" data="1000"/> <action application="bridge" data="loopback/app=voicemail:default ${domain_name} ${dialed_extension}"/> sleep表示暂停,1000表示暂停的毫秒数(1s),然后转到1001的语音信箱。注意,Freeswitch默认配置文件中是通过transfer加loopback Endpoint的方式转到voicemail的。 2、回声和延迟回声 关于回声,如果拨打9196,就能听见自己的回声。Dialplan如下: <extension name="echo"> <condition field="destination_number" expression="^9196$"> <action application="answer"/> <action application="echo"/></condition>
</extension> 延迟回声如下: <extension name="delay_echo"> <condition field="destination_number" expression="^9195$"> <action application="answer"/> <action application="delay_echo" data="5000"/> </condition>
</extension> 注意:版本不同expression的值有可能不同。 3、会议 下面是将来话转入会议电话,其中nb_conferences就是默认的8000Hz的窄带电话会议。 <extension name="nb_conferences"> <condition field="destination_number" expression="^(30\d{2})$"> <action application="answer"/> <action application="conference" data="$1-${domain_name}@default"/> </condition>
</extension> 正则表达式^(30)$ 匹配以30开头的4位数字的被叫号码。所有呼叫30xx的电话均可进入一个会议,大家可以畅所欲言。 4、将通话的双方转入会议 回头看一下上节的一条代码: <action application="bind_meta_app" data="3 b s execute_extension::cf XML features"/> bind_meta_app是一个APP,它有一系列参数,其中,3表示绑定DTMF按键3;b表示要绑到b-leg上;s表示same。如果在b-leg上按下*3(必须先按*),则执行execute_extension这个APP。execute_extension是临时去别的地方执行一些Dialplan指定的APP,在这里它的参数是cf XML features,表示要去XML Dialplan的features这个Context中找一个匹配cf的extension。 在conf/dialplan/features.xml中很容易找到匹配cf的这个extension: <!-- Used to transfer both legs into a conference --> <extension name="cf"> <condition field="destination_number" expression="^cf$"> <action application="answer"/> <action application="transfer" data="-both 30${dialed_extension:2} XML default"/> </condition> </extension> answer在这个APP里没有什么用,因为呼叫已经应答了。transfer是一个APP,它会将当前通话重新转移到ROUTING阶段,重新去Dialplan中进行路由。它的第一个参数是-both,表示将它自己和a-leg都转移到Dialplan中重新路由。路由的Dialplan类型仍然是XML,Context是Default,被叫号码30${dialed_extension:2}中的dialed_extension来自: <action application="export" data="dialed_extension=$1"/> 注意,上面是用export把变量设置到b-leg上的,实际上就是最初的被叫号码1001,${dialed_extension:2}是从1001的第二个位置开始截取,一直截取到字符串结尾的字符串,由于位置是从0开始计数的,因而1001:2最终结果就是01因而最终transfer的一行就等价于: <action application="transfer" data="-both 3001 XML default"/> 其中,-both表示将两条腿都分别转到3001这个extension上。所以,重新路由后就到了会议的情况。最终1000和1001都进入名为3001的会议上。 6、常用的Dialplan App (1)set 用于设置一个通道变量,如: <action application="set" data="my_var=123456"/> (2)echo 回声,在调试时比较有用,如: <action application="echo"/> (3)info info在调试时也比较有用,它会在日志中打印全部的通道变量,如: <action application="info"/> (4)answer 用于应答一路呼叫 <action application="answer"/> (5)bridge 负责桥接另一条腿,它的参数是一个呼叫字符串: <action application="bridge" data="user/1000"> bridge操作是阻塞,它会一直等到b-leg释放后才继续往下走。 (6)playback 用于给Channel放音,如果需要对主叫放音,如: <action application="playback" data="/tmp/test.wav"/> 它的参数是声音文件的路径,如果需要播放多个文件,可以串联操作,如: <action application="playback" data="/tmp/test1.wav"/> <action application="playback" data="/tmp/test2.wav"/> <action application="playback" data="/tmp/test3.wav"/> 另外,通过mod_shout模块,也可以支持本地货远程HTTP或Shout Cast服务器上的.mp3格式的文件,如: <action application="playback" data="/tmp/test.mp3"/> <action application="playback" data="http://localhost/test.mp3"/> <action application="playback" data="shout://localhost/test.mp3"/> 在播放过程中,用户可以按*键停止播放,或者在播放前通过Chan Var选择其他按键完成此功能: <action application="set" data="playback_terminators=1"/> 也可以使用如下方法取消按键中断的方式: <action application="set" data="playback_terminators=none"/> (7)sleep sleep用于设置可以等待/暂停的一段时间,单位默认为毫秒: <action application="sleep" data="1000"/> (8)ring_ready ring_ready用于在SIP中给对方回180消息,即通知对方可以振铃了: <action application="ring_ready" data="1000"/> (9)pre_answer pre_answer用于在SIP中给对方回183消息,后续的playback之类的动作将作为早期媒体给对方发过去,如彩铃音: <action application="ring_ready" data="1000"/> <action application="playback" data="/tmp/music.wav"/> 注意:虽然Freeswitch可以把媒体发给对方,但如果在一定时间内没有应答,对端通常也会挂断该通话。
|
|
来自: 草莓加冰 > 《Freeswitch》