[asterisk-commits] rmudgett: branch group/bridge_construction r387477 - in /team/group/bridge_co...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu May 2 13:58:18 CDT 2013


Author: rmudgett
Date: Thu May  2 13:58:16 2013
New Revision: 387477

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=387477
Log:
Make it safe for a channel to get the bridge it is currently in.

Change the bridge pointer returned/set by
ast_channel_internal_bridge()/ast_channel_internal_bridge_set() with the
channel locked so getting the pointer when the channel is locked is safe
and you can get a reference to the bridge object.

* Added the following API calls:
ast_channel_get_bridge()
ast_channel_is_bridged()
ast_channel_bridge_peer()
ast_bridge_peer_nolock()
ast_bridge_peer()

* Changed how ast_bridge_channel_peer() gets the peer because I could.

Modified:
    team/group/bridge_construction/bridges/bridge_builtin_features.c
    team/group/bridge_construction/include/asterisk/bridging.h
    team/group/bridge_construction/include/asterisk/channel.h
    team/group/bridge_construction/main/bridging.c
    team/group/bridge_construction/main/channel.c

Modified: team/group/bridge_construction/bridges/bridge_builtin_features.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_builtin_features.c?view=diff&rev=387477&r1=387476&r2=387477
==============================================================================
--- team/group/bridge_construction/bridges/bridge_builtin_features.c (original)
+++ team/group/bridge_construction/bridges/bridge_builtin_features.c Thu May  2 13:58:16 2013
@@ -349,10 +349,13 @@
  * to fully support existing functionality.  There will be one
  * and only one ast_bridge_channel structure per channel.
  */
-	/* Point the channel back to the original bridge_channel. */
+	/* Point the channel back to the original bridge and bridge_channel. */
+	ast_bridge_channel_lock(bridge_channel);
 	ast_channel_lock(bridge_channel->chan);
 	ast_channel_internal_bridge_channel_set(bridge_channel->chan, bridge_channel);
+	ast_channel_internal_bridge_set(bridge_channel->chan, bridge_channel->bridge);
 	ast_channel_unlock(bridge_channel->chan);
