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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Jan 31 13:18:47 CST 2013


Author: rmudgett
Date: Thu Jan 31 13:18:41 2013
New Revision: 380679

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=380679
Log:
Add an action queue to bridge_channels.

Modified:
    team/group/bridge_construction/apps/app_confbridge.c
    team/group/bridge_construction/bridges/bridge_multiplexed.c
    team/group/bridge_construction/bridges/bridge_simple.c
    team/group/bridge_construction/bridges/bridge_softmix.c
    team/group/bridge_construction/funcs/func_frame_trace.c
    team/group/bridge_construction/include/asterisk/bridging.h
    team/group/bridge_construction/include/asterisk/bridging_features.h
    team/group/bridge_construction/include/asterisk/bridging_technology.h
    team/group/bridge_construction/include/asterisk/frame.h
    team/group/bridge_construction/main/bridging.c
    team/group/bridge_construction/main/channel.c
    team/group/bridge_construction/main/frame.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=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/apps/app_confbridge.c (original)
+++ team/group/bridge_construction/apps/app_confbridge.c Thu Jan 31 13:18:41 2013
@@ -1373,21 +1373,9 @@
 	ast_free(pvt_data);
 }
 
-static void conf_handle_talker_cb(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *pvt_data)
-{
-	char *conf_name = pvt_data;
-	int talking;
-
-	switch (bridge_channel->state) {
-	case AST_BRIDGE_CHANNEL_STATE_START_TALKING:
-		talking = 1;
-		break;
-	case AST_BRIDGE_CHANNEL_STATE_STOP_TALKING:
-		talking = 0;
-		break;
-	default:
-		return; /* uhh this shouldn't happen, but bail if it does. */
-	}
+static void conf_handle_talker_cb(struct ast_bridge_channel *bridge_channel, void *pvt_data, int talking)
+{
+	const char *conf_name = pvt_data;
 
 	/* notify AMI someone is has either started or stopped talking */
 	/*** DOCUMENTATION
@@ -1405,11 +1393,14 @@
 		</managerEventInstance>
 	***/
 	ast_manager_event(bridge_channel->chan, EVENT_FLAG_CALL, "ConfbridgeTalking",
-	      "Channel: %s\r\n"
-	      "Uniqueid: %s\r\n"
-	      "Conference: %s\r\n"
-	      "TalkingStatus: %s\r\n",
-	      ast_channel_name(bridge_channel->chan), ast_channel_uniqueid(bridge_channel->chan), conf_name, talking ? "on" : "off");
+		"Channel: %s\r\n"
+		"Uniqueid: %s\r\n"
+		"Conference: %s\r\n"
+		"TalkingStatus: %s\r\n",
+		ast_channel_name(bridge_channel->chan),
+		ast_channel_uniqueid(bridge_channel->chan),
+		conf_name,
+		talking ? "on" : "off");
 }
 
 static int conf_get_pin(struct ast_channel *chan, struct conference_bridge_user *conference_bridge_user)

Modified: team/group/bridge_construction/bridges/bridge_multiplexed.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_multiplexed.c?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/bridges/bridge_multiplexed.c (original)
+++ team/group/bridge_construction/bridges/bridge_multiplexed.c Thu Jan 31 13:18:41 2013
@@ -465,9 +465,11 @@
 		return AST_BRIDGE_WRITE_FAILED;
 	}
 
-	/* Write the frame out if they are in the waiting state... don't worry about freeing it, the bridging core will take care of it */
+	/* The bridging core takes care of freeing the passed in frame. */
 	if (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
-		ast_write(other->chan, frame);
+		if (!other->suspended) {
+			ast_write(other->chan, frame);
+		}
 	}
 
 	return AST_BRIDGE_WRITE_SUCCESS;

Modified: team/group/bridge_construction/bridges/bridge_simple.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_simple.c?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/bridges/bridge_simple.c (original)
+++ team/group/bridge_construction/bridges/bridge_simple.c Thu Jan 31 13:18:41 2013
@@ -80,9 +80,11 @@
 		return AST_BRIDGE_WRITE_FAILED;
 	}
 
