Asterisk - The Open Source Telephony Project GIT-master-a358458
Data Structures | Macros | Functions | Variables
bridge_softmix.c File Reference

Multi-party software based channel mixing. More...

#include "asterisk.h"
#include <math.h>
#include "asterisk/stream.h"
#include "asterisk/test.h"
#include "asterisk/vector.h"
#include "asterisk/message.h"
#include "bridge_softmix/include/bridge_softmix_internal.h"
Include dependency graph for bridge_softmix.c:

Go to the source code of this file.

Data Structures

struct  softmix_remb_collector
 
struct  softmix_stats
 
struct  softmix_translate_helper
 
struct  softmix_translate_helper_entry
 

Macros

#define DEFAULT_SOFTMIX_INTERVAL   20
 Interval at which mixing will take place. Valid options are 10, 20, and 40. More...
 
#define DEFAULT_SOFTMIX_SILENCE_THRESHOLD   2500
 Default time in ms of silence necessary to declare talking stopped by the bridge. More...
 
#define DEFAULT_SOFTMIX_TALKING_THRESHOLD   160
 
#define SOFTBRIDGE_VIDEO_DEST_LEN   strlen(SOFTBRIDGE_VIDEO_DEST_PREFIX)
 
#define SOFTBRIDGE_VIDEO_DEST_PREFIX   "softbridge_dest"
 
#define SOFTBRIDGE_VIDEO_DEST_SEPARATOR   '_'
 
#define SOFTMIX_DATALEN(rate, interval)   ((rate/50) * (interval / 10))
 Size of the buffer used for sample manipulation. More...
 
#define SOFTMIX_MIN_SAMPLE_RATE   8000 /* 8 kHz sample rate */
 
#define SOFTMIX_SAMPLES(rate, interval)   (SOFTMIX_DATALEN(rate, interval) / 2)
 Number of samples we are dealing with. More...
 
#define SOFTMIX_STAT_INTERVAL   100
 Number of mixing iterations to perform between gathering statistics. More...
 

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, int binaural_active)
 
static int append_all_streams (struct ast_stream_topology *dest, const struct ast_stream_topology *source)
 
static int append_source_stream (struct ast_stream_topology *dest, const char *channel_name, const char *sdp_label, struct ast_stream *stream, int index)
 
static int append_source_streams (struct ast_stream_topology *dest, const char *channel_name, const char *sdp_label, const struct ast_stream_topology *source)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static void clear_talking (struct ast_bridge_channel *bridge_channel)
 
static void gather_softmix_stats (struct softmix_stats *stats, const struct softmix_bridge_data *softmix_data, struct ast_bridge_channel *bridge_channel)
 
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. More...
 
static int is_video_source (const struct ast_stream *stream)
 Determine if a stream is a video source stream. More...
 
static int load_module (void)
 
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. More...
 
static void remb_collect_report (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct softmix_bridge_data *softmix_data, struct softmix_channel *sc)
 
static void remb_collect_report_all (struct ast_bridge *bridge, struct softmix_bridge_data *softmix_data, float bitrate)
 
static struct softmix_remb_collectorremb_collector_alloc (void)
 Allocate a REMB collector. More...
 
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. More...
 
static void remb_send_report (struct ast_bridge_channel *bridge_channel, struct softmix_bridge_data *softmix_data, struct softmix_channel *sc)
 
static int remove_all_original_streams (struct ast_stream_topology *dest, const struct ast_stream_topology *source, const struct ast_stream_topology *original)
 
static int remove_destination_streams (struct ast_stream_topology *topology, const char *channel_name)
 
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)
 
static void sfu_topologies_on_join (struct ast_bridge *bridge, struct ast_bridge_channel *joiner)
 Issue channel stream topology change requests. More...
 
static int sfu_topologies_on_leave (struct ast_bridge_channel *leaver, struct ast_bridge_channels_list *participants)
 
static void sfu_topologies_on_source_change (struct ast_bridge *bridge, struct ast_bridge_channel *source)
 
static void softmix_bridge_check_voice (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
 
static int softmix_bridge_create (struct ast_bridge *bridge)
 Function called when a bridge is created. More...
 
static void softmix_bridge_data_destroy (struct softmix_bridge_data *softmix_data)
 
static void softmix_bridge_destroy (struct ast_bridge *bridge)
 Function called when a bridge is destroyed. More...
 
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. More...
 
static void softmix_bridge_leave (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
 Function called when a channel leaves the bridge. More...
 
static void softmix_bridge_stop (struct ast_bridge *bridge)
 
static void softmix_bridge_stream_sources_update (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct softmix_channel *sc)
 
static void softmix_bridge_stream_topology_changed (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
 stream_topology_changed callback More...
 
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. More...
 
static int softmix_bridge_write (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 
static int softmix_bridge_write_control (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 
static void softmix_bridge_write_rtcp (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 
static void softmix_bridge_write_text (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 
static void softmix_bridge_write_video (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 
static void softmix_bridge_write_voice (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
 
static void softmix_mixing_array_destroy (struct softmix_mixing_array *mixing_array, unsigned int binaural_active)
 
static int softmix_mixing_array_grow (struct softmix_mixing_array *mixing_array, unsigned int num_entries, unsigned int binaural_active)
 
static int softmix_mixing_array_init (struct softmix_mixing_array *mixing_array, unsigned int starting_num_entries, unsigned int binaural_active)
 
static int softmix_mixing_loop (struct ast_bridge *bridge)
 Mixing loop. More...
 
static void * softmix_mixing_thread (void *data)
 
static void softmix_pass_video_top_priority (struct ast_bridge *bridge, struct ast_frame *frame)
 
static void softmix_poke_thread (struct softmix_bridge_data *softmix_data)
 
static int16_tsoftmix_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, unsigned int default_sample_size)
 
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_entrysoftmix_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, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_bridge_technology softmix_bridge
 

Detailed Description

Multi-party software based channel mixing.

Author
Joshua Colp jcolp.nosp@m.@dig.nosp@m.ium.c.nosp@m.om
David Vossel dvoss.nosp@m.el@d.nosp@m.igium.nosp@m..com

Definition in file bridge_softmix.c.

Macro Definition Documentation

◆ DEFAULT_SOFTMIX_INTERVAL

#define DEFAULT_SOFTMIX_INTERVAL   20

Interval at which mixing will take place. Valid options are 10, 20, and 40.

Definition at line 48 of file bridge_softmix.c.

◆ DEFAULT_SOFTMIX_SILENCE_THRESHOLD

#define DEFAULT_SOFTMIX_SILENCE_THRESHOLD   2500

Default time in ms of silence necessary to declare talking stopped by the bridge.

This is the time at which a channel's own audio will stop getting mixed out of its own write audio stream because it is no longer talking.

Definition at line 66 of file bridge_softmix.c.

◆ DEFAULT_SOFTMIX_TALKING_THRESHOLD

#define DEFAULT_SOFTMIX_TALKING_THRESHOLD   160

Default minimum average magnitude threshold to determine talking by the DSP.

Definition at line 69 of file bridge_softmix.c.

◆ SOFTBRIDGE_VIDEO_DEST_LEN

#define SOFTBRIDGE_VIDEO_DEST_LEN   strlen(SOFTBRIDGE_VIDEO_DEST_PREFIX)

Definition at line 72 of file bridge_softmix.c.

◆ SOFTBRIDGE_VIDEO_DEST_PREFIX

#define SOFTBRIDGE_VIDEO_DEST_PREFIX   "softbridge_dest"

Definition at line 71 of file bridge_softmix.c.

◆ SOFTBRIDGE_VIDEO_DEST_SEPARATOR

#define SOFTBRIDGE_VIDEO_DEST_SEPARATOR   '_'

Definition at line 73 of file bridge_softmix.c.

◆ SOFTMIX_DATALEN

#define SOFTMIX_DATALEN (   rate,
  interval 
)    ((rate/50) * (interval / 10))

Size of the buffer used for sample manipulation.

Definition at line 51 of file bridge_softmix.c.

◆ SOFTMIX_MIN_SAMPLE_RATE

#define SOFTMIX_MIN_SAMPLE_RATE   8000 /* 8 kHz sample rate */

The minimum sample rate of the bridge.

Definition at line 45 of file bridge_softmix.c.

◆ SOFTMIX_SAMPLES

#define SOFTMIX_SAMPLES (   rate,
  interval 
)    (SOFTMIX_DATALEN(rate, interval) / 2)

Number of samples we are dealing with.

Definition at line 54 of file bridge_softmix.c.

◆ SOFTMIX_STAT_INTERVAL

#define SOFTMIX_STAT_INTERVAL   100

Number of mixing iterations to perform between gathering statistics.

Definition at line 57 of file bridge_softmix.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 2894 of file bridge_softmix.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 2894 of file bridge_softmix.c.

◆ analyse_softmix_stats()

static unsigned int analyse_softmix_stats ( struct softmix_stats stats,
struct softmix_bridge_data softmix_data,
int  binaural_active 
)
static

Definition at line 1604 of file bridge_softmix.c.

1606{
1607 int i;
1608
1609 if (binaural_active) {
1611 }
1612
1613 /*
1614 * Re-adjust the internal bridge sample rate if
1615 * 1. The bridge's internal sample rate is locked in at a sample
1616 * rate other than the current sample rate being used.
1617 * 2. two or more channels support a higher sample rate
1618 * 3. no channels support the current sample rate or a higher rate
1619 */
1620 if (stats->locked_rate) {
1621 /* if the rate is locked by the bridge, only update it if it differs
1622 * from the current rate we are using. */
1623 if (softmix_data->internal_rate != stats->locked_rate) {
1624 ast_debug(1, "Locking at new rate. Bridge changed from %u to %u.\n",
1625 softmix_data->internal_rate, stats->locked_rate);
1626 softmix_data->internal_rate = stats->locked_rate;
1627 return 1;
1628 }
1629 } else if (stats->num_above_maximum_rate) {
1630 /* if the bridge has a maximum rate set and channels are above it only
1631 * update if it differs from the current rate we are using. */
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",
1634 softmix_data->internal_rate, stats->maximum_rate);
1635 softmix_data->internal_rate = stats->maximum_rate;
1636 return 1;
1637 }
1638 } else if (stats->num_above_internal_rate >= 2) {
1639 /* the highest rate is just used as a starting point */
1640 unsigned int best_rate = stats->highest_supported_rate;
1641 int best_index = -1;
1642
1643 for (i = 0; i < ARRAY_LEN(stats->num_channels); i++) {
1644 if (stats->num_channels[i]) {
1645 break;
1646 }
1647 if (2 <= stats->num_channels[i]) {
1648 /* Two or more channels support this rate. */
1649 if (best_index == -1
1650 || stats->sample_rates[best_index] < stats->sample_rates[i]) {
1651 /*
1652 * best_rate starts out being the first sample rate
1653 * greater than the internal sample rate that two or
1654 * more channels support.
1655 *
1656 * or
1657 *
1658 * There are multiple rates above the internal rate
1659 * and this rate is higher than the previous rate two
1660 * or more channels support.
1661 */
1662 best_rate = stats->sample_rates[i];
1663 best_index = i;
1664 }
1665 } else if (best_index == -1) {
1666 /*
1667 * It is possible that multiple channels exist with native sample
1668 * rates above the internal sample rate, but none of those channels
1669 * have the same rate in common. In this case, the lowest sample
1670 * rate among those channels is picked. Over time as additional
1671 * statistic runs are made the internal sample rate number will
1672 * adjust to the most optimal sample rate, but it may take multiple
1673 * iterations.
1674 */
1675 best_rate = MIN(best_rate, stats->sample_rates[i]);
1676 }
1677 }
1678
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;
1682 return 1;
1683 } else if (!stats->num_at_internal_rate && !stats->num_above_internal_rate) {
1684 /* In this case, the highest supported rate is actually lower than the internal rate */
1685 ast_debug(1, "All below internal rate. Bridge changed from %u to %u.\n",
1686 softmix_data->internal_rate, stats->highest_supported_rate);
1687 softmix_data->internal_rate = stats->highest_supported_rate;
1688 return 1;
1689 }
1690 return 0;
1691}
#define SOFTMIX_BINAURAL_SAMPLE_RATE
#define ast_debug(level,...)
Log a DEBUG message.
unsigned int sample_rates[16]
unsigned int num_above_internal_rate
unsigned int num_channels[16]
unsigned int highest_supported_rate
unsigned int num_above_maximum_rate
unsigned int locked_rate
unsigned int num_at_internal_rate
unsigned int maximum_rate
#define MIN(a, b)
Definition: utils.h:231
#define ARRAY_LEN(a)
Definition: utils.h:666

References ARRAY_LEN, ast_debug, softmix_stats::highest_supported_rate, softmix_bridge_data::internal_rate, softmix_stats::locked_rate, softmix_stats::maximum_rate, MIN, softmix_stats::num_above_internal_rate, softmix_stats::num_above_maximum_rate, softmix_stats::num_at_internal_rate, softmix_stats::num_channels, softmix_stats::sample_rates, and SOFTMIX_BINAURAL_SAMPLE_RATE.

Referenced by softmix_mixing_loop().

◆ append_all_streams()

static int append_all_streams ( struct ast_stream_topology dest,
const struct ast_stream_topology source 
)
static

Definition at line 566 of file bridge_softmix.c.

568{
569 int i;
570 int dest_index = 0;
571
572 for (i = 0; i < ast_stream_topology_get_count(source); ++i) {
573 struct ast_stream *clone;
574 int added = 0;
575
577 if (!clone) {
578 return -1;
579 }
580
581 /* If we can reuse an existing removed stream then do so */
582 while (dest_index < ast_stream_topology_get_count(dest)) {
583 struct ast_stream *stream = ast_stream_topology_get_stream(dest, dest_index);
584
585 dest_index++;
586
588 /* This cannot fail because dest_index - 1 is less than the
589 * current count in dest. */
590 ast_stream_topology_set_stream(dest, dest_index - 1, clone);
591 added = 1;
592 break;
593 }
594 }
595
596 /* If no removed stream exists that we took the place of append the stream */
597 if (!added && ast_stream_topology_append_stream(dest, clone) < 0) {
598 ast_stream_free(clone);
599 return -1;
600 }
601 }
602
603 return 0;
604}
#define NULL
Definition: resample.c:96
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.
Definition: stream.c:796
@ AST_STREAM_STATE_REMOVED
Set when the stream has been removed/declined.
Definition: stream.h:78
int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)
Append a stream to the topology.
Definition: stream.c:748
struct ast_stream * ast_stream_clone(const struct ast_stream *stream, const char *name)
Create a deep clone of an existing stream.
Definition: stream.c:257
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
Definition: stream.c:292

References ast_stream_clone(), ast_stream_free(), ast_stream_get_state(), AST_STREAM_STATE_REMOVED, ast_stream_topology_append_stream(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), ast_stream_topology_set_stream(), and NULL.

Referenced by sfu_topologies_on_join(), sfu_topologies_on_source_change(), and softmix_bridge_stream_sources_update().

◆ append_source_stream()

static int append_source_stream ( struct ast_stream_topology dest,
const char *  channel_name,
const char *  sdp_label,
struct ast_stream stream,
int  index 
)
static

Definition at line 503 of file bridge_softmix.c.

506{
507 char *stream_clone_name = NULL;
508 struct ast_stream *stream_clone;
509
510 /* We use the stream topology index for the stream to uniquely identify and recognize it.
511 * This is guaranteed to remain the same across renegotiation of the source channel and
512 * ensures that the stream name is unique.
513 */
514 if (ast_asprintf(&stream_clone_name, "%s%c%s%c%d", SOFTBRIDGE_VIDEO_DEST_PREFIX,
516 index) < 0) {
517 return -1;
518 }
519
520 stream_clone = ast_stream_clone(stream, stream_clone_name);
521 ast_free(stream_clone_name);
522 if (!stream_clone) {
523 return -1;
524 }
525
526 /* Sends an "a:label" attribute in the SDP for participant event correlation */
527 if (!ast_strlen_zero(sdp_label)) {
528 ast_stream_set_metadata(stream_clone, "SDP:LABEL", sdp_label);
529 }
530
531 /* We will be sending them a stream and not expecting anything in return */
533
534 if (ast_stream_topology_append_stream(dest, stream_clone) < 0) {
535 ast_stream_free(stream_clone);
536 return -1;
537 }
538
539 return 0;
540}
#define ast_free(a)
Definition: astmm.h:180
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define SOFTBRIDGE_VIDEO_DEST_PREFIX
#define SOFTBRIDGE_VIDEO_DEST_SEPARATOR
int ast_stream_set_metadata(struct ast_stream *stream, const char *m_key, const char *value)
Set a stream metadata value.
Definition: stream.c:460
@ AST_STREAM_STATE_SENDONLY
Set when the stream is sending media only.
Definition: stream.h:86
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65

References ast_asprintf, ast_free, ast_stream_clone(), ast_stream_free(), ast_stream_set_metadata(), ast_stream_set_state(), AST_STREAM_STATE_SENDONLY, ast_stream_topology_append_stream(), ast_strlen_zero(), NULL, SOFTBRIDGE_VIDEO_DEST_PREFIX, and SOFTBRIDGE_VIDEO_DEST_SEPARATOR.

Referenced by append_source_streams(), and softmix_bridge_stream_sources_update().

◆ append_source_streams()

static int append_source_streams ( struct ast_stream_topology dest,
const char *  channel_name,
const char *  sdp_label,
const struct ast_stream_topology source 
)
static

Definition at line 543 of file bridge_softmix.c.

546{
547 int i;
548
549 for (i = 0; i < ast_stream_topology_get_count(source); ++i) {
550 struct ast_stream *stream;
551
552 stream = ast_stream_topology_get_stream(source, i);
553
554 if (!is_video_source(stream)) {
555 continue;
556 }
557
558 if (append_source_stream(dest, channel_name, sdp_label, stream, i)) {
559 return -1;
560 }
561 }
562
563 return 0;
564}
static int append_source_stream(struct ast_stream_topology *dest, const char *channel_name, const char *sdp_label, struct ast_stream *stream, int index)
static int is_video_source(const struct ast_stream *stream)
Determine if a stream is a video source stream.

References append_source_stream(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), and is_video_source().

Referenced by sfu_topologies_on_join(), and sfu_topologies_on_source_change().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 2894 of file bridge_softmix.c.

◆ clear_talking()

static void clear_talking ( struct ast_bridge_channel bridge_channel)
static

Definition at line 1035 of file bridge_softmix.c.

1036{
1037 struct softmix_channel *sc = bridge_channel->tech_pvt;
1038
1039 if (sc->talking) {
1040 ast_mutex_lock(&sc->lock);
1042 sc->talking = 0;
1043 ast_mutex_unlock(&sc->lock);
1044
1045 /* Notify that we are no longer talking. */
1046 ast_bridge_channel_notify_talking(bridge_channel, 0);
1047 }
1048}
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 ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
void ast_slinfactory_flush(struct ast_slinfactory *sf)
Flush the contents of a slinfactory.
Definition: slinfactory.c:204
void * tech_pvt
Private information unique to the bridge technology.
Structure which contains per-channel mixing information.
unsigned int talking
TRUE if a channel is talking.
struct ast_slinfactory factory

References ast_bridge_channel_notify_talking(), ast_mutex_lock, ast_mutex_unlock, ast_slinfactory_flush(), softmix_channel::factory, softmix_channel::lock, softmix_channel::talking, and ast_bridge_channel::tech_pvt.

Referenced by softmix_bridge_check_voice(), and softmix_bridge_write_control().

◆ gather_softmix_stats()

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 1560 of file bridge_softmix.c.

1563{
1564 int channel_native_rate;
1565
1566 /* Gather stats about channel sample rates. */
1567 ast_channel_lock(bridge_channel->chan);
1568 channel_native_rate = MAX(SOFTMIX_MIN_SAMPLE_RATE,
1570 ast_channel_unlock(bridge_channel->chan);
1571
1572 if (stats->highest_supported_rate < channel_native_rate) {
1573 stats->highest_supported_rate = channel_native_rate;
1574 }
1575 if (stats->maximum_rate && stats->maximum_rate < channel_native_rate) {
1576 stats->num_above_maximum_rate++;
1577 } else if (softmix_data->internal_rate < channel_native_rate) {
1578 int i;
1579
1580 for (i = 0; i < ARRAY_LEN(stats->sample_rates); i++) {
1581 if (stats->sample_rates[i] == channel_native_rate) {
1582 stats->num_channels[i]++;
1583 break;
1584 } else if (!stats->sample_rates[i]) {
1585 stats->sample_rates[i] = channel_native_rate;
1586 stats->num_channels[i]++;
1587 break;
1588 }
1589 }
1590 stats->num_above_internal_rate++;
1591 } else if (softmix_data->internal_rate == channel_native_rate) {
1592 stats->num_at_internal_rate++;
1593 }
1594}
#define SOFTMIX_MIN_SAMPLE_RATE
struct ast_format * ast_channel_rawreadformat(struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2922
#define ast_channel_unlock(chan)
Definition: channel.h:2923
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition: format.c:379
struct ast_channel * chan
#define MAX(a, b)
Definition: utils.h:233

References ARRAY_LEN, ast_channel_lock, ast_channel_rawreadformat(), ast_channel_unlock, ast_format_get_sample_rate(), ast_bridge_channel::chan, softmix_stats::highest_supported_rate, softmix_bridge_data::internal_rate, MAX, softmix_stats::maximum_rate, softmix_stats::num_above_internal_rate, softmix_stats::num_above_maximum_rate, softmix_stats::num_at_internal_rate, softmix_stats::num_channels, softmix_stats::sample_rates, and SOFTMIX_MIN_SAMPLE_RATE.

Referenced by softmix_mixing_loop().

◆ is_video_dest()

static int is_video_dest ( const struct ast_stream stream,
const char *  source_channel_name,
int  source_channel_stream_position 
)
static

Determine if a stream is a video destination stream.

A source channel name can be provided to narrow this to a destination stream for a particular source channel. Further, a source stream name can be provided to narrow this to a particular source stream's destination. However, empty strings can be provided to match any destination video stream, regardless of source channel or source stream.

Parameters
streamThe stream to test
source_channel_nameThe name of a source video channel to match
source_channel_stream_positionThe position of the video on the source channel
Return values
1The stream is a video destination stream
0The stream is not a video destination stream

Definition at line 466 of file bridge_softmix.c.

468{
469 char *dest_video_name;
470 size_t dest_video_name_len;
471
474 return 0;
475 }
476
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;
482 }
483
484 dest_video_name = ast_alloca(dest_video_name_len);
485 if (source_channel_stream_position != -1) {
486 /* We are looking for an exact stream position */
487 snprintf(dest_video_name, dest_video_name_len, "%s%c%s%c%d",
489 source_channel_name, SOFTBRIDGE_VIDEO_DEST_SEPARATOR,
490 source_channel_stream_position);
491 return !strcmp(ast_stream_get_name(stream), dest_video_name);
492 }
493 snprintf(dest_video_name, dest_video_name_len, "%s%c%s",
495 source_channel_name);
496 } else {
497 dest_video_name = SOFTBRIDGE_VIDEO_DEST_PREFIX;
498 }
499
500 return !strncmp(ast_stream_get_name(stream), dest_video_name, dest_video_name_len - 1);
501}
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define SOFTBRIDGE_VIDEO_DEST_LEN
@ AST_MEDIA_TYPE_VIDEO
Definition: codec.h:33
const char * ast_stream_get_name(const struct ast_stream *stream)
Get the name of a stream.
Definition: stream.c:309
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316

References ast_alloca, AST_MEDIA_TYPE_VIDEO, ast_stream_get_name(), ast_stream_get_state(), ast_stream_get_type(), AST_STREAM_STATE_REMOVED, ast_strlen_zero(), SOFTBRIDGE_VIDEO_DEST_LEN, SOFTBRIDGE_VIDEO_DEST_PREFIX, and SOFTBRIDGE_VIDEO_DEST_SEPARATOR.

Referenced by map_source_to_destinations(), remove_destination_streams(), and softmix_bridge_stream_sources_update().

◆ is_video_source()

static int is_video_source ( const struct ast_stream stream)
static

Determine if a stream is a video source stream.

Parameters
streamThe stream to test
Return values
1The stream is a video source
0The stream is not a video source

Definition at line 439 of file bridge_softmix.c.

440{
445 return 1;
446 }
447
448 return 0;
449}

