[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