diff --git a/apps/app_dial.c b/apps/app_dial.c
index fd42c1cc59..d38dd646c8 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -88,9 +88,12 @@
-
+
Specifies the number of seconds we attempt to dial the specified devices.
If not specified, this defaults to 136 years.
+ 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.
@@ -1254,7 +1257,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,
@@ -1267,7 +1270,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 */
@@ -1295,7 +1300,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",
@@ -1311,7 +1316,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;
@@ -1337,13 +1342,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;
@@ -1421,7 +1426,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) {
@@ -1559,6 +1564,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 */
@@ -1602,6 +1609,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;
@@ -1792,6 +1801,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)) {
@@ -1820,7 +1831,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);
@@ -1844,7 +1855,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;
@@ -1863,7 +1874,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);
@@ -1975,9 +1986,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) {
@@ -2349,7 +2365,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;
@@ -2963,14 +2979,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;
}
}
@@ -3010,7 +3043,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);
@@ -3018,7 +3051,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;