Support for AT&T *8 Transfer (VRU only)

This commit is contained in:
David Yat Sin 2011-05-26 11:38:24 -04:00
parent 3fa2fce3f3
commit bd7672242c
17 changed files with 845 additions and 197 deletions

View File

@ -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_cfg.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.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_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_support.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c \ $(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c \ $(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c \

View File

@ -2,6 +2,7 @@ APIs that result in an event when the API returns FTDM_SUCCESS
ftdm_channel_call_answer() ftdm_channel_call_answer()
ftdm_channel_call_indicate() ftdm_channel_call_indicate()
ftdm_channel_call_transfer()
FTDM_SIGEVENT_INDICATION_COMPLETED FTDM_SIGEVENT_INDICATION_COMPLETED
*note that FTDM_SIGEVENT_INDICATION_COMPLETED has associated data to indicate the result of the indication *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 *note this event is only delivered on non-blocking channels

View File

@ -67,7 +67,8 @@ typedef enum {
TFLAG_CODEC = (1 << 2), TFLAG_CODEC = (1 << 2),
TFLAG_BREAK = (1 << 3), TFLAG_BREAK = (1 << 3),
TFLAG_HOLD = (1 << 4), TFLAG_HOLD = (1 << 4),
TFLAG_DEAD = (1 << 5) TFLAG_DEAD = (1 << 5),
TFLAG_TRANSFER = (1 << 6),
} TFLAGS; } TFLAGS;
static struct { static struct {
@ -882,10 +883,30 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session,
ftdm_channel_call_answer(tech_pvt->ftdmchan); ftdm_channel_call_answer(tech_pvt->ftdmchan);
} }
break; break;
case SWITCH_MESSAGE_INDICATE_REDIRECT:
case SWITCH_MESSAGE_INDICATE_DEFLECT:
{
ftdm_usrmsg_t usrmsg;
const char *val = NULL;
memset(&usrmsg, 0, sizeof(usrmsg));
if ((val = switch_channel_get_variable(channel, "freetdm_transfer_data"))) {
ftdm_usrmsg_add_var(&usrmsg, "transfer_data", val);
}
switch_set_flag(tech_pvt, TFLAG_TRANSFER);
if (ftdm_channel_call_transfer_ex(tech_pvt->ftdmchan, msg->string_arg, &usrmsg) != FTDM_SUCCESS) {
switch_clear_flag(tech_pvt, TFLAG_TRANSFER);
}
while (switch_test_flag(tech_pvt, TFLAG_TRANSFER)) {
switch_yield(100000);
}
}
default: default:
break; break;
} }
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
@ -1749,11 +1770,13 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session
static FIO_SIGNAL_CB_FUNCTION(on_common_signal) static FIO_SIGNAL_CB_FUNCTION(on_common_signal)
{ {
switch_event_t *event = NULL;
ftdm_alarm_flag_t alarmbits = FTDM_ALARM_NONE;
uint32_t chanid, spanid; uint32_t chanid, spanid;
switch_event_t *event = NULL;
ftdm_alarm_flag_t alarmbits = FTDM_ALARM_NONE;
chanid = ftdm_channel_get_id(sigmsg->channel); chanid = ftdm_channel_get_id(sigmsg->channel);
spanid = ftdm_channel_get_span_id(sigmsg->channel); spanid = ftdm_channel_get_span_id(sigmsg->channel);
switch (sigmsg->event_id) { switch (sigmsg->event_id) {
case FTDM_SIGEVENT_ALARM_CLEAR: case FTDM_SIGEVENT_ALARM_CLEAR:
@ -1788,14 +1811,44 @@ static FIO_SIGNAL_CB_FUNCTION(on_common_signal)
} }
return FTDM_SUCCESS; return FTDM_SUCCESS;
} }
case FTDM_SIGEVENT_TRANSFER_COMPLETED:
{
switch_core_session_t *session = NULL;
switch_channel_t *channel = NULL;
private_t *tech_pvt = NULL;
case FTDM_SIGEVENT_RELEASED: if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
channel = switch_core_session_get_channel(session);
tech_pvt = switch_core_session_get_private(session);
switch_clear_flag_locked(tech_pvt, TFLAG_TRANSFER);
switch_channel_set_variable(channel, "freetdm_transfer_response", ftdm_transfer_response2str(sigmsg->ev_data.transfer_completed.response));
switch_core_session_rwunlock(session);
}
return FTDM_SUCCESS;
}
break;
case FTDM_SIGEVENT_RELEASED:
case FTDM_SIGEVENT_INDICATION_COMPLETED: case FTDM_SIGEVENT_INDICATION_COMPLETED:
case FTDM_SIGEVENT_DIALING: case FTDM_SIGEVENT_DIALING:
{ {
/* Swallow these events */ /* Swallow these events */
return FTDM_BREAK; return FTDM_BREAK;
} }
break;
case FTDM_SIGEVENT_STOP:
case FTDM_SIGEVENT_RESTART:
{
switch_core_session_t *session = NULL;
private_t *tech_pvt = NULL;
while((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
tech_pvt = switch_core_session_get_private(session);
switch_clear_flag_locked(tech_pvt, TFLAG_TRANSFER);
switch_core_session_rwunlock(session);
return FTDM_SUCCESS;
}
}
break; break;
default: default:
return FTDM_SUCCESS; return FTDM_SUCCESS;
@ -2350,6 +2403,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
break; break;
case FTDM_SIGEVENT_PROCEED: case FTDM_SIGEVENT_PROCEED:
case FTDM_SIGEVENT_FACILITY: case FTDM_SIGEVENT_FACILITY:
case FTDM_SIGEVENT_TRANSFER_COMPLETED:
/* FS does not have handlers for these messages, so ignore them for now */ /* FS does not have handlers for these messages, so ignore them for now */
break; break;
default: default:

View File

@ -58,6 +58,8 @@ struct tm *localtime_r(const time_t *clock, struct tm *result);
#define FTDM_READ_TRACE_INDEX 0 #define FTDM_READ_TRACE_INDEX 0
#define FTDM_WRITE_TRACE_INDEX 1 #define FTDM_WRITE_TRACE_INDEX 1
#define MAX_CALLIDS 6000 #define MAX_CALLIDS 6000
#define FTDM_HALF_DTMF_PAUSE 500
#define FTDM_FULL_DTMF_PAUSE 1000
ftdm_time_t time_last_throttle_log = 0; ftdm_time_t time_last_throttle_log = 0;
ftdm_time_t time_current_throttle_log = 0; ftdm_time_t time_current_throttle_log = 0;
@ -306,7 +308,10 @@ FTDM_ENUM_NAMES(CALLING_PARTY_CATEGORY_NAMES, CALLING_PARTY_CATEGORY_STRINGS)
FTDM_STR2ENUM(ftdm_str2ftdm_calling_party_category, ftdm_calling_party_category2str, ftdm_calling_party_category_t, CALLING_PARTY_CATEGORY_NAMES, FTDM_CPC_INVALID) FTDM_STR2ENUM(ftdm_str2ftdm_calling_party_category, ftdm_calling_party_category2str, ftdm_calling_party_category_t, CALLING_PARTY_CATEGORY_NAMES, FTDM_CPC_INVALID)
FTDM_ENUM_NAMES(INDICATION_NAMES, INDICATION_STRINGS) FTDM_ENUM_NAMES(INDICATION_NAMES, INDICATION_STRINGS)
FTDM_STR2ENUM(ftdm_str2channel_indication, ftdm_channel_indication2str, ftdm_channel_indication_t, INDICATION_NAMES, FTDM_CHANNEL_INDICATE_INVALID) FTDM_STR2ENUM(ftdm_str2ftdm_channel_indication, ftdm_channel_indication2str, ftdm_channel_indication_t, INDICATION_NAMES, FTDM_CHANNEL_INDICATE_INVALID)
FTDM_ENUM_NAMES(TRANSFER_RESPONSE_NAMES, TRANSFER_RESPONSE_STRINGS)
FTDM_STR2ENUM(ftdm_str2ftdm_transfer_response, ftdm_transfer_response2str, ftdm_transfer_response_t, TRANSFER_RESPONSE_NAMES, FTDM_TRANSFER_RESPONSE_INVALID)
static ftdm_status_t ftdm_group_add_channels(ftdm_span_t* span, int currindex, const char* name); static ftdm_status_t ftdm_group_add_channels(ftdm_span_t* span, int currindex, const char* name);
@ -1191,6 +1196,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read_event(ftdm_channel_t *ftdmchan, ftdm
goto done; goto done;
} }
if (ftdm_test_io_flag(ftdmchan, FTDM_CHANNEL_IO_EVENT)) {
ftdm_clear_io_flag(ftdmchan, FTDM_CHANNEL_IO_EVENT);
}
status = span->fio->channel_next_event(ftdmchan, event); status = span->fio->channel_next_event(ftdmchan, event);
if (status != FTDM_SUCCESS) { if (status != FTDM_SUCCESS) {
goto done; goto done;
@ -1952,6 +1961,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_set_blocking_mode(const ftdm_span_t *span, f
if (!citer) { if (!citer) {
return FTDM_ENOMEM; return FTDM_ENOMEM;
} }
for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) { for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) {
fchan = ftdm_iterator_current(curr); fchan = ftdm_iterator_current(curr);
if (enabled) { if (enabled) {
@ -2076,12 +2086,12 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_unhold(const char *file, const char
FT_DECLARE(void) ftdm_ack_indication(ftdm_channel_t *fchan, ftdm_channel_indication_t indication, ftdm_status_t status) FT_DECLARE(void) ftdm_ack_indication(ftdm_channel_t *fchan, ftdm_channel_indication_t indication, ftdm_status_t status)
{ {
ftdm_sigmsg_t msg; ftdm_sigmsg_t msg;
if (!ftdm_test_flag(fchan, FTDM_CHANNEL_IND_ACK_PENDING)) { if (!ftdm_test_flag(fchan, FTDM_CHANNEL_IND_ACK_PENDING)) {
return; return;
} }
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Acknowledging indication %s in state %s (rc = %d)\n", ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Acknowledging indication %s in state %s (rc = %d)\n",
ftdm_channel_indication2str(indication), ftdm_channel_state2str(fchan->state), status); ftdm_channel_indication2str(indication), ftdm_channel_state2str(fchan->state), status);
ftdm_clear_flag(fchan, FTDM_CHANNEL_IND_ACK_PENDING); ftdm_clear_flag(fchan, FTDM_CHANNEL_IND_ACK_PENDING);
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
@ -2155,11 +2165,36 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char
return status; return status;
} }
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)
{
ftdm_status_t status;
ftdm_usrmsg_t *msg = NULL;
ftdm_bool_t free_msg = FTDM_FALSE;
if (!usrmsg) {
msg = ftdm_calloc(1, sizeof(*msg));
ftdm_assert_return(msg, FTDM_FAIL, "Failed to allocate usr msg");
memset(msg, 0, sizeof(*msg));
free_msg = FTDM_TRUE;
} else {
msg = usrmsg;
}
ftdm_usrmsg_add_var(msg, "transfer_arg", arg);
/* we leave the locking up to ftdm_channel_call_indicate, DO NOT lock here since ftdm_channel_call_indicate expects
* the lock recursivity to be 1 */
status = _ftdm_channel_call_indicate(file, func, line, ftdmchan, FTDM_CHANNEL_INDICATE_TRANSFER, msg);
if (free_msg == FTDM_TRUE) {
ftdm_safe_free(msg);
}
return status;
}
/* lock must be acquired by the caller! */ /* lock must be acquired by the caller! */
static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char *func, int line, ftdm_channel_t *chan, ftdm_usrmsg_t *usrmsg) static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char *func, int line, ftdm_channel_t *chan, ftdm_usrmsg_t *usrmsg)
{ {
ftdm_status_t status = FTDM_SUCCESS; ftdm_status_t status = FTDM_SUCCESS;
if (chan->state != FTDM_CHANNEL_STATE_DOWN) { if (chan->state != FTDM_CHANNEL_STATE_DOWN) {
if (chan->state == FTDM_CHANNEL_STATE_HANGUP) { if (chan->state == FTDM_CHANNEL_STATE_HANGUP) {
/* make user's life easier, and just ignore double hangup requests */ /* make user's life easier, and just ignore double hangup requests */
@ -2351,6 +2386,14 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch
case FTDM_CHANNEL_INDICATE_ANSWER: case FTDM_CHANNEL_INDICATE_ANSWER:
status = _ftdm_channel_call_answer_nl(file, func, line, ftdmchan, usrmsg); status = _ftdm_channel_call_answer_nl(file, func, line, ftdmchan, usrmsg);
break; break;
case FTDM_CHANNEL_INDICATE_TRANSFER:
if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_TRANSFER)) {
ftdm_log_chan_ex_msg(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "Transfer not supported\n");
status = FTDM_EINVAL;
goto done;
}
status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_TRANSFER, 1, usrmsg);
break;
default: default:
/* See if signalling module can provide this indication */ /* See if signalling module can provide this indication */
status = ftdm_channel_sig_indicate(ftdmchan, indication, usrmsg); status = ftdm_channel_sig_indicate(ftdmchan, indication, usrmsg);
@ -2720,10 +2763,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_close(ftdm_channel_t **ftdmchan)
return status; return status;
} }
static ftdm_status_t ftdmchan_activate_dtmf_buffer(ftdm_channel_t *ftdmchan) static ftdm_status_t ftdmchan_activate_dtmf_buffer(ftdm_channel_t *ftdmchan)
{ {
if (!ftdmchan->dtmf_buffer) { if (!ftdmchan->dtmf_buffer) {
if (ftdm_buffer_create(&ftdmchan->dtmf_buffer, 1024, 3192, 0) != FTDM_SUCCESS) { if (ftdm_buffer_create(&ftdmchan->dtmf_buffer, 1024, 3192, 0) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "Failed to allocate DTMF Buffer!\n"); ftdm_log(FTDM_LOG_ERROR, "Failed to allocate DTMF Buffer!\n");
@ -2752,10 +2793,29 @@ static ftdm_status_t ftdmchan_activate_dtmf_buffer(ftdm_channel_t *ftdmchan)
return FTDM_SUCCESS; return FTDM_SUCCESS;
} }
/*
* ftdmchan_activate_dtmf_buffer to initialize ftdmchan->dtmf_buffer should be called prior to
* calling ftdm_insert_dtmf_pause
*/
static ftdm_status_t ftdm_insert_dtmf_pause(ftdm_channel_t *ftdmchan, ftdm_size_t pausems)
{
void *data = NULL;
unsigned int datalen = pausems * sizeof(uint16_t);
data = ftdm_malloc(datalen);
ftdm_assert(data, "Failed to allocate memory\n");
memset(data, FTDM_SILENCE_VALUE(ftdmchan), datalen);
ftdm_buffer_write(ftdmchan->dtmf_buffer, data, datalen);
ftdm_safe_free(data);
return FTDM_SUCCESS;
}
FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_command_t command, void *obj) FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_command_t command, void *obj)
{ {
ftdm_status_t status = FTDM_FAIL; ftdm_status_t status = FTDM_FAIL;
ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "No channel\n"); ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "No channel\n");
ftdm_assert_return(ftdmchan->fio != NULL, FTDM_FAIL, "No IO attached to channel\n"); ftdm_assert_return(ftdmchan->fio != NULL, FTDM_FAIL, "No IO attached to channel\n");
@ -3519,13 +3579,18 @@ skipdebug:
status = ftdm_buffer_write(ftdmchan->digit_buffer, dtmf, wr) ? FTDM_SUCCESS : FTDM_FAIL; status = ftdm_buffer_write(ftdmchan->digit_buffer, dtmf, wr) ? FTDM_SUCCESS : FTDM_FAIL;
ftdm_mutex_unlock(ftdmchan->mutex); ftdm_mutex_unlock(ftdmchan->mutex);
return status; return status;
} }
static FIO_WRITE_FUNCTION(ftdm_raw_write) FIO_WRITE_FUNCTION(ftdm_raw_write)
{ {
int dlen = (int) *datalen; int dlen = (int) *datalen;
if (ftdm_test_io_flag(ftdmchan, FTDM_CHANNEL_IO_WRITE)) {
ftdm_clear_io_flag(ftdmchan, FTDM_CHANNEL_IO_WRITE);
}
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TX_DISABLED)) { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TX_DISABLED)) {
ftdmchan->txdrops++; ftdmchan->txdrops++;
if (ftdmchan->txdrops <= 10) { if (ftdmchan->txdrops <= 10) {
@ -3545,11 +3610,16 @@ static FIO_WRITE_FUNCTION(ftdm_raw_write)
return ftdmchan->fio->write(ftdmchan, data, datalen); return ftdmchan->fio->write(ftdmchan, data, datalen);
} }
static FIO_READ_FUNCTION(ftdm_raw_read) FIO_READ_FUNCTION(ftdm_raw_read)
{ {
ftdm_status_t status = ftdmchan->fio->read(ftdmchan, data, datalen); ftdm_status_t status;
if (ftdm_test_io_flag(ftdmchan, FTDM_CHANNEL_IO_READ)) {
ftdm_clear_io_flag(ftdmchan, FTDM_CHANNEL_IO_READ);
}
status = ftdmchan->fio->read(ftdmchan, data, datalen);
if (status == FTDM_SUCCESS && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN) if (status == FTDM_SUCCESS && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN)
&& (ftdmchan->native_codec == FTDM_CODEC_ALAW || ftdmchan->native_codec == FTDM_CODEC_ULAW)) { && (ftdmchan->native_codec == FTDM_CODEC_ALAW || ftdmchan->native_codec == FTDM_CODEC_ULAW)) {
ftdm_size_t i = 0; ftdm_size_t i = 0;
unsigned char *rdata = data; unsigned char *rdata = data;
@ -3616,30 +3686,31 @@ static ftdm_status_t handle_tone_generation(ftdm_channel_t *ftdmchan)
if (ftdm_buffer_read(ftdmchan->gen_dtmf_buffer, digits, dblen) && !ftdm_strlen_zero_buf(digits)) { if (ftdm_buffer_read(ftdmchan->gen_dtmf_buffer, digits, dblen) && !ftdm_strlen_zero_buf(digits)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Generating DTMF [%s]\n", digits); ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Generating DTMF [%s]\n", digits);
cur = digits; cur = digits;
if (*cur == 'F') {
ftdm_channel_command(ftdmchan, FTDM_COMMAND_FLASH, NULL);
cur++;
}
for (; *cur; cur++) { for (; *cur; cur++) {
if ((wrote = teletone_mux_tones(&ftdmchan->tone_session, &ftdmchan->tone_session.TONES[(int)*cur]))) { if (*cur == 'F') {
ftdm_buffer_write(ftdmchan->dtmf_buffer, ftdmchan->tone_session.buffer, wrote * 2); ftdm_channel_command(ftdmchan, FTDM_COMMAND_FLASH, NULL);
x++; } else if (*cur == 'w') {
ftdm_insert_dtmf_pause(ftdmchan, FTDM_HALF_DTMF_PAUSE);
} else if (*cur == 'W') {
ftdm_insert_dtmf_pause(ftdmchan, FTDM_FULL_DTMF_PAUSE);
} else { } else {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Problem adding DTMF sequence [%s]\n", digits); if ((wrote = teletone_mux_tones(&ftdmchan->tone_session, &ftdmchan->tone_session.TONES[(int)*cur]))) {
return FTDM_FAIL; ftdm_buffer_write(ftdmchan->dtmf_buffer, ftdmchan->tone_session.buffer, wrote * 2);
x++;
} else {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Problem adding DTMF sequence [%s]\n", digits);
return FTDM_FAIL;
}
}
if (x) {
ftdmchan->skip_read_frames = (wrote / (ftdmchan->effective_interval * 8)) + 4;
} }
}
if (x) {
ftdmchan->skip_read_frames = (wrote / (ftdmchan->effective_interval * 8)) + 4;
} }
} }
} }
if (!ftdmchan->buffer_delay || --ftdmchan->buffer_delay == 0) { if (!ftdmchan->buffer_delay || --ftdmchan->buffer_delay == 0) {
/* time to pick a buffer, either the dtmf or fsk buffer */ /* time to pick a buffer, either the dtmf or fsk buffer */
@ -3699,6 +3770,7 @@ static ftdm_status_t handle_tone_generation(ftdm_channel_t *ftdmchan)
} }
FT_DECLARE(void) ftdm_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t divisor) FT_DECLARE(void) ftdm_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t divisor)
{ {
int16_t x; int16_t x;
@ -3720,49 +3792,12 @@ FT_DECLARE(void) ftdm_generate_sln_silence(int16_t *data, uint32_t samples, uint
} }
} }
FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t *datalen) FT_DECLARE(ftdm_status_t) ftdm_channel_process_media(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t *datalen)
{ {
ftdm_status_t status = FTDM_FAIL; ftdm_status_t status = FTDM_FAIL;
fio_codec_t codec_func = NULL; fio_codec_t codec_func = NULL;
ftdm_size_t max = *datalen; ftdm_size_t max = *datalen;
ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "ftdmchan is null\n");
ftdm_assert_return(ftdmchan->fio != NULL, FTDM_FAIL, "No I/O module attached to ftdmchan\n");
ftdm_channel_lock(ftdmchan);
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open");
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "cannot read from channel that is not open\n");
status = FTDM_FAIL;
goto done;
}
if (!ftdmchan->fio->read) {
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented");
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "read method not implemented\n");
status = FTDM_FAIL;
goto done;
}
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED)) {
ftdmchan->rxdrops++;
if (ftdmchan->rxdrops <= 10) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "cannot read from channel with rx disabled\n");
}
if (ftdmchan->rxdrops == 10) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "too many rx drops, not logging anymore\n");
}
status = FTDM_FAIL;
goto done;
}
status = ftdm_raw_read(ftdmchan, data, datalen);
if (status != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "raw I/O read filed\n");
goto done;
}
handle_tone_generation(ftdmchan); handle_tone_generation(ftdmchan);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_DIGITAL_MEDIA)) { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_DIGITAL_MEDIA)) {
@ -3789,8 +3824,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data
} }
} }
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT) || if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT) ||
ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT) ||
ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT)) { ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT)) {
uint8_t sln_buf[1024] = {0}; uint8_t sln_buf[1024] = {0};
int16_t *sln; int16_t *sln;
ftdm_size_t slen = 0; ftdm_size_t slen = 0;
@ -3894,8 +3931,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data
} }
} }
} }
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT) && !ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT) && !ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) {
teletone_dtmf_detect(&ftdmchan->dtmf_detect, sln, (int)slen); teletone_dtmf_detect(&ftdmchan->dtmf_detect, sln, (int)slen);
teletone_dtmf_get(&ftdmchan->dtmf_detect, digit_str, sizeof(digit_str)); teletone_dtmf_get(&ftdmchan->dtmf_detect, digit_str, sizeof(digit_str));
@ -3904,7 +3940,9 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data
if (ftdmchan->state == FTDM_CHANNEL_STATE_CALLWAITING && (*digit_str == 'D' || *digit_str == 'A')) { if (ftdmchan->state == FTDM_CHANNEL_STATE_CALLWAITING && (*digit_str == 'D' || *digit_str == 'A')) {
ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++; ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++;
} else { } else {
ftdm_channel_queue_dtmf(ftdmchan, digit_str); if (!ftdmchan->span->sig_dtmf || (ftdmchan->span->sig_dtmf(ftdmchan, (const char*)digit_str) != FTDM_BREAK)) {
ftdm_channel_queue_dtmf(ftdmchan, digit_str);
}
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF)) { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF)) {
ftdmchan->skip_read_frames = 20; ftdmchan->skip_read_frames = 20;
@ -3915,20 +3953,19 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data
} }
if (ftdmchan->skip_read_frames > 0 || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MUTE)) { if (ftdmchan->skip_read_frames > 0 || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MUTE)) {
ftdm_mutex_lock(ftdmchan->pre_buffer_mutex); ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
if (ftdmchan->pre_buffer && ftdm_buffer_inuse(ftdmchan->pre_buffer)) { if (ftdmchan->pre_buffer && ftdm_buffer_inuse(ftdmchan->pre_buffer)) {
ftdm_buffer_zero(ftdmchan->pre_buffer); ftdm_buffer_zero(ftdmchan->pre_buffer);
} }
ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex); ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
memset(data, FTDM_SILENCE_VALUE(ftdmchan), *datalen); memset(data, FTDM_SILENCE_VALUE(ftdmchan), *datalen);
if (ftdmchan->skip_read_frames > 0) { if (ftdmchan->skip_read_frames > 0) {
ftdmchan->skip_read_frames--; ftdmchan->skip_read_frames--;
} }
} else { } else {
ftdm_mutex_lock(ftdmchan->pre_buffer_mutex); ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
if (ftdmchan->pre_buffer_size && ftdmchan->pre_buffer) { if (ftdmchan->pre_buffer_size && ftdmchan->pre_buffer) {
ftdm_buffer_write(ftdmchan->pre_buffer, data, *datalen); ftdm_buffer_write(ftdmchan->pre_buffer, data, *datalen);
@ -3942,9 +3979,55 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data
} }
done: done:
return FTDM_SUCCESS;
}
FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t *datalen)
{
ftdm_status_t status = FTDM_FAIL;
ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "ftdmchan is null\n");
ftdm_assert_return(ftdmchan->fio != NULL, FTDM_FAIL, "No I/O module attached to ftdmchan\n");
ftdm_channel_lock(ftdmchan);
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "cannot read from channel that is not open\n");
status = FTDM_FAIL;
goto done;
}
if (!ftdmchan->fio->read) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "read method not implemented\n");
status = FTDM_FAIL;
goto done;
}
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED)) {
ftdmchan->rxdrops++;
if (ftdmchan->rxdrops <= 10) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "cannot read from channel with rx disabled\n");
}
if (ftdmchan->rxdrops == 10) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "too many rx drops, not logging anymore\n");
}
status = FTDM_FAIL;
goto done;
}
status = ftdm_raw_read(ftdmchan, data, datalen);
if (status != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "raw I/O read filed\n");
goto done;
}
status = ftdm_channel_process_media(ftdmchan, data, datalen);
if (status != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Failed to process media\n");
}
done:
ftdm_channel_unlock(ftdmchan); ftdm_channel_unlock(ftdmchan);
return status; return status;
} }
@ -3972,14 +4055,12 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_write(ftdm_channel_t *ftdmchan, void *dat
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) { if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "cannot write in channel not open\n"); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "cannot write in channel not open\n");
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open");
status = FTDM_FAIL; status = FTDM_FAIL;
goto done; goto done;
} }
if (!ftdmchan->fio->write) { if (!ftdmchan->fio->write) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "write method not implemented\n"); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "write method not implemented\n");
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented");
status = FTDM_FAIL; status = FTDM_FAIL;
goto done; goto done;
} }
@ -4003,8 +4084,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_write(ftdm_channel_t *ftdmchan, void *dat
status = codec_func(data, max, datalen); status = codec_func(data, max, datalen);
} else { } else {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Do not know how to handle transcoding from %d to %d\n", ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Do not know how to handle transcoding from %d to %d\n",
ftdmchan->effective_codec, ftdmchan->native_codec); ftdmchan->effective_codec, ftdmchan->native_codec);
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
status = FTDM_FAIL; status = FTDM_FAIL;
goto done; goto done;
} }

