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: demo_recog_engine.c 2193 2014-10-08 03:44:33Z achaloyan@gmail.com $
17  */
18 
19 /*
20  * Mandatory rules concerning plugin implementation.
21  * 1. Each plugin MUST implement a plugin/engine creator function
22  *    with the exact signature and name (the main entry point)
23  *        MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
24  * 2. Each plugin MUST declare its version number
25  *        MRCP_PLUGIN_VERSION_DECLARE
26  * 3. One and only one response MUST be sent back to the received request.
27  * 4. Methods (callbacks) of the MRCP engine channel MUST not block.
28  *   (asynchronous response can be sent from the context of other thread)
29  * 5. Methods (callbacks) of the MPF engine stream MUST not block.
30  */
31 
32 #include "mrcp_recog_engine.h"
33 #include "mpf_activity_detector.h"
34 #include "apt_consumer_task.h"
35 #include "apt_log.h"
36 
37 #define RECOG_ENGINE_TASK_NAME "Demo Recog Engine"
38 
39 typedef struct demo_recog_engine_t demo_recog_engine_t;
40 typedef struct demo_recog_channel_t demo_recog_channel_t;
41 typedef struct demo_recog_msg_t demo_recog_msg_t;
42 
43 /** Declaration of recognizer engine methods */
44 static apt_bool_t demo_recog_engine_destroy(mrcp_engine_t *engine);
45 static apt_bool_t demo_recog_engine_open(mrcp_engine_t *engine);
46 static apt_bool_t demo_recog_engine_close(mrcp_engine_t *engine);
47 static mrcp_engine_channel_t* demo_recog_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool);
48 
49 static const struct mrcp_engine_method_vtable_t engine_vtable = {
50 	demo_recog_engine_destroy,
51 	demo_recog_engine_open,
52 	demo_recog_engine_close,
53 	demo_recog_engine_channel_create
54 };
55 
56 
57 /** Declaration of recognizer channel methods */
58 static apt_bool_t demo_recog_channel_destroy(mrcp_engine_channel_t *channel);
59 static apt_bool_t demo_recog_channel_open(mrcp_engine_channel_t *channel);
60 static apt_bool_t demo_recog_channel_close(mrcp_engine_channel_t *channel);
61 static apt_bool_t demo_recog_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *request);
62 
63 static const struct mrcp_engine_channel_method_vtable_t channel_vtable = {
64 	demo_recog_channel_destroy,
65 	demo_recog_channel_open,
66 	demo_recog_channel_close,
67 	demo_recog_channel_request_process
68 };
69 
70 /** Declaration of recognizer audio stream methods */
71 static apt_bool_t demo_recog_stream_destroy(mpf_audio_stream_t *stream);
72 static apt_bool_t demo_recog_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec);
73 static apt_bool_t demo_recog_stream_close(mpf_audio_stream_t *stream);
74 static apt_bool_t demo_recog_stream_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame);
75 
76 static const mpf_audio_stream_vtable_t audio_stream_vtable = {
77 	demo_recog_stream_destroy,
78 	NULL,
79 	NULL,
80 	NULL,
81 	demo_recog_stream_open,
82 	demo_recog_stream_close,
83 	demo_recog_stream_write,
84 	NULL
85 };
86 
87 /** Declaration of demo recognizer engine */
88 struct demo_recog_engine_t {
89 	apt_consumer_task_t    *task;
90 };
91 
92 /** Declaration of demo recognizer channel */
93 struct demo_recog_channel_t {
94 	/** Back pointer to engine */
95 	demo_recog_engine_t     *demo_engine;
96 	/** Engine channel base */
97 	mrcp_engine_channel_t   *channel;
98 
99 	/** Active (in-progress) recognition request */
100 	mrcp_message_t          *recog_request;
101 	/** Pending stop response */
102 	mrcp_message_t          *stop_response;
103 	/** Indicates whether input timers are started */
104 	apt_bool_t               timers_started;
105 	/** Voice activity detector */
106 	mpf_activity_detector_t *detector;
107 	/** File to write utterance to */
108 	FILE                    *audio_out;
109 };
110 
111 typedef enum {
112 	DEMO_RECOG_MSG_OPEN_CHANNEL,
113 	DEMO_RECOG_MSG_CLOSE_CHANNEL,
114 	DEMO_RECOG_MSG_REQUEST_PROCESS
115 } demo_recog_msg_type_e;
116 
117 /** Declaration of demo recognizer task message */
118 struct demo_recog_msg_t {
119 	demo_recog_msg_type_e  type;
120 	mrcp_engine_channel_t *channel;
121 	mrcp_message_t        *request;
122 };
123 
124 static apt_bool_t demo_recog_msg_signal(demo_recog_msg_type_e type, mrcp_engine_channel_t *channel, mrcp_message_t *request);
125 static apt_bool_t demo_recog_msg_process(apt_task_t *task, apt_task_msg_t *msg);
126 
127 /** Declare this macro to set plugin version */
128 MRCP_PLUGIN_VERSION_DECLARE
129 
130 /** Declare this macro to use log routine of the server, plugin is loaded from */
131 MRCP_PLUGIN_LOGGER_IMPLEMENT
132 
133 /** Create demo recognizer engine */
MRCP_PLUGIN_DECLARE(mrcp_engine_t *)134 MRCP_PLUGIN_DECLARE(mrcp_engine_t*) mrcp_plugin_create(apr_pool_t *pool)
135 {
136 	demo_recog_engine_t *demo_engine = apr_palloc(pool,sizeof(demo_recog_engine_t));
137 	apt_task_t *task;
138 	apt_task_vtable_t *vtable;
139 	apt_task_msg_pool_t *msg_pool;
140 
141 	msg_pool = apt_task_msg_pool_create_dynamic(sizeof(demo_recog_msg_t),pool);
142 	demo_engine->task = apt_consumer_task_create(demo_engine,msg_pool,pool);
143 	if(!demo_engine->task) {
144 		return NULL;
145 	}
146 	task = apt_consumer_task_base_get(demo_engine->task);
147 	apt_task_name_set(task,RECOG_ENGINE_TASK_NAME);
148 	vtable = apt_task_vtable_get(task);
149 	if(vtable) {
150 		vtable->process_msg = demo_recog_msg_process;
151 	}
152 
153 	/* create engine base */
154 	return mrcp_engine_create(
155 				MRCP_RECOGNIZER_RESOURCE,  /* MRCP resource identifier */
156 				demo_engine,               /* object to associate */
157 				&engine_vtable,            /* virtual methods table of engine */
158 				pool);                     /* pool to allocate memory from */
159 }
160 
161 /** Destroy recognizer engine */
demo_recog_engine_destroy(mrcp_engine_t * engine)162 static apt_bool_t demo_recog_engine_destroy(mrcp_engine_t *engine)
163 {
164 	demo_recog_engine_t *demo_engine = engine->obj;
165 	if(demo_engine->task) {
166 		apt_task_t *task = apt_consumer_task_base_get(demo_engine->task);
167 		apt_task_destroy(task);
168 		demo_engine->task = NULL;
169 	}
170 	return TRUE;
171 }
172 
173 /** Open recognizer engine */
demo_recog_engine_open(mrcp_engine_t * engine)174 static apt_bool_t demo_recog_engine_open(mrcp_engine_t *engine)
175 {
176 	demo_recog_engine_t *demo_engine = engine->obj;
177 	if(demo_engine->task) {
178 		apt_task_t *task = apt_consumer_task_base_get(demo_engine->task);
179 		apt_task_start(task);
180 	}
181 	return mrcp_engine_open_respond(engine,TRUE);
182 }
183 
184 /** Close recognizer engine */
demo_recog_engine_close(mrcp_engine_t * engine)185 static apt_bool_t demo_recog_engine_close(mrcp_engine_t *engine)
186 {
187 	demo_recog_engine_t *demo_engine = engine->obj;
188 	if(demo_engine->task) {
189 		apt_task_t *task = apt_consumer_task_base_get(demo_engine->task);
190 		apt_task_terminate(task,TRUE);
191 	}
192 	return mrcp_engine_close_respond(engine);
193 }
194 
demo_recog_engine_channel_create(mrcp_engine_t * engine,apr_pool_t * pool)195 static mrcp_engine_channel_t* demo_recog_engine_channel_create(mrcp_engine_t *engine, apr_pool_t *pool)
196 {
197 	mpf_stream_capabilities_t *capabilities;
198 	mpf_termination_t *termination;
199 
200 	/* create demo recog channel */
201 	demo_recog_channel_t *recog_channel = apr_palloc(pool,sizeof(demo_recog_channel_t));
202 	recog_channel->demo_engine = engine->obj;
203 	recog_channel->recog_request = NULL;
204 	recog_channel->stop_response = NULL;
205 	recog_channel->detector = mpf_activity_detector_create(pool);
206 	recog_channel->audio_out = NULL;
207 
208 	capabilities = mpf_sink_stream_capabilities_create(pool);
209 	mpf_codec_capabilities_add(
210 			&capabilities->codecs,
211 			MPF_SAMPLE_RATE_8000 | MPF_SAMPLE_RATE_16000,
212 			"LPCM");
213 
214 	/* create media termination */
215 	termination = mrcp_engine_audio_termination_create(
216 			recog_channel,        /* object to associate */
217 			&audio_stream_vtable, /* virtual methods table of audio stream */
218 			capabilities,         /* stream capabilities */
219 			pool);                /* pool to allocate memory from */
220 
221 	/* create engine channel base */
222 	recog_channel->channel = mrcp_engine_channel_create(
223 			engine,               /* engine */
224 			&channel_vtable,      /* virtual methods table of engine channel */
225 			recog_channel,        /* object to associate */
226 			termination,          /* associated media termination */
227 			pool);                /* pool to allocate memory from */
228 
229 	return recog_channel->channel;
230 }
231 
232 /** Destroy engine channel */
demo_recog_channel_destroy(mrcp_engine_channel_t * channel)233 static apt_bool_t demo_recog_channel_destroy(mrcp_engine_channel_t *channel)
234 {
235 	/* nothing to destrtoy */
236 	return TRUE;
237 }
238 
239 /** Open engine channel (asynchronous response MUST be sent)*/
demo_recog_channel_open(mrcp_engine_channel_t * channel)240 static apt_bool_t demo_recog_channel_open(mrcp_engine_channel_t *channel)
241 {
242 	return demo_recog_msg_signal(DEMO_RECOG_MSG_OPEN_CHANNEL,channel,NULL);
243 }
244 
245 /** Close engine channel (asynchronous response MUST be sent)*/
demo_recog_channel_close(mrcp_engine_channel_t * channel)246 static apt_bool_t demo_recog_channel_close(mrcp_engine_channel_t *channel)
247 {
248 	return demo_recog_msg_signal(DEMO_RECOG_MSG_CLOSE_CHANNEL,channel,NULL);
249 }
250 
251 /** Process MRCP channel request (asynchronous response MUST be sent)*/
demo_recog_channel_request_process(mrcp_engine_channel_t * channel,mrcp_message_t * request)252 static apt_bool_t demo_recog_channel_request_process(mrcp_engine_channel_t *channel, mrcp_message_t *request)
253 {
254 	return demo_recog_msg_signal(DEMO_RECOG_MSG_REQUEST_PROCESS,channel,request);
255 }
256 
257 /** Process RECOGNIZE request */
demo_recog_channel_recognize(mrcp_engine_channel_t * channel,mrcp_message_t * request,mrcp_message_t * response)258 static apt_bool_t demo_recog_channel_recognize(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
259 {
260 	/* process RECOGNIZE request */
261 	mrcp_recog_header_t *recog_header;
262 	demo_recog_channel_t *recog_channel = channel->method_obj;
263 	const mpf_codec_descriptor_t *descriptor = mrcp_engine_sink_stream_codec_get(channel);
264 
265 	if(!descriptor) {
266 		apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Get Codec Descriptor "APT_SIDRES_FMT, MRCP_MESSAGE_SIDRES(request));
267 		response->start_line.status_code = MRCP_STATUS_CODE_METHOD_FAILED;
268 		return FALSE;
269 	}
270 
271 	recog_channel->timers_started = TRUE;
272 
273 	/* get recognizer header */
274 	recog_header = mrcp_resource_header_get(request);
275 	if(recog_header) {
276 		if(mrcp_resource_header_property_check(request,RECOGNIZER_HEADER_START_INPUT_TIMERS) == TRUE) {
277 			recog_channel->timers_started = recog_header->start_input_timers;
278 		}
279 		if(mrcp_resource_header_property_check(request,RECOGNIZER_HEADER_NO_INPUT_TIMEOUT) == TRUE) {
280 			mpf_activity_detector_noinput_timeout_set(recog_channel->detector,recog_header->no_input_timeout);
281 		}
282 		if(mrcp_resource_header_property_check(request,RECOGNIZER_HEADER_SPEECH_COMPLETE_TIMEOUT) == TRUE) {
283 			mpf_activity_detector_silence_timeout_set(recog_channel->detector,recog_header->speech_complete_timeout);
284 		}
285 	}
286 
287 	if(!recog_channel->audio_out) {
288 		const apt_dir_layout_t *dir_layout = channel->engine->dir_layout;
289 		char *file_name = apr_psprintf(channel->pool,"utter-%dkHz-%s.pcm",
290 							descriptor->sampling_rate/1000,
291 							request->channel_id.session_id.buf);
292 		char *file_path = apt_vardir_filepath_get(dir_layout,file_name,channel->pool);
293 		if(file_path) {
294 			apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open Utterance Output File [%s] for Writing",file_path);
295 			recog_channel->audio_out = fopen(file_path,"wb");
296 			if(!recog_channel->audio_out) {
297 				apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Utterance Output File [%s] for Writing",file_path);
298 			}
299 		}
300 	}
301 
302 	response->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
303 	/* send asynchronous response */
304 	mrcp_engine_channel_message_send(channel,response);
305 	recog_channel->recog_request = request;
306 	return TRUE;
307 }
308 
309 /** Process STOP request */
demo_recog_channel_stop(mrcp_engine_channel_t * channel,mrcp_message_t * request,mrcp_message_t * response)310 static apt_bool_t demo_recog_channel_stop(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
311 {
312 	/* process STOP request */
313 	demo_recog_channel_t *recog_channel = channel->method_obj;
314 	/* store STOP request, make sure there is no more activity and only then send the response */
315 	recog_channel->stop_response = response;
316 	return TRUE;
317 }
318 
319 /** Process START-INPUT-TIMERS request */
demo_recog_channel_timers_start(mrcp_engine_channel_t * channel,mrcp_message_t * request,mrcp_message_t * response)320 static apt_bool_t demo_recog_channel_timers_start(mrcp_engine_channel_t *channel, mrcp_message_t *request, mrcp_message_t *response)
321 {
322 	demo_recog_channel_t *recog_channel = channel->method_obj;
323 	recog_channel->timers_started = TRUE;
324 	return mrcp_engine_channel_message_send(channel,response);
325 }
326 
327 /** Dispatch MRCP request */
demo_recog_channel_request_dispatch(mrcp_engine_channel_t * channel,mrcp_message_t * request)328 static apt_bool_t demo_recog_channel_request_dispatch(mrcp_engine_channel_t *channel, mrcp_message_t *request)
329 {
330 	apt_bool_t processed = FALSE;
331 	mrcp_message_t *response = mrcp_response_create(request,request->pool);
332 	switch(request->start_line.method_id) {
333 		case RECOGNIZER_SET_PARAMS:
334 			break;
335 		case RECOGNIZER_GET_PARAMS:
336 			break;
337 		case RECOGNIZER_DEFINE_GRAMMAR:
338 			break;
339 		case RECOGNIZER_RECOGNIZE:
340 			processed = demo_recog_channel_recognize(channel,request,response);
341 			break;
342 		case RECOGNIZER_GET_RESULT:
343 			break;
344 		case RECOGNIZER_START_INPUT_TIMERS:
345 			processed = demo_recog_channel_timers_start(channel,request,response);
346 			break;
347 		case RECOGNIZER_STOP:
348 			processed = demo_recog_channel_stop(channel,request,response);
349 			break;
350 		default:
351 			break;
352 	}
353 	if(processed == FALSE) {
354 		/* send asynchronous response for not handled request */
355 		mrcp_engine_channel_message_send(channel,response);
356 	}
357 	return TRUE;
358 }
359 
360 /** Callback is called from MPF engine context to destroy any additional data associated with audio stream */
demo_recog_stream_destroy(mpf_audio_stream_t * stream)361 static apt_bool_t demo_recog_stream_destroy(mpf_audio_stream_t *stream)
362 {
363 	return TRUE;
364 }
365 
366 /** Callback is called from MPF engine context to perform any action before open */
demo_recog_stream_open(mpf_audio_stream_t * stream,mpf_codec_t * codec)367 static apt_bool_t demo_recog_stream_open(mpf_audio_stream_t *stream, mpf_codec_t *codec)
368 {
369 	return TRUE;
370 }
371 
372 /** Callback is called from MPF engine context to perform any action after close */
demo_recog_stream_close(mpf_audio_stream_t * stream)373 static apt_bool_t demo_recog_stream_close(mpf_audio_stream_t *stream)
374 {
375 	return TRUE;
376 }
377 
378 /* Raise demo START-OF-INPUT event */
demo_recog_start_of_input(demo_recog_channel_t * recog_channel)379 static apt_bool_t demo_recog_start_of_input(demo_recog_channel_t *recog_channel)
380 {
381 	/* create START-OF-INPUT event */
382 	mrcp_message_t *message = mrcp_event_create(
383 						recog_channel->recog_request,
384 						RECOGNIZER_START_OF_INPUT,
385 						recog_channel->recog_request->pool);
386 	if(!message) {
387 		return FALSE;
388 	}
389 
390 	/* set request state */
391 	message->start_line.request_state = MRCP_REQUEST_STATE_INPROGRESS;
392 	/* send asynch event */
393 	return mrcp_engine_channel_message_send(recog_channel->channel,message);
394 }
395 
396 /* Load demo recognition result */
demo_recog_result_load(demo_recog_channel_t * recog_channel,mrcp_message_t * message)397 static apt_bool_t demo_recog_result_load(demo_recog_channel_t *recog_channel, mrcp_message_t *message)
398 {
399 	FILE *file;
400 	mrcp_engine_channel_t *channel = recog_channel->channel;
401 	const apt_dir_layout_t *dir_layout = channel->engine->dir_layout;
402 	char *file_path = apt_datadir_filepath_get(dir_layout,"result.xml",message->pool);
403 	if(!file_path) {
404 		return FALSE;
405 	}
406 
407 	/* read the demo result from file */
408 	file = fopen(file_path,"r");
409 	if(file) {
410 		mrcp_generic_header_t *generic_header;
411 		char text[1024];
412 		apr_size_t size;
413 		size = fread(text,1,sizeof(text),file);
414 		apt_string_assign_n(&message->body,text,size,message->pool);
415 		fclose(file);
416 
417 		/* get/allocate generic header */
418 		generic_header = mrcp_generic_header_prepare(message);
419 		if(generic_header) {
420 			/* set content types */
421 			apt_string_assign(&generic_header->content_type,"application/x-nlsml",message->pool);
422 			mrcp_generic_header_property_add(message,GENERIC_HEADER_CONTENT_TYPE);
423 		}
424 	}
425 	return TRUE;
426 }
427 
428 /* Raise demo RECOGNITION-COMPLETE event */
demo_recog_recognition_complete(demo_recog_channel_t * recog_channel,mrcp_recog_completion_cause_e cause)429 static apt_bool_t demo_recog_recognition_complete(demo_recog_channel_t *recog_channel, mrcp_recog_completion_cause_e cause)
430 {
431 	mrcp_recog_header_t *recog_header;
432 	/* create RECOGNITION-COMPLETE event */
433 	mrcp_message_t *message = mrcp_event_create(
434 						recog_channel->recog_request,
435 						RECOGNIZER_RECOGNITION_COMPLETE,
436 						recog_channel->recog_request->pool);
437 	if(!message) {
438 		return FALSE;
439 	}
440 
441 	/* get/allocate recognizer header */
442 	recog_header = mrcp_resource_header_prepare(message);
443 	if(recog_header) {
444 		/* set completion cause */
445 		recog_header->completion_cause = cause;
446 		mrcp_resource_header_property_add(message,RECOGNIZER_HEADER_COMPLETION_CAUSE);
447 	}
448 	/* set request state */
449 	message->start_line.request_state = MRCP_REQUEST_STATE_COMPLETE;
450 
451 	if(cause == RECOGNIZER_COMPLETION_CAUSE_SUCCESS) {
452 		demo_recog_result_load(recog_channel,message);
453 	}
454 
455 	recog_channel->recog_request = NULL;
456 	/* send asynch event */
457 	return mrcp_engine_channel_message_send(recog_channel->channel,message);
458 }
459 
460 /** Callback is called from MPF engine context to write/send new frame */
demo_recog_stream_write(mpf_audio_stream_t * stream,const mpf_frame_t * frame)461 static apt_bool_t demo_recog_stream_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame)
462 {
463 	demo_recog_channel_t *recog_channel = stream->obj;
464 	if(recog_channel->stop_response) {
465 		/* send asynchronous response to STOP request */
466 		mrcp_engine_channel_message_send(recog_channel->channel,recog_channel->stop_response);
467 		recog_channel->stop_response = NULL;
468 		recog_channel->recog_request = NULL;
469 		return TRUE;
470 	}
471 
472 	if(recog_channel->recog_request) {
473 		mpf_detector_event_e det_event = mpf_activity_detector_process(recog_channel->detector,frame);
474 		switch(det_event) {
475 			case MPF_DETECTOR_EVENT_ACTIVITY:
476 				apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Voice Activity "APT_SIDRES_FMT,
477 					MRCP_MESSAGE_SIDRES(recog_channel->recog_request));
478 				demo_recog_start_of_input(recog_channel);
479 				break;
480 			case MPF_DETECTOR_EVENT_INACTIVITY:
481 				apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Voice Inactivity "APT_SIDRES_FMT,
482 					MRCP_MESSAGE_SIDRES(recog_channel->recog_request));
483 				demo_recog_recognition_complete(recog_channel,RECOGNIZER_COMPLETION_CAUSE_SUCCESS);
484 				break;
485 			case MPF_DETECTOR_EVENT_NOINPUT:
486 				apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Noinput "APT_SIDRES_FMT,
487 					MRCP_MESSAGE_SIDRES(recog_channel->recog_request));
488 				if(recog_channel->timers_started == TRUE) {
489 					demo_recog_recognition_complete(recog_channel,RECOGNIZER_COMPLETION_CAUSE_NO_INPUT_TIMEOUT);
490 				}
491 				break;
492 			default:
493 				break;
494 		}
495 
496 		if((frame->type & MEDIA_FRAME_TYPE_EVENT) == MEDIA_FRAME_TYPE_EVENT) {
497 			if(frame->marker == MPF_MARKER_START_OF_EVENT) {
498 				apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected Start of Event "APT_SIDRES_FMT" id:%d",
499 					MRCP_MESSAGE_SIDRES(recog_channel->recog_request),
500 					frame->event_frame.event_id);
501 			}
502 			else if(frame->marker == MPF_MARKER_END_OF_EVENT) {
503 				apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Detected End of Event "APT_SIDRES_FMT" id:%d duration:%d ts",
504 					MRCP_MESSAGE_SIDRES(recog_channel->recog_request),
505 					frame->event_frame.event_id,
506 					frame->event_frame.duration);
507 			}
508 		}
509 
510 		if(recog_channel->audio_out) {
511 			fwrite(frame->codec_frame.buffer,1,frame->codec_frame.size,recog_channel->audio_out);
512 		}
513 	}
514 	return TRUE;
515 }
516 
demo_recog_msg_signal(demo_recog_msg_type_e type,mrcp_engine_channel_t * channel,mrcp_message_t * request)517 static apt_bool_t demo_recog_msg_signal(demo_recog_msg_type_e type, mrcp_engine_channel_t *channel, mrcp_message_t *request)
518 {
519 	apt_bool_t status = FALSE;
520 	demo_recog_channel_t *demo_channel = channel->method_obj;
521 	demo_recog_engine_t *demo_engine = demo_channel->demo_engine;
522 	apt_task_t *task = apt_consumer_task_base_get(demo_engine->task);
523 	apt_task_msg_t *msg = apt_task_msg_get(task);
524 	if(msg) {
525 		demo_recog_msg_t *demo_msg;
526 		msg->type = TASK_MSG_USER;
527 		demo_msg = (demo_recog_msg_t*) msg->data;
528 
529 		demo_msg->type = type;
530 		demo_msg->channel = channel;
531 		demo_msg->request = request;
532 		status = apt_task_msg_signal(task,msg);
533 	}
534 	return status;
535 }
536 
demo_recog_msg_process(apt_task_t * task,apt_task_msg_t * msg)537 static apt_bool_t demo_recog_msg_process(apt_task_t *task, apt_task_msg_t *msg)
538 {
539 	demo_recog_msg_t *demo_msg = (demo_recog_msg_t*)msg->data;
540 	switch(demo_msg->type) {
541 		case DEMO_RECOG_MSG_OPEN_CHANNEL:
542 			/* open channel and send asynch response */
543 			mrcp_engine_channel_open_respond(demo_msg->channel,TRUE);
544 			break;
545 		case DEMO_RECOG_MSG_CLOSE_CHANNEL:
546 		{
547 			/* close channel, make sure there is no activity and send asynch response */
548 			demo_recog_channel_t *recog_channel = demo_msg->channel->method_obj;
549 			if(recog_channel->audio_out) {
550 				fclose(recog_channel->audio_out);
551 				recog_channel->audio_out = NULL;
552 			}
553 
554 			mrcp_engine_channel_close_respond(demo_msg->channel);
555 			break;
556 		}
557 		case DEMO_RECOG_MSG_REQUEST_PROCESS:
558 			demo_recog_channel_request_dispatch(demo_msg->channel,demo_msg->request);
559 			break;
560 		default:
561 			break;
562 	}
563 	return TRUE;
564 }
565