]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
chan_dahdi: Allow specifying waitfordialtone per call.
authorNaveen Albert <asterisk@phreaknet.org>
Sat, 2 Dec 2023 18:24:20 +0000 (13:24 -0500)
committerNaveen Albert <asterisk@phreaknet.org>
Wed, 20 Mar 2024 12:49:05 +0000 (12:49 +0000)
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
channels/chan_dahdi.h

index e6c41e51e959e200b350b69013a673f43599a65b..2cd6d46806e548dca941e0c859b50496f86276a7 100644 (file)
                                        <enum name="none" />
                                </enumlist>
                        </enum>
+                       <enum name="waitfordialtone">
+                               <para>W/O Duration in ms for which to wait for dial tone on the current call.</para>
+                               <para>This setting is will temporarily override the <literal>waitfordialtone</literal>
+                               setting in <literal>chan_dahdi.conf</literal> (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).</para>
+                               <para>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.</para>
+                               <para>This setting will only apply to the current (next) call made on the
+                               DAHDI channel, and will not persist for future calls.</para>
+                               <para>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.</para>
+                       </enum>
                </enumlist>
        </info>
        <info name="Dial_Resource" language="en_US" tech="DAHDI">
@@ -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) {
index b7955cdddfae3984ed1021bde3f38a988c47b123..4431efd9136e2f8891d7a4becc50f713367b3458 100644 (file)
@@ -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