Blindly merge jitter buffer patch of bug #4342)
[asterisk/asterisk.git] / jitterbuf.c
1 /*
2  * jitterbuf: an application-independent jitterbuffer
3  *
4  * Copyrights:
5  * Copyright (C) 2004-2005, Horizon Wimba, Inc.
6  *
7  * Contributors:
8  * Steve Kann <stevek@stevek.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU Lesser (Library) General Public License
12  *
13  * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
14  */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include "jitterbuf.h"
21
22 /* define these here, just for ancient compiler systems */
23 #define JB_LONGMAX 2147483647L
24 #define JB_LONGMIN (-JB_LONGMAX - 1L)
25
26 #define jb_warn(...) (warnf ? warnf(__VA_ARGS__) : (void)0)
27 #define jb_err(...) (errf ? errf(__VA_ARGS__) : (void)0)
28 #define jb_dbg(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
29
30 #ifdef DEEP_DEBUG
31 #define jb_dbg2(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
32 #else
33 #define jb_dbg2(...) ((void)0)
34 #endif
35
36 static jb_output_function_t warnf, errf, dbgf;
37
38 void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg) 
39 {
40         errf = err;
41         warnf = warn;
42         dbgf = dbg;
43 }
44
45 static void increment_losspct(jitterbuf *jb) 
46 {
47         jb->info.losspct = (100000 + 499 * jb->info.losspct)/500;    
48 }
49
50 static void decrement_losspct(jitterbuf *jb) 
51 {
52         jb->info.losspct = (499 * jb->info.losspct)/500;    
53 }
54
55 void jb_reset(jitterbuf *jb) 
56 {
57         /* only save settings */
58         jb_conf s = jb->info.conf;
59         memset(jb,0,sizeof(jitterbuf));
60         jb->info.conf = s;
61
62         /* initialize length */
63         jb->info.current = jb->info.target = JB_TARGET_EXTRA; 
64         jb->info.silence_begin_ts = -1; 
65 }
66
67 jitterbuf * jb_new() 
68 {
69         jitterbuf *jb;
70
71
72         jb = malloc(sizeof(jitterbuf));
73         if (!jb) 
74                 return NULL;
75
76         jb_reset(jb);
77
78         jb_dbg2("jb_new() = %x\n", jb);
79         return jb;
80 }
81
82 void jb_destroy(jitterbuf *jb) 
83 {
84         jb_frame *frame; 
85         jb_dbg2("jb_destroy(%x)\n", jb);
86
87         /* free all the frames on the "free list" */
88         frame = jb->free;
89         while (frame != NULL) {
90                 jb_frame *next = frame->next;
91                 free(frame);
92                 frame = next;
93         }
94
95         /* free ourselves! */ 
96         free(jb);
97 }
98
99
100
101 /* simple history manipulation */
102 /* maybe later we can make the history buckets variable size, or something? */
103 /* drop parameter determines whether we will drop outliers to minimize
104  * delay */
105 #if 0
106 static int longcmp(const void *a, const void *b) 
107 {
108         return *(long *)a - *(long *)b;
109 }
110 #endif
111
112 static int history_put(jitterbuf *jb, long ts, long now, long ms) 
113 {
114         long delay = now - (ts - jb->info.resync_offset);
115         long threshold = 2 * jb->info.jitter + jb->info.conf.resync_threshold;
116         long kicked;
117
118         /* don't add special/negative times to history */
119         if (ts <= 0) 
120                 return 0;
121
122         /* check for drastic change in delay */
123         if (jb->info.conf.resync_threshold != -1) {
124                 if (abs(delay - jb->info.last_delay) > threshold) {
125                         jb->info.cnt_delay_discont++;
126                         if (jb->info.cnt_delay_discont > 3) {
127                                 /* resync the jitterbuffer */
128                                 jb->info.cnt_delay_discont = 0;
129                                 jb->hist_ptr = 0;
130                                 jb->hist_maxbuf_valid = 0;
131
132                                 jb_warn("Resyncing the jb. last_delay %ld, this delay %ld, threshold %ld, new offset %ld\n", jb->info.last_delay, delay, threshold, ts - now);
133                                 jb->info.resync_offset = ts - now;
134                                 jb->info.last_delay = 0; /* after resync, frame is right on time */
135                         } else {
136                                 return -1;
137                         }
138                 } else {
139                         jb->info.last_delay = delay;
140                         jb->info.cnt_delay_discont = 0;
141                 }
142         }
143
144         kicked = jb->history[jb->hist_ptr & JB_HISTORY_SZ];
145
146         jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = delay;
147
148         /* optimization; the max/min buffers don't need to be recalculated, if this packet's
149          * entry doesn't change them.  This happens if this packet is not involved, _and_ any packet
150          * that got kicked out of the history is also not involved 
151          * We do a number of comparisons, but it's probably still worthwhile, because it will usually
152          * succeed, and should be a lot faster than going through all 500 packets in history */
153         if (!jb->hist_maxbuf_valid)
154                 return 0;
155
156         /* don't do this until we've filled history 
157          * (reduces some edge cases below) */
158         if (jb->hist_ptr < JB_HISTORY_SZ)
159                 goto invalidate;
160
161         /* if the new delay would go into min */
162         if (delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
163                 goto invalidate;
164     
165         /* or max.. */
166         if (delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
167                 goto invalidate;
168
169         /* or the kicked delay would be in min */
170         if (kicked <= jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) 
171                 goto invalidate;
172
173         if (kicked >= jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) 
174                 goto invalidate;
175
176         /* if we got here, we don't need to invalidate, 'cause this delay didn't 
177          * affect things */
178         return 0;
179         /* end optimization */
180
181
182 invalidate:
183         jb->hist_maxbuf_valid = 0;
184         return 0;
185 }
186
187 static void history_calc_maxbuf(jitterbuf *jb) 
188 {
189         int i,j;
190
191         if (jb->hist_ptr == 0) 
192                 return;
193
194
195         /* initialize maxbuf/minbuf to the latest value */
196         for (i=0;i<JB_HISTORY_MAXBUF_SZ;i++) {
197 /*
198  * jb->hist_maxbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
199  * jb->hist_minbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
200  */
201                 jb->hist_maxbuf[i] = JB_LONGMIN;
202                 jb->hist_minbuf[i] = JB_LONGMAX;
203         }
204
205         /* use insertion sort to populate maxbuf */
206         /* we want it to be the top "n" values, in order */
207
208         /* start at the beginning, or JB_HISTORY_SZ frames ago */
209         i = (jb->hist_ptr > JB_HISTORY_SZ) ? (jb->hist_ptr - JB_HISTORY_SZ) : 0; 
210
211         for (;i<jb->hist_ptr;i++) {
212                 long toins = jb->history[i % JB_HISTORY_SZ];
213
214                 /* if the maxbuf should get this */
215                 if (toins > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])  {
216
217                         /* insertion-sort it into the maxbuf */
218                         for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
219                                 /* found where it fits */
220                                 if (toins > jb->hist_maxbuf[j]) {
221                                         /* move over */
222                                         memmove(jb->hist_maxbuf+j+1,jb->hist_maxbuf+j, (JB_HISTORY_MAXBUF_SZ-(j+1)) * sizeof(long));
223                                         /* insert */
224                                         jb->hist_maxbuf[j] = toins;
225
226                                         break;
227                                 }
228                         }
229                 }
230
231                 /* if the minbuf should get this */
232                 if (toins < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])  {
233
234                         /* insertion-sort it into the maxbuf */
235                         for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
236                                 /* found where it fits */
237                                 if (toins < jb->hist_minbuf[j]) {
238                                         /* move over */
239                                         memmove(jb->hist_minbuf+j+1,jb->hist_minbuf+j, (JB_HISTORY_MAXBUF_SZ-(j+1)) * sizeof(long));
240                                         /* insert */
241                                         jb->hist_minbuf[j] = toins;
242
243                                         break;
244                                 }
245                         }
246                 }
247
248                 if (0) { 
249                         int k;
250                         fprintf(stderr, "toins = %ld\n", toins);
251                         fprintf(stderr, "maxbuf =");
252                         for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++) 
253                                 fprintf(stderr, "%ld ", jb->hist_maxbuf[k]);
254                         fprintf(stderr, "\nminbuf =");
255                         for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++) 
256                                 fprintf(stderr, "%ld ", jb->hist_minbuf[k]);
257                         fprintf(stderr, "\n");
258                 }
259         }
260
261         jb->hist_maxbuf_valid = 1;
262 }
263
264 static void history_get(jitterbuf *jb) 
265 {
266         long max, min, jitter;
267         int index;
268         int count;
269
270         if (!jb->hist_maxbuf_valid) 
271                 history_calc_maxbuf(jb);
272
273         /* count is how many items in history we're examining */
274         count = (jb->hist_ptr < JB_HISTORY_SZ) ? jb->hist_ptr : JB_HISTORY_SZ;
275
276         /* index is the "n"ths highest/lowest that we'll look for */
277         index = count * JB_HISTORY_DROPPCT / 100;
278
279         /* sanity checks for index */
280         if (index > (JB_HISTORY_MAXBUF_SZ - 1)) 
281                 index = JB_HISTORY_MAXBUF_SZ - 1;
282
283
284         if (index < 0) {
285                 jb->info.min = 0;
286                 jb->info.jitter = 0;
287                 return;
288         }
289
290         max = jb->hist_maxbuf[index];
291         min = jb->hist_minbuf[index];
292
293         jitter = max - min;
294
295         /* these debug stmts compare the difference between looking at the absolute jitter, and the
296          * values we get by throwing away the outliers */
297         /*
298         fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", index, min, max, jitter);
299         fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", 0, jb->hist_minbuf[0], jb->hist_maxbuf[0], jb->hist_maxbuf[0]-jb->hist_minbuf[0]);
300         */
301
302         jb->info.min = min;
303         jb->info.jitter = jitter;
304 }
305
306 /* returns 1 if frame was inserted into head of queue, 0 otherwise */
307 static int queue_put(jitterbuf *jb, void *data, int type, long ms, long ts) 
308 {
309         jb_frame *frame;
310         jb_frame *p;
311         int head = 0;
312         long resync_ts = ts - jb->info.resync_offset;
313
314         frame = jb->free;
315         if (frame) {
316                 jb->free = frame->next;
317         } else {
318                 frame = malloc(sizeof(jb_frame));
319         }
320
321         if (!frame) {
322                 jb_err("cannot allocate frame\n");
323                 return 0;
324         }
325
326         jb->info.frames_cur++;
327
328         frame->data = data;
329         frame->ts = resync_ts;
330         frame->ms = ms;
331         frame->type = type;
332
333         /* 
334          * frames are a circular list, jb-frames points to to the lowest ts, 
335          * jb->frames->prev points to the highest ts
336          */
337
338         if (!jb->frames) {  /* queue is empty */
339                 jb->frames = frame;
340                 frame->next = frame;
341                 frame->prev = frame;
342                 head = 1;
343         } else if (resync_ts < jb->frames->ts) {
344                 frame->next = jb->frames;
345                 frame->prev = jb->frames->prev;
346
347                 frame->next->prev = frame;
348                 frame->prev->next = frame;
349
350                 /* frame is out of order */
351                 jb->info.frames_ooo++;
352
353                 jb->frames = frame;
354                 head = 1;
355         } else { 
356                 p = jb->frames;
357
358                 /* frame is out of order */
359                 if (resync_ts < p->prev->ts) jb->info.frames_ooo++;
360
361                 while (resync_ts < p->prev->ts && p->prev != jb->frames) 
362                         p = p->prev;
363
364                 frame->next = p;
365                 frame->prev = p->prev;
366
367                 frame->next->prev = frame;
368                 frame->prev->next = frame;
369         }
370         return head;
371 }
372
373 static long queue_next(jitterbuf *jb) 
374 {
375         if (jb->frames) 
376                 return jb->frames->ts;
377         else 
378                 return -1;
379 }
380
381 static long queue_last(jitterbuf *jb) 
382 {
383         if (jb->frames) 
384                 return jb->frames->prev->ts;
385         else 
386                 return -1;
387 }
388
389 static jb_frame *_queue_get(jitterbuf *jb, long ts, int all) 
390 {
391         jb_frame *frame;
392         frame = jb->frames;
393
394         if (!frame)
395                 return NULL;
396
397         /*jb_warn("queue_get: ASK %ld FIRST %ld\n", ts, frame->ts); */
398
399         if (all || ts >= frame->ts) {
400                 /* remove this frame */
401                 frame->prev->next = frame->next;
402                 frame->next->prev = frame->prev;
403
404                 if (frame->next == frame)
405                         jb->frames = NULL;
406                 else
407                         jb->frames = frame->next;
408
409
410                 /* insert onto "free" single-linked list */
411                 frame->next = jb->free;
412                 jb->free = frame;
413
414                 jb->info.frames_cur--;
415
416                 /* we return the frame pointer, even though it's on free list, 
417                  * but caller must copy data */
418                 return frame;
419         } 
420
421         return NULL;
422 }
423
424 static jb_frame *queue_get(jitterbuf *jb, long ts) 
425 {
426         return _queue_get(jb,ts,0);
427 }
428
429 static jb_frame *queue_getall(jitterbuf *jb) 
430 {
431         return _queue_get(jb,0,1);
432 }
433
434 #if 0
435 /* some diagnostics */
436 static void jb_dbginfo(jitterbuf *jb) 
437 {
438         if (dbgf == NULL) 
439                 return;
440
441         jb_dbg("\njb info: fin=%ld fout=%ld flate=%ld flost=%ld fdrop=%ld fcur=%ld\n",
442                 jb->info.frames_in, jb->info.frames_out, jb->info.frames_late, jb->info.frames_lost, jb->info.frames_dropped, jb->info.frames_cur);
443         
444         jb_dbg("jitter=%ld current=%ld target=%ld min=%ld sil=%d len=%d len/fcur=%ld\n",
445                 jb->info.jitter, jb->info.current, jb->info.target, jb->info.min, jb->info.silence_begin_ts, jb->info.current - jb->info.min, 
446                 jb->info.frames_cur ? (jb->info.current - jb->info.min)/jb->info.frames_cur : -8);
447         if (jb->info.frames_in > 0) 
448                 jb_dbg("jb info: Loss PCT = %ld%%, Late PCT = %ld%%\n",
449                         jb->info.frames_lost * 100/(jb->info.frames_in + jb->info.frames_lost), 
450                         jb->info.frames_late * 100/jb->info.frames_in);
451         jb_dbg("jb info: queue %d -> %d.  last_ts %d (queue len: %d) last_ms %d\n",
452                 queue_next(jb), 
453                 queue_last(jb),
454                 jb->info.next_voice_ts, 
455                 queue_last(jb) - queue_next(jb),
456                 jb->info.last_voice_ms);
457 }
458 #endif
459
460 #ifdef DEEP_DEBUG
461 static void jb_chkqueue(jitterbuf *jb) 
462 {
463         int i=0;
464         jb_frame *p = jb->frames;
465
466         if (!p) {
467                 return;
468         }
469
470         do {
471                 if (p->next == NULL)  {
472                         jb_err("Queue is BROKEN at item [%d]", i);      
473                 }
474                 i++;
475                 p=p->next;
476         } while (p->next != jb->frames);
477 }
478
479 static void jb_dbgqueue(jitterbuf *jb) 
480 {
481         int i=0;
482         jb_frame *p = jb->frames;
483
484         jb_dbg("queue: ");
485
486         if (!p) {
487                 jb_dbg("EMPTY\n");
488                 return;
489         }
490
491         do {
492                 jb_dbg("[%d]=%ld ", i++, p->ts);
493                 p=p->next;
494         } while (p->next != jb->frames);
495
496         jb_dbg("\n");
497 }
498 #endif
499
500 int jb_put(jitterbuf *jb, void *data, int type, long ms, long ts, long now) 
501 {
502         jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now);
503
504         jb->info.frames_in++;
505
506         if (type == JB_TYPE_VOICE) {
507                 /* presently, I'm only adding VOICE frames to history and drift calculations; mostly because with the
508                  * IAX integrations, I'm sending retransmitted control frames with their awkward timestamps through */
509                 if (history_put(jb,ts,now,ms))
510                         return JB_DROP;
511         }
512
513         /* if put into head of queue, caller needs to reschedule */
514         if (queue_put(jb,data,type,ms,ts)) {
515                 return JB_SCHED;
516         }
517         return JB_OK;
518 }
519
520
521 static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) 
522 {
523         jb_frame *frame;
524         long diff;
525
526         /*if ((now - jb_next(jb)) > 2 * jb->info.last_voice_ms) jb_warn("SCHED: %ld", (now - jb_next(jb))); */
527         /* get jitter info */
528         history_get(jb);
529
530
531         /* target */
532         jb->info.target = jb->info.jitter + jb->info.min + JB_TARGET_EXTRA; 
533
534         /* if a hard clamp was requested, use it */
535         if ((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) {
536                 jb_dbg("clamping target from %d to %d\n", (jb->info.target - jb->info.min), jb->info.conf.max_jitterbuf);
537                 jb->info.target = jb->info.min + jb->info.conf.max_jitterbuf;
538         }
539
540         diff = jb->info.target - jb->info.current;
541
542         /* jb_warn("diff = %d lms=%d last = %d now = %d\n", diff,  */
543         /*      jb->info.last_voice_ms, jb->info.last_adjustment, now); */
544
545         /* let's work on non-silent case first */
546         if (!jb->info.silence_begin_ts) { 
547                 /* we want to grow */
548                 if ((diff > 0) && 
549                         /* we haven't grown in the delay length */
550                         (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) || 
551                         /* we need to grow more than the "length" we have left */
552                         (diff > queue_last(jb)  - queue_next(jb)) ) ) {
553                         /* grow by interp frame length */
554                         jb->info.current += interpl;
555                         jb->info.next_voice_ts += interpl;
556                         jb->info.last_voice_ms = interpl;
557                         jb->info.last_adjustment = now;
558                         jb_dbg("G");
559                         return JB_INTERP;
560                 }
561
562                 frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current);
563
564                 /* not a voice frame; just return it. */
565                 if (frame && frame->type != JB_TYPE_VOICE) {
566                         if (frame->type == JB_TYPE_SILENCE) 
567                                 jb->info.silence_begin_ts = frame->ts;
568
569                         *frameout = *frame;
570                         jb->info.frames_out++;
571                         jb_dbg("o");
572                         return JB_OK;
573                 }
574
575
576                 /* voice frame is later than expected */
577                 if (frame && frame->ts + jb->info.current < jb->info.next_voice_ts) {
578                         if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) {
579                                 /* either we interpolated past this frame in the last jb_get */
580                                 /* or the frame is still in order, but came a little too quick */ 
581                                 *frameout = *frame;
582                                 /* reset expectation for next frame */
583                                 jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
584                                 jb->info.frames_out++;
585                                 decrement_losspct(jb);
586                                 jb_dbg("v");
587                                 return JB_OK;
588                         } else {
589                                 /* voice frame is late */
590                                 *frameout = *frame;
591                                 jb->info.frames_out++;
592                                 decrement_losspct(jb);
593                                 jb->info.frames_late++;
594                                 jb->info.frames_lost--;
595                                 jb_dbg("l");
596                                 /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb));
597                                 jb_warninfo(jb); */
598                                 return JB_DROP;
599                         }
600                 }
601
602                 /* keep track of frame sizes, to allow for variable sized-frames */
603                 if (frame && frame->ms > 0) {
604                         jb->info.last_voice_ms = frame->ms;
605                 }
606
607                 /* we want to shrink; shrink at 1 frame / 500ms */
608                 /* unless we don't have a frame, then shrink 1 frame */
609                 /* every 80ms (though perhaps we can shrink even faster */
610                 /* in this case) */
611                 if (diff < -JB_TARGET_EXTRA && 
612                         ((!frame && jb->info.last_adjustment + 80 < now) || 
613                         (jb->info.last_adjustment + 500 < now))) {
614
615                         jb->info.last_adjustment = now;
616
617                         if (frame) {
618                                 *frameout = *frame;
619                                 /* shrink by frame size we're throwing out */
620                                 jb->info.current -= frame->ms;
621                                 jb->info.frames_out++;
622                                 decrement_losspct(jb);
623                                 jb->info.frames_dropped++;
624                                 jb_dbg("s");
625                                 return JB_DROP;
626                         } else {
627                                 /* shrink by last_voice_ms */
628                                 jb->info.current -= jb->info.last_voice_ms;
629                                 jb->info.frames_lost++;
630                                 increment_losspct(jb);
631                                 jb_dbg("S");
632                                 return JB_NOFRAME;
633                         }
634                 }
635
636                 /* lost frame */
637                 if (!frame) {
638                         /* this is a bit of a hack for now, but if we're close to
639                          * target, and we find a missing frame, it makes sense to
640                          * grow, because the frame might just be a bit late;
641                          * otherwise, we presently get into a pattern where we return
642                          * INTERP for the lost frame, then it shows up next, and we
643                          * throw it away because it's late */
644                         /* I've recently only been able to replicate this using
645                          * iaxclient talking to app_echo on asterisk.  In this case,
646                          * my outgoing packets go through asterisk's (old)
647                          * jitterbuffer, and then might get an unusual increasing delay 
648                          * there if it decides to grow?? */
649                         /* Update: that might have been a different bug, that has been fixed..
650                          * But, this still seemed like a good idea, except that it ended up making a single actual
651                          * lost frame get interpolated two or more times, when there was "room" to grow, so it might
652                          * be a bit of a bad idea overall */
653                         /*if (diff > -1 * jb->info.last_voice_ms) { 
654                                 jb->info.current += jb->info.last_voice_ms;
655                                 jb->info.last_adjustment = now;
656                                 jb_warn("g");
657                                 return JB_INTERP;
658                         } */
659                         jb->info.frames_lost++;
660                         increment_losspct(jb);
661                         jb->info.next_voice_ts += interpl;
662                         jb->info.last_voice_ms = interpl;
663                         jb_dbg("L");
664                         return JB_INTERP;
665                 }
666
667                 /* normal case; return the frame, increment stuff */
668                 *frameout = *frame;
669                 jb->info.next_voice_ts += frame->ms;
670                 jb->info.frames_out++;
671                 decrement_losspct(jb);
672                 jb_dbg("v");
673                 return JB_OK;
674         } else {     
675                 /* TODO: after we get the non-silent case down, we'll make the
676                  * silent case -- basically, we'll just grow and shrink faster
677                  * here, plus handle next_voice_ts a bit differently */
678       
679                 /* to disable silent special case altogether, just uncomment this: */
680                 /* jb->info.silence_begin_ts = 0; */
681
682                 /* shrink interpl len every 10ms during silence */
683                 if (diff < -JB_TARGET_EXTRA &&
684                         jb->info.last_adjustment + 10 <= now) {
685                         jb->info.current -= interpl;
686                         jb->info.last_adjustment = now;
687                 }
688
689                 frame = queue_get(jb, now - jb->info.current);
690                 if (!frame) {
691                         return JB_NOFRAME;
692                 } else if (frame->type != JB_TYPE_VOICE) {
693                         /* normal case; in silent mode, got a non-voice frame */
694                         *frameout = *frame;
695                         jb->info.frames_out++;
696                         return JB_OK;
697                 }
698                 if (frame->ts < jb->info.silence_begin_ts) {
699                         /* voice frame is late */
700                         *frameout = *frame;
701                         jb->info.frames_out++;
702                         decrement_losspct(jb);
703                         jb->info.frames_late++;
704                         jb->info.frames_lost--;
705                         jb_dbg("l");
706                         /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb));
707                         jb_warninfo(jb); */
708                         return JB_DROP;
709                 } else {
710                         /* voice frame */
711                         /* try setting current to target right away here */
712                         jb->info.current = jb->info.target;
713                         jb->info.silence_begin_ts = 0;
714                         jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
715                         jb->info.last_voice_ms = frame->ms;
716                         jb->info.frames_out++;
717                         decrement_losspct(jb);
718                         *frameout = *frame;
719                         jb_dbg("V");
720                         return JB_OK;
721                 }
722         }
723 }
724
725 long jb_next(jitterbuf *jb) 
726 {
727         if (jb->info.silence_begin_ts) {
728                 long next = queue_next(jb);
729                 if (next > 0) { 
730                         history_get(jb);
731                         /* shrink during silence */
732                         if (jb->info.target - jb->info.current < -JB_TARGET_EXTRA)
733                                 return jb->info.last_adjustment + 10;
734                         return next + jb->info.target;
735                 }
736                 else 
737                         return JB_LONGMAX;
738         } else {
739                 return jb->info.next_voice_ts;
740         }
741 }
742
743 int jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) 
744 {
745         int ret = _jb_get(jb,frameout,now,interpl);
746 #if 0
747         static int lastts=0;
748         int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0;
749         jb_warn("jb_get(%x,%x,%ld) = %d (%d)\n", jb, frameout, now, ret, thists);
750         if (thists && thists < lastts) jb_warn("XXXX timestamp roll-back!!!\n");
751         lastts = thists;
752 #endif
753         if(ret == JB_INTERP) 
754                 frameout->ms = jb->info.last_voice_ms;
755         
756         return ret;
757 }
758
759 int jb_getall(jitterbuf *jb, jb_frame *frameout) 
760 {
761         jb_frame *frame;
762         frame = queue_getall(jb);
763
764         if (!frame) {
765                 return JB_NOFRAME;
766         }
767
768         *frameout = *frame;
769         return JB_OK;
770 }
771
772
773 int jb_getinfo(jitterbuf *jb, jb_info *stats) 
774 {
775
776         history_get(jb);
777
778         *stats = jb->info;
779
780         return JB_OK;
781 }
782
783 int jb_setconf(jitterbuf *jb, jb_conf *conf) 
784 {
785         /* take selected settings from the struct */
786
787         jb->info.conf.max_jitterbuf = conf->max_jitterbuf;
788         jb->info.conf.resync_threshold = conf->resync_threshold;
789
790         return JB_OK;
791 }
792
793