summaryrefslogtreecommitdiff
path: root/apps/codecs/libspeex/jitter.c
diff options
context:
space:
mode:
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 @@
32 32
33*/ 33*/
34 34
35/*
36TODO:
37- Write generic functions for computing stats and shifting the histogram
38- Take into account the delay step when computing the stats and when shifting
39- Linked list structure for holding the packets instead of the current fixed-size array
40 + return memory to a pool
41 + allow pre-allocation of the pool
42 + optional max number of elements
43- Statistics
44 + drift
45 + loss
46 + late
47 + jitter
48 + buffering delay
49*/
35#ifdef HAVE_CONFIG_H 50#ifdef HAVE_CONFIG_H
36#include "config-speex.h" 51#include "config-speex.h"
37#endif 52#endif
38 53
39 54
40#include "misc.h" 55#include "arch.h"
41#include <speex/speex.h> 56#include <speex/speex.h>
42#include <speex/speex_bits.h> 57#include <speex/speex_bits.h>
43#include <speex/speex_jitter.h> 58#include <speex/speex_jitter.h>
@@ -52,29 +67,157 @@
52 67
53#define SPEEX_JITTER_MAX_BUFFER_SIZE 200 /**< Maximum number of packets in jitter buffer */ 68#define SPEEX_JITTER_MAX_BUFFER_SIZE 200 /**< Maximum number of packets in jitter buffer */
54 69
55 70#define TSUB(a,b) ((spx_int32_t)((a)-(b)))
56 71
57#define GT32(a,b) (((spx_int32_t)((a)-(b)))>0) 72#define GT32(a,b) (((spx_int32_t)((a)-(b)))>0)
58#define GE32(a,b) (((spx_int32_t)((a)-(b)))>=0) 73#define GE32(a,b) (((spx_int32_t)((a)-(b)))>=0)
59#define LT32(a,b) (((spx_int32_t)((a)-(b)))<0) 74#define LT32(a,b) (((spx_int32_t)((a)-(b)))<0)
60#define LE32(a,b) (((spx_int32_t)((a)-(b)))<=0) 75#define LE32(a,b) (((spx_int32_t)((a)-(b)))<=0)
61 76
77#define MAX_TIMINGS 20
78#define MAX_BUFFERS 3
79#define TOP_DELAY 25
80#define WINDOW_SIZE 200
81
82struct TimingBuffer {
83 int filled;
84 int curr_count;
85 spx_int16_t timing[MAX_TIMINGS];
86 spx_int16_t counts[MAX_TIMINGS];
87};
88
89static void tb_init(struct TimingBuffer *tb)
90{
91 tb->filled = 0;
92 tb->curr_count = 0;
93}
94
95static void tb_add(struct TimingBuffer *tb, spx_int16_t timing)
96{
97 int pos;
98 /*fprintf(stderr, "timing = %d\n", timing);*/
99 /*fprintf(stderr, "timing = %d, latest = %d, earliest = %d, filled = %d\n", timing, tb->timing[0], tb->timing[tb->filled-1], tb->filled);*/
100 if (tb->filled >= MAX_TIMINGS && timing >= tb->timing[tb->filled-1])
101 {
102 tb->curr_count++;
103 return;
104 }
105 pos = 0;
106 /* FIXME: Do bisection instead of linear search */
107 while (pos<tb->filled && timing >= tb->timing[pos])
108 {
109 pos++;
110 }
111
112 /*fprintf(stderr, "pos = %d filled = %d\n", pos, tb->filled);*/
113 speex_assert(pos <= tb->filled && pos < MAX_TIMINGS);
114 fprintf(stderr, "OK\n");
115 if (pos < tb->filled)
116 {
117 int move_size = tb->filled-pos;
118 if (tb->filled == MAX_TIMINGS)
119 move_size -= 1;
120 /*fprintf(stderr, "speex_move(%d %d %d)\n", pos+1, pos, move_size);*/
121 speex_move(&tb->timing[pos+1], &tb->timing[pos], move_size*sizeof(tb->timing[0]));
122 speex_move(&tb->counts[pos+1], &tb->counts[pos], move_size*sizeof(tb->counts[0]));
123 }
124 /*fprintf(stderr, "moved\n");*/
125 tb->timing[pos] = timing;
126 tb->counts[pos] = tb->curr_count;
127 /*{
128 int i;
129 for (i=0;i<MAX_TIMINGS;i++)
130 fprintf(stderr, "%d ", tb->timing[i]);
131 fprintf(stderr, "\n");
132 }*/
133 tb->curr_count++;
134 if (tb->filled<MAX_TIMINGS)
135 tb->filled++;
136 /*fprintf(stderr, "added\n");*/
137}
138
139/** Based on available data, this computes the optimal delay for the jitter buffer.
140 The optimised function is in timestamp units and is:
141 cost = delay + late_factor*[number of frames that would be late if we used that delay]
142 @param tb Array of buffers
143 @param late_factor Equivalent cost of a late frame (in timestamp units)
144*/
145static spx_int16_t tbs_get_opt_delay(struct TimingBuffer *tb, spx_int32_t late_factor)
146{
147 int i;
148 spx_int16_t opt=0;
149 spx_int32_t best_cost=0x7fffffff;
150 int late = 0;
151 int pos[MAX_BUFFERS];
152
153 /*fprintf(stderr, "tbs_get_opt_delay\n");*/
154 for (i=0;i<MAX_BUFFERS;i++)
155 pos[i] = 0;
156
157 for (i=0;i<TOP_DELAY;i++)
158 {
159 int j;
160 int next=-1;
161 int latest = 32767;
162 for (j=0;j<MAX_BUFFERS;j++)
163 {
164 if (pos[j] < tb[j].filled && tb[j].timing[pos[j]] < latest)
165 {
166 next = j;
167 latest = tb[j].timing[pos[j]];
168 }
169 }
170 late++;
171 if (next != -1)
172 {
173 spx_int32_t cost;
174 pos[next]++;
175 /* When considering reducing delay, "on-time" frames could twice (this provides hysteresis) */
176 if (latest > 0)
177 late++;
178 cost = -latest + late_factor*late;
179 /*fprintf(stderr, "cost %d = -%d + %d * %d\n", cost, latest, late_factor, late);*/
180 if (cost < best_cost)
181 {
182 best_cost = cost;
183 opt = latest;
184 }
185 } else {
186 break;
187 }
188 }
189 return opt;
190}
191
62/** Jitter buffer structure */ 192/** Jitter buffer structure */
63struct JitterBuffer_ { 193struct JitterBuffer_ {
64 spx_uint32_t pointer_timestamp; /**< Timestamp of what we will *get* next */ 194 spx_uint32_t pointer_timestamp; /**< Timestamp of what we will *get* next */
65 spx_uint32_t current_timestamp; /**< Timestamp of the local clock (what we will *play* next) */ 195 spx_uint32_t last_returned_timestamp;
66 196 spx_uint32_t next_stop;
67 char *buf[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Buffer of packets (NULL if slot is free) */ 197
68 spx_uint32_t timestamp[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Timestamp of packet */ 198 JitterBufferPacket packets[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packets stored in the buffer */
69 int span[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Timestamp of packet */ 199 spx_uint32_t arrival[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packet arrival time (0 means it was late, even though it's a valid timestamp) */
70 int len[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Number of bytes in packet */ 200
201 void (*destroy) (void *); /**< Callback for destroying a packet */
71 202
72 int tick_size; /**< Output granularity */ 203 int resolution; /**< Time resolution for histogram (timestamp units) */
204 int delay_step; /**< Size of the steps when adjusting buffering (timestamp units) */
205 int res_delay_step; /**< Size of the steps when adjusting buffering (resolution units) */
73 int reset_state; /**< True if state was just reset */ 206 int reset_state; /**< True if state was just reset */
74 int buffer_margin; /**< How many frames we want to keep in the buffer (lower bound) */ 207 int buffer_margin; /**< How many frames we want to keep in the buffer (lower bound) */
75 int late_cutoff; /**< How late must a packet be for it not to be considered at all */ 208 int late_cutoff; /**< How late must a packet be for it not to be considered at all */
76 int interp_requested; /**< An interpolation is requested by speex_jitter_update_delay() */ 209 int interp_requested; /**< An interpolation is requested by speex_jitter_update_delay() */
77 210
211 struct TimingBuffer _tb[MAX_BUFFERS]; /**< Don't use those directly */
212 struct TimingBuffer *timeBuffers[MAX_BUFFERS]; /**< Storing arrival time of latest frames so we can compute some stats */
213
214 float late_ratio_short;
215 float late_ratio_long;
216 float ontime_ratio_short;
217 float ontime_ratio_long;
218 float early_ratio_short;
219 float early_ratio_long;
220
78 int lost_count; /**< Number of consecutive lost packets */ 221 int lost_count; /**< Number of consecutive lost packets */
79 float shortterm_margin[MAX_MARGIN]; /**< Short term margin histogram */ 222 float shortterm_margin[MAX_MARGIN]; /**< Short term margin histogram */
80 float longterm_margin[MAX_MARGIN]; /**< Long term margin histogram */ 223 float longterm_margin[MAX_MARGIN]; /**< Long term margin histogram */
@@ -82,17 +225,21 @@ struct JitterBuffer_ {
82}; 225};
83 226
84/** Initialise jitter buffer */ 227/** Initialise jitter buffer */
85JitterBuffer *jitter_buffer_init(int tick) 228JitterBuffer *jitter_buffer_init(int resolution)
86{ 229{
87 JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer)); 230 JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer));
88 if (jitter) 231 if (jitter)
89 { 232 {
90 int i; 233 int i;
91 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) 234 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
92 jitter->buf[i]=NULL; 235 jitter->packets[i].data=NULL;
93 jitter->tick_size = tick; 236 jitter->resolution = resolution;
237 jitter->delay_step = resolution;
238 jitter->res_delay_step = 1;
239 /*FIXME: Should this be 0 or 1?*/
94 jitter->buffer_margin = 1; 240 jitter->buffer_margin = 1;
95 jitter->late_cutoff = 50; 241 jitter->late_cutoff = 50;
242 jitter->destroy = NULL;
96 jitter_buffer_reset(jitter); 243 jitter_buffer_reset(jitter);
97 } 244 }
98 return jitter; 245 return jitter;
@@ -104,15 +251,18 @@ void jitter_buffer_reset(JitterBuffer *jitter)
104 int i; 251 int i;
105 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) 252 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
106 { 253 {
107 if (jitter->buf[i]) 254 if (jitter->packets[i].data)
108 { 255 {
109 speex_free(jitter->buf[i]); 256 if (jitter->destroy)
110 jitter->buf[i] = NULL; 257 jitter->destroy(jitter->packets[i].data);
258 else
259 speex_free(jitter->packets[i].data);
260 jitter->packets[i].data = NULL;
111 } 261 }
112 } 262 }
113 /* Timestamp is actually undefined at this point */ 263 /* Timestamp is actually undefined at this point */
114 jitter->pointer_timestamp = 0; 264 jitter->pointer_timestamp = 0;
115 jitter->current_timestamp = 0; 265 jitter->next_stop = 0;
116 jitter->reset_state = 1; 266 jitter->reset_state = 1;
117 jitter->lost_count = 0; 267 jitter->lost_count = 0;
118 jitter->loss_rate = 0; 268 jitter->loss_rate = 0;
@@ -121,6 +271,12 @@ void jitter_buffer_reset(JitterBuffer *jitter)
121 jitter->shortterm_margin[i] = 0; 271 jitter->shortterm_margin[i] = 0;
122 jitter->longterm_margin[i] = 0; 272 jitter->longterm_margin[i] = 0;
123 } 273 }
274
275 for (i=0;i<MAX_BUFFERS;i++)
276 {
277 tb_init(&jitter->_tb[i]);
278 jitter->timeBuffers[i] = &jitter->_tb[i];
279 }
124 /*fprintf (stderr, "reset\n");*/ 280 /*fprintf (stderr, "reset\n");*/
125} 281}
126 282
@@ -131,79 +287,45 @@ void jitter_buffer_destroy(JitterBuffer *jitter)
131 speex_free(jitter); 287 speex_free(jitter);
132} 288}
133 289
134/** Put one packet into the jitter buffer */ 290static void update_timings(JitterBuffer *jitter, spx_int32_t timing)
135void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
136{ 291{
137 int i,j; 292 if (timing < -32767)
138 spx_int32_t arrival_margin; 293 timing = -32767;
139 /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/ 294 if (timing > 32767)
140 if (jitter->reset_state) 295 timing = 32767;
141 { 296 if (jitter->timeBuffers[0]->curr_count >= WINDOW_SIZE)
142 jitter->reset_state=0;
143 jitter->pointer_timestamp = packet->timestamp;
144 jitter->current_timestamp = packet->timestamp;
145 /*fprintf(stderr, "reset to %d\n", timestamp);*/
146 }
147
148 /* Cleanup buffer (remove old packets that weren't played) */
149 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
150 { 297 {
151 /* Make sure we don't discard a "just-late" packet in case we want to play it next (if we interpolate). */ 298 int i;
152 if (jitter->buf[i] && LE32(jitter->timestamp[i] + jitter->span[i], jitter->pointer_timestamp)) 299 /*fprintf(stderr, "Rotate buffer\n");*/
153 { 300 struct TimingBuffer *tmp = jitter->timeBuffers[MAX_BUFFERS-1];
154 /*fprintf (stderr, "cleaned (not played)\n");*/ 301 for (i=MAX_BUFFERS-1;i>=1;i--)
155 speex_free(jitter->buf[i]); 302 jitter->timeBuffers[i] = jitter->timeBuffers[i-1];
156 jitter->buf[i] = NULL; 303 jitter->timeBuffers[0] = tmp;
157 } 304 tb_init(jitter->timeBuffers[0]);
158 } 305 }
306 tb_add(jitter->timeBuffers[0], timing);
307 spx_int16_t opt = tbs_get_opt_delay(jitter->_tb, 2);
308 /*fprintf(stderr, "opt adjustment is %d\n", opt);*/
309}
159 310
160 /*Find an empty slot in the buffer*/ 311static void shift_timings(JitterBuffer *jitter, spx_int16_t amount)
161 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) 312{
313 int i, j;
314 for (i=0;i<MAX_BUFFERS;i++)
162 { 315 {
163 if (jitter->buf[i]==NULL) 316 for (j=0;j<jitter->timeBuffers[i]->filled;i++)
164 break; 317 jitter->timeBuffers[i]->timing[j] += amount;
165 } 318 }
319}
166 320
167 /*fprintf(stderr, "%d %d %f\n", timestamp, jitter->pointer_timestamp, jitter->drift_average);*/ 321static void update_histogram(JitterBuffer *jitter, spx_int32_t arrival_margin)
168 /*No place left in the buffer*/ 322{
169 if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) 323 int i;
170 {
171 int earliest=jitter->timestamp[0];
172 i=0;
173 for (j=1;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++)
174 {
175 if (!jitter->buf[i] || LT32(jitter->timestamp[j],earliest))
176 {
177 earliest = jitter->timestamp[j];
178 i=j;
179 }
180 }
181 speex_free(jitter->buf[i]);
182 jitter->buf[i]=NULL;
183 if (jitter->lost_count>20)
184 {
185 jitter_buffer_reset(jitter);
186 }
187 /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/
188 }
189
190 /* Copy packet in buffer */
191 jitter->buf[i]=(char*)speex_alloc(packet->len);
192 for (j=0;j<(int)packet->len;j++)
193 jitter->buf[i][j]=packet->data[j];
194 jitter->timestamp[i]=packet->timestamp;
195 jitter->span[i]=packet->span;
196 jitter->len[i]=packet->len;
197
198 /* Adjust the buffer size depending on network conditions.
199 The arrival margin is how much in advance (or late) the packet it */
200 arrival_margin = (((spx_int32_t)packet->timestamp) - ((spx_int32_t)jitter->current_timestamp))/jitter->tick_size - jitter->buffer_margin;
201
202 if (arrival_margin >= -jitter->late_cutoff) 324 if (arrival_margin >= -jitter->late_cutoff)
203 { 325 {
204 /* Here we compute the histogram based on the time of arrival of the packet. 326 /* Here we compute the histogram based on the time of arrival of the packet.
205 This is based on a (first-order) recursive average. We keep both a short-term 327 This is based on a (first-order) recursive average. We keep both a short-term
206 histogram and a long-term histogram */ 328 histogram and a long-term histogram */
207 spx_int32_t int_margin; 329 spx_int32_t int_margin;
208 /* First, apply the "damping" of the recursive average to all bins */ 330 /* First, apply the "damping" of the recursive average to all bins */
209 for (i=0;i<MAX_MARGIN;i++) 331 for (i=0;i<MAX_MARGIN;i++)
@@ -228,88 +350,215 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
228 jitter_buffer_reset(jitter); 350 jitter_buffer_reset(jitter);
229 } 351 }
230 } 352 }
231#if 0 /* Enable to check how much is being buffered */ 353}
232 if (rand()%1000==0) 354
355static void shift_histogram(JitterBuffer *jitter, int amount)
356{
357 int i, c;
358 if (amount == 0)
359 return;
360 if (amount > 0)
233 { 361 {
234 int count = 0; 362 /* FIXME: This is terribly inefficient */
235 for (j=0;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++) 363 for (c=0;c<amount;c++)
236 { 364 {
237 if (jitter->buf[j]) 365 jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2];
238 count++; 366 jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2];
367 for (i=MAX_MARGIN-3;i>=0;i--)
368 {
369 jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i];
370 jitter->longterm_margin[i+1] = jitter->longterm_margin[i];
371 }
372 jitter->shortterm_margin[0] = 0;
373 jitter->longterm_margin[0] = 0;
374 }
375 } else {
376 /* FIXME: This is terribly inefficient */
377 for (c=0;c<-amount;c++)
378 {
379 jitter->shortterm_margin[0] += jitter->shortterm_margin[1];
380 jitter->longterm_margin[0] += jitter->longterm_margin[1];
381 for (i=1;i<MAX_MARGIN-1;i++)
382 {
383 jitter->shortterm_margin[i] = jitter->shortterm_margin[i+1];
384 jitter->longterm_margin[i] = jitter->longterm_margin[i+1];
385 }
386 jitter->shortterm_margin[MAX_MARGIN-1] = 0;
387 jitter->longterm_margin[MAX_MARGIN-1] = 0;
239 } 388 }
240 fprintf (stderr, "buffer_size = %d\n", count);
241 } 389 }
242#endif
243} 390}
244 391
245/** Get one packet from the jitter buffer */ 392static void compute_statistics(JitterBuffer *jitter)
246int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
247{ 393{
248 int i; 394 int i;
249 unsigned int j; 395 jitter->late_ratio_short = 0;
250 float late_ratio_short; 396 jitter->late_ratio_long = 0;
251 float late_ratio_long; 397 /* Count the proportion of packets that are late */
252 float ontime_ratio_short; 398 for (i=0;i<LATE_BINS;i++)
253 float ontime_ratio_long;
254 float early_ratio_short;
255 float early_ratio_long;
256 int chunk_size;
257 int incomplete = 0;
258
259 if (jitter->interp_requested)
260 { 399 {
261 jitter->interp_requested = 0; 400 jitter->late_ratio_short += jitter->shortterm_margin[i];
262 if (start_offset) 401 jitter->late_ratio_long += jitter->longterm_margin[i];
263 *start_offset = 0;
264 packet->timestamp = jitter->pointer_timestamp;
265 packet->span = jitter->tick_size;
266 jitter->pointer_timestamp += jitter->tick_size;
267 packet->len = 0;
268 return JITTER_BUFFER_MISSING;
269 } 402 }
270 if (LT32(jitter->current_timestamp+jitter->tick_size, jitter->pointer_timestamp)) 403
404 /* Count the proportion of packets that are just on time */
405 jitter->ontime_ratio_short = 0;
406 jitter->ontime_ratio_long = 0;
407 for (;i<LATE_BINS+jitter->res_delay_step;i++)
271 { 408 {
272 jitter->current_timestamp = jitter->pointer_timestamp; 409 jitter->ontime_ratio_short = jitter->shortterm_margin[i];
273 speex_warning("did you forget to call jitter_buffer_tick() by any chance?"); 410 jitter->ontime_ratio_long = jitter->longterm_margin[i];
274 } 411 }
275 /*fprintf (stderr, "get packet %d %d\n", jitter->pointer_timestamp, jitter->current_timestamp);*/ 412
413 jitter->early_ratio_short = 0;
414 jitter->early_ratio_long = 0;
415 /* Count the proportion of packets that are early */
416 for (;i<MAX_MARGIN;i++)
417 {
418 jitter->early_ratio_short += jitter->shortterm_margin[i];
419 jitter->early_ratio_long += jitter->longterm_margin[i];
420 }
421}
276 422
277 /* FIXME: This should be only what remaining of the current tick */ 423/** Put one packet into the jitter buffer */
278 chunk_size = jitter->tick_size; 424void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
425{
426 int i,j;
427 int late;
428 spx_int32_t arrival_margin;
429 spx_int32_t arrival_time;
430 /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/
279 431
280 /* Compiling arrival statistics */ 432 /* Syncing on the first packet to arrive */
433 if (jitter->reset_state)
434 {
435 jitter->reset_state=0;
436 jitter->pointer_timestamp = packet->timestamp;
437 jitter->next_stop = packet->timestamp;
438 /*fprintf(stderr, "reset to %d\n", timestamp);*/
439 }
281 440
282 late_ratio_short = 0; 441 /* Cleanup buffer (remove old packets that weren't played) */
283 late_ratio_long = 0; 442 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
284 /* Count the proportion of packets that are late */
285 for (i=0;i<LATE_BINS;i++)
286 { 443 {
287 late_ratio_short += jitter->shortterm_margin[i]; 444 /* Make sure we don't discard a "just-late" packet in case we want to play it next (if we interpolate). */
288 late_ratio_long += jitter->longterm_margin[i]; 445 if (jitter->packets[i].data && LE32(jitter->packets[i].timestamp + jitter->packets[i].span, jitter->pointer_timestamp))
446 {
447 /*fprintf (stderr, "cleaned (not played)\n");*/
448 if (jitter->destroy)
449 jitter->destroy(jitter->packets[i].data);
450 else
451 speex_free(jitter->packets[i].data);
452 jitter->packets[i].data = NULL;
453 }
289 } 454 }
290 /* Count the proportion of packets that are just on time */ 455
291 ontime_ratio_short = jitter->shortterm_margin[LATE_BINS]; 456 /*fprintf(stderr, "arrival: %d %d %d\n", packet->timestamp, jitter->next_stop, jitter->pointer_timestamp);*/
292 ontime_ratio_long = jitter->longterm_margin[LATE_BINS]; 457 /* Check if packet is late (could still be useful though) */
293 early_ratio_short = early_ratio_long = 0; 458 if (LT32(packet->timestamp, jitter->next_stop))
294 /* Count the proportion of packets that are early */
295 for (i=LATE_BINS+1;i<MAX_MARGIN;i++)
296 { 459 {
297 early_ratio_short += jitter->shortterm_margin[i]; 460 /*fprintf(stderr, "late by %d\n", jitter->next_stop - packet->timestamp);*/
298 early_ratio_long += jitter->longterm_margin[i]; 461
462 /* The arrival margin is how much in advance (or in this case late) the packet it (in resolution units) */
463 arrival_margin = (((spx_int32_t)packet->timestamp) - ((spx_int32_t)jitter->next_stop))/jitter->resolution - jitter->buffer_margin;
464
465 /*fprintf(stderr, "put arrival_margin = %d\n", arrival_margin);*/
466 /*update_timings(jitter, ((spx_int32_t)packet->timestamp) - ((spx_int32_t)jitter->next_stop));*/
467 update_histogram(jitter, arrival_margin);
468 late = 1;
469 } else {
470 late = 0;
299 } 471 }
300 if (0&&jitter->pointer_timestamp%1000==0) 472
473 /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */
474 if (GE32(packet->timestamp+packet->span+jitter->delay_step, jitter->pointer_timestamp))
301 { 475 {
302 /*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);*/ 476
303 /*fprintf (stderr, "%f %f\n", early_ratio_short + ontime_ratio_short + late_ratio_short, early_ratio_long + ontime_ratio_long + late_ratio_long);*/ 477 /*Find an empty slot in the buffer*/
478 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
479 {
480 if (jitter->packets[i].data==NULL)
481 break;
482 }
483
484 /*No place left in the buffer, need to make room for it by discarding the oldest packet */
485 if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
486 {
487 int earliest=jitter->packets[0].timestamp;
488 i=0;
489 for (j=1;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++)
490 {
491 if (!jitter->packets[i].data || LT32(jitter->packets[j].timestamp,earliest))
492 {
493 earliest = jitter->packets[j].timestamp;
494 i=j;
495 }
496 }
497 if (jitter->destroy)
498 jitter->destroy(jitter->packets[i].data);
499 else
500 speex_free(jitter->packets[i].data);
501 jitter->packets[i].data=NULL;
502 if (jitter->lost_count>20)
503 {
504 jitter_buffer_reset(jitter);
505 }
506 /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/
507 }
508
509 /* Copy packet in buffer */
510 if (jitter->destroy)
511 {
512 jitter->packets[i].data = packet->data;
513 } else {
514 jitter->packets[i].data=(char*)speex_alloc(packet->len);
515 for (j=0;j<packet->len;j++)
516 jitter->packets[i].data[j]=packet->data[j];
517 }
518 jitter->packets[i].timestamp=packet->timestamp;
519 jitter->packets[i].span=packet->span;
520 jitter->packets[i].len=packet->len;
521 jitter->packets[i].user_data=packet->user_data;
522 if (late)
523 jitter->arrival[i] = 0;
524 else
525 jitter->arrival[i] = jitter->next_stop;
304 } 526 }
305 527
306 528
529}
530
531/** Get one packet from the jitter buffer */
532int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset)
533{
534 int i;
535 unsigned int j;
536 int incomplete = 0;
537
538 jitter->last_returned_timestamp = jitter->pointer_timestamp;
539
540 if (jitter->interp_requested)
541 {
542 jitter->interp_requested = 0;
543 if (start_offset)
544 *start_offset = 0;
545 packet->timestamp = jitter->pointer_timestamp;
546 packet->span = jitter->delay_step;
547
548 /* Increment the pointer because it got decremented in the delay update */
549 jitter->pointer_timestamp += jitter->delay_step;
550 packet->len = 0;
551 /*fprintf (stderr, "Deferred interpolate\n");*/
552
553 return JITTER_BUFFER_MISSING;
554 }
555
307 /* Searching for the packet that fits best */ 556 /* Searching for the packet that fits best */
308 557
309 /* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */ 558 /* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */
310 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) 559 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
311 { 560 {
312 if (jitter->buf[i] && jitter->timestamp[i]==jitter->pointer_timestamp && GE32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp+chunk_size)) 561 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))
313 break; 562 break;
314 } 563 }
315 564
@@ -318,7 +567,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
318 { 567 {
319 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) 568 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
320 { 569 {
321 if (jitter->buf[i] && LE32(jitter->timestamp[i], jitter->pointer_timestamp) && GE32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp+chunk_size)) 570 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))
322 break; 571 break;
323 } 572 }
324 } 573 }
@@ -328,7 +577,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
328 { 577 {
329 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) 578 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
330 { 579 {
331 if (jitter->buf[i] && LE32(jitter->timestamp[i], jitter->pointer_timestamp) && GT32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp)) 580 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))
332 break; 581 break;
333 } 582 }
334 } 583 }
@@ -343,12 +592,12 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
343 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) 592 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
344 { 593 {
345 /* check if packet starts within current chunk */ 594 /* check if packet starts within current chunk */
346 if (jitter->buf[i] && LT32(jitter->timestamp[i],jitter->pointer_timestamp+chunk_size) && GE32(jitter->timestamp[i],jitter->pointer_timestamp)) 595 if (jitter->packets[i].data && LT32(jitter->packets[i].timestamp,jitter->pointer_timestamp+desired_span) && GE32(jitter->packets[i].timestamp,jitter->pointer_timestamp))
347 { 596 {
348 if (!found || LT32(jitter->timestamp[i],best_time) || (jitter->timestamp[i]==best_time && GT32(jitter->span[i],best_span))) 597 if (!found || LT32(jitter->packets[i].timestamp,best_time) || (jitter->packets[i].timestamp==best_time && GT32(jitter->packets[i].span,best_span)))
349 { 598 {
350 best_time = jitter->timestamp[i]; 599 best_time = jitter->packets[i].timestamp;
351 best_span = jitter->span[i]; 600 best_span = jitter->packets[i].span;
352 besti = i; 601 besti = i;
353 found = 1; 602 found = 1;
354 } 603 }
@@ -358,31 +607,62 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
358 { 607 {
359 i=besti; 608 i=besti;
360 incomplete = 1; 609 incomplete = 1;
361 /*fprintf (stderr, "incomplete: %d %d %d %d\n", jitter->timestamp[i], jitter->pointer_timestamp, chunk_size, jitter->span[i]);*/ 610 /*fprintf (stderr, "incomplete: %d %d %d %d\n", jitter->packets[i].timestamp, jitter->pointer_timestamp, chunk_size, jitter->packets[i].span);*/
362 } 611 }
363 } 612 }
364 613
365 /* If we find something */ 614 /* If we find something */
366 if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE) 615 if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE)
367 { 616 {
617
618
368 /* We (obviously) haven't lost this packet */ 619 /* We (obviously) haven't lost this packet */
369 jitter->lost_count = 0; 620 jitter->lost_count = 0;
370 jitter->loss_rate = .999*jitter->loss_rate; 621 jitter->loss_rate = .999*jitter->loss_rate;
371 /* Check for potential overflow */ 622
372 packet->len = jitter->len[i]; 623 /* In this case, 0 isn't as a valid timestamp */
624 if (jitter->arrival[i] != 0)
625 {
626 spx_int32_t arrival_margin;
627 /*fprintf(stderr, "early by %d\n", jitter->packets[i].timestamp - jitter->arrival[i]);*/
628
629 /* The arrival margin is how much in advance (or in this case late) the packet it (in resolution units) */
630 arrival_margin = (((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]))/jitter->resolution - jitter->buffer_margin;
631
632 /*fprintf(stderr, "get arrival_margin = %d\n", arrival_margin);*/
633
634 /*update_timings(jitter, ((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]));*/
635
636 update_histogram(jitter, arrival_margin);
637
638 }
639
640
641 /* FIXME: Check for potential overflow */
642 packet->len = jitter->packets[i].len;
373 /* Copy packet */ 643 /* Copy packet */
374 for (j=0;j<packet->len;j++) 644 if (jitter->destroy)
375 packet->data[j] = jitter->buf[i][j]; 645 {
376 /* Remove packet */ 646 packet->data = jitter->packets[i].data;
377 speex_free(jitter->buf[i]); 647 } else {
378 jitter->buf[i] = NULL; 648 for (j=0;j<packet->len;j++)
649 packet->data[j] = jitter->packets[i].data[j];
650 /* Remove packet */
651 speex_free(jitter->packets[i].data);
652 }
653 jitter->packets[i].data = NULL;
379 /* Set timestamp and span (if requested) */ 654 /* Set timestamp and span (if requested) */
380 if (start_offset) 655 if (start_offset)
381 *start_offset = (spx_int32_t)jitter->timestamp[i]-(spx_int32_t)jitter->pointer_timestamp; 656 *start_offset = (spx_int32_t)jitter->packets[i].timestamp-(spx_int32_t)jitter->pointer_timestamp;
382 packet->timestamp = jitter->timestamp[i]; 657
383 packet->span = jitter->span[i]; 658 packet->timestamp = jitter->packets[i].timestamp;
384 /* Point at the end of the current packet */ 659 jitter->last_returned_timestamp = packet->timestamp;
385 jitter->pointer_timestamp = jitter->timestamp[i]+jitter->span[i]; 660
661 packet->span = jitter->packets[i].span;
662 packet->user_data = jitter->packets[i].user_data;
663 /* Point to the end of the current packet */
664 jitter->pointer_timestamp = jitter->packets[i].timestamp+jitter->packets[i].span;
665
386 if (incomplete) 666 if (incomplete)
387 return JITTER_BUFFER_INCOMPLETE; 667 return JITTER_BUFFER_INCOMPLETE;
388 else 668 else
@@ -391,6 +671,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
391 671
392 672
393 /* If we haven't found anything worth returning */ 673 /* If we haven't found anything worth returning */
674
394 /*fprintf (stderr, "not found\n");*/ 675 /*fprintf (stderr, "not found\n");*/
395 jitter->lost_count++; 676 jitter->lost_count++;
396 /*fprintf (stderr, "m");*/ 677 /*fprintf (stderr, "m");*/
@@ -398,34 +679,71 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
398 jitter->loss_rate = .999*jitter->loss_rate + .001; 679 jitter->loss_rate = .999*jitter->loss_rate + .001;
399 if (start_offset) 680 if (start_offset)
400 *start_offset = 0; 681 *start_offset = 0;
401 packet->timestamp = jitter->pointer_timestamp;
402 packet->span = jitter->tick_size;
403 jitter->pointer_timestamp += chunk_size;
404 packet->len = 0;
405 682
406 /* Adjusting the buffering bssed on the amount of packets that are early/on time/late */ 683 compute_statistics(jitter);
407 if (late_ratio_short > .1 || late_ratio_long > .03) 684
685 /* Should we force an increase in the buffer or just do normal interpolation? */
686 if (jitter->late_ratio_short > .1 || jitter->late_ratio_long > .03)
408 { 687 {
409 /* If too many packets are arriving late */ 688 /* Increase buffering */
410 jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2]; 689
411 jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2]; 690 /* Shift histogram to compensate */
412 for (i=MAX_MARGIN-3;i>=0;i--) 691 shift_histogram(jitter, jitter->res_delay_step);
413 { 692
414 jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i]; 693 packet->timestamp = jitter->pointer_timestamp;
415 jitter->longterm_margin[i+1] = jitter->longterm_margin[i]; 694 packet->span = jitter->delay_step;
416 } 695 /* Don't move the pointer_timestamp forward */
417 jitter->shortterm_margin[0] = 0; 696 packet->len = 0;
418 jitter->longterm_margin[0] = 0; 697
419 jitter->pointer_timestamp -= jitter->tick_size; 698 /*jitter->pointer_timestamp -= jitter->delay_step;*/
420 jitter->current_timestamp -= jitter->tick_size; 699 /*fprintf (stderr, "Forced to interpolate\n");*/
421 /*fprintf (stderr, "i");*/ 700 } else {
422 /*fprintf (stderr, "interpolate (getting some slack)\n");*/ 701 /* Normal packet loss */
702 packet->timestamp = jitter->pointer_timestamp;
703 packet->span = desired_span;
704 jitter->pointer_timestamp += desired_span;
705 packet->len = 0;
706 /*fprintf (stderr, "Normal loss\n");*/
423 } 707 }
424 708
425 return JITTER_BUFFER_MISSING; 709 return JITTER_BUFFER_MISSING;
426 710
427} 711}
428 712
713int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet)
714{
715 int i, j;
716 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
717 {
718 if (jitter->packets[i].data && jitter->packets[i].timestamp==jitter->last_returned_timestamp)
719 break;
720 }
721 if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE)
722 {
723 /* Copy packet */
724 packet->len = jitter->packets[i].len;
725 if (jitter->destroy)
726 {
727 packet->data = jitter->packets[i].data;
728 } else {
729 for (j=0;j<packet->len;j++)
730 packet->data[j] = jitter->packets[i].data[j];
731 /* Remove packet */
732 speex_free(jitter->packets[i].data);
733 }
734 jitter->packets[i].data = NULL;
735 packet->timestamp = jitter->packets[i].timestamp;
736 packet->span = jitter->packets[i].span;
737 packet->user_data = jitter->packets[i].user_data;
738 return JITTER_BUFFER_OK;
739 } else {
740 packet->data = NULL;
741 packet->len = 0;
742 packet->span = 0;
743 return JITTER_BUFFER_MISSING;
744 }
745}
746
429/** Get pointer timestamp of jitter buffer */ 747/** Get pointer timestamp of jitter buffer */
430int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter) 748int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter)
431{ 749{
@@ -434,81 +752,39 @@ int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter)
434 752
435void jitter_buffer_tick(JitterBuffer *jitter) 753void jitter_buffer_tick(JitterBuffer *jitter)
436{ 754{
437 jitter->current_timestamp += jitter->tick_size; 755 jitter->next_stop = jitter->pointer_timestamp;
756}
757
758void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem)
759{
760 jitter->next_stop = jitter->pointer_timestamp - rem;
438} 761}
439 762
440/* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */ 763/* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */
441int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset) 764int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
442{ 765{
443 int i; 766 int i;
444 float late_ratio_short;
445 float late_ratio_long;
446 float ontime_ratio_short;
447 float ontime_ratio_long;
448 float early_ratio_short;
449 float early_ratio_long;
450 767
451 if (LT32(jitter->current_timestamp+jitter->tick_size, jitter->pointer_timestamp)) 768 compute_statistics(jitter);
452 {
453 jitter->current_timestamp = jitter->pointer_timestamp;
454 speex_warning("did you forget to call jitter_buffer_tick() by any chance?");
455 }
456 /*fprintf (stderr, "get packet %d %d\n", jitter->pointer_timestamp, jitter->current_timestamp);*/
457 769
458 /* FIXME: This should be only what remaining of the current tick */
459 late_ratio_short = 0;
460 late_ratio_long = 0;
461 /* Count the proportion of packets that are late */
462 for (i=0;i<LATE_BINS;i++)
463 {
464 late_ratio_short += jitter->shortterm_margin[i];
465 late_ratio_long += jitter->longterm_margin[i];
466 }
467 /* Count the proportion of packets that are just on time */
468 ontime_ratio_short = jitter->shortterm_margin[LATE_BINS];
469 ontime_ratio_long = jitter->longterm_margin[LATE_BINS];
470 early_ratio_short = early_ratio_long = 0;
471 /* Count the proportion of packets that are early */
472 for (i=LATE_BINS+1;i<MAX_MARGIN;i++)
473 {
474 early_ratio_short += jitter->shortterm_margin[i];
475 early_ratio_long += jitter->longterm_margin[i];
476 }
477
478 /* Adjusting the buffering bssed on the amount of packets that are early/on time/late */ 770 /* Adjusting the buffering bssed on the amount of packets that are early/on time/late */
479 if (late_ratio_short > .1 || late_ratio_long > .03) 771 if (jitter->late_ratio_short > .1 || jitter->late_ratio_long > .03)
480 { 772 {
481 /* If too many packets are arriving late */ 773 /* If too many packets are arriving late */
482 jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2]; 774 shift_histogram(jitter, jitter->res_delay_step);
483 jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2]; 775
484 for (i=MAX_MARGIN-3;i>=0;i--) 776 jitter->pointer_timestamp -= jitter->delay_step;
485 {
486 jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i];
487 jitter->longterm_margin[i+1] = jitter->longterm_margin[i];
488 }
489 jitter->shortterm_margin[0] = 0;
490 jitter->longterm_margin[0] = 0;
491 jitter->pointer_timestamp -= jitter->tick_size;
492 jitter->current_timestamp -= jitter->tick_size;
493 jitter->interp_requested = 1; 777 jitter->interp_requested = 1;
778 /*fprintf (stderr, "Decision to interpolate\n");*/
494 return JITTER_BUFFER_ADJUST_INTERPOLATE; 779 return JITTER_BUFFER_ADJUST_INTERPOLATE;
495 780
496 } else if (late_ratio_short + ontime_ratio_short < .005 && late_ratio_long + ontime_ratio_long < .01 && early_ratio_short > .8) 781 } 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)
497 { 782 {
498 /* Many frames arriving early */ 783 /* Many frames arriving early */
499 jitter->shortterm_margin[0] += jitter->shortterm_margin[1]; 784 shift_histogram(jitter, -jitter->res_delay_step);
500 jitter->longterm_margin[0] += jitter->longterm_margin[1]; 785
501 for (i=1;i<MAX_MARGIN-1;i++) 786 jitter->pointer_timestamp += jitter->delay_step;
502 { 787 /*fprintf (stderr, "Decision to drop\n");*/
503 jitter->shortterm_margin[i] = jitter->shortterm_margin[i+1];
504 jitter->longterm_margin[i] = jitter->longterm_margin[i+1];
505 }
506 jitter->shortterm_margin[MAX_MARGIN-1] = 0;
507 jitter->longterm_margin[MAX_MARGIN-1] = 0;
508 /*fprintf (stderr, "drop frame\n");*/
509 /*fprintf (stderr, "d");*/
510 jitter->pointer_timestamp += jitter->tick_size;
511 jitter->current_timestamp += jitter->tick_size;
512 return JITTER_BUFFER_ADJUST_DROP; 788 return JITTER_BUFFER_ADJUST_DROP;
513 } 789 }
514 790
@@ -531,13 +807,26 @@ int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
531 count = 0; 807 count = 0;
532 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) 808 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
533 { 809 {
534 if (jitter->buf[i] && LE32(jitter->pointer_timestamp, jitter->timestamp[i])) 810 if (jitter->packets[i].data && LE32(jitter->pointer_timestamp, jitter->packets[i].timestamp))
535 { 811 {
536 count++; 812 count++;
537 } 813 }
538 } 814 }
539 *(spx_int32_t*)ptr = count; 815 *(spx_int32_t*)ptr = count;
540 break; 816 break;
817 case JITTER_BUFFER_SET_DESTROY_CALLBACK:
818 jitter->destroy = (void (*) (void *))ptr;
819 break;
820 case JITTER_BUFFER_GET_DESTROY_CALLBACK:
821 *(void (**) (void *))ptr = jitter->destroy;
822 break;
823 case JITTER_BUFFER_SET_DELAY_STEP:
824 jitter->delay_step = *(spx_int32_t*)ptr;
825 jitter->res_delay_step = jitter->delay_step/jitter->resolution;
826 break;
827 case JITTER_BUFFER_GET_DELAY_STEP:
828 *(spx_int32_t*)ptr = jitter->delay_step;
829 break;
541 default: 830 default:
542 speex_warning_int("Unknown jitter_buffer_ctl request: ", request); 831 speex_warning_int("Unknown jitter_buffer_ctl request: ", request);
543 return -1; 832 return -1;