2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2004-2005, Horizon Wimba, Inc.
7 * Steve Kann <stevek@stevek.com>
9 * A license has been granted to Digium (via disclaimer) for the use of
12 * See http://www.asterisk.org for more information about
13 * the Asterisk project. Please do not directly contact
14 * any of the maintainers of this project for assistance;
15 * the project provides a web site, mailing lists and IRC
16 * channels for your use.
18 * This program is free software, distributed under the terms of
19 * the GNU General Public License Version 2. See the LICENSE file
20 * at the top of the source tree.
25 * \brief jitterbuf: an application-independent jitterbuffer
26 * \author Steve Kann <stevek@stevek.com>
32 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
34 #include "jitterbuf.h"
35 #include "asterisk/utils.h"
37 /*! define these here, just for ancient compiler systems */
38 #define JB_LONGMAX 2147483647L
39 #define JB_LONGMIN (-JB_LONGMAX - 1L)
41 #define jb_warn(...) (warnf ? warnf(__VA_ARGS__) : (void)0)
42 #define jb_err(...) (errf ? errf(__VA_ARGS__) : (void)0)
43 #define jb_dbg(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
46 #define jb_dbg2(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
48 #define jb_dbg2(...) ((void)0)
51 static jb_output_function_t warnf
, errf
, dbgf
;
53 void jb_setoutput(jb_output_function_t err
, jb_output_function_t warn
, jb_output_function_t dbg
)
60 static void increment_losspct(jitterbuf
*jb
)
62 jb
->info
.losspct
= (100000 + 499 * jb
->info
.losspct
)/500;
65 static void decrement_losspct(jitterbuf
*jb
)
67 jb
->info
.losspct
= (499 * jb
->info
.losspct
)/500;
70 void jb_reset(jitterbuf
*jb
)
72 /* only save settings */
73 jb_conf s
= jb
->info
.conf
;
74 memset(jb
, 0, sizeof(*jb
));
77 /* initialize length, using the default value */
78 jb
->info
.current
= jb
->info
.target
= jb
->info
.conf
.target_extra
= JB_TARGET_EXTRA
;
79 jb
->info
.silence_begin_ts
= -1;
86 if (!(jb
= ast_malloc(sizeof(*jb
))))
91 jb_dbg2("jb_new() = %x\n", jb
);
95 void jb_destroy(jitterbuf
*jb
)
98 jb_dbg2("jb_destroy(%x)\n", jb
);
100 /* free all the frames on the "free list" */
102 while (frame
!= NULL
) {
103 jb_frame
*next
= frame
->next
;
108 /* free ourselves! */
115 static int longcmp(const void *a
, const void *b
)
117 return *(long *)a
- *(long *)b
;
121 /*! \brief simple history manipulation
122 \note maybe later we can make the history buckets variable size, or something? */
123 /* drop parameter determines whether we will drop outliers to minimize
125 static int history_put(jitterbuf
*jb
, long ts
, long now
, long ms
)
127 long delay
= now
- (ts
- jb
->info
.resync_offset
);
128 long threshold
= 2 * jb
->info
.jitter
+ jb
->info
.conf
.resync_threshold
;
131 /* don't add special/negative times to history */
135 /* check for drastic change in delay */
136 if (jb
->info
.conf
.resync_threshold
!= -1) {
137 if (abs(delay
- jb
->info
.last_delay
) > threshold
) {
138 jb
->info
.cnt_delay_discont
++;
139 if (jb
->info
.cnt_delay_discont
> 3) {
140 /* resync the jitterbuffer */
141 jb
->info
.cnt_delay_discont
= 0;
143 jb
->hist_maxbuf_valid
= 0;
145 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
);
146 jb
->info
.resync_offset
= ts
- now
;
147 jb
->info
.last_delay
= delay
= 0; /* after resync, frame is right on time */
152 jb
->info
.last_delay
= delay
;
153 jb
->info
.cnt_delay_discont
= 0;
157 kicked
= jb
->history
[jb
->hist_ptr
% JB_HISTORY_SZ
];
159 jb
->history
[(jb
->hist_ptr
++) % JB_HISTORY_SZ
] = delay
;
161 /* optimization; the max/min buffers don't need to be recalculated, if this packet's
162 * entry doesn't change them. This happens if this packet is not involved, _and_ any packet
163 * that got kicked out of the history is also not involved
164 * We do a number of comparisons, but it's probably still worthwhile, because it will usually
165 * succeed, and should be a lot faster than going through all 500 packets in history */
166 if (!jb
->hist_maxbuf_valid
)
169 /* don't do this until we've filled history
170 * (reduces some edge cases below) */
171 if (jb
->hist_ptr
< JB_HISTORY_SZ
)
174 /* if the new delay would go into min */
175 if (delay
< jb
->hist_minbuf
[JB_HISTORY_MAXBUF_SZ
-1])
179 if (delay
> jb
->hist_maxbuf
[JB_HISTORY_MAXBUF_SZ
-1])
182 /* or the kicked delay would be in min */
183 if (kicked
<= jb
->hist_minbuf
[JB_HISTORY_MAXBUF_SZ
-1])
186 if (kicked
>= jb
->hist_maxbuf
[JB_HISTORY_MAXBUF_SZ
-1])
189 /* if we got here, we don't need to invalidate, 'cause this delay didn't
192 /* end optimization */
196 jb
->hist_maxbuf_valid
= 0;
200 static void history_calc_maxbuf(jitterbuf
*jb
)
204 if (jb
->hist_ptr
== 0)
208 /* initialize maxbuf/minbuf to the latest value */
209 for (i
=0;i
<JB_HISTORY_MAXBUF_SZ
;i
++) {
211 * jb->hist_maxbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
212 * jb->hist_minbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
214 jb
->hist_maxbuf
[i
] = JB_LONGMIN
;
215 jb
->hist_minbuf
[i
] = JB_LONGMAX
;
218 /* use insertion sort to populate maxbuf */
219 /* we want it to be the top "n" values, in order */
221 /* start at the beginning, or JB_HISTORY_SZ frames ago */
222 i
= (jb
->hist_ptr
> JB_HISTORY_SZ
) ? (jb
->hist_ptr
- JB_HISTORY_SZ
) : 0;
224 for (;i
<jb
->hist_ptr
;i
++) {
225 long toins
= jb
->history
[i
% JB_HISTORY_SZ
];
227 /* if the maxbuf should get this */
228 if (toins
> jb
->hist_maxbuf
[JB_HISTORY_MAXBUF_SZ
-1]) {
230 /* insertion-sort it into the maxbuf */
231 for (j
=0;j
<JB_HISTORY_MAXBUF_SZ
;j
++) {
232 /* found where it fits */
233 if (toins
> jb
->hist_maxbuf
[j
]) {
235 memmove(jb
->hist_maxbuf
+ j
+ 1, jb
->hist_maxbuf
+ j
, (JB_HISTORY_MAXBUF_SZ
- (j
+ 1)) * sizeof(jb
->hist_maxbuf
[0]));
237 jb
->hist_maxbuf
[j
] = toins
;
244 /* if the minbuf should get this */
245 if (toins
< jb
->hist_minbuf
[JB_HISTORY_MAXBUF_SZ
-1]) {
247 /* insertion-sort it into the maxbuf */
248 for (j
=0;j
<JB_HISTORY_MAXBUF_SZ
;j
++) {
249 /* found where it fits */
250 if (toins
< jb
->hist_minbuf
[j
]) {
252 memmove(jb
->hist_minbuf
+ j
+ 1, jb
->hist_minbuf
+ j
, (JB_HISTORY_MAXBUF_SZ
- (j
+ 1)) * sizeof(jb
->hist_minbuf
[0]));
254 jb
->hist_minbuf
[j
] = toins
;
263 fprintf(stderr
, "toins = %ld\n", toins
);
264 fprintf(stderr
, "maxbuf =");
265 for (k
=0;k
<JB_HISTORY_MAXBUF_SZ
;k
++)
266 fprintf(stderr
, "%ld ", jb
->hist_maxbuf
[k
]);
267 fprintf(stderr
, "\nminbuf =");
268 for (k
=0;k
<JB_HISTORY_MAXBUF_SZ
;k
++)
269 fprintf(stderr
, "%ld ", jb
->hist_minbuf
[k
]);
270 fprintf(stderr
, "\n");
274 jb
->hist_maxbuf_valid
= 1;
277 static void history_get(jitterbuf
*jb
)
279 long max
, min
, jitter
;
283 if (!jb
->hist_maxbuf_valid
)
284 history_calc_maxbuf(jb
);
286 /* count is how many items in history we're examining */
287 count
= (jb
->hist_ptr
< JB_HISTORY_SZ
) ? jb
->hist_ptr
: JB_HISTORY_SZ
;
289 /* idx is the "n"ths highest/lowest that we'll look for */
290 idx
= count
* JB_HISTORY_DROPPCT
/ 100;
292 /* sanity checks for idx */
293 if (idx
> (JB_HISTORY_MAXBUF_SZ
- 1))
294 idx
= JB_HISTORY_MAXBUF_SZ
- 1;
302 max
= jb
->hist_maxbuf
[idx
];
303 min
= jb
->hist_minbuf
[idx
];
307 /* these debug stmts compare the difference between looking at the absolute jitter, and the
308 * values we get by throwing away the outliers */
310 fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", index, min, max, jitter);
311 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]);
315 jb
->info
.jitter
= jitter
;
318 /* returns 1 if frame was inserted into head of queue, 0 otherwise */
319 static int queue_put(jitterbuf
*jb
, void *data
, const enum jb_frame_type type
, long ms
, long ts
)
324 long resync_ts
= ts
- jb
->info
.resync_offset
;
326 if ((frame
= jb
->free
)) {
327 jb
->free
= frame
->next
;
328 } else if (!(frame
= ast_malloc(sizeof(*frame
)))) {
329 jb_err("cannot allocate frame\n");
333 jb
->info
.frames_cur
++;
336 frame
->ts
= resync_ts
;
341 * frames are a circular list, jb-frames points to to the lowest ts,
342 * jb->frames->prev points to the highest ts
345 if (!jb
->frames
) { /* queue is empty */
350 } else if (resync_ts
< jb
->frames
->ts
) {
351 frame
->next
= jb
->frames
;
352 frame
->prev
= jb
->frames
->prev
;
354 frame
->next
->prev
= frame
;
355 frame
->prev
->next
= frame
;
357 /* frame is out of order */
358 jb
->info
.frames_ooo
++;
365 /* frame is out of order */
366 if (resync_ts
< p
->prev
->ts
) jb
->info
.frames_ooo
++;
368 while (resync_ts
< p
->prev
->ts
&& p
->prev
!= jb
->frames
)
372 frame
->prev
= p
->prev
;
374 frame
->next
->prev
= frame
;
375 frame
->prev
->next
= frame
;
380 static long queue_next(jitterbuf
*jb
)
383 return jb
->frames
->ts
;
388 static long queue_last(jitterbuf
*jb
)
391 return jb
->frames
->prev
->ts
;
396 static jb_frame
*_queue_get(jitterbuf
*jb
, long ts
, int all
)
404 /*jb_warn("queue_get: ASK %ld FIRST %ld\n", ts, frame->ts); */
406 if (all
|| ts
>= frame
->ts
) {
407 /* remove this frame */
408 frame
->prev
->next
= frame
->next
;
409 frame
->next
->prev
= frame
->prev
;
411 if (frame
->next
== frame
)
414 jb
->frames
= frame
->next
;
417 /* insert onto "free" single-linked list */
418 frame
->next
= jb
->free
;
421 jb
->info
.frames_cur
--;
423 /* we return the frame pointer, even though it's on free list,
424 * but caller must copy data */
431 static jb_frame
*queue_get(jitterbuf
*jb
, long ts
)
433 return _queue_get(jb
,ts
,0);
436 static jb_frame
*queue_getall(jitterbuf
*jb
)
438 return _queue_get(jb
,0,1);
442 /* some diagnostics */
443 static void jb_dbginfo(jitterbuf
*jb
)
448 jb_dbg("\njb info: fin=%ld fout=%ld flate=%ld flost=%ld fdrop=%ld fcur=%ld\n",
449 jb
->info
.frames_in
, jb
->info
.frames_out
, jb
->info
.frames_late
, jb
->info
.frames_lost
, jb
->info
.frames_dropped
, jb
->info
.frames_cur
);
451 jb_dbg("jitter=%ld current=%ld target=%ld min=%ld sil=%d len=%d len/fcur=%ld\n",
452 jb
->info
.jitter
, jb
->info
.current
, jb
->info
.target
, jb
->info
.min
, jb
->info
.silence_begin_ts
, jb
->info
.current
- jb
->info
.min
,
453 jb
->info
.frames_cur
? (jb
->info
.current
- jb
->info
.min
)/jb
->info
.frames_cur
: -8);
454 if (jb
->info
.frames_in
> 0)
455 jb_dbg("jb info: Loss PCT = %ld%%, Late PCT = %ld%%\n",
456 jb
->info
.frames_lost
* 100/(jb
->info
.frames_in
+ jb
->info
.frames_lost
),
457 jb
->info
.frames_late
* 100/jb
->info
.frames_in
);
458 jb_dbg("jb info: queue %d -> %d. last_ts %d (queue len: %d) last_ms %d\n",
461 jb
->info
.next_voice_ts
,
462 queue_last(jb
) - queue_next(jb
),
463 jb
->info
.last_voice_ms
);
468 static void jb_chkqueue(jitterbuf
*jb
)
471 jb_frame
*p
= jb
->frames
;
478 if (p
->next
== NULL
) {
479 jb_err("Queue is BROKEN at item [%d]", i
);
483 } while (p
->next
!= jb
->frames
);
486 static void jb_dbgqueue(jitterbuf
*jb
)
489 jb_frame
*p
= jb
->frames
;
499 jb_dbg("[%d]=%ld ", i
++, p
->ts
);
501 } while (p
->next
!= jb
->frames
);
507 enum jb_return_code
jb_put(jitterbuf
*jb
, void *data
, const enum jb_frame_type type
, long ms
, long ts
, long now
)
511 jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb
, data
, ms
, ts
, now
);
513 jb
->info
.frames_in
++;
515 if (jb
->frames
&& jb
->dropem
)
519 if (type
== JB_TYPE_VOICE
) {
520 /* presently, I'm only adding VOICE frames to history and drift calculations; mostly because with the
521 * IAX integrations, I'm sending retransmitted control frames with their awkward timestamps through */
522 if (history_put(jb
,ts
,now
,ms
))
527 numts
= jb
->frames
->prev
->ts
- jb
->frames
->ts
;
528 if (numts
>= jb
->info
.conf
.max_jitterbuf
) {
529 ast_debug(1, "Attempting to exceed Jitterbuf max %ld timeslots\n",
530 jb
->info
.conf
.max_jitterbuf
);
534 /* if put into head of queue, caller needs to reschedule */
535 if (queue_put(jb
,data
,type
,ms
,ts
)) {
542 static enum jb_return_code
_jb_get(jitterbuf
*jb
, jb_frame
*frameout
, long now
, long interpl
)
546 static int dbg_cnt
= 0;
548 /*if ((now - jb_next(jb)) > 2 * jb->info.last_voice_ms) jb_warn("SCHED: %ld", (now - jb_next(jb))); */
549 /* get jitter info */
552 if (dbg_cnt
&& dbg_cnt
% 50 == 0) {
558 jb
->info
.target
= jb
->info
.jitter
+ jb
->info
.min
+ jb
->info
.conf
.target_extra
;
560 /* if a hard clamp was requested, use it */
561 if ((jb
->info
.conf
.max_jitterbuf
) && ((jb
->info
.target
- jb
->info
.min
) > jb
->info
.conf
.max_jitterbuf
)) {
562 jb_dbg("clamping target from %ld to %ld\n", (jb
->info
.target
- jb
->info
.min
), jb
->info
.conf
.max_jitterbuf
);
563 jb
->info
.target
= jb
->info
.min
+ jb
->info
.conf
.max_jitterbuf
;
566 diff
= jb
->info
.target
- jb
->info
.current
;
568 /* jb_warn("diff = %d lms=%d last = %d now = %d\n", diff, */
569 /* jb->info.last_voice_ms, jb->info.last_adjustment, now); */
571 /* let's work on non-silent case first */
572 if (!jb
->info
.silence_begin_ts
) {
573 /* we want to grow */
575 /* we haven't grown in the delay length */
576 (((jb
->info
.last_adjustment
+ JB_ADJUST_DELAY
) < now
) ||
577 /* we need to grow more than the "length" we have left */
578 (diff
> queue_last(jb
) - queue_next(jb
)) ) ) {
579 /* grow by interp frame length */
580 jb
->info
.current
+= interpl
;
581 jb
->info
.next_voice_ts
+= interpl
;
582 jb
->info
.last_voice_ms
= interpl
;
583 jb
->info
.last_adjustment
= now
;
584 jb
->info
.cnt_contig_interp
++;
585 if (jb
->info
.conf
.max_contig_interp
&& jb
->info
.cnt_contig_interp
>= jb
->info
.conf
.max_contig_interp
) {
586 jb
->info
.silence_begin_ts
= jb
->info
.next_voice_ts
- jb
->info
.current
;
592 frame
= queue_get(jb
, jb
->info
.next_voice_ts
- jb
->info
.current
);
594 /* not a voice frame; just return it. */
595 if (frame
&& frame
->type
!= JB_TYPE_VOICE
) {
596 if (frame
->type
== JB_TYPE_SILENCE
) {
597 jb
->info
.silence_begin_ts
= frame
->ts
;
598 jb
->info
.cnt_contig_interp
= 0;
602 jb
->info
.frames_out
++;
608 /* voice frame is later than expected */
609 if (frame
&& frame
->ts
+ jb
->info
.current
< jb
->info
.next_voice_ts
) {
610 if (frame
->ts
+ jb
->info
.current
> jb
->info
.next_voice_ts
- jb
->info
.last_voice_ms
) {
611 /* either we interpolated past this frame in the last jb_get */
612 /* or the frame is still in order, but came a little too quick */
614 /* reset expectation for next frame */
615 jb
->info
.next_voice_ts
= frame
->ts
+ jb
->info
.current
+ frame
->ms
;
616 jb
->info
.frames_out
++;
617 decrement_losspct(jb
);
618 jb
->info
.cnt_contig_interp
= 0;
622 /* voice frame is late */
624 jb
->info
.frames_out
++;
625 decrement_losspct(jb
);
626 jb
->info
.frames_late
++;
627 jb
->info
.frames_lost
--;
629 /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb));
635 /* keep track of frame sizes, to allow for variable sized-frames */
636 if (frame
&& frame
->ms
> 0) {
637 jb
->info
.last_voice_ms
= frame
->ms
;
640 /* we want to shrink; shrink at 1 frame / 500ms */
641 /* unless we don't have a frame, then shrink 1 frame */
642 /* every 80ms (though perhaps we can shrink even faster */
644 if (diff
< -jb
->info
.conf
.target_extra
&&
645 ((!frame
&& jb
->info
.last_adjustment
+ 80 < now
) ||
646 (jb
->info
.last_adjustment
+ 500 < now
))) {
648 jb
->info
.last_adjustment
= now
;
649 jb
->info
.cnt_contig_interp
= 0;
653 /* shrink by frame size we're throwing out */
654 jb
->info
.current
-= frame
->ms
;
655 jb
->info
.frames_out
++;
656 decrement_losspct(jb
);
657 jb
->info
.frames_dropped
++;
661 /* shrink by last_voice_ms */
662 jb
->info
.current
-= jb
->info
.last_voice_ms
;
663 jb
->info
.frames_lost
++;
664 increment_losspct(jb
);
672 /* this is a bit of a hack for now, but if we're close to
673 * target, and we find a missing frame, it makes sense to
674 * grow, because the frame might just be a bit late;
675 * otherwise, we presently get into a pattern where we return
676 * INTERP for the lost frame, then it shows up next, and we
677 * throw it away because it's late */
678 /* I've recently only been able to replicate this using
679 * iaxclient talking to app_echo on asterisk. In this case,
680 * my outgoing packets go through asterisk's (old)
681 * jitterbuffer, and then might get an unusual increasing delay
682 * there if it decides to grow?? */
683 /* Update: that might have been a different bug, that has been fixed..
684 * But, this still seemed like a good idea, except that it ended up making a single actual
685 * lost frame get interpolated two or more times, when there was "room" to grow, so it might
686 * be a bit of a bad idea overall */
687 /*if (diff > -1 * jb->info.last_voice_ms) {
688 jb->info.current += jb->info.last_voice_ms;
689 jb->info.last_adjustment = now;
693 jb
->info
.frames_lost
++;
694 increment_losspct(jb
);
695 jb
->info
.next_voice_ts
+= interpl
;
696 jb
->info
.last_voice_ms
= interpl
;
697 jb
->info
.cnt_contig_interp
++;
698 if (jb
->info
.conf
.max_contig_interp
&& jb
->info
.cnt_contig_interp
>= jb
->info
.conf
.max_contig_interp
) {
699 jb
->info
.silence_begin_ts
= jb
->info
.next_voice_ts
- jb
->info
.current
;
705 /* normal case; return the frame, increment stuff */
707 jb
->info
.next_voice_ts
+= frame
->ms
;
708 jb
->info
.frames_out
++;
709 jb
->info
.cnt_contig_interp
= 0;
710 decrement_losspct(jb
);
714 /* TODO: after we get the non-silent case down, we'll make the
715 * silent case -- basically, we'll just grow and shrink faster
716 * here, plus handle next_voice_ts a bit differently */
718 /* to disable silent special case altogether, just uncomment this: */
719 /* jb->info.silence_begin_ts = 0; */
721 /* shrink interpl len every 10ms during silence */
722 if (diff
< -jb
->info
.conf
.target_extra
&&
723 jb
->info
.last_adjustment
+ 10 <= now
) {
724 jb
->info
.current
-= interpl
;
725 jb
->info
.last_adjustment
= now
;
728 frame
= queue_get(jb
, now
- jb
->info
.current
);
731 } else if (frame
->type
!= JB_TYPE_VOICE
) {
732 /* normal case; in silent mode, got a non-voice frame */
734 jb
->info
.frames_out
++;
737 if (frame
->ts
< jb
->info
.silence_begin_ts
) {
738 /* voice frame is late */
740 jb
->info
.frames_out
++;
741 decrement_losspct(jb
);
742 jb
->info
.frames_late
++;
743 jb
->info
.frames_lost
--;
745 /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb));
750 /* try setting current to target right away here */
751 jb
->info
.current
= jb
->info
.target
;
752 jb
->info
.silence_begin_ts
= 0;
753 jb
->info
.next_voice_ts
= frame
->ts
+ jb
->info
.current
+ frame
->ms
;
754 jb
->info
.last_voice_ms
= frame
->ms
;
755 jb
->info
.frames_out
++;
756 decrement_losspct(jb
);
764 long jb_next(jitterbuf
*jb
)
766 if (jb
->info
.silence_begin_ts
) {
768 long next
= queue_next(jb
);
770 /* shrink during silence */
771 if (jb
->info
.target
- jb
->info
.current
< -jb
->info
.conf
.target_extra
)
772 return jb
->info
.last_adjustment
+ 10;
773 return next
+ jb
->info
.target
;
778 return jb
->info
.next_voice_ts
;
782 enum jb_return_code
jb_get(jitterbuf
*jb
, jb_frame
*frameout
, long now
, long interpl
)
784 enum jb_return_code ret
= _jb_get(jb
, frameout
, now
, interpl
);
787 int thists
= ((ret
== JB_OK
) || (ret
== JB_DROP
)) ? frameout
->ts
: 0;
788 jb_warn("jb_get(%x,%x,%ld) = %d (%d)\n", jb
, frameout
, now
, ret
, thists
);
789 if (thists
&& thists
< lastts
) jb_warn("XXXX timestamp roll-back!!!\n");
792 if (ret
== JB_INTERP
)
793 frameout
->ms
= jb
->info
.last_voice_ms
;
798 enum jb_return_code
jb_getall(jitterbuf
*jb
, jb_frame
*frameout
)
801 frame
= queue_getall(jb
);
812 enum jb_return_code
jb_getinfo(jitterbuf
*jb
, jb_info
*stats
)
822 enum jb_return_code
jb_setconf(jitterbuf
*jb
, jb_conf
*conf
)
824 /* take selected settings from the struct */
826 jb
->info
.conf
.max_jitterbuf
= conf
->max_jitterbuf
;
827 jb
->info
.conf
.resync_threshold
= conf
->resync_threshold
;
828 jb
->info
.conf
.max_contig_interp
= conf
->max_contig_interp
;
830 /* -1 indicates use of the default JB_TARGET_EXTRA value */
831 jb
->info
.conf
.target_extra
= ( conf
->target_extra
== -1 )
836 /* update these to match new target_extra setting */
837 jb
->info
.current
= jb
->info
.conf
.target_extra
;
838 jb
->info
.target
= jb
->info
.conf
.target_extra
;