[asterisk-commits] rmudgett: branch rmudgett/bridge_phase r380691 - in /team/rmudgett/bridge_pha...

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


Author: rmudgett
Date: Thu Jan 31 13:40:09 2013
New Revision: 380691

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=380691
Log:
Multiple revisions 380676,380679

........
  r380676 | root | 2013-01-31 13:17:27 -0600 (Thu, 31 Jan 2013) | 45 lines
  
  Merged revisions 380666,380674 via svnmerge from 
  file:///srv/subversion/repos/asterisk/trunk
  
  ................
    r380666 | rmudgett | 2013-01-31 12:22:56 -0600 (Thu, 31 Jan 2013) | 11 lines
    
    bridge_multiplexed: Keep the multiplexed thread until no more bridges use it.
    
    * Fixed the potential of losing the multiplexed bridge thread when the
    last channel leaves and another joins while the multiplexed thread is
    being shut down.
    
    * Refactored and improved the management of the serviced channels array.
    
    * Changed the channels count to a bridges count so it only needs to be
    incremented rather than changed by two.
  ................
    r380674 | qwell | 2013-01-31 13:04:57 -0600 (Thu, 31 Jan 2013) | 25 lines
    
    Multiple revisions 380671-380673
    
    ........
      r380671 | qwell | 2013-01-31 12:59:28 -0600 (Thu, 31 Jan 2013) | 4 lines
      
      Remove a cross-compile workaround.
      
      ar and ranlib can be easily detected with autoconf.
    ........
      r380672 | qwell | 2013-01-31 13:00:38 -0600 (Thu, 31 Jan 2013) | 2 lines
      
      Always check for libm, regardless of configure options.
    ........
      r380673 | qwell | 2013-01-31 13:03:03 -0600 (Thu, 31 Jan 2013) | 7 lines
      
      Add support for parallel builds of pjproject.
      
      Also adds proper dependency checking, and direct .a file targets.  We don't
      take advantage of this currently, but we will soon.
      
    ........
    
    Merged revisions 380671-380673 from http://svn.asterisk.org/svn/asterisk/branches/11
  ................
........
  r380679 | rmudgett | 2013-01-31 13:18:41 -0600 (Thu, 31 Jan 2013) | 2 lines
  
  Add an action queue to bridge_channels.
........

Merged revisions 380676,380679 from http://svn.asterisk.org/svn/asterisk/team/group/bridge_construction

Modified:
    team/rmudgett/bridge_phase/   (props changed)
    team/rmudgett/bridge_phase/apps/app_confbridge.c
    team/rmudgett/bridge_phase/bridges/bridge_multiplexed.c
    team/rmudgett/bridge_phase/bridges/bridge_simple.c
    team/rmudgett/bridge_phase/bridges/bridge_softmix.c
    team/rmudgett/bridge_phase/funcs/func_frame_trace.c
    team/rmudgett/bridge_phase/include/asterisk/bridging.h
    team/rmudgett/bridge_phase/include/asterisk/bridging_features.h
    team/rmudgett/bridge_phase/include/asterisk/bridging_technology.h
    team/rmudgett/bridge_phase/include/asterisk/frame.h
    team/rmudgett/bridge_phase/main/bridging.c
    team/rmudgett/bridge_phase/main/channel.c
    team/rmudgett/bridge_phase/main/frame.c
    team/rmudgett/bridge_phase/res/pjproject/aconfigure
    team/rmudgett/bridge_phase/res/pjproject/aconfigure.ac
    team/rmudgett/bridge_phase/res/pjproject/build/cc-auto.mak.in
    team/rmudgett/bridge_phase/res/pjproject/build/rules.mak
    team/rmudgett/bridge_phase/res/pjproject/pjlib-util/build/Makefile
    team/rmudgett/bridge_phase/res/pjproject/pjlib/build/Makefile
    team/rmudgett/bridge_phase/res/pjproject/pjmedia/build/Makefile
    team/rmudgett/bridge_phase/res/pjproject/pjnath/build/Makefile
    team/rmudgett/bridge_phase/res/pjproject/pjsip-apps/build/Makefile
    team/rmudgett/bridge_phase/res/pjproject/pjsip/build/Makefile

