[asterisk-commits] dvossel: branch dvossel/hd_confbridge r309946 - in /team/dvossel/hd_confbridg...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Mar 7 17:58:18 CST 2011


Author: dvossel
Date: Mon Mar  7 17:58:14 2011
New Revision: 309946

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=309946
Log:
Various performance tweaks to bridging.c and the softmix technology

Modified:
    team/dvossel/hd_confbridge/bridges/bridge_softmix.c
    team/dvossel/hd_confbridge/main/bridging.c

Modified: team/dvossel/hd_confbridge/bridges/bridge_softmix.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/hd_confbridge/bridges/bridge_softmix.c?view=diff&rev=309946&r1=309945&r2=309946
==============================================================================
--- team/dvossel/hd_confbridge/bridges/bridge_softmix.c (original)
+++ team/dvossel/hd_confbridge/bridges/bridge_softmix.c Mon Mar  7 17:58:14 2011
@@ -58,6 +58,10 @@
 
 /*! \brief Number of samples we are dealing with */
 #define SOFTMIX_SAMPLES(rate) (SOFTMIX_DATALEN(rate) / 2)
+
+/*! \brief Number of mixing iterations to perform between
+ * gathering statistics. */
+#define SOFTMIX_STAT_INTERVAL 25
 
 /*! \brief Define used to turn on 16 kHz audio support */
 /* #define SOFTMIX_16_SUPPORT */
@@ -120,6 +124,7 @@
 static void set_softmix_bridge_data(int rate, struct ast_bridge_channel *bridge_channel, int reset)
 {
 	struct softmix_channel *sc = bridge_channel->bridge_pvt;
+	ast_mutex_lock(&sc->lock);
 	if (reset) {
 		ast_slinfactory_destroy(&sc->factory);
 	}
@@ -136,6 +141,7 @@
 
 	ast_set_read_format(bridge_channel->chan, &sc->frame.subclass.format);
 	ast_set_write_format(bridge_channel->chan, &sc->frame.subclass.format);
+	ast_mutex_unlock(&sc->lock);
 }
 
 /*! \brief Function called when a channel is joined into the bridge */
@@ -231,10 +237,7 @@
 	return 0;
 }
 
