mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-03 11:25:35 +00:00
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 ........ Merged revisions 375965 from http://svn.asterisk.org/svn/asterisk/branches/10 ........ Merged revisions 375966 from http://svn.asterisk.org/svn/asterisk/branches/11 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@375967 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -3835,6 +3835,10 @@ void ast_channel_macroexten_set(struct ast_channel *chan, const char *value);
|
||||
|
||||
char ast_channel_dtmf_digit_to_emulate(const struct ast_channel *chan);
|
||||
void ast_channel_dtmf_digit_to_emulate_set(struct ast_channel *chan, char value);
|
||||
char ast_channel_sending_dtmf_digit(const struct ast_channel *chan);
|
||||
void ast_channel_sending_dtmf_digit_set(struct ast_channel *chan, char value);
|
||||
struct timeval ast_channel_sending_dtmf_tv(const struct ast_channel *chan);
|
||||
void ast_channel_sending_dtmf_tv_set(struct ast_channel *chan, struct timeval value);
|
||||
int ast_channel_amaflags(const struct ast_channel *chan);
|
||||
void ast_channel_amaflags_set(struct ast_channel *chan, int value);
|
||||
int ast_channel_epfd(const struct ast_channel *chan);
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -72,6 +72,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/global_datastores.h"
|
||||
#include "asterisk/data.h"
|
||||
#include "asterisk/channel_internal.h"
|
||||
#include "asterisk/features.h"
|
||||
|
||||
/*** DOCUMENTATION
|
||||
***/
|
||||
@@ -4778,6 +4779,11 @@ int ast_senddigit_begin(struct ast_channel *chan, char digit)
|
||||
if (!ast_channel_tech(chan)->send_digit_begin)
|
||||
return 0;
|
||||
|
||||
ast_channel_lock(chan);
|
||||
ast_channel_sending_dtmf_digit_set(chan, digit);
|
||||
ast_channel_sending_dtmf_tv_set(chan, ast_tvnow());
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
if (!ast_channel_tech(chan)->send_digit_begin(chan, digit))
|
||||
return 0;
|
||||
|
||||
@@ -4804,6 +4810,12 @@ int ast_senddigit_end(struct ast_channel *chan, char digit, unsigned int duratio
|
||||
if (ast_channel_tech(chan)->send_digit_end)
|
||||
res = ast_channel_tech(chan)->send_digit_end(chan, digit, duration);
|
||||
|
||||
ast_channel_lock(chan);
|
||||
if (ast_channel_sending_dtmf_digit(chan) == digit) {
|
||||
ast_channel_sending_dtmf_digit_set(chan, 0);
|
||||
}
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
if (res && ast_channel_generator(chan))
|
||||
ast_playtones_stop(chan);
|
||||
|
||||
@@ -6835,6 +6847,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
|
||||
@@ -6963,6 +6977,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 = ast_channel_sending_dtmf_digit(clonechan);
|
||||
clone_sending_dtmf_tv = ast_channel_sending_dtmf_tv(clonechan);
|
||||
|
||||
/* Save the original name */
|
||||
ast_copy_string(orig, ast_channel_name(original), sizeof(orig));
|
||||
/* Save the new name */
|
||||
@@ -7207,6 +7225,15 @@ int ast_do_masquerade(struct ast_channel *original)
|
||||
ast_channel_unlock(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.
|
||||
|
@@ -193,6 +193,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 dtmf_digit_to_emulate; /*!< 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.) */
|
||||
};
|
||||
|
||||
/* AST_DATA definitions, which will probably have to be re-thought since the channel will be opaque */
|
||||
@@ -523,6 +525,25 @@ void ast_channel_dtmf_digit_to_emulate_set(struct ast_channel *chan, char value)
|
||||
{
|
||||
chan->dtmf_digit_to_emulate = value;
|
||||
}
|
||||
|
||||
char ast_channel_sending_dtmf_digit(const struct ast_channel *chan)
|
||||
{
|
||||
return chan->sending_dtmf_digit;
|
||||
}
|
||||
void ast_channel_sending_dtmf_digit_set(struct ast_channel *chan, char value)
|
||||
{
|
||||
chan->sending_dtmf_digit = value;
|
||||
}
|
||||
|
||||
struct timeval ast_channel_sending_dtmf_tv(const struct ast_channel *chan)
|
||||
{
|
||||
return chan->sending_dtmf_tv;
|
||||
}
|
||||
void ast_channel_sending_dtmf_tv_set(struct ast_channel *chan, struct timeval value)
|
||||
{
|
||||
chan->sending_dtmf_tv = value;
|
||||
}
|
||||
|
||||
int ast_channel_amaflags(const struct ast_channel *chan)
|
||||
{
|
||||
return chan->amaflags;
|
||||
|
@@ -4249,6 +4249,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(ast_channel_flags(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, ast_channel_name(chan), why, duration);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief bridge the call and set CDR
|
||||
*
|
||||
@@ -4698,6 +4716,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 (ast_channel_sending_dtmf_digit(chan)) {
|
||||
ast_bridge_end_dtmf(chan, ast_channel_sending_dtmf_digit(chan),
|
||||
ast_channel_sending_dtmf_tv(chan), "bridge end");
|
||||
}
|
||||
if (ast_channel_sending_dtmf_digit(peer)) {
|
||||
ast_bridge_end_dtmf(peer, ast_channel_sending_dtmf_digit(peer),
|
||||
ast_channel_sending_dtmf_tv(peer), "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);
|
||||
|
Reference in New Issue
Block a user