FreeSWITCH中文Wiki

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

FreeSWITCH中文Wiki
目录:
* 1 Lua特性
* 1.1 可用来写IVR脚本
* 1.2 可作为事件钩子
* 1.3 可作为Directory Server(与mod_xml_curl功能相同) * 1.4 可用于发起呼叫
* 1.5 轻量级
* 1.6 高度内嵌
* 1.7 关于lua学习
* 1.8 Cli中的lua与luarun
* 1.8.1 参数传递
* 2配置
* 2.1事件钩子
* 2.1.1事件钩子脚本
* 2.2针对IVR用途的配置
* 2.3针对API呼叫的配置
* 2.4调用其他lua脚本
* 2.5提供配置文件服务
* 2.6 lua自启动脚本配置
* 3拨号方案示例
* 4拨号方案示例 - 内嵌扩展
* 5 IVR示例
* 5.1 Hello Lua示例
* 6模式匹配 (正则表达式)
* 6.1 API函数regex示例
* 6.2 Lua自带模式匹配
* 7杂例
* 7.1运行shell命令
* 8更多示例
* 9 FAQ
* 9.1我的debug信息在哪里?
* 9.2如何使用第三方的lua脚本或模块?
* 9.3如何让FreeSWITCH使用系统安装的lua环境?* 9.4第三方类库
* 9.5怎么让lua通过require函数识别我自己的库?* 9.6如何通过ODBC访问数据库?
* 9.7如何找出有用但是非正式的Session函数?
* 9.8如何判断文件是否存在?
* 10 API
* 10.1 Events
* 10.1.1 event:addBody
* 10.1.2 event:addHeader
* 10.1.3 event:delHeader
* 10.1.4 event:fire
* 10.1.5 event:getBody
* 10.1.6 event:getHeader
* 10.1.7 event:getType
* 10.1.8 event:serialize
* 10.1.9 event:setPriority
* 10.1.10 Sending an Event
* 10.2 Sessions
* 10.2.1 session:answer
* 10.2.2 session:answered
* 10.2.3 session:bridged
* 10.2.4 session:check_hangup_hook * 10.2.5 session:collectDigits
* 10.2.6 session:consoleLog
* 10.2.7 session:destroy
* 10.2.8 session:execute
* 10.2.9 session:executeString
* 10.2.10 session:flushDigits
* 10.2.11 session:flushEvents
* 10.2.12 session:get_uuid
* 10.2.13 session:getDigits
* 10.2.14 session:getState
* 10.2.15 session:getVariable
* 10.2.16 session:hangup
* 10.2.17 session:hangupCause
* 10.2.18 session:hangupState
* 10.2.19 session:insertFile
* 10.2.20 session:mediaReady
* 10.2.21 session:originate
* 10.2.22 session:playAndGetDigits * 10.2.22.1 Syntax
* 10.2.22.2 Arguments
* 10.2.22.3 Discussion
* 10.2.22.4 Examples
* 10.2.23 session:preAnswer
* 10.2.24 session:read
* 10.2.25 session:ready
* 10.2.26 session:recordFile
* 10.2.27 session:sayPhrase
* 10.2.28 session:sendEvent
* 10.2.29 session:setAutoHangup
* 10.2.30 session:setHangupHook * 10.2.31 session:setInputCallback * 10.2.32 session:setVariable
* 10.2.33 session:sleep
* 10.2.34 session:speak
* 10.2.35 session:say
* 10.2.36 session:streamFile
* 10.2.37 session:transfer
* 10.2.38 session:unsetInputCallback * 10.2.39 session:waitForAnswer
* 10.3 Non-Session API
* 10.3.1 freeswitch.API
* 10.3.2 freeswitch.bridge
* 10.3.3 freeswitch.consoleCleanLog * 10.3.4 freeswitch.consoleLog
* 10.3.5 freeswitch.Dbh
* 10.3.6 freeswitch.email
* 10.3.7 freeswitch.Event
* 10.3.8 freeswitch.EventConsumer * 10.3.9 freeswitch.getGlobalVariable * 10.3.10 freeswitch.IVRMenu
* 10.3.11 freeswitch.msleep
* 10.3.12 freeswitch.Session
* 10.3.13 stream:write
* 10.3.13.1 API commands
* 10.3.13.2 Web page interaction (via mod_xml_rpc)
* 10.3.14 Example: Call Control
* 10.3.15 Special Case: env object
* 11 See Also
Lua特性
可用来写IVR脚本
Lua的语法非常简单易用。

查看示例:Hello Lua脚本。

