Merged revisions 310902 via svnmerge from

https://origsvn.digium.com/svn/asterisk/branches/1.8

................
  r310902 | twilson | 2011-03-16 12:19:57 -0500 (Wed, 16 Mar 2011) | 43 lines
  
  Merged revisions 310889 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.6.2
  
  ................
    r310889 | twilson | 2011-03-16 12:03:27 -0500 (Wed, 16 Mar 2011) | 36 lines
    
    Merged revisions 310888 via svnmerge from 
    https://origsvn.digium.com/svn/asterisk/branches/1.4
    
    ........
      r310888 | twilson | 2011-03-16 11:58:42 -0500 (Wed, 16 Mar 2011) | 29 lines
      
      Don't delay DTMF in core bridge while listening for DTMF features
      
      This patch is mostly the work of Olle Johansson. I did some cleanup and
      added the silence generating code if transmit_silence is set.
      
      When a channel listens for DTMF in the core bridge, the outbound DTMF is not
      sent until we have received DTMF_END. For a long DTMF, this is a disaster. We
      send 4 seconds of DTMF to Asterisk, which sends no audio for those 4 seconds.
      Some products see this delay and the time skew on RTP packets that results and
      start ignoring the audio that is sent afterward.
      
      With this change, the DTMF_BEGIN frame is inspected and checked. If it matches
      a feature code, we wait for DTMF_END and activate the feature as before. If
      transmit_silence=yes in asterisk.conf, silence is sent if we paritally match a
      multi-digit feature. If it doesn't match a feature, the frame is forwarded
      along with the DTMF_END without delay. By doing it this way, DTMF is not delayed.
      
      (closes issue #15642)
      Reported by: jasonshugart
      Patches: 
            issue_15652_dtmf_ast-1.4.patch.txt uploaded by twilson (license 396)
      Tested by: globalnetinc, jde
      
      (closes issue #16625)
      Reported by: sharvanek
      
      Review: https://reviewboard.asterisk.org/r/1092/
      Review: https://reviewboard.asterisk.org/r/1125/
    ........
  ................
................


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@310941 65c4cc65-6c06-0410-ace0-fbb531ad65f3
10-digiumphones
Terry Wilson 15 years ago
parent f98f47ba8b
commit d958ca6953

@ -371,6 +371,12 @@ struct feature_group {
static AST_RWLIST_HEAD_STATIC(feature_groups, feature_group); static AST_RWLIST_HEAD_STATIC(feature_groups, feature_group);
typedef enum {
FEATURE_INTERPRET_DETECT, /* Used by ast_feature_detect */
FEATURE_INTERPRET_DO, /* Used by feature_interpret */
FEATURE_INTERPRET_CHECK, /* Used by feature_check */
} feature_interpret_op;
static char *parkedcall = "ParkedCall"; static char *parkedcall = "ParkedCall";
static char pickup_ext[AST_MAX_EXTENSION]; /*!< Call pickup extension */ static char pickup_ext[AST_MAX_EXTENSION]; /*!< Call pickup extension */
@ -2746,7 +2752,7 @@ static int remap_feature(const char *name, const char *value)
*/ */
static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel *peer, static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel *peer,
struct ast_bridge_config *config, const char *code, int sense, char *dynamic_features_buf, struct ast_bridge_config *config, const char *code, int sense, char *dynamic_features_buf,
struct ast_flags *features, int operation, struct ast_call_feature *feature) struct ast_flags *features, feature_interpret_op operation, struct ast_call_feature *feature)
{ {
int x; int x;
struct feature_group *fg = NULL; struct feature_group *fg = NULL;
@ -2756,7 +2762,7 @@ static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel
int res = AST_FEATURE_RETURN_PASSDIGITS; int res = AST_FEATURE_RETURN_PASSDIGITS;
int feature_detected = 0; int feature_detected = 0;
if (!(peer && chan && config) && operation) { if (!(peer && chan && config) && operation == FEATURE_INTERPRET_DO) {
return -1; /* can not run feature operation */ return -1; /* can not run feature operation */
} }
@ -2767,18 +2773,23 @@ static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel
/* Feature is up for consideration */ /* Feature is up for consideration */
if (!strcmp(builtin_features[x].exten, code)) { if (!strcmp(builtin_features[x].exten, code)) {
ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
if (operation) { if (operation == FEATURE_INTERPRET_CHECK) {
res = AST_FEATURE_RETURN_SUCCESS; /* We found something */
} else if (operation == FEATURE_INTERPRET_DO) {
res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
} }
if (feature) {
memcpy(feature, &builtin_features[x], sizeof(feature)); memcpy(feature, &builtin_features[x], sizeof(feature));
}
feature_detected = 1; feature_detected = 1;
break; break;
} else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
if (res == AST_FEATURE_RETURN_PASSDIGITS) if (res == AST_FEATURE_RETURN_PASSDIGITS) {
res = AST_FEATURE_RETURN_STOREDIGITS; res = AST_FEATURE_RETURN_STOREDIGITS;
} }
} }
} }
}
ast_rwlock_unlock(&features_lock); ast_rwlock_unlock(&features_lock);
if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
@ -2825,10 +2836,14 @@ static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel
/* Feature is up for consideration */ /* Feature is up for consideration */
if (!strcmp(tmpfeature->exten, code)) { if (!strcmp(tmpfeature->exten, code)) {
ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
if (operation) { if (operation == FEATURE_INTERPRET_CHECK) {
res = AST_FEATURE_RETURN_SUCCESS; /* We found something */
} else if (operation == FEATURE_INTERPRET_DO) {
res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
} }
if (feature) {
memcpy(feature, tmpfeature, sizeof(feature)); memcpy(feature, tmpfeature, sizeof(feature));
}
if (res != AST_FEATURE_RETURN_KEEPTRYING) { if (res != AST_FEATURE_RETURN_KEEPTRYING) {
AST_RWLIST_UNLOCK(&feature_list); AST_RWLIST_UNLOCK(&feature_list);
break; break;
@ -2876,13 +2891,19 @@ static int feature_interpret(struct ast_channel *chan, struct ast_channel *peer,
ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features_buf); ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features_buf);
return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature); return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, FEATURE_INTERPRET_DO, &feature);
} }
int ast_feature_detect(struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature) { int ast_feature_detect(struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature) {
return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature); return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_DETECT, feature);
}
/*! \brief Check if a feature exists */
static int feature_check(struct ast_channel *chan, struct ast_flags *features, char *code) {
return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, FEATURE_INTERPRET_CHECK, NULL);
} }
static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
@ -3419,6 +3440,7 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
int hasfeatures=0; int hasfeatures=0;
int hadfeatures=0; int hadfeatures=0;
int autoloopflag; int autoloopflag;
int sendingdtmfdigit = 0;
int we_disabled_peer_cdr = 0; int we_disabled_peer_cdr = 0;
struct ast_option_header *aoh; struct ast_option_header *aoh;
struct ast_cdr *bridge_cdr = NULL; struct ast_cdr *bridge_cdr = NULL;
@ -3427,6 +3449,7 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */ struct ast_cdr *peer_cdr = peer->cdr; /* the proper chan cdr, if there are forked cdrs */
struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
struct ast_silence_generator *silgen = NULL;
if (chan && peer) { if (chan && peer) {
pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
@ -3693,7 +3716,38 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
break; break;
} }
} else if (f->frametype == AST_FRAME_DTMF_BEGIN) { } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
/* eat it */ struct ast_flags *cfg;
char dtmfcode[2] = { f->subclass.integer, };
size_t featurelen;
if (who == chan) {
featurelen = strlen(chan_featurecode);
cfg = &(config->features_caller);
} else {
featurelen = strlen(peer_featurecode);
cfg = &(config->features_callee);
}
/* Take a peek if this (possibly) matches a feature. If not, just pass this
* DTMF along untouched. If this is not the first digit of a multi-digit code
* then we need to fall through and stream the characters if it matches */
if (featurelen == 0
&& feature_check(chan, cfg, &dtmfcode[0]) == AST_FEATURE_RETURN_PASSDIGITS) {
if (option_debug > 3) {
ast_log(LOG_DEBUG, "Passing DTMF through, since it is not a feature code\n");
}
ast_write(other, f);
sendingdtmfdigit = 1;
} else {
/* If ast_opt_transmit_silence is set, then we need to make sure we are
* transmitting something while we hold on to the DTMF waiting for a
* feature. */
if (!silgen && ast_opt_transmit_silence) {
silgen = ast_channel_start_silence_generator(other);
}
if (option_debug > 3) {
ast_log(LOG_DEBUG, "Not passing DTMF through, since it may be a feature code\n");
}
}
} else if (f->frametype == AST_FRAME_DTMF) { } else if (f->frametype == AST_FRAME_DTMF) {
char *featurecode; char *featurecode;
int sense; int sense;
@ -3707,6 +3761,13 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
sense = FEATURE_SENSE_PEER; sense = FEATURE_SENSE_PEER;
featurecode = peer_featurecode; featurecode = peer_featurecode;
} }
if (sendingdtmfdigit == 1) {
/* We let the BEGIN go through happily, so let's not bother with the END,
* since we already know it's not something we bother with */
ast_write(other, f);
sendingdtmfdigit = 0;
} else {
/*! append the event to featurecode. we rely on the string being zero-filled, and /*! append the event to featurecode. we rely on the string being zero-filled, and
* not overflowing it. * not overflowing it.
* \todo XXX how do we guarantee the latter ? * \todo XXX how do we guarantee the latter ?
@ -3715,6 +3776,10 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
/* Get rid of the frame before we start doing "stuff" with the channels */ /* Get rid of the frame before we start doing "stuff" with the channels */
ast_frfree(f); ast_frfree(f);
f = NULL; f = NULL;
if (silgen) {
ast_channel_stop_silence_generator(other, silgen);
silgen = NULL;
}
config->feature_timer = 0; config->feature_timer = 0;
res = feature_interpret(chan, peer, config, featurecode, sense); res = feature_interpret(chan, peer, config, featurecode, sense);
switch(res) { switch(res) {
@ -3744,12 +3809,19 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer); ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer);
} }
} }
}
if (f) if (f)
ast_frfree(f); ast_frfree(f);
} }
ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, NULL); ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, NULL);
before_you_go: before_you_go:
/* Just in case something weird happened and we didn't clean up the silence generator... */
if (silgen) {
ast_channel_stop_silence_generator(who == chan ? peer : chan, silgen);
silgen = NULL;
}
if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */

Loading…
Cancel
Save