app_dial: Add dial time for progress/ringing.

Add a timeout option to control the amount of time
to wait if no early media is received before giving
up. This allows aborting early if the destination
is not being responsive.

Resolves: #588

UserNote: The timeout argument to Dial now allows
specifying the maximum amount of time to dial if
early media is not received.
This commit is contained in:
Naveen Albert 2024-02-08 13:09:49 -05:00 committed by asterisk-org-access-app[bot]
parent b791c27385
commit 320c98eec8
1 changed files with 56 additions and 23 deletions

View File

@ -88,9 +88,12 @@
</argument>
<xi:include xpointer="xpointer(/docs/info[@name='Dial_Resource'])" />
</parameter>
<parameter name="timeout" required="false">
<parameter name="timeout" required="false" argsep="^">
<para>Specifies the number of seconds we attempt to dial the specified devices.</para>
<para>If not specified, this defaults to 136 years.</para>
<para>If a second argument is specified, this controls the number of seconds we attempt to dial the specified devices
without receiving early media or ringing. If neither progress, ringing, nor voice frames have been received when this
timeout expires, the call will be treated as a CHANUNAVAIL. This can be used to skip destinations that may not be responsive.</para>
</parameter>
<parameter name="options" required="false">
<optionlist>
@ -1197,7 +1200,7 @@ static void set_duration_var(struct ast_channel *chan, const char *var_base, int
}
static struct ast_channel *wait_for_answer(struct ast_channel *in,
struct dial_head *out_chans, int *to, struct ast_flags64 *peerflags,
struct dial_head *out_chans, int *to_answer, int *to_progress, struct ast_flags64 *peerflags,
char *opt_args[],
struct privacy_args *pa,
const struct cause_args *num_in, int *result, char *dtmf_progress,
@ -1210,7 +1213,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
{
struct cause_args num = *num_in;
int prestart = num.busy + num.congestion + num.nochan;
int orig = *to;
int orig_answer_to = *to_answer;
int progress_to_dup = *to_progress;
int orig_progress_to = *to_progress;
struct ast_channel *peer = NULL;
struct chanlist *outgoing = AST_LIST_FIRST(out_chans);
/* single is set if only one destination is enabled */
@ -1238,7 +1243,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
* there is no point in continuing. The bridge
* will just fail if it gets that far.
*/
*to = -1;
*to_answer = -1;
strcpy(pa->status, "CONGESTION");
ast_channel_publish_dial(in, outgoing->chan, NULL, pa->status);
SCOPE_EXIT_RTN_VALUE(NULL, "%s: can't be made compat with %s\n",
@ -1254,7 +1259,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
is_cc_recall = ast_cc_is_recall(in, &cc_recall_core_id, NULL);
while ((*to = ast_remaining_ms(start, orig)) && !peer) {
while ((*to_answer = ast_remaining_ms(start, orig_answer_to)) && (*to_progress = ast_remaining_ms(start, progress_to_dup)) && !peer) {
struct chanlist *o;
int pos = 0; /* how many channels do we handle */
int numlines = prestart;
@ -1280,13 +1285,13 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
} else {
ast_verb(3, "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan);
}
*to = 0;
*to_answer = 0;
if (is_cc_recall) {
ast_cc_failed(cc_recall_core_id, "Everyone is busy/congested for the recall. How sad");
}
SCOPE_EXIT_RTN_VALUE(NULL, "%s: No outgoing channels available\n", ast_channel_name(in));
}
winner = ast_waitfor_n(watchers, pos, to);
winner = ast_waitfor_n(watchers, pos, to_answer);
AST_LIST_TRAVERSE(out_chans, o, node) {
int res = 0;
struct ast_frame *f;
@ -1363,7 +1368,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
ast_channel_unlock(in);
}
do_forward(o, &num, peerflags, single, caller_entertained, &orig,
do_forward(o, &num, peerflags, single, caller_entertained, &orig_answer_to,
forced_clid, stored_clid);
if (o->chan) {
@ -1500,6 +1505,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
* fine for ringing frames to get sent through.
*/
++num_ringing;
*to_progress = -1;
progress_to_dup = -1;
if (ignore_cc || cc_frame_received || num_ringing == numlines) {
ast_verb(3, "%s is ringing\n", ast_channel_name(c));
/* Setup early media if appropriate */
@ -1543,6 +1550,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
ast_indicate(in, AST_CONTROL_PROGRESS);
}
}
*to_progress = -1;
progress_to_dup = -1;
if (!sent_progress) {
struct timeval now, then;
int64_t diff;
@ -1731,6 +1740,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
if (caller_entertained) {
break;
}
*to_progress = -1;
progress_to_dup = -1;
/* Fall through */
case AST_FRAME_TEXT:
if (single && ast_write(in, f)) {
@ -1759,7 +1770,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
#endif
if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
/* Got hung up */
*to = -1;
*to_answer = -1;
strcpy(pa->status, "CANCEL");
pa->canceled = 1;
publish_dial_end_event(in, out_chans, NULL, pa->status);
@ -1783,7 +1794,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
if (onedigit_goto(in, context, (char) f->subclass.integer, 1)) {
ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
*to = 0;
*to_answer = 0;
*result = f->subclass.integer;
strcpy(pa->status, "CANCEL");
pa->canceled = 1;
@ -1802,7 +1813,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) &&
detect_disconnect(in, f->subclass.integer, &featurecode)) {
ast_verb(3, "User requested call disconnect.\n");
*to = 0;
*to_answer = 0;
strcpy(pa->status, "CANCEL");
pa->canceled = 1;
publish_dial_end_event(in, out_chans, NULL, pa->status);
@ -1912,9 +1923,14 @@ skip_frame:;
}
wait_over:
if (!*to || ast_check_hangup(in)) {
ast_verb(3, "Nobody picked up in %d ms\n", orig);
if (!*to_answer || ast_check_hangup(in)) {
ast_verb(3, "Nobody picked up in %d ms\n", orig_answer_to);
publish_dial_end_event(in, out_chans, NULL, "NOANSWER");
} else if (!*to_progress) {
ast_verb(3, "No early media received in %d ms\n", orig_progress_to);
publish_dial_end_event(in, out_chans, NULL, "CHANUNAVAIL");
strcpy(pa->status, "CHANUNAVAIL");
*to_answer = 0; /* Reset to prevent hangup */
}
if (is_cc_recall) {
@ -2286,7 +2302,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
struct chanlist *outgoing;
struct chanlist *tmp;
struct ast_channel *peer = NULL;
int to; /* timeout */
int to_answer, to_progress; /* timeouts */
struct cause_args num = { chan, 0, 0, 0 };
int cause, hanguptreecause = -1;
@ -2897,14 +2913,31 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
AST_LIST_TRAVERSE_SAFE_END;
if (ast_strlen_zero(args.timeout)) {
to = -1;
to_answer = -1;
to_progress = -1;
} else {
to = atoi(args.timeout);
if (to > 0)
to *= 1000;
else {
ast_log(LOG_WARNING, "Invalid timeout specified: '%s'. Setting timeout to infinite\n", args.timeout);
to = -1;
char *anstimeout = strsep(&args.timeout, "^");
if (!ast_strlen_zero(anstimeout)) {
to_answer = atoi(anstimeout);
if (to_answer > 0) {
to_answer *= 1000;
} else {
ast_log(LOG_WARNING, "Invalid answer timeout specified: '%s'. Setting timeout to infinite\n", args.timeout);
to_answer = -1;
}
} else {
to_answer = -1;
}
if (!ast_strlen_zero(args.timeout)) {
to_progress = atoi(args.timeout);
if (to_progress > 0) {
to_progress *= 1000;
} else {
ast_log(LOG_WARNING, "Invalid progress timeout specified: '%s'. Setting timeout to infinite\n", args.timeout);
to_progress = -1;
}
} else {
to_progress = -1;
}
}
@ -2944,7 +2977,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
}
}
peer = wait_for_answer(chan, &out_chans, &to, peerflags, opt_args, &pa, &num, &result,
peer = wait_for_answer(chan, &out_chans, &to_answer, &to_progress, peerflags, opt_args, &pa, &num, &result,
dtmf_progress, mf_progress, mf_wink, sf_progress, sf_wink,
(ast_test_flag64(&opts, OPT_HEARPULSING) ? 1 : 0),
ignore_cc, &forced_clid, &stored_clid, &config);
@ -2952,7 +2985,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
if (!peer) {
if (result) {
res = result;
} else if (to) { /* Musta gotten hung up */
} else if (to_answer) { /* Musta gotten hung up */
res = -1;
} else { /* Nobody answered, next please? */
res = 0;