[svn-commits] rmudgett: branch group/bridge_construction r382467 - in /team/group/bridge_co...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Mar 5 14:01:10 CST 2013


Author: rmudgett
Date: Tue Mar  5 14:01:06 2013
New Revision: 382467

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=382467
Log:
Make ast_bridge_depart() channels able to move to other bridges.

Code is simplified as a bonus.

Modified:
    team/group/bridge_construction/apps/app_confbridge.c
    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_internal_api.c

Modified: team/group/bridge_construction/apps/app_confbridge.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/apps/app_confbridge.c?view=diff&rev=382467&r1=382466&r2=382467
==============================================================================
--- team/group/bridge_construction/apps/app_confbridge.c (original)
+++ team/group/bridge_construction/apps/app_confbridge.c Tue Mar  5 14:01:06 2013
@@ -1490,7 +1490,7 @@
 	}
 
 	ast_debug(1, "Departing underlying channel '%s' from bridge '%p'\n", ast_channel_name(underlying_channel), conference_bridge->bridge);
-	ast_bridge_depart(conference_bridge->bridge, underlying_channel);
+	ast_bridge_depart(underlying_channel);
 
 	ast_mutex_unlock(&conference_bridge->playback_lock);
 

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=382467&r1=382466&r2=382467
==============================================================================
--- team/group/bridge_construction/bridges/bridge_builtin_features.c (original)
+++ team/group/bridge_construction/bridges/bridge_builtin_features.c Tue Mar  5 14:01:06 2013
@@ -283,10 +283,10 @@
 
 	/* Wait for peer thread to exit bridge and die. */
 	if (!ast_autoservice_start(bridge_channel->chan)) {
-		ast_bridge_depart(attended_bridge, peer);
+		ast_bridge_depart(peer);
 		ast_autoservice_stop(bridge_channel->chan);
 	} else {
-		ast_bridge_depart(attended_bridge, peer);
+		ast_bridge_depart(peer);
 	}
 
 	/* Now that all channels are out of it we can destroy the bridge and the feature structures */

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=382467&r1=382466&r2=382467
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging.h Tue Mar  5 14:01:06 2013
@@ -91,8 +91,6 @@
 	AST_BRIDGE_CHANNEL_STATE_HANGUP,
 	/*! Bridged channel was ast_bridge_depart() from the bridge without being hung up */
 	AST_BRIDGE_CHANNEL_STATE_DEPART,
-	/*! Bridged channel was ast_bridge_depart() from the bridge during AST_BRIDGE_CHANNEL_STATE_END */
-	AST_BRIDGE_CHANNEL_STATE_DEPART_END,
 };
 
 /*! \brief Return values for bridge technology write function */
@@ -152,7 +150,7 @@
 	unsigned int just_joined:1;
 	/*! TRUE if the channel is suspended from the bridge. */
 	unsigned int suspended:1;
-	/*! TRUE if the imparted channel must wait for an explicit depart from the bridge to reclaim the channel. */
+	/*! TRUE if the channel must wait for an ast_bridge_depart to reclaim the channel. */
 	unsigned int depart_wait:1;
 	/*! Features structure for features that are specific to this channel */
 	struct ast_bridge_features *features;
@@ -271,8 +269,6 @@
 	struct ast_callid *callid;
 	/*! Linked list of channels participating in the bridge */
 	AST_LIST_HEAD_NOLOCK(, ast_bridge_channel) channels;
-	/*! Linked list of channels removed from the bridge and waiting to be departed. */
-	AST_LIST_HEAD_NOLOCK(, ast_bridge_channel) depart_wait;
 	/*! Queue of actions to perform on the bridge. */
 	AST_LIST_HEAD_NOLOCK(, ast_frame) action_queue;
 };
@@ -447,7 +443,6 @@
 /*!
  * \brief Depart a channel from a bridge
  *
- * \param bridge Bridge to depart from
  * \param chan Channel to depart
  *
  * \retval 0 on success
@@ -456,17 +451,17 @@
  * Example usage:
  *
  * \code
- * ast_bridge_depart(bridge, chan);
- * \endcode
- *
- * This removes the channel pointed to by the chan pointer from the bridge
- * pointed to by the bridge pointer and gives control to the calling thread.
+ * ast_bridge_depart(chan);
+ * \endcode
+ *
+ * This removes the channel pointed to by the chan pointer from any bridge
+ * it may be in and gives control to the calling thread.
  * This does not hang up the channel.
  *
  * \note This API call can only be used on channels that were added to the bridge
  *       using the ast_bridge_impart API call with the independent flag FALSE.
  */
