]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Modify bridging to properly evaluate DTMF after first warning is played
authorJeff Peeler <jpeeler@digium.com>
Tue, 17 Feb 2009 21:54:34 +0000 (21:54 +0000)
committerJeff Peeler <jpeeler@digium.com>
Tue, 17 Feb 2009 21:54:34 +0000 (21:54 +0000)
The main problem is currently if the Dial flag L is used with a warning sound,
DTMF is not evaluated after the first warning sound. To fix this, a flag has
been added in ast_generic_bridge for playing the warning which ensures that if
a scheduled warning is missed, multiple warrnings are not played back (due to a
feature evaluation or waiting for digits). ast_channel_bridge was modified to
store the nexteventts in the ast_bridge_config structure as that information
was lost every time ast_channel_bridge was reentered, causing a hangup due to
incorrect time calculations.

(closes issue #14315)
Reported by: tim_ringenbach

Reviewed on reviewboard:
http://reviewboard.digium.com/r/163/

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@176701 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/channel.h
main/channel.c
res/res_features.c

index 957d95d5c8d137c7f40847ca41c2bb519206cbe1..f7718684b8ac01c606ac6d03dc3f25eb046914dd 100644 (file)
@@ -529,12 +529,14 @@ enum {
        AST_FEATURE_AUTOMON =      (1 << 4),
        AST_FEATURE_PARKCALL =     (1 << 5),
        AST_FEATURE_NO_H_EXTEN =   (1 << 6),
+       AST_FEATURE_WARNING_ACTIVE = (1 << 7),
 };
 
 struct ast_bridge_config {
        struct ast_flags features_caller;
        struct ast_flags features_callee;
        struct timeval start_time;
+       struct timeval nexteventts;
        long feature_timer;
        long timelimit;
        long play_warning;
index 159de4c0bdf78945ea9872a01673e1a0290b4b05..25d45ec0d9907fc1ddaeca81692b2f86b12ac59a 100644 (file)
@@ -3933,10 +3933,13 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
                if (bridge_end.tv_sec) {
                        to = ast_tvdiff_ms(bridge_end, ast_tvnow());
                        if (to <= 0) {
-                               if (config->timelimit)
+                               if (config->timelimit) {
                                        res = AST_BRIDGE_RETRY;
-                               else
+                                       /* generic bridge ending to play warning */
+                                       ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
+                               } else {
                                        res = AST_BRIDGE_COMPLETE;
+                               }
                                break;
                        }
                } else
@@ -4018,6 +4021,7 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
                                        ast_log(LOG_DEBUG, "Got DTMF %s on channel (%s)\n", 
                                                f->frametype == AST_FRAME_DTMF_END ? "end" : "begin",
                                                who->name);
+
                                break;
                        }
                        /* Write immediately frames, not passed through jb */
@@ -4050,7 +4054,6 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
        int o0nativeformats;
        int o1nativeformats;
        long time_left_ms=0;
-       struct timeval nexteventts = { 0, };
        char caller_warning = 0;
        char callee_warning = 0;
 
@@ -4106,11 +4109,11 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
        o1nativeformats = c1->nativeformats;
 
        if (config->feature_timer) {
-               nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->feature_timer, 1000));
-       } else if (config->timelimit) {
-               nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
+               config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->feature_timer, 1000));
+       } else if (config->timelimit && firstpass) {
+               config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
                if (caller_warning || callee_warning)
-                       nexteventts = ast_tvsub(nexteventts, ast_samp2tv(config->play_warning, 1000));
+                       config->nexteventts = ast_tvsub(config->nexteventts, ast_samp2tv(config->play_warning, 1000));
        }
 
        if (!c0->tech->send_digit_begin)
@@ -4128,9 +4131,9 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
 
                to = -1;
 
-               if (!ast_tvzero(nexteventts)) {
+               if (!ast_tvzero(config->nexteventts)) {
                        now = ast_tvnow();
-                       to = ast_tvdiff_ms(nexteventts, now);
+                       to = ast_tvdiff_ms(config->nexteventts, now);
                        if (to <= 0) {
                                if (!config->timelimit) {
                                        res = AST_BRIDGE_COMPLETE;
@@ -4158,7 +4161,7 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                        }
                        
                        if (!to) {
-                               if (time_left_ms >= 5000 && config->warning_sound && config->play_warning) {
+                               if (time_left_ms >= 5000 && config->warning_sound && config->play_warning && ast_test_flag(config, AST_FEATURE_WARNING_ACTIVE)) {
                                        int t = (time_left_ms + 500) / 1000; /* round to nearest second */
                                        if (caller_warning)
                                                bridge_playfile(c0, c1, config->warning_sound, t);
@@ -4166,10 +4169,11 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                                                bridge_playfile(c1, c0, config->warning_sound, t);
                                }
                                if (config->warning_freq && (time_left_ms > (config->warning_freq + 5000)))
-                                       nexteventts = ast_tvadd(nexteventts, ast_samp2tv(config->warning_freq, 1000));
+                                       config->nexteventts = ast_tvadd(config->nexteventts, ast_samp2tv(config->warning_freq, 1000));
                                else
-                                       nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
+                                       config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
                        }
+                       ast_clear_flag(config, AST_FEATURE_WARNING_ACTIVE);
                }
 
                if (c0->_softhangup == AST_SOFTHANGUP_UNBRIDGE || c1->_softhangup == AST_SOFTHANGUP_UNBRIDGE) {
@@ -4283,9 +4287,13 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                if (!ast_strlen_zero(pbx_builtin_getvar_helper(c1, "BRIDGEPEER")))
                        pbx_builtin_setvar_helper(c1, "BRIDGEPEER", c0->name);
 
-               res = ast_generic_bridge(c0, c1, config, fo, rc, nexteventts);
-               if (res != AST_BRIDGE_RETRY)
+               res = ast_generic_bridge(c0, c1, config, fo, rc, config->nexteventts);
+               if (res != AST_BRIDGE_RETRY) {
+                       break;
+               } else if (config->feature_timer) {
+                       /* feature timer expired but has not been updated, sending to ast_bridge_call to do so */
                        break;
+               }
        }
 
        ast_clear_flag(c0, AST_FLAG_END_DTMF_ONLY);
index 7fadaa61a141b31158e5a08d82a1ce0dbf25903c..05bbd7fe443a53a5179bce2388bdd1d87f9acf9d 100644 (file)
@@ -1730,7 +1730,15 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
                if (config->feature_timer) {
                        /* Update time limit for next pass */
                        diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
-                       config->feature_timer -= diff;
+                       if (res == AST_BRIDGE_RETRY) {
+                               /* The feature fully timed out but has not been updated. Skip
+                                * the potential round error from the diff calculation and
+                                * explicitly set to expired. */
+                               config->feature_timer = -1;
+                       } else {
+                               config->feature_timer -= diff;
+                       }
+
                        if (hasfeatures) {
                                /* Running on backup config, meaning a feature might be being
                                   activated, but that's no excuse to keep things going