+	ast_bridge_channel_unlock(bridge_channel);
 
 	/* Wait for peer thread to exit bridge and die. */
 	if (!ast_autoservice_start(bridge_channel->chan)) {

Modified: team/group/bridge_construction/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/bridging.h?view=diff&rev=387477&r1=387476&r2=387477
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging.h Thu May  2 13:58:16 2013
@@ -1379,6 +1379,36 @@
  */
 struct ao2_container *ast_bridge_peers(struct ast_bridge *bridge);
 
+/*!
+ * \brief Get the channel's bridge peer only if the bridge is two-party.
+ * \since 12.0.0
+ *
+ * \param bridge The bridge which is already locked.
+ * \param chan Channel desiring the bridge peer channel.
+ *
+ * \note The returned peer channel is the current peer in the
+ * bridge when called.
+ *
+ * \retval NULL Channel not in a bridge or the bridge is not two-party.
+ * \retval non-NULL Reffed peer channel at time of calling.
+ */
+struct ast_channel *ast_bridge_peer_nolock(struct ast_bridge *bridge, struct ast_channel *chan);
+
+/*!
+ * \brief Get the channel's bridge peer only if the bridge is two-party.
+ * \since 12.0.0
+ *
+ * \param bridge The bridge
+ * \param chan Channel desiring the bridge peer channel.
+ *
+ * \note The returned peer channel is the current peer in the
+ * bridge when called.
+ *
+ * \retval NULL Channel not in a bridge or the bridge is not two-party.
+ * \retval non-NULL Reffed peer channel at time of calling.
+ */
+struct ast_channel *ast_bridge_peer(struct ast_bridge *bridge, struct ast_channel *chan);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif

Modified: team/group/bridge_construction/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/channel.h?view=diff&rev=387477&r1=387476&r2=387477
==============================================================================
--- team/group/bridge_construction/include/asterisk/channel.h (original)
+++ team/group/bridge_construction/include/asterisk/channel.h Thu May  2 13:58:16 2013
@@ -4136,4 +4136,51 @@
  */
 struct stasis_topic *ast_channel_topic(struct ast_channel *chan);
 
+/*!
+ * \brief Get the bridge associated with a channel
+ * \since 12.0.0
+ *
+ * \param chan The channel whose bridge we want
+ *
+ * \details
+ * The bridge returned has its reference count incremented.  Use
+ * ao2_cleanup() or ao2_ref() in order to decrement the
+ * reference count when you are finished with the bridge.
+ *
+ * \note This function expects the channel to be locked prior to
+ * being called and will not grab the channel lock.
+ *
+ * \retval NULL No bridge present on the channel
+ * \retval non-NULL The bridge the channel is in
+ */
+struct ast_bridge *ast_channel_get_bridge(const struct ast_channel *chan);
+
+/*!
+ * \brief Determine if a channel is in a bridge
+ * \since 12.0.0
+ *
+ * \param chan The channel to test
+ *
+ * \note This function expects the channel to be locked prior to
+ * being called and will not grab the channel lock.
+ *
+ * \retval 0 The channel is not bridged
+ * \retval non-zero The channel is bridged
+ */
+int ast_channel_is_bridged(const struct ast_channel *chan);
+
+/*!
+ * \brief Get the channel's bridge peer only if the bridge is two-party.
+ * \since 12.0.0
+ *
+ * \param chan Channel desiring the bridge peer channel.
+ *
+ * \note The returned peer channel is the current peer in the
+ * bridge when called.
+ *
+ * \retval NULL Channel not in a bridge or the bridge is not two-party.
+ * \retval non-NULL Reffed peer channel at time of calling.
+ */
+struct ast_channel *ast_channel_bridge_peer(struct ast_channel *chan);
+
 #endif /* _ASTERISK_CHANNEL_H */

Modified: team/group/bridge_construction/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/bridging.c?view=diff&rev=387477&r1=387476&r2=387477
==============================================================================
--- team/group/bridge_construction/main/bridging.c (original)
+++ team/group/bridge_construction/main/bridging.c Thu May  2 13:58:16 2013
@@ -2310,6 +2310,14 @@
 		bridge_channel->bridge->uniqueid,
 		bridge_channel, ast_channel_name(bridge_channel->chan));
 
+	/*
+	 * Get "in the bridge" before pushing the channel for any
+	 * masquerades on the channel to happen before bridging.
+	 */
+	ast_channel_lock(bridge_channel->chan);
+	ast_channel_internal_bridge_set(bridge_channel->chan, bridge_channel->bridge);
+	ast_channel_unlock(bridge_channel->chan);
+
 	/* Add the jitterbuffer if the channel requires it */
 	ast_jb_enable_for_channel(bridge_channel->chan);
 
@@ -2342,9 +2350,6 @@
 		ast_bridge_unlock(bridge_channel->bridge);
 		bridge_channel_handle_join(bridge_channel);
 		while (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
-			/* Update bridge pointer on channel */
-			ast_channel_internal_bridge_set(bridge_channel->chan, bridge_channel->bridge);
-
 			/* Wait for something to do. */
 			bridge_channel_wait(bridge_channel);
 		}
@@ -2378,7 +2383,9 @@
 	while (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)) {
 		sched_yield();
 	}
+	ast_channel_lock(bridge_channel->chan);
 	ast_channel_internal_bridge_set(bridge_channel->chan, NULL);
+	ast_channel_unlock(bridge_channel->chan);
 
 	ast_bridge_channel_restore_formats(bridge_channel);
 }
@@ -3122,7 +3129,10 @@
 		/* Point to new bridge.*/
 		ao2_ref(dst_bridge, +1);
 		ast_bridge_channel_lock(bridge_channel);
+		ast_channel_lock(bridge_channel->chan);
 		bridge_channel->bridge = dst_bridge;
+		ast_channel_internal_bridge_set(bridge_channel->chan, dst_bridge);
+		ast_channel_unlock(bridge_channel->chan);
 		ast_bridge_channel_unlock(bridge_channel);
 		ao2_ref(src_bridge, -1);
 
