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);
- freeswitch mrcp 源码分析--event事件产生
- freeswitch mrcp 源码分析--数据解析
- freeswitch mrcp 源码分析--数据接收(上)
- freeswitch mrcp 源码分析--数据接收(下)
- nova event事件源码分析
- jQuery源码分析之Event事件分析
- jQuery源码分析之Event事件分析
- nginx源码分析--event事件驱动初始化
- nginx源码分析--event事件驱动初始化
- Nginx源码分析 - Event事件篇 - epoll事件模块
- jQuery源码分析-10事件处理-Event-源码结构
- FreeSWITCH源码分析之mod_xml_curl
- Nginx源码分析 - Event事件篇 - Nginx的Event事件模块概览
- jQuery源码分析-10事件处理-Event-DOM-ready
- jQuery源码分析-10事件处理-Event-DOM-ready
- jQuery源码分析-10事件处理-Event-概述和基础知识
- jQuery源码分析-10事件处理-Event-DOM-ready
- storm事件管理器EventManager源码分析-event.clj
- 在eclipse中配置Go开发环境
- Android主流网络框架对比
- 求实数绝对值
- 牛客网 wannafly 月赛 完全平方数
- 模块独立性(一种软件设计原则)和面向对象设计原则
- freeswitch mrcp 源码分析--event事件产生
- 顺序表的增删查改&&各类排序问题
- Opencv编译生成的so文件及使用
- python连载第11篇 if 语句
- coding pages 搭建静态博客
- SDUT 2116-数据结构实验之链表一:顺序建立链表
- 三行Python代码搞定人脸识别
- 数据结构实验之查找七:线性之哈希表
- CodeForces 51 E.Pentagon(组合数学)