45 #define SOFTMIX_MIN_SAMPLE_RATE 8000
48 #define DEFAULT_SOFTMIX_INTERVAL 20
51 #define SOFTMIX_DATALEN(rate, interval) ((rate/50) * (interval / 10))
54 #define SOFTMIX_SAMPLES(rate, interval) (SOFTMIX_DATALEN(rate, interval) / 2)
57 #define SOFTMIX_STAT_INTERVAL 100
66 #define DEFAULT_SOFTMIX_SILENCE_THRESHOLD 2500
69 #define DEFAULT_SOFTMIX_TALKING_THRESHOLD 160
71 #define SOFTBRIDGE_VIDEO_DEST_PREFIX "softbridge_dest"
72 #define SOFTBRIDGE_VIDEO_DEST_LEN strlen(SOFTBRIDGE_VIDEO_DEST_PREFIX)
73 #define SOFTBRIDGE_VIDEO_DEST_SEPARATOR '_'
120 if (!(entry =
ast_calloc(1,
sizeof(*entry)))) {
144 static void softmix_translate_helper_init(
struct softmix_translate_helper *trans_helper,
unsigned int sample_rate)
146 memset(trans_helper, 0,
sizeof(*trans_helper));
150 static void softmix_translate_helper_destroy(
struct softmix_translate_helper *trans_helper)
155 softmix_translate_helper_free_entry(entry);
159 static void softmix_translate_helper_change_rate(
struct softmix_translate_helper *trans_helper,
unsigned int sample_rate)
169 entry = softmix_translate_helper_free_entry(entry);
184 static int16_t *softmix_process_read_audio(
struct softmix_channel *sc,
unsigned int num_samples)
203 static void softmix_process_write_audio(
struct softmix_translate_helper *trans_helper,
266 if (!entry && (entry = softmix_translate_helper_entry_alloc(raw_write_fmt))) {
271 static void softmix_translate_helper_cleanup(
struct softmix_translate_helper *trans_helper)
279 softmix_translate_helper_free_entry(entry);
303 static void set_softmix_bridge_data(
int rate,
int interval,
struct ast_bridge_channel *bridge_channel,
int reset,
int set_binaural,
int binaural_pos_id,
int is_announcement)
309 #ifdef BINAURAL_RENDERING
316 ast_assert(sc != NULL);
320 ast_mutex_lock(&sc->
lock);
323 ast_dsp_free(sc->
dsp);
344 if (set_binaural == 1) {
346 }
else if (set_binaural == 0) {
352 if (binaural_pos_id != -1) {
355 if (is_announcement != -1) {
369 ast_channel_lock(bridge_channel->
chan);
371 ast_channel_rawreadformat(bridge_channel->
chan), slin_format);
372 ast_channel_unlock(bridge_channel->
chan);
375 if (set_binaural == 1 || (set_binaural == -1 && sc->
binaural == 1)) {
377 }
else if (set_binaural == 0) {
383 if (setup_fail || !sc->
dsp) {
385 ast_mutex_unlock(&sc->
lock);
397 ast_mutex_unlock(&sc->
lock);
409 ast_mutex_lock(&softmix_data->
lock);
410 ast_cond_signal(&softmix_data->
cond);
411 ast_mutex_unlock(&softmix_data->
lock);
417 #ifdef BINAURAL_RENDERING
428 softmix_poke_thread(bridge->
tech_pvt);
444 SOFTBRIDGE_VIDEO_DEST_LEN)) {
467 int source_channel_stream_position)
469 char *dest_video_name;
470 size_t dest_video_name_len;
477 dest_video_name_len = SOFTBRIDGE_VIDEO_DEST_LEN + 1;
478 if (!ast_strlen_zero(source_channel_name)) {
479 dest_video_name_len += strlen(source_channel_name) + 1;
480 if (source_channel_stream_position != -1) {
481 dest_video_name_len += 11;
484 dest_video_name =
ast_alloca(dest_video_name_len);
485 if (source_channel_stream_position != -1) {
487 snprintf(dest_video_name, dest_video_name_len,
"%s%c%s%c%d",
488 SOFTBRIDGE_VIDEO_DEST_PREFIX, SOFTBRIDGE_VIDEO_DEST_SEPARATOR,
489 source_channel_name, SOFTBRIDGE_VIDEO_DEST_SEPARATOR,
490 source_channel_stream_position);
493 snprintf(dest_video_name, dest_video_name_len,
"%s%c%s",
494 SOFTBRIDGE_VIDEO_DEST_PREFIX, SOFTBRIDGE_VIDEO_DEST_SEPARATOR,
495 source_channel_name);
497 dest_video_name = SOFTBRIDGE_VIDEO_DEST_PREFIX;
504 const char *channel_name,
const char *sdp_label,
507 char *stream_clone_name = NULL;
514 if (
ast_asprintf(&stream_clone_name,
"%s%c%s%c%d", SOFTBRIDGE_VIDEO_DEST_PREFIX,
515 SOFTBRIDGE_VIDEO_DEST_SEPARATOR, channel_name, SOFTBRIDGE_VIDEO_DEST_SEPARATOR,
521 ast_free(stream_clone_name);
527 if (!ast_strlen_zero(sdp_label)) {
544 const char *channel_name,
const char *sdp_label,
558 if (append_source_stream(dest, channel_name, sdp_label, stream, i)) {
627 SCOPE_ENTER(3,
"%s: \n", ast_channel_name(joiner->
chan));
631 SCOPE_EXIT_LOG_RTN(LOG_ERROR,
"%s: Couldn't alloc topology\n", ast_channel_name(joiner->
chan));
636 ast_channel_lock(joiner->
chan);
637 res = append_source_streams(joiner_video, ast_channel_name(joiner->
chan),
641 ast_channel_unlock(joiner->
chan);
644 SCOPE_EXIT_LOG_RTN(LOG_ERROR,
"%s: Couldn't append source streams\n", ast_channel_name(joiner->
chan));
648 if (participant == joiner) {
651 ast_trace(-1,
"%s: Appending existing participant %s\n", ast_channel_name(joiner->
chan),
652 ast_channel_name(participant->
chan));
653 ast_channel_lock(participant->
chan);
654 res = append_source_streams(sc->
topology, ast_channel_name(participant->
chan),
657 ast_channel_unlock(participant->
chan);
659 SCOPE_EXIT_LOG_RTN(LOG_ERROR,
"%s/%s: Couldn't append source streams\n",
660 ast_channel_name(participant->
chan), ast_channel_name(joiner->
chan));
664 ast_trace(-1,
"%s: Requesting topology change.\n", ast_channel_name(joiner->
chan));
668 SCOPE_EXIT_RTN(
"%s: Couldn't request topology change\n", ast_channel_name(joiner->
chan));
672 if (participant == joiner) {
677 ast_trace(-1,
"%s: Appending joiner %s\n", ast_channel_name(participant->
chan),
678 ast_channel_name(joiner->
chan));
680 if (append_all_streams(sc->
topology, joiner_video)) {
681 SCOPE_EXIT_LOG_RTN(LOG_ERROR,
"%s/%s: Couldn't append streams\n",
682 ast_channel_name(participant->
chan), ast_channel_name(joiner->
chan));
684 ast_trace(-1,
"%s: Requesting topology change\n", ast_channel_name(participant->
chan));
687 ast_trace(-1,
"%s/%s: Couldn't request topology change\n",
688 ast_channel_name(participant->
chan), ast_channel_name(joiner->
chan));
700 int set_binaural = 0;
705 int skip_binaural_output = 1;
707 int is_announcement = 0;
708 int samplerate_change;
709 SCOPE_ENTER(3,
"%s:\n", ast_channel_name(bridge_channel->
chan));
713 SCOPE_EXIT_RTN_VALUE(-1,
"No tech_pvt\n");
718 SCOPE_EXIT_RTN_VALUE(-1,
"Couldn't alloc tech_pvt\n");
721 samplerate_change = softmix_data->internal_rate;
724 if (strncmp(ast_channel_name(bridge_channel->
chan),
"CBAnn", 5) != 0) {
727 softmix_data->internal_rate = samplerate_change;
729 skip_binaural_output = 0;
736 if (!skip_binaural_output) {
739 ast_log(LOG_ERROR,
"Bridge %s: Failed to join channel %s. "
740 "Could not allocate enough memory.\n", bridge->
uniqueid,
741 ast_channel_name(bridge_channel->
chan));
743 SCOPE_EXIT_RTN_VALUE(-1,
"Couldn't do binaural join\n");
749 ast_mutex_init(&sc->
lock);
754 set_softmix_bridge_data(softmix_data->internal_rate,
755 softmix_data->internal_mixing_interval
756 ? softmix_data->internal_mixing_interval
758 bridge_channel, 0, set_binaural, pos_id, is_announcement);
766 ast_debug(1,
"Channel %s simulating UNHOLD for bridge softmix join.\n",
767 ast_channel_name(bridge_channel->
chan));
771 softmix_poke_thread(softmix_data);
772 SCOPE_EXIT_RTN_VALUE(0);
776 const char *channel_name)
779 int stream_removed = 0;
791 return stream_removed;
801 if (!remove_destination_streams(sc->
topology, ast_channel_name(leaver->
chan))) {
808 if (remove_destination_streams(sc->
topology,
"")) {
828 sfu_topologies_on_leave(bridge_channel, &bridge->
channels);
847 ast_mutex_destroy(&sc->
lock);
856 ast_dsp_free(sc->
dsp);
889 int video_src_priority;
897 if (video_src_priority == 1) {
904 ast_mutex_lock(&sc->
lock);
908 ast_mutex_unlock(&sc->
lock);
910 if (video_src_priority == 1) {
912 int echo = num_src > 1 ? 0 : 1;
915 }
else if (video_src_priority == 2) {
916 softmix_pass_video_top_priority(bridge, frame);
942 int totalsilence = 0;
951 char update_talking = -1;
954 ast_mutex_lock(&sc->
lock);
967 ast_channel_lock(bridge_channel->
chan);
968 ast_debug(1,
"Channel %s wrote unexpected format into bridge. Got %s, expected %s.\n",
969 ast_channel_name(bridge_channel->
chan),
974 ast_channel_unlock(bridge_channel->
chan);
995 if (totalsilence < silence_threshold) {
1021 ast_mutex_unlock(&sc->
lock);
1023 if (update_talking != -1) {
1040 ast_mutex_lock(&sc->
lock);
1043 ast_mutex_unlock(&sc->
lock);
1067 clear_talking(bridge_channel);
1115 static void sfu_topologies_on_source_change(
struct ast_bridge *bridge,
1124 if (!source_video) {
1128 ast_channel_lock(source->
chan);
1129 res = append_source_streams(source_video, ast_channel_name(source->
chan),
1132 ast_channel_unlock(source->
chan);
1141 if (participant == source) {
1148 if (!original_topology) {
1155 if (append_all_streams(sc->
topology, source_video)) {
1163 if (remove_all_original_streams(sc->
topology, source_video, original_topology)) {
1186 static void softmix_bridge_write_text(
struct ast_bridge *bridge,
1189 if (DEBUG_ATLEAST(1)) {
1191 char frame_type[64];
1196 ast_log(LOG_DEBUG,
"Received %s frame from '%s:%s': %s\n", frame_type,
1198 ast_channel_name(bridge_channel->
chan),
1201 ast_log(LOG_DEBUG,
"Received %s frame from '%s': %.*s\n", frame_type,
1202 ast_channel_name(bridge_channel->
chan), frame->
datalen,
1203 (
char *)frame->
data.ptr);
1241 clear_talking(bridge_channel);
1252 sfu_topologies_on_source_change(bridge, bridge_channel);
1288 ast_mutex_lock(&sc->
lock);
1290 ast_mutex_unlock(&sc->
lock);
1326 softmix_bridge_check_voice(bridge, bridge_channel);
1333 softmix_bridge_write_voice(bridge, bridge_channel, frame);
1336 softmix_bridge_write_video(bridge, bridge_channel, frame);
1340 softmix_bridge_write_text(bridge, bridge_channel, frame);
1343 res = softmix_bridge_write_control(bridge, bridge_channel, frame);
1346 softmix_bridge_write_rtcp(bridge, bridge_channel, frame);
1352 ast_log(LOG_ERROR,
"Synchronous bridge action written to a softmix bridge.\n");
1367 softmix_data->
bitrate = bitrate;
1376 if (bitrate < softmix_data->bitrate) {
1377 softmix_data->
bitrate = bitrate;
1381 if (bitrate > softmix_data->
bitrate) {
1382 softmix_data->
bitrate = bitrate;
1427 remb_collect_report_all(bridge, softmix_data, bitrate);
1447 if (bitrate < collector->bitrate) {
1452 if (bitrate > collector->
bitrate) {
1477 float bitrate = softmix_data->
bitrate;
1534 frexp(bitrate, &exp);
1535 exp = exp > 18 ? exp - 18 : 0;
1546 if (bridge_num == -1) {
1560 static void gather_softmix_stats(
struct softmix_stats *stats,
1564 int channel_native_rate;
1567 ast_channel_lock(bridge_channel->
chan);
1570 ast_channel_unlock(bridge_channel->
chan);
1577 }
else if (softmix_data->internal_rate < channel_native_rate) {
1591 }
else if (softmix_data->internal_rate == channel_native_rate) {
1604 static unsigned int analyse_softmix_stats(
struct softmix_stats *stats,
1609 if (binaural_active) {
1623 if (softmix_data->internal_rate != stats->
locked_rate) {
1624 ast_debug(1,
"Locking at new rate. Bridge changed from %u to %u.\n",
1632 if (softmix_data->internal_rate != stats->
maximum_rate) {
1633 ast_debug(1,
"Locking at new maximum rate. Bridge changed from %u to %u.\n",
1641 int best_index = -1;
1649 if (best_index == -1
1665 }
else if (best_index == -1) {
1679 ast_debug(1,
"Multiple above internal rate. Bridge changed from %u to %u.\n",
1680 softmix_data->internal_rate, best_rate);
1681 softmix_data->internal_rate = best_rate;
1685 ast_debug(1,
"All below internal rate. Bridge changed from %u to %u.\n",
1694 unsigned int starting_num_entries,
unsigned int binaural_active)
1696 memset(mixing_array, 0,
sizeof(*mixing_array));
1697 mixing_array->max_num_entries = starting_num_entries;
1698 if (!(mixing_array->buffers =
ast_calloc(mixing_array->max_num_entries,
sizeof(int16_t *)))) {
1699 ast_log(LOG_NOTICE,
"Failed to allocate softmix mixing structure.\n");
1702 if (binaural_active) {
1705 ast_log(LOG_NOTICE,
"Failed to allocate softmix mixing structure.\n");
1713 unsigned int binaural_active)
1715 ast_free(mixing_array->buffers);
1716 if (binaural_active) {
1722 unsigned int num_entries,
unsigned int binaural_active)
1727 mixing_array->max_num_entries = num_entries;
1728 if (!(tmp =
ast_realloc(mixing_array->buffers, (mixing_array->max_num_entries *
sizeof(int16_t *))))) {
1729 ast_log(LOG_NOTICE,
"Failed to re-allocate softmix mixing structure.\n");
1732 mixing_array->buffers = tmp;
1734 if (binaural_active) {
1738 ast_log(LOG_NOTICE,
"Failed to re-allocate softmix mixing structure.\n");
1758 struct softmix_translate_helper trans_helper;
1759 int16_t buf[MAX_DATALEN];
1760 #ifdef BINAURAL_RENDERING
1761 int16_t bin_buf[MAX_DATALEN];
1762 int16_t ann_buf[MAX_DATALEN];
1764 unsigned int stat_iteration_counter = 0;
1766 int update_all_rates = 0;
1771 timer = softmix_data->timer;
1773 softmix_translate_helper_init(&trans_helper, softmix_data->internal_rate);
1777 if (softmix_mixing_array_init(&mixing_array, bridge->
num_channels + 10,
1779 goto softmix_cleanup;
1790 unsigned int softmix_samples =
SOFTMIX_SAMPLES(softmix_data->internal_rate, softmix_data->internal_mixing_interval);
1791 unsigned int softmix_datalen =
SOFTMIX_DATALEN(softmix_data->internal_rate, softmix_data->internal_mixing_interval);
1792 int remb_update = 0;
1794 if (softmix_datalen > MAX_DATALEN) {
1799 ast_log(LOG_WARNING,
1800 "Bridge %s: Conference mixing error, requested mixing length greater than mixing buffer.\n",
1802 goto softmix_cleanup;
1806 if (mixing_array.max_num_entries < bridge->
num_channels
1807 && softmix_mixing_array_grow(&mixing_array, bridge->
num_channels + 5,
1809 goto softmix_cleanup;
1814 mixing_array.used_entries = 0;
1817 if (!stat_iteration_counter) {
1818 memset(&stats, 0,
sizeof(stats));
1824 if (update_all_rates) {
1825 softmix_translate_helper_change_rate(&trans_helper, softmix_data->internal_rate);
1828 #ifdef BINAURAL_RENDERING
1850 if (update_all_rates) {
1851 set_softmix_bridge_data(softmix_data->internal_rate,
1852 softmix_data->internal_mixing_interval, bridge_channel, 1, -1, -1, -1);
1856 if (!stat_iteration_counter) {
1857 gather_softmix_stats(&stats, softmix_data, bridge_channel);
1866 ast_mutex_lock(&sc->
lock);
1867 if ((mixing_array.buffers[mixing_array.used_entries] = softmix_process_read_audio(sc, softmix_samples))) {
1868 #ifdef BINAURAL_RENDERING
1870 ast_channel_name(bridge_channel->
chan));
1872 mixing_array.used_entries++;
1875 remb_collect_report(bridge, bridge_channel, softmix_data, sc);
1877 ast_mutex_unlock(&sc->
lock);
1881 memset(buf, 0, softmix_datalen);
1882 for (idx = 0; idx < mixing_array.used_entries; ++idx) {
1883 for (x = 0; x < softmix_samples; ++x) {
1884 ast_slinear_saturated_add(buf + x, mixing_array.buffers[idx] + x);
1888 #ifdef BINAURAL_RENDERING
1889 binaural_mixing(bridge, softmix_data, &mixing_array, bin_buf, ann_buf);
1901 ast_mutex_lock(&sc->
lock);
1905 "Replace softmix channel slin format");
1906 #ifdef BINAURAL_RENDERING
1910 softmix_samples, buf);
1916 memcpy(sc->
final_buf, buf, softmix_datalen);
1919 softmix_process_write_audio(&trans_helper,
1920 ast_channel_rawwriteformat(bridge_channel->
chan), sc,
1923 ast_mutex_unlock(&sc->
lock);
1929 remb_send_report(bridge_channel, softmix_data, sc);
1938 update_all_rates = 0;
1939 if (!stat_iteration_counter) {
1940 update_all_rates = analyse_softmix_stats(&stats, softmix_data,
1944 stat_iteration_counter--;
1948 softmix_translate_helper_cleanup(&trans_helper);
1952 ast_log(LOG_ERROR,
"Bridge %s: Failed to acknowledge timer in softmix.\n",
1955 goto softmix_cleanup;
1964 update_all_rates = 1;
1971 softmix_translate_helper_destroy(&trans_helper);
1985 static void *softmix_mixing_thread(
void *data)
1997 while (!softmix_data->
stop) {
2001 ast_mutex_lock(&softmix_data->
lock);
2002 if (!softmix_data->
stop) {
2003 ast_cond_wait(&softmix_data->
cond, &softmix_data->
lock);
2005 ast_mutex_unlock(&softmix_data->
lock);
2011 #ifndef BINAURAL_RENDERING
2015 ast_log(LOG_WARNING,
"Bridge: %s: Binaural rendering active by config but not "
2021 softmix_data->internal_mixing_interval);
2028 ast_log(LOG_ERROR,
"Bridge: %s: Unable to allocate memory for "
2029 "binaural processing, Will only process mono audio.\n",
2056 if (softmix_data->timer) {
2058 softmix_data->timer = NULL;
2060 ast_mutex_destroy(&softmix_data->
lock);
2061 ast_cond_destroy(&softmix_data->
cond);
2064 ast_free(softmix_data);
2072 softmix_data =
ast_calloc(1,
sizeof(*softmix_data));
2073 if (!softmix_data) {
2077 ast_mutex_init(&softmix_data->
lock);
2078 ast_cond_init(&softmix_data->
cond, NULL);
2080 if (!softmix_data->timer) {
2081 ast_log(AST_LOG_WARNING,
"Failed to open timer for softmix bridge\n");
2082 softmix_bridge_data_destroy(softmix_data);
2089 #ifdef BINAURAL_RENDERING
2091 softmix_data->internal_mixing_interval);
2099 if (ast_pthread_create(&softmix_data->
thread, NULL, softmix_mixing_thread,
2101 softmix_data->
thread = AST_PTHREADT_NULL;
2102 softmix_bridge_data_destroy(softmix_data);
2117 static void softmix_bridge_stop(
struct ast_bridge *bridge)
2122 if (!softmix_data) {
2126 ast_mutex_lock(&softmix_data->
lock);
2127 softmix_data->
stop = 1;
2128 ast_mutex_unlock(&softmix_data->
lock);
2138 if (!softmix_data) {
2143 ast_mutex_lock(&softmix_data->
lock);
2144 softmix_data->
stop = 1;
2145 ast_cond_signal(&softmix_data->
cond);
2146 thread = softmix_data->
thread;
2147 softmix_data->
thread = AST_PTHREADT_NULL;
2148 ast_mutex_unlock(&softmix_data->
lock);
2149 if (thread != AST_PTHREADT_NULL) {
2150 ast_debug(1,
"Bridge %s: Waiting for mixing thread to die.\n", bridge->
uniqueid);
2151 pthread_join(thread, NULL);
2153 #ifdef BINAURAL_RENDERING
2156 softmix_bridge_data_destroy(softmix_data);
2177 if (!strcmp(source_channel_name, ast_channel_name(participant->
chan))) {
2182 ast_channel_lock(participant->
chan);
2189 if (
is_video_dest(stream, source_channel_name, source_channel_stream_position)) {
2197 ast_channel_unlock(participant->
chan);
2234 size_t bridge_stream_position)
2263 size_t removed_streams_count = 0;
2267 SCOPE_ENTER(3,
"%s: OT: %s NT: %s\n", ast_channel_name(bridge_channel->
chan),
2272 if (!added_streams) {
2273 SCOPE_EXIT_LOG(LOG_ERROR,
"%s: Couldn't alloc topology\n", ast_channel_name(bridge_channel->
chan));
2282 ast_trace(-1,
"%s: Checking for state changes\n", ast_channel_name(bridge_channel->
chan));
2286 SCOPE_ENTER(4,
"%s: Slot: %d Old stream: %s New stream: %s\n", ast_channel_name(bridge_channel->
chan),
2293 SOFTBRIDGE_VIDEO_DEST_LEN)) {
2294 SCOPE_EXIT_EXPR(
continue,
"%s: Stream %d ignored\n", ast_channel_name(bridge_channel->
chan), index);
2299 ast_trace(-1,
"%s: Stream %d added to remove list\n", ast_channel_name(bridge_channel->
chan), index);
2300 removed_streams[removed_streams_count++] = index;
2304 if (append_source_stream(added_streams, ast_channel_name(bridge_channel->
chan),
2306 new_stream, index)) {
2307 SCOPE_EXIT_EXPR(
goto cleanup,
"%s: Couldn't append source stream %d:%s\n", ast_channel_name(bridge_channel->
chan),
2310 ast_trace(-1,
"%s: Stream %d changed from non-video to video\n", ast_channel_name(bridge_channel->
chan), index);
2314 ast_trace(-1,
"%s: Stream %d added to remove list\n", ast_channel_name(bridge_channel->
chan), index);
2316 removed_streams[removed_streams_count++] = index;
2322 if (append_source_stream(added_streams, ast_channel_name(bridge_channel->
chan),
2324 new_stream, index)) {
2325 SCOPE_EXIT_EXPR(
goto cleanup,
"%s: Couldn't append source stream %d:%s\n", ast_channel_name(bridge_channel->
chan),
2328 ast_trace(-1,
"%s: Stream %d:%s changed state from %s to %s\n", ast_channel_name(bridge_channel->
chan),
2332 ast_trace(-1,
"%s: Stream %d:%s didn't do anything\n", ast_channel_name(bridge_channel->
chan),
2343 ast_trace(-1,
"%s: Checking for newly added streams\n", ast_channel_name(bridge_channel->
chan));
2347 SCOPE_ENTER(4,
"%s: Checking stream %d:%s\n", ast_channel_name(bridge_channel->
chan), index,
2351 SCOPE_EXIT_EXPR(
continue,
"%s: Stream %d:%s is not video source\n", ast_channel_name(bridge_channel->
chan),
2355 if (append_source_stream(added_streams, ast_channel_name(bridge_channel->
chan),
2358 SCOPE_EXIT_EXPR(
goto cleanup,
"%s: Couldn't append stream %d:%s\n", ast_channel_name(bridge_channel->
chan),
2361 SCOPE_EXIT(
"%s: Added new stream %s\n", ast_channel_name(bridge_channel->
chan),
2377 ast_trace(-1,
"%s: Nothing added or removed\n", ast_channel_name(bridge_channel->
chan));
2381 ast_trace(-1,
"%s: Processing adds and removes\n", ast_channel_name(bridge_channel->
chan));
2386 SCOPE_ENTER(4,
"%s/%s: Old participant topology %s\n",
2387 ast_channel_name(bridge_channel->
chan),
2388 ast_channel_name(participant->
chan),
2391 if (participant == bridge_channel) {
2392 SCOPE_EXIT_EXPR(
continue,
"%s/%s: Same channel. Skipping\n",
2393 ast_channel_name(bridge_channel->
chan),
2394 ast_channel_name(participant->
chan));
2400 if (append_all_streams(participant_sc->
topology, added_streams)) {
2401 SCOPE_EXIT_EXPR(
goto cleanup,
"%s/%s: Couldn't append streams\n", ast_channel_name(bridge_channel->
chan),
2402 ast_channel_name(participant->
chan));
2404 ast_trace(-1,
"%s/%s: Adding streams %s\n", ast_channel_name(bridge_channel->
chan),
2405 ast_channel_name(participant->
chan),
2414 for (removed_stream = 0; removed_stream < removed_streams_count; ++removed_stream) {
2416 removed_streams[removed_stream])) {
2417 ast_trace(-1,
"%s/%s: Removing stream %s\n",
2418 ast_channel_name(bridge_channel->
chan),
2419 ast_channel_name(participant->
chan),
2426 SCOPE_EXIT(
"%s/%s: New participant topology %s\n",
2427 ast_channel_name(bridge_channel->
chan),
2428 ast_channel_name(participant->
chan),
2432 ast_trace(-1,
"%s: New topology %s\n", ast_channel_name(bridge_channel->
chan),
2456 int nths[AST_MEDIA_TYPE_END] = {0};
2458 SCOPE_ENTER(3,
"%s: \n", ast_channel_name(bridge_channel->
chan));
2466 SCOPE_EXIT_RTN(
"%s: Not in SFU mode\n", ast_channel_name(bridge_channel->
chan));
2471 ast_channel_lock(bridge_channel->
chan);
2472 softmix_bridge_stream_sources_update(bridge, bridge_channel, sc);
2473 ast_channel_unlock(bridge_channel->
chan);
2512 ast_channel_lock(participant->
chan);
2517 ast_channel_unlock(participant->
chan);
2538 ast_channel_unlock(participant->
chan);
2542 AST_VECTOR_SIZE(&media_types) - 1, &bridge->
channels, i);
2544 ast_channel_lock(participant->
chan);
2571 ast_channel_unlock(participant->
chan);
2576 SCOPE_EXIT_RTN(
"%s\n", ast_channel_name(bridge_channel->
chan));
2582 .preference = AST_BRIDGE_PREFERENCE_BASE_MULTIMIX,
2584 .stop = softmix_bridge_stop,
2589 .write = softmix_bridge_write,
2593 #ifdef TEST_FRAMEWORK
2594 struct stream_parameters {
2600 static struct ast_stream_topology *build_topology(
const struct stream_parameters *params,
size_t num_streams)
2610 for (i = 0; i < num_streams; ++i) {
2639 static int validate_stream(
struct ast_test *
test,
struct ast_stream *stream,
2640 const struct stream_parameters *params)
2646 ast_test_status_update(test,
"Expected stream type '%s' but got type '%s'\n",
2652 ast_test_status_update(test,
"Expected stream name '%s' but got type '%s'\n",
2660 ast_test_status_update(test,
"Allocation error on capabilities\n");
2666 ast_test_status_update(test,
"Formats are not as expected on stream '%s'\n",
2668 ao2_cleanup(params_caps);
2672 ao2_cleanup(params_caps);
2676 static int validate_original_streams(
struct ast_test *test,
struct ast_stream_topology *topology,
2677 const struct stream_parameters *params,
size_t num_streams)
2682 ast_test_status_update(test,
"Topology only has %d streams. Needs to have at least %zu\n",
2687 for (i = 0; i < num_streams; ++i) {
2698 enum ast_test_result_state res = AST_TEST_FAIL;
2699 static const struct stream_parameters bob_streams[] = {
2700 {
"bob_audio",
"ulaw,alaw,g722,opus", AST_MEDIA_TYPE_AUDIO, },
2701 {
"bob_video",
"h264,vp8", AST_MEDIA_TYPE_VIDEO, },
2703 static const struct stream_parameters alice_streams[] = {
2704 {
"alice_audio",
"ulaw,opus", AST_MEDIA_TYPE_AUDIO, },
2705 {
"alice_video",
"vp8", AST_MEDIA_TYPE_VIDEO, },
2707 static const struct stream_parameters alice_dest_stream = {
2708 "softbridge_dest_PJSIP/Bob-00000001_1",
"h264,vp8", AST_MEDIA_TYPE_VIDEO,
2710 static const struct stream_parameters bob_dest_stream = {
2711 "softbridge_dest_PJSIP/Alice-00000000_1",
"vp8", AST_MEDIA_TYPE_VIDEO,
2718 info->name =
"sfu_append_source_streams";
2719 info->category =
"/bridges/bridge_softmix/";
2720 info->summary =
"Test appending of video streams";
2722 "This tests does stuff.";
2723 return AST_TEST_NOT_RUN;
2728 topology_alice = build_topology(alice_streams, ARRAY_LEN(alice_streams));
2729 if (!topology_alice) {
2733 topology_bob = build_topology(bob_streams, ARRAY_LEN(bob_streams));
2734 if (!topology_bob) {
2738 if (append_source_streams(topology_alice,
"PJSIP/Bob-00000001", NULL, topology_bob)) {
2739 ast_test_status_update(test,
"Failed to append Bob's streams to Alice\n");
2744 ast_test_status_update(test,
"Alice's topology isn't large enough! It's %d but needs to be %d\n",
2749 if (validate_original_streams(test, topology_alice, alice_streams, ARRAY_LEN(alice_streams))) {
2757 if (append_source_streams(topology_bob,
"PJSIP/Alice-00000000", NULL, topology_alice)) {
2758 ast_test_status_update(test,
"Failed to append Alice's streams to Bob\n");
2763 ast_test_status_update(test,
"Bob's topology isn't large enough! It's %d but needs to be %d\n",
2768 if (validate_original_streams(test, topology_bob, bob_streams, ARRAY_LEN(bob_streams))) {
2776 res = AST_TEST_PASS;
2786 enum ast_test_result_state res = AST_TEST_FAIL;
2787 static const struct stream_parameters params[] = {
2788 {
"alice_audio",
"ulaw,alaw,g722,opus", AST_MEDIA_TYPE_AUDIO, },
2789 {
"alice_video",
"h264,vp8", AST_MEDIA_TYPE_VIDEO, },
2790 {
"softbridge_dest_PJSIP/Bob-00000001_video",
"vp8", AST_MEDIA_TYPE_VIDEO, },
2791 {
"softbridge_dest_PJSIP/Carol-00000002_video",
"h264", AST_MEDIA_TYPE_VIDEO, },
2793 static const struct {
2794 const char *channel_name;
2796 int params_index[4];
2797 } removal_results[] = {
2798 {
"PJSIP/Bob-00000001", 4, { 0, 1, 2, 3 }, },
2799 {
"PJSIP/Edward-00000004", 4, { 0, 1, 2, 3 }, },
2800 {
"", 4, { 0, 1, 2, 3 }, },
2807 info->name =
"sfu_remove_destination_streams";
2808 info->category =
"/bridges/bridge_softmix/";
2809 info->summary =
"Test removal of destination video streams";
2811 "This tests does stuff.";
2812 return AST_TEST_NOT_RUN;
2817 orig = build_topology(params, ARRAY_LEN(params));
2819 ast_test_status_update(test,
"Unable to build initial stream topology\n");
2823 for (i = 0; i < ARRAY_LEN(removal_results); ++i) {
2826 remove_destination_streams(orig, removal_results[i].channel_name);
2829 ast_test_status_update(test,
"Resulting topology has %d streams, when %d are expected\n",
2834 for (j = 0; j < removal_results[i].num_streams; ++j) {
2841 orig_index = removal_results[i].params_index[j];
2849 expected_str = ast_str_alloca(64);
2850 actual_str = ast_str_alloca(64);
2852 ast_test_status_update(test,
"Mismatch between expected (%s) and actual (%s) stream formats\n",
2858 if (
is_video_dest(actual, removal_results[i].channel_name, -1) &&
2860 ast_test_status_update(test,
"Removed stream %s does not have a state of removed\n",
ast_stream_get_name(actual));
2866 res = AST_TEST_PASS;
2875 static int unload_module(
void)
2878 AST_TEST_UNREGISTER(sfu_append_source_streams);
2879 AST_TEST_UNREGISTER(sfu_remove_destination_streams);
2883 static int load_module(
void)
2889 AST_TEST_REGISTER(sfu_append_source_streams);
2890 AST_TEST_REGISTER(sfu_remove_destination_streams);
2894 AST_MODULE_INFO_STANDARD(
ASTERISK_GPL_KEY,
"Multi-party software based channel mixing");
void check_binaural_position_change(struct ast_bridge *bridge, struct softmix_bridge_data *softmix_data)
Checks if a position change in the virtual enviroment is requested by one of the participants.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
unsigned int num_above_maximum_rate
Multi-party software based channel mixing (header)
const char * ast_stream_to_str(const struct ast_stream *stream, struct ast_str **buf)
Get a string representing the stream for debugging/display purposes.
struct convolve_channel_pair ** chan_pairs
#define AST_VECTOR_GET_INDEX_NTH(vec, nth, value, cmp)
Get the nth index from a vector that matches the given comparison.
Asterisk main include file. File version handling, generic pbx functions.
const ast_string_field uniqueid
#define ast_realloc(p, len)
A wrapper for realloc()
struct ast_bridge_features * features
int ast_dsp_silence_with_energy(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence, int *frames_energy)
Process the audio frame for silence.
int init_convolve_data(struct convolve_data *data, unsigned int default_sample_size)
Preinits a specific number of channels (CONVOLVE_CHANNEL_PREALLOC) at the beginning of a conference...
struct ast_stream_topology * ast_channel_get_stream_topology(const struct ast_channel *chan)
Retrieve the topology of streams on a channel.
void ast_slinfactory_flush(struct ast_slinfactory *sf)
Flush the contents of a slinfactory.
unsigned int remb_send_interval
struct ast_stream_topology * topology
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
static int softmix_bridge_create(struct ast_bridge *bridge)
Function called when a bridge is created.
unsigned int internal_mixing_interval
The mixing interval indicates how quickly softmix mixing should occur to mix audio.
unsigned int talking_threshold
unsigned int default_sample_size
#define AST_VECTOR_ELEM_DEFAULT_CMP(elem, value)
Default comparator for AST_VECTOR_REMOVE_ELEM_UNORDERED()
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
unsigned int binaural_init
unsigned int binaural_pos
static void sfu_topologies_on_join(struct ast_bridge *bridge, struct ast_bridge_channel *joiner)
Issue channel stream topology change requests.
struct ast_bridge_video_mode video_mode
const char * ast_codec_media_type2str(enum ast_media_type type)
Conversion function to take a media type and turn it into a string.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
An object that represents data received in a feedback report.
Set when the stream has been removed/declined.
int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
Feed audio into a slinfactory.
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Structure used to transport a message through the frame core.
short our_buf[MAX_DATALEN]
struct ast_timer * ast_timer_open(void)
Open a timer.
static struct softmix_remb_collector * remb_collector_alloc(void)
Allocate a REMB collector.
#define SCOPE_EXIT_LOG(__log_level,...)
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
#define SOFTMIX_MIN_SAMPLE_RATE
struct timeval last_video_update
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
struct ast_frame * ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f, int consume)
translates one or more frames Apply an input frame into the translator and receive zero or one output...
Set when the stream is not sending OR receiving media.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
void softmix_process_write_binaural_audio(struct softmix_channel *sc, unsigned int default_sample_size)
Writes the binaural audio to a channel.
struct ast_rtp_rtcp_feedback_remb remb
int ast_channel_request_stream_topology_change(struct ast_channel *chan, struct ast_stream_topology *topology, void *change_source)
Request that the stream topology of a channel change.
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)
Append a stream to the topology.
static void map_source_to_destinations(const char *source_channel_name, size_t bridge_stream_position, struct ast_bridge_channels_list *participants, int source_channel_stream_position)
Map a source stream to all of its destination streams.
#define DEFAULT_SOFTMIX_SILENCE_THRESHOLD
Default time in ms of silence necessary to declare talking stopped by the bridge. ...
Out-of-call text message support.
int ast_bridge_queue_everyone_else(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
Queue the given frame to everyone else.
void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
Set the current negotiated formats of a stream.
short final_buf[MAX_DATALEN]
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
int ast_stream_topology_set_stream(struct ast_stream_topology *topology, unsigned int position, struct ast_stream *stream)
Set a specific position in a topology.
struct ast_format * dst_format
struct ast_bridge_softmix softmix
unsigned int ast_slinfactory_available(const struct ast_slinfactory *sf)
Retrieve number of samples currently in a slinfactory.
enum ast_bridge_video_sfu_remb_behavior remb_behavior
static void softmix_bridge_destroy(struct ast_bridge *bridge)
Function called when a bridge is destroyed.
struct ast_vector_int to_bridge
struct ast_frame_subclass subclass
int ast_set_write_format_interleaved_stereo(struct ast_channel *chan, struct ast_format *format)
Sets write format for a channel. All internal data will than be handled in an interleaved format...
unsigned int silence_threshold
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
int ast_set_read_format_path(struct ast_channel *chan, struct ast_format *raw_format, struct ast_format *core_format)
Set specific read path on channel.
struct softmix_channel::@95 video_sources
unsigned int sample_rates[16]
char name[0]
Name for the stream within the context of the channel it is on.
#define DEFAULT_SOFTMIX_INTERVAL
Interval at which mixing will take place. Valid options are 10, 20, and 40.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
#define SOFTMIX_SAMPLES(rate, interval)
Number of samples we are dealing with.
#define SOFTMIX_BINAURAL_SAMPLE_RATE
#define ast_str_tmp(init_len, __expr)
Provides a temporary ast_str and returns a copy of its buffer.
static void cleanup(void)
Clean up any old apps that we don't need any more.
const char * ast_stream_topology_to_str(const struct ast_stream_topology *topology, struct ast_str **buf)
Get a string representing the topology for debugging/display purposes.
#define ast_bridge_channel_lock(bridge_channel)
Lock the bridge_channel.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
struct ast_trans_pvt * ast_translator_build_path(struct ast_format *dest, struct ast_format *source)
Builds a translator path Build a path (possibly NULL) from source to dest.
int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
Waits for input on an fd.
#define BINAURAL_MIXING_INTERVAL
enum ast_media_type type
The type of media the stream is handling.
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
static void softmix_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
Function called when a channel is unsuspended from the bridge.
struct ast_format * read_slin_format
int ast_bridge_channel_notify_talking(struct ast_bridge_channel *bridge_channel, int started_talking)
Lets the bridging indicate when a bridge channel has stopped or started talking.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
unsigned int maximum_rate
#define ast_debug(level,...)
Log a DEBUG message.
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
unsigned int num_at_internal_rate
const struct ast_format_cap * ast_stream_get_formats(const struct ast_stream *stream)
Get the current negotiated formats of a stream.
void set_binaural_data_leave(struct convolve_data *data, unsigned int pos, unsigned int default_sample_size)
Removes a channel from the binaural conference bridge. Marks the position in the virtual room as unus...
void ast_slinfactory_destroy(struct ast_slinfactory *sf)
Destroy the contents of a slinfactory.
struct ast_format * write_format
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set the minimum average magnitude threshold to determine talking by the DSP.
#define ast_bridge_technology_register(technology)
See __ast_bridge_technology_register()
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
static int is_video_dest(const struct ast_stream *stream, const char *source_channel_name, int source_channel_stream_position)
Determine if a stream is a video destination stream.
#define ast_bridge_channel_unlock(bridge_channel)
Unlock the bridge_channel.
struct ast_vector_int to_channel
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
int ast_slinfactory_init_with_format(struct ast_slinfactory *sf, struct ast_format *slin_out)
Initialize a slinfactory.
void free_convolve_data(struct convolve_data *data)
Frees all channels and data needed for binaural audio processing.
Structure that contains information about a bridge.
int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
Acknowledge a timer event.
Set when the stream is sending and receiving media.
int ast_bridge_technology_unregister(struct ast_bridge_technology *technology)
Unregister a bridge technology from use.
struct ast_frame write_frame
struct ast_format * slin_src
Support for dynamic strings.
Default structure for translators, with the basic fields and buffers, all allocated as part of the sa...
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
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.
Structure which contains per-channel mixing information.
void create_binaural_frame(struct ast_bridge_channel *bridge_channel, struct softmix_channel *sc, int16_t *bin_buf, int16_t *ann_buf, unsigned int softmix_datalen, unsigned int softmix_samples, int16_t *buf)
Creates a frame out of binaural audio data.
struct ast_bridge_tech_optimizations tech_args
int ast_bridge_is_video_src(struct ast_bridge *bridge, struct ast_channel *chan)
Determine if a channel is a video src for the bridge.
const char * ast_msg_data_get_attribute(struct ast_msg_data *msg, enum ast_msg_data_attribute_type attribute_type)
Get attribute from ast_msg_data.
struct softmix_bridge_data::@96 remb_collectors
void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause)
Set bridge channel state to leave bridge (if not leaving already).
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
struct ast_slinfactory factory
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Set when the stream is sending media only.
union ast_frame::@224 data
#define ast_calloc(num, len)
A wrapper for calloc()
struct ast_bridge * bridge
Bridge pointer passed to the softmix mixing thread.
int energy_history_cur_slot
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
struct ast_frame * out_frame
struct video_follow_talker_data video_talker
struct ast_rtp_rtcp_feedback_remb remb
unsigned int frame_ending
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
static int is_video_source(const struct ast_stream *stream)
Determine if a stream is a video source stream.
unsigned int video_update_discard
Module has failed to load, may be in an inconsistent state.
struct ast_trans_pvt * trans_pvt
Vector container support.
unsigned int talking
TRUE if a channel is talking.
unsigned int num_channels[16]
int set_binaural_data_join(struct convolve_data *data, unsigned int default_sample_size)
Joins a channel into a virtual enviroment build with the help of binaural synthesis.
void * tech_pvt
Private information unique to the bridge technology.
int ast_timer_fd(const struct ast_timer *handle)
Get a poll()-able file descriptor for a timer.
int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
Set the timing tick rate.
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
char * ast_frame_type2str(enum ast_frame_type frame_type, char *ftype, size_t len)
Copy the discription of a frame type into the provided string.
struct timeval last_remb_update
unsigned int send_sdp_label
static void remb_enable_collection(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, size_t bridge_stream_position)
Setup REMB collection for a particular bridge stream and channel.
struct ast_stream_topology * ast_stream_topology_clone(const struct ast_stream_topology *topology)
Create a deep clone of an existing stream topology.
#define ast_bridge_lock(bridge)
Lock the bridge.
int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *fr)
Write a frame to the specified bridge_channel.
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
struct ast_bridge_channels_list channels
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
struct ast_channel * chan
Structure that contains information regarding a channel in a bridge.
struct ast_stream * ast_stream_alloc(const char *name, enum ast_media_type type)
Create a new media stream representation.
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
void add_binaural_mixing(struct ast_bridge *bridge, struct softmix_bridge_data *softmix_data, unsigned int softmix_samples, struct softmix_mixing_array *mixing_array, struct softmix_channel *sc, const char *channel_name)
Processes audio data with the binaural synthesis and adds the result to the mixing array...
struct ast_stream * ast_stream_clone(const struct ast_stream *stream, const char *name)
Create a deep clone of an existing stream.
struct convolve_data convolve
Structure that is the essence of a bridge technology.
unsigned int num_above_internal_rate
struct ast_rtp_rtcp_feedback feedback
const char * ast_stream_state2str(enum ast_stream_state state)
Convert the state of a stream into a string.
int ast_stream_set_metadata(struct ast_stream *stream, const char *m_key, const char *value)
Set a stream metadata value.
#define AST_VECTOR_REPLACE(vec, idx, elem)
Replace an element at a specific position in a vector, growing the vector if needed.
void ast_bridge_channel_stream_map(struct ast_bridge_channel *bridge_channel)
Maps a channel's stream topology to and from the bridge.
Data structure associated with a single frame of data.
#define AST_RTP_RTCP_PSFB
int ast_slinfactory_read(struct ast_slinfactory *sf, short *buf, size_t samples)
Read samples from a slinfactory.
#define AST_TEST_DEFINE(hdr)
void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct ast_channel *chan, int talker_energy, int is_keyframe)
Update information about talker energy for talker src video mode.
struct ast_dsp * ast_dsp_new_with_rate(unsigned int sample_rate)
Allocates a new dsp with a specific internal sample rate used during processing.
unsigned int is_announcement
unsigned int drop_silence
ast_media_type
Types of media.
int energy_history[DEFAULT_ENERGY_HISTORY_LEN]
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
enum ast_frame_type frametype
static void softmix_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
Function called when a channel leaves the bridge.
struct ast_format * format
static void softmix_bridge_stream_topology_changed(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
stream_topology_changed callback
void ast_stream_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
const char * ast_stream_get_name(const struct ast_stream *stream)
Get the name of a stream.
#define ASTERISK_GPL_KEY
The text the key() function should return.
unsigned int internal_sample_rate
The internal sample rate softmix uses to mix channels.
#define DEFAULT_SOFTMIX_TALKING_THRESHOLD
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
unsigned int highest_supported_rate
static int softmix_mixing_loop(struct ast_bridge *bridge)
Mixing loop.
Integer vector definition.
unsigned int maximum_sample_rate
The maximum sample rate softmix uses to mix channels.
unsigned int num_channels
Set when the stream is receiving media only.
int ast_bridge_number_video_src(struct ast_bridge *bridge)
Returns the number of video sources currently active in the bridge.
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
struct softmix_remb_collector * remb_collector
void ast_translator_free_path(struct ast_trans_pvt *tr)
Frees a translator path Frees the given translator path structure.
void binaural_mixing(struct ast_bridge *bridge, struct softmix_bridge_data *softmix_data, struct softmix_mixing_array *mixing_array, int16_t *bin_buf, int16_t *ann_buf)
Mixes all binaural audio data contained in the mixing array.
#define SOFTMIX_DATALEN(rate, interval)
Size of the buffer used for sample manipulation.
unsigned int binaural_active
#define SOFTMIX_STAT_INTERVAL
Number of mixing iterations to perform between gathering statistics.
#define AST_RTP_RTCP_FMT_REMB