-/*! \brief Function which acts as the mixing thread */
-static int softmix_bridge_thread(struct ast_bridge *bridge)
-{
-	struct {
+struct mixing_stats {
 		/*! Each index represents a sample rate used above the internal rate. */
 		unsigned int sample_rates[8];
 		/*! Each index represents the number of channels using the same index in the sample_rates array.  */
@@ -247,13 +250,105 @@
 		unsigned int highest_supported_rate;
 		/*! Is the sample rate locked by the bridge, if so what is that rate.*/
 		unsigned int locked_rate;
-	} stats;
+};
+
+static void gather_mixing_stats(struct mixing_stats *stats,
+	const struct softmix_bridge_data *bridge_data,
+	struct ast_bridge_channel *bridge_channel)
+{
+	int channel_native_rate;
+	int i;
+	/* Gather stats about channel sample rates. */
+	channel_native_rate = MAX(ast_format_rate(&bridge_channel->chan->rawwriteformat),
+		ast_format_rate(&bridge_channel->chan->rawreadformat));
+
+	if (channel_native_rate > stats->highest_supported_rate) {
+		stats->highest_supported_rate = channel_native_rate;
+	}
+	if (channel_native_rate > bridge_data->internal_rate) {
+		for (i = 0; i < ARRAY_LEN(stats->sample_rates); i++) {
+			if (stats->sample_rates[i] == channel_native_rate) {
+				stats->num_channels[i]++;
+				break;
+			} else if (!stats->sample_rates[i]) {
+				stats->sample_rates[i] = channel_native_rate;
+				stats->num_channels[i]++;
+				break;
+			}
+		}
+		stats->num_above_internal_rate++;
+	} else if (channel_native_rate == bridge_data->internal_rate) {
+		stats->num_at_internal_rate++;
+	}
+}
+/*!
+ * \internal
+ * \brief Analyse mixing statistics and change bridges internal rate
+ * if necessary.
+ *
+ * \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_mixing_stats(struct mixing_stats *stats, struct softmix_bridge_data *bridge_data)
+{
+	int i;
+	/* Re-adjust the internal bridge sample rate if
+	 * 1. The bridge's internal sample rate is locked in at a sample
+	 *    rate other than the current sample rate being used.
+	 * 2. two or more channels support a higher sample rate
+	 * 3. no channels support the current sample rate or a higher rate
+	 */
+	if (stats->locked_rate) {
+		/* if the rate is locked by the bridge, only update it if it differs
+		 * from the current rate we are using. */
+		if (bridge_data->internal_rate != stats->locked_rate) {
+			bridge_data->internal_rate = stats->locked_rate;
+			ast_debug(1, " Bridge is locked in at sample rate %d\n", bridge_data->internal_rate);
+			return 1;
+		}
+	} else if (stats->num_above_internal_rate >= 2) {
+		/* the highest rate is just used as a starting point */
+		unsigned int best_rate = stats->highest_supported_rate;
+		int best_index = -1;
+
+		/* 1. pick the best sample rate two or more channels support
+		 * 2. if two or more channels do not support the same rate, pick the
+		 * lowest sample rate that is still above the internal rate. */
+		for (i = 0; ((i < ARRAY_LEN(stats->num_channels)) && stats->num_channels[i]); i++) {
+			if ((stats->num_channels[i] >= 2 && (best_index == -1)) ||
+				((best_index != -1) &&
+				(stats->num_channels[i] >= 2) &&
+				(stats->sample_rates[best_index] < stats->sample_rates[i]))) {
+
+				best_rate = stats->sample_rates[i];
+				best_index = i;
+			} else if (best_index == -1) {
+				best_rate = MIN(best_rate, stats->sample_rates[i]);
+			}
+		}
+
+		ast_debug(1, " Bridge changed from %d To %d\n", bridge_data->internal_rate, best_rate);
+		bridge_data->internal_rate = best_rate;
+		return 1;
+	} else if (!stats->num_at_internal_rate && !stats->num_above_internal_rate) {
+		/* in this case, the highest supported rate is actually lower than the internal rate */
+		bridge_data->internal_rate = stats->highest_supported_rate;
+		ast_debug(1, " Bridge changed from %d to %d\n", bridge_data->internal_rate, stats->highest_supported_rate);
+		return 1;
+	}
+	return 0;
+}
+
+/*! \brief Function which acts as the mixing thread */
+static int softmix_bridge_thread(struct ast_bridge *bridge)
+{
+	struct mixing_stats stats;
 	struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
 	struct ast_timer *timer = bridge_data->timer;
 	short *data1, *data2;
 	int timingfd = ast_timer_fd(timer);
 	int update_all_rates = 0; /* set this when the internal sample rate has changed */
-	int channel_native_rate;
+	unsigned int stat_iteration_counter = SOFTMIX_STAT_INTERVAL; /* counts down, gather stats at zero and reset. */
 	int i;
 
 	ast_timer_set_rate(timer, (1000 / SOFTMIX_INTERVAL));
@@ -267,64 +362,49 @@
 
 		/* these variables help determine if a rate change is required */
 		memset(&stats, 0, sizeof(stats));
-		stats.highest_supported_rate = 8000;
-		/* If the bridge has an internal sample rate set, we must lock in
-		 * on that rate */
+		/* If the bridge has an internal sample rate set, we must lock in on that rate */
 		stats.locked_rate = bridge->internal_sample_rate;
 
 		/* 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;
 
-			ast_mutex_lock(&sc->lock);
-
+			if (bridge_channel->suspended) {
+				continue;
+			}
+
+			/* Update the sample rate to match the bridge's native sample rate if necessary. */
 			if (update_all_rates) {
 				set_softmix_bridge_data(bridge_data->internal_rate, bridge_channel, 1);
 			}
 
+			if (!stat_iteration_counter) {
+				gather_mixing_stats(&stats, bridge_data, bridge_channel);
+			}
+
+			ast_mutex_lock(&sc->lock);
+			sc->have_audio = 0;
 			/* Try to get audio from the factory if available */
 			if ((ast_slinfactory_available(&sc->factory) >= softmix_samples) &&
 				ast_slinfactory_read(&sc->factory, sc->our_buf, softmix_samples)) {
 
 				/* Put into the local final buffer */
-				for (i = 0, data1 = buf, data2 = sc->our_buf; i < softmix_datalen; i++, data1++, data2++)
+				for (i = 0, data1 = buf, data2 = sc->our_buf; i < softmix_datalen; i++, data1++, data2++) {
 					ast_slinear_saturated_add(data1, data2);
+				}
 				/* Yay we have our own audio */
 				sc->have_audio = 1;
-			} else {
-				/* Awww we don't have audio ;( */
-				sc->have_audio = 0;
-			}
-
-			/* Gather stats about channel sample rates.  */
-			channel_native_rate = MAX(ast_format_rate(&bridge_channel->chan->rawwriteformat),
-				ast_format_rate(&bridge_channel->chan->rawreadformat));
-
-			if (channel_native_rate > stats.highest_supported_rate) {
-				stats.highest_supported_rate = channel_native_rate;
-			}
-			if (channel_native_rate > bridge_data->internal_rate) {
-				for (i = 0; i < ARRAY_LEN(stats.sample_rates); i++) {
-					if (stats.sample_rates[i] == channel_native_rate) {
-						stats.num_channels[i]++;
-						break;
-					} else if (!stats.sample_rates[i]) {
-						stats.sample_rates[i] = channel_native_rate;
-						stats.num_channels[i]++;
-						break;
-					}
-				}
-				stats.num_above_internal_rate++;
-			} else if (channel_native_rate == bridge_data->internal_rate) {
-				stats.num_at_internal_rate++;
-			}
-
+			}
 			ast_mutex_unlock(&sc->lock);
 		}
 
 		/* 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;
+
+			if (bridge_channel->suspended) {
+				continue;
+			}
 
 			/* Copy from local final buffer to our final buffer */
 			memcpy(sc->final_buf, buf, sizeof(sc->final_buf));
