这里写自定义目录标题
一、 Freeswtich介绍以及各模块介绍
二、Freeswtich常用的配置
1、dialplan
介绍:
在freeswitch中比较重要的一个部分就是diaplan了,diaplan拨号计划简单的来说就是一种号码规则(类似于就是一个路由表,可以理解成 Spring Cloud Gateway中的路由配置,匹配到对应的路由,执行下一步操作),他可以根据自己定义的规则,设置对应did(目标号码)或者设置匹配的规则,每一步如何实现,都在这里设置实现的。
拨号计划由多个context(多xml配置文件)组成,每个context中有多个extension(多个路由,或者说多个匹配规则)。所以context就是多个extension的逻辑集合,它相当于一个分组。一个context的extension和其他context中的extension在逻辑上是隔离的。
配置方式:
例如freeswtich安装在/usr/local/,那dialplan路径就在/usr/local/freeswitch/conf/dialplan,系统默认有两个拨号计划配置文件,分别是public
和default,最常用的是public。
接下来我们打开一个public看下格式,
<include> <!—固定格式标签-->
<context name="public"> <!—dialplan名称 -->
<extension name="test"> <!—单个拨号计划、路由名称 -->
<!—匹配规则,该规则说明所有被叫号码(destination_number)都可以匹配到 –
condition field表示你需要匹配的信息是取什么参数进行匹配,expressio:写正则表达式>
<condition field="destination_number" expression="^(.*)$">
<!—匹配完成后,执行lua脚本 -->
<!—action #执行具体的APP或者API动作,一个action通常有两个属性,一个是application代表要执行的APP、另一个是data就是 #APP的参数,当APP没有参数时,data也可以省略--> <action application="lua" data="95_cu,stomer.lua"/>
</condition>
</extension>
</context>
</include>
注:一些参考例子
① 匹配主叫规则
<extension name="test">
<condition field="caller_id_number" expression="^(.*)$">
<action application="answer"/>
</condition>
</extension>
② 匹配被叫规则
<extension name="test">
<condition field="destination_number" expression="^(.*)$">
<action application="answer"/>
</condition>
</extension>
③ 匹配对端ip
<extension name="test">
<condition field="network_addr" expression="^(127.0.0.1)$">
<action application="answer"/>
</condition>
</extension>
④匹配主被叫和对端ip
<extension name="test">
<condition field="network_addr" expression="^(127.0.0.1)$" />
<condition field="caller_id_number" expression="^(18649760218)$"/>
<condition field="destination_number" expression="^(01086469999)$">
<action application="answer"/>
</condition>
</extension>
⑤一些常用的action
(1)播放欢迎音
<action application="playback" data="/tmp/test.wav"/>
(2)通用录音
<action application="record_session" data="/home/${uuid}.wav"/>
(3)通话接通
(4)桥接通话
1)、直接用ip端口外呼
<action application="bridge" data="sofia/external/${destination_number}@172.16.246.38:5080"/>
2)、使用gateway方式呼叫, gatewayName是动态的,在profile里配置的网关
3)、使用轮训组方式呼叫,使用xhsbc这个轮训组,profile为xhsbc
<action application="bridge" data="sofia/gateway/${distributor(xhsbc ${sofia(profile test gwlist down)})}/${destination_number}/>
(5)在通道中set一些需要用到的参数,将vccid为1007写入通道变量中,将msg为1007写入通道变量中
<action application="set" data="vccid=1007"/>
<action application="set" data="msg=1007"/>
freeswitch提供匹配的参数很多,以下三个是目前最经常用到的参数:
destination_number :被叫号码
caller_id_number:主叫号码
network_addr :对端ip地址
常用的dialplan APP
set #用于设置一个通道变量
<action application="set" data="my_var=123456"/>
info #打印全部的通道变量
<action application="info"/>
answer #用于应答一路呼叫,FreeSWITCH做被叫时,如果想给主叫放音,则必须应答后才可以,有些app(如conference或fifo)
#等会隐含应答,因而不需要明确的应答,但有些app(如playback和ivr等)不会隐含应答,因而需要明确的应答
<action application="answer"/>
bridge #负责桥接另一条腿(b-leg),它的参数是一个呼叫字符串,bridge操作是阻塞的,它会一直等到b-leg释放后才继续往下走
<action application="bridge" data="user/1000"/>
<action application="bridge" data="sofia/external/${destination_number}@172.16.246.38:5080"/>
sleep #设置可以等待/暂停的一段时间,单位默认为毫秒
playback用于给channel放音,它的参数是声音文件的路径
#播放多个文件,可以串联操作,如下
<action application="playback" data="/tmp/test1.wav"/>
<action application="playback" data="/tmp/test2.wav"/>
#或者通过file_string协议来串联,如下"!"是文件名的分隔符
#另外通过mod_shout模块,也可以支持本地或远程http或者shout cast服务器上的.mp3格式的文件,如下
<action application="playback" data="http://localhost/test1.wav"/>
<action application="playback" data="shout://localhost/test2.wav"/>
2、profile
介绍
简单的说就是在在freeswtich配置不同的ip和端口,每一个profile都拥有一个xml文件以及一个对应的文件夹,文件夹下存放的就是gateway了
配置方式:
例如freeswtich安装在/usr/local/,那profile路径就在/usr/local/freeswitch/conf/sip_profiles,系统默认有两个profile,分别是external
和internal,最常用的是external。
接下来我们打开一个profile看下,
3、gateway
介绍
,FreeSWITCH里Gateway(网关)的概念。网关又成协议转换器,通常都是进行协议转换。这里说的网关指的是语音网关,如常用的SIP网关,负责SIP协议和七号信令或ISDN PRI(模拟信号)之间的转换。但FreeSWITCH中的网关有时候不一定是真的网关,也可以是另外一个SIP Server(如另一个FreeSWITCH, Asterisk等)。但最终会有一个设备或系统,将SIP转换成模拟信号。简化一下过程,我们认为FreeSWITCH送到的就是真的网关。
配置方式
例如freeswtich安装在/usr/local/,那gateway路径就在/usr/local/freeswitch/conf/sip_profiles/{profile},我们用xhsbc这个profile来举例
对接的网关大致分2种,一种网关为注册式网关,一种为非注册式网关,,一下讲的是非注册方式
<include> <!—固定格式标签-->
<gateway name="yzxhsbc01"> <!—gateway名称-->
<!—对端ip端口-->
<param name="realm" value="172.16.246.38:5080"/>
<!—默认udp -->
<param name="register-transport" value="udp"/>
<!—内部使用不需要填写账号 -->
<param name="username" value=""/>
<!—内部使用不需要填写密码 -->
<param name="password" value=""/>
<!—发送心跳的间隔时间,单位为ms-->
<param name="ping" value="10" />
<!—发送心疼最大次数-->
<param name="ping-max" value="3"/>
<!—发送心疼最小次数-->
<param name="ping-min" value="1"/>
<!—指定在SIP消息中的源用户信息,一般写该服务器内网地址-->
<param name="from-domain" value="172.16.246.40"/>
<!--仅对注册式有效,注册的有效时间,达到了这个时间后,会重新对中继进行注册-->
<param name="expire-seconds" value="3600"/>
<!--顾名思义,是否使用from头域中的主叫信息,默认是false的,如果设置后,就可以使用from头域里的主叫信息了-->
<param name="caller-id-in-from" value="false"/>
<param name="register" value="false"/>
</gateway>
</include>
4、distributor.conf
介绍
网关轮询模块,我们一般叫他dis组,
修改代码根目录中 /usr/local/freeswitch/conf/modules.conf,将applications/mod_distributor注释打开,然后执行mod_distributor && make mod_distributor-install,最后生成mod_distributor.so
配置方式:
例如freeswtich安装在/usr/local/,那profile路径就在/usr/local/freeswitch/conf/ distributor.conf.xml
<configuration name="distributor.conf" description="Distributor Configuration">
<lists><!—固定格式标签-->
<list name="iccpsn"><!—distributor名称 -->
<node name="iccpsn01" weight="1"/> <!—配置的网关名称 ,weight :表示权重,配置0,标识屏蔽该节点,-->
<node name="iccpsn02" weight="1"/>
</list>
</lists>
</configuration>
在配置中,list 就是一个distributor组,node填写的是gateway的名称,weight填写的是这个组的轮询权重,distributor组不和普通的负载机制一样,他会根据保持的session数进行负载,如果有设置权重的话,他会将按照这个权重对session进行定量的负载,避免出现长短电话而导致的服务器负载不均产生。
5、amqp模块
Freeswtich支持将通话事件推送到rabbitmq上,目前在用是rabbitmq的fanout,其他模式应该也是支持
例如freeswtich安装在/usr/local/,那profile路径就在/usr/local/freeswitch/conf/ amqp.xml
<configuration name="amqp.conf" description="mod_amqp">
<producers>
<profile name="default">
<connections>
<connection name="primary">
<!—mq设备ip-->
<param name="hostname" value="172.16.246.45"/>
<!—virtualhost"->
<param name="virtualhost" value="fsbc"/>
<!—连接mq账号"->
<param name="username" value="fsbc"/>
<!—连接mq密码"->
<param name="password" value="fsbc_0591_..."/>
<!—连接mq端口,一般是5672"->
<param name="port" value="5672"/>
<param name="heartbeat" value="0"/>
</connection>
</connections>
<params>
<!—交换机名称"->
<param name="exchange-name" value="iccp_cdr_exchanges"/>
<!—交换机类型"->
<param name="exchange-type" value="fanout"/>
<param name="reconnect_interval_ms" value="1000"/>
<param name="send_queue_size" value="88888"/>
<param name="enable_fallback_format_fields" value="1"/>
<param name="format_fields" value="FreeSWITCH-Hostname,Event-Name,Event-Subclass,Unique-ID"/>
<!—freeswtich挂机事件"->
<param name="event_filter" value="SWITCH_EVENT_CHANNEL_DESTROY"/>
</params>
</profile>
</producers>
</configuration>
6、lua在freeswtich使用
1、首先是在拨号计划中配置好需要调用的lua脚本
<extension name="test">
<condition field="destination_number" expression="^(.*)$">
<!—匹配完成后,执行lua脚本 -->
<action application="lua" data="test.lua 22"/>
</condition>
</extension>
2、在脚本中进行业务逻辑处理
输出日志
local test = "test";
--输出info日志
freeswitch.consoleLog("INFO", test);
--输出error日志
freeswitch.consoleLog("err", test);
--输出debug日志
freeswitch.consoleLog("debug", test);
获取通道中的变量
-- 获取通道变量中的主叫
local callerNumber=session:getVariable("caller_id_number");
-- 获取通道变量中的被叫
local calledNumber=session:getVariable("destination_number");
-- 获取通道变量中的uuid,每通通话都是唯一的
local uuid=session:getVariable("uuid");
--注:获取通道中的变量方式session:getVariable("{变量}");
脚本接收外部传入参数
--传入第一个参数
local argv1 = argv[1];
--传入第二个参数
local argv2 = argv[2];
--...
--注:传入的参数不能为空,为空下一个参数会填充
脚本简单的一些set操作
--将通话接听
session:answer();
--播放ivr音
session:execute("playback", "/home/test.wav");
--将vccid为1007set到通道变量中
session:execute("set", "vccid=1007");
--通话录音
session:execute("record_session", "/home/record.wav")
进行外呼操作
--定义参数
local called="18649760218"
(1)第一种方式
--呼叫18649760218号码,简单的用ip端口外呼方式,lua脚本拼接参数是用..
session:execute("bridge", "sofia/external/"..called.."@172.16.246.38:5080")
--使用13000000000为主叫进行外呼
session:execute("bridge", "{origination_caller_id_number=13000000000}sofia/external/"..called.."@172.16.246.38:5080")
--呼叫18649760218号码,使用gateway方式呼叫, gatewayName是动态的,在profile里配置的网关
session:execute("bridge", "sofia/gateway/{gatewayName}/"..called.."")
--使用13000000000为主叫进行外呼
session:execute("bridge", "{origination_caller_id_number=13000000000}sofia/gateway/{gatewayName}/"..called.."")
--呼叫18649760218号码,使用轮训组方式呼叫,使用xhsbc这个轮训组,profile为xhsbc
session:execute("bridge", "sofia/gateway/${distributor(xhsbc ${sofia(profile test gwlist down)})}/"..called.."")
--使用13000000000为主叫进行外呼
session:execute("bridge", "{origination_caller_id_number=13000000000}sofia/gateway/${distributor(xhsbc ${sofia(profile test gwlist down)})}/"..called.."")
(2)第二种方式,将呼叫命令提取出来,单独定义
local command="{origination_caller_id_number=13000000000}sofia/external/"..called.."@172.16.246.38:5080";
session:execute("bridge", command)
(3)第三种方式,将呼叫命令提取出来,单独定义,并且拆分多个内容
local ostrs = {};
ostrs[1] = "{maxDuration=3600,origination_caller_id_number=13000000000";
ostrs[2] = ",vccid=1007";
ostrs[3] = ",servicekey=1007";
ostrs[4] = "}";
ostrs[5]="sofia/external/"..called.."@172.16.246.38:5080";
--将上述所有指令进行整合
ostr0 = table.concat(ostrs);
--最后是这样的
ostr0="{maxDuration=3600,origination_caller_id_number=13000000000,vccid=1007,servicekey=1007}sofia/external/"..called.."@172.16.246.38:5080";
--最后进行外呼操作
session:execute("bridge", ostr0)
调用另一个脚本使用bgapi命令
local str1="str1";
local str2="str2";
--注意:传入的参数,两个参数之间要空格
commad = "bgapi lua test.lua "..str1.." "..str2.."";
api:executeString(commad);
使用uuid方式进行放音
api = freeswitch.API();
-- 获取通道变量中的uuid,每通通话都是唯一的
local uuid=session:getVariable("uuid");
local callCaller = "uuid_broadcast " .. uuid .. " /home/test.wav";
api:executeString(callCaller);
将某些操作封装成方法
function playback()
session:execute("playback", "/home/test.wav");
end
--执行这个方法
playback();
--判断文件是否存在
function exists(recordHintTone)
local path="/usr/local/freeswitch/sounds/en/us/callie/";
local exists=loadConfig(path..recordHintTone);
if exists then
return "true";
else
return "false";
end
end
--执行这个方法
local exists=exists("test.wav");
lua脚本get请求url
(1)没有返回值
require "curl"
--请求完整路径(包含请求参数)
local requestUrl = "http://172.16.251.71:8091/forward/eventInfo?vccid=1007";
c:setopt(curl.OPT_URL, requestUrl)
c:perform()
freeswitch.consoleLog("INFO", record_id.."|"..callStatus.."|状态推送成功\n");
(2)有返回值,返回json字符串
require "curl"
local cjson = require "cjson"
c = curl.easy_init()
--主函数
function main()
requestUrl="http://172.16.251.71:8091/forward/eventInfo?vccid=1007";
freeswitch.consoleLog("INFO", "请求url|"..requestUrl.."\n")
c:setopt(curl.OPT_URL, requestUrl)
c:setopt(curl.OPT_WRITEFUNCTION, function(buffer)
freeswitch.consoleLog("info", "打印日志: "..buffer.."\r\n");
--将字符转转换成json
result = cjson.decode(buffer);
--获取code参数
local code= result["code"];
return #buffer
end)
c:perform()
end