-	/* Write the frame out if they are in the waiting state... don't worry about freeing it, the bridging core will take care of it */
+	/* The bridging core takes care of freeing the passed in frame. */
 	if (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
-		ast_write(other->chan, frame);
+		if (!other->suspended) {
+			ast_write(other->chan, frame);
+		}
 	}
 
 	return AST_BRIDGE_WRITE_SUCCESS;

Modified: team/group/bridge_construction/bridges/bridge_softmix.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_softmix.c?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/bridges/bridge_softmix.c (original)
+++ team/group/bridge_construction/bridges/bridge_softmix.c Thu Jan 31 13:18:41 2013
@@ -578,7 +578,7 @@
 	ast_mutex_unlock(&sc->lock);
 
 	if (update_talking != -1) {
-		ast_bridge_notify_talking(bridge, bridge_channel, update_talking);
+		ast_bridge_notify_talking(bridge_channel, update_talking);
 	}
 
 	return res;

Modified: team/group/bridge_construction/funcs/func_frame_trace.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/funcs/func_frame_trace.c?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/funcs/func_frame_trace.c (original)
+++ team/group/bridge_construction/funcs/func_frame_trace.c Thu Jan 31 13:18:41 2013
@@ -376,6 +376,10 @@
 		ast_verbose("Digit: 0x%02X '%c'\n", frame->subclass.integer,
 			frame->subclass.integer < ' ' ? ' ' : frame->subclass.integer);
 		break;
+	case AST_FRAME_BRIDGE_ACTION:
+		ast_verbose("FrameType: Bridge\n");
+		ast_verbose("SubClass: %d\n", frame->subclass.integer);
+		break;
 	}
 
 	ast_verbose("Src: %s\n", ast_strlen_zero(frame->src) ? "NOT PRESENT" : frame->src);

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=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging.h Thu Jan 31 13:18:41 2013
@@ -93,14 +93,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 is executing a feature hook */
-	AST_BRIDGE_CHANNEL_STATE_FEATURE,
-	/*! Bridged channel is sending a DTMF stream out */
-	AST_BRIDGE_CHANNEL_STATE_DTMF,
-	/*! Bridged channel began talking */
-	AST_BRIDGE_CHANNEL_STATE_START_TALKING,
-	/*! Bridged channel has stopped talking */
-	AST_BRIDGE_CHANNEL_STATE_STOP_TALKING,
 };
 
 /*! \brief Return values for bridge technology write function */
@@ -161,12 +153,23 @@
 	/*! Technology optimization parameters used by bridging technologies capable of
 	 *  optimizing based upon talk detection. */
 	struct ast_bridge_tech_optimizations tech_args;
-	/*! Queue of DTMF digits used for DTMF streaming */
-	char dtmf_stream_q[8];
 	/*! Call ID associated with bridge channel */
 	struct ast_callid *callid;
 	/*! Linked list information */
 	AST_LIST_ENTRY(ast_bridge_channel) entry;
+	/*! Queue of actions to perform on the channel. */
+	AST_LIST_HEAD_NOLOCK(, ast_frame) action_queue;
+};
+
+enum ast_bridge_action_type {
+	/*! Bridged channel is to detect a feature hook */
+	AST_BRIDGE_ACTION_FEATURE,
+	/*! Bridged channel is to send a DTMF stream out */
+	AST_BRIDGE_ACTION_DTMF_STREAM,
+	/*! Bridged channel is to indicate talking start */
+	AST_BRIDGE_ACTION_TALKING_START,
+	/*! Bridged channel is to indicate talking stop */
+	AST_BRIDGE_ACTION_TALKING_STOP,
 };
 
 enum ast_bridge_video_mode_type {
@@ -557,6 +560,21 @@
 void ast_bridge_change_state(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state);
 
 /*!
+ * \brief Put an action onto the specified bridge_channel.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Channel to queue the action on.
+ * \param action What to do.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ *
+ * \note This API call is meant for internal bridging operations.
+ * \note BUGBUG This may get moved.
+ */
+int ast_bridge_channel_queue_action(struct ast_bridge_channel *bridge_channel, struct ast_frame *action);
+
+/*!
  * \brief Adjust the internal mixing sample rate of a bridge
  * used during multimix mode.
  *

Modified: team/group/bridge_construction/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/bridging_features.h?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging_features.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging_features.h Thu Jan 31 13:18:41 2013
@@ -107,13 +107,13 @@
  * to receive updates on when a bridge_channel has started and stopped
  * talking
  *
- * \param bridge The bridge that the channel is part of
  * \param bridge_channel Channel executing the feature
+ * \param talking TRUE if the channel is now talking
  *
  * \retval 0 success
  * \retval -1 failure
  */
-typedef void (*ast_bridge_talking_indicate_callback)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *pvt_data);
+typedef void (*ast_bridge_talking_indicate_callback)(struct ast_bridge_channel *bridge_channel, void *pvt_data, int talking);
 
 
 typedef void (*ast_bridge_talking_indicate_destructor)(void *pvt_data);