References AST_MEDIA_TYPE_VIDEO, ast_stream_get_name(), ast_stream_get_state(), ast_stream_get_type(), AST_STREAM_STATE_REMOVED, SOFTBRIDGE_VIDEO_DEST_LEN, and SOFTBRIDGE_VIDEO_DEST_PREFIX.

Referenced by append_source_streams(), softmix_bridge_stream_sources_update(), and softmix_bridge_stream_topology_changed().

◆ load_module()

static int load_module ( void  )
static

Definition at line 2883 of file bridge_softmix.c.

2884{
2886 unload_module();
2888 }
2889 AST_TEST_REGISTER(sfu_append_source_streams);
2890 AST_TEST_REGISTER(sfu_remove_destination_streams);
2892}
static struct ast_bridge_technology softmix_bridge
static int unload_module(void)
#define ast_bridge_technology_register(technology)
See __ast_bridge_technology_register()
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define AST_TEST_REGISTER(cb)
Definition: test.h:127

References ast_bridge_technology_register, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, AST_TEST_REGISTER, softmix_bridge, and unload_module().

◆ map_source_to_destinations()

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 
)
static

Map a source stream to all of its destination streams.

Parameters
source_channel_nameName of channel where the source stream originates
bridge_stream_positionThe slot in the bridge where source video will come from
participantsThe bridge_channels in the bridge
source_channel_stream_positionThe position of the stream on the source channel

Definition at line 2168 of file bridge_softmix.c.

2170{
2171 struct ast_bridge_channel *participant;
2172
2173 AST_LIST_TRAVERSE(participants, participant, entry) {
2174 int i;
2175 struct ast_stream_topology *topology;
2176
2177 if (!strcmp(source_channel_name, ast_channel_name(participant->chan))) {
2178 continue;
2179 }
2180
2181 ast_bridge_channel_lock(participant);
2182 ast_channel_lock(participant->chan);
2183 topology = ast_channel_get_stream_topology(participant->chan);
2184
2185 for (i = 0; i < ast_stream_topology_get_count(topology); ++i) {
2186 struct ast_stream *stream;
2187
2188 stream = ast_stream_topology_get_stream(topology, i);
2189 if (is_video_dest(stream, source_channel_name, source_channel_stream_position)) {
2190 struct softmix_channel *sc = participant->tech_pvt;
2191
2192 AST_VECTOR_REPLACE(&participant->stream_map.to_channel, bridge_stream_position, i);
2193 AST_VECTOR_APPEND(&sc->video_sources, bridge_stream_position);
2194 break;
2195 }
2196 }
2197 ast_channel_unlock(participant->chan);
2198 ast_bridge_channel_unlock(participant);
2199 }
2200}
#define ast_bridge_channel_unlock(bridge_channel)
Unlock the bridge_channel.
#define ast_bridge_channel_lock(bridge_channel)
Lock the bridge_channel.
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.
const char * ast_channel_name(const struct ast_channel *chan)
struct ast_stream_topology * ast_channel_get_stream_topology(const struct ast_channel *chan)
Retrieve the topology of streams on a channel.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
Structure that contains information regarding a channel in a bridge.
struct ast_bridge_channel::@198 stream_map
struct ast_vector_int to_channel
Definition: search.h:40
struct softmix_channel::@101 video_sources
#define AST_VECTOR_REPLACE(vec, idx, elem)
Replace an element at a specific position in a vector, growing the vector if needed.
Definition: vector.h:284
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256

References ast_bridge_channel_lock, ast_bridge_channel_unlock, ast_channel_get_stream_topology(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, AST_LIST_TRAVERSE, ast_stream_topology_get_count(), ast_stream_topology_get_stream(), AST_VECTOR_APPEND, AST_VECTOR_REPLACE, ast_bridge_channel::chan, is_video_dest(), ast_bridge_channel::stream_map, ast_bridge_channel::tech_pvt, ast_bridge_channel::to_channel, and softmix_channel::video_sources.

Referenced by softmix_bridge_stream_topology_changed().

◆ remb_collect_report()

static void remb_collect_report ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
struct softmix_bridge_data softmix_data,
struct softmix_channel sc 
)
static

Definition at line 1394 of file bridge_softmix.c.

1396{
1397 int i;
1398 float bitrate;
1399
1400 /* If there are no video sources that we are a receiver of then we have noone to
1401 * report REMB to.
1402 */
1403 if (!AST_VECTOR_SIZE(&sc->video_sources)) {
1404 return;
1405 }
1406
1407 /* We evenly divide the available maximum bitrate across the video sources
1408 * to this receiver so each source gets an equal slice.
1409 */
1410
1413 return;
1414 }
1415
1416 bitrate = (sc->remb.br_mantissa << sc->remb.br_exp) / AST_VECTOR_SIZE(&sc->video_sources);
1417
1418 /* If this receiver has no bitrate yet ignore it */
1419 if (!bitrate) {
1420 return;
1421 }
1422
1423 /* If we are using the "all" variants then we should use the bridge bitrate to store information */
1427 remb_collect_report_all(bridge, softmix_data, bitrate);
1428 return;
1429 }
1430
1431 for (i = 0; i < AST_VECTOR_SIZE(&sc->video_sources); ++i) {
1432 struct softmix_remb_collector *collector;
1433
1434 /* The collector will always exist if a video source is in our list */
1435 collector = AST_VECTOR_GET(&softmix_data->remb_collectors, AST_VECTOR_GET(&sc->video_sources, i));
1436
1437 if (!collector->bitrate) {
1438 collector->bitrate = bitrate;
1439 continue;
1440 }
1441
1444 collector->bitrate = (collector->bitrate + bitrate) / 2;
1445 break;
1447 if (bitrate < collector->bitrate) {
1448 collector->bitrate = bitrate;
1449 }
1450 break;
1452 if (bitrate > collector->bitrate) {
1453 collector->bitrate = bitrate;
1454 }
1455 break;
1459 /* These will never actually get hit due to being handled by remb_collect_report_all above */
1460 break;
1462 /* Don't do anything, we've already forced it */
1463 break;
1464 }
1465 }
1466
1467 /* After the report is integrated we reset this to 0 in case they stop producing
1468 * REMB reports.
1469 */
1470 sc->remb.br_mantissa = 0;
1471 sc->remb.br_exp = 0;
1472}
@ AST_BRIDGE_VIDEO_SFU_REMB_LOWEST
Definition: bridge.h:135
@ AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL
Definition: bridge.h:143
@ AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE
Definition: bridge.h:133
@ AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST
Definition: bridge.h:137
@ AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE_ALL
Definition: bridge.h:139
@ AST_BRIDGE_VIDEO_SFU_REMB_FORCE
Definition: bridge.h:145
@ AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL
Definition: bridge.h:141
static void remb_collect_report_all(struct ast_bridge *bridge, struct softmix_bridge_data *softmix_data, float bitrate)
struct ast_bridge_video_mode video_mode
Definition: bridge.h:279
union ast_bridge_video_mode::@189 mode_data
struct ast_bridge_video_sfu_data sfu_data
Definition: bridge.h:165
enum ast_bridge_video_sfu_remb_behavior remb_behavior
Definition: bridge.h:153
struct ast_bridge_softmix softmix
Definition: bridge.h:367
struct softmix_bridge_data::@102 remb_collectors
struct ast_rtp_rtcp_feedback_remb remb
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680

References AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE, AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE_ALL, AST_BRIDGE_VIDEO_SFU_REMB_FORCE, AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST, AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL, AST_BRIDGE_VIDEO_SFU_REMB_LOWEST, AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL, AST_VECTOR_GET, AST_VECTOR_SIZE, softmix_remb_collector::bitrate, softmix_bridge_data::bitrate, ast_rtp_rtcp_feedback_remb::br_exp, ast_rtp_rtcp_feedback_remb::br_mantissa, ast_bridge_video_sfu_data::estimated_bitrate, ast_bridge_video_mode::mode_data, softmix_channel::remb, ast_bridge_video_sfu_data::remb_behavior, remb_collect_report_all(), softmix_bridge_data::remb_collectors, ast_bridge_video_mode::sfu_data, ast_bridge::softmix, ast_bridge_softmix::video_mode, and softmix_channel::video_sources.

Referenced by softmix_mixing_loop().

◆ remb_collect_report_all()

static void remb_collect_report_all ( struct ast_bridge bridge,
struct softmix_bridge_data softmix_data,
float  bitrate 
)
static

Definition at line 1363 of file bridge_softmix.c.

1365{
1366 if (!softmix_data->bitrate) {
1367 softmix_data->bitrate = bitrate;
1368 return;
1369 }
1370
1373 softmix_data->bitrate = (softmix_data->bitrate + bitrate) / 2;
1374 break;
1376 if (bitrate < softmix_data->bitrate) {
1377 softmix_data->bitrate = bitrate;
1378 }
1379 break;
1381 if (bitrate > softmix_data->bitrate) {
1382 softmix_data->bitrate = bitrate;
1383 }
1384 break;
1389 /* These will never actually get hit due to being handled by remb_collect_report below */
1390 break;
1391 }
1392}

References AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE, AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE_ALL, AST_BRIDGE_VIDEO_SFU_REMB_FORCE, AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST, AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL, AST_BRIDGE_VIDEO_SFU_REMB_LOWEST, AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL, softmix_bridge_data::bitrate, ast_bridge_video_mode::mode_data, ast_bridge_video_sfu_data::remb_behavior, ast_bridge_video_mode::sfu_data, ast_bridge::softmix, and ast_bridge_softmix::video_mode.

Referenced by remb_collect_report().

◆ remb_collector_alloc()

static struct softmix_remb_collector * remb_collector_alloc ( void  )
static

Allocate a REMB collector.

Return values
non-NULLsuccess
NULLfailure

Definition at line 2208 of file bridge_softmix.c.

2209{
2210 struct softmix_remb_collector *collector;
2211
2212 collector = ao2_alloc_options(sizeof(*collector), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
2213 if (!collector) {
2214 return NULL;
2215 }
2216
2217 collector->frame.frametype = AST_FRAME_RTCP;
2219 collector->feedback.fmt = AST_RTP_RTCP_FMT_REMB;
2220 collector->frame.data.ptr = &collector->feedback;
2221 collector->frame.datalen = sizeof(collector->feedback);
2222
2223 return collector;
2224}
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
@ AST_FRAME_RTCP
#define AST_RTP_RTCP_PSFB
Definition: rtp_engine.h:324
#define AST_RTP_RTCP_FMT_REMB
Definition: rtp_engine.h:334
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
unsigned int fmt
Definition: rtp_engine.h:384
struct ast_rtp_rtcp_feedback feedback
struct ast_frame frame

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, AST_FRAME_RTCP, AST_RTP_RTCP_FMT_REMB, AST_RTP_RTCP_PSFB, ast_frame::data, ast_frame::datalen, softmix_remb_collector::feedback, ast_rtp_rtcp_feedback::fmt, softmix_remb_collector::frame, ast_frame::frametype, ast_frame_subclass::integer, NULL, ast_frame::ptr, and ast_frame::subclass.

Referenced by remb_enable_collection().

◆ remb_enable_collection()

static void remb_enable_collection ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
size_t  bridge_stream_position 
)
static

