freeswitch mrcp 源码分析--event事件产生

来源:互联网 发布:取英文名字的软件 编辑:程序博客网 时间:2024/06/05 06:27

event事件的构建主要在speech_thread()函数里面。

static void *SWITCH_THREAD_FUNC speech_thread(switch_thread_t *thread, void *obj){    struct speech_thread_handle *sth = (struct speech_thread_handle *) obj;    switch_channel_t *channel = switch_core_session_get_channel(sth->session);    switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE;    switch_status_t status;    switch_event_t *event;    switch_thread_cond_create(&sth->cond, sth->pool);    switch_mutex_init(&sth->mutex, SWITCH_MUTEX_NESTED, sth->pool);    if (switch_core_session_read_lock(sth->session) != SWITCH_STATUS_SUCCESS) {        sth->ready = 0;        return NULL;    }    switch_mutex_lock(sth->mutex);    sth->ready = 1;    while (switch_channel_up_nosig(channel) && !switch_test_flag(sth->ah, SWITCH_ASR_FLAG_CLOSED)) {        char *xmlstr = NULL;        switch_event_t *headers = NULL;        switch_thread_cond_wait(sth->cond, sth->mutex);        if (switch_channel_down_nosig(channel) || switch_test_flag(sth->ah, SWITCH_ASR_FLAG_CLOSED)) {            break;        }        if (switch_core_asr_check_results(sth->ah, &flags) == SWITCH_STATUS_SUCCESS) {            status = switch_core_asr_get_results(sth->ah, &xmlstr, &flags);            if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {                goto done;            } else if (status == SWITCH_STATUS_SUCCESS) {                /* Try to fetch extra information for this result, the return value doesn't really matter here - it's just optional data. */                switch_core_asr_get_result_headers(sth->ah, &headers, &flags);            }            if (status == SWITCH_STATUS_SUCCESS && switch_true(switch_channel_get_variable(channel, "asr_intercept_dtmf"))) {                const char *p;                if ((p = switch_stristr("<input>", xmlstr))) {                    p += 7;                }                while (p && *p) {                    char c;                    if (*p == '<') {                        break;                    }                    if (!strncasecmp(p, "pound", 5)) {                        c = '#';                        p += 5;                    } else if (!strncasecmp(p, "hash", 4)) {                        c = '#';                        p += 4;                    } else if (!strncasecmp(p, "star", 4)) {                        c = '*';                        p += 4;                    } else if (!strncasecmp(p, "asterisk", 8)) {                        c = '*';                        p += 8;                    } else {                        c = *p;                        p++;                    }                    if (is_dtmf(c)) {                        switch_dtmf_t dtmf = {0};                        dtmf.digit = c;                        dtmf.duration = switch_core_default_dtmf_duration(0);                        dtmf.source = SWITCH_DTMF_INBAND_AUDIO;                        switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Queue speech detected dtmf %c\n", c);                        switch_channel_queue_dtmf(channel, &dtmf);                    }                }                switch_ivr_resume_detect_speech(sth->session);            }            if (switch_event_create(&event, SWITCH_EVENT_DETECTED_SPEECH) == SWITCH_STATUS_SUCCESS) {                if (status == SWITCH_STATUS_SUCCESS) {                    switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "detected-speech");                    if (headers) {                        switch_event_merge(event, headers);                    }                    switch_event_add_body(event, "%s", xmlstr);                } else {                    switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "begin-speaking");                }                if (switch_test_flag(sth->ah, SWITCH_ASR_FLAG_FIRE_EVENTS)) {                    switch_event_t *dup;                    if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {                        switch_channel_event_set_data(channel, dup);                        switch_event_fire(&dup);                    }                }                if (switch_core_session_queue_event(sth->session, &event) != SWITCH_STATUS_SUCCESS) {                    switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Event queue failed!\n");                    switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");                    switch_event_fire(&event);                }            }            switch_safe_free(xmlstr);            if (headers) {                switch_event_destroy(&headers);            }        }    }  done:    if (switch_event_create(&event, SWITCH_EVENT_DETECTED_SPEECH) == SWITCH_STATUS_SUCCESS) {        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "closed");        if (switch_test_flag(sth->ah, SWITCH_ASR_FLAG_FIRE_EVENTS)) {            switch_event_t *dup;            if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {                switch_channel_event_set_data(channel, dup);                switch_event_fire(&dup);            }        }        if (switch_core_session_queue_event(sth->session, &event) != SWITCH_STATUS_SUCCESS) {            switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Event queue failed!\n");            switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");            switch_event_fire(&event);        }    }    switch_mutex_unlock(sth->mutex);    switch_core_session_rwunlock(sth->session);    return NULL;}

可以看到里面是一个while循环,会阻塞在sth->cond这个信号了里面。在对应的session读取完一帧数据后会产生sth->cond这个信号量。这个信号量最后是在speech_callback里面产生的。详细的产生过程这里就不进行介绍。不过本人通过gdb调试将他的调用栈打了出来,可以自己分析一下。

#0  speech_callback (bug=0x7f7840125f68, user_data=0x7f7840135ce8, type=<optimized out>) at src/switch_ivr_async.c:4549#1  0x00007f788a3bb9e7 in switch_core_session_read_frame (session=session@entry=0x7f7840051608, frame=frame@entry=0x7f7883fae068, flags=flags@entry=0, stream_id=stream_id@entry=0) at src/switch_core_io.c:742#2  0x00007f788a427361 in audio_bridge_thread (obj=obj@entry=0x7f784012c8a0, thread=0x0) at src/switch_ivr_bridge.c:686#3  0x00007f788a4294d5 in switch_ivr_multi_threaded_bridge (session=0x7f7840051608, peer_session=0x7f784008d258, input_callback=<optimized out>, session_data=<optimized out>, peer_session_data=0x7f784002df40)    at src/switch_ivr_bridge.c:1616#4  0x00007f788a48c001 in bridge (session_a=..., session_b=...) at src/switch_cpp.cpp:1420#5  0x00007f783ee89461 in _wrap_bridge (L=0x7f7840003b40) at mod_lua_wrap.cpp:7791#6  0x00007f783ec4b328 in luaD_precall () from /lib64/liblua-5.1.so#7  0x00007f783ec55e7f in luaV_execute () from /lib64/liblua-5.1.so#8  0x00007f783ec4b73d in luaD_call () from /lib64/liblua-5.1.so#9  0x00007f783ec4aa6e in luaD_rawrunprotected () from /lib64/liblua-5.1.so#10 0x00007f783ec4b8ca in luaD_pcall () from /lib64/liblua-5.1.so#11 0x00007f783ec4744d in lua_pcall () from /lib64/liblua-5.1.so#12 0x00007f783ee765e2 in docall (L=0x7f7840003b40, narg=0, nresults=0, perror=0, fatal=1) at mod_lua.cpp:92#13 0x00007f783ee76bdd in lua_parse_and_execute (L=L@entry=0x7f7840003b40, input_code=<optimized out>, session=session@entry=0x0) at mod_lua.cpp:195#14 0x00007f783ee76c77 in lua_thread_run (thread=<optimized out>, obj=0x7f7840004c40) at mod_lua.cpp:222#15 0x00007f788a668210 in dummy_worker (opaque=0x7f7840004f48) at threadproc/unix/thread.c:151#16 0x00007f7888479dc5 in start_thread () from /lib64/libpthre

回到speech_thread函数
进程被唤醒后会执行switch_core_asr_check_results()这个函数,去检查是否有识别结果数据。

SWITCH_DECLARE(switch_status_t) switch_core_asr_check_results(switch_asr_handle_t *ah, switch_asr_flag_t *flags){    switch_assert(ah != NULL);    return ah->asr_interface->asr_check_results(ah, flags);}

asr_interface是个switch_asr_interface_t结构体指针,也是在recog_load()里面赋值的。

    asr_interface->interface_name = MOD_UNIMRCP;    asr_interface->asr_open = recog_asr_open;    asr_interface->asr_load_grammar = recog_asr_load_grammar;    asr_interface->asr_unload_grammar = recog_asr_unload_grammar;    asr_interface->asr_enable_grammar = recog_asr_enable_grammar;    asr_interface->asr_disable_grammar = recog_asr_disable_grammar;    asr_interface->asr_disable_all_grammars = recog_asr_disable_all_grammars;    asr_interface->asr_close = recog_asr_close;    asr_interface->asr_feed = recog_asr_feed;    asr_interface->asr_feed_dtmf = recog_asr_feed_dtmf;    asr_interface->asr_resume = recog_asr_resume;    asr_interface->asr_pause = recog_asr_pause;    asr_interface->asr_check_results = recog_asr_check_results;    asr_interface->asr_get_results = recog_asr_get_results;    asr_interface->asr_get_result_headers = recog_asr_get_result_headers;    asr_interface->asr_start_input_timers = recog_asr_start_input_timers;    asr_interface->asr_text_param = recog_asr_text_param;    asr_interface->asr_numeric_param = recog_asr_numeric_param;    asr_interface->asr_float_param = recog_asr_float_param;

所以其实调用的是recog_asr_check_results()。

static switch_status_t recog_asr_check_results(switch_asr_handle_t *ah, switch_asr_flag_t *flags){    speech_channel_t *schannel = (speech_channel_t *) ah->private_info;    return recog_channel_check_results(schannel);}
static switch_status_t recog_channel_check_results(speech_channel_t *schannel){    switch_status_t status = SWITCH_STATUS_SUCCESS;    recognizer_data_t *r;    switch_mutex_lock(schannel->mutex);    r = (recognizer_data_t *) schannel->data;    if (!zstr(r->result)) {        switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) SUCCESS, have result\n", schannel->name);    } else if (r->start_of_input == START_OF_INPUT_RECEIVED) {        switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) SUCCESS, start of input\n", schannel->name);    } else {        status = SWITCH_STATUS_FALSE;    }    switch_mutex_unlock(schannel->mutex);    return status;}

在上一篇博文freeswitch mrcp 源码分析–数据接收(下)里面,我们说过:识别结果的具体内容放到recognizer_data_t的result中。所以当有识别结果的时候:r->result 不为空,所以函数的返回是SWITCH_STATUS_SUCCESS。

if (switch_event_create(&event, SWITCH_EVENT_DETECTED_SPEECH) == SWITCH_STATUS_SUCCESS) {                if (status == SWITCH_STATUS_SUCCESS) {                    switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "detected-speech");                    if (headers) {                        switch_event_merge(event, headers);                    }                    switch_event_add_body(event, "%s", xmlstr);                } else {                    switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "begin-speaking");                }                if (switch_test_flag(sth->ah, SWITCH_ASR_FLAG_FIRE_EVENTS)) {                    switch_event_t *dup;                    if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {                        switch_channel_event_set_data(channel, dup);                        switch_event_fire(&dup);                    }                }                if (switch_core_session_queue_event(sth->session, &event) != SWITCH_STATUS_SUCCESS) {                    switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Event queue failed!\n");                    switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");                    switch_event_fire(&event);                }            }            switch_safe_free(xmlstr);            if (headers) {                switch_event_destroy(&headers);            }

接下来就是顺理成章的数据组装了,先调用switch_event_create()创建fs事件:

switch_event_create(&event, SWITCH_EVENT_DETECTED_SPEECH)

然后switch_event_add_header_string()和switch_event_merge()添加事件的头部信息:

switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "detected-speech");                    if (headers) {                        switch_event_merge(event, headers);                    }

然后调用switch_event_add_body()添加消息体。

switch_event_add_body(event, "%s", xmlstr);

最后调用switch_channel_event_set_data增加通道信息,并调用switch_event_fire将事件发出去:

switch_channel_event_set_data(channel, dup);switch_event_fire(&dup);