Propchange: team/rmudgett/bridge_phase/
------------------------------------------------------------------------------
    automerge = *

Propchange: team/rmudgett/bridge_phase/
------------------------------------------------------------------------------
Binary property 'branch-11-merged' - no diff available.

Propchange: team/rmudgett/bridge_phase/
------------------------------------------------------------------------------
--- bridge_construction-integrated (original)
+++ bridge_construction-integrated Thu Jan 31 13:40:09 2013
@@ -1,1 +1,1 @@
-/trunk:1-380655
+/trunk:1-380675

Propchange: team/rmudgett/bridge_phase/
------------------------------------------------------------------------------
--- bridge_phase-integrated (original)
+++ bridge_phase-integrated Thu Jan 31 13:40:09 2013
@@ -1,1 +1,1 @@
-/team/group/bridge_construction:1-380667
+/team/group/bridge_construction:1-380690

Modified: team/rmudgett/bridge_phase/apps/app_confbridge.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/apps/app_confbridge.c?view=diff&rev=380691&r1=380690&r2=380691
==============================================================================
--- team/rmudgett/bridge_phase/apps/app_confbridge.c (original)
+++ team/rmudgett/bridge_phase/apps/app_confbridge.c Thu Jan 31 13:40:09 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/rmudgett/bridge_phase/bridges/bridge_multiplexed.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/bridges/bridge_multiplexed.c?view=diff&rev=380691&r1=380690&r2=380691
==============================================================================
--- team/rmudgett/bridge_phase/bridges/bridge_multiplexed.c (original)
+++ team/rmudgett/bridge_phase/bridges/bridge_multiplexed.c Thu Jan 31 13:40:09 2013
@@ -50,25 +50,24 @@
 /*! \brief Number of buckets our multiplexed thread container can have */
 #define MULTIPLEXED_BUCKETS 53
 
-/*! \brief Number of channels we handle in a single thread */
-#define MULTIPLEXED_MAX_CHANNELS 8
+/*! \brief Number of bridges we handle in a single thread */
+#define MULTIPLEXED_MAX_BRIDGES		4
 
 /*! \brief Structure which represents a single thread handling multiple 2 channel bridges */
 struct multiplexed_thread {
 	/*! Thread itself */
 	pthread_t thread;
+/* BUGBUG this is only large enough for the supported number of bridge channel pairs.  It is not large enough to handle transient channels being swapped. */
+	/*! Channels serviced by this thread */
+	struct ast_channel *chans[2 * MULTIPLEXED_MAX_BRIDGES];
 	/*! Pipe used to wake up the multiplexed thread */
 	int pipe[2];
-/* BUGBUG this is only large enough for the supported number of bridge channel pairs.  It is not large enough to handle transient channels being swapped. */
-	/*! Channels in this thread */
-	struct ast_channel *chans[MULTIPLEXED_MAX_CHANNELS];
-/* BUGBUG this should be changed to the number of 1-1 bridges muxed instead of the number of channels. */
-	/*! Number of channels in this thread */
-	unsigned int count;
-	/*! Bit used to indicate that the thread is waiting on channels */
-	unsigned int waiting:1;
 	/*! Number of channels actually being serviced by this thread */
 	unsigned int service_count;
+	/*! Number of bridges in this thread */
+	unsigned int bridges;
+	/*! TRUE if the thread is waiting on channels */
+	unsigned int waiting:1;
 };
 
 /*! \brief Container of all operating multiplexed threads */
@@ -78,7 +77,8 @@
 static int find_multiplexed_thread(void *obj, void *arg, int flags)
 {
 	struct multiplexed_thread *muxed_thread = obj;
-	return (muxed_thread->count <= (MULTIPLEXED_MAX_CHANNELS - 2)) ? CMP_MATCH | CMP_STOP : 0;
+
+	return (muxed_thread->bridges < MULTIPLEXED_MAX_BRIDGES) ? CMP_MATCH | CMP_STOP : 0;
 }
 
 /*! \brief Destroy callback for a multiplexed thread structure */
