在mod_lua.cpp文件中定义了两个api
SWITCH_STANDARD_APP(lua_function)
SWITCH_STANDARD_API(luarun_api_function)
分别对应lua和luarun命令,所有以宏SWITCH_STANDARD_API定义的都是freeswitch暴露的api接口。
我们这里以luarun为例分析
SWITCH_STANDARD_API(luarun_api_function)
{
if (zstr(cmd)) {
stream->write_function(stream, "-ERR no args specified!\n");
} else {
lua_thread(cmd);
stream->write_function(stream, "+OK\n");
}
return SWITCH_STATUS_SUCCESS;
}
所以当执行luarun的时候主要是调用lua_thread()函数处理。
int lua_thread(const char *text)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
switch_memory_pool_t *pool;
lua_thread_helper *lth;
switch_core_new_memory_pool(&pool);
lth = (lua_thread_helper *) switch_core_alloc(pool, sizeof(*lth));
lth->pool = pool;
lth->input_code = switch_core_strdup(lth->pool, text);
switch_threadattr_create(&thd_attr, lth->pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&thread, thd_attr, lua_thread_run, lth, lth->pool);
return 0;
}
在lua_thread中主要是创建一个新线程,并在线程里面执行:lua_thread_run
static void *SWITCH_THREAD_FUNC lua_thread_run(switch_thread_t *thread, void *obj)
{
struct lua_thread_helper *lth = (struct lua_thread_helper *) obj;
switch_memory_pool_t *pool = lth->pool;
lua_State *L = lua_init(); /* opens Lua */
lua_parse_and_execute(L, lth->input_code, NULL);
lth = NULL;
switch_core_destroy_memory_pool(&pool);
lua_uninit(L);
return NULL;
}
在lua_thread_run中先初始化了一个lua_State,然后调用lua_parse_and_execute去加载lua脚本文件并执行
static int lua_parse_and_execute(lua_State * L, char *input_code, switch_core_session_t *session)
{
int error = 0;
if (zstr(input_code)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No code to execute!\n");
return 1;
}
while(input_code && (*input_code == ' ' || *input_code == '\n' || *input_code == '\r')) input_code++;
if (*input_code == '~') {
char *buff = input_code + 1;
error = luaL_loadbuffer(L, buff, strlen(buff), "line") || docall(L, 0, 0, 0, 1); //lua_pcall(L, 0, 0, 0);
} else if (!strncasecmp(input_code, "#!/lua", 6)) {
char *buff = input_code + 6;
error = luaL_loadbuffer(L, buff, strlen(buff), "line") || docall(L, 0, 0, 0, 1); //lua_pcall(L, 0, 0, 0);
} else {
char *args = strchr(input_code, ' ');
if (args) {
char *code = NULL;
int x, argc;
char *argv[128] = { 0 };
*args++ = '\0';
if ((argc = switch_separate_string(args, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
switch_stream_handle_t stream = { 0 };
SWITCH_STANDARD_STREAM(stream);
stream.write_function(&stream, " argv = {[0]='%y', ", input_code);
for (x = 0; x < argc; x++) {
stream.write_function(&stream, "'%y'%s", argv[x], x == argc - 1 ? "" : ", ");
}
stream.write_function(&stream, " };");
code = (char *) stream.data;
} else {
code = switch_mprintf("argv = {[0]='%s'};", input_code);
}
if (code) {
error = luaL_loadbuffer(L, code, strlen(code), "line") || docall(L, 0, 0, 0, 1);
switch_safe_free(code);
}
} else {
// Force empty argv table
char *code = NULL;
code = switch_mprintf("argv = {[0]='%s'};", input_code);
error = luaL_loadbuffer(L, code, strlen(code), "line") || docall(L, 0, 0, 0, 1);
switch_safe_free(code);
}
if (!error) {
char *file = input_code, *fdup = NULL;
if (!switch_is_file_path(file)) {
fdup = switch_mprintf("%s/%s", SWITCH_GLOBAL_dirs.script_dir, file);
switch_assert(fdup);
file = fdup;
}
error = luaL_loadfile(L, file) || docall(L, 0, 0, 0, 1);
switch_safe_free(fdup);
}
}
if (error) {
const char *err = lua_tostring(L, -1);
if (!zstr(err)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s\n", err);
}
lua_pop(L, 1); /* pop error message from the stack */
}
return error;
}
前面一段都是在处理参数最核心的是下面这一行
luaL_loadfile(L, file) || docall(L, 0, 0, 0, 1)
加载文件并执行
int docall(lua_State * L, int narg, int nresults, int perror, int fatal)
{
int status;
int base = lua_gettop(L) - narg; /* function index */
lua_pushcfunction(L, traceback); /* push traceback function */
lua_insert(L, base); /* put it under chunk and args */
status = lua_pcall(L, narg, nresults, base);
lua_remove(L, base); /* remove traceback function */
/* force a complete garbage collection in case of errors */
if (status != 0) {
lua_gc(L, LUA_GCCOLLECT, 0);
}
if (status && perror) {
const char *err = lua_tostring(L, -1);
if (!zstr(err)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s\n", err);
}
// pass error up to top
if (fatal) {
lua_error(L);
} else {
lua_pop(L, 1); /* pop error message from the stack */
}
}
return status;
}
最后调用lua_pcall执行lua脚本。
下面再介绍一下一个lua的接口怎么找到他对应的c++l代码:
所有的暴露给lua的接口都放在mod_lua_wrap.cpp这文件的swig_type_initial里面,然后lua模块启动的时候会逐个加载。
static swig_type_info *swig_type_initial[] = {
&_swigt__p_API,
&_swigt__p_CoreSession,
&_swigt__p_DTMF,
&_swigt__p_Event,
&_swigt__p_EventConsumer,
&_swigt__p_IVRMenu,
&_swigt__p_LUA__Dbh,
&_swigt__p_LUA__Session,
&_swigt__p_SWIGLUA_FN,
&_swigt__p_Stream,
&_swigt__p_input_callback_state,
&_swigt__p_int,
&_swigt__p_lua_State,
&_swigt__p_p_switch_event_node_t,
&_swigt__p_session_flag_t,
&_swigt__p_switch_call_cause_t,
&_swigt__p_switch_channel_state_t,
&_swigt__p_switch_channel_t,
&_swigt__p_switch_core_session_t,
&_swigt__p_switch_event_t,
&_swigt__p_switch_event_types_t,
&_swigt__p_switch_input_args_t,
&_swigt__p_switch_input_type_t,
&_swigt__p_switch_priority_t,
&_swigt__p_switch_queue_t,
&_swigt__p_switch_state_handler_table_t,
&_swigt__p_switch_status_t,
&_swigt__p_switch_stream_handle_t,
&_swigt__p_uint32_t,
&_swigt__p_void,
};
我们以Session的接口为例介绍一下,他在_swigt__p_CoreSession这个结构体里面描述。
static swig_type_info _swigt__p_CoreSession = {"_p_CoreSession", "CoreSession *", 0, 0, (void*)&_wrap_class_CoreSession, 0};
static swig_lua_class _wrap_class_CoreSession = { "CoreSession", "CoreSession", &SWIGTYPE_p_CoreSession,0, swig_delete_CoreSession, swig_CoreSession_methods, swig_CoreSession_attributes, &swig_CoreSession_Sf_SwigStatic, swig_CoreSession_meta, swig_CoreSession_bases, swig_CoreSession_base_names };
被注册的方法放在swig_CoreSession_methods这个结构体里面:
static swig_lua_method swig_CoreSession_methods[]= {
{ "insertFile", _wrap_CoreSession_insertFile},
{ "answer", _wrap_CoreSession_answer},
{ "preAnswer", _wrap_CoreSession_preAnswer},
{ "hangup", _wrap_CoreSession_hangup},
{ "hangupState", _wrap_CoreSession_hangupState},
{ "setVariable", _wrap_CoreSession_setVariable},
{ "setPrivate", _wrap_CoreSession_setPrivate},
{ "getPrivate", _wrap_CoreSession_getPrivate},
{ "getVariable", _wrap_CoreSession_getVariable},
{ "process_callback_result", _wrap_CoreSession_process_callback_result},
{ "say", _wrap_CoreSession_say},
{ "sayPhrase", _wrap_CoreSession_sayPhrase},
{ "hangupCause", _wrap_CoreSession_hangupCause},
{ "getState", _wrap_CoreSession_getState},
{ "recordFile", _wrap_CoreSession_recordFile},
{ "originate", _wrap_CoreSession_originate},
{ "destroy", _wrap_CoreSession_destroy},
{ "setDTMFCallback", _wrap_CoreSession_setDTMFCallback},
{ "speak", _wrap_CoreSession_speak},
{ "set_tts_parms", _wrap_CoreSession_set_tts_parms},
{ "set_tts_params", _wrap_CoreSession_set_tts_params},
{ "collectDigits", _wrap_CoreSession_collectDigits},
{ "getDigits", _wrap_CoreSession_getDigits},
{ "transfer", _wrap_CoreSession_transfer},
{ "read", _wrap_CoreSession_read},
{ "playAndGetDigits", _wrap_CoreSession_playAndGetDigits},
{ "streamFile", _wrap_CoreSession_streamFile},
{ "sleep", _wrap_CoreSession_sleep},
{ "flushEvents", _wrap_CoreSession_flushEvents},
{ "flushDigits", _wrap_CoreSession_flushDigits},
{ "setAutoHangup", _wrap_CoreSession_setAutoHangup},
{ "setHangupHook", _wrap_CoreSession_setHangupHook},
{ "ready", _wrap_CoreSession_ready},
{ "bridged", _wrap_CoreSession_bridged},
{ "answered", _wrap_CoreSession_answered},
{ "mediaReady", _wrap_CoreSession_mediaReady},
{ "waitForAnswer", _wrap_CoreSession_waitForAnswer},
{ "execute", _wrap_CoreSession_execute},
{ "sendEvent", _wrap_CoreSession_sendEvent},
{ "setEventData", _wrap_CoreSession_setEventData},
{ "getXMLCDR", _wrap_CoreSession_getXMLCDR},
{ "begin_allow_threads", _wrap_CoreSession_begin_allow_threads},
{ "end_allow_threads", _wrap_CoreSession_end_allow_threads},
{ "get_uuid", _wrap_CoreSession_get_uuid},
{ "get_cb_args", _wrap_CoreSession_get_cb_args},
{ "check_hangup_hook", _wrap_CoreSession_check_hangup_hook},
{ "run_dtmf_callback", _wrap_CoreSession_run_dtmf_callback},
{ "consoleLog", _wrap_CoreSession_consoleLog},
{ "consoleLog2", _wrap_CoreSession_consoleLog2},
{0,0}
};
在这里可以看到很熟悉的answer,bridge等方法了。
本文介绍了freeswitch模块下的lua_function和luarun_api_function两个API,重点分析了luarun的执行过程,涉及lua_thread函数及lua_thread_run中的lua_State初始化和lua_parse_and_execute的脚本加载执行。同时,讲解了lua接口如何映射到C++代码,以CoreSession接口为例,说明其在mod_lua_wrap.cpp中的swig_type_initial和swig_CoreSession_methods结构体中的实现。
4053

被折叠的 条评论
为什么被折叠?



