diff -urN asterisk-10.9.0-rc2.orig/include/asterisk/channel.h asterisk-10.9.0-rc2/include/asterisk/channel.h --- asterisk-10.9.0-rc2.orig/include/asterisk/channel.h 2012-06-11 10:08:50.000000000 -0700 +++ asterisk-10.9.0-rc2/include/asterisk/channel.h 2012-10-04 15:01:19.738388025 -0700 @@ -874,6 +874,7 @@ 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 current_dtmf_digit; /*!< Digit in progress */ }; /*! \brief ast_channel_tech Properties */ diff -urN asterisk-10.9.0-rc2.orig/main/channel.c asterisk-10.9.0-rc2/main/channel.c --- asterisk-10.9.0-rc2.orig/main/channel.c 2012-09-10 10:14:46.000000000 -0700 +++ asterisk-10.9.0-rc2/main/channel.c 2012-10-04 15:01:19.742387860 -0700 @@ -4085,6 +4085,7 @@ case AST_FRAME_DTMF_END: send_dtmf_event(chan, "Received", f->subclass.integer, "No", "Yes"); ast_log(LOG_DTMF, "DTMF end '%c' received on %s, duration %ld ms\n", f->subclass.integer, chan->name, f->len); + chan->current_dtmf_digit = 0; /* Queue it up if DTMF is deferred, or if DTMF emulation is forced. */ if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF) || ast_test_flag(chan, AST_FLAG_EMULATE_DTMF)) { queue_dtmf_readq(chan, f); @@ -4177,6 +4178,7 @@ ast_frfree(f); f = &ast_null_frame; } else { + chan->current_dtmf_digit = f->subclass.integer; ast_set_flag(chan, AST_FLAG_IN_DTMF); chan->dtmf_tv = ast_tvnow(); ast_log(LOG_DTMF, "DTMF begin passthrough '%c' on %s\n", f->subclass.integer, chan->name); @@ -6583,6 +6585,21 @@ } } +static void bridge_end_dtmf(struct ast_channel *c0, struct ast_channel *c1) +{ + struct ast_frame *f; + + if (ast_test_flag(c1, AST_FLAG_ZOMBIE) || ast_check_hangup(c1)) + return; + + f = &c1->dtmff; + f->frametype = AST_FRAME_DTMF_END; + f->subclass.integer = c0->current_dtmf_digit; + f->len = ast_tvdiff_ms(ast_tvnow(), c0->dtmf_tv); + ast_log(LOG_DTMF, "Simulating end of DTMF '%c' due to unbridge on %s\n", c0->current_dtmf_digit, c1->name); + ast_write(c1, f); +} + /*! * \pre chan is locked */ @@ -6682,6 +6699,7 @@ } exchange; struct ast_channel *clonechan, *chans[2]; struct ast_channel *bridged; + struct ast_channel *bridgepeer; struct ast_cdr *cdr; struct ast_datastore *xfer_ds; struct xfer_masquerade_ds *xfer_colp; @@ -6783,6 +6801,10 @@ ast_debug(4, "Actually Masquerading %s(%d) into the structure of %s(%d)\n", clonechan->name, clonechan->_state, original->name, original->_state); + if ((bridgepeer = ast_bridged_channel(clonechan))) { + ast_channel_ref(bridgepeer); + } + chans[0] = clonechan; chans[1] = original; ast_manager_event_multichan(EVENT_FLAG_CALL, "Masquerade", 2, chans, @@ -7074,9 +7096,20 @@ ast_channel_unref(bridged); } else { ast_channel_unlock(original); + + /* + * If clonechan was bridged and original is now unbridged, + * end any in-progress DTMF that was being relayed. + */ + if (bridgepeer && bridgepeer->current_dtmf_digit) { + bridge_end_dtmf(bridgepeer, original); + } } ast_indicate(original, AST_CONTROL_SRCCHANGE); + if (bridgepeer) + ast_channel_unref(bridgepeer); + if (xfer_colp) { /* * After the masquerade, the original channel pointer actually @@ -7832,6 +7865,12 @@ } } + if (c0->current_dtmf_digit) + bridge_end_dtmf(c0, c1); + + if (c1->current_dtmf_digit) + bridge_end_dtmf(c1, c0); + ast_clear_flag(c0, AST_FLAG_END_DTMF_ONLY); ast_clear_flag(c1, AST_FLAG_END_DTMF_ONLY);