/* * Copyright 2008-2010 Arsen Chaloyan * * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * $Id: unimrcp_server.c 1711 2010-05-25 17:54:02Z achaloyan $ */ #include #include #include #include "uni_version.h" #include "unimrcp_server.h" #include "mrcp_resource_loader.h" #include "mpf_engine.h" #include "mpf_codec_manager.h" #include "mpf_rtp_termination_factory.h" #include "mrcp_sofiasip_server_agent.h" #include "mrcp_unirtsp_server_agent.h" #include "mrcp_server_connection.h" #include "apt_net.h" #include "apt_log.h" #define CONF_FILE_NAME "unimrcpserver.xml" #define DEFAULT_PLUGIN_DIR_PATH "../plugin" #ifdef WIN32 #define DEFAULT_PLUGIN_EXT "dll" #else #define DEFAULT_PLUGIN_EXT "so" #endif #define DEFAULT_IP_ADDRESS "127.0.0.1" #define DEFAULT_SIP_PORT 8060 #define DEFAULT_RTSP_PORT 1554 #define DEFAULT_MRCP_PORT 1544 #define DEFAULT_RTP_PORT_MIN 5000 #define DEFAULT_RTP_PORT_MAX 6000 #define DEFAULT_SOFIASIP_UA_NAME "UniMRCP SofiaSIP" #define DEFAULT_SDP_ORIGIN "UniMRCPServer" #define XML_FILE_BUFFER_LENGTH 16000 /** UniMRCP server loader */ typedef struct unimrcp_server_loader_t unimrcp_server_loader_t; /** UniMRCP server loader */ struct unimrcp_server_loader_t { /** MRCP server */ mrcp_server_t *server; /** Directory layout */ apt_dir_layout_t *dir_layout; /** XML document */ apr_xml_doc *doc; /** Pool to allocate memory from */ apr_pool_t *pool; /** Default ip address (named property) */ const char *ip; /** Default external (NAT) ip address (named property) */ const char *ext_ip; /** Implicitly detected, cached ip address */ const char *auto_ip; }; static apt_bool_t unimrcp_server_load(mrcp_server_t *mrcp_server, apt_dir_layout_t *dir_layout, apr_pool_t *pool); /** Start UniMRCP server */ MRCP_DECLARE(mrcp_server_t*) unimrcp_server_start(apt_dir_layout_t *dir_layout) { apr_pool_t *pool; mrcp_server_t *server; if(!dir_layout) { return NULL; } apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"UniMRCP Server ["UNI_VERSION_STRING"]"); apt_log(APT_LOG_MARK,APT_PRIO_INFO,"APR ["APR_VERSION_STRING"]"); server = mrcp_server_create(dir_layout); if(!server) { return NULL; } pool = mrcp_server_memory_pool_get(server); if(!pool) { return NULL; } if(unimrcp_server_load(server,dir_layout,pool) == FALSE) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Load UniMRCP Server Document"); } mrcp_server_start(server); return server; } /** Shutdown UniMRCP server */ MRCP_DECLARE(apt_bool_t) unimrcp_server_shutdown(mrcp_server_t *server) { if(mrcp_server_shutdown(server) == FALSE) { return FALSE; } return mrcp_server_destroy(server); } /** Check whether specified attribute is valid */ static APR_INLINE apt_bool_t is_attr_valid(const apr_xml_attr *attr) { return (attr && attr->value && attr->value != '\0'); } /** Check whether specified attribute is enabled (true) */ static APR_INLINE apt_bool_t is_attr_enabled(const apr_xml_attr *attr) { if(attr && strcasecmp(attr->value,"false") == 0) { return FALSE; } return TRUE; } /** Check whether cdata is valid */ static APR_INLINE apt_bool_t is_cdata_valid(const apr_xml_elem *elem) { return (elem->first_cdata.first && elem->first_cdata.first->text); } /** Get text cdata */ static APR_INLINE const char* cdata_text_get(const apr_xml_elem *elem) { return elem->first_cdata.first->text; } /** Get boolean cdata */ static APR_INLINE apt_bool_t cdata_bool_get(const apr_xml_elem *elem) { return (strcasecmp(elem->first_cdata.first->text,"true") == 0) ? TRUE : FALSE; } /** Copy cdata */ static APR_INLINE char* cdata_copy(const apr_xml_elem *elem, apr_pool_t *pool) { return apr_pstrdup(pool,elem->first_cdata.first->text); } /** Get generic "id" and "enable" attributes */ static apt_bool_t header_attribs_get(const apr_xml_elem *elem, const apr_xml_attr **id, const apr_xml_attr **enable) { const apr_xml_attr *attr; if(!id || !enable) { return FALSE; } *id = NULL; *enable = NULL; for(attr = elem->attr; attr; attr = attr->next) { if(strcasecmp(attr->name,"id") == 0) { *id = attr; } else if(strcasecmp(attr->name,"enable") == 0) { *enable = attr; } } if(is_attr_valid(*id) == FALSE) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Missing Required Attribute in Element <%s>",elem->name); return FALSE; } return TRUE; } /** Get generic "name" and "value" attributes */ static apt_bool_t name_value_attribs_get(const apr_xml_elem *elem, const apr_xml_attr **name, const apr_xml_attr **value) { const apr_xml_attr *attr; if(!name || !value) { return FALSE; } *name = NULL; *value = NULL; for(attr = elem->attr; attr; attr = attr->next) { if(strcasecmp(attr->name,"name") == 0) { *name = attr; } else if(strcasecmp(attr->name,"value") == 0) { *value = attr; } } return (*name && *value) ? TRUE : FALSE; } static char* unimrcp_server_ip_address_get(unimrcp_server_loader_t *loader, const apr_xml_elem *elem) { const apr_xml_attr *attr = NULL; for(attr = elem->attr; attr; attr = attr->next) { if(strcasecmp(attr->name,"type") == 0) { break; } } if(attr && strcasecmp(attr->value,"auto") == 0) { /* implicitly detect ip address, if not already detected */ if(!loader->auto_ip) { char *auto_addr = DEFAULT_IP_ADDRESS; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Detecting IP Address"); apt_ip_get(&auto_addr,loader->pool); loader->auto_ip = auto_addr; } return apr_pstrdup(loader->pool,loader->auto_ip); } if(is_cdata_valid(elem)) { /* use provided ip address */ return cdata_copy(elem,loader->pool); } /* use default ip address */ return apr_pstrdup(loader->pool,loader->ip); } /** Load resource */ static apt_bool_t unimrcp_server_resource_load(mrcp_resource_loader_t *resource_loader, const apr_xml_elem *root, apr_pool_t *pool) { apt_str_t resource_class; const apr_xml_attr *id_attr; const apr_xml_attr *enable_attr; apt_string_reset(&resource_class); if(header_attribs_get(root,&id_attr,&enable_attr) == FALSE) { return FALSE; } if(is_attr_enabled(enable_attr) == FALSE) { return TRUE; } apt_string_set(&resource_class,id_attr->value); return mrcp_resource_load(resource_loader,&resource_class); } /** Load resource factory */ static apt_bool_t unimrcp_server_resource_factory_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root) { const apr_xml_elem *elem; mrcp_resource_factory_t *resource_factory; mrcp_resource_loader_t *resource_loader = mrcp_resource_loader_create(FALSE,loader->pool); if(!resource_loader) { return FALSE; } apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Resources"); for(elem = root->first_child; elem; elem = elem->next) { if(strcasecmp(elem->name,"resource") == 0) { unimrcp_server_resource_load(resource_loader,elem,loader->pool); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } resource_factory = mrcp_resource_factory_get(resource_loader); return mrcp_server_resource_factory_register(loader->server,resource_factory); } /** Load SofiaSIP signaling agent */ static apt_bool_t unimrcp_server_sip_uas_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; mrcp_sig_agent_t *agent; mrcp_sofia_server_config_t *config; config = mrcp_sofiasip_server_config_alloc(loader->pool); config->local_port = DEFAULT_SIP_PORT; config->user_agent_name = DEFAULT_SOFIASIP_UA_NAME; config->origin = DEFAULT_SDP_ORIGIN; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading SofiaSIP Agent <%s>",id); for(elem = root->first_child; elem; elem = elem->next) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); if(strcasecmp(elem->name,"sip-ip") == 0) { config->local_ip = unimrcp_server_ip_address_get(loader,elem); } else if(strcasecmp(elem->name,"sip-ext-ip") == 0) { config->ext_ip = unimrcp_server_ip_address_get(loader,elem); } else if(strcasecmp(elem->name,"sip-port") == 0) { if(is_cdata_valid(elem) == TRUE) { config->local_port = (apr_port_t)atol(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"sip-transport") == 0) { if(is_cdata_valid(elem) == TRUE) { config->transport = cdata_copy(elem,loader->pool); } } else if(strcasecmp(elem->name,"ua-name") == 0) { if(is_cdata_valid(elem) == TRUE) { config->user_agent_name = cdata_copy(elem,loader->pool); } } else if(strcasecmp(elem->name,"sdp-origin") == 0) { if(is_cdata_valid(elem) == TRUE) { config->origin = cdata_copy(elem,loader->pool); } } else if(strcasecmp(elem->name,"force-destination") == 0) { if(is_cdata_valid(elem) == TRUE) { config->force_destination = cdata_bool_get(elem); } } else if(strcasecmp(elem->name,"sip-t1") == 0) { if(is_cdata_valid(elem) == TRUE) { config->sip_t1 = atol(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"sip-t2") == 0) { if(is_cdata_valid(elem) == TRUE) { config->sip_t2 = atol(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"sip-t4") == 0) { if(is_cdata_valid(elem) == TRUE) { config->sip_t4 = atol(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"sip-t1x64") == 0) { if(is_cdata_valid(elem) == TRUE) { config->sip_t1x64 = atol(cdata_text_get(elem)); } } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } if(!config->local_ip) { /* use default ip address if not specified */ config->local_ip = apr_pstrdup(loader->pool,loader->ip); } if(!config->ext_ip && loader->ext_ip) { /* use default ext ip address if not specified */ config->ext_ip = apr_pstrdup(loader->pool,loader->ext_ip); } agent = mrcp_sofiasip_server_agent_create(id,config,loader->pool); return mrcp_server_signaling_agent_register(loader->server,agent); } /** Load UniRTSP signaling agent */ static apt_bool_t unimrcp_server_rtsp_uas_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; mrcp_sig_agent_t *agent; rtsp_server_config_t *config; config = mrcp_unirtsp_server_config_alloc(loader->pool); config->origin = DEFAULT_SDP_ORIGIN; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading UniRTSP Agent <%s>",id); for(elem = root->first_child; elem; elem = elem->next) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); if(strcasecmp(elem->name,"rtsp-ip") == 0) { config->local_ip = unimrcp_server_ip_address_get(loader,elem); } else if(strcasecmp(elem->name,"rtsp-port") == 0) { if(is_cdata_valid(elem) == TRUE) { config->local_port = (apr_port_t)atol(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"sdp-origin") == 0) { if(is_cdata_valid(elem) == TRUE) { config->origin = cdata_copy(elem,loader->pool); } } else if(strcasecmp(elem->name,"max-connection-count") == 0) { if(is_cdata_valid(elem) == TRUE) { config->max_connection_count = atol(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"force-destination") == 0) { if(is_cdata_valid(elem) == TRUE) { config->force_destination = cdata_bool_get(elem); } } else if(strcasecmp(elem->name,"resource-map") == 0) { const apr_xml_attr *name_attr; const apr_xml_attr *value_attr; const apr_xml_elem *child_elem; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Resource Map"); for(child_elem = elem->first_child; child_elem; child_elem = child_elem->next) { if(name_value_attribs_get(child_elem,&name_attr,&value_attr) == TRUE) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",name_attr->value,value_attr->value); apr_table_set(config->resource_map,name_attr->value,value_attr->value); } } } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } if(!config->local_ip) { /* use default ip address if not specified */ config->local_ip = apr_pstrdup(loader->pool,loader->ip); } agent = mrcp_unirtsp_server_agent_create(id,config,loader->pool); return mrcp_server_signaling_agent_register(loader->server,agent); } /** Load MRCPv2 connection agent */ static apt_bool_t unimrcp_server_mrcpv2_uas_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; mrcp_connection_agent_t *agent; char *mrcp_ip = NULL; apr_port_t mrcp_port = DEFAULT_MRCP_PORT; apr_size_t max_connection_count = 100; apt_bool_t force_new_connection = FALSE; apr_size_t rx_buffer_size = 0; apr_size_t tx_buffer_size = 0; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading MRCPv2 Agent <%s>",id); for(elem = root->first_child; elem; elem = elem->next) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); if(strcasecmp(elem->name,"mrcp-ip") == 0) { mrcp_ip = unimrcp_server_ip_address_get(loader,elem); } else if(strcasecmp(elem->name,"mrcp-port") == 0) { if(is_cdata_valid(elem) == TRUE) { mrcp_port = (apr_port_t)atol(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"max-connection-count") == 0) { if(is_cdata_valid(elem) == TRUE) { max_connection_count = atol(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"force-new-connection") == 0) { if(is_cdata_valid(elem) == TRUE) { force_new_connection = cdata_bool_get(elem); } } else if(strcasecmp(elem->name,"rx-buffer-size") == 0) { if(is_cdata_valid(elem) == TRUE) { rx_buffer_size = atol(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"tx-buffer-size") == 0) { if(is_cdata_valid(elem) == TRUE) { tx_buffer_size = atol(cdata_text_get(elem)); } } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } if(!mrcp_ip) { /* use default ip address if not specified */ mrcp_ip = apr_pstrdup(loader->pool,loader->ip); } agent = mrcp_server_connection_agent_create(id,mrcp_ip,mrcp_port,max_connection_count,force_new_connection,loader->pool); if(agent) { if(rx_buffer_size) { mrcp_server_connection_rx_size_set(agent,rx_buffer_size); } if(tx_buffer_size) { mrcp_server_connection_tx_size_set(agent,tx_buffer_size); } } return mrcp_server_connection_agent_register(loader->server,agent); } /** Load media engine */ static apt_bool_t unimrcp_server_media_engine_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; mpf_engine_t *media_engine; unsigned long realtime_rate = 1; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Media Engine <%s>",id); for(elem = root->first_child; elem; elem = elem->next) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); if(strcasecmp(elem->name,"realtime-rate") == 0) { if(is_cdata_valid(elem) == TRUE) { realtime_rate = atol(cdata_text_get(elem)); } } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } media_engine = mpf_engine_create(id,loader->pool); if(media_engine) { mpf_engine_scheduler_rate_set(media_engine,realtime_rate); } return mrcp_server_media_engine_register(loader->server,media_engine); } /** Load RTP factory */ static apt_bool_t unimrcp_server_rtp_factory_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; char *rtp_ip = NULL; char *rtp_ext_ip = NULL; mpf_termination_factory_t *rtp_factory; mpf_rtp_config_t *rtp_config; rtp_config = mpf_rtp_config_alloc(loader->pool); rtp_config->rtp_port_min = DEFAULT_RTP_PORT_MIN; rtp_config->rtp_port_max = DEFAULT_RTP_PORT_MAX; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading RTP Factory <%s>",id); for(elem = root->first_child; elem; elem = elem->next) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); if(strcasecmp(elem->name,"rtp-ip") == 0) { rtp_ip = unimrcp_server_ip_address_get(loader,elem); } else if(strcasecmp(elem->name,"rtp-ext-ip") == 0) { rtp_ext_ip = unimrcp_server_ip_address_get(loader,elem); } else if(strcasecmp(elem->name,"rtp-port-min") == 0) { if(is_cdata_valid(elem) == TRUE) { rtp_config->rtp_port_min = (apr_port_t)atol(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"rtp-port-max") == 0) { if(is_cdata_valid(elem) == TRUE) { rtp_config->rtp_port_max = (apr_port_t)atol(cdata_text_get(elem)); } } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } if(rtp_ip) { apt_string_set(&rtp_config->ip,rtp_ip); } else { apt_string_set(&rtp_config->ip,loader->ip); } if(rtp_ext_ip) { apt_string_set(&rtp_config->ext_ip,rtp_ext_ip); } else if(loader->ext_ip){ apt_string_set(&rtp_config->ext_ip,loader->ext_ip); } rtp_factory = mpf_rtp_termination_factory_create(rtp_config,loader->pool); return mrcp_server_rtp_factory_register(loader->server,rtp_factory,id); } /** Load plugin */ static apt_bool_t unimrcp_server_plugin_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root) { mrcp_engine_t *engine; mrcp_engine_config_t *config; const char *plugin_id = NULL; const char *plugin_name = NULL; const char *plugin_ext = NULL; const char *plugin_path = NULL; apt_bool_t plugin_enabled = TRUE; const apr_xml_attr *attr; for(attr = root->attr; attr; attr = attr->next) { if(strcasecmp(attr->name,"id") == 0) { plugin_id = apr_pstrdup(loader->pool,attr->value); } else if(strcasecmp(attr->name,"name") == 0) { plugin_name = attr->value; } else if(strcasecmp(attr->name,"ext") == 0) { plugin_ext = attr->value; } else if(strcasecmp(attr->name,"enable") == 0) { plugin_enabled = is_attr_enabled(attr); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Attribute <%s>",attr->name); } } if(!plugin_id || !plugin_name) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Missing plugin id or name"); return FALSE; } if(!plugin_enabled) { /* disabled plugin, just skip it */ return TRUE; } if(!plugin_ext) { plugin_ext = DEFAULT_PLUGIN_EXT; } if(*loader->dir_layout->plugin_dir_path == '\0') { plugin_path = apr_psprintf(loader->pool,"%s.%s", plugin_name,plugin_ext); } else { plugin_path = apr_psprintf(loader->pool,"%s/%s.%s", loader->dir_layout->plugin_dir_path,plugin_name,plugin_ext); } config = mrcp_engine_config_alloc(loader->pool); /* load optional named and generic name/value params */ if(root->first_child){ const apr_xml_attr *attr_name; const apr_xml_attr *attr_value; const apr_xml_elem *elem; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Engine Params"); config->params = apr_table_make(loader->pool,1); for(elem = root->first_child; elem; elem = elem->next) { if(strcasecmp(elem->name,"max-channel-count") == 0) { if(is_cdata_valid(elem) == TRUE) { config->max_channel_count = atol(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"param") == 0) { if(name_value_attribs_get(elem,&attr_name,&attr_value) == TRUE) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",attr_name->value,attr_value->value); apr_table_set(config->params,attr_name->value,attr_value->value); } } } } engine = mrcp_server_engine_load(loader->server,plugin_id,plugin_path,config); return mrcp_server_engine_register(loader->server,engine); } /** Load plugin (engine) factory */ static apt_bool_t unimrcp_server_plugin_factory_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root) { const apr_xml_elem *elem; if(!loader->dir_layout->plugin_dir_path) { loader->dir_layout->plugin_dir_path = DEFAULT_PLUGIN_DIR_PATH; } apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Plugin Factory"); for(elem = root->first_child; elem; elem = elem->next) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); if(strcasecmp(elem->name,"engine") == 0) { unimrcp_server_plugin_load(loader,elem); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } return TRUE; } /** Load jitter buffer settings */ static apt_bool_t unimrcp_server_jb_settings_load(unimrcp_server_loader_t *loader, mpf_jb_config_t *jb, const apr_xml_elem *root) { const apr_xml_elem *elem; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Jitter Buffer Settings"); for(elem = root->first_child; elem; elem = elem->next) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); if(strcasecmp(elem->name,"playout-delay") == 0) { if(is_cdata_valid(elem) == TRUE) { jb->initial_playout_delay = atol(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"min-playout-delay") == 0) { if(is_cdata_valid(elem) == TRUE) { jb->min_playout_delay = atol(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"max-playout-delay") == 0) { if(is_cdata_valid(elem) == TRUE) { jb->max_playout_delay = atol(cdata_text_get(elem)); } } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } return TRUE; } /** Load RTCP settings */ static apt_bool_t unimrcp_server_rtcp_settings_load(unimrcp_server_loader_t *loader, mpf_rtp_settings_t *rtcp_settings, const apr_xml_elem *root) { const apr_xml_elem *elem; const apr_xml_attr *attr = NULL; for(attr = root->attr; attr; attr = attr->next) { if(strcasecmp(attr->name,"enable") == 0) { break; } } if(is_attr_enabled(attr) == FALSE) { /* RTCP is disabled, skip the rest */ return TRUE; } rtcp_settings->rtcp = TRUE; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading RTCP Settings"); for(elem = root->first_child; elem; elem = elem->next) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); if(strcasecmp(elem->name,"rtcp-bye") == 0) { if(is_cdata_valid(elem) == TRUE) { rtcp_settings->rtcp_bye_policy = atoi(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"tx-interval") == 0) { if(is_cdata_valid(elem) == TRUE) { rtcp_settings->rtcp_tx_interval = (apr_uint16_t)atoi(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"rx-resolution") == 0) { if(is_cdata_valid(elem) == TRUE) { rtcp_settings->rtcp_rx_resolution = (apr_uint16_t)atol(cdata_text_get(elem)); } } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } return TRUE; } /** Load RTP settings */ static apt_bool_t unimrcp_server_rtp_settings_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; mpf_rtp_settings_t *rtp_settings = mpf_rtp_settings_alloc(loader->pool); apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading RTP Settings <%s>",id); for(elem = root->first_child; elem; elem = elem->next) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); if(strcasecmp(elem->name,"jitter-buffer") == 0) { unimrcp_server_jb_settings_load(loader,&rtp_settings->jb_config,elem); } else if(strcasecmp(elem->name,"ptime") == 0) { if(is_cdata_valid(elem) == TRUE) { rtp_settings->ptime = (apr_uint16_t)atol(cdata_text_get(elem)); } } else if(strcasecmp(elem->name,"codecs") == 0) { const apr_xml_attr *attr; const mpf_codec_manager_t *codec_manager = mrcp_server_codec_manager_get(loader->server); if(is_cdata_valid(elem) == TRUE && codec_manager) { mpf_codec_manager_codec_list_load( codec_manager, &rtp_settings->codec_list, cdata_text_get(elem), loader->pool); } for(attr = elem->attr; attr; attr = attr->next) { if(strcasecmp(attr->name,"own-preference") == 0) { rtp_settings->own_preferrence = is_attr_enabled(attr); break; } } } else if(strcasecmp(elem->name,"rtcp") == 0) { unimrcp_server_rtcp_settings_load(loader,rtp_settings,elem); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } return mrcp_server_rtp_settings_register(loader->server,rtp_settings,id); } /** Load map of resources and engines */ static apr_table_t* resource_engine_map_load(const apr_xml_elem *root, apr_pool_t *pool) { const apr_xml_attr *attr_name; const apr_xml_attr *attr_value; const apr_xml_elem *elem; apr_table_t *plugin_map = apr_table_make(pool,2); apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Plugin Map"); for(elem = root->first_child; elem; elem = elem->next) { if(strcasecmp(elem->name,"param") == 0) { if(name_value_attribs_get(elem,&attr_name,&attr_value) == TRUE) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Param %s:%s",attr_name->value,attr_value->value); apr_table_set(plugin_map,attr_name->value,attr_value->value); } } } return plugin_map; } /** Load MRCPv2 profile */ static apt_bool_t unimrcp_server_mrcpv2_profile_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; mrcp_profile_t *profile; mrcp_sig_agent_t *sip_agent = NULL; mrcp_connection_agent_t *mrcpv2_agent = NULL; mpf_engine_t *media_engine = NULL; mpf_termination_factory_t *rtp_factory = NULL; mpf_rtp_settings_t *rtp_settings = NULL; apr_table_t *resource_engine_map = NULL; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading MRCPv2 Profile <%s>",id); for(elem = root->first_child; elem; elem = elem->next) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); if(is_cdata_valid(elem) == FALSE) { continue; } if(strcasecmp(elem->name,"sip-uas") == 0) { sip_agent = mrcp_server_signaling_agent_get(loader->server,cdata_text_get(elem)); } else if(strcasecmp(elem->name,"mrcpv2-uas") == 0) { mrcpv2_agent = mrcp_server_connection_agent_get(loader->server,cdata_text_get(elem)); } else if(strcasecmp(elem->name,"media-engine") == 0) { media_engine = mrcp_server_media_engine_get(loader->server,cdata_text_get(elem)); } else if(strcasecmp(elem->name,"rtp-factory") == 0) { rtp_factory = mrcp_server_rtp_factory_get(loader->server,cdata_text_get(elem)); } else if(strcasecmp(elem->name,"rtp-settings") == 0) { rtp_settings = mrcp_server_rtp_settings_get(loader->server,cdata_text_get(elem)); } else if(strcasecmp(elem->name,"resource-engine-map") == 0) { resource_engine_map = resource_engine_map_load(elem,loader->pool); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create MRCPv2 Profile [%s]",id); profile = mrcp_server_profile_create( id, NULL, sip_agent, mrcpv2_agent, media_engine, rtp_factory, rtp_settings, loader->pool); return mrcp_server_profile_register(loader->server,profile,resource_engine_map); } /** Load MRCPv1 profile */ static apt_bool_t unimrcp_server_mrcpv1_profile_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root, const char *id) { const apr_xml_elem *elem; mrcp_profile_t *profile; mrcp_sig_agent_t *rtsp_agent = NULL; mpf_engine_t *media_engine = NULL; mpf_termination_factory_t *rtp_factory = NULL; mpf_rtp_settings_t *rtp_settings = NULL; apr_table_t *resource_engine_map = NULL; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading MRCPv1 Profile <%s>",id); for(elem = root->first_child; elem; elem = elem->next) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); if(is_cdata_valid(elem) == FALSE) { continue; } if(strcasecmp(elem->name,"rtsp-uas") == 0) { rtsp_agent = mrcp_server_signaling_agent_get(loader->server,cdata_text_get(elem)); } else if(strcasecmp(elem->name,"media-engine") == 0) { media_engine = mrcp_server_media_engine_get(loader->server,cdata_text_get(elem)); } else if(strcasecmp(elem->name,"rtp-factory") == 0) { rtp_factory = mrcp_server_rtp_factory_get(loader->server,cdata_text_get(elem)); } else if(strcasecmp(elem->name,"rtp-settings") == 0) { rtp_settings = mrcp_server_rtp_settings_get(loader->server,cdata_text_get(elem)); } else if(strcasecmp(elem->name,"resource-engine-map") == 0) { resource_engine_map = resource_engine_map_load(elem,loader->pool); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create MRCPv1 Profile [%s]",id); profile = mrcp_server_profile_create( id, NULL, rtsp_agent, NULL, media_engine, rtp_factory, rtp_settings, loader->pool); return mrcp_server_profile_register(loader->server,profile,resource_engine_map); } /** Load properties */ static apt_bool_t unimrcp_server_properties_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root) { const apr_xml_elem *elem; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Properties"); for(elem = root->first_child; elem; elem = elem->next) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Element <%s>",elem->name); if(strcasecmp(elem->name,"ip") == 0) { loader->ip = unimrcp_server_ip_address_get(loader,elem); apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Property ip:%s",loader->ip); } else if(strcasecmp(elem->name,"ext-ip") == 0) { loader->ext_ip = unimrcp_server_ip_address_get(loader,elem); apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Set Property ext-ip:%s",loader->ext_ip); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } return TRUE; } /** Load components */ static apt_bool_t unimrcp_server_components_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root) { const apr_xml_elem *elem; const apr_xml_attr *id_attr; const apr_xml_attr *enable_attr; const char *id; /* Create codec manager first (probably it should be loaded from config either) */ mpf_codec_manager_t *codec_manager = mpf_engine_codec_manager_create(loader->pool); if(codec_manager) { mrcp_server_codec_manager_register(loader->server,codec_manager); } apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Components"); for(elem = root->first_child; elem; elem = elem->next) { if(strcasecmp(elem->name,"resource-factory") == 0) { unimrcp_server_resource_factory_load(loader,elem); continue; } if(strcasecmp(elem->name,"plugin-factory") == 0) { unimrcp_server_plugin_factory_load(loader,elem); continue; } /* get common "id" and "enable" attributes */ if(header_attribs_get(elem,&id_attr,&enable_attr) == FALSE) { /* invalid id */ continue; } if(is_attr_enabled(enable_attr) == FALSE) { /* disabled element, just skip it */ continue; } id = apr_pstrdup(loader->pool,id_attr->value); if(strcasecmp(elem->name,"sip-uas") == 0) { unimrcp_server_sip_uas_load(loader,elem,id); } else if(strcasecmp(elem->name,"rtsp-uas") == 0) { unimrcp_server_rtsp_uas_load(loader,elem,id); } else if(strcasecmp(elem->name,"mrcpv2-uas") == 0) { unimrcp_server_mrcpv2_uas_load(loader,elem,id); } else if(strcasecmp(elem->name,"media-engine") == 0) { unimrcp_server_media_engine_load(loader,elem,id); } else if(strcasecmp(elem->name,"rtp-factory") == 0) { unimrcp_server_rtp_factory_load(loader,elem,id); } else if(strcasecmp(elem->name,"plugin-factory") == 0) { unimrcp_server_plugin_factory_load(loader,elem); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } return TRUE; } /** Load settings */ static apt_bool_t unimrcp_server_settings_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root) { const apr_xml_elem *elem; const apr_xml_attr *id_attr; const apr_xml_attr *enable_attr; const char *id; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Settings"); for(elem = root->first_child; elem; elem = elem->next) { /* get common "id" and "enable" attributes */ if(header_attribs_get(elem,&id_attr,&enable_attr) == FALSE) { /* invalid id */ continue; } if(is_attr_enabled(enable_attr) == FALSE) { /* disabled element, just skip it */ continue; } id = apr_pstrdup(loader->pool,id_attr->value); if(strcasecmp(elem->name,"rtp-settings") == 0) { unimrcp_server_rtp_settings_load(loader,elem,id); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } return TRUE; } /** Load profiles */ static apt_bool_t unimrcp_server_profiles_load(unimrcp_server_loader_t *loader, const apr_xml_elem *root) { const apr_xml_elem *elem; const apr_xml_attr *id_attr; const apr_xml_attr *enable_attr; const char *id; apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Loading Profiles"); for(elem = root->first_child; elem; elem = elem->next) { /* get common "id" and "enable" attributes */ if(header_attribs_get(elem,&id_attr,&enable_attr) == FALSE) { /* invalid id */ continue; } if(is_attr_enabled(enable_attr) == FALSE) { /* disabled element, just skip it */ continue; } id = apr_pstrdup(loader->pool,id_attr->value); if(strcasecmp(elem->name,"mrcpv2-profile") == 0) { unimrcp_server_mrcpv2_profile_load(loader,elem,id); } else if(strcasecmp(elem->name,"mrcpv1-profile") == 0) { unimrcp_server_mrcpv1_profile_load(loader,elem,id); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } return TRUE; } /** Parse XML document */ static apr_xml_doc* unimrcp_server_doc_parse(const char *file_path, apr_pool_t *pool) { apr_xml_parser *parser = NULL; apr_xml_doc *xml_doc = NULL; apr_file_t *fd = NULL; apr_status_t rv; apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Open Config File [%s]",file_path); rv = apr_file_open(&fd,file_path,APR_READ|APR_BINARY,0,pool); if(rv != APR_SUCCESS) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open Config File [%s]",file_path); return NULL; } rv = apr_xml_parse_file(pool,&parser,&xml_doc,fd,XML_FILE_BUFFER_LENGTH); if(rv != APR_SUCCESS) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse Config File [%s]",file_path); xml_doc = NULL; } apr_file_close(fd); return xml_doc; } static apt_bool_t unimrcp_server_load(mrcp_server_t *mrcp_server, apt_dir_layout_t *dir_layout, apr_pool_t *pool) { const char *file_path; apr_xml_doc *doc; const apr_xml_elem *elem; const apr_xml_elem *root; const apr_xml_attr *attr; unimrcp_server_loader_t *loader; const char *version = NULL; file_path = apt_confdir_filepath_get(dir_layout,CONF_FILE_NAME,pool); if(!file_path) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Get Path to Conf File [%s]",CONF_FILE_NAME); return FALSE; } /* Parse XML document */ doc = unimrcp_server_doc_parse(file_path,pool); if(!doc) { return FALSE; } root = doc->root; /* Match document name */ if(!root || strcasecmp(root->name,"unimrcpserver") != 0) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Document <%s>",root->name); return FALSE; } /* Read attributes */ for(attr = root->attr; attr; attr = attr->next) { if(strcasecmp(attr->name,"version") == 0) { version = attr->value; } } /* Check version number first */ if(!version) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Version"); return FALSE; } loader = apr_palloc(pool,sizeof(unimrcp_server_loader_t)); loader->doc = doc; loader->server = mrcp_server; loader->dir_layout = dir_layout; loader->pool = pool; loader->ip = DEFAULT_IP_ADDRESS; loader->ext_ip = NULL; loader->auto_ip = NULL; /* Navigate through document */ for(elem = root->first_child; elem; elem = elem->next) { if(strcasecmp(elem->name,"properties") == 0) { unimrcp_server_properties_load(loader,elem); } else if(strcasecmp(elem->name,"components") == 0) { unimrcp_server_components_load(loader,elem); } else if(strcasecmp(elem->name,"settings") == 0) { unimrcp_server_settings_load(loader,elem); } else if(strcasecmp(elem->name,"profiles") == 0) { unimrcp_server_profiles_load(loader,elem); } else { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Unknown Element <%s>",elem->name); } } return TRUE; }