View File

@ -44,6 +44,7 @@
static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj); 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_stop(ftdm_span_t *span);
static ftdm_status_t ftdm_sangoma_isdn_start(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); 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); 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_wakeup_phy(ftdm_channel_t *dchan);
static void ftdm_sangoma_isdn_dchan_set_queue_size(ftdm_channel_t *ftdmchan); 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; 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 = { ftdm_state_map_t sangoma_isdn_state_map = {
{ {
@ -126,8 +130,7 @@ ftdm_state_map_t sangoma_isdn_state_map = {
ZSD_INBOUND, ZSD_INBOUND,
ZSM_UNACCEPTABLE, ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_PROCEED, FTDM_END}, {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_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}
FTDM_CHANNEL_STATE_UP, FTDM_END}
}, },
{ {
ZSD_INBOUND, ZSD_INBOUND,
@ -151,7 +154,14 @@ ftdm_state_map_t sangoma_isdn_state_map = {
ZSD_INBOUND, ZSD_INBOUND,
ZSM_UNACCEPTABLE, ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_UP, FTDM_END}, {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, ZSD_INBOUND,
@ -352,49 +362,96 @@ static void ftdm_sangoma_isdn_wakeup_phy(ftdm_channel_t *dchan)
return; 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]; uint8_t data[1000];
unsigned i;
ftdm_status_t status = FTDM_SUCCESS; ftdm_status_t status = FTDM_SUCCESS;
ftdm_wait_flag_t wflags = FTDM_READ; ftdm_wait_flag_t wflags = FTDM_READ;
ftdm_span_t *span = (ftdm_span_t*) obj; 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_size_t len = 0;
ftdm_channel_t *ftdmchan = NULL;
ftdm_channel_set_feature(dchan, FTDM_CHANNEL_FEATURE_IO_STATS); unsigned waitms = 10000;
ftdm_sangoma_isdn_dchan_set_queue_size(dchan); 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))) { while (ftdm_running() && !(ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD))) {
len = 1000;
waitms = 1000;
wflags = FTDM_READ; wflags = FTDM_READ;
status = ftdm_channel_wait(dchan, &wflags, 10000); memset(poll_events, 0, sizeof(short)*span->chan_count);
switch(status) {
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: 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; break;
case FTDM_TIMEOUT: case FTDM_TIMEOUT:
break; break;
case FTDM_SUCCESS: case FTDM_SUCCESS:
if ((wflags & FTDM_READ)) { for (citer = ftdm_span_get_chan_iterator(span, chaniter); citer; citer = ftdm_iterator_next(citer)) {
len = 1000; len = 1000;
status = ftdm_channel_read(dchan, data, &len); ftdmchan = ftdm_iterator_current(citer);
if (status == FTDM_SUCCESS) { if (FTDM_IS_VOICE_CHANNEL(ftdmchan)) {
sngisdn_snd_data(dchan, data, len); 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 { } 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; break;
default: 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; 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 */ /* 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) static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
{ {
ftdm_sigmsg_t sigev; ftdm_sigmsg_t sigev;
ftdm_channel_state_t initial_state; ftdm_channel_state_t initial_state;
sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
uint8_t state_change = 0; uint8_t state_change = 0;
memset(&sigev, 0, sizeof(sigev)); memset(&sigev, 0, sizeof(sigev));
@ -632,18 +689,15 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm
break; break;
case FTDM_CHANNEL_STATE_GET_CALLERID: 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 */
/* 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};
ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID}; sngisdn_snd_proceed(ftdmchan, prog_ind);
sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED); /* Wait in this state until we get FACILITY msg */
sngisdn_snd_proceed(ftdmchan, prog_ind);
}
/* Wait in this state until we get FACILITY msg */
} }
break; break;
case FTDM_CHANNEL_STATE_RING: /* incoming call request */ 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); 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*/ /* 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); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
} }
} else { } else {
if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) { ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID};
/* By default, we do not send a progress indicator in the proceed */ sngisdn_snd_proceed(ftdmchan, prog_ind);
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);
}
} }
} }
break; break;
@ -846,7 +895,6 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm
ftdm_channel_close(&close_chan); ftdm_channel_close(&close_chan);
} }
if (glare) { if (glare) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Glare detected, processing saved call\n"); 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, /* 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 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; 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: case FTDM_CHANNEL_STATE_RESTART:
{ {
/* IMPLEMENT ME */ /* IMPLEMENT ME */
} }
break; break;
case FTDM_CHANNEL_STATE_SUSPENDED: 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; 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) static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span)
{ {
sngisdn_span_data_t *signal_data = span->signal_data; 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); ftdm_log(FTDM_LOG_CRIT, "Failed to start span %s\n", span->name);
return FTDM_FAIL; return FTDM_FAIL;
} }
/* clear the monitor thread stop flag */ /* clear the monitor thread stop flag */
ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD); ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
ftdm_clear_flag(span, FTDM_SPAN_IN_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*/ /*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"); ftdm_log(FTDM_LOG_CRIT,"Failed to start Sangoma ISDN d-channel Monitor Thread!\n");
return FTDM_FAIL; 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->indicate = ftdm_sangoma_isdn_indicate;
span->channel_request = NULL; span->channel_request = NULL;
span->signal_cb = sig_cb; 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->get_channel_sig_status = ftdm_sangoma_isdn_get_chan_sig_status;
span->set_channel_sig_status = ftdm_sangoma_isdn_set_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; 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_PROCEED_STATE);
ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES); ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES);
ftdm_set_flag(span, FTDM_SPAN_NON_STOPPABLE); ftdm_set_flag(span, FTDM_SPAN_NON_STOPPABLE);
ftdm_set_flag(span, FTDM_SPAN_USE_TRANSFER);
if (span->trunk_type == FTDM_TRUNK_BRI_PTMP || if (FTDM_SPAN_IS_BRI(span)) {
span->trunk_type == FTDM_TRUNK_BRI) {
sngisdn_set_span_avail_rate(span, SNGISDN_AVAIL_PWR_SAVING); sngisdn_set_span_avail_rate(span, SNGISDN_AVAIL_PWR_SAVING);
} }
@ -1321,6 +1391,7 @@ done:
return status; return status;
} }
static FIO_IO_LOAD_FUNCTION(ftdm_sangoma_isdn_io_init) static FIO_IO_LOAD_FUNCTION(ftdm_sangoma_isdn_io_init)
{ {
memset(&g_sngisdn_io_interface, 0, sizeof(g_sngisdn_io_interface)); memset(&g_sngisdn_io_interface, 0, sizeof(g_sngisdn_io_interface));

View File

@ -82,6 +82,8 @@ typedef enum {
FLAG_MEDIA_READY = (1 << 11), FLAG_MEDIA_READY = (1 << 11),
/* Set when we already sent a Channel ID IE */ /* Set when we already sent a Channel ID IE */
FLAG_SENT_CHAN_ID = (1 << 12), FLAG_SENT_CHAN_ID = (1 << 12),
/* Set when we already sent a Connect */
FLAG_SENT_CONNECT = (1 << 13),
} sngisdn_flag_t; } sngisdn_flag_t;
@ -152,10 +154,11 @@ typedef struct ftdm_sngisdn_prog_ind {
} ftdm_sngisdn_progind_t; } ftdm_sngisdn_progind_t;
/* Only timers that can be cancelled are listed here */ /* 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 */ /* Increase NUM_TIMERS as number of ftdm_sngisdn_timer_t increases */
typedef enum { typedef enum {
SNGISDN_TIMER_FACILITY = 0, SNGISDN_TIMER_FACILITY = 0,
SNGISDN_TIMER_ATT_TRANSFER,
} ftdm_sngisdn_timer_t; } ftdm_sngisdn_timer_t;
typedef struct sngisdn_glare_data { typedef struct sngisdn_glare_data {
@ -165,8 +168,35 @@ typedef struct sngisdn_glare_data {
int16_t dChan; int16_t dChan;
ConEvnt setup; ConEvnt setup;
uint8_t ces; 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 */ /* Channel specific data */
typedef struct sngisdn_chan_data { typedef struct sngisdn_chan_data {
@ -180,7 +210,8 @@ typedef struct sngisdn_chan_data {
uint8_t globalFlg; uint8_t globalFlg;
sngisdn_glare_data_t glare; 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 /* variables saved here will be sent to the user application
on next SIGEVENT_XXX */ on next SIGEVENT_XXX */
@ -211,8 +242,10 @@ typedef struct sngisdn_span_data {
uint8_t facility_ie_decode; uint8_t facility_ie_decode;
uint8_t facility; uint8_t facility;
int8_t facility_timeout; int8_t facility_timeout;
uint8_t att_remove_dtmf;
int32_t transfer_timeout;
uint8_t num_local_numbers; 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_q931; /* TODO: combine with trace_flags */
uint8_t trace_q921; /* TODO: combine with trace_flags */ uint8_t trace_q921; /* TODO: combine with trace_flags */
uint8_t raw_trace_q931; /* 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_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(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_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_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_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); 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); 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_infoTranCap_from_user(ftdm_bearer_cap_t bearer_capability);
uint8_t sngisdn_get_usrInfoLyr1Prot_from_user(ftdm_user_layer1_prot_t layer1_prot); 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_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_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) static __inline__ uint32_t sngisdn_test_flag(sngisdn_chan_data_t *sngisdn_info, sngisdn_flag_t flag)
{ {
return (uint32_t) sngisdn_info->flags & flag; return (uint32_t) sngisdn_info->flags & flag;

View File

@ -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->timer_t3 = 8;
signal_data->restart_opt = SNGISDN_OPT_DEFAULT; signal_data->restart_opt = SNGISDN_OPT_DEFAULT;
signal_data->link_id = span->span_id; 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.plan = FTDM_NPI_INVALID;
span->default_caller_data.dnis.type = FTDM_TON_INVALID; span->default_caller_data.dnis.type = FTDM_TON_INVALID;
span->default_caller_data.cid_num.plan = FTDM_NPI_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) { if (signal_data->facility_timeout < 0) {
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")) { } else if (!strcasecmp(var, "facility-ie-decode")) {
parse_yesno(var, val, &signal_data->facility_ie_decode); parse_yesno(var, val, &signal_data->facility_ie_decode);
} else if (!strcasecmp(var, "ignore-cause-value")) { } else if (!strcasecmp(var, "ignore-cause-value")) {

View File

@ -318,8 +318,9 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event)
} }
} else { } else {
switch(ftdmchan->state) { switch(ftdmchan->state) {
case FTDM_CHANNEL_STATE_TRANSFER:
case FTDM_CHANNEL_STATE_UP: 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 */ /* do nothing */
break; break;
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: 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 /* TODO: readjust this when NFAS is implemented as signal_data will not always be the first
* span for that d-channel */ * 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]; signal_data = g_sngisdn_data.dchans[dChan].spans[1];

View File

@ -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_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; 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); 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); sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
return; return;
} }
memset(&cnStEvnt, 0, sizeof(cnStEvnt)); memset(&cnStEvnt, 0, sizeof(cnStEvnt));
/* Indicate channel ID only in first response */ /* 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_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind);
set_facility_ie(ftdmchan, &cnStEvnt.facilityStr); 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); 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)) { 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) 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_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; 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}; 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); 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); sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); 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); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
return; 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); 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)) { if (sng_isdn_disc_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &discEvnt)) {

View File

@ -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_spInstIds[sngisdn_info->spInstId]=NULL;
g_sngisdn_data.ccs[cc_id].active_suInstIds[sngisdn_info->suInstId]=NULL; g_sngisdn_data.ccs[cc_id].active_suInstIds[sngisdn_info->suInstId]=NULL;
ftdm_mutex_unlock(g_sngisdn_data.ccs[cc_id].mutex); ftdm_mutex_unlock(g_sngisdn_data.ccs[cc_id].mutex);
sngisdn_info->suInstId = 0; sngisdn_info->suInstId = 0;
sngisdn_info->spInstId = 0; sngisdn_info->spInstId = 0;
sngisdn_info->globalFlg = 0; sngisdn_info->globalFlg = 0;
sngisdn_info->flags = 0; sngisdn_info->flags = 0;
sngisdn_info->transfer_data.type = SNGISDN_TRANSFER_NONE;
return; return;
} }
@ -845,6 +846,41 @@ ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_s
return FTDM_SUCCESS; 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) 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; 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); ftdm_set_flag(sngisdn_info, FLAG_SENT_CHAN_ID);
chanId->eh.pres = PRSNT_NODEF; chanId->eh.pres = PRSNT_NODEF;
chanId->prefExc.pres = PRSNT_NODEF; chanId->prefExc.pres = PRSNT_NODEF;
chanId->prefExc.val = IN_PE_EXCLSVE; 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.pres = PRSNT_NODEF;
chanId->intIdentPres.val = IN_IIP_IMPLICIT; chanId->intIdentPres.val = IN_IIP_IMPLICIT;
if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI || if (FTDM_SPAN_IS_BRI(ftdmchan->span)) {
ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
/* BRI only params */ /* BRI only params */
chanId->intType.pres = PRSNT_NODEF; 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.data = sngisdn_info->raw_data;
sigev.raw.len = sngisdn_info->raw_data_len; sigev.raw.len = sngisdn_info->raw_data_len;
sngisdn_info->raw_data = NULL; sngisdn_info->raw_data = NULL;
sngisdn_info->raw_data_len = 0; 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); ftdm_span_send_signal(ftdmchan->span, &sigev);
} }