可作为事件钩子
你可以定义一个Lua脚本,用于每次特定事件被触发的时候执行。

查看示例: Event_Hooks
可作为Directory Server(与mod_xml_curl功能相同)
Lua可以为xml_curl模块提供配置文件服务,不需要xml_curl去请求web服务器。

具体请看:Serving_Configuration
可用于发起呼叫
Examples
轻量级
精简过的mod_lua.so文件只有272k大小。

高度内嵌
就嵌入能力来说,Python得分2,Perl得分4,JavaScript得分5,而Lua是10!
关于Lua学习
这里有一份Lua与JavaScript在某些特性方面的对比,详见Learning Lua From JS.
Cli中的lua与luarun
你可以通过使用命令“luarun /path/to/script.lua”,启动一个线程来跑你的lua脚本。

“lua”命令用于拨号方案的内联lua,如${lua(codehere)}。

“luarun”会创建一个进程来异步运行,而“lua”将会阻塞直到代码执行结束。

在参数前面加上“~”,会运行单行的
lua命令。

需要注意的是,通过luarun执行的脚本不能通过stream:write API向控制台写入,因为没有stream对象。

参数传递
在向lua传递参数时,是用空格隔开各个参数值,如下:
luarun arg1 arg2 arg3
lua中是以argv对象来获取传递进来的参数,如下:
my_first_var = argv[1];
my_next_var = argv[2];
以此类推。

freeswitch@DVORAK> lua ~print(string.find("1234#5678", "(%d+)#(%d+)"))
1 9 1234 5678
freeswitch@DVORAK> luarun ~print(string.find("1234#5678", "(%d+)#(%d+)"))
+OK
1 9 1234 5678
freeswitch@DVORAK> luarun ~stream:write("1234#5678") +OK
2011-06-20 13:35:35.274782 [ERR] mod_lua.cpp:191 [string "line"]:1: attempt to index global 'stream' (a nil value) stack traceback:
[string "line"]:1: in main chunk
freeswitch@DVORAK> lua ~stream:write("1234#5678")
1234#5678
配置
事件钩子
下面的配置实例将会告诉你如何在每次DETECTED_TONE事件被触发的时候,执行tone_event.lua脚本。

<configuration name="lua.conf" description="LUA
Configuration">
<settings>
<param name="script-directory" value="$${base_dir}/scripts/?.lua"/>
<hook event="DETECTED_TONE" script="tone_event.lua"/> </settings>
</configuration>
事件钩子脚本
这是一个事件钩子脚本示例,通过调用event对象的getHeader()方法来获取事件的相关信息。

local uuid = event:getHeader("Unique-ID")
local tone = event:getHeader("Detected-Tone")
freeswitch.consoleLog("info", uuid .. " detected tone: " .. tone .. "\n")
针对IVR用途的配置
不需要任何配置。

针对API呼叫的配置
api = freeswitch.API();
digits = api:execute("regex", "testing1234|/(\\d+)/|$1");
-- The returned output of the API call is stored in the variable if you need it.
freeswitch.consoleLog("info", "Extracted digits: " .. digits .. "\n")
注:请务必对传入的参数进行转义,像上面正则表达式字符串一样。

调用其他lua脚本
api = freeswitch.API();
reply = api:executeString("luarun another.lua");
提供配置文件服务
FreeSWITH是从静态XML文件中请求并加载配置文件数据,而
Lua模块可以替换该操作,使用脚本提供该服务,更多信息详见Serving_Configuration
Lua自启动脚本配置
下面是最小的Lua配置文件:
<configuration name="lua.conf" description="LUA Configuration">
<settings>
<!--
The following options identifies a lua script that is launched
at startup and may live forever in the background.
You can define multiple lines, one for each script you
need to run.
-->
<!--<param name="startup-script" value="startup_script_1.lua"/>-->
<!--<param name="startup-script" value="startup_script_2.lua"/>-->
</settings>
</configuration>
参数startup-script用于配置在FreeSWITCH启动时,加载的lua 脚本文件(位于scripts/目录下)。

这些脚本分别运行在各自独立的线程中。

你可以利用这些脚本处理一些简单的任务(处理完就关闭),或者让这些脚本处于死循环中,进行监控事件、发起呼叫等操作。

拨号方案示例
<action application="lua" data="helloworld.lua arg1 arg2"/> 注1:在脚本中,可以通过argv[1]和argv[2]来访问传递进来的参数。

注2:默认到prefix/scripts目录中寻找helloworld.lua文件。

