您的位置:首页 > 编程语言 > Lua

FreeSwitch LUA API ——Non-Session API

2016-07-12 16:33 721 查看
目录浏览:

Non-Session API
freeswitch.API
freeswitch.bridge
freeswitch.consoleCleanLog
freeswitch.consoleLog
freeswitch.Dbh
freeswitch.email
freeswitch.Event
freeswitch.EventConsumer
freeswitch.getGlobalVariable
freeswitch.IVRMenu
freeswitch.msleep
freeswitch.Session
stream:write
API commands
Web page interaction (via mod_xml_rpc)
Example: Call Control

Special Case: env object

freeswitch.API

api = freeswitch.API();
-- get current time in milliseconds
time = api:getTime()
当从拨号计划(dialplan)中调用LUA脚本后,将会得到一个session对象。然而LUA脚本也能在命令行界面(CLI)被调用。无论是那种情况下,在LUA中,当创建完一个API对象后,就可以执行API命令了。

api = freeswitch.API();
reply = api:executeString("version");
在以上的代码段中,LUA变量将会从FreeSWTICH中接收到版本号。

也可以做一些复杂的操作,例如:

api = freeswitch.API();
sofia = api:executeString("sofia status");
LUA变量sofia将包含sofia status命令的所有输出。

 

freeswitch.bridge

session1 = freeswitch.Session("sofia/internal/1001%192.168.1.1");
session2 = freeswitch.Session("sofia/internal/1002%192.168.1.1");
freeswitch.bridge(session1, session2);
 

freeswitch.consoleCleanLog

freeswitch.consoleCleanLog("This Rocks!!!\n");


 

freeswitch.consoleLog

向FreeSWITCH记录器记录一些数据,参数为log级别,消息

freeswitch.consoleLog("info",   "lua rocks\n");
freeswitch.consoleLog("notice", "lua rocks\n");
freeswitch.consoleLog("err",    "lua rocks\n");
freeswitch.consoleLog("debug",  "lua rocks\n");
freeswitch.consoleLog("warning","lua rocks\n");
 

freeswitch.Dbh

作用:从FreeSWITCH中获得一个ODBC或者sqlite句柄,并且可以在用该句柄执行SQL语句。

这种方法的优点是充分利用了由FreeSWITCH提供的连接池,即当创建的LUASQL env:connect()的TCP连接增加时,对于每个连接的速度不会有太大的影响。

工作流程如下:

local dbh = freeswitch.Dbh("dsn","user","pass") -- when using ODBC (deprecated)
-- OR --
local dbh = freeswitch.Dbh("core:my_db") -- when using sqlite (deprecated, if you have to use this to make it work you should upgrade your FS installation)
-- OR --
local dbh = freeswitch.Dbh("sqlite://my_db") -- sqlite database in subdirectory "db"
-- OR --
local dbh = freeswitch.Dbh("odbc://my_db:uname:passwd") -- connect to ODBC database

 
assert(dbh:connected()) -- exits the script if we didn't connect properly
 
dbh:test_reactive("SELECT * FROM my_table",
                  "DROP TABLE my_table",
                  "CREATE TABLE my_table (id INTEGER(8), name VARCHAR(255))")
 
dbh:query("INSERT INTO my_table VALUES(1, 'foo')") -- populate the table
dbh:query("INSERT INTO my_table VALUES(2, 'bar')") -- with some test data
 
dbh:query("SELECT id, name FROM my_table", function(row)
  stream:write(string.format("%5s : %s\n", row.id, row.name))
end)
 
dbh:query("UPDATE my_table SET name = 'changed'")
stream:write("Affected rows: " .. dbh:affected_rows() .. "\n")
 
