1 /*
2  * Copyright 2008-2014 Arsen Chaloyan
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * $Id: mrcp_stream.c 2136 2014-07-04 06:33:36Z achaloyan@gmail.com $
17  */
18 
19 #include "mrcp_stream.h"
20 #include "mrcp_message.h"
21 #include "mrcp_resource_factory.h"
22 #include "mrcp_resource.h"
23 #include "apt_log.h"
24 
25 
26 /** MRCP parser */
27 struct mrcp_parser_t {
28 	apt_message_parser_t          *base;
29 	const mrcp_resource_factory_t *resource_factory;
30 	mrcp_resource_t               *resource;
31 };
32 
33 /** MRCP generator */
34 struct mrcp_generator_t {
35 	apt_message_generator_t       *base;
36 	const mrcp_resource_factory_t *resource_factory;
37 };
38 
39 /** Create message and read start line */
40 static apt_bool_t mrcp_parser_on_start(apt_message_parser_t *parser, apt_message_context_t *context, apt_text_stream_t *stream, apr_pool_t *pool);
41 /** Header section handler */
42 static apt_bool_t mrcp_parser_on_header_complete(apt_message_parser_t *parser, apt_message_context_t *context);
43 
44 static const apt_message_parser_vtable_t parser_vtable = {
45 	mrcp_parser_on_start,
46 	mrcp_parser_on_header_complete,
47 	NULL
48 };
49 
50 /** Start message generation  */
51 apt_bool_t mrcp_generator_on_start(apt_message_generator_t *generator, apt_message_context_t *context, apt_text_stream_t *stream);
52 /** Finalize by setting overall message length in start line */
53 apt_bool_t mrcp_generator_on_header_complete(apt_message_generator_t *generator, apt_message_context_t *context, apt_text_stream_t *stream);
54 
55 static const apt_message_generator_vtable_t generator_vtable = {
56 	mrcp_generator_on_start,
57 	mrcp_generator_on_header_complete,
58 	NULL
59 };
60 
61 
62 /** Create MRCP stream parser */
mrcp_parser_create(const mrcp_resource_factory_t * resource_factory,apr_pool_t * pool)63 MRCP_DECLARE(mrcp_parser_t*) mrcp_parser_create(const mrcp_resource_factory_t *resource_factory, apr_pool_t *pool)
64 {
65 	mrcp_parser_t *parser = apr_palloc(pool,sizeof(mrcp_parser_t));
66 	parser->base = apt_message_parser_create(parser,&parser_vtable,pool);
67 	parser->resource_factory = resource_factory;
68 	parser->resource = NULL;
69 	return parser;
70 }
71 
72 /** Set resource by name to be used for parsing of MRCPv1 messages */
mrcp_parser_resource_set(mrcp_parser_t * parser,const apt_str_t * resource_name)73 MRCP_DECLARE(void) mrcp_parser_resource_set(mrcp_parser_t *parser, const apt_str_t *resource_name)
74 {
75 	if(resource_name) {
76 		parser->resource = mrcp_resource_find(parser->resource_factory,resource_name);
77 	}
78 }
79 
80 /** Set verbose mode for the parser */
mrcp_parser_verbose_set(mrcp_parser_t * parser,apt_bool_t verbose)81 MRCP_DECLARE(void) mrcp_parser_verbose_set(mrcp_parser_t *parser, apt_bool_t verbose)
82 {
83 	apt_message_parser_verbose_set(parser->base,verbose);
84 }
85 
86 /** Parse MRCP stream */
mrcp_parser_run(mrcp_parser_t * parser,apt_text_stream_t * stream,mrcp_message_t ** message)87 MRCP_DECLARE(apt_message_status_e) mrcp_parser_run(mrcp_parser_t *parser, apt_text_stream_t *stream, mrcp_message_t **message)
88 {
89 	return apt_message_parser_run(parser->base,stream,(void**)message);
90 }
91 
92 /** Create message and read start line */
mrcp_parser_on_start(apt_message_parser_t * parser,apt_message_context_t * context,apt_text_stream_t * stream,apr_pool_t * pool)93 static apt_bool_t mrcp_parser_on_start(apt_message_parser_t *parser, apt_message_context_t *context, apt_text_stream_t *stream, apr_pool_t *pool)
94 {
95 	mrcp_message_t *mrcp_message;
96 	apt_str_t start_line;
97 	/* read start line */
98 	if(apt_text_line_read(stream,&start_line) == FALSE) {
99 		return FALSE;
100 	}
101 
102 	/* create new MRCP message */
103 	mrcp_message = mrcp_message_create(pool);
104 	/* parse start-line */
105 	if(mrcp_start_line_parse(&mrcp_message->start_line,&start_line,mrcp_message->pool) == FALSE) {
106 		return FALSE;
107 	}
108 
109 	if(mrcp_message->start_line.version == MRCP_VERSION_1) {
110 		mrcp_parser_t *mrcp_parser = apt_message_parser_object_get(parser);
111 		if(!mrcp_parser->resource) {
112 			return FALSE;
113 		}
114 		apt_string_copy(
115 			&mrcp_message->channel_id.resource_name,
116 			&mrcp_parser->resource->name,
117 			pool);
118 
119 		if(mrcp_message_resource_set(mrcp_message,mrcp_parser->resource) == FALSE) {
120 			return FALSE;
121 		}
122 	}
123 
124 	context->message = mrcp_message;
125 	context->header = &mrcp_message->header.header_section;
126 	context->body = &mrcp_message->body;
127 	return TRUE;
128 }
129 
130 /** Header section handler */
mrcp_parser_on_header_complete(apt_message_parser_t * parser,apt_message_context_t * context)131 static apt_bool_t mrcp_parser_on_header_complete(apt_message_parser_t *parser, apt_message_context_t *context)
132 {
133 	mrcp_message_t *mrcp_message = context->message;
134 	if(mrcp_message->start_line.version == MRCP_VERSION_2) {
135 		mrcp_resource_t *resource;
136 		mrcp_parser_t *mrcp_parser;
137 		if(mrcp_channel_id_parse(&mrcp_message->channel_id,&mrcp_message->header,mrcp_message->pool) == FALSE) {
138 			return FALSE;
139 		}
140 		mrcp_parser = apt_message_parser_object_get(parser);
141 		/* find resource */
142 		resource = mrcp_resource_find(mrcp_parser->resource_factory,&mrcp_message->channel_id.resource_name);
143 		if(!resource) {
144 			return FALSE;
145 		}
146 
147 		if(mrcp_message_resource_set(mrcp_message,resource) == FALSE) {
148 			return FALSE;
149 		}
150 	}
151 
152 	if(mrcp_header_fields_parse(&mrcp_message->header,mrcp_message->pool) == FALSE) {
153 		return FALSE;
154 	}
155 
156 	if(context->body && mrcp_generic_header_property_check(mrcp_message,GENERIC_HEADER_CONTENT_LENGTH) == TRUE) {
157 		mrcp_generic_header_t *generic_header = mrcp_generic_header_get(mrcp_message);
158 		if(generic_header && generic_header->content_length) {
159 			context->body->length = generic_header->content_length;
160 		}
161 	}
162 	return TRUE;
163 }
164 
165 
166 /** Create MRCP stream generator */
mrcp_generator_create(const mrcp_resource_factory_t * resource_factory,apr_pool_t * pool)167 MRCP_DECLARE(mrcp_generator_t*) mrcp_generator_create(const mrcp_resource_factory_t *resource_factory, apr_pool_t *pool)
168 {
169 	mrcp_generator_t *generator = apr_palloc(pool,sizeof(mrcp_generator_t));
170 	generator->base = apt_message_generator_create(generator,&generator_vtable,pool);
171 	generator->resource_factory = resource_factory;
172 	return generator;
173 }
174 
175 /** Set verbose mode for the generator */
mrcp_generator_verbose_set(mrcp_generator_t * generator,apt_bool_t verbose)176 MRCP_DECLARE(void) mrcp_generator_verbose_set(mrcp_generator_t *generator, apt_bool_t verbose)
177 {
178 	apt_message_generator_verbose_set(generator->base,verbose);
179 }
180 
181 /** Generate MRCP stream */
mrcp_generator_run(mrcp_generator_t * generator,mrcp_message_t * message,apt_text_stream_t * stream)182 MRCP_DECLARE(apt_message_status_e) mrcp_generator_run(mrcp_generator_t *generator, mrcp_message_t *message, apt_text_stream_t *stream)
183 {
184 	return apt_message_generator_run(generator->base,message,stream);
185 }
186 
187 /** Initialize by generating message start line and return header section and body */
mrcp_generator_on_start(apt_message_generator_t * generator,apt_message_context_t * context,apt_text_stream_t * stream)188 apt_bool_t mrcp_generator_on_start(apt_message_generator_t *generator, apt_message_context_t *context, apt_text_stream_t *stream)
189 {
190 	mrcp_message_t *mrcp_message = context->message;
191 	/* validate message */
192 	if(mrcp_message_validate(mrcp_message) == FALSE) {
193 		return FALSE;
194 	}
195 	/* generate start-line */
196 	if(mrcp_start_line_generate(&mrcp_message->start_line,stream) == FALSE) {
197 		return FALSE;
198 	}
199 
200 	if(mrcp_message->start_line.version == MRCP_VERSION_2) {
201 		mrcp_channel_id_generate(&mrcp_message->channel_id,stream);
202 	}
203 
204 	context->header = &mrcp_message->header.header_section;
205 	context->body = &mrcp_message->body;
206 	return TRUE;
207 }
208 
209 /** Finalize by setting overall message length in start line */
mrcp_generator_on_header_complete(apt_message_generator_t * generator,apt_message_context_t * context,apt_text_stream_t * stream)210 apt_bool_t mrcp_generator_on_header_complete(apt_message_generator_t *generator, apt_message_context_t *context, apt_text_stream_t *stream)
211 {
212 	mrcp_message_t *mrcp_message = context->message;
213 	/* finalize start-line generation */
214 	return mrcp_start_line_finalize(&mrcp_message->start_line,mrcp_message->body.length,stream);
215 }
216 
217 /** Generate MRCP message (excluding message body) */
mrcp_message_generate(const mrcp_resource_factory_t * resource_factory,mrcp_message_t * message,apt_text_stream_t * stream)218 MRCP_DECLARE(apt_bool_t) mrcp_message_generate(const mrcp_resource_factory_t *resource_factory, mrcp_message_t *message, apt_text_stream_t *stream)
219 {
220 	/* validate message */
221 	if(mrcp_message_validate(message) == FALSE) {
222 		return FALSE;
223 	}
224 
225 	/* generate start-line */
226 	if(mrcp_start_line_generate(&message->start_line,stream) == FALSE) {
227 		return FALSE;
228 	}
229 
230 	if(message->start_line.version == MRCP_VERSION_2) {
231 		mrcp_channel_id_generate(&message->channel_id,stream);
232 	}
233 
234 	/* generate header section */
235 	if(apt_header_section_generate(&message->header.header_section,stream) == FALSE) {
236 		return FALSE;
237 	}
238 
239 	/* finalize start-line generation */
240 	if(mrcp_start_line_finalize(&message->start_line,message->body.length,stream) == FALSE) {
241 		return FALSE;
242 	}
243 
244 	return TRUE;
245 }
246