拨号方案示例-内嵌扩展
示例1:<action application="set" data="MY_VAR=${lua(helloworld.lua arv1 arg2)}"/>
示例2:<action application="set" data="MY_VAR=${lua(helloworld.lua $1)}" />
示例3: <action application="set" data="MY_VAR=${lua(helloworld.lua $1 ${caller_id_number})}" /> 示例4: <action application="set" data="MY_VAR=${lua(helloworld.lua ${caller_id_number})}" inline="true" />
示例5: <condition field="${lua(helloworld.lua arv1 arg2)}" expression="^Hello World$" >
IVR示例
Hello Lua
-- 接听来电
session:answer();
-- 休眠1秒
session:sleep(1000);
-- 播放语音提示文件
session:streamFile("/path/to/blah.wav");
-- 挂机
session:hangup();
模式匹配(正则表达式)
API函数regex示例
通过这种方式,你可以在lua脚本内执行正则表达式条件(感谢bkw_)。

session:execute("set", "some_chan_variable=${regex(" .. destination .. "|^([0-9]{10})$)}")
如果destination是一个lua变量,用于存储你拨打的目标号码,
同时你的正则表达式是[0-9]{10}$ 在上述命令执行完毕后,匹配的结果将会放入"some_chan_variable"这个通道变量中,在lua脚本中通过session:getVariable即可获取到结果。

同样,通过下面的命令
session:execute("set", "some_chan_variable=${regex(" .. destination .. "|^(0\\|61)([2,3,7,8][0-9]{8})$|$2)}")
来匹配并返回捕获到的值。

Lua自带的模式匹配
Lua支持一种简单但同样强大的模式匹配语法。

虽然没有PCRE强大,但是却能处理脚本中绝大部分模式匹配问题。

下面是一个简单脚本,可以通过fs_cli中的luarun运行,主要用来展示字符串捕获:
-- pattern.lua
data = "1234#5678";
_,_,var1,var2 = string.find(data,"(%d+)#(%d+)");
freeswitch.consoleLog("INFO","\ndata: " .. data .. "\nvar1: " .. var1 .. "\nvar2: " .. var2 .. "\n");
Output:
freeswitch@internal> luarun pattern.lua
+OK
2011-04-18 08:28:49.242080 [INFO] switch_cpp.cpp:1197
data: 1234#5678
var1: 1234
var2: 5678
其他资料: * FreeSWITCH书149-151页* /pil/20.2.html 和/pil/20.3.html * /manual/5.1/manual.html#5.4.1
杂项
运行Shell命令
当使用session:execute()和api:execute()去执行shell命令(如Bash脚本)的时候,会只返回整型的错误码。

如果需要获取shell命令的返回值,可以使用io.popen()方法。

下面的例子来自/wiki/ShellAccess.
function shell(c)
local o, h
h = assert(io.popen(c,"r"))
o = h:read("*all")
h:close()
return o
end
更多示例
•See scripts/lua directory on the file system
•[[IVR|Example IVRs]]
•[[Lua MythTV alert example]]
•[[Fakecall responder]]
•[[Fun Lua Examples]]
•[[Call retry based on hangup cause]]
•[[Bridging two calls with retry]]
FAQ
我的调试信息在哪里
Q:当我使用静态XML或xml_curl(去执行命令)时,能通过fs_cli和xml_cdr文件的“application log”节点看到执行的命令日志。

但是,当我通过lua脚本去执行命令的时候,去怎么也看不到这些信息。

A: 在lua脚本中,当你有一个真实可用的呼叫会话时(译者注:比如从拨号方案中转入lua脚本时,可以使用session对象来操作此次呼叫),可以使用session:execute("$application","$data")命令,使用该方法会在fs_cli和xml_cdr的日志中显示出命令执行情况。

但如果没有呼叫会话,比如你的lua脚本是在后台运行或从cli启
动的,那你只能使用其他不能记录日志的命令。

如何使用第三方的lua脚本或模块?
Q: 我需要把自己的lua文件放到什么地方,以便让FreeSWITCH 能读取到。

我正在运行一个/scripts目录下面的lua脚本,但是它需要包含另一个lua文件。

A: 答案是/usr/local/share/lua/5.1/
或者,你可以安装系统lua环境(通过apt-get或yum),freeswitch内嵌的lua会到插件目录中去查找库文件。

