]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
freetdm: Added Analog E&M outbound call answer supervision
authorMoises Silva <moy@sangoma.com>
Wed, 19 Dec 2012 03:50:49 +0000 (22:50 -0500)
committerMoises Silva <moy@sangoma.com>
Wed, 19 Dec 2012 03:55:14 +0000 (22:55 -0500)
         You must add answer-supervision=yes in your freetdm.conf.xml
         Also added dial-timeout parameter which was previously hard-coded

libs/freetdm/mod_freetdm/mod_freetdm.c
libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h
libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c
libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c
libs/freetdm/src/include/private/ftdm_core.h

index 7ed8be290aa73e57489c280e8fb35c9cf449ae14..514fbcf5273f009cdcce4807491a9be8c7314816 100755 (executable)
@@ -3775,11 +3775,14 @@ static switch_status_t load_config(void)
                        const char *dialplan = "XML";
                        const char *tonegroup = NULL;
                        char *digit_timeout = NULL;
+                       char *dial_timeout = NULL;
                        char *max_digits = NULL;
                        char *dial_regex = NULL;
                        char *hold_music = 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;
                        analog_option_t analog_options = ANALOG_OPTION_NONE;
 
@@ -3791,6 +3794,8 @@ static switch_status_t load_config(void)
                                        tonegroup = val;
                                } else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
                                        digit_timeout = val;
+                               } else if (!strcasecmp(var, "dial-timeout")) {
+                                       dial_timeout = val;
                                } else if (!strcasecmp(var, "context")) {
                                        context = val;
                                } else if (!strcasecmp(var, "dialplan")) {
@@ -3803,6 +3808,8 @@ static switch_status_t load_config(void)
                                        hold_music = val;
                                } else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
                                        max_digits = val;
+                               } else if (!strcasecmp(var, "answer-supervision")) {
+                                       answer_supervision = val;
                                } else if (!strcasecmp(var, "enable-analog-option")) {
                                        analog_options = enable_analog_option(val, analog_options);
                                }
@@ -3821,6 +3828,10 @@ static switch_status_t load_config(void)
                                to = atoi(digit_timeout);
                        }
 
+                       if (dial_timeout) {
+                               dial_timeout_int = atoi(dial_timeout);
+                       }
+
                        if (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,
                                                                   "tonemap", tonegroup,
+                                                                  "answer_supervision", answer_supervision,
                                                                   "digit_timeout", &to,
+                                                                  "dial_timeout", &dial_timeout_int,
                                                                   "max_dialstr", &max,
                                                                   FTDM_TAG_END) != FTDM_SUCCESS) {
                                LOAD_ERROR("Error starting FreeTDM span %d\n", span_id);
index 22a1c251322c3b3be9099083adfc3729e8af7966..30c4877d26d84dce1ace056d50784aac254c4271 100644 (file)
@@ -51,6 +51,8 @@ struct ftdm_analog_data {
        uint32_t flags;
        uint32_t max_dialstr;
        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);
index 6888cbf8c5c8209bfe1cabf4b53657914dfc5c73..c073c5364e3e016b9fc5f6aa4ba7380fd800b863 100644 (file)
@@ -120,8 +120,10 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
 {
        ftdm_analog_em_data_t *analog_data;
        const char *tonemap = "us";
-       uint32_t digit_timeout = 10;
+       uint32_t digit_timeout = 2000;
        uint32_t max_dialstr = 11;
+       uint32_t dial_timeout = 0;
+       ftdm_bool_t answer_supervision = FTDM_FALSE;
        const char *var, *val;
        int *intval;
 
@@ -137,11 +139,22 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
        memset(analog_data, 0, sizeof(*analog_data));
 
        while((var = va_arg(ap, char *))) {
+               ftdm_log(FTDM_LOG_DEBUG, "Parsing analog em parameter '%s'\n", var);
                if (!strcasecmp(var, "tonemap")) {
                        if (!(val = va_arg(ap, char *))) {
                                break;
                        }
                        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")) {
                        if (!(intval = va_arg(ap, int *))) {
                                break;
@@ -153,7 +166,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
                        }
                        max_dialstr = *intval;
                } 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;
                }
        }
@@ -171,6 +184,8 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
        span->start = ftdm_analog_em_start;
        analog_data->digit_timeout = digit_timeout;
        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_type = FTDM_SIGTYPE_ANALOG;
        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;
        uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
        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");
 
@@ -259,6 +277,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
        sig.channel = ftdmchan;
        
        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)) {
                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;
                state_counter += interval;
-               
+
                if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
                        switch(ftdmchan->state) {
                        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_FAIL3] = 1;
                                                                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;
@@ -295,10 +319,25 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
                                        if (state_counter > dial_timeout) {
                                                if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
                                                        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);
+                                               }
+                                       }
+                                       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;
                        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_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
                        } 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);
@@ -617,7 +660,9 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
        case FTDM_OOB_OFFHOOK:
                {
                        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 {
                                ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
                                ftdm_mutex_unlock(event->channel->mutex);
index dc95c9ac088c1aec63a7efd957456363b21df864..c937c1bcd25231c2364ab91520ba29baf102d052 100644 (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)
 {
+       ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Processing zap hardware event %d\n", zt_event_id);
        switch(zt_event_id) {
        case ZT_EVENT_RINGEROFF:
                {
@@ -1132,16 +1133,30 @@ static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan,
                break;
        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_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);
                                }
-                               *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) {
                                *event_id = FTDM_OOB_RING_START;
-                       } else {
-                               *event_id = FTDM_OOB_NOOP;
                        }
                }
                break;
index e3780011834bb2c0a472fda27b0b43b20fe698eb..728390dd542d6a13239c9ed017ccd8be72c4a997 100644 (file)
@@ -92,7 +92,7 @@
                           !strcasecmp(expr, "true") ||         \
                           !strcasecmp(expr, "enabled") ||      \
                           !strcasecmp(expr, "active") ||       \
-                          atoi(expr))) ? 1 : 0
+                          atoi(expr))) ? FTDM_TRUE : FTDM_FALSE
 
 #ifdef WIN32_LEAN_AND_MEAN
 #include <winsock2.h>