Skip to content

监听模式 spy 使用说明

spy 模式用于旁路监听 FreeSWITCH 通话音频,并把音频实时推送给 EasyMrcp 做 ASR 识别。

普通通话模式下,EasyMrcp 通过 SIP/SDP 协商拿到 RTP 音频;spy 模式下,EasyMrcp 不参与被监听通话的 SIP 协商,而是先给客户端分配一个 ASR RTP 接收端口,再由 FreeSWITCH 的 mod_easymrcp_spy 模块把通话音频推过来。

1. 适用场景

spy 模式适合这些场景:

  • 对已有通话做旁路实时转写。
  • 呼叫双方仍按原有业务流程通话,EasyMrcp 只负责识别音频。
  • 需要同时监听 A-leg、B-leg,或者只监听其中一路。
  • 不希望改造原有 SIP 媒体协商链路。

如果业务本身就是让机器人和用户对话,优先使用普通 EasyMrcp 通话模式;如果业务是“已有通话旁边再挂一条识别链路”,再使用 spy

2. 整体流程

text
业务脚本
  ├─ 连接 EasyMrcp TCP 端口
  ├─ 发送 ClientConnect,data={"Type":"spy"}
  ├─ 等待 EasyMrcp 返回 rtpPort
  ├─ 调用 FreeSWITCH 命令 easymrcp_spy_start <EasyMrcpIP>:<rtpPort>
  └─ 发送 DetectSpeech 开始识别

FreeSWITCH mod_easymrcp_spy
  └─ 把当前通话音频编码为 G.711A RTP,推给 EasyMrcp

EasyMrcp
  ├─ 接收 RTP
  ├─ 按当前 ASR 配置识别
  └─ 返回 RecognitionComplete / NoInputTimeout 等事件

源码里 ClientConnectEventHandlerType=spy 做了特殊处理:创建 ASR 处理器、分配 ASR RTP 端口,并通过 ClientConnect 事件把 rtpPort 返回给客户端。

3. 编译安装 FreeSWITCH 模块

模块示例位于:

text
examples/mod_easymrcp_spy/

编译:

bash
cd /path/to/EasyMrcp/examples/mod_easymrcp_spy
make

安装:

bash
sudo make install

加载模块:

text
load mod_easymrcp_spy

也可以加入 FreeSWITCH 的 modules.conf.xml

xml
<load module="mod_easymrcp_spy"/>

4. FreeSWITCH 命令

启动监听:

text
easymrcp_spy_start <target_ip>:<target_port>

停止监听:

text
easymrcp_spy_stop

其中:

参数说明
target_ipEasyMrcp 服务地址。
target_portEasyMrcp 返回的 rtpPort

示例:

text
easymrcp_spy_start 192.168.1.100:20000

这个命令必须在某一路 FreeSWITCH session 里执行,不能脱离通话上下文单独执行。

5. TCP 连接参数

客户端连接 EasyMrcp 时,ClientConnectdata 里需要传入:

json
{
  "Type": "spy"
}

EasyMrcp 返回:

json
{
  "rtpPort": 20000
}

拿到 rtpPort 后,再调用:

text
easymrcp_spy_start <EasyMrcpIP>:<rtpPort>

随后按普通 ASR 流程发送 DetectSpeech

json
{
  "StartInputTimers": false,
  "NoInputTimeout": 60000,
  "SpeechCompleteTimeout": 800,
  "AutomaticInterruption": true
}

spy 模式下源码会强制把 PushAsrRealtimeResult 设为 false。如果需要实时中间结果,建议先确认业务是否能接受监听链路和普通对话链路的事件语义差异。

6. Python 示例脚本

示例脚本位于:

text
examples/mod_easymrcp_spy/spy_handler.py

核心逻辑是:

  1. 用当前通话 UUID 创建 EasyMrcpTcpClient
  2. 注册 ClientConnectRecognitionCompleteNoInputTimeout 回调。
  3. 发送 ClientConnect,参数为 {"Type":"spy"}
  4. 从返回数据里取出 rtpPort
  5. 执行 session.execute("easymrcp_spy_start", "<EasyMrcpIP>:<rtpPort>")
  6. 发送 DetectSpeech 开始识别。
  7. 通话结束时关闭 TCP 连接,并停止监听。

如果需要同时监听 A-leg 和 B-leg,可以为两路通话分别创建 TCP 客户端和 spy 推流。

7. 注意事项

  1. mod_easymrcp_spy 输出的是 G.711A RTP,EasyMrcp 侧按 mediaType=8 接收。
  2. EasyMrcp 返回的 rtpPort 来自 ASR RTP 端口池,要确保防火墙已放通 UDP。
  3. ClientConnect 必须先完成,拿到 rtpPort 后才能启动 easymrcp_spy_start
  4. 如果没有识别结果,优先检查 FreeSWITCH 到 EasyMrcp 的 UDP 连通性。
  5. 监听模式不会自动桥接或控制原通话,桥接、挂断、双路监听都由业务脚本负责。
  6. 通话结束时要停止监听并关闭 TCP 客户端,避免 RTP 端口和会话资源残留。

8. 常见问题

现象排查方向
ClientConnect 没有返回 rtpPort检查 data 是否为 {"Type":"spy"},以及 EasyMrcp ASR RTP 端口池是否可用。
FreeSWITCH 命令执行失败确认 mod_easymrcp_spy 已加载,并且命令在通话 session 中执行。
能连接但没有识别结果检查 UDP 是否放通,easymrcp_spy_start 的 IP/端口是否使用 EasyMrcp 返回值。
识别结果延迟明显检查网络抖动、ASR 模式、VAD 参数和 SpeechCompleteTimeout
多路监听串音每路监听必须使用独立 TCP client id 和独立返回的 rtpPort