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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Mar 25 16:24:08 CDT 2013


Author: rmudgett
Date: Mon Mar 25 16:23:58 2013
New Revision: 383786

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=383786
Log:
Bridge API enhancements: Implement threading model for bridge management thread.

High level overview of the bridging module objects.

Bridge-manager: This thread handles odd jobs for all bridges in the
system.  The manager has a service request queue that tells it to see what
needs doing to a bridge.

Bridge: The bridge object does not have a thread associated with it.  It
simply directs where a bridge channel thread should put frames written
into the bridge.  The bridge has an action queue for general bridge
servicing.  The only actions currently posted to the queue are deferred
destruction of the softmix bridge private structure.

Bridge-channel: The bridge channel component of a bridge has a thread
associated with it that services the reads and writes between the channel
and the bridge.  The thread also performs any actions to the channel such
as playing a file or running the connected line interception routines.

Bridge-technology: The bridge technology component of a bridge gives the
bridge its basic characteristics for how media passes through the bridge.
The current technologies implemented are holding (For parking calls),
simple two party, softmix (For multiparty like ConfBridge).

(closes issue ASTERISK-21052)
Reported by: Matt Jordan

Review: https://reviewboard.asterisk.org/r/2391/

Removed:
    team/group/bridge_construction/bridges/bridge_multiplexed.c
Modified:
    team/group/bridge_construction/bridges/bridge_holding.c
    team/group/bridge_construction/bridges/bridge_simple.c
    team/group/bridge_construction/bridges/bridge_softmix.c
    team/group/bridge_construction/include/asterisk/_private.h
    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/main/asterisk.c
    team/group/bridge_construction/main/bridging.c