@@ -149,8 +149,8 @@
 		ast_debug(1, "Found multiplexed thread '%p' for bridge '%p'\n", muxed_thread, bridge);
 	}
 
-	/* Bump the count of the thread structure up by two since the channels for this bridge will be joining shortly */
-	muxed_thread->count += 2;
+	/* Increase the number of bridges using this multiplexed bridge */
+	++muxed_thread->bridges;
 
 	ao2_unlock(muxed_threads);
 
@@ -159,7 +159,17 @@
 	return 0;
 }
 
-/*! \brief Internal function which nudges the thread */
+/*!
+ * \internal
+ * \brief Nudges the multiplex thread.
+ * \since 12.0.0
+ *
+ * \param muxed_thread Controller to poke the thread.
+ *
+ * \note This function assumes the muxed_thread is locked.
+ *
+ * \return Nothing
+ */
 static void multiplexed_nudge(struct multiplexed_thread *muxed_thread)
 {
 	int nudge = 0;
@@ -181,28 +191,39 @@
 static int multiplexed_bridge_destroy(struct ast_bridge *bridge)
 {
 	struct multiplexed_thread *muxed_thread;
+	pthread_t thread;
 
 	muxed_thread = bridge->bridge_pvt;
 	if (!muxed_thread) {
 		return -1;
 	}
+	bridge->bridge_pvt = NULL;
 
 	ao2_lock(muxed_threads);
 
-	muxed_thread->count -= 2;
-
-	if (!muxed_thread->count) {
-		ast_debug(1, "Unlinking multiplexed thread '%p' since nobody is using it anymore\n", muxed_thread);
+	if (--muxed_thread->bridges) {
+		/* Other bridges are still using the multiplexed thread. */
+		ao2_unlock(muxed_threads);
+	} else {
+		ast_debug(1, "Unlinking multiplexed thread '%p' since nobody is using it anymore\n",
+			muxed_thread);
 		ao2_unlink(muxed_threads, muxed_thread);
-	}
-
-	multiplexed_nudge(muxed_thread);
-
-	ao2_unlock(muxed_threads);
+		ao2_unlock(muxed_threads);
+
+		/* Stop the multiplexed bridge thread. */
+		ao2_lock(muxed_thread);
+		multiplexed_nudge(muxed_thread);
+		thread = muxed_thread->thread;
+		muxed_thread->thread = AST_PTHREADT_STOP;
+		ao2_unlock(muxed_thread);
+
+		if (thread != AST_PTHREADT_NULL) {
+			/* Wait for multiplexed bridge thread to die. */
+			pthread_join(thread, NULL);
+		}
+	}
 
 	ao2_ref(muxed_thread, -1);
-	bridge->bridge_pvt = NULL;
-
 	return 0;
 }
 
@@ -212,20 +233,24 @@
 	struct multiplexed_thread *muxed_thread = data;
 	int fds = muxed_thread->pipe[0];
 
+	ast_debug(1, "Starting actual thread for multiplexed thread '%p'\n", muxed_thread);
+
 	ao2_lock(muxed_thread);
-
-	ast_debug(1, "Starting actual thread for multiplexed thread '%p'\n", muxed_thread);
 
 	while (muxed_thread->thread != AST_PTHREADT_STOP) {
 		struct ast_channel *winner;
-		struct ast_channel *first = muxed_thread->chans[0];
 		int to = -1;
 		int outfd = -1;
 
-		/* Move channels around so not just the first one gets priority */
-		memmove(muxed_thread->chans, muxed_thread->chans + 1,
-			sizeof(struct ast_channel *) * (muxed_thread->service_count - 1));
-		muxed_thread->chans[muxed_thread->service_count - 1] = first;
+		if (1 < muxed_thread->service_count) {
+			struct ast_channel *first;
+
+			/* Move channels around so not just the first one gets priority */
+			first = muxed_thread->chans[0];
+			memmove(muxed_thread->chans, muxed_thread->chans + 1,
+				sizeof(struct ast_channel *) * (muxed_thread->service_count - 1));
+			muxed_thread->chans[muxed_thread->service_count - 1] = first;
+		}
 
 		muxed_thread->waiting = 1;
 		ao2_unlock(muxed_thread);
@@ -265,70 +290,108 @@
 		}
 	}
 