Setup REMB collection for a particular bridge stream and channel.

Parameters
bridgeThe bridge
bridge_channelChannel that is collecting REMB information
bridge_stream_positionThe slot in the bridge where source video comes from

Definition at line 2233 of file bridge_softmix.c.

2235{
2236 struct softmix_channel *sc = bridge_channel->tech_pvt;
2237 struct softmix_bridge_data *softmix_data = bridge->tech_pvt;
2238
2239 if (!sc->remb_collector) {
2241 if (!sc->remb_collector) {
2242 /* This is not fatal. Things will still continue to work but we won't
2243 * produce a REMB report to the sender.
2244 */
2245 return;
2246 }
2247 }
2248
2249 ao2_ref(sc->remb_collector, +1);
2250 if (AST_VECTOR_REPLACE(&softmix_data->remb_collectors, bridge_stream_position,
2251 sc->remb_collector)) {
2252 ao2_ref(sc->remb_collector, -1);
2253 }
2254}
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
static struct softmix_remb_collector * remb_collector_alloc(void)
Allocate a REMB collector.
void * tech_pvt
Definition: bridge.h:357
struct ast_bridge * bridge
Bridge pointer passed to the softmix mixing thread.
struct softmix_remb_collector * remb_collector

References ao2_ref, AST_VECTOR_REPLACE, softmix_bridge_data::bridge, softmix_channel::remb_collector, remb_collector_alloc(), softmix_bridge_data::remb_collectors, ast_bridge::tech_pvt, and ast_bridge_channel::tech_pvt.

Referenced by softmix_bridge_stream_topology_changed().

◆ remb_send_report()

static void remb_send_report ( struct ast_bridge_channel bridge_channel,
struct softmix_bridge_data softmix_data,
struct softmix_channel sc 
)
static

Definition at line 1474 of file bridge_softmix.c.

1476{
1477 float bitrate = softmix_data->bitrate;
1478 int i;
1479 int exp;
1480
1481 if (!sc->remb_collector) {
1482 return;
1483 }
1484
1485 /* If there is no bridge level bitrate fall back to collector level */
1486 if (!bitrate) {
1487 bitrate = sc->remb_collector->bitrate;
1488 sc->remb_collector->bitrate = 0;
1489 }
1490
1491 /* We always do this calculation as even when the bitrate is zero the browser
1492 * still prefers it to be accurate instead of lying.
1493 *
1494 * The mantissa only has 18 bits available, so make sure it fits. Adjust the
1495 * value and exponent for those values that don't.
1496 *
1497 * For example given the following:
1498 *
1499 * bitrate = 123456789.0
1500 * frexp(bitrate, &exp);
1501 *
1502 * 'exp' should now equal 27 (number of bits needed to represent the value). Since
1503 * the mantissa must fit into an 18-bit unsigned integer, and the given bitrate is
1504 * too large to fit, we must subtract 18 from the exponent in order to get the
1505 * number of times the bitrate will fit into that size integer.
1506 *
1507 * exp -= 18;
1508 *
1509 * 'exp' is now equal to 9. Now we can get the mantissa that fits into an 18-bit
1510 * unsigned integer by dividing the bitrate by 2^exp:
1511 *
1512 * mantissa = 123456789.0 / 2^9
1513 *
1514 * This makes the final mantissa equal to 241126 (implicitly cast), which is less
1515 * than 262143 (the max value that can be put into an unsigned 18-bit integer).
1516 * So now we have the following:
1517 *
1518 * exp = 9;
1519 * mantissa = 241126;
1520 *
1521 * If we multiply that back we should come up with something close to the original
1522 * bit rate:
1523 *
1524 * 241126 * 2^9 = 123456512
1525 *
1526 * Precision is lost due to the nature of floating point values. Easier to why from
1527 * the binary:
1528 *
1529 * 241126 * 2^9 = 241126 << 9 = 111010110111100110 << 9 = 111010110111100110000000000
1530 *
1531 * Precision on the "lower" end is lost due to zeros being shifted in. This loss is
1532 * both expected and acceptable.
1533 */
1534 frexp(bitrate, &exp);
1535 exp = exp > 18 ? exp - 18 : 0;
1536
1537 sc->remb_collector->feedback.remb.br_mantissa = bitrate / (1 << exp);
1539
1540 for (i = 0; i < AST_VECTOR_SIZE(&bridge_channel->stream_map.to_bridge); ++i) {
1541 int bridge_num = AST_VECTOR_GET(&bridge_channel->stream_map.to_bridge, i);
1542
1543 /* If this stream is not being provided to the bridge there can be no receivers of it
1544 * so therefore no REMB reports.
1545 */
1546 if (bridge_num == -1) {
1547 continue;
1548 }
1549
1550 /* We need to update the frame with this stream, or else it won't be
1551 * properly routed. We don't use the actual channel stream identifier as
1552 * the bridging core will do the translation from bridge stream identifier to
1553 * channel stream identifier.
1554 */
1555 sc->remb_collector->frame.stream_num = bridge_num;
1557 }
1558}
int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *fr)
Write a frame to the specified bridge_channel.
struct ast_vector_int to_bridge
struct ast_rtp_rtcp_feedback_remb remb
Definition: rtp_engine.h:386

References ast_bridge_channel_queue_frame(), AST_VECTOR_GET, AST_VECTOR_SIZE, softmix_remb_collector::bitrate, softmix_bridge_data::bitrate, ast_rtp_rtcp_feedback_remb::br_exp, ast_rtp_rtcp_feedback_remb::br_mantissa, softmix_remb_collector::feedback, softmix_remb_collector::frame, ast_rtp_rtcp_feedback::remb, softmix_channel::remb_collector, ast_bridge_channel::stream_map, ast_frame::stream_num, and ast_bridge_channel::to_bridge.

Referenced by softmix_mixing_loop().

◆ remove_all_original_streams()

static int remove_all_original_streams ( struct ast_stream_topology dest,
const struct ast_stream_topology source,
const struct ast_stream_topology original 
)
static

Definition at line 1071 of file bridge_softmix.c.

1074{
1075 int i;
1076
1077 for (i = 0; i < ast_stream_topology_get_count(source); ++i) {
1078 struct ast_stream *stream;
1079 int original_index;
1080
1081 stream = ast_stream_topology_get_stream(source, i);
1082
1083 /* Mark the existing stream as removed so we get a new one, this will get
1084 * reused on a subsequent renegotiation.
1085 */
1086 for (original_index = 0; original_index < ast_stream_topology_get_count(original); ++original_index) {
1087 struct ast_stream *original_stream = ast_stream_topology_get_stream(original, original_index);
1088
1089 if (!strcmp(ast_stream_get_name(stream), ast_stream_get_name(original_stream))) {
1090 struct ast_stream *removed;
1091
1092 removed = ast_stream_clone(stream, NULL);
1093 if (!removed) {
1094 return -1;
1095 }
1096
1098
1099 /* The destination topology can only ever contain the same, or more,
1100 * streams than the original so this is safe.
1101 */
1102 if (ast_stream_topology_set_stream(dest, original_index, removed)) {
1103 ast_stream_free(removed);
1104 return -1;
1105 }
1106
1107 break;
1108 }
1109 }
1110 }
1111
1112 return 0;
1113}

References ast_stream_clone(), ast_stream_free(), ast_stream_get_name(), ast_stream_set_state(), AST_STREAM_STATE_REMOVED, ast_stream_topology_get_count(), ast_stream_topology_get_stream(), ast_stream_topology_set_stream(), and NULL.

Referenced by sfu_topologies_on_source_change().

◆ remove_destination_streams()

static int remove_destination_streams ( struct ast_stream_topology topology,
const char *  channel_name 
)
static

Definition at line 775 of file bridge_softmix.c.

777{
778 int i;
779 int stream_removed = 0;
780
781 for (i = 0; i < ast_stream_topology_get_count(topology); ++i) {
782 struct ast_stream *stream;
783
784 stream = ast_stream_topology_get_stream(topology, i);
785
786 if (is_video_dest(stream, channel_name, -1)) {
788 stream_removed = 1;
789 }
790 }
791 return stream_removed;
792}

References ast_stream_set_state(), AST_STREAM_STATE_REMOVED, ast_stream_topology_get_count(), ast_stream_topology_get_stream(), and is_video_dest().

Referenced by sfu_topologies_on_leave().

◆ set_softmix_bridge_data()

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 
)
static

Definition at line 303 of file bridge_softmix.c.

304{
305 struct softmix_channel *sc = bridge_channel->tech_pvt;
306 struct ast_format *slin_format;
307 int setup_fail;
308
309#ifdef BINAURAL_RENDERING
310 if (interval != BINAURAL_MIXING_INTERVAL) {
311 interval = BINAURAL_MIXING_INTERVAL;
312 }
313#endif
314
315 /* The callers have already ensured that sc is never NULL. */
316 ast_assert(sc != NULL);
317
318 slin_format = ast_format_cache_get_slin_by_rate(rate);
319
320 ast_mutex_lock(&sc->lock);
321 if (reset) {
323 ast_dsp_free(sc->dsp);
324 }
325
326 /* Setup write frame parameters */
328 /*
329 * NOTE: The write_frame format holds a reference because translation
330 * could be needed and the format changed to the translated format
331 * for the channel. The translated format may not be a
332 * static cached format.
333 */
334 ao2_replace(sc->write_frame.subclass.format, slin_format);
335 sc->write_frame.data.ptr = sc->final_buf;
336 sc->write_frame.datalen = SOFTMIX_DATALEN(rate, interval);
337 sc->write_frame.samples = SOFTMIX_SAMPLES(rate, interval);
338
339 /* We will store the rate here cause we need to set the data again when a channel is unsuspended */
340 sc->rate = rate;
341
342 /* If the channel will contain binaural data we will set a identifier in the channel
343 * if set_binaural == -1 this is just a sample rate update, will ignore it. */
344 if (set_binaural == 1) {
345 sc->binaural = 1;
346 } else if (set_binaural == 0) {
347 sc->binaural = 0;
348 }
349
350 /* Setting the binaural position. This doesn't require a change of the overlaying channel infos
351 * and doesn't have to be done if we just updating sample rates. */
352 if (binaural_pos_id != -1) {
353 sc->binaural_pos = binaural_pos_id;
354 }
355 if (is_announcement != -1) {
356 sc->is_announcement = is_announcement;
357 }
358
359 /*
360 * NOTE: The read_slin_format does not hold a reference because it
361 * will always be a signed linear format.
362 */
363 sc->read_slin_format = slin_format;
364
365 /* Setup smoother */
366 setup_fail = ast_slinfactory_init_with_format(&sc->factory, slin_format);
367
368 /* set new read and write formats on channel. */
369 ast_channel_lock(bridge_channel->chan);
370 setup_fail |= ast_set_read_format_path(bridge_channel->chan,
371 ast_channel_rawreadformat(bridge_channel->chan), slin_format);
372 ast_channel_unlock(bridge_channel->chan);
373
374 /* If channel contains binaural data we will set it here for the trans_pvt. */
375 if (set_binaural == 1 || (set_binaural == -1 && sc->binaural == 1)) {
376 setup_fail |= ast_set_write_format_interleaved_stereo(bridge_channel->chan, slin_format);
377 } else if (set_binaural == 0) {
378 setup_fail |= ast_set_write_format(bridge_channel->chan, slin_format);
379 }
380
381 /* set up new DSP. This is on the read side only right before the read frame enters the smoother. */
382 sc->dsp = ast_dsp_new_with_rate(rate);
383 if (setup_fail || !sc->dsp) {
384 /* Bad news. Could not setup the channel for softmix. */
387 return;
388 }
389
390 /* we want to aggressively detect silence to avoid feedback */
391 if (bridge_channel->tech_args.talking_threshold) {
393 } else {
395 }
396
398}
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition: astobj2.h:501
@ BRIDGE_CHANNEL_STATE_END
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 SOFTMIX_DATALEN(rate, interval)
Size of the buffer used for sample manipulation.
#define SOFTMIX_SAMPLES(rate, interval)
Number of samples we are dealing with.
#define DEFAULT_SOFTMIX_TALKING_THRESHOLD
#define BINAURAL_MIXING_INTERVAL
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.
Definition: channel.c:5488
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....
Definition: channel.c:5785
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5803
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set the minimum average magnitude threshold to determine talking by the DSP.
Definition: dsp.c:1788
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1783
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.
Definition: dsp.c:1763
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
Definition: format_cache.c:512
@ AST_FRAME_VOICE
int ast_slinfactory_init_with_format(struct ast_slinfactory *sf, struct ast_format *slin_out)
Initialize a slinfactory.
Definition: slinfactory.c:46
void ast_slinfactory_destroy(struct ast_slinfactory *sf)
Destroy the contents of a slinfactory.
Definition: slinfactory.c:58
struct ast_bridge_tech_optimizations tech_args
Definition of a media format.
Definition: format.c:43
struct ast_format * format
short final_buf[MAX_DATALEN]
struct ast_format * read_slin_format
struct ast_frame write_frame
#define ast_assert(a)
Definition: utils.h:739

References ao2_replace, ast_assert, ast_bridge_channel_leave_bridge(), ast_channel_lock, ast_channel_rawreadformat(), ast_channel_unlock, ast_dsp_free(), ast_dsp_new_with_rate(), ast_dsp_set_threshold(), ast_format_cache_get_slin_by_rate(), AST_FRAME_VOICE, ast_mutex_lock, ast_mutex_unlock, ast_set_read_format_path(), ast_set_write_format(), ast_set_write_format_interleaved_stereo(), ast_slinfactory_destroy(), ast_slinfactory_init_with_format(), softmix_channel::binaural, BINAURAL_MIXING_INTERVAL, softmix_channel::binaural_pos, BRIDGE_CHANNEL_STATE_END, 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::is_announcement, softmix_channel::lock, NULL, ast_frame::ptr, softmix_channel::rate, softmix_channel::read_slin_format, ast_frame::samples, SOFTMIX_DATALEN, SOFTMIX_SAMPLES, ast_frame::subclass, ast_bridge_tech_optimizations::talking_threshold, ast_bridge_channel::tech_args, ast_bridge_channel::tech_pvt, and softmix_channel::write_frame.

Referenced by softmix_bridge_join(), and softmix_mixing_loop().

◆ sfu_topologies_on_join()

static void sfu_topologies_on_join ( struct ast_bridge bridge,
struct ast_bridge_channel joiner 
)
static

Issue channel stream topology change requests.

When in SFU mode, each participant needs to be able to send video directly to other participants in the bridge. This means that all participants need to have their topologies updated. The joiner needs to have destination streams for all current participants, and the current participants need to have destinations streams added for the joiner's sources.

Parameters
bridge
joinerThe channel that is joining the softmix bridge

Definition at line 619 of file bridge_softmix.c.

621{
623 struct ast_bridge_channels_list *participants = &bridge->channels;
624 struct ast_bridge_channel *participant;
625 int res;
626 struct softmix_channel *sc;
627 SCOPE_ENTER(3, "%s: \n", ast_channel_name(joiner->chan));
628
629 joiner_video = ast_stream_topology_alloc();
630 if (!joiner_video) {
631 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Couldn't alloc topology\n", ast_channel_name(joiner->chan));
632 }
633
634 sc = joiner->tech_pvt;
635
636 ast_channel_lock(joiner->chan);
637 res = append_source_streams(joiner_video, ast_channel_name(joiner->chan),
641 ast_channel_unlock(joiner->chan);
642
643 if (res || !sc->topology) {
644 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Couldn't append source streams\n", ast_channel_name(joiner->chan));
645 }
646
647 AST_LIST_TRAVERSE(participants, participant, entry) {
648 if (participant == joiner) {
649 continue;
650 }
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),
655 bridge->softmix.send_sdp_label ? ast_channel_uniqueid(participant->chan) : NULL,
657 ast_channel_unlock(participant->chan);
658 if (res) {
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));
661 }
662 }
663
664 ast_trace(-1, "%s: Requesting topology change.\n", ast_channel_name(joiner->chan));
666 if (res) {
667 /* There are conditions under which this is expected so no need to log an ERROR. */
668 SCOPE_EXIT_RTN("%s: Couldn't request topology change\n", ast_channel_name(joiner->chan));
669 }
670
671 AST_LIST_TRAVERSE(participants, participant, entry) {
672 if (participant == joiner) {
673 continue;
674 }
675
676 sc = participant->tech_pvt;
677 ast_trace(-1, "%s: Appending joiner %s\n", ast_channel_name(participant->chan),
678 ast_channel_name(joiner->chan));
679
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));
683 }
684 ast_trace(-1, "%s: Requesting topology change\n", ast_channel_name(participant->chan));
686 if (res) {
687 ast_trace(-1, "%s/%s: Couldn't request topology change\n",
688 ast_channel_name(participant->chan), ast_channel_name(joiner->chan));
689 }
690 }
691
692 SCOPE_EXIT();
693}
static int append_all_streams(struct ast_stream_topology *dest, const struct ast_stream_topology *source)
static int append_source_streams(struct ast_stream_topology *dest, const char *channel_name, const char *sdp_label, const struct ast_stream_topology *source)
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.
Definition: channel.c:10966
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define SCOPE_EXIT_RTN(...)
#define SCOPE_ENTER(level,...)
#define SCOPE_EXIT(...)
#define SCOPE_EXIT_LOG_RTN(__log_level,...)
#define ast_trace(level,...)
#define LOG_ERROR
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition: stream.c:650
void ast_stream_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
Definition: stream.c:743
struct ast_stream_topology * ast_stream_topology_clone(const struct ast_stream_topology *topology)
Create a deep clone of an existing stream topology.
Definition: stream.c:667
unsigned int send_sdp_label
Definition: bridge.h:300
struct ast_bridge_channels_list channels
Definition: bridge.h:363
struct ast_stream_topology * topology
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

