freeswitch mrcp 源码分析--数据解析


/** Parse message by raising corresponding event handlers */
APT_DECLARE(apt_message_status_e) apt_message_parser_run(apt_message_parser_t *parser, apt_text_stream_t *stream, void **message)
{
    const char *pos;
    apt_message_status_e status = APT_MESSAGE_STATUS_INCOMPLETE;
    if(parser->skip_lf == TRUE) {
        /* skip occurred as a result of message segmentation between and */
        apt_text_char_skip(stream,APT_TOKEN_LF);
        parser->skip_lf = FALSE;
    }
    if(message) {
        *message = NULL;
    }
 
    do {
        pos = stream->pos;
        if(parser->stage == APT_MESSAGE_STAGE_START_LINE) {
            if(parser->vtable->on_start(parser,&parser->context,stream,parser->pool) == FALSE) {
                if(apt_text_is_eos(stream) == FALSE) {
                    status = APT_MESSAGE_STATUS_INVALID;
                }
                break;
            }
            
            apt_crlf_segmentation_test(parser,stream);
 
            parser->stage = APT_MESSAGE_STAGE_HEADER;
        }
 
        if(parser->stage == APT_MESSAGE_STAGE_HEADER) {
            /* read header section */
            apt_bool_t res = apt_header_section_parse(parser->context.header,stream,parser->pool);
            if(parser->verbose == TRUE) {
                apr_size_t length = stream->pos - pos;
                apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Parsed Message Header [%"APR_SIZE_T_FMT" bytes]\n%.*s",
                        length, length, pos);
            }
            
            apt_crlf_segmentation_test(parser,stream);
 
            if(res == FALSE) {
                break;
            }
 
            if(parser->vtable->on_header_complete) {
                if(parser->vtable->on_header_complete(parser,&parser->context) == FALSE) {
                    status = APT_MESSAGE_STATUS_INVALID;
                    break;
                }
            }
            
            if(parser->context.body && parser->context.body->length) {
                apt_str_t *body = parser->context.body;
                parser->content_length = body->length;
                body->buf = apr_palloc(parser->pool,parser->content_length+1);
                body->buf[parser->content_length] = '\0';
                body->length = 0;
                parser->stage = APT_MESSAGE_STAGE_BODY;
            }
            else {
                status = APT_MESSAGE_STATUS_COMPLETE;
                if(message) {
                    *message = parser->context.message;
                }
                parser->stage = APT_MESSAGE_STAGE_START_LINE;
                break;
            }
        }
 
        if(parser->stage == APT_MESSAGE_STAGE_BODY) {
            if(apt_message_body_read(parser,stream) == FALSE) {
                break;
            }
            
            if(parser->vtable->on_body_complete) {
                parser->vtable->on_body_complete(parser,&parser->context);
            }
            status = APT_MESSAGE_STATUS_COMPLETE;
            if(message) {
                *message = parser->context.message;
            }
            parser->stage = APT_MESSAGE_STAGE_START_LINE;
            break;
        }
    }
    while(apt_text_is_eos(stream) == FALSE);
 
    return status;
}
 

首先apt_message_parser_run中首先调用

parser->vtable->on_start(parser,&parser->context,stream,parser->pool)

解析第一行,然后调用

parser->vtable->on_header_complete(parser,&parser->context)

解析其他部分。

这里vtable是一个apt_message_parser_vtable_t对象,他被初始化为:

static const apt_message_parser_vtable_t parser_vtable = {
mrcp_parser_on_start,
mrcp_parser_on_header_complete,
NULL
};

所以实际上他分别调用的是mrcp_parser_on_start()和mrcp_parser_on_header_complete()

/** Parse MRCP start-line */
MRCP_DECLARE(apt_bool_t) mrcp_start_line_parse(mrcp_start_line_t *start_line, apt_str_t *str, apr_pool_t *pool)
{
    apt_text_stream_t line;
    apt_str_t field;
    apt_bool_t status = TRUE;
 
    start_line->message_type = MRCP_MESSAGE_TYPE_UNKNOWN;
    apt_text_stream_init(&line,str->buf,str->length);
    if(apt_text_field_read(&line,APT_TOKEN_SP,TRUE,&field) == FALSE) {
        apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot read the first field in start-line");
        return FALSE;
    }
 
    if(field.buf == strstr(field.buf,MRCP_NAME)) {
        start_line->version = mrcp_version_parse(&field);
 
        if(start_line->version == MRCP_VERSION_1) {
            /* parsing MRCP v1 response */
            start_line->message_type = MRCP_MESSAGE_TYPE_RESPONSE;
            status = mrcp_response_line_parse(start_line,&line);
        }
        else if(start_line->version == MRCP_VERSION_2) {
            /* parsing MRCP v2 start-line (request/response/event) */
            status = mrcp_v2_start_line_parse(start_line,&line,pool);
        }
        else {
            apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown MRCP version");
            return FALSE;
        }
    }
    else {
        /* parsing MRCP v1 request or event */
        apt_string_copy(&start_line->method_name,&field,pool);
        status = mrcp_request_line_parse(start_line,&line);
    }
    return status;
}
在mrcp_start_line_parse()中先调用mrcp_version_parse()解析得到使用的MRCP的版本号,对于V2的显然会调用mrcp_v2_start_line_parse()做进一步的解析。

