static void safe_bridge_destroy(struct ast_bridge *bridge) { if (!bridge) { return; } ast_bridge_destroy(bridge, 0); }
static void wait_bridge_wrapper_destructor(void *obj) { struct wait_bridge_wrapper *wrapper = obj; if (wrapper->bridge) { ast_bridge_destroy(wrapper->bridge, 0); } }
static int manager_bridge_destroy(struct mansession *s, const struct message *m) { const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid"); struct ast_bridge *bridge; if (ast_strlen_zero(bridge_uniqueid)) { astman_send_error(s, m, "BridgeUniqueid must be provided"); return 0; } bridge = ast_bridge_find_by_id(bridge_uniqueid); if (!bridge) { astman_send_error(s, m, "Specified BridgeUniqueid not found"); return 0; } ast_bridge_destroy(bridge, 0); astman_send_ack(s, m, "Bridge has been destroyed"); return 0; }
/*! * \internal * \since 12.0.0 * \brief Allocate a new holding bridge wrapper with the given bridge name and bridge ID. * * \param bridge_name name of the bridge wrapper * \param bridge the bridge being wrapped * * \retval Pointer to the newly allocated holding bridge wrapper * \retval NULL if allocation failed. The bridge will be destroyed if this function fails. */ static struct wait_bridge_wrapper *wait_bridge_wrapper_alloc(const char *bridge_name, struct ast_bridge *bridge) { struct wait_bridge_wrapper *bridge_wrapper; bridge_wrapper = ao2_alloc_options(sizeof(*bridge_wrapper) + strlen(bridge_name) + 1, wait_bridge_wrapper_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!bridge_wrapper) { ast_bridge_destroy(bridge, 0); return NULL; } strcpy(bridge_wrapper->name, bridge_name); bridge_wrapper->bridge = bridge; if (!ao2_link(wait_bridge_wrappers, bridge_wrapper)) { ao2_cleanup(bridge_wrapper); return NULL; } return bridge_wrapper; }
/*! \brief Internal built in feature for attended transfers */ static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) { char exten[AST_MAX_EXTENSION] = ""; struct ast_channel *chan = NULL; struct ast_bridge *attended_bridge = NULL; struct ast_bridge_features caller_features, called_features; enum ast_bridge_channel_state attended_bridge_result; struct ast_bridge_features_attended_transfer *attended_transfer = hook_pvt; const char *context = (attended_transfer && !ast_strlen_zero(attended_transfer->context) ? attended_transfer->context : bridge_channel->chan->context); /* Grab the extension to transfer to */ if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) { ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY); ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT); return 0; } /* Get a channel that is the destination we wish to call */ if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) { ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY); ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT); return 0; } /* Create a bridge to use to talk to the person we are calling */ if (!(attended_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_1TO1MIX, 0))) { ast_hangup(chan); ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY); ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT); return 0; } /* Setup our called features structure so that if they hang up we immediately get thrown out of the bridge */ ast_bridge_features_init(&called_features); ast_bridge_features_set_flag(&called_features, AST_BRIDGE_FLAG_DISSOLVE); /* This is how this is going down, we are imparting the channel we called above into this bridge first */ ast_bridge_impart(attended_bridge, chan, NULL, &called_features); /* Before we join setup a features structure with the hangup option, just in case they want to use DTMF */ ast_bridge_features_init(&caller_features); ast_bridge_features_enable(&caller_features, AST_BRIDGE_BUILTIN_HANGUP, (attended_transfer && !ast_strlen_zero(attended_transfer->complete) ? attended_transfer->complete : "*1"), NULL); ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->threeway) ? attended_transfer->threeway : "*2"), attended_threeway_transfer, NULL); ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->abort) ? attended_transfer->abort : "*3"), attended_abort_transfer, NULL); /* But for the caller we want to join the bridge in a blocking fashion so we don't spin around in this function doing nothing while waiting */ attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features); /* Since the above returned the caller features structure is of no more use */ ast_bridge_features_cleanup(&caller_features); /* Drop the channel we are transferring to out of the above bridge since it has ended */ if ((attended_bridge_result != AST_BRIDGE_CHANNEL_STATE_HANGUP) && !ast_bridge_depart(attended_bridge, chan)) { /* If the user wants to turn this into a threeway transfer then do so, otherwise they take our place */ if (attended_bridge_result == AST_BRIDGE_CHANNEL_STATE_DEPART) { /* We want to impart them upon the bridge and just have us return to it as normal */ ast_bridge_impart(bridge, chan, NULL, NULL); } else { ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL); } } else { ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY); ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT); } /* Now that all channels are out of it we can destroy the bridge and the called features structure */ ast_bridge_features_cleanup(&called_features); ast_bridge_destroy(attended_bridge); return 0; }
/*! * \brief Bridge channels together * \param s * \param m * * Make sure valid channels were specified, * send errors if any of the channels could not be found/locked, answer channels if needed, * create the placeholder channels and grab the other channels * make the channels compatible, send error if we fail doing so * setup the bridge thread object and start the bridge. * * \retval 0 */ static int action_bridge(struct mansession *s, const struct message *m) { const char *channela = astman_get_header(m, "Channel1"); const char *channelb = astman_get_header(m, "Channel2"); enum play_tone_action playtone = parse_playtone(astman_get_header(m, "Tone")); RAII_VAR(struct ast_channel *, chana, NULL, ao2_cleanup); RAII_VAR(struct ast_channel *, chanb, NULL, ao2_cleanup); const char *chana_exten; const char *chana_context; int chana_priority; const char *chanb_exten; const char *chanb_context; int chanb_priority; struct ast_bridge *bridge; char buf[256]; RAII_VAR(struct ast_features_xfer_config *, xfer_cfg_a, NULL, ao2_cleanup); RAII_VAR(struct ast_features_xfer_config *, xfer_cfg_b, NULL, ao2_cleanup); /* make sure valid channels were specified */ if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { astman_send_error(s, m, "Missing channel parameter in request"); return 0; } ast_debug(1, "Performing Bridge action on %s and %s\n", channela, channelb); /* Start with chana */ chana = ast_channel_get_by_name_prefix(channela, strlen(channela)); if (!chana) { snprintf(buf, sizeof(buf), "Channel1 does not exist: %s", channela); astman_send_error(s, m, buf); return 0; } ast_channel_lock(chana); xfer_cfg_a = ast_get_chan_features_xfer_config(chana); chana_exten = ast_strdupa(ast_channel_exten(chana)); chana_context = ast_strdupa(ast_channel_context(chana)); chana_priority = ast_channel_priority(chana); if (!ast_test_flag(ast_channel_flags(chana), AST_FLAG_IN_AUTOLOOP)) { chana_priority++; } ast_channel_unlock(chana); chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb)); if (!chanb) { snprintf(buf, sizeof(buf), "Channel2 does not exist: %s", channelb); astman_send_error(s, m, buf); return 0; } ast_channel_lock(chanb); xfer_cfg_b = ast_get_chan_features_xfer_config(chanb); chanb_exten = ast_strdupa(ast_channel_exten(chanb)); chanb_context = ast_strdupa(ast_channel_context(chanb)); chanb_priority = ast_channel_priority(chanb); if (!ast_test_flag(ast_channel_flags(chanb), AST_FLAG_IN_AUTOLOOP)) { chanb_priority++; } ast_channel_unlock(chanb); bridge = ast_bridge_basic_new(); if (!bridge) { astman_send_error(s, m, "Unable to create bridge\n"); return 0; } ast_bridge_set_after_go_on(chana, chana_context, chana_exten, chana_priority, NULL); if (ast_bridge_add_channel(bridge, chana, NULL, playtone & PLAYTONE_CHANNEL1, xfer_cfg_a ? xfer_cfg_a->xfersound : NULL)) { snprintf(buf, sizeof(buf), "Unable to add Channel1 to bridge: %s", ast_channel_name(chana)); astman_send_error(s, m, buf); ast_bridge_destroy(bridge, 0); return 0; } ast_bridge_set_after_go_on(chanb, chanb_context, chanb_exten, chanb_priority, NULL); if (ast_bridge_add_channel(bridge, chanb, NULL, playtone & PLAYTONE_CHANNEL2, xfer_cfg_b ? xfer_cfg_b->xfersound : NULL)) { snprintf(buf, sizeof(buf), "Unable to add Channel2 to bridge: %s", ast_channel_name(chanb)); astman_send_error(s, m, buf); ast_bridge_destroy(bridge, 0); return 0; } astman_send_ack(s, m, "Channels have been bridged"); ao2_cleanup(bridge); return 0; }
int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, unsigned int flags) { int res; struct ast_bridge *bridge; struct ast_bridge_features chan_features; struct ast_bridge_features *peer_features; /* Setup features. */ res = ast_bridge_features_init(&chan_features); peer_features = ast_bridge_features_new(); if (res || !peer_features) { ast_bridge_features_destroy(peer_features); ast_bridge_features_cleanup(&chan_features); bridge_failed_peer_goto(chan, peer); return -1; } if (pre_bridge_setup(chan, peer, config, &chan_features, peer_features)) { ast_bridge_features_destroy(peer_features); ast_bridge_features_cleanup(&chan_features); bridge_failed_peer_goto(chan, peer); return -1; } /* Create bridge */ bridge = ast_bridge_basic_new(); if (!bridge) { ast_bridge_features_destroy(peer_features); ast_bridge_features_cleanup(&chan_features); bridge_failed_peer_goto(chan, peer); return -1; } ast_bridge_basic_set_flags(bridge, flags); /* Put peer into the bridge */ if (ast_bridge_impart(bridge, peer, NULL, peer_features, AST_BRIDGE_IMPART_CHAN_INDEPENDENT | AST_BRIDGE_IMPART_INHIBIT_JOIN_COLP)) { ast_bridge_destroy(bridge, 0); ast_bridge_features_cleanup(&chan_features); bridge_failed_peer_goto(chan, peer); return -1; } /* Join bridge */ ast_bridge_join(bridge, chan, NULL, &chan_features, NULL, AST_BRIDGE_JOIN_PASS_REFERENCE | AST_BRIDGE_JOIN_INHIBIT_JOIN_COLP); /* * If the bridge was broken for a hangup that isn't real, then * don't run the h extension, because the channel isn't really * hung up. This should really only happen with * AST_SOFTHANGUP_ASYNCGOTO. */ res = -1; ast_channel_lock(chan); if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) { res = 0; } ast_channel_unlock(chan); ast_bridge_features_cleanup(&chan_features); if (res && config->end_bridge_callback) { config->end_bridge_callback(config->end_bridge_callback_data); } return res; }