static void after_bridge_move_channel(struct ast_channel *chan_bridged, void *data)
{
RAII_VAR(struct ast_channel *, chan_target, data, ao2_cleanup);
- ast_channel_move(chan_target, chan_bridged);
+
+ if (ast_channel_move(chan_target, chan_bridged)) {
+ ast_softhangup(chan_target, AST_SOFTHANGUP_DEV);
+ }
}
static void after_bridge_move_channel_fail(enum ast_after_bridge_cb_reason reason, void *data)
RAII_VAR(struct ast_channel *, chan_target, data, ao2_cleanup);
ast_log(LOG_WARNING, "Unable to complete transfer: %s\n",
- ast_after_bridge_cb_reason_string(reason));
+ ast_after_bridge_cb_reason_string(reason));
+ ast_softhangup(chan_target, AST_SOFTHANGUP_DEV);
}
static void bridge_channel_attended_transfer(struct ast_bridge_channel *bridge_channel,
chan_target = ast_channel_get_by_name(target_chan_name);
if (!chan_target) {
/* Dang, it disappeared somehow */
+ bridge_handle_hangup(bridge_channel);
return;
}
- {
- SCOPED_CHANNELLOCK(lock, bridge_channel);
- chan_bridged = bridge_channel->chan;
- if (!chan_bridged) {
- return;
- }
- ao2_ref(chan_bridged, +1);
- }
+ ast_bridge_channel_lock(bridge_channel);
+ chan_bridged = bridge_channel->chan;
+ ast_assert(chan_bridged != NULL);
+ ao2_ref(chan_bridged, +1);
+ ast_bridge_channel_unlock(bridge_channel);
if (ast_after_bridge_callback_set(chan_bridged, after_bridge_move_channel,
- after_bridge_move_channel_fail, ast_channel_ref(chan_target))) {
- return;
+ after_bridge_move_channel_fail, ast_channel_ref(chan_target))) {
+ ast_softhangup(chan_target, AST_SOFTHANGUP_DEV);
+
+ /* Release the ref we tried to pass to ast_after_bridge_callback_set(). */
+ ast_channel_unref(chan_target);
}
bridge_handle_hangup(bridge_channel);
}
}
ast_copy_string(unbridged_chan_name, ast_channel_name(unbridged_chan),
- sizeof(unbridged_chan_name));
+ sizeof(unbridged_chan_name));
ast_bridge_channel_queue_action_data(transferee_bridge_channel,
- AST_BRIDGE_ACTION_ATTENDED_TRANSFER, unbridged_chan_name,
- sizeof(unbridged_chan_name));
+ AST_BRIDGE_ACTION_ATTENDED_TRANSFER, unbridged_chan_name,
+ sizeof(unbridged_chan_name));
return 0;
}
{
SCOPED_LOCK(lock, bridge, ast_bridge_lock, ast_bridge_unlock);
+
channels = ast_bridge_peers_nolock(bridge);
if (!channels) {
return AST_BRIDGE_TRANSFER_FAIL;
struct ast_bridge_channel *bridged_to_source;
bridged_to_source = ast_bridge_channel_peer(source_bridge_channel);
- if (bridged_to_source && bridged_to_source->state == AST_BRIDGE_CHANNEL_STATE_WAIT
- && !ast_test_flag(&bridged_to_source->features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE)) {
+ if (bridged_to_source
+ && bridged_to_source->state == AST_BRIDGE_CHANNEL_STATE_WAIT
+ && !ast_test_flag(&bridged_to_source->features->feature_flags,
+ AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE)) {
bridged_to_source->swap = swap_channel;
- return bridge_move_do(dest_bridge, bridged_to_source, 1) ?
- AST_BRIDGE_TRANSFER_FAIL : AST_BRIDGE_TRANSFER_SUCCESS;
+ if (bridge_move_do(dest_bridge, bridged_to_source, 1)) {
+ return AST_BRIDGE_TRANSFER_FAIL;
+ }
+ /* Must kick the source channel out of its bridge. */
+ ast_bridge_change_state(source_bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ return AST_BRIDGE_TRANSFER_SUCCESS;
} else {
return AST_BRIDGE_TRANSFER_INVALID;
}