Enable applications to enable/disable digit and tone detection.
authorKevin P. Fleming <kpfleming@digium.com>
Tue, 16 Jun 2009 21:10:15 +0000 (21:10 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Tue, 16 Jun 2009 21:10:15 +0000 (21:10 +0000)
Some applications (notably app_fax) do not need digit detection nor FAX tone
detection while they are running, and if Asterisk is using software DSPs to provide
the detection, this consumes extra CPU cycles that could be better spent on the
actual application. This patch allows applications to query and control the state
of digit and tone detection on a channel, and modifies app_fax to disable them
while the FAX operations are occurring (and re-enable digit detection afterwards).

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

apps/app_fax.c
channels/chan_dahdi.c
channels/chan_sip.c
include/asterisk/frame.h

index bd6bdf9..e2b7a90 100644 (file)
@@ -710,6 +710,7 @@ static int sndfax_exec(struct ast_channel *chan, const char *data)
        int res = 0;
        char *parse;
        fax_session session;
        int res = 0;
        char *parse;
        fax_session session;
+       char restore_digit_detect = 0;
 
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(file_name);
 
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(file_name);
@@ -744,8 +745,32 @@ static int sndfax_exec(struct ast_channel *chan, const char *data)
        session.chan = chan;
        session.finished = 0;
 
        session.chan = chan;
        session.finished = 0;
 
+       /* get current digit detection mode, then disable digit detection if enabled */
+       {
+               int dummy = sizeof(restore_digit_detect);
+
+               ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
+       }
+
+       if (restore_digit_detect) {
+               char new_digit_detect = 0;
+
+               ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
+       }
+
+       /* disable FAX tone detection if enabled */
+       {
+               char new_fax_detect = 0;
+
+               ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
+       }
+
        res = transmit(&session);
 
        res = transmit(&session);
 
+       if (restore_digit_detect) {
+               ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
+       }
+
        return res;
 }
 
        return res;
 }
 
@@ -754,6 +779,7 @@ static int rcvfax_exec(struct ast_channel *chan, const char *data)
        int res = 0;
        char *parse;
        fax_session session;
        int res = 0;
        char *parse;
        fax_session session;
+       char restore_digit_detect = 0;
 
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(file_name);
 
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(file_name);
@@ -788,8 +814,32 @@ static int rcvfax_exec(struct ast_channel *chan, const char *data)
        session.chan = chan;
        session.finished = 0;
 
        session.chan = chan;
        session.finished = 0;
 
+       /* get current digit detection mode, then disable digit detection if enabled */
+       {
+               int dummy = sizeof(restore_digit_detect);
+
+               ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
+       }
+
+       if (restore_digit_detect) {
+               char new_digit_detect = 0;
+
+               ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
+       }
+
+       /* disable FAX tone detection if enabled */
+       {
+               char new_fax_detect = 0;
+
+               ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
+       }
+
        res = transmit(&session);
 
        res = transmit(&session);
 
+       if (restore_digit_detect) {
+               ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
+       }
+
        return res;
 }
 
        return res;
 }
 
index 3567aa9..bd11e51 100644 (file)
@@ -1507,6 +1507,7 @@ static struct ast_frame *dahdi_exception(struct ast_channel *ast);
 static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
 static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen);
 static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
 static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen);
+static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen);
 static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len);
 static int handle_init_event(struct dahdi_pvt *i, int event);
 static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value);
 static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len);
 static int handle_init_event(struct dahdi_pvt *i, int event);
 static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value);
@@ -1529,6 +1530,7 @@ static const struct ast_channel_tech dahdi_tech = {
        .indicate = dahdi_indicate,
        .fixup = dahdi_fixup,
        .setoption = dahdi_setoption,
        .indicate = dahdi_indicate,
        .fixup = dahdi_fixup,
        .setoption = dahdi_setoption,
+       .queryoption = dahdi_queryoption,
        .func_channel_read = dahdi_func_read,
        .func_channel_write = dahdi_func_write,
 };
        .func_channel_read = dahdi_func_read,
        .func_channel_write = dahdi_func_write,
 };
@@ -5890,6 +5892,66 @@ static int dahdi_answer(struct ast_channel *ast)
        return res;
 }
 
        return res;
 }
 
