diff options
author | Richard Mudgett <rmudgett@digium.com> | 2016-04-15 14:36:59 -0500 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2016-04-20 15:45:46 -0500 |
commit | a036c359036a4b8e6b51f53d51c707658cbf77ff (patch) | |
tree | 9fa0007f0634e7b06c5aeed724b5a31f5596d035 /res/stasis/stasis_bridge.c | |
parent | 9942d50aa5cca7f864344069e924d9b254380638 (diff) |
res_stasis: Handle re-enter stasis bridge with swap channel.
We lose the fact that there is a swap channel if there is one. We
currently wind up rejoining the stasis bridge as a normal join after the
swap channel has already been kicked from the bridge.
This patch preserves the swap channel so the AMI/ARI events can note that
the channel joining the bridge is swapping with another channel. Another
benefit to swaqpping in one operation is if there are any channels that
get lonely (MOH, bridge playback, and bridge record channels). The lonely
channels won't leave before the joining channel has a chance to come back
in under stasis if the swap channel is the only reason the lonely channels
are staying in the bridge.
ASTERISK-25947 #close
Reported by: Richard Mudgett
ASTERISK-24649
Reported by: John Bigelow
ASTERISK-24782
Reported by: John Bigelow
Change-Id: If37ea508831d1fed6dbfac2f191c638fc0a850ee
Diffstat (limited to 'res/stasis/stasis_bridge.c')
-rw-r--r-- | res/stasis/stasis_bridge.c | 54 |
1 files changed, 40 insertions, 14 deletions
diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c index f97673d78..9ffc2d7be 100644 --- a/res/stasis/stasis_bridge.c +++ b/res/stasis/stasis_bridge.c @@ -76,24 +76,54 @@ static void bridge_stasis_run_cb(struct ast_channel *chan, void *data) pbx_exec(chan, app_stasis, app_name); } -static int add_channel_to_bridge( +struct defer_bridge_add_obj { + /*! Bridge to join (has ref) */ + struct ast_bridge *bridge; + /*! + * \brief Channel to swap with in the bridge. (has ref) + * + * \note NULL if not swapping with a channel. + */ + struct ast_channel *swap; +}; + +static void defer_bridge_add_dtor(void *obj) +{ + struct defer_bridge_add_obj *defer = obj; + + ao2_cleanup(defer->bridge); + ast_channel_cleanup(defer->swap); +} + +static int defer_bridge_add( struct stasis_app_control *control, struct ast_channel *chan, void *obj) { - struct ast_bridge *bridge = obj; - int res; + struct defer_bridge_add_obj *defer = obj; - res = control_add_channel_to_bridge(control, - chan, bridge); - return res; + return control_swap_channel_in_bridge(control, defer->bridge, chan, defer->swap); } static void bridge_stasis_queue_join_action(struct ast_bridge *self, - struct ast_bridge_channel *bridge_channel) + struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap) { + struct defer_bridge_add_obj *defer; + + defer = ao2_alloc_options(sizeof(*defer), defer_bridge_add_dtor, + AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!defer) { + return; + } + ao2_ref(self, +1); + defer->bridge = self; + if (swap) { + ast_channel_ref(swap->chan); + defer->swap = swap->chan; + } + ast_channel_lock(bridge_channel->chan); - command_prestart_queue_command(bridge_channel->chan, add_channel_to_bridge, - ao2_bump(self), __ao2_cleanup); + command_prestart_queue_command(bridge_channel->chan, defer_bridge_add, + defer, __ao2_cleanup); ast_channel_unlock(bridge_channel->chan); } @@ -179,11 +209,7 @@ static int bridge_stasis_push(struct ast_bridge *self, struct ast_bridge_channel return -1; } - bridge_stasis_queue_join_action(self, bridge_channel); - if (swap) { - /* nudge the swap channel out of the bridge */ - ast_bridge_channel_leave_bridge(swap, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, 0); - } + bridge_stasis_queue_join_action(self, bridge_channel, swap); /* Return -1 so the push fails and the after-bridge callback gets called * This keeps the bridging framework from putting the channel into the bridge |