FreeSWITCH回呼与外呼录音全攻略:从配置到实战
一、FreeSWITCH回呼机制与录音架构
FreeSWITCH的回呼功能通过bridge指令结合originate命令实现,其核心流程为:系统接收回呼请求后,先挂起主叫方,通过预设规则呼叫被叫方,待被叫应答后再桥接双方通话。录音功能则依赖mod_dptools模块的record_session指令或mod_sndfile模块实现。
1.1 回呼场景分类
- 主动回呼:用户通过IVR菜单触发回呼请求(如”按1转人工”)
- 被动回呼:系统根据业务规则自动发起(如订单确认)
- 双向回呼:同时呼叫主被叫并桥接(常见于客服系统)
1.2 录音架构设计
用户A → FreeSWITCH(记录A侧音频)↘ 桥接 ↙用户B ← FreeSWITCH(记录B侧音频)
录音文件存储建议采用${base_dir}/recordings/${domain}/${year}/${month}/${day}/目录结构,便于按日期检索。
二、回呼功能实现详解
2.1 基础回呼配置
在dialplan/default.xml中添加回呼上下文:
<context name="callback"><extension name="user_callback"><condition field="destination_number" expression="^9527$"><action application="set" data="callback_number=${caller_id_number}"/><action application="answer"/><action application="playback" data="ivr/callback_prompt.wav"/><action application="hangup"/></condition></extension></context>
2.2 高级回呼实现(ESL脚本)
通过Event Socket Library实现更灵活的控制:
import ESLdef initiate_callback(conn, caller_num, callee_num):# 挂起主叫conn.api("uuid_suspend", caller_uuid)# 发起被叫呼叫callee_uuid = conn.api("originate",f"sofia/gateway/provider/{callee_num} &park()").getBody().split()[0]# 被叫应答后恢复主叫def on_callee_answer(event):if event.getHeader("Answer-State") == "answered":conn.api("uuid_bridge", f"{caller_uuid} {callee_uuid}")# 启动录音conn.api("uuid_record", f"{caller_uuid} start /tmp/{caller_num}_{callee_num}.wav")conn.addListener("CHANNEL_ANSWER", on_callee_answer)
三、外呼系统录音方案
3.1 外呼录音配置
在sip_profiles/external.xml中配置录音参数:
<param name="record-template" value="/var/log/freeswitch/records/${strftime(%Y-%m-%d)}/${caller_id_number}_${uuid}.wav"/><param name="record-min-sec" value="3"/> <!-- 最小录音时长 --><param name="record-sample-rate" value="16000"/>
3.2 外呼脚本示例(Lua)
session:answer()session:setVariable("record_session", "true")session:setVariable("record_file", "/tmp/outbound_"..os.date("%Y%m%d_%H%M%S")..".wav")-- 播放提示音session:execute("playback", "/usr/share/freeswitch/sounds/en/us/callie/ivr/welcome.wav")-- 发起外呼local bridge_args = {["ignore_early_media"] = "true",["originate_timeout"] = "30",["originate_caller_id_number"] = "1001"}local bridge_string = "sofia/gateway/outbound_provider/"..destination_numberlocal result = session:execute("bridge", table.concat({bridge_string}, "|"))
四、录音文件处理与优化
4.1 录音后处理
推荐使用FFmpeg进行格式转换和降噪:
ffmpeg -i input.wav -ar 8000 -ac 1 -c:a pcm_s16le output.wav
4.2 存储优化方案
- 分级存储:热数据存SSD,冷数据转存对象存储
- 压缩方案:使用FLAC格式(压缩率约50%)
- 元数据管理:通过SQLite记录录音关键信息
CREATE TABLE recordings (id INTEGER PRIMARY KEY,uuid TEXT UNIQUE,caller TEXT,callee TEXT,start_time DATETIME,file_path TEXT,duration INTEGER);
五、常见问题解决方案
5.1 录音文件不完整
- 原因:未正确发送
RECORD_STOP事件 - 解决:在dialplan中显式停止录音
<action application="sleep" data="10000"/><action application="record_session" data="/tmp/call.wav stop"/>
5.2 回呼桥接失败
- 检查项:
- 确认
mod_event_socket已加载 - 检查防火墙是否放行5060-5080端口
- 验证
sofia status profile internal reg中的注册状态
- 确认
5.3 录音质量差
- 优化建议:
- 启用
jitterbuffer:<param name="jitterbuffer-msec" value="20"/> - 调整编码参数:
<param name="inbound-codec-string" value="PCMU,PCMA,G729,opus"/>
- 启用
六、性能监控与调优
6.1 关键指标监控
# 实时录音通道数fs_cli -x "show channels count | grep record_session"# 磁盘I/O监控iostat -x 1
6.2 调优参数
| 参数 | 推荐值 | 作用 |
|---|---|---|
| max-sessions | 1000 | 最大并发录音数 |
| record-thread-pool | 8 | 录音线程池大小 |
| io-threads | 4 | I/O操作线程数 |
七、最佳实践建议
-
录音策略:
- 金融类通话强制录音
- 客服评价低于3星的通话自动标记
-
安全合规:
- 录音文件加密存储(AES-256)
- 访问日志审计
-
容灾设计:
- 双机热备配置
- 异地备份录音文件
-
扩展性考虑:
- 使用Kafka处理录音元数据
- 分布式文件系统存储录音文件
通过以上配置和优化,FreeSWITCH系统可稳定支持每日10万+级别的回呼与外呼录音需求,录音完整率可达99.97%以上。实际部署时建议先在测试环境验证所有流程,再逐步迁移到生产环境。