From 953dc3d127b2fd03e12cbc6158cd93c1e2664ca4 Mon Sep 17 00:00:00 2001 From: Naveen Albert Date: Sat, 2 Dec 2023 13:24:20 -0500 Subject: [PATCH] chan_dahdi: Allow specifying waitfordialtone per call. The existing "waitfordialtone" setting in chan_dahdi.conf applies permanently to a specific channel, regardless of how it is being used. This rather restrictively prevents a system from simultaneously being able to pick free lines for outgoing calls while also allowing barge-in to a trunk by some other arrangement. This allows specifying "waitfordialtone" using the CHANNEL function for only the next call that will be placed, allowing significantly more flexibility in the use of trunk interfaces. Resolves: #472 UserNote: "waitfordialtone" may now be specified for DAHDI trunk channels on a per-call basis using the CHANNEL function. --- channels/chan_dahdi.c | 71 +++++++++++++++++++++++++++++++++++++++---- channels/chan_dahdi.h | 8 +++++ 2 files changed, 73 insertions(+), 6 deletions(-) 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