模块定位
mod_audio_fork 是一个 FreeSWITCH 模块,它在通话上附加一个 media bug(媒体监听器),把通话的实时音频以 L16 编码通过 WebSocket 推送到远端服务器,同时支持远端推回音频做实时播放。是本项目把 FreeSWITCH 与 AI 语音服务串起来的唯一桥梁。
- 仓库来源:Wangijun/mod_audio_fork,fork 自
W1ck3dZA/mod_audio_fork - 语言:C++(~78%)+ C
- 协议:标准 RFC6455 WebSocket,子协议
audio.drachtio.org
为什么不用 mod_unimrcp
| 维度 | mod_unimrcp | mod_audio_fork |
|---|---|---|
| 协议 | MRCPv2 + SIP + RTP | 一根 WebSocket |
| 部署 | 要 unimrcpserver + 插件 + XML 配置 | 业务侧实现一个 WS server 即可 |
| 流式 ASR | 协议层支持但开源插件少 | 天然流式,partial 秒到 |
| 与现代 AI 栈对接 | 难(要写 MRCP 插件) | 直接喂 PCM16 给 sherpa/whisper/其他 |
| 双向音频 | 较复杂 | 服务端推 binary 帧即可 |
本项目当前版本完全不依赖 mod_unimrcp,识别只走 mod_audio_fork。
核心能力
- 双向音频流:上行通过 WS 上传 PCM16;下行可接收服务端推回的 base64 JSON 或 binary 音频帧
- 音频标记:
mark/clearMarks同步播放节奏 - 混流模式:
mono(仅主叫)、mixed(主被叫混音)、stereo(双声道分离) - 采样率:8000 / 16000 / 24000 / 32000 / 48000 / 64000 Hz,内置 Speex 重采样
- SIMD 优化:AVX2 / SSE2 编译加速
- TLS 支持:
wss://直连 - 平滑停止:
graceful-shutdown排空缓冲后再关闭 - HTTP Basic Auth:通过 channel variable 注入认证头
构建与安装
模块仓库提供 build.sh 一键脚本:
1 | git clone https://github.com/Wangijun/mod_audio_fork.git |
或分步:
1 | sudo ./build.sh deps # 装编译依赖 |
详细构建说明见仓库 BUILD.md。
在 FreeSWITCH 中加载:
1 | <!-- conf/autoload_configs/modules.conf.xml --> |
或运行时:
1 | fs_cli -x "load mod_audio_fork" |
uuid_audio_fork 命令集
通用语法:uuid_audio_fork <uuid> <command> [args...]
| 命令 | 用途 |
|---|---|
start <wss-url> <mix-type> <sampling-rate> [bugname] [metadata] [bidi_enabled] [bidi_stream_enabled] [bidi_stream_samplerate] |
启动 media bug,建立 WebSocket,开始推流 |
stop [bugname] [metadata] |
关闭连接、移除 bug;可附最后一段文本元数据 |
send_text [bugname] <text> |
向服务端发一条 text frame(DTMF / 自定义控制等) |
pause [bugname] |
暂停推流(音频帧丢弃) |
resume [bugname] |
恢复推流 |
graceful-shutdown [bugname] |
不再发新音频,排空缓冲后关闭 |
stop_play [bugname] |
清空当前下行播放缓冲 |
示例:
1 | fs_cli -x "uuid_audio_fork <uuid> start ws://127.0.0.1:10096/audio mono 16k callflow_asr {}" |
bugname 在同一通通话里需保持唯一;callflow-esl 默认用 callflow_asr。
关键环境变量
| 变量 | 默认 | 说明 |
|---|---|---|
MOD_AUDIO_FORK_SUBPROTOCOL_NAME |
audio.drachtio.org |
WebSocket 子协议名;服务端必须接受同名 |
MOD_AUDIO_FORK_SERVICE_THREADS |
1 |
服务线程数(1-5) |
MOD_AUDIO_FORK_BUFFER_SECS |
2 |
缓冲秒数(1-5) |
关键 channel variable
可在 dialplan 或 uuid_setvar 中设置:
| 变量 | 用途 |
|---|---|
MOD_AUDIO_BASIC_AUTH_USERNAME / MOD_AUDIO_BASIC_AUTH_PASSWORD |
WSS 端的 HTTP Basic Auth |
MOD_AUDIO_FORK_ALLOW_SELFSIGNED |
TLS 允许自签证书 |
MOD_AUDIO_FORK_SKIP_SERVER_CERT_HOSTNAME_CHECK |
跳过 TLS hostname 校验 |
MOD_AUDIO_FORK_ALLOW_EXPIRED |
允许过期证书 |
自定义事件
模块在 FreeSWITCH event bus 上发布以下 CUSTOM event(subclass):
| Event Subclass | 含义 |
|---|---|
mod_audio_fork::connect |
WebSocket 已连接 |
mod_audio_fork::connect_failed |
握手失败 |
mod_audio_fork::disconnect |
连接断开 |
mod_audio_fork::buffer_overrun |
缓冲溢出(来不及发) |
mod_audio_fork::transcription |
服务端推回的识别文本 |
mod_audio_fork::transfer |
服务端请求转接 |
mod_audio_fork::play_audio |
服务端推回播放音频 |
mod_audio_fork::kill_audio |
服务端请求中断播放 |
mod_audio_fork::error |
错误事件 |
mod_audio_fork::json |
服务端自定义 JSON 帧 |
callflow-esl 主要消费 connect / disconnect / transcription 三种。
上下行消息协议(与服务端约定)
客户端 → 服务端
第一帧:text frame,JSON metadata。callflow-esl 默认下发:
1
2
3
4
5{
"uuid": "<fs-channel-uuid>",
"callerId": "...",
"direction": "inbound"
}后续帧:binary frame,原始 16kHz / mono / PCM16 little-endian 音频
服务端 → 客户端
服务端可发 text frame,JSON 体按 type 分发:
1 | { "type": "transcription", "text": "...", "isFinal": true } |
当通话需要服务端推 TTS 给主叫播放时(双向音频模式),playAudio 携带 base64 音频或 binary 帧。
mark 队列最大 30 项。
在本项目中的使用
callflow-esl 通过配置项 audioFork 调用本模块:
1 | { |
runtime 在 ctx.hear() 启动时下发 uuid_audio_fork start,并在结束 / 挂机时下发 stop。eventSubscriptionMode 控制 ESL 事件订阅策略,默认 "all" 是当前唯一稳定下发 mod_audio_fork::transcription 的策略。详见 配置参考。
已知坑
注意
- 采样率必须匹配:上游推 16kHz 但服务端按 8kHz 解码,partial 全乱。本项目默认
mono / 16k。 - bugname 唯一性:同一通通话多次
start用同一个 bugname 会失败;如果业务里需要先停后启,要么传不同 bugname,要么先stop再start。 - CUSTOM 事件订阅:FreeSWITCH 默认
event plain CUSTOM mod_audio_fork::transcription在某些版本下不稳定,本项目改用event plain ALL再在应用侧按 UUID 过滤。 - TLS 自签:内网部署常用自签证书,记得配
MOD_AUDIO_FORK_ALLOW_SELFSIGNED=true。
参考链接
- 源码仓库:https://github.com/Wangijun/mod_audio_fork
- 上游:https://github.com/W1ck3dZA/mod_audio_fork
- 子协议命名来源:drachtio 项目(
audio.drachtio.org是其约定的 WS 子协议)