summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2016-04-15 14:36:59 -0500
committerRichard Mudgett <rmudgett@digium.com>2016-04-20 15:44:30 -0500
commit6b1a632290567b0d482b57a07fe94ecbca164b7d (patch)
treef954fc6515ff5a0f687acb98ee9d3e3e5568d83e
parent1c5248c3839a3b8f6295d4ed94765bfe0d718ef9 (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
-rw-r--r--res/stasis/control.c12
-rw-r--r--res/stasis/control.h18
-rw-r--r--res/stasis/stasis_bridge.c54
3 files changed, 60 insertions, 24 deletions
diff --git a/res/stasis/control.c b/res/stasis/control.c
index 3c5b75041..aa6866aee 100644
--- a/res/stasis/control.c
+++ b/res/stasis/control.c
@@ -903,11 +903,8 @@ static void bridge_after_cb_failed(enum ast_bridge_after_cb_reason reason,
ast_bridge_after_cb_reason_string(reason));
}
-int control_add_channel_to_bridge(
- struct stasis_app_control *control,
- struct ast_channel *chan, void *data)
+int control_swap_channel_in_bridge(struct stasis_app_control *control, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap)
{
- struct ast_bridge *bridge = data;
int res;
if (!control || !bridge) {
@@ -960,7 +957,7 @@ int control_add_channel_to_bridge(
res = ast_bridge_impart(bridge,
chan,
- NULL, /* swap channel */
+ swap,
NULL, /* features */
AST_BRIDGE_IMPART_CHAN_DEPARTABLE);
if (res != 0) {
@@ -976,6 +973,11 @@ int control_add_channel_to_bridge(
return 0;
}
+int control_add_channel_to_bridge(struct stasis_app_control *control, struct ast_channel *chan, void *data)
+{
+ return control_swap_channel_in_bridge(control, data, chan, NULL);
+}
+
int stasis_app_control_add_channel_to_bridge(
struct stasis_app_control *control, struct ast_bridge *bridge)
{
diff --git a/res/stasis/control.h b/res/stasis/control.h
index 1d37a494a..868a8091b 100644
--- a/res/stasis/control.h
+++ b/res/stasis/control.h
@@ -111,12 +111,20 @@ struct stasis_app *control_app(struct stasis_app_control *control);
* \brief Command callback for adding a channel to a bridge
*
* \param control The control for chan
- * \param channel The channel on which commands should be executed
- * \param bridge Data to be passed to the callback
+ * \param chan The channel on which commands should be executed
+ * \param data Bridge to be passed to the callback
+ */
+int control_add_channel_to_bridge(struct stasis_app_control *control, struct ast_channel *chan, void *data);
+
+/*!
+ * \brief Command for swapping a channel in a bridge
+ *
+ * \param control The control for chan
+ * \param chan The channel on which commands should be executed
+ * \param bridge Bridge to be passed to the callback
+ * \param swap Channel to swap with when joining the bridge
*/
-int control_add_channel_to_bridge(
- struct stasis_app_control *control,
- struct ast_channel *chan, void *obj);
+int control_swap_channel_in_bridge(struct stasis_app_control *control, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap);
/*!
* \brief Stop playing silence to a channel right now.
diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c
index bfd287226..aa21ec29c 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