+static void disable_dtmf_detect(struct dahdi_pvt *p)
+{
+       int val = 0;
+
+       p->ignoredtmf = 1;
+
+       ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
+
+       if (!p->hardwaredtmf && p->dsp) {
+               p->dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
+               ast_dsp_set_features(p->dsp, p->dsp_features);
+       }
+}
+
+static void enable_dtmf_detect(struct dahdi_pvt *p)
+{
+       int val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
+
+       if (p->channel == CHAN_PSEUDO)
+               return;
+
+       p->ignoredtmf = 0;
+
+       ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
+
+       if (!p->hardwaredtmf && p->dsp) {
+               p->dsp_features |= DSP_FEATURE_DIGIT_DETECT;
+               ast_dsp_set_features(p->dsp, p->dsp_features);
+       }
+}
+
+static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
+{
+       char *cp;
+       struct dahdi_pvt *p = chan->tech_pvt;
+
+       /* all supported options require data */
+       if (!data || (*datalen < 1)) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       switch (option) {
+       case AST_OPTION_DIGIT_DETECT:
+               cp = (char *) data;
+               *cp = p->ignoredtmf ? 0 : 1;
+               ast_debug(1, "Reporting digit detection %sabled on %s\n", *cp ? "en" : "dis", chan->name);
+               break;
+       case AST_OPTION_FAX_DETECT:
+               cp = (char *) data;
+               *cp = (p->callprogress & CALLPROGRESS_FAX) ? 0 : 1;
+               ast_debug(1, "Reporting fax tone detection %sabled on %s\n", *cp ? "en" : "dis", chan->name);
+               break;
+       }
+
+       errno = 0;
+
+       return 0;
+}
+
 static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
 {
        char *cp;
 static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
 {
        char *cp;
@@ -6072,6 +6134,29 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int
                        dahdi_disable_ec(p);
                }
                break;
                        dahdi_disable_ec(p);
                }
                break;
+       case AST_OPTION_DIGIT_DETECT:
+               cp = (char *) data;
+               ast_debug(1, "%sabling digit detection on %s\n", *cp ? "En" : "Dis", chan->name);
+               if (*cp) {
+                       enable_dtmf_detect(p);
+               } else {
+                       disable_dtmf_detect(p);
+               }
+               break;
+       case AST_OPTION_FAX_DETECT:
+               cp = (char *) data;
+               if (p->dsp) {
+                       ast_debug(1, "%sabling fax tone detection on %s\n", *cp ? "En" : "Dis", chan->name);
+                       if (*cp) {
+                               p->callprogress |= CALLPROGRESS_FAX;
+                               p->dsp_features |= DSP_FEATURE_FAX_DETECT;
+                       } else {
+                               p->callprogress &= ~CALLPROGRESS_FAX;
+                               p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
+                       }
+                       ast_dsp_set_features(p->dsp, p->dsp_features);
+               }
+               break;
        default:
                return -1;
        }
        default:
                return -1;
        }
@@ -6279,39 +6364,6 @@ static void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master) {
        ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
 }
 
        ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
 }
 
-static void disable_dtmf_detect(struct dahdi_pvt *p)
-{
-       int val;
-
-       p->ignoredtmf = 1;
-
-       val = 0;
-       ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
-
-       if (!p->hardwaredtmf && p->dsp) {
-               p->dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
-               ast_dsp_set_features(p->dsp, p->dsp_features);
-       }
-}
-
-static void enable_dtmf_detect(struct dahdi_pvt *p)
-{
-       int val;
-
-       if (p->channel == CHAN_PSEUDO)
-               return;
-
-       p->ignoredtmf = 0;
-
-       val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
-       ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
-
-       if (!p->hardwaredtmf && p->dsp) {
-               p->dsp_features |= DSP_FEATURE_DIGIT_DETECT;
-               ast_dsp_set_features(p->dsp, p->dsp_features);
-       }
-}
-
 static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
 {
        struct ast_channel *who;
 static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
 {
        struct ast_channel *who;
@@ -6814,6 +6866,10 @@ static void dahdi_handle_dtmfup(struct ast_channel *ast, int idx, struct ast_fra
                                }
                        }
                        p->faxhandled = 1;
                                }
                        }
                        p->faxhandled = 1;
