mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-11-11 03:57:14 +00:00
Support for AT&T *8 Transfer (VRU only)
This commit is contained in:
1 parent
3fa2fce3f3
commit
bd7672242c
17 files changed
+845
-197
No files matched your search
@@ -44,6 +44,7 @@
|
||||
static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj);
|
||||
static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span);
|
||||
static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span);
|
||||
static ftdm_status_t ftdm_sangoma_isdn_dtmf(ftdm_channel_t *ftdmchan, const char* dtmf);
|
||||
|
||||
ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event);
|
||||
static void ftdm_sangoma_isdn_poll_events(ftdm_span_t *span);
|
||||
@@ -53,10 +54,13 @@ static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_ev
|
||||
static void ftdm_sangoma_isdn_wakeup_phy(ftdm_channel_t *dchan);
|
||||
static void ftdm_sangoma_isdn_dchan_set_queue_size(ftdm_channel_t *ftdmchan);
|
||||
|
||||
static ftdm_io_interface_t g_sngisdn_io_interface;
|
||||
static ftdm_io_interface_t g_sngisdn_io_interface;
|
||||
static sng_isdn_event_interface_t g_sngisdn_event_interface;
|
||||
|
||||
ftdm_sngisdn_data_t g_sngisdn_data;
|
||||
ftdm_sngisdn_data_t g_sngisdn_data;
|
||||
|
||||
FTDM_ENUM_NAMES(SNGISDN_TRANSFER_TYPE_NAMES, SNGISDN_TRANSFER_TYPE_STRINGS)
|
||||
FTDM_STR2ENUM(ftdm_str2sngisdn_transfer_type, sngisdn_transfer_type2str, sngisdn_transfer_type_t, SNGISDN_TRANSFER_TYPE_NAMES, SNGISDN_TRANSFER_INVALID)
|
||||
|
||||
ftdm_state_map_t sangoma_isdn_state_map = {
|
||||
{
|
||||
@@ -126,8 +130,7 @@ ftdm_state_map_t sangoma_isdn_state_map = {
|
||||
ZSD_INBOUND,
|
||||
ZSM_UNACCEPTABLE,
|
||||
{FTDM_CHANNEL_STATE_PROCEED, FTDM_END},
|
||||
{FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
|
||||
FTDM_CHANNEL_STATE_UP, FTDM_END}
|
||||
{FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_TRANSFER, FTDM_END}
|
||||
},
|
||||
{
|
||||
ZSD_INBOUND,
|
||||
@@ -151,7 +154,14 @@ ftdm_state_map_t sangoma_isdn_state_map = {
|
||||
ZSD_INBOUND,
|
||||
ZSM_UNACCEPTABLE,
|
||||
{FTDM_CHANNEL_STATE_UP, FTDM_END},
|
||||
{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
|
||||
{FTDM_CHANNEL_STATE_TRANSFER, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
|
||||
},
|
||||
|
||||
{
|
||||
ZSD_INBOUND,
|
||||
ZSM_UNACCEPTABLE,
|
||||
{FTDM_CHANNEL_STATE_TRANSFER, FTDM_END},
|
||||
{FTDM_CHANNEL_STATE_PROCEED, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_TERMINATING,FTDM_END},
|
||||
},
|
||||
{
|
||||
ZSD_INBOUND,
|
||||
@@ -352,49 +362,96 @@ static void ftdm_sangoma_isdn_wakeup_phy(ftdm_channel_t *dchan)
|
||||
return;
|
||||
}
|
||||
|
||||
static void *ftdm_sangoma_isdn_dchan_run(ftdm_thread_t *me, void *obj)
|
||||
static void *ftdm_sangoma_isdn_io_run(ftdm_thread_t *me, void *obj)
|
||||
{
|
||||
uint8_t data[1000];
|
||||
unsigned i;
|
||||
ftdm_status_t status = FTDM_SUCCESS;
|
||||
ftdm_wait_flag_t wflags = FTDM_READ;
|
||||
ftdm_span_t *span = (ftdm_span_t*) obj;
|
||||
ftdm_channel_t *dchan = ((sngisdn_span_data_t*)span->signal_data)->dchan;
|
||||
ftdm_size_t len = 0;
|
||||
|
||||
ftdm_channel_set_feature(dchan, FTDM_CHANNEL_FEATURE_IO_STATS);
|
||||
ftdm_sangoma_isdn_dchan_set_queue_size(dchan);
|
||||
ftdm_channel_t *ftdmchan = NULL;
|
||||
unsigned waitms = 10000;
|
||||
ftdm_iterator_t *chaniter = NULL;
|
||||
ftdm_iterator_t *citer = NULL;
|
||||
short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count);
|
||||
|
||||
/* Initialize the d-channel */
|
||||
ftdm_assert(((sngisdn_span_data_t*)span->signal_data)->dchan, "Span does not have a dchannel");
|
||||
ftdm_channel_set_feature(((sngisdn_span_data_t*)span->signal_data)->dchan, FTDM_CHANNEL_FEATURE_IO_STATS);
|
||||
ftdm_sangoma_isdn_dchan_set_queue_size(((sngisdn_span_data_t*)span->signal_data)->dchan);
|
||||
ftdm_channel_open_chan(((sngisdn_span_data_t*)span->signal_data)->dchan);
|
||||
|
||||
chaniter = ftdm_span_get_chan_iterator(span, NULL);
|
||||
if (!chaniter) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ftdm_assert(dchan, "Span does not have a dchannel");
|
||||
ftdm_channel_open_chan(dchan);
|
||||
|
||||
while (ftdm_running() && !(ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD))) {
|
||||
len = 1000;
|
||||
waitms = 1000;
|
||||
wflags = FTDM_READ;
|
||||
status = ftdm_channel_wait(dchan, &wflags, 10000);
|
||||
switch(status) {
|
||||
memset(poll_events, 0, sizeof(short)*span->chan_count);
|
||||
|
||||
for (i = 0, citer = ftdm_span_get_chan_iterator(span, chaniter); citer; citer = ftdm_iterator_next(citer), i++) {
|
||||
ftdmchan = ftdm_iterator_current(citer);
|
||||
|
||||
if (FTDM_IS_VOICE_CHANNEL(ftdmchan)) {
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED)) {
|
||||
poll_events[i] |= FTDM_READ;
|
||||
waitms = 20;
|
||||
}
|
||||
} else {
|
||||
/* We always read the d-channel */
|
||||
poll_events[i] |= FTDM_READ;
|
||||
}
|
||||
}
|
||||
|
||||
status = ftdm_span_poll_event(span, waitms, poll_events);
|
||||
switch (status) {
|
||||
case FTDM_FAIL:
|
||||
ftdm_log_chan_msg(dchan, FTDM_LOG_CRIT, "Failed to wait for d-channel\n");
|
||||
ftdm_log(FTDM_LOG_CRIT, "Failed to poll span for IO\n");
|
||||
break;
|
||||
case FTDM_TIMEOUT:
|
||||
break;
|
||||
case FTDM_SUCCESS:
|
||||
if ((wflags & FTDM_READ)) {
|
||||
for (citer = ftdm_span_get_chan_iterator(span, chaniter); citer; citer = ftdm_iterator_next(citer)) {
|
||||
len = 1000;
|
||||
status = ftdm_channel_read(dchan, data, &len);
|
||||
if (status == FTDM_SUCCESS) {
|
||||
sngisdn_snd_data(dchan, data, len);
|
||||
ftdmchan = ftdm_iterator_current(citer);
|
||||
if (FTDM_IS_VOICE_CHANNEL(ftdmchan)) {
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED)) {
|
||||
if (ftdm_test_io_flag(ftdmchan, FTDM_CHANNEL_IO_READ)) {
|
||||
status = ftdm_raw_read(ftdmchan, data, &len);
|
||||
if (status != FTDM_SUCCESS) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "raw I/O read failed\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
status = ftdm_channel_process_media(ftdmchan, data, &len);
|
||||
if (status != FTDM_SUCCESS) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Failed to process media\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ftdm_log_chan_msg(dchan, FTDM_LOG_WARNING, "Failed to read from channel \n");
|
||||
if (ftdm_test_io_flag(ftdmchan, FTDM_CHANNEL_IO_READ)) {
|
||||
status = ftdm_channel_read(ftdmchan, data, &len);
|
||||
if (status == FTDM_SUCCESS) {
|
||||
sngisdn_snd_data(ftdmchan, data, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef WIN32 /* It is valid on WIN32 for poll to return without errors, but no flags set */
|
||||
} else {
|
||||
ftdm_log_chan_msg(dchan, FTDM_LOG_CRIT, "Failed to poll for d-channel\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ftdm_log_chan_msg(dchan, FTDM_LOG_CRIT, "Unhandled IO event\n");
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Unhandled IO event\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
ftdm_iterator_free(chaniter);
|
||||
ftdm_safe_free(poll_events);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -600,10 +657,10 @@ static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_ev
|
||||
/* this function is called with the channel already locked by the core */
|
||||
static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
ftdm_sigmsg_t sigev;
|
||||
ftdm_channel_state_t initial_state;
|
||||
sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
|
||||
uint8_t state_change = 0;
|
||||
ftdm_sigmsg_t sigev;
|
||||
ftdm_channel_state_t initial_state;
|
||||
sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
|
||||
uint8_t state_change = 0;
|
||||
|
||||
memset(&sigev, 0, sizeof(sigev));
|
||||
|
||||
@@ -632,18 +689,15 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm
|
||||
break;
|
||||
case FTDM_CHANNEL_STATE_GET_CALLERID:
|
||||
{
|
||||
if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
|
||||
/* By default, we do not send a progress indicator in the proceed */
|
||||
ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID};
|
||||
|
||||
sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
|
||||
sngisdn_snd_proceed(ftdmchan, prog_ind);
|
||||
}
|
||||
/* Wait in this state until we get FACILITY msg */
|
||||
/* By default, we do not send a progress indicator in the proceed */
|
||||
ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID};
|
||||
sngisdn_snd_proceed(ftdmchan, prog_ind);
|
||||
|
||||
/* Wait in this state until we get FACILITY msg */
|
||||
}
|
||||
break;
|
||||
case FTDM_CHANNEL_STATE_RING: /* incoming call request */
|
||||
{
|
||||
{
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending incoming call from %s to %s to FTDM core\n", ftdmchan->caller_data.ani.digits, ftdmchan->caller_data.dnis.digits);
|
||||
|
||||
/* we have enough information to inform FTDM of the call*/
|
||||
@@ -678,13 +732,8 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
|
||||
}
|
||||
} else {
|
||||
if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
|
||||
/* By default, we do not send a progress indicator in the proceed */
|
||||
ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID};
|
||||
sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
|
||||
|
||||
sngisdn_snd_proceed(ftdmchan, prog_ind);
|
||||
}
|
||||
ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID};
|
||||
sngisdn_snd_proceed(ftdmchan, prog_ind);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -846,7 +895,6 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm
|
||||
ftdm_channel_close(&close_chan);
|
||||
}
|
||||
if (glare) {
|
||||
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Glare detected, processing saved call\n");
|
||||
/* We are calling sngisdn_rcv_con_ind with ftdmchan->mutex being locked,
|
||||
so no other threads will be able to touch this channel. The next time we will
|
||||
@@ -856,11 +904,17 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FTDM_CHANNEL_STATE_TRANSFER:
|
||||
{
|
||||
/* sngisdn_transfer function will always result in a state change */
|
||||
sngisdn_transfer(ftdmchan);
|
||||
state_change++;
|
||||
}
|
||||
break;
|
||||
case FTDM_CHANNEL_STATE_RESTART:
|
||||
{
|
||||
/* IMPLEMENT ME */
|
||||
}
|
||||
|
||||
break;
|
||||
case FTDM_CHANNEL_STATE_SUSPENDED:
|
||||
{
|
||||
@@ -984,6 +1038,21 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_span_sig_status)
|
||||
return FTDM_NOTIMPL;
|
||||
}
|
||||
|
||||
static ftdm_status_t ftdm_sangoma_isdn_dtmf(ftdm_channel_t *ftdmchan, const char* dtmf)
|
||||
{
|
||||
sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
|
||||
switch(sngisdn_info->transfer_data.type) {
|
||||
case SNGISDN_TRANSFER_ATT_COURTESY_VRU:
|
||||
case SNGISDN_TRANSFER_ATT_COURTESY_VRU_DATA:
|
||||
return sngisdn_att_transfer_process_dtmf(ftdmchan, dtmf);
|
||||
default:
|
||||
/* We do not care about DTMF events, do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span)
|
||||
{
|
||||
sngisdn_span_data_t *signal_data = span->signal_data;
|
||||
@@ -992,6 +1061,7 @@ static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span)
|
||||
ftdm_log(FTDM_LOG_CRIT, "Failed to start span %s\n", span->name);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
/* clear the monitor thread stop flag */
|
||||
ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
|
||||
ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
|
||||
@@ -1015,7 +1085,7 @@ static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span)
|
||||
}
|
||||
|
||||
/*start the dchan monitor thread*/
|
||||
if (ftdm_thread_create_detached(ftdm_sangoma_isdn_dchan_run, span) != FTDM_SUCCESS) {
|
||||
if (ftdm_thread_create_detached(ftdm_sangoma_isdn_io_run, span) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_CRIT,"Failed to start Sangoma ISDN d-channel Monitor Thread!\n");
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
@@ -1106,6 +1176,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
|
||||
span->indicate = ftdm_sangoma_isdn_indicate;
|
||||
span->channel_request = NULL;
|
||||
span->signal_cb = sig_cb;
|
||||
span->sig_dtmf = ftdm_sangoma_isdn_dtmf;
|
||||
span->get_channel_sig_status = ftdm_sangoma_isdn_get_chan_sig_status;
|
||||
span->set_channel_sig_status = ftdm_sangoma_isdn_set_chan_sig_status;
|
||||
span->get_span_sig_status = ftdm_sangoma_isdn_get_span_sig_status;
|
||||
@@ -1117,10 +1188,9 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
|
||||
ftdm_set_flag(span, FTDM_SPAN_USE_PROCEED_STATE);
|
||||
ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES);
|
||||
ftdm_set_flag(span, FTDM_SPAN_NON_STOPPABLE);
|
||||
ftdm_set_flag(span, FTDM_SPAN_USE_TRANSFER);
|
||||
|
||||
if (span->trunk_type == FTDM_TRUNK_BRI_PTMP ||
|
||||
span->trunk_type == FTDM_TRUNK_BRI) {
|
||||
|
||||
if (FTDM_SPAN_IS_BRI(span)) {
|
||||
sngisdn_set_span_avail_rate(span, SNGISDN_AVAIL_PWR_SAVING);
|
||||
}
|
||||
|
||||
@@ -1321,6 +1391,7 @@ done:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static FIO_IO_LOAD_FUNCTION(ftdm_sangoma_isdn_io_init)
|
||||
{
|
||||
memset(&g_sngisdn_io_interface, 0, sizeof(g_sngisdn_io_interface));
|
||||
|
||||
@@ -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 */
|
||||
@@ -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")) {
|
||||
|
||||
@@ -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:
|
||||
@@ -1265,6 +1266,10 @@ void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event)
|
||||
|
||||
/* 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];
|
||||
|
||||
|
||||
@@ -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);
|
||||
memset(&discEvnt, 0, sizeof(discEvnt));
|
||||
|
||||
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)) {
|
||||
|
||||
@@ -100,11 +100,12 @@ void clear_call_data(sngisdn_chan_data_t *sngisdn_info)
|
||||
g_sngisdn_data.ccs[cc_id].active_spInstIds[sngisdn_info->spInstId]=NULL;
|
||||
g_sngisdn_data.ccs[cc_id].active_suInstIds[sngisdn_info->suInstId]=NULL;
|
||||
ftdm_mutex_unlock(g_sngisdn_data.ccs[cc_id].mutex);
|
||||
|
||||
|
||||
sngisdn_info->suInstId = 0;
|
||||
sngisdn_info->spInstId = 0;
|
||||
sngisdn_info->globalFlg = 0;
|
||||
sngisdn_info->flags = 0;
|
||||
sngisdn_info->transfer_data.type = SNGISDN_TRANSFER_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -845,6 +846,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;
|
||||
@@ -853,7 +889,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;
|
||||
@@ -862,8 +898,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;
|
||||
@@ -1294,10 +1329,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Sangoma Technologies
|
||||
* David Yat Sin <davidy@sangoma.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ftmod_sangoma_isdn.h"
|
||||
|
||||
#define TRANSFER_FUNC(name) ftdm_status_t (name)(ftdm_channel_t *ftdmchan, sngisdn_transfer_type_t type, char* target)
|
||||
|
||||
#define SNGISDN_ATT_TRANSFER_RESPONSE_CP_DROP_OFF "**1"
|
||||
#define SNGISDN_ATT_TRANSFER_RESPONSE_LIMITS_EXCEEDED "**5"
|
||||
#define SNGISDN_ATT_TRANSFER_RESPONSE_OK "**6"
|
||||
#define SNGISDN_ATT_TRANSFER_RESPONSE_INVALID_NUM "**7"
|
||||
#define SNGISDN_ATT_TRANSFER_RESPONSE_INVALID_COMMAND "**8"
|
||||
|
||||
|
||||
void att_courtesy_transfer_complete(sngisdn_chan_data_t *sngisdn_info, ftdm_transfer_response_t response);
|
||||
void att_courtesy_transfer_timeout(void* p_sngisdn_info);
|
||||
static ftdm_status_t att_courtesy_vru(ftdm_channel_t *ftdmchan, sngisdn_transfer_type_t type, char* target);
|
||||
|
||||
typedef struct transfer_interfaces {
|
||||
const char *name;
|
||||
sngisdn_transfer_type_t type;
|
||||
TRANSFER_FUNC(*func);
|
||||
}transfer_interface_t;
|
||||
|
||||
static transfer_interface_t transfer_interfaces[] = {
|
||||
/* AT&T TR-50075 Courtesy Transfer - VRU -- No Data (Section 4.3) */
|
||||
{ "ATT_COURTESY_TRANSFER_V", SNGISDN_TRANSFER_ATT_COURTESY_VRU, att_courtesy_vru},
|
||||
/* AT&T TR-50075 Courtesy Transfer - VRU --Data (Section 4.4) */
|
||||
{ "ATT_COURTESY_TRANSFER_V_DATA", SNGISDN_TRANSFER_ATT_COURTESY_VRU_DATA, att_courtesy_vru},
|
||||
};
|
||||
|
||||
void att_courtesy_transfer_complete(sngisdn_chan_data_t *sngisdn_info, ftdm_transfer_response_t response)
|
||||
{
|
||||
ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
|
||||
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED);
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_DTMF_DETECT, NULL);
|
||||
|
||||
sngisdn_info->transfer_data.type = SNGISDN_TRANSFER_NONE;
|
||||
sngisdn_info->transfer_data.response = response;
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Transfer Complete:%s\n", ftdm_transfer_response2str(sngisdn_info->transfer_data.response));
|
||||
sngisdn_send_signal(sngisdn_info, FTDM_SIGEVENT_TRANSFER_COMPLETED);
|
||||
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_FLUSH_RX_BUFFERS, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
void att_courtesy_transfer_timeout(void* p_sngisdn_info)
|
||||
{
|
||||
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)p_sngisdn_info;
|
||||
ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
|
||||
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
|
||||
|
||||
ftdm_mutex_lock(ftdmchan->mutex);
|
||||
if (sngisdn_info->transfer_data.type == SNGISDN_TRANSFER_NONE) {
|
||||
/* Call was already cleared */
|
||||
ftdm_mutex_unlock(ftdmchan->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "AT&T Courtesy Transfer timeout (%d)\n", signal_data->transfer_timeout);
|
||||
att_courtesy_transfer_complete(sngisdn_info, FTDM_TRANSFER_RESPONSE_TIMEOUT);
|
||||
ftdm_mutex_unlock(ftdmchan->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
static ftdm_status_t att_courtesy_vru(ftdm_channel_t *ftdmchan, sngisdn_transfer_type_t type, char* args)
|
||||
{
|
||||
char dtmf_digits[64];
|
||||
ftdm_status_t status = FTDM_FAIL;
|
||||
sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
|
||||
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
|
||||
char *p = args;
|
||||
uint8_t forced_answer = 0;
|
||||
|
||||
switch (signal_data->switchtype) {
|
||||
case SNGISDN_SWITCH_5ESS:
|
||||
case SNGISDN_SWITCH_4ESS:
|
||||
break;
|
||||
default:
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "AT&T Courtesy Transfer not supported for switchtype\n");
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
while (!ftdm_strlen_zero(p)) {
|
||||
if (!isdigit(*p) && *p != 'w' && *p != 'W') {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Cannot transfer to non-numeric number:%s\n", args);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Performing AT&T Courtesy Transfer-VRU%s to %s\n", (type == SNGISDN_TRANSFER_ATT_COURTESY_VRU_DATA) ?"--data" : "", args);
|
||||
sprintf(dtmf_digits, "*8w%s", args);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending digits %s\n", dtmf_digits);
|
||||
|
||||
switch (ftdmchan->last_state) {
|
||||
case FTDM_CHANNEL_STATE_PROCEED:
|
||||
case FTDM_CHANNEL_STATE_PROGRESS:
|
||||
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
|
||||
/* Call has to be in answered state - so send a CONNECT message if we did not answer this call yet */
|
||||
forced_answer++;
|
||||
sngisdn_snd_connect(ftdmchan);
|
||||
/* fall-through */
|
||||
case FTDM_CHANNEL_STATE_UP:
|
||||
memset(&sngisdn_info->transfer_data.tdata.att_courtesy_vru.dtmf_digits, 0, sizeof(sngisdn_info->transfer_data.tdata.att_courtesy_vru.dtmf_digits));
|
||||
sngisdn_info->transfer_data.type = type;
|
||||
|
||||
/* We will be polling the channel for IO so that we can receive the DTMF events,
|
||||
* Disable user RX otherwise it is a race between who calls channel_read */
|
||||
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED);
|
||||
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_DTMF_DETECT, NULL);
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SEND_DTMF, dtmf_digits);
|
||||
|
||||
if (type == SNGISDN_TRANSFER_ATT_COURTESY_VRU_DATA) {
|
||||
/* We need to save transfer data, so we can send it in the disconnect msg */
|
||||
const char *val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "transfer_data");
|
||||
if (ftdm_strlen_zero(val)) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Cannot perform data transfer because transfer_data variable is not set\n");
|
||||
goto done;
|
||||
}
|
||||
if (strlen(val) > COURTESY_TRANSFER_MAX_DATA_SIZE) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Data exceeds max size (len:%d max:%d), cannot perform transfer\n", strlen(val), COURTESY_TRANSFER_MAX_DATA_SIZE);
|
||||
goto done;
|
||||
}
|
||||
memcpy(sngisdn_info->transfer_data.tdata.att_courtesy_vru.data, val, strlen(val));
|
||||
}
|
||||
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
|
||||
if (forced_answer) {
|
||||
/* Notify the user that we answered the call */
|
||||
sngisdn_send_signal(sngisdn_info, FTDM_SIGEVENT_UP);
|
||||
}
|
||||
if (signal_data->transfer_timeout) {
|
||||
ftdm_sched_timer(((sngisdn_span_data_t*)ftdmchan->span->signal_data)->sched, "courtesy_transfer_timeout", signal_data->transfer_timeout, att_courtesy_transfer_timeout, (void*) sngisdn_info, &sngisdn_info->timers[SNGISDN_TIMER_ATT_TRANSFER]);
|
||||
}
|
||||
|
||||
status = FTDM_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Cannot perform transfer in state %s\n", ftdm_channel_state2str(ftdmchan->state));
|
||||
break;
|
||||
|
||||
}
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
ftdm_status_t sngisdn_transfer(ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
const char* args;
|
||||
char *p;
|
||||
char *type = NULL;
|
||||
char *target = NULL;
|
||||
ftdm_status_t status = FTDM_FAIL;
|
||||
sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
|
||||
unsigned i;
|
||||
|
||||
args = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "transfer_arg");
|
||||
if (ftdm_strlen_zero(args)) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Cannot perform transfer because call_transfer_arg variable is not set\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
type = ftdm_strdup(args);
|
||||
if ((p = strchr(type, '/'))) {
|
||||
target = ftdm_strdup(p+1);
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
if (ftdm_strlen_zero(type) || ftdm_strlen_zero(target)) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Invalid parameters for transfer %s, expected <type>/<target>\n", args);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (sngisdn_info->transfer_data.type != SNGISDN_TRANSFER_NONE) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Cannot perform transfer because an existing transfer transfer is pending (%s)\n", sngisdn_transfer_type2str(sngisdn_info->transfer_data.type));
|
||||
goto done;
|
||||
}
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Transfer requested type:%s target:%s\n", type, target);
|
||||
for (i = 0; i < ftdm_array_len(transfer_interfaces); i++ ) {
|
||||
if (!strcasecmp(transfer_interfaces[i].name, type)) {
|
||||
/* Depending on the transfer type, the transfer function may change the
|
||||
* channel state to UP, or last_state, but the transfer function will always result in
|
||||
* an immediate state change if FTDM_SUCCESS is returned */
|
||||
|
||||
status = transfer_interfaces[i].func(ftdmchan, transfer_interfaces[i].type, target);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Invalid transfer type:%s\n", type);
|
||||
|
||||
done:
|
||||
if (status != FTDM_SUCCESS) {
|
||||
ftdm_set_state(ftdmchan, ftdmchan->last_state);
|
||||
}
|
||||
|
||||
ftdm_safe_free(type);
|
||||
ftdm_safe_free(target);
|
||||
return status;
|
||||
}
|
||||
|
||||
ftdm_status_t sngisdn_att_transfer_process_dtmf(ftdm_channel_t *ftdmchan, const char* dtmf)
|
||||
{
|
||||
ftdm_status_t status = FTDM_SUCCESS;
|
||||
sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
|
||||
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
|
||||
char *dtmf_digits = sngisdn_info->transfer_data.tdata.att_courtesy_vru.dtmf_digits;
|
||||
ftdm_size_t dtmf_digits_len = strlen(dtmf_digits);
|
||||
|
||||
dtmf_digits_len += sprintf(&dtmf_digits[dtmf_digits_len], "%s", dtmf);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Transfer response digits:%s\n", dtmf_digits);
|
||||
if (dtmf_digits_len == 3) {
|
||||
if (!strcmp(dtmf_digits, SNGISDN_ATT_TRANSFER_RESPONSE_CP_DROP_OFF)) {
|
||||
sngisdn_info->transfer_data.response = FTDM_TRANSFER_RESPONSE_CP_DROP_OFF;
|
||||
} else if (!strcmp(dtmf_digits, SNGISDN_ATT_TRANSFER_RESPONSE_LIMITS_EXCEEDED)) {
|
||||
sngisdn_info->transfer_data.response = FTDM_TRANSFER_RESPONSE_LIMITS_EXCEEDED;
|
||||
} else if (!strcmp(dtmf_digits, SNGISDN_ATT_TRANSFER_RESPONSE_OK)) {
|
||||
sngisdn_info->transfer_data.response = FTDM_TRANSFER_RESPONSE_OK;
|
||||
} else if (!strcmp(dtmf_digits, SNGISDN_ATT_TRANSFER_RESPONSE_INVALID_NUM)) {
|
||||
sngisdn_info->transfer_data.response = FTDM_TRANSFER_RESPONSE_INVALID_NUM;
|
||||
} else if (!strcmp(dtmf_digits, SNGISDN_ATT_TRANSFER_RESPONSE_INVALID_COMMAND)) {
|
||||
sngisdn_info->transfer_data.response = FTDM_TRANSFER_RESPONSE_INVALID_COMMAND;
|
||||
} else {
|
||||
sngisdn_info->transfer_data.response = FTDM_TRANSFER_RESPONSE_INVALID;
|
||||
}
|
||||
if (signal_data->transfer_timeout) {
|
||||
ftdm_sched_cancel_timer(signal_data->sched, sngisdn_info->timers[SNGISDN_TIMER_ATT_TRANSFER]);
|
||||
}
|
||||
|
||||
if (sngisdn_info->transfer_data.response == FTDM_TRANSFER_RESPONSE_OK &&
|
||||
sngisdn_info->transfer_data.type == SNGISDN_TRANSFER_ATT_COURTESY_VRU_DATA) {
|
||||
sngisdn_set_flag(sngisdn_info, FLAG_SEND_DISC);
|
||||
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
|
||||
sngisdn_snd_disconnect(ftdmchan);
|
||||
}
|
||||
/* Network side will send disconnect in case of NO-DATA Transfer */
|
||||
att_courtesy_transfer_complete(sngisdn_info, sngisdn_info->transfer_data.response);
|
||||
}
|
||||
|
||||
if (signal_data->att_remove_dtmf) {
|
||||
/* If we return FTDM_BREAK, dtmf event is not queue'ed to user */
|
||||
status = FTDM_BREAK;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user