[asterisk-commits] jrose: branch jrose/bridge_projects r386683 - in /team/jrose/bridge_projects:...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Apr 26 16:31:06 CDT 2013


Author: jrose
Date: Fri Apr 26 16:31:02 2013
New Revision: 386683

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=386683
Log:
merge new bridging changes including Richachard's ast_bridge_move function which replaces my hack implementation of it

Modified:
    team/jrose/bridge_projects/   (props changed)
    team/jrose/bridge_projects/apps/app_bridgewait.c
    team/jrose/bridge_projects/apps/confbridge/conf_config_parser.c
    team/jrose/bridge_projects/bridges/bridge_simple.c
    team/jrose/bridge_projects/configs/res_sip.conf.sample
    team/jrose/bridge_projects/include/asterisk/bridging.h
    team/jrose/bridge_projects/include/asterisk/bridging_features.h
    team/jrose/bridge_projects/main/bridging.c
    team/jrose/bridge_projects/res/parking/parking_applications.c
    team/jrose/bridge_projects/res/parking/parking_bridge.c
    team/jrose/bridge_projects/res/parking/parking_bridge_features.c
    team/jrose/bridge_projects/res/parking/parking_controller.c
    team/jrose/bridge_projects/res/parking/parking_ui.c

Propchange: team/jrose/bridge_projects/
------------------------------------------------------------------------------
--- bridge_construction-integrated (original)
+++ bridge_construction-integrated Fri Apr 26 16:31:02 2013
@@ -1,1 +1,1 @@
-/trunk:1-386543
+/trunk:1-386590

Propchange: team/jrose/bridge_projects/
------------------------------------------------------------------------------
--- bridge_projects-integrated (original)
+++ bridge_projects-integrated Fri Apr 26 16:31:02 2013
@@ -1,1 +1,1 @@
-/team/group/bridge_construction:1-386561
+/team/group/bridge_construction:1-386625

Modified: team/jrose/bridge_projects/apps/app_bridgewait.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/apps/app_bridgewait.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/apps/app_bridgewait.c (original)
+++ team/jrose/bridge_projects/apps/app_bridgewait.c Fri Apr 26 16:31:02 2013
@@ -196,7 +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_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
+				| AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM);
 	}
 	ast_mutex_unlock(&bridgewait_lock);
 	if (!holding_bridge) {

Modified: team/jrose/bridge_projects/apps/confbridge/conf_config_parser.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/apps/confbridge/conf_config_parser.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/apps/confbridge/conf_config_parser.c (original)
+++ team/jrose/bridge_projects/apps/confbridge/conf_config_parser.c Fri Apr 26 16:31:02 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/jrose/bridge_projects/bridges/bridge_simple.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/bridges/bridge_simple.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/bridges/bridge_simple.c (original)
+++ team/jrose/bridge_projects/bridges/bridge_simple.c Fri Apr 26 16:31:02 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/jrose/bridge_projects/configs/res_sip.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/configs/res_sip.conf.sample?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/configs/res_sip.conf.sample (original)
+++ team/jrose/bridge_projects/configs/res_sip.conf.sample Fri Apr 26 16:31:02 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/jrose/bridge_projects/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/include/asterisk/bridging.h?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/include/asterisk/bridging.h (original)
+++ team/jrose/bridge_projects/include/asterisk/bridging.h Fri Apr 26 16:31:02 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,20 +781,19 @@
 int ast_bridge_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge);
 
 /*!
- * \brief XXX Hack function for moving a channel from one bridge to another
- *
- * \param bridge_src bridge the channel is being moved from
- * \param bridge_dst bridge the chnanel is being moved to
- * \param chan Channel being moved
- *
- * \retval 0 on success
- * \retval -1 on failure
- *
- * \code
- * ast_bridge_move(old_bridge, new_bridge, chan);
- * \endcode
- */
-int ast_bridge_move(struct ast_bridge *bridge_src, struct ast_bridge *bridge_dst, struct ast_channel *chan);
+ * \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.
@@ -1197,6 +1209,21 @@
 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
  * used during multimix mode.
  *

Modified: team/jrose/bridge_projects/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/include/asterisk/bridging_features.h?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/include/asterisk/bridging_features.h (original)
+++ team/jrose/bridge_projects/include/asterisk/bridging_features.h Fri Apr 26 16:31:02 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),
 };
 
 /*! \brief Flags used for per bridge channel features */

