[xiph-commits] r6836 - trunk/speex/libspeex

jm at dactyl.lonelymoon.com jm
Fri Jun 25 13:43:56 PDT 2004


Author: jm
Date: Fri Jun 25 13:43:56 2004
New Revision: 6836

Modified:
trunk/speex/libspeex/jitter.c
trunk/speex/libspeex/speex_jitter.h
Log:
Jitter buffer is now adaptive and should resume properly when link is lost.


Modified: trunk/speex/libspeex/jitter.c
===================================================================
--- trunk/speex/libspeex/jitter.c	2004-06-19 06:10:21 UTC (rev 6835)
+++ trunk/speex/libspeex/jitter.c	2004-06-20 04:52:29 UTC (rev 6836)
@@ -39,6 +39,7 @@
#include "speex.h"
#include "speex_bits.h"
#include "speex_jitter.h"
+#include <stdio.h>

void speex_jitter_init(SpeexJitter *jitter, void *decoder, int sampling_rate)
{
@@ -56,13 +57,12 @@
speex_bits_init(&jitter->current_packet);
jitter->valid_bits = 0;

-   jitter->buffer_size = 10;
+   jitter->buffer_size = 4;

jitter->pointer_timestamp = -jitter->frame_time * jitter->buffer_size;
-
-   jitter->underflow_count = 0;
-   jitter->drop_frame = 0;
-   jitter->interp_frame = 0;
+   jitter->reset_state = 1;
+   jitter->lost_count = 0;
+   jitter->loss_rate = 0;
}

void speex_jitter_destroy(SpeexJitter *jitter)
@@ -73,12 +73,28 @@
void speex_jitter_put(SpeexJitter *jitter, char *packet, int len, int timestamp)
{
int i,j;
-
+   int timestamp_offset;
+   int arrival_margin;
+
+   if (jitter->reset_state)
+   {
+      jitter->reset_state=0;
+      jitter->pointer_timestamp = timestamp-jitter->frame_time * jitter->buffer_size;
+      jitter->drift_average = 0;
+      jitter->late_ratio = 0;
+      jitter->early_ratio = 0;
+      jitter->ontime_ratio = 0;
+   }
+
/* Cleanup buffer (remove old packets that weren't played) */
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
{
if (jitter->timestamp[i]<jitter->pointer_timestamp)
+      {
jitter->len[i]=-1;
+         /*if (jitter->timestamp[i] != -1)
+            fprintf (stderr, "discarding %d %d\n", jitter->timestamp[i], jitter->pointer_timestamp);*/
+      }
}

/*Find an empty slot in the buffer*/
@@ -88,8 +104,10 @@
break;
}

+   /*fprintf(stderr, "%d %d %f\n", timestamp, jitter->pointer_timestamp, jitter->drift_average);*/
if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
{
+      fprintf (stderr, "Buffer is full, discarding frame\n");
/*No place left in the buffer*/

/*skip some frame(s) */
@@ -104,34 +122,70 @@
jitter->timestamp[i]=timestamp;
jitter->len[i]=len;

-   /* Detect when it's time to drop frames (too much stuff in buffer) */
-   if (timestamp-jitter->pointer_timestamp > (jitter->buffer_size+3)*jitter->frame_time)
-      jitter->drop_frame = 1;
-
-   /*Detect when it's time to interpolate a frame (not wnough stuff in buffer) */
-   if (timestamp-jitter->pointer_timestamp < (jitter->buffer_size-3)*jitter->frame_time)
-      jitter->underflow_count++;
-   else
-      jitter->underflow_count=0;
-   if (jitter->underflow_count > 10)
+   /* Don't count late packets when adjusting the synchro (we're taking care of them elsewhere) */
+   if (timestamp > jitter->pointer_timestamp)
{
-      jitter->underflow_count=0;
-      jitter->interp_frame = 1;
+      timestamp_offset = timestamp-jitter->pointer_timestamp - (jitter->buffer_size+1)*jitter->frame_time;
+      jitter->drift_average = .99*jitter->drift_average + .01*timestamp_offset;
+   } else {
+      fprintf (stderr, "frame for timestamp %d arrived too late\n", timestamp);
}

/* Adjust the buffer size depending on network conditions */
+   arrival_margin = (timestamp - jitter->pointer_timestamp - jitter->frame_time) - (int)jitter->drift_average;
+   if (arrival_margin >= -2*jitter->frame_time)
+   {
+      jitter->late_ratio *= .99;
+      jitter->early_ratio *= .99;
+      jitter->ontime_ratio *= .99;
+   }
+
+   if (arrival_margin < 0 && arrival_margin >= -3*jitter->frame_time)
+   {
+      jitter->late_ratio += .01;
+   } else if (arrival_margin <= jitter->frame_time && arrival_margin >= 0)
+   {
+      jitter->ontime_ratio += .01;
+   } else if (arrival_margin > jitter->frame_time)
+   {
+      jitter->early_ratio += .01;
+   }
+
+   if (jitter->late_ratio + jitter->ontime_ratio < .01 && jitter->early_ratio > .8)
+   {
+      jitter->buffer_size--;
+      jitter->early_ratio = 0;
+      jitter->drift_average += jitter->frame_time;
+      fprintf (stderr, "buffer %d -> %d\n", jitter->buffer_size+1, jitter->buffer_size);
+   }
+   if (jitter->late_ratio > .03)
+   {
+      jitter->buffer_size++;
+      jitter->late_ratio = 0;
+      jitter->drift_average -= jitter->frame_time;
+      fprintf (stderr, "buffer %d -> %d\n", jitter->buffer_size-1, jitter->buffer_size);
+   }
+   /*fprintf (stderr, "margin : %d %d %f %f %f %f\n", arrival_margin, jitter->buffer_size, 100*jitter->loss_rate, 100*jitter->late_ratio, 100*jitter->ontime_ratio, 100*jitter->early_ratio);*/
}