References append_all_streams(), append_source_streams(), ast_channel_get_stream_topology(), ast_channel_lock, ast_channel_name(), ast_channel_request_stream_topology_change(), ast_channel_uniqueid(), ast_channel_unlock, AST_LIST_TRAVERSE, ast_stream_topology_alloc(), ast_stream_topology_clone(), ast_stream_topology_free(), ast_trace, ast_bridge_channel::chan, ast_bridge::channels, LOG_ERROR, NULL, RAII_VAR, SCOPE_ENTER, SCOPE_EXIT, SCOPE_EXIT_LOG_RTN, SCOPE_EXIT_RTN, ast_bridge_softmix::send_sdp_label, ast_bridge::softmix, ast_bridge_channel::tech_pvt, and softmix_channel::topology.

Referenced by softmix_bridge_join().

◆ sfu_topologies_on_leave()

static int sfu_topologies_on_leave ( struct ast_bridge_channel leaver,
struct ast_bridge_channels_list participants 
)
static

Definition at line 794 of file bridge_softmix.c.

795{
796 struct ast_bridge_channel *participant;
797 struct softmix_channel *sc;
798
799 AST_LIST_TRAVERSE(participants, participant, entry) {
800 sc = participant->tech_pvt;
802 continue;
803 }
805 }
806
807 sc = leaver->tech_pvt;
810 }
811
812 return 0;
813}
static int remove_destination_streams(struct ast_stream_topology *topology, const char *channel_name)

References ast_channel_name(), ast_channel_request_stream_topology_change(), AST_LIST_TRAVERSE, ast_bridge_channel::chan, NULL, remove_destination_streams(), ast_bridge_channel::tech_pvt, and softmix_channel::topology.

Referenced by softmix_bridge_leave().

◆ sfu_topologies_on_source_change()

static void sfu_topologies_on_source_change ( struct ast_bridge bridge,
struct ast_bridge_channel source 
)
static

Definition at line 1115 of file bridge_softmix.c.

1117{
1118 struct ast_stream_topology *source_video = NULL;
1119 struct ast_bridge_channels_list *participants = &bridge->channels;
1120 struct ast_bridge_channel *participant;
1121 int res;
1122
1123 source_video = ast_stream_topology_alloc();
1124 if (!source_video) {
1125 return;
1126 }
1127
1128 ast_channel_lock(source->chan);
1129 res = append_source_streams(source_video, ast_channel_name(source->chan),
1132 ast_channel_unlock(source->chan);
1133 if (res) {
1134 goto cleanup;
1135 }
1136
1137 AST_LIST_TRAVERSE(participants, participant, entry) {
1138 struct ast_stream_topology *original_topology;
1139 struct softmix_channel *sc;
1140
1141 if (participant == source) {
1142 continue;
1143 }
1144
1145 sc = participant->tech_pvt;
1146
1147 original_topology = ast_stream_topology_clone(sc->topology);
1148 if (!original_topology) {
1149 goto cleanup;
1150 }
1151
1152 /* We add all the source streams back in, if any removed streams are already present they will
1153 * get used first followed by appending new ones.
1154 */
1155 if (append_all_streams(sc->topology, source_video)) {
1156 ast_stream_topology_free(original_topology);
1157 goto cleanup;
1158 }
1159
1160 /* And the original existing streams get marked as removed. This causes the remote side to see
1161 * a new stream for the source streams.
1162 */
1163 if (remove_all_original_streams(sc->topology, source_video, original_topology)) {
1164 ast_stream_topology_free(original_topology);
1165 goto cleanup;
1166 }
1167
1169 ast_stream_topology_free(original_topology);
1170 }
1171
1172cleanup:
1173 ast_stream_topology_free(source_video);
1174}
static int remove_all_original_streams(struct ast_stream_topology *dest, const struct ast_stream_topology *source, const struct ast_stream_topology *original)
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
struct ast_bridge * bridge
Bridge this channel is participating in.

References append_all_streams(), append_source_streams(), ast_channel_get_stream_topology(), ast_channel_lock, ast_channel_name(), ast_channel_request_stream_topology_change(), ast_channel_uniqueid(), ast_channel_unlock, AST_LIST_TRAVERSE, ast_stream_topology_alloc(), ast_stream_topology_clone(), ast_stream_topology_free(), ast_bridge_channel::bridge, ast_bridge_channel::chan, ast_bridge::channels, cleanup(), NULL, remove_all_original_streams(), ast_bridge_softmix::send_sdp_label, ast_bridge::softmix, ast_bridge_channel::tech_pvt, and softmix_channel::topology.

Referenced by softmix_bridge_write_control().

◆ softmix_bridge_check_voice()

static void softmix_bridge_check_voice ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel 
)
static

Definition at line 1058 of file bridge_softmix.c.

1059{
1060 if (bridge_channel->features->mute) {
1061 /*
1062 * We were muted while we were talking.
1063 *
1064 * Immediately stop contributing to mixing
1065 * and report no longer talking.
1066 */
1067 clear_talking(bridge_channel);
1068 }
1069}
static void clear_talking(struct ast_bridge_channel *bridge_channel)
struct ast_bridge_features * features

References clear_talking(), ast_bridge_channel::features, and ast_bridge_features::mute.

Referenced by softmix_bridge_write().

◆ softmix_bridge_create()

static int softmix_bridge_create ( struct ast_bridge bridge)
static

Function called when a bridge is created.

Definition at line 2068 of file bridge_softmix.c.

2069{
2070 struct softmix_bridge_data *softmix_data;
2071
2072 softmix_data = ast_calloc(1, sizeof(*softmix_data));
2073 if (!softmix_data) {
2074 return -1;
2075 }
2076 softmix_data->bridge = bridge;
2077 ast_mutex_init(&softmix_data->lock);
2078 ast_cond_init(&softmix_data->cond, NULL);
2079 softmix_data->timer = ast_timer_open();
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);
2083 return -1;
2084 }
2085 /* start at minimum rate, let it grow from there */
2086 softmix_data->internal_rate = SOFTMIX_MIN_SAMPLE_RATE;
2088
2089#ifdef BINAURAL_RENDERING
2090 softmix_data->default_sample_size = SOFTMIX_SAMPLES(softmix_data->internal_rate,
2091 softmix_data->internal_mixing_interval);
2092#endif
2093
2094 AST_VECTOR_INIT(&softmix_data->remb_collectors, 0);
2095
2096 bridge->tech_pvt = softmix_data;
2097
2098 /* Start the mixing thread. */
2100 softmix_data)) {
2101 softmix_data->thread = AST_PTHREADT_NULL;
2102 softmix_bridge_data_destroy(softmix_data);
2103 bridge->tech_pvt = NULL;
2104 return -1;
2105 }
2106
2107 return 0;
2108}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
static void softmix_bridge_data_destroy(struct softmix_bridge_data *softmix_data)
static void * softmix_mixing_thread(void *data)
#define DEFAULT_SOFTMIX_INTERVAL
Interval at which mixing will take place. Valid options are 10, 20, and 40.
#define AST_LOG_WARNING
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_cond_init(cond, attr)
Definition: lock.h:201
#define ast_mutex_init(pmutex)
Definition: lock.h:186
struct ast_timer * ast_timer_open(void)
Open a timer.
Definition: timing.c:122
#define ast_pthread_create(a, b, c, d)
Definition: utils.h:584
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113

References ast_calloc, ast_cond_init, ast_log, AST_LOG_WARNING, ast_mutex_init, ast_pthread_create, AST_PTHREADT_NULL, ast_timer_open(), AST_VECTOR_INIT, softmix_bridge_data::bridge, softmix_bridge_data::cond, softmix_bridge_data::default_sample_size, DEFAULT_SOFTMIX_INTERVAL, softmix_bridge_data::internal_mixing_interval, softmix_bridge_data::internal_rate, softmix_bridge_data::lock, NULL, softmix_bridge_data::remb_collectors, softmix_bridge_data_destroy(), SOFTMIX_MIN_SAMPLE_RATE, softmix_mixing_thread(), SOFTMIX_SAMPLES, ast_bridge::tech_pvt, softmix_bridge_data::thread, and softmix_bridge_data::timer.

◆ softmix_bridge_data_destroy()

static void softmix_bridge_data_destroy ( struct softmix_bridge_data softmix_data)
static

Definition at line 2054 of file bridge_softmix.c.

2055{
2056 if (softmix_data->timer) {
2057 ast_timer_close(softmix_data->timer);
2058 softmix_data->timer = NULL;
2059 }
2060 ast_mutex_destroy(&softmix_data->lock);
2061 ast_cond_destroy(&softmix_data->cond);
2063 AST_VECTOR_FREE(&softmix_data->remb_collectors);
2064 ast_free(softmix_data);
2065}
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ast_cond_destroy(cond)
Definition: lock.h:202
#define ast_mutex_destroy(a)
Definition: lock.h:188
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Definition: timing.c:154
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:625
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174

References ao2_cleanup, ast_cond_destroy, ast_free, ast_mutex_destroy, ast_timer_close(), AST_VECTOR_FREE, AST_VECTOR_RESET, softmix_bridge_data::cond, softmix_bridge_data::lock, NULL, softmix_bridge_data::remb_collectors, and softmix_bridge_data::timer.

Referenced by softmix_bridge_create(), and softmix_bridge_destroy().

◆ softmix_bridge_destroy()

static void softmix_bridge_destroy ( struct ast_bridge bridge)
static

Function called when a bridge is destroyed.

Definition at line 2132 of file bridge_softmix.c.

2133{
2134 struct softmix_bridge_data *softmix_data;
2135 pthread_t thread;
2136
2137 softmix_data = bridge->tech_pvt;
2138 if (!softmix_data) {
2139 return;
2140 }
2141
2142 /* Stop the mixing thread. */
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);
2152 }
2153#ifdef BINAURAL_RENDERING
2154 free_convolve_data(&softmix_data->convolve);
2155#endif
2156 softmix_bridge_data_destroy(softmix_data);
2157 bridge->tech_pvt = NULL;
2158}
pthread_t thread
Definition: app_sla.c:329
void free_convolve_data(struct convolve_data *data)
Frees all channels and data needed for binaural audio processing.
#define ast_cond_signal(cond)
Definition: lock.h:203
const ast_string_field uniqueid
Definition: bridge.h:401
struct convolve_data convolve

References ast_cond_signal, ast_debug, ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, softmix_bridge_data::bridge, softmix_bridge_data::cond, softmix_bridge_data::convolve, free_convolve_data(), softmix_bridge_data::lock, NULL, softmix_bridge_data_destroy(), softmix_bridge_data::stop, ast_bridge::tech_pvt, thread, softmix_bridge_data::thread, and ast_bridge::uniqueid.

◆ softmix_bridge_join()

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 696 of file bridge_softmix.c.

697{
698 struct softmix_channel *sc;
699 struct softmix_bridge_data *softmix_data;
700 int set_binaural = 0;
701 /*
702 * If false, the channel will be convolved, but since it is a non stereo channel, output
703 * will be mono.
704 */
705 int skip_binaural_output = 1;
706 int pos_id;
707 int is_announcement = 0;
708 int samplerate_change;
709 SCOPE_ENTER(3, "%s:\n", ast_channel_name(bridge_channel->chan));
710
711 softmix_data = bridge->tech_pvt;
712 if (!softmix_data) {
713 SCOPE_EXIT_RTN_VALUE(-1, "No tech_pvt\n");
714 }
715
716 /* Create a new softmix_channel structure and allocate various things on it */
717 if (!(sc = ast_calloc(1, sizeof(*sc)))) {
718 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't alloc tech_pvt\n");
719 }
720
721 samplerate_change = softmix_data->internal_rate;
722 pos_id = -1;
724 if (strncmp(ast_channel_name(bridge_channel->chan), "CBAnn", 5) != 0) {
725 set_binaural = ast_format_get_channel_count(bridge_channel->write_format) > 1 ? 1 : 0;
726 if (set_binaural) {
727 softmix_data->internal_rate = samplerate_change;
728 }
729 skip_binaural_output = 0;
730 } else {
731 is_announcement = 1;
732 }
733 if (set_binaural) {
734 softmix_data->convolve.binaural_active = 1;
735 }
736 if (!skip_binaural_output) {
737 pos_id = set_binaural_data_join(&softmix_data->convolve, softmix_data->default_sample_size);
738 if (pos_id == -1) {
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));
742 ast_free(sc);
743 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't do binaural join\n");
744 }
745 }
746 }
747
748 /* Can't forget the lock */
749 ast_mutex_init(&sc->lock);
750
751 /* Can't forget to record our pvt structure within the bridged channel structure */
752 bridge_channel->tech_pvt = sc;
753
755 softmix_data->internal_mixing_interval
756 ? softmix_data->internal_mixing_interval
758 bridge_channel, 0, set_binaural, pos_id, is_announcement);
759
761 sfu_topologies_on_join(bridge, bridge_channel);
762 }
763
764 /* Complete any active hold before entering, or transitioning to softmix. */
765 if (ast_channel_hold_state(bridge_channel->chan) == AST_CONTROL_HOLD) {
766 ast_debug(1, "Channel %s simulating UNHOLD for bridge softmix join.\n",
767 ast_channel_name(bridge_channel->chan));
768 ast_indicate(bridge_channel->chan, AST_CONTROL_UNHOLD);
769 }
770
771 softmix_poke_thread(softmix_data);
773}
@ AST_BRIDGE_VIDEO_MODE_SFU
Definition: bridge.h:109
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)
static void softmix_poke_thread(struct softmix_bridge_data *softmix_data)
static void sfu_topologies_on_join(struct ast_bridge *bridge, struct ast_bridge_channel *joiner)
Issue channel stream topology change requests.
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.
int ast_channel_hold_state(const struct ast_channel *chan)
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4277
unsigned int ast_format_get_channel_count(const struct ast_format *format)
Get the channel count on a format.
Definition: format.c:135
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
@ AST_CONTROL_UNHOLD
@ AST_CONTROL_HOLD
struct ast_format * write_format
unsigned int binaural_active
Definition: bridge.h:295
enum ast_bridge_video_mode_type mode
Definition: bridge.h:160

References AST_BRIDGE_VIDEO_MODE_SFU, ast_calloc, ast_channel_hold_state(), ast_channel_name(), AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_debug, ast_format_get_channel_count(), ast_free, ast_indicate(), ast_log, ast_mutex_init, convolve_data::binaural_active, ast_bridge_softmix::binaural_active, softmix_bridge_data::bridge, ast_bridge_channel::chan, softmix_bridge_data::convolve, softmix_bridge_data::default_sample_size, DEFAULT_SOFTMIX_INTERVAL, softmix_bridge_data::internal_mixing_interval, softmix_bridge_data::internal_rate, softmix_channel::lock, LOG_ERROR, ast_bridge_video_mode::mode, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, set_binaural_data_join(), set_softmix_bridge_data(), sfu_topologies_on_join(), ast_bridge::softmix, softmix_poke_thread(), ast_bridge::tech_pvt, ast_bridge_channel::tech_pvt, ast_bridge::uniqueid, ast_bridge_softmix::video_mode, and ast_bridge_channel::write_format.

◆ softmix_bridge_leave()

static void 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 816 of file bridge_softmix.c.

817{
818 struct softmix_channel *sc;
819 struct softmix_bridge_data *softmix_data;
820
821 softmix_data = bridge->tech_pvt;
822 sc = bridge_channel->tech_pvt;
823 if (!sc) {
824 return;
825 }
826
828 sfu_topologies_on_leave(bridge_channel, &bridge->channels);
829 }
830
832 if (sc->binaural) {
834 softmix_data->default_sample_size);
835 }
836 }
837
838 bridge_channel->tech_pvt = NULL;
839
841
843
845
846 /* Drop mutex lock */
848
849 /* Drop the factory */
851
852 /* Drop any formats on the frames */
854
855 /* Drop the DSP */
856 ast_dsp_free(sc->dsp);
857
858 /* Eep! drop ourselves */
859 ast_free(sc);
860}
static int sfu_topologies_on_leave(struct ast_bridge_channel *leaver, struct ast_bridge_channels_list *participants)
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...

References ao2_cleanup, AST_BRIDGE_VIDEO_MODE_SFU, ast_dsp_free(), ast_free, ast_mutex_destroy, ast_slinfactory_destroy(), ast_stream_topology_free(), AST_VECTOR_FREE, softmix_channel::binaural, ast_bridge_softmix::binaural_active, softmix_channel::binaural_pos, softmix_bridge_data::bridge, ast_bridge::channels, softmix_bridge_data::convolve, softmix_bridge_data::default_sample_size, softmix_channel::dsp, softmix_channel::factory, ast_frame_subclass::format, softmix_channel::lock, ast_bridge_video_mode::mode, NULL, softmix_channel::remb_collector, set_binaural_data_leave(), sfu_topologies_on_leave(), ast_bridge::softmix, ast_frame::subclass, ast_bridge::tech_pvt, ast_bridge_channel::tech_pvt, softmix_channel::topology, ast_bridge_softmix::video_mode, softmix_channel::video_sources, and softmix_channel::write_frame.

