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.
This commit is contained in:
Naveen Albert 2023-12-02 13:24:20 -05:00 committed by asterisk-org-access-app[bot]
parent 786f45d94e
commit 953dc3d127
2 changed files with 73 additions and 6 deletions

View File

@ -276,6 +276,21 @@
<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) {

View 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