-int ast_bridge_depart(struct ast_bridge *bridge, struct ast_channel *chan);
+int ast_bridge_depart(struct ast_channel *chan);
 
 /*!
  * \brief Remove a channel from a bridge

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=382467&r1=382466&r2=382467
==============================================================================
--- team/group/bridge_construction/include/asterisk/channel.h (original)
+++ team/group/bridge_construction/include/asterisk/channel.h Tue Mar  5 14:01:06 2013
@@ -4032,6 +4032,9 @@
 struct ast_bridge *ast_channel_internal_bridge(const struct ast_channel *chan);
 void ast_channel_internal_bridge_set(struct ast_channel *chan, struct ast_bridge *value);
 
+struct ast_bridge_channel *ast_channel_internal_bridge_channel(const struct ast_channel *chan);
+void ast_channel_internal_bridge_channel_set(struct ast_channel *chan, struct ast_bridge_channel *value);
+
 struct ast_channel *ast_channel_internal_bridged_channel(const struct ast_channel *chan);
 void ast_channel_internal_bridged_channel_set(struct ast_channel *chan, struct ast_channel *value);
 

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=382467&r1=382466&r2=382467
==============================================================================
--- team/group/bridge_construction/main/bridging.c (original)
+++ team/group/bridge_construction/main/bridging.c Tue Mar  5 14:01:06 2013
@@ -934,7 +934,6 @@
 
 	/* There should not be any channels left in the bridge. */
 	ast_assert(AST_LIST_EMPTY(&bridge->channels));
-	ast_assert(AST_LIST_EMPTY(&bridge->depart_wait));
 
 	ao2_lock(bridge);
 	if (bridge->thread != AST_PTHREADT_NULL) {
@@ -1629,9 +1628,6 @@
 
 	ast_format_copy(&formats[0], ast_channel_readformat(bridge_channel->chan));
 	ast_format_copy(&formats[1], ast_channel_writeformat(bridge_channel->chan));
-
-	/* Record the thread that will be the owner of us */
-	bridge_channel->thread = pthread_self();
 
 	ast_debug(1, "Joining bridge channel %p(%s) to bridge %p\n",
 		bridge_channel, ast_channel_name(bridge_channel->chan), bridge_channel->bridge);
@@ -1712,23 +1708,10 @@
 	/* See if we need to dissolve the bridge itself if they hung up */
 	switch (bridge_channel->state) {
 	case AST_BRIDGE_CHANNEL_STATE_END:
-	case AST_BRIDGE_CHANNEL_STATE_DEPART_END:
 		bridge_check_dissolve(bridge_channel->bridge, bridge_channel);
 		break;
 	default:
 		break;
-	}
-
-	if (bridge_channel->depart_wait) {
-		switch (bridge_channel->state) {
-		case AST_BRIDGE_CHANNEL_STATE_DEPART:
-		case AST_BRIDGE_CHANNEL_STATE_DEPART_END:
-			break;
-		default:
-			/* Put the channel into the ast_bridge_depart wait list. */
-			AST_LIST_INSERT_TAIL(&bridge_channel->bridge->depart_wait, bridge_channel, entry);
-			break;
-		}
 	}
 
 	ao2_unlock(bridge_channel->bridge);
@@ -2117,6 +2100,8 @@
 	}
 
 	/* Initialize various other elements of the bridge channel structure that we can't do above */
+	ast_channel_internal_bridge_channel_set(chan, bridge_channel);
+	bridge_channel->thread = pthread_self();
 	bridge_channel->chan = chan;
 	bridge_channel->swap = swap;
 	bridge_channel->features = features;
@@ -2125,6 +2110,7 @@
 	state = bridge_channel->state;
 
 	/* Cleanup all the data in the bridge channel after it leaves the bridge. */
+	ast_channel_internal_bridge_channel_set(chan, NULL);
 	bridge_channel->chan = NULL;
 	bridge_channel->swap = NULL;
 	bridge_channel->features = NULL;
@@ -2180,6 +2166,7 @@
 	chan = bridge_channel->chan;
 
 	/* cleanup */
+	ast_channel_internal_bridge_channel_set(bridge_channel->chan, NULL);
 	bridge_channel->chan = NULL;
 	bridge_channel->swap = NULL;
 	ast_bridge_features_destroy(bridge_channel->features);
@@ -2187,19 +2174,6 @@
 
 	ao2_ref(bridge_channel, -1);
 
-	switch (state) {
-	case AST_BRIDGE_CHANNEL_STATE_DEPART:
-	case AST_BRIDGE_CHANNEL_STATE_DEPART_END:
-		ast_log(LOG_ERROR, "Independently imparted channel was departed: %s\n",
-			ast_channel_name(chan));
-		ast_assert(0);
-		/* fallthrough */
-	case AST_BRIDGE_CHANNEL_STATE_HANGUP:
-	case AST_BRIDGE_CHANNEL_STATE_END:
-	default:
-		break;
-	}
-
 	ast_after_bridge_goto_run(chan);
 	return NULL;
 }
@@ -2216,6 +2190,7 @@
 	}
 
 	/* Setup various parameters */
+	ast_channel_internal_bridge_channel_set(chan, bridge_channel);
 	bridge_channel->chan = chan;
 	bridge_channel->swap = swap;
 	bridge_channel->features = features;
