summaryrefslogtreecommitdiffstats
path: root/apps/codecs/libspeex/jitter.c
diff options
context:
space:
mode:
authorThom Johansen <thomj@rockbox.org>2007-11-14 02:15:56 +0000
committerThom Johansen <thomj@rockbox.org>2007-11-14 02:15:56 +0000
commit85b325fdb991a0602a2f16a55fc1df2c303aded1 (patch)
tree6eba0129ce3cc84831b37e2ed64c473d053317ac /apps/codecs/libspeex/jitter.c
parent91f618f1ba1e507a9aa1cf7ee87eaf0370272b17 (diff)
downloadrockbox-85b325fdb991a0602a2f16a55fc1df2c303aded1.tar.gz
rockbox-85b325fdb991a0602a2f16a55fc1df2c303aded1.zip
Sync Speex to SVN. Disable stereo compatibility hack since we don't needed it and it produced warnings. Remove unneeded math.h
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15613 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/libspeex/jitter.c')
-rw-r--r--apps/codecs/libspeex/jitter.c753
1 files changed, 521 insertions, 232 deletions
diff --git a/apps/codecs/libspeex/jitter.c b/apps/codecs/libspeex/jitter.c
index 57bb4c2958..e31a131bba 100644
--- a/apps/codecs/libspeex/jitter.c
+++ b/apps/codecs/libspeex/jitter.c
@@ -32,12 +32,27 @@
*/
+/*
+TODO:
+- Write generic functions for computing stats and shifting the histogram
+- Take into account the delay step when computing the stats and when shifting
+- Linked list structure for holding the packets instead of the current fixed-size array
+ + return memory to a pool
+ + allow pre-allocation of the pool
+ + optional max number of elements
+- Statistics
+ + drift
+ + loss
+ + late
+ + jitter
+ + buffering delay
+*/
#ifdef HAVE_CONFIG_H
#include "config-speex.h"
#endif
-#include "misc.h"
+#include "arch.h"
#include <speex/speex.h>
#include <speex/speex_bits.h>
#include <speex/speex_jitter.h>
@@ -52,29 +67,157 @@
#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)
#define LE32(a,b) (((spx_int32_t)((a)-(b)))<=0)
+#define MAX_TIMINGS 20
+#define MAX_BUFFERS 3
+#define TOP_DELAY 25
+#define WINDOW_SIZE 200
+
+struct TimingBuffer {
+ int filled;
+ int curr_count;
+ spx_int16_t timing[MAX_TIMINGS];
+ spx_int16_t counts[MAX_TIMINGS];
+};
+
+static void tb_init(struct TimingBuffer *tb)
+{
+ tb->filled = 0;
+ tb->curr_count = 0;
+}
+
+static void tb_add(struct TimingBuffer *tb, spx_int16_t timing)
+{
+ int pos;
+ /*fprintf(stderr, "timing = %d\n", timing);*/
+ /*fprintf(stderr, "timing = %d, latest = %d, earliest = %d, filled = %d\n", timing, tb->timing[0], tb->timing[tb->filled-1], tb->filled);*/
+ if (tb->filled >= MAX_TIMINGS && timing >= tb->timing[tb->filled-1])
+ {
+ tb->curr_count++;
+ return;
+ }
+ pos = 0;
+ /* FIXME: Do bisection instead of linear search */
+ while (pos<tb->filled && timing >= tb->timing[pos])
+ {
+ pos++;
+ }
+
+ /*fprintf(stderr, "pos = %d filled = %d\n", pos, tb->filled);*/
+ speex_assert(pos <= tb->filled && pos < MAX_TIMINGS);
+ fprintf(stderr, "OK\n");
+ if (pos < tb->filled)
+ {
+ int move_size = tb->filled-pos;
+ if (tb->filled == MAX_TIMINGS)
+ move_size -= 1;
+ /*fprintf(stderr, "speex_move(%d %d %d)\n", pos+1, pos, move_size);*/
+ speex_move(&tb->timing[pos+1], &tb->timing[pos], move_size*sizeof(tb->timing[0]));
+ speex_move(&tb->counts[pos+1], &tb->counts[pos], move_size*sizeof(tb->counts[0]));
+ }
+ /*fprintf(stderr, "moved\n");*/
+ tb->timing[pos] = timing;
+ tb->counts[pos] = tb->curr_count;
+ /*{
+ int i;
+ for (i=0;i<MAX_TIMINGS;i++)
+ fprintf(stderr, "%d ", tb->timing[i]);
+ fprintf(stderr, "\n");
+ }*/
+ tb->curr_count++;
+ if (tb->filled<MAX_TIMINGS)
+ tb->filled++;
+ /*fprintf(stderr, "added\n");*/
+}
+
+/** Based on available data, this computes the optimal delay for the jitter buffer.
+ The optimised function is in timestamp units and is:
+ cost = delay + late_factor*[number of frames that would be late if we used that delay]
+ @param tb Array of buffers
+ @param late_factor Equivalent cost of a late frame (in timestamp units)
+*/
+static spx_int16_t tbs_get_opt_delay(struct TimingBuffer *tb, spx_int32_t late_factor)
+{
+ int i;
+ spx_int16_t opt=0;
+ spx_int32_t best_cost=0x7fffffff;
+ int late = 0;
+ int pos[MAX_BUFFERS];
+
+ /*fprintf(stderr, "tbs_get_opt_delay\n");*/
+ for (i=0;i<MAX_BUFFERS;i++)
+ pos[i] = 0;
+
+ for (i=0;i<TOP_DELAY;i++)
+ {
+ int j;
+ int next=-1;
+ int latest = 32767;
+ for (j=0;j<MAX_BUFFERS;j++)
+ {
+ if (pos[j] < tb[j].filled && tb[j].timing[pos[j]] < latest)
+ {
+ next = j;
+ latest = tb[j].timing[pos[j]];
+ }
+ }
+ late++;
+ if (next != -1)
+ {
+ spx_int32_t cost;
+ pos[next]++;
+ /* When considering reducing delay, "on-time" frames could twice (this provides hysteresis) */
+ if (latest > 0)
+ late++;
+ cost = -latest + late_factor*late;
+ /*fprintf(stderr, "cost %d = -%d + %d * %d\n", cost, latest, late_factor, late);*/
+ if (cost < best_cost)
+ {
+ best_cost = cost;
+ opt = latest;
+ }
+ } else {
+ break;
+ }
+ }
+ return opt;
+}
+
/** Jitter buffer structure */
struct JitterBuffer_ {
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) */
-
- char *buf[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Buffer of packets (NULL if slot is free) */
- spx_uint32_t timestamp[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Timestamp of packet */
- int span[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Timestamp of packet */
- int len[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Number of bytes in packet */
+ 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 */
- int tick_size; /**< Output granularity */
+ int resolution; /**< Time resolution for histogram (timestamp units) */
+ int delay_step; /**< Size of the steps when adjusting buffering (timestamp units) */
+ int res_delay_step; /**< Size of the steps when adjusting buffering (resolution units) */
int reset_state; /**< True if state was just reset */
int buffer_margin; /**< How many frames we want to keep in the buffer (lower bound) */
int late_cutoff; /**< How late must a packet be for it not to be considered at all */
int interp_requested; /**< An interpolation is requested by speex_jitter_update_delay() */
+ struct TimingBuffer _tb[MAX_BUFFERS]; /**< Don't use those directly */
+ struct TimingBuffer *timeBuffers[MAX_BUFFERS]; /**< Storing arrival time of latest frames so we can compute some stats */
+
+ float late_ratio_short;
+ float late_ratio_long;
+ float ontime_ratio_short;
+ float ontime_ratio_long;
+ float early_ratio_short;
+ float early_ratio_long;
+
int lost_count; /**< Number of consecutive lost packets */
float shortterm_margin[MAX_MARGIN]; /**< Short term margin histogram */
float longterm_margin[MAX_MARGIN]; /**< Long term margin histogram */
@@ -82,17 +225,21 @@ struct JitterBuffer_ {
};
/** Initialise jitter buffer */
-JitterBuffer *jitter_buffer_init(int tick)
+JitterBuffer *jitter_buffer_init(int resolution)
{
JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer));
if (jitter)
{
int i;
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
- jitter->buf[i]=NULL;
- jitter->tick_size = tick;
+ jitter->packets[i].data=NULL;
+ jitter->resolution = resolution;
+ jitter->delay_step = resolution;
+ jitter->res_delay_step = 1;
+ /*FIXME: Should this be 0 or 1?*/
jitter->buffer_margin = 1;
jitter->late_cutoff = 50;
+ jitter->destroy = NULL;
jitter_buffer_reset(jitter);
}
return jitter;
@@ -104,15 +251,18 @@ void jitter_buffer_reset(JitterBuffer *jitter)
int i;
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
{
- if (jitter->buf[i])
+ if (jitter->packets[i].data)
{
- speex_free(jitter->buf[i]);
- jitter->buf[i] = NULL;
+ if (jitter->destroy)
+ jitter->destroy(jitter->packets[i].data);
+ else
+ speex_free(jitter->packets[i].data);
+ jitter->packets[i].data = NULL;
}
}
/* 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;
@@ -121,6 +271,12 @@ void jitter_buffer_reset(JitterBuffer *jitter)
jitter->shortterm_margin[i] = 0;
jitter->longterm_margin[i] = 0;
}
+
+ for (i=0;i<MAX_BUFFERS;i++)
+ {
+ tb_init(&jitter->_tb[i]);
+ jitter->timeBuffers[i] = &jitter->_tb[i];
+ }
/*fprintf (stderr, "reset\n");*/
}
@@ -131,79 +287,45 @@ void jitter_buffer_destroy(JitterBuffer *jitter)
speex_free(jitter);
}
-/** Put one packet into the jitter buffer */
-void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
+static void update_timings(JitterBuffer *jitter, spx_int32_t timing)
{
- int i,j;
- spx_int32_t arrival_margin;
- /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/
- if (jitter->reset_state)
- {
- jitter->reset_state=0;
- jitter->pointer_timestamp = packet->timestamp;
- jitter->current_timestamp = packet->timestamp;
- /*fprintf(stderr, "reset to %d\n", timestamp);*/
- }
-
- /* Cleanup buffer (remove old packets that weren't played) */
- for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+ if (timing < -32767)
+ timing = -32767;
+ if (timing > 32767)
+ timing = 32767;
+ if (jitter->timeBuffers[0]->curr_count >= WINDOW_SIZE)
{
- /* Make sure we don't discard a "just-late" packet in case we want to play it next (if we interpolate). */
- if (jitter->buf[i] && LE32(jitter->timestamp[i] + jitter->span[i], jitter->pointer_timestamp))
- {
- /*fprintf (stderr, "cleaned (not played)\n");*/
- speex_free(jitter->buf[i]);
- jitter->buf[i] = NULL;
- }
+ int i;
+ /*fprintf(stderr, "Rotate buffer\n");*/
+ struct TimingBuffer *tmp = jitter->timeBuffers[MAX_BUFFERS-1];
+ for (i=MAX_BUFFERS-1;i>=1;i--)
+ jitter->timeBuffers[i] = jitter->timeBuffers[i-1];
+ jitter->timeBuffers[0] = tmp;
+ tb_init(jitter->timeBuffers[0]);
}
+ tb_add(jitter->timeBuffers[0], timing);
+ spx_int16_t opt = tbs_get_opt_delay(jitter->_tb, 2);
+ /*fprintf(stderr, "opt adjustment is %d\n", opt);*/
+}
- /*Find an empty slot in the buffer*/
- for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+static void shift_timings(JitterBuffer *jitter, spx_int16_t amount)
+{
+ int i, j;
+ for (i=0;i<MAX_BUFFERS;i++)
{
- if (jitter->buf[i]==NULL)
- break;
+ for (j=0;j<jitter->timeBuffers[i]->filled;i++)
+ jitter->timeBuffers[i]->timing[j] += amount;
}
+}
- /*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->timestamp[0];
- i=0;
- for (j=1;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++)
- {
- if (!jitter->buf[i] || LT32(jitter->timestamp[j],earliest))
- {
- earliest = jitter->timestamp[j];
- i=j;
- }
- }
- speex_free(jitter->buf[i]);
- jitter->buf[i]=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 */
- jitter->buf[i]=(char*)speex_alloc(packet->len);
- for (j=0;j<(int)packet->len;j++)
- jitter->buf[i][j]=packet->data[j];
- jitter->timestamp[i]=packet->timestamp;
- jitter->span[i]=packet->span;
- jitter->len[i]=packet->len;
-
- /* Adjust the buffer size depending on network conditions.
- The arrival margin is how much in advance (or late) the packet it */
- arrival_margin = (((spx_int32_t)packet->timestamp) - ((spx_int32_t)jitter->current_timestamp))/jitter->tick_size - jitter->buffer_margin;
-
+static 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 */
+ 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++)
@@ -228,88 +350,215 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
jitter_buffer_reset(jitter);
}
}
-#if 0 /* Enable to check how much is being buffered */
- if (rand()%1000==0)
+}
+
+static void shift_histogram(JitterBuffer *jitter, int amount)
+{
+ int i, c;
+ if (amount == 0)
+ return;
+ if (amount > 0)
{
- int count = 0;
- for (j=0;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++)
+ /* FIXME: This is terribly inefficient */
+ for (c=0;c<amount;c++)
{
- if (jitter->buf[j])
- count++;
+ jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2];
+ jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2];
+ for (i=MAX_MARGIN-3;i>=0;i--)
+ {
+ jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i];
+ jitter->longterm_margin[i+1] = jitter->longterm_margin[i];
+ }
+ jitter->shortterm_margin[0] = 0;
+ jitter->longterm_margin[0] = 0;
+ }
+ } else {
+ /* FIXME: This is terribly inefficient */
+ for (c=0;c<-amount;c++)
+ {
+ jitter->shortterm_margin[0] += jitter->shortterm_margin[1];
+ jitter->longterm_margin[0] += jitter->longterm_margin[1];
+ for (i=1;i<MAX_MARGIN-1;i++)
+ {
+ jitter->shortterm_margin[i] = jitter->shortterm_margin[i+1];
+ jitter->longterm_margin[i] = jitter->longterm_margin[i+1];
+ }
+ jitter->shortterm_margin[MAX_MARGIN-1] = 0;
+ jitter->longterm_margin[MAX_MARGIN-1] = 0;
}
- fprintf (stderr, "buffer_size = %d\n", count);
}
-#endif
}
-/** Get one packet from the jitter buffer */
-int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
+static void compute_statistics(JitterBuffer *jitter)
{
int i;
- unsigned int j;
- float late_ratio_short;
- float late_ratio_long;
- float ontime_ratio_short;
- float ontime_ratio_long;
- float early_ratio_short;
- float early_ratio_long;
- int chunk_size;
- int incomplete = 0;
-
- if (jitter->interp_requested)
+ jitter->late_ratio_short = 0;
+ jitter->late_ratio_long = 0;
+ /* Count the proportion of packets that are late */
+ for (i=0;i<LATE_BINS;i++)
{
- jitter->interp_requested = 0;
- if (start_offset)
- *start_offset = 0;
- packet->timestamp = jitter->pointer_timestamp;
- packet->span = jitter->tick_size;
- jitter->pointer_timestamp += jitter->tick_size;
- packet->len = 0;
- return JITTER_BUFFER_MISSING;
+ jitter->late_ratio_short += jitter->shortterm_margin[i];
+ jitter->late_ratio_long += jitter->longterm_margin[i];
}
- if (LT32(jitter->current_timestamp+jitter->tick_size, jitter->pointer_timestamp))
+
+ /* Count the proportion of packets that are just on time */
+ jitter->ontime_ratio_short = 0;
+ jitter->ontime_ratio_long = 0;
+ for (;i<LATE_BINS+jitter->res_delay_step;i++)
{
- jitter->current_timestamp = jitter->pointer_timestamp;
- speex_warning("did you forget to call jitter_buffer_tick() by any chance?");
+ jitter->ontime_ratio_short = jitter->shortterm_margin[i];
+ jitter->ontime_ratio_long = jitter->longterm_margin[i];
}
- /*fprintf (stderr, "get packet %d %d\n", jitter->pointer_timestamp, jitter->current_timestamp);*/
+
+ jitter->early_ratio_short = 0;
+ jitter->early_ratio_long = 0;
+ /* Count the proportion of packets that are early */
+ for (;i<MAX_MARGIN;i++)
+ {
+ jitter->early_ratio_short += jitter->shortterm_margin[i];
+ jitter->early_ratio_long += jitter->longterm_margin[i];
+ }
+}
- /* FIXME: This should be only what remaining of the current tick */
- chunk_size = jitter->tick_size;
+/** 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);*/
- /* Compiling arrival statistics */
+ /* Syncing on the first packet to arrive */
+ if (jitter->reset_state)
+ {
+ jitter->reset_state=0;
+ jitter->pointer_timestamp = packet->timestamp;
+ jitter->next_stop = packet->timestamp;
+ /*fprintf(stderr, "reset to %d\n", timestamp);*/
+ }
- late_ratio_short = 0;
- late_ratio_long = 0;
- /* Count the proportion of packets that are late */
- for (i=0;i<LATE_BINS;i++)
+ /* Cleanup buffer (remove old packets that weren't played) */
+ for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
{
- late_ratio_short += jitter->shortterm_margin[i];
- late_ratio_long += jitter->longterm_margin[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))
+ {
+ /*fprintf (stderr, "cleaned (not played)\n");*/
+ if (jitter->destroy)
+ jitter->destroy(jitter->packets[i].data);
+ else
+ speex_free(jitter->packets[i].data);
+ jitter->packets[i].data = NULL;
+ }
}
- /* Count the proportion of packets that are just on time */
- ontime_ratio_short = jitter->shortterm_margin[LATE_BINS];
- ontime_ratio_long = jitter->longterm_margin[LATE_BINS];
- early_ratio_short = early_ratio_long = 0;
- /* Count the proportion of packets that are early */
- for (i=LATE_BINS+1;i<MAX_MARGIN;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))
{
- early_ratio_short += jitter->shortterm_margin[i];
- early_ratio_long += jitter->longterm_margin[i];
+ /*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_timings(jitter, ((spx_int32_t)packet->timestamp) - ((spx_int32_t)jitter->next_stop));*/
+ update_histogram(jitter, arrival_margin);
+ late = 1;
+ } else {
+ late = 0;
}
- if (0&&jitter->pointer_timestamp%1000==0)
+
+ /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */
+ if (GE32(packet->timestamp+packet->span+jitter->delay_step, jitter->pointer_timestamp))
{
- /*fprintf (stderr, "%f %f %f %f %f %f\n", early_ratio_short, early_ratio_long, ontime_ratio_short, ontime_ratio_long, late_ratio_short, late_ratio_long);*/
- /*fprintf (stderr, "%f %f\n", early_ratio_short + ontime_ratio_short + late_ratio_short, early_ratio_long + ontime_ratio_long + late_ratio_long);*/
+
+ /*Find an empty slot in the buffer*/
+ for (i=0;i<SPEEX_JITTER_MAX_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)
+ {
+ int earliest=jitter->packets[0].timestamp;
+ i=0;
+ for (j=1;j<SPEEX_JITTER_MAX_BUFFER_SIZE;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->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 (late)
+ jitter->arrival[i] = 0;
+ else
+ jitter->arrival[i] = jitter->next_stop;
}
+}
+
+/** Get one packet from the jitter buffer */
+int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset)
+{
+ int i;
+ unsigned int j;
+ int incomplete = 0;
+
+ jitter->last_returned_timestamp = jitter->pointer_timestamp;
+
+ if (jitter->interp_requested)
+ {
+ jitter->interp_requested = 0;
+ if (start_offset)
+ *start_offset = 0;
+ packet->timestamp = jitter->pointer_timestamp;
+ packet->span = jitter->delay_step;
+
+ /* Increment the pointer because it got decremented in the delay update */
+ jitter->pointer_timestamp += jitter->delay_step;
+ packet->len = 0;
+ /*fprintf (stderr, "Deferred interpolate\n");*/
+
+ return JITTER_BUFFER_MISSING;
+ }
+
/* 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++)
{
- if (jitter->buf[i] && jitter->timestamp[i]==jitter->pointer_timestamp && GE32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp+chunk_size))
+ 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;
}
@@ -318,7 +567,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
{
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
{
- if (jitter->buf[i] && LE32(jitter->timestamp[i], jitter->pointer_timestamp) && GE32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp+chunk_size))
+ 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;
}
}
@@ -328,7 +577,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
{
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
{
- if (jitter->buf[i] && LE32(jitter->timestamp[i], jitter->pointer_timestamp) && GT32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp))
+ 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;
}
}
@@ -343,12 +592,12 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
{
/* check if packet starts within current chunk */
- if (jitter->buf[i] && LT32(jitter->timestamp[i],jitter->pointer_timestamp+chunk_size) && GE32(jitter->timestamp[i],jitter->pointer_timestamp))
+ if (jitter->packets[i].data && LT32(jitter->packets[i].timestamp,jitter->pointer_timestamp+desired_span) && GE32(jitter->packets[i].timestamp,jitter->pointer_timestamp))
{
- if (!found || LT32(jitter->timestamp[i],best_time) || (jitter->timestamp[i]==best_time && GT32(jitter->span[i],best_span)))
+ if (!found || LT32(jitter->packets[i].timestamp,best_time) || (jitter->packets[i].timestamp==best_time && GT32(jitter->packets[i].span,best_span)))
{
- best_time = jitter->timestamp[i];
- best_span = jitter->span[i];
+ best_time = jitter->packets[i].timestamp;
+ best_span = jitter->packets[i].span;
besti = i;
found = 1;
}
@@ -358,31 +607,62 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
{
i=besti;
incomplete = 1;
- /*fprintf (stderr, "incomplete: %d %d %d %d\n", jitter->timestamp[i], jitter->pointer_timestamp, chunk_size, jitter->span[i]);*/
+ /*fprintf (stderr, "incomplete: %d %d %d %d\n", jitter->packets[i].timestamp, jitter->pointer_timestamp, chunk_size, jitter->packets[i].span);*/
}
}
/* 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 */
- packet->len = jitter->len[i];
+
+ /* 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_timings(jitter, ((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]));*/
+
+ update_histogram(jitter, arrival_margin);
+
+ }
+
+
+ /* FIXME: Check for potential overflow */
+ packet->len = jitter->packets[i].len;
/* Copy packet */
- for (j=0;j<packet->len;j++)
- packet->data[j] = jitter->buf[i][j];
- /* Remove packet */
- speex_free(jitter->buf[i]);
- jitter->buf[i] = NULL;
+ if (jitter->destroy)
+ {
+ packet->data = jitter->packets[i].data;
+ } else {
+ for (j=0;j<packet->len;j++)
+ packet->data[j] = jitter->packets[i].data[j];
+ /* Remove packet */
+ speex_free(jitter->packets[i].data);
+ }
+ jitter->packets[i].data = NULL;
/* Set timestamp and span (if requested) */
if (start_offset)
- *start_offset = (spx_int32_t)jitter->timestamp[i]-(spx_int32_t)jitter->pointer_timestamp;
- packet->timestamp = jitter->timestamp[i];
- packet->span = jitter->span[i];
- /* Point at the end of the current packet */
- jitter->pointer_timestamp = jitter->timestamp[i]+jitter->span[i];
+ *start_offset = (spx_int32_t)jitter->packets[i].timestamp-(spx_int32_t)jitter->pointer_timestamp;
+
+ packet->timestamp = jitter->packets[i].timestamp;
+ jitter->last_returned_timestamp = packet->timestamp;
+
+ packet->span = jitter->packets[i].span;
+ 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
@@ -391,6 +671,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
/* If we haven't found anything worth returning */
+
/*fprintf (stderr, "not found\n");*/
jitter->lost_count++;
/*fprintf (stderr, "m");*/
@@ -398,34 +679,71 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
jitter->loss_rate = .999*jitter->loss_rate + .001;
if (start_offset)
*start_offset = 0;
- packet->timestamp = jitter->pointer_timestamp;
- packet->span = jitter->tick_size;
- jitter->pointer_timestamp += chunk_size;
- packet->len = 0;
- /* Adjusting the buffering bssed on the amount of packets that are early/on time/late */
- if (late_ratio_short > .1 || late_ratio_long > .03)
+ compute_statistics(jitter);
+
+ /* Should we force an increase in the buffer or just do normal interpolation? */
+ if (jitter->late_ratio_short > .1 || jitter->late_ratio_long > .03)
{
- /* If too many packets are arriving late */
- jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2];
- jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2];
- for (i=MAX_MARGIN-3;i>=0;i--)
- {
- jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i];
- jitter->longterm_margin[i+1] = jitter->longterm_margin[i];
- }
- jitter->shortterm_margin[0] = 0;
- jitter->longterm_margin[0] = 0;
- jitter->pointer_timestamp -= jitter->tick_size;
- jitter->current_timestamp -= jitter->tick_size;
- /*fprintf (stderr, "i");*/
- /*fprintf (stderr, "interpolate (getting some slack)\n");*/
+ /* Increase buffering */
+
+ /* Shift histogram to compensate */
+ shift_histogram(jitter, jitter->res_delay_step);
+
+ packet->timestamp = jitter->pointer_timestamp;
+ packet->span = jitter->delay_step;
+ /* Don't move the pointer_timestamp forward */
+ packet->len = 0;
+
+ /*jitter->pointer_timestamp -= jitter->delay_step;*/
+ /*fprintf (stderr, "Forced to interpolate\n");*/
+ } else {
+ /* Normal packet loss */
+ packet->timestamp = jitter->pointer_timestamp;
+ packet->span = desired_span;
+ jitter->pointer_timestamp += desired_span;
+ packet->len = 0;
+ /*fprintf (stderr, "Normal loss\n");*/
}
return JITTER_BUFFER_MISSING;
}
+int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet)
+{
+ int i, j;
+ for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+ {
+ if (jitter->packets[i].data && jitter->packets[i].timestamp==jitter->last_returned_timestamp)
+ break;
+ }
+ if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE)
+ {
+ /* Copy packet */
+ packet->len = jitter->packets[i].len;
+ if (jitter->destroy)
+ {
+ packet->data = jitter->packets[i].data;
+ } else {
+ for (j=0;j<packet->len;j++)
+ packet->data[j] = jitter->packets[i].data[j];
+ /* Remove packet */
+ speex_free(jitter->packets[i].data);
+ }
+ jitter->packets[i].data = NULL;
+ packet->timestamp = jitter->packets[i].timestamp;
+ packet->span = jitter->packets[i].span;
+ packet->user_data = jitter->packets[i].user_data;
+ return JITTER_BUFFER_OK;
+ } else {
+ packet->data = NULL;
+ packet->len = 0;
+ packet->span = 0;
+ return JITTER_BUFFER_MISSING;
+ }
+}
+
/** Get pointer timestamp of jitter buffer */
int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter)
{
@@ -434,81 +752,39 @@ int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter)
void jitter_buffer_tick(JitterBuffer *jitter)
{
- jitter->current_timestamp += jitter->tick_size;
+ 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)
{
int i;
- float late_ratio_short;
- float late_ratio_long;
- float ontime_ratio_short;
- float ontime_ratio_long;
- float early_ratio_short;
- float early_ratio_long;
- if (LT32(jitter->current_timestamp+jitter->tick_size, jitter->pointer_timestamp))
- {
- jitter->current_timestamp = jitter->pointer_timestamp;
- speex_warning("did you forget to call jitter_buffer_tick() by any chance?");
- }
- /*fprintf (stderr, "get packet %d %d\n", jitter->pointer_timestamp, jitter->current_timestamp);*/
+ compute_statistics(jitter);
- /* FIXME: This should be only what remaining of the current tick */
- late_ratio_short = 0;
- late_ratio_long = 0;
- /* Count the proportion of packets that are late */
- for (i=0;i<LATE_BINS;i++)
- {
- late_ratio_short += jitter->shortterm_margin[i];
- late_ratio_long += jitter->longterm_margin[i];
- }
- /* Count the proportion of packets that are just on time */
- ontime_ratio_short = jitter->shortterm_margin[LATE_BINS];
- ontime_ratio_long = jitter->longterm_margin[LATE_BINS];
- early_ratio_short = early_ratio_long = 0;
- /* Count the proportion of packets that are early */
- for (i=LATE_BINS+1;i<MAX_MARGIN;i++)
- {
- early_ratio_short += jitter->shortterm_margin[i];
- early_ratio_long += jitter->longterm_margin[i];
- }
-
/* Adjusting the buffering bssed on the amount of packets that are early/on time/late */
- if (late_ratio_short > .1 || late_ratio_long > .03)
+ if (jitter->late_ratio_short > .1 || jitter->late_ratio_long > .03)
{
/* If too many packets are arriving late */
- jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2];
- jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2];
- for (i=MAX_MARGIN-3;i>=0;i--)
- {
- jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i];
- jitter->longterm_margin[i+1] = jitter->longterm_margin[i];
- }
- jitter->shortterm_margin[0] = 0;
- jitter->longterm_margin[0] = 0;
- jitter->pointer_timestamp -= jitter->tick_size;
- jitter->current_timestamp -= jitter->tick_size;
+ shift_histogram(jitter, jitter->res_delay_step);
+
+ jitter->pointer_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)
+ } else if (jitter->late_ratio_short + jitter->ontime_ratio_short < .005 && jitter->late_ratio_long + jitter->ontime_ratio_long < .01 && jitter->early_ratio_short > .8)
{
/* Many frames arriving early */
- jitter->shortterm_margin[0] += jitter->shortterm_margin[1];
- jitter->longterm_margin[0] += jitter->longterm_margin[1];
- for (i=1;i<MAX_MARGIN-1;i++)
- {
- jitter->shortterm_margin[i] = jitter->shortterm_margin[i+1];
- jitter->longterm_margin[i] = jitter->longterm_margin[i+1];
- }
- jitter->shortterm_margin[MAX_MARGIN-1] = 0;
- jitter->longterm_margin[MAX_MARGIN-1] = 0;
- /*fprintf (stderr, "drop frame\n");*/
- /*fprintf (stderr, "d");*/
- jitter->pointer_timestamp += jitter->tick_size;
- jitter->current_timestamp += jitter->tick_size;
+ shift_histogram(jitter, -jitter->res_delay_step);
+
+ jitter->pointer_timestamp += jitter->delay_step;
+ /*fprintf (stderr, "Decision to drop\n");*/
return JITTER_BUFFER_ADJUST_DROP;
}
@@ -531,13 +807,26 @@ int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
count = 0;
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
{
- if (jitter->buf[i] && LE32(jitter->pointer_timestamp, jitter->timestamp[i]))
+ if (jitter->packets[i].data && LE32(jitter->pointer_timestamp, jitter->packets[i].timestamp))
{
count++;
}
}
*(spx_int32_t*)ptr = count;
break;
+ case JITTER_BUFFER_SET_DESTROY_CALLBACK:
+ jitter->destroy = (void (*) (void *))ptr;
+ break;
+ case JITTER_BUFFER_GET_DESTROY_CALLBACK:
+ *(void (**) (void *))ptr = jitter->destroy;
+ break;
+ case JITTER_BUFFER_SET_DELAY_STEP:
+ jitter->delay_step = *(spx_int32_t*)ptr;
+ jitter->res_delay_step = jitter->delay_step/jitter->resolution;
+ break;
+ case JITTER_BUFFER_GET_DELAY_STEP:
+ *(spx_int32_t*)ptr = jitter->delay_step;
+ break;
default:
speex_warning_int("Unknown jitter_buffer_ctl request: ", request);
return -1;