-	muxed_thread->thread = AST_PTHREADT_NULL;
+	ao2_unlock(muxed_thread);
 
 	ast_debug(1, "Stopping actual thread for multiplexed thread '%p'\n", muxed_thread);
-
-	ao2_unlock(muxed_thread);
 	ao2_ref(muxed_thread, -1);
 
 	return NULL;
 }
 
-/*! \brief Helper function which adds or removes a channel and nudges the thread */
-static void multiplexed_add_or_remove(struct multiplexed_thread *muxed_thread, struct ast_channel *chan, int add)
-{
-	int idx;
-	pthread_t thread = AST_PTHREADT_NULL;
-
-	ao2_lock(muxed_thread);
-
-	multiplexed_nudge(muxed_thread);
-
-	for (idx = 0; idx < ARRAY_LEN(muxed_thread->chans); ++idx) {
-		if (muxed_thread->chans[idx] == chan) {
-			if (!add) {
-				memmove(muxed_thread->chans + idx,
-					muxed_thread->chans + idx + 1,
-					sizeof(struct ast_channel *) * (ARRAY_LEN(muxed_thread->chans) - (idx + 1)));
-				muxed_thread->chans[ARRAY_LEN(muxed_thread->chans) - 1] = NULL;
-				--muxed_thread->service_count;
-			}
-			break;
-		}
-		if (!muxed_thread->chans[idx]) {
-			if (add) {
-				muxed_thread->chans[idx] = chan;
-				++muxed_thread->service_count;
-			}
-			break;
-		}
-	}
-	if (ARRAY_LEN(muxed_thread->chans) == idx && add) {
-		ast_log(LOG_ERROR, "Could not add channel %s to multiplexed thread %p.  Array not large enough.\n",
-			ast_channel_name(chan), muxed_thread);
-		ast_assert(0);
-	}
-
+/*!
+ * \internal
+ * \brief Check to see if the multiplexed bridge thread needs to be started.
+ * \since 12.0.0
+ *
+ * \param muxed_thread Controller to check if need to start thread.
+ *
+ * \note This function assumes the muxed_thread is locked.
+ *
+ * \return Nothing
+ */
+static void multiplexed_thread_start(struct multiplexed_thread *muxed_thread)
+{
 	if (muxed_thread->service_count && muxed_thread->thread == AST_PTHREADT_NULL) {
 		ao2_ref(muxed_thread, +1);
 		if (ast_pthread_create(&muxed_thread->thread, NULL, multiplexed_thread_function, muxed_thread)) {
+			muxed_thread->thread = AST_PTHREADT_NULL;/* For paranoia's sake. */
 			ao2_ref(muxed_thread, -1);
-			ast_log(LOG_WARNING, "Failed to create the bridge thread for multiplexed thread '%p', trying next time\n",
+			ast_log(LOG_WARNING, "Failed to create the common thread for multiplexed thread '%p', trying next time\n",
 				muxed_thread);
 		}
-	} else if (!muxed_thread->service_count
-		&& muxed_thread->thread != AST_PTHREADT_NULL
-		&& muxed_thread->thread != AST_PTHREADT_STOP) {
-		thread = muxed_thread->thread;
-		muxed_thread->thread = AST_PTHREADT_STOP;
-	}
+	}
+}
+
+/*!
+ * \internal
+ * \brief Add a channel to the multiplexed bridge.
+ * \since 12.0.0
+ *
+ * \param muxed_thread Controller to add a channel.
+ * \param chan Channel to add to the channel service array.
+ *
+ * \return Nothing
+ */
+static void multiplexed_chan_add(struct multiplexed_thread *muxed_thread, struct ast_channel *chan)
+{
+	int idx;
+
+	ao2_lock(muxed_thread);
+
+	multiplexed_nudge(muxed_thread);
+
+	/* Check if already in the channel service array for safety. */
+	for (idx = 0; idx < muxed_thread->service_count; ++idx) {
+		if (muxed_thread->chans[idx] == chan) {
+			break;
+		}
+	}
+	if (idx == muxed_thread->service_count) {
+		/* Channel to add was not already in the array. */
+		if (muxed_thread->service_count < ARRAY_LEN(muxed_thread->chans)) {
+			muxed_thread->chans[muxed_thread->service_count++] = chan;
+		} else {
+			ast_log(LOG_ERROR, "Could not add channel %s to multiplexed thread %p.  Array not large enough.\n",
+				ast_channel_name(chan), muxed_thread);
+			ast_assert(0);
+		}
+	}
+
+	multiplexed_thread_start(muxed_thread);
 
 	ao2_unlock(muxed_thread);
-
-	if (thread != AST_PTHREADT_NULL) {
-		pthread_join(thread, NULL);
-	}
+}
+
+/*!
+ * \internal
+ * \brief Remove a channel from the multiplexed bridge.
+ * \since 12.0.0
+ *
+ * \param muxed_thread Controller to remove a channel.
+ * \param chan Channel to remove from the channel service array.
+ *
+ * \return Nothing
+ */
+static void multiplexed_chan_remove(struct multiplexed_thread *muxed_thread, struct ast_channel *chan)
+{
+	int idx;
+
+	ao2_lock(muxed_thread);
+
+	multiplexed_nudge(muxed_thread);
+
+	/* Remove channel from service array. */
+	for (idx = 0; idx < muxed_thread->service_count; ++idx) {
+		if (muxed_thread->chans[idx] != chan) {
+			continue;
+		}
+		muxed_thread->chans[idx] = muxed_thread->chans[--muxed_thread->service_count];
+		break;
+	}
+
+	multiplexed_thread_start(muxed_thread);
+
+	ao2_unlock(muxed_thread);
 }
 
 /*! \brief Join function which actually adds the channel into the array to be monitored */
@@ -340,7 +403,7 @@
 
 	ast_debug(1, "Adding channel '%s' to multiplexed thread '%p' for monitoring\n", ast_channel_name(bridge_channel->chan), muxed_thread);
 
-	multiplexed_add_or_remove(muxed_thread, bridge_channel->chan, 1);
+	multiplexed_chan_add(muxed_thread, bridge_channel->chan);
 
 	/* If the second channel has not yet joined do not make things compatible */
 	if (c0 == c1) {
@@ -363,7 +426,7 @@
 
 	ast_debug(1, "Removing channel '%s' from multiplexed thread '%p'\n", ast_channel_name(bridge_channel->chan), muxed_thread);
 
-	multiplexed_add_or_remove(muxed_thread, bridge_channel->chan, 0);
+	multiplexed_chan_remove(muxed_thread, bridge_channel->chan);
 
 	return 0;
 }
@@ -375,7 +438,7 @@
 
 	ast_debug(1, "Suspending channel '%s' from multiplexed thread '%p'\n", ast_channel_name(bridge_channel->chan), muxed_thread);
 
-	multiplexed_add_or_remove(muxed_thread, bridge_channel->chan, 0);
+	multiplexed_chan_remove(muxed_thread, bridge_channel->chan);
 }
 
 /*! \brief Unsuspend function which means control of the channel is coming back to us */