@@ -3380,7 +3390,10 @@
 	/* Point to new bridge.*/
 	ao2_ref(dst_bridge, +1);
 	ast_bridge_channel_lock(bridge_channel);
+	ast_channel_lock(bridge_channel->chan);
 	bridge_channel->bridge = dst_bridge;
+	ast_channel_internal_bridge_set(bridge_channel->chan, dst_bridge);
+	ast_channel_unlock(bridge_channel->chan);
 	ast_bridge_channel_unlock(bridge_channel);
 
 	if (bridge_channel_push(bridge_channel)) {
@@ -3389,7 +3402,10 @@
 			/* Point back to original bridge. */
 			ao2_ref(orig_bridge, +1);
 			ast_bridge_channel_lock(bridge_channel);
+			ast_channel_lock(bridge_channel->chan);
 			bridge_channel->bridge = orig_bridge;
+			ast_channel_internal_bridge_set(bridge_channel->chan, orig_bridge);
+			ast_channel_unlock(bridge_channel->chan);
 			ast_bridge_channel_unlock(bridge_channel);
 			ao2_ref(dst_bridge, -1);
 
@@ -3502,9 +3518,10 @@
 	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);
+		AST_LIST_TRAVERSE(&bridge->channels, other, entry) {
+			if (other != bridge_channel) {
+				break;
+			}
 		}
 	}
 
@@ -4693,6 +4710,45 @@
 	return channels;
 }
 
+struct ast_channel *ast_bridge_peer_nolock(struct ast_bridge *bridge, struct ast_channel *chan)
+{
+	struct ast_channel *peer = NULL;
+	struct ast_bridge_channel *iter;
+
+	/* Asking for the peer channel only makes sense on a two-party bridge. */
+	if (bridge->num_channels == 2
+		&& bridge->technology->capabilities
+			& (AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX)) {
+		int in_bridge = 0;
+
+		AST_LIST_TRAVERSE(&bridge->channels, iter, entry) {
+			if (iter->chan != chan) {
+				peer = iter->chan;
+			} else {
+				in_bridge = 1;
+			}
+		}
+		if (in_bridge && peer) {
+			ast_channel_ref(peer);
+		} else {
+			peer = NULL;
+		}
+	}
+
+	return peer;
+}
+
+struct ast_channel *ast_bridge_peer(struct ast_bridge *bridge, struct ast_channel *chan)
+{
+	struct ast_channel *peer;
+
+	ast_bridge_lock(bridge);
+	peer = ast_bridge_peer_nolock(bridge, chan);
+	ast_bridge_unlock(bridge);
+
+	return peer;
+}
+
 /*!
  * \internal
  * \brief Service the bridge manager request.

Modified: team/group/bridge_construction/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/channel.c?view=diff&rev=387477&r1=387476&r2=387477
==============================================================================
--- team/group/bridge_construction/main/channel.c (original)
+++ team/group/bridge_construction/main/channel.c Thu May  2 13:58:16 2013
@@ -11297,3 +11297,37 @@
 {
 	ao2_unlink(channels, chan);
 }
+
+struct ast_bridge *ast_channel_get_bridge(const struct ast_channel *chan)
+{
+	struct ast_bridge *bridge;
+
+	bridge = ast_channel_internal_bridge(chan);
+	if (bridge) {
+		ao2_ref(bridge, +1);
+	}
+	return bridge;
+}
+
+int ast_channel_is_bridged(const struct ast_channel *chan)
+{
+	return ast_channel_internal_bridge(chan) != NULL;
+}
+
+struct ast_channel *ast_channel_bridge_peer(struct ast_channel *chan)
+{
+	struct ast_channel *peer;
+	struct ast_bridge *bridge;
+
+	/* Get the bridge the channel is in. */
+	ast_channel_lock(chan);
+	bridge = ast_channel_get_bridge(chan);
+	ast_channel_unlock(chan);
+	if (!bridge) {
+		return NULL;
+	}
+
+	peer = ast_bridge_peer(bridge, chan);
+	ao2_ref(bridge, -1);
+	return peer;
+}




More information about the asterisk-commits mailing list