◆ softmix_bridge_stop()

static void softmix_bridge_stop ( struct ast_bridge bridge)
static

Definition at line 2117 of file bridge_softmix.c.

2118{
2119 struct softmix_bridge_data *softmix_data;
2120
2121 softmix_data = bridge->tech_pvt;
2122 if (!softmix_data) {
2123 return;
2124 }
2125
2126 ast_mutex_lock(&softmix_data->lock);
2127 softmix_data->stop = 1;
2128 ast_mutex_unlock(&softmix_data->lock);
2129}

References ast_mutex_lock, ast_mutex_unlock, softmix_bridge_data::bridge, softmix_bridge_data::lock, softmix_bridge_data::stop, and ast_bridge::tech_pvt.

◆ softmix_bridge_stream_sources_update()

static void softmix_bridge_stream_sources_update ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
struct softmix_channel sc 
)
static

Definition at line 2256 of file bridge_softmix.c.

2258{
2259 int index;
2260 struct ast_stream_topology *old_topology = sc->topology;
2261 struct ast_stream_topology *new_topology = ast_channel_get_stream_topology(bridge_channel->chan);
2262 int removed_streams[MAX(ast_stream_topology_get_count(sc->topology), ast_stream_topology_get_count(new_topology))];
2263 size_t removed_streams_count = 0;
2264 struct ast_stream_topology *added_streams;
2265 struct ast_bridge_channels_list *participants = &bridge->channels;
2266 struct ast_bridge_channel *participant;
2267 SCOPE_ENTER(3, "%s: OT: %s NT: %s\n", ast_channel_name(bridge_channel->chan),
2268 ast_str_tmp(256, ast_stream_topology_to_str(old_topology, &STR_TMP)),
2269 ast_str_tmp(256, ast_stream_topology_to_str(new_topology, &STR_TMP)));
2270
2271 added_streams = ast_stream_topology_alloc();
2272 if (!added_streams) {
2273 SCOPE_EXIT_LOG(LOG_ERROR, "%s: Couldn't alloc topology\n", ast_channel_name(bridge_channel->chan));
2274 }
2275
2276 /* We go through the old topology comparing it to the new topology to determine what streams
2277 * changed state. A state transition can result in the stream being considered a new source
2278 * (for example it was removed and is now present) or being removed (a stream became inactive).
2279 * Added streams are copied into a topology and added to each other participant while for
2280 * removed streams we merely store their position and mark them as removed later.
2281 */
2282 ast_trace(-1, "%s: Checking for state changes\n", ast_channel_name(bridge_channel->chan));
2283 for (index = 0; index < ast_stream_topology_get_count(sc->topology) && index < ast_stream_topology_get_count(new_topology); ++index) {
2284 struct ast_stream *old_stream = ast_stream_topology_get_stream(sc->topology, index);
2285 struct ast_stream *new_stream = ast_stream_topology_get_stream(new_topology, index);
2286 SCOPE_ENTER(4, "%s: Slot: %d Old stream: %s New stream: %s\n", ast_channel_name(bridge_channel->chan),
2287 index, ast_str_tmp(256, ast_stream_to_str(old_stream, &STR_TMP)),
2288 ast_str_tmp(256, ast_stream_to_str(new_stream, &STR_TMP)));
2289
2290 /* Ignore all streams that don't carry video and streams that are strictly outgoing destination streams */
2294 SCOPE_EXIT_EXPR(continue, "%s: Stream %d ignored\n", ast_channel_name(bridge_channel->chan), index);
2295 }
2296
2298 /* If a stream renegotiates from video to non-video then we need to remove it as a source */
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;
2301 } else if (ast_stream_get_type(old_stream) != AST_MEDIA_TYPE_VIDEO && ast_stream_get_type(new_stream) == AST_MEDIA_TYPE_VIDEO) {
2303 /* If a stream renegotiates from non-video to video in a non-removed state we need to add it as a source */
2304 if (append_source_stream(added_streams, ast_channel_name(bridge_channel->chan),
2305 bridge->softmix.send_sdp_label ? ast_channel_uniqueid(bridge_channel->chan) : NULL,
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),
2308 index, ast_stream_get_name(new_stream));
2309 }
2310 ast_trace(-1, "%s: Stream %d changed from non-video to video\n", ast_channel_name(bridge_channel->chan), index);
2311 }
2312 } else if (ast_stream_get_state(old_stream) != AST_STREAM_STATE_REMOVED &&
2314 ast_trace(-1, "%s: Stream %d added to remove list\n", ast_channel_name(bridge_channel->chan), index);
2315 /* If a stream renegotiates and is removed then we remove it */
2316 removed_streams[removed_streams_count++] = index;
2321 /* If a stream renegotiates and is added then we add it */
2322 if (append_source_stream(added_streams, ast_channel_name(bridge_channel->chan),
2323 bridge->softmix.send_sdp_label ? ast_channel_uniqueid(bridge_channel->chan) : NULL,
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),
2326 index, ast_stream_get_name(new_stream));
2327 }
2328 ast_trace(-1, "%s: Stream %d:%s changed state from %s to %s\n", ast_channel_name(bridge_channel->chan),
2329 index, ast_stream_get_name(old_stream), ast_stream_state2str(ast_stream_get_state(old_stream)),
2331 } else {
2332 ast_trace(-1, "%s: Stream %d:%s didn't do anything\n", ast_channel_name(bridge_channel->chan),
2333 index, ast_stream_get_name(old_stream));
2334 }
2335 SCOPE_EXIT();
2336 }
2337
2338 /* Any newly added streams that did not take the position of a removed stream
2339 * will be present at the end of the new topology. Since streams are never
2340 * removed from the topology but merely marked as removed we can pick up where we
2341 * left off when comparing the old and new topologies.
2342 */
2343 ast_trace(-1, "%s: Checking for newly added streams\n", ast_channel_name(bridge_channel->chan));
2344
2345 for (; index < ast_stream_topology_get_count(new_topology); ++index) {
2346 struct ast_stream *stream = ast_stream_topology_get_stream(new_topology, index);
2347 SCOPE_ENTER(4, "%s: Checking stream %d:%s\n", ast_channel_name(bridge_channel->chan), index,
2348 ast_stream_get_name(stream));
2349
2350 if (!is_video_source(stream)) {
2351 SCOPE_EXIT_EXPR(continue, "%s: Stream %d:%s is not video source\n", ast_channel_name(bridge_channel->chan),
2352 index, ast_stream_get_name(stream));
2353 }
2354
2355 if (append_source_stream(added_streams, ast_channel_name(bridge_channel->chan),
2356 bridge->softmix.send_sdp_label ? ast_channel_uniqueid(bridge_channel->chan) : NULL,
2357 stream, index)) {
2358 SCOPE_EXIT_EXPR(goto cleanup, "%s: Couldn't append stream %d:%s\n", ast_channel_name(bridge_channel->chan),
2359 index, ast_stream_get_name(stream));
2360 }
2361 SCOPE_EXIT("%s: Added new stream %s\n", ast_channel_name(bridge_channel->chan),
2362 ast_str_tmp(256, ast_stream_to_str(stream, &STR_TMP)));
2363 }
2364
2365 /* We always update the stored topology if we can to reflect what is currently negotiated */
2366 sc->topology = ast_stream_topology_clone(new_topology);
2367 if (!sc->topology) {
2368 sc->topology = old_topology;
2369 } else {
2370 ast_stream_topology_free(old_topology);
2371 }
2372
2373 /* If there are no removed sources and no added sources we don't need to renegotiate the
2374 * other participants.
2375 */
2376 if (!removed_streams_count && !ast_stream_topology_get_count(added_streams)) {
2377 ast_trace(-1, "%s: Nothing added or removed\n", ast_channel_name(bridge_channel->chan));
2378 goto cleanup;
2379 }
2380
2381 ast_trace(-1, "%s: Processing adds and removes\n", ast_channel_name(bridge_channel->chan));
2382 /* Go through each participant adding in the new streams and removing the old ones */
2383 AST_LIST_TRAVERSE(participants, participant, entry)
2384 {
2385 struct softmix_channel *participant_sc = participant->tech_pvt;
2386 SCOPE_ENTER(4, "%s/%s: Old participant topology %s\n",
2387 ast_channel_name(bridge_channel->chan),
2388 ast_channel_name(participant->chan),
2389 ast_str_tmp(256, ast_stream_topology_to_str(participant_sc->topology, &STR_TMP)));
2390
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));
2395 }
2396
2397 /* We add in all the new streams first so that they do not take the place
2398 * of any of our removed streams, allowing the remote side to reset the state
2399 * for each removed stream. */
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));
2403 }
2404 ast_trace(-1, "%s/%s: Adding streams %s\n", ast_channel_name(bridge_channel->chan),
2405 ast_channel_name(participant->chan),
2406 ast_str_tmp(256, ast_stream_topology_to_str(added_streams, &STR_TMP)));
2407
2408 /* Then we go through and remove any ones that were removed */
2409 for (index = 0;
2410 removed_streams_count && index < ast_stream_topology_get_count(sc->topology); ++index) {
2411 struct ast_stream *stream = ast_stream_topology_get_stream(sc->topology, index);
2412 int removed_stream;
2413
2414 for (removed_stream = 0; removed_stream < removed_streams_count; ++removed_stream) {
2415 if (is_video_dest(stream, ast_channel_name(bridge_channel->chan),
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),
2420 ast_str_tmp(256, ast_stream_to_str(stream, &STR_TMP)));
2422 }
2423 }
2424 }
2425 ast_channel_request_stream_topology_change(participant->chan, participant_sc->topology, NULL);
2426 SCOPE_EXIT("%s/%s: New participant topology %s\n",
2427 ast_channel_name(bridge_channel->chan),
2428 ast_channel_name(participant->chan),
2429 ast_str_tmp(256, ast_stream_topology_to_str(participant_sc->topology, &STR_TMP)));
2430 }
2431
2432 ast_trace(-1, "%s: New topology %s\n", ast_channel_name(bridge_channel->chan),
2433 ast_str_tmp(256, ast_stream_topology_to_str(sc->topology, &STR_TMP)));
2434
2435cleanup:
2436 ast_stream_topology_free(added_streams);
2437 SCOPE_EXIT();
2438}
#define SCOPE_EXIT_LOG(__log_level,...)
#define SCOPE_EXIT_EXPR(__expr,...)
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.
Definition: stream.c:337
@ AST_STREAM_STATE_RECVONLY
Set when the stream is receiving media only.
Definition: stream.h:90
@ AST_STREAM_STATE_INACTIVE
Set when the stream is not sending OR receiving media.
Definition: stream.h:94
@ AST_STREAM_STATE_SENDRECV
Set when the stream is sending and receiving media.
Definition: stream.h:82
const char * ast_stream_state2str(enum ast_stream_state state)
Convert the state of a stream into a string.
Definition: stream.c:388
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.
Definition: stream.c:936
#define ast_str_tmp(init_len, __expr)
Provides a temporary ast_str and returns a copy of its buffer.
Definition: strings.h:1189

References append_all_streams(), append_source_stream(), ast_channel_get_stream_topology(), ast_channel_name(), ast_channel_request_stream_topology_change(), ast_channel_uniqueid(), AST_LIST_TRAVERSE, AST_MEDIA_TYPE_VIDEO, ast_str_tmp, ast_stream_get_name(), ast_stream_get_state(), ast_stream_get_type(), ast_stream_set_state(), ast_stream_state2str(), AST_STREAM_STATE_INACTIVE, AST_STREAM_STATE_RECVONLY, AST_STREAM_STATE_REMOVED, AST_STREAM_STATE_SENDONLY, AST_STREAM_STATE_SENDRECV, ast_stream_to_str(), ast_stream_topology_alloc(), ast_stream_topology_clone(), ast_stream_topology_free(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), ast_stream_topology_to_str(), ast_trace, ast_bridge_channel::chan, ast_bridge::channels, cleanup(), is_video_dest(), is_video_source(), LOG_ERROR, MAX, NULL, SCOPE_ENTER, SCOPE_EXIT, SCOPE_EXIT_EXPR, SCOPE_EXIT_LOG, ast_bridge_softmix::send_sdp_label, SOFTBRIDGE_VIDEO_DEST_LEN, SOFTBRIDGE_VIDEO_DEST_PREFIX, ast_bridge::softmix, ast_bridge_channel::tech_pvt, and softmix_channel::topology.

Referenced by softmix_bridge_stream_topology_changed().

◆ softmix_bridge_stream_topology_changed()

static void softmix_bridge_stream_topology_changed ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel 
)
static

stream_topology_changed callback

For most video modes, nothing beyond the ordinary is required. For the SFU case, though, we need to completely remap the streams in order to ensure video gets directed where it is expected to go.

Parameters
bridgeThe bridge
bridge_channelChannel whose topology has changed

Definition at line 2450 of file bridge_softmix.c.

2451{
2452 struct softmix_bridge_data *softmix_data = bridge->tech_pvt;
2453 struct softmix_channel *sc = bridge_channel->tech_pvt;
2454 struct ast_bridge_channel *participant;
2455 struct ast_vector_int media_types;
2456 int nths[AST_MEDIA_TYPE_END] = {0};
2457 int idx;
2458 SCOPE_ENTER(3, "%s: \n", ast_channel_name(bridge_channel->chan));
2459
2460 switch (bridge->softmix.video_mode.mode) {
2464 default:
2465 ast_bridge_channel_stream_map(bridge_channel);
2466 SCOPE_EXIT_RTN("%s: Not in SFU mode\n", ast_channel_name(bridge_channel->chan));
2468 break;
2469 }
2470
2471 ast_channel_lock(bridge_channel->chan);
2472 softmix_bridge_stream_sources_update(bridge, bridge_channel, sc);
2473 ast_channel_unlock(bridge_channel->chan);
2474
2475 AST_VECTOR_INIT(&media_types, AST_MEDIA_TYPE_END);
2476
2477 /* The bridge stream identifiers may change, so reset the mapping for them.
2478 * When channels end up getting added back in they'll reuse their existing
2479 * collector and won't need to allocate a new one (unless they were just added).
2480 */
2481 for (idx = 0; idx < AST_VECTOR_SIZE(&softmix_data->remb_collectors); ++idx) {
2482 ao2_cleanup(AST_VECTOR_GET(&softmix_data->remb_collectors, idx));
2483 AST_VECTOR_REPLACE(&softmix_data->remb_collectors, idx, NULL);
2484 }
2485
2486 /* First traversal: re-initialize all of the participants' stream maps */
2487 AST_LIST_TRAVERSE(&bridge->channels, participant, entry) {
2488 ast_bridge_channel_lock(participant);
2489
2492
2493 sc = participant->tech_pvt;
2495
2496 ast_bridge_channel_unlock(participant);
2497 }
2498
2499 /* Second traversal: Map specific video channels from their source to their destinations.
2500 *
2501 * This is similar to what is done in ast_stream_topology_map(),
2502 * except that video channels are handled differently. Each video
2503 * source has it's own unique index on the bridge. This way, a
2504 * particular channel's source video can be distributed to the
2505 * appropriate destination streams on the other channels.
2506 */
2507 AST_LIST_TRAVERSE(&bridge->channels, participant, entry) {
2508 int i;
2509 struct ast_stream_topology *topology;
2510
2511 ast_bridge_channel_lock(participant);
2512 ast_channel_lock(participant->chan);
2513
2514 topology = ao2_bump(ast_channel_get_stream_topology(participant->chan));
2515 if (!topology) {
2516 /* Oh, my, we are in trouble. */
2517 ast_channel_unlock(participant->chan);
2518 ast_bridge_channel_unlock(participant);
2519 continue;
2520 }
2521
2522 for (i = 0; i < ast_stream_topology_get_count(topology); ++i) {
2523 struct ast_stream *stream = ast_stream_topology_get_stream(topology, i);
2524
2525 if (is_video_source(stream)) {
2527 AST_VECTOR_REPLACE(&participant->stream_map.to_bridge, i, AST_VECTOR_SIZE(&media_types) - 1);
2528 /*
2529 * There are cases where we need to bidirectionally send frames, such as for REMB reports
2530 * so we also map back to the channel.
2531 */
2532 AST_VECTOR_REPLACE(&participant->stream_map.to_channel, AST_VECTOR_SIZE(&media_types) - 1, i);
2533 remb_enable_collection(bridge, participant, AST_VECTOR_SIZE(&media_types) - 1);
2534 /*
2535 * Unlock the channel and participant to prevent
2536 * potential deadlock in map_source_to_destinations().
2537 */
2538 ast_channel_unlock(participant->chan);
2539 ast_bridge_channel_unlock(participant);
2540
2542 AST_VECTOR_SIZE(&media_types) - 1, &bridge->channels, i);
2543 ast_bridge_channel_lock(participant);
2544 ast_channel_lock(participant->chan);
2545 } else if (ast_stream_get_type(stream) == AST_MEDIA_TYPE_VIDEO) {
2546 /* Video stream mapping occurs directly when a video source stream
2547 * is found on a channel. Video streams should otherwise remain
2548 * unmapped.
2549 */
2550 AST_VECTOR_REPLACE(&participant->stream_map.to_bridge, i, -1);
2551 } else if (ast_stream_get_state(stream) != AST_STREAM_STATE_REMOVED) {
2552 /* XXX This is copied from ast_stream_topology_map(). This likely could
2553 * be factored out in some way
2554 */
2556 int index = AST_VECTOR_GET_INDEX_NTH(&media_types, ++nths[type],
2558
2559 if (index == -1) {
2560 AST_VECTOR_APPEND(&media_types, type);
2561 index = AST_VECTOR_SIZE(&media_types) - 1;
2562 }
2563
2564 AST_VECTOR_REPLACE(&participant->stream_map.to_bridge, i, index);
2565 AST_VECTOR_REPLACE(&participant->stream_map.to_channel, index, i);
2566 }
2567 }
2568
2569 ast_stream_topology_free(topology);
2570
2571 ast_channel_unlock(participant->chan);
2572 ast_bridge_channel_unlock(participant);
2573 }
2574
2575 AST_VECTOR_FREE(&media_types);
2576 SCOPE_EXIT_RTN("%s\n", ast_channel_name(bridge_channel->chan));
2577}
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
@ AST_BRIDGE_VIDEO_MODE_SINGLE_SRC
Definition: bridge.h:102
@ AST_BRIDGE_VIDEO_MODE_TALKER_SRC
Definition: bridge.h:105
@ AST_BRIDGE_VIDEO_MODE_NONE
Definition: bridge.h:100
void ast_bridge_channel_stream_map(struct ast_bridge_channel *bridge_channel)
Maps a channel's stream topology to and from the bridge.
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.
static void softmix_bridge_stream_sources_update(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct softmix_channel *sc)
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.
static const char type[]
Definition: chan_ooh323.c:109
ast_media_type
Types of media.
Definition: codec.h:30
@ AST_MEDIA_TYPE_END
Definition: codec.h:36
Integer vector definition.
Definition: vector.h:52
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
Definition: vector.h:571
#define AST_VECTOR_GET_INDEX_NTH(vec, nth, value, cmp)
Get the nth index from a vector that matches the given comparison.
Definition: vector.h:696
#define AST_VECTOR_ELEM_DEFAULT_CMP(elem, value)
Default comparator for AST_VECTOR_REMOVE_ELEM_UNORDERED()
Definition: vector.h:564