Modified: team/jrose/bridge_projects/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/main/bridging.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/main/bridging.c (original)
+++ team/jrose/bridge_projects/main/bridging.c Fri Apr 26 16:31:02 2013
@@ -1261,7 +1261,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);
@@ -1407,6 +1408,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,
@@ -1414,6 +1431,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)
@@ -3073,66 +3091,6 @@
 	return 0;
 }
 
-static void ast_bridge_move_do(struct ast_bridge *bridge_src, struct ast_bridge *bridge_dst, struct ast_channel *chan)
-{
-	struct ast_bridge_channel *bridge_channel;
-
-	ast_debug(1, "Moving channel %s from bridge %p into bridge %p\n", ast_channel_name(chan), bridge_src, bridge_dst);
-
-	AST_LIST_TRAVERSE(&bridge_src->channels, bridge_channel, entry) {
-		if (bridge_channel->chan == chan) {
-			break;
-		}
-	}
-
-	bridge_channel_pull(bridge_channel);
-
-	/* Point to new bridge. */
-	ao2_ref(bridge_dst, +1);
-	ast_bridge_channel_lock(bridge_channel);
-	bridge_channel->bridge = bridge_dst;
-	ast_bridge_channel_unlock(bridge_channel);
-	ao2_ref(bridge_src, -1);
-
-	bridge_channel_push(bridge_channel);
-
-	bridge_reconfigured(bridge_dst);
-	bridge_reconfigured(bridge_src);
-
-	ast_debug(1, "Moved channel %s from bridge %p into bridge %p\n", ast_channel_name(chan), bridge_src, bridge_dst);
-}
-
-int ast_bridge_move(struct ast_bridge *bridge_src, struct ast_bridge *bridge_dst, struct ast_channel *chan)
-{
-	int res = -1;
-
-	/* Deadlock avoidance. */
-	for (;;) {
-		ast_bridge_lock(bridge_src);
-		if (!ast_bridge_trylock(bridge_dst)) {
-			break;
-		}
-		ast_bridge_unlock(bridge_src);
-		sched_yield();
-	}
-
-	if (bridge_src->dissolved || bridge_dst->dissolved) {
-		ast_debug(1, "Can't move from bridge %p into bridge %p, one or both bridges are dissolved.\n",
-			bridge_src, bridge_dst);
-	} else {
-		++bridge_src->inhibit_merge;
-		++bridge_dst->inhibit_merge;
-		ast_bridge_move_do(bridge_src, bridge_dst, chan);
-		--bridge_dst->inhibit_merge;
-		--bridge_src->inhibit_merge;
-		res = 0;
-	}
-
-	ast_bridge_unlock(bridge_dst);
-	ast_bridge_unlock(bridge_src);
-	return res;
-}
-
 /*!
  * \internal
  * \brief Do the merge of two bridges.
@@ -3227,6 +3185,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
  *
@@ -3259,6 +3325,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);
@@ -3305,6 +3372,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);
@@ -3314,76 +3382,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. */

Modified: team/jrose/bridge_projects/res/parking/parking_applications.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_applications.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_applications.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_applications.c Fri Apr 26 16:31:02 2013
@@ -494,7 +494,7 @@
 	}
 
 	/* Move the parkee into the new bridge */
