一般情况下,SIP通话很少在同一个FreeSWITCH实例内部,大多会跨FreeSWITCH进行通话(或者走中继线路),下面我们来看看如何实现跨FreeSWITCH通话。

写在前面的话

本次实验涉及到了拨号计划的配置,为了避免原来默认的拨号计划干扰,建议将conf/dialplan下面的default.xmlpublic.xml备份,然后新建两个纯净的拨号计划。

本次实验中第二个FS使用的拨号计划如下:

  • default.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="utf-8"?>
<include>
<context name="default">

<extension name="Local_Extension">
<condition field="destination_number" expression="^(10d+)$">
<action application="bridge" data="user/$1"/>
</condition>
</extension>

<extension name="Local_Extension_1">
<condition field="destination_number" expression="^(21d+)$">
<action application="set" data="video_possible=false"/>
<action application="bridge" data="user/$1"/>
</condition>
</extension>

</context>
</include>
  • public.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<include>
<context name="public">

<extension name="unloop">
<condition field="${unroll_loops}" expression="^true$"/>
<condition field="${sip_looped_call}" expression="^true$">
<action application="deflect" data="${destination_number}"/>
</condition>
</extension>
<!--
Tag anything pass thru here as an outside_call so you can make sure not
to create any routing loops based on the conditions that it came from
the outside of the switch.
-->
<X-PRE-PROCESS cmd="include" data="public/*.xml"/>

<extension name="call_debug" continue="true">
<condition field="${call_debug}" expression="^true$" break="never">
<action application="info"/>
</condition>
</extension>

<extension name="public_extensions">
<condition field="destination_number" expression="^(10[01][0-9])$">
<action application="transfer" data="$1 XML default"/>
</condition>
</extension>

<extension name="public_extensions_1">
<condition field="destination_number" expression="^027(21d{3})$">
<action application="transfer" data="$1 XML default"/>
</condition>
</extension>

</context>
</include>

启动多个FreeSWITCH实例

FreeSWITCH是支持在同一台主机上启动多个实例的,如果希望启动多个实例,只需要复制一份原来FreeSWITCH的配置文件,修改一些端口即可。

复制配置文件

1
2
3
4
5
mkdir -p /usr/local/freeswitch2/
cp -R /usr/local/freeswitch/conf /usr/local/freeswitch2/
mkdir /usr/local/freeswitch2/log
mkdir /usr/local/freeswitch2/db
ln -sf /usr/local/freeswitch/sounds /usr/local/freeswitch2/sounds

建立软连接是为了确保新实例可以访问声音文件。

修改端口信息

  • 修改Event Socket端口
    编辑/usr/local/freeswitch2/conf/autoload_configs/event_socket.conf.xml ,将8021端口修改为28021端口。

    1
    <param name="listen-port" value="28021"/>
  • 修改RTP端口范围
    编辑/usr/local/freeswitch2/conf/autoload_configs/switch.conf.xml

    1
    2
    <param name="rtp-start-port" value="17000"/>
    <param name="rtp-end-port" value="20000"/>

    注意:多个FS之间的RTP端口不能重叠,否则可能打电话的时候可能会串线。

  • 修改SIP端口
    编辑/usr/local/freeswitch2/conf/vars.xml ,找到internal_sip_port, internal_tls_port, external_sip_port, external_tls_port,把后面的端口前面都加一个2(加2没有任何特殊意义,只是为了和第一个FS的端口进行区分)

启动第二个实例

使用如下命令启动第二个FS实例:

1
freeswitch -conf /usr/local/freeswitch2/conf/ -db /usr/local/freeswitch2/db -log /usr/local/freeswitch2/log -nc -nonat

登录控制台

1
fs_cli -P 28021

因为两个FS都是在同一台主机上,上面的命令省略了-H参数,默认的host就是当前机器。

截止到目前为止,第二个FS的实例已经启动完毕了,接下来在第二个实例中创建一些用户(就从21000开始吧,和第一个FS的用户区分开)。

跨FreeSWITCH的SIP呼叫

网关-注册模式

如果我们拥有另外一个FS的账号,那么我们就可以给另一个FS上的账户进行SIP通话了,这个FS的账号被称为SIP网关。要建立一个SIP网关,只需要在conf/sip_profiles/external 下新建一个xml文件即可,具体内容可以参考同级目录下的example.xml

我们新建的网关的配置文件如下:

1
2
3
4
5
<gateway name="gw-fs-2">
<param name="realm" value="192.168.3.211:25060"/>
<param name="username" value="21000"/>
<param name="password" value="112233"/>
</gateway>

在第一个FS的控制台,执行sofia profile external rescan即可刷新到新的网关配置,通过sofia status指令,可以查看新网关是否生效。

1
2
3
4
5
6
7
8
9
10
11
freeswitch@ubuntu> sofia status
Name Type DataState
=================================================================================================
external-ipv6profile sip:mod_sofia@[::1]:5080RUNNING (0)
192.168.1.111 alias internalALIASED
externalprofile sip:[email protected]:5080RUNNING (0)
external::gw-fs-2gateway sip:[email protected]:25060REGED
external::example.comgateway sip:[email protected]
internal-ipv6profile sip:mod_sofia@[::1]:5060RUNNING (0)
internalprofile sip:[email protected]:5060RUNNING (0)
=================================================================================================

如果发现网关处于REGED 状态,说明网关已经成功注册到了第二个FS上。

修改第二个FS的dialplan/public.xml,增加如下内容,然后在控制台刷新配置reloadxml