Modified: team/group/bridge_construction/include/asterisk/bridging_technology.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/bridging_technology.h?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging_technology.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging_technology.h Thu Jan 31 13:18:41 2013
@@ -155,12 +155,11 @@
  * application, this function has been created to allow the bridging technology to communicate
  * that information with the bridging core.
  *
- * \param bridge The bridge that the channel is a part of.
  * \param bridge_channel The bridge channel that has either started or stopped talking.
  * \param started_talking set to 1 when this indicates the channel has started talking set to 0
  * when this indicates the channel has stopped talking.
  */
-void ast_bridge_notify_talking(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, int started_talking);
+void ast_bridge_notify_talking(struct ast_bridge_channel *bridge_channel, int started_talking);
 
 /*!
  * \brief Suspend a bridge technology from consideration

Modified: team/group/bridge_construction/include/asterisk/frame.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/frame.h?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/include/asterisk/frame.h (original)
+++ team/group/bridge_construction/include/asterisk/frame.h Thu Jan 31 13:18:41 2013
@@ -120,6 +120,8 @@
 	AST_FRAME_MODEM,	
 	/*! DTMF begin event, subclass is the digit */
 	AST_FRAME_DTMF_BEGIN,
+	/*! Internal bridge module action. */
+	AST_FRAME_BRIDGE_ACTION,
 };
 #define AST_FRAME_DTMF AST_FRAME_DTMF_END
 

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=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/main/bridging.c (original)
+++ team/group/bridge_construction/main/bridging.c Thu Jan 31 13:18:41 2013
@@ -129,6 +129,9 @@
 /*! \note This function assumes the bridge_channel is locked. */
 static void ast_bridge_change_state_nolock(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state)
 {
+	ast_debug(1, "BUGBUG Setting bridge channel %p state from:%d to:%d\n",
+		bridge_channel, bridge_channel->state, new_state);
+
 	/* Change the state on the bridge channel */
 	bridge_channel->state = new_state;
 
@@ -144,6 +147,30 @@
 	ao2_lock(bridge_channel);
 	ast_bridge_change_state_nolock(bridge_channel, new_state);
 	ao2_unlock(bridge_channel);
+}
+
+int ast_bridge_channel_queue_action(struct ast_bridge_channel *bridge_channel, struct ast_frame *action)
+{
+	struct ast_frame *dup;
+
+	dup = ast_frdup(action);
+	if (!dup) {
+		return -1;
+	}
+
+	ast_debug(1, "BUGBUG Queueing action type:%d sub:%d on bridge channel %p\n",
+		action->frametype, action->subclass.integer, bridge_channel);
+
+	ao2_lock(bridge_channel);
+	AST_LIST_INSERT_TAIL(&bridge_channel->action_queue, dup, frame_list);
+
+	/* Only poke the channel's thread if it is not us */
+	if (!pthread_equal(pthread_self(), bridge_channel->thread)) {
+		pthread_kill(bridge_channel->thread, SIGURG);
+		ast_cond_signal(&bridge_channel->cond);
+	}
+	ao2_unlock(bridge_channel);
+	return 0;
 }
 
 /*!
@@ -219,7 +246,8 @@
 	bridge_poke(bridge);
 }
 
-/*! \brief Helper function to remove a channel from the bridge array
+/*!
+ * \brief Helper function to remove a channel from the bridge array
  *
  * \note This function assumes the bridge is locked.
  */