+                       p->callprogress &= ~CALLPROGRESS_FAX;
+                       p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
+                       ast_dsp_set_features(p->dsp, p->dsp_features);
+                       ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast->name);
                        if (strcmp(ast->exten, "fax")) {
                                const char *target_context = S_OR(ast->macrocontext, ast->context);
 
                        if (strcmp(ast->exten, "fax")) {
                                const char *target_context = S_OR(ast->macrocontext, ast->context);
 
index 4158ba5..4fd774b 100644 (file)
@@ -1833,7 +1833,7 @@ struct sip_pvt {
        int laststate;                          /*!< SUBSCRIBE: Last known extension state */
        int dialogver;                          /*!< SUBSCRIBE: Version for subscription dialog-info */
 
        int laststate;                          /*!< SUBSCRIBE: Last known extension state */
        int dialogver;                          /*!< SUBSCRIBE: Version for subscription dialog-info */
 
-       struct ast_dsp *vad;                    /*!< Inband DTMF Detection dsp */
+       struct ast_dsp *dsp;                    /*!< Inband DTMF Detection dsp */
 
        struct sip_peer *relatedpeer;           /*!< If this dialog is related to a peer, which one 
                                                        Used in peerpoke, mwi subscriptions */
 
        struct sip_peer *relatedpeer;           /*!< If this dialog is related to a peer, which one 
                                                        Used in peerpoke, mwi subscriptions */
@@ -4076,21 +4076,62 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittyp
        return res;
 }
 
        return res;
 }
 
+static void enable_digit_detect(struct sip_pvt *p)
+{
+       if (p->dsp) {
+               return;
+       }
+
+       if (!(p->dsp = ast_dsp_new())) {
+               return;
+       }
+
+       ast_dsp_set_features(p->dsp, DSP_FEATURE_DIGIT_DETECT);
+       if (global_relaxdtmf) {
+               ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
+       }
+}
+
+static void disable_digit_detect(struct sip_pvt *p)
+{
+       if (p->dsp) {
+               ast_dsp_free(p->dsp);
+               p->dsp = NULL;
+       }
+}
+
 /*! \brief Set an option on a SIP dialog */
 static int sip_setoption(struct ast_channel *chan, int option, void *data, int datalen)
 {
        int res = -1;
        struct sip_pvt *p = chan->tech_pvt;
 
 /*! \brief Set an option on a SIP dialog */
 static int sip_setoption(struct ast_channel *chan, int option, void *data, int datalen)
 {
        int res = -1;
        struct sip_pvt *p = chan->tech_pvt;
 
-       if (option == AST_OPTION_FORMAT_READ) {
-               int format = *(int *)data;
-               res = ast_rtp_instance_set_read_format(p->rtp, format);
-       } else if (option == AST_OPTION_FORMAT_WRITE) {
-               int format = *(int *)data;
-               res = ast_rtp_instance_set_write_format(p->rtp, format);
-       } else if (option == AST_OPTION_MAKE_COMPATIBLE) {
-               struct ast_channel *peer = data;
-               res = ast_rtp_instance_make_compatible(chan, p->rtp, peer);
+       switch (option) {
+       case AST_OPTION_FORMAT_READ:
+               res = ast_rtp_instance_set_read_format(p->rtp, *(int *) data);
+               break;
+       case AST_OPTION_FORMAT_WRITE:
+               res = ast_rtp_instance_set_write_format(p->rtp, *(int *) data);
+               break;
+       case AST_OPTION_MAKE_COMPATIBLE:
+               res = ast_rtp_instance_make_compatible(chan, p->rtp, (struct ast_channel *) data);
+               break;
+       case AST_OPTION_DIGIT_DETECT:
+               if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) ||
+                   (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) {
+                       char *cp = (char *) data;
+
+                       ast_debug(1, "%sabling digit detection on %s\n", *cp ? "En" : "Dis", chan->name);
+                       if (*cp) {
+                               enable_digit_detect(p);
+                       } else {
+                               disable_digit_detect(p);
+                       }
+                       res = 0;
+               }
+               break;
+       default:
+               break;
        }
 
        return res;
        }
 
        return res;
@@ -4102,6 +4143,7 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int
        int res = -1;
        enum ast_t38_state state = T38_STATE_UNAVAILABLE;
        struct sip_pvt *p = (struct sip_pvt *) chan->tech_pvt;
        int res = -1;
        enum ast_t38_state state = T38_STATE_UNAVAILABLE;
        struct sip_pvt *p = (struct sip_pvt *) chan->tech_pvt;
+       char *cp;
 
        switch (option) {
        case AST_OPTION_T38_STATE:
 
        switch (option) {
        case AST_OPTION_T38_STATE:
@@ -4135,6 +4177,11 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int
                res = 0;
 
                break;
                res = 0;
 
                break;
+       case AST_OPTION_DIGIT_DETECT:
+               cp = (char *) data;
+               *cp = p->dsp ? 1 : 0;
+               ast_debug(1, "Reporting digit detection %sabled on %s\n", *cp ? "en" : "dis", chan->name);
+               break;
        default:
                break;
        }
        default:
                break;
        }
@@ -5823,7 +5870,6 @@ static const char *hangup_cause2sip(int cause)
        return 0;
 }
 
        return 0;
 }
 
-
 /*! \brief  sip_hangup: Hangup SIP call
  * Part of PBX interface, called from ast_hangup */
 static int sip_hangup(struct ast_channel *ast)
 /*! \brief  sip_hangup: Hangup SIP call
  * Part of PBX interface, called from ast_hangup */
 static int sip_hangup(struct ast_channel *ast)