-	if (ast_bridge_move(lot->parking_bridge, retrieval_bridge, pu->chan)) {
+	if (ast_bridge_move(retrieval_bridge, lot->parking_bridge, pu->chan, NULL, 0)) {
 		ast_bridge_destroy(retrieval_bridge);
 		return -1;
 	}

Modified: team/jrose/bridge_projects/res/parking/parking_bridge.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_bridge.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_bridge.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_bridge.c Fri Apr 26 16:31:02 2013
@@ -192,7 +192,8 @@
 	if (swap) {
 		pu = swap->bridge_pvt;
 		if (!pu) {
-			/* This should be impossible since the only way a channel can enter in the first place is if it has a parked user associated with it */
+			/* This should be impossible since the only way a channel can enter in the first place
+			 * is if it has a parked user associated with it */
 			publish_parked_call_failure(bridge_channel->chan);
 			return -1;
 		}
@@ -210,6 +211,20 @@
 	get_park_common_datastore_data(bridge_channel->chan, &parker_uuid, &randomize, &time_limit, &silence);
 	parker = ast_channel_get_by_name(parker_uuid);
 
+	/* If the parker and the parkee are the same channel pointer, then the channel entered using
+	 * the park application. It's possible the the blindtransfer channel is still alive (particularly
+	 * when a multichannel bridge is parked), so try to get the real parker if possible. */
+	blind_transfer = S_OR(pbx_builtin_getvar_helper(bridge_channel->chan, "BLINDTRANSFER"),
+		ast_channel_name(bridge_channel->chan));
+
+	if (parker == bridge_channel->chan) {
+		struct ast_channel *real_parker = ast_channel_get_by_name(blind_transfer);
+		if (real_parker) {
+			ao2_cleanup(parker);
+			parker = real_parker;
+		}
+	}
+
 	if (!parker) {
 		return -1;
 	}
@@ -228,8 +243,6 @@
 
 	/* Raise bridged flag so that the call can actually be retrieved. XXX this whole concept probably isn't necessary any more. */
 	pu->bridged = 1;
-
-	blind_transfer = S_OR(pbx_builtin_getvar_helper(bridge_channel->chan, "BLINDTRANSFER"), ast_channel_name(bridge_channel->chan));
 
 	/* If the parkee and the parker are the same and silence_announce isn't set, play the announcement to the parkee */
 	if (!strcmp(blind_transfer, ast_channel_name(bridge_channel->chan)) && !silence) {
@@ -328,6 +341,11 @@
 static void bridge_parking_notify_masquerade(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
 {
 	ast_bridge_base_v_table.notify_masquerade(&self->base, bridge_channel);
+}
+
+static void bridge_parking_get_merge_priority(struct ast_bridge_parking *self)
+{
+	ast_bridge_base_v_table.get_merge_priority(&self->base);
 }
 
 struct ast_bridge_methods ast_bridge_parking_v_table = {
@@ -337,6 +355,7 @@
 	.push = (ast_bridge_push_channel_fn) bridge_parking_push,
 	.pull = (ast_bridge_pull_channel_fn) bridge_parking_pull,
 	.notify_masquerade = (ast_bridge_notify_masquerade_fn) bridge_parking_notify_masquerade,
+	.get_merge_priority = (ast_bridge_merge_priority_fn) bridge_parking_get_merge_priority,
 };
 
 static struct ast_bridge *ast_bridge_parking_init(struct ast_bridge_parking *self, struct parking_lot *bridge_lot)
@@ -363,7 +382,8 @@
 
 	bridge = ast_bridge_alloc(sizeof(struct ast_bridge_parking), &ast_bridge_parking_v_table);
 	bridge = ast_bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_HOLDING,
-		AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM);
+		AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
+		| AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM);
 	bridge = ast_bridge_parking_init(bridge, bridge_lot);
 	bridge = ast_bridge_register(bridge);
 	return bridge;

Modified: team/jrose/bridge_projects/res/parking/parking_bridge_features.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_bridge_features.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_bridge_features.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_bridge_features.c Fri Apr 26 16:31:02 2013
@@ -350,7 +350,9 @@
 		return;
 	}
 
-	if (ast_bridge_move(bridge_channel->bridge, parking_bridge, bridge_channel->chan)) {
+	pbx_builtin_setvar_helper(bridge_channel->chan, "BLINDTRANSFER", ast_channel_name(parker));
+
+	if (ast_bridge_move(parking_bridge, bridge_channel->bridge, bridge_channel->chan, NULL, 1)) {
 		ast_log(LOG_ERROR, "Failed to move %s into the parking bridge.\n",
 			ast_channel_name(bridge_channel->chan));
 	}

Modified: team/jrose/bridge_projects/res/parking/parking_controller.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_controller.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_controller.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_controller.c Fri Apr 26 16:31:02 2013
@@ -252,7 +252,13 @@
 int comeback_goto(struct parked_user *pu, struct parking_lot *lot)
 {
 	struct ast_channel *chan = pu->chan;
-	char *peername = ast_strdupa(pu->parker->name);
+	char *peername;
+	const char *blindtransfer = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
+
+	peername = blindtransfer ? ast_strdupa(blindtransfer) : ast_strdupa(pu->parker->name);
+
+	/* XXX Comeback to origin mode: Generate an extension in park-dial to Dial the peer */
+
 
 	/* Flatten the peername so that it can be used for performing the timeout PBX operations */
 	flatten_peername(peername);

Modified: team/jrose/bridge_projects/res/parking/parking_ui.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_ui.c?view=diff&rev=386683&r1=386682&r2=386683
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_ui.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_ui.c Fri Apr 26 16:31:02 2013
@@ -42,6 +42,7 @@
 {
 	ast_cli(fd, "  Space: %d\n", user->parking_space);
 	ast_cli(fd, "  Channel: %s\n", ast_channel_name(user->chan));
+	ast_cli(fd, "  Parker: %s\n", user->parker ? user->parker->name : "<unknown>");
 	ast_cli(fd, "\n");
 }
 




More information about the asterisk-commits mailing list