/** Parse MRCP v2 start-line */
static apt_bool_t mrcp_v2_start_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *stream, apr_pool_t *pool)
{
    apt_str_t field;
    if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
        apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse message-length in v2 start-line");
        return FALSE;
    }
    start_line->length = apt_size_value_parse(&field);
 
    if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
        apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-id in v2 start-line");
        return FALSE;
    }
    start_line->request_id = mrcp_request_id_parse(&field);
    if(start_line->request_id == 0 && *field.buf != '0') {
        /* parsing MRCP v2 request or event */
        start_line->message_type = MRCP_MESSAGE_TYPE_REQUEST;
        apt_string_copy(&start_line->method_name,&field,pool);
 
        if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
            apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-id in v2 start-line");
            return FALSE;
        }
        start_line->request_id = mrcp_request_id_parse(&field);
 
        if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == TRUE) {
            /* parsing MRCP v2 event */
            start_line->request_state = mrcp_request_state_parse(&field);
            start_line->message_type = MRCP_MESSAGE_TYPE_EVENT;
        }
    }
    else {
        /* parsing MRCP v2 response */
        start_line->message_type = MRCP_MESSAGE_TYPE_RESPONSE;
 
        if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
            apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse status-code in v2 start-line");
            return FALSE;
        }
        start_line->status_code = mrcp_status_code_parse(&field);
 
        if(apt_text_field_read(stream,APT_TOKEN_SP,TRUE,&field) == FALSE) {
            apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Cannot parse request-state in v2 start-line");
            return FALSE;
        }
        start_line->request_state = mrcp_request_state_parse(&field);
    }
 
    return TRUE;
}

接着,调用mrcp_start_line的mrcp_v2_start_line_parse()函数解析第一行文本MRCP/2.0后的内容:
MRCP/2.0 689 RECOGNITION-COMPLETE 9 COMPLETE 

首先调用apt_size_value_parse()获取数据长度也就是 689。然后调用mrcp_request_id_parse()获取request_id,这里有个坑,因为下一个是RECOGNITION-COMPLETE,他不是数字,所以获取id失败会返回0。所以接下来会执行apt_string_copy(&start_line->method_name,&field,pool);将RECOGNITION-COMPLETE 赋值给start_line->method_name。这个变量在后面会起到非常重要的作用。

然后调用mrcp_request_id_parse解析request_id。最后调用mrcp_request_state_parse得到状态。

/** Header section handler */
static apt_bool_t mrcp_parser_on_header_complete(apt_message_parser_t *parser, apt_message_context_t *context)
{
    mrcp_message_t *mrcp_message = context->message;
    if(mrcp_message->start_line.version == MRCP_VERSION_2) {
        mrcp_resource_t *resource;
        mrcp_parser_t *mrcp_parser;
        if(mrcp_channel_id_parse(&mrcp_message->channel_id,&mrcp_message->header,mrcp_message->pool) == FALSE) {
            return FALSE;
        }
        mrcp_parser = apt_message_parser_object_get(parser);
        /* find resource */
        resource = mrcp_resource_find(mrcp_parser->resource_factory,&mrcp_message->channel_id.resource_name);
        if(!resource) {
            return FALSE;
        }
 
        if(mrcp_message_resource_set(mrcp_message,resource) == FALSE) {
            return FALSE;
        }
    }
 
    if(mrcp_header_fields_parse(&mrcp_message->header,mrcp_message->pool) == FALSE) {
        return FALSE;
    }
 
    if(context->body && mrcp_generic_header_property_check(mrcp_message,GENERIC_HEADER_CONTENT_LENGTH) == TRUE) {
        mrcp_generic_header_t *generic_header = mrcp_generic_header_get(mrcp_message);
        if(generic_header && generic_header->content_length) {
            context->body->length = generic_header->content_length;
        }
    }
    return TRUE;
}


在mrcp_parser_on_header_complete中首相调用mrcp_channel_id_parse()解析通道号。

Channel-Identifier: b4f5e73a39b84816@speechrecog

然后调用mrcp_resource_find()找到通道对应的资源。

进而调用mrcp_message_resource_set()

/** Associate MRCP resource specific data by resource name */
MRCP_DECLARE(apt_bool_t) mrcp_message_resource_set(mrcp_message_t *message, const mrcp_resource_t *resource)
{
    if(!resource) {
        return FALSE;
    }
    message->resource = resource;
    mrcp_message_header_data_alloc(
        &message->header,
        mrcp_generic_header_vtable_get(message->start_line.version),
        resource->get_resource_header_vtable(message->start_line.version),
        message->pool);
    
    /* associate method_name and method_id */
    if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
        message->start_line.method_id = apt_string_table_id_find(
            resource->get_method_str_table(message->start_line.version),
            resource->method_count,
            &message->start_line.method_name);
        if(message->start_line.method_id >= resource->method_count) {
            return FALSE;
        }
    }
    else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
        message->start_line.method_id = apt_string_table_id_find(
            resource->get_event_str_table(message->start_line.version),
            resource->event_count,
            &message->start_line.method_name);
        if(message->start_line.method_id >= resource->event_count) {
            return FALSE;
        }
    }
 
    return TRUE;
}

找到事件对应的方法ID, 并设置给:message->start_line.method_id。这里resource->get_event_str_table(message->start_line.version)返回的就是:

/** String table of MRCPv2 recognizer events (mrcp_recognizer_event_id) */
static const apt_str_table_item_t v2_recog_event_string_table[] = {
{{"START-OF-INPUT",           14},0},
{{"RECOGNITION-COMPLETE",     20},0},
{{"INTERPRETATION-COMPLETE",  23},0}
};
————————————————
版权声明:本文为CSDN博主「罗自荣」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/luozirong/article/details/78857016

你可能感兴趣的:(Freeswitch,Freeswitch,Mrcp)