(下面的英文暂不翻译,没开发好,翻译有个毛用!) To do this in the mod_lua.conf file (currently not possible), the following development would be needed.
•Install them to a nonstandard.
•Push a nonstandard place into the path of where it looks.
'''NOTE:''' Assuming you have in lua.conf.xml, in the scripts, require statements in the form of:
require "luasql.mysql"
This will look for the shared object ${base_dir}/scripts/luasql/mysql.so
'''NOTE:''' The native MySQL driver for Lua has a very bad memory leak. Do not use it.
怎么让FreeSWITCH使用系统lua环境?
Q: 我已经安装好了lua环境,但是mod_lua貌似忽略掉我安装的lua。

A: Lua太小了,以至于整个lua库被静态链接到模块上。

第三方类库
Q : 能对FreeSWITCH使用luarocks吗?
A : 可以,luarocks是lua的包库管理器。

它可以将库安装到系统目录中,然后你就可以通过FreeSWITCH中的lua来引用它们。

为了能正常安装luarocks,你同样需要在系统中安装lua环境。

举例来说,如果你想在Ubuntu 12.04上面使用LuaXML库,则需要如下操作:
sudo apt-get install lua-5.1 luarocks
luarocks install luaxml
然后,编辑/usr/local/freeswitch/conf/autoload_configs/lua.conf.xml文件,取消下面的注释,如下:
<param name="module-directory" value="/usr/lib/lua/5.1/?.so"/>
<param name="module-directory" value="/usr/local/lib/lua/5.1/?.so"/>
现在,FreeSWITCH中的lua脚本就可以使用XML相关的方法了,示例如下:
require("LuaXml")
local xobj = xml.eval('<Cmd Message="Hello"/>')
freeswitch.consoleLog("INFO","The message in the XML is "..xobj["Message"].."\n")
怎么让lua通过require函数识别我自己的库?
Q: 在FreeSWITCH的lua脚本中,我能通过require函数将其他lua库包含进来不?
A: 你可以通过修改环境变量LUA_PATH,以便告诉FreeSWITCH 的内置Lua如何找到你的库。

下面是一个简单的实现脚本:#!/bin/bash
export LUA_PATH=/usr/local/freeswitch/scripts/?.lua\;\;
ulimit -s 240
screen /usr/local/freeswitch/bin/freeswitch
默认的路径为/usr/local/share/lua/5.1/,需要根据情况修改。

还有一种方式,是使用‘dofile’命令,如下:
eg. dofile("/home/fred/scripts/fredLuaFunctions.lua")
注:dofile只是把文件中包含的命令,当做一条命令来执行,和
创建lua模块不一样。

能通过ODBC访问数据库不?
可以。

有两种方式来访问,分别是自带的freeswitch.Dbh和luaSQL模块。

这里主要介绍第二种方法。

通过LuaSQL,你不仅可以访问ODBC数据源,还可以访问PostgreSQL, Oracle和MySQL。

LuaSQL自己实现了对这些数据库的连接。

想了解更多的话,查看/luasql/
下面是安装LuaSQL的简短说明。

提醒下,在X64_86平台上面,配置文件要稍作更改。

/frs/download.php/2686/luasql-2.1.1.tar.gz
tar xfvz luasql-2.1.1.tar.gz
cd luasql-2.1.1/
配置文件分成三个部分:
1、数据库名称
2、指向不同库的路径设置
3、执行数据库相关库的路径设置
第一步,根据操作系统类型,调整路径的设置方式
第二步,选择一种数据库驱动进行编译(每次只能编译一个驱动)。

如编译MySQL,需要取消配置文件#1和#3中关于MySQL的注释,其他配置行需要注释掉。

注:在RHEL/CentOS中,LuaSQL默认的指向MySQL的libs和include的路径,不是真实路径,需要做如下调整:
DRIVER_LIBS= -L/usr/lib/mysql -lmysqlclient -lz
DRIVER_INCS= -I/usr/include/mysql
示例: 连接Microsoft SQL Server配置,
sed -i 's/#T= odbc/T= odbc/g' config
sed -i 's/T=sqlite3/#T=sqlite3/g' config
DRIVER_LIBS= -L/usr/lib64 -lodbc
DRIVER_INCS= -DUNIXODBC -I/usr/include
根据真实安装环境设置LUA_LIBDIR, LUA_DIR , LUA_INC , DRIVER_LIBS, DRIVER_INCS
为了编译顺利,修改如下:
sed -i 's/WARN= /WARN= -fPIC /g' config
编译...
make
make install
你要先下载安装Lua,然后下载LuaSQL,针对你要的数据库模块进行编译安装。

