/* * OpenMRCP - Open Source Media Resource Control Protocol Stack * Copyright (C) 2007, Cepstral LLC * * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Author(s): * Arsen Chaloyan * * Contributor(s): * */ #include #include "media_processor.h" #include "media_timer.h" #include "codec_manager.h" #include "media_context.h" typedef enum { MEDIA_REQUEST_ADD_CONTEXT, MEDIA_REQUEST_REMOVE_CONTEXT, MEDIA_REQUEST_ADD_SOURCE, MEDIA_REQUEST_REMOVE_SOURCE, MEDIA_REQUEST_ADD_SINK, MEDIA_REQUEST_REMOVE_SINK } media_request_id; typedef struct media_request_msg_t media_request_msg_t; struct media_request_msg_t { media_request_id id; rtp_session_t *rtp_session; media_context_t *context; audio_source_t *source; audio_sink_t *sink; media_request_type type; media_request_msg_t *next; }; struct media_processor_t { apr_pool_t *pool; apr_thread_mutex_t *guard; apr_thread_cond_t *wait_object; media_timer_t *timer; codec_manager_t *codec_manager; media_request_msg_t *request_queue; media_context_t *context_head; media_context_t *context_tail; }; static media_request_msg_t* media_processor_request_create(media_request_id id, media_request_type type, apr_pool_t *pool); static apr_status_t media_processor_request_send(media_processor_t *processor, media_request_msg_t *request); static void media_processor_main(media_timer_t *timer, void *data); apr_status_t g711u_codec_init(codec_manager_t *codec_manager); apr_status_t g711a_codec_init(codec_manager_t *codec_manager); media_processor_t* media_processor_create(apr_pool_t *pool) { media_processor_t *processor = apr_palloc(pool,sizeof(media_processor_t)); processor->pool = pool; processor->request_queue = NULL; processor->context_head = processor->context_tail = NULL; processor->timer = NULL; processor->codec_manager = codec_manager_create(pool); if(processor->codec_manager) { g711u_codec_init(processor->codec_manager); g711a_codec_init(processor->codec_manager); } return processor; } apr_status_t media_processor_start(media_processor_t *processor) { apr_thread_mutex_create(&processor->guard,APR_THREAD_MUTEX_UNNESTED,processor->pool); apr_thread_cond_create(&processor->wait_object, processor->pool); processor->timer = media_timer_start(CODEC_FRAME_TIME_BASE,media_processor_main,processor,processor->pool); return APR_SUCCESS; } apr_status_t media_processor_terminate(media_processor_t *processor) { media_timer_stop(processor->timer); apr_thread_cond_destroy(processor->wait_object); apr_thread_mutex_destroy(processor->guard); processor->guard = NULL; return APR_SUCCESS; } apr_status_t media_processor_destroy(media_processor_t *processor) { if(processor->codec_manager) { codec_manager_destroy(processor->codec_manager); processor->codec_manager = NULL; } return APR_SUCCESS; } apr_status_t media_processor_context_add(media_processor_t *processor, media_context_t *context, media_request_type type) { media_request_msg_t *request = media_processor_request_create(MEDIA_REQUEST_ADD_CONTEXT,type,context->pool); request->context = context; return media_processor_request_send(processor,request); } apr_status_t media_processor_context_remove(media_processor_t *processor, media_context_t *context, media_request_type type) { media_request_msg_t *request = media_processor_request_create(MEDIA_REQUEST_REMOVE_CONTEXT,type,context->pool); request->context = context; return media_processor_request_send(processor,request); } apr_status_t media_context_source_add(media_processor_t *processor, media_context_t *context, audio_source_t *source, media_request_type type) { media_request_msg_t *request = media_processor_request_create(MEDIA_REQUEST_ADD_SOURCE,type,context->pool); request->context = context; request->source = source; return media_processor_request_send(processor,request); } apr_status_t media_context_source_remove(media_processor_t *processor, media_context_t *context, audio_source_t *source, media_request_type type) { media_request_msg_t *request = media_processor_request_create(MEDIA_REQUEST_REMOVE_SOURCE,type,context->pool); request->context = context; request->source = source; return media_processor_request_send(processor,request); } apr_status_t media_context_sink_add(media_processor_t *processor, media_context_t *context, audio_sink_t *sink, media_request_type type) { media_request_msg_t *request = media_processor_request_create(MEDIA_REQUEST_ADD_SINK,type,context->pool); request->context = context; request->sink = sink; return media_processor_request_send(processor,request); } apr_status_t media_context_sink_remove(media_processor_t *processor, media_context_t *context, audio_sink_t *sink, media_request_type type) { media_request_msg_t *request = media_processor_request_create(MEDIA_REQUEST_REMOVE_SINK,type,context->pool); request->context = context; request->sink = sink; return media_processor_request_send(processor,request); } apr_status_t media_context_destroy(media_context_t *context) { if(context && context->method_set->destroy) { context->method_set->destroy(context); } return APR_SUCCESS; } codec_manager_t* media_processor_codec_manager_get(media_processor_t *processor) { return processor->codec_manager; } static apr_status_t media_processor_do_context_add(media_processor_t *processor, media_context_t *context) { if(!context) { return APR_INCOMPLETE; } context->next = NULL; context->prev = processor->context_tail; if(processor->context_tail) { processor->context_tail->next = context; processor->context_tail = context; } else { processor->context_head = processor->context_tail = context; } return APR_SUCCESS; } static apr_status_t media_processor_do_context_remove(media_processor_t *processor, media_context_t *context) { if(!context) { return APR_INCOMPLETE; } if(context->prev) { context->prev->next = context->next; } else { processor->context_head = context->next; } if(context->next) { context->next->prev = context->prev; } else { processor->context_tail = context->prev; } context->next = NULL; context->prev = NULL; return APR_SUCCESS; } static apr_status_t request_queue_process(media_processor_t *processor) { apr_thread_mutex_lock(processor->guard); while(processor->request_queue) { media_request_msg_t *request; request = processor->request_queue; switch(request->id) { case MEDIA_REQUEST_ADD_CONTEXT: media_processor_do_context_add(processor,request->context); break; case MEDIA_REQUEST_REMOVE_CONTEXT: media_processor_do_context_remove(processor,request->context); break; case MEDIA_REQUEST_ADD_SOURCE: if(request->context->method_set->audio_source_add) { request->context->method_set->audio_source_add(request->context,request->source); } break; case MEDIA_REQUEST_REMOVE_SOURCE: if(request->context->method_set->audio_source_remove) { request->context->method_set->audio_source_remove(request->context,request->source); } break; case MEDIA_REQUEST_ADD_SINK: if(request->context->method_set->audio_sink_add) { request->context->method_set->audio_sink_add(request->context,request->sink); } break; case MEDIA_REQUEST_REMOVE_SINK: if(request->context->method_set->audio_sink_remove) { request->context->method_set->audio_sink_remove(request->context,request->sink); } break; } if(request->type == MEDIA_REQUEST_TYPE_SYNC) { apr_thread_cond_signal(processor->wait_object); } processor->request_queue = request->next; } apr_thread_mutex_unlock(processor->guard); return APR_SUCCESS; } static media_request_msg_t* media_processor_request_create(media_request_id id, media_request_type type, apr_pool_t *pool) { media_request_msg_t *request = apr_palloc(pool,sizeof(media_request_msg_t)); request->id = id; request->type = type; request->next = NULL; return request; } static apr_status_t media_processor_request_send(media_processor_t *processor, media_request_msg_t *request) { apr_thread_mutex_lock(processor->guard); if(processor->request_queue) { media_request_msg_t *tail = processor->request_queue; while(tail->next) { tail = tail->next; } tail->next = request; } else { processor->request_queue = request; } if(request->type == MEDIA_REQUEST_TYPE_SYNC) { apr_thread_cond_wait(processor->wait_object,processor->guard); } apr_thread_mutex_unlock(processor->guard); return APR_SUCCESS; } static void media_processor_main(media_timer_t *timer, void *data) { media_processor_t *processor = data; media_context_t *context; request_queue_process(processor); context = processor->context_head; while(context) { context->method_set->process(context); context = context->next; } }