@@ -5902,8 +5948,7 @@ static int sip_hangup(struct ast_channel *ast)
        append_history(p, needcancel ? "Cancel" : "Hangup", "Cause %s", p->owner ? ast_cause2str(p->hangupcause) : "Unknown");
 
        /* Disconnect */
        append_history(p, needcancel ? "Cancel" : "Hangup", "Cause %s", p->owner ? ast_cause2str(p->hangupcause) : "Unknown");
 
        /* Disconnect */
-       if (p->vad)
-               ast_dsp_free(p->vad);
+       disable_digit_detect(p);
 
        p->owner = NULL;
        ast->tech_pvt = dialog_unref(ast->tech_pvt, "unref ast->tech_pvt");
 
        p->owner = NULL;
        ast->tech_pvt = dialog_unref(ast->tech_pvt, "unref ast->tech_pvt");
@@ -6453,7 +6498,6 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
        return res;
 }
 
        return res;
 }
 
-
 /*! \brief Initiate a call in the SIP channel
        called from sip_request_call (calls from the pbx ) for outbound channels
        and from handle_request_invite for inbound channels
 /*! \brief Initiate a call in the SIP channel
        called from sip_request_call (calls from the pbx ) for outbound channels
        and from handle_request_invite for inbound channels
@@ -6552,12 +6596,10 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
        else
                ast_debug(3, "This channel will not be able to handle video.\n");
 
        else
                ast_debug(3, "This channel will not be able to handle video.\n");
 
-       if ((ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) || (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) {
+       if ((ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) ||
+           (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) {
                if (!i->rtp || ast_rtp_instance_dtmf_mode_set(i->rtp, AST_RTP_DTMF_MODE_INBAND)) {
                if (!i->rtp || ast_rtp_instance_dtmf_mode_set(i->rtp, AST_RTP_DTMF_MODE_INBAND)) {
-                       i->vad = ast_dsp_new();
-                       ast_dsp_set_features(i->vad, DSP_FEATURE_DIGIT_DETECT);
-                       if (global_relaxdtmf)
-                               ast_dsp_set_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
+                       enable_digit_detect(i);
                }
        } else if (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) {
                if (i->rtp) {
                }
        } else if (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) {
                if (i->rtp) {
@@ -6853,8 +6895,8 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
                ast_set_write_format(p->owner, p->owner->writeformat);
        }
 
                ast_set_write_format(p->owner, p->owner->writeformat);
        }
 
-       if (f && (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
-               f = ast_dsp_process(p->owner, p->vad, f);
+       if (f && p->dsp) {
+               f = ast_dsp_process(p->owner, p->dsp, f);
                if (f && f->frametype == AST_FRAME_DTMF) {
                        if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && f->subclass == 'f') {
                                ast_debug(1, "Fax CNG detected on %s\n", ast->name);
                if (f && f->frametype == AST_FRAME_DTMF) {
                        if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && f->subclass == 'f') {
                                ast_debug(1, "Fax CNG detected on %s\n", ast->name);
@@ -25354,16 +25396,11 @@ static int sip_dtmfmode(struct ast_channel *chan, const char *data)
                ast_log(LOG_WARNING, "I don't know about this dtmf mode: %s\n", mode);
        if (p->rtp)
                ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
                ast_log(LOG_WARNING, "I don't know about this dtmf mode: %s\n", mode);
        if (p->rtp)
                ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
-       if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) {
-               if (!p->vad) {
-                       p->vad = ast_dsp_new();
-                       ast_dsp_set_features(p->vad, DSP_FEATURE_DIGIT_DETECT);
-               }
+       if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) ||
+           (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) {
+               enable_digit_detect(p);
        } else {
        } else {
-               if (p->vad) {
-                       ast_dsp_free(p->vad);
-                       p->vad = NULL;
-               }
+               disable_digit_detect(p);
        }
        sip_pvt_unlock(p);
        ast_channel_unlock(chan);
        }
        sip_pvt_unlock(p);
        ast_channel_unlock(chan);
index 46500d2..8b79a5e 100644 (file)
@@ -400,6 +400,12 @@ enum ast_control_transfer {
 /*! Request that the channel driver make two channels of the same tech type compatible if possible */
 #define AST_OPTION_MAKE_COMPATIBLE      13
 
 /*! Request that the channel driver make two channels of the same tech type compatible if possible */
 #define AST_OPTION_MAKE_COMPATIBLE      13
 
+/*! Get or set the digit detection state of the channel */
+#define AST_OPTION_DIGIT_DETECT                14
+
+/*! Get or set the fax tone detection state of the channel */
+#define AST_OPTION_FAX_DETECT          15
+
 struct oprmode {
        struct ast_channel *peer;
        int mode;
 struct oprmode {
        struct ast_channel *peer;
        int mode;