[asterisk-commits] mmichelson: branch mmichelson/more_transfer r387857 - /team/mmichelson/more_t...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue May 7 15:24:12 CDT 2013


Author: mmichelson
Date: Tue May  7 15:24:10 2013
New Revision: 387857

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=387857
Log:
Get the Bridge application working properly.

This took a bit of work to be able to pull off properly, but
the big change is that ast_bridge_call() has some code factored
out that the Bridge application also uses.


Modified:
    team/mmichelson/more_transfer/main/features.c

Modified: team/mmichelson/more_transfer/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/more_transfer/main/features.c?view=diff&rev=387857&r1=387856&r2=387857
==============================================================================
--- team/mmichelson/more_transfer/main/features.c (original)
+++ team/mmichelson/more_transfer/main/features.c Tue May  7 15:24:10 2013
@@ -4606,24 +4606,10 @@
 	}
 }
 
-/*!
- * \brief bridge the call and set CDR
- *
- * \param chan The bridge considers this channel the caller.
- * \param peer The bridge considers this channel the callee.
- * \param config Configuration for this bridge.
- *
- * Set start time, check for two channels,check if monitor on
- * check for feature activation, create new CDR
- * \retval res on success.
- * \retval -1 on failure to bridge.
- */
-int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
+static int pre_bridge_setup(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config,
+		struct ast_bridge_features *chan_features, struct ast_bridge_features *peer_features)
 {
 	int res;
-	struct ast_bridge *bridge;
-	struct ast_bridge_features chan_features;
-	struct ast_bridge_features *peer_features;
 
 /* BUGBUG these channel vars may need to be made dynamic so they update when transfers happen. */
 	pbx_builtin_setvar_helper(chan, "BRIDGEPEER", ast_channel_name(peer));
@@ -4656,7 +4642,6 @@
 	/* Answer if need be */
 	if (ast_channel_state(chan) != AST_STATE_UP) {
 		if (ast_raw_answer(chan, 1)) {
-			bridge_failed_peer_goto(chan, peer);
 			return -1;
 		}
 	}
@@ -4685,10 +4670,69 @@
 	ast_channel_lock(peer);
 	res |= ast_bridge_features_ds_set(peer, &config->features_callee);
 	ast_channel_unlock(peer);
+
 	if (res) {
-		bridge_failed_peer_goto(chan, peer);
 		return -1;
 	}
+
+	if (config->timelimit) {
+		struct ast_bridge_features_limits call_duration_limits_chan;
+		struct ast_bridge_features_limits call_duration_limits_peer;
+		int abandon_call = 0; /* TRUE if set limits fails so we can abandon the call. */
+
+		if (ast_bridge_features_limits_construct(&call_duration_limits_chan)) {
+			ast_log(LOG_ERROR, "Could not construct caller duration limits. Bridge canceled.\n");
+
+			return -1;
+		}
+
+		if (ast_bridge_features_limits_construct(&call_duration_limits_peer)) {
+			ast_log(LOG_ERROR, "Could not construct callee duration limits. Bridge canceled.\n");
+			ast_bridge_features_limits_destroy(&call_duration_limits_chan);
+
+			return -1;
+		}
+
+		bridge_config_set_limits(config, &call_duration_limits_chan, &call_duration_limits_peer);
+
+		if (ast_bridge_features_set_limits(chan_features, &call_duration_limits_chan, 0)) {
+			abandon_call = 1;
+		}
+		if (ast_bridge_features_set_limits(peer_features, &call_duration_limits_peer, 0)) {
+			abandon_call = 1;
+		}
+
+		/* At this point we are done with the limits structs since they have been copied to the individual feature sets. */
+		ast_bridge_features_limits_destroy(&call_duration_limits_chan);
+		ast_bridge_features_limits_destroy(&call_duration_limits_peer);
+
+		if (abandon_call) {
+			ast_log(LOG_ERROR, "Could not set duration limits on one or more sides of the call. Bridge canceled.\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*!
+ * \brief bridge the call and set CDR
+ *
+ * \param chan The bridge considers this channel the caller.
+ * \param peer The bridge considers this channel the callee.
+ * \param config Configuration for this bridge.
+ *
+ * Set start time, check for two channels,check if monitor on
+ * check for feature activation, create new CDR
+ * \retval res on success.
+ * \retval -1 on failure to bridge.
+ */
+int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
+{
+	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);
@@ -4700,50 +4744,11 @@
 		return -1;
 	}
 
-	if (config->timelimit) {
-		struct ast_bridge_features_limits call_duration_limits_chan;
-		struct ast_bridge_features_limits call_duration_limits_peer;
-		int abandon_call = 0; /* TRUE if set limits fails so we can abandon the call. */
-
-		if (ast_bridge_features_limits_construct(&call_duration_limits_chan)) {
-			ast_log(LOG_ERROR, "Could not construct caller duration limits. Bridge canceled.\n");
-
-			ast_bridge_features_destroy(peer_features);
-			ast_bridge_features_cleanup(&chan_features);
-			bridge_failed_peer_goto(chan, peer);
-			return -1;
-		}
-
-		if (ast_bridge_features_limits_construct(&call_duration_limits_peer)) {
-			ast_log(LOG_ERROR, "Could not construct callee duration limits. Bridge canceled.\n");
-			ast_bridge_features_limits_destroy(&call_duration_limits_chan);
-
-			ast_bridge_features_destroy(peer_features);
-			ast_bridge_features_cleanup(&chan_features);
-			bridge_failed_peer_goto(chan, peer);
-			return -1;
-		}
-
-		bridge_config_set_limits(config, &call_duration_limits_chan, &call_duration_limits_peer);
-
-		if (ast_bridge_features_set_limits(&chan_features, &call_duration_limits_chan, 0)) {
-			abandon_call = 1;
-		}
-		if (ast_bridge_features_set_limits(peer_features, &call_duration_limits_peer, 0)) {
-			abandon_call = 1;
-		}
-
-		/* At this point we are done with the limits structs since they have been copied to the individual feature sets. */
-		ast_bridge_features_limits_destroy(&call_duration_limits_chan);
-		ast_bridge_features_limits_destroy(&call_duration_limits_peer);
-
-		if (abandon_call) {
-			ast_log(LOG_ERROR, "Could not set duration limits on one or more sides of the call. Bridge canceled.\n");
-			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 */
@@ -7132,48 +7137,8 @@
 	return CLI_SUCCESS;
 }
 
-/*!
- * \brief Actual bridge
- * \param chan
- * \param tmpchan
- *
- * Stop hold music, lock both channels, masq channels,
- * after bridge return channel to next priority.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
-{
-	const char *context;
-	const char *exten;
-	int priority;
-
-	ast_moh_stop(chan);
-	ast_channel_lock_both(chan, tmpchan);
-	context = ast_strdupa(ast_channel_context(chan));
-	exten = ast_strdupa(ast_channel_exten(chan));
-	priority = ast_channel_priority(chan);
-	ast_setstate(tmpchan, ast_channel_state(chan));
-	ast_format_copy(ast_channel_readformat(tmpchan), ast_channel_readformat(chan));
-	ast_format_copy(ast_channel_writeformat(tmpchan), ast_channel_writeformat(chan));
-	ast_channel_unlock(chan);
-	ast_channel_unlock(tmpchan);
-
-	/* Masquerade setup and execution must be done without any channel locks held */
-	if (ast_channel_masquerade(tmpchan, chan)) {
-		return -1;
-	}
-	ast_do_masquerade(tmpchan);
-
-	/* when returning from bridge, the channel will continue at the next priority */
-	ast_explicit_goto(tmpchan, context, exten, priority + 1);
-
-	return 0;
-}
-
 static int add_to_bridge(struct ast_bridge *bridge, struct ast_channel *chan,
-		char buf[], size_t size, int play_tone)
+		struct ast_bridge_features *features, int play_tone)
 {
 	RAII_VAR(struct ast_bridge *, chan_bridge, NULL, ao2_cleanup);
 	struct ast_channel *bridge_chan;
@@ -7185,6 +7150,13 @@
 	if (chan_bridge) {
 		/* XXX Is there a way to play the tone to chan before moving it? A
 		 * bridge action on the channel's bridge_channel perhaps?
+		 */
+		/* XXX ast_bridge_move() does not take an ast_bridge_features
+		 * parameter. I could presumably get the channel's bridge_channel
+		 * and substitute the features directly onto the bridge_channel.
+		 * However, because of inconsistencies with allocation of features,
+		 * I can't know whether I need to free the old bridge features or
+		 * if attempting to free the bridge features will cause a crash.
 		 */
 		return ast_bridge_move(bridge, chan_bridge, chan, NULL, 1);
 	}
@@ -7194,7 +7166,7 @@
 	 */
 	bridge_chan = ast_channel_yank(chan);
 	if (!bridge_chan) {
-		snprintf(buf, size, "Could not gain control of channel %s\n", ast_channel_name(chan));
+		ast_log(LOG_WARNING, "Could not gain control of channel %s\n", ast_channel_name(chan));
 		return -1;
 	}
 	if (ast_channel_state(bridge_chan) != AST_STATE_UP) {
@@ -7207,8 +7179,8 @@
 					ast_channel_name(bridge_chan));
 		}
 	}
-	if (ast_bridge_impart(bridge, bridge_chan, NULL, NULL, 1)) {
-		snprintf(buf, size, "Could not add %s to the bridge\n", ast_channel_name(chan));
+	if (ast_bridge_impart(bridge, bridge_chan, NULL, features, 1)) {
+		ast_log(LOG_WARNING, "Could not add %s to the bridge\n", ast_channel_name(chan));
 		return -1;
 	}
 	return 0;
@@ -7264,12 +7236,14 @@
 		return 0;
 	}
 
-	if (add_to_bridge(bridge, chana, buf, sizeof(buf), ast_true(playtone))) {
+	if (add_to_bridge(bridge, chana, NULL, ast_true(playtone))) {
+		snprintf(buf, sizeof(buf), "Unable to add Channel1 to bridge: %s", channela);
 		astman_send_error(s, m, buf);
 		return 0;
 	}
 
-	if (add_to_bridge(bridge, chanb, buf, sizeof(buf), ast_true(playtone))) {
+	if (add_to_bridge(bridge, chanb, NULL, ast_true(playtone))) {
+		snprintf(buf, sizeof(buf), "Unable to add Channel2 to bridge: %s", channelb);
 		astman_send_error(s, m, buf);
 		return 0;
 	}
@@ -7995,8 +7969,7 @@
  */
 static int bridge_exec(struct ast_channel *chan, const char *data)
 {
-	struct ast_channel *current_dest_chan;
-	struct ast_channel *final_dest_chan;
+	RAII_VAR(struct ast_channel *, current_dest_chan, NULL, ao2_cleanup);
 	struct ast_channel *chans[2];
 	char *tmp_data  = NULL;
 	struct ast_flags opts = { 0, };
@@ -8006,6 +7979,9 @@
 	const char *context;
 	const char *extension;
 	int priority;
+	struct ast_bridge_features chan_features;
+	struct ast_bridge_features *peer_features;
+	struct ast_bridge *bridge;
 
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(dest_chan);
@@ -8057,20 +8033,6 @@
 		return 0;
 	}
 
-	/* try to allocate a place holder where current_dest_chan will be placed */
-	if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
-		NULL, NULL, ast_channel_linkedid(current_dest_chan), 0, "Bridge/%s", ast_channel_name(current_dest_chan)))) {
-		ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
-		ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
-			"Response: Failed\r\n"
-			"Reason: Cannot create placeholder channel\r\n"
-			"Channel1: %s\r\n"
-			"Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan);
-		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
-		ast_channel_unref(current_dest_chan);
-		return 0;
-	}
-
 	if (ast_test_flag(&opts, OPT_DURATION_LIMIT)
 		&& !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])
 		&& ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) {
@@ -8079,48 +8041,13 @@
 			"Reason: Cannot setup bridge time limit\r\n"
 			"Channel1: %s\r\n"
 			"Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan);
-		ast_hangup(final_dest_chan);
 		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
 		current_dest_chan = ast_channel_unref(current_dest_chan);
 		goto done;
 	}
 
