[asterisk-commits] mmichelson: branch mmichelson/transfer r386618 - in /team/mmichelson/transfer...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Apr 26 12:00:02 CDT 2013


Author: mmichelson
Date: Fri Apr 26 11:59:58 2013
New Revision: 386618

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=386618
Log:
Resolve conflict and reset automerge.


Modified:
    team/mmichelson/transfer/   (props changed)
    team/mmichelson/transfer/apps/app_bridgewait.c
    team/mmichelson/transfer/apps/confbridge/conf_config_parser.c
    team/mmichelson/transfer/bridges/bridge_simple.c
    team/mmichelson/transfer/configs/res_sip.conf.sample
    team/mmichelson/transfer/include/asterisk/bridging.h
    team/mmichelson/transfer/include/asterisk/bridging_features.h
    team/mmichelson/transfer/main/bridging.c

Propchange: team/mmichelson/transfer/
------------------------------------------------------------------------------
    automerge = *

Propchange: team/mmichelson/transfer/
------------------------------------------------------------------------------
--- bridge_construction-integrated (original)
+++ bridge_construction-integrated Fri Apr 26 11:59:58 2013
@@ -1,1 +1,1 @@
-/trunk:1-386543
+/trunk:1-386590

Propchange: team/mmichelson/transfer/
------------------------------------------------------------------------------
--- transfer-integrated (original)
+++ transfer-integrated Fri Apr 26 11:59:58 2013
@@ -1,1 +1,1 @@
-/team/group/bridge_construction:1-386571
+/team/group/bridge_construction:1-386617

Modified: team/mmichelson/transfer/apps/app_bridgewait.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/transfer/apps/app_bridgewait.c?view=diff&rev=386618&r1=386617&r2=386618
==============================================================================
--- team/mmichelson/transfer/apps/app_bridgewait.c (original)
+++ team/mmichelson/transfer/apps/app_bridgewait.c Fri Apr 26 11:59:58 2013
@@ -196,8 +196,8 @@
 	ast_mutex_lock(&bridgewait_lock);
 	if (!holding_bridge) {
 		holding_bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_HOLDING,
-			AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM |
-			AST_BRIDGE_FLAG_TRANSFER_PROHIBITED);
+			AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
+				| AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED);
 	}
 	ast_mutex_unlock(&bridgewait_lock);
 	if (!holding_bridge) {

Modified: team/mmichelson/transfer/apps/confbridge/conf_config_parser.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/transfer/apps/confbridge/conf_config_parser.c?view=diff&rev=386618&r1=386617&r2=386618
==============================================================================
--- team/mmichelson/transfer/apps/confbridge/conf_config_parser.c (original)
+++ team/mmichelson/transfer/apps/confbridge/conf_config_parser.c Fri Apr 26 11:59:58 2013
@@ -1915,6 +1915,7 @@
 	/* This option should only be used with the CONFBRIDGE dialplan function */
 	aco_option_register_custom(&cfg_info, "template", ACO_EXACT, user_types, NULL, user_template_handler, 0);
 
+/* BUGBUG need a user supplied bridge merge_priority to merge ConfBridges (default = 1, range 1-INT_MAX) */
 	/* Bridge options */
 	aco_option_register(&cfg_info, "type", ACO_EXACT, bridge_types, NULL, OPT_NOOP_T, 0, 0);
 	aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), USER_OPT_JITTERBUFFER);