dbh:release() -- optional
-freeswitch.Dbh(odbc://my_db:uname:passwd):从连接池中获得一个ODBC的句柄-freeswitch.Dbh("sqlite://my_db"):从连接池中获得一个SQLITE句柄 (如果不存在也会自动创建)。-dbh:connected():检查句柄时候还与数据保持连接,如果是则返回true,否则返回false-dbh:test_reactive("test_sql","drop_sql", "reactive_sql"):运行test.sql,如果失败则执行drop_sql和reactive.sql(适用于初始化表创建的目的)-dbh:query("query", function()):将“query”当做一个字符串执行,从数据库中返回的结果的每一行都会调用LUA的回调函数进行处理。

1.在每次遍历时,回调函数将获得一个以表的形式表示的行数据对于每一行的语法为:{ ["column_name_1"]= "value_1", ["column_name_2"] = "value_2" }.

2.如果回调函数返回一个非0值,将终止循环
dbh:affected_rows() :除了select操作外,返回对应操作受影响的行数dbh:release() (可选) :释放句柄至连接池中,供其他线程的重复使用。当dbh超出作用范围或者被垃圾回收机制回收(例如脚本返回)时该操作也将被自动执行。在长期运行的脚本中,及时释放连接是十分有必要的。
 

freeswitch.email

作用:发送一封邮件(可带附件)

需要注意的是,如果要用该功能,需要在服务器上安装MTA,当然还需要在switch.conf.xml中配
fe60
置mailer-app

语法:

freeswitch.email(to, from, headers, body, file, convert_cmd, convert_ext)

参数说明:

参数
是否必要
作用
to

一个有效的收件人地址
from

一个有效的发件人地址
headers

标题名
body

正文
file

附件
convert_cmd

发送前转换成其他格式
convert_ext

替换文件(file)的拓展名
 

freeswitch.email("receiver@bar.com",
                 "sender@foo.com",
                 "subject: Voicemail from 1234\n",
                 "Hello,\n\nYou've got a voicemail, click the attachment to listen to it.",
                 "message.wav",
                 "mp3enc",
                 "mp3")
 

freeswitch.Event

作用:生效(firing)一个普通事件my::event

local event = freeswitch.Event("custom", "my::event");
event:addHeader("My-Header", "test");
event:fire();
-- Send an event MESSAGE to a receiver
function FSMan:fire(nameHeader, header, body)
    local myEvent = freeswitch.Event("MESSAGE");
    nameHeader = Utils:trim(nameHeader); header = Utils:trim(header); body = Utils:trim(body);
    if (nameHeader == false ) then nameHeader="Generic_Name_Header" end
    if (header == false) then header="Header_Generic" end
    if (body == false) then body="Body_Generic" end
    myEvent:addHeader(nameHeader, header);
    myEvent:addBody(body);
    myEvent:fire();
end
 

freeswitch.EventConsumer

作用:处理(consume)FreeSWITCH的事件

用法:

con = freeswitch.EventConsumer("<event_name>"[,"<subclass type>"]);
 
-- pop() returns an event or nil if no events
con:pop()
 
-- pop(1) blocks until there is an event
con:pop(1)
 
-- pop(1,500) blocks for max half a second until there is an event
con:pop(1,500)
示例:

con = freeswitch.EventConsumer("all");
session = freeswitch.Session("sofia/default/dest@host.com");
while session:ready() do
    session:execute("sleep", "1000");
    for e in (function() return con:pop() end) do
        print("event\n" .. e:serialize("xml"));
    end
end
-- or
while session:ready() do
    for e in (function() return con:pop(1,1000) end) do
        print("event\n" .. e:serialize("xml"))
    end
end
-- You may subscribe to specific events if you want to, and even subclasses
con = freeswitch.EventConsumer("CUSTOM");
con = freeswitch.EventConsumer("CUSTOM","conference::maintenance");
-- wait for a specific event but continue after 500 ms
function poll()
    -- create event and listener
    local event = freeswitch.Event("CUSTOM", "ping::running?")
    local con = freeswitch.EventConsumer("CUSTOM", "ping::running!")
    -- add text ad libitum
    event:addHeader("hi", "there")
    -- fire event
    event:fire()
    -- and wait for reply but not very long
    if con:pop(1, 500) then
        print("reply received")
        return true
    end
    print("no reply")
    return false
end
 

freeswitch.getGobalVariable

作用:检索一个全局变量

my_globalvar = freeswitch.getGlobalVariable("varname")


 

freeswitch.IVRMenu

hash = {
   ["main"] = undef,
   ["name"] = "top",
   ["greet_long"] = "phrase:demo_ivr_main_menu",
   ["greet_short"] = "phrase:demo_ivr_main_menu_short",
   ["invalid_sound"] = "ivr/ivr-that_was_an_invalid_entry.wav",
   ["exit_sound"] = "voicemail/vm-goodbye.wav",
   ["confirm_macro"] = "undef",
   ["confirm_key"] = "undef",
   ["confirm_attempts"] = "3",
   ["inter_digit_timeout"] = "2000",
   ["digit_len"] = "1",
   ["timeout"] = "10000",
   ["max_failures"] = "3"
}
top = freeswitch.IVRMenu(hash["main"],
                         hash["name"],
                         hash["greet_long"],
                         hash["greet_short"],
                         hash["invalid_sound"],
                         hash["exit_sound"],
                         hash["confirm_macro"],
                         hash["confirm_key"],
                         hash["confirm_attempts"],
                         hash["inter_digit_timeout"],
                         hash["digit_len"],
                         hash["timeout"],
                         hash["max_failures"]);
top:bindAction("menu-exec-app", "playback /tmp/swimp.raw", "2");
top:execute(session, "top");
当使用”SAY”时,需要设置三个额外的变量,否则你将会得到以下的错误:

> [ERR] mod_lua.cpp:182 Error in IVRMenu expected 16..16 args, got 13 stack traceback:

> [C]: in function 'IVRMenu'

> /usr/local/freeswitch/scripts/ivr.lua:19: in main chunk

这三个变量为:

    ["tts_engine"]          = "flite",

    ["tts_voice"]           = "rms",

    ["max_timeouts"]        = "2"

 

freeswitch.msleep

作用:通知脚本休眠一段时间(单位:毫秒)

注意:不要用在基于会话的脚本中,否则坏事将发生

-- Sleep for 500 milliseconds
freeswitch.msleep(500);
 

freeswitch.Session

作用:创建一个新会话(session)

local session = freeswitch.Session("sofia/10.0.1.100/1001");
session:transfer("3000", "XML", "default");
根据变量execute_on_answer创建一个新会话:

local session = freeswitch.Session("[execute_on_answer=info notice]sofia/10.0.1.100/1001");


 

stream:write

作用:你可以根据LUA FreeSWITCH API命令,在LUA中写FreeSWITCH API命令并运行LUA脚本,还可以带一些参数。然后就可以在命令行中得到你写的流对象对应的结果。例如,在scripts中放入hello.lua脚本,然后在命令行中调用该脚本。

stream:write("hello world")


在FreeSWITCH的命令行界面执行lua hello.lua即可返回hello world。

或者在拨号计划(dialplan)中调用它:

<action application="set" data="foo=${lua(hello.lua)}"/>
以上命令将信道变量foo设置为hello world

 

网页交互示例(调用mod_xml_rpc)

--
-- lua/api.lua
--
-- enable mod_xml_rpc and try http://127.0.0.1:8080/api/lua?lua/api.lua in your webbrowser
--
stream:write("Content-Type: text/html\n\n");
stream:write("<title>FreeSWITCH Command Portal</title>");
stream:write("<h2>FreeSWITCH Command Portal</h2>");
stream:write("<form method=post><input name=command size=40> ");
stream:write("<input type=submit value=\"Execute\">");
stream:write("</form><hr noshade size=1><br>");
 
command = env:getHeader("command");
 
if (command) then
   api = freeswitch.API();
   reply = api:executeString(command);
 
   if (reply) then
      stream:write("<br><B>Command Result</b><br><pre>" .. reply .. "</pre>\n");
   end
end
 
env:addHeader("cool", "true");
stream:write(env:serialize() .. "\n\n");
 

 

示例:呼叫控制

--
-- call control lua script
--
dialA = "sofia/gateway/fs1/9903"
dialB = "user/1001"
legA = freeswitch.Session(dialA)
dispoA = "None"
while(legA:ready() and dispoA ~= "ANSWER") do
    dispoA = legA:getVariable("endpoint_disposition")
    freeswitch.consoleLog("INFO","Leg A disposition is '" .. dispoA .. "'\n")
    os.execute("sleep 1")
end -- legA while
if( not legA:ready() ) then
    -- oops, lost leg A handle this case
    freeswitch.consoleLog("NOTICE","It appears that " .. dialA .. " disconnected...\n")
else
    legB = freeswitch.Session(dialB)
    dispoB = "None"
    while(legA:ready() and legB:ready() and dispoB ~= "ANSWER") do
        if ( not legA:ready() ) then
            -- oops, leg A hung up or got disconnected, handle this case
            freeswitch.consoleLog("NOTICE","It appears that " .. dialA .. " disconnected...\n")
        else
            os.execute("sleep 1")
            dispoB = legB:getVariable("endpoint_disposition")
            freeswitch.consoleLog("NOTICE","Leg B disposition is '" .. dispoB .. "'\n")
        end -- inner if legA ready
    end -- legB while
    if ( legA:ready() and legB:ready() ) then
        freeswitch.bridge(legA,legB)
    else
        -- oops, one of the above legs hung up, handle this case
       freeswitch.consoleLog("NOTICE","It appears that " .. dialA .. " or " .. dialB .. " disconnected...\n")
    end
end -- outter if legA ready
 

 

SpecialCase:env object(特殊案例:环境对象)

当将LUA脚本当做挂断钩子(hangup hook)调用时,将产生一个包含刚刚失去连接的信道中所有的信道变量的特殊对象——env

添加一个extension来测试这个特性

<extension name="lua-env-hangup-hook-test">
  <condition field="destination_number" expression="^(1234)$">
    <action application="answer"/>
    <action application="set" data="api_hangup_hook=lua hook-test.lua"/>
    <action application="set" data="my_custom_var=foobar"/>
    <action application="sleep" data="10000"/>
    <action application="hangup"/>                  
  </condition>                            
</extension>
然后添加scripts目录下添加hook-test.lua:

-- hook-test.lua                
-- demonstrates using env to look at channel variables in hangup hook script
 
-- See everything
dat = env:serialize()           
freeswitch.consoleLog("INFO","Here's everything:\n" .. dat .. "\n")
 
-- Grab a specific channel variable
dat = env:getHeader("uuid")     
freeswitch.consoleLog("INFO","Inside hangup hook, uuid is: " .. dat .. "\n")                           

 
-- Drop some info into a log file...
res = os.execute("echo " .. dat .. " >> /tmp/fax.log")
res = os.execute("echo YOUR COMMAND HERE >> /tmp/fax.log")
 
-- If you created a custom variable you can get it also...
dat = env:getHeader("my_custom_var")
freeswitch.consoleLog("INFO","my_custom_var is '" .. dat .. "'\n")
查看FS控制台,拨打1234并挂断,你将看到相关信道的所有变量

翻译出处:https://freeswitch.org/confluence/display/FREESWITCH/mod_lua

注:译者翻译能力有限,欢迎指明
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C freeSWITCH LUA API