提交 5e8e23f5 authored 作者: David Yat Sin's avatar David Yat Sin

Merge remote branch 'smgfs/master'

Conflicts:
	libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
......@@ -235,6 +235,7 @@ ftmod_sangoma_isdn_la_SOURCES = \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_transfer.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c \
......
......@@ -18,6 +18,11 @@ with the signaling protocols that you can run on top of your I/O interfaces.
-->
<!--<param name="enable-analog-option" value="call-swap"/>-->
<!--<param name="enable-analog-option" value="3-way"/>-->
<!--
Refuse to load the module if there is configuration errors
Defaults to 'no'
-->
<!--<param name="fail-on-error" value="no"/>-->
</settings>
<!-- Sample analog configuration (The analog_spans tag is for ftmod_analog) -->
......
......@@ -2,6 +2,7 @@ APIs that result in an event when the API returns FTDM_SUCCESS
ftdm_channel_call_answer()
ftdm_channel_call_indicate()
ftdm_channel_call_transfer()
FTDM_SIGEVENT_INDICATION_COMPLETED
*note that FTDM_SIGEVENT_INDICATION_COMPLETED has associated data to indicate the result of the indication
*note this event is only delivered on non-blocking channels
......
差异被折叠。
......@@ -82,6 +82,8 @@ typedef enum {
FLAG_MEDIA_READY = (1 << 11),
/* Set when we already sent a Channel ID IE */
FLAG_SENT_CHAN_ID = (1 << 12),
/* Set when we already sent a Connect */
FLAG_SENT_CONNECT = (1 << 13),
} sngisdn_flag_t;
......@@ -152,10 +154,11 @@ typedef struct ftdm_sngisdn_prog_ind {
} ftdm_sngisdn_progind_t;
/* Only timers that can be cancelled are listed here */
#define SNGISDN_NUM_TIMERS 1
#define SNGISDN_NUM_TIMERS 2
/* Increase NUM_TIMERS as number of ftdm_sngisdn_timer_t increases */
typedef enum {
SNGISDN_TIMER_FACILITY = 0,
SNGISDN_TIMER_ATT_TRANSFER,
} ftdm_sngisdn_timer_t;
typedef struct sngisdn_glare_data {
......@@ -165,8 +168,35 @@ typedef struct sngisdn_glare_data {
int16_t dChan;
ConEvnt setup;
uint8_t ces;
}sngisdn_glare_data_t;
} sngisdn_glare_data_t;
typedef enum {
SNGISDN_TRANSFER_NONE = 0, /* Default value, no transfer being done */
SNGISDN_TRANSFER_ATT_COURTESY_VRU,
SNGISDN_TRANSFER_ATT_COURTESY_VRU_DATA,
SNGISDN_TRANSFER_INVALID,
} sngisdn_transfer_type_t;
#define SNGISDN_TRANSFER_TYPE_STRINGS "NONE", "ATT_COURTESY_VRU", "ATT_COURTERY_VRU_DATA", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2sngisdn_transfer_type, sngisdn_transfer_type2str, sngisdn_transfer_type_t)
/* From section 4.2 of TR50075, max length of data is 100 when single UUI is sent */
#define COURTESY_TRANSFER_MAX_DATA_SIZE 100
typedef struct _att_courtesy_vru
{
char dtmf_digits [20];
char data[COURTESY_TRANSFER_MAX_DATA_SIZE];
} att_courtesy_vru_t;
typedef struct _sngisdn_transfer_data
{
sngisdn_transfer_type_t type; /* Specifies which type of transfer is being used */
ftdm_transfer_response_t response;
union
{
att_courtesy_vru_t att_courtesy_vru;
} tdata;
} sngisdn_transfer_data_t;
/* Channel specific data */
typedef struct sngisdn_chan_data {
......@@ -180,7 +210,8 @@ typedef struct sngisdn_chan_data {
uint8_t globalFlg;
sngisdn_glare_data_t glare;
ftdm_timer_id_t timers[SNGISDN_NUM_TIMERS];
ftdm_timer_id_t timers[SNGISDN_NUM_TIMERS];
sngisdn_transfer_data_t transfer_data;
/* variables saved here will be sent to the user application
on next SIGEVENT_XXX */
......@@ -211,8 +242,10 @@ typedef struct sngisdn_span_data {
uint8_t facility_ie_decode;
uint8_t facility;
int8_t facility_timeout;
uint8_t att_remove_dtmf;
int32_t transfer_timeout;
uint8_t num_local_numbers;
uint8_t ignore_cause_value;
uint8_t ignore_cause_value;
uint8_t trace_q931; /* TODO: combine with trace_flags */
uint8_t trace_q921; /* TODO: combine with trace_flags */
uint8_t raw_trace_q931; /* TODO: combine with trace_flags */
......@@ -394,7 +427,7 @@ void sngisdn_trace_interpreted_q931(sngisdn_span_data_t *signal_data, ftdm_trace
void sngisdn_trace_raw_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len);
void sngisdn_trace_raw_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len);
void get_memory_info(void);
void sngisdn_get_memory_info(void);
ftdm_status_t sng_isdn_activate_trace(ftdm_span_t *span, sngisdn_tracetype_t trace_opt);
ftdm_status_t sngisdn_check_free_ids(void);
......@@ -432,18 +465,23 @@ ftdm_status_t set_chan_id_ie(ftdm_channel_t *ftdmchan, ChanId *chanId);
ftdm_status_t set_restart_ind_ie(ftdm_channel_t *ftdmchan, RstInd *rstInd);
ftdm_status_t set_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr);
ftdm_status_t set_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8_t *data_len);
ftdm_status_t set_user_to_user_ie(ftdm_channel_t *ftdmchan, UsrUsr *usrUsr);
ftdm_status_t set_cause_ie(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn);
ftdm_status_t sngisdn_add_var(sngisdn_chan_data_t *sngisdn_info, const char* var, const char* val);
ftdm_status_t sngisdn_add_raw_data(sngisdn_chan_data_t *sngisdn_info, uint8_t* data, ftdm_size_t data_len);
ftdm_status_t sngisdn_clear_data(sngisdn_chan_data_t *sngisdn_info);
void sngisdn_send_signal(sngisdn_chan_data_t *sngisdn_info, ftdm_signal_event_t event_id);
uint8_t sngisdn_get_infoTranCap_from_user(ftdm_bearer_cap_t bearer_capability);
uint8_t sngisdn_get_usrInfoLyr1Prot_from_user(ftdm_user_layer1_prot_t layer1_prot);
ftdm_bearer_cap_t sngisdn_get_infoTranCap_from_stack(uint8_t bearer_capability);
ftdm_user_layer1_prot_t sngisdn_get_usrInfoLyr1Prot_from_stack(uint8_t layer1_prot);
ftdm_status_t sngisdn_transfer(ftdm_channel_t *ftdmchan);
ftdm_status_t sngisdn_att_transfer_process_dtmf(ftdm_channel_t *ftdmchan, const char* dtmf);
static __inline__ uint32_t sngisdn_test_flag(sngisdn_chan_data_t *sngisdn_info, sngisdn_flag_t flag)
{
return (uint32_t) sngisdn_info->flags & flag;
......
......@@ -285,7 +285,9 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
signal_data->timer_t3 = 8;
signal_data->restart_opt = SNGISDN_OPT_DEFAULT;
signal_data->link_id = span->span_id;
signal_data->transfer_timeout = 20000;
signal_data->att_remove_dtmf = 1;
span->default_caller_data.dnis.plan = FTDM_NPI_INVALID;
span->default_caller_data.dnis.type = FTDM_TON_INVALID;
span->default_caller_data.cid_num.plan = FTDM_NPI_INVALID;
......@@ -365,6 +367,13 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
if (signal_data->facility_timeout < 0) {
signal_data->facility_timeout = 0;
}
} else if (!strcasecmp(var, "transfer-timeout")) {
signal_data->transfer_timeout = atoi(val);
if (signal_data->transfer_timeout < 0) {
signal_data->transfer_timeout = 0;
}
} else if (!strcasecmp(var, "att-remove-dtmf")) {
parse_yesno(var, val, &signal_data->att_remove_dtmf);
} else if (!strcasecmp(var, "facility-ie-decode")) {
parse_yesno(var, val, &signal_data->facility_ie_decode);
} else if (!strcasecmp(var, "ignore-cause-value")) {
......
......@@ -35,6 +35,7 @@
#include "ftmod_sangoma_isdn.h"
static ftdm_status_t sngisdn_cause_val_requires_disconnect(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn);
static void sngisdn_process_restart_confirm(ftdm_channel_t *ftdmchan);
static ftdm_status_t sngisdn_force_down(ftdm_channel_t *ftdmchan);
/* Remote side transmit a SETUP */
void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
......@@ -191,8 +192,7 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
strcpy(ftdmchan->caller_data.cid_name, retrieved_str);
}
}
#endif
#endif
if (signal_data->overlap_dial == SNGISDN_OPT_TRUE && !conEvnt->sndCmplt.eh.pres) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
} else {
......@@ -318,8 +318,9 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event)
}
} else {
switch(ftdmchan->state) {
case FTDM_CHANNEL_STATE_TRANSFER:
case FTDM_CHANNEL_STATE_UP:
/* This is the only valid state we should get a CONNECT ACK on */
/* These are the only valid states we should get a CONNECT ACK on */
/* do nothing */
break;
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
......@@ -926,36 +927,8 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event)
switch(call_state) {
/* Sere ITU-T Q931 for definition of call states */
case 0: /* Remote switch thinks there are no calls on this channel */
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_COLLECT:
case FTDM_CHANNEL_STATE_DIALING:
case FTDM_CHANNEL_STATE_UP:
sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
break;
case FTDM_CHANNEL_STATE_TERMINATING:
/* We are in the process of clearing local states,
just make sure we will not send any messages to remote switch */
sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
break;
case FTDM_CHANNEL_STATE_HANGUP:
/* This cannot happen, state_advance always sets
ftdmchan to STATE_HANGUP_COMPLETE when in STATE_HANGUP
and we called check_for_state_change earlier so something is very wrong here!!! */
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "How can we we in FTDM_CHANNEL_STATE_HANGUP after checking for state change?\n");
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
break;
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
/* We were waiting for remote switch to send RELEASE COMPLETE
but this will not happen, so just clear local state */
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
break;
case FTDM_CHANNEL_STATE_DOWN:
/* If our local state is down as well, then there is nothing to do */
break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state));
break;
if (sngisdn_force_down(ftdmchan) != FTDM_SUCCESS) {
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state));
}
break;
case 1:
......@@ -1165,6 +1138,48 @@ static void sngisdn_process_restart_confirm(ftdm_channel_t *ftdmchan)
return;
}
static ftdm_status_t sngisdn_force_down(ftdm_channel_t *ftdmchan)
{
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data;
ftdm_status_t status = FTDM_SUCCESS;
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Forcing channel to DOWN state (%s)\n", ftdm_channel_state2str(ftdmchan->state));
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_DOWN:
/* Do nothing */
break;
case FTDM_CHANNEL_STATE_RESET:
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
break;
case FTDM_CHANNEL_STATE_COLLECT:
case FTDM_CHANNEL_STATE_DIALING:
case FTDM_CHANNEL_STATE_UP:
sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
break;
case FTDM_CHANNEL_STATE_TERMINATING:
/* We are already waiting for usr to respond to SIGEVENT stop.
FreeTDM already scheduled a timout in case the User does respond to
SIGEVENT_STOP, no need to do anything here */
break;
case FTDM_CHANNEL_STATE_HANGUP:
/* This cannot happen, state_advance always sets
ftdmchan to STATE_HANGUP_COMPLETE when in STATE_HANGUP
and we called check_for_state_change earlier so something is very wrong here!!! */
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "How can we we in FTDM_CHANNEL_STATE_HANGUP after checking for state change?\n");
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
break;
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
/* We were waiting for remote switch to send RELEASE COMPLETE
but this will not happen, so just clear local state */
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
break;
default:
status = FTDM_FAIL;
}
return status;
}
void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event)
{
......@@ -1177,12 +1192,12 @@ void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event)
sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[dChan].spans[1];
if (!signal_data) {
ftdm_log(FTDM_LOG_CRIT, "Received RESTART on unconfigured span (suId:%d)\n", suId);
ftdm_log(FTDM_LOG_CRIT, "Received RESTART CFM on unconfigured span (suId:%d)\n", suId);
return;
}
if (!rstEvnt->rstInd.eh.pres || !rstEvnt->rstInd.rstClass.pres) {
ftdm_log(FTDM_LOG_DEBUG, "Receved RESTART, but Restart Indicator IE not present\n");
if (rstEvnt->rstInd.eh.pres != PRSNT_NODEF && rstEvnt->rstInd.rstClass.pres != PRSNT_NODEF) {
ftdm_log(FTDM_LOG_DEBUG, "Received RESTART, but Restart Indicator IE not present\n");
return;
}
......@@ -1239,24 +1254,105 @@ void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event)
}
/* The remote side sent us a RESTART Msg. Trillium automatically acks with RESTART ACK, but
we need to clear our call states if there is a call on this channel */
void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event)
{
uint8_t chan_no = 0;
int16_t suId = sngisdn_event->suId;
int16_t dChan = sngisdn_event->dChan;
uint8_t ces = sngisdn_event->ces;
uint8_t evntType = sngisdn_event->evntType;
Rst *rstEvnt = NULL;
sngisdn_span_data_t *signal_data = NULL;
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
/* Function does not require any info from ssHlEvnt struct for now */
/*Rst *rstEvnt = &sngisdn_event->event.rstEvnt;*/
ftdm_log(FTDM_LOG_DEBUG, "Processing RESTART CFM (suId:%u dChan:%d ces:%d %s)\n", suId, dChan, ces,
rstEvnt = &sngisdn_event->event.rstEvnt;
/* TODO: readjust this when NFAS is implemented as signal_data will not always be the first
* span for that d-channel */
if (!rstEvnt->rstInd.eh.pres || !rstEvnt->rstInd.rstClass.pres) {
ftdm_log(FTDM_LOG_DEBUG, "Received RESTART IND, but Restart Indicator IE not present\n");
return;
}
signal_data = g_sngisdn_data.dchans[dChan].spans[1];
if (!signal_data) {
ftdm_log(FTDM_LOG_CRIT, "Received RESTART IND on unconfigured span (suId:%d)\n", suId);
return;
}
ftdm_log(FTDM_LOG_DEBUG, "Processing RESTART IND (suId:%u dChan:%d ces:%d %s)\n", suId, dChan, ces,
(evntType == IN_LNK_DWN)?"LNK_DOWN":
(evntType == IN_LNK_UP)?"LNK_UP":
(evntType == IN_INDCHAN)?"b-channel":
(evntType == IN_LNK_DWN_DM_RLS)?"NFAS service procedures":
(evntType == IN_SWCHD_BU_DCHAN)?"NFAS switchover to backup":"Unknown");
if (!rstEvnt->rstInd.eh.pres || !rstEvnt->rstInd.rstClass.pres) {
ftdm_log(FTDM_LOG_DEBUG, "Received RESTART IND, but Restart Indicator IE not present\n");
return;
}
switch(rstEvnt->rstInd.rstClass.val) {
case IN_CL_INDCHAN: /* Indicated b-channel */
if (rstEvnt->chanId.eh.pres) {
if (rstEvnt->chanId.intType.val == IN_IT_BASIC) {
if (rstEvnt->chanId.infoChanSel.pres == PRSNT_NODEF) {
chan_no = rstEvnt->chanId.infoChanSel.val;
}
} else if (rstEvnt->chanId.intType.val == IN_IT_OTHER) {
if (rstEvnt->chanId.chanNmbSlotMap.pres == PRSNT_NODEF) {
chan_no = rstEvnt->chanId.chanNmbSlotMap.val[0];
}
}
}
if (!chan_no) {
ftdm_log(FTDM_LOG_CRIT, "Failed to determine channel from RESTART\n");
return;
}
break;
case IN_CL_SNGINT: /* Single interface */
case IN_CL_ALLINT: /* All interfaces */
/* In case restart class indicates all interfaces, we will duplicate
this event on each span associated to this d-channel in sngisdn_rcv_rst_cfm,
so treat it as a single interface anyway */
break;
default:
ftdm_log(FTDM_LOG_CRIT, "Invalid restart indicator class:%d\n", rstEvnt->rstInd.rstClass.val);
return;
}
if (chan_no) { /* For a single channel */
if (chan_no > ftdm_span_get_chan_count(signal_data->ftdm_span)) {
ftdm_log(FTDM_LOG_CRIT, "Received RESTART IND on invalid channel:%d\n", chan_no);
} else {
ftdm_iterator_t *chaniter = NULL;
ftdm_iterator_t *curr = NULL;
chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
ftdm_channel_t *ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr);
if (ftdmchan->physical_chan_id == chan_no) {
sngisdn_force_down(ftdmchan);
}
}
ftdm_iterator_free(chaniter);
}
} else { /* for all channels */
ftdm_iterator_t *chaniter = NULL;
ftdm_iterator_t *curr = NULL;
chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
sngisdn_force_down((ftdm_channel_t*)ftdm_iterator_current(curr));
}
ftdm_iterator_free(chaniter);
}
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
......
......@@ -146,13 +146,18 @@ void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_i
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
if (sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
return;
}
sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending PROGRESS, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
return;
}
memset(&cnStEvnt, 0, sizeof(cnStEvnt));
/* Indicate channel ID only in first response */
......@@ -161,7 +166,7 @@ void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_i
}
set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind);
set_facility_ie(ftdmchan, &cnStEvnt.facilityStr);
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending PROCEED (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, MI_CALLPROC, signal_data->dchan_id, sngisdn_info->ces)) {
......@@ -230,12 +235,17 @@ void sngisdn_snd_alert(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind
void sngisdn_snd_connect(ftdm_channel_t *ftdmchan)
{
CnStEvnt cnStEvnt;
CnStEvnt cnStEvnt;
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_NETE_ISDN};
if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
if (sngisdn_test_flag(sngisdn_info, FLAG_SENT_CONNECT)) {
return;
}
sngisdn_set_flag(sngisdn_info, FLAG_SENT_CONNECT);
if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending CONNECT, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
......@@ -353,22 +363,12 @@ void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan)
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
return;
}
memset(&discEvnt, 0, sizeof(discEvnt));
/* Fill discEvnt here */
/* TODO move this to set_cause_ie function */
discEvnt.causeDgn[0].eh.pres = PRSNT_NODEF;
discEvnt.causeDgn[0].location.pres = PRSNT_NODEF;
discEvnt.causeDgn[0].location.val = IN_LOC_PRIVNETLU;
discEvnt.causeDgn[0].codeStand3.pres = PRSNT_NODEF;
discEvnt.causeDgn[0].codeStand3.val = IN_CSTD_CCITT;
discEvnt.causeDgn[0].causeVal.pres = PRSNT_NODEF;
discEvnt.causeDgn[0].causeVal.val = ftdmchan->caller_data.hangup_cause;
discEvnt.causeDgn[0].recommend.pres = NOTPRSNT;
discEvnt.causeDgn[0].dgnVal.pres = NOTPRSNT;
set_facility_ie(ftdmchan, &discEvnt.facilityStr);
set_cause_ie(ftdmchan, &discEvnt.causeDgn[0]);
set_facility_ie(ftdmchan, &discEvnt.facilityStr);
set_user_to_user_ie(ftdmchan, &discEvnt.usrUsr);
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending DISCONNECT (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
if (sng_isdn_disc_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &discEvnt)) {
......
......@@ -712,10 +712,12 @@ void sngisdn_rcv_q921_ind(BdMngmt *status)
}
void sngisdn_rcv_q931_ind(InMngmt *status)
{
#ifndef WIN32
if (status->t.usta.alarm.cause == 287) {
get_memory_info();
sngisdn_get_memory_info();
return;
}
#endif
switch (status->t.usta.alarm.event) {
case LCM_EVENT_UP:
......
......@@ -47,7 +47,6 @@ static uint8_t get_trillium_val(ftdm2trillium_t *vals, uint8_t ftdm_val, uint8_t
static uint8_t get_ftdm_val(ftdm2trillium_t *vals, uint8_t trillium_val, uint8_t default_val);
extern ftdm_sngisdn_data_t g_sngisdn_data;
void get_memory_info(void);
ftdm2trillium_t npi_codes[] = {
{FTDM_NPI_UNKNOWN, IN_NP_UNK},
......@@ -105,6 +104,8 @@ void clear_call_data(sngisdn_chan_data_t *sngisdn_info)
sngisdn_info->spInstId = 0;
sngisdn_info->globalFlg = 0;
sngisdn_info->flags = 0;
sngisdn_info->transfer_data.type = SNGISDN_TRANSFER_NONE;
ftdm_mutex_unlock(g_sngisdn_data.ccs[cc_id].mutex);
return;
}
......@@ -846,6 +847,41 @@ ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_s
return FTDM_SUCCESS;
}
ftdm_status_t set_user_to_user_ie(ftdm_channel_t *ftdmchan, UsrUsr *usrUsr)
{
sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
if (sngisdn_info->transfer_data.type == SNGISDN_TRANSFER_ATT_COURTESY_VRU_DATA) {
usrUsr->eh.pres = PRSNT_NODEF;
usrUsr->protocolDisc.pres = PRSNT_NODEF;
usrUsr->protocolDisc.val = 0x08;
usrUsr->usrInfo.pres = PRSNT_NODEF;
usrUsr->usrInfo.len = strlen(sngisdn_info->transfer_data.tdata.att_courtesy_vru.data);
memcpy(usrUsr->usrInfo.val, sngisdn_info->transfer_data.tdata.att_courtesy_vru.data, usrUsr->usrInfo.len);
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending AT&T Transfer data len:%d\n", usrUsr->usrInfo.len);
return FTDM_SUCCESS;
}
return FTDM_SUCCESS;
}
ftdm_status_t set_cause_ie(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn)
{
causeDgn->eh.pres = PRSNT_NODEF;
causeDgn->location.pres = PRSNT_NODEF;
causeDgn->location.val = IN_LOC_PRIVNETLU;
causeDgn->codeStand3.pres = PRSNT_NODEF;
causeDgn->codeStand3.val = IN_CSTD_CCITT;
causeDgn->causeVal.pres = PRSNT_NODEF;
causeDgn->causeVal.val = ftdmchan->caller_data.hangup_cause;
causeDgn->recommend.pres = NOTPRSNT;
causeDgn->dgnVal.pres = NOTPRSNT;
return FTDM_SUCCESS;
}
ftdm_status_t set_chan_id_ie(ftdm_channel_t *ftdmchan, ChanId *chanId)
{
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data;
......@@ -854,7 +890,7 @@ ftdm_status_t set_chan_id_ie(ftdm_channel_t *ftdmchan, ChanId *chanId)
}
ftdm_set_flag(sngisdn_info, FLAG_SENT_CHAN_ID);
chanId->eh.pres = PRSNT_NODEF;
chanId->prefExc.pres = PRSNT_NODEF;
chanId->prefExc.val = IN_PE_EXCLSVE;
......@@ -863,8 +899,7 @@ ftdm_status_t set_chan_id_ie(ftdm_channel_t *ftdmchan, ChanId *chanId)
chanId->intIdentPres.pres = PRSNT_NODEF;
chanId->intIdentPres.val = IN_IIP_IMPLICIT;
if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
if (FTDM_SPAN_IS_BRI(ftdmchan->span)) {
/* BRI only params */
chanId->intType.pres = PRSNT_NODEF;
......@@ -1085,10 +1120,17 @@ ftdm_status_t sngisdn_check_free_ids(void)
return FTDM_SUCCESS;
}
void get_memory_info(void)
void sngisdn_get_memory_info(void)
{
#ifdef WIN32
/* SRegInfoShow is not formally supported by Trillium with Windows */
ftdm_log(FTDM_LOG_WARNING, "SRegInfoShow not supported on Windows\n");
#else
/* SRegInfoShow is not formally supported by Trillium in Linux either, but
* it seems like its working fine so far */
U32 availmen = 0;
SRegInfoShow(S_REG, &availmen);
#endif
return;
}
......@@ -1288,10 +1330,13 @@ void sngisdn_send_signal(sngisdn_chan_data_t *sngisdn_info, ftdm_signal_event_t
sigev.raw.data = sngisdn_info->raw_data;
sigev.raw.len = sngisdn_info->raw_data_len;
sngisdn_info->raw_data = NULL;
sngisdn_info->raw_data_len = 0;
}
if (event_id == FTDM_SIGEVENT_TRANSFER_COMPLETED) {
sigev.ev_data.transfer_completed.response = sngisdn_info->transfer_data.response;
}
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
......
......@@ -757,7 +757,7 @@ void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_
{
uint32_t k;
*str_len += sprintf(&str[*str_len], " [ ");
for(k=index_start; k <= index_end; k++) {
for(k=index_start; k < index_end; k++) {
if (k && !(k%32)) {
*str_len += sprintf(&str[*str_len], "\n ");
}
......@@ -917,7 +917,7 @@ static ftdm_status_t sngisdn_map_call(sngisdn_span_data_t *signal_data, sngisdn_
case PROT_Q931_MSGTYPE_USER_INFO:
case PROT_Q931_MSGTYPE_DISCONNECT:
case PROT_Q931_MSGTYPE_RELEASE:
case PROT_Q931_MSGTYPE_RELEASE_ACK:
case PROT_Q931_MSGTYPE_RESTART_ACK:
case PROT_Q931_MSGTYPE_RELEASE_COMPLETE:
case PROT_Q931_MSGTYPE_FACILITY:
case PROT_Q931_MSGTYPE_NOTIFY:
......
......@@ -211,7 +211,7 @@ struct code2str dcodQ931CallRefLoTable[] = {
#define PROT_Q931_MSGTYPE_DISCONNECT 69
#define PROT_Q931_MSGTYPE_RESTART 70
#define PROT_Q931_MSGTYPE_RELEASE 77
#define PROT_Q931_MSGTYPE_RELEASE_ACK 78
#define PROT_Q931_MSGTYPE_RESTART_ACK 78
#define PROT_Q931_MSGTYPE_RELEASE_COMPLETE 90
#define PROT_Q931_MSGTYPE_SEGMENT 96
#define PROT_Q931_MSGTYPE_FACILITY 98
......@@ -240,7 +240,7 @@ struct code2str dcodQ931MsgTypeTable[] = {
{PROT_Q931_MSGTYPE_DISCONNECT, "DISCONNECT"},
{PROT_Q931_MSGTYPE_RESTART, "RESTART"},
{PROT_Q931_MSGTYPE_RELEASE, "RELEASE"},
{PROT_Q931_MSGTYPE_RELEASE_ACK, "RELEASR ACK"},
{PROT_Q931_MSGTYPE_RESTART_ACK, "RESTART ACK"},
{PROT_Q931_MSGTYPE_RELEASE_COMPLETE, "RELEASE COMPLETE"},
{PROT_Q931_MSGTYPE_SEGMENT, "SEGMENT"},
{PROT_Q931_MSGTYPE_FACILITY, "FACILITY"},
......
......@@ -1193,12 +1193,26 @@ FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
#else
if (pfds[i-1].revents & POLLPRI) {
#endif
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_EVENT);
ftdm_set_io_flag(ftdmchan, FTDM_CHANNEL_IO_EVENT);
ftdmchan->last_event_time = ftdm_current_time_in_ms();
k++;
}
#ifdef LIBSANGOMA_VERSION
if (outflags[i-1] & POLLIN) {
#else
if (pfds[i-1].revents & POLLIN) {
#endif
ftdm_set_io_flag(ftdmchan, FTDM_CHANNEL_IO_READ);
}
#ifdef LIBSANGOMA_VERSION
if (outflags[i-1] & POLLOUT) {
#else
if (pfds[i-1].revents & POLLOUT) {
#endif
ftdm_set_io_flag(ftdmchan, FTDM_CHANNEL_IO_WRITE);
}
}
/* when k is 0 it might be that an async wanpipe device signal was delivered */
/* when k is 0 it might be that an async wanpipe device signal was delivered */
return FTDM_SUCCESS;
}
......@@ -1445,14 +1459,9 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event)
wanpipe_tdm_api_t tdm_api;
ftdm_span_t *span = ftdmchan->span;
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT);
}
memset(&tdm_api, 0, sizeof(tdm_api));
status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
if (status != FTDM_SUCCESS) {
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to read event from channel: %s\n", strerror(errno));
return FTDM_FAIL;
}
......@@ -1488,7 +1497,7 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
for(i = 1; i <= span->chan_count; i++) {
/* as a hack for wink/flash detection, wanpipe_poll_event overrides the timeout parameter
* to force the user to call this function each 5ms or so to detect the timeout of our wink/flash */
if (span->channels[i]->last_event_time && !ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
if (span->channels[i]->last_event_time && !ftdm_test_io_flag(span->channels[i], FTDM_CHANNEL_IO_EVENT)) {
ftdm_time_t diff = ftdm_current_time_in_ms() - span->channels[i]->last_event_time;
/* XX printf("%u %u %u\n", diff, (unsigned)ftdm_current_time_in_ms(), (unsigned)span->channels[i]->last_event_time); */
if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) {
......@@ -1520,13 +1529,13 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
goto event;
}
}
}
if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
}
if (ftdm_test_io_flag(span->channels[i], FTDM_CHANNEL_IO_EVENT)) {
ftdm_status_t status;
wanpipe_tdm_api_t tdm_api;
ftdm_channel_t *ftdmchan = span->channels[i];
memset(&tdm_api, 0, sizeof(tdm_api));
ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
ftdm_clear_io_flag(span->channels[i], FTDM_CHANNEL_IO_EVENT);
err = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
if (err != FTDM_SUCCESS) {
......
......@@ -976,13 +976,19 @@ FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
return FTDM_FAIL;
}
for(i = 1; i <= span->chan_count; i++) {
if (pfds[i-1].revents & POLLPRI) {
ftdm_set_flag(span->channels[i], FTDM_CHANNEL_EVENT);
ftdm_set_io_flag(span->channels[i], FTDM_CHANNEL_IO_EVENT);
span->channels[i]->last_event_time = ftdm_current_time_in_ms();
k++;
}
if (pfds[i-1].revents & POLLIN) {
ftdm_set_io_flag(span->channels[i], FTDM_CHANNEL_IO_READ);
}
if (pfds[i-1].revents & POLLOUT) {
ftdm_set_io_flag(span->channels[i], FTDM_CHANNEL_IO_WRITE);
}
}
if (!k) {
......@@ -1106,8 +1112,8 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event)
zt_event_t zt_event_id = 0;
ftdm_span_t *span = ftdmchan->span;
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT);
if (ftdm_test_io_flag(ftdmchan, FTDM_CHANNEL_IO_EVENT)) {
ftdm_clear_io_flag(ftdmchan, FTDM_CHANNEL_IO_EVENT);
}
if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
......@@ -1143,8 +1149,8 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
for(i = 1; i <= span->chan_count; i++) {
ftdm_channel_t *fchan = span->channels[i];
if (ftdm_test_flag(fchan, FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_EVENT);
if (ftdm_test_io_flag(fchan, FTDM_CHANNEL_IO_EVENT)) {
ftdm_clear_io_flag(fchan, FTDM_CHANNEL_IO_EVENT);
if (ioctl(fchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
return FTDM_FAIL;
......
......@@ -30,9 +30,10 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
* Contributors:
*
* Moises Silva <moy@sangoma.com>
* David Yat Sin <dyatsin@sangoma.com>
*
*/
......@@ -317,6 +318,19 @@ typedef enum {
#define CALLING_PARTY_CATEGORY_STRINGS "unknown", "operator", "operator-french", "operator-english", "operator-german", "operator-russian", "operator-spanish", "ordinary", "priority", "data-call", "test-call", "payphone", "invalid"
FTDM_STR2ENUM_P(ftdm_str2ftdm_calling_party_category, ftdm_calling_party_category2str, ftdm_calling_party_category_t)
/*! Network responses to transfer requests */
typedef enum {
FTDM_TRANSFER_RESPONSE_OK, /* Call is being transferred */
FTDM_TRANSFER_RESPONSE_CP_DROP_OFF, /* Calling Party drop off */
FTDM_TRANSFER_RESPONSE_LIMITS_EXCEEDED, /* Cannot redirect, limits exceeded */
FTDM_TRANSFER_RESPONSE_INVALID_NUM, /* Network did not receive or recognize dialed number */
FTDM_TRANSFER_RESPONSE_INVALID_COMMAND, /* Network received an invalid command */
FTDM_TRANSFER_RESPONSE_TIMEOUT, /* We did not receive a response from Network */
FTDM_TRANSFER_RESPONSE_INVALID,
} ftdm_transfer_response_t;
#define TRANSFER_RESPONSE_STRINGS "transfer-ok", "cp-drop-off", "limits-exceeded", "invalid-num", "invalid-command", "timeout", "invalid"
FTDM_STR2ENUM_P(ftdm_str2ftdm_transfer_response, ftdm_transfer_response2str, ftdm_transfer_response_t)
/*! \brief Digit limit used in DNIS/ANI */
#define FTDM_DIGITS_LIMIT 25
......@@ -436,13 +450,14 @@ typedef enum {
FTDM_SIGEVENT_TRACE, /*!<Interpreted trace event */
FTDM_SIGEVENT_TRACE_RAW, /*!<Raw trace event */
FTDM_SIGEVENT_INDICATION_COMPLETED, /*!< Last requested indication was completed */
FTDM_SIGEVENT_DIALING, /* Outgoing call just started */
FTDM_SIGEVENT_DIALING, /*!< Outgoing call just started */
FTDM_SIGEVENT_TRANSFER_COMPLETED, /*!< Transfer request is completed */
FTDM_SIGEVENT_INVALID, /*!<Invalid */
} ftdm_signal_event_t;
#define SIGNAL_STRINGS "START", "STOP", "RELEASED", "UP", "FLASH", "PROCEED", "RINGING", "PROGRESS", \
"PROGRESS_MEDIA", "ALARM_TRAP", "ALARM_CLEAR", \
"COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGSTATUS_CHANGED", "FACILITY", \
"TRACE", "TRACE_RAW", "INDICATION_COMPLETED", "DIALING", "INVALID"
"TRACE", "TRACE_RAW", "INDICATION_COMPLETED", "DIALING", "TRANSFER_COMPLETED", "INVALID"
/*! \brief Move from string to ftdm_signal_event_t and viceversa */
FTDM_STR2ENUM_P(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t)
......@@ -545,12 +560,13 @@ typedef enum {
/* Using this indication is equivalent to call ftdm_channel_call_answer API */
FTDM_CHANNEL_INDICATE_ANSWER,
FTDM_CHANNEL_INDICATE_FACILITY,
FTDM_CHANNEL_INDICATE_TRANSFER,
FTDM_CHANNEL_INDICATE_INVALID,
} ftdm_channel_indication_t;
#define INDICATION_STRINGS "NONE", "RINGING", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "BUSY", "ANSWER", "FACILITY", "INVALID"
#define INDICATION_STRINGS "NONE", "RINGING", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "BUSY", "ANSWER", "FACILITY", "TRANSFER", "INVALID"
/*! \brief Move from string to ftdm_channel_indication_t and viceversa */
FTDM_STR2ENUM_P(ftdm_str2channel_indication, ftdm_channel_indication2str, ftdm_channel_indication_t)
FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_indication, ftdm_channel_indication2str, ftdm_channel_indication_t)
typedef struct {
/* The indication that was completed */
......@@ -559,6 +575,10 @@ typedef struct {
ftdm_status_t status;
} ftdm_event_indication_completed_t;
typedef struct {
ftdm_transfer_response_t response;
} ftdm_event_transfer_completed_t;
typedef void * ftdm_variable_container_t;
typedef struct {
......@@ -580,6 +600,7 @@ struct ftdm_sigmsg {
ftdm_event_trace_t trace; /*!< valid if event_id is FTDM_SIGEVENT_TRACE or FTDM_SIGEVENT_TRACE_RAW */
ftdm_event_collected_t collected; /*!< valid if event_id is FTDM_SIGEVENT_COLLECTED_DIGIT */
ftdm_event_indication_completed_t indication_completed; /*!< valid if the event_id is FTDM_SIGEVENT_INDICATION_COMPLETED */
ftdm_event_transfer_completed_t transfer_completed;
} ev_data;
ftdm_raw_data_t raw;
};
......@@ -913,7 +934,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char
#define ftdm_channel_call_place(ftdmchan) _ftdm_channel_call_place(__FILE__, __FUNCTION__, __LINE__, (ftdmchan), NULL)
#define ftdm_channel_call_place_ex(ftdmchan, usrmsg) _ftdm_channel_call_place_ex(__FILE__, __FUNCTION__, __LINE__, (ftdmchan), (usrmsg))
/*! \brief Place an outgoing call recording the source code point where it was called (see ftdm_channel_call_place for an easy to use macro)
/*! \brief Place an outgoing call recording the source code point where it was called (see ftdm_channel_call_place for an easy to use macro)
* \deprecated This function is deprecated since leaves the door open to glare issues, use ftdm_call_place instead
*/
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_usrmsg_t *usrmsg);
......@@ -972,6 +993,20 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup(const char *file, const char
/*! \brief Hangup the call with cause recording the source code point where it was called (see ftdm_channel_call_hangup_with_cause for an easy to use macro) */
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup_with_cause(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_call_cause_t, ftdm_usrmsg_t *usrmsg);
/*! \brief Transfer call. This can also be accomplished by ftdm_channel_call_indicate with FTDM_CHANNEL_INDICATE_TRANSFER, in both
* cases you will get a FTDM_SIGEVENT_INDICATION_COMPLETED when the indication is sent (or an error occurs).
* Just as with ftdm_channel_call_indicate you won't receive FTDM_SIGEVENT_INDICATION_COMPLETED when this function
* returns anything else than FTDM_SUCCESS
* \note Although this API may result in FTDM_SIGEVENT_INDICATION_COMPLETED event being delivered,
* there is no guarantee of whether the event will arrive after or before your execution thread returns
* from ftdm_channel_call_transfer
*/
#define ftdm_channel_call_transfer(ftdmchan, arg) _ftdm_channel_call_transfer(__FILE__, __FUNCTION__, __LINE__, (ftdmchan), (arg), NULL)
#define ftdm_channel_call_transfer_ex(ftdmchan, arg, usrmsg) _ftdm_channel_call_transfer(__FILE__, __FUNCTION__, __LINE__, (ftdmchan), (arg), (usrmsg))
/*! \brief Answer call recording the source code point where the it was called (see ftdm_channel_call_tranasfer for an easy to use macro) */
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_transfer(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, const char* arg, ftdm_usrmsg_t *usrmsg);
/*! \brief Reset the channel */
#define ftdm_channel_reset(ftdmchan) _ftdm_channel_reset(__FILE__, __FUNCTION__, __LINE__, (ftdmchan), NULL)
#define ftdm_channel_reset_ex(ftdmchan, usrmsg) _ftdm_channel_reset(__FILE__, __FUNCTION__, __LINE__, (ftdmchan), usrmsg)
......@@ -1242,7 +1277,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_add_to_group(const char* name, ftdm_chann
/*! \brief Remove the channel from a hunt group */
FT_DECLARE(ftdm_status_t) ftdm_channel_remove_from_group(ftdm_group_t* group, ftdm_channel_t* ftdmchan);
/*!
/*!
* \brief Retrieves an event from the span
*
* \note
......
......@@ -155,6 +155,10 @@ extern "C" {
#define ftdm_clear_alarm_flag(obj, flag) (obj)->alarm_flags &= ~(flag)
#define ftdm_test_alarm_flag(obj, flag) ((obj)->alarm_flags & flag)
#define ftdm_set_io_flag(obj, flag) (obj)->io_flags |= (flag)
#define ftdm_clear_io_flag(obj, flag) (obj)->io_flags &= ~(flag)
#define ftdm_test_io_flag(obj, flag) ((obj)->io_flags & flag)
/*!
\brief Set a flag on an arbitrary object
\command obj the object to set the flags on
......@@ -399,6 +403,7 @@ struct ftdm_channel {
uint64_t flags;
uint32_t pflags;
uint32_t sflags;
uint8_t io_flags;
ftdm_alarm_flag_t alarm_flags;
ftdm_channel_feature_t features;
ftdm_codec_t effective_codec;
......@@ -503,6 +508,7 @@ struct ftdm_span {
ftdm_span_stop_t stop;
ftdm_channel_sig_read_t sig_read;
ftdm_channel_sig_write_t sig_write;
ftdm_channel_sig_dtmf_t sig_dtmf;
ftdm_channel_state_processor_t state_processor; /*!< This guy is called whenever state processing is required */
void *io_data; /*!< Private I/O data per span. Do not touch unless you are an I/O module */
char *type;
......@@ -591,6 +597,10 @@ FT_DECLARE(void) ftdm_ack_indication(ftdm_channel_t *ftdmchan, ftdm_channel_indi
FT_DECLARE(ftdm_iterator_t *) ftdm_get_iterator(ftdm_iterator_type_t type, ftdm_iterator_t *iter);
FT_DECLARE(ftdm_status_t) ftdm_channel_process_media(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t *datalen);
FIO_WRITE_FUNCTION(ftdm_raw_write);
FIO_READ_FUNCTION(ftdm_raw_read);
/*!
* \brief Retrieves an event from the span
......
......@@ -67,6 +67,7 @@ typedef enum {
FTDM_CHANNEL_STATE_PROGRESS,
FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
FTDM_CHANNEL_STATE_UP,
FTDM_CHANNEL_STATE_TRANSFER,
FTDM_CHANNEL_STATE_IDLE,
FTDM_CHANNEL_STATE_TERMINATING,
FTDM_CHANNEL_STATE_CANCEL,
......@@ -78,7 +79,7 @@ typedef enum {
} ftdm_channel_state_t;
#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \
"RING", "RINGING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \
"RESTART", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", \
"RESTART", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "UP", "TRANSFER", "IDLE", "TERMINATING", "CANCEL", \
"HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "RESET", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t)
......
......@@ -189,6 +189,8 @@ typedef enum {
/* If this flag is set, then this span cannot be stopped individually, it can only be stopped
on freetdm unload */
FTDM_SPAN_NON_STOPPABLE = (1 << 13),
/* If this flag is set, then this span supports TRANSFER state */
FTDM_SPAN_USE_TRANSFER = (1 << 14),
} ftdm_span_flag_t;
/*! \brief Channel supported features */
......@@ -206,6 +208,13 @@ typedef enum {
FTDM_CHANNEL_FEATURE_MF_GENERATE = (1<<10), /*!< Channel can generate R2 MF tones (read-only) */
} ftdm_channel_feature_t;
/*! \brief Channel IO pending flags */
typedef enum {
FTDM_CHANNEL_IO_EVENT = (1 << 0),
FTDM_CHANNEL_IO_READ = (1 << 1),
FTDM_CHANNEL_IO_WRITE = (1 << 2),
} ftdm_channel_io_flags_t;
/*!< Channel flags. This used to be an enum but we reached the 32bit limit for enums, is safer this way */
#define FTDM_CHANNEL_CONFIGURED (1ULL << 0)
#define FTDM_CHANNEL_READY (1ULL << 1)
......@@ -214,7 +223,6 @@ typedef enum {
#define FTDM_CHANNEL_SUPRESS_DTMF (1ULL << 4)
#define FTDM_CHANNEL_TRANSCODE (1ULL << 5)
#define FTDM_CHANNEL_BUFFER (1ULL << 6)
#define FTDM_CHANNEL_EVENT (1ULL << 7)
#define FTDM_CHANNEL_INTHREAD (1ULL << 8)
#define FTDM_CHANNEL_WINK (1ULL << 9)
#define FTDM_CHANNEL_FLASH (1ULL << 10)
......@@ -331,10 +339,11 @@ typedef ftdm_status_t (*ftdm_span_start_t)(ftdm_span_t *span);
typedef ftdm_status_t (*ftdm_span_stop_t)(ftdm_span_t *span);
typedef ftdm_status_t (*ftdm_channel_sig_read_t)(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t size);
typedef ftdm_status_t (*ftdm_channel_sig_write_t)(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t size);
typedef ftdm_status_t (*ftdm_channel_sig_dtmf_t)(ftdm_channel_t *ftdmchan, const char *dtmf);
typedef enum {
FTDM_ITERATOR_VARS = 1,
FTDM_ITERATOR_CHANS,
FTDM_ITERATOR_CHANS,
} ftdm_iterator_type_t;
struct ftdm_iterator {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论