#include "asterisk.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/bridging.h"
#include "asterisk/bridging_technology.h"
#include "asterisk/frame.h"
#include "asterisk/options.h"
#include "asterisk/logger.h"
#include "asterisk/slinfactory.h"
#include "asterisk/astobj2.h"
#include "asterisk/timing.h"
#include "asterisk/translate.h"

Go to the source code of this file.
Data Structures | |
| struct | softmix_bridge_data |
| struct | softmix_channel |
| Structure which contains per-channel mixing information. More... | |
| struct | softmix_mixing_array |
| struct | softmix_stats |
| struct | softmix_translate_helper |
| struct | softmix_translate_helper_entry |
| struct | video_follow_talker_data |
Defines | |
| #define | DEFAULT_ENERGY_HISTORY_LEN 150 |
| #define | DEFAULT_SOFTMIX_INTERVAL 20 |
| Interval at which mixing will take place. Valid options are 10, 20, and 40. | |
| #define | DEFAULT_SOFTMIX_SILENCE_THRESHOLD 2500 |
| #define | DEFAULT_SOFTMIX_TALKING_THRESHOLD 160 |
| #define | MAX_DATALEN 8096 |
| #define | SOFTMIX_DATALEN(rate, interval) ((rate/50) * (interval / 10)) |
| Size of the buffer used for sample manipulation. | |
| #define | SOFTMIX_SAMPLES(rate, interval) (SOFTMIX_DATALEN(rate, interval) / 2) |
| Number of samples we are dealing with. | |
| #define | SOFTMIX_STAT_INTERVAL 100 |
| Number of mixing iterations to perform between gathering statistics. | |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static unsigned int | analyse_softmix_stats (struct softmix_stats *stats, struct softmix_bridge_data *softmix_data) |
| static void | gather_softmix_stats (struct softmix_stats *stats, const struct softmix_bridge_data *softmix_data, struct ast_bridge_channel *bridge_channel) |
| static int | load_module (void) |
| static void | set_softmix_bridge_data (int rate, int interval, struct ast_bridge_channel *bridge_channel, int reset) |
| static int | softmix_bridge_create (struct ast_bridge *bridge) |
| Function called when a bridge is created. | |
| static void | softmix_bridge_data_destroy (void *obj) |
| static int | softmix_bridge_destroy (struct ast_bridge *bridge) |
| Function called when a bridge is destroyed. | |
| static int | softmix_bridge_join (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) |
| Function called when a channel is joined into the bridge. | |
| static int | softmix_bridge_leave (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) |
| Function called when a channel leaves the bridge. | |
| static int | softmix_bridge_poke (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) |
| Function called when the channel's thread is poked. | |
| static int | softmix_bridge_thread (struct ast_bridge *bridge) |
| Function which acts as the mixing thread. | |
| static enum ast_bridge_write_result | softmix_bridge_write (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) |
| Function called when a channel writes a frame into the bridge. | |
| static void | softmix_mixing_array_destroy (struct softmix_mixing_array *mixing_array) |
| static int | softmix_mixing_array_grow (struct softmix_mixing_array *mixing_array, unsigned int num_entries) |
| static int | softmix_mixing_array_init (struct softmix_mixing_array *mixing_array, unsigned int starting_num_entries) |
| static void | softmix_pass_dtmf (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) |
| static void | softmix_pass_video_all (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame, int echo) |
| static void | softmix_pass_video_top_priority (struct ast_bridge *bridge, struct ast_frame *frame) |
| static int16_t * | softmix_process_read_audio (struct softmix_channel *sc, unsigned int num_samples) |
| static void | softmix_process_write_audio (struct softmix_translate_helper *trans_helper, struct ast_format *raw_write_fmt, struct softmix_channel *sc) |
| static void | softmix_translate_helper_change_rate (struct softmix_translate_helper *trans_helper, unsigned int sample_rate) |
| static void | softmix_translate_helper_cleanup (struct softmix_translate_helper *trans_helper) |
| static void | softmix_translate_helper_destroy (struct softmix_translate_helper *trans_helper) |
| static struct softmix_translate_helper_entry * | softmix_translate_helper_entry_alloc (struct ast_format *dst) |
| static void * | softmix_translate_helper_free_entry (struct softmix_translate_helper_entry *entry) |
| static void | softmix_translate_helper_init (struct softmix_translate_helper *trans_helper, unsigned int sample_rate) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Multi-party software based channel mixing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_bridge_technology | softmix_bridge |
Definition in file bridge_softmix.c.
| #define DEFAULT_ENERGY_HISTORY_LEN 150 |
| #define DEFAULT_SOFTMIX_INTERVAL 20 |
Interval at which mixing will take place. Valid options are 10, 20, and 40.
Definition at line 61 of file bridge_softmix.c.
Referenced by softmix_bridge_create(), and softmix_bridge_join().
| #define DEFAULT_SOFTMIX_SILENCE_THRESHOLD 2500 |
| #define DEFAULT_SOFTMIX_TALKING_THRESHOLD 160 |
| #define MAX_DATALEN 8096 |
Definition at line 58 of file bridge_softmix.c.
Referenced by softmix_bridge_thread(), and softmix_process_write_audio().
| #define SOFTMIX_DATALEN | ( | rate, | |||
| interval | ) | ((rate/50) * (interval / 10)) |
Size of the buffer used for sample manipulation.
Definition at line 64 of file bridge_softmix.c.
Referenced by set_softmix_bridge_data(), and softmix_bridge_thread().
| #define SOFTMIX_SAMPLES | ( | rate, | |||
| interval | ) | (SOFTMIX_DATALEN(rate, interval) / 2) |
Number of samples we are dealing with.
Definition at line 67 of file bridge_softmix.c.
Referenced by set_softmix_bridge_data(), softmix_bridge_thread(), and softmix_bridge_write().
| #define SOFTMIX_STAT_INTERVAL 100 |
Number of mixing iterations to perform between gathering statistics.
Definition at line 70 of file bridge_softmix.c.
Referenced by softmix_bridge_thread().
| static void __reg_module | ( | void | ) | [static] |
Definition at line 936 of file bridge_softmix.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 936 of file bridge_softmix.c.
| static unsigned int analyse_softmix_stats | ( | struct softmix_stats * | stats, | |
| struct softmix_bridge_data * | softmix_data | |||
| ) | [static] |
Definition at line 647 of file bridge_softmix.c.
References ARRAY_LEN, ast_debug, softmix_stats::highest_supported_rate, softmix_bridge_data::internal_rate, softmix_stats::locked_rate, MIN, softmix_stats::num_above_internal_rate, softmix_stats::num_at_internal_rate, softmix_stats::num_channels, and softmix_stats::sample_rates.
Referenced by softmix_bridge_thread().
00648 { 00649 int i; 00650 /* Re-adjust the internal bridge sample rate if 00651 * 1. The bridge's internal sample rate is locked in at a sample 00652 * rate other than the current sample rate being used. 00653 * 2. two or more channels support a higher sample rate 00654 * 3. no channels support the current sample rate or a higher rate 00655 */ 00656 if (stats->locked_rate) { 00657 /* if the rate is locked by the bridge, only update it if it differs 00658 * from the current rate we are using. */ 00659 if (softmix_data->internal_rate != stats->locked_rate) { 00660 softmix_data->internal_rate = stats->locked_rate; 00661 ast_debug(1, " Bridge is locked in at sample rate %d\n", softmix_data->internal_rate); 00662 return 1; 00663 } 00664 } else if (stats->num_above_internal_rate >= 2) { 00665 /* the highest rate is just used as a starting point */ 00666 unsigned int best_rate = stats->highest_supported_rate; 00667 int best_index = -1; 00668 00669 for (i = 0; i < ARRAY_LEN(stats->num_channels); i++) { 00670 if (stats->num_channels[i]) { 00671 break; 00672 } 00673 /* best_rate starts out being the first sample rate 00674 * greater than the internal sample rate that 2 or 00675 * more channels support. */ 00676 if (stats->num_channels[i] >= 2 && (best_index == -1)) { 00677 best_rate = stats->sample_rates[i]; 00678 best_index = i; 00679 /* If it has been detected that multiple rates above 00680 * the internal rate are present, compare those rates 00681 * to each other and pick the highest one two or more 00682 * channels support. */ 00683 } else if (((best_index != -1) && 00684 (stats->num_channels[i] >= 2) && 00685 (stats->sample_rates[best_index] < stats->sample_rates[i]))) { 00686 best_rate = stats->sample_rates[i]; 00687 best_index = i; 00688 /* It is possible that multiple channels exist with native sample 00689 * rates above the internal sample rate, but none of those channels 00690 * have the same rate in common. In this case, the lowest sample 00691 * rate among those channels is picked. Over time as additional 00692 * statistic runs are made the internal sample rate number will 00693 * adjust to the most optimal sample rate, but it may take multiple 00694 * iterations. */ 00695 } else if (best_index == -1) { 00696 best_rate = MIN(best_rate, stats->sample_rates[i]); 00697 } 00698 } 00699 00700 ast_debug(1, " Bridge changed from %d To %d\n", softmix_data->internal_rate, best_rate); 00701 softmix_data->internal_rate = best_rate; 00702 return 1; 00703 } else if (!stats->num_at_internal_rate && !stats->num_above_internal_rate) { 00704 /* In this case, the highest supported rate is actually lower than the internal rate */ 00705 softmix_data->internal_rate = stats->highest_supported_rate; 00706 ast_debug(1, " Bridge changed from %d to %d\n", softmix_data->internal_rate, stats->highest_supported_rate); 00707 return 1; 00708 } 00709 return 0; 00710 }
| static void gather_softmix_stats | ( | struct softmix_stats * | stats, | |
| const struct softmix_bridge_data * | softmix_data, | |||
| struct ast_bridge_channel * | bridge_channel | |||
| ) | [static] |
Definition at line 610 of file bridge_softmix.c.
References ARRAY_LEN, ast_format_rate(), ast_bridge_channel::chan, softmix_stats::highest_supported_rate, softmix_bridge_data::internal_rate, MAX, softmix_stats::num_above_internal_rate, softmix_stats::num_at_internal_rate, softmix_stats::num_channels, ast_channel::rawreadformat, ast_channel::rawwriteformat, and softmix_stats::sample_rates.
Referenced by softmix_bridge_thread().
00613 { 00614 int channel_native_rate; 00615 int i; 00616 /* Gather stats about channel sample rates. */ 00617 channel_native_rate = MAX(ast_format_rate(&bridge_channel->chan->rawwriteformat), 00618 ast_format_rate(&bridge_channel->chan->rawreadformat)); 00619 00620 if (channel_native_rate > stats->highest_supported_rate) { 00621 stats->highest_supported_rate = channel_native_rate; 00622 } 00623 if (channel_native_rate > softmix_data->internal_rate) { 00624 for (i = 0; i < ARRAY_LEN(stats->sample_rates); i++) { 00625 if (stats->sample_rates[i] == channel_native_rate) { 00626 stats->num_channels[i]++; 00627 break; 00628 } else if (!stats->sample_rates[i]) { 00629 stats->sample_rates[i] = channel_native_rate; 00630 stats->num_channels[i]++; 00631 break; 00632 } 00633 } 00634 stats->num_above_internal_rate++; 00635 } else if (channel_native_rate == softmix_data->internal_rate) { 00636 stats->num_at_internal_rate++; 00637 } 00638 }
| static int load_module | ( | void | ) | [static] |
Definition at line 926 of file bridge_softmix.c.
References ast_bridge_technology_register, ast_format_cap_add(), ast_format_cap_alloc(), ast_format_set(), AST_FORMAT_SLINEAR, AST_MODULE_LOAD_DECLINE, and ast_bridge_technology::format_capabilities.
00927 { 00928 struct ast_format tmp; 00929 if (!(softmix_bridge.format_capabilities = ast_format_cap_alloc())) { 00930 return AST_MODULE_LOAD_DECLINE; 00931 } 00932 ast_format_cap_add(softmix_bridge.format_capabilities, ast_format_set(&tmp, AST_FORMAT_SLINEAR, 0)); 00933 return ast_bridge_technology_register(&softmix_bridge); 00934 }
| static void set_softmix_bridge_data | ( | int | rate, | |
| int | interval, | |||
| struct ast_bridge_channel * | bridge_channel, | |||
| int | reset | |||
| ) | [static] |
Definition at line 336 of file bridge_softmix.c.
References ast_dsp_free(), ast_dsp_new_with_rate(), ast_dsp_set_threshold(), ast_format_rate(), ast_format_set(), ast_format_slin_by_rate(), AST_FRAME_VOICE, ast_mutex_lock, ast_mutex_unlock, ast_set_read_format(), ast_set_write_format(), ast_slinfactory_destroy(), ast_slinfactory_init_with_format(), ast_bridge_channel::bridge_pvt, ast_bridge_channel::chan, ast_frame::data, ast_frame::datalen, DEFAULT_SOFTMIX_TALKING_THRESHOLD, softmix_channel::dsp, softmix_channel::factory, softmix_channel::final_buf, ast_frame_subclass::format, ast_frame::frametype, softmix_channel::lock, softmix_channel::our_buf, ast_frame::ptr, ast_channel::rawreadformat, softmix_channel::read_frame, ast_frame::samples, SOFTMIX_DATALEN, SOFTMIX_SAMPLES, ast_frame::subclass, ast_bridge_tech_optimizations::talking_threshold, ast_bridge_channel::tech_args, and softmix_channel::write_frame.
Referenced by softmix_bridge_join(), and softmix_bridge_thread().
00337 { 00338 struct softmix_channel *sc = bridge_channel->bridge_pvt; 00339 unsigned int channel_read_rate = ast_format_rate(&bridge_channel->chan->rawreadformat); 00340 00341 ast_mutex_lock(&sc->lock); 00342 if (reset) { 00343 ast_slinfactory_destroy(&sc->factory); 00344 ast_dsp_free(sc->dsp); 00345 } 00346 /* Setup read/write frame parameters */ 00347 sc->write_frame.frametype = AST_FRAME_VOICE; 00348 ast_format_set(&sc->write_frame.subclass.format, ast_format_slin_by_rate(rate), 0); 00349 sc->write_frame.data.ptr = sc->final_buf; 00350 sc->write_frame.datalen = SOFTMIX_DATALEN(rate, interval); 00351 sc->write_frame.samples = SOFTMIX_SAMPLES(rate, interval); 00352 00353 sc->read_frame.frametype = AST_FRAME_VOICE; 00354 ast_format_set(&sc->read_frame.subclass.format, ast_format_slin_by_rate(channel_read_rate), 0); 00355 sc->read_frame.data.ptr = sc->our_buf; 00356 sc->read_frame.datalen = SOFTMIX_DATALEN(channel_read_rate, interval); 00357 sc->read_frame.samples = SOFTMIX_SAMPLES(channel_read_rate, interval); 00358 00359 /* Setup smoother */ 00360 ast_slinfactory_init_with_format(&sc->factory, &sc->write_frame.subclass.format); 00361 00362 /* set new read and write formats on channel. */ 00363 ast_set_read_format(bridge_channel->chan, &sc->read_frame.subclass.format); 00364 ast_set_write_format(bridge_channel->chan, &sc->write_frame.subclass.format); 00365 00366 /* set up new DSP. This is on the read side only right before the read frame enters the smoother. */ 00367 sc->dsp = ast_dsp_new_with_rate(channel_read_rate); 00368 /* we want to aggressively detect silence to avoid feedback */ 00369 if (bridge_channel->tech_args.talking_threshold) { 00370 ast_dsp_set_threshold(sc->dsp, bridge_channel->tech_args.talking_threshold); 00371 } else { 00372 ast_dsp_set_threshold(sc->dsp, DEFAULT_SOFTMIX_TALKING_THRESHOLD); 00373 } 00374 00375 ast_mutex_unlock(&sc->lock); 00376 }
| static int softmix_bridge_create | ( | struct ast_bridge * | bridge | ) | [static] |
Function called when a bridge is created.
Definition at line 304 of file bridge_softmix.c.
References ao2_alloc, ao2_ref, ast_timer_open(), ast_bridge::bridge_pvt, DEFAULT_SOFTMIX_INTERVAL, softmix_bridge_data::internal_mixing_interval, softmix_bridge_data::internal_rate, softmix_bridge_data_destroy(), and softmix_bridge_data::timer.
00305 { 00306 struct softmix_bridge_data *softmix_data; 00307 00308 if (!(softmix_data = ao2_alloc(sizeof(*softmix_data), softmix_bridge_data_destroy))) { 00309 return -1; 00310 } 00311 if (!(softmix_data->timer = ast_timer_open())) { 00312 ao2_ref(softmix_data, -1); 00313 return -1; 00314 } 00315 00316 /* start at 8khz, let it grow from there */ 00317 softmix_data->internal_rate = 8000; 00318 softmix_data->internal_mixing_interval = DEFAULT_SOFTMIX_INTERVAL; 00319 00320 bridge->bridge_pvt = softmix_data; 00321 return 0; 00322 }
| static void softmix_bridge_data_destroy | ( | void * | obj | ) | [static] |
Definition at line 297 of file bridge_softmix.c.
References ast_timer_close(), and softmix_bridge_data::timer.
Referenced by softmix_bridge_create().
00298 { 00299 struct softmix_bridge_data *softmix_data = obj; 00300 ast_timer_close(softmix_data->timer); 00301 }
| static int softmix_bridge_destroy | ( | struct ast_bridge * | bridge | ) | [static] |
Function called when a bridge is destroyed.
Definition at line 325 of file bridge_softmix.c.
References ao2_ref, and ast_bridge::bridge_pvt.
00326 { 00327 struct softmix_bridge_data *softmix_data = bridge->bridge_pvt; 00328 if (!bridge->bridge_pvt) { 00329 return -1; 00330 } 00331 ao2_ref(softmix_data, -1); 00332 bridge->bridge_pvt = NULL; 00333 return 0; 00334 }
| static int softmix_bridge_join | ( | struct ast_bridge * | bridge, | |
| struct ast_bridge_channel * | bridge_channel | |||
| ) | [static] |
Function called when a channel is joined into the bridge.
Definition at line 379 of file bridge_softmix.c.
References ast_calloc, ast_mutex_init, ast_bridge_channel::bridge_pvt, ast_bridge::bridge_pvt, DEFAULT_SOFTMIX_INTERVAL, softmix_bridge_data::internal_mixing_interval, softmix_bridge_data::internal_rate, softmix_channel::lock, and set_softmix_bridge_data().
00380 { 00381 struct softmix_channel *sc = NULL; 00382 struct softmix_bridge_data *softmix_data = bridge->bridge_pvt; 00383 00384 /* Create a new softmix_channel structure and allocate various things on it */ 00385 if (!(sc = ast_calloc(1, sizeof(*sc)))) { 00386 return -1; 00387 } 00388 00389 /* Can't forget the lock */ 00390 ast_mutex_init(&sc->lock); 00391 00392 /* Can't forget to record our pvt structure within the bridged channel structure */ 00393 bridge_channel->bridge_pvt = sc; 00394 00395 set_softmix_bridge_data(softmix_data->internal_rate, 00396 softmix_data->internal_mixing_interval ? softmix_data->internal_mixing_interval : DEFAULT_SOFTMIX_INTERVAL, 00397 bridge_channel, 0); 00398 00399 return 0; 00400 }
| static int softmix_bridge_leave | ( | struct ast_bridge * | bridge, | |
| struct ast_bridge_channel * | bridge_channel | |||
| ) | [static] |
Function called when a channel leaves the bridge.
Definition at line 403 of file bridge_softmix.c.
References ast_dsp_free(), ast_free, ast_mutex_destroy, ast_slinfactory_destroy(), ast_bridge_channel::bridge_pvt, softmix_channel::dsp, softmix_channel::factory, and softmix_channel::lock.
00404 { 00405 struct softmix_channel *sc = bridge_channel->bridge_pvt; 00406 00407 if (!(bridge_channel->bridge_pvt)) { 00408 return 0; 00409 } 00410 bridge_channel->bridge_pvt = NULL; 00411 00412 /* Drop mutex lock */ 00413 ast_mutex_destroy(&sc->lock); 00414 00415 /* Drop the factory */ 00416 ast_slinfactory_destroy(&sc->factory); 00417 00418 /* Drop the DSP */ 00419 ast_dsp_free(sc->dsp); 00420 00421 /* Eep! drop ourselves */ 00422 ast_free(sc); 00423 00424 return 0; 00425 }
| static int softmix_bridge_poke | ( | struct ast_bridge * | bridge, | |
| struct ast_bridge_channel * | bridge_channel | |||
| ) | [static] |
Function called when the channel's thread is poked.
Definition at line 594 of file bridge_softmix.c.
References ast_mutex_lock, ast_mutex_unlock, ast_write(), ast_bridge_channel::bridge_pvt, ast_bridge_channel::chan, softmix_channel::have_frame, softmix_channel::lock, and softmix_channel::write_frame.
00595 { 00596 struct softmix_channel *sc = bridge_channel->bridge_pvt; 00597 00598 ast_mutex_lock(&sc->lock); 00599 00600 if (sc->have_frame) { 00601 ast_write(bridge_channel->chan, &sc->write_frame); 00602 sc->have_frame = 0; 00603 } 00604 00605 ast_mutex_unlock(&sc->lock); 00606 00607 return 0; 00608 }
| static int softmix_bridge_thread | ( | struct ast_bridge * | bridge | ) | [static] |
Function which acts as the mixing thread.
Definition at line 742 of file bridge_softmix.c.
References analyse_softmix_stats(), ao2_lock, ao2_ref, ao2_unlock, ast_bridge::array_num, ast_format_set(), ast_format_slin_by_rate(), AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_slinear_saturated_add(), ast_timer_ack(), ast_timer_fd(), ast_timer_set_rate(), ast_waitfor_n_fd(), ast_bridge_channel::bridge_pvt, ast_bridge::bridge_pvt, softmix_mixing_array::buffers, ast_bridge_channel::chan, ast_frame::datalen, softmix_channel::final_buf, ast_frame_subclass::format, gather_softmix_stats(), softmix_channel::have_frame, ast_format::id, ast_bridge::internal_mixing_interval, softmix_bridge_data::internal_mixing_interval, softmix_bridge_data::internal_rate, ast_bridge::internal_sample_rate, softmix_channel::lock, softmix_stats::locked_rate, LOG_NOTICE, LOG_WARNING, MAX_DATALEN, softmix_mixing_array::max_num_entries, ast_bridge::num, ast_channel::rawwriteformat, ast_bridge::refresh, ast_frame::samples, set_softmix_bridge_data(), SOFTMIX_DATALEN, softmix_mixing_array_destroy(), softmix_mixing_array_grow(), softmix_mixing_array_init(), softmix_process_read_audio(), softmix_process_write_audio(), SOFTMIX_SAMPLES, SOFTMIX_STAT_INTERVAL, softmix_translate_helper_change_rate(), softmix_translate_helper_cleanup(), softmix_translate_helper_destroy(), softmix_translate_helper_init(), ast_bridge::stop, ast_frame::subclass, ast_bridge_channel::suspended, ast_bridge_channel::thread, softmix_bridge_data::timer, timer, softmix_mixing_array::used_entries, and softmix_channel::write_frame.
00743 { 00744 struct softmix_stats stats = { { 0 }, }; 00745 struct softmix_mixing_array mixing_array; 00746 struct softmix_bridge_data *softmix_data = bridge->bridge_pvt; 00747 struct ast_timer *timer; 00748 struct softmix_translate_helper trans_helper; 00749 int16_t buf[MAX_DATALEN] = { 0, }; 00750 unsigned int stat_iteration_counter = 0; /* counts down, gather stats at zero and reset. */ 00751 int timingfd; 00752 int update_all_rates = 0; /* set this when the internal sample rate has changed */ 00753 int i, x; 00754 int res = -1; 00755 00756 if (!(softmix_data = bridge->bridge_pvt)) { 00757 goto softmix_cleanup; 00758 } 00759 00760 ao2_ref(softmix_data, 1); 00761 timer = softmix_data->timer; 00762 timingfd = ast_timer_fd(timer); 00763 softmix_translate_helper_init(&trans_helper, softmix_data->internal_rate); 00764 ast_timer_set_rate(timer, (1000 / softmix_data->internal_mixing_interval)); 00765 00766 /* Give the mixing array room to grow, memory is cheap but allocations are expensive. */ 00767 if (softmix_mixing_array_init(&mixing_array, bridge->num + 10)) { 00768 ast_log(LOG_NOTICE, "Failed to allocate softmix mixing structure. \n"); 00769 goto softmix_cleanup; 00770 } 00771 00772 while (!bridge->stop && !bridge->refresh && bridge->array_num) { 00773 struct ast_bridge_channel *bridge_channel = NULL; 00774 int timeout = -1; 00775 enum ast_format_id cur_slin_id = ast_format_slin_by_rate(softmix_data->internal_rate); 00776 unsigned int softmix_samples = SOFTMIX_SAMPLES(softmix_data->internal_rate, softmix_data->internal_mixing_interval); 00777 unsigned int softmix_datalen = SOFTMIX_DATALEN(softmix_data->internal_rate, softmix_data->internal_mixing_interval); 00778 00779 if (softmix_datalen > MAX_DATALEN) { 00780 /* This should NEVER happen, but if it does we need to know about it. Almost 00781 * all the memcpys used during this process depend on this assumption. Rather 00782 * than checking this over and over again through out the code, this single 00783 * verification is done on each iteration. */ 00784 ast_log(LOG_WARNING, "Conference mixing error, requested mixing length greater than mixing buffer.\n"); 00785 goto softmix_cleanup; 00786 } 00787 00788 /* Grow the mixing array buffer as participants are added. */ 00789 if (mixing_array.max_num_entries < bridge->num && softmix_mixing_array_grow(&mixing_array, bridge->num + 5)) { 00790 goto softmix_cleanup; 00791 } 00792 00793 /* init the number of buffers stored in the mixing array to 0. 00794 * As buffers are added for mixing, this number is incremented. */ 00795 mixing_array.used_entries = 0; 00796 00797 /* These variables help determine if a rate change is required */ 00798 if (!stat_iteration_counter) { 00799 memset(&stats, 0, sizeof(stats)); 00800 stats.locked_rate = bridge->internal_sample_rate; 00801 } 00802 00803 /* If the sample rate has changed, update the translator helper */ 00804 if (update_all_rates) { 00805 softmix_translate_helper_change_rate(&trans_helper, softmix_data->internal_rate); 00806 } 00807 00808 /* Go through pulling audio from each factory that has it available */ 00809 AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { 00810 struct softmix_channel *sc = bridge_channel->bridge_pvt; 00811 00812 /* Update the sample rate to match the bridge's native sample rate if necessary. */ 00813 if (update_all_rates) { 00814 set_softmix_bridge_data(softmix_data->internal_rate, softmix_data->internal_mixing_interval, bridge_channel, 1); 00815 } 00816 00817 /* If stat_iteration_counter is 0, then collect statistics during this mixing interation */ 00818 if (!stat_iteration_counter) { 00819 gather_softmix_stats(&stats, softmix_data, bridge_channel); 00820 } 00821 00822 /* if the channel is suspended, don't check for audio, but still gather stats */ 00823 if (bridge_channel->suspended) { 00824 continue; 00825 } 00826 00827 /* Try to get audio from the factory if available */ 00828 ast_mutex_lock(&sc->lock); 00829 if ((mixing_array.buffers[mixing_array.used_entries] = softmix_process_read_audio(sc, softmix_samples))) { 00830 mixing_array.used_entries++; 00831 } 00832 ast_mutex_unlock(&sc->lock); 00833 } 00834 00835 /* mix it like crazy */ 00836 memset(buf, 0, softmix_datalen); 00837 for (i = 0; i < mixing_array.used_entries; i++) { 00838 for (x = 0; x < softmix_samples; x++) { 00839 ast_slinear_saturated_add(buf + x, mixing_array.buffers[i] + x); 00840 } 00841 } 00842 00843 /* Next step go through removing the channel's own audio and creating a good frame... */ 00844 AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) { 00845 struct softmix_channel *sc = bridge_channel->bridge_pvt; 00846 00847 if (bridge_channel->suspended) { 00848 continue; 00849 } 00850 00851 ast_mutex_lock(&sc->lock); 00852 00853 /* Make SLINEAR write frame from local buffer */ 00854 if (sc->write_frame.subclass.format.id != cur_slin_id) { 00855 ast_format_set(&sc->write_frame.subclass.format, cur_slin_id, 0); 00856 } 00857 sc->write_frame.datalen = softmix_datalen; 00858 sc->write_frame.samples = softmix_samples; 00859 memcpy(sc->final_buf, buf, softmix_datalen); 00860 00861 /* process the softmix channel's new write audio */ 00862 softmix_process_write_audio(&trans_helper, &bridge_channel->chan->rawwriteformat, sc); 00863 00864 /* The frame is now ready for use... */ 00865 sc->have_frame = 1; 00866 00867 ast_mutex_unlock(&sc->lock); 00868 00869 /* Poke bridged channel thread just in case */ 00870 pthread_kill(bridge_channel->thread, SIGURG); 00871 } 00872 00873 update_all_rates = 0; 00874 if (!stat_iteration_counter) { 00875 update_all_rates = analyse_softmix_stats(&stats, softmix_data); 00876 stat_iteration_counter = SOFTMIX_STAT_INTERVAL; 00877 } 00878 stat_iteration_counter--; 00879 00880 ao2_unlock(bridge); 00881 /* cleanup any translation frame data from the previous mixing iteration. */ 00882 softmix_translate_helper_cleanup(&trans_helper); 00883 /* Wait for the timing source to tell us to wake up and get things done */ 00884 ast_waitfor_n_fd(&timingfd, 1, &timeout, NULL); 00885 ast_timer_ack(timer, 1); 00886 ao2_lock(bridge); 00887 00888 /* make sure to detect mixing interval changes if they occur. */ 00889 if (bridge->internal_mixing_interval && (bridge->internal_mixing_interval != softmix_data->internal_mixing_interval)) { 00890 softmix_data->internal_mixing_interval = bridge->internal_mixing_interval; 00891 ast_timer_set_rate(timer, (1000 / softmix_data->internal_mixing_interval)); 00892 update_all_rates = 1; /* if the interval changes, the rates must be adjusted as well just to be notified new interval.*/ 00893 } 00894 } 00895 00896 res = 0; 00897 00898 softmix_cleanup: 00899 softmix_translate_helper_destroy(&trans_helper); 00900 softmix_mixing_array_destroy(&mixing_array); 00901 if (softmix_data) { 00902 ao2_ref(softmix_data, -1); 00903 } 00904 return res; 00905 }
| static enum ast_bridge_write_result softmix_bridge_write | ( | struct ast_bridge * | bridge, | |
| struct ast_bridge_channel * | bridge_channel, | |||
| struct ast_frame * | frame | |||
| ) | [static] |
Function called when a channel writes a frame into the bridge.
Definition at line 471 of file bridge_softmix.c.
References ast_bridge_is_video_src(), ast_bridge_notify_talking(), ast_bridge_number_video_src(), ast_bridge_update_talker_src_video_mode(), AST_BRIDGE_VIDEO_MODE_NONE, AST_BRIDGE_VIDEO_MODE_SINGLE_SRC, AST_BRIDGE_VIDEO_MODE_TALKER_SRC, AST_BRIDGE_WRITE_SUCCESS, AST_BRIDGE_WRITE_UNSUPPORTED, ast_dsp_silence_with_energy(), ast_format_get_video_mark(), ast_format_is_slinear(), AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_mutex_lock, ast_mutex_unlock, ast_slinfactory_available(), ast_slinfactory_feed(), ast_slinfactory_flush(), ast_write(), ast_bridge::bridge_pvt, ast_bridge_channel::bridge_pvt, ast_bridge_channel::chan, ast_frame::datalen, DEFAULT_ENERGY_HISTORY_LEN, DEFAULT_SOFTMIX_SILENCE_THRESHOLD, ast_bridge_tech_optimizations::drop_silence, softmix_channel::dsp, video_follow_talker_data::energy_accum, video_follow_talker_data::energy_average, video_follow_talker_data::energy_history, video_follow_talker_data::energy_history_cur_slot, softmix_channel::factory, ast_frame_subclass::format, ast_frame::frametype, softmix_channel::have_frame, softmix_bridge_data::internal_mixing_interval, softmix_bridge_data::internal_rate, softmix_channel::lock, ast_bridge_video_mode::mode, ast_bridge_tech_optimizations::silence_threshold, softmix_pass_dtmf(), softmix_pass_video_all(), softmix_pass_video_top_priority(), SOFTMIX_SAMPLES, ast_frame::subclass, softmix_channel::talking, ast_bridge_channel::tech_args, ast_bridge::video_mode, softmix_channel::video_talker, and softmix_channel::write_frame.
00472 { 00473 struct softmix_channel *sc = bridge_channel->bridge_pvt; 00474 struct softmix_bridge_data *softmix_data = bridge->bridge_pvt; 00475 int totalsilence = 0; 00476 int cur_energy = 0; 00477 int silence_threshold = bridge_channel->tech_args.silence_threshold ? 00478 bridge_channel->tech_args.silence_threshold : 00479 DEFAULT_SOFTMIX_SILENCE_THRESHOLD; 00480 char update_talking = -1; /* if this is set to 0 or 1, tell the bridge that the channel has started or stopped talking. */ 00481 int res = AST_BRIDGE_WRITE_SUCCESS; 00482 00483 /* Only accept audio frames, all others are unsupported */ 00484 if (frame->frametype == AST_FRAME_DTMF_END || frame->frametype == AST_FRAME_DTMF_BEGIN) { 00485 softmix_pass_dtmf(bridge, bridge_channel, frame); 00486 goto bridge_write_cleanup; 00487 } else if (frame->frametype != AST_FRAME_VOICE && frame->frametype != AST_FRAME_VIDEO) { 00488 res = AST_BRIDGE_WRITE_UNSUPPORTED; 00489 goto bridge_write_cleanup; 00490 } else if (frame->datalen == 0) { 00491 goto bridge_write_cleanup; 00492 } 00493 00494 /* Determine if this video frame should be distributed or not */ 00495 if (frame->frametype == AST_FRAME_VIDEO) { 00496 int num_src = ast_bridge_number_video_src(bridge); 00497 int video_src_priority = ast_bridge_is_video_src(bridge, bridge_channel->chan); 00498 00499 switch (bridge->video_mode.mode) { 00500 case AST_BRIDGE_VIDEO_MODE_NONE: 00501 break; 00502 case AST_BRIDGE_VIDEO_MODE_SINGLE_SRC: 00503 if (video_src_priority == 1) { 00504 softmix_pass_video_all(bridge, bridge_channel, frame, 1); 00505 } 00506 break; 00507 case AST_BRIDGE_VIDEO_MODE_TALKER_SRC: 00508 ast_mutex_lock(&sc->lock); 00509 ast_bridge_update_talker_src_video_mode(bridge, bridge_channel->chan, sc->video_talker.energy_average, ast_format_get_video_mark(&frame->subclass.format)); 00510 ast_mutex_unlock(&sc->lock); 00511 if (video_src_priority == 1) { 00512 int echo = num_src > 1 ? 0 : 1; 00513 softmix_pass_video_all(bridge, bridge_channel, frame, echo); 00514 } else if (video_src_priority == 2) { 00515 softmix_pass_video_top_priority(bridge, frame); 00516 } 00517 break; 00518 } 00519 goto bridge_write_cleanup; 00520 } 00521 00522 /* If we made it here, we are going to write the frame into the conference */ 00523 ast_mutex_lock(&sc->lock); 00524 ast_dsp_silence_with_energy(sc->dsp, frame, &totalsilence, &cur_energy); 00525 00526 if (bridge->video_mode.mode == AST_BRIDGE_VIDEO_MODE_TALKER_SRC) { 00527 int cur_slot = sc->video_talker.energy_history_cur_slot; 00528 sc->video_talker.energy_accum -= sc->video_talker.energy_history[cur_slot]; 00529 sc->video_talker.energy_accum += cur_energy; 00530 sc->video_talker.energy_history[cur_slot] = cur_energy; 00531 sc->video_talker.energy_average = sc->video_talker.energy_accum / DEFAULT_ENERGY_HISTORY_LEN; 00532 sc->video_talker.energy_history_cur_slot++; 00533 if (sc->video_talker.energy_history_cur_slot == DEFAULT_ENERGY_HISTORY_LEN) { 00534 sc->video_talker.energy_history_cur_slot = 0; /* wrap around */ 00535 } 00536 } 00537 00538 if (totalsilence < silence_threshold) { 00539 if (!sc->talking) { 00540 update_talking = 1; 00541 } 00542 sc->talking = 1; /* tell the write process we have audio to be mixed out */ 00543 } else { 00544 if (sc->talking) { 00545 update_talking = 0; 00546 } 00547 sc->talking = 0; 00548 } 00549 00550 /* Before adding audio in, make sure we haven't fallen behind. If audio has fallen 00551 * behind 4 times the amount of samples mixed on every iteration of the mixer, Re-sync 00552 * the audio by flushing the buffer before adding new audio in. */ 00553 if (ast_slinfactory_available(&sc->factory) > (4 * SOFTMIX_SAMPLES(softmix_data->internal_rate, softmix_data->internal_mixing_interval))) { 00554 ast_slinfactory_flush(&sc->factory); 00555 } 00556 00557 /* If a frame was provided add it to the smoother, unless drop silence is enabled and this frame 00558 * is not determined to be talking. */ 00559 if (!(bridge_channel->tech_args.drop_silence && !sc->talking) && 00560 (frame->frametype == AST_FRAME_VOICE && ast_format_is_slinear(&frame->subclass.format))) { 00561 ast_slinfactory_feed(&sc->factory, frame); 00562 } 00563 00564 /* If a frame is ready to be written out, do so */ 00565 if (sc->have_frame) { 00566 ast_write(bridge_channel->chan, &sc->write_frame); 00567 sc->have_frame = 0; 00568 } 00569 00570 /* Alllll done */ 00571 ast_mutex_unlock(&sc->lock); 00572 00573 if (update_talking != -1) { 00574 ast_bridge_notify_talking(bridge, bridge_channel, update_talking); 00575 } 00576 00577 return res; 00578 00579 bridge_write_cleanup: 00580 /* Even though the frame is not being written into the conference because it is not audio, 00581 * we should use this opportunity to check to see if a frame is ready to be written out from 00582 * the conference to the channel. */ 00583 ast_mutex_lock(&sc->lock); 00584 if (sc->have_frame) { 00585 ast_write(bridge_channel->chan, &sc->write_frame); 00586 sc->have_frame = 0; 00587 } 00588 ast_mutex_unlock(&sc->lock); 00589 00590 return res; 00591 }
| static void softmix_mixing_array_destroy | ( | struct softmix_mixing_array * | mixing_array | ) | [static] |
Definition at line 723 of file bridge_softmix.c.
References ast_free, and softmix_mixing_array::buffers.
Referenced by softmix_bridge_thread().
| static int softmix_mixing_array_grow | ( | struct softmix_mixing_array * | mixing_array, | |
| unsigned int | num_entries | |||
| ) | [static] |
Definition at line 728 of file bridge_softmix.c.
References ast_log(), ast_realloc, softmix_mixing_array::buffers, LOG_NOTICE, and softmix_mixing_array::max_num_entries.
Referenced by softmix_bridge_thread().
00729 { 00730 int16_t **tmp; 00731 /* give it some room to grow since memory is cheap but allocations can be expensive */ 00732 mixing_array->max_num_entries = num_entries; 00733 if (!(tmp = ast_realloc(mixing_array->buffers, (mixing_array->max_num_entries * sizeof(int16_t *))))) { 00734 ast_log(LOG_NOTICE, "Failed to re-allocate softmix mixing structure. \n"); 00735 return -1; 00736 } 00737 mixing_array->buffers = tmp; 00738 return 0; 00739 }
| static int softmix_mixing_array_init | ( | struct softmix_mixing_array * | mixing_array, | |
| unsigned int | starting_num_entries | |||
| ) | [static] |
Definition at line 712 of file bridge_softmix.c.
References ast_calloc, ast_log(), softmix_mixing_array::buffers, LOG_NOTICE, and softmix_mixing_array::max_num_entries.
Referenced by softmix_bridge_thread().
00713 { 00714 memset(mixing_array, 0, sizeof(*mixing_array)); 00715 mixing_array->max_num_entries = starting_num_entries; 00716 if (!(mixing_array->buffers = ast_calloc(mixing_array->max_num_entries, sizeof(int16_t *)))) { 00717 ast_log(LOG_NOTICE, "Failed to allocate softmix mixing structure. \n"); 00718 return -1; 00719 } 00720 return 0; 00721 }
| static void softmix_pass_dtmf | ( | struct ast_bridge * | bridge, | |
| struct ast_bridge_channel * | bridge_channel, | |||
| struct ast_frame * | frame | |||
| ) | [static] |
Definition at line 431 of file bridge_softmix.c.
References AST_LIST_TRAVERSE, ast_write(), and ast_bridge_channel::chan.
Referenced by softmix_bridge_write().
00432 { 00433 struct ast_bridge_channel *tmp; 00434 AST_LIST_TRAVERSE(&bridge->channels, tmp, entry) { 00435 if (tmp == bridge_channel) { 00436 continue; 00437 } 00438 ast_write(tmp->chan, frame); 00439 } 00440 }
| static void softmix_pass_video_all | ( | struct ast_bridge * | bridge, | |
| struct ast_bridge_channel * | bridge_channel, | |||
| struct ast_frame * | frame, | |||
| int | echo | |||
| ) | [static] |
Definition at line 456 of file bridge_softmix.c.
References AST_LIST_TRAVERSE, ast_write(), ast_bridge_channel::chan, and ast_bridge_channel::suspended.
Referenced by softmix_bridge_write().
00457 { 00458 struct ast_bridge_channel *tmp; 00459 AST_LIST_TRAVERSE(&bridge->channels, tmp, entry) { 00460 if (tmp->suspended) { 00461 continue; 00462 } 00463 if ((tmp->chan == bridge_channel->chan) && !echo) { 00464 continue; 00465 } 00466 ast_write(tmp->chan, frame); 00467 } 00468 }
| static void softmix_pass_video_top_priority | ( | struct ast_bridge * | bridge, | |
| struct ast_frame * | frame | |||
| ) | [static] |
Definition at line 442 of file bridge_softmix.c.
References ast_bridge_is_video_src(), AST_LIST_TRAVERSE, ast_write(), ast_bridge_channel::chan, and ast_bridge_channel::suspended.
Referenced by softmix_bridge_write().
00443 { 00444 struct ast_bridge_channel *tmp; 00445 AST_LIST_TRAVERSE(&bridge->channels, tmp, entry) { 00446 if (tmp->suspended) { 00447 continue; 00448 } 00449 if (ast_bridge_is_video_src(bridge, tmp->chan) == 1) { 00450 ast_write(tmp->chan, frame); 00451 break; 00452 } 00453 } 00454 }
| static int16_t* softmix_process_read_audio | ( | struct softmix_channel * | sc, | |
| unsigned int | num_samples | |||
| ) | [static] |
Definition at line 221 of file bridge_softmix.c.
References ast_slinfactory_available(), ast_slinfactory_read(), softmix_channel::factory, softmix_channel::have_audio, and softmix_channel::our_buf.
Referenced by softmix_bridge_thread().
00222 { 00223 if ((ast_slinfactory_available(&sc->factory) >= num_samples) && 00224 ast_slinfactory_read(&sc->factory, sc->our_buf, num_samples)) { 00225 sc->have_audio = 1; 00226 return sc->our_buf; 00227 } 00228 sc->have_audio = 0; 00229 return NULL; 00230 }
| static void softmix_process_write_audio | ( | struct softmix_translate_helper * | trans_helper, | |
| struct ast_format * | raw_write_fmt, | |||
| struct softmix_channel * | sc | |||
| ) | [static] |
Definition at line 240 of file bridge_softmix.c.
References ast_format_cmp(), AST_FORMAT_CMP_EQUAL, ast_format_copy(), AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_slinear_saturated_subtract(), ast_translate(), ast_translator_build_path(), ast_frame::data, ast_frame::datalen, softmix_translate_helper_entry::dst_format, softmix_translate_helper::entries, softmix_channel::final_buf, ast_frame_subclass::format, softmix_channel::have_audio, MAX_DATALEN, softmix_translate_helper_entry::num_times_requested, softmix_channel::our_buf, softmix_translate_helper_entry::out_frame, ast_frame::ptr, ast_frame::samples, softmix_translate_helper::slin_src, softmix_translate_helper_entry_alloc(), ast_frame::subclass, softmix_channel::talking, softmix_translate_helper_entry::trans_pvt, and softmix_channel::write_frame.
Referenced by softmix_bridge_thread().
00243 { 00244 struct softmix_translate_helper_entry *entry = NULL; 00245 int i; 00246 00247 /* If we provided audio that was not determined to be silence, 00248 * then take it out while in slinear format. */ 00249 if (sc->have_audio && sc->talking) { 00250 for (i = 0; i < sc->write_frame.samples; i++) { 00251 ast_slinear_saturated_subtract(&sc->final_buf[i], &sc->our_buf[i]); 00252 } 00253 /* do not do any special write translate optimization if we had to make 00254 * a special mix for them to remove their own audio. */ 00255 return; 00256 } 00257 00258 AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) { 00259 if (ast_format_cmp(&entry->dst_format, raw_write_fmt) == AST_FORMAT_CMP_EQUAL) { 00260 entry->num_times_requested++; 00261 } else { 00262 continue; 00263 } 00264 if (!entry->trans_pvt && (entry->num_times_requested > 1)) { 00265 entry->trans_pvt = ast_translator_build_path(&entry->dst_format, &trans_helper->slin_src); 00266 } 00267 if (entry->trans_pvt && !entry->out_frame) { 00268 entry->out_frame = ast_translate(entry->trans_pvt, &sc->write_frame, 0); 00269 } 00270 if (entry->out_frame && (entry->out_frame->datalen < MAX_DATALEN)) { 00271 ast_format_copy(&sc->write_frame.subclass.format, &entry->out_frame->subclass.format); 00272 memcpy(sc->final_buf, entry->out_frame->data.ptr, entry->out_frame->datalen); 00273 sc->write_frame.datalen = entry->out_frame->datalen; 00274 sc->write_frame.samples = entry->out_frame->samples; 00275 } 00276 break; 00277 } 00278 00279 /* add new entry into list if this format destination was not matched. */ 00280 if (!entry && (entry = softmix_translate_helper_entry_alloc(raw_write_fmt))) { 00281 AST_LIST_INSERT_HEAD(&trans_helper->entries, entry, entry); 00282 } 00283 }
| static void softmix_translate_helper_change_rate | ( | struct softmix_translate_helper * | trans_helper, | |
| unsigned int | sample_rate | |||
| ) | [static] |
Definition at line 196 of file bridge_softmix.c.
References ast_format_set(), ast_format_slin_by_rate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_translator_build_path(), ast_translator_free_path(), softmix_translate_helper_entry::dst_format, softmix_translate_helper::entries, softmix_translate_helper::slin_src, softmix_translate_helper_free_entry(), and softmix_translate_helper_entry::trans_pvt.
Referenced by softmix_bridge_thread().
00197 { 00198 struct softmix_translate_helper_entry *entry; 00199 00200 ast_format_set(&trans_helper->slin_src, ast_format_slin_by_rate(sample_rate), 0); 00201 AST_LIST_TRAVERSE_SAFE_BEGIN(&trans_helper->entries, entry, entry) { 00202 if (entry->trans_pvt) { 00203 ast_translator_free_path(entry->trans_pvt); 00204 if (!(entry->trans_pvt = ast_translator_build_path(&entry->dst_format, &trans_helper->slin_src))) { 00205 AST_LIST_REMOVE_CURRENT(entry); 00206 entry = softmix_translate_helper_free_entry(entry); 00207 } 00208 } 00209 } 00210 AST_LIST_TRAVERSE_SAFE_END; 00211 }
| static void softmix_translate_helper_cleanup | ( | struct softmix_translate_helper * | trans_helper | ) | [static] |
Definition at line 285 of file bridge_softmix.c.
References ast_frfree, AST_LIST_TRAVERSE, softmix_translate_helper::entries, softmix_translate_helper_entry::num_times_requested, and softmix_translate_helper_entry::out_frame.
Referenced by softmix_bridge_thread().
00286 { 00287 struct softmix_translate_helper_entry *entry = NULL; 00288 AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) { 00289 if (entry->out_frame) { 00290 ast_frfree(entry->out_frame); 00291 entry->out_frame = NULL; 00292 } 00293 entry->num_times_requested = 0; 00294 } 00295 }
| static void softmix_translate_helper_destroy | ( | struct softmix_translate_helper * | trans_helper | ) | [static] |
Definition at line 187 of file bridge_softmix.c.
References AST_LIST_REMOVE_HEAD, softmix_translate_helper::entries, and softmix_translate_helper_free_entry().
Referenced by softmix_bridge_thread().
00188 { 00189 struct softmix_translate_helper_entry *entry; 00190 00191 while ((entry = AST_LIST_REMOVE_HEAD(&trans_helper->entries, entry))) { 00192 softmix_translate_helper_free_entry(entry); 00193 } 00194 }
| static struct softmix_translate_helper_entry* softmix_translate_helper_entry_alloc | ( | struct ast_format * | dst | ) | [static, read] |
Definition at line 159 of file bridge_softmix.c.
References ast_calloc, ast_format_copy(), and softmix_translate_helper_entry::dst_format.
Referenced by softmix_process_write_audio().
00160 { 00161 struct softmix_translate_helper_entry *entry; 00162 if (!(entry = ast_calloc(1, sizeof(*entry)))) { 00163 return NULL; 00164 } 00165 ast_format_copy(&entry->dst_format, dst); 00166 return entry; 00167 }
| static void* softmix_translate_helper_free_entry | ( | struct softmix_translate_helper_entry * | entry | ) | [static] |
Definition at line 169 of file bridge_softmix.c.
References ast_free, ast_frfree, ast_translator_free_path(), softmix_translate_helper_entry::out_frame, and softmix_translate_helper_entry::trans_pvt.
Referenced by softmix_translate_helper_change_rate(), and softmix_translate_helper_destroy().
00170 { 00171 if (entry->trans_pvt) { 00172 ast_translator_free_path(entry->trans_pvt); 00173 } 00174 if (entry->out_frame) { 00175 ast_frfree(entry->out_frame); 00176 } 00177 ast_free(entry); 00178 return NULL; 00179 }
| static void softmix_translate_helper_init | ( | struct softmix_translate_helper * | trans_helper, | |
| unsigned int | sample_rate | |||
| ) | [static] |
Definition at line 181 of file bridge_softmix.c.
References ast_format_set(), ast_format_slin_by_rate(), and softmix_translate_helper::slin_src.
Referenced by softmix_bridge_thread().
00182 { 00183 memset(trans_helper, 0, sizeof(*trans_helper)); 00184 ast_format_set(&trans_helper->slin_src, ast_format_slin_by_rate(sample_rate), 0); 00185 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 920 of file bridge_softmix.c.
References ast_bridge_technology_unregister(), ast_format_cap_destroy(), and ast_bridge_technology::format_capabilities.
00921 { 00922 ast_format_cap_destroy(softmix_bridge.format_capabilities); 00923 return ast_bridge_technology_unregister(&softmix_bridge); 00924 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Multi-party software based channel mixing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 936 of file bridge_softmix.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 936 of file bridge_softmix.c.
struct ast_bridge_technology softmix_bridge [static] |
Definition at line 907 of file bridge_softmix.c.
1.5.6