[xiph-commits] r14162 - in trunk/speex: include/speex libspeex
jm at svn.xiph.org
jm at svn.xiph.org
Thu Nov 15 20:45:36 PST 2007
Author: jm
Date: 2007-11-15 20:45:36 -0800 (Thu, 15 Nov 2007)
New Revision: 14162
Modified:
trunk/speex/include/speex/speex_jitter.h
trunk/speex/libspeex/jitter.c
Log:
jitter buffer: comments on new algo
Modified: trunk/speex/include/speex/speex_jitter.h
===================================================================
--- trunk/speex/include/speex/speex_jitter.h 2007-11-16 02:40:08 UTC (rev 14161)
+++ trunk/speex/include/speex/speex_jitter.h 2007-11-16 04:45:36 UTC (rev 14162)
@@ -90,22 +90,27 @@
/** Included because of an early misspelling (will remove in next release) */
#define JITTER_BUFFER_GET_AVALIABLE_COUNT 3
-/** */
+/** Assign a function to destroy unused packet. When setting that, the jitter
+ buffer no longer copies packet data. */
#define JITTER_BUFFER_SET_DESTROY_CALLBACK 4
/** */
#define JITTER_BUFFER_GET_DESTROY_CALLBACK 5
-/** */
+/** Tell the jitter buffer to only adjust the delay in multiples of the step parameter provided */
#define JITTER_BUFFER_SET_DELAY_STEP 6
/** */
#define JITTER_BUFFER_GET_DELAY_STEP 7
+/** Tell the jitter buffer to only do concealment in multiples of the size parameter provided */
#define JITTER_BUFFER_SET_CONCEALMENT_SIZE 8
#define JITTER_BUFFER_GET_CONCEALMENT_SIZE 9
+/** Absolute max amount of loss that can be tolerated regardless of the delay. Typical loss
+ should be half of that or less. */
#define JITTER_BUFFER_SET_MAX_LATE_RATE 10
#define JITTER_BUFFER_GET_MAX_LATE_RATE 11
+/** Equivalent cost of one percent late packet in timestamp units */
#define JITTER_BUFFER_SET_LATE_COST 12
#define JITTER_BUFFER_GET_LATE_COST 13
Modified: trunk/speex/libspeex/jitter.c
===================================================================
--- trunk/speex/libspeex/jitter.c 2007-11-16 02:40:08 UTC (rev 14161)
+++ trunk/speex/libspeex/jitter.c 2007-11-16 04:45:36 UTC (rev 14162)
@@ -79,11 +79,12 @@
#define MAX_BUFFERS 3
#define TOP_DELAY 20
+/** Buffer that keeps the time of arrival of the latest packets */
struct TimingBuffer {
- int filled;
- int curr_count;
- spx_int16_t timing[MAX_TIMINGS];
- spx_int16_t counts[MAX_TIMINGS];
+ int filled; /**< Number of entries occupied in "timing" and "counts"*/
+ int curr_count; /**< Number of packet timings we got (including those we discarded) */
+ spx_int16_t timing[MAX_TIMINGS]; /**< Sorted list of all timings ("latest" packets first) */
+ spx_int16_t counts[MAX_TIMINGS]; /**< Order the packets were put in (will be used for short-term estimate) */
};
static void tb_init(struct TimingBuffer *tb)
@@ -92,16 +93,18 @@
tb->curr_count = 0;
}
+/* Add the timing of a new packet to the TimingBuffer */
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);*/
+ /* Discard packet that won't make it into the list because they're too early */
if (tb->filled >= MAX_TIMINGS && timing >= tb->timing[tb->filled-1])
{
tb->curr_count++;
return;
}
+
+ /* Find where the timing info goes in the sorted list */
pos = 0;
/* FIXME: Do bisection instead of linear search */
while (pos<tb->filled && timing >= tb->timing[pos])
@@ -109,31 +112,24 @@
pos++;
}
- /*fprintf(stderr, "pos = %d filled = %d\n", pos, tb->filled);*/
speex_assert(pos <= tb->filled && pos < MAX_TIMINGS);
- /*fprintf(stderr, "OK\n");*/
+
+ /* Shift everything so we can perform the insertion */
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");*/
+ /* Insert */
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");*/
}
@@ -141,8 +137,8 @@
/** Jitter buffer structure */
struct JitterBuffer_ {
spx_uint32_t pointer_timestamp; /**< Timestamp of what we will *get* next */
- spx_uint32_t last_returned_timestamp;
- spx_uint32_t next_stop;
+ spx_uint32_t last_returned_timestamp; /**< Useful for getting the next packet with the same timestamp (for fragmented media) */
+ spx_uint32_t next_stop; /**< Estimated time the next get() will be called */
spx_int32_t buffered; /**< Amount of data we think is still buffered by the application (timestamp units)*/
@@ -192,11 +188,14 @@
tb = jitter->_tb;
+ /* Number of packet timings we have received (including those we didn't keep) */
tot_count = 0;
for (i=0;i<MAX_BUFFERS;i++)
tot_count += tb[i].curr_count;
if (tot_count==0)
return 0;
+
+ /* Compute cost for one lost packet */
if (jitter->latency_tradeoff != 0)
late_factor = jitter->latency_tradeoff * 100.0f / tot_count;
else
@@ -206,11 +205,14 @@
for (i=0;i<MAX_BUFFERS;i++)
pos[i] = 0;
+ /* Pick the TOP_DELAY "latest" packets (doesn't need to actually be late
+ for the current settings) */
for (i=0;i<TOP_DELAY;i++)
{
int j;
int next=-1;
int latest = 32767;
+ /* Pick latest amoung all sub-windows */
for (j=0;j<MAX_BUFFERS;j++)
{
if (pos[j] < tb[j].filled && tb[j].timing[pos[j]] < latest)
@@ -228,6 +230,8 @@
best = latest;
latest = ROUND_DOWN(latest, jitter->delay_step);
pos[next]++;
+
+ /* Actual cost function that tells us how bad using this delay would be */
cost = -latest + late_factor*late;
/*fprintf(stderr, "cost %d = %d + %f * %d\n", cost, -latest, late_factor, late);*/
if (cost < best_cost)
@@ -239,8 +243,9 @@
break;
}
+ /* For the next timing we will consider, there will be one more late packet to count */
late++;
- /* Two-frame penalty if we're going to increase the amount of late frames */
+ /* Two-frame penalty if we're going to increase the amount of late frames (hysteresis) */
if (latest >= 0 && !penalty_taken)
{
penalty_taken = 1;
@@ -254,6 +259,8 @@
/*fprintf(stderr, "auto_tradeoff = %d (%d %d %d)\n", jitter->auto_tradeoff, best, worst, i);*/
/* FIXME: Compute a short-term estimate too and combine with the long-term one */
+
+ /* Prevents reducing the buffer size when we haven't really had much data */
if (tot_count < TOP_DELAY && opt > 0)
return 0;
return opt;
@@ -322,12 +329,14 @@
speex_free(jitter);
}
+/** Take the following timing into consideration for future calculations */
static void update_timings(JitterBuffer *jitter, spx_int32_t timing)
{
if (timing < -32767)
timing = -32767;
if (timing > 32767)
timing = 32767;
+ /* If the current sub-window is full, perform a rotation and discard oldest sub-widow */
if (jitter->timeBuffers[0]->curr_count >= jitter->subwindow_size)
{
int i;
@@ -341,6 +350,7 @@
tb_add(jitter->timeBuffers[0], timing);
}
+/** Compensate all timings when we do an adjustment of the buffering */
static void shift_timings(JitterBuffer *jitter, spx_int16_t amount)
{
int i, j;
More information about the commits
mailing list