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

本文介绍MRCPv2消息的解析过程,包括消息头部、请求ID、方法名称及状态等关键字段的解析方法,并详细解释了如何通过解析确定消息类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



/** 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 <LF> occurred as a result of message segmentation between <CR> and <LF> */
		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}
};


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值