diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index e6c41e51e9..2cd6d46806 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -276,6 +276,21 @@ + + W/O Duration in ms for which to wait for dial tone on the current call. + This setting is will temporarily override the waitfordialtone + setting in chan_dahdi.conf (typically if that setting is disabled). + You must call this in a pre-dial handler when making a call on an analog trunk + (e.g. FXS-signalled interface). + This allows, for example, being able to barge in on an in-use trunk, + if dialed specifically, but allows skipping the trunk when routing calls + if dial tone is not present on a channel. + This setting will only apply to the current (next) call made on the + DAHDI channel, and will not persist for future calls. + Please keep in mind that due to the way that chan_dahdi implements dial tone detection, + DTMF digits on an in-use channel will temporarily relay to any other channels attempting to use the channel for a call. + However, voice transmission will not leak. + @@ -2104,11 +2119,40 @@ static void my_set_waitingfordt(void *pvt, struct ast_channel *ast) { struct dahdi_pvt *p = pvt; - if (p->waitfordialtone && CANPROGRESSDETECT(p) && p->dsp) { - ast_debug(1, "Defer dialing for %dms or dialtone\n", p->waitfordialtone); - gettimeofday(&p->waitingfordt, NULL); - ast_setstate(ast, AST_STATE_OFFHOOK); + /* We reset p->waitfordialtonetemp here, to prevent leaking to future calls, + * but we also need to check against this value until we get dialtone + * or the timer expires, since waitingfordt is when the timer started, + * not when it should expire. + * + * Critically, we only set p->waitingfordt here if waitfordialtone or waitfordialtonetemp + * has already been set, as waitingfordt is what is checked at runtime to determine + * if we should be waiting for dial tone. This ensures that if a second call + * is initiated concurrently, the first one "consumes" waitfordialtonetemp and resets it, + * preventing leaking to other calls while remaining available to check on the first one while dialing. + */ + p->waitfordialtoneduration = p->waitfordialtonetemp ? p->waitfordialtonetemp : p->waitfordialtone; + p->waitfordialtonetemp = 0; + + if (!(p->waitfordialtoneduration && CANPROGRESSDETECT(p))) { + return; } + + /* Because the DSP is allocated when the channel is created, + * if we requested waitfordialtone later (in a predial handler), + * we need to create it now */ + if (!p->dsp) { + p->dsp = ast_dsp_new(); + if (!p->dsp) { + ast_log(LOG_ERROR, "Unable to allocate DSP\n"); + return; + } + } + p->dsp_features |= DSP_FEATURE_WAITDIALTONE; + ast_dsp_set_features(p->dsp, p->dsp_features); + + ast_debug(1, "Defer dialing for %dms or dialtone\n", p->waitfordialtoneduration); + gettimeofday(&p->waitingfordt, NULL); + ast_setstate(ast, AST_STATE_OFFHOOK); } static int my_check_waitingfordt(void *pvt) @@ -7254,6 +7298,21 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char res = -1; } ast_mutex_unlock(&p->lock); + } else if (!strcasecmp(data, "waitfordialtone")) { + if (ast_strlen_zero(value)) { + ast_log(LOG_WARNING, "waitfordialtone requires a duration in ms\n"); + return -1; + } + + ast_mutex_lock(&p->lock); + if (!CANPROGRESSDETECT(p)) { + ast_log(LOG_WARNING, "%s only supported on analog trunks\n", data); + ast_mutex_unlock(&p->lock); + return -1; + } + /* Only set the temp waitfordialtone setting, not the permanent one. */ + p->waitfordialtonetemp = atoi(value); + ast_mutex_unlock(&p->lock); } else { res = -1; } @@ -9093,9 +9152,9 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast) /* DSP clears us of being pulse */ p->pulsedial = 0; } else if (p->waitingfordt.tv_sec) { - if (ast_tvdiff_ms(ast_tvnow(), p->waitingfordt) >= p->waitfordialtone ) { + if (ast_tvdiff_ms(ast_tvnow(), p->waitingfordt) >= p->waitfordialtoneduration) { p->waitingfordt.tv_sec = 0; - ast_log(LOG_WARNING, "Never saw dialtone on channel %d\n", p->channel); + ast_log(LOG_NOTICE, "Never saw dialtone on channel %d\n", p->channel); ast_frfree(f); f = NULL; } else if (f->frametype == AST_FRAME_VOICE) { diff --git a/channels/chan_dahdi.h b/channels/chan_dahdi.h index b7955cdddf..4431efd913 100644 --- a/channels/chan_dahdi.h +++ b/channels/chan_dahdi.h @@ -654,6 +654,14 @@ struct dahdi_pvt { * \note Set from the "waitfordialtone" value read in from chan_dahdi.conf */ int waitfordialtone; + /*! + * \brief Transient variable. Same as waitfordialtone, but temporarily set for a specific call, rather than permanently for the channel. + */ + int waitfordialtonetemp; + /*! + * \brief Transient variable. Stored off waitfordialtone duration at runtime. + */ + int waitfordialtoneduration; /*! * \brief Number of frames to watch for dialtone in incoming calls * \note Set from the "dialtone_detect" value read in from chan_dahdi.conf