IVR
最初熟悉可能是移动,电信,联通三大运营商的手机电话,拨打10086等号码,客服端会提示你:按键1,查询本机花费,按键2,人工客服,按键0,重听一遍,请用#号键确认。
很简单,这就是一个IVR的典型应用。
最近几年,实时语音识别的普及,IVR中又加入了音频识别,用户不再需要通过按键的形式,直接通过发音表达的方式就可以实现原来按键的功能。
1、流程
学习任何一个框架,必须知道软件框架的底层逻辑是什么样的,代码执行流程是什么样的。熟悉了核心执行流程,系统整个优势,功能,包括按需开发真的是一目了然。要不然,在程序出现BUG,或者有新的需求的时候,就会感觉到无从下手。
我们以 5000 拨号,为例:
查找路由表:vi /user/local/freeswitch/conf/dialplan/default.xml
我们看到 action 在响应answer
后,sleep了2秒钟,然后执行了ivr的app,传参为demo_ivr 菜单
所有ivr的相关demo文件,都在/user/local/freeswitch/conf/ivr_menus
目录下
我们打开demo_ivr.xml
, 找到name
为demo_ivr
的menu
,如下:
<menu name="demo_ivr"
greet-long="phrase:demo_ivr_main_menu"
greet-short="phrase:demo_ivr_main_menu_short"
invalid-sound="ivr/ivr-that_was_an_invalid_entry.wav"
exit-sound="voicemail/vm-goodbye.wav"
confirm-macro=""
confirm-key=""
tts-engine="flite"
tts-voice="rms"
confirm-attempts="3"
timeout="10000"
inter-digit-timeout="2000"
max-failures="3"
max-timeouts="3"
digit-len="4">
<!-- The following are the definitions for the digits the user dials -->
<!-- Digit 1 transfer caller to the public FreeSWITCH conference -->
<entry action="menu-exec-app" digits="1" param="bridge sofia/$${domain}/888@conference.freeswitch.org"/>
<entry action="menu-exec-app" digits="2" param="transfer 9196 XML default"/> <!-- FS echo -->
<entry action="menu-exec-app" digits="3" param="transfer 9664 XML default"/> <!-- MOH -->
<entry action="menu-exec-app" digits="4" param="transfer 9191 XML default"/> <!-- ClueCon -->
<entry action="menu-exec-app" digits="5" param="transfer 1234*256 enum"/> <!-- Screaming monkeys -->
<entry action="menu-sub" digits="6" param="demo_ivr_submenu"/> <!-- demo sub menu -->
<!-- Using a regex in the digits tag lets you define a dial pattern for the caller
You may define multiple regexes if you need a different pattern for some reason -->
<entry action="menu-exec-app" digits="/^(10[01][0-9])$/" param="transfer $1 XML features"/>
<entry action="menu-top" digits="9"/> <!-- Repeat this menu -->
</menu>
其实从上述代码就可以看到,实现ivr的拨号功能的模块就是menu
的子模块entry
。参数digits代表拨号按键,action
表示执行app
, param
是参数。这儿有点像
<action application="bridge" data="user/1005" />
接下来,详细解析下menu
节点参数和entry
节点参数:
1.1 Menu-name
这儿name
是拨号路由表dialplan
中,ivr app 引用菜单传递的data参数值。它与文件名字无关,只和文件内的标签有关。
1.2 Menu-greet-long
传递给呼叫者的第一条信息内容,一般语音提醒用户:公司名称
(您好,我们是xxx公司xxxx,)+
操作步骤
(按键1,xxx, 按键2, xxx)等。
我们看到该字段内容分两部分:phrase:demo_ivr_main_menu
这是一个短语宏,格式是:phrase:macroname[:one or more arguments]
,冒号前面是phrase,代表短语宏;冒号后面macroname是短语宏名称,再如果还有冒号,后面所有内容就表示宏参数。
短语宏,是一种Freeswitch
配置的XML结构
,将一些简单的声音文件进行组合,配置成复杂的提示音。比如:库中只有简单的‘我’ ,‘和‘, ’你‘的三段音频文件,那么就可以通过配置每个字的音速,将三段音频合成一个完成的’我和你‘的音频。
短语宏配置文件:/usr/local/freeswitch/conf/lang
下 ,该文件夹放置支持的不同的语言
当然,freeswitch在初次加载的时候就已经加载进来了,
vi /user/local/freeswitch/conf/freeswitch.xml
每个目录下,都打开*.xml
和demo/*.xml
文件,看看
我们找到demo_ivr_main_menu
短语宏macro
名称name
在 en/demo/demo-ivr.xml
文件中
<macro name="demo_ivr_main_menu" pause="100"> <!-- See conf/autoload_config/ivr.conf.xml for an example on how to use this macro in an IVR -->
<input pattern="(.*)">
<match>
<!-- string together several existing sound files to create one long greeting -->
<action function="play-file" data="ivr/ivr-welcome_to_freeswitch.wav"/>
<action function="play-file" data="ivr/ivr-this_ivr_will_let_you_test_features.wav"/>
<action function="play-file" data="ivr/ivr-you_may_exit_by_hanging_up.wav"/>
<!-- note that you can do more than just play files, e.g. have pauses and do TTS -->
<!-- Menu option 1: Call FreeSWITCH conference-->
<action function="play-file" data="ivr/ivr-enter_ext_pound.wav"/>
<action function="play-file" data="silence_stream://1500"/>
<action function="play-file" data="ivr/ivr-to_call_the_freeswitch_conference.wav"/>
<action function="play-file" data="ivr/ivr-please.wav"/>
<action function="play-file" data="voicemail/vm-press.wav"/>
<action function="play-file" data="digits/1.wav"/>
<!-- Menu option 2: Do FreeSWITCH echo test -->
<action function="play-file" data="ivr/ivr-to_do_a_freeswitch_echo_test.wav"/>
<action function="play-file" data="ivr/ivr-please.wav"/>
<action function="play-file" data="voicemail/vm-press.wav"/>
<action function="play-file" data="digits/2.wav"/>
<!-- Menu option 3: Listen to Music on Hold -->
<action function="play-file" data="ivr/ivr-to_listen_to_moh.wav"/>
<action function="play-file" data="ivr/ivr-please.wav"/>
<action function="play-file" data="voicemail/vm-press.wav"/>
<action function="play-file" data="digits/3.wav"/>
<!-- Menu option 4: Register for ClueCon -->
<action function="play-file" data="ivr/ivr-register_for_cluecon.wav"/>
<action function="play-file" data="digits/4.wav"/>
<!-- Menu option 5: Listen to screaming monkeys -->
<action function="play-file" data="ivr/ivr-to_hear_screaming_monkeys.wav"/>
<action function="play-file" data="ivr/ivr-please.wav"/>
<action function="play-file" data="voicemail/vm-press.wav"/>
<action function="play-file" data="digits/5.wav"/>
<!-- Menu option 6: Hear a sample submenu -->
<action function="play-file" data="ivr/ivr-to_hear_sample_submenu.wav"/>
<action function="play-file" data="ivr/ivr-please.wav"/>
<action function="play-file" data="voicemail/vm-press.wav"/>
<action function="play-file" data="digits/6.wav"/>
<!-- Menu option 9: Repeat these options -->
<action function="play-file" data="ivr/ivr-to_repeat_these_options.wav"/>
<action function="play-file" data="ivr/ivr-please.wav"/>
<action function="play-file" data="voicemail/vm-press.wav"/>
<action function="play-file" data="digits/9.wav"/>
<action function="play-file" data="silence_stream://2000"/>
</match>
</input>
</macro>
参数介绍:
1.2.1 macro
短语宏标签
1.2.2 macro-name
短语宏名称,用于拨号方案中调用短语宏时的引用的内容。
1.2.3 macro-pause
(可选)指定每个播放文件播放完后,休眠的时间。单位时毫秒,此处100表示100毫秒。
1.2.4 input-pattern
此处是正则匹配参数。也就是上面提到的宏参数
。如果匹配到,执行子节点<match>,
反之执行<nomatch>
。
大多数,不会向短语传递任何参数,灵活应用。
1.2.5 action
这个比较熟悉,路由表中基本都有,这就是执行短语宏要执行的动作的标签,通常是"play- file"
或"sleep"
(play-file
表示播放文件,sleep
表示停止多长时间执行下一个play-file
, 另一个有用的action叫"say
",它以特定的语言(英语、汉语等)规则,正确播报数字、日期、数量、货币、序号、拼写等信息。)参数data
是音频路径,这儿可以是绝对路径,也可以是相对路径。
相对路径是相对于 ${sound_prefix}
的路径,定义在/user/local/freeswitch/conf/vars.xml
中,可以使用命令:eval $${sound_prefix}
查询。
其实,
<action functinotallow="play-file" data="ivr/ivr-welcome_to_freeswitch.wav"/>
和
<action function="play-file" data="$${sound_prefix}ivr/ivr-welcome_to_freeswitch.wav"/>
和
<action function="play-file" data="/usr/local/freeswitch/sounds/en/us/callie/ivr/ivr-welcome_to_freeswitch.wav"/>
表达的意思是一致的。
注:
如果你的呼叫使用PCMU编码(比如说G711),因为这种编码的采样率是8khz,所以,相对路径"ivr/ivr-welcome_to_freeswitch.wav"
将会被解析为” /usr/local/freeswitch/sounds/en/us/callie/ivr/8000/ivr-welcome_to_freeswitch.wav”
,IVR将读取并播放这个文件。如果这个文件不存在,FreeSWITCH将首先使用48khz采样率的同名文件(/usr/local/freeswitch/sounds/en/us/callie/ivr/48000/ivr- welcome_to_freeswitch.wav
),因为FreeSWITCH音频混音的格式是48khz的。如果还找不到,再尝试32khz,再然后是16khz。如果还是没找到,FreeSWITCH会查找/usr/local/freeswitch/sounds/en/us/callie/ivr/ivr- welcome_to_freeswitch.wav
文件(在路径中不插入采样率),并通过自动检测采样率播放文件。如果所有地方都找不到,FreeSWITCH将输出一条错误日志并继续播放下一个音频文件。
1.3 menu-greet-short
定义返回主菜单的短语宏。
1.4 menu-invalid-sound
当呼叫者输入的DTMF
与菜单“条目”不符时读取的内容。
注:DTMF
暂时理解为 按键值。比如:按键1,DTMF值为1
1.5 menu-exit-sound
退出菜单,用户挂机前播报的内容(因为输入错误超限,超时等原因退出菜单)
1.6 menu-confirm-macro
1.7 menu-confirm-key
用户结束序列输入时的按键。默认值是#。
1.8 menu-tts-engine
FreeSWITCH配置文件中注册的TTS引擎名称,通常测试用"flite",生产环境用"cepstral"。
1.9 menu-tts-voice
这是传递给TTS引擎的"voice"参数值。TTS引擎能够提供不同的声音转换,比如说男声,女声或方言。令人好奇的是,flite TTS引擎提供的"rms"声音是从GNU项目创始人Richard Marshall Stallman的声音采样出来的。
1.10 menu-confirm-attempts
1.11 menu-timeout
在greet-long
或greet-short
播报之后,等待用为输入DTMF
的时间,单位是毫秒
。如果超时触发,会重复播报欢迎辞greet-short
,最多尝试max-timeout
指定的次数。
1.12 menu-max-failures
菜单转到exit-sound
并挂机之前,超时重试的次数限定,每次超时,如果没有超限,将播报invalid-sound
,并重新播报欢迎辞。
1.13 menu-max-timeouts
参考 menu-timeout
1.14 menu-digit-len
单词允许输入的最大位数。
例如,你可能希望把它设置为4,这样对应演示配置实例中,"Local_Extension"对应的分机号长度,这样可以接受1001到1019这些号码的输入。允许用户通过“确认键”(通常是#)或者等待超时(“inter-digit-timeout”)输入较短的号码序列(不满四位的号码)。
1.15 entry-action
1.15.1 menu-exec-app
这是IVR菜单的主力。它允许执行一个FreeSWITCH拨号方案的APP,还可以向APP传递参数。
1.15.1 menu-play-sound
播放一个声音文件(以绝对路径或相对路径定位);或者播放一个"phrase:"结构;或者一个TTS的"say:"结构。
1.15.1 menu-sub
执行(跳转到)另一个XML语音菜单,通过菜单名标识。
1.15.1 menu-back
从一个子菜单跳转回上一层XML语音菜单。
1.15.1 menu-top
从子菜单直接跳转回顶层入口的主菜单。
1.15.1 menu-exit
你可能不相信,但事实在它就是存在,望文生义,它退出菜单!
1.16 entry-digits
用户发过来触发菜单执行action的完整DTMF序列
1.16 entry-param
传递给action的参数描述
这些参数一目了然,bridge 桥接B-leg,transfer 转到 default context 的路由表中,并执行路由表。
2、测试
通过上面的流程,其实很简单,但是我们了解了IVR的运行机制,从最初的路由表,到最终核心逻辑执行menu--exec-app
的action
。也能够随意copy demo
,去实现自己的需求。
我们可以用测试电话 eyeBeam
,拨打5000
就进入了IVR
逻辑,会听到一段欢迎词,并且提示输入按键,我们输入2,即执行回音路由流程,电话端就听到了自己的回音。
3、扩展
3.1 嵌套菜单
方案一:通过menu-sub
这个 action
,跳转到 其他菜单。
方案二:通过menu-exec-app
执行参数transfer
的方式,通过路由表,再转到 其他菜单。