Fix stuck DTMF when bridge is broken.

When a bridge is broken by an AMI Redirect action or the ChannelRedirect
application, an in progress DTMF digit could be stuck sending forever.

* Made simulate a DTMF end event when a bridge is broken and a DTMF digit
was in progress.

(closes issue ASTERISK-20492)
Reported by: Jeremiah Gowdy
Patches:
      bridge_end_dtmf-v3.patch.txt (license #6358) patch uploaded by Jeremiah Gowdy
      Modified to jira_asterisk_20492_v1.8.patch
      jira_asterisk_20492_v1.8.patch (license #5621) patch uploaded by rmudgett
Tested by: rmudgett

Review: https://reviewboard.asterisk.org/r/2169/
........

Merged revisions 375964 from http://svn.asterisk.org/svn/asterisk/branches/1.8


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/10@375965 65c4cc65-6c06-0410-ace0-fbb531ad65f3
10
Richard Mudgett 13 years ago
parent b381cb05c4
commit a92996da8e

@ -1,3 +1 @@
39
40

@ -874,6 +874,8 @@ struct ast_channel {
char macrocontext[AST_MAX_CONTEXT]; /*!< Macro: Current non-macro context. See app_macro.c */
char macroexten[AST_MAX_EXTENSION]; /*!< Macro: Current non-macro extension. See app_macro.c */
char emulate_dtmf_digit; /*!< Digit being emulated */
char sending_dtmf_digit; /*!< Digit this channel is currently sending out. (zero if not sending) */
struct timeval sending_dtmf_tv; /*!< The time this channel started sending the current digit. (Invalid if sending_dtmf_digit is zero.) */
};
/*! \brief ast_channel_tech Properties */

@ -169,6 +169,18 @@ int ast_parking_ext_valid(const char *exten_str, struct ast_channel *chan, const
/*! \brief Determine system call pickup extension */
const char *ast_pickup_ext(void);
/*!
* \brief Simulate a DTMF end on a broken bridge channel.
*
* \param chan Channel sending DTMF that has not ended.
* \param digit DTMF digit to stop.
* \param start DTMF digit start time.
* \param why Reason bridge broken.
*
* \return Nothing
*/
void ast_bridge_end_dtmf(struct ast_channel *chan, char digit, struct timeval start, const char *why);
/*! \brief Bridge a call, optionally allowing redirection */
int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer,struct ast_bridge_config *config);

@ -71,6 +71,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/stringfields.h"
#include "asterisk/global_datastores.h"
#include "asterisk/data.h"
#include "asterisk/features.h"
#ifdef HAVE_EPOLL
#include <sys/epoll.h>
@ -4740,6 +4741,11 @@ int ast_senddigit_begin(struct ast_channel *chan, char digit)
if (!chan->tech->send_digit_begin)
return 0;
ast_channel_lock(chan);
chan->sending_dtmf_digit = digit;
chan->sending_dtmf_tv = ast_tvnow();
ast_channel_unlock(chan);
if (!chan->tech->send_digit_begin(chan, digit))
return 0;
@ -4763,6 +4769,12 @@ int ast_senddigit_end(struct ast_channel *chan, char digit, unsigned int duratio
{
int res = -1;
ast_channel_lock(chan);
if (chan->sending_dtmf_digit == digit) {
chan->sending_dtmf_digit = 0;
}
ast_channel_unlock(chan);
if (chan->tech->send_digit_end)
res = chan->tech->send_digit_end(chan, digit, duration);
@ -6711,6 +6723,8 @@ int ast_do_masquerade(struct ast_channel *original)
char orig[AST_CHANNEL_NAME];
char masqn[AST_CHANNEL_NAME];
char zombn[AST_CHANNEL_NAME];
char clone_sending_dtmf_digit;
struct timeval clone_sending_dtmf_tv;
/* XXX This operation is a bit odd. We're essentially putting the guts of
* the clone channel into the original channel. Start by killing off the
@ -6820,6 +6834,10 @@ int ast_do_masquerade(struct ast_channel *original)
free_translation(clonechan);
free_translation(original);
/* Save the current DTMF digit being sent if any. */
clone_sending_dtmf_digit = clonechan->sending_dtmf_digit;
clone_sending_dtmf_tv = clonechan->sending_dtmf_tv;
/* Save the original name */
ast_copy_string(orig, original->name, sizeof(orig));
/* Save the new name */
@ -7064,6 +7082,15 @@ int ast_do_masquerade(struct ast_channel *original)
ast_channel_unlock(clonechan);
if (clone_sending_dtmf_digit) {
/*
* The clonechan was sending a DTMF digit that was not completed
* before the masquerade.
*/
ast_bridge_end_dtmf(original, clone_sending_dtmf_digit, clone_sending_dtmf_tv,
"masquerade");
}
/*
* If an indication is currently playing, maintain it on the
* channel that is taking the place of original.

@ -3910,6 +3910,24 @@ static void clear_dialed_interfaces(struct ast_channel *chan)
ast_channel_unlock(chan);
}
void ast_bridge_end_dtmf(struct ast_channel *chan, char digit, struct timeval start, const char *why)
{
int dead;
long duration;
ast_channel_lock(chan);
dead = ast_test_flag(chan, AST_FLAG_ZOMBIE) || ast_check_hangup(chan);
ast_channel_unlock(chan);
if (dead) {
return;
}
duration = ast_tvdiff_ms(ast_tvnow(), start);
ast_senddigit_end(chan, digit, duration);
ast_log(LOG_DTMF, "DTMF end '%c' simulated on %s due to %s, duration %ld ms\n",
digit, chan->name, why, duration);
}
/*!
* \brief bridge the call and set CDR
*
@ -4357,6 +4375,15 @@ int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct a
ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer);
before_you_go:
if (chan->sending_dtmf_digit) {
ast_bridge_end_dtmf(chan, chan->sending_dtmf_digit, chan->sending_dtmf_tv,
"bridge end");
}
if (peer->sending_dtmf_digit) {
ast_bridge_end_dtmf(peer, peer->sending_dtmf_digit, peer->sending_dtmf_tv,
"bridge end");
}
/* 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);

Loading…
Cancel
Save