From: Richard Mudgett Date: Thu, 23 Jan 2014 22:53:50 +0000 (+0000) Subject: Multiple revisions 375964,381466 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9aa3d65e39a669584624141740d76dbac8a81482;p=thirdparty%2Fasterisk.git Multiple revisions 375964,381466 ........ r375964 | rmudgett | 2012-11-06 12:18:32 -0600 (Tue, 06 Nov 2012) | 18 lines 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/ ........ r381466 | rmudgett | 2013-02-14 13:41:17 -0600 (Thu, 14 Feb 2013) | 7 lines End stuck DTMF if AST_SOFTHANGUP_ASYNCGOTO because it isn't a real hangup. It doesn't hurt to check AST_SOFTHANGUP_UNBRIDGE either, but it should not be set outside of a bridge. (issue ASTERISK-20492) ........ Merged revisions 375964,381466 from http://svn.asterisk.org/svn/asterisk/branches/1.8 git-svn-id: https://origsvn.digium.com/svn/asterisk/certified/branches/1.8.15@406310 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/.cleancount b/.cleancount index c7f5afc52a..425151f3a4 100644 --- a/.cleancount +++ b/.cleancount @@ -1,3 +1 @@ -39 - - +40 diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index cd59843abd..e0f1e084ea 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -870,6 +870,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 */ diff --git a/include/asterisk/features.h b/include/asterisk/features.h index 42dc57fba2..1246a5d9a0 100644 --- a/include/asterisk/features.h +++ b/include/asterisk/features.h @@ -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); diff --git a/main/channel.c b/main/channel.c index 222fb1bdc3..29dd1eab42 100644 --- a/main/channel.c +++ b/main/channel.c @@ -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 @@ -4627,6 +4628,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; @@ -4650,6 +4656,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); @@ -6457,6 +6469,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 @@ -6566,6 +6580,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 */ @@ -6806,6 +6824,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. diff --git a/main/features.c b/main/features.c index aa5916fea3..1d91a10413 100644 --- a/main/features.c +++ b/main/features.c @@ -3872,6 +3872,27 @@ 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) + || (chan->_softhangup + & ~(AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE)); + ast_channel_unlock(chan); + if (dead) { + /* Channel is a zombie or a real hangup. */ + 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 * @@ -4318,6 +4339,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);