From 6ebfac8e70b0863fd96ee4fe6ca4b254696fe9c4 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 23 Aug 2013 18:33:36 +0000 Subject: Handle DTMF and hold wrapup when a channel leaves the bridging system. DTMF start/end and hold/unhold events have state because a DTMF begin event and hold event must be ended by something. The following cases need to be handled when a channel is moved around in the system. * When a channel leaves a bridge it may owe a DTMF end event to the bridge. * When a channel leaves a bridge it may owe an UNHOLD event to the bridge. (This case is explicitly ignored because things like transfers need explicit control over this.) * When a channel leaves the bridging system it may need to simulate a DTMF end event to the channel. * When a channel leaves the bridging system it may need to simulate an UNHOLD event to the channel. The patch also fixes the following: * Fixes playing a file and restarting MOH using the latest MOH class used. (closes issue ASTERISK-22043) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2791/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397577 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- main/channel.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) (limited to 'main/channel.c') diff --git a/main/channel.c b/main/channel.c index 1abed5e94..f085d31e8 100644 --- a/main/channel.c +++ b/main/channel.c @@ -941,6 +941,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char /* Initial state */ ast_channel_state_set(tmp, state); + ast_channel_hold_state_set(tmp, AST_CONTROL_UNHOLD); ast_channel_streamid_set(tmp, -1); @@ -1072,6 +1073,8 @@ struct ast_channel *ast_dummy_channel_alloc(void) ast_channel_epfd_set(tmp, -1); #endif + ast_channel_hold_state_set(tmp, AST_CONTROL_UNHOLD); + ast_channel_internal_setup_topics(tmp); headp = ast_channel_varshead(tmp); @@ -4453,7 +4456,6 @@ int ast_indicate_data(struct ast_channel *chan, int _condition, ast_channel_connected(chan)); } break; - case AST_CONTROL_REDIRECTING: { struct ast_party_redirecting redirecting; @@ -4466,7 +4468,10 @@ int ast_indicate_data(struct ast_channel *chan, int _condition, ast_party_redirecting_free(&redirecting); } break; - + case AST_CONTROL_HOLD: + case AST_CONTROL_UNHOLD: + ast_channel_hold_state_set(chan, condition); + break; default: break; } @@ -6376,6 +6381,7 @@ void ast_do_masquerade(struct ast_channel *original) int origstate; int visible_indication; int clone_was_zombie = 0;/*!< TRUE if the clonechan was a zombie before the masquerade. */ + int clone_hold_state; struct ast_frame *current; const struct ast_channel_tech *t; void *t_pvt; @@ -6478,6 +6484,8 @@ void ast_do_masquerade(struct ast_channel *original) free_translation(clonechan); free_translation(original); + clone_hold_state = ast_channel_hold_state(clonechan); + /* 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); @@ -6712,6 +6720,11 @@ void ast_do_masquerade(struct ast_channel *original) ast_bridge_notify_masquerade(original); + if (clone_hold_state == AST_CONTROL_HOLD) { + ast_debug(1, "Channel %s simulating UNHOLD for masquerade.\n", + ast_channel_name(original)); + ast_indicate(original, AST_CONTROL_UNHOLD); + } if (clone_sending_dtmf_digit) { /* * The clonechan was sending a DTMF digit that was not completed @@ -6731,7 +6744,23 @@ void ast_do_masquerade(struct ast_channel *original) * (RINGING, CONGESTION, etc.) */ if (visible_indication) { - ast_indicate(original, visible_indication); + if (visible_indication == AST_CONTROL_HOLD) { + const char *latest_musicclass; + int len; + + ast_channel_lock(original); + latest_musicclass = ast_strdupa(ast_channel_latest_musicclass(original)); + ast_channel_unlock(original); + if (ast_strlen_zero(latest_musicclass)) { + latest_musicclass = NULL; + len = 0; + } else { + len = strlen(latest_musicclass) + 1; + } + ast_indicate_data(original, visible_indication, latest_musicclass, len); + } else { + ast_indicate(original, visible_indication); + } } ast_channel_lock(original); @@ -10390,6 +10419,9 @@ void ast_channel_end_dtmf(struct ast_channel *chan, char digit, struct timeval s } duration = ast_tvdiff_ms(ast_tvnow(), start); + if (duration < option_dtmfminduration) { + duration = option_dtmfminduration; + } 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); -- cgit v1.2.3