@@ -385,7 +448,7 @@
 
 	ast_debug(1, "Unsuspending channel '%s' from multiplexed thread '%p'\n", ast_channel_name(bridge_channel->chan), muxed_thread);
 
-	multiplexed_add_or_remove(muxed_thread, bridge_channel->chan, 1);
+	multiplexed_chan_add(muxed_thread, bridge_channel->chan);
 }
 
 /*! \brief Write function for writing frames into the bridge */
@@ -403,9 +466,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/rmudgett/bridge_phase/bridges/bridge_simple.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/bridges/bridge_simple.c?view=diff&rev=380691&r1=380690&r2=380691
==============================================================================
--- team/rmudgett/bridge_phase/bridges/bridge_simple.c (original)
+++ team/rmudgett/bridge_phase/bridges/bridge_simple.c Thu Jan 31 13:40:09 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/rmudgett/bridge_phase/bridges/bridge_softmix.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/bridges/bridge_softmix.c?view=diff&rev=380691&r1=380690&r2=380691
==============================================================================
--- team/rmudgett/bridge_phase/bridges/bridge_softmix.c (original)
+++ team/rmudgett/bridge_phase/bridges/bridge_softmix.c Thu Jan 31 13:40:09 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/rmudgett/bridge_phase/funcs/func_frame_trace.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/funcs/func_frame_trace.c?view=diff&rev=380691&r1=380690&r2=380691
==============================================================================
--- team/rmudgett/bridge_phase/funcs/func_frame_trace.c (original)
+++ team/rmudgett/bridge_phase/funcs/func_frame_trace.c Thu Jan 31 13:40:09 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/rmudgett/bridge_phase/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/include/asterisk/bridging.h?view=diff&rev=380691&r1=380690&r2=380691
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/bridging.h (original)
+++ team/rmudgett/bridge_phase/include/asterisk/bridging.h Thu Jan 31 13:40:09 2013
@@ -93,15 +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,
-/* BUGBUG the following states should be removed and replaced with bridge queued actions. */
-	/*! 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 */
@@ -162,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 {
@@ -558,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/rmudgett/bridge_phase/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/include/asterisk/bridging_features.h?view=diff&rev=380691&r1=380690&r2=380691
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/bridging_features.h (original)
+++ team/rmudgett/bridge_phase/include/asterisk/bridging_features.h Thu Jan 31 13:40:09 2013
@@ -108,13 +108,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/rmudgett/bridge_phase/include/asterisk/bridging_technology.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/include/asterisk/bridging_technology.h?view=diff&rev=380691&r1=380690&r2=380691
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/bridging_technology.h (original)
+++ team/rmudgett/bridge_phase/include/asterisk/bridging_technology.h Thu Jan 31 13:40:09 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/rmudgett/bridge_phase/include/asterisk/frame.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/include/asterisk/frame.h?view=diff&rev=380691&r1=380690&r2=380691
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/frame.h (original)
+++ team/rmudgett/bridge_phase/include/asterisk/frame.h Thu Jan 31 13:40:09 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/rmudgett/bridge_phase/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/main/bridging.c?view=diff&rev=380691&r1=380690&r2=380691
==============================================================================
--- team/rmudgett/bridge_phase/main/bridging.c (original)
+++ team/rmudgett/bridge_phase/main/bridging.c Thu Jan 31 13:40:09 2013
@@ -149,6 +149,30 @@
 	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;
+}
+
 /*!
  * \brief Helper function to poke the bridge thread
  *
@@ -222,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.
  */
@@ -308,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;
 	}
@@ -320,9 +350,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;
 		}
 	}
@@ -351,13 +386,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)
@@ -380,7 +417,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);
@@ -880,14 +921,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];
 			}
@@ -896,30 +941,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);
@@ -929,8 +975,6 @@
 	}
 	ao2_unlock(bridge_channel);
 	ao2_lock(bridge_channel->bridge);
-
-	return bridge_channel->state;
 }
 
 /*! \brief Internal function that suspends a channel from a bridge */
@@ -1032,7 +1076,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);
@@ -1042,32 +1086,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));
 
@@ -1101,7 +1209,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 */
@@ -1142,55 +1254,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);

[... 850 lines stripped ...]



More information about the asterisk-commits mailing list