资讯动态

FreeSWITCH呼入呼出路由配置:Dialplan与SIP Profile联动详解

发布时间:2026/9/30 11:34:29 来源:尧图企业网站定制
简介呼入呼出路由配置详解文档面向使用FreeSWITCH搭建VoIP通信系统的运维、集成与二次开发人员。文档系统梳理了FreeSWITCH V1.2.7的核心架构与路由机制围绕呼入、呼出两条主线详细说明如何通过XML拨号计划处理外部来电以及如何以对等中继模式配置SIP中继并填写FreeSWITCH的IP与监听端口实现稳定外呼。同时作者结合与网关设备的实际对接经验给出了TLS安全加密、多中继负载均衡、错误恢复与备用路由、日志与性能监控等生产环境配置建议。压缩包内共1个文件为约221KB的Doc文档内容涵盖FreeSWITCH整体架构、程序启动与消息分发、核心模块介绍、MOD_SOFIA模块组成与启动等章节目录清晰便于循序阅读。已有6448人学习下载对于需要独立完成呼入呼出路由规划、中继对接及故障排查的工程师是一份务实且可直接参考的说明文档。1. 呼入呼出路由配置一张 Dialplan 吃下全部呼叫方向做 FreeSWITCH 路由配置最常见的一个误解是呼入、呼出要分开两套逻辑去写。实际拆过之后你会发现呼入和呼出最终都汇到同一张拨号计划Dialplan里区别只在入口呼入走 sofia profile 的 context呼出走 originate 时指定的 dialplan 或在 dialplan 里通过 bridge/forward 触发。这套配置的核心是三件事vars.xml 里的全局变量、sip_profiles 里的中继网关、dialplan 里的路由规则。只要把这三件套的对应关系理清内呼外呼、SIP 中继、对等中继模式基本都能稳稳落地。本文按我实际配置 FreeSWITCH V1.2.7 内部测试环境的思路来拆适合正被路由绕晕的人直接照着改。2. 配置三件套vars 变量、SIP Profile 和 Dialplan 的联动关系2.1 vars.xml全局变量决定路由基线刚接触 FreeSWITCH 的人往往先改 dialplan改了半天发现号码匹配不上最后查出来是全局变量的锅。vars.xml 里定义的变量作用域覆盖所有 contextdialplan 里的${local_ip_v4}、${domain}都是从这儿取的。我们测试环境里最常用的默认值是X-PRE-PROCESS cmdset datadomain$${local_ip_v4}/ X-PRE-PROCESS cmdset datalocal_ip_v4192.168.1.100/ X-PRE-PROCESS cmdset datadialplanXML/ X-PRE-PROCESS cmdset datadefault_areacode010/X-PRE-PROCESS不是运行时解析而是 FreeSWITCH 加载 vars.xml 时做的预处理相当于先执行这些赋值后面的 XML 配置里所有${local_ip_v4}都会被替换成192.168.1.100。如果你在 conf 目录下已有默认 vars.xml需要重点检查domain和local_ip_v4这两个值外呼网关的注册或对等中继常因为这里写成了默认的localhost或127.0.0.1导致对端注册过来时域名匹配不上。2.2 sip_profiles呼入的入口和呼出的出口sip_profiles 决定 FreeSWITCH 监听哪些 IP 和端口以及每个 profile 默认把呼叫丢到哪个 context。很多路由不生效不是 dialplan 写错而是呼入的包根本没进你预期的 context。内部测试环境我一般开一个 internal profile 用于内部分机注册再开一个 external profile 对接网关或上游 SIP 中继profile nameexternal settings param namesip-ip value192.168.1.100/ param namesip-port value5080/ param namedialplan valueXML/ param namecontext valuepublic/ param nameinbound-codec-prefs valuePCMU,PCMA/ param nameoutbound-codec-prefs valuePCMU,PCMA/ param namertp-ip value192.168.1.100/ /settings /profile这个 profile 监听 5080 端口收到的呼入全部落到publiccontext。对等中继模式下网关侧把 SIP 中继的地址填成192.168.1.100:5080FreeSWITCH 这边不用注册账号只要外部 profile 允许匿名呼入accept-blind-reg等参数按需开包就能进来。需要提醒的是顺带检查external的auth-calls参数对等中继场景通常设成false否则网关发来的 INVITE 会被当成未认证请求拒绝。2.3 dialplan 才是路由本体路由规则全写在conf/dialplan/下的 XML 文件里。FreeSWITCH 按 context 组织 dialplan同一张表里既处理分机互拨也处理走中继的外呼。关键是理解匹配顺序当一个呼入到达publiccontext它会按extension的先后顺序逐条尝试匹配。condition里的表达式命中后执行action。一个最简单的外呼到 PSTN 网关extension nameoutbound_pstn condition fielddestination_number expression^9(\d{7,})$ action applicationbridge datasofia/gateway/gsm_gateway/$1/ /condition /extensiondestination_number是叫到 FreeSWITCH 的号码正则^9(\d{7,})$匹配以 9 开头的号码截掉 9 后把剩余部分桥接到名为gsm_gateway的网关。bridge 的执行逻辑是创建一条新呼叫到网关接通后将两条腿桥在一起。条件的背后是 FreeSWITCH 对每个呼叫建立 channel 后把呼叫的元数据填进模板再做条件求值命中才执行动作。任何字段都能做条件destination_number和caller_id_number用得最多。2.4 网关 gateway 和对等中继的关系外呼的出口在网关配置里。很多没做过 VoIP 的人分不清 SIP Profile 和 Gateway 的区别Profile 是 FreeSWITCH 自己的监听口和属性Gateway 是 FreeSWITCH 主动连接的上游设备的账号或地址。对等中继模式下网关侧没有账号体系FreeSWITCH 配置里同样可以不填username/password只填地址gateway namegsm_gateway param nameproxy value192.168.1.200/ param nameregister valuefalse/ param nameextension-in-contact valuetrue/ /gatewayregisterfalse意味着 FreeSWITCH 不做 REGISTER 注册直接发 INVITE 到 proxy 地址。extension-in-contact让 FreeSWITCH 在 Contact 头带上主叫号码部分网关没有这一项会回 486 或直接拒绝匿名呼叫。这个配置跟你对接的网关设备强相关网关要求注册模式就填registertrue并补username/password要求对等中继就把register关掉。3. 呼入路由从 SIP 包进来到分机响铃的完整链路3.1 呼入时数字怎么被解析和匹配呼入链路从外部 INVITE 到达 profile 开始。sofia 模块解析 SIP 报文后把 Request-URI 里的号码存入 channel 的destination_number把主叫号码存入caller_id_number随后进入你在 profile 里指定的 context。很多人上来就写condition fielddestination_number expression^(100[0-9])$但发现分机没反应原因往往是号码带了前缀或参数。调试呼入匹配最直接的手段是在 dialplan 里打印变量。我用得最多的是action applicationlog dataINFO dest${destination_number} caller${caller_id_number}/然后到控制台看日志。V1.2.7 的日志格式比较简单信息里能看到完整的被叫号码。判断号码到底长什么样比反复改正则猜要快得多。呼入分发常见做法是按被叫号码做分支打电话到总机 0 转 ivr打某个号码段直接转分机extension nameivr_main condition fielddestination_number expression^0$ action applicationanswer/ action applicationplayback dataivr/ivr_main.wav/ /condition /extension extension nameext_2000_2005 condition fielddestination_number expression^(200[0-5])$ action applicationbridge datauser/$1${domain}/ /condition /extension第一个 extension 匹配到 0answer 后播放 IVR 语音第二个 extension 匹配2000-2005直接桥到本地分机。user/$1${domain}是 FreeSWITCH 的内部呼叫语法$1是正则捕获的完整号码。需要留意的是bridge和transfer的区别transfer会重新进入 dialplan 匹配新的 context 或 extension而bridge只是呼叫另一条腿通道建立后还会继续在原来的 dialplan 上下文里。3.2 呼入默认路由和失败兜底呼入一个没有匹配到任何 extension 的号码时FreeSWITCH 会返回 404。对生产环境来说这不够友好通常会在 context 末尾加一条默认路由。兜底的方式有两种一种是转到语音邮箱一种是转到前台座席组extension namedefault_inbound condition action applicationanswer/ action applicationplayback datatone_stream://4000/ action applicationhangup/ /condition /extension没有 field 的 condition 等于无条件命中。这里 answer 后播放 4 秒提示音再挂断至少让主叫明确听到已被接起的声音。有的环境希望做总机人工接听就把 playback 换成bridge到固定坐席分机。要注意兜底 extension 不要写在前面否则所有号码都被它截胡。3.3 同一个号码段呼入与呼出走向不同实际环境中常见的需求是同一个号码段从外部呼入落地到 A 组坐席从内部分机呼出时却要交给网关处理。这类场景不要试图在 context 名称上玩花样而是用条件字段区分来源。呼入的 channel 的sofia_profile和network_addr可以用来判断来源extension nameinbound_from_gateway condition fieldsofia_profile expression^external$/ condition fielddestination_number expression^(6000)$ action applicationbridge datauser/6001${domain}/ /condition /extension同时命中两个 condition 才执行 action。这比维护两张 dialplan 表清晰得多。需要提醒的是 condition 之间是 AND 关系不是 OR想表达号码是 6000 或 6001要拆成两个 extension 或者用正则^(6000|6001)$。4. 外呼路由对等中继模式下的网关对接与 originate 外呼4.1 外呼的三种触发方式FreeSWITCH 外呼不是只有拨号计划这一条路。实际拆项目时会碰到三种触发方式分机拨号触发、ESL 或 API 直接 originate、呼叫被 transfer 到外呼 extension。第一种最常见分机拨 9 开头号码dialplan bridge 到网关第二种多用于 CRM 点击外呼或自动外呼系统通过originate命令拉起呼叫第三种是呼叫先在本地被接听再由 IVR 流程转出去。对等中继模式下分机拨号的外呼模板延续第 2 章的写法核心动作是 bridge。但要注意外部网关未必接受任意主叫号码Freedom 这类网关可能要求主叫必须在白名单内。常见做法是 bridge 前先 set 主叫号码extension nameout_gsm condition fielddestination_number expression^9(\d)$ action applicationset dataeffective_caller_id_number10086/ action applicationbridge datasofia/gateway/gsm_gateway/$1/ /condition /extensioneffective_caller_id_number只影响当前呼叫向对端显示的主叫号不影响本地分机的号码。需要注意 bridge 到网关时sofia/gateway/网关名/号码的语义FreeSWITCH 会在该网关的 proxy 地址上发起一条呼出号码作为 Request-URI 传过去。4.2 originate 拉起外呼和 inline dialplanCRM 或呼叫中心场景通常不走分机拨号而是由平台侧直接呼出。ESL 命令的典型写法originate user/2000${domain} 9${destination} bridge(sofia/gateway/gsm_gateway/${destination})这条命令的执行逻辑是这样的先让分机 2000 响铃主叫腿分机接听后再由bridge()生成一条新呼叫到网关。后跟的是拨号计划应用不是立即执行而是等主叫腿进入应答状态后才触发。这样写的好处是绕过 XML dialplan路由逻辑集中在外部程序里。另一种方式是把外呼号码塞进字符串里直接打在 dialplan 上originate sofia/gateway/gsm_gateway/13800000000 10086 XML public前一个串是外呼的腿后一个串10086作为对端看到的主叫XML表示使用 XML dialplanpublic是 context。这条命令会让 FreeSWITCH 先呼出到网关再把收到的来电作为新呼叫路由进publiccontext。如果网关回 486会直接导致原有呼叫失败日志里能看到具体原因这类外呼的排错重点在网关响应码而不在 dialplan。4.3 呼出号码清洗前缀、加码和编码转换外呼路由不能只做透明转发。网关设备通常对号码格式有要求比如本地网内呼叫要加0或9异地手机要加0固话要加区号国际号码要加00。这些清洗工作放在 dialplan 里做比放外部程序里改更直观。我的习惯是把号码清洗放独立 extension用条件分支区分号码段extension nameout_local_fixed condition fielddestination_number expression^9(\d{7,8})$ action applicationset dataout_number0$1/ action applicationbridge datasofia/gateway/gsm_gateway/${out_number}/ /condition /extension extension nameout_mobile condition fielddestination_number expression^91[3-9]\d{9}$ action applicationset dataout_number$1/ action applicationbridge datasofia/gateway/gsm_gateway/${out_number}/ /condition /extension正则里的捕获组在这里承担了剥壳任务用户拨 901012345678实际发到网关的是001012345678。清洗规则因网关而异这个例子代表的是最常见的去掉前缀、补区号套路。重点是set后的变量在bridge里用${out_number}引用中间隔了多条 action 也没问题因为变量挂在 channel 上。4.4 外呼失败的重试与备用路由生产环境最不能忍的就是单条中继故障导致整个外呼瘫痪。FreeSWITCH 原生支持 gateway 级 failover在 dialplan 里写多个 bridge 是无效的正确的做法是用bridge的逗号语法多个出口用逗号分隔FreeSWITCH 会按顺序逐个尝试action applicationbridge datasofia/gateway/gsm_gateway/$1,sofia/gateway/backup_pstn/$1/这套机制的原理是 bridge 执行时会逐条尝试呼叫前一条失败立即释放并进入下一条。可用于跨区域网关容灾也可用于主备中继切换。要注意的是如果两个网关同时振铃而不是先后尝试需要用多腿 bridge 的复杂语法日常主备切换用逗号分隔就够了。5. 呼入呼出路由配置避坑正则、变量、认证与 NAT 的五个典型翻车现场5.1 拨号计划正则匹配不生效现象明明写了condition fielddestination_number expression^1000$拨打 1000 却没有匹配到任何 extension控制台显示 No dialplan match。原因呼叫进入的 context 不对。比如 external profile 配置的 context 是public但你改的 dialplan 写在了defaultcontext 下路由永远不可能命中。解决在vars.xml里确认default_areacode和domain值然后在对应 profile 的context参数上排查。我常用的排查顺序是先sofia status profile external查看当前 profile 绑定的 context再对着 dialplan 里同名的context块检查。另外^1000$这类全匹配是对的但要留意 FreeSWITCH 某些版本会把destination_number带上额外的前缀字符用第 3 章的 log 打印确认实际值再做正则。5.2 分机注册成功但外呼 403/404现象内部分机之间互拨正常一旦拨打 9 开头的号码网关返回 403 Forbidden 或 404 Not Found而网关设备直连分机测试没有任何问题。原因对等中继模式下网关虽然不要求注册但对主叫号码做了白名单校验。FreeSWITCH 默认会把注册分机的号码作为主叫发过去网关不认识就拒了。解决dialplan 里在外呼动作前强制改写effective_caller_id_numberaction applicationset dataeffective_caller_id_number实际放行号码/注意这里要写在 bridge 之前否则改写只对后续应用生效通道已经带着原主叫号发出去了。5.3 外呼显示的主叫号码被网关吞掉现象dialplan 里设置了effective_caller_id_number10086bridge 到网关后对方手机上看到的仍是乱码或空号。原因网关未必使用来自 FreeSWITCH 的 Caller-ID 头。部分 GSM 网关要求单独通过 SIP 扩展头传主叫还有的网关直接用自己的通道号做为主叫。解决翻阅网关配置手册找主叫透传或通道主叫设置项。FreeSWITCH 侧能做的只是把effective_caller_id_number写好同时保证 bridge 前没有别的模块改写它。如果网关走 SMPP 或私有协议对接这个工作就更多取决于网关设备FreeSWITCH 只是把该传的字段传到。5.4 内部呼入正常外部呼入却只能听到回铃没有声音现象从 SIP 话机注册到 internal profile 后互拨正常但外部 PSTN 呼入到外呼落地分机后能接通双方向没有任何声音。原因外部 profile 和内部 profile 用了不同的 RTP 端口区间或者 NAT 穿透没有配置。FreeSWITCH 默认 RTP 端口区间写在switch.conf.xml里如果 external profile 的rtp-ip没绑对媒体流会发到错误地址。解决确认 external profile 的rtp-ip和sip-ip指向同一个本机 IP并在switch.conf.xml里检查rtp-start-port与rtp-end-port确保防火墙放行了整个区间。NAT 环境下需要开ext-rtp-ip和ext-sip-ip否则媒体流地址是内网 IP对端回包找不到路。5.5 拨打总机号码却进了语音信箱现象呼入路由明明写的是 IVR 播放实际却直接进了某个分机语音信箱日志里能看到拨号计划匹配到了 voicemail 相关 extension。原因dialplan 的 extension 匹配是按顺序进行的如果前面有一个匹配范围更大的 extension 先命中了后面的 IVR 规则根本没机会执行。解决把精确匹配的 extension 放在前面通配或兜底规则放最后。比如^6000$要比^6\d{3}$更靠前否则 6000 会被后面的范围匹配先吃掉。排查时用第 3 章的 log 打印当前命中的 extension name能立刻看出来是哪条规则截胡。6. 用控制台和日志验证一套呼入呼出从拨号到挂断的完整检查习惯配置完成后不要直接连接生产网关先在测试环境走一遍完整的呼入呼出验证。我的固定流程分三步确认 profile 状态、观察呼叫日志、核对 CDR 输出。第一步确认 sofia profile 和网关状态sofia status sofia profile external status sofia gateway status gsm_gateway正常状态下网关状态应该显示State: REGED或State: NOREG前者是注册模式后者是对等中继模式registerfalse的预期结果。如果注册模式显示 REGED说明账号认证通过了如果长时间停留在State: Error问题基本出在账号密码或 proxy 地址。第二步一边发起呼叫一边在 fs_cli 里开日志观察console log info呼入时重点看三行INVITE 到达的行会打印 Request-URI进入 dialplan 后能看到匹配到的 extension namebridge 执行后能看到通道 UUID 和目的网关地址。外呼时重点看网关侧返回的 SIP 响应码100 Trying后的180 Ringing表示网关已振铃483 Too Many Hops或503 Service Unavailable多半是网关链路问题而486 Busy Here是远端拒绝。这些响应码信息量远比 no route 这类模糊日志大。第三步挂断后查 CDR确认路由结果。V1.2.7 的 CDR 模块默认打开存放路径在log/下fs_cli -x show channels as json | head -20CDR 里能看到的字段比较有限重点关注destination_number、context、hangup_cause三项。hangup_cause是呼出排查的第一线索NORMAL_CLEARING表示正常挂断NO_ANSWER说明对端没接ORIGINATOR_CANCEL说明主叫先挂了INVALID_NUMBER_FORMAT则是号码清洗或正则的问题。整套配置从接线到验收我吃过最大的亏是在没有抓sofia profile external的 context 是否匹配的情况下猛改 dialplan。从那以后我每次新增呼入或外呼路由都会强制自己先在 profile 上确认 context 名再用 console log 走一遍真实呼叫最后核对 CDR 的 hangup_cause 才敢交给业务侧接入。这套流程虽然慢但能挡住九成以上的低级错误。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