Modified: team/mmichelson/transfer/bridges/bridge_simple.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/transfer/bridges/bridge_simple.c?view=diff&rev=386618&r1=386617&r2=386618
==============================================================================
--- team/mmichelson/transfer/bridges/bridge_simple.c (original)
+++ team/mmichelson/transfer/bridges/bridge_simple.c Fri Apr 26 11:59:58 2013
@@ -70,15 +70,10 @@
 {
 	struct ast_bridge_channel *other;
 
-	/* If this is the only channel in this bridge then immediately exit */
-	if (AST_LIST_FIRST(&bridge->channels) == AST_LIST_LAST(&bridge->channels)) {
+	/* Find the channel we actually want to write to */
+	other = ast_bridge_channel_peer(bridge_channel);
+	if (!other) {
 		return -1;
-	}
-
-	/* Find the channel we actually want to write to */
-	other = AST_LIST_FIRST(&bridge->channels);
-	if (other == bridge_channel) {
-		other = AST_LIST_LAST(&bridge->channels);
 	}
 
 	/* The bridging core takes care of freeing the passed in frame. */

Modified: team/mmichelson/transfer/configs/res_sip.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/transfer/configs/res_sip.conf.sample?view=diff&rev=386618&r1=386617&r2=386618
==============================================================================
--- team/mmichelson/transfer/configs/res_sip.conf.sample (original)
+++ team/mmichelson/transfer/configs/res_sip.conf.sample Fri Apr 26 11:59:58 2013
@@ -1,10 +1,10 @@
 ; This is an in-flux configuration file for the res_sip module, it will change as things progress
 
 ;;; Transports
-[local]
-type=transport
-protocol=udp ; Supported protocols are udp, tcp, and tls
-bind=0.0.0.0 ; This supports both IPv4 and IPv6, port is optional
+;[local]
+;type=transport
+;protocol=udp ; Supported protocols are udp, tcp, and tls
+;bind=0.0.0.0 ; This supports both IPv4 and IPv6, port is optional
 
 ;;; Endpoints
 [endpoint]

Modified: team/mmichelson/transfer/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/transfer/include/asterisk/bridging.h?view=diff&rev=386618&r1=386617&r2=386618
==============================================================================
--- team/mmichelson/transfer/include/asterisk/bridging.h (original)
+++ team/mmichelson/transfer/include/asterisk/bridging.h Fri Apr 26 11:59:58 2013
@@ -351,6 +351,17 @@
 typedef void (*ast_bridge_notify_masquerade_fn)(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel);
 
 /*!
+ * \brief Get the merge priority of this bridge.
+ *
+ * \param self Bridge to operate upon.
+ *
+ * \note On entry, self is already locked.
+ *
+ * \return Merge priority
+ */
+typedef int (*ast_bridge_merge_priority_fn)(struct ast_bridge *self);
+
+/*!
  * \brief Bridge virtual methods table definition.
  *
  * \note Any changes to this struct must be reflected in
@@ -369,6 +380,8 @@
 	ast_bridge_pull_channel_fn pull;
 	/*! Notify the bridge of a masquerade with the channel. */
 	ast_bridge_notify_masquerade_fn notify_masquerade;
+	/*! Get the bridge merge priority. */
+	ast_bridge_merge_priority_fn get_merge_priority;
 };
 
 /*!
@@ -768,6 +781,21 @@
 int ast_bridge_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge);
 
 /*!
+ * \brief Move a channel from one bridge to another.
+ * \since 12.0.0
+ *
+ * \param dst_bridge Destination bridge of bridge channel move.
+ * \param src_bridge Source bridge of bridge channel move.
+ * \param chan Channel to move.
+ * \param swap Channel to replace in dst_bridge.
+ * \param attempt_recovery TRUE if failure attempts to push channel back into original bridge.
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+int ast_bridge_move(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_channel *chan, struct ast_channel *swap, int attempt_recovery);
+
+/*!
  * \brief Adjust the bridge merge inhibit request count.
  * \since 12.0.0
  *
@@ -1163,6 +1191,21 @@
  * \param bridge_channel Channel to restore
  */
 void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channel);
