Exemple #1
0
static int bridgeadd_exec(struct ast_channel *chan, const char *data)
{
	struct ast_channel *c_ref;
	struct ast_bridge_features chan_features;
	struct ast_bridge *bridge;
	char *c_name;

	/* Answer the channel if needed */
	if (ast_channel_state(chan) != AST_STATE_UP) {
		ast_answer(chan);
	}

	if (!(c_ref = ast_channel_get_by_name_prefix(data, strlen(data)))) {
		ast_log(LOG_WARNING, "Channel %s not found\n", data);
		return -1;
	}

	c_name = ast_strdupa(ast_channel_name(c_ref));

	ast_channel_lock(c_ref);
	bridge = ast_channel_get_bridge(c_ref);
	ast_channel_unlock(c_ref);

	ast_channel_unref(c_ref);

	if (!bridge) {
		ast_log(LOG_WARNING, "Channel %s is not in a bridge\n", c_name);
		return -1;
	}

	ast_verb(3, "%s is joining %s in bridge %s\n", ast_channel_name(chan),
		c_name, bridge->uniqueid);

	if (ast_bridge_features_init(&chan_features)
		|| ast_bridge_join(bridge, chan, NULL, &chan_features, NULL, 0)) {

		ast_log(LOG_WARNING, "%s failed to join %s in bridge %s\n", ast_channel_name(chan),
			 c_name, bridge->uniqueid);

		ast_bridge_features_cleanup(&chan_features);
		ao2_cleanup(bridge);
		return -1;
	}

	ast_bridge_features_cleanup(&chan_features);
	ao2_cleanup(bridge);
	return 0;
}
/*! \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;
}
Exemple #3
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;
}