diff options
-rw-r--r-- | include/asterisk/bridge.h | 31 | ||||
-rw-r--r-- | include/asterisk/bridge_channel.h | 13 | ||||
-rw-r--r-- | main/bridge.c | 43 | ||||
-rw-r--r-- | main/bridge_channel.c | 25 |
4 files changed, 78 insertions, 34 deletions
diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h index 973490769..9522962bc 100644 --- a/include/asterisk/bridge.h +++ b/include/asterisk/bridge.h @@ -563,6 +563,37 @@ int ast_bridge_depart(struct ast_channel *chan); int ast_bridge_remove(struct ast_bridge *bridge, struct ast_channel *chan); /*! + * \brief Kick a channel from a bridge + * + * \param bridge Bridge that the channel is to be kicked from + * \param chan Channel to kick + * + * \retval 0 on success + * \retval -1 on failure + * + * Example usage: + * + * \code + * ast_bridge_kick(bridge, chan); + * \endcode + * + * \details + * This kicks the channel pointed to by the chan pointer from + * the bridge pointed to by the bridge pointer and requests that + * it be hung up. Control over the channel will NOT be given to + * the calling thread. + * + * \note The functional difference between ast_bridge_kick() and + * ast_bridge_remove() is that the bridge may dissolve as a + * result of the channel being kicked. + * + * \note This API call can be used on channels that were added + * to the bridge using both ast_bridge_join and + * ast_bridge_impart. + */ +int ast_bridge_kick(struct ast_bridge *bridge, struct ast_channel *chan); + +/*! * \brief Merge two bridges together * * \param dst_bridge Destination bridge of merge. diff --git a/include/asterisk/bridge_channel.h b/include/asterisk/bridge_channel.h index 32ef66248..39526611a 100644 --- a/include/asterisk/bridge_channel.h +++ b/include/asterisk/bridge_channel.h @@ -583,6 +583,19 @@ int ast_bridge_channel_queue_callback(struct ast_bridge_channel *bridge_channel, int ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid, const char *parker_uuid, const char *app_data); +/*! + * \brief Kick the channel out of the bridge. + * \since 12.0.0 + * + * \param bridge_channel Which channel is being kicked or hungup. + * + * \note This is intended to be called by bridge hooks and the + * bridge channel thread. + * + * \return Nothing + */ +void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/bridge.c b/main/bridge.c index 1c25303d1..a9ee02b94 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -1681,6 +1681,31 @@ int ast_bridge_remove(struct ast_bridge *bridge, struct ast_channel *chan) return 0; } +static void kick_it(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size) +{ + ast_bridge_channel_kick(bridge_channel); +} + +int ast_bridge_kick(struct ast_bridge *bridge, struct ast_channel *chan) +{ + struct ast_bridge_channel *bridge_channel; + int res; + + ast_bridge_lock(bridge); + + /* Try to find the channel that we want to kick. */ + if (!(bridge_channel = bridge_find_channel(bridge, chan))) { + ast_bridge_unlock(bridge); + return -1; + } + + res = ast_bridge_channel_queue_callback(bridge_channel, kick_it, NULL, 0); + + ast_bridge_unlock(bridge); + + return res; +} + /*! * \internal * \brief Point the bridge_channel to a new bridge. @@ -4651,25 +4676,9 @@ static char *handle_bridge_kick_channel(struct ast_cli_entry *e, int cmd, struct return CLI_SUCCESS; } -/* - * BUGBUG the CLI kick needs to get the bridge to decide if it should dissolve. - * - * Likely the best way to do this is to add a kick method. The - * basic bridge class can then decide to dissolve the bridge if - * one of two channels is kicked. - * - * SIP/foo -- Local;1==Local;2 -- .... -- Local;1==Local;2 -- SIP/bar - * Kick a ;1 channel and the chain toward SIP/foo goes away. - * Kick a ;2 channel and the chain toward SIP/bar goes away. - * - * This can leave a local channel chain between the kicked ;1 - * and ;2 channels that are orphaned until you manually request - * one of those channels to hangup or request the bridge to - * dissolve. - */ ast_cli(a->fd, "Kicking channel '%s' from bridge '%s'\n", ast_channel_name(chan), a->argv[2]); - ast_bridge_remove(bridge, chan); + ast_bridge_kick(bridge, chan); return CLI_SUCCESS; } diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 6a96b1e3b..ae9d65cd5 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -263,16 +263,7 @@ void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_ch } } -/*! -* \internal -* \brief Handle bridge hangup event. -* \since 12.0.0 -* -* \param bridge_channel Which channel is hanging up. -* -* \return Nothing -*/ -static void bridge_channel_handle_hangup(struct ast_bridge_channel *bridge_channel) +void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel) { struct ast_bridge_features *features = bridge_channel->features; struct ast_bridge_hook *hook; @@ -522,7 +513,7 @@ void ast_bridge_channel_run_app(struct ast_bridge_channel *bridge_channel, const } if (run_app_helper(bridge_channel->chan, app_name, S_OR(app_args, ""))) { /* Break the bridge if the app returns non-zero. */ - bridge_channel_handle_hangup(bridge_channel); + ast_bridge_channel_kick(bridge_channel); } if (moh_class) { ast_bridge_channel_write_unhold(bridge_channel); @@ -1100,7 +1091,7 @@ static void bridge_channel_feature(struct ast_bridge_channel *bridge_channel, co * here if the hook did not already change the state. */ if (bridge_channel->chan && ast_check_hangup_locked(bridge_channel->chan)) { - bridge_channel_handle_hangup(bridge_channel); + ast_bridge_channel_kick(bridge_channel); } } else if (features->dtmf_passthrough) { /* Stream any collected DTMF to the other channels. */ @@ -1213,7 +1204,7 @@ static void bridge_channel_blind_transfer(struct ast_bridge_channel *bridge_chan struct blind_transfer_data *blind_data) { ast_async_goto(bridge_channel->chan, blind_data->context, blind_data->exten, 1); - bridge_channel_handle_hangup(bridge_channel); + ast_bridge_channel_kick(bridge_channel); } /*! @@ -1229,7 +1220,7 @@ static void bridge_channel_attended_transfer(struct ast_bridge_channel *bridge_c chan_target = ast_channel_get_by_name(target_chan_name); if (!chan_target) { /* Dang, it disappeared somehow */ - bridge_channel_handle_hangup(bridge_channel); + ast_bridge_channel_kick(bridge_channel); return; } @@ -1246,7 +1237,7 @@ static void bridge_channel_attended_transfer(struct ast_bridge_channel *bridge_c /* Release the ref we tried to pass to ast_bridge_set_after_callback(). */ ast_channel_unref(chan_target); } - bridge_channel_handle_hangup(bridge_channel); + ast_bridge_channel_kick(bridge_channel); } /*! @@ -1674,14 +1665,14 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel) } if (!frame) { - bridge_channel_handle_hangup(bridge_channel); + ast_bridge_channel_kick(bridge_channel); return; } switch (frame->frametype) { case AST_FRAME_CONTROL: switch (frame->subclass.integer) { case AST_CONTROL_HANGUP: - bridge_channel_handle_hangup(bridge_channel); + ast_bridge_channel_kick(bridge_channel); ast_frfree(frame); return; /* BUGBUG This is where incoming HOLD/UNHOLD memory should register. Write UNHOLD into bridge when this channel is pulled. */ |