+
+/*!
+ * \brief Get the peer bridge channel of a two party bridge.
+ * \since 12.0.0
+ *
+ * \param bridge_channel What to get the peer of.
+ *
+ * \note On entry, bridge_channel->bridge is already locked.
+ *
+ * \note This is an internal bridge function.
+ *
+ * \retval peer on success.
+ * \retval NULL no peer channel.
+ */
+struct ast_bridge_channel *ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel);
 
 /*!
  * \brief Adjust the internal mixing sample rate of a bridge

Modified: team/mmichelson/transfer/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/transfer/include/asterisk/bridging_features.h?view=diff&rev=386618&r1=386617&r2=386618
==============================================================================
--- team/mmichelson/transfer/include/asterisk/bridging_features.h (original)
+++ team/mmichelson/transfer/include/asterisk/bridging_features.h Fri Apr 26 11:59:58 2013
@@ -40,8 +40,12 @@
 	AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM = (1 << 3),
 	/*! Bridge channels cannot be merged to this bridge. */
 	AST_BRIDGE_FLAG_MERGE_INHIBIT_TO = (1 << 4),
+	/*! Bridge channels cannot be local channel swap optimized from this bridge. */
+	AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM = (1 << 5),
+	/*! Bridge channels cannot be local channel swap optimized to this bridge. */
+	AST_BRIDGE_FLAG_SWAP_INHIBIT_TO = (1 << 6),
 	/*! Bridge channels can be moved to another bridge only by masquerade (ConfBridge) */
-	AST_BRIDGE_FLAG_MASQUERADE_ONLY = (1 << 5),
+	AST_BRIDGE_FLAG_MASQUERADE_ONLY = (1 << 7),
 	/*! Bridge does not allow transfers of channels out */
 	AST_BRIDGE_FLAG_TRANSFER_PROHIBITED = (1 << 6),
 	/*! Bridge transfers require transfer of entire bridge rather than individual channels */

Modified: team/mmichelson/transfer/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/transfer/main/bridging.c?view=diff&rev=386618&r1=386617&r2=386618
==============================================================================
--- team/mmichelson/transfer/main/bridging.c (original)
+++ team/mmichelson/transfer/main/bridging.c Fri Apr 26 11:59:58 2013
@@ -1214,7 +1214,8 @@
 		|| !v_table->dissolving
 		|| !v_table->push
 		|| !v_table->pull
-		|| !v_table->notify_masquerade) {
+		|| !v_table->notify_masquerade
+		|| !v_table->get_merge_priority) {
 		ast_log(LOG_ERROR, "Virtual method table for bridge class %s not complete.\n",
 			v_table && v_table->name ? v_table->name : "<unknown>");
 		ast_assert(0);
@@ -1360,6 +1361,22 @@
 	self->reconfigured = 1;
 }
 
+/*!
+ * \internal
+ * \brief Get the merge priority of this bridge.
+ * \since 12.0.0
+ *
+ * \param self Bridge to operate upon.
+ *
+ * \note On entry, self is already locked.
+ *
+ * \return Merge priority
+ */
+static int bridge_base_get_merge_priority(struct ast_bridge *self)
+{
+	return 0;
+}
+
 struct ast_bridge_methods ast_bridge_base_v_table = {
 	.name = "base",
 	.destroy = bridge_base_destroy,
@@ -1367,6 +1384,7 @@
 	.push = bridge_base_push,
 	.pull = bridge_base_pull,
 	.notify_masquerade = bridge_base_notify_masquerade,
+	.get_merge_priority = bridge_base_get_merge_priority,
 };
 
 struct ast_bridge *ast_bridge_base_new(uint32_t capabilities, unsigned int flags)
