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

freeswitch lua/luarun的执行过程

2018-01-02 15:15 573 查看
在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 err
e4a6
or;
}


前面一段都是在处理参数最核心的是下面这一行

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等方法了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: