mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-02 02:18:31 +00:00
Fix CLI "bridge kick <bridge> <channel>" to check if the bridge needs dissolving.
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. * Added ast_bridge_kick() as a companion to ast_bridge_remove(). The functional difference is that ast_bridge_kick() may dissolve the bridge as a result of the channel leaving the bridge. * Made CLI "bridge kick <bridge> <channel>" use ast_bridge_kick() instead of ast_bridge_remove() so the bridge can dissolve if needed. * Renamed bridge_channel_handle_hangup() to ast_bridge_channel_kick() and made it accessible to other files. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@396877 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -562,6 +562,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
|
||||
*
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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. */
|
||||
|
Reference in New Issue
Block a user