View File

@ -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;
}

View File

@ -1193,12 +1193,26 @@ FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
#else #else
if (pfds[i-1].revents & POLLPRI) { if (pfds[i-1].revents & POLLPRI) {
#endif #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(); ftdmchan->last_event_time = ftdm_current_time_in_ms();
k++; 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; return FTDM_SUCCESS;
} }
@ -1445,14 +1459,9 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event)
wanpipe_tdm_api_t tdm_api; wanpipe_tdm_api_t tdm_api;
ftdm_span_t *span = ftdmchan->span; 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)); memset(&tdm_api, 0, sizeof(tdm_api));
status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api); status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
if (status != FTDM_SUCCESS) { 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)); ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to read event from channel: %s\n", strerror(errno));
return FTDM_FAIL; return FTDM_FAIL;
} }
@ -1488,7 +1497,7 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
for(i = 1; i <= span->chan_count; i++) { for(i = 1; i <= span->chan_count; i++) {
/* as a hack for wink/flash detection, wanpipe_poll_event overrides the timeout parameter /* 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 */ * 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; 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); */ /* 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)) { 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; 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; ftdm_status_t status;
wanpipe_tdm_api_t tdm_api; wanpipe_tdm_api_t tdm_api;
ftdm_channel_t *ftdmchan = span->channels[i]; ftdm_channel_t *ftdmchan = span->channels[i];
memset(&tdm_api, 0, sizeof(tdm_api)); 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); err = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
if (err != FTDM_SUCCESS) { if (err != FTDM_SUCCESS) {

View File

@ -976,13 +976,19 @@ FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno)); snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
return FTDM_FAIL; return FTDM_FAIL;
} }
for(i = 1; i <= span->chan_count; i++) { for(i = 1; i <= span->chan_count; i++) {
if (pfds[i-1].revents & POLLPRI) { 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(); span->channels[i]->last_event_time = ftdm_current_time_in_ms();
k++; 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) { if (!k) {
@ -1106,8 +1112,8 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event)
zt_event_t zt_event_id = 0; zt_event_t zt_event_id = 0;
ftdm_span_t *span = ftdmchan->span; ftdm_span_t *span = ftdmchan->span;
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) { if (ftdm_test_io_flag(ftdmchan, FTDM_CHANNEL_IO_EVENT)) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT); ftdm_clear_io_flag(ftdmchan, FTDM_CHANNEL_IO_EVENT);
} }
if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) { 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++) { for(i = 1; i <= span->chan_count; i++) {
ftdm_channel_t *fchan = span->channels[i]; ftdm_channel_t *fchan = span->channels[i];
if (ftdm_test_flag(fchan, FTDM_CHANNEL_EVENT)) { if (ftdm_test_io_flag(fchan, FTDM_CHANNEL_IO_EVENT)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_EVENT); ftdm_clear_io_flag(fchan, FTDM_CHANNEL_IO_EVENT);
if (ioctl(fchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) { if (ioctl(fchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno)); snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
return FTDM_FAIL; return FTDM_FAIL;

View File

@ -30,9 +30,10 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* Contributors: * Contributors:
* *
* Moises Silva <moy@sangoma.com> * 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" #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) 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 */ /*! \brief Digit limit used in DNIS/ANI */
#define FTDM_DIGITS_LIMIT 25 #define FTDM_DIGITS_LIMIT 25
@ -436,13 +450,14 @@ typedef enum {
FTDM_SIGEVENT_TRACE, /*!<Interpreted trace event */ FTDM_SIGEVENT_TRACE, /*!<Interpreted trace event */
FTDM_SIGEVENT_TRACE_RAW, /*!<Raw trace event */ FTDM_SIGEVENT_TRACE_RAW, /*!<Raw trace event */
FTDM_SIGEVENT_INDICATION_COMPLETED, /*!< Last requested indication was completed */ 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_SIGEVENT_INVALID, /*!<Invalid */
} ftdm_signal_event_t; } ftdm_signal_event_t;
#define SIGNAL_STRINGS "START", "STOP", "RELEASED", "UP", "FLASH", "PROCEED", "RINGING", "PROGRESS", \ #define SIGNAL_STRINGS "START", "STOP", "RELEASED", "UP", "FLASH", "PROCEED", "RINGING", "PROGRESS", \
"PROGRESS_MEDIA", "ALARM_TRAP", "ALARM_CLEAR", \ "PROGRESS_MEDIA", "ALARM_TRAP", "ALARM_CLEAR", \
"COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGSTATUS_CHANGED", "FACILITY", \ "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 */ /*! \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) 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 */ /* Using this indication is equivalent to call ftdm_channel_call_answer API */
FTDM_CHANNEL_INDICATE_ANSWER, FTDM_CHANNEL_INDICATE_ANSWER,
FTDM_CHANNEL_INDICATE_FACILITY, FTDM_CHANNEL_INDICATE_FACILITY,
FTDM_CHANNEL_INDICATE_TRANSFER,
FTDM_CHANNEL_INDICATE_INVALID, FTDM_CHANNEL_INDICATE_INVALID,
} ftdm_channel_indication_t; } 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 */ /*! \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 { typedef struct {
/* The indication that was completed */ /* The indication that was completed */
@ -559,6 +575,10 @@ typedef struct {
ftdm_status_t status; ftdm_status_t status;
} ftdm_event_indication_completed_t; } ftdm_event_indication_completed_t;
typedef struct {
ftdm_transfer_response_t response;
} ftdm_event_transfer_completed_t;
typedef void * ftdm_variable_container_t; typedef void * ftdm_variable_container_t;
typedef struct { 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_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_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_indication_completed_t indication_completed; /*!< valid if the event_id is FTDM_SIGEVENT_INDICATION_COMPLETED */
ftdm_event_transfer_completed_t transfer_completed;
} ev_data; } ev_data;
ftdm_raw_data_t raw; 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(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)) #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 * \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); 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) */ /*! \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); 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 */ /*! \brief Reset the channel */
#define ftdm_channel_reset(ftdmchan) _ftdm_channel_reset(__FILE__, __FUNCTION__, __LINE__, (ftdmchan), NULL) #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) #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 */ /*! \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); 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 * \brief Retrieves an event from the span
* *
* \note * \note