-	if (do_bridge_masquerade(current_dest_chan, final_dest_chan)) {
-		ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
-			"Response: Failed\r\n"
-			"Reason: Cannot masquerade channels\r\n"
-			"Channel1: %s\r\n"
-			"Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan);
-		ast_hangup(final_dest_chan);
-		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
-		current_dest_chan = ast_channel_unref(current_dest_chan);
-		goto done;
-	}
-
-	/* answer the channel if needed */
-	if (ast_channel_state(final_dest_chan) != AST_STATE_UP) {
-		ast_answer(final_dest_chan);
-	}
-
-	chans[0] = current_dest_chan;
-	chans[1] = final_dest_chan;
-
-	/* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
-	/* try to make compatible, send error if we fail */
-	if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
-		ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", ast_channel_name(chan), ast_channel_name(final_dest_chan));
-		ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
-			"Response: Failed\r\n"
-			"Reason: Could not make channels compatible for bridge\r\n"
-			"Channel1: %s\r\n"
-			"Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(final_dest_chan));
-
-		bridge_failed_peer_goto(chan, final_dest_chan);
-
-		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
-		current_dest_chan = ast_channel_unref(current_dest_chan);
-		goto done;
-	}
+	chans[0] = chan;
+	chans[1] = current_dest_chan;
 
 	/* Report that the bridge will be successfull */
 	/*** DOCUMENTATION
@@ -8134,17 +8061,7 @@
 	ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
 		"Response: Success\r\n"
 		"Channel1: %s\r\n"
-		"Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(final_dest_chan));
-
-	current_dest_chan = ast_channel_unref(current_dest_chan);
-
-	/* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */
-	if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
-		if (!ast_streamfile(final_dest_chan, xfersound, ast_channel_language(final_dest_chan))) {
-			if (ast_waitstream(final_dest_chan, "") < 0)
-				ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", ast_channel_name(final_dest_chan));
-		}
-	}
+		"Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(current_dest_chan));
 
 	if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
 		ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