References ao2_bump, ao2_cleanup, ast_bridge_channel_lock, ast_bridge_channel_stream_map(), ast_bridge_channel_unlock, AST_BRIDGE_VIDEO_MODE_NONE, AST_BRIDGE_VIDEO_MODE_SFU, AST_BRIDGE_VIDEO_MODE_SINGLE_SRC, AST_BRIDGE_VIDEO_MODE_TALKER_SRC, ast_channel_get_stream_topology(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, AST_LIST_TRAVERSE, AST_MEDIA_TYPE_END, AST_MEDIA_TYPE_VIDEO, ast_stream_get_state(), ast_stream_get_type(), AST_STREAM_STATE_REMOVED, ast_stream_topology_free(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), AST_VECTOR_APPEND, AST_VECTOR_ELEM_CLEANUP_NOOP, AST_VECTOR_ELEM_DEFAULT_CMP, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_GET_INDEX_NTH, AST_VECTOR_INIT, AST_VECTOR_REPLACE, AST_VECTOR_RESET, AST_VECTOR_SIZE, softmix_bridge_data::bridge, ast_bridge_channel::chan, ast_bridge::channels, is_video_source(), map_source_to_destinations(), ast_bridge_video_mode::mode, NULL, softmix_bridge_data::remb_collectors, remb_enable_collection(), SCOPE_ENTER, SCOPE_EXIT_RTN, ast_bridge::softmix, softmix_bridge_stream_sources_update(), ast_bridge_channel::stream_map, ast_bridge::tech_pvt, ast_bridge_channel::tech_pvt, ast_bridge_channel::to_bridge, ast_bridge_channel::to_channel, type, ast_bridge_softmix::video_mode, and softmix_channel::video_sources.

◆ softmix_bridge_unsuspend()

static void softmix_bridge_unsuspend ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel 
)
static

Function called when a channel is unsuspended from the bridge.

Definition at line 415 of file bridge_softmix.c.

416{
417#ifdef BINAURAL_RENDERING
418 struct softmix_channel *sc = bridge_channel->tech_pvt;
419 if (sc->binaural) {
420 /* Restore some usefull data if it was a binaural channel */
421 struct ast_format *slin_format;
422
423 slin_format = ast_format_cache_get_slin_by_rate(sc->rate);
424 ast_set_write_format_interleaved_stereo(bridge_channel->chan, slin_format);
425 }
426#endif
427 if (bridge->tech_pvt) {
429 }
430}

References ast_format_cache_get_slin_by_rate(), ast_set_write_format_interleaved_stereo(), softmix_channel::binaural, ast_bridge_channel::chan, softmix_channel::rate, softmix_poke_thread(), ast_bridge::tech_pvt, and ast_bridge_channel::tech_pvt.

◆ softmix_bridge_write()

static int softmix_bridge_write ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
struct ast_frame frame 
)
static

Definition at line 1309 of file bridge_softmix.c.

1310{
1311 int res = 0;
1312
1313 if (!bridge->tech_pvt || !bridge_channel || !bridge_channel->tech_pvt) {
1314 /* "Accept" the frame and discard it. */
1315 return 0;
1316 }
1317
1318 /*
1319 * XXX Softmix needs to use channel roles to determine who gets
1320 * what frame. Possible roles: announcer, recorder, agent,
1321 * supervisor.
1322 */
1323 switch (frame->frametype) {
1324 case AST_FRAME_NULL:
1325 /* "Accept" the frame and discard it. */
1326 softmix_bridge_check_voice(bridge, bridge_channel);
1327 break;
1329 case AST_FRAME_DTMF_END:
1330 res = ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
1331 break;
1332 case AST_FRAME_VOICE:
1333 softmix_bridge_write_voice(bridge, bridge_channel, frame);
1334 break;
1335 case AST_FRAME_VIDEO:
1336 softmix_bridge_write_video(bridge, bridge_channel, frame);
1337 break;
1338 case AST_FRAME_TEXT:
1340 softmix_bridge_write_text(bridge, bridge_channel, frame);
1341 break;
1342 case AST_FRAME_CONTROL:
1343 res = softmix_bridge_write_control(bridge, bridge_channel, frame);
1344 break;
1345 case AST_FRAME_RTCP:
1346 softmix_bridge_write_rtcp(bridge, bridge_channel, frame);
1347 break;
1349 res = ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
1350 break;
1352 ast_log(LOG_ERROR, "Synchronous bridge action written to a softmix bridge.\n");
1353 ast_assert(0);
1354 default:
1355 ast_debug(3, "Frame type %u unsupported\n", frame->frametype);
1356 /* "Accept" the frame and discard it. */
1357 break;
1358 }
1359
1360 return res;
1361}
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.
static void softmix_bridge_write_voice(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
static void softmix_bridge_check_voice(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
static void softmix_bridge_write_rtcp(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
static int softmix_bridge_write_control(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
static void softmix_bridge_write_video(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
static void softmix_bridge_write_text(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
@ AST_FRAME_VIDEO
@ AST_FRAME_NULL
@ AST_FRAME_DTMF_END
@ AST_FRAME_DTMF_BEGIN
@ AST_FRAME_BRIDGE_ACTION_SYNC
@ AST_FRAME_TEXT_DATA
@ AST_FRAME_CONTROL
@ AST_FRAME_BRIDGE_ACTION
@ AST_FRAME_TEXT

References ast_assert, ast_bridge_queue_everyone_else(), ast_debug, AST_FRAME_BRIDGE_ACTION, AST_FRAME_BRIDGE_ACTION_SYNC, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_NULL, AST_FRAME_RTCP, AST_FRAME_TEXT, AST_FRAME_TEXT_DATA, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_log, ast_frame::frametype, LOG_ERROR, softmix_bridge_check_voice(), softmix_bridge_write_control(), softmix_bridge_write_rtcp(), softmix_bridge_write_text(), softmix_bridge_write_video(), softmix_bridge_write_voice(), ast_bridge::tech_pvt, and ast_bridge_channel::tech_pvt.

◆ softmix_bridge_write_control()

static int softmix_bridge_write_control ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
struct ast_frame frame 
)
static

Definition at line 1222 of file bridge_softmix.c.

1223{
1224 struct softmix_bridge_data *softmix_data = bridge->tech_pvt;
1225
1226 /*
1227 * XXX Softmix needs to use channel roles to determine what to
1228 * do with control frames.
1229 */
1230
1231 switch (frame->subclass.integer) {
1232 case AST_CONTROL_HOLD:
1233 /*
1234 * Doing anything for holds in a conference bridge could be considered a bit
1235 * odd. That being said, in most cases one would probably want the talking
1236 * flag cleared when 'hold' is pressed by the remote endpoint, so go ahead
1237 * and do that here. However, that is all we'll do. Meaning if for some reason
1238 * the endpoint continues to send audio frames despite pressing 'hold' talking
1239 * will once again be detected for that channel.
1240 */
1241 clear_talking(bridge_channel);
1242 break;
1247 softmix_data->last_video_update = ast_tvnow();
1248 }
1249 break;
1252 sfu_topologies_on_source_change(bridge, bridge_channel);
1253 }
1254 break;
1255 default:
1256 break;
1257 }
1258
1259 return 0;
1260}
static void sfu_topologies_on_source_change(struct ast_bridge *bridge, struct ast_bridge_channel *source)
@ AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED
@ AST_CONTROL_VIDUPDATE
unsigned int video_update_discard
Definition: bridge.h:168
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References ast_bridge_queue_everyone_else(), AST_BRIDGE_VIDEO_MODE_SFU, AST_CONTROL_HOLD, AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED, AST_CONTROL_VIDUPDATE, ast_tvdiff_ms(), ast_tvnow(), softmix_bridge_data::bridge, clear_talking(), ast_frame_subclass::integer, softmix_bridge_data::last_video_update, ast_bridge_video_mode::mode, NULL, sfu_topologies_on_source_change(), ast_bridge::softmix, ast_frame::subclass, ast_bridge::tech_pvt, ast_bridge_softmix::video_mode, and ast_bridge_video_mode::video_update_discard.

Referenced by softmix_bridge_write().

◆ softmix_bridge_write_rtcp()

static void softmix_bridge_write_rtcp ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
struct ast_frame frame 
)
static

Definition at line 1271 of file bridge_softmix.c.

1272{
1273 struct ast_rtp_rtcp_feedback *feedback = frame->data.ptr;
1274 struct softmix_channel *sc = bridge_channel->tech_pvt;
1275
1276 /* We only care about REMB reports right now. In the future we may be able to use sender or
1277 * receiver reports to further tweak things, but not yet.
1278 */
1279 if (frame->subclass.integer != AST_RTP_RTCP_PSFB || feedback->fmt != AST_RTP_RTCP_FMT_REMB ||
1282 return;
1283 }
1284
1285 /* REMB is the total estimated maximum bitrate across all streams within the session, so we store
1286 * only the latest report and use it everywhere.
1287 */
1288 ast_mutex_lock(&sc->lock);
1289 sc->remb = feedback->remb;
1290 ast_mutex_unlock(&sc->lock);
1291
1292 return;
1293}
unsigned int remb_send_interval
Definition: bridge.h:151
An object that represents data received in a feedback report.
Definition: rtp_engine.h:383

References AST_BRIDGE_VIDEO_MODE_SFU, ast_mutex_lock, ast_mutex_unlock, AST_RTP_RTCP_FMT_REMB, AST_RTP_RTCP_PSFB, ast_frame::data, ast_rtp_rtcp_feedback::fmt, ast_frame_subclass::integer, softmix_channel::lock, ast_bridge_video_mode::mode, ast_bridge_video_mode::mode_data, ast_frame::ptr, softmix_channel::remb, ast_rtp_rtcp_feedback::remb, ast_bridge_video_sfu_data::remb_send_interval, ast_bridge_video_mode::sfu_data, ast_bridge::softmix, ast_frame::subclass, ast_bridge_channel::tech_pvt, and ast_bridge_softmix::video_mode.

Referenced by softmix_bridge_write().

◆ softmix_bridge_write_text()

static void softmix_bridge_write_text ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
struct ast_frame frame 
)
static

Definition at line 1186 of file bridge_softmix.c.

1188{
1189 if (DEBUG_ATLEAST(1)) {
1190 struct ast_msg_data *msg = frame->data.ptr;
1191 char frame_type[64];
1192
1194
1195 if (frame->frametype == AST_FRAME_TEXT_DATA) {
1196 ast_log(LOG_DEBUG, "Received %s frame from '%s:%s': %s\n", frame_type,
1198 ast_channel_name(bridge_channel->chan),
1200 } else {
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);
1204 }
1205 }
1206
1207 ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
1208}
frame_type
Definition: codec_builtin.c:44
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.
@ AST_MSG_DATA_ATTR_BODY
Definition: message.h:458
@ AST_MSG_DATA_ATTR_FROM
Definition: message.h:456
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.
Definition: main/frame.c:671
#define DEBUG_ATLEAST(level)
#define LOG_DEBUG
Structure used to transport a message through the frame core.

References ast_bridge_queue_everyone_else(), ast_channel_name(), AST_FRAME_TEXT_DATA, ast_frame_type2str(), ast_log, AST_MSG_DATA_ATTR_BODY, AST_MSG_DATA_ATTR_FROM, ast_msg_data_get_attribute(), ast_bridge_channel::chan, ast_frame::data, ast_frame::datalen, DEBUG_ATLEAST, ast_frame::frametype, LOG_DEBUG, and ast_frame::ptr.

Referenced by softmix_bridge_write().

◆ softmix_bridge_write_video()

static void softmix_bridge_write_video ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
struct ast_frame frame 
)
static

Definition at line 886 of file bridge_softmix.c.

887{
888 struct softmix_channel *sc;
889 int video_src_priority;
890
891 /* Determine if the video frame should be distributed or not */
892 switch (bridge->softmix.video_mode.mode) {
894 break;
896 video_src_priority = ast_bridge_is_video_src(bridge, bridge_channel->chan);
897 if (video_src_priority == 1) {
898 /* Pass to me and everyone else. */
899 ast_bridge_queue_everyone_else(bridge, NULL, frame);
900 }
901 break;
903 sc = bridge_channel->tech_pvt;
904 ast_mutex_lock(&sc->lock);
905 ast_bridge_update_talker_src_video_mode(bridge, bridge_channel->chan,
907 frame->subclass.frame_ending);
909 video_src_priority = ast_bridge_is_video_src(bridge, bridge_channel->chan);
910 if (video_src_priority == 1) {
911 int num_src = ast_bridge_number_video_src(bridge);
912 int echo = num_src > 1 ? 0 : 1;
913
914 ast_bridge_queue_everyone_else(bridge, echo ? NULL : bridge_channel, frame);
915 } else if (video_src_priority == 2) {
916 softmix_pass_video_top_priority(bridge, frame);
917 }
918 break;
920 /* Nothing special to do here, the bridge channel stream map will ensure the
921 * video goes everywhere it needs to
922 */
923 ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
924 break;
925 }
926}
int ast_bridge_number_video_src(struct ast_bridge *bridge)
Returns the number of video sources currently active in the bridge.
Definition: bridge.c:3864
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.
Definition: bridge.c:3816
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.
Definition: bridge.c:3891
static void softmix_pass_video_top_priority(struct ast_bridge *bridge, struct ast_frame *frame)
struct video_follow_talker_data video_talker

References ast_bridge_is_video_src(), ast_bridge_number_video_src(), ast_bridge_queue_everyone_else(), ast_bridge_update_talker_src_video_mode(), AST_BRIDGE_VIDEO_MODE_NONE, AST_BRIDGE_VIDEO_MODE_SFU, AST_BRIDGE_VIDEO_MODE_SINGLE_SRC, AST_BRIDGE_VIDEO_MODE_TALKER_SRC, ast_mutex_lock, ast_mutex_unlock, ast_bridge_channel::chan, video_follow_talker_data::energy_average, ast_frame_subclass::frame_ending, softmix_channel::lock, ast_bridge_video_mode::mode, NULL, ast_bridge::softmix, softmix_pass_video_top_priority(), ast_frame::subclass, ast_bridge_channel::tech_pvt, ast_bridge_softmix::video_mode, and softmix_channel::video_talker.

Referenced by softmix_bridge_write().

◆ softmix_bridge_write_voice()

static void softmix_bridge_write_voice ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
struct ast_frame frame 
)
static

Definition at line 937 of file bridge_softmix.c.

