From ab93ea0e43381b5d885f65eef44b6b253f219526 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Fri, 14 Nov 2025 13:11:26 +0100 Subject: [PATCH] Smoothen AudioBridge mix instead of clamping/truncating (see #3593 and #3601) --- src/plugins/janus_audiobridge.c | 46 +++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/plugins/janus_audiobridge.c b/src/plugins/janus_audiobridge.c index d90d069913..ae834b85fb 100644 --- a/src/plugins/janus_audiobridge.c +++ b/src/plugins/janus_audiobridge.c @@ -1254,6 +1254,10 @@ room-: { #define JANUS_AUDIOBRIDGE_MAX_GROUPS 5 +/* Audio mixing with overflow protection - tuned to 0.9 of MAX/MIN to prevent clipping */ +#define JANUS_AUDIOBRIDGE_SHRT_MAX_TUNED 29491 +#define JANUS_AUDIOBRIDGE_SHRT_MIN_TUNED -29491 + /* Plugin methods */ janus_plugin *create(void); int janus_audiobridge_init(janus_callbacks *callback, const char *config_path); @@ -8451,6 +8455,30 @@ static void janus_audiobridge_update_wav_header(janus_audiobridge_room *audiobri } } +/* Helper to limit/clamp mixed audio */ +static inline void janus_audiobridge_limit_mix(opus_int32 *sumBuffer, opus_int16 *outBuffer, int samples) { + /* Find the loudest sample first, if there's one */ + opus_int32 loudest = 0, sample = 0; + int i = 0; + for(i=0; i JANUS_AUDIOBRIDGE_SHRT_MAX_TUNED && sample > loudest) + loudest = sample; + } + int gain = 100; + if(loudest > JANUS_AUDIOBRIDGE_SHRT_MAX_TUNED) { + /* We need to apply a negative gain to contain the mix */ + float gainF = (float)JANUS_AUDIOBRIDGE_SHRT_MAX_TUNED / (float)loudest; + gainF *= 100; + gain = gainF; + } + /* Transform to 16-bit samples, limiting if necessary */ + for(i=0; irecording != NULL && g_list_length(participants_list) > 0) { - for(i=0; irecording); /* Every 5 seconds we update the wav header */ gint64 now = janus_get_monotonic_time(); @@ -8905,9 +8930,7 @@ static void *janus_audiobridge_mixer_thread(void *data) { } } } - for(i=0; idata = g_malloc(samples*2); @@ -8965,8 +8988,7 @@ static void *janus_audiobridge_mixer_thread(void *data) { if(go_on) { /* By default, let's send the mixed frame to everybody */ if(groups_num == 0) { - for(i=0; i 0) { if(rfm->group == 0) { /* We're forwarding the main mix */ - for(i=0; igroup-1; - for(i=0; icodec == JANUS_AUDIOCODEC_OPUS) {