From 85b325fdb991a0602a2f16a55fc1df2c303aded1 Mon Sep 17 00:00:00 2001 From: Thom Johansen Date: Wed, 14 Nov 2007 02:15:56 +0000 Subject: 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 --- apps/codecs/libspeex/jitter.c | 753 +++++++++++++++++++++++++++++------------- 1 file changed, 521 insertions(+), 232 deletions(-) (limited to 'apps/codecs/libspeex/jitter.c') 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 #include #include @@ -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 (posfilled && 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;itiming[i]); + fprintf(stderr, "\n"); + }*/ + tb->curr_count++; + if (tb->filledfilled++; + /*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 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;ibuf[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;ibuf[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_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 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;ibuf[i]==NULL) - break; + for (j=0;jtimeBuffers[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;jbuf[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 0) { - int count = 0; - for (j=0;jbuf[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;ishortterm_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;iinterp_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 (;ires_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 (;iearly_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;ishortterm_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;itimestamp, 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;ipackets[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;jpackets[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;jlen;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;ibuf[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;ibuf[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;ibuf[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;ibuf[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;jlen;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;jlen;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;ipackets[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;jlen;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;ishortterm_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;ishortterm_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;ishortterm_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;ibuf[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; -- cgit v1.2.3