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