公司业务用到对讲系统,采用FreeSWITCH自己搭对讲服务器。原本有一台对讲服务器部署在华为云,因为价格贵及经常受攻击的原因,要迁移到阿里云服务器。于是,运维人员在阿里云服务器部署一个FreeSWITCH,版本比原FreeSWITCH新,配置基本复制原FreeSWITCH。
阿里云FreeSWITCH部署好后,我们发现局域网内2台对讲机可以相互呼通并通话,公网2台对讲机(比如一个在公司电脑的MicroSIP走公司外网、一个自己手机zoiper走运营商4G)可以相互呼叫,但接通后没有声音。华为云FreeSWITCH这2种情况都正常。
SIP 会话初始协议。SIP是负责建立和关闭会话的协议。SIP就类似建一条高速公路,只负责建路,路上跑什么不负责。
SDP 会话描述协议。放在SIP的body中,和SIP配合使用。用于媒体协商。类似说明公路上跑什么车。
RTP 实时传输协议。在SIP和SDP协商后,媒体数据通过RTP传输。类似公路上跑的车,而媒体数据就是货物。
STUN服务——即SIP终端先向STUN服务获取自己的外网IP和端口,再与FreeSWITCH通讯。
ICE——综合利用STUN和TURN(详细待研究)。
配置sip_profiles/internal.xml
<param name="apply-nat-acl" value="nat.auto"/>
nat.auto是一个IP列表,里面包含RFC1918规定的私网地址,且去掉本地网络地址。
这样,SIP终端在注册时,FreeSWITCH对比这个IP列表和concat地址判断终端是否在NAT后面,如果是,就把concat地址换成数据来源包的网络地址。
在fs_cli终端,命令sofia status profile internal reg 查看注册信息,contact会有nat及外网信息。
Concat:
SIP终端没有采取穿越方案情况下,SDP信息的IP地址会是SIP终端私网地址,RTP包无法发到这些私网地址,语音就不通。
FreeSWITCH有RTP自动调整功能。基本流程如下,
1、SIP协商阶段,FreeSWITCH返回SIP终端一个公网RTP地址。
2、SIP终端往上述公网RTP地址发送一个RTP包。
3、FreeSWITCH获取2步骤的RTP包来源地址作为SIP终端RTP通讯地址。
4、后续FreeSWITCH就通过上述地址给这个SIP终端发送RTP包。
为防止步骤2被黑客攻击把RTP包引到自己那里,FreeSWITCH只允许在电话开始时做一次调整。
RTP自动调整功能默认开始。可以通过sip_profiles/internal.xml配置关闭。
<param name="disable-rtp-auto-adjust" value="true"/>
也可以指定某些呼叫禁止,设置呼叫通道变量rtp_auto_adjust=false。
FreeSWITCH日志一般存储在/var/log/freeswitch目录。FreeSWITCH会话日志显示RTP自动调整操作,样例如下,
[INFO] switch_rtp.c:7268 Auto Changing audio port from 10.11.64.109:33888 to 223.104.64.162:38179
设置sip_profiles/internal.xml文件ext-sip-ip和ext-sip-ip为服务器外网IP或者autonat:外网IP
<param name="ext-sip-ip" value="1.1.1.1"/>
<param name="ext-sip-ip" value="1.1.1.1"/>
或
<param name="ext-sip-ip" value="autonat:1.1.1.1"/>
<param name="ext-sip-ip" value="autonat:1.1.1.1"/>
配置成autonat:1.1.1.1,sofia status profile internal显示Auto-NAT为true。
我们的情况是局域网有声音,公网无声音,应该是NAT问题。
能呼通,说明SIP穿越无问题,应该是RTP穿越问题。
我们的SIP终端没有采用任何穿越NAT方案,所以SDP包上的地址是私网地址,需要依赖FreeSWITCH服务器实现RTP穿越。
查看配置,disable-rtp-auto-adjust项设置是false,就是RTP自动调整功能是开启的。
查看无声音的会话日志,并没有RTP自动调整日志。难道还有其他参数影响?
通过fs_cli终端命令sofia status profile internal查看internal配置信息,对比2台FreeSWITCH配置信息,发现NOMEDIA项不同:
通话正常的NOMEDIA=false,通话无声音的NOMEDIA=true。
(如神来之笔?其实定位过程花了一天时间)
Freeswitch.org资料显示,NOMEDIA是由inbound-bypass-media参数控制,称为无媒体模式(no media mode)。说明如下,
无媒体模式是一个SDP传输控制参数,它允许2个终端可以直连它们的媒体会话,而FreeSWITCH只负责维护SIP相关操作。但它不能用于NA网络下的终端。
在终端有FreeSWITCH不支持的媒体编码协议或者想让FreeSWITCH高效处理SIP会话而不用关注RTP的应用场景下,可以考虑开启这个参数。
开启inbound-bypass-media这个参数,终端的RTP通讯就是终端之间点对点传输,不再经过FreeSWITCH,不会执行RTP自动调整操作。而在NAT网络下终端相互不知道对方的外网地址,无法正常传输RTP数据,所以语音不通。
注释掉sip_profiles/internal.xml中inbound-bypass-media配置
重启FreeSWITCH,问题解决。
fs_cli终端命令
查看profile配置 sofia status profile internal
查看注册用户 sofia status profile internal reg
重启 fsctl shutdown restart
直接服务器终端运行命令 fs_cli -x fs_cli终端命令
freeswitch日志找到某次呼叫起始位置(21161498是电话账号)
grep -n 21161498 freeswitch.log |grep switch_core_state_machine|grep CS_NEW|less
Bypass Media
FreeSWITCH配置手记