下一步就是收获的时候了,用法如下:
#!/usr/local/bin/lua
require "luasql.mysql"
env = assert (luasql.mysql())
con = assert (env:connect("database","username","password","localhost")) cur = assert (con:execute"SELECT * FROM table")
row = cur:fetch ({}, "a")
session:setVariable("varname", tostring(row.column));
cur:close()
con:close()
env:close()
对于配置ODBC,你需要编辑odbc.ini和odbcinst.ini文件(RHEL默认在/etc/目录下)。

以MySQL为例,
File: odbcinst.ini
# Driver from the MyODBC package
# Setup from the unixODBC package
[MySQL]
Description = ODBC for MySQL
Driver = /usr/lib/libmyodbc.so
Setup = /usr/lib/libodbcmyS.so
FileUsage = 1
注:需要确保lib目录中有libmyodbc.so和libodbcmyS.so文件File: odbc.ini
[mydsn]
Driver = MySQL
SERVER = localhost
PORT = 3306
DATABASE = mydatabase
OPTION = 67108864
SOCKET = /var/lib/mysql/mysql.sock
注1:为了让脚本正常执行,你还得设置一些环境变量,
echo export LUA_PATH=/usr/local/freeswitch/scripts/?.lua >> /etc/bashrc
echo export LUA_CPATH=/usr/local/freeswitch/scripts/?.so >> /etc/bashrc
echo export PATH=$PATH:/usr/local/freeswitch/bin >> ~/.bashrc
注2:你需要将共享库,如mysql.so,符号连接到/usr/local/lib/lua/5.1/luasql/mysql.so
警告:该修改打破了原先外部lua模块的加载方式 :8081/changelog/FreeSWITCH?cs=9605
注3:上述修改已被修复,:8081/changelog/FreeSWITCH?cs=10306
如何找出非正式公布出来的Session函数?
有时会发生这样的情况,增加了新函数,但是没有更新文档。

下面的脚本可能会给你些帮助:
-- This function simply tells us what function are available in
Session
-- It just prints a list of all functions. We may be able to find functions
-- that have not yet been documented but are useful. I did :) function printSessionFunctions( session )
metatbl = getmetatable(session)
if not metatbl then return nil end
local f=metatbl['.fn'] -- gets the functions table
if not f then return nil end
print("\n***Session Functions***\n")
for k,v in pairs(f) do print(k,v) end
print("\n\n")
end
new_session = freeswitch.Session() -- create a blank session
printSessionFunctions(new_session)
在freeswitch版本16256上,该脚本输出如下:
process_callback_result function: 0x79b380
flushDigits function: 0x798db0
execute function: 0x798ed0
setAutoHangup function: 0x798de0
collectDigits function: 0x798c30
mediaReady function: 0x7993d0
speak function: 0x79b2d0
setHangupHook function: 0x799510
getDigits function: 0x798c60
check_hangup_hook function: 0x799380 playAndGetDigits function: 0x798cf0 getState function: 0x79b1e0 hangupState function: 0x79b4e0
say function: 0x79b150
recordFile function: 0x79b210 waitForAnswer function: 0x798ea0
sleep function: 0x798d50 setEventData function: 0x798f30 setPrivate function: 0x79b540
setLUA function: 0x7995d0
begin_allow_threads function: 0x799320 setInputCallback function: 0x7994e0 unsetInputCallback function: 0x799470 run_dtmf_callback function: 0x799400 get_cb_args function: 0x799020
read function: 0x798cc0
getPrivate function: 0x79b570
answer function: 0x79b450
setVariable function: 0x79b510 getXMLCDR function: 0x798f60 originate function: 0x799570
destroy function: 0x7992f0
answered function: 0x798e70
set_tts_parms function: 0x79b300 sendEvent function: 0x798f00
ready function: 0x799540
preAnswer function: 0x79b4b0 streamFile function: 0x798d20
hangupCause function: 0x79b1b0
setDTMFCallback function: 0x79b2a0
getVariable function: 0x79b350
transfer function: 0x798c90
get_uuid function: 0x798ff0
hangup function: 0x79b480
end_allow_threads function: 0x799350
flushEvents function: 0x798d80
sayPhrase function: 0x79b180
如何测试文件是否存在?
在Lua中,你可以使用API命令中的file_exists来判断文件是否存在。

下面的例子用来检查hello.wav文件是否存在于/usr/local/freeswitch/sounds/messages目录中。

如果存在,使用playback函数向主叫播放该语音文件。

如果不存在,则播放goodbye.wav文件。

