chan_dahdi.c: Flush the DAHDI write buffer after starting DTMF.
authorRichard Mudgett <rmudgett@digium.com>
Mon, 10 Aug 2015 18:43:19 +0000 (13:43 -0500)
committerRichard Mudgett <rmudgett@digium.com>
Tue, 11 Aug 2015 21:58:32 +0000 (16:58 -0500)
Pressing DTMF digits on a phone to go out on a DAHDI channel can result in
the digit not being recognized or even heard by the peer.

Phone -> Asterisk -> DAHDI/channel

Turns out the DAHDI behavior with DTMF generation (and any other generated
tones) is exposed by the "buffers=" setting in chan_dahdi.conf.  When
Asterisk requests to start sending DTMF then DAHDI waits until its write
buffer is empty before generating any samples for the DTMF tones.  When
Asterisk subsequently requests DAHDI to stop sending DTMF then DAHDI
immediately stops generating the DTMF samples.  As a result, the more
samples there are in the DAHDI write buffer the shorter the time DTMF
actually gets sent on the wire.  If there are more samples in the write
buffer than the time DTMF is supposed to be sent then no DTMF gets sent on
the wire.  With the "buffers=12,half" setting and each buffer representing
20 ms of samples then the DAHDI write buffer is going to contain around
120 ms of samples.  For DTMF to be recognized by the peer the actual sent
DTMF duration needs to be a minimum of 40 ms.  Therefore, the intended
duration needs to be a minimum of 160 ms for the peer to receive the
minimum DTMF digit duration to recognize it.

A simple and effective solution to work around the DAHDI behavior is for
Asterisk to flush the DAHDI write buffer when sending DTMF so the full
duration of DTMF is actually sent on the wire.  When someone is going to
send DTMF they are not likely to be talking before sending the tones so
the flushed write samples are expected to just contain silence.

* Made dahdi_digit_begin() flush the DAHDI write buffer after requesting
to send a DTMF digit.

ASTERISK-25315 #close
Reported by John Hardin

Change-Id: Ib56262c708cb7858082156bfc70ebd0a220efa6a

channels/chan_dahdi.c

index fe61309..ac15952 100644 (file)
@@ -4198,7 +4198,7 @@ static int dahdi_digit_begin(struct ast_channel *chan, char digit)
 {
        struct dahdi_pvt *pvt;
        int idx;
-       int dtmf = -1;
+       int dtmf;
        int res;
 
        pvt = ast_channel_tech_pvt(chan);
@@ -4221,8 +4221,11 @@ static int dahdi_digit_begin(struct ast_channel *chan, char digit)
                break;
        }
 #endif
-       if ((dtmf = digit_to_dtmfindex(digit)) == -1)
+       dtmf = digit_to_dtmfindex(digit);
+       if (dtmf == -1) {
+               /* Not a valid DTMF digit */
                goto out;
+       }
 
        if (pvt->pulse || ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &dtmf)) {
                char dial_str[] = { 'T', digit, '\0' };
@@ -4232,10 +4235,19 @@ static int dahdi_digit_begin(struct ast_channel *chan, char digit)
                        pvt->dialing = 1;
                }
        } else {
-               ast_debug(1, "Channel %s started VLDTMF digit '%c'\n",
-                       ast_channel_name(chan), digit);
                pvt->dialing = 1;
                pvt->begindigit = digit;
+
+               /* Flush the write buffer in DAHDI to start sending the digit immediately. */
+               dtmf = DAHDI_FLUSH_WRITE;
+               res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &dtmf);
+               if (res) {
+                       ast_log(LOG_WARNING, "Unable to flush the DAHDI write buffer to send DTMF on channel %d: %s\n",
+                               pvt->channel, strerror(errno));
+               }
+
+               ast_debug(1, "Channel %s started VLDTMF digit '%c'\n",
+                       ast_channel_name(chan), digit);
        }
 
 out: