freeswithc “Auto Changing audio port from” 原理解析
整体环境
在对接外部运营商的落地网关的时候,流程图如下,core区的机器无法连接到外网,需要在外网区域增加一台转发服务器fs,来达到内网和外部手机的通信
dmz区IP:100.69.208.59
core区IP:100.69.216.126
对接所做配置文件修改
呼出的配置
- core区修改dialplan/default.xml ,添加如下,转接到dmz区的服务器上
<extension name="out-dmz">
<condition field="destination_number" expression="^0(.*)$">
<action application="bridge" data="sofia/external/sip:$1@100.69.208.59:5060"/>
</condition>
</extension>
- dmz区的external统一由dialplan/public/00_inbound_did.xml 来处理,添加 如下代码,转接到IMS网关上
<extension name="test-to-ims">
<condition field="destination_number" expression="^10(.*)$">
<action application="set" data="domain_name=$${domain}"/>
<action application="bridge" data="sofia/gateway/ims/99$1"/>
</condition>
</extension>
- 增加了 IMS网关 增加sip_profiles/external/gateway.xml 文件,如下配置 ;
<include>
<gateway name="ims">
<param name="username" value="075533614xxx"/>
<param name="password" value="none"/>
<param name="proxy" value="122.13.xx.xx:5060"/>
<param name="register" value="false"/>
</gateway>
</include>
- 由于在呼出的时候invite 中的sdp会替换成dmz区的内网IP,所以需要在internal.xml中修改ext-rtp-ip为映射的外网IP如:112.xxx.xxx.xxx ;否者会出现呼叫能通但是没有语音
呼入的配置
- public下的xml 增加外部呼入的规则,如下我写定转接到core区的1000,也可以做一个IVR分机拨号的功能;
<extension name="test-to-core">
<condition field="destination_number" expression="^(07553361xxxx)$">
<action application="set" data="domain_name=$${domain}"/>
<action application="bridge" data="sofia/external/sip:1000@100.69.216.126:5060"/>
</condition>
</extension>
- core区的public下的xml增加1000的拨号规则,转到internal的1000上
<extension name="public_test">
<condition field="destination_number" expression="^(10[01][0-9])$">
<action application="transfer" data="$1 XML default"/>
</condition>
</extension>
3. 由于在呼入的时候,回复invite 的包中的sdp会替换成dmz区的内网IP,所以需要在external.xml中修改ext-rtp-ip为映射的外网IP如:112.xxx.xxx.xxx ;否者会出现入能通但是没有语音
疑问点1:
呼出的时候dmz的internal.xml修改了回复invite中的sdp的IP信息为外网IP,按理说应该core区访问不了外网IP的。
解答:
在日志中看到如下日志,core区的freesiwtch会把dmz区的rtp-ip从外网112.95.xx.xx自动changing 到dmz内网IP:100.69.208.59,因为core区给126-》dmz,dmz会给126发送RTP包做一个auto changing port用
[INFO] switch_rtp.c:7497 Auto Changing audio port from 112.95.xxx.xxx:20604 to 100.69.208.59:20604
原理:
freeswitch如下图
麻烦:当B处于NAT后,A的RTP流从freeswitch是不能到B的(因为B为内网的IP),而且交换信令的时候,不可能给出NAT后的B的RPT IP和端口
解决:前期freeswitch的RTP-IP给到B,B会给FS发rtp流,以便FS能知道B的真实NAT后的IP和端口(这也是auto changing port的原理),freeswitch会监听UDP的 IP和端口以便接受B发送过来的RTP流
rtp_common_read 代码中有设置switch_rtp_set_remote_address 设置RTP远程地址的操作
if (bytes && rtp_session->flags[SWITCH_RTP_FLAG_AUTOADJ] && switch_sockaddr_get_port(rtp_session->rtp_from_addr)) {
if (!switch_cmp_addr(rtp_session->rtp_from_addr, rtp_session->remote_addr)) {
if (++rtp_session->autoadj_tally >= rtp_session->autoadj_threshold) {
const char *err;
uint32_t old = rtp_session->remote_port;
const char *tx_host;
const char *old_host;
char bufa[50], bufb[50];
char adj_port[6];
tx_host = switch_get_addr(bufa, sizeof(bufa), rtp_session->rtp_from_addr);
old_host = switch_get_addr(bufb, sizeof(bufb), rtp_session->remote_addr);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_INFO,
"Auto Changing %s port from %s:%u to %s:%u\n", rtp_type(rtp_session), old_host, old, tx_host,
switch_sockaddr_get_port(rtp_session->rtp_from_addr));
rtp_session->auto_adj_used = 1;
switch_rtp_set_remote_address(rtp_session, tx_host, switch_sockaddr_get_port(rtp_session->rtp_from_addr), 0, SWITCH_FALSE, &err);
疑问点2:
ext-sip-ip 设置成外网IP后,sip信令将使用外网IP来通信,导致core和dmz区不能正常sip交互