]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Added detection DTMF CID without polarity change alert.
authorDoug Bailey <dbailey@digium.com>
Thu, 3 Sep 2009 19:40:37 +0000 (19:40 +0000)
committerDoug Bailey <dbailey@digium.com>
Thu, 3 Sep 2009 19:40:37 +0000 (19:40 +0000)
Added detection of DTMF tone energy levels on FXO channels in chan_dahdi
monitoring loop so DTMF CID can be detected without the need of a polarity
change precursor.

(closes issue #9096)
Reported by: fleed
Patches:
      9096-chan_dahdi-trunk.diff uploaded by dbailey (license 819)
Tested by: cyberplant, sum, maturs

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@216094 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_dahdi.c
channels/sig_analog.c
channels/sig_analog.h
include/asterisk/callerid.h

index 7f4c7f6d1aa140c16f6a1a9e76b5bad0a09b7619..e6e83ed31efedb61cbd511aa731c804bcecf83d6 100644 (file)
@@ -416,6 +416,7 @@ static int distinctiveringaftercid = 0;
 static int numbufs = 4;
 
 static int mwilevel = 512;
+static int dtmfcid_level = 256;
 
 #ifdef HAVE_PRI
 #ifdef PRI_GETSET_TIMERS
@@ -1081,7 +1082,9 @@ static struct dahdi_pvt {
        int span;                                       /*!< Span number */
        time_t guardtime;                               /*!< Must wait this much time before using for new call */
        int cid_signalling;                             /*!< CID signalling type bell202 or v23 */
-       int cid_start;                                  /*!< CID start indicator, polarity or ring */
+       int cid_start;                                  /*!< CID start indicator, polarity or ring or DTMF without warning event */
+       int dtmfcid_holdoff_state;              /*!< State indicator that allows for line to settle before checking for dtmf energy */
+       struct timeval  dtmfcid_delay;  /*!< Time value used for allow line to settle */
        int callingpres;                                /*!< The value of calling presentation that we're going to use when placing a PRI call */
        int callwaitingrepeat;                          /*!< How many samples to wait before repeating call waiting */
        int cidcwexpire;                                /*!< When to expire our muting for CID/CW */
@@ -8924,7 +8927,8 @@ static void *analog_ss_thread(void *data)
                /* If we want caller id, we're in a prering state due to a polarity reversal
                 * and we're set to use a polarity reversal to trigger the start of caller id,
                 * grab the caller id and wait for ringing to start... */
-               } else if (p->use_callerid && (chan->_state == AST_STATE_PRERING && (p->cid_start == CID_START_POLARITY || p->cid_start == CID_START_POLARITY_IN))) {
+               } else if (p->use_callerid && (chan->_state == AST_STATE_PRERING &&
+                                                (p->cid_start == CID_START_POLARITY || p->cid_start == CID_START_POLARITY_IN || p->cid_start == CID_START_DTMF_NOALERT))) {
                        /* If set to use DTMF CID signalling, listen for DTMF */
                        if (p->cid_signalling == CID_SIG_DTMF) {
                                int k = 0;
@@ -10082,8 +10086,10 @@ static void *do_monitor(void *data)
                                                pfds[count].events = POLLPRI;
                                                pfds[count].revents = 0;
                                                /* Message waiting or r2 channels also get watched for reading */
-                                               if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk)
+                                               if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk || 
+                                                       (i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
                                                        pfds[count].events |= POLLIN;
+                                               }
                                                count++;
                                        }
                                } else {
@@ -10094,8 +10100,10 @@ static void *do_monitor(void *data)
                                                pfds[count].revents = 0;
                                                /* If we are monitoring for VMWI or sending CID, we need to
                                                   read from the channel as well */
-                                               if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk)
+                                               if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk ||
+                                                       (i->cid_start == CID_START_DTMF_NOALERT && (i->sig == SIG_FXSLS || i->sig == SIG_FXSGS || i->sig == SIG_FXSKS))) {
                                                        pfds[count].events |= POLLIN;
+                                               }
                                                count++;
                                        }
                                }
@@ -10185,7 +10193,7 @@ static void *do_monitor(void *data)
                                                i = i->next;
                                                continue;
                                        }
-                                       if (!i->mwimonitor_fsk && !i->mwisendactive) {
+                                       if (!i->mwimonitor_fsk && !i->mwisendactive  && i->cid_start != CID_START_DTMF_NOALERT) {
                                                ast_log(LOG_WARNING, "Whoa....  I'm not looking for MWI or sending MWI but am reading (%d)...\n", i->subs[SUB_REAL].dfd);
                                                i = i->next;
                                                continue;
@@ -10213,6 +10221,50 @@ static void *do_monitor(void *data)
                                                                        i->mwimonitoractive = 1;
                                                                }
                                                        }
