ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FreeSWITCH呼入呼出路由配置:从拨号计划到多网关调度实战

FreeSWITCH呼入呼出路由配置:从拨号计划到多网关调度实战 简介面向企业VoIP运维与开发人员的Freeswitch呼入呼出路由配置详解文档聚焦呼入、外呼、SIP中继与拨号计划等关键环节适合正在搭建基于Freeswitch与网关设备内呼外呼环境的读者。文档先梳理Freeswitch事件驱动架构与模块组成再结合XML拨号计划讲解呼入路由转发、外呼对等中继模式及sip_profiles中继配置并给出安全加密、负载均衡、错误处理、日志监控等落地建议。包体为1份doc文档约221KB目录按引言、项目背景、Core、Module等章节展开包含系统启动过程、消息分发与MOD_SOFIA组成等模块化说明可边读边对照实验环境验证。该文档已有6446人学习下载可作为从零配置Freeswitch路由、理解拨号计划及排查SIP中继问题的实用参考资料无论初次部署还是已有环境调优都能从中获得清晰的配置思路。1. 呼入呼出路由配置先解决“电话进来没人接、出去就被挂断”的问题电话打进来没人接拨出去就被挂断这是很多刚接触 FreeSWITCH 的人遇到的第一道坎。freeswitch 呼入呼出路由配置说白了就是回答两个问题外线来话该送到哪个分机内部分机打外线该走哪条中继。路由没理清楚之前软交换做得再顺手也没用。这篇笔记按呼入、呼出两条线拆拨号计划配置给出可以直接抄进 XML 的最小路由也会把最容易翻车的几个现场单独列出来。适合正在对接 SIP 中继、做分公司电话互通或者想把拨号规则彻底理清的运维和通信工程师。2. 先把路由骨架搭对context、extension与condition怎么配合2.1 三个概念管住所有入局与出局呼叫FreeSWITCH 的呼入呼出路由几乎全部在拨号计划dialplan里完成。拨号计划由 context、extension、condition 三层组成。context 是隔离域一个呼叫进入某个 context 后只在这里面找 extension不会跑到别的 context 里捡到一条不相关的路由extension 是一条完整的路由规则condition 是规则里的匹配条件常用 field 指定呼叫变量用 expression 写正则表达式。呼入和呼出在 FreeSWITCH 里没有本质区别都是从 SIP 进入 dialplan 的呼叫真正的差别是它们从哪个 context 进来。外部中继呼叫通过 external profile 接入默认进入 public context内部分机注册在 internal profile 上拨号进 default context。所以常说的呼入路由是处理“从中继进来的号码往哪送”呼出路由是处理“从分机拨出的号码怎么改、走哪个网关”。理解了这个入口差异后面就不会把两个方向的规则搅在一起。常见的部署是 x86 服务器但 FreeSWITCH 也支持 arm 架构树莓派、ARM 软路由上都有人跑拨号计划语法完全一样只是有些编译模块需要按平台单独确认。不管跑在哪路由配置的骨架逻辑不变。2.2 一条最小呼入路由把外线电话接进分机最常见的呼入需求中继送来一个号码希望转给某个内部分机。在 public context 或你自己指定的 context 文件里加一条 extensioncontext namepublic_in extension nameinbound_to_2001 condition fielddestination_number expression^(2001)$ action applicationbridge datauser/2001${domain_name}/ /condition /extension /context逻辑说明condition 的 field 是 destination_number也就是 SIP 请求里的被叫号码expression 用 PCRE 正则^ 和 $ 把匹配限定为整串避免“2001”匹配成“20010”。action 里的 bridge 做真正的呼叫接续data 用 user/分机号域名的格式把呼叫送到内部分机。如果分机不在线bridge 会失败呼叫按失败原因继续执行后续动作默认返回忙音。参数说明${domain_name} 是 FreeSWITCH 预置的全局变量指向当前主机的域如果给分机配了独立域直接写那个域名。condition 里可以同时写多个 field比如 caller_id_number 匹配主叫、destination_number 匹配被叫匹配正则里的括号分组可以用 $1 引用到 action 中这个特点在后面呼出号码清洗时很重要。2.3 一条最小呼出路由让分机能拨9出外线呼出路由的最小形态是分机拨 9 开头的号码剥掉 9从某个网关发出去。在 default context 里加 extensioncontext namedefault extension nameoutbound_9 condition fielddestination_number expression^9(\d)$ action applicationbridge datasofia/gateway/telecom/$1/ /condition /extension /context逻辑说明分机拨 912345678 后destination_number 是“912345678”正则 ^9(\d)$ 把 9 后面的数字捕获到 $1。bridge 的 data 用 sofia/gateway/网关名/$1把去掉 9 后的号码送往名为 telecom 的网关。如果运营商要求被叫号码带 9 才能出局data 里直接写 ${destination_number} 即可具体按中继对接规范来定。参数说明网关名是 conf 里定义的 gateway 名称不是 IP 地址。bridge 到网关前先做号码变换是呼出路由的常规操作第 4 章会给完整写法。这里还有一个容易忽略的点dialplan 从上往下匹配多个 extension 有重合号码段时先匹配到的先执行想让某些条件继续往下走可以在 condition 上写 breaknever。2.4 路由匹配顺序continue 与 break 的两个典型写法dialplan 的顺序敏感是新手最容易忽略的。同一 context 里两个 extension 都匹配同一个号码时排在前面的先执行。如果你在 public context 里放了一个演示用的 echo extension又往里加了呼入分配路由很可能所有电话都进了回声测试而不是你的分机。extension namerecord_all_in continuetrue condition fielddestination_number expression^(\d)$ action applicationset datacall_recordtrue/ /condition /extension逻辑说明continuetrue 让这条 extension 执行完 set 后不中断匹配继续寻找下一个 extension。这样可以在不改动原有呼入路由的前提下给所有呼入打一个“需要录音”的标记。如果去掉 continuerecord_all_in 就会吃掉所有呼叫后面的路由永远轮不到。这是把公共逻辑放在路由头部时最典型的错误。参数说明extension 上的 continue 控制“整个 extension 执行完是否继续找下一条”condition 上的 breaknever 控制“当前 condition 匹配完是否继续本 extension 内下一条 condition”。两者作用层级不同别混用。实际项目中我一般把录音、号码清洗这类公共逻辑放最前面并加 continue把具体路由放后面这样既不影响原有路由又能给所有呼叫打标记。3. 呼入路由配置从外线中继到分机、IVR、语音信箱的实际写法3.1 先定“电话进哪个门”external profile与context的关系呼入路由第一步不是写 extension而是看呼叫从哪个 SIP profile 进来。FreeSWITCH 默认有两个 profileinternal 和 external。internal 用于内部分机注册信号端口 5060external 用于跟运营商或上游 SIP trunk 对接端口 5080。每个 profile 里有一个 context 参数决定该 profile 上收到的呼叫进入哪个 dialplan contextprofile nameexternal param namecontext valuepublic_in/ param namesip-port value5080/ /profile逻辑说明这段配置在 conf/sip_profiles/external.xml 里。把 context 从默认的 public 改成 public_in相当于给所有从 external 进来的呼叫开了一条专用路由通道。内部注册的呼叫走 internal profile进入 default context。呼入呼出要在逻辑上分家第一步就是把这两个入口分开否则后面所有匹配都会互相干扰。参数说明sip-port 是 external profile 的监听端口很多运营商只允许固定端口对接端口改了路由逻辑不变。我一般会建议新建一个 public_in context而不是直接复用 public因为 public context 默认带着 echo、MusicOnHold 等演示 extension不清掉很容易误匹配。这里是纯配置调整改完要重启 external profile 才会生效这一点在第 5 章会单独展开。3.2 呼入路由的三种去向分机、IVR、语音信箱下面是一段比较完整的呼入路由块覆盖最常用的三种去向转分机、转 IVR、转语音信箱。extension namein_to_2001 condition fielddestination_number expression^(2001)$ action applicationbridge datauser/2001${domain_name}/ /condition /extension extension namein_to_ivr condition fielddestination_number expression^(800\d{3})$ action applicationanswer/ action applicationplay_and_get_digits data2 8 3 7000 # /ivr/welcome.wav /ivr/choice.wav ivr_choice/ action applicationtransfer data${ivr_choice} XML default/ /condition /extension extension namein_to_vm condition fielddestination_number expression^(5001)$ action applicationanswer/ action applicationvoicemail datadefault 5001/ /condition /extension逻辑说明第一条 bridge 到分机 2001第二条 answer 后播放欢迎音并收按键用户按键内容写入 ivr_choice紧接着用 transfer 把 ivr_choice 作为新被叫号码转到 default context 执行第三条直接进语音信箱。三条 extension 按号码段区分互不干扰。参数说明play_and_get_digits 的参数顺序是“最少位数、最多位数、尝试次数、超时毫秒、结束符、提示音文件、无效输入音文件、结果变量”。很多人把变量名和文件名顺序写反结果按键收集不到。这里 2 是最少位数8 是最多位数3 是尝试次数7000 是超时毫秒# 是结束符ivr_choice 是结果变量。bridge 失败后的兜底可以在 bridge 后面直接加 voicemailaction applicationbridge datauser/2001${domain_name}/ action applicationvoicemail datadefault 2001/这样分机没接起来时自动进留言而不是干巴巴的忙音。3.3 呼入路由的营业时间切换与号码归一化呼入路由经常要跟着营业时间变工作时间转 IVR下班转语音信箱节假日直接播报。FreeSWITCH 的 condition 原生支持时间匹配属性extension namebusiness_hours_route condition wday1-5 hour9-18 action applicationtransfer dataivr_main XML default/ /condition /extension extension nameafter_hours_route condition wday6,0 hour0-23 action applicationvoicemail datadefault 2001/ /condition /extension逻辑说明wday 的取值范围是 0-60 表示周日所以周六周日写成 6,0。hour 9-18 表示 9 点到 18 点。第一条匹配时转到名为 ivr_main 的 IVR extension不匹配就继续检查第二条。注意这两条 extension 的顺序工作时间那条要放在前面因为匹配成功后不会再往后走。号码归一化是呼入路由里另一类高频需求。运营商送来的主叫可能带 86 或 00做黑名单、VIP 路由时直接比对经常对不上。用 regex 变量函数做清洗action applicationset datacaller_clean${regex(${caller_id_number}|^(?:\?86|00)?(1[3-9]\d{9})$|$1)}/逻辑说明set 会把 caller_id_number 里匹配到的分组内容存进 caller_clean这样 8613812345678、008613812345678、13812345678 三种格式都会被归一化成 13812345678。后续 condition 用 fieldcaller_clean 再做黑名单或 VIP 判断就避免了运营商格式差异带来的匹配失误。4. 呼出路由配置拨号前缀、号码变换与多网关调度的完整方案4.1 呼出不改号线路直接拒收呼出与呼入本质上的差异是呼出多了一个“号码变换”步骤。分机拨号往往是短号比如 9手机号、9固话、或内线短号但运营商中继要求的是标准 E.164 或特定号码格式。如果直接把分机拨的号码 bridge 到 gateway常见后果是9 没剥掉被运营商当拒收号码、手机号没补 0 被当作无效区号、固话没加区号被路由到别的城市。所以呼出路由的骨架一定是先匹配被叫号码 → 清洗/变换 → set 成新变量 → bridge 到网关。我把清洗和 bridge 分开写中间过一遍日志这样排查时能知道是哪一步改坏了。在正式配置之前最好先用 fs_cli 看一条真实呼叫的 destination_number 到底长什么样再写正则不要凭想象写匹配很多企业对短号、分机号段的规划有历史包袱。4.2 可抄的呼出拨号计划去9、补0、带上国家码下面是一段可以直接放进 default context 的呼出配置覆盖三种常见呼出类型extension nameout_mobile condition fielddestination_number expression^9(1[3-9]\d{9})$ action applicationset dataoutbound_number$1/ action applicationlog dataINFO inbound-number${destination_number} outbound-number${outbound_number}/ action applicationbridge datasofia/gateway/telecom/${outbound_number}/ /condition /extension extension nameout_local condition fielddestination_number expression^9(0\d{2,3}\d{7,8})$ action applicationset dataoutbound_number$1/ action applicationbridge datasofia/gateway/telecom/${outbound_number}/ /condition /extension extension nameout_international condition fielddestination_number expression^9(00\d{6,})$ action applicationset dataoutbound_number${destination_number:1}/ action applicationbridge datasofia/gateway/international/${outbound_number}/ /condition /extension逻辑说明三条 extension 分别匹配 11 位手机号、带区号的固定电话、国际长途。手机号从 9 后面捕获 11 位直接送给 telecom 网关固话同理。国际长途那一条用户拨 900国家码号码去掉 9 后送 international 网关。${destination_number:1} 表示从第 1 个字符之后开始截取也就是去掉开头的 9。参数说明set 把清洗后的号码存进 outbound_numberbridge 时用 ${outbound_number} 替换。中间加了一条 logINFO 级别会在日志里打印最终发往网关的号码出问题的时候第一个查这里。如果不想打印日志删掉这一行即可。为什么不用 $1 直接写进 bridge因为中间多了一个 set 变量之后你可以在 bridge 前插入任何号码变换逻辑也方便在 log 里看清清洗前后的差异。4.3 多网关按优先级接续跑一个不行换下一个企业级呼出很少只有一个网关。可能是电信加联通双线路也可能是主用运营商加备用运营商。FreeSWITCH 里做多网关最简单的方式是在同一个 bridge 里用竖线列出多个目的地action applicationbridge datasofia/gateway/telecom/${outbound_number}|sofia/gateway/unicom/${outbound_number}/逻辑说明bridge 会从左到右依次尝试第一个网关如果返回失败比如网关未注册、对方无应答会自动尝试第二个。整个过程对用户是透明的。但要注意如果第一个网关“假成功”——SIP 返回 100 Trying 后迟迟没有 180 或 200bridge 会一直等直到底层超时才切到第二个。所以双网关策略要配合网关级的超时参数。更精细的控制是先定义好候选网关列表再用 loop 和 execute 逐条尝试但大多数场景用 bridge 多目的地就能覆盖。网关对接时SIP trunk 对端通常是一个固定 IP 加端口不是动态注册所以路由能否成功很大程度上取决于网关注册是否在线。检查网关在线状态用fs_cli -x sofia status gateway telecom如果所有网关都失败可以在 bridge 后面加一段兜底播放一个预录提示音再挂断action applicationplayback data/var/record/outbound_fail.wav/ action applicationhangup/这样就可以告诉用户“外线暂时不可用”而不是干巴巴的忙音。5. 呼入呼出路由配置常见问题排查5个让你翻车的现场与解法5.1 呼入能听到回铃但分机不响现象外线拨打后主叫侧正常听到回铃音但内部分机没有任何反应几秒后呼叫结束。原因这是典型的 bridge 已经执行、但内部分机不可达。可能分机没有注册也可能 user/域名写错导致找不到该分机。另一个常见来源是正则把完整被叫号码截错比如写成(200)匹配到 2001 的一部分实际 bridge 给了不存在的号码。解决先确认分机是否注册执行fs_cli -x show registrations再手工测试fs_cli -x originate user/2001127.0.0.1 echo()。如果这条能通问题在路由匹配检查 condition 正则和 context如果这条也不通检查分机配置和域。特别注意 external context 里是否有其它 extension 先匹配了 2001 并执行了错误动作。5.2 呼出拨号后对方来电显示不对或直接拒收现象分机拨 9号码自己侧能听到接通但对方来电显示不对或者对方根本不响铃。原因最常见是没剥 9把数字 9 当成被叫号码的一部分送给了网关。某些软交换或运营商收到带 9 的号码会拒收或按短号处理。另一种是主叫号码没有透传网关默认用了中继线路的主叫号码。解决先看 bridge 前的 outbound_number 是否已经是清理后的号码。我之前说过在呼出 extension 里加 log这一步就是派这个用场。日志里确认号码没问题后检查 gateway 配置里的 caller_id 相关参数不同 FreeSWITCH 版本参数名略有差异以你当前版本的示例配置为准。一般方向是让网关把主叫号码原样放进 SIP 请求。5.3 呼入呼出混用default context导致号码互踩现象分机拨某个短号比如 10086结果触发的是呼入路由中的 IVR 或语音信箱而不是出局路由。原因default context 同时承载了呼入和呼出。呼入电话从 external 进 default呼出分机拨号也进 defaultfield 都是 destination_number短号 10086 可能同时被呼入 extension 的号码段覆盖两个业务逻辑就打架了。解决呼入独立 context比如 public_in只让 external profile 转发进去呼出留在 default。然后在规划号码段时把分机号段和中继号段错开。分机用 2xxx呼入特服用 8xxx呼出统一 9 开头这样互相踩的概率最低。这一步是路由规划层面的根治方案比在正则里规避来得可靠。5.4 正则匹配失败destination_number末尾带#号现象SIP 话机拨号后日志里 destination_number 显示为“2001#”或“862001”正则写^(2001)$死活匹配不上。原因很多话机和 IPPBX 在拨号结束时会带 # 表示结束中继呼入时有些运营商把号码格式化成 86 开头或 00 开头。destination_number 的实际值并不是你想象的那个“纯净号码”。解决在呼入 context 顶部加一条公共清洗把非数字字符剥掉再走后续路由extension namenormalize_in continuetrue condition fielddestination_number expression^(.)$ action applicationset datadest_clean${regex(${destination_number}|[^0-9]||)}/ /condition /extension逻辑说明continuetrue 保证清洗执行完继续匹配下面的 extension。regex 把所有非数字字符替换成空串dest_clean 就是纯数字。后续呼入 extension 的 condition 把 field 从 destination_number 改成 dest_clean。注意带号来源不同时86 前缀是否要保留要看业务这里只做了去符号处理不做国家码判断。5.5 reloadxml不生效与Windows路径坑现象改了 xml执行 reloadxml再呼测试还是走老路由甚至直接报 not found。原因FreeSWITCH 的 XML 配置是分层加载的。reloadxml 能重新加载大部分拨号计划但 external profile 里的 context 参数和 gateway 参数改动需要重启 SIP profile 才会生效。另一个常见原因是你在 Windows 版 FreeSWITCH 上改文件路径分隔符、文件编码或权限问题导致 xml 没有真正被读到。解决只改 extension 内容时执行fs_cli -x reloadxml改了 profile 或 gateway 参数时执行fs_cli -x sofia profile external restart。注意 restart 会中断该 profile 上正在进行的呼叫生产环境要挑窗口期。Windows 上优先用 UTF-8 无 BOM 保存改完先确认文件能被正常解析再进 fs_cli 验证。排查时用uuid debug抓一条呼叫看它实际加载了哪个文件不要凭猜。6. 验证路由配置的三板斧originate、uuid debug与状态检查6.1 用originate给路由做冒烟测试改完路由不要急着让业务方拨号测试先用 fs_cli 做冒烟fs_cli -x originate user/2001127.0.0.1 echo() fs_cli -x originate sofia/gateway/telecom/13812345678 echo()逻辑说明第一条命令模拟内部分机呼叫验证 user 拨号串和分机注册状态第二条命令直接从网关发起外呼验证网关注册和号码变换结果。echo() 是回声应用接通后能听到自己的声音如果直接呼叫真实号码要确认测试对象能接受避免打扰真实用户。6.2 用uuid debug与状态检查定位问题冒烟不通过时先用状态检查缩小范围再用 uuid debug 看细节fs_cli -x show registrations fs_cli -x sofia status gateway telecom fs_cli -x show channels呼叫发生时用 show channels 拿到 uuid再执行uuid debug uuid日志里会逐条打印匹配过的 extension、condition 是否命中、action 执行顺序。这是排查路由配置的终极手段比反复改 xml 重载高效得多。我现在每次改完路由都先跑一轮 originate 冒烟再看一眼分机和网关的注册状态最后才通知业务方测试。这个顺序养成了习惯之后至少能拦掉一半“路由不生效”的反馈。希望帮到你。本文还有配套的精品资源点击获取
返回列表