@@ -305,10 +333,15 @@
 /*! \brief Internal function to handle DTMF from a channel */
 static struct ast_frame *bridge_handle_dtmf(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 {
-	struct ast_bridge_features *features = (bridge_channel->features ? bridge_channel->features : &bridge->features);
+	struct ast_bridge_features *features;
 	struct ast_bridge_features_hook *hook;
 
-	/* If the features structure we grabbed is not usable immediately return the frame */
+	features = bridge_channel->features;
+	if (!features) {
+		features = &bridge->features;
+	}
+
+	/* If the features structure we grabbed is not usable, immediately return the frame */
 	if (!features->usable) {
 		return frame;
 	}
@@ -316,9 +349,14 @@
 	/* See if this DTMF matches the beginnings of any feature hooks, if so we switch to the feature state to either execute the feature or collect more DTMF */
 	AST_LIST_TRAVERSE(&features->hooks, hook, entry) {
 		if (hook->dtmf[0] == frame->subclass.integer) {
+			struct ast_frame action = {
+				.frametype = AST_FRAME_BRIDGE_ACTION,
+				.subclass.integer = AST_BRIDGE_ACTION_FEATURE,
+			};
+
 			ast_frfree(frame);
 			frame = NULL;
-			ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_FEATURE);
+			ast_bridge_channel_queue_action(bridge_channel, &action);
 			break;
 		}
 	}
@@ -346,13 +384,15 @@
 	}
 }
 
-void ast_bridge_notify_talking(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, int started_talking)
-{
-	if (started_talking) {
-		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_START_TALKING);
-	} else {
-		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_STOP_TALKING);
-	}
+void ast_bridge_notify_talking(struct ast_bridge_channel *bridge_channel, int started_talking)
+{
+	struct ast_frame action = {
+		.frametype = AST_FRAME_BRIDGE_ACTION,
+		.subclass.integer = started_talking
+			? AST_BRIDGE_ACTION_TALKING_START : AST_BRIDGE_ACTION_TALKING_STOP,
+	};
+
+	ast_bridge_channel_queue_action(bridge_channel, &action);
 }
 
 void ast_bridge_handle_trip(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_channel *chan, int outfd)
@@ -375,7 +415,11 @@
 		/* This is pretty simple... see if they hung up */
 		if (!frame || (frame->frametype == AST_FRAME_CONTROL && frame->subclass.integer == AST_CONTROL_HANGUP)) {
 			/* Signal the thread that is handling the bridged channel that it should be ended */
-			ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+			ao2_lock(bridge_channel);
+			if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+				ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+			}
+			ao2_unlock(bridge_channel);
 		} else if (frame->frametype == AST_FRAME_CONTROL && bridge_drop_control_frame(frame->subclass.integer)) {
 			ast_debug(1, "Dropping control frame %d from bridge channel %p\n",
 				frame->subclass.integer, bridge_channel);
@@ -866,14 +910,18 @@
 }
 
 /*! \brief Run in a multithreaded model. Each joined channel does writing/reading in their own thread. TODO: Improve */
