FreeSWITCH 使用指北(2)-多段音频顺序播放的设置

1. 多段音频顺序播放的设置

在 FreeSWITCH 中涉及到放音的 APP 有不少,比较典型的是播放录音文件的 playbackplay_and_detect_speech 。这两个 APP 播放录音的功能都依赖于 switch_ivr_play_say.c#switch_ivr_play_file() 函数,而该函数可以借助 file_string 实现多段音频播放,示例如下:

originate user/1000 &playback(file_string://ivr/8000/ivr-welcome1.wav!ivr/8000/welcome2.wav)

file_string:// 前缀不能省略,这个代表的是 FreeSWITCH 中的一个文件管理模块,多个音频文件用 ! 拼起来即可。注意如果文件名中含有 ! 符号,也可以使用通道变量 playback_delimiter 来修改文件间的分隔符号

2. uuid_bridge 时机问题

在 FreeSWITCH 外呼系统中,常驻坐席拨打用户时接通双方的 uuid_bridge 命令执行时机很关键。通常如果坐席不需要听用户的早媒体,那么在收到 CHANNEL_ANSWER 事件时执行 uuid_bridge 最稳妥,几乎不会产生什么问题。 但是当坐席需要听早媒体的时候,就需要在 SIP 交互更早期 bridge 坐席和用户,比较合适的事件是 CHANNEL_PROGRESS_MEDIA

CHANNEL_PROGRESS_MEDIA 的产生时机是 FreeSWITCH 收到被叫 180/183 响应并且响应中带了 sdp 时,一般这时候已经开始拉起 RTP 传输早媒体了,但是使用这个事件也有以下几个问题:

  1. 线路商直到 200 响应才带 sdp
    生产环境发现线路商返回的 SIP 响应中偶现 180 不带 sdp,183 直接不发,直到 200 才把 sdp 带过来,这就直接导致 FreeSWITCH 根本不会发出 CHANNEL_PROGRESS_MEDIA 事件,进而导致 uuid_bridge 未执行,坐席和用户互相听不到对方的声音。对于这种情况,一个解决方案是在收到 CHANNEL_ANSWER 事件时根据相关通道变量判断当前坐席和用户是否已经 bridge 上,如果没有对接上,则兜底执行 uuid_bridge 即可
  2. 用户拒接导致坐席挂断
    在收到 CHANNEL_PROGRESS_MEDIA 事件执行 uuid_bridge 后,如果被叫拒接 FreeSWITCH 会偶现 DESTINATION_OUT_OF_ORDER 挂断异常,并导致常驻坐席也被挂断。这个问题多方查找资料未找到原因,大致猜测是 FreeSWITCH 执行 uuid_bridge 命令时会修改坐席会话状态,被叫拒接动作也会修改主叫坐席的会话状态,二者同时发生时可能有多线程操作造成坐席会话状态机流转异常,进而造成坐席会话提前挂断。这个暂时没有什么好的解决方案,一个 workaround 是在收到 CHANNEL_PROGRESS_MEDIA 事件后延时执行 uuid_bridge,可以降低问题发生的频率
  3. 参数顺序问题
    uuid_bridge <originator_uuid> <originatee_uuid> 命令的第一个参数作为主叫 leg,第二个参数作为被叫 leg,参数顺序会影响到 FreeSWITCH 的一些特性。如果将常驻坐席作为主叫 leg,那么很大概率在这条腿上的 park_after_bridge 参数不会生效,被叫 leg 挂断后坐席这条腿也会被 FreeSWITCH 发送 BYE 信令挂断

3. INVITE 外呼请求中 FROM 头域的设置

FreeSWITCH 通过 gateway 来对接外部网关,如果想呼叫用户必须使用线路商提供的主叫号码和网关地址生成相应的 gateway,而线路商通常采用 INVITE 请求 FROM 头中携带的账号做鉴权,并据此执行相关的呼叫策略。在这种情况下,如果一条线路有多个主叫号码,推荐的 gateway 配置模版如下:

  1. gateway 标签的 name 属性为网关的名称,在呼叫字符串中必须匹配使用
  2. username 属性如不做相关配置,默认会填充到 INVITE 请求 FROM 头相关字段
  3. proxy 配置外部网关的真实端口 IP
  4. caller-id-in-from 指定使用主叫 id 填充到外呼的 INVITE 请求 FROM 头相关字段,会覆盖 username 属性
<gateway name="nathan">
   <param name="username" value="cluecon"/>
   <param name="password" value="cluecon"/>
   <param name="proxy" value="192.168.0.1:5060"/>
   <param name="register" value="false"/>
   <param name="context" value="public"/> 
  <param name="caller-id-in-from" value="true"/> 
</gateway>

这样配置 gateway 后,执行以下呼叫命令即可通过名称为 nathan 的 gateway 使用主叫号码 1008611 呼叫用户号码 10151786791

originate {
    
    origination_caller_id_number=1008611,origination_uuid=call-2219554683886258238,origination_caller_id_name=1008611}sofia/gateway/nathan/10151786791 9000 XML default

4. 网关设置导致 RTP 无法送达问题

外呼系统放量切换过程中,有个别坐席会发生一定时间内不呼叫用户,再次呼叫后就听不到用户声音的问题。排除设备和软电话的问题后,远程指导坐席本地安装 wireshark 抓包,发现一段时间后服务器发过去的 RTP 包就无法送达坐席本地了。初步判断是坐席所在网络的网关设置有问题,可能在一定时限内没有收到 udp 数据包往后就会拒掉这个方向上的网络数据,基于此推断通知坐席切换手机热点测试,问题果然不再复现。由于坐席所在分公司办公网由第三方部署,无法远程干预,最终只能由外呼系统兼容:

这种一定时限后 RTP 就无法送达的问题通常是目标网关的心跳之类的机制在起作用,要应对这种情况,比较简单的处理方式就是由系统执行 RTP 保活。具体做法就是在坐席空闲时不断给他的软电话发送 RTP 包,在 FreeSWICTH 中可以使用 silence_stream 发送静音流以保持 udp 通信活跃, 一个示例是 playback(silence_stream://-1,1400)

猜你喜欢

转载自blog.csdn.net/weixin_45505313/article/details/134017541