From 320c98eec87c473bfa814f76188a37603ea65ddd Mon Sep 17 00:00:00 2001 From: Naveen Albert Date: Thu, 8 Feb 2024 13:09:49 -0500 Subject: [PATCH] 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. --- apps/app_dial.c | 79 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/apps/app_dial.c b/apps/app_dial.c index 5b718dc272..f244191376 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. @@ -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;