@@ -8170,18 +8087,40 @@
 		extension = ast_strdupa(ast_channel_exten(chan));
 		priority = ast_channel_priority(chan);
 		ast_channel_unlock(chan);
-		ast_after_bridge_set_go_on(final_dest_chan, context, extension, priority,
+		ast_after_bridge_set_go_on(current_dest_chan, context, extension, priority,
 			opt_args[OPT_ARG_CALLEE_GO_ON]);
 	} else if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
-		ast_channel_lock(final_dest_chan);
-		context = ast_strdupa(ast_channel_context(final_dest_chan));
-		extension = ast_strdupa(ast_channel_exten(final_dest_chan));
-		priority = ast_channel_priority(final_dest_chan);
-		ast_channel_unlock(final_dest_chan);
-		ast_after_bridge_set_goto(final_dest_chan, context, extension, priority);
-	}
-
-	ast_bridge_call(chan, final_dest_chan, &bconfig);
+		ast_channel_lock(current_dest_chan);
+		context = ast_strdupa(ast_channel_context(current_dest_chan));
+		extension = ast_strdupa(ast_channel_exten(current_dest_chan));
+		priority = ast_channel_priority(current_dest_chan);
+		ast_channel_unlock(current_dest_chan);
+		ast_after_bridge_set_goto(current_dest_chan, context, extension, priority);
+	}
+
+	if (ast_bridge_features_init(&chan_features)) {
+		goto done;
+	}
+
+	peer_features = ast_bridge_features_new();
+	if (!peer_features) {
+		ast_bridge_features_cleanup(&chan_features);
+		goto done;
+	}
+
+	if (pre_bridge_setup(chan, current_dest_chan, &bconfig, &chan_features, peer_features)) {
+		ast_bridge_features_destroy(peer_features);
+		ast_bridge_features_cleanup(&chan_features);
+		goto done;
+	}
+
+	bridge = ast_bridge_basic_new();
+
+	add_to_bridge(bridge, current_dest_chan, peer_features, ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE));
+
+	ast_bridge_join(bridge, chan, NULL, &chan_features, NULL, 1);
+
+	ast_bridge_features_cleanup(&chan_features);
 
 	/* The bridge has ended, set BRIDGERESULT to SUCCESS. */
 	pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");




More information about the asterisk-commits mailing list