View File

@ -155,6 +155,10 @@ extern "C" {
#define ftdm_clear_alarm_flag(obj, flag) (obj)->alarm_flags &= ~(flag) #define ftdm_clear_alarm_flag(obj, flag) (obj)->alarm_flags &= ~(flag)
#define ftdm_test_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 \brief Set a flag on an arbitrary object
\command obj the object to set the flags on \command obj the object to set the flags on
@ -399,6 +403,7 @@ struct ftdm_channel {
uint64_t flags; uint64_t flags;
uint32_t pflags; uint32_t pflags;
uint32_t sflags; uint32_t sflags;
uint8_t io_flags;
ftdm_alarm_flag_t alarm_flags; ftdm_alarm_flag_t alarm_flags;
ftdm_channel_feature_t features; ftdm_channel_feature_t features;
ftdm_codec_t effective_codec; ftdm_codec_t effective_codec;
@ -503,6 +508,7 @@ struct ftdm_span {
ftdm_span_stop_t stop; ftdm_span_stop_t stop;
ftdm_channel_sig_read_t sig_read; ftdm_channel_sig_read_t sig_read;
ftdm_channel_sig_write_t sig_write; 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 */ 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 */ void *io_data; /*!< Private I/O data per span. Do not touch unless you are an I/O module */
char *type; 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_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 * \brief Retrieves an event from the span

View File

@ -67,6 +67,7 @@ typedef enum {
FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS,
FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_UP,
FTDM_CHANNEL_STATE_TRANSFER,
FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_IDLE,
FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_TERMINATING,
FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_CANCEL,
@ -78,7 +79,7 @@ typedef enum {
} ftdm_channel_state_t; } ftdm_channel_state_t;
#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \ #define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \
"RING", "RINGING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \ "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" "HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "RESET", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t) FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t)

View File

@ -189,6 +189,8 @@ typedef enum {
/* If this flag is set, then this span cannot be stopped individually, it can only be stopped /* If this flag is set, then this span cannot be stopped individually, it can only be stopped
on freetdm unload */ on freetdm unload */
FTDM_SPAN_NON_STOPPABLE = (1 << 13), 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; } ftdm_span_flag_t;
/*! \brief Channel supported features */ /*! \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_MF_GENERATE = (1<<10), /*!< Channel can generate R2 MF tones (read-only) */
} ftdm_channel_feature_t; } 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 */ /*!< 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_CONFIGURED (1ULL << 0)
#define FTDM_CHANNEL_READY (1ULL << 1) #define FTDM_CHANNEL_READY (1ULL << 1)
@ -214,7 +223,6 @@ typedef enum {
#define FTDM_CHANNEL_SUPRESS_DTMF (1ULL << 4) #define FTDM_CHANNEL_SUPRESS_DTMF (1ULL << 4)
#define FTDM_CHANNEL_TRANSCODE (1ULL << 5) #define FTDM_CHANNEL_TRANSCODE (1ULL << 5)
#define FTDM_CHANNEL_BUFFER (1ULL << 6) #define FTDM_CHANNEL_BUFFER (1ULL << 6)
#define FTDM_CHANNEL_EVENT (1ULL << 7)
#define FTDM_CHANNEL_INTHREAD (1ULL << 8) #define FTDM_CHANNEL_INTHREAD (1ULL << 8)
#define FTDM_CHANNEL_WINK (1ULL << 9) #define FTDM_CHANNEL_WINK (1ULL << 9)
#define FTDM_CHANNEL_FLASH (1ULL << 10) #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_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_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_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 { typedef enum {
FTDM_ITERATOR_VARS = 1, FTDM_ITERATOR_VARS = 1,
FTDM_ITERATOR_CHANS, FTDM_ITERATOR_CHANS,
} ftdm_iterator_type_t; } ftdm_iterator_type_t;
struct ftdm_iterator { struct ftdm_iterator {