在前两篇我们介绍了mrcp接收后的处理,最后会调用apr_queue_push扔到消息队列里面。
对应的,在apt_consumer_task.apt_consumer_task_run()中会循环调用pr_queue.apr_queue_pop()从队列里面取出数据:
apt_consumer_task.apt_consumer_task_run –>
apr_queue.apr_queue_pop –>
apt_task.apt_task_msg_process –>
mrcp_client.mrcp_client_msg_process –>
mrcp_client_session.mrcp_client_on_message_receive–>
mrcp_client_session.mrcp_app_control_message_raise–>
mod_unimrcp.recog_message_handler –> mrcp_application.mrcp_application_message_dispatch–>
mod_unimrcp.recog_on_message_receive–>
mod_unimrcp.recog_channel_set_result_headers–>
mod_unimrcp.recog_channel_set_results–>
mod_unimrcp.speech_channel_set_state
在apt_consumer_task_run中是一个while循环,调用apr_queue_pop不断去读取队列数据。然后调用apt_task_msg_process处理取出来的数据。
APT_DECLARE(apt_bool_t) apt_task_msg_process(apt_task_t *task, apt_task_msg_t *msg)
{
apt_bool_t status = FALSE;
apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process Message [%s] ["APT_PTR_FMT";%d;%d]",
task->name, msg, msg->type, msg->sub_type);
if(msg->type == TASK_MSG_CORE) {
status = apt_core_task_msg_process(task,msg);
}
else {
if(task->vtable.process_msg) {
status = task->vtable.process_msg(task,msg);
}
}
apt_task_msg_release(msg);
return status;
}
这里主要调用task->vtable.process_msg来处理。在mrcp_client_create函数中,process_msg 被赋值为mrcp_client_msg_process:
vtable = apt_task_vtable_get(task);
if(vtable) {
vtable->process_msg = mrcp_client_msg_process;
vtable->on_start_complete = mrcp_client_on_start_complete;
vtable->on_terminate_complete = mrcp_client_on_terminate_complete;
}
所以实际上调用的是mrcp_client_msg_process()。消息的type为:MRCP_CLIENT_CONNECTION_TASK_MSG,subtype为:CONNECTION_AGENT_TASK_MSG_RECEIVE_MESSAGE,所以会调用mrcp_client_on_message_receive,进而调用mrcp_app_control_message_raise()。
static apt_bool_t mrcp_app_control_message_raise(mrcp_client_session_t *session, mrcp_channel_t *channel, mrcp_message_t *mrcp_message)
{
if(mrcp_message->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
mrcp_app_message_t *response;
mrcp_message_t *mrcp_request;
if(!session->active_request || !session->active_request->control_message) {
return FALSE;
}
response = mrcp_client_app_response_create(session->active_request,0,session->base.pool);
mrcp_request = session->active_request->control_message;
mrcp_message->start_line.method_id = mrcp_request->start_line.method_id;
mrcp_message->start_line.method_name = mrcp_request->start_line.method_name;
response->control_message = mrcp_message;
apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Raise App MRCP Response "APT_NAMESID_FMT,
MRCP_SESSION_NAMESID(session));
session->application->handler(response);
session->active_request = apt_list_pop_front(session->request_queue);
if(session->active_request) {
mrcp_app_request_dispatch(session,session->active_request);
}
}
else if(mrcp_message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
mrcp_app_message_t *app_message;
app_message = mrcp_client_app_control_message_create(session->base.pool);
app_message->control_message = mrcp_message;
app_message->application = session->application;
app_message->session = &session->base;
app_message->channel = channel;
apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Raise App MRCP Event "APT_NAMESID_FMT,
MRCP_SESSION_NAMESID(session));
session->application->handler(app_message);
}
return TRUE;
}
最终调用的是session->application->handler(app_message),application是一个mrcp_application_t对象。在recog_load()的时候创建
/* Create the recognizer application and link its callbacks */
if ((globals.recog.app = mrcp_application_create(recog_message_handler, (void *) 0, pool)) == NULL) {
return SWITCH_STATUS_FALSE;
}
mrcp_application_create的实现如下:
/** Create application instance */
MRCP_DECLARE(mrcp_application_t*) mrcp_application_create(const mrcp_app_message_handler_f handler, void *obj, apr_pool_t *pool)
{
mrcp_application_t *application;
if(!handler) {
return FALSE;
}
apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create Application");
application = apr_palloc(pool,sizeof(mrcp_application_t));
application->obj = obj;
application->handler = handler;
application->client = NULL;
return application;
}
所以最后调用的是recog_message_handler(),进而调用mrcp_application_message_dispatch()。message_type为:MRCP_APP_MESSAGE_TYPE_CONTROL。
case MRCP_APP_MESSAGE_TYPE_CONTROL:
{
if(dispatcher->on_message_receive) {
status = dispatcher->on_message_receive(
app_message->application,
app_message->session,
app_message->channel,
app_message->control_message);
}
break;
}
在recog_load()函数中
globals.recog.dispatcher.on_session_update = NULL;
globals.recog.dispatcher.on_session_terminate = speech_on_session_terminate;
globals.recog.dispatcher.on_channel_add = speech_on_channel_add;
globals.recog.dispatcher.on_channel_remove = speech_on_channel_remove;
globals.recog.dispatcher.on_message_receive = recog_on_message_receive;
所以实际上调用的是:recog_on_message_receive()。
/**
* Handle the MRCP responses/events
*/
static apt_bool_t recog_on_message_receive(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message)
{
speech_channel_t *schannel = (speech_channel_t *) mrcp_application_channel_object_get(channel);
mrcp_recog_header_t *recog_hdr = (mrcp_recog_header_t *) mrcp_resource_header_get(message);
if (message->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
/* received MRCP response */
if (message->start_line.method_id == RECOGNIZER_RECOGNIZE) {
/* received the response to RECOGNIZE request */
if (message->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS) {
/* RECOGNIZE in progress */
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) RECOGNIZE IN PROGRESS\n", schannel->name);
speech_channel_set_state(schannel, SPEECH_CHANNEL_PROCESSING);
} else if (message->start_line.request_state == MRCP_REQUEST_STATE_COMPLETE) {
/* RECOGNIZE failed to start */
if (!recog_hdr || recog_hdr->completion_cause == RECOGNIZER_COMPLETION_CAUSE_UNKNOWN) {
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) RECOGNIZE failed: status = %d\n", schannel->name,
message->start_line.status_code);
} else {
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) RECOGNIZE failed: status = %d, completion-cause = %03d\n",
schannel->name, message->start_line.status_code, recog_hdr->completion_cause);
}
speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR);
} else if (message->start_line.request_state == MRCP_REQUEST_STATE_PENDING) {
/* RECOGNIZE is queued */
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) RECOGNIZE PENDING\n", schannel->name);
} else {
/* received unexpected request_state */
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) unexpected RECOGNIZE request state: %d\n", schannel->name,
message->start_line.request_state);
speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR);
}
} else if (message->start_line.method_id == RECOGNIZER_STOP) {
/* received response to the STOP request */
if (message->start_line.request_state == MRCP_REQUEST_STATE_COMPLETE) {
/* got COMPLETE */
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) RECOGNIZE STOPPED\n", schannel->name);
speech_channel_set_state(schannel, SPEECH_CHANNEL_READY);
} else {
/* received unexpected request state */
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) unexpected STOP request state: %d\n", schannel->name,
message->start_line.request_state);
speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR);
}
} else if (message->start_line.method_id == RECOGNIZER_START_INPUT_TIMERS) {
/* received response to START-INPUT-TIMERS request */
if (message->start_line.request_state == MRCP_REQUEST_STATE_COMPLETE) {
if (message->start_line.status_code >= 200 && message->start_line.status_code <= 299) {
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) timers started\n", schannel->name);
recog_channel_set_timers_started(schannel);
} else {
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) timers failed to start, status code = %d\n", schannel->name,
message->start_line.status_code);
}
}
} else if (message->start_line.method_id == RECOGNIZER_DEFINE_GRAMMAR) {
/* received response to DEFINE-GRAMMAR request */
if (message->start_line.request_state == MRCP_REQUEST_STATE_COMPLETE) {
if (message->start_line.status_code >= 200 && message->start_line.status_code <= 299) {
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) grammar loaded\n", schannel->name);
speech_channel_set_state(schannel, SPEECH_CHANNEL_READY);
} else {
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) grammar failed to load, status code = %d\n", schannel->name,
message->start_line.status_code);
speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR);
}
}
} else {
/* received unexpected response */
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) unexpected response, method_id = %d\n", schannel->name,
(int) message->start_line.method_id);
speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR);
}
} else if (message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
/* received MRCP event */
if (message->start_line.method_id == RECOGNIZER_RECOGNITION_COMPLETE) {
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) RECOGNITION COMPLETE, Completion-Cause: %03d\n", schannel->name,
recog_hdr->completion_cause);
if (message->body.length > 0) {
if (message->body.buf[message->body.length - 1] == '\0') {
recog_channel_set_result_headers(schannel, recog_hdr);
recog_channel_set_results(schannel, message->body.buf);
} else {
/* string is not null terminated */
char *result = (char *) switch_core_alloc(schannel->memory_pool, message->body.length + 1);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
"(%s) Recognition result is not null-terminated. Appending null terminator.\n", schannel->name);
strncpy(result, message->body.buf, message->body.length);
result[message->body.length] = '\0';
recog_channel_set_result_headers(schannel, recog_hdr);
recog_channel_set_results(schannel, result);
}
} else {
char *completion_cause = switch_mprintf("Completion-Cause: %03d", recog_hdr->completion_cause);
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) No result\n", schannel->name);
recog_channel_set_result_headers(schannel, recog_hdr);
recog_channel_set_results(schannel, completion_cause);
switch_safe_free(completion_cause);
}
speech_channel_set_state(schannel, SPEECH_CHANNEL_READY);
} else if (message->start_line.method_id == RECOGNIZER_START_OF_INPUT) {
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) START OF INPUT\n", schannel->name);
recog_channel_set_start_of_input(schannel);
} else {
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) unexpected event, method_id = %d\n", schannel->name,
(int) message->start_line.method_id);
speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR);
}
} else {
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) unexpected message type, message_type = %d\n", schannel->name,
message->start_line.message_type);
speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR);
}
return TRUE;
}
在这里干了几件实事!在介绍之前先介绍一个对象
speech_channel_t,每个通道都有一个speech_channel_t对象,speech_channel_t里面有个属性叫data,类型为recognizer_data_t。
这个就是用来保存识别结果的,非常重要,后面会看到每一个数据传输周期后都会校验一下是否有识别结果并上传给上层应用。
这里做的事情主要有:
1.recog_channel_set_result_headers
将识别结果的头部信息放到recognizer_data_t的result_headers中。
2.recog_channel_set_results
将识别结果的具体内容放到recognizer_data_t的result中。
3.speech_channel_set_state
更新通道的状态