Skip to content

Commit

Permalink
[audiobridge] jitter buffer: manually update internal delay and set a…
Browse files Browse the repository at this point in the history
… max size (see #3353)
  • Loading branch information
atoppi committed Apr 8, 2024
1 parent e425898 commit 4d43aba
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 35 deletions.
45 changes: 26 additions & 19 deletions src/plugins/audiobridge-deps/jitter.c
Expand Up @@ -140,6 +140,7 @@ struct JitterBuffer_ {

spx_int32_t buffered; /**< Amount of data we think is still buffered by the application (timestamp units)*/

spx_uint32_t buffer_size;
JitterBufferPacket packets[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packets stored in the buffer */
spx_uint32_t arrival[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packet arrival time (0 means it was late, even though it's a valid timestamp) */

Expand Down Expand Up @@ -284,6 +285,7 @@ EXPORT JitterBuffer *jitter_buffer_init(int step_size)
jitter->destroy = NULL;
jitter->latency_tradeoff = 0;
jitter->auto_adjust = 1;
jitter->buffer_size = SPEEX_JITTER_MAX_BUFFER_SIZE;
tmp = 4;
jitter_buffer_ctl(jitter, JITTER_BUFFER_SET_MAX_LATE_RATE, &tmp);
jitter_buffer_reset(jitter);
Expand Down Expand Up @@ -372,7 +374,7 @@ EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *pa
/* Cleanup buffer (remove old packets that weren't played) */
if (!jitter->reset_state)
{
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
for (i=0;i<jitter->buffer_size;i++)
{
/* Make sure we don't discard a "just-late" packet in case we want to play it next (if we interpolate). */
if (jitter->packets[i].data && LE32(jitter->packets[i].timestamp + jitter->packets[i].span, jitter->pointer_timestamp))
Expand Down Expand Up @@ -409,18 +411,18 @@ EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *pa
{

/*Find an empty slot in the buffer*/
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
for (i=0;i<jitter->buffer_size;i++)
{
if (jitter->packets[i].data==NULL)
break;
}

/*No place left in the buffer, need to make room for it by discarding the oldest packet */
if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
if (i==jitter->buffer_size)
{
int earliest=jitter->packets[0].timestamp;
i=0;
for (j=1;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++)
for (j=1;j<jitter->buffer_size;j++)
{
if (!jitter->packets[i].data || LT32(jitter->packets[j].timestamp,earliest))
{
Expand Down Expand Up @@ -469,7 +471,7 @@ EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *pa
/** Get one packet from the jitter buffer */
EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset)
{
int i;
spx_uint32_t i;
unsigned int j;
spx_int16_t opt;

Expand All @@ -482,7 +484,7 @@ EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, s
int found = 0;
/* Find the oldest packet */
spx_uint32_t oldest=0;
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
for (i=0;i<jitter->buffer_size;i++)
{
if (jitter->packets[i].data && (!found || LT32(jitter->packets[i].timestamp,oldest)))
{
Expand Down Expand Up @@ -518,47 +520,46 @@ EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, s
jitter->interp_requested = 0;

jitter->buffered = packet->span - desired_span;

return JITTER_BUFFER_INSERTION;
}

/* Searching for the packet that fits best */

/* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
for (i=0;i<jitter->buffer_size;i++)
{
if (jitter->packets[i].data && jitter->packets[i].timestamp==jitter->pointer_timestamp && GE32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp+desired_span))
break;
}

/* If no match, try for an "older" packet that still spans (fully) the current chunk */
if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
if (i==jitter->buffer_size)
{
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
for (i=0;i<jitter->buffer_size;i++)
{
if (jitter->packets[i].data && LE32(jitter->packets[i].timestamp, jitter->pointer_timestamp) && GE32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp+desired_span))
break;
}
}

/* If still no match, try for an "older" packet that spans part of the current chunk */
if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
if (i==jitter->buffer_size)
{
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
for (i=0;i<jitter->buffer_size;i++)
{
if (jitter->packets[i].data && LE32(jitter->packets[i].timestamp, jitter->pointer_timestamp) && GT32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp))
break;
}
}

/* If still no match, try for earliest packet possible */
if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
if (i==jitter->buffer_size)
{
int found = 0;
spx_uint32_t best_time=0;
int best_span=0;
int besti=0;
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
for (i=0;i<jitter->buffer_size;i++)
{
/* check if packet starts within current chunk */
if (jitter->packets[i].data && LT32(jitter->packets[i].timestamp,jitter->pointer_timestamp+desired_span) && GE32(jitter->packets[i].timestamp,jitter->pointer_timestamp))
Expand All @@ -580,7 +581,7 @@ EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, s
}

/* If we find something */
if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE)
if (i!=jitter->buffer_size)
{
spx_int32_t offset;

Expand Down Expand Up @@ -683,12 +684,12 @@ EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, s
EXPORT int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet)
{
spx_uint32_t i, j;
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
for (i=0;i<jitter->buffer_size;i++)
{
if (jitter->packets[i].data && jitter->packets[i].timestamp==jitter->last_returned_timestamp)
break;
}
if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE)
if (i!=jitter->buffer_size)
{
/* Copy packet */
packet->len = jitter->packets[i].len;
Expand Down Expand Up @@ -785,7 +786,8 @@ EXPORT void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem)
/* Used like the ioctl function to control the jitter buffer parameters */
EXPORT int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
{
int count, i;
int count;
spx_uint32_t i;
switch(request)
{
case JITTER_BUFFER_SET_MARGIN:
Expand All @@ -796,7 +798,7 @@ EXPORT int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
break;
case JITTER_BUFFER_GET_AVALIABLE_COUNT:
count = 0;
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
for (i=0;i<jitter->buffer_size;i++)
{
if (jitter->packets[i].data && LE32(jitter->pointer_timestamp, jitter->packets[i].timestamp))
{
Expand Down Expand Up @@ -837,6 +839,11 @@ EXPORT int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
case JITTER_BUFFER_GET_LATE_COST:
*(spx_int32_t*)ptr = jitter->latency_tradeoff;
break;
case JITTER_BUFFER_SET_LIMIT:
spx_int32_t buffer_size = *(spx_int32_t*)ptr;
jitter->buffer_size = (buffer_size > 1 && buffer_size <= SPEEX_JITTER_MAX_BUFFER_SIZE) ? buffer_size : SPEEX_JITTER_MAX_BUFFER_SIZE;
jitter_buffer_reset(jitter);
break;
default:
speex_warning_int("Unknown jitter_buffer_ctl request: ", request);
return -1;
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/audiobridge-deps/speex/speex_jitter.h
Expand Up @@ -113,6 +113,8 @@ struct _JitterBufferPacket {
#define JITTER_BUFFER_SET_LATE_COST 12
#define JITTER_BUFFER_GET_LATE_COST 13

#define JITTER_BUFFER_SET_LIMIT 101


/** Initialises jitter buffer
*
Expand Down
28 changes: 12 additions & 16 deletions src/plugins/janus_audiobridge.c
Expand Up @@ -2133,7 +2133,7 @@ static int janus_audiobridge_resample(int16_t *input, int input_num, int input_r

/* Jitter Buffer and queue-in settings */
#define JITTER_BUFFER_MIN_PACKETS 2
#define JITTER_BUFFER_MAX_PACKETS 40
#define JITTER_BUFFER_MAX_PACKETS 50
#define JITTER_BUFFER_CHECK_USECS 1*G_USEC_PER_SEC
#define QUEUE_IN_MAX_PACKETS 4

Expand Down Expand Up @@ -5895,21 +5895,6 @@ void janus_audiobridge_incoming_rtp(janus_plugin_session *handle, janus_plugin_r
if(participant->jitter) {
janus_audiobridge_buffer_packet *pkt = janus_audiobridge_buffer_packet_create(packet);
janus_mutex_lock(&participant->qmutex);
/* Limit the size of the jitter buffer */
gint64 now = janus_get_monotonic_time();
if(participant->jitter_next_check == 0) {
/* Schedule next check */
participant->jitter_next_check = now + JITTER_BUFFER_CHECK_USECS;
} else if(now >= participant->jitter_next_check) {
spx_int32_t count = 0;
jitter_buffer_ctl(participant->jitter, JITTER_BUFFER_GET_AVALIABLE_COUNT, &count);
if(count > JITTER_BUFFER_MAX_PACKETS) {
JANUS_LOG(LOG_WARN, "Jitter buffer contains too many packets, clearing now (count=%d)\n", count);
janus_audiobridge_participant_clear_jitter_buffer(participant);
}
/* Schedule next check */
participant->jitter_next_check = now + JITTER_BUFFER_CHECK_USECS;
}
JitterBufferPacket jbp = {0};
jbp.data = (char *)pkt;
jbp.len = 0;
Expand Down Expand Up @@ -6429,6 +6414,10 @@ static void *janus_audiobridge_handler(void *data) {
jitter_buffer_ctl(participant->jitter, JITTER_BUFFER_SET_DESTROY_CALLBACK, &janus_audiobridge_buffer_packet_destroy);
spx_int32_t min_buffer_size = participant->codec == JANUS_AUDIOCODEC_OPUS ? (JITTER_BUFFER_MIN_PACKETS * 960) : (JITTER_BUFFER_MIN_PACKETS * 160);
jitter_buffer_ctl(participant->jitter, JITTER_BUFFER_SET_MARGIN, &min_buffer_size);
spx_int32_t max_buffer_size = JITTER_BUFFER_MAX_PACKETS;
jitter_buffer_ctl(participant->jitter, JITTER_BUFFER_SET_LIMIT, &max_buffer_size);
/* disable automatic adjustment */
jitter_buffer_update_delay(participant->jitter, NULL, NULL);
participant->inbuf = NULL;
participant->outbuf = NULL;
participant->encoder = NULL;
Expand Down Expand Up @@ -8551,6 +8540,7 @@ static void *janus_audiobridge_participant_thread(void *data) {
janus_audiobridge_buffer_packet *bpkt = NULL;
janus_audiobridge_rtp_relay_packet *pkt = NULL;
janus_audiobridge_rtp_relay_packet *mixedpkt = NULL;
int jitter_ticks = 0;
janus_rtp_header *rtp = NULL;
gint64 now = janus_get_monotonic_time(), before = now;
gboolean first = TRUE, use_fec = FALSE;
Expand All @@ -8577,6 +8567,12 @@ static void *janus_audiobridge_participant_thread(void *data) {
before += 20000;
if(participant->jitter) {
ret = jitter_buffer_get(participant->jitter, &jbp, participant->codec == JANUS_AUDIOCODEC_OPUS ? 960 : 160, NULL);
jitter_ticks++;
/* Adjust the buffer size every 50 ticks (~1 second) */
if(jitter_ticks == JITTER_BUFFER_MAX_PACKETS) {
jitter_buffer_update_delay(participant->jitter, NULL, NULL);
jitter_ticks = 0;
}
jitter_buffer_tick(participant->jitter);
if(ret != JITTER_BUFFER_OK) {
/* No packet in the jitter buffer? Move on the talking detection, if needed */
Expand Down

0 comments on commit 4d43aba

Please sign in to comment.