diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h index fecca1dd2e..8fa0f36ede 100644 --- a/include/asterisk/bridge.h +++ b/include/asterisk/bridge.h @@ -241,6 +241,8 @@ struct ast_bridge_methods { ast_bridge_notify_masquerade_fn notify_masquerade; /*! Get the bridge merge priority. */ ast_bridge_merge_priority_fn get_merge_priority; + /*! Peek at swap channel before it can hang up, prior to push. */ + ast_bridge_push_channel_fn push_peek; }; /*! Softmix technology parameters. */ diff --git a/main/bridge.c b/main/bridge.c index 9fb6e32232..c1fc145c6e 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -904,6 +904,26 @@ static int bridge_base_get_merge_priority(struct ast_bridge *self) return 0; } +/*! + * \internal + * \brief ast_bridge base push_peek method. + * \since 13.2.0 + * + * \param self Bridge to operate upon. + * \param bridge_channel Bridge channel to push. + * \param swap Bridge channel to swap places with if not NULL. + * + * \note On entry, self is already locked. + * \note Stub because of nothing to do. + * + * \retval 0 on success + * \retval -1 on failure + */ +static int bridge_base_push_peek(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap) +{ + return 0; +} + struct ast_bridge_methods ast_bridge_base_v_table = { .name = "base", .destroy = bridge_base_destroy, @@ -912,6 +932,7 @@ struct ast_bridge_methods ast_bridge_base_v_table = { .pull = bridge_base_pull, .notify_masquerade = bridge_base_notify_masquerade, .get_merge_priority = bridge_base_get_merge_priority, + .push_peek = bridge_base_push_peek, }; struct ast_bridge *ast_bridge_base_new(uint32_t capabilities, unsigned int flags, const char *creator, const char *name, const char *id) @@ -1589,6 +1610,18 @@ int ast_bridge_join(struct ast_bridge *bridge, bridge_channel->features = features; bridge_channel->inhibit_colp = !!(flags & AST_BRIDGE_JOIN_INHIBIT_JOIN_COLP); + /* allow subclass to peek at upcoming push operation */ + if (bridge->v_table->push_peek && !res) { + struct ast_bridge_channel *bcswap = NULL; + + ast_bridge_lock(bridge); + if (bridge_channel->swap) { + bcswap = bridge_find_channel(bridge, bridge_channel->swap); + } + res = bridge->v_table->push_peek(bridge, bridge_channel, bcswap); + ast_bridge_unlock(bridge); + } + if (!res) { res = bridge_channel_internal_join(bridge_channel); } @@ -1724,6 +1757,18 @@ int ast_bridge_impart(struct ast_bridge *bridge, (flags & AST_BRIDGE_IMPART_CHAN_MASK) == AST_BRIDGE_IMPART_CHAN_DEPARTABLE; bridge_channel->callid = ast_read_threadstorage_callid(); + /* allow subclass to peek at swap channel before it can hangup */ + if (bridge->v_table->push_peek && !res) { + struct ast_bridge_channel *bcswap = NULL; + + ast_bridge_lock(bridge); + if (bridge_channel->swap) { + bcswap = bridge_find_channel(bridge, bridge_channel->swap); + } + res = bridge->v_table->push_peek(bridge, bridge_channel, bcswap); + ast_bridge_unlock(bridge); + } + /* Actually create the thread that will handle the channel */ if (!res) { if ((flags & AST_BRIDGE_IMPART_CHAN_MASK) == AST_BRIDGE_IMPART_CHAN_INDEPENDENT) { diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c index 657238417c..e410881341 100644 --- a/res/stasis/stasis_bridge.c +++ b/res/stasis/stasis_bridge.c @@ -97,6 +97,56 @@ static void bridge_stasis_queue_join_action(struct ast_bridge *self, ast_channel_unlock(bridge_channel->chan); } +/*! + * \internal + * \brief Peek at channel before it is pushed into bridge + * \since 13.2.0 + * + * \param self Bridge to operate upon. + * \param bridge_channel Bridge channel to push. + * \param swap Bridge channel to swap places with if not NULL. + * + * \note On entry, self is already locked. + * + * \retval 0 on success. + * \retval -1 on failure. The channel should not be pushed. + */ +static int bridge_stasis_push_peek(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap) +{ + struct stasis_app_control *swap_control; + struct ast_channel_snapshot *to_be_replaced; + + if (!swap) { + goto done; + } + + swap_control = stasis_app_control_find_by_channel(swap->chan); + if (!swap_control) { + ast_log(LOG_ERROR,"Failed to find stasis app control for swapped channel %s\n", ast_channel_name(swap->chan)); + return -1; + } + to_be_replaced = ast_channel_snapshot_get_latest(ast_channel_uniqueid(swap->chan)); + + ast_debug(3, "Copying stasis app name %s from %s to %s\n", app_name(control_app(swap_control)), + ast_channel_name(swap->chan), ast_channel_name(bridge_channel->chan)); + + ast_channel_lock(bridge_channel->chan); + + /* copy the app name from the swap channel */ + app_set_replace_channel_app(bridge_channel->chan, app_name(control_app(swap_control))); + + /* set the replace channel snapshot */ + app_set_replace_channel_snapshot(bridge_channel->chan, to_be_replaced); + + ast_channel_unlock(bridge_channel->chan); + + ao2_ref(swap_control, -1); + ao2_cleanup(to_be_replaced); + +done: + return ast_bridge_base_v_table.push_peek(self, bridge_channel, swap); +} + /*! * \internal * \brief Push this channel into the Stasis bridge. @@ -115,27 +165,6 @@ static int bridge_stasis_push(struct ast_bridge *self, struct ast_bridge_channel { struct stasis_app_control *control = stasis_app_control_find_by_channel(bridge_channel->chan); - if (swap) { - struct ast_channel_snapshot *to_be_replaced = ast_channel_snapshot_get_latest(ast_channel_uniqueid(swap->chan)); - struct stasis_app_control *swap_control = stasis_app_control_find_by_channel(swap->chan); - - /* set the replace channel snapshot */ - ast_channel_lock(bridge_channel->chan); - app_set_replace_channel_snapshot(bridge_channel->chan, to_be_replaced); - - /* copy the app name from the swap channel */ - if (swap_control) { - ast_debug(3, "Copying stasis app name %s from %s to %s\n", - app_name(control_app(swap_control)), - ast_channel_name(swap->chan), - ast_channel_name(bridge_channel->chan)); - app_set_replace_channel_app(bridge_channel->chan, app_name(control_app(swap_control))); - } - ast_channel_unlock(bridge_channel->chan); - ao2_cleanup(to_be_replaced); - ao2_cleanup(swap_control); - } - if (!control && !stasis_app_channel_is_internal(bridge_channel->chan)) { /* channel not in Stasis(), get it there */ /* Attach after-bridge callback and pass ownership of swap_app to it */ @@ -256,4 +285,5 @@ void bridge_stasis_init(void) bridge_stasis_v_table.name = "stasis"; bridge_stasis_v_table.push = bridge_stasis_push; bridge_stasis_v_table.pull = bridge_stasis_pull; + bridge_stasis_v_table.push_peek = bridge_stasis_push_peek; }