[xiph-commits] r14086 - in trunk/speex: include/speex libspeex

jm at svn.xiph.org jm at svn.xiph.org
Fri Nov 2 00:01:26 PDT 2007


Author: jm
Date: 2007-11-02 00:01:25 -0700 (Fri, 02 Nov 2007)
New Revision: 14086

Modified:
   trunk/speex/include/speex/speex_jitter.h
   trunk/speex/libspeex/jitter.c
Log:
jitter buffer: First attempt at using the application's bufer status and
timing estimation on the get() side.


Modified: trunk/speex/include/speex/speex_jitter.h
===================================================================
--- trunk/speex/include/speex/speex_jitter.h	2007-11-01 21:27:27 UTC (rev 14085)
+++ trunk/speex/include/speex/speex_jitter.h	2007-11-02 07:01:25 UTC (rev 14086)
@@ -159,6 +159,12 @@
 */
 void jitter_buffer_tick(JitterBuffer *jitter);
 
+/** Telling the jitter buffer about the remaining data in the application buffer
+ * @param jitter Jitter buffer state
+ * @param rem Amount of data buffered by the application (timestamp units)
+ */
+void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem);
+
 /** Used like the ioctl function to control the jitter buffer parameters
  * 
  * @param jitter Jitter buffer state

Modified: trunk/speex/libspeex/jitter.c
===================================================================
--- trunk/speex/libspeex/jitter.c	2007-11-01 21:27:27 UTC (rev 14085)
+++ trunk/speex/libspeex/jitter.c	2007-11-02 07:01:25 UTC (rev 14086)
@@ -53,8 +53,8 @@
 
 #define SPEEX_JITTER_MAX_BUFFER_SIZE 200   /**< Maximum number of packets in jitter buffer */
 
+#define TSUB(a,b) ((spx_int32_t)((a)-(b)))
 
-
 #define GT32(a,b) (((spx_int32_t)((a)-(b)))>0)
 #define GE32(a,b) (((spx_int32_t)((a)-(b)))>=0)
 #define LT32(a,b) (((spx_int32_t)((a)-(b)))<0)
@@ -65,8 +65,10 @@
    spx_uint32_t pointer_timestamp;                                        /**< Timestamp of what we will *get* next */
    spx_uint32_t current_timestamp;                                        /**< Timestamp of the local clock (what we will *play* next) */
    spx_uint32_t last_returned_timestamp;
+   spx_uint32_t next_stop;
    
    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) */
    
    void (*destroy) (void *);                                              /**< Callback for destroying a packet */
 
@@ -121,6 +123,7 @@
    /* Timestamp is actually undefined at this point */
    jitter->pointer_timestamp = 0;
    jitter->current_timestamp = 0;
+   jitter->next_stop = 0;
    jitter->reset_state = 1;
    jitter->lost_count = 0;
    jitter->loss_rate = 0;
@@ -139,18 +142,56 @@
    speex_free(jitter);
 }
 
+void update_histogram(JitterBuffer *jitter, spx_int32_t arrival_margin)
+{
+   int i;
+   if (arrival_margin >= -jitter->late_cutoff)
+   {
+      /* Here we compute the histogram based on the time of arrival of the packet.
+      This is based on a (first-order) recursive average. We keep both a short-term
+      histogram and a long-term histogram */
+      spx_int32_t int_margin;
+      /* First, apply the "damping" of the recursive average to all bins */
+      for (i=0;i<MAX_MARGIN;i++)
+      {
+         jitter->shortterm_margin[i] *= .98;
+         jitter->longterm_margin[i] *= .995;
+      }
+      /* What histogram bin the packet should be counted in */
+      int_margin = LATE_BINS + arrival_margin;
+      if (int_margin>MAX_MARGIN-1)
+         int_margin = MAX_MARGIN-1;
+      if (int_margin<0)
+         int_margin = 0;
+      /* Add the packet to the right bin */
+      jitter->shortterm_margin[int_margin] += .02;
+      jitter->longterm_margin[int_margin] += .005;
+   } else {
+      /* Packet has arrived *way* too late, we pretty much consider it lost and not take it into account in the histogram */
+      /*fprintf (stderr, "way too late = %d\n", arrival_margin);*/
+      if (jitter->lost_count>20)
+      {
+         jitter_buffer_reset(jitter);
+      }
+   }
+}
+
 /** Put one packet into the jitter buffer */
 void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
 {
    int i,j;
+   int late;
    spx_int32_t arrival_margin;
    spx_int32_t arrival_time;
    /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/
+   
+   /* Syncing on the first packet to arrive */
    if (jitter->reset_state)
    {
       jitter->reset_state=0;
       jitter->pointer_timestamp = packet->timestamp;
       jitter->current_timestamp = packet->timestamp;
+      jitter->next_stop = packet->timestamp;
       /*fprintf(stderr, "reset to %d\n", timestamp);*/
    }
    
@@ -169,107 +210,79 @@
       }
    }
 
