freetdm: Added Analog E&M outbound call answer supervision
You must add answer-supervision=yes in your freetdm.conf.xml Also added dial-timeout parameter which was previously hard-coded
This commit is contained in:
parent
59f44b6055
commit
2b4aa48049
|
@ -3775,11 +3775,14 @@ static switch_status_t load_config(void)
|
||||||
const char *dialplan = "XML";
|
const char *dialplan = "XML";
|
||||||
const char *tonegroup = NULL;
|
const char *tonegroup = NULL;
|
||||||
char *digit_timeout = NULL;
|
char *digit_timeout = NULL;
|
||||||
|
char *dial_timeout = NULL;
|
||||||
char *max_digits = NULL;
|
char *max_digits = NULL;
|
||||||
char *dial_regex = NULL;
|
char *dial_regex = NULL;
|
||||||
char *hold_music = NULL;
|
char *hold_music = NULL;
|
||||||
char *fail_dial_regex = NULL;
|
char *fail_dial_regex = NULL;
|
||||||
uint32_t span_id = 0, to = 0, max = 0;
|
char str_false[] = "false";
|
||||||
|
char *answer_supervision = str_false;
|
||||||
|
uint32_t span_id = 0, to = 0, max = 0, dial_timeout_int = 0;
|
||||||
ftdm_span_t *span = NULL;
|
ftdm_span_t *span = NULL;
|
||||||
analog_option_t analog_options = ANALOG_OPTION_NONE;
|
analog_option_t analog_options = ANALOG_OPTION_NONE;
|
||||||
|
|
||||||
|
@ -3791,6 +3794,8 @@ static switch_status_t load_config(void)
|
||||||
tonegroup = val;
|
tonegroup = val;
|
||||||
} else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
|
} else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
|
||||||
digit_timeout = val;
|
digit_timeout = val;
|
||||||
|
} else if (!strcasecmp(var, "dial-timeout")) {
|
||||||
|
dial_timeout = val;
|
||||||
} else if (!strcasecmp(var, "context")) {
|
} else if (!strcasecmp(var, "context")) {
|
||||||
context = val;
|
context = val;
|
||||||
} else if (!strcasecmp(var, "dialplan")) {
|
} else if (!strcasecmp(var, "dialplan")) {
|
||||||
|
@ -3803,6 +3808,8 @@ static switch_status_t load_config(void)
|
||||||
hold_music = val;
|
hold_music = val;
|
||||||
} else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
|
} else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
|
||||||
max_digits = val;
|
max_digits = val;
|
||||||
|
} else if (!strcasecmp(var, "answer-supervision")) {
|
||||||
|
answer_supervision = val;
|
||||||
} else if (!strcasecmp(var, "enable-analog-option")) {
|
} else if (!strcasecmp(var, "enable-analog-option")) {
|
||||||
analog_options = enable_analog_option(val, analog_options);
|
analog_options = enable_analog_option(val, analog_options);
|
||||||
}
|
}
|
||||||
|
@ -3821,6 +3828,10 @@ static switch_status_t load_config(void)
|
||||||
to = atoi(digit_timeout);
|
to = atoi(digit_timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dial_timeout) {
|
||||||
|
dial_timeout_int = atoi(dial_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
if (max_digits) {
|
if (max_digits) {
|
||||||
max = atoi(max_digits);
|
max = atoi(max_digits);
|
||||||
}
|
}
|
||||||
|
@ -3851,7 +3862,9 @@ static switch_status_t load_config(void)
|
||||||
|
|
||||||
if (ftdm_configure_span(span, "analog_em", on_analog_signal,
|
if (ftdm_configure_span(span, "analog_em", on_analog_signal,
|
||||||
"tonemap", tonegroup,
|
"tonemap", tonegroup,
|
||||||
|
"answer_supervision", answer_supervision,
|
||||||
"digit_timeout", &to,
|
"digit_timeout", &to,
|
||||||
|
"dial_timeout", &dial_timeout_int,
|
||||||
"max_dialstr", &max,
|
"max_dialstr", &max,
|
||||||
FTDM_TAG_END) != FTDM_SUCCESS) {
|
FTDM_TAG_END) != FTDM_SUCCESS) {
|
||||||
LOAD_ERROR("Error starting FreeTDM span %d\n", span_id);
|
LOAD_ERROR("Error starting FreeTDM span %d\n", span_id);
|
||||||
|
|
|
@ -51,6 +51,8 @@ struct ftdm_analog_data {
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
uint32_t max_dialstr;
|
uint32_t max_dialstr;
|
||||||
uint32_t digit_timeout;
|
uint32_t digit_timeout;
|
||||||
|
uint32_t dial_timeout;
|
||||||
|
ftdm_bool_t answer_supervision;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void *ftdm_analog_em_run(ftdm_thread_t *me, void *obj);
|
static void *ftdm_analog_em_run(ftdm_thread_t *me, void *obj);
|
||||||
|
|
|
@ -120,8 +120,10 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
|
||||||
{
|
{
|
||||||
ftdm_analog_em_data_t *analog_data;
|
ftdm_analog_em_data_t *analog_data;
|
||||||
const char *tonemap = "us";
|
const char *tonemap = "us";
|
||||||
uint32_t digit_timeout = 10;
|
uint32_t digit_timeout = 2000;
|
||||||
uint32_t max_dialstr = 11;
|
uint32_t max_dialstr = 11;
|
||||||
|
uint32_t dial_timeout = 0;
|
||||||
|
ftdm_bool_t answer_supervision = FTDM_FALSE;
|
||||||
const char *var, *val;
|
const char *var, *val;
|
||||||
int *intval;
|
int *intval;
|
||||||
|
|
||||||
|
@ -137,11 +139,22 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
|
||||||
memset(analog_data, 0, sizeof(*analog_data));
|
memset(analog_data, 0, sizeof(*analog_data));
|
||||||
|
|
||||||
while((var = va_arg(ap, char *))) {
|
while((var = va_arg(ap, char *))) {
|
||||||
|
ftdm_log(FTDM_LOG_DEBUG, "Parsing analog em parameter '%s'\n", var);
|
||||||
if (!strcasecmp(var, "tonemap")) {
|
if (!strcasecmp(var, "tonemap")) {
|
||||||
if (!(val = va_arg(ap, char *))) {
|
if (!(val = va_arg(ap, char *))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tonemap = val;
|
tonemap = val;
|
||||||
|
} else if (!strcasecmp(var, "answer_supervision")) {
|
||||||
|
if (!(val = va_arg(ap, char *))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
answer_supervision = ftdm_true(val);
|
||||||
|
} else if (!strcasecmp(var, "dial_timeout")) {
|
||||||
|
if (!(intval = va_arg(ap, int *))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dial_timeout = *intval;
|
||||||
} else if (!strcasecmp(var, "digit_timeout")) {
|
} else if (!strcasecmp(var, "digit_timeout")) {
|
||||||
if (!(intval = va_arg(ap, int *))) {
|
if (!(intval = va_arg(ap, int *))) {
|
||||||
break;
|
break;
|
||||||
|
@ -153,7 +166,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
|
||||||
}
|
}
|
||||||
max_dialstr = *intval;
|
max_dialstr = *intval;
|
||||||
} else {
|
} else {
|
||||||
snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
|
ftdm_log(FTDM_LOG_ERROR, "Invalid parameter for analog em span: '%s'\n", var);
|
||||||
return FTDM_FAIL;
|
return FTDM_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,6 +184,8 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
|
||||||
span->start = ftdm_analog_em_start;
|
span->start = ftdm_analog_em_start;
|
||||||
analog_data->digit_timeout = digit_timeout;
|
analog_data->digit_timeout = digit_timeout;
|
||||||
analog_data->max_dialstr = max_dialstr;
|
analog_data->max_dialstr = max_dialstr;
|
||||||
|
analog_data->dial_timeout = dial_timeout;
|
||||||
|
analog_data->answer_supervision = answer_supervision;
|
||||||
span->signal_cb = sig_cb;
|
span->signal_cb = sig_cb;
|
||||||
span->signal_type = FTDM_SIGTYPE_ANALOG;
|
span->signal_type = FTDM_SIGTYPE_ANALOG;
|
||||||
span->signal_data = analog_data;
|
span->signal_data = analog_data;
|
||||||
|
@ -221,6 +236,9 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||||
ftdm_channel_t *closed_chan;
|
ftdm_channel_t *closed_chan;
|
||||||
uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
|
uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
|
||||||
ftdm_sigmsg_t sig;
|
ftdm_sigmsg_t sig;
|
||||||
|
int cas_bits = 0;
|
||||||
|
uint32_t cas_answer = 0;
|
||||||
|
int cas_answer_ms = 500;
|
||||||
|
|
||||||
ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM CHANNEL thread starting.\n");
|
ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM CHANNEL thread starting.\n");
|
||||||
|
|
||||||
|
@ -259,6 +277,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||||
sig.channel = ftdmchan;
|
sig.channel = ftdmchan;
|
||||||
|
|
||||||
assert(interval != 0);
|
assert(interval != 0);
|
||||||
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "IO Interval: %u\n", interval);
|
||||||
|
|
||||||
while (ftdm_running() && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
|
while (ftdm_running() && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
|
||||||
ftdm_wait_flag_t flags = FTDM_READ;
|
ftdm_wait_flag_t flags = FTDM_READ;
|
||||||
|
@ -266,7 +285,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||||
|
|
||||||
elapsed += interval;
|
elapsed += interval;
|
||||||
state_counter += interval;
|
state_counter += interval;
|
||||||
|
|
||||||
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
||||||
switch(ftdmchan->state) {
|
switch(ftdmchan->state) {
|
||||||
case FTDM_CHANNEL_STATE_DIALING:
|
case FTDM_CHANNEL_STATE_DIALING:
|
||||||
|
@ -288,6 +307,11 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||||
ftdmchan->needed_tones[FTDM_TONEMAP_FAIL2] = 1;
|
ftdmchan->needed_tones[FTDM_TONEMAP_FAIL2] = 1;
|
||||||
ftdmchan->needed_tones[FTDM_TONEMAP_FAIL3] = 1;
|
ftdmchan->needed_tones[FTDM_TONEMAP_FAIL3] = 1;
|
||||||
dial_timeout = ((ftdmchan->dtmf_on + ftdmchan->dtmf_off) * strlen(ftdmchan->caller_data.dnis.digits)) + 2000;
|
dial_timeout = ((ftdmchan->dtmf_on + ftdmchan->dtmf_off) * strlen(ftdmchan->caller_data.dnis.digits)) + 2000;
|
||||||
|
if (analog_data->dial_timeout) {
|
||||||
|
dial_timeout += analog_data->dial_timeout;
|
||||||
|
}
|
||||||
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Outbound dialing timeout: %dms\n", dial_timeout);
|
||||||
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Outbound CAS answer timeout: %dms\n", cas_answer_ms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -295,10 +319,25 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||||
if (state_counter > dial_timeout) {
|
if (state_counter > dial_timeout) {
|
||||||
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
|
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
|
||||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
|
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
|
||||||
} else {
|
} else if (!analog_data->answer_supervision) {
|
||||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
|
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cas_bits = 0;
|
||||||
|
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_CAS_BITS, &cas_bits);
|
||||||
|
if (!(state_counter % 1000)) {
|
||||||
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "CAS bits: 0x%X\n", cas_bits);
|
||||||
|
}
|
||||||
|
if (cas_bits == 0xF) {
|
||||||
|
cas_answer += interval;
|
||||||
|
if (cas_answer >= cas_answer_ms) {
|
||||||
|
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Answering on CAS answer signal persistence!\n");
|
||||||
|
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
|
||||||
|
}
|
||||||
|
} else if (cas_answer) {
|
||||||
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Resetting cas answer to 0: 0x%X!\n", cas_bits);
|
||||||
|
cas_answer = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FTDM_CHANNEL_STATE_DIALTONE:
|
case FTDM_CHANNEL_STATE_DIALTONE:
|
||||||
|
@ -515,7 +554,11 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||||
ftdm_log(FTDM_LOG_ERROR, "Failure indication detected!\n");
|
ftdm_log(FTDM_LOG_ERROR, "Failure indication detected!\n");
|
||||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
|
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
|
||||||
} else if (ftdmchan->detected_tones[FTDM_TONEMAP_RING]) {
|
} else if (ftdmchan->detected_tones[FTDM_TONEMAP_RING]) {
|
||||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
|
if (!analog_data->answer_supervision) {
|
||||||
|
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
|
||||||
|
} else {
|
||||||
|
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ringing, but not answering since answer supervision is enabled\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ftdm_channel_clear_detected_tones(ftdmchan);
|
ftdm_channel_clear_detected_tones(ftdmchan);
|
||||||
|
@ -617,7 +660,9 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
|
||||||
case FTDM_OOB_OFFHOOK:
|
case FTDM_OOB_OFFHOOK:
|
||||||
{
|
{
|
||||||
if (ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD)) {
|
if (ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD)) {
|
||||||
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
|
if (event->channel->state < FTDM_CHANNEL_STATE_UP) {
|
||||||
|
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
|
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
|
||||||
ftdm_mutex_unlock(event->channel->mutex);
|
ftdm_mutex_unlock(event->channel->mutex);
|
||||||
|
|
|
@ -1098,6 +1098,7 @@ static __inline__ int handle_dtmf_event(ftdm_channel_t *fchan, zt_event_t zt_eve
|
||||||
*/
|
*/
|
||||||
static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan, ftdm_oob_event_t *event_id, zt_event_t zt_event_id)
|
static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan, ftdm_oob_event_t *event_id, zt_event_t zt_event_id)
|
||||||
{
|
{
|
||||||
|
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Processing zap hardware event %d\n", zt_event_id);
|
||||||
switch(zt_event_id) {
|
switch(zt_event_id) {
|
||||||
case ZT_EVENT_RINGEROFF:
|
case ZT_EVENT_RINGEROFF:
|
||||||
{
|
{
|
||||||
|
@ -1132,16 +1133,30 @@ static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan,
|
||||||
break;
|
break;
|
||||||
case ZT_EVENT_RINGOFFHOOK:
|
case ZT_EVENT_RINGOFFHOOK:
|
||||||
{
|
{
|
||||||
|
*event_id = FTDM_OOB_NOOP;
|
||||||
if (fchan->type == FTDM_CHAN_TYPE_FXS || (fchan->type == FTDM_CHAN_TYPE_EM && fchan->state != FTDM_CHANNEL_STATE_UP)) {
|
if (fchan->type == FTDM_CHAN_TYPE_FXS || (fchan->type == FTDM_CHAN_TYPE_EM && fchan->state != FTDM_CHANNEL_STATE_UP)) {
|
||||||
if (fchan->type != FTDM_CHAN_TYPE_EM) {
|
if (fchan->type != FTDM_CHAN_TYPE_EM) {
|
||||||
/* In E&M we're supposed to set this flag when the tx side goes offhook, not the rx */
|
/* In E&M we're supposed to set this flag only when the local side goes offhook, not the remote */
|
||||||
ftdm_set_flag_locked(fchan, FTDM_CHANNEL_OFFHOOK);
|
ftdm_set_flag_locked(fchan, FTDM_CHANNEL_OFFHOOK);
|
||||||
}
|
}
|
||||||
*event_id = FTDM_OOB_OFFHOOK;
|
|
||||||
|
/* For E&M let's count the ring count (it seems sometimes we receive RINGOFFHOOK once before the other end
|
||||||
|
* answers, then another RINGOFFHOOK when the other end answers?? anyways, now we count rings before delivering the
|
||||||
|
* offhook event ... the E&M signaling code in ftmod_analog_em also polls the RBS bits looking for answer, just to
|
||||||
|
* be safe and not rely on this event, so even if this event does not arrive, when there is answer supervision
|
||||||
|
* the analog signaling code should detect the cas persistance pattern and answer */
|
||||||
|
if (fchan->type == FTDM_CHAN_TYPE_EM && ftdm_test_flag(fchan, FTDM_CHANNEL_OUTBOUND)) {
|
||||||
|
fchan->ring_count++;
|
||||||
|
/* perhaps some day we'll make this configurable, but since I am not even sure what the hell is going on
|
||||||
|
* no point in making a configuration option for something that may not be technically correct */
|
||||||
|
if (fchan->ring_count == 2) {
|
||||||
|
*event_id = FTDM_OOB_OFFHOOK;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*event_id = FTDM_OOB_OFFHOOK;
|
||||||
|
}
|
||||||
} else if (fchan->type == FTDM_CHAN_TYPE_FXO) {
|
} else if (fchan->type == FTDM_CHAN_TYPE_FXO) {
|
||||||
*event_id = FTDM_OOB_RING_START;
|
*event_id = FTDM_OOB_RING_START;
|
||||||
} else {
|
|
||||||
*event_id = FTDM_OOB_NOOP;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
!strcasecmp(expr, "true") || \
|
!strcasecmp(expr, "true") || \
|
||||||
!strcasecmp(expr, "enabled") || \
|
!strcasecmp(expr, "enabled") || \
|
||||||
!strcasecmp(expr, "active") || \
|
!strcasecmp(expr, "active") || \
|
||||||
atoi(expr))) ? 1 : 0
|
atoi(expr))) ? FTDM_TRUE : FTDM_FALSE
|
||||||
|
|
||||||
#ifdef WIN32_LEAN_AND_MEAN
|
#ifdef WIN32_LEAN_AND_MEAN
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
|
Loading…
Reference in New Issue