938{
939 struct softmix_channel *sc = bridge_channel->tech_pvt;
940 struct softmix_bridge_data *softmix_data = bridge->tech_pvt;
941 int silent = 0;
942 int totalsilence = 0;
943 int cur_energy = 0;
944 int silence_threshold = bridge_channel->tech_args.silence_threshold ?
945 bridge_channel->tech_args.silence_threshold :
947 /*
948 * If update_talking is set to 0 or 1, tell the bridge that the channel
949 * has started or stopped talking.
950 */
951 char update_talking = -1;
952
953 /* Write the frame into the conference */
954 ast_mutex_lock(&sc->lock);
955
957 /*
958 * The incoming frame is not the expected format. Update
959 * the channel's translation path to get us slinear from
960 * the new format for the next frame.
961 *
962 * There is the possibility that this frame is an old slinear
963 * rate frame that was in flight when the softmix bridge
964 * changed rates. If so it will self correct on subsequent
965 * frames.
966 */
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),
972 ast_set_read_format_path(bridge_channel->chan, frame->subclass.format,
973 sc->read_slin_format);
974 ast_channel_unlock(bridge_channel->chan);
975 }
976
977 /* The channel will be leaving soon if there is no dsp. */
978 if (sc->dsp) {
979 silent = ast_dsp_silence_with_energy(sc->dsp, frame, &totalsilence, &cur_energy);
980 }
981
983 int cur_slot = sc->video_talker.energy_history_cur_slot;
984
986 sc->video_talker.energy_accum += cur_energy;
987 sc->video_talker.energy_history[cur_slot] = cur_energy;
991 sc->video_talker.energy_history_cur_slot = 0; /* wrap around */
992 }
993 }
994
995 if (totalsilence < silence_threshold) {
996 if (!sc->talking && !silent) {
997 /* Tell the write process we have audio to be mixed out */
998 sc->talking = 1;
999 update_talking = 1;
1000 }
1001 } else {
1002 if (sc->talking) {
1003 sc->talking = 0;
1004 update_talking = 0;
1005 }
1006 }
1007
1008 /* Before adding audio in, make sure we haven't fallen behind. If audio has fallen
1009 * behind 4 times the amount of samples mixed on every iteration of the mixer, Re-sync
1010 * the audio by flushing the buffer before adding new audio in. */
1011 if (ast_slinfactory_available(&sc->factory) > (4 * SOFTMIX_SAMPLES(softmix_data->internal_rate, softmix_data->internal_mixing_interval))) {
1013 }
1014
1015 if (sc->talking || !bridge_channel->tech_args.drop_silence) {
1016 /* Add frame to the smoother for mixing with other channels. */
1017 ast_slinfactory_feed(&sc->factory, frame);
1018 }
1019
1020 /* Alllll done */
1021 ast_mutex_unlock(&sc->lock);
1022
1023 if (update_talking != -1) {
1024 ast_bridge_channel_notify_talking(bridge_channel, update_talking);
1025 }
1026}
#define DEFAULT_SOFTMIX_SILENCE_THRESHOLD
Default time in ms of silence necessary to declare talking stopped by the bridge.
#define DEFAULT_ENERGY_HISTORY_LEN
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.
Definition: dsp.c:1483
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
@ AST_FORMAT_CMP_EQUAL
Definition: format.h:36
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
unsigned int ast_slinfactory_available(const struct ast_slinfactory *sf)
Retrieve number of samples currently in a slinfactory.
Definition: slinfactory.c:199
int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
Feed audio into a slinfactory.
Definition: slinfactory.c:77
int energy_history[DEFAULT_ENERGY_HISTORY_LEN]

References ast_bridge_channel_notify_talking(), AST_BRIDGE_VIDEO_MODE_TALKER_SRC, ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_debug, ast_dsp_silence_with_energy(), ast_format_cmp(), AST_FORMAT_CMP_EQUAL, ast_format_get_name(), ast_mutex_lock, ast_mutex_unlock, ast_set_read_format_path(), ast_slinfactory_available(), ast_slinfactory_feed(), ast_slinfactory_flush(), softmix_bridge_data::bridge, ast_bridge_channel::chan, 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, softmix_bridge_data::internal_mixing_interval, softmix_bridge_data::internal_rate, softmix_channel::lock, ast_bridge_video_mode::mode, softmix_channel::read_slin_format, ast_bridge_tech_optimizations::silence_threshold, ast_bridge::softmix, SOFTMIX_SAMPLES, ast_frame::subclass, softmix_channel::talking, ast_bridge_channel::tech_args, ast_bridge::tech_pvt, ast_bridge_channel::tech_pvt, ast_bridge_softmix::video_mode, and softmix_channel::video_talker.

Referenced by softmix_bridge_write().

◆ softmix_mixing_array_destroy()

static void softmix_mixing_array_destroy ( struct softmix_mixing_array mixing_array,
unsigned int  binaural_active 
)
static

Definition at line 1712 of file bridge_softmix.c.

1714{
1715 ast_free(mixing_array->buffers);
1716 if (binaural_active) {
1717 ast_free(mixing_array->chan_pairs);
1718 }
1719}
struct convolve_channel_pair ** chan_pairs

References ast_free, softmix_mixing_array::buffers, and softmix_mixing_array::chan_pairs.

Referenced by softmix_mixing_loop().

◆ softmix_mixing_array_grow()

static int softmix_mixing_array_grow ( struct softmix_mixing_array mixing_array,
unsigned int  num_entries,
unsigned int  binaural_active 
)
static

Definition at line 1721 of file bridge_softmix.c.

1723{
1724 int16_t **tmp;
1725
1726 /* give it some room to grow since memory is cheap but allocations can be expensive */
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");
1730 return -1;
1731 }
1732 mixing_array->buffers = tmp;
1733
1734 if (binaural_active) {
1735 struct convolve_channel_pair **tmp2;
1736 if (!(tmp2 = ast_realloc(mixing_array->chan_pairs,
1737 (mixing_array->max_num_entries * sizeof(struct convolve_channel_pair *))))) {
1738 ast_log(LOG_NOTICE, "Failed to re-allocate softmix mixing structure.\n");
1739 return -1;
1740 }
1741 mixing_array->chan_pairs = tmp2;
1742 }
1743 return 0;
1744}
#define ast_realloc(p, len)
A wrapper for realloc()
Definition: astmm.h:226
static int tmp()
Definition: bt_open.c:389
short int16_t
Definition: db.h:59
#define LOG_NOTICE

References ast_log, ast_realloc, softmix_mixing_array::buffers, softmix_mixing_array::chan_pairs, LOG_NOTICE, softmix_mixing_array::max_num_entries, and tmp().

Referenced by softmix_mixing_loop().

◆ softmix_mixing_array_init()

static int softmix_mixing_array_init ( struct softmix_mixing_array mixing_array,
unsigned int  starting_num_entries,
unsigned int  binaural_active 
)
static

Definition at line 1693 of file bridge_softmix.c.

1695{
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");
1700 return -1;
1701 }
1702 if (binaural_active) {
1703 if (!(mixing_array->chan_pairs = ast_calloc(mixing_array->max_num_entries,
1704 sizeof(struct convolve_channel_pair *)))) {
1705 ast_log(LOG_NOTICE, "Failed to allocate softmix mixing structure.\n");
1706 return -1;
1707 }
1708 }
1709 return 0;
1710}

References ast_calloc, ast_log, softmix_mixing_array::buffers, softmix_mixing_array::chan_pairs, LOG_NOTICE, and softmix_mixing_array::max_num_entries.

Referenced by softmix_mixing_loop().

◆ softmix_mixing_loop()

static int softmix_mixing_loop ( struct ast_bridge bridge)
static

Mixing loop.

Return values
0on success
-1on failure

Definition at line 1752 of file bridge_softmix.c.

1753{
1754 struct softmix_stats stats = { { 0 }, };
1755 struct softmix_mixing_array mixing_array;
1756 struct softmix_bridge_data *softmix_data = bridge->tech_pvt;
1757 struct ast_timer *timer;
1758 struct softmix_translate_helper trans_helper;
1760#ifdef BINAURAL_RENDERING
1761 int16_t bin_buf[MAX_DATALEN];
1762 int16_t ann_buf[MAX_DATALEN];
1763#endif
1764 unsigned int stat_iteration_counter = 0; /* counts down, gather stats at zero and reset. */
1765 int timingfd;
1766 int update_all_rates = 0; /* set this when the internal sample rate has changed */
1767 unsigned int idx;
1768 unsigned int x;
1769 int res = -1;
1770
1771 timer = softmix_data->timer;
1772 timingfd = ast_timer_fd(timer);
1773 softmix_translate_helper_init(&trans_helper, softmix_data->internal_rate);
1774 ast_timer_set_rate(timer, (1000 / softmix_data->internal_mixing_interval));
1775
1776 /* Give the mixing array room to grow, memory is cheap but allocations are expensive. */
1777 if (softmix_mixing_array_init(&mixing_array, bridge->num_channels + 10,
1778 bridge->softmix.binaural_active)) {
1779 goto softmix_cleanup;
1780 }
1781
1782 /*
1783 * XXX Softmix needs to use channel roles to determine who gets
1784 * what audio mixed.
1785 */
1786 while (!softmix_data->stop && bridge->num_active) {
1787 struct ast_bridge_channel *bridge_channel;
1788 int timeout = -1;
1789 struct ast_format *cur_slin = ast_format_cache_get_slin_by_rate(softmix_data->internal_rate);
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;
1793
1794 if (softmix_datalen > MAX_DATALEN) {
1795 /* This should NEVER happen, but if it does we need to know about it. Almost
1796 * all the memcpys used during this process depend on this assumption. Rather
1797 * than checking this over and over again through out the code, this single
1798 * verification is done on each iteration. */
1800 "Bridge %s: Conference mixing error, requested mixing length greater than mixing buffer.\n",
1801 bridge->uniqueid);
1802 goto softmix_cleanup;
1803 }
1804
1805 /* Grow the mixing array buffer as participants are added. */
1806 if (mixing_array.max_num_entries < bridge->num_channels
1807 && softmix_mixing_array_grow(&mixing_array, bridge->num_channels + 5,
1808 bridge->softmix.binaural_active)) {
1809 goto softmix_cleanup;
1810 }
1811
1812 /* init the number of buffers stored in the mixing array to 0.
1813 * As buffers are added for mixing, this number is incremented. */
1814 mixing_array.used_entries = 0;
1815
1816 /* These variables help determine if a rate change is required */
1817 if (!stat_iteration_counter) {
1818 memset(&stats, 0, sizeof(stats));
1821 }
1822
1823 /* If the sample rate has changed, update the translator helper */
1824 if (update_all_rates) {
1825 softmix_translate_helper_change_rate(&trans_helper, softmix_data->internal_rate);
1826 }
1827
1828#ifdef BINAURAL_RENDERING
1829 check_binaural_position_change(bridge, softmix_data);
1830#endif
1831
1832 /* If we need to do a REMB update to all video sources then do so */
1836 remb_update = 1;
1837 softmix_data->last_remb_update = ast_tvnow();
1838 }
1839
1840 /* Go through pulling audio from each factory that has it available */
1841 AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
1842 struct softmix_channel *sc = bridge_channel->tech_pvt;
1843
1844 if (!sc) {
1845 /* This channel failed to join successfully. */
1846 continue;
1847 }
1848
1849 /* Update the sample rate to match the bridge's native sample rate if necessary. */
1850 if (update_all_rates) {
1852 softmix_data->internal_mixing_interval, bridge_channel, 1, -1, -1, -1);
1853 }
1854
1855 /* If stat_iteration_counter is 0, then collect statistics during this mixing interaction */
1856 if (!stat_iteration_counter) {
1857 gather_softmix_stats(&stats, softmix_data, bridge_channel);
1858 }
1859
1860 /* if the channel is suspended, don't check for audio, but still gather stats */
1861 if (bridge_channel->suspended) {
1862 continue;
1863 }
1864
1865 /* Try to get audio from the factory if available */
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
1869 add_binaural_mixing(bridge, softmix_data, softmix_samples, &mixing_array, sc,
1870 ast_channel_name(bridge_channel->chan));
1871#endif
1872 mixing_array.used_entries++;
1873 }
1874 if (remb_update) {
1875 remb_collect_report(bridge, bridge_channel, softmix_data, sc);
1876 }
1877 ast_mutex_unlock(&sc->lock);
1878 }
1879
1880 /* mix it like crazy (non binaural channels)*/
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);
1885 }
1886 }
1887
1888#ifdef BINAURAL_RENDERING
1889 binaural_mixing(bridge, softmix_data, &mixing_array, bin_buf, ann_buf);
1890#endif
1891
1892 /* Next step go through removing the channel's own audio and creating a good frame... */
1893 AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
1894 struct softmix_channel *sc = bridge_channel->tech_pvt;
1895
1896 if (!sc || bridge_channel->suspended) {
1897 /* This channel failed to join successfully or is suspended. */
1898 continue;
1899 }
1900
1901 ast_mutex_lock(&sc->lock);
1902
1903 /* Make SLINEAR write frame from local buffer */
1905 "Replace softmix channel slin format");
1906#ifdef BINAURAL_RENDERING
1907 if (bridge->softmix.binaural_active && softmix_data->convolve.binaural_active
1908 && sc->binaural) {
1909 create_binaural_frame(bridge_channel, sc, bin_buf, ann_buf, softmix_datalen,
1910 softmix_samples, buf);
1911 } else
1912#endif
1913 {
1914 sc->write_frame.datalen = softmix_datalen;
1915 sc->write_frame.samples = softmix_samples;
1916 memcpy(sc->final_buf, buf, softmix_datalen);
1917 }
1918 /* process the softmix channel's new write audio */
1919 softmix_process_write_audio(&trans_helper,
1920 ast_channel_rawwriteformat(bridge_channel->chan), sc,
1921 softmix_data->default_sample_size);
1922
1923 ast_mutex_unlock(&sc->lock);
1924
1925 /* A frame is now ready for the channel. */
1926 ast_bridge_channel_queue_frame(bridge_channel, &sc->write_frame);
1927
1928 if (remb_update) {
1929 remb_send_report(bridge_channel, softmix_data, sc);
1930 }
1931 }
1932
1933 if (remb_update) {
1934 /* In case we are doing bridge level REMB reset the bitrate so we start fresh */
1935 softmix_data->bitrate = 0;
1936 }
1937
1938 update_all_rates = 0;
1939 if (!stat_iteration_counter) {
1940 update_all_rates = analyse_softmix_stats(&stats, softmix_data,
1941 bridge->softmix.binaural_active);
1942 stat_iteration_counter = SOFTMIX_STAT_INTERVAL;
1943 }
1944 stat_iteration_counter--;
1945
1946 ast_bridge_unlock(bridge);
1947 /* cleanup any translation frame data from the previous mixing iteration. */
1948 softmix_translate_helper_cleanup(&trans_helper);
1949 /* Wait for the timing source to tell us to wake up and get things done */
1950 ast_waitfor_n_fd(&timingfd, 1, &timeout, NULL);
1951 if (ast_timer_ack(timer, 1) < 0) {
1952 ast_log(LOG_ERROR, "Bridge %s: Failed to acknowledge timer in softmix.\n",
1953 bridge->uniqueid);
1954 ast_bridge_lock(bridge);
1955 goto softmix_cleanup;
1956 }
1957 ast_bridge_lock(bridge);
1958
1959 /* make sure to detect mixing interval changes if they occur. */
1961 && (bridge->softmix.internal_mixing_interval != softmix_data->internal_mixing_interval)) {
1963 ast_timer_set_rate(timer, (1000 / softmix_data->internal_mixing_interval));
1964 update_all_rates = 1; /* if the interval changes, the rates must be adjusted as well just to be notified new interval.*/
1965 }
1966 }
1967
1968 res = 0;
1969
1970softmix_cleanup:
1971 softmix_translate_helper_destroy(&trans_helper);
1973 return res;
1974}
#define ao2_t_replace(dst, src, tag)
Definition: astobj2.h:504
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition: bridge.h:481
#define ast_bridge_lock(bridge)
Lock the bridge.
Definition: bridge.h:470
static void gather_softmix_stats(struct softmix_stats *stats, const struct softmix_bridge_data *softmix_data, struct ast_bridge_channel *bridge_channel)
static void remb_collect_report(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct softmix_bridge_data *softmix_data, struct softmix_channel *sc)
static void softmix_process_write_audio(struct softmix_translate_helper *trans_helper, struct ast_format *raw_write_fmt, struct softmix_channel *sc, unsigned int default_sample_size)
static void remb_send_report(struct ast_bridge_channel *bridge_channel, struct softmix_bridge_data *softmix_data, struct softmix_channel *sc)
static void softmix_translate_helper_destroy(struct softmix_translate_helper *trans_helper)
static unsigned int analyse_softmix_stats(struct softmix_stats *stats, struct softmix_bridge_data *softmix_data, int binaural_active)
static void softmix_mixing_array_destroy(struct softmix_mixing_array *mixing_array, unsigned int binaural_active)
static int softmix_mixing_array_init(struct softmix_mixing_array *mixing_array, unsigned int starting_num_entries, unsigned int binaural_active)
static void softmix_translate_helper_cleanup(struct softmix_translate_helper *trans_helper)
static int16_t * softmix_process_read_audio(struct softmix_channel *sc, unsigned int num_samples)
#define SOFTMIX_STAT_INTERVAL
Number of mixing iterations to perform between gathering statistics.
static void softmix_translate_helper_change_rate(struct softmix_translate_helper *trans_helper, unsigned int sample_rate)
static int softmix_mixing_array_grow(struct softmix_mixing_array *mixing_array, unsigned int num_entries, unsigned int binaural_active)
static void softmix_translate_helper_init(struct softmix_translate_helper *trans_helper, unsigned int sample_rate)
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.
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.
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.
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 MAX_DATALEN
static struct ast_timer * timer
Definition: chan_iax2.c:364
int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
Waits for input on an fd.
Definition: channel.c:2980
struct ast_format * ast_channel_rawwriteformat(struct ast_channel *chan)
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
unsigned int suspended
unsigned int maximum_sample_rate
The maximum sample rate softmix uses to mix channels.
Definition: bridge.h:306
unsigned int internal_sample_rate
The internal sample rate softmix uses to mix channels.
Definition: bridge.h:285
unsigned int internal_mixing_interval
The mixing interval indicates how quickly softmix mixing should occur to mix audio.
Definition: bridge.h:293
unsigned int num_active
Definition: bridge.h:375
unsigned int num_channels
Definition: bridge.h:373
int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
Acknowledge a timer event.
Definition: timing.c:171
int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
Set the timing tick rate.
Definition: timing.c:166
int ast_timer_fd(const struct ast_timer *handle)
Get a poll()-able file descriptor for a timer.
Definition: timing.c:161
static force_inline void ast_slinear_saturated_add(short *input, short *value)
Definition: utils.h:450