@@ -343,51 +423,11 @@
 			pthread_kill(bridge_channel->thread, SIGURG);
 		}
 
-		update_all_rates = 0;
-		/* Re-adjust the internal bridge sample rate if
-		 * 1. The bridge's internal sample rate is locked in at a sample
-		 *    rate other than the current sample rate being used.
-		 * 2. two or more channels support a higher sample rate
-		 * 3. no channels support the current sample rate or a higher rate
-		 */
-		if (stats.locked_rate) {
-			/* if the rate is locked by the bridge, only update it if it differs
-			 * from the current rate we are using. */
-			if (bridge_data->internal_rate != stats.locked_rate) {
-				bridge_data->internal_rate = stats.locked_rate;
-				ast_debug(1, " Bridge is locked in at sample rate %d\n", bridge_data->internal_rate);
-				update_all_rates = 1;
-			}
-		} else if (stats.num_above_internal_rate >= 2) {
-			/* the highest rate is just used as a starting point */
-			unsigned int best_rate = stats.highest_supported_rate;
-			int best_index = -1;
-
-			/* 1. pick the best sample rate two or more channels support
-			 * 2. if two or more channels do not support the same rate, pick the
-			 * lowest sample rate that is still above the internal rate. */
-			for (i = 0; ((i < ARRAY_LEN(stats.num_channels)) && stats.num_channels[i]); i++) {
-				if ((stats.num_channels[i] >= 2 && (best_index == -1)) ||
-					((best_index != -1) &&
-					(stats.num_channels[i] >= 2) &&
-					(stats.sample_rates[best_index] < stats.sample_rates[i]))) {
-
-					best_rate = stats.sample_rates[i];
-					best_index = i;
-				} else if (best_index == -1) {
-					best_rate = MIN(best_rate, stats.sample_rates[i]);
-				}
-			}
-
-			ast_debug(1, " Bridge changed from %d To %d\n", bridge_data->internal_rate, best_rate);
-			bridge_data->internal_rate = best_rate;
-			update_all_rates = 1;
-		} else if (!stats.num_at_internal_rate && !stats.num_above_internal_rate) {
-			/* in this case, the highest supported rate is actually lower than the internal rate */
-			bridge_data->internal_rate = stats.highest_supported_rate;
-			ast_debug(1, " Bridge changed from %d to %d\n", bridge_data->internal_rate, stats.highest_supported_rate);
-			update_all_rates = 1;
-		}
+		if (!stat_iteration_counter) {
+			update_all_rates = analyse_mixing_stats(&stats, bridge_data);
+			stat_iteration_counter = SOFTMIX_STAT_INTERVAL;
+		}
+		stat_iteration_counter--;
 
 		ao2_unlock(bridge);
 

Modified: team/dvossel/hd_confbridge/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/hd_confbridge/main/bridging.c?view=diff&rev=309946&r1=309945&r2=309946
==============================================================================
--- team/dvossel/hd_confbridge/main/bridging.c (original)
+++ team/dvossel/hd_confbridge/main/bridging.c Mon Mar  7 17:58:14 2011
@@ -782,7 +782,11 @@
 	return;
 }
 
-/*! \brief Internal function that executes a feature on a bridge channel */
+/*!
+ * \brief Internal function that executes a feature on a bridge channel
+ * \note Neither the bridge nor the bridge_channel locks should be held when entering
+ * this function.
+ */
 static void bridge_channel_feature(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
 {
 	struct ast_bridge_features *features = (bridge_channel->features ? bridge_channel->features : &bridge->features);
@@ -934,7 +938,9 @@
 		/* Depending on the above state see what we need to do */
 		if (state == 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);
 			bridge_channel_unsuspend(bridge_channel->bridge, bridge_channel);
 		} else if (state == AST_BRIDGE_CHANNEL_STATE_DTMF) {
 			bridge_channel_suspend(bridge_channel->bridge, bridge_channel);




More information about the asterisk-commits mailing list