@@ -2238,6 +2213,7 @@
 	}
 	if (res) {
 		/* cleanup */
+		ast_channel_internal_bridge_channel_set(chan, NULL);
 		bridge_channel->chan = NULL;
 		bridge_channel->swap = NULL;
 		ast_bridge_features_destroy(bridge_channel->features);
@@ -2250,66 +2226,41 @@
 	return 0;
 }
 
-int ast_bridge_depart(struct ast_bridge *bridge, struct ast_channel *chan)
+int ast_bridge_depart(struct ast_channel *chan)
 {
 	struct ast_bridge_channel *bridge_channel;
-	pthread_t thread;
-
-	ao2_lock(bridge);
-
-	do {
-		/* Try to find the channel that we want to depart */
-		bridge_channel = find_bridge_channel(bridge, chan);
-		if (bridge_channel) {
-			/* Channel is still in the bridge. */
-			if (!bridge_channel->depart_wait) {
-				ast_log(LOG_ERROR, "Bridged channel cannot be departed: %s\n",
-					ast_channel_name(bridge_channel->chan));
-				ao2_unlock(bridge);
-				return -1;
-			}
-			ao2_lock(bridge_channel);
-			switch (bridge_channel->state) {
-			case AST_BRIDGE_CHANNEL_STATE_END:
-				ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_DEPART_END);
-				break;
-			case AST_BRIDGE_CHANNEL_STATE_DEPART:
-			case AST_BRIDGE_CHANNEL_STATE_DEPART_END:
-				/*
-				 * Should never happen.  It likely means that
-				 * ast_bridge_depart() is called by two threads for the same
-				 * channel.
-				 */
-				ast_assert(0);
-				break;
-			default:
-				ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_DEPART);
-				break;
-			}
-			ao2_unlock(bridge_channel);
-			break;
-		}
-
-		/* Was the channel already removed from the bridge? */
-		AST_LIST_TRAVERSE_SAFE_BEGIN(&bridge->depart_wait, bridge_channel, entry) {
-			if (bridge_channel->chan == chan) {
-				AST_LIST_REMOVE_CURRENT(entry);
-				break;
-			}
-		}
-		AST_LIST_TRAVERSE_SAFE_END;
-		if (!bridge_channel) {
-			/* Channel does not exist. */
-			ao2_unlock(bridge);
-			return -1;
-		}
-	} while (0);
-	thread = bridge_channel->thread;
-
-	ao2_unlock(bridge);
+
+	bridge_channel = ast_channel_internal_bridge_channel(chan);
+	if (!bridge_channel || !bridge_channel->depart_wait) {
+		ast_log(LOG_ERROR, "Channel %s cannot be departed.\n",
+			ast_channel_name(chan));
+		/*
+		 * Should never happen.  It likely means that
+		 * ast_bridge_depart() is called by two threads for the same
+		 * channel, the channel was never imparted to be departed, or it
+		 * has already been departed.
+		 */
+		ast_assert(0);
+		return -1;
+	}
+
+	/* We are claiming the reference held by the depart thread. */
+
+	ao2_lock(bridge_channel);
+	switch (bridge_channel->state) {
+	case AST_BRIDGE_CHANNEL_STATE_WAIT:
+		ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+		break;
+	default:
+		/* The channel is already leaving the bridge. */
+		break;
+	}
+	ao2_unlock(bridge_channel);
 
 	/* Wait for the depart thread to die */
-	pthread_join(thread, NULL);
+	pthread_join(bridge_channel->thread, NULL);
+
+	ast_channel_internal_bridge_channel_set(chan, NULL);
 
 	/* We can get rid of the bridge_channel after the depart thread has died. */
 	ao2_ref(bridge_channel, -1);

Modified: team/group/bridge_construction/main/channel_internal_api.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/channel_internal_api.c?view=diff&rev=382467&r1=382466&r2=382467
==============================================================================
--- team/group/bridge_construction/main/channel_internal_api.c (original)
+++ team/group/bridge_construction/main/channel_internal_api.c Tue Mar  5 14:01:06 2013
@@ -188,6 +188,7 @@
 
 /* BUGBUG the bridge pointer must change to an ast_channel_bridge pointer because it will never change while the channel is in the bridging system whereas the bridge could change. */
 	struct ast_bridge *bridge;                      /*!< Bridge this channel is participating in */
+	struct ast_bridge_channel *bridge_channel;/*!< The bridge_channel this channel is linked with. */
 	struct ast_timer *timer;			/*!< timer object that provided timingfd */
 
 	char context[AST_MAX_CONTEXT];			/*!< Dialplan: Current extension context */
@@ -1252,6 +1253,15 @@
 	chan->bridge = value;
 }
 
+struct ast_bridge_channel *ast_channel_internal_bridge_channel(const struct ast_channel *chan)
+{
+	return chan->bridge_channel;
+}
+void ast_channel_internal_bridge_channel_set(struct ast_channel *chan, struct ast_bridge_channel *value)
+{
+	chan->bridge_channel = value;
+}
+
 struct ast_channel *ast_channel_internal_bridged_channel(const struct ast_channel *chan)
 {
 	return chan->bridged_channel;




More information about the svn-commits mailing list