[xiph-commits] r14143 - trunk/speex/libspeex
jm at svn.xiph.org
jm at svn.xiph.org
Wed Nov 14 22:31:02 PST 2007
Author: jm
Date: 2007-11-14 22:31:02 -0800 (Wed, 14 Nov 2007)
New Revision: 14143
Modified:
trunk/speex/libspeex/jitter.c
Log:
jitter buffer: completely new (time sorting) algorithm enabled now. Still
more changes to come.
Modified: trunk/speex/libspeex/jitter.c
===================================================================
--- trunk/speex/libspeex/jitter.c 2007-11-15 05:41:35 UTC (rev 14142)
+++ trunk/speex/libspeex/jitter.c 2007-11-15 06:31:02 UTC (rev 14143)
@@ -62,9 +62,6 @@
#define NULL 0
#endif
-#define LATE_BINS 15
-#define MAX_MARGIN 30 /**< Number of bins in margin histogram */
-
#define SPEEX_JITTER_MAX_BUFFER_SIZE 200 /**< Maximum number of packets in jitter buffer */
#define TSUB(a,b) ((spx_int32_t)((a)-(b)))
@@ -76,7 +73,7 @@
#define MAX_TIMINGS 20
#define MAX_BUFFERS 3
-#define TOP_DELAY 12
+#define TOP_DELAY 20
struct TimingBuffer {
int filled;
@@ -135,13 +132,43 @@
/*fprintf(stderr, "added\n");*/
}
+
+
+/** 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;
+
+ 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 delay_step; /**< Size of the steps when adjusting buffering (timestamp 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 */
+ int window_size; /**< Total window over which the late frames are counted */
+ int subwindow_size; /**< Sub-window size for faster computation */
+ int max_late_rate; /**< Absolute maximum amount of late packets tolerable (in percent) */
+ int latency_tradeoff; /**< Latency equivalent of losing one percent of packets */
+ int auto_tradeoff; /**< Latency equivalent of losing one percent of packets (automatic default) */
+
+ int lost_count; /**< Number of consecutive lost packets */
+};
+
/** 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 latency_tradeoff)
+ */
+static spx_int16_t compute_opt_delay(JitterBuffer *jitter)
{
int i;
spx_int16_t opt=0;
@@ -151,15 +178,24 @@
int tot_count;
float late_factor;
int penalty_taken = 0;
+ int best = 0;
+ int worst = 0;
+ spx_int32_t deltaT;
+ struct TimingBuffer *tb;
+ tb = jitter->_tb;
+
tot_count = 0;
for (i=0;i<MAX_BUFFERS;i++)
tot_count += tb[i].curr_count;
if (tot_count==0)
return 0;
- late_factor = latency_tradeoff * 100.0f / tot_count;
+ if (jitter->latency_tradeoff != 0)
+ late_factor = jitter->latency_tradeoff * 100.0f / tot_count;
+ else
+ late_factor = jitter->auto_tradeoff * jitter->window_size/tot_count;
- /*fprintf(stderr, "tbs_get_opt_delay\n");*/
+ /*fprintf(stderr, "late_factor = %f\n", late_factor);*/
for (i=0;i<MAX_BUFFERS;i++)
pos[i] = 0;
@@ -179,9 +215,13 @@
if (next != -1)
{
spx_int32_t cost;
+
+ if (i==0)
+ worst = latest;
+ best = latest;
pos[next]++;
cost = -latest + late_factor*late;
- /*fprintf(stderr, "cost %d = -%d + %d * %d\n", cost, latest, late_factor, late);*/
+ /*fprintf(stderr, "cost %d = %d + %f * %d\n", cost, -latest, late_factor, late);*/
if (cost < best_cost)
{
best_cost = cost;
@@ -199,48 +239,19 @@
late+=2;
}
}
+
+ deltaT = best-worst;
+ /* This is a default "automatic latency tradeoff" when none is provided */
+ jitter->auto_tradeoff = 1 + deltaT/TOP_DELAY;
+ /*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 */
+ if (tot_count < TOP_DELAY && opt > 0)
+ return 0;
return opt;
}
-/** 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;
-
- 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 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 */
- int window_size; /**< Total window over which the late frames are counted */
- int subwindow_size; /**< Sub-window size for faster computation */
- int max_late_rate; /**< Absolute maximum amount of late packets tolerable (in percent) */
- int latency_tradeoff; /**< Latency equivalent of losing one percent of packets */
-
- 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 */
- float loss_rate; /**< Average loss rate */
-};
-
/** Initialise jitter buffer */
JitterBuffer *jitter_buffer_init(int resolution)
{
@@ -251,15 +262,14 @@
spx_int32_t tmp;
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
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 = 0;
jitter->late_cutoff = 50;
+ jitter->auto_tradeoff = 32000;
jitter->destroy = NULL;
- jitter->latency_tradeoff = 8;
- tmp = 2;
+ jitter->latency_tradeoff = 0;
+ tmp = 4;
jitter_buffer_ctl(jitter, JITTER_BUFFER_SET_MAX_LATE_RATE, &tmp);
jitter_buffer_reset(jitter);
}
@@ -286,12 +296,6 @@
jitter->next_stop = 0;
jitter->reset_state = 1;
jitter->lost_count = 0;
- jitter->loss_rate = 0;
- for (i=0;i<MAX_MARGIN;i++)
- {
- jitter->shortterm_margin[i] = 0;
- jitter->longterm_margin[i] = 0;
- }
for (i=0;i<MAX_BUFFERS;i++)
{
@@ -325,8 +329,6 @@
tb_init(jitter->timeBuffers[0]);
}
tb_add(jitter->timeBuffers[0], timing);
- spx_int16_t opt = tbs_get_opt_delay(jitter->_tb, jitter->latency_tradeoff);
- /*fprintf(stderr, "opt adjustment is %d\n", opt);*/
}
static void shift_timings(JitterBuffer *jitter, spx_int16_t amount)
@@ -334,120 +336,17 @@
int i, j;
for (i=0;i<MAX_BUFFERS;i++)
{
- for (j=0;j<jitter->timeBuffers[i]->filled;i++)
+ for (j=0;j<jitter->timeBuffers[i]->filled;j++)
jitter->timeBuffers[i]->timing[j] += amount;
}
}
-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 */
- 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);
- }
- }
-}
-static void shift_histogram(JitterBuffer *jitter, int amount)
-{
- int i, c;
- if (amount == 0)
- return;
- if (amount > 0)
- {
- /* FIXME: This is terribly inefficient */
- for (c=0;c<amount;c++)
- {
- 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;
- }
- }
-}
-
-static void compute_statistics(JitterBuffer *jitter)
-{
- int i;
- 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->late_ratio_short += jitter->shortterm_margin[i];
- jitter->late_ratio_long += jitter->longterm_margin[i];
- }
-
- /* 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->ontime_ratio_short = jitter->shortterm_margin[i];
- jitter->ontime_ratio_long = jitter->longterm_margin[i];
- }
-
- 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];
- }
-}
-
/** 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 */
@@ -478,14 +377,7 @@
/* Check if packet is late (could still be useful though) */
if (LT32(packet->timestamp, jitter->next_stop))
{
- /*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);
+ update_timings(jitter, ((spx_int32_t)packet->timestamp) - ((spx_int32_t)jitter->next_stop) - jitter->buffer_margin);
late = 1;
} else {
late = 0;
@@ -555,6 +447,7 @@
int i;
unsigned int j;
int incomplete = 0;
+ spx_int16_t opt;
jitter->last_returned_timestamp = jitter->pointer_timestamp;
@@ -639,23 +532,11 @@
/* We (obviously) haven't lost this packet */
jitter->lost_count = 0;
- jitter->loss_rate = .999*jitter->loss_rate;
/* 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);
-
+ update_timings(jitter, ((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]) - jitter->buffer_margin);
}
@@ -697,19 +578,18 @@
jitter->lost_count++;
/*fprintf (stderr, "m");*/
/*fprintf (stderr, "lost_count = %d\n", jitter->lost_count);*/
- jitter->loss_rate = .999*jitter->loss_rate + .001;
if (start_offset)
*start_offset = 0;
- compute_statistics(jitter);
+ opt = compute_opt_delay(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 (opt < 0)
{
/* Increase buffering */
/* Shift histogram to compensate */
- shift_histogram(jitter, jitter->res_delay_step);
+ shift_timings(jitter, jitter->delay_step);
packet->timestamp = jitter->pointer_timestamp;
packet->span = jitter->delay_step;
@@ -784,32 +664,35 @@
/* 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;
-
- compute_statistics(jitter);
+ spx_int16_t opt = compute_opt_delay(jitter);
+ /*fprintf(stderr, "opt adjustment is %d ", opt);*/
- /* Adjusting the buffering bssed on the amount of packets that are early/on time/late */
- if (jitter->late_ratio_short > .1 || jitter->late_ratio_long > .03)
+ /* Round down to next delay_step */
+ if (opt < 0)
+ opt = ((opt-jitter->delay_step+1)/jitter->delay_step)*jitter->delay_step;
+ else
+ opt = (opt/jitter->delay_step)*jitter->delay_step;
+
+ /*fprintf(stderr, "(%d for multiple of %d)\n", opt, jitter->delay_step);*/
+
+ if (opt < 0)
{
- /* If too many packets are arriving late */
- shift_histogram(jitter, jitter->res_delay_step);
+ shift_timings(jitter, -opt);
- jitter->pointer_timestamp -= jitter->delay_step;
+ jitter->pointer_timestamp += opt;
jitter->interp_requested = 1;
- /*fprintf (stderr, "Decision to interpolate\n");*/
+ /*fprintf (stderr, "Decision to interpolate %d samples\n", -opt);*/
return JITTER_BUFFER_ADJUST_INTERPOLATE;
- } 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)
+ } else if (opt > 0)
{
- /* Many frames arriving early */
- shift_histogram(jitter, -jitter->res_delay_step);
-
- jitter->pointer_timestamp += jitter->delay_step;
- /*fprintf (stderr, "Decision to drop\n");*/
+ shift_timings(jitter, -opt);
+ jitter->pointer_timestamp += opt;
+ /*fprintf (stderr, "Decision to drop %d samples\n", opt);*/
return JITTER_BUFFER_ADJUST_DROP;
+ } else {
+ return JITTER_BUFFER_ADJUST_OK;
}
-
- return JITTER_BUFFER_ADJUST_OK;
}
/* Used like the ioctl function to control the jitter buffer parameters */
@@ -843,7 +726,6 @@
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;
More information about the commits
mailing list