diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 6c0bfd4092..5d58674a0c 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -208,6 +208,11 @@ void megaco_termination_destroy(mg_termination_t *term) if (term->type == MG_TERM_RTP && term->u.rtp.local_port != 0) { switch_rtp_release_port(term->u.rtp.local_addr, term->u.rtp.local_port); } + + if(term->active_events){ + free(term->active_events); + term->active_events = NULL; + } switch_core_hash_delete_wrlock(term->profile->terminations, term->name, term->profile->terminations_rwlock); switch_core_destroy_memory_pool(&term->pool); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c index 3e3b034df5..f249d012f4 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cli.c @@ -98,29 +98,61 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre /**********************************************************************************/ }else if(!strcmp(argv[2], "send")) { /**********************************************************************************/ - /* mg profile send sc */ printf("count = %d \n",argc); - if(argc < 7){ - goto usage; - } - if(zstr(argv[3]) || zstr(argv[4]) || zstr(argv[5]) || zstr(argv[6])){ - goto usage; - } - if (profile) { - if(!zstr(argv[7]) && !strcasecmp(argv[7],"wild")){ - wild = 0x01; - } + if (profile) { - printf("Input to Send Service Change command : " - "Profile Name[%s], term-id[%s] method[%s] reason[%s] \n", - profile->name, argv[4], argv[5], argv[6]); + switch(argc) + { + case 7: + { + /* mg profile send sc */ + printf("ARGC = 7 \n"); + if(zstr(argv[3]) || zstr(argv[4]) || zstr(argv[5]) || zstr(argv[6])){ + goto usage; + } + + if(!zstr(argv[7]) && !strcasecmp(argv[7],"wild")){ + wild = 0x01; + } + + printf("Input to Send Service Change command : " + "Profile Name[%s], term-id[%s] method[%s] reason[%s] \n", + profile->name, argv[4], argv[5], argv[6]); + + megaco_profile_release(profile); + mg_send_service_change(profile->idx, argv[4], atoi(argv[5]), atoi(argv[6]),wild); + + break; + } + case 6: + { + /* mg profile send notify */ + if(zstr(argv[3]) || zstr(argv[4]) || zstr(argv[5])){ + goto usage; + } + + if(strcasecmp(argv[3],"notify")){ + stream->write_function(stream, "-ERR wrong input \n"); + goto usage; + } + + printf("Sending DTMF digits[%s] NOTIFY for termination[%s]\n", argv[5], argv[4]); + + megaco_profile_release(profile); + mg_send_dtmf_notify(profile, argv[4], (char*)argv[5], (int)strlen(argv[5])); + + break; + } + default: + { + goto usage; + } + } + }else{ + stream->write_function(stream, "-ERR No such profile\n"); + } - megaco_profile_release(profile); - mg_send_service_change(profile->idx, argv[4], atoi(argv[5]), atoi(argv[6]),wild); - } else { - stream->write_function(stream, "-ERR No such profile\n"); - } /**********************************************************************************/ }else { /**********************************************************************************/ @@ -154,6 +186,7 @@ switch_status_t mg_process_cli_cmd(const char *cmd, switch_stream_handle_t *stre goto done; usage: + megaco_profile_release(profile); stream->write_function(stream, "-ERR Usage: \n""\t"MEGACO_CLI_SYNTAX" \n \t"MEGACO_FUNCTION_SYNTAX"\n \t" MEGACO_LOGGING_CLI_SYNTAX "\n"); done: diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c index bee845a8c1..12174639ae 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_cmd_handler.c @@ -2135,3 +2135,200 @@ err: return ret; } /*****************************************************************************************************************************/ +/* API to send DTMF Digits Notification */ + +switch_status_t mg_send_dtmf_notify(megaco_profile_t* mg_profile, const char* term_name, char* digits, int num_of_collected_digits ) +{ + MgMgcoObsEvt *oevt; + MgMgcoEvtPar* param; + int ascii = 0x00; + int cnt = 0x00; + + switch_assert(term_name); + switch_assert(mg_profile); + switch_assert(digits); + + if(0 == num_of_collected_digits ){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"num_of_collected_digits cannt be ZERO \n"); + return SWITCH_STATUS_FALSE; + } + + mg_stack_alloc_mem((Ptr*)&oevt, sizeof(MgMgcoObsEvt)); + + oevt->pres.pres = PRSNT_NODEF; + + mg_get_time_stamp(&oevt->time); + + MG_INIT_TOKEN_VALUE(&(oevt->pkg.pkgType), MGT_PKG_KNOWN); + + MG_INIT_TOKEN_VALUE(&(oevt->pkg.valType), MGT_PKG_KNOWN); + + MG_INIT_TOKEN_VALUE(&(oevt->pkg.u.val), MGT_PKG_EXT_DTMF); + + MG_INIT_TOKEN_VALUE(&(oevt->name.type),MGT_GEN_TYPE_KNOWN); + + MG_INIT_TOKEN_VALUE(&(oevt->name.u.val),(U8)MGT_PKG_ENUM_REQEVT_EXT_DTMF_EXT_CE); + + if (mgUtlGrowList((void ***)&oevt->pl.parms, sizeof(MgMgcoEvtPar), &oevt->pl.num, NULL) != ROK) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + param = oevt->pl.parms[0]; + + MG_INIT_TOKEN_VALUE(&(param->type),(U8)MGT_EVTPAR_OTHER); + + MG_INIT_TOKEN_VALUE(&(param->u.other.name.type),MGT_GEN_TYPE_KNOWN); + MG_INIT_TOKEN_VALUE(&(param->u.other.name.u.val),MGT_PKG_ENUM_OBSEVTOTHER_EXT_DTMF_EXT_CE_DGT_STR); + + MG_INIT_TOKEN_VALUE(&(param->u.other.val.type),MGT_VALUE_EQUAL); + MG_INIT_TOKEN_VALUE(&(param->u.other.val.u.eq.type),MGT_VALTYPE_OCTSTRXL); + + mg_stack_alloc_mem((Ptr*)¶m->u.other.val.u.eq.u.osxl.val, num_of_collected_digits+2); + + param->u.other.val.u.eq.u.osxl.pres = 0x01; + param->u.other.val.u.eq.u.osxl.len = num_of_collected_digits+2; + + param->u.other.val.u.eq.u.osxl.val[0] = '\"'; + + /* copy collected DTMF digits */ + if(ascii) + { + for(cnt = 1; cnt< num_of_collected_digits; cnt++){ + /* convert values to ascii */ + if(digits[cnt-1] <= 9){ + param->u.other.val.u.eq.u.osxl.val[cnt] = digits[cnt-1] + '0'; + }else{ + /* 10 for decimal equivalent of A */ + param->u.other.val.u.eq.u.osxl.val[cnt] = digits[cnt-1] + 'A' - 10; + } + } + } else { + /* If incoming digits are already in ascii format .. simply copy */ + for(cnt = 1; cnt< num_of_collected_digits; cnt++){ + param->u.other.val.u.eq.u.osxl.val[cnt] = digits[cnt-1]; + } + } + + + param->u.other.val.u.eq.u.osxl.val[num_of_collected_digits+1] = '\"'; + + if (mgUtlGrowList((void ***)&oevt->pl.parms, sizeof(MgMgcoEvtPar), &oevt->pl.num, NULL) != ROK) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + param = oevt->pl.parms[1]; + + + /* Set method */ + MG_INIT_TOKEN_VALUE(&(param->type),MGT_EVTPAR_OTHER); + MG_INIT_TOKEN_VALUE(&(param->u.other.name.type),MGT_GEN_TYPE_KNOWN); + MG_INIT_TOKEN_VALUE(&(param->u.other.name.u.val),MGT_PKG_ENUM_OBSEVTOTHER_EXT_DTMF_EXT_CE_TERM_METH); + + MG_INIT_TOKEN_VALUE(&(param->u.other.val.type),MGT_VALUE_EQUAL); + MG_INIT_TOKEN_VALUE(&(param->u.other.val.u.eq.type),MGT_VALTYPE_ENUM); + MG_INIT_TOKEN_VALUE(&(param->u.other.val.u.eq.u.enume),MGT_PKG_ENUM_OBSEVTOTHER_EXT_DTMF_EXT_CE_TERM_METHFM); + + return mg_send_notify(mg_profile, term_name, oevt); +} + +/*****************************************************************************************************************************/ + +/* Note : API to send NOTIFY Message */ +/* INPUT : +* mg_profile - MG profile structure pointer +* term_name - Termination Name(as specified for MEGACO ) +* oevt - Observed Event structure pointer +*/ +switch_status_t mg_send_notify(megaco_profile_t* mg_profile, const char* term_name, MgMgcoObsEvt* oevt) +{ + switch_status_t ret; + MgMgcoCommand request; + MgMgcoTermId* termId; + mg_termination_t* term = NULL; + MgMgcoObsEvtDesc *obs_desc = NULL; + MgMgcoRequestId reqId; + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "Sending Notify Message for termination[%s] !\n", term_name); + + MG_ZERO(&request, sizeof(request)); + MG_ZERO(&reqId, sizeof(reqId)); + + term = megaco_find_termination(mg_profile, (char*)term_name); + + if(!term){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "No termination configured for given name[%s] !\n", term_name); + return SWITCH_STATUS_FALSE; + } + + if(NULL == term->active_events){ + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "No Active events observed on given termination[%s] !\n", term_name); + /* return SWITCH_STATUS_FALSE; */ + /*TODO - ideally we should return ... + * as of now not returning .. if we dont have active signals then + * setting default request id and sending notification to MGC */ + MG_SET_DEF_REQID(&reqId); + }else{ + MG_MEM_COPY(&reqId, &term->active_events->reqId, sizeof(MgMgcoRequestId)); + } + + + if(SWITCH_STATUS_FALSE == (ret = mg_create_mgco_command(&request, CH_CMD_TYPE_REQ, MGT_NTFY))){ + return SWITCH_STATUS_FALSE; + } + + if (mgUtlGrowList((void ***)&request.u.mgCmdReq[0]->cmd.u.ntfy.obs.el.evts, sizeof(MgMgcoObsEvtLst), + &request.u.mgCmdReq[0]->cmd.u.ntfy.obs.el.num, &request.u.mgCmdReq[0]->memCp) != ROK) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + + obs_desc = &request.u.mgCmdReq[0]->cmd.u.ntfy.obs; + + MG_INIT_TOKEN_VALUE(&(obs_desc->pres), PRSNT_NODEF); + + /* copy request id */ + MG_MEM_COPY(&obs_desc->reqId, &reqId, sizeof(MgMgcoRequestId)); + + /* copy observe event */ + /*MG_MEM_COPY(obs_desc->el.evts[0], oevt, sizeof(MgMgcoObsEvt));*/ + + obs_desc->el.evts[0] = oevt; + + + /*fill txn id */ + request.transId.pres = PRSNT_NODEF; + request.transId.val = get_txn_id(); + + request.contextId.type.pres = PRSNT_NODEF; + request.contextId.type.val = MGT_CXTID_NULL; + + request.cmdStatus.pres = PRSNT_NODEF; + request.cmdStatus.val = CH_CMD_STATUS_END_OF_TXN; + + request.cmdType.pres = PRSNT_NODEF; + request.cmdType.val = CH_CMD_TYPE_REQ; + + /* fill termination */ + if (mgUtlGrowList((void ***)&request.u.mgCmdReq[0]->cmd.u.ntfy.termIdLst.terms, sizeof(MgMgcoTermIdLst), + &request.u.mgCmdReq[0]->cmd.u.ntfy.termIdLst.num, &request.u.mgCmdReq[0]->memCp) != ROK) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR,"Grow List failed\n"); + return SWITCH_STATUS_FALSE; + } + +#ifdef GCP_VER_2_1 + termId = request.u.mgCmdReq[0]->cmd.u.ntfy.termIdLst.terms[0]; +#else + termId = &(request.u.mgCmdReq[0]->cmd.u.ntfy.termId); +#endif + + mg_fill_mgco_termid(termId, (char*)term_name ,strlen(term_name), &request.u.mgCmdReq[0]->memCp); + + sng_mgco_send_cmd(mg_profile->idx, &request); + + return SWITCH_STATUS_SUCCESS; +} +/*****************************************************************************************************************************/ + diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h index fc27386d9a..f308496b1e 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.h @@ -120,6 +120,13 @@ typedef enum { cmMemcpy((U8*)((_tkn).val), (U8*)(_val), _len);\ } +#define MG_SET_DEF_REQID(_reqId) \ + (_reqId)->type.pres = PRSNT_NODEF; \ + (_reqId)->type.val = MGT_REQID_OTHER; \ + (_reqId)->id.pres = PRSNT_NODEF; \ + (_reqId)->id.val = 0xFFFFFFFF; + + switch_status_t mg_prc_descriptors(megaco_profile_t* mg_profile, MgMgcoCommand *inc_cmd, mg_termination_t* term); void handle_sng_log(uint8_t level, char *fmt, ...); void handle_mgco_sta_ind(Pst *pst, SuId suId, MgMgtSta* msg); @@ -174,6 +181,9 @@ switch_status_t mg_create_mgco_command(MgMgcoCommand *cmd, uint8_t apiType, ui switch_status_t mg_send_oos_service_change(megaco_profile_t* mg_profile, const char* term_name, int wild); switch_status_t mg_send_ins_service_change(megaco_profile_t* mg_profile, const char* term_name, int wild); +switch_status_t mg_send_notify(megaco_profile_t* mg_profile, const char* term_name, MgMgcoObsEvt* oevt); +switch_status_t mg_send_dtmf_notify(megaco_profile_t* mg_profile, const char* term_name, char* digits, int num_of_collected_digits); +switch_status_t mg_util_build_obs_evt_desc (MgMgcoObsEvt *obs_event, MgMgcoRequestId *request_id, MgMgcoObsEvtDesc **ptr_obs_desc); diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c index 73d467f8de..b6751c6eea 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_utils.c @@ -1353,3 +1353,39 @@ void mg_fill_null_context(MgMgcoContextId* ctxt) MG_SET_TKN_VAL_PRES(&ctxt->type, MGT_CXTID_NULL, PRSNT_NODEF); } /*****************************************************************************************************************************/ +switch_status_t mg_util_build_obs_evt_desc (MgMgcoObsEvt *obs_event, MgMgcoRequestId *request_id, MgMgcoObsEvtDesc **ptr_obs_desc) +{ + MgMgcoObsEvtDesc *obs_desc = NULL; + + /* Check for valid request Id, if not then fill default value */ + if (NOTPRSNT == request_id->type.pres) + { + MG_SET_DEF_REQID(request_id); + } + + mg_stack_alloc_mem((Ptr*)&obs_desc, sizeof(MgMgcoObsEvtDesc)); + if (NULL == obs_desc) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Failed to allocate MgMgcoObsEvtDesc!\n"); + return SWITCH_STATUS_FALSE; + } + + obs_desc->pres.pres = PRSNT_NODEF; + MG_MEM_COPY(&obs_desc->reqId, request_id, sizeof(MgMgcoRequestId)); + obs_desc->el.num.pres = PRSNT_NODEF; + obs_desc->el.num.val = 1; + + mg_stack_alloc_mem((Ptr*)&obs_desc->el.evts, sizeof(MgMgcoObsEvt*)); + if (NULL == obs_desc->el.evts) + { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Failed to allocate MgMgcoObsEvt!\n"); + return SWITCH_STATUS_FALSE; + } + + MG_MEM_COPY(obs_desc->el.evts[0], obs_event, sizeof(obs_event)); + + *ptr_obs_desc = obs_desc; + + return SWITCH_STATUS_SUCCESS; +} +/*****************************************************************************************************************************/