[asterisk-commits] dvossel: branch dvossel/hd_confbridge r310137 - in /team/dvossel/hd_confbridg...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Mar 9 13:40:03 CST 2011
Author: dvossel
Date: Wed Mar 9 13:40:00 2011
New Revision: 310137
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=310137
Log:
ConfBridge translation optimization
If multiple channels are using the same format, ConfBridge
does the encoding of the write frame and sends a single copy
out to all of them. This drastically improves performance as
it requires only a single translation to take place per format.
Note, at the moment the 'drop_silence' option must be enabled to
take advantage of this feature. This is because the optimization
can only take place when silence is detected on the channel in the
read direction. Otherwise the channel's own read audio has to be
mixed out of the conference mix which results in a unique frame for
that channel on write.
Also, some might consider this optimization of F7esh.
Modified:
team/dvossel/hd_confbridge/bridges/bridge_softmix.c
team/dvossel/hd_confbridge/configs/confbridge.conf.sample
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=310137&r1=310136&r2=310137
==============================================================================
--- team/dvossel/hd_confbridge/bridges/bridge_softmix.c (original)
+++ team/dvossel/hd_confbridge/bridges/bridge_softmix.c Wed Mar 9 13:40:00 2011
@@ -47,6 +47,7 @@
#include "asterisk/slinfactory.h"
#include "asterisk/astobj2.h"
#include "asterisk/timing.h"
+#include "asterisk/translate.h"
#define MAX_DATALEN 3840
@@ -89,159 +90,11 @@
unsigned int internal_rate;
};
-/*! \brief Function called when a bridge is created */
-static int softmix_bridge_create(struct ast_bridge *bridge)
-{
- struct softmix_bridge_data *bridge_data;
-
- if (!(bridge_data = ast_calloc(1, sizeof(*bridge_data)))) {
- return -1;
- }
- if (!(bridge_data->timer = ast_timer_open())) {
- ast_free(bridge_data);
- return -1;
- }
-
- /* start at 8khz, let it grow from there */
- bridge_data->internal_rate = 8000;
-
- bridge->bridge_pvt = bridge_data;
- return 0;
-}
-
-/*! \brief Function called when a bridge is destroyed */
-static int softmix_bridge_destroy(struct ast_bridge *bridge)
-{
- struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
- if (!bridge->bridge_pvt) {
- return -1;
- }
- ast_timer_close(bridge_data->timer);
- ast_free(bridge_data);
- return 0;
-}
-
-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);
- }
- /* Setup frame parameters */
- sc->frame.frametype = AST_FRAME_VOICE;
-
- ast_format_set(&sc->frame.subclass.format, ast_format_slin_by_rate(rate), 0);
- sc->frame.data.ptr = sc->final_buf;
- sc->frame.datalen = SOFTMIX_DATALEN(rate);
- sc->frame.samples = SOFTMIX_SAMPLES(rate);
-
- /* Setup smoother */
- ast_slinfactory_init_with_format(&sc->factory, &sc->frame.subclass.format);
-
- 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 */
-static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
- struct softmix_channel *sc = NULL;
- struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
-
- /* Create a new softmix_channel structure and allocate various things on it */
- if (!(sc = ast_calloc(1, sizeof(*sc)))) {
- return -1;
- }
-
- /* Can't forget the lock */
- ast_mutex_init(&sc->lock);
-
- /* Can't forget to record our pvt structure within the bridged channel structure */
- bridge_channel->bridge_pvt = sc;
-
- set_softmix_bridge_data(bridge_data->internal_rate, bridge_channel, 0);
-
- return 0;
-}
-
-/*! \brief Function called when a channel leaves the bridge */
-static int softmix_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
-{
- struct softmix_channel *sc = bridge_channel->bridge_pvt;
-
- /* Drop mutex lock */
- ast_mutex_destroy(&sc->lock);
-
- /* Drop the factory */
- ast_slinfactory_destroy(&sc->factory);
-
- /* Eep! drop ourselves */
- ast_free(sc);
-
- return 0;
-}
-
-/*! \brief Function called when a channel writes a frame into the bridge */
-static enum ast_bridge_write_result 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 *bridge_data = bridge->bridge_pvt;
-
- /* Only accept audio frames, all others are unsupported */
- if (frame->frametype != AST_FRAME_VOICE) {
- return AST_BRIDGE_WRITE_UNSUPPORTED;
- }
-
- ast_mutex_lock(&sc->lock);
-
- /* Before adding audio in, make sure we haven't fallen behind. If audio has fallen
- * behind 4 times the amount of samples mixed on every iteration of the mixer, Re-sync
- * the audio by flushing the buffer before adding new audio in. */
- if (ast_slinfactory_available(&sc->factory) > (4 * SOFTMIX_SAMPLES(bridge_data->internal_rate))) {
- ast_slinfactory_flush(&sc->factory);
- }
-
- /* If a frame was provided add it to the smoother */
- if (frame->frametype == AST_FRAME_VOICE && ast_format_is_slinear(&frame->subclass.format)) {
- 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->frame);
- sc->have_frame = 0;
- }
-
- /* Alllll done */
- ast_mutex_unlock(&sc->lock);
-
- return AST_BRIDGE_WRITE_SUCCESS;
-}
-
-/*! \brief Function called when the channel's thread is poked */
-static int softmix_bridge_poke(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->frame);
- sc->have_frame = 0;
- }
-
- ast_mutex_unlock(&sc->lock);
-
- return 0;
-}
-
struct softmix_stats {
/*! Each index represents a sample rate used above the internal rate. */
- unsigned int sample_rates[8];
+ 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[8];
+ 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 */
@@ -251,6 +104,303 @@
/*! 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;
+ int16_t **buffers;
+};
+
+struct softmix_translate_helper_entry {
+ int num_times_requested; /*!< Once this entry is no longer requested, free the trans_pvt
+ and re-init if it was usable. */
+ struct ast_format dst_format; /*!< The destination format for this helper */
+ struct ast_trans_pvt *trans_pvt; /*!< the translator for this slot. */
+ struct ast_frame *out_frame; /*!< The output frame from the last translation */
+ AST_LIST_ENTRY(softmix_translate_helper_entry) entry;
+};
+
+struct softmix_translate_helper {
+ struct ast_format slin_src; /*!< the source format expected for all the translators */
+ AST_LIST_HEAD_NOLOCK(, softmix_translate_helper_entry) entries;
+};
+
+static struct softmix_translate_helper_entry *softmix_translate_helper_entry_alloc(struct ast_format *dst)
+{
+ struct softmix_translate_helper_entry *entry;
+ if (!(entry = ast_calloc(1, sizeof(*entry)))) {
+ return NULL;
+ }
+ ast_format_copy(&entry->dst_format, dst);
+ return entry;
+}
+
+static void *softmix_translate_helper_free_entry(struct softmix_translate_helper_entry *entry)
+{
+ if (entry->trans_pvt) {
+ ast_translator_free_path(entry->trans_pvt);
+ }
+ if (entry->out_frame) {
+ ast_frfree(entry->out_frame);
+ }
+ ast_free(entry);
+ return NULL;
+}
+
+static void softmix_translate_helper_init(struct softmix_translate_helper *trans_helper, unsigned int sample_rate)
+{
+ memset(trans_helper, 0, sizeof(*trans_helper));
+ ast_format_set(&trans_helper->slin_src, ast_format_slin_by_rate(sample_rate), 0);
+}
+
+static void softmix_translate_helper_destroy(struct softmix_translate_helper *trans_helper)
+{
+ struct softmix_translate_helper_entry *entry;
+
+ while ((entry = AST_LIST_REMOVE_HEAD(&trans_helper->entries, entry))) {
+ softmix_translate_helper_free_entry(entry);
+ }
+}
+
+static void softmix_translate_helper_change_rate(struct softmix_translate_helper *trans_helper, unsigned int sample_rate)
+{
+ struct softmix_translate_helper_entry *entry;
+
+ ast_format_set(&trans_helper->slin_src, ast_format_slin_by_rate(sample_rate), 0);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&trans_helper->entries, entry, entry) {
+ if (entry->trans_pvt) {
+ ast_translator_free_path(entry->trans_pvt);
+ if (!(entry->trans_pvt = ast_translator_build_path(&entry->dst_format, &trans_helper->slin_src))) {
+ AST_LIST_REMOVE_CURRENT(entry);
+ entry = softmix_translate_helper_free_entry(entry);
+ }
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+}
+
+
+/*!
+ * \internal
+ * \brief Process a softmix channels write audio
+ *
+ * \details This function will remove the channel's talking from its own audio if present and
+ * possibly even do the channel's write translation for it depending on how many other
+ * channels use the same write format.
+ */
+static void softmix_process_write_audio(struct softmix_translate_helper *trans_helper,
+ struct ast_format *raw_write_fmt,
+ struct softmix_channel *sc)
+{
+ struct softmix_translate_helper_entry *entry = NULL;
+ int i;
+
+ /* If we provided audio then take it out while in slinear format. */
+ if (sc->have_audio) {
+ for (i = 0; i < sc->frame.samples; i++) {
+ ast_slinear_saturated_subtract(&sc->final_buf[i], &sc->our_buf[i]);
+ }
+ /* do not do any special write translate optimization if we had to make
+ * a special mix for them to remove their own audio. */
+ return;
+ }
+
+ AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) {
+ if (ast_format_cmp(&entry->dst_format, raw_write_fmt) == AST_FORMAT_CMP_EQUAL) {
+ entry->num_times_requested++;
+ } else {
+ continue;
+ }
+ if (!entry->trans_pvt && (entry->num_times_requested > 1)) {
+ entry->trans_pvt = ast_translator_build_path(&entry->dst_format, &trans_helper->slin_src);
+ }
+ if (entry->trans_pvt && !entry->out_frame) {
+ entry->out_frame = ast_translate(entry->trans_pvt, &sc->frame, 0);
+ }
+ if (entry->out_frame && (entry->out_frame->datalen < MAX_DATALEN)) {
+ ast_format_copy(&sc->frame.subclass.format, &entry->out_frame->subclass.format);
+ memcpy(sc->final_buf, entry->out_frame->data.ptr, entry->out_frame->datalen);
+ sc->frame.datalen = entry->out_frame->datalen;
+ sc->frame.samples = entry->out_frame->samples;
+ }
+ break;
+ }
+
+ /* add new entry into list if this format destination was not matched. */
+ if (!entry && (entry = softmix_translate_helper_entry_alloc(raw_write_fmt))) {
+ AST_LIST_INSERT_HEAD(&trans_helper->entries, entry, entry);
+ }
+}
+
+static void softmix_translate_helper_cleanup(struct softmix_translate_helper *trans_helper)
+{
+ struct softmix_translate_helper_entry *entry = NULL;
+ AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) {
+ if (entry->out_frame) {
+ ast_frfree(entry->out_frame);
+ entry->out_frame = NULL;
+ }
+ }
+}
+
+static void softmix_bridge_data_destroy(void *obj)
+{
+ struct softmix_bridge_data *bridge_data = obj;
+ ast_timer_close(bridge_data->timer);
+}
+
+/*! \brief Function called when a bridge is created */
+static int softmix_bridge_create(struct ast_bridge *bridge)
+{
+ struct softmix_bridge_data *bridge_data;
+
+ if (!(bridge_data = ao2_alloc(sizeof(*bridge_data), softmix_bridge_data_destroy))) {
+ return -1;
+ }
+ if (!(bridge_data->timer = ast_timer_open())) {
+ ao2_ref(bridge_data, -1);
+ return -1;
+ }
+
+ /* start at 8khz, let it grow from there */
+ bridge_data->internal_rate = 8000;
+
+ bridge->bridge_pvt = bridge_data;
+ return 0;
+}
+
+/*! \brief Function called when a bridge is destroyed */
+static int softmix_bridge_destroy(struct ast_bridge *bridge)
+{
+ struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
+ if (!bridge->bridge_pvt) {
+ return -1;
+ }
+ ao2_ref(bridge_data, -1);
+ bridge->bridge_pvt = NULL;
+ return 0;
+}
+
+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);
+ }
+ /* Setup frame parameters */
+ sc->frame.frametype = AST_FRAME_VOICE;
+
+ ast_format_set(&sc->frame.subclass.format, ast_format_slin_by_rate(rate), 0);
+ sc->frame.data.ptr = sc->final_buf;
+ sc->frame.datalen = SOFTMIX_DATALEN(rate);
+ sc->frame.samples = SOFTMIX_SAMPLES(rate);
+
+ /* Setup smoother */
+ ast_slinfactory_init_with_format(&sc->factory, &sc->frame.subclass.format);
+
+ 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 */
+static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+ struct softmix_channel *sc = NULL;
+ struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
+
+ /* Create a new softmix_channel structure and allocate various things on it */
+ if (!(sc = ast_calloc(1, sizeof(*sc)))) {
+ return -1;
+ }
+
+ /* Can't forget the lock */
+ ast_mutex_init(&sc->lock);
+
+ /* Can't forget to record our pvt structure within the bridged channel structure */
+ bridge_channel->bridge_pvt = sc;
+
+ set_softmix_bridge_data(bridge_data->internal_rate, bridge_channel, 0);
+
+ return 0;
+}
+
+/*! \brief Function called when a channel leaves the bridge */
+static int 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)) {
+ return 0;
+ }
+ bridge_channel->bridge_pvt = NULL;
+
+ /* Drop mutex lock */
+ ast_mutex_destroy(&sc->lock);
+
+ /* Drop the factory */
+ ast_slinfactory_destroy(&sc->factory);
+
+ /* Eep! drop ourselves */
+ ast_free(sc);
+
+ return 0;
+}
+
+/*! \brief Function called when a channel writes a frame into the bridge */
+static enum ast_bridge_write_result 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 *bridge_data = bridge->bridge_pvt;
+
+ /* Only accept audio frames, all others are unsupported */
+ if (frame->frametype != AST_FRAME_VOICE) {
+ return AST_BRIDGE_WRITE_UNSUPPORTED;
+ }
+
+ ast_mutex_lock(&sc->lock);
+
+ /* Before adding audio in, make sure we haven't fallen behind. If audio has fallen
+ * behind 4 times the amount of samples mixed on every iteration of the mixer, Re-sync
+ * the audio by flushing the buffer before adding new audio in. */
+ if (ast_slinfactory_available(&sc->factory) > (4 * SOFTMIX_SAMPLES(bridge_data->internal_rate))) {
+ ast_slinfactory_flush(&sc->factory);
+ }
+
+ /* If a frame was provided add it to the smoother */
+ if (frame->frametype == AST_FRAME_VOICE && ast_format_is_slinear(&frame->subclass.format)) {
+ 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->frame);
+ sc->have_frame = 0;
+ }
+
+ /* Alllll done */
+ ast_mutex_unlock(&sc->lock);
+
+ return AST_BRIDGE_WRITE_SUCCESS;
+}
+
+/*! \brief Function called when the channel's thread is poked */
+static int softmix_bridge_poke(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->frame);
+ sc->have_frame = 0;
+ }
+
+ ast_mutex_unlock(&sc->lock);
+
+ return 0;
+}
static void gather_softmix_stats(struct softmix_stats *stats,
const struct softmix_bridge_data *bridge_data,
@@ -339,12 +489,6 @@
return 0;
}
-struct softmix_mixing_array {
- int max_num_entries;
- int used_entries;
- int16_t **buffers;
-};
-
static int softmix_mixing_array_init(struct softmix_mixing_array *mixing_array, unsigned int starting_num_entries)
{
memset(mixing_array, 0, sizeof(*mixing_array));
@@ -377,41 +521,52 @@
/*! \brief Function which acts as the mixing thread */
static int softmix_bridge_thread(struct ast_bridge *bridge)
{
- struct softmix_stats stats;
+ struct softmix_stats stats = { { 0 }, };
struct softmix_mixing_array mixing_array;
struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
- struct ast_timer *timer = bridge_data->timer;
- int16_t buf[MAX_DATALEN] = {0, };
+ struct ast_timer *timer;
+ struct softmix_translate_helper trans_helper;
+ int16_t buf[MAX_DATALEN] = { 0, };
unsigned int stat_iteration_counter = 0; /* counts down, gather stats at zero and reset. */
- int timingfd = ast_timer_fd(timer);
+ int timingfd;
int update_all_rates = 0; /* set this when the internal sample rate has changed */
int i, x;
+ int res = -1;
+
+ if (!(bridge_data = bridge->bridge_pvt)) {
+ goto softmix_cleanup;
+ }
+
+ ao2_ref(bridge_data, 1);
+ timer = bridge_data->timer;
+ timingfd = ast_timer_fd(timer);
/* give it room to grow, memory is cheap but allocations are expensive */
if (softmix_mixing_array_init(&mixing_array, bridge->num + 10)) {
ast_log(LOG_NOTICE, "Failed to allocate softmix mixing structure. \n");
- return -1;
- }
+ goto softmix_cleanup;
+ }
+
+ softmix_translate_helper_init(&trans_helper, bridge_data->internal_rate);
ast_timer_set_rate(timer, (1000 / SOFTMIX_INTERVAL));
while (!bridge->stop && !bridge->refresh && bridge->array_num) {
struct ast_bridge_channel *bridge_channel = NULL;
int timeout = -1;
+ enum ast_format_id cur_slin_id = ast_format_slin_by_rate(bridge_data->internal_rate);
unsigned int softmix_samples = SOFTMIX_SAMPLES(bridge_data->internal_rate);
unsigned int softmix_datalen = SOFTMIX_DATALEN(bridge_data->internal_rate);
if (softmix_datalen > MAX_DATALEN) {
/* This should NEVER happen, but if it does we need to know about it. */
ast_log(LOG_WARNING, "Conference mixing error, requested mixing length greater than mixing buffer.\n");
- softmix_mixing_array_destroy(&mixing_array);
- return -1;
+ goto softmix_cleanup;
}
/* If the number of participants in the bridge has changed, the mixing array
* buffer must realloc */
if (mixing_array.max_num_entries < bridge->num && softmix_mixing_array_grow(&mixing_array, bridge->num + 5)) {
- softmix_mixing_array_destroy(&mixing_array);
- return -1;
+ goto softmix_cleanup;
}
mixing_array.used_entries = 0;
@@ -420,6 +575,11 @@
memset(&stats, 0, sizeof(stats));
/* If the bridge has an internal sample rate set, we must lock in on that rate */
stats.locked_rate = bridge->internal_sample_rate;
+ }
+
+ /* if the sample rate has changed, update the translator helper */
+ if (update_all_rates) {
+ softmix_translate_helper_change_rate(&trans_helper, bridge_data->internal_rate);
}
/* Go through pulling audio from each factory that has it available */
@@ -457,7 +617,7 @@
/* mix it like crazy */
memset(buf, 0, softmix_datalen);
for (i = 0; i < mixing_array.used_entries; i++) {
- for (x = 0; x < softmix_datalen; x++) {
+ for (x = 0; x < softmix_samples; x++) {
ast_slinear_saturated_add(buf + x, mixing_array.buffers[i] + x);
}
}
@@ -470,23 +630,27 @@
continue;
}
- /* Copy from local final buffer to our final buffer */
- memcpy(sc->final_buf, buf, sizeof(sc->final_buf));
-
- /* If we provided audio then take it out */
- if (sc->have_audio) {
- for (i = 0; i < softmix_datalen; i++) {
- ast_slinear_saturated_subtract(&sc->final_buf[i], &sc->our_buf[i]);
- }
- }
-
+ ast_mutex_lock(&sc->lock);
+
+ /* Make SLINEAR write frame from local buffer */
+ if (sc->frame.subclass.format.id != cur_slin_id) {
+ ast_format_set(&sc->frame.subclass.format, cur_slin_id, 0);
+ }
+ sc->frame.datalen = softmix_datalen;
+ sc->frame.samples = softmix_samples;
+ memcpy(sc->final_buf, buf, softmix_datalen);
+
+ /* process the softmix channel's new write audio */
+ softmix_process_write_audio(&trans_helper, &bridge_channel->chan->rawwriteformat, 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);
}
+ update_all_rates = 0;
if (!stat_iteration_counter) {
update_all_rates = analyse_softmix_stats(&stats, bridge_data);
stat_iteration_counter = SOFTMIX_STAT_INTERVAL;
@@ -494,17 +658,23 @@
stat_iteration_counter--;
ao2_unlock(bridge);
-
+ /* cleanup any translation frame data from the previous mixing iteration. */
+ softmix_translate_helper_cleanup(&trans_helper);
/* Wait for the timing source to tell us to wake up and get things done */
ast_waitfor_n_fd(&timingfd, 1, &timeout, NULL);
-
ast_timer_ack(timer, 1);
-
ao2_lock(bridge);
}
+ res = 0;
+
+softmix_cleanup:
+ softmix_translate_helper_destroy(&trans_helper);
softmix_mixing_array_destroy(&mixing_array);
- return 0;
+ if (bridge_data) {
+ ao2_ref(bridge_data, -1);
+ }
+ return res;
}
static struct ast_bridge_technology softmix_bridge = {
Modified: team/dvossel/hd_confbridge/configs/confbridge.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/hd_confbridge/configs/confbridge.conf.sample?view=diff&rev=310137&r1=310136&r2=310137
==============================================================================
--- team/dvossel/hd_confbridge/configs/confbridge.conf.sample (original)
+++ team/dvossel/hd_confbridge/configs/confbridge.conf.sample Wed Mar 9 13:40:00 2011
@@ -22,7 +22,7 @@
; when a channel enters a empty conference. On by default.
;wait_marked=yes ; Sets if the user must wait for a marked user to enter before
; joining the conference. Off by default
-;drop_silence=yes ; Sets if a channel's audio should be dropped from mixing
+drop_silence=yes ; Sets if a channel's audio should be dropped from mixing
; after a certain number of milliseconds of silence is detected.
; Once the user begins talking audio will enter back into
; the bridge. This option will improve the performance
More information about the asterisk-commits
mailing list