1
2
3
4
5
<extension name="public_extensions_1">
<condition field="destination_number" expression="^027(21d{3})$">
<action application="transfer" data="$1 XML default"/>
</condition>
</extension>

此时我们可以尝试使用命令接通两个FS,在第一个FS的控制台输入如下指令:

1
originate user/1001 &bridge(sofia/gateway/gw-fs-2/02721001)

如果不出意外的话,此时登录了1001账户的SIP电话会先响铃,接通之后,登录21001的SIP账户也会响铃,双方都接通之后,就可以进行通话了,任何一方挂断之后,整个通话就结束了。

需要说明的是,此时这两个账户是不能通过SIP电话直接进行通话的,因为第一个FS上没有配置相关的拨号计划,如果我们希望从SIP电话上进行测试,需要在第一个FS的conf/dialplan/default 目录下新建一个拨号计划,内容如下:

1
2
3
4
5
6
7
8
root@ubuntu:/usr/local/freeswitch/conf/dialplan/default# cat out-call-fs-2.xml
<include>
<extension name="default_user">
<condition field="destination_number" expression="^027(21d{3})$">
<action application="bridge" data="sofia/gateway/gw-fs-2/027$1"/>
</condition>
</extension>
</include>

拨号计划中的正则表达式为^027(21d{3})$ ,意思是匹配027开头的,然后是21开头的5位数字。027在这里被称为出局字冠(以前叫电话局,拨打外部电话叫出局)。

新建完毕拨号计划之后,需要在第一个FS上执行reloadxml命令,然后就可以在登录了1001账户的SIP电话上拨打第二个FS上的账户了,特别要注意的是,拨打21001的时候,需要在前面增加027,完整的被叫号码是02721001

需要注意的是<action application="bridge" data="sofia/gateway/gw-fs-2/027$1"/> ,这里的027(027$1)是和第二个FS约定的被叫前缀改写(因为第二个FS的拨号计划要求了匹配027开头的内容,当然,这里的027也可以换成其他的内容,只要保持一致即可),和第一个FS的出局字冠没有关系,为什么需要改写被叫前缀呢,这个后面会讲到。

网关-非注册模式

上面我们使用了网关的注册模式完成了跨FS的电话拨打,这样对接的方式比较安全,但是需要知道另外的FS的账号和密码,对于第二个FS来讲,可能不是那么友好了(如果对接10个FS,岂不是要占用10个账户?)。因此,还有一种网关的对接方式,只需要知道对方的IP即可,通过IP来识别来源是否合法,这个功能就是ACL。

修改第二个FS的ACL控制列表(该文件在freeswitch2/conf/autoload_configs/acl.conf.xml),允许第一个FS所有服务器的IP访问,内容如下:

1
2
3
4
<list name="lan" default="allow">
<node type="allow" cidr="192.168.3.211/32"/>
</list>
<!-- 删除下面的deny的内容 -->

第一个FS所有的IP为192.168.3.211。

为了测试,可以删除第一个FS的网关配置文件中的用户和密码,修改之后的内容如下:

1
2
3
4
<gateway name="gw-fs-2">
<param name="realm" value="192.168.3.211:25060"/>
<param name="register" value="false"/>
</gateway>

重新刷新网关的配置文件,然后该网关的状态将会变成NOREG

1
2
3
4
5
6
7
8
9
10
11
12
13
14
freeswitch@localhost> sofia profile external rescan

freeswitch@localhost> sofia status
Name Type DataState
=================================================================================================
external-ipv6profile sip:mod_sofia@[::1]:5080RUNNING (0)
192.168.3.211 alias internalALIASED
externalprofile sip:[email protected]:5080RUNNING (0)
external::example.comgateway sip:[email protected]
external::gw-fs-2gateway sip:[email protected]:25060NOREG
internal-ipv6profile sip:mod_sofia@[::1]:5060RUNNING (0)
internalprofile sip:[email protected]:5060RUNNING (0)
=================================================================================================
4 profiles 1 alias

此时在第一个FS上,执行originate user/1004 &bridge(sofia/gateway/gw-fs-2/02721002)命令。

如果是按找本文档顺序执行的话,此时应该可以接通两个电话了,但是如果没有执行「网关-非注册模式」中的步骤,则会被第二个FS的拨号计划拦住,应为找不到拨号计划,处理起来也简单,新建相应的拨号计划即可,此处就不再赘述了。

SIP地址的方式拨打

通过网关的方式进行跨FS的电话拨打,无论是否注册,都需要新建网关配置文件,这样也不是特别方便,最简单的是直接通过第二个FS的IP地址发起跨FS的呼叫,当然,这个功能还是要配合ACL一起使用。

在第一个FS上执行如下命令:

1
originate user/1004 &bridge(sofia/external/sip:[email protected]:25060)

如果第二个FS的拨号计划没有问题的话,此时1004和21002的电话都响铃了。这个命令其实也好理解,首先呼叫1004,然后通过SIP地址去呼叫sip:[email protected]:25060,接通之后,双方做一个桥接即可。

因为21002用户已经注册到了第二个FS上,所以FS2可以找到21002的真实地址,假如我们知道了21002的真实地址,我们也可以直接呼叫这个地址即可。

在第二个FS上执行如下命令可以查看地址:

1
2
freeswitch@localhost> sofia_contact 21002
sofia/internal/sip:[email protected]:1024;line=3787deb8b96f5b8

找到21002的真实SIP地址后,可以直接在第一个FS上呼叫它:

1
originate user/1004 &bridge(sofia/internal/sip:[email protected]:1024)

直接呼叫用户所在的真实SIP地址,既FS1直接呼叫21001的SIP话机,这里不经过FS2的。