jitter buffer: minor fix with tick()
[speexdsp.git] / libspeex / jitter.c
1 /* Copyright (C) 2002 Jean-Marc Valin 
2    File: speex_jitter.h
3
4    Adaptive jitter buffer for Speex
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9    
10    - Redistributions of source code must retain the above copyright
11    notice, this list of conditions and the following disclaimer.
12    
13    - Redistributions in binary form must reproduce the above copyright
14    notice, this list of conditions and the following disclaimer in the
15    documentation and/or other materials provided with the distribution.
16    
17    - Neither the name of the Xiph.org Foundation nor the names of its
18    contributors may be used to endorse or promote products derived from
19    this software without specific prior written permission.
20    
21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
25    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33 */
34
35 /* TODO:
36  - Implement JITTER_BUFFER_SET_DESTROY_CALLBACK
37  - Multiple get / get_multiple()
38  - User data?
39  - Use JitterBufferPacket internally
40 */
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46
47 #include "misc.h"
48 #include <speex/speex.h>
49 #include <speex/speex_bits.h>
50 #include <speex/speex_jitter.h>
51 #include "os_support.h"
52
53 #ifndef NULL
54 #define NULL 0
55 #endif
56
57 #define LATE_BINS 15
58 #define MAX_MARGIN 30                     /**< Number of bins in margin histogram */
59
60 #define SPEEX_JITTER_MAX_BUFFER_SIZE 200   /**< Maximum number of packets in jitter buffer */
61
62
63
64 #define GT32(a,b) (((spx_int32_t)((a)-(b)))>0)
65 #define GE32(a,b) (((spx_int32_t)((a)-(b)))>=0)
66 #define LT32(a,b) (((spx_int32_t)((a)-(b)))<0)
67 #define LE32(a,b) (((spx_int32_t)((a)-(b)))<=0)
68
69 /** Jitter buffer structure */
70 struct JitterBuffer_ {
71    spx_uint32_t pointer_timestamp;                                        /**< Timestamp of what we will *get* next */
72    spx_uint32_t current_timestamp;                                        /**< Timestamp of the local clock (what we will *play* next) */
73
74    char *buf[SPEEX_JITTER_MAX_BUFFER_SIZE];                               /**< Buffer of packets (NULL if slot is free) */
75    spx_uint32_t timestamp[SPEEX_JITTER_MAX_BUFFER_SIZE];                  /**< Timestamp of packet                 */
76    int span[SPEEX_JITTER_MAX_BUFFER_SIZE];                                /**< Timestamp of packet                 */
77    int len[SPEEX_JITTER_MAX_BUFFER_SIZE];                                 /**< Number of bytes in packet           */
78    
79    void (*destroy) (void *);                                           /**< Callback for destroying a packet */
80
81    spx_int32_t sub_clock;                                                 /** Time since last get() call (incremented by tick()) */
82    int resolution;                                                        /**< Time resolution for histogram (timestamp units) */
83    int delay_step;                                                        /**< Size of the steps when adjusting buffering (timestamp units) */
84    int reset_state;                                                       /**< True if state was just reset        */
85    int buffer_margin;                                                     /**< How many frames we want to keep in the buffer (lower bound) */
86    int late_cutoff;                                                       /**< How late must a packet be for it not to be considered at all */
87    int interp_requested;                                                  /**< An interpolation is requested by speex_jitter_update_delay() */
88
89    int lost_count;                                                        /**< Number of consecutive lost packets  */
90    float shortterm_margin[MAX_MARGIN];                                    /**< Short term margin histogram         */
91    float longterm_margin[MAX_MARGIN];                                     /**< Long term margin histogram          */
92    float loss_rate;                                                       /**< Average loss rate                   */
93 };
94
95 /** Initialise jitter buffer */
96 JitterBuffer *jitter_buffer_init(int resolution)
97 {
98    JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer));
99    if (jitter)
100    {
101       int i;
102       for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
103          jitter->buf[i]=NULL;
104       jitter->resolution = resolution;
105       jitter->delay_step = resolution;
106       jitter->buffer_margin = 1;
107       jitter->late_cutoff = 50;
108       jitter->destroy = NULL;
109       jitter_buffer_reset(jitter);
110    }
111    return jitter;
112 }
113
114 /** Reset jitter buffer */
115 void jitter_buffer_reset(JitterBuffer *jitter)
116 {
117    int i;
118    for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
119    {
120       if (jitter->buf[i])
121       {
122          if (jitter->destroy)
123             jitter->destroy(jitter->buf[i]);
124          else
125             speex_free(jitter->buf[i]);
126          jitter->buf[i] = NULL;
127       }
128    }
129    /* Timestamp is actually undefined at this point */
130    jitter->pointer_timestamp = 0;
131    jitter->current_timestamp = 0;
132    jitter->reset_state = 1;
133    jitter->lost_count = 0;
134    jitter->loss_rate = 0;
135    for (i=0;i<MAX_MARGIN;i++)
136    {
137       jitter->shortterm_margin[i] = 0;
138       jitter->longterm_margin[i] = 0;
139    }
140    /*fprintf (stderr, "reset\n");*/
141 }
142
143 /** Destroy jitter buffer */
144 void jitter_buffer_destroy(JitterBuffer *jitter)
145 {
146    jitter_buffer_reset(jitter);
147    speex_free(jitter);
148 }
149
150 /** Put one packet into the jitter buffer */
151 void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
152 {
153    int i,j;
154    spx_int32_t arrival_margin;
155    spx_int32_t arrival_time;
156    /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/
157    if (jitter->reset_state)
158    {
159       jitter->reset_state=0;
160       jitter->pointer_timestamp = packet->timestamp;
161       jitter->current_timestamp = packet->timestamp;
162       /*fprintf(stderr, "reset to %d\n", timestamp);*/
163    }
164    
165    /* Cleanup buffer (remove old packets that weren't played) */
166    for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
167    {
168       /* Make sure we don't discard a "just-late" packet in case we want to play it next (if we interpolate). */
169       if (jitter->buf[i] && LE32(jitter->timestamp[i] + jitter->span[i], jitter->pointer_timestamp))
170       {
171          /*fprintf (stderr, "cleaned (not played)\n");*/
172          if (jitter->destroy)
173             jitter->destroy(jitter->buf[i]);
174          else
175             speex_free(jitter->buf[i]);
176          jitter->buf[i] = NULL;
177       }
178    }
179
180    /*Find an empty slot in the buffer*/
181    for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
182    {
183       if (jitter->buf[i]==NULL)
184          break;
185    }
186
187    /*fprintf(stderr, "%d %d %f\n", timestamp, jitter->pointer_timestamp, jitter->drift_average);*/
188    /*No place left in the buffer*/
189    if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
190    {
191       int earliest=jitter->timestamp[0];
192       i=0;
193       for (j=1;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++)
194       {
195          if (!jitter->buf[i] || LT32(jitter->timestamp[j],earliest))
196          {
197             earliest = jitter->timestamp[j];
198             i=j;
199          }
200       }
201       if (jitter->destroy)
202          jitter->destroy(jitter->buf[i]);
203       else
204          speex_free(jitter->buf[i]);
205       jitter->buf[i]=NULL;
206       if (jitter->lost_count>20)
207       {
208          jitter_buffer_reset(jitter);
209       }
210       /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/      
211    }
212    
213    /* Copy packet in buffer */
214    if (jitter->destroy)
215    {
216       jitter->buf[i] = packet->data;
217    } else {
218       jitter->buf[i]=(char*)speex_alloc(packet->len);
219       for (j=0;j<packet->len;j++)
220          jitter->buf[i][j]=packet->data[j];
221    }
222    jitter->timestamp[i]=packet->timestamp;
223    jitter->span[i]=packet->span;
224    jitter->len[i]=packet->len;
225    
226    if (jitter->sub_clock == -1)
227       arrival_time = jitter->pointer_timestamp;
228    else
229       arrival_time = jitter->current_timestamp + jitter->sub_clock;
230    
231    if (jitter->current_timestamp + jitter->sub_clock > jitter->pointer_timestamp)
232       speex_warning("something's wrong with the time");
233    
234    /* Adjust the buffer size depending on network conditions.
235       The arrival margin is how much in advance (or late) the packet it */
236    /* FIXME: We might be one tick off in considering what's late */
237    arrival_margin = (((spx_int32_t)packet->timestamp) - ((spx_int32_t)arrival_time))/jitter->resolution - jitter->buffer_margin;
238    
239    if (arrival_margin >= -jitter->late_cutoff)
240    {
241       /* Here we compute the histogram based on the time of arrival of the packet.
242          This is based on a (first-order) recursive average. We keep both a short-term
243          histogram and a long-term histogram */
244       spx_int32_t int_margin;
245       /* First, apply the "damping" of the recursive average to all bins */
246       for (i=0;i<MAX_MARGIN;i++)
247       {
248          jitter->shortterm_margin[i] *= .98;
249          jitter->longterm_margin[i] *= .995;
250       }
251       /* What histogram bin the packet should be counted in */
252       int_margin = LATE_BINS + arrival_margin;
253       if (int_margin>MAX_MARGIN-1)
254          int_margin = MAX_MARGIN-1;
255       if (int_margin<0)
256          int_margin = 0;
257       /* Add the packet to the right bin */
258       jitter->shortterm_margin[int_margin] += .02;
259       jitter->longterm_margin[int_margin] += .005;
260    } else {
261       /* Packet has arrived *way* too late, we pretty much consider it lost and not take it into account in the histogram */
262       /*fprintf (stderr, "way too late = %d\n", arrival_margin);*/
263       if (jitter->lost_count>20)
264       {
265          jitter_buffer_reset(jitter);
266       }
267    }
268 #if 0 /* Enable to check how much is being buffered */
269    if (rand()%1000==0)
270    {
271       int count = 0;
272       for (j=0;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++)
273       {
274          if (jitter->buf[j])
275             count++;
276       }
277       fprintf (stderr, "buffer_size = %d\n", count);
278    }
279 #endif
280 }
281
282 /** Get one packet from the jitter buffer */
283 int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset)
284 {
285    int i;
286    unsigned int j;
287    float late_ratio_short;
288    float late_ratio_long;
289    float ontime_ratio_short;
290    float ontime_ratio_long;
291    float early_ratio_short;
292    float early_ratio_long;
293    int incomplete = 0;
294    
295    if (jitter->current_timestamp + jitter->sub_clock > jitter->pointer_timestamp)
296       speex_warning("something's wrong with the time");
297
298    jitter->sub_clock = -1;
299    jitter->current_timestamp = jitter->pointer_timestamp;
300    
301    if (jitter->interp_requested)
302    {
303       jitter->interp_requested = 0;
304       if (start_offset)
305          *start_offset = 0;
306       packet->timestamp = jitter->pointer_timestamp;
307       packet->span = jitter->delay_step;
308       jitter->pointer_timestamp += jitter->delay_step;
309       packet->len = 0;
310       return JITTER_BUFFER_MISSING;
311    }
312    /*fprintf (stderr, "get packet %d %d\n", jitter->pointer_timestamp, jitter->current_timestamp);*/
313    
314    /* Compiling arrival statistics */
315    
316    late_ratio_short = 0;
317    late_ratio_long = 0;
318    /* Count the proportion of packets that are late */
319    for (i=0;i<LATE_BINS;i++)
320    {
321       late_ratio_short += jitter->shortterm_margin[i];
322       late_ratio_long += jitter->longterm_margin[i];
323    }
324    /* Count the proportion of packets that are just on time */
325    ontime_ratio_short = jitter->shortterm_margin[LATE_BINS];
326    ontime_ratio_long = jitter->longterm_margin[LATE_BINS];
327    early_ratio_short = early_ratio_long = 0;
328    /* Count the proportion of packets that are early */
329    for (i=LATE_BINS+1;i<MAX_MARGIN;i++)
330    {
331       early_ratio_short += jitter->shortterm_margin[i];
332       early_ratio_long += jitter->longterm_margin[i];
333    }
334    if (0&&jitter->pointer_timestamp%1000==0)
335    {
336       /*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);*/
337       /*fprintf (stderr, "%f %f\n", early_ratio_short + ontime_ratio_short + late_ratio_short, early_ratio_long + ontime_ratio_long + late_ratio_long);*/
338    }
339    
340    
341    /* Searching for the packet that fits best */
342    
343    /* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */
344    for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
345    {
346       if (jitter->buf[i] && jitter->timestamp[i]==jitter->pointer_timestamp && GE32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp+desired_span))
347          break;
348    }
349    
350    /* If no match, try for an "older" packet that still spans (fully) the current chunk */
351    if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
352    {
353       for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
354       {
355          if (jitter->buf[i] && LE32(jitter->timestamp[i], jitter->pointer_timestamp) && GE32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp+desired_span))
356             break;
357       }
358    }
359    
360    /* If still no match, try for an "older" packet that spans part of the current chunk */
361    if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
362    {
363       for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
364       {
365          if (jitter->buf[i] && LE32(jitter->timestamp[i], jitter->pointer_timestamp) && GT32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp))
366             break;
367       }
368    }
369    
370    /* If still no match, try for earliest packet possible */
371    if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
372    {
373       int found = 0;
374       spx_uint32_t best_time=0;
375       int best_span=0;
376       int besti=0;
377       for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
378       {
379          /* check if packet starts within current chunk */
380          if (jitter->buf[i] && LT32(jitter->timestamp[i],jitter->pointer_timestamp+desired_span) && GE32(jitter->timestamp[i],jitter->pointer_timestamp))
381          {
382             if (!found || LT32(jitter->timestamp[i],best_time) || (jitter->timestamp[i]==best_time && GT32(jitter->span[i],best_span)))
383             {
384                best_time = jitter->timestamp[i];
385                best_span = jitter->span[i];
386                besti = i;
387                found = 1;
388             }
389          }
390       }
391       if (found)
392       {
393          i=besti;
394          incomplete = 1;
395          /*fprintf (stderr, "incomplete: %d %d %d %d\n", jitter->timestamp[i], jitter->pointer_timestamp, chunk_size, jitter->span[i]);*/
396       }
397    }
398
399    /* If we find something */
400    if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE)
401    {
402       /* We (obviously) haven't lost this packet */
403       jitter->lost_count = 0;
404       jitter->loss_rate = .999*jitter->loss_rate;
405       /* Check for potential overflow */
406       packet->len = jitter->len[i];
407       /* Copy packet */
408       if (jitter->destroy)
409       {
410          packet->data = jitter->buf[i];
411       } else {
412          for (j=0;j<packet->len;j++)
413             packet->data[j] = jitter->buf[i][j];
414          /* Remove packet */
415          speex_free(jitter->buf[i]);
416       }
417       jitter->buf[i] = NULL;
418       /* Set timestamp and span (if requested) */
419       if (start_offset)
420          *start_offset = (spx_int32_t)jitter->timestamp[i]-(spx_int32_t)jitter->pointer_timestamp;
421       packet->timestamp = jitter->timestamp[i];
422       packet->span = jitter->span[i];
423       /* Point to the end of the current packet */
424       jitter->pointer_timestamp = jitter->timestamp[i]+jitter->span[i];
425       if (incomplete)
426          return JITTER_BUFFER_INCOMPLETE;
427       else
428          return JITTER_BUFFER_OK;
429    }
430    
431    
432    /* If we haven't found anything worth returning */
433    
434    /*fprintf (stderr, "not found\n");*/
435    jitter->lost_count++;
436    /*fprintf (stderr, "m");*/
437    /*fprintf (stderr, "lost_count = %d\n", jitter->lost_count);*/
438    jitter->loss_rate = .999*jitter->loss_rate + .001;
439    if (start_offset)
440       *start_offset = 0;
441    packet->timestamp = jitter->pointer_timestamp;
442    packet->span = desired_span;
443    jitter->pointer_timestamp += desired_span;
444    packet->len = 0;
445    
446    /* Adjusting the buffering bssed on the amount of packets that are early/on time/late */   
447    if (late_ratio_short > .1 || late_ratio_long > .03)
448    {
449       /* If too many packets are arriving late */
450       jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2];
451       jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2];
452       for (i=MAX_MARGIN-3;i>=0;i--)
453       {
454          jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i];
455          jitter->longterm_margin[i+1] = jitter->longterm_margin[i];         
456       }
457       jitter->shortterm_margin[0] = 0;
458       jitter->longterm_margin[0] = 0;            
459       jitter->pointer_timestamp -= jitter->delay_step;
460       jitter->current_timestamp -= jitter->delay_step;
461       /*fprintf (stderr, "i");*/
462       /*fprintf (stderr, "interpolate (getting some slack)\n");*/
463    }
464
465    return JITTER_BUFFER_MISSING;
466
467 }
468
469 /** Get pointer timestamp of jitter buffer */
470 int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter)
471 {
472    return jitter->pointer_timestamp;
473 }
474
475 void jitter_buffer_tick(JitterBuffer *jitter)
476 {
477    if (jitter->sub_clock == -1)
478       jitter->sub_clock = 0;
479    jitter->sub_clock += jitter->resolution;
480 }
481
482 /* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */
483 int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
484 {
485    int i;
486    float late_ratio_short;
487    float late_ratio_long;
488    float ontime_ratio_short;
489    float ontime_ratio_long;
490    float early_ratio_short;
491    float early_ratio_long;
492    
493    /*fprintf (stderr, "get packet %d %d\n", jitter->pointer_timestamp, jitter->current_timestamp);*/
494
495    /* FIXME: This should be only what remaining of the current tick */
496    late_ratio_short = 0;
497    late_ratio_long = 0;
498    /* Count the proportion of packets that are late */
499    for (i=0;i<LATE_BINS;i++)
500    {
501       late_ratio_short += jitter->shortterm_margin[i];
502       late_ratio_long += jitter->longterm_margin[i];
503    }
504    /* Count the proportion of packets that are just on time */
505    ontime_ratio_short = jitter->shortterm_margin[LATE_BINS];
506    ontime_ratio_long = jitter->longterm_margin[LATE_BINS];
507    early_ratio_short = early_ratio_long = 0;
508    /* Count the proportion of packets that are early */
509    for (i=LATE_BINS+1;i<MAX_MARGIN;i++)
510    {
511       early_ratio_short += jitter->shortterm_margin[i];
512       early_ratio_long += jitter->longterm_margin[i];
513    }
514    
515    /* Adjusting the buffering bssed on the amount of packets that are early/on time/late */   
516    if (late_ratio_short > .1 || late_ratio_long > .03)
517    {
518       /* If too many packets are arriving late */
519       jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2];
520       jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2];
521       for (i=MAX_MARGIN-3;i>=0;i--)
522       {
523          jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i];
524          jitter->longterm_margin[i+1] = jitter->longterm_margin[i];         
525       }
526       jitter->shortterm_margin[0] = 0;
527       jitter->longterm_margin[0] = 0;            
528       jitter->pointer_timestamp -= jitter->delay_step;
529       jitter->current_timestamp -= jitter->delay_step;
530       jitter->interp_requested = 1;
531       return JITTER_BUFFER_ADJUST_INTERPOLATE;
532    
533    } else if (late_ratio_short + ontime_ratio_short < .005 && late_ratio_long + ontime_ratio_long < .01 && early_ratio_short > .8)
534    {
535       /* Many frames arriving early */
536       jitter->shortterm_margin[0] += jitter->shortterm_margin[1];
537       jitter->longterm_margin[0] += jitter->longterm_margin[1];
538       for (i=1;i<MAX_MARGIN-1;i++)
539       {
540          jitter->shortterm_margin[i] = jitter->shortterm_margin[i+1];
541          jitter->longterm_margin[i] = jitter->longterm_margin[i+1];         
542       }
543       jitter->shortterm_margin[MAX_MARGIN-1] = 0;
544       jitter->longterm_margin[MAX_MARGIN-1] = 0;      
545       /*fprintf (stderr, "drop frame\n");*/
546       /*fprintf (stderr, "d");*/
547       jitter->pointer_timestamp += jitter->delay_step;
548       jitter->current_timestamp += jitter->delay_step;
549       return JITTER_BUFFER_ADJUST_DROP;
550    }
551    
552    return JITTER_BUFFER_ADJUST_OK;
553 }
554
555 /* Used like the ioctl function to control the jitter buffer parameters */
556 int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
557 {
558    int count, i;
559    switch(request)
560    {
561       case JITTER_BUFFER_SET_MARGIN:
562          jitter->buffer_margin = *(spx_int32_t*)ptr;
563          break;
564       case JITTER_BUFFER_GET_MARGIN:
565          *(spx_int32_t*)ptr = jitter->buffer_margin;
566          break;
567       case JITTER_BUFFER_GET_AVALIABLE_COUNT:
568          count = 0;
569          for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
570          {
571             if (jitter->buf[i] && LE32(jitter->pointer_timestamp, jitter->timestamp[i]))
572             {
573                count++;
574             }
575          }
576          *(spx_int32_t*)ptr = count;
577          break;
578       case JITTER_BUFFER_SET_DESTROY_CALLBACK:
579          jitter->destroy = (void (*) (void *))ptr;
580          break;
581       case JITTER_BUFFER_GET_DESTROY_CALLBACK:
582          *(void (**) (void *))ptr = jitter->destroy;
583          break;
584       case JITTER_BUFFER_SET_DELAY_STEP:
585          jitter->delay_step = *(spx_int32_t*)ptr;
586          break;
587       case JITTER_BUFFER_GET_DELAY_STEP:
588          *(spx_int32_t*)ptr = jitter->delay_step;
589          break;
590       default:
591          speex_warning_int("Unknown jitter_buffer_ctl request: ", request);
592          return -1;
593    }
594    return 0;
595 }
596