References add_binaural_mixing(), analyse_softmix_stats(), ao2_t_replace, ast_bridge_channel_queue_frame(), ast_bridge_lock, ast_bridge_unlock, AST_BRIDGE_VIDEO_MODE_SFU, ast_channel_name(), ast_channel_rawwriteformat(), ast_format_cache_get_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_tvdiff_ms(), ast_tvnow(), ast_waitfor_n_fd(), softmix_channel::binaural, convolve_data::binaural_active, ast_bridge_softmix::binaural_active, binaural_mixing(), softmix_bridge_data::bitrate, softmix_bridge_data::bridge, buf, softmix_mixing_array::buffers, ast_bridge_channel::chan, ast_bridge::channels, check_binaural_position_change(), softmix_bridge_data::convolve, create_binaural_frame(), ast_frame::datalen, softmix_bridge_data::default_sample_size, softmix_channel::final_buf, ast_frame_subclass::format, gather_softmix_stats(), softmix_bridge_data::internal_mixing_interval, ast_bridge_softmix::internal_mixing_interval, softmix_bridge_data::internal_rate, ast_bridge_softmix::internal_sample_rate, softmix_bridge_data::last_remb_update, softmix_channel::lock, softmix_stats::locked_rate, LOG_ERROR, LOG_WARNING, MAX_DATALEN, softmix_mixing_array::max_num_entries, softmix_stats::maximum_rate, ast_bridge_softmix::maximum_sample_rate, ast_bridge_video_mode::mode, ast_bridge_video_mode::mode_data, NULL, ast_bridge::num_active, ast_bridge::num_channels, remb_collect_report(), ast_bridge_video_sfu_data::remb_send_interval, remb_send_report(), ast_frame::samples, set_softmix_bridge_data(), ast_bridge_video_mode::sfu_data, ast_bridge::softmix, 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(), softmix_bridge_data::stop, ast_frame::subclass, ast_bridge_channel::suspended, ast_bridge::tech_pvt, ast_bridge_channel::tech_pvt, softmix_bridge_data::timer, timer, ast_bridge::uniqueid, softmix_mixing_array::used_entries, ast_bridge_softmix::video_mode, and softmix_channel::write_frame.

Referenced by softmix_mixing_thread().

◆ softmix_mixing_thread()

static void * softmix_mixing_thread ( void *  data)
static

Definition at line 1985 of file bridge_softmix.c.

1986{
1987 struct softmix_bridge_data *softmix_data = data;
1988 struct ast_bridge *bridge = softmix_data->bridge;
1989
1990 ast_bridge_lock(bridge);
1991 if (bridge->callid) {
1993 }
1994
1995 ast_debug(1, "Bridge %s: starting mixing thread\n", bridge->uniqueid);
1996
1997 while (!softmix_data->stop) {
1998 if (!bridge->num_active) {
1999 /* Wait for something to happen to the bridge. */
2000 ast_bridge_unlock(bridge);
2001 ast_mutex_lock(&softmix_data->lock);
2002 if (!softmix_data->stop) {
2003 ast_cond_wait(&softmix_data->cond, &softmix_data->lock);
2004 }
2005 ast_mutex_unlock(&softmix_data->lock);
2006 ast_bridge_lock(bridge);
2007 continue;
2008 }
2009
2010 if (bridge->softmix.binaural_active && !softmix_data->binaural_init) {
2011#ifndef BINAURAL_RENDERING
2012 ast_bridge_lock(bridge);
2013 bridge->softmix.binaural_active = 0;
2014 ast_bridge_unlock(bridge);
2015 ast_log(LOG_WARNING, "Bridge: %s: Binaural rendering active by config but not "
2016 "compiled.\n", bridge->uniqueid);
2017#else
2018 /* Set and init binaural data if binaural is activated in the configuration. */
2020 softmix_data->default_sample_size = SOFTMIX_SAMPLES(softmix_data->internal_rate,
2021 softmix_data->internal_mixing_interval);
2022 /* If init for binaural processing fails we will fall back to mono audio processing. */
2023 if (init_convolve_data(&softmix_data->convolve, softmix_data->default_sample_size)
2024 == -1) {
2025 ast_bridge_lock(bridge);
2026 bridge->softmix.binaural_active = 0;
2027 ast_bridge_unlock(bridge);
2028 ast_log(LOG_ERROR, "Bridge: %s: Unable to allocate memory for "
2029 "binaural processing, Will only process mono audio.\n",
2030 bridge->uniqueid);
2031 }
2032 softmix_data->binaural_init = 1;
2033#endif
2034 }
2035
2036 if (softmix_mixing_loop(bridge)) {
2037 /*
2038 * A mixing error occurred. Sleep and try again later so we
2039 * won't flood the logs.
2040 */
2041 ast_bridge_unlock(bridge);
2042 sleep(1);
2043 ast_bridge_lock(bridge);
2044 }
2045 }
2046
2047 ast_bridge_unlock(bridge);
2048
2049 ast_debug(1, "Bridge %s: stopping mixing thread\n", bridge->uniqueid);
2050
2051 return NULL;
2052}
static int softmix_mixing_loop(struct ast_bridge *bridge)
Mixing loop.
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.
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition: logger.c:2308
#define ast_cond_wait(cond, mutex)
Definition: lock.h:205
Structure that contains information about a bridge.
Definition: bridge.h:349
ast_callid callid
Definition: bridge.h:361

References ast_bridge_lock, ast_bridge_unlock, ast_callid_threadassoc_add(), ast_cond_wait, ast_debug, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_bridge_softmix::binaural_active, softmix_bridge_data::binaural_init, softmix_bridge_data::bridge, ast_bridge::callid, softmix_bridge_data::cond, softmix_bridge_data::convolve, softmix_bridge_data::default_sample_size, init_convolve_data(), softmix_bridge_data::internal_mixing_interval, softmix_bridge_data::internal_rate, softmix_bridge_data::lock, LOG_ERROR, LOG_WARNING, NULL, ast_bridge::num_active, ast_bridge::softmix, SOFTMIX_BINAURAL_SAMPLE_RATE, softmix_mixing_loop(), SOFTMIX_SAMPLES, softmix_bridge_data::stop, and ast_bridge::uniqueid.

Referenced by softmix_bridge_create().

◆ softmix_pass_video_top_priority()

static void softmix_pass_video_top_priority ( struct ast_bridge bridge,
struct ast_frame frame 
)
static

Definition at line 862 of file bridge_softmix.c.

863{
864 struct ast_bridge_channel *cur;
865
867 if (cur->suspended) {
868 continue;
869 }
870 if (ast_bridge_is_video_src(bridge, cur->chan) == 1) {
872 break;
873 }
874 }
875}

References ast_bridge_channel_queue_frame(), ast_bridge_is_video_src(), AST_LIST_TRAVERSE, ast_bridge_channel::bridge, ast_bridge_channel::chan, ast_bridge::channels, and ast_bridge_channel::suspended.

Referenced by softmix_bridge_write_video().

◆ softmix_poke_thread()

static void softmix_poke_thread ( struct softmix_bridge_data softmix_data)
static

Definition at line 407 of file bridge_softmix.c.

408{
409 ast_mutex_lock(&softmix_data->lock);
410 ast_cond_signal(&softmix_data->cond);
411 ast_mutex_unlock(&softmix_data->lock);
412}

References ast_cond_signal, ast_mutex_lock, ast_mutex_unlock, softmix_bridge_data::cond, and softmix_bridge_data::lock.

Referenced by softmix_bridge_join(), and softmix_bridge_unsuspend().

◆ softmix_process_read_audio()

static int16_t * softmix_process_read_audio ( struct softmix_channel sc,
unsigned int  num_samples 
)
static

Definition at line 184 of file bridge_softmix.c.

185{
186 if ((ast_slinfactory_available(&sc->factory) >= num_samples) &&
187 ast_slinfactory_read(&sc->factory, sc->our_buf, num_samples)) {
188 sc->have_audio = 1;
189 return sc->our_buf;
190 }
191 sc->have_audio = 0;
192 return NULL;
193}
int ast_slinfactory_read(struct ast_slinfactory *sf, short *buf, size_t samples)
Read samples from a slinfactory.
Definition: slinfactory.c:145
short our_buf[MAX_DATALEN]

References ast_slinfactory_available(), ast_slinfactory_read(), softmix_channel::factory, softmix_channel::have_audio, NULL, and softmix_channel::our_buf.

Referenced by softmix_mixing_loop().

◆ softmix_process_write_audio()

static void softmix_process_write_audio ( struct softmix_translate_helper trans_helper,
struct ast_format raw_write_fmt,
struct softmix_channel sc,
unsigned int  default_sample_size 
)
static

Definition at line 203 of file bridge_softmix.c.

206{
208 int i;
209
210 /* If we provided any audio then take it out while in slinear format. */
211 if (sc->have_audio && !sc->binaural) {
212 for (i = 0; i < sc->write_frame.samples; i++) {
214 }
215 /* check to see if any entries exist for the format. if not we'll want
216 to remove it during cleanup */
217 AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) {
218 if (ast_format_cmp(entry->dst_format, raw_write_fmt) == AST_FORMAT_CMP_EQUAL) {
219 ++entry->num_times_requested;
220 break;
221 }
222 }
223 /* do not do any special write translate optimization if we had to make
224 * a special mix for them to remove their own audio. */
225 return;
226 } else if (sc->have_audio && sc->binaural > 0) {
227 /*
228 * Binaural audio requires special saturated substract since we have two
229 * audio signals per channel now.
230 */
231 softmix_process_write_binaural_audio(sc, default_sample_size);
232 return;
233 }
234
235 /* Attempt to optimize channels using the same translation path/codec. Build a list of entries
236 of translation paths and track the number of references for each type. Each one of the same
237 type should be able to use the same out_frame. Since the optimization is only necessary for
238 multiple channels (>=2) using the same codec make sure resources are allocated only when
239 needed and released when not (see also softmix_translate_helper_cleanup */
240 AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) {
241 if (sc->binaural != 0) {
242 continue;
243 }
244 if (ast_format_cmp(entry->dst_format, raw_write_fmt) == AST_FORMAT_CMP_EQUAL) {
245 entry->num_times_requested++;
246 } else {
247 continue;
248 }
249 if (!entry->trans_pvt && (entry->num_times_requested > 1)) {
250 entry->trans_pvt = ast_translator_build_path(entry->dst_format, trans_helper->slin_src);
251 }
252 if (entry->trans_pvt && !entry->out_frame) {
253 entry->out_frame = ast_translate(entry->trans_pvt, &sc->write_frame, 0);
254 }
255 if (entry->out_frame && entry->out_frame->frametype == AST_FRAME_VOICE
256 && entry->out_frame->datalen < MAX_DATALEN) {
257 ao2_replace(sc->write_frame.subclass.format, entry->out_frame->subclass.format);
258 memcpy(sc->final_buf, entry->out_frame->data.ptr, entry->out_frame->datalen);
259 sc->write_frame.datalen = entry->out_frame->datalen;
260 sc->write_frame.samples = entry->out_frame->samples;
261 }
262 break;
263 }
264
265 /* add new entry into list if this format destination was not matched. */
266 if (!entry && (entry = softmix_translate_helper_entry_alloc(raw_write_fmt))) {
267 AST_LIST_INSERT_HEAD(&trans_helper->entries, entry, entry);
268 }
269}
static struct softmix_translate_helper_entry * softmix_translate_helper_entry_alloc(struct ast_format *dst)
void softmix_process_write_binaural_audio(struct softmix_channel *sc, unsigned int default_sample_size)
Writes the binaural audio to a channel.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
char * data
Definition: search.h:42
struct softmix_translate_helper::@100 entries
struct ast_format * slin_src
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...
Definition: translate.c:566
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.
Definition: translate.c:486
static force_inline void ast_slinear_saturated_subtract(short *input, short *value)
Definition: utils.h:463

References ao2_replace, ast_format_cmp(), AST_FORMAT_CMP_EQUAL, AST_FRAME_VOICE, AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_slinear_saturated_subtract(), ast_translate(), ast_translator_build_path(), softmix_channel::binaural, entry::data, ast_frame::datalen, softmix_translate_helper::entries, softmix_channel::final_buf, ast_frame_subclass::format, softmix_channel::have_audio, MAX_DATALEN, NULL, softmix_channel::our_buf, ast_frame::samples, softmix_translate_helper::slin_src, softmix_process_write_binaural_audio(), softmix_translate_helper_entry_alloc(), ast_frame::subclass, and softmix_channel::write_frame.

Referenced by softmix_mixing_loop().

◆ softmix_translate_helper_change_rate()

static void softmix_translate_helper_change_rate ( struct softmix_translate_helper trans_helper,
unsigned int  sample_rate 
)
static

Definition at line 159 of file bridge_softmix.c.

160{
162
163 trans_helper->slin_src = ast_format_cache_get_slin_by_rate(sample_rate);
165 if (entry->trans_pvt) {
167 if (!(entry->trans_pvt = ast_translator_build_path(entry->dst_format, trans_helper->slin_src))) {
170 }
171 }
172 }
174}
static void * softmix_translate_helper_free_entry(struct softmix_translate_helper_entry *entry)
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
struct softmix_translate_helper_entry::@99 entry
void ast_translator_free_path(struct ast_trans_pvt *tr)
Frees a translator path Frees the given translator path structure.
Definition: translate.c:476

References ast_format_cache_get_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::entries, softmix_translate_helper_entry::entry, softmix_translate_helper::slin_src, and softmix_translate_helper_free_entry().

Referenced by softmix_mixing_loop().

◆ softmix_translate_helper_cleanup()

static void softmix_translate_helper_cleanup ( struct softmix_translate_helper trans_helper)
static

Definition at line 271 of file bridge_softmix.c.

272{
274
276 /* if it hasn't been requested then remove it */
277 if (!entry->num_times_requested) {
280 continue;
281 }
282
283 if (entry->out_frame) {
284 ast_frfree(entry->out_frame);
285 entry->out_frame = NULL;
286 }
287
288 /* nothing is optimized for a single path reference, so there is
289 no reason to continue to hold onto the codec */
290 if (entry->num_times_requested == 1 && entry->trans_pvt) {
292 entry->trans_pvt = NULL;
293 }
294
295 /* for each iteration (a mixing run) in the bridge softmix thread the number
296 of references to a given entry is recalculated, so reset the number of
297 times requested */
298 entry->num_times_requested = 0;
299 }
301}
#define ast_frfree(fr)

References ast_frfree, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_translator_free_path(), softmix_translate_helper::entries, softmix_translate_helper_entry::entry, NULL, and softmix_translate_helper_free_entry().

Referenced by softmix_mixing_loop().

◆ softmix_translate_helper_destroy()

static void softmix_translate_helper_destroy ( struct softmix_translate_helper trans_helper)
static

Definition at line 150 of file bridge_softmix.c.

151{
153
154 while ((entry = AST_LIST_REMOVE_HEAD(&trans_helper->entries, entry))) {
156 }
157}
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833

References AST_LIST_REMOVE_HEAD, softmix_translate_helper::entries, softmix_translate_helper_entry::entry, and softmix_translate_helper_free_entry().

Referenced by softmix_mixing_loop().

◆ softmix_translate_helper_entry_alloc()

static struct softmix_translate_helper_entry * softmix_translate_helper_entry_alloc ( struct ast_format dst)
static

Definition at line 117 of file bridge_softmix.c.

118{
120 if (!(entry = ast_calloc(1, sizeof(*entry)))) {
121 return NULL;
122 }
123 entry->dst_format = ao2_bump(dst);
124 /* initialize this to one so that the first time through the cleanup code after
125 allocation it won't be removed from the entry list */
126 entry->num_times_requested = 1;
127 return entry;
128}

References ao2_bump, ast_calloc, softmix_translate_helper_entry::entry, and NULL.

Referenced by softmix_process_write_audio().

◆ softmix_translate_helper_free_entry()

static void * softmix_translate_helper_free_entry ( struct softmix_translate_helper_entry entry)
static

Definition at line 130 of file bridge_softmix.c.

131{
132 ao2_cleanup(entry->dst_format);
133
134 if (entry->trans_pvt) {
136 }
137 if (entry->out_frame) {
138 ast_frfree(entry->out_frame);
139 }
141 return NULL;
142}

References ao2_cleanup, ast_free, ast_frfree, ast_translator_free_path(), and NULL.

Referenced by softmix_translate_helper_change_rate(), softmix_translate_helper_cleanup(), and softmix_translate_helper_destroy().

◆ softmix_translate_helper_init()

static void softmix_translate_helper_init ( struct softmix_translate_helper trans_helper,
unsigned int  sample_rate 
)
static

Definition at line 144 of file bridge_softmix.c.

145{
146 memset(trans_helper, 0, sizeof(*trans_helper));
147 trans_helper->slin_src = ast_format_cache_get_slin_by_rate(sample_rate);
148}

References ast_format_cache_get_slin_by_rate(), and softmix_translate_helper::slin_src.

Referenced by softmix_mixing_loop().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 2875 of file bridge_softmix.c.

2876{
2878 AST_TEST_UNREGISTER(sfu_append_source_streams);
2879 AST_TEST_UNREGISTER(sfu_remove_destination_streams);
2880 return 0;
2881}
int ast_bridge_technology_unregister(struct ast_bridge_technology *technology)
Unregister a bridge technology from use.
Definition: bridge.c:263
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

References ast_bridge_technology_unregister(), AST_TEST_UNREGISTER, and softmix_bridge.

Referenced by load_module().

Variable Documentation

◆ __mod_info

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, .support_level = AST_MODULE_SUPPORT_CORE, }
static

Definition at line 2894 of file bridge_softmix.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 2894 of file bridge_softmix.c.

◆ softmix_bridge

struct ast_bridge_technology softmix_bridge
static

Definition at line 2579 of file bridge_softmix.c.

Referenced by load_module(), and unload_module().