diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 3cd5856bd2..e618b5ef6c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -46,6 +46,97 @@ void megaco_peer_profile_release(mg_peer_profile_t *profile) switch_thread_rwlock_unlock(profile->rwlock); } +mg_context_t *megaco_get_context(megaco_profile_t *profile, uint32_t context_id) +{ + mg_context_t *result = NULL; + + if (context_id > MG_MAX_CONTEXTS) { + return NULL; + } + + switch_thread_rwlock_rdlock(profile->contexts_rwlock); + + /* Context exists */ + if (profile->contexts_bitmap[context_id % 8] & (1 << (context_id / 8))) { + for (result = profile->contexts[context_id % MG_CONTEXT_MODULO]; result; result = result->next) { + if (result->context_id == context_id) { + break; + } + } + } + + switch_thread_rwlock_unlock(profile->contexts_rwlock); + + return result; +} + +/* Returns a fresh new context */ +mg_context_t *megaco_choose_context(megaco_profile_t *profile) +{ + mg_context_t *ctx; + + switch_thread_rwlock_wrlock(profile->contexts_rwlock); + /* Try the next one */ + if (profile->next_context_id >= MG_MAX_CONTEXTS) { + profile->next_context_id = 1; + } + + /* Look for an available context */ + for (; profile->next_context_id < MG_MAX_CONTEXTS; profile->next_context_id++) { + if ((profile->contexts_bitmap[profile->next_context_id % 8] & (1 << (profile->next_context_id / 8))) == 0) { + /* Found! */ + profile->contexts_bitmap[profile->next_context_id % 8] |= 1 << (profile->next_context_id / 8); + int i = profile->next_context_id % MG_CONTEXT_MODULO; + ctx = malloc(sizeof *ctx); + ctx->context_id = profile->next_context_id; + ctx->profile = profile; + + if (!profile->contexts[i]) { + profile->contexts[i] = ctx; + } else { + mg_context_t *it; + for (it = profile->contexts[i]; it && it->next; it = it->next) + ; + it->next = ctx; + } + + profile->next_context_id++; + break; + } + } + + switch_thread_rwlock_unlock(profile->contexts_rwlock); + + return ctx; +} + +void megaco_release_context(mg_context_t *ctx) +{ + uint32_t context_id = ctx->context_id; + megaco_profile_t *profile = ctx->profile; + int i = context_id % MG_CONTEXT_MODULO; + + switch_thread_rwlock_wrlock(profile->contexts_rwlock); + if (profile->contexts[i] == ctx) { + profile->contexts[i] = ctx->next; + } else { + mg_context_t *it = profile->contexts[i]->next, *prev = profile->contexts[i]; + for (; it; prev = it, it = it->next) { + if (it == ctx) { + prev->next = it->next; + break; + } + } + } + + profile->contexts_bitmap[context_id % 8] &= ~(1 << (context_id / 8)); + + memset(ctx, 0, sizeof *ctx); + free(ctx); + + switch_thread_rwlock_unlock(profile->contexts_rwlock); +} + switch_status_t megaco_profile_start(const char *profilename) { switch_memory_pool_t *pool; @@ -59,9 +150,14 @@ switch_status_t megaco_profile_start(const char *profilename) profile = switch_core_alloc(pool, sizeof(*profile)); profile->pool = pool; profile->name = switch_core_strdup(pool, profilename); + profile->next_context_id++; switch_thread_rwlock_create(&profile->rwlock, pool); + + switch_thread_rwlock_create(&profile->contexts_rwlock, pool); +// switch_core_hash_init(&profile->contexts_hash, pool); + if (SWITCH_STATUS_SUCCESS != config_profile(profile, SWITCH_FALSE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error configuring profile %s\n", profile->name); goto fail; @@ -94,6 +190,8 @@ switch_status_t megaco_profile_destroy(megaco_profile_t **profile) if(SWITCH_STATUS_FALSE == sng_mgco_stop((*profile))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error stopping MEGACO Stack for profile %s\n", (*profile)->name); } + + /* TODO: Cleanup contexts */ switch_thread_rwlock_unlock((*profile)->rwlock); @@ -104,7 +202,7 @@ switch_status_t megaco_profile_destroy(megaco_profile_t **profile) switch_core_destroy_memory_pool(&(*profile)->pool); - return SWITCH_STATUS_SUCCESS; + return SWITCH_STATUS_SUCCESS; } switch_status_t megaco_peer_profile_destroy(mg_peer_profile_t **profile) diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index f1259ed544..3eee1504d8 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -131,6 +131,7 @@ switch_status_t mg_config_cleanup(megaco_profile_t* profile) { switch_xml_config_item_t *instructions = (profile ? get_instructions(profile) : NULL); switch_xml_config_cleanup(instructions); + free(instructions); return SWITCH_STATUS_SUCCESS; } @@ -140,6 +141,7 @@ switch_status_t mg_peer_config_cleanup(mg_peer_profile_t* profile) { switch_xml_config_item_t *instructions = (profile ? get_peer_instructions(profile) : NULL); switch_xml_config_cleanup(instructions); + free(instructions); return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c index bca39abb30..b9f38fb798 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c @@ -18,7 +18,7 @@ static sng_mg_event_interface_t sng_event; SWITCH_MODULE_LOAD_FUNCTION(mod_media_gateway_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_media_gateway_shutdown); SWITCH_MODULE_DEFINITION(mod_media_gateway, mod_media_gateway_load, mod_media_gateway_shutdown, NULL); -switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq); +switch_status_t handle_mg_add_cmd(SuId suId, MgMgcoCommand *req, MgMgcoAmmReq *addReq); switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); switch_status_t mg_stack_free_mem(MgMgcoMsg* msg); switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ); @@ -195,7 +195,6 @@ static void mgco_print_sdp(CmSdpInfoSet *sdp) for (mediaId = 0; mediaId < s->attrSet.numComp.val; mediaId++) { /*CmSdpAttr *a = s->attrSet.attr[mediaId];*/ - } } @@ -218,6 +217,74 @@ static void mgco_print_sdp(CmSdpInfoSet *sdp) } } + +static switch_status_t mgco_parse_local_sdp(mg_termination_t *term, CmSdpInfoSet *sdp) +{ + int i; + CmSdpInfoSet *local_sdp; + /* Parse the local SDP while copying the important bits over to our local structure, + * while taking care of editing choose request and replacing them by real values */ + + if (!term->u.rtp.local_sdp) { + local_sdp = term->u.rtp.local_sdp = switch_core_alloc(term->context->pool, sizeof *term->u.rtp.local_sdp); + } + + + if (sdp->numComp.pres == NOTPRSNT) { + return SWITCH_STATUS_FALSE; + } + + for (i = 0; i < sdp->numComp.val; i++) { + CmSdpInfo *s = sdp->info[i]; + int mediaId; + + local_sdp->info[i] = switch_core_alloc(term->context->pool, sizeof *(local_sdp->info[i])); + *(local_sdp->info[i]) = *(sdp->info[i]); + + if (s->conn.addrType.pres && s->conn.addrType.val == CM_SDP_ADDR_TYPE_IPV4 && + s->conn.netType.type.val == CM_SDP_NET_TYPE_IN && + s->conn.u.ip4.addrType.val == CM_SDP_IPV4_IP_UNI) { + + if (s->conn.u.ip4.addrType.pres) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Local address: %d.%d.%d.%d\n", + s->conn.u.ip4.u.uniIp.b[0].val, + s->conn.u.ip4.u.uniIp.b[1].val, + s->conn.u.ip4.u.uniIp.b[2].val, + s->conn.u.ip4.u.uniIp.b[3].val); + + /* TODO: Double-check bind address for this profile */ + + } + if (s->attrSet.numComp.pres) { + for (mediaId = 0; mediaId < s->attrSet.numComp.val; mediaId++) { + CmSdpAttr *a = s->attrSet.attr[mediaId]; + local_sdp->info[i]->attrSet.attr[mediaId] = switch_core_alloc(term->context->pool, sizeof(CmSdpAttr)); + *(local_sdp->info[i]->attrSet.attr[mediaId]) = *a; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Media %p\n", a); + } + } + + if (s->mediaDescSet.numComp.pres) { + for (mediaId = 0; mediaId < s->mediaDescSet.numComp.val; mediaId++) { + CmSdpMediaDesc *desc = s->mediaDescSet.mediaDesc[mediaId]; + local_sdp->info[i]->mediaDescSet.mediaDesc[mediaId] = switch_core_alloc(term->context->pool, sizeof(CmSdpMediaDesc)); + *(local_sdp->info[i]->mediaDescSet.mediaDesc[mediaId]) = *desc; + + if (desc->field.mediaType.val == CM_SDP_MEDIA_AUDIO && + desc->field.id.type.val == CM_SDP_VCID_PORT && + desc->field.id.u.port.type.val == CM_SDP_PORT_INT && + desc->field.id.u.port.u.portInt.port.type.val == CM_SDP_SPEC) { + int port = desc->field.id.u.port.u.portInt.port.val.val; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Port: %d\n", port); + + } + } + } + } + } +} + /*****************************************************************************************************************************/ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) @@ -330,17 +397,17 @@ void handle_mgco_txn_ind(Pst *pst, SuId suId, MgMgcoMsg* msg) } case MGT_MEDIAPAR_STRPAR: { - MgMgcoStreamDesc *mgStream = &mediaPar->u.stream; - - if (mgStream->sl.remote.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); - mgco_print_sdp(&mgStream->sl.remote.sdp); - } - - if (mgStream->sl.local.pres.pres) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); - mgco_print_sdp(&mgStream->sl.local.sdp); - } +// MgMgcoStreamDesc *mgStream = &mediaPar->u.stream; +// +// if (mgStream->sl.remote.pres.pres) { +// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got remote stream media description:\n"); +// mgco_print_sdp(&mgStream->sl.remote.sdp); +// } +// +// if (mgStream->sl.local.pres.pres) { +// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Got local stream media description:\n"); +// mgco_print_sdp(&mgStream->sl.local.sdp); +// } break; @@ -438,8 +505,7 @@ void handle_mgco_cmd_ind(Pst *pst, SuId suId, MgMgcoCommand* cmd) { case MGT_ADD: { - handle_mg_add_cmd(&cmd->u.mgCmdInd[0]->cmd.u.add); - mg_send_add_rsp(suId, cmd); + handle_mg_add_cmd(suId, cmd, &cmd->u.mgCmdInd[0]->cmd.u.add); break; } @@ -598,7 +664,7 @@ MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd) break; default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); break; } break; @@ -651,12 +717,12 @@ MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd) break; default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported Command[%s]\n", __PRETTY_FUNCTION__, PRNT_MG_CMD(cmd_type)); } /* switch command type for reply */ break; default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported api_type[%s]!\n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(api_type)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s: failed, Unsupported api_type[%s]!\n", __PRETTY_FUNCTION__, PRNT_MG_CMD_TYPE(api_type)); break; } /* switch -api_type */ @@ -665,9 +731,40 @@ MgMgcoTermIdLst *mg_get_term_id_list(MgMgcoCommand *cmd) /*****************************************************************************************************************************/ -switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq) +switch_status_t handle_mg_add_cmd(SuId suId, MgMgcoCommand *req, MgMgcoAmmReq *addReq) { - int descId; + int descId; + mg_context_t *ctx = NULL; + + MgMgcoCommand cmd; + int ret = 0x00; + MgMgcoTermId *termId; + MgMgcoCtxt ctxt; + + memset(&cmd,0, sizeof(cmd)); + + /*copy transaction-id*/ + memcpy(&cmd.transId, &req->transId, sizeof(MgMgcoTransId)); + + if (req->contextId.type.val == MGT_CXTID_CHOOSE) { + ctx = megaco_choose_context(NULL); + } else if (req->contextId.type.val == MGT_CXTID_OTHER) { + ctx = megaco_get_context(NULL, req->contextId.val.val); + } + + + /*copy context-id*/ /*TODO - in case of $ context should be generated by app, we should not simply copy incoming structure */ + memcpy(&cmd.contextId, &req->contextId, sizeof(MgMgcoContextId)); + + /*copy peer identifier */ + memcpy(&cmd.peerId, &req->peerId, sizeof(TknU32)); + + /*fill response structue */ + if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&cmd.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ + return ret; + } + + for (descId = 0; descId < addReq->dl.num.val; descId++) { switch (addReq->dl.descs[descId]->type.val) { case MGT_MEDIADESC: @@ -727,72 +824,43 @@ switch_status_t handle_mg_add_cmd(MgMgcoAmmReq *addReq) break; } } - - - return SWITCH_STATUS_SUCCESS; -} - - -/*****************************************************************************************************************************/ -switch_status_t mg_send_add_rsp(SuId suId, MgMgcoCommand *req) -{ - MgMgcoCommand cmd; - int ret = 0x00; - MgMgcoTermId *termId; - MgMgcoCtxt ctxt; - - memset(&cmd,0, sizeof(cmd)); - - /*copy transaction-id*/ - memcpy(&cmd.transId, &req->transId,sizeof(MgMgcoTransId)); - - /*copy context-id*/ /*TODO - in case of $ context should be generated by app, we should not simply copy incoming structure */ - memcpy(&cmd.contextId, &req->contextId,sizeof(MgMgcoContextId)); - - /*copy peer identifier */ - memcpy(&cmd.peerId, &req->peerId,sizeof(TknU32)); - - /*fill response structue */ - if(SWITCH_STATUS_FALSE == (ret = mg_stack_alloc_mem((Ptr*)&cmd.u.mgCmdRsp[0],sizeof(MgMgcoCmdReply)))){ - return ret; - } - - cmd.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; + + cmd.u.mgCmdRsp[0]->pres.pres = PRSNT_NODEF; cmd.u.mgCmdRsp[0]->type.pres = PRSNT_NODEF; cmd.u.mgCmdRsp[0]->type.val = MGT_ADD; cmd.u.mgCmdRsp[0]->u.add.pres.pres = PRSNT_NODEF; - - + + cmd.u.mgCmdRsp[0]->u.add.termIdLst.num.pres = PRSNT_NODEF; cmd.u.mgCmdRsp[0]->u.add.termIdLst.num.val = 1; - + mgUtlAllocMgMgcoTermIdLst(&cmd.u.mgCmdRsp[0]->u.add.termIdLst, &req->u.mgCmdReq[0]->cmd.u.add.termIdLst); - + #ifdef GCP_VER_2_1 termId = cmd.u.mgCmdRsp[0]->u.add.termIdLst.terms[0]; #else termId = &(cmd.u.mgCmdRsp[0]->u.add.termId); #endif + /* FIXME */ mg_fill_mgco_termid(termId, (CONSTANT U8*)"term1",&req->u.mgCmdRsp[0]->memCp); - + /* We will always send one command at a time..*/ cmd.cmdStatus.pres = PRSNT_NODEF; cmd.cmdStatus.val = CH_CMD_STATUS_END_OF_CMD; - + cmd.cmdType.pres = PRSNT_NODEF; cmd.cmdType.val = CH_CMD_TYPE_RSP; - - + + ret = sng_mgco_send_cmd(suId, &cmd); - + memcpy(&ctxt.transId,&req->transId,sizeof(MgMgcoTransId)); - memcpy(&ctxt.cntxtId, &req->contextId,sizeof(MgMgcoContextId)); + memcpy(&ctxt.cntxtId, &cmd.contextId,sizeof(MgMgcoContextId)); memcpy(&ctxt.peerId, &req->peerId,sizeof(TknU32)); ctxt.cmdStatus.pres = PRSNT_NODEF; ctxt.cmdStatus.val = CH_CMD_STATUS_END_OF_AXN; - ret = sng_mgco_send_axn_req(suId, &ctxt); - return ret; + return sng_mgco_send_axn_req(suId, &ctxt);; } /*****************************************************************************************************************************/ @@ -811,7 +879,7 @@ switch_status_t mg_stack_alloc_mem( Ptr* _memPtr, Size _memSize ) if ( ROK != cmAllocEvnt( _memSize, MG_MAXBLKSIZE, &sMem, _memPtr ) ) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_alloc_mem: cmAllocEvnt return failure for _memSize=%d\n",_memSize); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_alloc_mem: cmAllocEvnt return failure for _memSize=%d\n", (int)_memSize); return SWITCH_STATUS_FALSE; } @@ -850,7 +918,7 @@ switch_status_t mg_stack_free_mem(MgMgcoMsg* msg) { if ( !msg ) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_get_mem: invalid message\n"); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, " Failed mg_stack_free_mem: invalid message\n"); return SWITCH_STATUS_FALSE; } diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 8aa0dae0d3..91dc74210c 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -15,6 +15,8 @@ #define MG_MAX_PEERS 5 +#define MG_CONTEXT_MAX_TERMS 3 + #define MEGACO_CLI_SYNTAX "profile|logging" #define MEGACO_LOGGING_CLI_SYNTAX "logging [enable|disable]" #define MEGACO_FUNCTION_SYNTAX "profile [name] [start | stop] [status] [xmlstatus] [peerxmlstatus]" @@ -50,10 +52,57 @@ typedef struct mg_peer_profile_s{ char* mid; /* Peer H.248 MID */ char* transport_type; /* UDP/TCP */ char* encoding_type; /* Encoding TEXT/Binary */ -}mg_peer_profile_t; +} mg_peer_profile_t; -typedef struct megaco_profile_s { +typedef enum { + MG_TERM_FREE = 0, + MG_TERM_TDM, + MG_TERM_RTP +} mg_termination_type_t; + +typedef struct megaco_profile_s megaco_profile_t; +typedef struct mg_context_s mg_context_t; + +typedef struct mg_termination_s { + mg_termination_type_t type; + const char *uuid; + mg_context_t *context; + + union { + struct { + const char *codec; + int ptime; + const char *remote_address; + switch_port_t remote_port; + switch_port_t local_port; + + CmSdpInfoSet *local_sdp; + CmSdpInfoSet *remote_sdp; + + unsigned mode:2; + unsigned :0; + } rtp; + struct { + int span; + int channel; + } tdm; + } u; +} mg_termination_t; + + +struct mg_context_s { + uint32_t context_id; + mg_termination_t terminations[MG_CONTEXT_MAX_TERMS]; + megaco_profile_t *profile; + mg_context_t *next; + switch_memory_pool_t *pool; +}; + +#define MG_CONTEXT_MODULO 16 +#define MG_MAX_CONTEXTS 32768 + +struct megaco_profile_s { char *name; switch_memory_pool_t *pool; switch_thread_rwlock_t *rwlock; /* < Reference counting rwlock */ @@ -71,7 +120,12 @@ typedef struct megaco_profile_s { char* rtp_termination_id_prefix; int rtp_termination_id_len; char* peer_list[MG_MAX_PEERS]; /* MGC Peer ID LIST */ -} megaco_profile_t; + + switch_thread_rwlock_t *contexts_rwlock; + uint32_t next_context_id; + uint8_t contexts_bitmap[MG_MAX_CONTEXTS/8]; /* Availability matrix, enough bits for a 32768 bitmap */ + mg_context_t *contexts[MG_CONTEXT_MODULO]; +}; megaco_profile_t *megaco_profile_locate(const char *name); @@ -80,6 +134,11 @@ void megaco_profile_release(megaco_profile_t *profile); switch_status_t megaco_profile_start(const char *profilename); switch_status_t megaco_profile_destroy(megaco_profile_t **profile); + +mg_context_t *megaco_get_context(megaco_profile_t *profile, uint32_t context_id); +mg_context_t *megaco_choose_context(megaco_profile_t *profile); +void megaco_release_context(mg_context_t *ctx); + switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload); switch_status_t sng_mgco_start(megaco_profile_t* profile); switch_status_t sng_mgco_stop(megaco_profile_t* profile); diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 4a8107f859..e99eef1b76 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -32,10 +32,11 @@ #include #include "mod_sofia.h" -#define kRSDP "r_sdp" -#define kLSDP "l_sdp" #define kBINDADDRESS "bind_address" -#define kCODECSTRING "codec_string" +#define kLOCALADDR "local_addr" +#define kLOCALPORT "local_port" +#define kREMOTEADDR "remote_addr" +#define kREMOTEPORT "remote_port" static struct { switch_memory_pool_t *pool; @@ -88,19 +89,16 @@ switch_io_routines_t crtp_io_routines = { .send_dtmf = channel_send_dtmf }; -#if 0 SWITCH_STANDARD_API(test_function) { return SWITCH_STATUS_SUCCESS; } -#endif void crtp_init(switch_loadable_module_interface_t *module_interface) { switch_endpoint_interface_t *endpoint_interface; -#if 0 /* DAVIDY */ switch_api_interface_t *api_interface; -#endif + crtp.pool = module_interface->pool; endpoint_interface = switch_loadable_module_create_interface(module_interface, SWITCH_ENDPOINT_INTERFACE); endpoint_interface->interface_name = "rtp"; @@ -108,390 +106,9 @@ void crtp_init(switch_loadable_module_interface_t *module_interface) endpoint_interface->state_handler = &crtp_state_handlers; crtp.endpoint_interface = endpoint_interface; -// SWITCH_ADD_API(api_interface, "rtp_test", "test", test_function, ""); + SWITCH_ADD_API(api_interface, "rtp_test", "test", test_function, ""); } - -typedef struct parsed_sdp_s { - const char *c; /*!< Connection */ - - -} parsed_sdp_t; - - -//static switch_status_t check_codec - -/* - * Setup the local RTP side - * A lot of values can be chosen by the MG, those will have $ as a placeholder. - * We need to validate the SDP, making sure we can support everything that's offered on our behalf, - * amend it if we don't support everything, or systematically reject it if we cannot support it. - * - * Would this function be called using NULL as l_sdp, we will generate an SDP payload. - */ - -static switch_status_t setup_local_rtp(crtp_private_t *tech_pvt, const char *l_sdp, const char *codec_string) -{ - int codec_order_last; - int num_codecs; -#if 0 /* DAVIDY */ - switch_core_session_t const * session = tech_pvt->session; -#endif - const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS] = { 0 }; - char *codec_order[SWITCH_MAX_CODECS] = { 0 }; -#if 1 /* DAVIDY */ - char *sdpbuf = NULL; - sdp_connection_t *connection = NULL; - sdp_printer_t *printer = NULL; -#endif - - - /* Load in the list of codecs we support. If we have a codec string we use our priorities first */ - if (codec_string) { - char *tmp_codec_string; - if ((tmp_codec_string = switch_core_session_strdup(tech_pvt->session, codec_string))) { - codec_order_last = switch_separate_string(tmp_codec_string, ',', codec_order, SWITCH_MAX_CODECS); - num_codecs = switch_loadable_module_get_codecs_sorted(codecs, SWITCH_MAX_CODECS, codec_order, codec_order_last); - } - } else { - num_codecs = switch_loadable_module_get_codecs(codecs, switch_arraylen(codecs)); - } - - /* TODO: Look at remote settings */ - - if (zstr(l_sdp)) { - /* Generate a local SDP here */ -#if 0 /* DAVIDY */ - const char *sdpbuf = switch_core_session_sprintf(session, "v=0\nIN IP4 %s\nm=audio %d RTP/AVP %d"); -#endif - - } else { - /* Parse the SDP and remove anything we cannot support, then validate it to make sure it contains at least one codec - * so that we reject invalid ones. */ -#if 0 - uint8_t match = 0; - int first = 0, last = 0; - int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0; - int sendonly = 0, recvonly = 0; - int greedy = 0, x = 0, skip = 0; -#endif - int ptime = 0, maxptime = 0; - int sdp_modified = 0; - int cur_codec = 0; - - sdp_parser_t *parser = NULL; -#if 1 /* DAVIDY */ - sdp_session_t *sdp; -#else - sdp_session_t *sdp, *lsdp; -#endif - sdp_media_t *m; - sdp_attribute_t *attr; - su_home_t *sdp_home; - - if (!(parser = sdp_parse(NULL, l_sdp, (int) strlen(l_sdp), sdp_f_megaco /* accept $ values */ | sdp_f_insane /* accept omitted o= */))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Malformed SDP\n"); - goto fail; - } - - if (!(sdp = sdp_session(parser))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't get session from sdp.\n"); - goto fail; - } - sdp_home = sdp_parser_home(parser); - for (m = sdp->sdp_media; m; m = m->m_next) { - - if (m->m_type == sdp_media_audio) { - sdp_rtpmap_t *map; - - for (attr = m->m_attributes; attr; attr = attr->a_next) { - if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) { - ptime = atoi(attr->a_value); - } else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) { - maxptime = atoi(attr->a_value); - } - } - - connection = sdp->sdp_connection; - if (m->m_connections) { - connection = m->m_connections; - } - - /* Check for wildcards in m= (media) and c= (connection) */ - if (!zstr(connection->c_address)) { - if (!strcmp(connection->c_address, "$")) { - connection->c_address = su_strdup(sdp_home, tech_pvt->bind_address); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using bind address: %s\n", tech_pvt->bind_address); - switch_channel_set_variable(tech_pvt->channel, kBINDADDRESS, tech_pvt->bind_address); - sdp_modified = 1; - } else if (strcmp(connection->c_address, tech_pvt->bind_address)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MGC requested to bind on [%s] which is different than the configuration [%s]\n", - connection->c_address, tech_pvt->bind_address); - goto fail; - } - - if (m->m_port == MEGACO_CHOOSE) { - tech_pvt->local_port = m->m_port = switch_rtp_request_port(tech_pvt->bind_address); - switch_channel_set_variable_printf(tech_pvt->channel, "rtp_local_port", "%d", tech_pvt->local_port); - if (!tech_pvt->local_port) { - /* Port request failed */ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No available RTP ports on [%s]\n", tech_pvt->bind_address); - goto fail; - } - sdp_modified = 1; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using local port: %d\n", tech_pvt->local_port); - } - } - - /* Validate codecs */ - for (map = m->m_rtpmaps; map; map = map->rm_next) { - if (map->rm_any) { - /* Pick our first favorite codec */ - if (codecs[cur_codec]) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Choosing a codec: %s/%d\n", codecs[cur_codec]->iananame, codecs[cur_codec]->ianacode); - map->rm_encoding = su_strdup(sdp_home, codecs[cur_codec]->iananame); - map->rm_pt = codecs[cur_codec]->ianacode; - map->rm_any = 0; - map->rm_predef = codecs[cur_codec]->ianacode < 96; - cur_codec++; - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No more codecs in preferences!\n"); - goto fail; - } - } - } - } else if (m->m_type == sdp_media_image && m->m_port) { - /* TODO: Handle T38 */ - - } - } -#if 0 /* DAVIDY */ - char sdpbuf[2048] = ""; -#endif - printer = sdp_print(sdp_home, sdp, sdpbuf, sizeof(sdpbuf), 0); - switch_channel_set_variable(tech_pvt->channel, kLSDP, sdpbuf); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting local SDP: [%s]\n", sdpbuf); - sdp_printer_free(printer); - - goto done; - - fail: - if (tech_pvt->local_port) { - switch_rtp_release_port(tech_pvt->bind_address, tech_pvt->local_port); - } - - if (parser) { - sdp_parser_free(parser); - } - - return SWITCH_STATUS_FALSE; - } - -done: - return SWITCH_STATUS_SUCCESS; - -} - -#if 0 -static void setup_rtp(crtp_private_t *tech_pvt, const char *r_sdp, const char *l_sdp) -{ - switch_core_session_t const * session = tech_pvt->session; - uint8_t match = 0; - int first = 0, last = 0; - int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0; - int sendonly = 0, recvonly = 0; - int greedy = 0, x = 0, skip = 0, mine = 0; - int got_crypto = 0, got_audio = 0, got_avp = 0, got_savp = 0, got_udptl = 0; - - sdp_parser_t *parser = NULL, *l_parser = NULL; - sdp_session_t *sdp, *lsdp; - sdp_media_t *m; - sdp_attribute_t *attr; - - - int scrooge = 0; - - - if (zstr(r_sdp)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No SDP\n"); - goto fail; - } - - if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Malformed SDP\n"); - goto fail; - } - - if (!(sdp = sdp_session(parser))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't get session from sdp.\n"); - goto fail; - } - - for (m = sdp->sdp_media; m; m = m->m_next) { - sdp_connection_t *connection; - ptime = dptime; - maxptime = dmaxptime; - - if (m->m_proto == sdp_proto_srtp) { - got_savp++; - } else if (m->m_proto == sdp_proto_rtp) { - got_avp++; - } else if (m->m_proto == sdp_proto_udptl) { - got_udptl++; - } - - if (got_udptl && m->m_type == sdp_media_image && m->m_port) { - //switch_t38_options_t *t38_options = tech_process_udptl(tech_pvt, sdp, m); - - /* TODO: Process T38 */ - - } else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) { - sdp_rtpmap_t *map; - - connection = sdp->sdp_connection; - if (m->m_connections) { - connection = m->m_connections; - } - - if (!connection) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n"); - match = 0; - break; - } - - /* Begin Codec Negotiation */ - for (map = m->m_rtpmaps; map; map = map->rm_next) { - int32_t i; - uint32_t near_rate = 0; - const switch_codec_implementation_t *mimp = NULL, *near_match = NULL; - const char *rm_encoding; - uint32_t map_bit_rate = 0; - int codec_ms = 0; - switch_codec_fmtp_t codec_fmtp = { 0 }; - - if (x++ < skip) { - continue; - } - - if (!(rm_encoding = map->rm_encoding)) { - rm_encoding = ""; - } - - if (!strcasecmp(rm_encoding, "telephone-event")) { - if (!best_te || map->rm_rate == tech_pvt->rm_rate) { - best_te = (switch_payload_t) map->rm_pt; - }9 - } - - if (!cng_pt && !strcasecmp(rm_encoding, "CN")) { - cng_pt = (switch_payload_t) map->rm_pt; - if (tech_pvt->rtp_session) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", cng_pt); - switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt); - } - } - - if (match) { - continue; - } - - if (greedy) { - first = mine; - last = first + 1; - } else { - first = 0; - last = num_codecs; - } - - codec_ms = ptime; - - if (maxptime && (!codec_ms || codec_ms > maxptime)) { - codec_ms = maxptime; - } - - if (!codec_ms) { - codec_ms = switch_default_ptime(rm_encoding, map->rm_pt); - } - - map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt); - - if (!ptime && !strcasecmp(map->rm_encoding, "g723")) { - ptime = codec_ms = 30; - } - - if (zstr(map->rm_fmtp)) { - if (!strcasecmp(map->rm_encoding, "ilbc")) { - ptime = codec_ms = 30; - map_bit_rate = 13330; - } - } else { - if ((switch_core_codec_parse_fmtp(map->rm_encoding, map->rm_fmtp, map->rm_rate, &codec_fmtp)) == SWITCH_STATUS_SUCCESS) { - if (codec_fmtp.bits_per_second) { - map_bit_rate = codec_fmtp.bits_per_second; - } - if (codec_fmtp.microseconds_per_packet) { - codec_ms = (codec_fmtp.microseconds_per_packet / 1000); - } - } - } - - - for (i = first; i < last && i < total_codecs; i++) { - const switch_codec_implementation_t *imp = codec_array[i]; - uint32_t bit_rate = imp->bits_per_second; - uint32_t codec_rate = imp->samples_per_second; - if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) { - continue; - } - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Compare [%s:%d:%u:%d:%u]/[%s:%d:%u:%d:%u]\n", - rm_encoding, map->rm_pt, (int) map->rm_rate, codec_ms, map_bit_rate, - imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000, bit_rate); - if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { - match = (map->rm_pt == imp->ianacode) ? 1 : 0; - } else { - match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1; - } - - if (match && bit_rate && map_bit_rate && map_bit_rate != bit_rate && strcasecmp(map->rm_encoding, "ilbc")) { - /* nevermind */ - match = 0; - } - - if (match) { - if (scrooge) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, - "Bah HUMBUG! Sticking with %s@%uh@%ui\n", - imp->iananame, imp->samples_per_second, imp->microseconds_per_packet / 1000); - } else { - if ((ptime && codec_ms && codec_ms * 1000 != imp->microseconds_per_packet) || map->rm_rate != codec_rate) { - near_rate = map->rm_rate; - near_match = imp; - match = 0; - continue; - } - } - mimp = imp; - break; - } else { - match = 0; - } - } - } - - /* End */ - - - } - } - -fail: - if (parser) { - sdp_parser_free(parser); - } -} -#endif - static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session,