-static enum ast_bridge_channel_state bridge_channel_join_multithreaded(struct ast_bridge_channel *bridge_channel)
-{
-	int fds[4] = { -1, }, nfds = 0, i = 0, outfd = -1, ms = -1;
+static void bridge_channel_join_multithreaded(struct ast_bridge_channel *bridge_channel)
+{
+	int fds[4] = { -1, };
+	int nfds = 0;
+	int outfd = -1;
+	int ms = -1;
+	int i;
 	struct ast_channel *chan;
 
 	/* Add any file descriptors we may want to monitor */
 	if (bridge_channel->bridge->technology->fd) {
-		for (i = 0; i < 4; i ++) {
+		for (i = 0; i < 4; ++i) {
 			if (bridge_channel->fds[i] >= 0) {
 				fds[nfds++] = bridge_channel->fds[i];
 			}
@@ -882,30 +930,31 @@
 
 	ao2_unlock(bridge_channel->bridge);
 
+	/* Wait for data to either come from the channel or us to be signaled */
 	ao2_lock(bridge_channel);
-	/* Wait for data to either come from the channel or us to be signalled */
-	if (!bridge_channel->suspended) {
+	if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
 		ao2_unlock(bridge_channel);
-		ast_debug(10, "Going into a multithreaded waitfor for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
-		chan = ast_waitfor_nandfds(&bridge_channel->chan, 1, fds, nfds, NULL, &outfd, &ms);
-	} else {
-		ast_debug(10, "Going into a multithreaded signal wait for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
+		ao2_lock(bridge_channel->bridge);
+	} else if (bridge_channel->suspended) {
+		ast_debug(10, "Going into a multithreaded signal wait for bridge channel %p of bridge %p\n",
+			bridge_channel, bridge_channel->bridge);
 		ast_cond_wait(&bridge_channel->cond, ao2_object_get_lockaddr(bridge_channel));
 		ao2_unlock(bridge_channel);
-		chan = NULL;
-	}
-
-	ao2_lock(bridge_channel->bridge);
-
-	if (!bridge_channel->suspended) {
-		ast_bridge_handle_trip(bridge_channel->bridge, bridge_channel, chan, outfd);
-	}
-
-	return bridge_channel->state;
+		ao2_lock(bridge_channel->bridge);
+	} else {
+		ao2_unlock(bridge_channel);
+		ast_debug(10, "Going into a multithreaded waitfor for bridge channel %p of bridge %p\n",
+			bridge_channel, bridge_channel->bridge);
+		chan = ast_waitfor_nandfds(&bridge_channel->chan, 1, fds, nfds, NULL, &outfd, &ms);
+		ao2_lock(bridge_channel->bridge);
+		if (!bridge_channel->suspended) {
+			ast_bridge_handle_trip(bridge_channel->bridge, bridge_channel, chan, outfd);
+		}
+	}
 }
 
 /*! \brief Run in a singlethreaded model. Each joined channel yields itself to the main bridge thread. TODO: Improve */
-static enum ast_bridge_channel_state bridge_channel_join_singlethreaded(struct ast_bridge_channel *bridge_channel)
+static void bridge_channel_join_singlethreaded(struct ast_bridge_channel *bridge_channel)
 {
 	ao2_unlock(bridge_channel->bridge);
 	ao2_lock(bridge_channel);
@@ -915,8 +964,6 @@
 	}
 	ao2_unlock(bridge_channel);
 	ao2_lock(bridge_channel->bridge);
-
-	return bridge_channel->state;
 }
 
 /*! \brief Internal function that suspends a channel from a bridge */
@@ -1017,7 +1064,7 @@
 		 */
 		if (bridge_channel->chan && ast_check_hangup_locked(bridge_channel->chan)) {
 			ao2_lock(bridge_channel);
-			if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_FEATURE) {
+			if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
 				ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
 			}
 			ao2_unlock(bridge_channel);
@@ -1027,32 +1074,96 @@
 	}
 }
 
-static void bridge_channel_talking(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	struct ast_bridge_features *features = (bridge_channel->features ? bridge_channel->features : &bridge->features);
-
-	if (features && features->talker_cb) {
-		features->talker_cb(bridge, bridge_channel, features->talker_pvt_data);
+static void bridge_channel_talking(struct ast_bridge_channel *bridge_channel, int talking)
+{
+	struct ast_bridge_features *features;
+
+	features = bridge_channel->features;
+	if (!features) {
+		features = &bridge_channel->bridge->features;
+	}
+	if (features->talker_cb) {
+		features->talker_cb(bridge_channel, features->talker_pvt_data, talking);
 	}
 }
 
 /*! \brief Internal function that plays back DTMF on a bridge channel */
-static void bridge_channel_dtmf_stream(struct ast_bridge_channel *bridge_channel)
-{
-	char dtmf_q[8] = "";
-
-	ast_copy_string(dtmf_q, bridge_channel->dtmf_stream_q, sizeof(dtmf_q));
-	bridge_channel->dtmf_stream_q[0] = '\0';
-
-	ast_debug(1, "Playing DTMF stream '%s' out to bridge channel %p\n", dtmf_q, bridge_channel);
-	ast_dtmf_stream(bridge_channel->chan, NULL, dtmf_q, 250, 0);
+static void bridge_channel_dtmf_stream(struct ast_bridge_channel *bridge_channel, const char *dtmf)
+{
+	ast_debug(1, "Playing DTMF stream '%s' out to bridge channel %p\n", dtmf, bridge_channel);
+	ast_dtmf_stream(bridge_channel->chan, NULL, dtmf, 0, 0);
+}
+
+/*!
+ * \internal
+ * \brief Handle bridge action.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Channel to execute the action on.
+ * \param action What to do.
+ *
+ * \return Nothing
+ *
+ * \note This function assumes the bridge is locked.
+ */
+static void bridge_channel_action_bridge(struct ast_bridge_channel *bridge_channel, struct ast_frame *action)
+{
+	switch (action->subclass.integer) {
+	case AST_BRIDGE_ACTION_FEATURE:
+		bridge_channel_suspend(bridge_channel->bridge, bridge_channel);
+		ao2_unlock(bridge_channel->bridge);
+		bridge_channel_feature(bridge_channel->bridge, bridge_channel);
+		ao2_lock(bridge_channel->bridge);
+		bridge_channel_unsuspend(bridge_channel->bridge, bridge_channel);
+		break;
+	case AST_BRIDGE_ACTION_DTMF_STREAM:
+		bridge_channel_suspend(bridge_channel->bridge, bridge_channel);
+		ao2_unlock(bridge_channel->bridge);
+		bridge_channel_dtmf_stream(bridge_channel, action->data.ptr);
+		ao2_lock(bridge_channel->bridge);
+		bridge_channel_unsuspend(bridge_channel->bridge, bridge_channel);
+		break;
+	case AST_BRIDGE_ACTION_TALKING_START:
+	case AST_BRIDGE_ACTION_TALKING_STOP:
+		ao2_unlock(bridge_channel->bridge);
+		bridge_channel_talking(bridge_channel,
+			action->subclass.integer == AST_BRIDGE_ACTION_TALKING_START);
+		ao2_lock(bridge_channel->bridge);
+		break;
+	default:
+		break;
+	}
+}
+
+/*!
+ * \internal
+ * \brief Handle control frame action.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Channel to execute the control frame action on.
+ * \param action What to do.
+ *
+ * \return Nothing
+ *
+ * \note This function assumes the bridge is locked.
+ */
+static void bridge_channel_action_control(struct ast_bridge_channel *bridge_channel, struct ast_frame *action)
+{
+	switch (action->subclass.integer) {
+	case AST_CONTROL_CONNECTED_LINE:
+		break;
+	default:
+		break;
+	}
+	/*! \todo BUGBUG bridge_channel_action_control() not written */
 }
 
 /*! \brief Join a channel to a bridge and handle anything the bridge may want us to do */
-static enum ast_bridge_channel_state bridge_channel_join(struct ast_bridge_channel *bridge_channel)
-{
+static void bridge_channel_join(struct ast_bridge_channel *bridge_channel)
+{
+	struct ast_frame *action;
 	struct ast_format formats[2];
-	enum ast_bridge_channel_state state;
+
 	ast_format_copy(&formats[0], ast_channel_readformat(bridge_channel->chan));
 	ast_format_copy(&formats[1], ast_channel_writeformat(bridge_channel->chan));
 
@@ -1086,7 +1197,11 @@
 		bridge_channel->swap = NULL;
 		if (bridge_channel2) {
 			ast_debug(1, "Swapping bridge channel %p out from bridge %p so bridge channel %p can slip in\n", bridge_channel2, bridge_channel->bridge, bridge_channel);
-			ast_bridge_change_state(bridge_channel2, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+			ao2_lock(bridge_channel2);
+			if (bridge_channel2->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+				ast_bridge_change_state_nolock(bridge_channel2, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+			}
+			ao2_unlock(bridge_channel2);
 		}
 	} else if (ast_test_flag(&bridge_channel->bridge->feature_flags, AST_BRIDGE_FLAG_SMART)) {
 		/* Perform the smart bridge operation, basically see if we need to move around between technologies */
@@ -1127,55 +1242,43 @@
 				continue;
 			}
 		}
+
 		/* Execute the threading model */
-		state = (bridge_channel->bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTITHREADED)
-			? bridge_channel_join_multithreaded(bridge_channel)
-			: bridge_channel_join_singlethreaded(bridge_channel);
-		/* Depending on the above state see what we need to do */
-		switch (state) {
-		case AST_BRIDGE_CHANNEL_STATE_FEATURE:
-			bridge_channel_suspend(bridge_channel->bridge, bridge_channel);
-			ao2_unlock(bridge_channel->bridge);
-			bridge_channel_feature(bridge_channel->bridge, bridge_channel);
-			ao2_lock(bridge_channel->bridge);
-			ao2_lock(bridge_channel);
-			if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_FEATURE) {
-				ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
-			}
+		if (bridge_channel->bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTITHREADED) {
+			bridge_channel_join_multithreaded(bridge_channel);
+		} else {
+			bridge_channel_join_singlethreaded(bridge_channel);
+		}
+
+		/* Run any queued actions on the channel. */
+		ao2_lock(bridge_channel);
+		while (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT
+			&& (action = AST_LIST_REMOVE_HEAD(&bridge_channel->action_queue, frame_list))) {
 			ao2_unlock(bridge_channel);
-			bridge_channel_unsuspend(bridge_channel->bridge, bridge_channel);
-			break;
-		case AST_BRIDGE_CHANNEL_STATE_DTMF:
-			bridge_channel_suspend(bridge_channel->bridge, bridge_channel);
-			ao2_unlock(bridge_channel->bridge);
-			bridge_channel_dtmf_stream(bridge_channel);
-			ao2_lock(bridge_channel->bridge);
-			ao2_lock(bridge_channel);
-			if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_DTMF) {
-				ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
-			}
-			ao2_unlock(bridge_channel);
-			bridge_channel_unsuspend(bridge_channel->bridge, bridge_channel);
-			break;
-		case AST_BRIDGE_CHANNEL_STATE_START_TALKING:
-		case AST_BRIDGE_CHANNEL_STATE_STOP_TALKING:
-			ao2_unlock(bridge_channel->bridge);
-			bridge_channel_talking(bridge_channel->bridge, bridge_channel);
-			ao2_lock(bridge_channel->bridge);
-			ao2_lock(bridge_channel);
-			switch (bridge_channel->state) {
-			case AST_BRIDGE_CHANNEL_STATE_START_TALKING:
-			case AST_BRIDGE_CHANNEL_STATE_STOP_TALKING:
-				ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
+			switch (action->frametype) {
+			case AST_FRAME_BRIDGE_ACTION:
+				bridge_channel_action_bridge(bridge_channel, action);
+				break;
+			case AST_FRAME_CONTROL:
+				bridge_channel_action_control(bridge_channel, action);
+				break;
+			case AST_FRAME_TEXT:
+			case AST_FRAME_IMAGE:
+			case AST_FRAME_HTML:
+				/* Write the deferred frame to the channel. */
+				ao2_unlock(bridge_channel->bridge);
+				ast_write(bridge_channel->chan, action);
+				ao2_lock(bridge_channel->bridge);
 				break;
 			default:
+				/* Unexpected deferred frame type.  Sould never happen. */
+				ast_assert(0);
 				break;
 			}
-			ao2_unlock(bridge_channel);
-			break;
-		default:
-			break;
-		}
+			ast_frfree(action);
+			ao2_lock(bridge_channel);
+		}
+		ao2_unlock(bridge_channel);
 	}
 
 	ast_channel_internal_bridge_set(bridge_channel->chan, NULL);
@@ -1212,6 +1315,13 @@
 
 	ao2_unlock(bridge_channel->bridge);
 
+	/* Flush any unhandled actions. */
+	ao2_lock(bridge_channel);
+	while ((action = AST_LIST_REMOVE_HEAD(&bridge_channel->action_queue, frame_list))) {
+		ast_frfree(action);
+	}
+	ao2_unlock(bridge_channel);
+
 	/* Restore original formats of the channel as they came in */
 	if (ast_format_cmp(ast_channel_readformat(bridge_channel->chan), &formats[0]) == AST_FORMAT_CMP_NOT_EQUAL) {
 		ast_debug(1, "Bridge is returning %p to read format %s(%d)\n", bridge_channel, ast_getformatname(&formats[0]), formats[0].id);
@@ -1225,8 +1335,6 @@
 			ast_debug(1, "Bridge failed to return channel %p to write format %s(%d)\n", bridge_channel, ast_getformatname(&formats[1]), formats[1].id);
 		}
 	}
-
-	return bridge_channel->state;
 }
 
 static void bridge_channel_destroy(void *obj)
@@ -1283,7 +1391,8 @@
 	bridge_channel->swap = swap;
 	bridge_channel->features = features;
 
-	state = bridge_channel_join(bridge_channel);
+	bridge_channel_join(bridge_channel);
+	state = bridge_channel->state;
 
 	/* Cleanup all the data in the bridge channel after it leaves the bridge. */
 	bridge_channel->chan = NULL;
@@ -1324,8 +1433,8 @@
 		ast_callid_threadassoc_add(bridge_channel->callid);
 	}
 
-	state = bridge_channel_join(bridge_channel);
-
+	bridge_channel_join(bridge_channel);
+	state = bridge_channel->state;
 	chan = bridge_channel->chan;
 
 	/* cleanup */
@@ -1453,7 +1562,11 @@
 		return -1;
 	}
 
-	ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+	ao2_lock(bridge_channel);
+	if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+		ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+	}
+	ao2_unlock(bridge_channel);
 
 	ao2_unlock(bridge);
 