void speex_jitter_get(SpeexJitter *jitter, short *out)
{
int i;
int ret;
+   int drop, interp;
+   int drop_margin, interp_margin;

-   /* Handle frame interpolation (receiving too fast) */
-   if (jitter->interp_frame)
+   drop_margin = (1+jitter->buffer_size) * jitter->frame_time/2;
+   interp_margin = jitter->frame_time/2;
+   /*drop_margin = 15;
+   interp_margin = 15;*/
+
+   /* Handle frame interpolation (playing too fast) */
+   if (-jitter->drift_average > interp_margin)
{
+      fprintf (stderr, "interpolate frame\n");
speex_decode_int(jitter->dec, NULL, out);
-      jitter->interp_frame = 0;
+      jitter->drift_average += jitter->frame_time;
return;
}

@@ -139,10 +193,11 @@
jitter->pointer_timestamp += jitter->frame_time;

/* Handle frame dropping (receiving too fast) */
-   if (jitter->drop_frame)
+   if (jitter->drift_average > drop_margin)
{
+      fprintf (stderr, "drop frame\n");
jitter->pointer_timestamp += jitter->frame_time;
-      jitter->drop_frame = 0;
+      jitter->drift_average -= jitter->frame_time;
}

/* Send zeros while we fill in the buffer */
@@ -173,8 +228,17 @@
jitter->valid_bits = 0;
}

+      fprintf (stderr, "lost/late frame %d\n", jitter->pointer_timestamp);
/*Packet is late or lost*/
speex_decode_int(jitter->dec, NULL, out);
+      jitter->lost_count++;
+      if (jitter->lost_count>=25)
+      {
+         jitter->lost_count = 0;
+         jitter->reset_state = 1;
+         speex_decoder_ctl(jitter->dec, SPEEX_RESET_STATE, NULL);
+      }
+      jitter->loss_rate = .999*jitter->loss_rate + .001;
} else {
/* Found the right packet */
speex_bits_read_from(&jitter->current_packet, jitter->buf[i], jitter->len[i]);
@@ -189,8 +253,18 @@
for (i=0;i<jitter->frame_size;i++)
out[i]=0;
}
+      jitter->loss_rate = .999*jitter->loss_rate;
}


}

+int speex_jitter_get_pointer_timestamp(SpeexJitter *jitter)
+{
+   return jitter->pointer_timestamp;
+}
+
+int speex_jitter_set_buffersize(SpeexJitter *jitter, int size)
+{
+   jitter->buffer_size = size;
+}

Modified: trunk/speex/libspeex/speex_jitter.h
===================================================================
--- trunk/speex/libspeex/speex_jitter.h	2004-06-19 06:10:21 UTC (rev 6835)
+++ trunk/speex/libspeex/speex_jitter.h	2004-06-20 04:52:29 UTC (rev 6836)
@@ -59,11 +59,14 @@
void *dec;
int frame_size;
int frame_time;
-
-   int underflow_count;
-   int drop_frame;
-   int interp_frame;
-
+   int reset_state;
+
+   int lost_count;
+   float drift_average;
+   float late_ratio;
+   float ontime_ratio;
+   float early_ratio;
+   float loss_rate;
} SpeexJitter;

void speex_jitter_init(SpeexJitter *jitter, void *decoder, int sampling_rate);
@@ -74,6 +77,10 @@

void speex_jitter_get(SpeexJitter *jitter, short *out);

+int speex_jitter_get_pointer_timestamp(SpeexJitter *jitter);
+
+int speex_jitter_set_buffersize(SpeexJitter *jitter, int size);
+
#ifdef __cplusplus
}
#endif



More information about the commits mailing list