local message_location = "/usr/local/freeswitch/sounds/messages/"
local message = "hello.wav"
message = message_location .. message
session:consoleLog("debug", "file_exists: Check for message1: ".. message .."\n")
api = freeswitch.API(); -- create API-session
reply = api:executeString("file_exists " .. message); -- execute file_exists with message and return result in reply
if reply=="true" then
session:consoleLog("info", "file_exists: Initial file found.
Playing " .. message"\n")
else
message = message_location .. "goodbye.wav"
session:consoleLog("info", "file_exists: Initial file not found. Playing " .. message"\n")
end
session:sleep(250) -- making sure that the beginning of the file is not skipped
session:execute("playback", message)
API
Events
下面的这些方法用于生成事件
event:addBody
--Create Custom event
custom_msg = "dial_record_id: " .. dial_record_id .. "\n" ..
"call_disposition: " .. Disposition .. "\n" ..
"campaign_number: " .. Campaign .. "\n" ..
"called_number: " .. dial_num .."\n" ;
local e = freeswitch.Event("custom", "dial::dial-result");
e:addBody(custom_msg);
e:fire();
在事件体body中,随你添加需要的内容。

在上面的例子中,定义了4个条目来发送。

结果如下:
[Content-Length] => 555
[Content-Type] => text/event-plain
[Body] => Array
(
[Event-Subclass] => dial::dial-result
[Event-Name] => CUSTOM
[Core-UUID] => 2dc7cc50-b157-4868-ae16-04e5f4b95dae [FreeSWITCH-Hostname] => [FreeSWITCH-IPv4] => 192.168.0.106
[FreeSWITCH-IPv6] => ::1
[Event-Date-Local] => 2009-02-17 23:15:49
[Event-Date-GMT] => Tue, 17 Feb 2009 23:15:49 GMT [Event-Date-Timestamp] => 1234912549610060 [Event-Calling-File] => switch_cpp.cpp
[Event-Calling-Function] => fire
[Event-Calling-Line-Number] => 297
[Content-Length] => 85
[Body] => Array
(
[dial_record_id] => 1234
[call_disposition] => AA
[campaign_number] => 20
[called_number] => 7777777
)
)
)
event:addHeader
event:delHeader
event:fire
bkw童鞋提供了下面的例子:
local event = freeswitch.Event("message_waiting");
event:addHeader("MWI-Messages-Waiting", "no");
event:addHeader("MWI-Message-Account",
"sip:*********.1.100");
event:addHeader("Sofia-Profile", "internal");
event:fire();
event:getBody
event:getHeader
这是一个常用的API调用。

event:getHeader("Caller-Caller-ID-Name")
或者,在dialplan.lua中使用该函数获取某些信息:
params:getHeader("variable_sip_req_uri")
event:getType
event:serialize
该函数用于向控制台输出所有的头部参数(Headers)。

-- Print as text
io.write(params:serialize());
io.write(params:serialize("text"));
-- Print as JSON
io.write(params:serialize("json"));
或者,作为info日志信息输出,
freeswitch.consoleLog("info",params:serialize())
event:setPriority
Sending an Event
使用luarun执行下面的命令,以用来控制注册话机MWI灯的开
启和关闭。

local event = freeswitch.Event("message_waiting");
event:addHeader("MWI-Messages-Waiting", "no");
event:addHeader("MWI-Message-Account",
"sip:*********.1.100");
event:fire();
Sessions
下面的方法适用于存在session对象的lua脚本中。

session:answer
接听通话:
session:answer();
session:answered
用于检查会话是否被标记为已接听(只要通话被接听,就总是为true)
session:bridged
用于检查当前会话通道是否桥接到其他会话通道。

if (session:bridged() == true) do
-- Do something
end
session:check_hangup_hook
session:collectDigits
session:consoleLog
通过session对象,向freeswitch日志记录器写入日志。

参数分别为日志级别和日志消息。

session:consoleLog("info", "lua rocks\n");
session:consoleLog("notice", "lua rocks\n");
session:consoleLog("err", "lua rocks\n");
session:consoleLog("debug", "lua rocks\n");
session:consoleLog("warning","lua rocks\n");
session:destroy
该函数用于销毁会话,释放资源。

当你的脚本执行结束的时候,该方法会被自动调用。

但是如果你的脚本中包含一个死循环,则需要使用该函数来停止会话。