-   /*Find an empty slot in the buffer*/
-   for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+   fprintf(stderr, "arrival: %d %d %d\n", packet->timestamp, jitter->next_stop, jitter->pointer_timestamp);
+   /* Check if packet is late (could still be useful though) */
+   if (LT32(packet->timestamp, jitter->next_stop))
    {
-      if (jitter->packets[i].data==NULL)
-         break;
+      fprintf(stderr, "late by %d\n", jitter->next_stop - packet->timestamp);
+      
+      /* The arrival margin is how much in advance (or in this case late) the packet it (in resolution units) */
+      arrival_margin = (((spx_int32_t)packet->timestamp) - ((spx_int32_t)jitter->next_stop))/jitter->resolution - jitter->buffer_margin;
+   
+      fprintf(stderr, "put arrival_margin = %d\n", arrival_margin);
+
+      update_histogram(jitter, arrival_margin);
+      late = 1;
+   } else {
+      late = 0;
    }
+   
+   /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */
+   if (GE32(packet->timestamp+packet->span, jitter->pointer_timestamp))
+   {
 
-   /*fprintf(stderr, "%d %d %f\n", timestamp, jitter->pointer_timestamp, jitter->drift_average);*/
-   /*No place left in the buffer*/
-   if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
-   {
-      int earliest=jitter->packets[0].timestamp;
-      i=0;
-      for (j=1;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++)
+      /*Find an empty slot in the buffer*/
+      for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
       {
-         if (!jitter->packets[i].data || LT32(jitter->packets[j].timestamp,earliest))
+         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)
+      {
+         int earliest=jitter->packets[0].timestamp;
+         i=0;
+         for (j=1;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++)
          {
-            earliest = jitter->packets[j].timestamp;
-            i=j;
+            if (!jitter->packets[i].data || LT32(jitter->packets[j].timestamp,earliest))
+            {
+               earliest = jitter->packets[j].timestamp;
+               i=j;
+            }
          }
+         if (jitter->destroy)
+            jitter->destroy(jitter->packets[i].data);
+         else
+            speex_free(jitter->packets[i].data);
+         jitter->packets[i].data=NULL;
+         if (jitter->lost_count>20)
+         {
+            jitter_buffer_reset(jitter);
+         }
+         /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/      
       }
+   
+      /* Copy packet in buffer */
       if (jitter->destroy)
-         jitter->destroy(jitter->packets[i].data);
-      else
-         speex_free(jitter->packets[i].data);
-      jitter->packets[i].data=NULL;
-      if (jitter->lost_count>20)
       {
-         jitter_buffer_reset(jitter);
+         jitter->packets[i].data = packet->data;
+      } else {
+         jitter->packets[i].data=(char*)speex_alloc(packet->len);
+         for (j=0;j<packet->len;j++)
+            jitter->packets[i].data[j]=packet->data[j];
       }
-      /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/      
+      jitter->packets[i].timestamp=packet->timestamp;
+      jitter->packets[i].span=packet->span;
+      jitter->packets[i].len=packet->len;
+      jitter->packets[i].user_data=packet->user_data;
+      if (late)
+         jitter->arrival[i] = 0;
+      else
+         jitter->arrival[i] = jitter->next_stop;
    }
    
-   /* Copy packet in buffer */
-   if (jitter->destroy)
-   {
-      jitter->packets[i].data = packet->data;
-   } else {
-      jitter->packets[i].data=(char*)speex_alloc(packet->len);
-      for (j=0;j<packet->len;j++)
-         jitter->packets[i].data[j]=packet->data[j];
-   }
-   jitter->packets[i].timestamp=packet->timestamp;
-   jitter->packets[i].span=packet->span;
-   jitter->packets[i].len=packet->len;
-   jitter->packets[i].user_data=packet->user_data;
    
-   if (jitter->sub_clock == -1)
-      arrival_time = jitter->pointer_timestamp;
-   else
-      arrival_time = jitter->current_timestamp + jitter->sub_clock;
-   
-   if (jitter->current_timestamp + jitter->sub_clock > jitter->pointer_timestamp)
-      speex_warning("something's wrong with the time");
-   
-   /* Adjust the buffer size depending on network conditions.
-      The arrival margin is how much in advance (or late) the packet it */
-   /* FIXME: We might be one tick off in considering what's late */
-   arrival_margin = (((spx_int32_t)packet->timestamp) - ((spx_int32_t)arrival_time))/jitter->resolution - jitter->buffer_margin;
-   
-   if (arrival_margin >= -jitter->late_cutoff)
-   {
-      /* Here we compute the histogram based on the time of arrival of the packet.
-         This is based on a (first-order) recursive average. We keep both a short-term
-         histogram and a long-term histogram */
-      spx_int32_t int_margin;
-      /* First, apply the "damping" of the recursive average to all bins */
-      for (i=0;i<MAX_MARGIN;i++)
-      {
-         jitter->shortterm_margin[i] *= .98;
-         jitter->longterm_margin[i] *= .995;
-      }
-      /* What histogram bin the packet should be counted in */
-      int_margin = LATE_BINS + arrival_margin;
-      if (int_margin>MAX_MARGIN-1)
-         int_margin = MAX_MARGIN-1;
-      if (int_margin<0)
-         int_margin = 0;
-      /* Add the packet to the right bin */
-      jitter->shortterm_margin[int_margin] += .02;
-      jitter->longterm_margin[int_margin] += .005;
-   } else {
-      /* Packet has arrived *way* too late, we pretty much consider it lost and not take it into account in the histogram */
-      /*fprintf (stderr, "way too late = %d\n", arrival_margin);*/
-      if (jitter->lost_count>20)
-      {
-         jitter_buffer_reset(jitter);
-      }
-   }
-#if 0 /* Enable to check how much is being buffered */
-   if (rand()%1000==0)
-   {
-      int count = 0;
-      for (j=0;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++)
-      {
-         if (jitter->buf[j])
-            count++;
-      }
-      fprintf (stderr, "buffer_size = %d\n", count);
-   }
-#endif
 }
 
 /** Get one packet from the jitter buffer */
