您当前的位置是:  首页 > 资讯 > 文章精选 >
 首页 > 资讯 > 文章精选 >

使用FreeSWITCH检测声音文件中的DTMF信息

2019-10-12 09:59:47   作者:杜金房   来源:CTI论坛   评论:0  点击:


  今天,有网友问到一个问题——使用什么工具检测录音文件中的DTMF信息。其实FreeSWITCH本身就具备检测DTMF的功能,简单配置一下,写几个脚本就可以了。
  先简单说一下DTMF,DTMF是Double Tone Multiple Frequency的缩写,即双音多频。在电话通话中,通过两个不同的频率的组合来传递按键信息,如题图中所显示的,1209和697两种频率的组合就代表1,其它依此类推。
  在模拟电话以及传统的PSTN中,DTMF与声音数据是混在一起的,因为它们根本没法分开。在VoIP中常常使用DTMF2833或SIP INFO来传输DTMF,但那不是我们今天要讲的内容。
  由于DTMF与声音都混在话路中,在录音时就也一块将DTMF信息录在了录音文件中,如果想从录音文件中提取这些DTMF信息,就需要对声音文件进行分析,也就是今天我们要解决的问题。
  我们有了FreeSWITCH,当然不需要去找别的工具,下面我们就来看一看怎么做。
  为了做一次完整的实验,我们先得有个录音文件。首先把SIP电话设成使用inband方式发送DTMF,以便能够录到DTMF信息,具体的设置方式因不同的话机(或软电话)而已,我们就不多说了。然后,使用如下方法我们可以得到一个录音文件:
  freeswitch> originate user/1008 &record(/tmp/dtmf.wav)
  上面使用originate命令呼叫1008,被叫接听后,开始录音。记得接听后要按几个键啊。在本次实验中,我按了1234,并挂机。
  挂机后找个工具播放一下dtmf.wav,便能听到嘀嘀的按键音,虽然每个按键的声音不一样,但我们的耳朵认不出来,还得借助软件。
  我们昨天刚讲了Lua,今天正好进一步再来一个例子,因而我们写了一个Lua脚本来检测DTMF,命名为dtmf.lua,内容如下:
  function onInputCBF(s, type, obj, arg)
  if (type == "dtmf") then
  freeswitch.consoleLog("INFO", "Got DTMF: "  obj.digit  " Duration: "  obj.duration  "\n")
  end
  return ''
  end
  session:answer()
  session:execute("start_dtmf", "")
  session:setInputCallback('onInputCBF', '')
  session:streamFile("local_stream://moh」)
  其中,我们设了一个回调函数 onInputCBF,当检测到DTMF时便进行回调,在日志中打印相关的DTMF信息。
  session:answer() 对Channel进行应答 session:execute()执行一个App,这里我们执行了start_dtmf以启动对inband类型的DTMF的检测 session:setInputCallbck()安装一个回调函数,在检测到DTMF时便执行该回调函数,就是我们上面写的那个onInputCBF session:streamFile() 一行只是播放一个无限长的声音文件,防止挂机
  通过该Lua脚本,当有电话呼入时,我们将来电路由到该脚本,便可以实时检测来电中的DTMF了。但是在这里我们有一个问题,那就是我们要检测的是录音文件里面的,它不是一路电话,即不是一个Channel。
  当然,这也难不住我们,既然我们有FreeSWITCH,那我们可以弄两个FreeSWITCH实例,从一个中呼叫另一个,在其中一个执行playback以播放声音文件,另一个执行上面的Lua脚本检测,问题不就解决了?
  是的,但我们还有更简单的解决办法。
  在FreeSWITCH中,不管是播放声音文件还是检测DTMF都需要一个Channel,在没有实际Channel的情况下,我们就可以生成一个假的Channel。对于这一点,FreeSWITCH早就帮我们想到了,那就是loopback Interface。它其实也是一个Endpoint,通过下面的命令生成一个Channel,并执行我们的Lua脚本:
  freeswitch> originate loopback/dtmf &lua(dtmf.lua)
  其中,loopback/ 后面的dtmf是被叫号码,当一个Channel产生后,该Channel的一端(一头)会进入Dialplan查找路由,另一头则执行 lua App,即执行我们的Lua脚本。关于loopback我们就不多解释了,我们只需要知道它在查找Dialplan时需要在Dialplan中让它能找到,因而,我们在默认的Dialplan(default.xml)中加入以下内容:
  •  
  •  
  上述Dialplan会匹配被叫号码dtmf,然后应答,然后播放一个声音文件,就是我们刚才录的那一个。
  在Channel的另一头执行我们的Lua脚本,就可以检测DTMF了,笔者测试时,日志输出如下:
  • [INFO] switch_cpp.cpp:1291 Got DTMF: 1 Duration: 1120
  • [INFO] switch_cpp.cpp:1291 Got DTMF: 2 Duration: 1120
  • [INFO] switch_cpp.cpp:1291 Got DTMF: 3 Duration: 1120
  • [INFO] switch_cpp.cpp:1291 Got DTMF: 4 Duration: 1120
  帅不帅?
  当然,以上我们的Lua脚本比较简单,通过增加一些语句,你也可以比较精确的打印DTMF在录音文件中的时间等信息,这些,自己练习一下吧。
  广告时间:
  本文收录于《FreeSWITCH 实例解析》中,感兴趣的小伙伴可以点击链接购买商品。
  现在加入FreeSWITCH VIP知识星球即可获取全部『FreeSWITCH系列』电子书。
  VIP星球:
  2019年最新一期FreeSWITCH培训(北京站)以及第八届FreeSWITCH开发者沙龙正在火热报名中,现在报名还可享受八折优惠,欢迎点击『阅读原文』了解详情。
  同时欢迎赞助商及讲师加入我们本次的FreeSWITCH开发者沙龙。
【免责声明】本文仅代表作者本人观点,与CTI论坛无关。CTI论坛对文中陈述、观点判断保持中立,不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。请读者仅作参考,并请自行承担全部责任。

相关阅读:

专题

CTI论坛会员企业