+                                               /* If configured to check for a DTMF CID spill that comes without alert (e.g no polarity reversal) */
+                                               } else if (i->cid_start == CID_START_DTMF_NOALERT) {
+                                                       int energy;
+                                                       struct timeval now;
+                                                       /* State machine dtmfcid_holdoff_state allows for the line to settle
+                                                        * before checking agin for dtmf energy.  Presently waits for 500 mS before checking again 
+                                                       */
+                                                       if (1 == i->dtmfcid_holdoff_state) {
+                                                               gettimeofday(&i->dtmfcid_delay, NULL);
+                                                               i->dtmfcid_holdoff_state = 2;
+                                                       } else if (2 == i->dtmfcid_holdoff_state) {
+                                                               gettimeofday(&now, NULL);
+                                                               if ((int)(now.tv_sec - i->dtmfcid_delay.tv_sec) * 1000000 + (int)now.tv_usec - (int)i->dtmfcid_delay.tv_usec > 500000) {
+                                                                       i->dtmfcid_holdoff_state = 0;
+                                                               }
+                                                       } else {
+                                                               energy = calc_energy((unsigned char *) buf, res, AST_LAW(i));
+                                                               if (!i->mwisendactive && energy > dtmfcid_level) {
+                                                                       pthread_t threadid;
+                                                                       struct ast_channel *chan;
+                                                                       ast_mutex_unlock(&iflock);
+                                                                       if (analog_lib_handles(i->sig, i->radio, i->oprmode)) {
+                                                                               res = analog_handle_init_event(i->sig_pvt, ANALOG_EVENT_DTMFCID);  
+                                                                               if (res) {
+                                                                                       ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
+                                                                               } else {
+                                                                                       i->dtmfcid_holdoff_state = 1;
+                                                                               }
+                                                                       } else {
+                                                                               chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, 0, NULL);
+                                                                               if (!chan) {
+                                                                                       ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
+                                                                               } else {
+                                                                                       res = ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan);
+                                                                                       if (res) {
+                                                                                               ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
+                                                                                       } else {
+                                                                                               i->dtmfcid_holdoff_state = 1;
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                                       ast_mutex_lock(&iflock);
+                                                               }
+                                                       }
                                                }
                                                if (i->mwisendactive) {
                                                        mwi_send_process_buffer(i, res);
@@ -11191,7 +11243,19 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                                analog_p->echotraining = conf->chan.echotraining;
                                analog_p->cid_signalling = conf->chan.cid_signalling;
                                analog_p->stripmsd = conf->chan.stripmsd;
-                               analog_p->cid_start = ANALOG_CID_START_RING;
+                               switch (conf->chan.cid_start) {
+                                       case CID_START_POLARITY:
+                                               analog_p->cid_start = ANALOG_CID_START_POLARITY;
+                                               break;
+                                       case CID_START_POLARITY_IN:
+                                               analog_p->cid_start = ANALOG_CID_START_POLARITY_IN;
+                                               break;
+                                       case CID_START_DTMF_NOALERT:
+                                               analog_p->cid_start = ANALOG_CID_START_DTMF_NOALERT;
+                                               break;
+                                       default:
+                                               analog_p->cid_start = ANALOG_CID_START_RING;
+                               }
                                analog_p->callwaitingcallerid = conf->chan.callwaitingcallerid;
                                analog_p->usedistinctiveringdetection = conf->chan.usedistinctiveringdetection;
                                analog_p->ringt = conf->chan.ringt;
@@ -15181,6 +15245,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
                                confp->chan.cid_start = CID_START_POLARITY_IN;
                        else if (!strcasecmp(v->value, "polarity"))
                                confp->chan.cid_start = CID_START_POLARITY;
+                       else if (!strcasecmp(v->value, "dtmf"))
+                               confp->chan.cid_start = CID_START_DTMF_NOALERT;
                        else if (ast_true(v->value))
                                confp->chan.cid_start = CID_START_RING;
                } else if (!strcasecmp(v->name, "threewaycalling")) {
@@ -16016,6 +16082,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
                                ast_copy_string(defaultozz, v->value, sizeof(defaultozz));
                        } else if (!strcasecmp(v->name, "mwilevel")) {
                                mwilevel = atoi(v->value);
+                       } else if (!strcasecmp(v->name, "dtmfcidlevel")) {
+                               dtmfcid_level = atoi(v->value);
                        }
                } else if (!(options & PROC_DAHDI_OPT_NOWARN) )
                        ast_log(LOG_WARNING, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
index ae6620f49db21bc6fca333af1eeecfc2cec833a0..2b4119fb7fce30377a64537c1dd22bd0d31a3f9e 100644 (file)
@@ -193,6 +193,8 @@ enum analog_cid_start analog_str_to_cidstart(const char *value)
                return ANALOG_CID_START_POLARITY;
        } else if (!strcasecmp(value, "polarity_in")) {
                return ANALOG_CID_START_POLARITY_IN;
+       } else if (!strcasecmp(value, "dtmf")) {
+               return ANALOG_CID_START_DTMF_NOALERT;
        }
 
        return 0;
@@ -207,6 +209,8 @@ const char *analog_cidstart_to_str(enum analog_cid_start cid_start)
                return "Polarity";
        case ANALOG_CID_START_POLARITY_IN:
                return "Polarity_In";
+       case ANALOG_CID_START_DTMF_NOALERT:
+               return "DTMF";
        }
 
        return "Unknown";
