diff --git a/apps/app_fax.c b/apps/app_fax.c index bd6bdf9f63..e2b7a90ee2 100644 --- a/apps/app_fax.c +++ b/apps/app_fax.c @@ -710,6 +710,7 @@ static int sndfax_exec(struct ast_channel *chan, const char *data) int res = 0; char *parse; fax_session session; + char restore_digit_detect = 0; 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; + /* 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); + if (restore_digit_detect) { + ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0); + } + 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; + char restore_digit_detect = 0; 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; + /* 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); + if (restore_digit_detect) { + ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0); + } + return res; } diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 3567aa9e9e..bd11e51ea5 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -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_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); @@ -1529,6 +1530,7 @@ static const struct ast_channel_tech dahdi_tech = { .indicate = dahdi_indicate, .fixup = dahdi_fixup, .setoption = dahdi_setoption, + .queryoption = dahdi_queryoption, .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; } +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; @@ -6072,6 +6134,29 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int 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; } @@ -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); } -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; @@ -6814,6 +6866,10 @@ static void dahdi_handle_dtmfup(struct ast_channel *ast, int idx, struct ast_fra } } 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); diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 4158ba5d48..4fd774b944 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1833,7 +1833,7 @@ struct sip_pvt { 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 */ @@ -4076,21 +4076,62 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittyp 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; - 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; @@ -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; + char *cp; switch (option) { case AST_OPTION_T38_STATE: @@ -4134,6 +4176,11 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int *((enum ast_t38_state *) data) = state; 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; @@ -5823,7 +5870,6 @@ static const char *hangup_cause2sip(int cause) return 0; } - /*! \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 */ - 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"); @@ -6453,7 +6498,6 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data 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 @@ -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"); - 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)) { - 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) { @@ -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); } - 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); @@ -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); - 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 { - if (p->vad) { - ast_dsp_free(p->vad); - p->vad = NULL; - } + disable_digit_detect(p); } sip_pvt_unlock(p); ast_channel_unlock(chan); diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 46500d2e98..8b79a5e998 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -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 +/*! 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;