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_server_session.c 2237 2014-11-12 01:48:46Z achaloyan@gmail.com $
17  */
18 
19 #include "mrcp_server.h"
20 #include "mrcp_server_session.h"
21 #include "mrcp_resource.h"
22 #include "mrcp_resource_factory.h"
23 #include "mrcp_engine_iface.h"
24 #include "mrcp_sig_agent.h"
25 #include "mrcp_server_connection.h"
26 #include "mrcp_session_descriptor.h"
27 #include "mrcp_control_descriptor.h"
28 #include "mrcp_state_machine.h"
29 #include "mrcp_message.h"
30 #include "mpf_termination_factory.h"
31 #include "mpf_stream.h"
32 #include "apt_consumer_task.h"
33 #include "apt_log.h"
34 
35 /** Macro to log session name and identifier */
36 #define MRCP_SESSION_NAMESID(session) \
37 	session->base.name, MRCP_SESSION_SID(&session->base)
38 
39 #define MRCP_SESSION_ID_HEX_STRING_LENGTH 16
40 
41 struct mrcp_channel_t {
42 	/** Memory pool */
43 	apr_pool_t             *pool;
44 	/** MRCP resource */
45 	mrcp_resource_t        *resource;
46 	/** MRCP session entire channel belongs to */
47 	mrcp_session_t         *session;
48 	/** MRCP control channel */
49 	mrcp_control_channel_t *control_channel;
50 	/** MRCP engine channel */
51 	mrcp_engine_channel_t  *engine_channel;
52 	/** MRCP resource state machine  */
53 	mrcp_state_machine_t   *state_machine;
54 	/** media descriptor id (position in session descriptor) */
55 	apr_size_t              id;
56 	/** array of cmid attributes (used for resource grouping) */
57 	apr_array_header_t     *cmid_arr;
58 	/** waiting state of control media */
59 	apt_bool_t              waiting_for_channel;
60 	/** waiting state of media termination */
61 	apt_bool_t              waiting_for_termination;
62 };
63 
64 typedef struct mrcp_termination_slot_t mrcp_termination_slot_t;
65 
66 struct mrcp_termination_slot_t {
67 	/** RTP termination */
68 	mpf_termination_t  *termination;
69 	/** media descriptor id (position in SDP message) */
70 	apr_size_t          id;
71 	/** media id (used for resource grouping) */
72 	apr_size_t          mid;
73 	/** Array of associated MRCP channels (mrcp_channel_t*) */
74 	apr_array_header_t *channels;
75 
76 	/** waiting state */
77 	apt_bool_t          waiting;
78 };
79 
80 extern const mrcp_engine_channel_event_vtable_t engine_channel_vtable;
81 
82 void mrcp_server_session_add(mrcp_server_session_t *session);
83 void mrcp_server_session_remove(mrcp_server_session_t *session);
84 
85 static apt_bool_t mrcp_server_signaling_message_dispatch(mrcp_server_session_t *session, mrcp_signaling_message_t *signaling_message);
86 
87 static apt_bool_t mrcp_server_resource_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor);
88 static apt_bool_t mrcp_server_control_media_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor);
89 static apt_bool_t mrcp_server_av_media_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor);
90 
91 static apt_bool_t mrcp_server_engine_channels_update(mrcp_server_session_t *session);
92 static apt_bool_t mrcp_server_session_answer_send(mrcp_server_session_t *session);
93 static apt_bool_t mrcp_server_session_terminate_process(mrcp_server_session_t *session);
94 static apt_bool_t mrcp_server_session_terminate_send(mrcp_server_session_t *session);
95 
96 static mrcp_channel_t* mrcp_server_channel_find(mrcp_server_session_t *session, const apt_str_t *resource_name);
97 
98 static apt_bool_t state_machine_on_message_dispatch(mrcp_state_machine_t *state_machine, mrcp_message_t *message);
99 static apt_bool_t state_machine_on_deactivate(mrcp_state_machine_t *state_machine);
100 
101 
mrcp_server_session_create()102 mrcp_server_session_t* mrcp_server_session_create()
103 {
104 	mrcp_server_session_t *session = (mrcp_server_session_t*) mrcp_session_create(sizeof(mrcp_server_session_t)-sizeof(mrcp_session_t));
105 	session->context = NULL;
106 	session->terminations = apr_array_make(session->base.pool,2,sizeof(mrcp_termination_slot_t));
107 	session->channels = apr_array_make(session->base.pool,2,sizeof(mrcp_channel_t*));
108 	session->active_request = NULL;
109 	session->request_queue = apt_list_create(session->base.pool);
110 	session->offer = NULL;
111 	session->answer = NULL;
112 	session->mpf_task_msg = NULL;
113 	session->subrequest_count = 0;
114 	session->state = SESSION_STATE_NONE;
115 	session->base.name = apr_psprintf(session->base.pool,"0x%pp",session);
116 	return session;
117 }
118 
mrcp_session_version_get(mrcp_server_session_t * session)119 static APR_INLINE mrcp_version_e mrcp_session_version_get(mrcp_server_session_t *session)
120 {
121 	return session->profile->mrcp_version;
122 }
123 
mrcp_server_engine_channel_create(mrcp_server_session_t * session,mrcp_channel_t * channel,const apt_str_t * resource_name)124 static mrcp_engine_channel_t* mrcp_server_engine_channel_create(
125 								mrcp_server_session_t *session,
126 								mrcp_channel_t *channel,
127 								const apt_str_t *resource_name)
128 {
129 	mrcp_engine_t *engine = apr_hash_get(
130 									session->profile->engine_table,
131 									resource_name->buf,
132 									resource_name->length);
133 	if(!engine) {
134 		apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Find MRCP Engine "APT_NAMESID_FMT" [%s]",
135 			MRCP_SESSION_NAMESID(session),
136 			resource_name->buf);
137 		return NULL;
138 	}
139 
140 	channel->state_machine = engine->create_state_machine(
141 						channel,
142 						mrcp_session_version_get(session),
143 						channel->pool);
144 	if(channel->state_machine) {
145 		channel->state_machine->on_dispatch = state_machine_on_message_dispatch;
146 		channel->state_machine->on_deactivate = state_machine_on_deactivate;
147 	}
148 
149 	return mrcp_engine_channel_virtual_create(engine,mrcp_session_version_get(session),session->base.pool);
150 }
151 
mrcp_server_channel_create(mrcp_server_session_t * session,const apt_str_t * resource_name,apr_size_t id,apr_array_header_t * cmid_arr)152 static mrcp_channel_t* mrcp_server_channel_create(mrcp_server_session_t *session, const apt_str_t *resource_name, apr_size_t id, apr_array_header_t *cmid_arr)
153 {
154 	mrcp_channel_t *channel;
155 	apr_pool_t *pool = session->base.pool;
156 
157 	channel = apr_palloc(pool,sizeof(mrcp_channel_t));
158 	channel->pool = pool;
159 	channel->session = &session->base;
160 	channel->resource = NULL;
161 	channel->control_channel = NULL;
162 	channel->state_machine = NULL;
163 	channel->engine_channel = NULL;
164 	channel->id = id;
165 	channel->cmid_arr = cmid_arr;
166 	channel->waiting_for_channel = FALSE;
167 	channel->waiting_for_termination = FALSE;
168 
169 	if(resource_name && resource_name->buf) {
170 		mrcp_resource_t *resource;
171 		mrcp_engine_channel_t *engine_channel;
172 		resource = mrcp_resource_find(session->profile->resource_factory,resource_name);
173 		if(resource) {
174 			channel->resource = resource;
175 			if(mrcp_session_version_get(session) == MRCP_VERSION_2) {
176 				channel->control_channel = mrcp_server_control_channel_create(
177 									session->profile->connection_agent,
178 									channel,
179 									pool);
180 			}
181 			engine_channel = mrcp_server_engine_channel_create(session,channel,resource_name);
182 			if(engine_channel) {
183 				engine_channel->id = session->base.id;
184 				engine_channel->event_obj = channel;
185 				engine_channel->event_vtable = &engine_channel_vtable;
186 				channel->engine_channel = engine_channel;
187 			}
188 			else {
189 				apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create Engine Channel "APT_NAMESID_FMT" [%s]",
190 					MRCP_SESSION_NAMESID(session),
191 					resource_name->buf);
192 				session->answer->status = MRCP_SESSION_STATUS_UNACCEPTABLE_RESOURCE;
193 			}
194 		}
195 		else {
196 			apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such Resource "APT_NAMESID_FMT" [%s]",
197 				MRCP_SESSION_NAMESID(session),
198 				resource_name->buf);
199 			session->answer->status = MRCP_SESSION_STATUS_NO_SUCH_RESOURCE;
200 		}
201 	}
202 	else {
203 		apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Invalid Resource Identifier "APT_NAMESID_FMT,
204 			MRCP_SESSION_NAMESID(session));
205 		session->answer->status = MRCP_SESSION_STATUS_NO_SUCH_RESOURCE;
206 	}
207 
208 	return channel;
209 }
210 
mrcp_server_session_state_set(mrcp_server_session_t * session,mrcp_server_session_state_e state)211 static APR_INLINE void mrcp_server_session_state_set(mrcp_server_session_t *session, mrcp_server_session_state_e state)
212 {
213 	if(session->subrequest_count != 0) {
214 		/* error case */
215 		session->subrequest_count = 0;
216 	}
217 	session->state = state;
218 }
219 
mrcp_server_session_subrequest_add(mrcp_server_session_t * session)220 static APR_INLINE void mrcp_server_session_subrequest_add(mrcp_server_session_t *session)
221 {
222 	session->subrequest_count++;
223 }
224 
mrcp_server_session_subrequest_remove(mrcp_server_session_t * session)225 static void mrcp_server_session_subrequest_remove(mrcp_server_session_t *session)
226 {
227 	if(!session->subrequest_count) {
228 		/* error case */
229 		return;
230 	}
231 	session->subrequest_count--;
232 	if(!session->subrequest_count) {
233 		switch(session->state) {
234 			case SESSION_STATE_GENERATING_ANSWER:
235 				mrcp_server_engine_channels_update(session);
236 				break;
237 			case SESSION_STATE_INITIALIZING:
238 				/* send answer to client */
239 				mrcp_server_session_answer_send(session);
240 				break;
241 			case SESSION_STATE_DEACTIVATING:
242 				mrcp_server_session_terminate_process(session);
243 				break;
244 			case SESSION_STATE_TERMINATING:
245 				mrcp_server_session_terminate_send(session);
246 				break;
247 			default:
248 				break;
249 		}
250 	}
251 }
252 
mrcp_server_channel_session_get(mrcp_channel_t * channel)253 mrcp_session_t* mrcp_server_channel_session_get(mrcp_channel_t *channel)
254 {
255 	return channel->session;
256 }
257 
mrcp_server_signaling_message_process(mrcp_signaling_message_t * signaling_message)258 apt_bool_t mrcp_server_signaling_message_process(mrcp_signaling_message_t *signaling_message)
259 {
260 	mrcp_server_session_t *session = signaling_message->session;
261 	if(session->active_request) {
262 		apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Push Request to Queue "APT_NAMESID_FMT,
263 			MRCP_SESSION_NAMESID(session));
264 		apt_list_push_back(session->request_queue,signaling_message,session->base.pool);
265 	}
266 	else {
267 		session->active_request = signaling_message;
268 		mrcp_server_signaling_message_dispatch(session,signaling_message);
269 	}
270 	return TRUE;
271 }
272 
mrcp_server_on_channel_modify(mrcp_channel_t * channel,mrcp_control_descriptor_t * answer,apt_bool_t status)273 apt_bool_t mrcp_server_on_channel_modify(mrcp_channel_t *channel, mrcp_control_descriptor_t *answer, apt_bool_t status)
274 {
275 	mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
276 	apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Control Channel Modified "APT_NAMESIDRES_FMT,
277 			MRCP_SESSION_NAMESID(session),
278 			channel->resource->name.buf);
279 	if(!answer) {
280 		return FALSE;
281 	}
282 	if(!channel->waiting_for_channel) {
283 		return FALSE;
284 	}
285 	channel->waiting_for_channel = FALSE;
286 	answer->session_id = session->base.id;
287 	mrcp_session_control_media_set(session->answer,channel->id,answer);
288 	mrcp_server_session_subrequest_remove(session);
289 	return TRUE;
290 }
291 
mrcp_server_on_channel_remove(mrcp_channel_t * channel,apt_bool_t status)292 apt_bool_t mrcp_server_on_channel_remove(mrcp_channel_t *channel, apt_bool_t status)
293 {
294 	mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
295 	apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Control Channel Removed "APT_NAMESIDRES_FMT,
296 			MRCP_SESSION_NAMESID(session),
297 			channel->resource->name.buf);
298 	if(!channel->waiting_for_channel) {
299 		return FALSE;
300 	}
301 	channel->waiting_for_channel = FALSE;
302 	mrcp_server_session_subrequest_remove(session);
303 	return TRUE;
304 }
305 
mrcp_server_on_channel_message(mrcp_channel_t * channel,mrcp_message_t * message)306 apt_bool_t mrcp_server_on_channel_message(mrcp_channel_t *channel, mrcp_message_t *message)
307 {
308 	mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
309 	mrcp_signaling_message_t *signaling_message;
310 	signaling_message = apr_palloc(session->base.pool,sizeof(mrcp_signaling_message_t));
311 	signaling_message->type = SIGNALING_MESSAGE_CONTROL;
312 	signaling_message->session = session;
313 	signaling_message->descriptor = NULL;
314 	signaling_message->channel = channel;
315 	signaling_message->message = message;
316 	return mrcp_server_signaling_message_process(signaling_message);
317 }
318 
mrcp_server_on_disconnect(mrcp_channel_t * channel)319 apt_bool_t mrcp_server_on_disconnect(mrcp_channel_t *channel)
320 {
321 	/* to be processed */
322 	return TRUE;
323 }
324 
mrcp_server_on_engine_channel_open(mrcp_channel_t * channel,apt_bool_t status)325 apt_bool_t mrcp_server_on_engine_channel_open(mrcp_channel_t *channel, apt_bool_t status)
326 {
327 	mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
328 	apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Engine Channel Opened "APT_NAMESIDRES_FMT" [%s]",
329 			MRCP_SESSION_NAMESID(session),
330 			channel->resource->name.buf,
331 			status == TRUE ? "OK" : "Failed");
332 	if(status == FALSE) {
333 		session->answer->status = MRCP_SESSION_STATUS_UNAVAILABLE_RESOURCE;
334 	}
335 	mrcp_server_session_subrequest_remove(session);
336 	return TRUE;
337 }
338 
mrcp_server_on_engine_channel_close(mrcp_channel_t * channel)339 apt_bool_t mrcp_server_on_engine_channel_close(mrcp_channel_t *channel)
340 {
341 	mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
342 	apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Engine Channel Closed "APT_NAMESIDRES_FMT,
343 			MRCP_SESSION_NAMESID(session),
344 			channel->resource->name.buf);
345 	mrcp_server_session_subrequest_remove(session);
346 	return TRUE;
347 }
348 
mrcp_server_on_engine_channel_message(mrcp_channel_t * channel,mrcp_message_t * message)349 apt_bool_t mrcp_server_on_engine_channel_message(mrcp_channel_t *channel, mrcp_message_t *message)
350 {
351 	if(!channel->state_machine) {
352 		return FALSE;
353 	}
354 	/* update state machine */
355 	return mrcp_state_machine_update(channel->state_machine,message);
356 }
357 
358 
mrcp_session_answer_create(mrcp_session_descriptor_t * offer,apr_pool_t * pool)359 static mrcp_session_descriptor_t* mrcp_session_answer_create(mrcp_session_descriptor_t *offer, apr_pool_t *pool)
360 {
361 	int i;
362 	mrcp_session_descriptor_t *answer = apr_palloc(pool,sizeof(mrcp_session_descriptor_t));
363 	apt_string_reset(&answer->origin);
364 	apt_string_reset(&answer->ip);
365 	apt_string_reset(&answer->ext_ip);
366 	answer->resource_name = offer->resource_name;
367 	answer->resource_state = offer->resource_state;
368 	answer->status = offer->status;
369 	answer->control_media_arr = apr_array_make(pool,offer->control_media_arr->nelts,sizeof(void*));
370 	for(i=0; i<offer->control_media_arr->nelts; i++) {
371 		APR_ARRAY_PUSH(answer->control_media_arr,void*) = NULL;
372 	}
373 	answer->audio_media_arr = apr_array_make(pool,offer->audio_media_arr->nelts,sizeof(mpf_rtp_media_descriptor_t*));
374 	for(i=0; i<offer->audio_media_arr->nelts; i++) {
375 		APR_ARRAY_PUSH(answer->audio_media_arr,mpf_rtp_media_descriptor_t*) = NULL;
376 	}
377 	answer->video_media_arr = apr_array_make(pool,offer->video_media_arr->nelts,sizeof(mpf_rtp_media_descriptor_t*));
378 	for(i=0; i<offer->video_media_arr->nelts; i++) {
379 		APR_ARRAY_PUSH(answer->video_media_arr,mpf_rtp_media_descriptor_t*) = NULL;
380 	}
381 	return answer;
382 }
383 
mrcp_server_session_offer_process(mrcp_server_session_t * session,mrcp_session_descriptor_t * descriptor)384 static apt_bool_t mrcp_server_session_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor)
385 {
386 	if(!session->context) {
387 		/* initial offer received, generate session id and add to session's table */
388 		if(!session->base.id.length) {
389 			apt_unique_id_generate(&session->base.id,MRCP_SESSION_ID_HEX_STRING_LENGTH,session->base.pool);
390 		}
391 		mrcp_server_session_add(session);
392 
393 		session->context = mpf_engine_context_create(
394 			session->profile->media_engine,
395 			session->base.name,
396 			session,5,session->base.pool);
397 	}
398 	apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive Offer "APT_NAMESID_FMT" [c:%d a:%d v:%d]",
399 		MRCP_SESSION_NAMESID(session),
400 		descriptor->control_media_arr->nelts,
401 		descriptor->audio_media_arr->nelts,
402 		descriptor->video_media_arr->nelts);
403 
404 	/* store received offer */
405 	session->offer = descriptor;
406 	session->answer = mrcp_session_answer_create(descriptor,session->base.pool);
407 
408 	mrcp_server_session_state_set(session,SESSION_STATE_GENERATING_ANSWER);
409 
410 	/* first, reset/destroy existing associations and topology */
411 	if(mpf_engine_topology_message_add(
412 				session->profile->media_engine,
413 				MPF_RESET_ASSOCIATIONS,session->context,
414 				&session->mpf_task_msg) == TRUE){
415 		mrcp_server_session_subrequest_add(session);
416 	}
417 
418 	if(mrcp_session_version_get(session) == MRCP_VERSION_1) {
419 		if(mrcp_server_resource_offer_process(session,descriptor) == TRUE) {
420 			mrcp_server_av_media_offer_process(session,descriptor);
421 		}
422 		else {
423 			session->answer->resource_state = FALSE;
424 		}
425 	}
426 	else {
427 		mrcp_server_control_media_offer_process(session,descriptor);
428 		mrcp_server_av_media_offer_process(session,descriptor);
429 	}
430 
431 	/* apply topology based on assigned associations */
432 	if(mpf_engine_topology_message_add(
433 				session->profile->media_engine,
434 				MPF_APPLY_TOPOLOGY,session->context,
435 				&session->mpf_task_msg) == TRUE) {
436 		mrcp_server_session_subrequest_add(session);
437 	}
438 	mpf_engine_message_send(session->profile->media_engine,&session->mpf_task_msg);
439 
440 	if(!session->subrequest_count) {
441 		/* send answer to client */
442 		mrcp_server_session_answer_send(session);
443 	}
444 	return TRUE;
445 }
446 
mrcp_server_session_terminate_process(mrcp_server_session_t * session)447 static apt_bool_t mrcp_server_session_terminate_process(mrcp_server_session_t *session)
448 {
449 	mrcp_channel_t *channel;
450 	mrcp_termination_slot_t *slot;
451 	int i;
452 	apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Terminate Session "APT_NAMESID_FMT,MRCP_SESSION_NAMESID(session));
453 
454 	mrcp_server_session_state_set(session,SESSION_STATE_TERMINATING);
455 
456 	if(session->context) {
457 		/* first, destroy existing topology */
458 		if(mpf_engine_topology_message_add(
459 					session->profile->media_engine,
460 					MPF_RESET_ASSOCIATIONS,session->context,
461 					&session->mpf_task_msg) == TRUE){
462 			mrcp_server_session_subrequest_add(session);
463 		}
464 	}
465 
466 	for(i=0; i<session->channels->nelts; i++) {
467 		channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
468 		if(!channel) continue;
469 
470 		/* send remove channel request */
471 		apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Remove Control Channel "APT_NAMESIDRES_FMT" [%d]",
472 			MRCP_SESSION_NAMESID(session),
473 			channel->resource->name.buf,
474 			i);
475 		if(channel->control_channel) {
476 			if(mrcp_server_control_channel_remove(channel->control_channel) == TRUE) {
477 				channel->waiting_for_channel = TRUE;
478 				mrcp_server_session_subrequest_add(session);
479 			}
480 		}
481 
482 		if(channel->engine_channel) {
483 			mpf_termination_t *termination = channel->engine_channel->termination;
484 			/* send subtract termination request */
485 			if(termination) {
486 				apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Media Termination "APT_NAMESIDRES_FMT,
487 					MRCP_SESSION_NAMESID(session),
488 					mpf_termination_name_get(termination));
489 				if(mpf_engine_termination_message_add(
490 							session->profile->media_engine,
491 							MPF_SUBTRACT_TERMINATION,session->context,termination,NULL,
492 							&session->mpf_task_msg) == TRUE) {
493 					channel->waiting_for_termination = TRUE;
494 					mrcp_server_session_subrequest_add(session);
495 				}
496 			}
497 
498 			/* close engine channel */
499 			if(mrcp_engine_channel_virtual_close(channel->engine_channel) == TRUE) {
500 				mrcp_server_session_subrequest_add(session);
501 			}
502 		}
503 	}
504 	for(i=0; i<session->terminations->nelts; i++) {
505 		/* get existing termination */
506 		slot = &APR_ARRAY_IDX(session->terminations,i,mrcp_termination_slot_t);
507 		if(!slot->termination) continue;
508 
509 		/* send subtract termination request */
510 		apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Subtract Media Termination "APT_NAMESIDRES_FMT,
511 			MRCP_SESSION_NAMESID(session),
512 			mpf_termination_name_get(slot->termination));
513 		if(mpf_engine_termination_message_add(
514 				session->profile->media_engine,
515 				MPF_SUBTRACT_TERMINATION,session->context,slot->termination,NULL,
516 				&session->mpf_task_msg) == TRUE) {
517 			slot->waiting = TRUE;
518 			mrcp_server_session_subrequest_add(session);
519 		}
520 	}
521 
522 	if(session->context) {
523 		mpf_engine_message_send(session->profile->media_engine,&session->mpf_task_msg);
524 	}
525 
526 	mrcp_server_session_remove(session);
527 
528 	if(!session->subrequest_count) {
529 		mrcp_server_session_terminate_send(session);
530 	}
531 
532 	return TRUE;
533 }
534 
mrcp_server_session_deactivate(mrcp_server_session_t * session)535 static apt_bool_t mrcp_server_session_deactivate(mrcp_server_session_t *session)
536 {
537 	mrcp_channel_t *channel;
538 	int i;
539 	apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Deactivate Session "APT_NAMESID_FMT,MRCP_SESSION_NAMESID(session));
540 	mrcp_server_session_state_set(session,SESSION_STATE_DEACTIVATING);
541 	for(i=0; i<session->channels->nelts; i++) {
542 		channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
543 		if(!channel || !channel->state_machine) continue;
544 
545 		if(mrcp_state_machine_deactivate(channel->state_machine) == TRUE) {
546 			mrcp_server_session_subrequest_add(session);
547 		}
548 	}
549 
550 	if(!session->subrequest_count) {
551 		mrcp_server_session_terminate_process(session);
552 	}
553 
554 	return TRUE;
555 }
556 
mrcp_server_on_message_receive(mrcp_server_session_t * session,mrcp_channel_t * channel,mrcp_message_t * message)557 static apt_bool_t mrcp_server_on_message_receive(mrcp_server_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message)
558 {
559 	if(!channel) {
560 		channel = mrcp_server_channel_find(session,&message->channel_id.resource_name);
561 		if(!channel) {
562 			apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"No Such Channel "APT_NAMESIDRES_FMT,
563 				MRCP_SESSION_NAMESID(session),
564 				message->channel_id.resource_name.buf);
565 			return FALSE;
566 		}
567 	}
568 	if(!channel->resource || !channel->state_machine) {
569 		apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Missing Resource "APT_NAMESIDRES_FMT,
570 			MRCP_SESSION_NAMESID(session),
571 			message->channel_id.resource_name.buf);
572 		return FALSE;
573 	}
574 
575 	/* update state machine */
576 	return mrcp_state_machine_update(channel->state_machine,message);
577 }
578 
mrcp_server_signaling_message_dispatch(mrcp_server_session_t * session,mrcp_signaling_message_t * signaling_message)579 static apt_bool_t mrcp_server_signaling_message_dispatch(mrcp_server_session_t *session, mrcp_signaling_message_t *signaling_message)
580 {
581 	apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Dispatch Signaling Message [%d]",signaling_message->type);
582 	switch(signaling_message->type) {
583 		case SIGNALING_MESSAGE_OFFER:
584 			mrcp_server_session_offer_process(signaling_message->session,signaling_message->descriptor);
585 			break;
586 		case SIGNALING_MESSAGE_CONTROL:
587 			mrcp_server_on_message_receive(signaling_message->session,signaling_message->channel,signaling_message->message);
588 			break;
589 		case SIGNALING_MESSAGE_TERMINATE:
590 			mrcp_server_session_deactivate(signaling_message->session);
591 			break;
592 		default:
593 			break;
594 	}
595 	return TRUE;
596 }
597 
mrcp_server_engine_channels_update(mrcp_server_session_t * session)598 static apt_bool_t mrcp_server_engine_channels_update(mrcp_server_session_t *session)
599 {
600 	mrcp_channel_t *channel;
601 	mrcp_session_descriptor_t *descriptor = session->offer;
602 	if(!descriptor) {
603 		return FALSE;
604 	}
605 
606 	mrcp_server_session_state_set(session,SESSION_STATE_INITIALIZING);
607 
608 	if(mrcp_session_version_get(session) == MRCP_VERSION_1) {
609 		if(session->offer) {
610 			channel = mrcp_server_channel_find(session,&descriptor->resource_name);
611 			if(channel && channel->engine_channel) {
612 				/* open engine channel */
613 				if(mrcp_engine_channel_virtual_open(channel->engine_channel) == TRUE) {
614 					mrcp_server_session_subrequest_add(session);
615 				}
616 			}
617 		}
618 	}
619 	else {
620 		int i;
621 		mrcp_control_descriptor_t *control_descriptor;
622 		for(i=0; i<session->channels->nelts; i++) {
623 			channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
624 			if(!channel || !channel->engine_channel) continue;
625 
626 			control_descriptor = mrcp_session_control_media_get(descriptor,i);
627 			if(!control_descriptor) continue;
628 
629 			if(control_descriptor->port) {
630 				/* open engine channel */
631 				if(mrcp_engine_channel_virtual_open(channel->engine_channel) == TRUE) {
632 					mrcp_server_session_subrequest_add(session);
633 				}
634 			}
635 			else {
636 				/* close engine channel */
637 				if(mrcp_engine_channel_virtual_close(channel->engine_channel) == TRUE) {
638 					mrcp_server_session_subrequest_add(session);
639 				}
640 			}
641 		}
642 	}
643 
644 	if(!session->subrequest_count) {
645 		mrcp_server_session_answer_send(session);
646 	}
647 	return TRUE;
648 }
649 
mrcp_server_resource_offer_process(mrcp_server_session_t * session,mrcp_session_descriptor_t * descriptor)650 static apt_bool_t mrcp_server_resource_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor)
651 {
652 	if(descriptor->resource_state == TRUE) {
653 		/* setup */
654 		mrcp_channel_t *channel;
655 		int count = session->channels->nelts;
656 		channel = mrcp_server_channel_find(session,&descriptor->resource_name);
657 		if(channel) {
658 			/* channel already exists */
659 			return TRUE;
660 		}
661 		/* create new MRCP channel instance */
662 		channel = mrcp_server_channel_create(session,&descriptor->resource_name,count,NULL);
663 		if(!channel || !channel->resource) {
664 			return FALSE;
665 		}
666 		/* add to channel array */
667 		apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Control Channel "APT_NAMESIDRES_FMT" [%d]",
668 			MRCP_SESSION_NAMESID(session),
669 			channel->resource->name.buf,
670 			count);
671 		APR_ARRAY_PUSH(session->channels,mrcp_channel_t*) = channel;
672 		if(channel->engine_channel && channel->engine_channel->termination) {
673 			mpf_termination_t *termination = channel->engine_channel->termination;
674 			/* send add termination request (add to media context) */
675 			if(mpf_engine_termination_message_add(
676 					session->profile->media_engine,
677 					MPF_ADD_TERMINATION,session->context,termination,NULL,
678 					&session->mpf_task_msg) == TRUE) {
679 				channel->waiting_for_termination = TRUE;
680 				mrcp_server_session_subrequest_add(session);
681 			}
682 		}
683 	}
684 	else {
685 		/* teardown */
686 	}
687 	return TRUE;
688 }
689 
mrcp_server_control_media_offer_process(mrcp_server_session_t * session,mrcp_session_descriptor_t * descriptor)690 static apt_bool_t mrcp_server_control_media_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor)
691 {
692 	mrcp_channel_t *channel;
693 	mrcp_control_descriptor_t *control_descriptor;
694 	int i;
695 	int count = session->channels->nelts;
696 	if(count > descriptor->control_media_arr->nelts) {
697 		apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Number of Control Channels [%d] > Number of Control Media in Offer [%d]",
698 			count,descriptor->control_media_arr->nelts);
699 		count = descriptor->control_media_arr->nelts;
700 	}
701 
702 	/* update existing control channels */
703 	for(i=0; i<count; i++) {
704 		channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
705 		if(!channel) continue;
706 
707 		channel->waiting_for_channel = FALSE;
708 		/* get control descriptor */
709 		control_descriptor = mrcp_session_control_media_get(descriptor,i);
710 		if(!control_descriptor) continue;
711 
712 		apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Modify Control Channel "APT_NAMESIDRES_FMT" [%d]",
713 			MRCP_SESSION_NAMESID(session),
714 			channel->resource->name.buf,
715 			i);
716 		if(channel->control_channel) {
717 			/* send offer */
718 			if(mrcp_server_control_channel_modify(channel->control_channel,control_descriptor) == TRUE) {
719 				channel->waiting_for_channel = TRUE;
720 				mrcp_server_session_subrequest_add(session);
721 			}
722 		}
723 
724 		if(channel->waiting_for_channel == FALSE) {
725 			mrcp_control_descriptor_t *answer = mrcp_control_answer_create(control_descriptor,channel->pool);
726 			answer->port = 0;
727 			answer->session_id = session->base.id;
728 			mrcp_session_control_media_set(session->answer,channel->id,answer);
729 		}
730 	}
731 
732 	/* add new control channels */
733 	for(; i<descriptor->control_media_arr->nelts; i++) {
734 		/* get control descriptor */
735 		control_descriptor = mrcp_session_control_media_get(descriptor,i);
736 		if(!control_descriptor) continue;
737 
738 		/* create new MRCP channel instance */
739 		channel = mrcp_server_channel_create(session,&control_descriptor->resource_name,i,control_descriptor->cmid_arr);
740 		if(!channel || !channel->resource) continue;
741 
742 		control_descriptor->session_id = session->base.id;
743 		apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Control Channel "APT_NAMESIDRES_FMT" [%d]",
744 			MRCP_SESSION_NAMESID(session),
745 			channel->resource->name.buf,
746 			i);
747 		APR_ARRAY_PUSH(session->channels,mrcp_channel_t*) = channel;
748 
749 		if(channel->control_channel) {
750 			/* send modify connection request */
751 			if(mrcp_server_control_channel_add(channel->control_channel,control_descriptor) == TRUE) {
752 				channel->waiting_for_channel = TRUE;
753 				mrcp_server_session_subrequest_add(session);
754 			}
755 		}
756 
757 		if(channel->waiting_for_channel == FALSE) {
758 			mrcp_control_descriptor_t *answer = mrcp_control_answer_create(control_descriptor,channel->pool);
759 			answer->port = 0;
760 			answer->session_id = session->base.id;
761 			mrcp_session_control_media_set(session->answer,channel->id,answer);
762 		}
763 
764 		if(channel->engine_channel && channel->engine_channel->termination) {
765 			mpf_termination_t *termination = channel->engine_channel->termination;
766 			/* send add termination request (add to media context) */
767 			if(mpf_engine_termination_message_add(
768 					session->profile->media_engine,
769 					MPF_ADD_TERMINATION,session->context,termination,NULL,
770 					&session->mpf_task_msg) == TRUE) {
771 				channel->waiting_for_termination = TRUE;
772 				mrcp_server_session_subrequest_add(session);
773 			}
774 		}
775 	}
776 
777 	return TRUE;
778 }
779 
mrcp_server_associations_build(mrcp_server_session_t * session,mrcp_session_descriptor_t * descriptor,mrcp_termination_slot_t * slot)780 static mpf_rtp_termination_descriptor_t* mrcp_server_associations_build(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor, mrcp_termination_slot_t *slot)
781 {
782 	int i;
783 	mrcp_channel_t *channel;
784 	mpf_audio_stream_t *audio_stream;
785 	mpf_stream_capabilities_t *capabilities = NULL;
786 	mpf_rtp_termination_descriptor_t *rtp_descriptor;
787 	mpf_rtp_media_descriptor_t *media_descriptor = mrcp_session_audio_media_get(descriptor,slot->id);
788 	if(!media_descriptor) {
789 		return NULL;
790 	}
791 	/* construct termination descriptor */
792 	rtp_descriptor = apr_palloc(session->base.pool,sizeof(mpf_rtp_termination_descriptor_t));
793 	mpf_rtp_termination_descriptor_init(rtp_descriptor);
794 	rtp_descriptor->audio.local = NULL;
795 	rtp_descriptor->audio.remote = media_descriptor;
796 	rtp_descriptor->audio.settings = session->profile->rtp_settings;
797 
798 	slot->mid = media_descriptor->mid;
799 	slot->channels = apr_array_make(session->base.pool,1,sizeof(mrcp_channel_t*));
800 	for(i=0; i<session->channels->nelts; i++) {
801 		channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
802 		if(!channel) continue;
803 
804 		if(session->terminations->nelts == 1 || (!channel->cmid_arr || mrcp_cmid_find(channel->cmid_arr,slot->mid) == TRUE)) {
805 			APR_ARRAY_PUSH(slot->channels, mrcp_channel_t*) = channel;
806 
807 			audio_stream = NULL;
808 			if(channel->engine_channel && channel->engine_channel->termination) {
809 				audio_stream = mpf_termination_audio_stream_get(channel->engine_channel->termination);
810 			}
811 			if(!audio_stream) continue;
812 
813 			if(audio_stream->capabilities) {
814 				/* set descriptor according to media termination(s)
815 				of associated control channel(s) */
816 				if(capabilities) {
817 					mpf_stream_capabilities_merge(
818 						capabilities,
819 						audio_stream->capabilities,
820 						session->base.pool);
821 					}
822 				else {
823 					capabilities = mpf_stream_capabilities_clone(
824 						audio_stream->capabilities,
825 						session->base.pool);
826 				}
827 			}
828 
829 			if(mrcp_session_version_get(session) == MRCP_VERSION_1) {
830 				mpf_stream_direction_e direction = audio_stream->direction;
831 				/* implicitly modify the descriptor, if needed */
832 				if(media_descriptor->direction == STREAM_DIRECTION_NONE && mpf_codec_list_is_empty(&media_descriptor->codec_list) == TRUE) {
833 					/* this is the case when SETUP contains no SDP, assume all the available codecs are offered */
834 					if(mpf_codec_list_is_empty(&session->profile->rtp_settings->codec_list) == FALSE) {
835 						mpf_codec_list_copy(&media_descriptor->codec_list,
836 								&session->profile->rtp_settings->codec_list,
837 								session->base.pool);
838 					}
839 				}
840 
841 				media_descriptor->direction |= direction;
842 				if(media_descriptor->state == MPF_MEDIA_DISABLED) {
843 					media_descriptor->state = MPF_MEDIA_ENABLED;
844 				}
845 			}
846 		}
847 	}
848 	if(capabilities) {
849 		capabilities->direction = mpf_stream_reverse_direction_get(capabilities->direction);
850 		rtp_descriptor->audio.capabilities = capabilities;
851 	}
852 	return rtp_descriptor;
853 }
854 
mrcp_server_associations_set(mrcp_server_session_t * session,mrcp_session_descriptor_t * descriptor,mrcp_termination_slot_t * slot)855 static apt_bool_t mrcp_server_associations_set(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor, mrcp_termination_slot_t *slot)
856 {
857 	int i;
858 	mrcp_channel_t *channel;
859 	for(i=0; i<slot->channels->nelts; i++) {
860 		channel = ((mrcp_channel_t**)slot->channels->elts)[i];
861 		if(!channel || !channel->engine_channel) continue;
862 
863 		if(mpf_engine_assoc_message_add(
864 				session->profile->media_engine,
865 				MPF_ADD_ASSOCIATION,session->context,slot->termination,channel->engine_channel->termination,
866 				&session->mpf_task_msg) == TRUE) {
867 			mrcp_server_session_subrequest_add(session);
868 		}
869 	}
870 	return TRUE;
871 }
872 
mrcp_server_av_media_offer_process(mrcp_server_session_t * session,mrcp_session_descriptor_t * descriptor)873 static apt_bool_t mrcp_server_av_media_offer_process(mrcp_server_session_t *session, mrcp_session_descriptor_t *descriptor)
874 {
875 	mpf_rtp_termination_descriptor_t *rtp_descriptor;
876 	mrcp_termination_slot_t *slot;
877 	int i;
878 	int count = session->terminations->nelts;
879 	if(!descriptor->audio_media_arr->nelts) {
880 		/* no media to process */
881 		return TRUE;
882 	}
883 	if(count > descriptor->audio_media_arr->nelts) {
884 		apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Number of Terminations [%d] > Number of Audio Media in Offer [%d]",
885 			count,descriptor->audio_media_arr->nelts);
886 		count = descriptor->audio_media_arr->nelts;
887 	}
888 
889 	/* update existing terminations */
890 	for(i=0; i<count; i++) {
891 		/* get existing termination */
892 		slot = &APR_ARRAY_IDX(session->terminations,i,mrcp_termination_slot_t);
893 		if(!slot->termination) continue;
894 
895 		/* build associations between specified RTP termination and control channels */
896 		rtp_descriptor = mrcp_server_associations_build(session,descriptor,slot);
897 		if(!rtp_descriptor) continue;
898 
899 		/* send modify termination request */
900 		apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Modify Media Termination "APT_NAMESIDRES_FMT" [%d]",
901 				MRCP_SESSION_NAMESID(session),
902 				mpf_termination_name_get(slot->termination),
903 				i);
904 		if(mpf_engine_termination_message_add(
905 				session->profile->media_engine,
906 				MPF_MODIFY_TERMINATION,session->context,slot->termination,rtp_descriptor,
907 				&session->mpf_task_msg) == TRUE) {
908 			slot->waiting = TRUE;
909 			mrcp_server_session_subrequest_add(session);
910 		}
911 
912 		/* set built associations */
913 		mrcp_server_associations_set(session,descriptor,slot);
914 	}
915 
916 	/* add new terminations */
917 	for(; i<descriptor->audio_media_arr->nelts; i++) {
918 		mpf_termination_t *termination;
919 		/* create new RTP termination instance */
920 		termination = mpf_termination_create(session->profile->rtp_termination_factory,session,session->base.pool);
921 		/* add to termination array */
922 		apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Add Media Termination "APT_NAMESIDRES_FMT" [%d]",
923 				MRCP_SESSION_NAMESID(session),
924 				mpf_termination_name_get(termination),
925 				i);
926 		slot = apr_array_push(session->terminations);
927 		slot->id = i;
928 		slot->mid = 0;
929 		slot->waiting = FALSE;
930 		slot->termination = termination;
931 		slot->channels = NULL;
932 
933 		/* build associations between specified RTP termination and control channels */
934 		rtp_descriptor = mrcp_server_associations_build(session,descriptor,slot);
935 		if(!rtp_descriptor) continue;
936 
937 		/* send add termination request (add to media context) */
938 		if(mpf_engine_termination_message_add(
939 				session->profile->media_engine,
940 				MPF_ADD_TERMINATION,session->context,termination,rtp_descriptor,
941 				&session->mpf_task_msg) == TRUE) {
942 			slot->waiting = TRUE;
943 			mrcp_server_session_subrequest_add(session);
944 		}
945 
946 		/* set built associations */
947 		mrcp_server_associations_set(session,descriptor,slot);
948 	}
949 	return TRUE;
950 }
951 
mrcp_server_session_answer_send(mrcp_server_session_t * session)952 static apt_bool_t mrcp_server_session_answer_send(mrcp_server_session_t *session)
953 {
954 	apt_bool_t status;
955 	mrcp_session_descriptor_t *descriptor = session->answer;
956 	apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Send Answer "APT_NAMESID_FMT" [c:%d a:%d v:%d] Status %s",
957 		MRCP_SESSION_NAMESID(session),
958 		descriptor->control_media_arr->nelts,
959 		descriptor->audio_media_arr->nelts,
960 		descriptor->video_media_arr->nelts,
961 		mrcp_session_status_phrase_get(descriptor->status));
962 	status = mrcp_session_answer(&session->base,descriptor);
963 	session->offer = NULL;
964 	session->answer = NULL;
965 
966 	session->active_request = apt_list_pop_front(session->request_queue);
967 	if(session->active_request) {
968 		mrcp_server_signaling_message_dispatch(session,session->active_request);
969 	}
970 	return status;
971 }
972 
mrcp_server_session_terminate_send(mrcp_server_session_t * session)973 static apt_bool_t mrcp_server_session_terminate_send(mrcp_server_session_t *session)
974 {
975 	int i;
976 	mrcp_channel_t *channel;
977 	for(i=0; i<session->channels->nelts; i++) {
978 		channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
979 		if(!channel) continue;
980 
981 		if(channel->control_channel) {
982 			mrcp_server_control_channel_destroy(channel->control_channel);
983 			channel->control_channel = NULL;
984 		}
985 		if(channel->engine_channel) {
986 			mrcp_engine_channel_virtual_destroy(channel->engine_channel);
987 			channel->engine_channel = NULL;
988 		}
989 	}
990 	apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Session Terminated "APT_NAMESID_FMT,MRCP_SESSION_NAMESID(session));
991 	mrcp_session_terminate_response(&session->base);
992 	return TRUE;
993 }
994 
995 
mrcp_server_rtp_termination_find(mrcp_server_session_t * session,mpf_termination_t * termination)996 static mrcp_termination_slot_t* mrcp_server_rtp_termination_find(mrcp_server_session_t *session, mpf_termination_t *termination)
997 {
998 	int i;
999 	mrcp_termination_slot_t *slot;
1000 	for(i=0; i<session->terminations->nelts; i++) {
1001 		slot = &APR_ARRAY_IDX(session->terminations,i,mrcp_termination_slot_t);
1002 		if(slot->termination == termination) {
1003 			return slot;
1004 		}
1005 	}
1006 	return NULL;
1007 }
1008 
mrcp_server_channel_termination_find(mrcp_server_session_t * session,mpf_termination_t * termination)1009 static mrcp_channel_t* mrcp_server_channel_termination_find(mrcp_server_session_t *session, mpf_termination_t *termination)
1010 {
1011 	int i;
1012 	mrcp_channel_t *channel;
1013 	for(i=0; i<session->channels->nelts; i++) {
1014 		channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
1015 		if(!channel) continue;
1016 
1017 		if(channel->engine_channel && channel->engine_channel->termination == termination) {
1018 			return channel;
1019 		}
1020 	}
1021 	return NULL;
1022 }
1023 
mrcp_server_channel_find(mrcp_server_session_t * session,const apt_str_t * resource_name)1024 static mrcp_channel_t* mrcp_server_channel_find(mrcp_server_session_t *session, const apt_str_t *resource_name)
1025 {
1026 	int i;
1027 	mrcp_channel_t *channel;
1028 	for(i=0; i<session->channels->nelts; i++) {
1029 		channel = APR_ARRAY_IDX(session->channels,i,mrcp_channel_t*);
1030 		if(!channel) continue;
1031 
1032 		if(apt_string_compare(&channel->resource->name,resource_name) == TRUE) {
1033 			return channel;
1034 		}
1035 	}
1036 	return NULL;
1037 }
1038 
mrcp_server_on_termination_modify(mrcp_server_session_t * session,const mpf_message_t * mpf_message)1039 static apt_bool_t mrcp_server_on_termination_modify(mrcp_server_session_t *session, const mpf_message_t *mpf_message)
1040 {
1041 	mrcp_termination_slot_t *termination_slot;
1042 	apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Media Termination Modified "APT_NAMESIDRES_FMT,
1043 		MRCP_SESSION_NAMESID(session),
1044 		mpf_termination_name_get(mpf_message->termination));
1045 	termination_slot = mrcp_server_rtp_termination_find(session,mpf_message->termination);
1046 	if(termination_slot) {
1047 		/* rtp termination */
1048 		mpf_rtp_termination_descriptor_t *rtp_descriptor;
1049 		if(termination_slot->waiting == FALSE) {
1050 			return FALSE;
1051 		}
1052 		termination_slot->waiting = FALSE;
1053 		rtp_descriptor = mpf_message->descriptor;
1054 		if(rtp_descriptor->audio.local) {
1055 			session->answer->ip = rtp_descriptor->audio.local->ip;
1056 			session->answer->ext_ip = rtp_descriptor->audio.local->ext_ip;
1057 			mrcp_session_audio_media_set(session->answer,termination_slot->id,rtp_descriptor->audio.local);
1058 		}
1059 		mrcp_server_session_subrequest_remove(session);
1060 	}
1061 	else {
1062 		/* engine channel termination */
1063 		mrcp_channel_t *channel = mrcp_server_channel_termination_find(session,mpf_message->termination);
1064 		if(channel && channel->waiting_for_termination == TRUE) {
1065 			channel->waiting_for_termination = FALSE;
1066 			mrcp_server_session_subrequest_remove(session);
1067 		}
1068 	}
1069 	return TRUE;
1070 }
1071 
mrcp_server_on_termination_subtract(mrcp_server_session_t * session,const mpf_message_t * mpf_message)1072 static apt_bool_t mrcp_server_on_termination_subtract(mrcp_server_session_t *session, const mpf_message_t *mpf_message)
1073 {
1074 	mrcp_termination_slot_t *termination_slot;
1075 	apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Media Termination Subtracted "APT_NAMESIDRES_FMT,
1076 		MRCP_SESSION_NAMESID(session),
1077 		mpf_termination_name_get(mpf_message->termination));
1078 	termination_slot = mrcp_server_rtp_termination_find(session,mpf_message->termination);
1079 	if(termination_slot) {
1080 		/* rtp termination */
1081 		if(termination_slot->waiting == FALSE) {
1082 			return FALSE;
1083 		}
1084 		termination_slot->waiting = FALSE;
1085 		mrcp_server_session_subrequest_remove(session);
1086 	}
1087 	else {
1088 		/* engine channel termination */
1089 		mrcp_channel_t *channel = mrcp_server_channel_termination_find(session,mpf_message->termination);
1090 		if(channel && channel->waiting_for_termination == TRUE) {
1091 			channel->waiting_for_termination = FALSE;
1092 			mrcp_server_session_subrequest_remove(session);
1093 		}
1094 	}
1095 	return TRUE;
1096 }
1097 
mrcp_server_mpf_message_process(mpf_message_container_t * mpf_message_container)1098 apt_bool_t mrcp_server_mpf_message_process(mpf_message_container_t *mpf_message_container)
1099 {
1100 	apr_size_t i;
1101 	mrcp_server_session_t *session;
1102 	const mpf_message_t *mpf_message;
1103 	for(i=0; i<mpf_message_container->count; i++) {
1104 		mpf_message = &mpf_message_container->messages[i];
1105 		if(mpf_message->context) {
1106 			session = mpf_engine_context_object_get(mpf_message->context);
1107 		}
1108 		else {
1109 			session = NULL;
1110 		}
1111 		if(!session) {
1112 			apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Received MPF Message: NULL session");
1113 			continue;
1114 		}
1115 		if(mpf_message->message_type == MPF_MESSAGE_TYPE_RESPONSE) {
1116 			switch(mpf_message->command_id) {
1117 				case MPF_ADD_TERMINATION:
1118 					mrcp_server_on_termination_modify(session,mpf_message);
1119 					break;
1120 				case MPF_MODIFY_TERMINATION:
1121 					mrcp_server_on_termination_modify(session,mpf_message);
1122 					break;
1123 				case MPF_SUBTRACT_TERMINATION:
1124 					mrcp_server_on_termination_subtract(session,mpf_message);
1125 					break;
1126 				case MPF_ADD_ASSOCIATION:
1127 				case MPF_REMOVE_ASSOCIATION:
1128 				case MPF_RESET_ASSOCIATIONS:
1129 				case MPF_APPLY_TOPOLOGY:
1130 				case MPF_DESTROY_TOPOLOGY:
1131 					mrcp_server_session_subrequest_remove(session);
1132 					break;
1133 				default:
1134 					break;
1135 			}
1136 		}
1137 		else if(mpf_message->message_type == MPF_MESSAGE_TYPE_EVENT) {
1138 			apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process MPF Event");
1139 		}
1140 	}
1141 	return TRUE;
1142 }
1143 
state_machine_on_message_dispatch(mrcp_state_machine_t * state_machine,mrcp_message_t * message)1144 static apt_bool_t state_machine_on_message_dispatch(mrcp_state_machine_t *state_machine, mrcp_message_t *message)
1145 {
1146 	mrcp_channel_t *channel = state_machine->obj;
1147 
1148 	if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
1149 		/* send request message to engine for actual processing */
1150 		if(channel->engine_channel) {
1151 			mrcp_engine_channel_request_process(channel->engine_channel,message);
1152 		}
1153 	}
1154 	else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
1155 		mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
1156 		/* send response message to client */
1157 		if(channel->control_channel) {
1158 			/* MRCPv2 */
1159 			mrcp_server_control_message_send(channel->control_channel,message);
1160 		}
1161 		else {
1162 			/* MRCPv1 */
1163 			mrcp_session_control_response(channel->session,message);
1164 		}
1165 
1166 		session->active_request = apt_list_pop_front(session->request_queue);
1167 		if(session->active_request) {
1168 			mrcp_server_signaling_message_dispatch(session,session->active_request);
1169 		}
1170 	}
1171 	else {
1172 		/* send event message to client */
1173 		if(channel->control_channel) {
1174 			/* MRCPv2 */
1175 			mrcp_server_control_message_send(channel->control_channel,message);
1176 		}
1177 		else {
1178 			/* MRCPv1 */
1179 			mrcp_session_control_response(channel->session,message);
1180 		}
1181 	}
1182 	return TRUE;
1183 }
1184 
state_machine_on_deactivate(mrcp_state_machine_t * state_machine)1185 static apt_bool_t state_machine_on_deactivate(mrcp_state_machine_t *state_machine)
1186 {
1187 	mrcp_channel_t *channel = state_machine->obj;
1188 	mrcp_server_session_t *session = (mrcp_server_session_t*)channel->session;
1189 	mrcp_server_session_subrequest_remove(session);
1190 	return TRUE;
1191 }
1192