此篇文章记录我学习freeswitch中lua脚本,从官网搬运api并且补充官网没有给出的解释。
一、常用与session有关的函数
·getVariable。取得通道变量的值,如:
local moh = session:getVariable("hold_music")
local dest_number = session:getVariable("context")
local dest_number = session:getVariable("destination_number")
local cid_name = session:getVariable("caller_id_name")
local cid_number = session:getVariable("caller_id_number")
local ani = session:getVariable("ani")
local uuid = session:getVariable("uuid")
·getUUID。取得当前Session的UUID,下列两行是等价的:
local uuid = session:get_uuid();
local uuid = session:getVariable("uuid")
·setVariable。设置通道变量,等价于Dialplan App里的set:
session:setVariable("varname", "varval")
·hangup。挂断当前通话:
session:hangup();
--也可以同时指定挂断原因,如以下函数将在挂断时向对方返回用户忙:
session:hangup("USER_BUSY")
·session:hangupCause 您可以找到接通的电话的挂机原因和/或发起的电话未完成的原因。
-- 发起外呼
obSession = freeswitch.Session("sofia/192.168.0.4/1002")
-- Check to see if the call was answered
if obSession:ready() then
-- Do something good here
else -- This means the call was not answered ... Check for the reason
local obCause = obSession:hangupCause()
freeswitch.consoleLog("info", "obSession:hangupCause() = " .. obCause )
if ( obCause == "USER_BUSY" ) then -- SIP 486
-- For BUSY you may reschedule the call for later
elseif ( obCause == "NO_ANSWER" ) then
-- Call them back in an hour
elseif ( obCause == "ORIGINATOR_CANCEL" ) then -- SIP 487
-- May need to check for network congestion or problems
else
-- Log these issues
end
end
·ready。检查Session是否可正常使用,如果已经挂机就会返回false。在写脚本时,如果有循环,一定需要经常检测session:ready()是否为true,否则Session挂机后Lua脚本可能仍然在死循环地运行。
while (session:ready() == true) do
-- do something here
end
·streamFile:放音,相当于Dialplan App里的playback。
session:streamFile("/tmp/test.wav")
--也可以通过session:execute()函数来执行相关的App,
--如
session:execute("playback","/tmp/sound.wav")
与
session:streamFile("/tmp/sound.wav")
是等价的
·recordFile:录音,相当于Dialplan App里的record,参数是:file_name [,max_len_secs] [,silence_threshold] [,silence_secs]
其中,各参数含义如下:
·file_name:录音文件名。
·max_len_secs:录音最长的秒数。
·silence_threashold:一个声音阈值,如果声音小于该值,就认为是静音。
·silence_secs:如果静音时长大于一定秒数,则停止录音。
例如,以下函数将对当前的Channel录音,并存放到/tmp/test_record.wav中:
session:recordFile("/tmp/test_record.wav")
·read。类似于Dialplan App中的read,用于播放一个声音并获取DTMF。它的5个参数与read含义相同:
digits = session:read(15, 18, "/tmp/input-id-card.wav", "5000", "#");
session:("log", "INFO ID Card Number: ".. digits .."\n");
读者可以发现Lua中的read比Dialplan App中的read少了一个参数。由于session:read()能返回值,因此那个参数就不需要了,实际收到的DTMF会返回到本例的digits变量中。
·playAndGetDigits。与Dialplan App中的play_and_get_digits类似,它的参数格式是:
其中,大部分参数都很直观,也跟play_and_get_digits中类似。其中timeout是收齐所有号的超时值,而digit_timeout是允许的两次按键之音的时间间隔最大值,最后transfer_on_failure指明如果失败后是否转到Dialplan中的一个Extension上去,它的格式应该是一个Dialplan三要素的格式串,如“failed XML dialplan”。
digits = session:playAndGetDigits(15, 18, 3, 10000, "#",
"/tmp/input-id-card.wav", "/tmp/invalid_num.wav",
"^\\d{15}|\\d{17}[0-9\\*]$")
session:execute("log", "INFO ID Card Number: ".. digits .."\n");
·setInputCallback。在放音或录音时,用户按下的DTMF可以用于触发一些功能。所以在这些状态下,Lua 支持如果收到DTMF等外部输入时,则调用相关的回调函数。setInputCallback的作用就是设置(安装)一个回调函数。
01 function onInputCBF(s, type, obj, arg)
02 if (type == "dtmf") then
03 freeswitch.consoleLog("INFO",
04 "Got DTMF: " .. obj.digit .. " Duration: " .. obj.duration .. "\\n")
05 if (obj.digit == "3") then
06 return 'break'
07 end
08 end
09 return ''
10 end
11 session:setInputCallback('onInputCBF', '');
12 session:streamFile("local_stream://moh");
其中,第1行,我们定义了一个回调函数onInputCBF,并在第11行使用setInput-Callback将该函数绑定到该 Session上。第12行执行streamFile实现一直不停地播放等待音乐。当用户按下话机上的键时,FreeSWITCH就会回 调上面指定的回调函数。下面我们来看一下该函数的内容。回调函数一共有4个参数,在这里我们只关注type和obj两个参数。在此,由于我们的回调函数是由DTMF触发的,因此这里的type值为“dtmf”。obj是一个Table,它的两个Key分别是digit和duration,分别表示DTMF的链值和时长。
上面的例子中第2行测试该回调是否是由DTMF引起,如果是,就打印相关DTMF信息。在第5行测试如果用户按 了3的话,就返回break。返回break会停止当前正在执行的App(在这里我们正在播放保持音乐),如果后面没有 其他脚本语句的话,Lua App就会退出。如果返回空值(空字符串,如第9行),则它什么也不做。
如果我们顺序按1、2、3,则上面例子在控制台上的输出结果如下:
[INFO] switch_cpp.cpp:1288 Got DTMF: 1
[INFO] switch_cpp.cpp:1288 Got DTMF: 2
[INFO] switch_cpp.cpp:1288 Got DTMF: 3
除DTMF外,回调还可能由其他的输入引起,如在进行语音识别的时候识别到相关关键词.
`session:say
播放预先录制的声音文件,包括数字,日期,货币等内容。请参阅拨号计划工具say中有关于say的app信息。
参数:
session:say("12345", "en", "number", "pronounced");
其中:常用参数
session:say("9999", "zh", "number", "pronounced"); --zh 表示中文语音包,en表示英文语音包
session:say("192.168.52.35", "zh", "ip_address", "iterated"); -- number表示读数字,ip_address表示ip地址,name_spelled表示读文字
session:say("AAABBB", "zh", "name_spelled", "iterated"); -- pronounced表示读计数量,比如99读成九十九,iterated表示逐字读,99就成九九
二、非session函数和独立的Lua脚本
Lua脚本中也可以使用跟Session不相关的函数,最典型的是freeswitch.consoleLog(),其用于输出日志,如
freeswitch.consoleLog("NOTICE", "Hello lua log!\n")
另外一个是freeswitch.API(),允许你在Lua中执行任意API,如:
api = freeswitch.API()
reply = api:execute("version", "")
freeswitch.consoleLog("INFO", "Got reply:\n\n" .. reply .. "\n")
上面Lua脚本可以直接在FreeSWITCH控制台上执行,如果将上述脚本保存到/tmp/a.lua中,则输出结果为:
freeswitch> lua /tmp/a.lua
2013-09-16 16:20:31.363305 [INFO] switch_cpp.cpp:1288 Got reply:
FreeSWITCH Version 1.5.6b+git~20130914T180606Z~60f5dec57e (git 60f5dec 2013-09-14 18:06:06Z)
除此之外,其他的非Session函数还有freeswitch.bridge()、freeswitch.email()等,在此就不多介绍了。非Session函数一般运行在独立的Lua脚本中。独立的Lua脚本可以直接在控制台终端上执行(使用luarun), 这种脚本大部分可用于执行一些非Session相关的功能(因为这里面没有Session)。读到这里读者已经了解到 了,Lua是一个App,而luarun是一个API。 我们刚刚讲到的a.lua就是一个典型的可独立运行的Lua脚本。独立运行的Lua脚本跟在Dialplan中用Lua App运行的不同,前者不会自动获得一个session对象(Table)。当然,独立运行的脚本也可以自行创建session对象。