@@ -3149,6 +3167,114 @@
 
 /*!
  * \internal
+ * \brief Move a bridge channel from one bridge to another.
+ * \since 12.0.0
+ *
+ * \param dst_bridge Destination bridge of bridge channel move.
+ * \param bridge_channel Channel moving from one bridge to another.
+ * \param attempt_recovery TRUE if failure attempts to push channel back into original bridge.
+ *
+ * \note The dst_bridge and bridge_channel->bridge are assumed already locked.
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+static int bridge_move_do(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bridge_channel, int attempt_recovery)
+{
+	struct ast_bridge *orig_bridge;
+	int was_in_bridge;
+	int res = 0;
+
+/* BUGBUG need bridge move stasis event and a success/fail event. */
+	if (bridge_channel->swap) {
+		ast_debug(1, "Moving %p(%s) into bridge %s swapping with %s\n",
+			bridge_channel, ast_channel_name(bridge_channel->chan), dst_bridge->uniqueid,
+			ast_channel_name(bridge_channel->swap));
+	} else {
+		ast_debug(1, "Moving %p(%s) into bridge %s\n",
+			bridge_channel, ast_channel_name(bridge_channel->chan), dst_bridge->uniqueid);
+	}
+
+	orig_bridge = bridge_channel->bridge;
+	was_in_bridge = bridge_channel->in_bridge;
+
+	bridge_channel_pull(bridge_channel);
+
+	/* Point to new bridge.*/
+	ao2_ref(dst_bridge, +1);
+	ast_bridge_channel_lock(bridge_channel);
+	bridge_channel->bridge = dst_bridge;
+	ast_bridge_channel_unlock(bridge_channel);
+
+	if (bridge_channel_push(bridge_channel)) {
+		/* Try to put the channel back into the original bridge. */
+		if (attempt_recovery && was_in_bridge) {
+			/* Point back to original bridge. */
+			ao2_ref(orig_bridge, +1);
+			ast_bridge_channel_lock(bridge_channel);
+			bridge_channel->bridge = orig_bridge;
+			ast_bridge_channel_unlock(bridge_channel);
+			ao2_ref(dst_bridge, -1);
+
+			if (bridge_channel_push(bridge_channel)) {
+				ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+			}
+		} else {
+			ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+		}
+		res = -1;
+	}
+
+	bridge_reconfigured(dst_bridge);
+	bridge_reconfigured(orig_bridge);
+	ao2_ref(orig_bridge, -1);
+	return res;
+}
+
+int ast_bridge_move(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_channel *chan, struct ast_channel *swap, int attempt_recovery)
+{
+	struct ast_bridge_channel *bridge_channel;
+	int res = -1;
+
+	ast_bridge_lock_both(dst_bridge, src_bridge);
+
+	bridge_channel = find_bridge_channel(src_bridge, chan);
+	if (!bridge_channel) {
+		ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, channel not in bridge.\n",
+			ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid);
+	} else if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
+		ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, channel leaving bridge.\n",
+			ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid);
+	} else if (dst_bridge->dissolved || src_bridge->dissolved) {
+		ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, one or both bridges are dissolved.\n",
+			ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid);
+	} else {
+		bridge_channel->swap = swap;
+		res = bridge_move_do(dst_bridge, bridge_channel, attempt_recovery);
+	}
+
+	ast_bridge_unlock(src_bridge);
+	ast_bridge_unlock(dst_bridge);
+	return res;
+}
+
+struct ast_bridge_channel *ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel)
+{
+	struct ast_bridge *bridge = bridge_channel->bridge;
+	struct ast_bridge_channel *other = NULL;
+
+	if (bridge_channel->in_bridge && bridge->num_channels == 2) {
+		other = AST_LIST_FIRST(&bridge->channels);
+		if (other == bridge_channel) {
+			other = AST_LIST_LAST(&bridge->channels);
+		}
+	}
+
+	return other;
+}
+
+/*!
+ * \internal
  * \brief Lock the local channel stack for chan and prequalify it.
  * \since 12.0.0
  *
@@ -3181,6 +3307,7 @@
 	if (bridge->inhibit_merge
 		|| bridge->dissolved
 		|| ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_MASQUERADE_ONLY)
+		|| !bridge_channel->in_bridge
 		|| !AST_LIST_EMPTY(&bridge_channel->wr_queue)) {
 		ast_bridge_unlock(bridge);
 		ast_bridge_channel_unlock(bridge_channel);
@@ -3227,6 +3354,7 @@
 	if (bridge->inhibit_merge
 		|| bridge->dissolved
 		|| ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_MASQUERADE_ONLY)
+		|| !bridge_channel->in_bridge
 		|| !AST_LIST_EMPTY(&bridge_channel->wr_queue)) {
 		ast_bridge_unlock(bridge);
 		ast_bridge_channel_unlock(bridge_channel);
@@ -3236,76 +3364,207 @@
 	return bridge;
 }
 
-int ast_bridge_local_optimized_out(struct ast_channel *chan, struct ast_channel *peer)
-{
-	struct ast_bridge *chan_bridge;
-	struct ast_bridge *peer_bridge;
-	struct ast_bridge_channel *chan_bridge_channel;
-	struct ast_bridge_channel *peer_bridge_channel;
+/*!
+ * \internal
+ * \brief Check and attempt to swap optimize out the local channels.
+ * \since 12.0.0
+ *
+ * \param chan_bridge
+ * \param chan_bridge_channel
+ * \param peer_bridge
+ * \param peer_bridge_channel
+ *
+ * \retval 1 if local channels failed to optimize out.
+ * \retval 0 if local channels were not optimized out.
+ * \retval -1 if local channels were optimized out.
+ */
+static int check_swap_optimize_out(struct ast_bridge *chan_bridge,
+	struct ast_bridge_channel *chan_bridge_channel, struct ast_bridge *peer_bridge,
+	struct ast_bridge_channel *peer_bridge_channel)
+{
+	struct ast_bridge *dst_bridge = NULL;
+	struct ast_bridge *src_bridge = NULL;
+	struct ast_bridge_channel *dst_bridge_channel = NULL;
+	struct ast_bridge_channel *src_bridge_channel = NULL;
+	int peer_priority;
+	int chan_priority;
 	int res = 0;
 
-	chan_bridge = optimize_lock_chan_stack(chan);
-	if (!chan_bridge) {
-		return res;
-	}
-	chan_bridge_channel = ast_channel_internal_bridge_channel(chan);
-
-	peer_bridge = optimize_lock_peer_stack(peer);
-	if (peer_bridge) {
-		struct ast_bridge *dst_bridge = NULL;
-		struct ast_bridge *src_bridge = NULL;
-
-		peer_bridge_channel = ast_channel_internal_bridge_channel(peer);
-
-		if (!ast_test_flag(&chan_bridge->feature_flags,
-				AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)
-			&& !ast_test_flag(&peer_bridge->feature_flags,
-				AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
-/* BUGBUG need to have a merge priority bridge class method to help determine which way to optimize merge. */
-			/* Can merge either way. */
+	if (!ast_test_flag(&chan_bridge->feature_flags,
+			AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM)
+		&& !ast_test_flag(&peer_bridge->feature_flags,
+			AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM)) {
+		/*
+		 * Can swap either way.  Swap to the higher priority merge
+		 * bridge.
+		 */
+		chan_priority = chan_bridge->v_table->get_merge_priority(chan_bridge);
+		peer_priority = peer_bridge->v_table->get_merge_priority(peer_bridge);
+		if (chan_bridge->num_channels == 2
+			&& chan_priority <= peer_priority) {
+			dst_bridge = peer_bridge;
+			src_bridge = chan_bridge;
+			dst_bridge_channel = peer_bridge_channel;
+			src_bridge_channel = chan_bridge_channel;
+		} else if (peer_bridge->num_channels == 2
+			&& peer_priority <= chan_priority) {
+			dst_bridge = chan_bridge;
+			src_bridge = peer_bridge;
+			dst_bridge_channel = chan_bridge_channel;
+			src_bridge_channel = peer_bridge_channel;
+		}
+	} else if (chan_bridge->num_channels == 2
+		&& !ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM)
+		&& !ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_SWAP_INHIBIT_TO)) {
+		/* Can swap optimize only one way. */
+		dst_bridge = peer_bridge;
+		src_bridge = chan_bridge;
+		dst_bridge_channel = peer_bridge_channel;
+		src_bridge_channel = chan_bridge_channel;
+	} else if (peer_bridge->num_channels == 2
+		&& !ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM)
+		&& !ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_SWAP_INHIBIT_TO)) {
+		/* Can swap optimize only one way. */
+		dst_bridge = chan_bridge;
+		src_bridge = peer_bridge;
+		dst_bridge_channel = chan_bridge_channel;
+		src_bridge_channel = peer_bridge_channel;
+	}
+	if (dst_bridge) {
+		struct ast_bridge_channel *other;
+
+		res = 1;
+		other = ast_bridge_channel_peer(src_bridge_channel);
+		if (other) {
+			ast_debug(1, "Move-swap optimizing %s <-- %s.\n",
+				ast_channel_name(dst_bridge_channel->chan),
+				ast_channel_name(other->chan));
+
+			other->swap = dst_bridge_channel->chan;
+			if (!bridge_move_do(dst_bridge, other, 1)) {
+				ast_bridge_change_state(src_bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+				res = -1;
+			}
+		}
+	}
+	return res;
+}
+
+/*!
+ * \internal
+ * \brief Check and attempt to merge optimize out the local channels.
+ * \since 12.0.0
+ *
+ * \param chan_bridge
+ * \param chan_bridge_channel
+ * \param peer_bridge
+ * \param peer_bridge_channel
+ *
+ * \retval 0 if local channels were not optimized out.
+ * \retval -1 if local channels were optimized out.
+ */
+static int check_merge_optimize_out(struct ast_bridge *chan_bridge,
+	struct ast_bridge_channel *chan_bridge_channel, struct ast_bridge *peer_bridge,
+	struct ast_bridge_channel *peer_bridge_channel)
+{
+	struct ast_bridge *dst_bridge = NULL;
+	struct ast_bridge *src_bridge = NULL;
+	int peer_priority;
+	int chan_priority;
+	int res = 0;
+
+	if (!ast_test_flag(&chan_bridge->feature_flags,
+			AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)
+		&& !ast_test_flag(&peer_bridge->feature_flags,
+			AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
+		/*
+		 * Can merge either way.  Merge to the higher priority merge
+		 * bridge.  Otherwise merge to the larger bridge.
+		 */
+		chan_priority = chan_bridge->v_table->get_merge_priority(chan_bridge);
+		peer_priority = peer_bridge->v_table->get_merge_priority(peer_bridge);
+		if (peer_priority < chan_priority) {
+			dst_bridge = chan_bridge;
+			src_bridge = peer_bridge;
+		} else if (chan_priority < peer_priority) {
+			dst_bridge = peer_bridge;
+			src_bridge = chan_bridge;
+		} else {
+			/* Merge to the larger bridge. */
 			if (peer_bridge->num_channels <= chan_bridge->num_channels) {
-				/* Merge to the larger bridge. */
 				dst_bridge = chan_bridge;
 				src_bridge = peer_bridge;
 			} else {
 				dst_bridge = peer_bridge;
 				src_bridge = chan_bridge;
 			}
-		} else if (!ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO)
-			&& !ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
-			/* Can merge only one way. */
-			dst_bridge = chan_bridge;
-			src_bridge = peer_bridge;
-		} else if (!ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO)
-			&& !ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
-			/* Can merge only one way. */
-			dst_bridge = peer_bridge;
-			src_bridge = chan_bridge;
-		}
-
-		if (dst_bridge) {
-			if (src_bridge->num_channels < 2 || dst_bridge->num_channels < 2) {
-				ast_debug(4, "Can't optimize %s -- %s out, not enough channels in a bridge.\n",
-					ast_channel_name(chan), ast_channel_name(peer));
-			} else if ((2 + 2) < dst_bridge->num_channels + src_bridge->num_channels
-				&& !(dst_bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX)
-				&& !ast_test_flag(&dst_bridge->feature_flags, AST_BRIDGE_FLAG_SMART)) {
-				ast_debug(4, "Can't optimize %s -- %s out, multimix is needed and it cannot be acquired.\n",
-					ast_channel_name(chan), ast_channel_name(peer));
-			} else {
-				struct ast_bridge_channel *kick_me[] = {
-					chan_bridge_channel,
-					peer_bridge_channel,
-					};
-
-				ast_debug(1, "Optimizing %s -- %s out.\n",
-					ast_channel_name(chan), ast_channel_name(peer));
-
-				bridge_merge_do(dst_bridge, src_bridge, kick_me, ARRAY_LEN(kick_me));
-				res = -1;
-			}
+		}
+	} else if (!ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO)
+		&& !ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
+		/* Can merge only one way. */
+		dst_bridge = chan_bridge;
+		src_bridge = peer_bridge;
+	} else if (!ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO)
+		&& !ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM)) {
+		/* Can merge only one way. */
+		dst_bridge = peer_bridge;
+		src_bridge = chan_bridge;
+	}
+
+	if (dst_bridge) {
+		if (src_bridge->num_channels < 2 || dst_bridge->num_channels < 2) {
+			ast_debug(4, "Can't optimize %s -- %s out, not enough channels in a bridge.\n",
+				ast_channel_name(chan_bridge_channel->chan),
+				ast_channel_name(peer_bridge_channel->chan));
+		} else if ((2 + 2) < dst_bridge->num_channels + src_bridge->num_channels
+			&& !(dst_bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX)
+			&& !ast_test_flag(&dst_bridge->feature_flags, AST_BRIDGE_FLAG_SMART)) {
+			ast_debug(4, "Can't optimize %s -- %s out, multimix is needed and it cannot be acquired.\n",
+				ast_channel_name(chan_bridge_channel->chan),
+				ast_channel_name(peer_bridge_channel->chan));
 		} else {
-/* BUGBUG this is where we would decide if we can swap a channel instead of merging. */
+			struct ast_bridge_channel *kick_me[] = {
+				chan_bridge_channel,
+				peer_bridge_channel,
+				};
+
+			ast_debug(1, "Merge optimizing %s -- %s out.\n",
+				ast_channel_name(chan_bridge_channel->chan),
+				ast_channel_name(peer_bridge_channel->chan));
+
+			bridge_merge_do(dst_bridge, src_bridge, kick_me, ARRAY_LEN(kick_me));
+			res = -1;
+		}
+	}
+
+	return res;
+}
+
+int ast_bridge_local_optimized_out(struct ast_channel *chan, struct ast_channel *peer)
+{
+	struct ast_bridge *chan_bridge;
+	struct ast_bridge *peer_bridge;
+	struct ast_bridge_channel *chan_bridge_channel;
+	struct ast_bridge_channel *peer_bridge_channel;
+	int res = 0;
+
+	chan_bridge = optimize_lock_chan_stack(chan);
+	if (!chan_bridge) {
+		return res;
+	}
+	chan_bridge_channel = ast_channel_internal_bridge_channel(chan);
+
+	peer_bridge = optimize_lock_peer_stack(peer);
+	if (peer_bridge) {
+		peer_bridge_channel = ast_channel_internal_bridge_channel(peer);
+
+		res = check_swap_optimize_out(chan_bridge, chan_bridge_channel,
+			peer_bridge, peer_bridge_channel);
+		if (!res) {
+			res = check_merge_optimize_out(chan_bridge, chan_bridge_channel,
+				peer_bridge, peer_bridge_channel);
+		} else if (0 < res) {
+			res = 0;
 		}
 
 		/* Release peer locks. */




More information about the asterisk-commits mailing list