diff options
author | Richard Mudgett <rmudgett@digium.com> | 2013-08-23 18:33:36 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2013-08-23 18:33:36 +0000 |
commit | 6ebfac8e70b0863fd96ee4fe6ca4b254696fe9c4 (patch) | |
tree | df6a91c733cc32ae5179493b800384824dcdcfa3 /main/bridge_channel.c | |
parent | 31ab4866275aa28f6ec9fe7ce166b4f86f8ecf24 (diff) |
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
Diffstat (limited to 'main/bridge_channel.c')
-rw-r--r-- | main/bridge_channel.c | 81 |
1 files changed, 56 insertions, 25 deletions
diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 385be6d3e..7e26f6598 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -346,6 +346,24 @@ static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, * simple_bridge/native_bridge are likely the only techs that will do this. */ bridge_channel->bridge->technology->write(bridge_channel->bridge, bridge_channel, frame); + + /* Remember any owed events to the bridge. */ + switch (frame->frametype) { + case AST_FRAME_DTMF_BEGIN: + bridge_channel->owed.dtmf_tv = ast_tvnow(); + bridge_channel->owed.dtmf_digit = frame->subclass.integer; + break; + case AST_FRAME_DTMF_END: + bridge_channel->owed.dtmf_digit = '\0'; + break; + case AST_FRAME_CONTROL: + /* + * We explicitly will not remember HOLD/UNHOLD frames because + * things like attended transfers will handle them. + */ + default: + break; + } ast_bridge_unlock(bridge_channel->bridge); /* @@ -355,6 +373,27 @@ static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, return 0; } +void bridge_channel_settle_owed_events(struct ast_bridge *orig_bridge, struct ast_bridge_channel *bridge_channel) +{ + if (bridge_channel->owed.dtmf_digit) { + struct ast_frame frame = { + .frametype = AST_FRAME_DTMF_END, + .subclass.integer = bridge_channel->owed.dtmf_digit, + .src = "Bridge channel owed DTMF", + }; + + frame.len = ast_tvdiff_ms(ast_tvnow(), bridge_channel->owed.dtmf_tv); + if (frame.len < option_dtmfminduration) { + frame.len = option_dtmfminduration; + } + ast_log(LOG_DTMF, "DTMF end '%c' simulated to bridge %s because %s left. Duration %ld ms.\n", + bridge_channel->owed.dtmf_digit, orig_bridge->uniqueid, + ast_channel_name(bridge_channel->chan), frame.len); + bridge_channel->owed.dtmf_digit = '\0'; + orig_bridge->technology->write(orig_bridge, NULL, &frame); + } +} + /*! * \internal * \brief Suspend a channel from a bridge. @@ -719,14 +758,14 @@ void ast_bridge_channel_playfile(struct ast_bridge_channel *bridge_channel, ast_ /* * It may be necessary to resume music on hold after we finish * playing the announcment. - * - * XXX We have no idea what MOH class was in use before playing - * the file. This method also fails to restore ringing indications. - * the proposed solution is to create a resume_entertainment callback - * for the bridge technology and execute it here. */ if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_MOH)) { - ast_moh_start(bridge_channel->chan, NULL, NULL); + const char *latest_musicclass; + + ast_channel_lock(bridge_channel->chan); + latest_musicclass = ast_strdupa(ast_channel_latest_musicclass(bridge_channel->chan)); + ast_channel_unlock(bridge_channel->chan); + ast_moh_start(bridge_channel->chan, latest_musicclass, NULL); } } @@ -1420,8 +1459,6 @@ void bridge_channel_internal_pull(struct ast_bridge_channel *bridge_channel) bridge->v_table->name, bridge->uniqueid); -/* BUGBUG This is where incoming HOLD/UNHOLD memory should write UNHOLD into bridge. (if not local optimizing) */ -/* BUGBUG This is where incoming DTMF begin/end memory should write DTMF end into bridge. (if not local optimizing) */ if (!bridge_channel->just_joined) { /* Tell the bridge technology we are leaving so they tear us down */ ast_debug(1, "Bridge %s: %p(%s) is leaving %s technology\n", @@ -1559,17 +1596,6 @@ static void bridge_channel_handle_control(struct ast_bridge_channel *bridge_chan ast_indicate_data(chan, fr->subclass.integer, fr->data.ptr, fr->datalen); } break; - case AST_CONTROL_HOLD: - case AST_CONTROL_UNHOLD: -/* - * BUGBUG bridge_channels should remember sending/receiving an outstanding HOLD to/from the bridge - * - * When the sending channel is pulled from the bridge it needs to write into the bridge an UNHOLD before being pulled. - * When the receiving channel is pulled from the bridge it needs to generate its own UNHOLD. - * Something similar needs to be done for DTMF begin/end. - */ - ast_indicate_data(chan, fr->subclass.integer, fr->data.ptr, fr->datalen); - break; case AST_CONTROL_OPTION: /* * Forward option Requests, but only ones we know are safe These @@ -1720,7 +1746,6 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel) ast_bridge_channel_kick(bridge_channel, 0); ast_frfree(frame); return; -/* BUGBUG This is where incoming HOLD/UNHOLD memory should register. Write UNHOLD into bridge when this channel is pulled. */ default: break; } @@ -1735,7 +1760,6 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel) ast_frfree(frame); return; } -/* BUGBUG This is where incoming DTMF begin/end memory should register. Write DTMF end into bridge when this channel is pulled. */ break; default: break; @@ -1887,6 +1911,7 @@ static void bridge_channel_event_join_leave(struct ast_bridge_channel *bridge_ch int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel) { int res = 0; + ast_format_copy(&bridge_channel->read_format, ast_channel_readformat(bridge_channel->chan)); ast_format_copy(&bridge_channel->write_format, ast_channel_writeformat(bridge_channel->chan)); @@ -1952,15 +1977,18 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel) } bridge_channel_internal_pull(bridge_channel); + bridge_channel_settle_owed_events(bridge_channel->bridge, bridge_channel); bridge_reconfigured(bridge_channel->bridge, 1); ast_bridge_unlock(bridge_channel->bridge); - /* Indicate a source change since this channel is leaving the bridge system. */ - ast_indicate(bridge_channel->chan, AST_CONTROL_SRCCHANGE); + /* Complete any active hold before exiting the bridge. */ + if (ast_channel_hold_state(bridge_channel->chan) == AST_CONTROL_HOLD) { + ast_debug(1, "Channel %s simulating UNHOLD for bridge end.\n", + ast_channel_name(bridge_channel->chan)); + ast_indicate(bridge_channel->chan, AST_CONTROL_UNHOLD); + } -/* BUGBUG Revisit in regards to moving channels between bridges and local channel optimization. */ -/* BUGBUG This is where outgoing HOLD/UNHOLD memory should write UNHOLD to channel. */ /* Complete any partial DTMF digit before exiting the bridge. */ if (ast_channel_sending_dtmf_digit(bridge_channel->chan)) { ast_channel_end_dtmf(bridge_channel->chan, @@ -1968,6 +1996,9 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel) ast_channel_sending_dtmf_tv(bridge_channel->chan), "bridge end"); } + /* Indicate a source change since this channel is leaving the bridge system. */ + ast_indicate(bridge_channel->chan, AST_CONTROL_SRCCHANGE); + /* * Wait for any dual redirect to complete. * |