@@ -1736,6 +1849,12 @@
 int ast_bridge_dtmf_stream(struct ast_bridge *bridge, const char *dtmf, struct ast_channel *chan)
 {
 	struct ast_bridge_channel *bridge_channel;
+	struct ast_frame action = {
+		.frametype = AST_FRAME_BRIDGE_ACTION,
+		.subclass.integer = AST_BRIDGE_ACTION_DTMF_STREAM,
+		.datalen = strlen(dtmf) + 1,
+		.data.ptr = (char *) dtmf,
+	};
 
 	ao2_lock(bridge);
 
@@ -1743,8 +1862,7 @@
 		if (bridge_channel->chan == chan) {
 			continue;
 		}
-		ast_copy_string(bridge_channel->dtmf_stream_q, dtmf, sizeof(bridge_channel->dtmf_stream_q));
-		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_DTMF);
+		ast_bridge_channel_queue_action(bridge_channel, &action);
 	}
 
 	ao2_unlock(bridge);

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=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/main/channel.c (original)
+++ team/group/bridge_construction/main/channel.c Thu Jan 31 13:18:41 2013
@@ -1653,6 +1653,7 @@
 	 * be queued up or not.
 	 */
 	switch (frame->frametype) {
+	case AST_FRAME_BRIDGE_ACTION:
 	case AST_FRAME_CONTROL:
 	case AST_FRAME_TEXT:
 	case AST_FRAME_IMAGE:
@@ -3072,6 +3073,7 @@
 					break;
 				case AST_FRAME_CONTROL:
 				case AST_FRAME_IAX:
+				case AST_FRAME_BRIDGE_ACTION:
 				case AST_FRAME_NULL:
 				case AST_FRAME_CNG:
 					break;

Modified: team/group/bridge_construction/main/frame.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/frame.c?view=diff&rev=380679&r1=380678&r2=380679
==============================================================================
--- team/group/bridge_construction/main/frame.c (original)
+++ team/group/bridge_construction/main/frame.c Thu Jan 31 13:18:41 2013
@@ -628,6 +628,10 @@
 		/* Should never happen */
 		snprintf(subclass, slen, "IAX Frametype %d", f->subclass.integer);
 		break;
+	case AST_FRAME_BRIDGE_ACTION:
+		/* Should never happen */
+		snprintf(subclass, slen, "Bridge Frametype %d", f->subclass.integer);
+		break;
 	case AST_FRAME_TEXT:
 		ast_copy_string(subclass, "N/A", slen);
 		if (moreinfo) {
@@ -714,6 +718,10 @@
 	case AST_FRAME_IAX:
 		/* Should never happen */
 		ast_copy_string(ftype, "IAX Specific", len);
+		break;
+	case AST_FRAME_BRIDGE_ACTION:
+		/* Should never happen */
+		ast_copy_string(ftype, "Bridge Specific", len);
 		break;
 	case AST_FRAME_TEXT:
 		ast_copy_string(ftype, "Text", len);




More information about the asterisk-commits mailing list