session:execute
session:execute(app, data)
local mySound = "/usr/local/freeswitch/sounds/music/16000/partita-no-3-in-e-major-bwv-1006-1-preludio.wav"
session:execute("playback", mySound)
注:在execute命令执行过程中,不能执行回调函数(如DTMF 监听等各种小伙伴)
session:executeString
等同于session:execute(api_string)
local mySound = "/usr/local/freeswitch/sounds/music/16000/partita-no-3-in-e-major-bwv-1006-1-preludio.wav"
session:executeString("playback "..mySound)
注:在execute命令执行过程中,不能执行回调函数(如DTMF 监听等各种小伙伴)
session:flushDigits
session:flushEvents
session:get_uuid
session:getDigits
获取DTMF输入: * 函数有三个参数: Get digits: 最大数, 终止键, 超时时长 * 最大数: 最多能收到几个DTMF信号(即最多能接到的按键数) * 终止键: 当接收到字符后,停止DTMF收取 * 超时时长: 收取DTMF输入的最大时间(单位毫秒) * 返回值:收到的DTMF输入字符串
该方法会处于堵塞状态,直到出现终止条件(如出现终止键或超时)
digits = session:getDigits(5, "#", 3000);
session:consoleLog("info", "Got dtmf: ".. digits .."\n");
session:getState
获取通话状态,如“CS_EXECUTE”。

全部的状态详见switch_types.h。

state=session:getState();
session:getVariable
用于获取系统变量,如${hold_music}
local moh = session:getVariable("hold_music")
--[[ events obtained from "switch_channel.c"
regards Monroy from Mexico
]]
session:getVariable("context");
session:getVariable("destination_number");
session:getVariable("caller_id_name");
session:getVariable("caller_id_number");
session:getVariable("network_addr");
session:getVariable("ani");
session:getVariable("aniii");
session:getVariable("rdnis");
session:getVariable("source");
session:getVariable("chan_name");
session:getVariable("uuid");
session:hangup
你可以在挂断通话的时候,顺便指明挂机原因(可选),如下:session:hangup("USER_BUSY");
当然,还有下面无参数的挂机方式(挂机原因默认为normal_clearing),
session:hangup(); -- default normal_clearing
session:hangupCause
通过该函数,可以获取到已接听通话的挂机原因,或获取发起的呼叫没有成功的原因。

具体挂机原因详见[[Hangup causes]].
-- Initiate an outbound call
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
session:hangupState
session:insertFile
session:insertFile(<orig_file>, <file_to_insert>, <insertion_sample_point>)
该函数用于将(语音)文件插入到另一个文件中。

三个参数是必需的。

第三个参数是file_to_insert中要插入到orig_file中的样本数。

产生的文件将会被以会话的采样率写入,并最终取代orig_file.
因为需要根据样本数得出插入的位置,你需要知道文件的采样率,正确计算X秒有多少个样本,以便插入文件中。

例如,将文件插入到wav文件2秒钟后的位置,目标文件采样率为8000Hz,你需要将insertion_sample_point这个参数设置为16000。

注意,此方法需要一个活跃的通道和一个有效的session对象,因为需要从session对象中获取采样率和编码信息。

例子:在一个使用ulaw的通道上,将bar.wav插入到foo.war1秒后的位置: session:insertFile("foo.wav", "bar.wav", 8000) 将bar.wav加到foo.wav之前:session:insertFile("foo.wav", "bar.wav", 0)
将bar.wav加到foo.wav之后:session:insertFile("bar.wav", "foo.wav", 0)
session:mediaReady
session:originate
session:originate已过时,请使用下面的方法代替:
new_session = freeswitch.Session("sofia/gateway/gatewayname/180****4567", session);
下面的代码仅作历史保留,请不要使用:(译者注:剩下的就不翻了,有兴趣自己看看,要是闲的蛋有点疼的话)
''The code below is here for the sake of history only; please do not use it going forward.''
-- this usage of originate is deprecated, use freeswitch.Session(dest, session)
new_session = freeswitch.Session();
new_session.originate(session, dest[, timeout]);
dest - quoted dialplan destination. For example: "sofia/internal/*********.0.1"or "sofia/gateway/my_sip_provider/my_dest_number"
timeout - origination timeout in seconds
Note: session.originate expects at least 2 arguments.
session:playAndGetDigits
播放一个语音文件,并获取DTMF输入的数字。

在获取完毕后,将会与正则表达式进行匹配。

匹配失败或超时都会触发播放包含错误提示信息的文件。

可选参数用于在获取失败的时候将通话转到指定的拨号方案上,或者将获取到的数字存储到某个通道变量上。