@@ -301,6 +314,8 @@
       packet->span = jitter->delay_step;
       jitter->pointer_timestamp += jitter->delay_step;
       packet->len = 0;
+      fprintf (stderr, "Deferred interpolate\n");
+      
       return JITTER_BUFFER_MISSING;
    }
    /*fprintf (stderr, "get packet %d %d\n", jitter->pointer_timestamp, jitter->current_timestamp);*/
@@ -393,10 +408,29 @@
    /* If we find something */
    if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE)
    {
+      
+      
       /* We (obviously) haven't lost this packet */
       jitter->lost_count = 0;
       jitter->loss_rate = .999*jitter->loss_rate;
-      /* Check for potential overflow */
+      
+      /* In this case, 0 isn't as a valid timestamp */
+      if (jitter->arrival[i] != 0)
+      {
+         spx_int32_t arrival_margin;
+         fprintf(stderr, "early by %d\n", jitter->packets[i].timestamp - jitter->arrival[i]);
+         
+         /* The arrival margin is how much in advance (or in this case late) the packet it (in resolution units) */
+         arrival_margin = (((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]))/jitter->resolution - jitter->buffer_margin;
+   
+         fprintf(stderr, "get arrival_margin = %d\n", arrival_margin);
+
+         update_histogram(jitter, arrival_margin);
+
+      }
+      
+      
+      /* FIXME: Check for potential overflow */
       packet->len = jitter->packets[i].len;
       /* Copy packet */
       if (jitter->destroy)
@@ -420,6 +454,7 @@
       packet->user_data = jitter->packets[i].user_data;
       /* Point to the end of the current packet */
       jitter->pointer_timestamp = jitter->packets[i].timestamp+jitter->packets[i].span;
+
       if (incomplete)
          return JITTER_BUFFER_INCOMPLETE;
       else
@@ -456,6 +491,8 @@
       jitter->longterm_margin[0] = 0;            
       jitter->pointer_timestamp -= jitter->delay_step;
       jitter->current_timestamp -= jitter->delay_step;
+      fprintf (stderr, "Forced to interpolate\n");
+
       /*fprintf (stderr, "i");*/
       /*fprintf (stderr, "interpolate (getting some slack)\n");*/
    }
@@ -509,8 +546,14 @@
    if (jitter->sub_clock == -1)
       jitter->sub_clock = 0;
    jitter->sub_clock += jitter->resolution;
+   jitter->next_stop = jitter->pointer_timestamp;
 }
 
+void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem)
+{
+   jitter->next_stop = jitter->pointer_timestamp - rem;
+}
+
 /* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */
 int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
 {
@@ -560,6 +603,7 @@
       jitter->pointer_timestamp -= jitter->delay_step;
       jitter->current_timestamp -= jitter->delay_step;
       jitter->interp_requested = 1;
+      fprintf (stderr, "Decision to interpolate\n");
       return JITTER_BUFFER_ADJUST_INTERPOLATE;
    
    } else if (late_ratio_short + ontime_ratio_short < .005 && late_ratio_long + ontime_ratio_long < .01 && early_ratio_short > .8)
@@ -578,6 +622,7 @@
       /*fprintf (stderr, "d");*/
       jitter->pointer_timestamp += jitter->delay_step;
       jitter->current_timestamp += jitter->delay_step;
+      fprintf (stderr, "Decision to drop\n");
       return JITTER_BUFFER_ADJUST_DROP;
    }
    



More information about the commits mailing list