Modified: team/group/bridge_construction/bridges/bridge_holding.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_holding.c?view=diff&rev=383786&r1=383785&r2=383786
==============================================================================
--- team/group/bridge_construction/bridges/bridge_holding.c (original)
+++ team/group/bridge_construction/bridges/bridge_holding.c Mon Mar 25 16:23:58 2013
@@ -71,7 +71,7 @@
 
 static void participant_stop_hold_audio(struct ast_bridge_channel *bridge_channel)
 {
-	struct holding_channel *hc = bridge_channel->bridge_pvt;
+	struct holding_channel *hc = bridge_channel->tech_pvt;
 	if (!hc) {
 		return;
 	}
@@ -101,7 +101,7 @@
 /* This should only be called on verified holding_participants. */
 static void participant_start_hold_audio(struct ast_bridge_channel *bridge_channel)
 {
-	struct holding_channel *hc = bridge_channel->bridge_pvt;
+	struct holding_channel *hc = bridge_channel->tech_pvt;
 	const char *moh_class;
 
 	if (!hc) {
@@ -124,7 +124,7 @@
 static void handle_participant_join(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *announcer_channel)
 {
 	struct ast_channel *us = bridge_channel->chan;
-	struct holding_channel *hc = bridge_channel->bridge_pvt;
+	struct holding_channel *hc = bridge_channel->tech_pvt;
 	const char *idle_mode = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "idle_mode");
 
 
@@ -165,22 +165,22 @@
 		return -1;
 	}
 
-	bridge_channel->bridge_pvt = hc;
+	bridge_channel->tech_pvt = hc;
 
 	/* The bridge pvt holds the announcer channel if we have one. */
-	announcer_channel = bridge->bridge_pvt;
+	announcer_channel = bridge->tech_pvt;
 
 	if (ast_bridge_channel_has_role(bridge_channel, "announcer")) {
 		/* If another announcer already exists, scrap the holding channel struct so we know to ignore it in the future */
 		if (announcer_channel) {
-			bridge_channel->bridge_pvt = NULL;
+			bridge_channel->tech_pvt = NULL;
 			ast_free(hc);
 			ast_log(LOG_WARNING, "A second announcer channel %s attempted to enter a holding bridge.\n",
 				ast_channel_name(announcer_channel->chan));
 			return -1;
 		}
 
-		bridge->bridge_pvt = bridge_channel;
+		bridge->tech_pvt = bridge_channel;
 		ast_set_flag(&hc->holding_roles, HOLDING_ROLE_ANNOUNCER);
 
 		/* The announcer should always be made compatible with signed linear */
@@ -208,7 +208,7 @@
 
 static void participant_reaction_announcer_leave(struct ast_bridge_channel *bridge_channel)
 {
-	struct holding_channel *hc = bridge_channel->bridge_pvt;
+	struct holding_channel *hc = bridge_channel->tech_pvt;
 
 	if (!hc) {
 		/* We are dealing with a channel that failed to join properly. Skip it. */
@@ -224,20 +224,20 @@
 static void holding_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
 {
 	struct ast_bridge_channel *other_channel;
-	struct holding_channel *hc = bridge_channel->bridge_pvt;
+	struct holding_channel *hc = bridge_channel->tech_pvt;
 
 	if (!hc) {
 		return;
 	}
 
 	if (!ast_test_flag(&hc->holding_roles, HOLDING_ROLE_ANNOUNCER)) {
-		/* It's not an announcer so nothing needs to react to its departure. Just free the bridge_pvt. */
-		if (!bridge->bridge_pvt) {
+		/* It's not an announcer so nothing needs to react to its departure. Just free the tech_pvt. */
+		if (!bridge->tech_pvt) {
 			/* Since no announcer is in the channel, we may be playing MOH/ringing. Stop that. */
 			participant_stop_hold_audio(bridge_channel);
 		}
 		ast_free(hc);
-		bridge_channel->bridge_pvt = NULL;
+		bridge_channel->tech_pvt = NULL;
 		return;
 	}
 
@@ -246,19 +246,19 @@
 		participant_reaction_announcer_leave(other_channel);
 	}
 
-	/* Since the announcer is leaving, we should clear the bridge_pvt pointing to it */
-	bridge->bridge_pvt = NULL;
+	/* Since the announcer is leaving, we should clear the tech_pvt pointing to it */
+	bridge->tech_pvt = NULL;
 
 	ast_free(hc);
-	bridge_channel->bridge_pvt = NULL;
+	bridge_channel->tech_pvt = NULL;
 }
 
 static int holding_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 {
 	struct ast_bridge_channel *other;
-	struct holding_channel *hc = bridge_channel->bridge_pvt;
-
-	/* If there is no bridge_pvt, then the channel failed to allocate one when it joined and is borked. Don't listen to him. */
+	struct holding_channel *hc = bridge_channel->tech_pvt;
+
+	/* If there is no tech_pvt, then the channel failed to allocate one when it joined and is borked. Don't listen to him. */
 	if (!hc) {
 		return -1;
 	}
@@ -270,15 +270,18 @@
 
 	/* Ok, so we are the announcer and there are one or more people available to receive our writes. Let's do it. */
 	AST_LIST_TRAVERSE(&bridge->channels, other, entry) {
-		struct hc *other_hc = other->bridge_pvt;
-		/* Skip writes on channels without the bridge pvt struct. */
-		if (!other_hc) {
+		if (!other->tech_pvt) {
 			continue;
 		}
-
-		if ((bridge_channel != other) && (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT)) {
-			if (!other->suspended) {
-				ast_write(other->chan, frame);
+		if (bridge_channel == other) {
+			continue;
+		}
+
+		if (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+/* BUGBUG need to handle control frames in a bridge tech specific way here.  Mostly just queue action to bridge channel. */
+			if (!other->suspended
+				|| ast_is_deferrable_frame(frame)) {
+				ast_bridge_channel_queue_frame(other, frame);
 			}
 		}
 	}
@@ -292,7 +295,6 @@
 	.preference = AST_BRIDGE_PREFERENCE_MEDIUM,
 	.write = holding_bridge_write,
 	.join = holding_bridge_join,
-	.thread_loop = ast_bridge_thread_generic,
 	.leave = holding_bridge_leave,
 };
 

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=383786&r1=383785&r2=383786
==============================================================================
--- team/group/bridge_construction/bridges/bridge_simple.c (original)
+++ team/group/bridge_construction/bridges/bridge_simple.c Mon Mar 25 16:23:58 2013
@@ -84,8 +84,9 @@
 	/* The bridging core takes care of freeing the passed in frame. */
 	if (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
 /* BUGBUG need to handle control frames in a bridge tech specific way here.  Mostly just queue action to bridge channel. */
-		if (!other->suspended) {
-			ast_write(other->chan, frame);
+		if (!other->suspended
+			|| ast_is_deferrable_frame(frame)) {
+			ast_bridge_channel_queue_frame(other, frame);
 		}
 	}
 
@@ -97,7 +98,6 @@
 	.capabilities = AST_BRIDGE_CAPABILITY_1TO1MIX,
 	.preference = AST_BRIDGE_PREFERENCE_MEDIUM,
 	.join = simple_bridge_join,
-	.thread_loop = ast_bridge_thread_generic,
 	.write = simple_bridge_write,
 };
 

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=383786&r1=383785&r2=383786
==============================================================================
--- team/group/bridge_construction/bridges/bridge_softmix.c (original)
+++ team/group/bridge_construction/bridges/bridge_softmix.c Mon Mar 25 16:23:58 2013
@@ -100,13 +100,15 @@
 	struct ast_frame read_frame;
 	/*! DSP for detecting silence */
 	struct ast_dsp *dsp;
-	/*! Bit used to indicate if a channel is talking or not. This affects how
-	 * the channel's audio is mixed back to it. */
-	int talking:1;
-	/*! Bit used to indicate that the channel provided audio for this mixing interval */
-	int have_audio:1;
-	/*! Bit used to indicate that a frame is available to be written out to the channel */
-	int have_frame:1;
+	/*!
+	 * \brief TRUE if a channel is talking.
+	 *
+	 * \note This affects how the channel's audio is mixed back to
+	 * it.
+	 */
+	unsigned int talking:1;
+	/*! TRUE if the channel provided audio for this mixing interval */
+	unsigned int have_audio:1;
 	/*! Buffer containing final mixed audio from all sources */
 	short final_buf[MAX_DATALEN];
 	/*! Buffer containing only the audio from the channel */
@@ -117,28 +119,36 @@
 
 struct softmix_bridge_data {
 	struct ast_timer *timer;
+	/*! Lock for signaling the mixing thread. */
+	ast_mutex_t lock;
+	/*! Condition, used if we need to wake up the mixing thread. */
+	ast_cond_t cond;
+	/*! Thread handling the mixing */
+	pthread_t thread;
 	unsigned int internal_rate;
 	unsigned int internal_mixing_interval;
+	/*! TRUE if the mixing thread should stop */
+	unsigned int stop:1;
 };
 
 struct softmix_stats {
-		/*! Each index represents a sample rate used above the internal rate. */
-		unsigned int sample_rates[16];
-		/*! Each index represents the number of channels using the same index in the sample_rates array.  */
-		unsigned int num_channels[16];
-		/*! the number of channels above the internal sample rate */
-		unsigned int num_above_internal_rate;
-		/*! the number of channels at the internal sample rate */
-		unsigned int num_at_internal_rate;
-		/*! the absolute highest sample rate supported by any channel in the bridge */
-		unsigned int highest_supported_rate;
-		/*! Is the sample rate locked by the bridge, if so what is that rate.*/
-		unsigned int locked_rate;
+	/*! Each index represents a sample rate used above the internal rate. */
+	unsigned int sample_rates[16];
+	/*! Each index represents the number of channels using the same index in the sample_rates array.  */
+	unsigned int num_channels[16];
+	/*! the number of channels above the internal sample rate */
+	unsigned int num_above_internal_rate;
+	/*! the number of channels at the internal sample rate */
+	unsigned int num_at_internal_rate;
+	/*! the absolute highest sample rate supported by any channel in the bridge */
+	unsigned int highest_supported_rate;
+	/*! Is the sample rate locked by the bridge, if so what is that rate.*/
+	unsigned int locked_rate;
 };
 
 struct softmix_mixing_array {
-	int max_num_entries;
-	int used_entries;
+	unsigned int max_num_entries;
+	unsigned int used_entries;
 	int16_t **buffers;
 };
 
@@ -213,7 +223,7 @@
 /*!
  * \internal
  * \brief Get the next available audio on the softmix channel's read stream
- * and determine if it should be mixed out or not on the write stream. 
+ * and determine if it should be mixed out or not on the write stream.
  *
  * \retval pointer to buffer containing the exact number of samples requested on success.
  * \retval NULL if no samples are present
@@ -295,53 +305,9 @@
 	}
 }
 
-static void softmix_bridge_data_destroy(void *obj)
-{
-	struct softmix_bridge_data *softmix_data = obj;
-
-	if (softmix_data->timer) {
-		ast_timer_close(softmix_data->timer);
-		softmix_data->timer = NULL;
-	}
-}
-
-/*! \brief Function called when a bridge is created */
-static int softmix_bridge_create(struct ast_bridge *bridge)
-{
-	struct softmix_bridge_data *softmix_data;
-
-	if (!(softmix_data = ao2_alloc(sizeof(*softmix_data), softmix_bridge_data_destroy))) {
-		return -1;
-	}
-	if (!(softmix_data->timer = ast_timer_open())) {
-		ao2_ref(softmix_data, -1);
-		return -1;
-	}
-
-	/* start at 8khz, let it grow from there */
-	softmix_data->internal_rate = 8000;
-	softmix_data->internal_mixing_interval = DEFAULT_SOFTMIX_INTERVAL;
-
-	bridge->bridge_pvt = softmix_data;
-	return 0;
-}
-
-/*! \brief Function called when a bridge is destroyed */
-static void softmix_bridge_destroy(struct ast_bridge *bridge)
-{
-	struct softmix_bridge_data *softmix_data;
-
-	softmix_data = bridge->bridge_pvt;
-	if (!softmix_data) {
-		return;
-	}
-	ao2_ref(softmix_data, -1);
-	bridge->bridge_pvt = NULL;
-}
-
 static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_channel *bridge_channel, int reset)
 {
-	struct softmix_channel *sc = bridge_channel->bridge_pvt;
+	struct softmix_channel *sc = bridge_channel->tech_pvt;
 	unsigned int channel_read_rate = ast_format_rate(ast_channel_rawreadformat(bridge_channel->chan));
 
 	ast_mutex_lock(&sc->lock);
@@ -381,11 +347,33 @@
 	ast_mutex_unlock(&sc->lock);
 }
 
+/*!
+ * \internal
+ * \brief Poke the mixing thread in case it is waiting for an active channel.
+ * \since 12.0.0
+ *
+ * \param softmix_data Bridge mixing data.
+ *
+ * \return Nothing
+ */
+static void softmix_poke_thread(struct softmix_bridge_data *softmix_data)
+{
+	ast_mutex_lock(&softmix_data->lock);
+	ast_cond_signal(&softmix_data->cond);
+	ast_mutex_unlock(&softmix_data->lock);
+}
+
+/*! \brief Function called when a channel is unsuspended from the bridge */
+static void softmix_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+	softmix_poke_thread(bridge->tech_pvt);
+}
+
 /*! \brief Function called when a channel is joined into the bridge */
 static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
 {
 	struct softmix_channel *sc;
-	struct softmix_bridge_data *softmix_data = bridge->bridge_pvt;
+	struct softmix_bridge_data *softmix_data = bridge->tech_pvt;
 
 	/* Create a new softmix_channel structure and allocate various things on it */
 	if (!(sc = ast_calloc(1, sizeof(*sc)))) {
@@ -396,24 +384,27 @@
 	ast_mutex_init(&sc->lock);
 
 	/* Can't forget to record our pvt structure within the bridged channel structure */
-	bridge_channel->bridge_pvt = sc;
+	bridge_channel->tech_pvt = sc;
 
 	set_softmix_bridge_data(softmix_data->internal_rate,
-		softmix_data->internal_mixing_interval ? softmix_data->internal_mixing_interval : DEFAULT_SOFTMIX_INTERVAL,
+		softmix_data->internal_mixing_interval
+			? softmix_data->internal_mixing_interval
+			: DEFAULT_SOFTMIX_INTERVAL,
 		bridge_channel, 0);
 
+	softmix_poke_thread(softmix_data);
 	return 0;
 }
 
 /*! \brief Function called when a channel leaves the bridge */
 static void softmix_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
 {
-	struct softmix_channel *sc = bridge_channel->bridge_pvt;
-
-	if (!(bridge_channel->bridge_pvt)) {
+	struct softmix_channel *sc = bridge_channel->tech_pvt;
+
+	if (!sc) {
 		return;
 	}
-	bridge_channel->bridge_pvt = NULL;
+	bridge_channel->tech_pvt = NULL;
 
 	/* Drop mutex lock */
 	ast_mutex_destroy(&sc->lock);
@@ -434,24 +425,29 @@
  */
 static void softmix_pass_dtmf(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 {
-	struct ast_bridge_channel *tmp;
-	AST_LIST_TRAVERSE(&bridge->channels, tmp, entry) {
-		if (tmp == bridge_channel) {
+	struct ast_bridge_channel *cur;
+
+	AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
+		if (cur->suspended) {
 			continue;
 		}
-		ast_write(tmp->chan, frame);
+		if (cur == bridge_channel) {
+			continue;
+		}
+		ast_bridge_channel_queue_frame(cur, frame);
 	}
 }
 
 static void softmix_pass_video_top_priority(struct ast_bridge *bridge, struct ast_frame *frame)
 {
-	struct ast_bridge_channel *tmp;
-	AST_LIST_TRAVERSE(&bridge->channels, tmp, entry) {
-		if (tmp->suspended) {
+	struct ast_bridge_channel *cur;
+
+	AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
+		if (cur->suspended) {
 			continue;
 		}
-		if (ast_bridge_is_video_src(bridge, tmp->chan) == 1) {
-			ast_write(tmp->chan, frame);
+		if (ast_bridge_is_video_src(bridge, cur->chan) == 1) {
+			ast_bridge_channel_queue_frame(cur, frame);
 			break;
 		}
 	}
@@ -459,23 +455,24 @@
 
 static void softmix_pass_video_all(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame, int echo)
 {
-	struct ast_bridge_channel *tmp;
-	AST_LIST_TRAVERSE(&bridge->channels, tmp, entry) {
-		if (tmp->suspended) {
+	struct ast_bridge_channel *cur;
+
+	AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
+		if (cur->suspended) {
 			continue;
 		}
-		if ((tmp->chan == bridge_channel->chan) && !echo) {
+		if (cur == bridge_channel && !echo) {
 			continue;
 		}
-		ast_write(tmp->chan, frame);
+		ast_bridge_channel_queue_frame(cur, frame);
 	}
 }
 
 /*! \brief Function called when a channel writes a frame into the bridge */
 static int softmix_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 {
-	struct softmix_channel *sc = bridge_channel->bridge_pvt;
-	struct softmix_bridge_data *softmix_data = bridge->bridge_pvt;
+	struct softmix_channel *sc = bridge_channel->tech_pvt;
+	struct softmix_bridge_data *softmix_data = bridge->tech_pvt;
 	int totalsilence = 0;
 	int cur_energy = 0;
 	int silence_threshold = bridge_channel->tech_args.silence_threshold ?
@@ -487,13 +484,13 @@
 	/* Only accept audio frames, all others are unsupported */
 	if (frame->frametype == AST_FRAME_DTMF_END || frame->frametype == AST_FRAME_DTMF_BEGIN) {
 		softmix_pass_dtmf(bridge, bridge_channel, frame);
-		goto bridge_write_cleanup;
+		return res;
 	} else if (frame->frametype != AST_FRAME_VOICE && frame->frametype != AST_FRAME_VIDEO) {
 		/* Frame type unsupported. */
 		res = -1;
-		goto bridge_write_cleanup;
+		return res;
 	} else if (frame->datalen == 0) {
-		goto bridge_write_cleanup;
+		return res;
 	}
 
 	/* Determine if this video frame should be distributed or not */
@@ -521,7 +518,7 @@
 			}
 			break;
 		}
-		goto bridge_write_cleanup;
+		return res;
 	}
 
 	/* If we made it here, we are going to write the frame into the conference */
@@ -530,6 +527,7 @@
 
 	if (bridge->video_mode.mode == AST_BRIDGE_VIDEO_MODE_TALKER_SRC) {
 		int cur_slot = sc->video_talker.energy_history_cur_slot;
+
 		sc->video_talker.energy_accum -= sc->video_talker.energy_history[cur_slot];
 		sc->video_talker.energy_accum += cur_energy;
 		sc->video_talker.energy_history[cur_slot] = cur_energy;
@@ -566,12 +564,6 @@
 		ast_slinfactory_feed(&sc->factory, frame);
 	}
 
-	/* If a frame is ready to be written out, do so */
-	if (sc->have_frame) {
-		ast_write(bridge_channel->chan, &sc->write_frame);
-		sc->have_frame = 0;
-	}
-
 	/* Alllll done */
 	ast_mutex_unlock(&sc->lock);
 
@@ -580,34 +572,6 @@
 	}
 
 	return res;
-
-bridge_write_cleanup:
-	/* Even though the frame is not being written into the conference because it is not audio,
-	 * we should use this opportunity to check to see if a frame is ready to be written out from
-	 * the conference to the channel. */
-	ast_mutex_lock(&sc->lock);
-	if (sc->have_frame) {
-		ast_write(bridge_channel->chan, &sc->write_frame);
-		sc->have_frame = 0;
-	}
-	ast_mutex_unlock(&sc->lock);
-
-	return res;
-}
-
-/*! \brief Function called when the channel's thread is poked */
-static void softmix_bridge_poke_channel(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
-	struct softmix_channel *sc = bridge_channel->bridge_pvt;
-
-	ast_mutex_lock(&sc->lock);
-
-	if (sc->have_frame) {
-		ast_write(bridge_channel->chan, &sc->write_frame);
-		sc->have_frame = 0;
-	}
-
-	ast_mutex_unlock(&sc->lock);
 }
 
 static void gather_softmix_stats(struct softmix_stats *stats,
@@ -644,7 +608,7 @@
  * \brief Analyse mixing statistics and change bridges internal rate
  * if necessary.
  *
- * \retval 0, no changes to internal rate 
+ * \retval 0, no changes to internal rate
  * \ratval 1, internal rate was changed, update all the channels on the next mixing iteration.
  */
 static unsigned int analyse_softmix_stats(struct softmix_stats *stats, struct softmix_bridge_data *softmix_data)
@@ -744,27 +708,27 @@
 	return 0;
 }
 
-/*! \brief Function which acts as the mixing thread */
-static int softmix_bridge_thread(struct ast_bridge *bridge)
+/*!
+ * \brief Mixing loop.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+static int softmix_mixing_loop(struct ast_bridge *bridge)
 {
 	struct softmix_stats stats = { { 0 }, };
 	struct softmix_mixing_array mixing_array;
-	struct softmix_bridge_data *softmix_data;
+	struct softmix_bridge_data *softmix_data = bridge->tech_pvt;
 	struct ast_timer *timer;
 	struct softmix_translate_helper trans_helper;
 	int16_t buf[MAX_DATALEN];
 	unsigned int stat_iteration_counter = 0; /* counts down, gather stats at zero and reset. */
 	int timingfd;
 	int update_all_rates = 0; /* set this when the internal sample rate has changed */
-	int i, x;
+	unsigned int idx;
+	unsigned int x;
 	int res = -1;
 
-	softmix_data = bridge->bridge_pvt;
-	if (!softmix_data) {
-		goto softmix_cleanup;
-	}
-
-	ao2_ref(softmix_data, 1);
 	timer = softmix_data->timer;
 	timingfd = ast_timer_fd(timer);
 	softmix_translate_helper_init(&trans_helper, softmix_data->internal_rate);
@@ -775,7 +739,7 @@
 		goto softmix_cleanup;
 	}
 
-	while (!bridge->interrupt && bridge->array_num) {
+	while (!softmix_data->stop && bridge->num_active) {
 		struct ast_bridge_channel *bridge_channel;
 		int timeout = -1;
 		enum ast_format_id cur_slin_id = ast_format_slin_by_rate(softmix_data->internal_rate);
@@ -814,7 +778,7 @@
 
 		/* Go through pulling audio from each factory that has it available */
 		AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-			struct softmix_channel *sc = bridge_channel->bridge_pvt;
+			struct softmix_channel *sc = bridge_channel->tech_pvt;
 
 			/* Update the sample rate to match the bridge's native sample rate if necessary. */
 			if (update_all_rates) {
@@ -841,15 +805,15 @@
 
 		/* mix it like crazy */
 		memset(buf, 0, softmix_datalen);
-		for (i = 0; i < mixing_array.used_entries; i++) {
-			for (x = 0; x < softmix_samples; x++) {
-				ast_slinear_saturated_add(buf + x, mixing_array.buffers[i] + x);
+		for (idx = 0; idx < mixing_array.used_entries; ++idx) {
+			for (x = 0; x < softmix_samples; ++x) {
+				ast_slinear_saturated_add(buf + x, mixing_array.buffers[idx] + x);
 			}
 		}
 
 		/* Next step go through removing the channel's own audio and creating a good frame... */
 		AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-			struct softmix_channel *sc = bridge_channel->bridge_pvt;
+			struct softmix_channel *sc = bridge_channel->tech_pvt;
 
 			if (bridge_channel->suspended) {
 				continue;
@@ -868,13 +832,10 @@
 			/* process the softmix channel's new write audio */
 			softmix_process_write_audio(&trans_helper, ast_channel_rawwriteformat(bridge_channel->chan), sc);
 
-			/* The frame is now ready for use... */
-			sc->have_frame = 1;
-
 			ast_mutex_unlock(&sc->lock);
 
-			/* Poke bridged channel thread just in case */
-			pthread_kill(bridge_channel->thread, SIGURG);
+			/* A frame is now ready for the channel. */
+			ast_bridge_channel_queue_frame(bridge_channel, &sc->write_frame);
 		}
 
 		update_all_rates = 0;
@@ -909,23 +870,140 @@
 softmix_cleanup:
 	softmix_translate_helper_destroy(&trans_helper);
 	softmix_mixing_array_destroy(&mixing_array);
-	if (softmix_data) {
-		ao2_ref(softmix_data, -1);
-	}
 	return res;
+}
+
+/*!
+ * \internal
+ * \brief Mixing thread.
+ * \since 12.0.0
+ *
+ * \note The thread does not have its own reference to the
+ * bridge.  The lifetime of the thread is tied to the lifetime
+ * of the mixing technology association with the bridge.
+ */
+static void *softmix_mixing_thread(void *data)
+{
+	struct ast_bridge *bridge = data;
+	struct softmix_bridge_data *softmix_data;
+
+	ao2_lock(bridge);
+	if (bridge->callid) {
+		ast_callid_threadassoc_add(bridge->callid);
+	}
+
+	ast_debug(1, "Starting mixing thread for bridge %p\n", bridge);
+
+	softmix_data = bridge->tech_pvt;
+	while (!softmix_data->stop) {
+		if (!bridge->num_active) {
+			/* Wait for something to happen to the bridge. */
+			ao2_unlock(bridge);
+			ast_mutex_lock(&softmix_data->lock);
+			if (!softmix_data->stop) {
+				ast_cond_wait(&softmix_data->cond, &softmix_data->lock);
+			}
+			ast_mutex_unlock(&softmix_data->lock);
+			ao2_lock(bridge);
+			continue;
+		}
+
+		if (softmix_mixing_loop(bridge)) {
+			/*
+			 * A mixing error occurred.  Sleep and try again later so we
+			 * won't flood the logs.
+			 */
+			ao2_unlock(bridge);
+			sleep(1);
+			ao2_lock(bridge);
+		}
+	}
+
+	ao2_unlock(bridge);
+
+	ast_debug(1, "Stopping mixing thread for bridge %p\n", bridge);
+
+	return NULL;
+}
+
+static void softmix_bridge_data_destroy(struct softmix_bridge_data *softmix_data)
+{
+	if (softmix_data->timer) {
+		ast_timer_close(softmix_data->timer);
+		softmix_data->timer = NULL;
+	}
+	ast_mutex_destroy(&softmix_data->lock);
+	ast_free(softmix_data);
+}
+
+/*! \brief Function called when a bridge is created */
+static int softmix_bridge_create(struct ast_bridge *bridge)
+{
+	struct softmix_bridge_data *softmix_data;
+
+	softmix_data = ast_calloc(1, sizeof(*softmix_data));
+	if (!softmix_data) {
+		return -1;
+	}
+	ast_mutex_init(&softmix_data->lock);
+	softmix_data->timer = ast_timer_open();
+	if (!softmix_data->timer) {
+		softmix_bridge_data_destroy(softmix_data);
+		return -1;
+	}
+	/* start at 8khz, let it grow from there */
+	softmix_data->internal_rate = 8000;
+	softmix_data->internal_mixing_interval = DEFAULT_SOFTMIX_INTERVAL;
+
+	bridge->tech_pvt = softmix_data;
+
+	/* Start the mixing thread. */
+	if (ast_pthread_create(&softmix_data->thread, NULL, softmix_mixing_thread, bridge)) {
+		softmix_data->thread = AST_PTHREADT_NULL;
+		softmix_bridge_data_destroy(softmix_data);
+		bridge->tech_pvt = NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
+/*! \brief Function called when a bridge is destroyed */
+static void softmix_bridge_destroy(struct ast_bridge *bridge)
+{
+	struct softmix_bridge_data *softmix_data;
+	pthread_t thread;
+
+	softmix_data = bridge->tech_pvt;
+	if (!softmix_data) {
+		return;
+	}
+
+	/* Stop the mixing thread. */
+	ast_mutex_lock(&softmix_data->lock);
+	softmix_data->stop = 1;
+	ast_cond_signal(&softmix_data->cond);
+	thread = softmix_data->thread;
+	softmix_data->thread = AST_PTHREADT_NULL;
+	ast_mutex_unlock(&softmix_data->lock);
+	if (thread != AST_PTHREADT_NULL) {
+		pthread_join(thread, NULL);
+	}
+
+	softmix_bridge_data_destroy(softmix_data);
+	bridge->tech_pvt = NULL;
 }
 
 static struct ast_bridge_technology softmix_bridge = {
 	.name = "softmix",
-	.capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX | AST_BRIDGE_CAPABILITY_MULTITHREADED | AST_BRIDGE_CAPABILITY_OPTIMIZE | AST_BRIDGE_CAPABILITY_VIDEO,
+	.capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX,
 	.preference = AST_BRIDGE_PREFERENCE_LOW,
 	.create = softmix_bridge_create,
 	.destroy = softmix_bridge_destroy,
 	.join = softmix_bridge_join,
 	.leave = softmix_bridge_leave,
+	.unsuspend = softmix_bridge_unsuspend,
 	.write = softmix_bridge_write,
-	.thread_loop = softmix_bridge_thread,
-	.poke_channel = softmix_bridge_poke_channel,
 };
 
 static int unload_module(void)

Modified: team/group/bridge_construction/include/asterisk/_private.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/_private.h?view=diff&rev=383786&r1=383785&r2=383786
==============================================================================
--- team/group/bridge_construction/include/asterisk/_private.h (original)
+++ team/group/bridge_construction/include/asterisk/_private.h Mon Mar 25 16:23:58 2013
@@ -50,6 +50,15 @@
 int ast_msg_init(void);             /*!< Provided by message.c */
 void ast_msg_shutdown(void);        /*!< Provided by message.c */
 int aco_init(void);             /*!< Provided by config_options.c */
+
+/*!
+ * \brief Initialize the bridging system.
+ * \since 12.0.0
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int ast_bridging_init(void);
 
 /*!
  * \brief Reload asterisk modules.

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=383786&r1=383785&r2=383786
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging.h Mon Mar 25 16:23:58 2013
@@ -1,8 +1,9 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2007 - 2009, Digium, Inc.
- *
+ * Copyright (C) 2007 - 2009, 2013 Digium, Inc.
+ *
+ * Richard Mudgett <rmudgett at digium.com>
  * Joshua Colp <jcolp at digium.com>
  *
  * See http://www.asterisk.org for more information about
@@ -16,10 +17,16 @@
  * at the top of the source tree.
  */
 
-/*! \file
+/*!
+ * \file
  * \brief Channel Bridging API
+ *
+ * \author Richard Mudgett <rmudgett at digium.com>
  * \author Joshua Colp <jcolp at digium.com>
  * \ref AstBridging
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
  */
 
 /*!
@@ -76,12 +83,6 @@
 	AST_BRIDGE_CAPABILITY_1TO1MIX = (1 << 2),
 	/*! Bridge is capable of mixing 2 or more channels */
 	AST_BRIDGE_CAPABILITY_MULTIMIX = (1 << 3),
-	/*! Bridge should run using the multithreaded model */
-	AST_BRIDGE_CAPABILITY_MULTITHREADED = (1 << 4),
-	/*! Bridge technology can do video mixing (or something along those lines) */
-	AST_BRIDGE_CAPABILITY_VIDEO = (1 << 6),
-	/*! Bridge technology can optimize things based on who is talking */
-	AST_BRIDGE_CAPABILITY_OPTIMIZE = (1 << 7),
 };
 
 /*! \brief State information about a bridged channel */
@@ -128,11 +129,9 @@
 	/*! Bridge this channel is participating in */
 	struct ast_bridge *bridge;
 	/*! Private information unique to the bridge technology */
-	void *bridge_pvt;
-	/*! Thread handling the bridged channel */
+	void *tech_pvt;
+	/*! Thread handling the bridged channel (Needed by ast_bridge_depart) */
 	pthread_t thread;
-	/*! TRUE if the channel has been poked. */
-	unsigned int poked;
 	/*! TRUE if the channel is in a bridge. */
 	unsigned int in_bridge:1;
 	/*! TRUE if the channel just joined the bridge. */
@@ -156,8 +155,10 @@
 	struct bridge_roles_datastore *bridge_roles;
 	/*! 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;
+	/*! Queue of outgoing frames to the channel. */
+	AST_LIST_HEAD_NOLOCK(, ast_frame) wr_queue;
+	/*! Pipe to alert thread when frames are put into the wr_queue. */
+	int alert_pipe[2];
 };
 
 enum ast_bridge_action_type {
@@ -171,6 +172,8 @@
 	AST_BRIDGE_ACTION_TALKING_START,
 	/*! Bridged channel is to indicate talking stop */
 	AST_BRIDGE_ACTION_TALKING_STOP,
+	/*! Bridge reconfiguration deferred technology destruction. */
+	AST_BRIDGE_ACTION_DEFERRED_TECH_DESTROY,
 };
 
 enum ast_bridge_video_mode_type {
@@ -214,10 +217,10 @@
  * \brief Structure that contains information about a bridge
  */
 struct ast_bridge {
-	/*! Condition, used if we want to wake up the bridge thread. */
-	ast_cond_t cond;
 	/*! Number of channels participating in the bridge */
-	int num_channels;
+	unsigned int num_channels;
+	/*! Number of active channels in the bridge. */
+	unsigned int num_active;
 	/*! The video mode this bridge is using */
 	struct ast_bridge_video_mode video_mode;
 	/*!
@@ -234,14 +237,8 @@
 	 * for bridge technologies that mix audio. When set to 0, the bridge tech must choose a
 	 * default interval for itself. */
 	unsigned int internal_mixing_interval;
-	/*! TRUE if the bridge thread is waiting on channels in the bridge array */
-	unsigned int waiting:1;
-	/*! TRUE if the bridge thread should stop */
-	unsigned int stop:1;
 	/*! TRUE if the bridge was reconfigured. */
 	unsigned int reconfigured:1;
-	/*! TRUE if the bridge thread loop should break.  Reconfig, stop, action-queue. */
-	unsigned int interrupt:1;
 	/*! TRUE if the bridge has been dissolved.  Any channel that now tries to join is immediately ejected. */
 	unsigned int dissolved:1;
 	/*! Bridge flags to tweak behavior */
@@ -249,17 +246,7 @@
 	/*! Bridge technology that is handling the bridge */
 	struct ast_bridge_technology *technology;
 	/*! Private information unique to the bridge technology */
-	void *bridge_pvt;
-	/*! Thread running the bridge */
-	pthread_t thread;
-	/*! Enabled features information */
-	struct ast_bridge_features features;
-	/*! Array of channels that the bridge thread is currently handling */
-	struct ast_channel **array;
-	/*! Number of channels in the above array (Number of active channels) */
-	unsigned int array_num;
-	/*! Number of channels the array can handle */
-	unsigned int array_size;
+	void *tech_pvt;
 	/*! Call ID associated with the bridge */
 	struct ast_callid *callid;
 	/*! Linked list of channels participating in the bridge */
@@ -622,11 +609,11 @@
 int ast_bridge_queue_action(struct ast_bridge *bridge, struct ast_frame *action);
 
 /*!
- * \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.
+ * \brief Write a frame to the specified bridge_channel.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Channel to queue the frame.
+ * \param fr Frame to write.
  *
  * \retval 0 on success.
  * \retval -1 on error.
@@ -634,7 +621,7 @@
  * \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);
+int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *fr);
 
 /*!
  * \brief Restore the formats of a bridge channel's channel to how they were before bridge_channel_join
@@ -800,4 +787,4 @@
 }
 #endif
 
-#endif /* _ASTERISK_BRIDGING_H */
+#endif	/* _ASTERISK_BRIDGING_H */

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=383786&r1=383785&r2=383786
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging_features.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging_features.h Mon Mar 25 16:23:58 2013
@@ -156,9 +156,8 @@
 	unsigned int seqno;
 };
 
-/*!
- * \brief Structure that is the essence of a feature hook.
- */
+/* BUGBUG ast_bridge_hook needs to be turned into ao2 objects so bridge push/pulls can add/remove hooks */
+/*! \brief Structure that is the essence of a feature hook. */
 struct ast_bridge_hook {
 	/*! Linked list information */
 	AST_LIST_ENTRY(ast_bridge_hook) entry;
@@ -183,10 +182,13 @@
  * \brief Structure that contains features information
  */
 struct ast_bridge_features {
+/* BUGBUG dtmf_hooks needs to be an ao2_container so it would be possible to iterate without keeping a lock */
 	/*! Attached DTMF feature hooks */
 	AST_LIST_HEAD_NOLOCK(, ast_bridge_hook) dtmf_hooks;
+/* BUGBUG hangup_hooks needs to be an ao2_container so it would be possible to iterate without keeping a lock */
 	/*! Attached hangup interception hooks */
 	AST_LIST_HEAD_NOLOCK(, ast_bridge_hook) hangup_hooks;
+/* BUGBUG use of interval_hooks needs to be made ao2 safe */
 	/*! Attached interval hooks */
 	struct ast_heap *interval_hooks;
 	/*! Used to determine when interval based features should be checked */
@@ -203,12 +205,11 @@
 	struct ast_flags feature_flags;
 	/*! Used to assign the sequence number to the next interval hook added. */
 	unsigned int interval_sequence;
-	/*! Bit to indicate that the feature_flags and hook list is setup */
+	/*! TRUE if feature_flags is setup */
 	unsigned int usable:1;
-	/*! Bit to indicate whether the channel/bridge is muted or not */
+	/*! TRUE if the channel/bridge is muted. */
 	unsigned int mute:1;
-/* BUGBUG why is dtmf_passthrough not a feature_flags bit? */
-	/*! Bit to indicate whether DTMF should be passed into the bridge tech or not.  */
+	/*! TRUE if DTMF should be passed into the bridge tech.  */
 	unsigned int dtmf_passthrough:1;
 };
 

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=383786&r1=383785&r2=383786
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging_technology.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging_technology.h Mon Mar 25 16:23:58 2013
@@ -85,15 +85,6 @@
 	 * \retval -1 on failure
 	 */
 	int (*write)(struct ast_bridge *bridge, struct ast_bridge_channel *bridged_channel, struct ast_frame *frame);
-	/*!
-	 * \brief Callback for bridge thread loop.
-	 *
-	 * \retval 0 on success
-	 * \retval -1 on failure
-	 */
-	int (*thread_loop)(struct ast_bridge *bridge);
-	/*! Callback for poking a bridge channel thread */
-	void (*poke_channel)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);
 	/*! Formats that the bridge technology supports */
 	struct ast_format_cap *format_capabilities;
 	/*! TRUE if the bridge technology is currently suspended. */
@@ -149,61 +140,6 @@
 int ast_bridge_technology_unregister(struct ast_bridge_technology *technology);
 
 /*!
- * \brief Generic bridge thread loop.
- * \since 12.0.0
- *
- * \param bridge Handle this bridge thread's loop.
- *
- * \retval 0 on success.
- * \retval non-zero on error.
- */
-int ast_bridge_thread_generic(struct ast_bridge *bridge);
-
-/*!
- * \brief Poke the bridge thread if it is not us.
- * \since 12.0.0
- *
- * \param bridge What to poke.
- *
- * \note This function assumes the bridge is locked.
- *
- * \return Nothing
- */
-void ast_bridge_poke(struct ast_bridge *bridge);
-
-/*!
- * \brief Poke the bridge channel thread if it is not us.
- * \since 12.0.0
- *
- * \param bridge_channel What to poke.
- *
- * \note This function assumes the bridge_channel is locked.
- *
- * \return Nothing
- */
-void ast_bridge_channel_poke(struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \brief Feed notification that a frame is waiting on a channel into the bridging core
- *
- * \param bridge The bridge that the notification should influence
- * \param bridge_channel Bridge channel the notification was received on (if known)

[... 2097 lines stripped ...]



More information about the asterisk-commits mailing list