summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzuul <zuul@gerrit.asterisk.org>2016-04-22 17:08:06 -0500
committerGerrit Code Review <gerrit2@gerrit.digium.api>2016-04-22 17:08:06 -0500
commitac50fdecdbdd574e8f433a30c1149bbed9951b68 (patch)
tree3347d883a4fb8c4b5dd515eb12423650175fe2de
parent1df086f821520d1b6e960d3304fb62137ae783f7 (diff)
parent6b1a632290567b0d482b57a07fe94ecbca164b7d (diff)
Merge "res_stasis: Handle re-enter stasis bridge with swap channel."
-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