语法
digits = session:playAndGetDigits (
min_digits, max_digits, max_attempts, timeout, terminators, prompt_audio_files, input_error_audio_files,
digit_regex, variable_name, digit_timeout,
transfer_on_failure)
参数
min_digits 要求输入的最小位数
max_digits 要求输入的最大位数
max_attempts 函数重复播放提示音乐等待输入的次数
timeout 两次输入之间的时间间隔(单位为毫秒)
terminators 输入终止符(译者注:一般为#之类)
prompt_audio_file 最初播放的语音文件。

在播放时,如果用户有按键输入则中止播放。

每次等待输入超时后,都会播放该文件,直到播放次数超过max_attempts。

input_error_audio_file 当接受到的数字不符合digit_regex制定的规则的时候,播放该错误提示文件。

同时,会清空之前输入的内容。

如果不需要播放错误提示文件的话,该属性置空即可。

digit_regex 用于匹配输入数字的正则表达式
variable_name (可选)用于存储输入数字的通道变量
digit_timeout (可选) 数字间超市时长。

该属性被设置后,会在每次数字输入后重置timeout属性。

从而让用户以比较慢的速度输入的时候,不会引起超时。

如果没指定,该属性值与timeout属性相同。

transfer_on_failure (可选) 该属性用于在出现输入异常时将通话转到指定的拨号方案上。

语法为"extension-name [dialplan-id [context]]"
注意事项
•当所有超时和重试次数用尽后,这个函数返回一个空字符串。

•当允许输入的数字达到最大个数时,函数立即返回,即使还没有输入截止符。

•如果用户已经输入完毕,但是忘记输入截止符,在下一个超时结束后函数返回(输入的数字也返回)。

•需要通话被answer后,才能接收用户输入。

如果通话没被接听,提示语音还是可以播放,但是不会接收不到任何输入
示例
例1:
digits = session:playAndGetDigits(2, 5, 3, 3000, "#", "/prompt.wav", "/error.wav", "\\d+")
session:consoleLog("info", "Got DTMF digits: ".. digits .."\n") 该例子将会先播放prompt.wav提示音,接收2到5个数字输入,以#作为截止符。

如果用户没有任何输入,或输入的不是数字,如*之类,将会播放error.wav文件。

播放完毕后,你还剩下两次输入机会。

例2:
digits = session:playAndGetDigits(1, 1, 3, 3000, "", "/menu.wav", "/error.wav", "[134]", "digits_received", 3, "operator XML default")
session:consoleLog("info", "Got DTMF digits: ".. digits .."\n") 这次,我们只要求输入一个数字,必须是1、3、4中的一个。


果用户三次输入都不在范围内,则直接转到拨号方案operator XML
default上。

如果用户输入正确,则输入的数字会返回给调用者,并保存到通
道变量digits_received中。

If the user presses a correct key, that
digit is returned to the caller, and the "digits_received" channel
variable is set to the same value.
友情提醒: 如果需要在正则表达式中匹配字符,则需要引用两次,
如下:digits = session:playAndGetDigits(2, 5, 3, 3000, "#",
"/sr8k.wav", "", "\d+|\");
session:preAnswer
预答会话
session:preAnswer();
session:read
播放语音提示,并获取用户输入数字
digits = session:read(5, 10, "/sr8k.wav", 3000, "#");
session:consoleLog("info", "Got dtmf: ".. digits .."\n");
session:read有5个参数:
session:ready
用于检查当前会话是否仍处于活跃状态(在通话开始之后,挂断
之前,都是为true)。

如果通话被转移,则session:ready返回false。

你需要在脚本中循环检查session:ready的值,一旦为false则立
即退出。

while (session:ready() == true) do -- do something here end
session:recordFile
语法是session:recordFile(file_name, max_len_secs,
silence_threshold, silence_secs)
silence_secs:在结束录音前,能忍耐的静默语音时长
例子:
function onInputCBF(s, _type, obj, arg)
local k, v = nil, nil
local _debug = true
if _debug then
for k, v in pairs(obj) do
printSessionFunctions(obj)
print(string.format('obj k-> %s v->%s\n', tostring(k), tostring(v)))
end
if _type == 'table' then
for k, v in pairs(_type) do
print(string.format('_type k-> %s v->%s\n', tostring(k), tostring(v)))
end
end
print(string.format('\n(%s ## dtmf) and (obj.digit [%s])\n', _type, obj.digit))
end
if (_type == "dtmf") then
return 'break'
else
return ''
end
end
recording_dir = '/tmp/'
filename = 'myfile.wav'
recording_filename = string.format('%s%s', recording_dir, filename)。

相关文档
最新文档