Merge branch 'v1.2.stable' of ssh://git.freeswitch.org:222/freeswitch into v1.2.stable

This commit is contained in:
Michael S Collins 2012-12-28 16:17:59 -08:00
commit e04eab7902
5 changed files with 112 additions and 18 deletions

View File

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

View File

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

View File

@ -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,10 @@ 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_bool_t digits_sent = FTDM_FALSE;
ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM CHANNEL thread starting.\n"); ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM CHANNEL thread starting.\n");
@ -259,13 +278,12 @@ 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;
ftdm_size_t dlen = 0; ftdm_size_t dlen = 0;
len = sizeof(frame);
elapsed += interval; elapsed += interval;
state_counter += interval; state_counter += interval;
@ -274,7 +292,8 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
case FTDM_CHANNEL_STATE_DIALING: case FTDM_CHANNEL_STATE_DIALING:
{ {
if (! ftdmchan->needed_tones[FTDM_TONEMAP_RING] if (! ftdmchan->needed_tones[FTDM_TONEMAP_RING]
&& ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) { && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)
&& !digits_sent) {
if (ftdm_strlen_zero(ftdmchan->caller_data.dnis.digits)) { if (ftdm_strlen_zero(ftdmchan->caller_data.dnis.digits)) {
ftdm_log(FTDM_LOG_ERROR, "No Digits to send!\n"); ftdm_log(FTDM_LOG_ERROR, "No Digits to send!\n");
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
@ -284,12 +303,18 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
} else { } else {
state_counter = 0; state_counter = 0;
digits_sent = FTDM_TRUE;
ftdmchan->needed_tones[FTDM_TONEMAP_RING] = 1; ftdmchan->needed_tones[FTDM_TONEMAP_RING] = 1;
ftdmchan->needed_tones[FTDM_TONEMAP_BUSY] = 1; ftdmchan->needed_tones[FTDM_TONEMAP_BUSY] = 1;
ftdmchan->needed_tones[FTDM_TONEMAP_FAIL1] = 1; ftdmchan->needed_tones[FTDM_TONEMAP_FAIL1] = 1;
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;
@ -297,10 +322,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:
@ -488,11 +528,17 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
continue; continue;
} }
len = sizeof(frame);
if (ftdm_channel_read(ftdmchan, frame, &len) != FTDM_SUCCESS) { if (ftdm_channel_read(ftdmchan, frame, &len) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "READ ERROR [%s]\n", ftdmchan->last_error); ftdm_log(FTDM_LOG_ERROR, "READ ERROR [%s]\n", ftdmchan->last_error);
goto done; goto done;
} }
if (0 == len) {
ftdm_log(FTDM_LOG_DEBUG, "Nothing read\n");
continue;
}
if (ftdmchan->detected_tones[0]) { if (ftdmchan->detected_tones[0]) {
int i; int i;
@ -511,7 +557,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]) {
if (!analog_data->answer_supervision) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP); 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);
@ -613,7 +663,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)) {
if (event->channel->state < FTDM_CHANNEL_STATE_UP) {
ftdm_set_state_locked(event->channel, 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);

View File

@ -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);
} }
/* 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; *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;
@ -1309,8 +1324,20 @@ static FIO_READ_FUNCTION(zt_read)
else { else {
if (errno == EAGAIN || errno == EINTR) if (errno == EAGAIN || errno == EINTR)
continue; continue;
if (errno == ELAST) if (errno == ELAST) {
zt_event_t zt_event_id = 0;
if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event after ELAST on read: %s\n", strerror(errno));
r = -1;
break; break;
}
if (handle_dtmf_event(ftdmchan, zt_event_id)) {
/* we should enqueue this event somewhere so it can be retrieved by the user, for now, dropping it to see what it is! */
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dropping event %d to be able to read data\n", zt_event_id);
}
continue;
}
ftdm_log(FTDM_LOG_ERROR, "read failed: %s\n", strerror(errno)); ftdm_log(FTDM_LOG_ERROR, "read failed: %s\n", strerror(errno));
} }

View File

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