少量呼出,不在本文讨论之列
如果是我来实现批量呼出,那么可能是这样:
先建一张数据库的表,字段有:
id 自增加,主键
caller varchar 主叫号码
called varchar 被叫号码
service varchar 业务相关字段
uuid varchar channel-uuid,如果为空,那么调用 fs_cli -x 'create_uuid'
done int 是否已完成
然后起一个 taskloop.lua 进行处理:
每秒处理一次
调用 status 查看
如果当前 channels 数超过某个阈值,则退出
如果当前 sps 超过某个阈值,则退出
调用 fsapi 呼出,并写回数据库的表
回头给出 taskloop.lua 的具体内容
讨论另外一个问题:
fs --- 语音网关 --- 运营商
运营商说,语音网关发送 INVITE,每个源端口有 30 sps 的限制,比如:
语音网关 5060 --- 运营商
语音网关 5062 --- 运营商
语音网关 5064 --- 运营商
语音网关 5066 --- 运营商
如上图所示,这样就能做到 120 sps
那么要怎样配置呢?
非常简单呀!
比如在 fs 起多个 SIP Profile:
<profile name="external0">
<gateways>
<X-PRE-PROCESS cmd="include" data="gw/wgw1.xml"/>
</gateways>
<param name="rtp-ip" value="$${local_ip_v4}"/>
<param name="sip-ip" value="$${local_ip_v4}"/>
<param name="sip-port" value="5060"/>
...
</profile>
<profile name="external1">
<gateways>
<X-PRE-PROCESS cmd="include" data="gw/gw2.xml"/>
</gateways>
<param name="rtp-ip" value="$${local_ip_v4}"/>
<param name="sip-ip" value="$${local_ip_v4}"/>
<param name="sip-port" value="5062"/>
...
</profile>
<profile name="external2">
<gateways>
<X-PRE-PROCESS cmd="include" data="gw/gw3.xml"/>
</gateways>
<param name="rtp-ip" value="$${local_ip_v4}"/>
<param name="sip-ip" value="$${local_ip_v4}"/>
<param name="sip-port" value="5064"/>
...
</profile>
<profile name="external3">
<gateways>
<X-PRE-PROCESS cmd="include" data="gw/gw4.xml"/>
</gateways>
<param name="rtp-ip" value="$${local_ip_v4}"/>
<param name="sip-ip" value="$${local_ip_v4}"/>
<param name="sip-port" value="5066"/>
...
</profile>
4 个 SIP Profile,其中每个 Profile 对应一个网关,所有的这些网关都指向同一个语音网关
接着就是 distributor 的配置,非常简单:
<configuration name="distributor.conf" description="Distributor Configuration">
<lists>
<list name="testdist">
<node name="gw1" weight="1"/>
<node name="gw2" weight="1"/>
<node name="gw3" weight="1"/>
<node name="gw4" weight="1"/>
</list>
</lists>
</configuration>
最后是拨号字符串的配置
以前这样写:
originate sofia/gateway/gwxx/1234567 &echo
现在调整为:
originate sofia/gateway/${distributor(testdist)}/1234567 &echo
除了用 fs mod_distributor 之外是否还有别的办法呢?
换我上的话我肯定用 Kamailio,控制起来比较方便
建表(PostgreSQL):
CREATE TABLE dialtasks (
id SERIAL PRIMARY KEY NOT NULL,
uuid VARCHAR DEFAULT '',
caller VARCHAR NOT NULL,
called VARCHAR NOT NULL,
service VARCHAR NOT NULL,
done INTEGER DEFAULT 0
);
插入测试数据:
insert into dialtasks(caller, called, service) values ('1234567', '777777', 'foo');
taskloop.lua 的内容可以是:
local dsn = "odbc://freeswitch"
-- local dsn = "pgsql://hostaddr=127.0.0.1 port=5432 dbname=freeswitch user=freeswitch password='****'"
local json = freeswitch.JSON()
local api = freeswitch.API()
local dbh = freeswitch.Dbh(dsn)
local config = {}
-- 根据具体情况进行修改
config.limit = 10
config.sps = 30
config.maxchannels = 1000
config.gw = "gw1" -- 或者用 distributor
function debug(s)
freeswitch.consoleLog("ERR", (s or "nil") .. "\n")
end
function serialize(o)
local s = ""
if type(o) == "number" then
s = s .. o
elseif type(o) == "string" then
s = s .. string.format("%q", o)
elseif type(o) == "table" then
s = s .. "{\n"
local len = #o
for k, v in pairs(o) do
if(type(k) ~= "number" or (type(k) == "number" and k > len)) then
s = s .. ' ' .. k .. ' = '
end
s = s .. serialize(v)
s = s .. ",\n"
end
s = s .. "}"
elseif type(o) == "boolean" then
if o then
s = s .. "true"
else
s = s .. "false"
end
else
s = s .. " [" .. type(o) .. "]"
end
return s
end
function get_rows(sql)
local rows = {}
assert (dbh:query(sql, function(row)
table.insert(rows, row)
end))
return rows
end
local rows = get_rows("select * from dialtasks where done = 0" .. " limit " .. config.limit)
debug(serialize(rows))
for i = 1, #rows do
local row = rows[i]
local status = json:execute({ command = "status", data = {} })
if status.sessions.count.active >= config.maxchannels then break end
if status.sessions.rate.current >= config.sps then break end
local id = tonumber(row.id)
local uuid = row.uuid
local caller = row.caller
local called = row.called
local service = row.service -- 暂时不用
if uuid == "" then
uuid = api:execute("create_uuid")
debug("uuid = " .. uuid)
end
local cmd = string.format("[origination_uuid=%s][origination_caller_id_number=%s]originate sofia/gateway/%s/%s &park", uuid, caller, called, config.gw)
debug(cmd)
-- api:execute(cmd)
local sql = string.format("update dialtasks set done = 1, uuid = '%s' where id = %d", uuid, id)
debug(sql)
-- dbh:query(sql)
end