work out contexts, cleanup rtp endpoint in preparation for mg-based setup
This commit is contained in:
parent
c82c11b02a
commit
658ce0ba91
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -32,10 +32,11 @@
|
|||
#include <switch.h>
|
||||
#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,
|
||||
|
|
Loading…
Reference in New Issue