@@ -2032,7 +2036,8 @@ static void *__analog_ss_thread(void *data)
                /* If we want caller id, we're in a prering state due to a polarity reversal
                 * and we're set to use a polarity reversal to trigger the start of caller id,
                 * grab the caller id and wait for ringing to start... */
-               if (p->use_callerid && (chan->_state == AST_STATE_PRERING && (p->cid_start == ANALOG_CID_START_POLARITY || p->cid_start == ANALOG_CID_START_POLARITY_IN))) {
+               if (p->use_callerid && (chan->_state == AST_STATE_PRERING &&
+                                 (p->cid_start == ANALOG_CID_START_POLARITY || p->cid_start == ANALOG_CID_START_POLARITY_IN || p->cid_start == ANALOG_CID_START_DTMF_NOALERT))) {
                        /* If set to use DTMF CID signalling, listen for DTMF */
                        if (p->cid_signalling == CID_SIG_DTMF) {
                                int i = 0;
@@ -3239,7 +3244,7 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
                case ANALOG_SIG_SF_FEATB:
                case ANALOG_SIG_SF:
                        /* Check for callerid, digits, etc */
-                       if (i->cid_start == ANALOG_CID_START_POLARITY_IN) {
+                       if (i->cid_start == ANALOG_CID_START_POLARITY_IN || i->cid_start == ANALOG_CID_START_DTMF_NOALERT) {
                                chan = analog_new_ast_channel(i, AST_STATE_PRERING, 0, ANALOG_SUB_REAL, NULL);
                        } else {
                                chan = analog_new_ast_channel(i, AST_STATE_RING, 0, ANALOG_SUB_REAL, NULL);
@@ -3356,6 +3361,27 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
                                "interface %d\n", i->channel);
                }
                break;
+       case ANALOG_EVENT_DTMFCID:
+               switch (i->sig) {
+                       case ANALOG_SIG_FXSLS:
+                       case ANALOG_SIG_FXSKS:
+                       case ANALOG_SIG_FXSGS:
+                               if (i->cid_start == ANALOG_CID_START_DTMF_NOALERT) {
+                                       ast_verbose(VERBOSE_PREFIX_2 "Starting DTMF CID detection on channel %d\n",
+                                                               i->channel);
+                                       chan = analog_new_ast_channel(i, AST_STATE_PRERING, 0, ANALOG_SUB_REAL, NULL);
+                                       i->ss_astchan = chan;
+                                       if (chan && ast_pthread_create(&threadid, &attr, __analog_ss_thread, i)) {
+                                               ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
+                                       }
+                               }
+                               break;
+                       default:
+                               ast_log(LOG_WARNING, "handle_init_event detected "
+                                               "dtmfcid generation event on non-FXO (ANALOG_SIG_FXS) "
+                                                               "interface %d\n", i->channel);
+               }
+               break;
        case ANALOG_EVENT_NEONMWI_ACTIVE:
                analog_handle_notify_message(NULL, i, -1, ANALOG_EVENT_NEONMWI_ACTIVE);
                break;
index 381655021e97e90d5aaa7fd68780007fe9bc3141..b937ec665a6cfce898a03b06601f28f22a51a81a 100644 (file)
@@ -80,6 +80,7 @@ enum analog_event {
        ANALOG_EVENT_ERROR,
        ANALOG_EVENT_NEONMWI_ACTIVE,
        ANALOG_EVENT_NEONMWI_INACTIVE,
+       ANALOG_EVENT_DTMFCID,
 };
 
 enum analog_sub {
@@ -97,6 +98,7 @@ enum analog_cid_start {
        ANALOG_CID_START_POLARITY = 1,
        ANALOG_CID_START_POLARITY_IN,
        ANALOG_CID_START_RING,
+       ANALOG_CID_START_DTMF_NOALERT,
 };
 
 #define ANALOG_MAX_CID 300
@@ -187,6 +189,7 @@ struct analog_callback {
        void (* const decrease_ss_count)(void);
 
        int (* const distinctive_ring)(struct ast_channel *chan, void *pvt, int idx, int *ringdata);
+       /* Sets the specified sub-channel in and out of signed linear mode, returns the value that was overwritten */
        int (* const set_linear_mode)(void *pvt, int idx, int linear_mode);
        void (* const get_and_handle_alarms)(void *pvt);
        void * (* const get_sigpvt_bridged_channel)(struct ast_channel *chan);
index b8ff53cc16c9caef7aa6e38fb899fa287a6bc451..717248c12ce5dd37a6bdd24c72394cc7f2a135ea 100644 (file)
 #define CID_SIG_V23_JP 4
 #define CID_SIG_SMDI   5
 
-#define CID_START_RING 1
-#define CID_START_POLARITY 2
-#define CID_START_POLARITY_IN 3
+#define CID_START_RING                 1
+#define CID_START_POLARITY             2
+#define CID_START_POLARITY_IN  3
+#define CID_START_DTMF_NOALERT 4
 
 /* defines dealing with message waiting indication generation */
 /*! MWI SDMF format */