团队博客

用 XSwitch 检查 WAV 文件里面的 DTMF

韩小仿  2024-03

用 XSwitch 检查 WAV 文件里面的 DTMF

跟着我做下面操作:

浏览器打开 XSwitch,登录之后,新建一条路由,参数如下:

  • 名称: 检查带内 dtmf
  • 被叫号码: dtmfdetect
  • 最大号长: 10
  • 呼叫源: 分机(context-1)
  • 目的地类型: 系统

在文本里面输入下面的内容:

answer
set min_dup_digit_spacing_ms=60
spandsp_start_dtmf
set playback_terminators=none
playback silence_stream://-1,1400

接着找到 ”维护/终端“,输入下面命令:

originate loopback/dtmfdetect/context-1 &playback(tone_stream://1234567890)

下面是部分执行的日志:

EXECUTE [depth=0] loopback/dtmfdetect-b answer()
2025-06-25 14:15:05.926618 99.70% [NOTICE] mod_dptools.c:1412 Channel [loopback/dtmfdetect-b] has been answered
2025-06-25 14:15:05.927614 99.70% [DEBUG] switch_channel.c:4024 (loopback/dtmfdetect-b) Callstate Change RINGING -> ACTIVE
EXECUTE [depth=0] loopback/dtmfdetect-b spandsp_start_dtmf()
2025-06-25 14:15:05.927614 99.70% [DEBUG] switch_core_media_bug.c:1003 Attaching BUG spandsp_dtmf_detect to loopback/dtmfdetect
EXECUTE [depth=0] loopback/dtmfdetect-b set(playback_terminators=none)
2025-06-25 14:15:05.927614 99.70% [DEBUG] mod_dptools.c:1677 SET loopback/dtmfdetect-b [playback_terminators]=[none]
EXECUTE [depth=0] loopback/dtmfdetect-b playback(silence_stream://-1,1400)
2025-06-25 14:15:05.928617 99.70% [DEBUG] switch_ivr_play_say.c:1561 Codec Activated L16@8000hz 1 channels 20ms
2025-06-25 14:15:05.952599 99.70% [DEBUG] billing.c:475 billing task started id=13
2025-06-25 14:15:05.970633 99.70% [DEBUG] switch_core_io.c:448 Setting BUG Codec L16:100
2025-06-25 14:15:05.990630 99.70% [DEBUG] mod_spandsp_dsp.c:405 DTMF BEGIN DETECTED: [1]
2025-06-25 14:15:05.990630 99.70% [INFO] switch_channel.c:539 RECV DTMF 1:2000
2025-06-25 14:15:05.990630 99.70% [DEBUG] mod_dptools.c:2378 Digit 1
2025-06-25 14:15:06.190604 99.70% [DEBUG] mod_spandsp_dsp.c:417 DTMF END DETECTED: [1], duration = 204 ms
2025-06-25 14:15:06.270605 99.70% [DEBUG] mod_spandsp_dsp.c:405 DTMF BEGIN DETECTED: [2]
2025-06-25 14:15:06.270605 99.70% [INFO] switch_channel.c:539 RECV DTMF 2:2000
2025-06-25 14:15:06.270605 99.70% [DEBUG] mod_dptools.c:2378 Digit 2
2025-06-25 14:15:06.510605 99.70% [DEBUG] mod_spandsp_dsp.c:417 DTMF END DETECTED: [2], duration = 242 ms
2025-06-25 14:15:06.570605 99.70% [DEBUG] mod_spandsp_dsp.c:405 DTMF BEGIN DETECTED: [3]
2025-06-25 14:15:06.570605 99.70% [INFO] switch_channel.c:539 RECV DTMF 3:2000
2025-06-25 14:15:06.570605 99.70% [DEBUG] mod_dptools.c:2378 Digit 3
2025-06-25 14:15:06.810639 99.70% [DEBUG] mod_spandsp_dsp.c:417 DTMF END DETECTED: [3], duration = 242 ms
2025-06-25 14:15:06.890638 99.70% [DEBUG] mod_spandsp_dsp.c:405 DTMF BEGIN DETECTED: [4]
2025-06-25 14:15:06.890638 99.70% [INFO] switch_channel.c:539 RECV DTMF 4:2000
2025-06-25 14:15:06.890638 99.70% [DEBUG] mod_dptools.c:2378 Digit 4
2025-06-25 14:15:07.130639 99.70% [DEBUG] mod_spandsp_dsp.c:417 DTMF END DETECTED: [4], duration = 242 ms
2025-06-25 14:15:07.190636 99.70% [DEBUG] mod_spandsp_dsp.c:405 DTMF BEGIN DETECTED: [5]
2025-06-25 14:15:07.190636 99.70% [INFO] switch_channel.c:539 RECV DTMF 5:2000
2025-06-25 14:15:07.190636 99.70% [DEBUG] mod_dptools.c:2378 Digit 5
2025-06-25 14:15:07.430639 99.70% [DEBUG] mod_spandsp_dsp.c:417 DTMF END DETECTED: [5], duration = 242 ms
2025-06-25 14:15:07.510640 99.70% [DEBUG] mod_spandsp_dsp.c:405 DTMF BEGIN DETECTED: [6]
2025-06-25 14:15:07.510640 99.70% [INFO] switch_channel.c:539 RECV DTMF 6:2000
2025-06-25 14:15:07.510640 99.70% [DEBUG] mod_dptools.c:2378 Digit 6
2025-06-25 14:15:07.750636 99.70% [DEBUG] mod_spandsp_dsp.c:417 DTMF END DETECTED: [6], duration = 242 ms
2025-06-25 14:15:07.810640 99.70% [DEBUG] mod_spandsp_dsp.c:405 DTMF BEGIN DETECTED: [7]
2025-06-25 14:15:07.810640 99.70% [INFO] switch_channel.c:539 RECV DTMF 7:2000
2025-06-25 14:15:07.810640 99.70% [DEBUG] mod_dptools.c:2378 Digit 7
2025-06-25 14:15:08.070639 99.70% [DEBUG] mod_spandsp_dsp.c:417 DTMF END DETECTED: [7], duration = 242 ms
2025-06-25 14:15:08.130639 99.70% [DEBUG] mod_spandsp_dsp.c:405 DTMF BEGIN DETECTED: [8]
2025-06-25 14:15:08.130639 99.70% [INFO] switch_channel.c:539 RECV DTMF 8:2000
2025-06-25 14:15:08.130639 99.70% [DEBUG] mod_dptools.c:2378 Digit 8
2025-06-25 14:15:08.390637 99.70% [DEBUG] mod_spandsp_dsp.c:417 DTMF END DETECTED: [8], duration = 242 ms
2025-06-25 14:15:08.450638 99.70% [DEBUG] mod_spandsp_dsp.c:405 DTMF BEGIN DETECTED: [9]
2025-06-25 14:15:08.450638 99.70% [INFO] switch_channel.c:539 RECV DTMF 9:2000
2025-06-25 14:15:08.450638 99.70% [DEBUG] mod_dptools.c:2378 Digit 9
2025-06-25 14:15:08.690637 99.70% [DEBUG] mod_spandsp_dsp.c:417 DTMF END DETECTED: [9], duration = 242 ms
2025-06-25 14:15:08.770639 99.70% [DEBUG] mod_spandsp_dsp.c:405 DTMF BEGIN DETECTED: [0]
2025-06-25 14:15:08.770639 99.70% [INFO] switch_channel.c:539 RECV DTMF 0:2000
2025-06-25 14:15:08.770639 99.70% [DEBUG] mod_dptools.c:2378 Digit 0
2025-06-25 14:15:09.010638 99.70% [DEBUG] mod_spandsp_dsp.c:417 DTMF END DETECTED: [0], duration = 242 ms

拨号字符串 loopback/dtmfdetect/context-1 分成了三部分,其中 loopback 是端点,dtmfdetect 是被叫号码,context-1 是呼叫源。

loopback 比较特别,自动创建两个相互连通的通道,其中呼出的通道在呼出成功后播放带内 DTMF 1234567890,呼入的通道执行创建好的路由: 应答,设置通道变量,执行 spandsp_start_dtmf(检查带内 DTMF),循环播放静音。

上面的日志可以看到,呼出通道发送的是 1234567890,呼入通道接收到全部 DTMF,不多也不少。

在上面的路由里面可以再增加一个通道变量 set dtmf_verbose=true,识别的过程可以在日志里面更清楚地体现出来。

一般来说,VoIP 倾向于用 RFC2833 来传递 DTMF,但如果 XSwitch 跟落地网关对接,网关一侧按了键,但 XSwitch 收不到,那怎么办呢? 可以在路由里面选择录音,通话结束后把录音文件复制到 /tmp 目录,比如文件名为 test.wav,再执行下面的 API:

originate loopback/dtmfdetect/context-1 &playback(/tmp/test.wav)

观察日志就可以知道是否真的有带内 DTMF 送过来。

此外,如果二个按键间隔时间比较长,可以用 start_dtmf 来代替 spandsp_start_dtmf,但如果间隔时间比较短,建议使用 spandsp_start_dtmf。 一般来说,min_dup_digit_spacing_ms 建议设置为 60 毫秒,这个参数来自经验,设置过大过小可能就不合适,导致收到重复的按键或者丢失按键。

Kamailio rr 的秘密