这里写自定义目录标题


一、 Freeswtich介绍以及各模块介绍

freeswitch上面正常挂断是什么 freeswitch 拨号计划_lua

二、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。

freeswitch上面正常挂断是什么 freeswitch 拨号计划_ci_02

接下来我们打开一个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了

freeswitch上面正常挂断是什么 freeswitch 拨号计划_bc_03

配置方式:
例如freeswtich安装在/usr/local/,那profile路径就在/usr/local/freeswitch/conf/sip_profiles,系统默认有两个profile,分别是external
和internal,最常用的是external。

接下来我们打开一个profile看下,

freeswitch上面正常挂断是什么 freeswitch 拨号计划_bc_04

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