jitterbuf: an application-independent jitterbuffer More...
#include "asterisk.h"
#include "jitterbuf.h"
#include "asterisk/utils.h"
Go to the source code of this file.
Defines | |
#define | jb_dbg(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0) |
#define | jb_dbg2(...) ((void)0) |
#define | jb_err(...) (errf ? errf(__VA_ARGS__) : (void)0) |
#define | JB_LONGMAX 2147483647L |
#define | JB_LONGMIN (-JB_LONGMAX - 1L) |
#define | jb_warn(...) (warnf ? warnf(__VA_ARGS__) : (void)0) |
Functions | |
static enum jb_return_code | _jb_get (jitterbuf *jb, jb_frame *frameout, long now, long interpl) |
static jb_frame * | _queue_get (jitterbuf *jb, long ts, int all) |
static int | check_resync (jitterbuf *jb, long ts, long now, long ms, const enum jb_frame_type type, long *delay) |
static void | decrement_losspct (jitterbuf *jb) |
static void | history_calc_maxbuf (jitterbuf *jb) |
static void | history_get (jitterbuf *jb) |
static int | history_put (jitterbuf *jb, long ts, long now, long ms, long delay) |
static void | increment_losspct (jitterbuf *jb) |
void | jb_destroy (jitterbuf *jb) |
destroy jitterbuf | |
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! JB_DROP: Here's an audio frame you should just drop. Ask me again for this time.. JB_NOFRAME: There's no frame scheduled for this time. JB_INTERP: Please interpolate an interpl-length frame for this time (either we need to grow, or there was a lost frame) JB_EMPTY: The jb is empty. | |
enum jb_return_code | jb_getall (jitterbuf *jb, jb_frame *frameout) |
unconditionally get frames from jitterbuf until empty | |
enum jb_return_code | jb_getinfo (jitterbuf *jb, jb_info *stats) |
get jitterbuf info: only "statistics" may be valid | |
jitterbuf * | jb_new () |
new jitterbuf | |
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 added (esp non-audio frames) | |
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 | |
void | jb_reset (jitterbuf *jb) |
reset jitterbuf | |
enum jb_return_code | jb_setconf (jitterbuf *jb, jb_conf *conf) |
set jitterbuf conf | |
void | jb_setoutput (jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg) |
static jb_frame * | queue_get (jitterbuf *jb, long ts) |
static jb_frame * | queue_getall (jitterbuf *jb) |
static long | queue_last (jitterbuf *jb) |
static long | queue_next (jitterbuf *jb) |
static int | queue_put (jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, long ts) |
Variables | |
static jb_output_function_t | dbgf |
static jb_output_function_t | errf |
static jb_output_function_t | warnf |
jitterbuf: an application-independent jitterbuffer
Definition in file jitterbuf.c.
Definition at line 47 of file jitterbuf.c.
Referenced by _jb_get().
#define jb_dbg2 | ( | ... | ) | ((void)0) |
Definition at line 52 of file jitterbuf.c.
Referenced by jb_destroy(), jb_new(), and jb_put().
Definition at line 46 of file jitterbuf.c.
Referenced by queue_put().
#define JB_LONGMAX 2147483647L |
define these here, just for ancient compiler systems
Definition at line 42 of file jitterbuf.c.
Referenced by history_calc_maxbuf(), and jb_next().
#define JB_LONGMIN (-JB_LONGMAX - 1L) |
Definition at line 43 of file jitterbuf.c.
Referenced by history_calc_maxbuf().
Definition at line 45 of file jitterbuf.c.
Referenced by check_resync(), and jb_get().
static enum jb_return_code _jb_get | ( | jitterbuf * | jb, | |
jb_frame * | frameout, | |||
long | now, | |||
long | interpl | |||
) | [static] |
Definition at line 552 of file jitterbuf.c.
References jb_info::cnt_contig_interp, jb_info::conf, jb_info::current, decrement_losspct(), jb_info::frames_dropped, jb_info::frames_late, jb_info::frames_lost, jb_info::frames_out, history_get(), increment_losspct(), jitterbuf::info, JB_ADJUST_DELAY, jb_dbg, JB_DROP, JB_INTERP, JB_NOFRAME, JB_OK, JB_TYPE_SILENCE, JB_TYPE_VOICE, jb_info::jitter, jb_info::last_adjustment, jb_info::last_voice_ms, jb_conf::max_contig_interp, jb_conf::max_jitterbuf, jb_info::min, jb_frame::ms, jb_info::next_voice_ts, queue_get(), queue_last(), queue_next(), jb_info::silence_begin_ts, jb_info::target, jb_conf::target_extra, jb_frame::ts, and jb_frame::type.
Referenced by jb_get().
00553 { 00554 jb_frame *frame; 00555 long diff; 00556 static int dbg_cnt = 0; 00557 00558 /* get jitter info */ 00559 history_get(jb); 00560 00561 if (dbg_cnt && dbg_cnt % 50 == 0) { 00562 jb_dbg("\n"); 00563 } 00564 dbg_cnt++; 00565 00566 /* target */ 00567 jb->info.target = jb->info.jitter + jb->info.min + jb->info.conf.target_extra; 00568 00569 /* if a hard clamp was requested, use it */ 00570 if ((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) { 00571 jb_dbg("clamping target from %ld to %ld\n", (jb->info.target - jb->info.min), jb->info.conf.max_jitterbuf); 00572 jb->info.target = jb->info.min + jb->info.conf.max_jitterbuf; 00573 } 00574 00575 diff = jb->info.target - jb->info.current; 00576 00577 /* jb_warn("diff = %d lms=%d last = %d now = %d\n", diff, */ 00578 /* jb->info.last_voice_ms, jb->info.last_adjustment, now); */ 00579 00580 /* let's work on non-silent case first */ 00581 if (!jb->info.silence_begin_ts) { 00582 /* we want to grow */ 00583 if ((diff > 0) && 00584 /* we haven't grown in the delay length */ 00585 (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) || 00586 /* we need to grow more than the "length" we have left */ 00587 (diff > queue_last(jb) - queue_next(jb)) ) ) { 00588 /* grow by interp frame length */ 00589 jb->info.current += interpl; 00590 jb->info.next_voice_ts += interpl; 00591 jb->info.last_voice_ms = interpl; 00592 jb->info.last_adjustment = now; 00593 jb->info.cnt_contig_interp++; 00594 if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) { 00595 jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current; 00596 } 00597 jb_dbg("G"); 00598 return JB_INTERP; 00599 } 00600 00601 frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current); 00602 00603 /* not a voice frame; just return it. */ 00604 if (frame && frame->type != JB_TYPE_VOICE) { 00605 if (frame->type == JB_TYPE_SILENCE) { 00606 jb->info.silence_begin_ts = frame->ts; 00607 jb->info.cnt_contig_interp = 0; 00608 } 00609 00610 *frameout = *frame; 00611 jb->info.frames_out++; 00612 jb_dbg("o"); 00613 return JB_OK; 00614 } 00615 00616 00617 /* voice frame is later than expected */ 00618 if (frame && frame->ts + jb->info.current < jb->info.next_voice_ts) { 00619 if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) { 00620 /* either we interpolated past this frame in the last jb_get */ 00621 /* or the frame is still in order, but came a little too quick */ 00622 *frameout = *frame; 00623 /* reset expectation for next frame */ 00624 jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms; 00625 jb->info.frames_out++; 00626 decrement_losspct(jb); 00627 jb->info.cnt_contig_interp = 0; 00628 jb_dbg("v"); 00629 return JB_OK; 00630 } else { 00631 /* voice frame is late */ 00632 *frameout = *frame; 00633 jb->info.frames_out++; 00634 decrement_losspct(jb); 00635 jb->info.frames_late++; 00636 jb->info.frames_lost--; 00637 jb_dbg("l"); 00638 return JB_DROP; 00639 } 00640 } 00641 00642 /* keep track of frame sizes, to allow for variable sized-frames */ 00643 if (frame && frame->ms > 0) { 00644 jb->info.last_voice_ms = frame->ms; 00645 } 00646 00647 /* we want to shrink; shrink at 1 frame / 500ms */ 00648 /* unless we don't have a frame, then shrink 1 frame */ 00649 /* every 80ms (though perhaps we can shrink even faster */ 00650 /* in this case) */ 00651 if (diff < -jb->info.conf.target_extra && 00652 ((!frame && jb->info.last_adjustment + 80 < now) || 00653 (jb->info.last_adjustment + 500 < now))) { 00654 00655 jb->info.last_adjustment = now; 00656 jb->info.cnt_contig_interp = 0; 00657 00658 if (frame) { 00659 *frameout = *frame; 00660 /* shrink by frame size we're throwing out */ 00661 jb->info.current -= frame->ms; 00662 jb->info.frames_out++; 00663 decrement_losspct(jb); 00664 jb->info.frames_dropped++; 00665 jb_dbg("s"); 00666 return JB_DROP; 00667 } else { 00668 /* shrink by last_voice_ms */ 00669 jb->info.current -= jb->info.last_voice_ms; 00670 jb->info.frames_lost++; 00671 increment_losspct(jb); 00672 jb_dbg("S"); 00673 return JB_NOFRAME; 00674 } 00675 } 00676 00677 /* lost frame */ 00678 if (!frame) { 00679 /* this is a bit of a hack for now, but if we're close to 00680 * target, and we find a missing frame, it makes sense to 00681 * grow, because the frame might just be a bit late; 00682 * otherwise, we presently get into a pattern where we return 00683 * INTERP for the lost frame, then it shows up next, and we 00684 * throw it away because it's late */ 00685 /* I've recently only been able to replicate this using 00686 * iaxclient talking to app_echo on asterisk. In this case, 00687 * my outgoing packets go through asterisk's (old) 00688 * jitterbuffer, and then might get an unusual increasing delay 00689 * there if it decides to grow?? */ 00690 /* Update: that might have been a different bug, that has been fixed.. 00691 * But, this still seemed like a good idea, except that it ended up making a single actual 00692 * lost frame get interpolated two or more times, when there was "room" to grow, so it might 00693 * be a bit of a bad idea overall */ 00694 /*if (diff > -1 * jb->info.last_voice_ms) { 00695 jb->info.current += jb->info.last_voice_ms; 00696 jb->info.last_adjustment = now; 00697 jb_warn("g"); 00698 return JB_INTERP; 00699 } */ 00700 jb->info.frames_lost++; 00701 increment_losspct(jb); 00702 jb->info.next_voice_ts += interpl; 00703 jb->info.last_voice_ms = interpl; 00704 jb->info.cnt_contig_interp++; 00705 if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) { 00706 jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current; 00707 } 00708 jb_dbg("L"); 00709 return JB_INTERP; 00710 } 00711 00712 /* normal case; return the frame, increment stuff */ 00713 *frameout = *frame; 00714 jb->info.next_voice_ts += frame->ms; 00715 jb->info.frames_out++; 00716 jb->info.cnt_contig_interp = 0; 00717 decrement_losspct(jb); 00718 jb_dbg("v"); 00719 return JB_OK; 00720 } else { 00721 /* TODO: after we get the non-silent case down, we'll make the 00722 * silent case -- basically, we'll just grow and shrink faster 00723 * here, plus handle next_voice_ts a bit differently */ 00724 00725 /* to disable silent special case altogether, just uncomment this: */ 00726 /* jb->info.silence_begin_ts = 0; */ 00727 00728 /* shrink interpl len every 10ms during silence */ 00729 if (diff < -jb->info.conf.target_extra && 00730 jb->info.last_adjustment + 10 <= now) { 00731 jb->info.current -= interpl; 00732 jb->info.last_adjustment = now; 00733 } 00734 00735 frame = queue_get(jb, now - jb->info.current); 00736 if (!frame) { 00737 return JB_NOFRAME; 00738 } else if (frame->type != JB_TYPE_VOICE) { 00739 /* normal case; in silent mode, got a non-voice frame */ 00740 *frameout = *frame; 00741 jb->info.frames_out++; 00742 return JB_OK; 00743 } 00744 if (frame->ts < jb->info.silence_begin_ts) { 00745 /* voice frame is late */ 00746 *frameout = *frame; 00747 jb->info.frames_out++; 00748 decrement_losspct(jb); 00749 jb->info.frames_late++; 00750 jb->info.frames_lost--; 00751 jb_dbg("l"); 00752 return JB_DROP; 00753 } else { 00754 /* voice frame */ 00755 /* try setting current to target right away here */ 00756 jb->info.current = jb->info.target; 00757 jb->info.silence_begin_ts = 0; 00758 jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms; 00759 jb->info.last_voice_ms = frame->ms; 00760 jb->info.frames_out++; 00761 decrement_losspct(jb); 00762 *frameout = *frame; 00763 jb_dbg("V"); 00764 return JB_OK; 00765 } 00766 } 00767 }
Definition at line 416 of file jitterbuf.c.
References jitterbuf::frames, jb_info::frames_cur, jitterbuf::free, jitterbuf::info, jb_frame::next, jb_frame::prev, and jb_frame::ts.
Referenced by queue_get(), and queue_getall().
00417 { 00418 jb_frame *frame; 00419 frame = jb->frames; 00420 00421 if (!frame) 00422 return NULL; 00423 00424 /*jb_warn("queue_get: ASK %ld FIRST %ld\n", ts, frame->ts); */ 00425 00426 if (all || ts >= frame->ts) { 00427 /* remove this frame */ 00428 frame->prev->next = frame->next; 00429 frame->next->prev = frame->prev; 00430 00431 if (frame->next == frame) 00432 jb->frames = NULL; 00433 else 00434 jb->frames = frame->next; 00435 00436 00437 /* insert onto "free" single-linked list */ 00438 frame->next = jb->free; 00439 jb->free = frame; 00440 00441 jb->info.frames_cur--; 00442 00443 /* we return the frame pointer, even though it's on free list, 00444 * but caller must copy data */ 00445 return frame; 00446 } 00447 00448 return NULL; 00449 }
static int check_resync | ( | jitterbuf * | jb, | |
long | ts, | |||
long | now, | |||
long | ms, | |||
const enum jb_frame_type | type, | |||
long * | delay | |||
) | [static] |
Definition at line 118 of file jitterbuf.c.
References ast_debug, jb_info::cnt_delay_discont, jb_info::conf, jitterbuf::dropem, jitterbuf::frames, jb_info::frames_dropped, jitterbuf::hist_maxbuf_valid, jitterbuf::hist_ptr, jitterbuf::info, JB_TYPE_CONTROL, jb_warn, jb_info::jitter, jb_info::last_delay, jb_conf::max_jitterbuf, jb_frame::prev, jb_info::resync_offset, jb_conf::resync_threshold, and jb_frame::ts.
Referenced by jb_put().
00119 { 00120 long numts = 0; 00121 long threshold = 2 * jb->info.jitter + jb->info.conf.resync_threshold; 00122 00123 /* Check for overfill of the buffer */ 00124 if (jb->frames) { 00125 numts = jb->frames->prev->ts - jb->frames->ts; 00126 } 00127 00128 if (numts >= (jb->info.conf.max_jitterbuf)) { 00129 if (!jb->dropem) { 00130 ast_debug(1, "Attempting to exceed Jitterbuf max %ld timeslots\n", 00131 jb->info.conf.max_jitterbuf); 00132 jb->dropem = 1; 00133 } 00134 jb->info.frames_dropped++; 00135 return -1; 00136 } else { 00137 jb->dropem = 0; 00138 } 00139 00140 /* check for drastic change in delay */ 00141 if (jb->info.conf.resync_threshold != -1) { 00142 if (abs(*delay - jb->info.last_delay) > threshold) { 00143 jb->info.cnt_delay_discont++; 00144 /* resync the jitterbuffer on 3 consecutive discontinuities, 00145 * or immediately if a control frame */ 00146 if ((jb->info.cnt_delay_discont > 3) || (type == JB_TYPE_CONTROL)) { 00147 jb->info.cnt_delay_discont = 0; 00148 jb->hist_ptr = 0; 00149 jb->hist_maxbuf_valid = 0; 00150 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); 00151 jb->info.resync_offset = ts - now; 00152 jb->info.last_delay = *delay = 0; /* after resync, frame is right on time */ 00153 } else { 00154 jb->info.frames_dropped++; 00155 return -1; 00156 } 00157 } else { 00158 jb->info.last_delay = *delay; 00159 jb->info.cnt_delay_discont = 0; 00160 } 00161 } 00162 return 0; 00163 }
static void decrement_losspct | ( | jitterbuf * | jb | ) | [static] |
Definition at line 69 of file jitterbuf.c.
References jitterbuf::info, and jb_info::losspct.
Referenced by _jb_get().
static void history_calc_maxbuf | ( | jitterbuf * | jb | ) | [static] |
Definition at line 216 of file jitterbuf.c.
References jitterbuf::hist_maxbuf, jitterbuf::hist_maxbuf_valid, jitterbuf::hist_minbuf, jitterbuf::hist_ptr, jitterbuf::history, JB_HISTORY_MAXBUF_SZ, JB_HISTORY_SZ, JB_LONGMAX, and JB_LONGMIN.
Referenced by history_get().
00217 { 00218 int i,j; 00219 00220 if (jb->hist_ptr == 0) 00221 return; 00222 00223 00224 /* initialize maxbuf/minbuf to the latest value */ 00225 for (i=0;i<JB_HISTORY_MAXBUF_SZ;i++) { 00226 /* 00227 * jb->hist_maxbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ]; 00228 * jb->hist_minbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ]; 00229 */ 00230 jb->hist_maxbuf[i] = JB_LONGMIN; 00231 jb->hist_minbuf[i] = JB_LONGMAX; 00232 } 00233 00234 /* use insertion sort to populate maxbuf */ 00235 /* we want it to be the top "n" values, in order */ 00236 00237 /* start at the beginning, or JB_HISTORY_SZ frames ago */ 00238 i = (jb->hist_ptr > JB_HISTORY_SZ) ? (jb->hist_ptr - JB_HISTORY_SZ) : 0; 00239 00240 for (;i<jb->hist_ptr;i++) { 00241 long toins = jb->history[i % JB_HISTORY_SZ]; 00242 00243 /* if the maxbuf should get this */ 00244 if (toins > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) { 00245 00246 /* insertion-sort it into the maxbuf */ 00247 for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) { 00248 /* found where it fits */ 00249 if (toins > jb->hist_maxbuf[j]) { 00250 /* move over */ 00251 if (j != JB_HISTORY_MAXBUF_SZ - 1) { 00252 memmove(jb->hist_maxbuf + j + 1, jb->hist_maxbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_maxbuf[0])); 00253 } 00254 /* insert */ 00255 jb->hist_maxbuf[j] = toins; 00256 00257 break; 00258 } 00259 } 00260 } 00261 00262 /* if the minbuf should get this */ 00263 if (toins < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) { 00264 00265 /* insertion-sort it into the maxbuf */ 00266 for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) { 00267 /* found where it fits */ 00268 if (toins < jb->hist_minbuf[j]) { 00269 /* move over */ 00270 if (j != JB_HISTORY_MAXBUF_SZ - 1) { 00271 memmove(jb->hist_minbuf + j + 1, jb->hist_minbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_minbuf[0])); 00272 } 00273 /* insert */ 00274 jb->hist_minbuf[j] = toins; 00275 00276 break; 00277 } 00278 } 00279 } 00280 00281 if (0) { 00282 int k; 00283 fprintf(stderr, "toins = %ld\n", toins); 00284 fprintf(stderr, "maxbuf ="); 00285 for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++) 00286 fprintf(stderr, "%ld ", jb->hist_maxbuf[k]); 00287 fprintf(stderr, "\nminbuf ="); 00288 for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++) 00289 fprintf(stderr, "%ld ", jb->hist_minbuf[k]); 00290 fprintf(stderr, "\n"); 00291 } 00292 } 00293 00294 jb->hist_maxbuf_valid = 1; 00295 }
static void history_get | ( | jitterbuf * | jb | ) | [static] |
Definition at line 297 of file jitterbuf.c.
References jitterbuf::hist_maxbuf, jitterbuf::hist_maxbuf_valid, jitterbuf::hist_minbuf, jitterbuf::hist_ptr, history_calc_maxbuf(), jitterbuf::info, JB_HISTORY_DROPPCT, JB_HISTORY_MAXBUF_SZ, JB_HISTORY_SZ, jb_info::jitter, and jb_info::min.
Referenced by _jb_get(), jb_getinfo(), and jb_next().
00298 { 00299 long max, min, jitter; 00300 int idx; 00301 int count; 00302 00303 if (!jb->hist_maxbuf_valid) 00304 history_calc_maxbuf(jb); 00305 00306 /* count is how many items in history we're examining */ 00307 count = (jb->hist_ptr < JB_HISTORY_SZ) ? jb->hist_ptr : JB_HISTORY_SZ; 00308 00309 /* idx is the "n"ths highest/lowest that we'll look for */ 00310 idx = count * JB_HISTORY_DROPPCT / 100; 00311 00312 /* sanity checks for idx */ 00313 if (idx > (JB_HISTORY_MAXBUF_SZ - 1)) 00314 idx = JB_HISTORY_MAXBUF_SZ - 1; 00315 00316 if (idx < 0) { 00317 jb->info.min = 0; 00318 jb->info.jitter = 0; 00319 return; 00320 } 00321 00322 max = jb->hist_maxbuf[idx]; 00323 min = jb->hist_minbuf[idx]; 00324 00325 jitter = max - min; 00326 00327 /* these debug stmts compare the difference between looking at the absolute jitter, and the 00328 * values we get by throwing away the outliers */ 00329 /* 00330 fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", index, min, max, jitter); 00331 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]); 00332 */ 00333 00334 jb->info.min = min; 00335 jb->info.jitter = jitter; 00336 }
static int history_put | ( | jitterbuf * | jb, | |
long | ts, | |||
long | now, | |||
long | ms, | |||
long | delay | |||
) | [static] |
Definition at line 165 of file jitterbuf.c.
References jitterbuf::hist_maxbuf, jitterbuf::hist_maxbuf_valid, jitterbuf::hist_ptr, jitterbuf::history, JB_HISTORY_MAXBUF_SZ, and JB_HISTORY_SZ.
Referenced by jb_put().
00166 { 00167 long kicked; 00168 00169 /* don't add special/negative times to history */ 00170 if (ts <= 0) 00171 return 0; 00172 00173 kicked = jb->history[jb->hist_ptr % JB_HISTORY_SZ]; 00174 00175 jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = delay; 00176 00177 /* optimization; the max/min buffers don't need to be recalculated, if this packet's 00178 * entry doesn't change them. This happens if this packet is not involved, _and_ any packet 00179 * that got kicked out of the history is also not involved 00180 * We do a number of comparisons, but it's probably still worthwhile, because it will usually 00181 * succeed, and should be a lot faster than going through all 500 packets in history */ 00182 if (!jb->hist_maxbuf_valid) 00183 return 0; 00184 00185 /* don't do this until we've filled history 00186 * (reduces some edge cases below) */ 00187 if (jb->hist_ptr < JB_HISTORY_SZ) 00188 goto invalidate; 00189 00190 /* if the new delay would go into min */ 00191 if (delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) 00192 goto invalidate; 00193 00194 /* or max.. */ 00195 if (delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) 00196 goto invalidate; 00197 00198 /* or the kicked delay would be in min */ 00199 if (kicked <= jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) 00200 goto invalidate; 00201 00202 if (kicked >= jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) 00203 goto invalidate; 00204 00205 /* if we got here, we don't need to invalidate, 'cause this delay didn't 00206 * affect things */ 00207 return 0; 00208 /* end optimization */ 00209 00210 00211 invalidate: 00212 jb->hist_maxbuf_valid = 0; 00213 return 0; 00214 }
static void increment_losspct | ( | jitterbuf * | jb | ) | [static] |
Definition at line 64 of file jitterbuf.c.
References jitterbuf::info, and jb_info::losspct.
Referenced by _jb_get().
void jb_destroy | ( | jitterbuf * | jb | ) |
destroy jitterbuf
Definition at line 101 of file jitterbuf.c.
References ast_free, jitterbuf::free, jb_dbg2, and jb_frame::next.
Referenced by jb_destroy_adaptive(), and pvt_destructor().
00102 { 00103 jb_frame *frame; 00104 jb_dbg2("jb_destroy(%x)\n", jb); 00105 00106 /* free all the frames on the "free list" */ 00107 frame = jb->free; 00108 while (frame != NULL) { 00109 jb_frame *next = frame->next; 00110 ast_free(frame); 00111 frame = next; 00112 } 00113 00114 /* free ourselves! */ 00115 ast_free(jb); 00116 }
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! JB_DROP: Here's an audio frame you should just drop. Ask me again for this time.. JB_NOFRAME: There's no frame scheduled for this time. JB_INTERP: Please interpolate an interpl-length frame for this time (either we need to grow, or there was a lost frame) JB_EMPTY: The jb is empty.
Definition at line 787 of file jitterbuf.c.
References _jb_get(), jitterbuf::info, JB_DROP, JB_INTERP, JB_OK, jb_warn, jb_info::last_voice_ms, jb_frame::ms, and jb_frame::ts.
Referenced by __get_from_jb(), and jb_get_adaptive().
00788 { 00789 enum jb_return_code ret = _jb_get(jb, frameout, now, interpl); 00790 #if 0 00791 static int lastts=0; 00792 int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0; 00793 jb_warn("jb_get(%x,%x,%ld) = %d (%d)\n", jb, frameout, now, ret, thists); 00794 if (thists && thists < lastts) jb_warn("XXXX timestamp roll-back!!!\n"); 00795 lastts = thists; 00796 #endif 00797 if (ret == JB_INTERP) 00798 frameout->ms = jb->info.last_voice_ms; 00799 00800 return ret; 00801 }
enum jb_return_code jb_getall | ( | jitterbuf * | jb, | |
jb_frame * | frameout | |||
) |
unconditionally get frames from jitterbuf until empty
Definition at line 803 of file jitterbuf.c.
References JB_NOFRAME, JB_OK, and queue_getall().
Referenced by complete_transfer(), jb_empty_and_reset_adaptive(), jb_remove_adaptive(), pvt_destructor(), and schedule_delivery().
00804 { 00805 jb_frame *frame; 00806 frame = queue_getall(jb); 00807 00808 if (!frame) { 00809 return JB_NOFRAME; 00810 } 00811 00812 *frameout = *frame; 00813 return JB_OK; 00814 }
enum jb_return_code jb_getinfo | ( | jitterbuf * | jb, | |
jb_info * | stats | |||
) |
get jitterbuf info: only "statistics" may be valid
Definition at line 817 of file jitterbuf.c.
References history_get(), jitterbuf::info, and JB_OK.
Referenced by ast_cli_netstats(), construct_rr(), handle_cli_iax2_show_channels(), and log_jitterstats().
00818 { 00819 00820 history_get(jb); 00821 00822 *stats = jb->info; 00823 00824 return JB_OK; 00825 }
jitterbuf* jb_new | ( | void | ) |
new jitterbuf
Definition at line 88 of file jitterbuf.c.
References ast_calloc, jb_dbg2, and jb_reset().
Referenced by jb_create_adaptive(), and new_iax().
00089 { 00090 jitterbuf *jb; 00091 00092 if (!(jb = ast_calloc(1, sizeof(*jb)))) 00093 return NULL; 00094 00095 jb_reset(jb); 00096 00097 jb_dbg2("jb_new() = %x\n", jb); 00098 return jb; 00099 }
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 added (esp non-audio frames)
Definition at line 769 of file jitterbuf.c.
References jb_info::conf, jb_info::current, jitterbuf::frames, history_get(), jitterbuf::info, JB_LONGMAX, jb_info::last_adjustment, jb_info::next_voice_ts, queue_next(), jb_info::silence_begin_ts, jb_info::target, and jb_conf::target_extra.
Referenced by __get_from_jb(), jb_next_adaptive(), and update_jbsched().
00770 { 00771 if (jb->info.silence_begin_ts) { 00772 if (jb->frames) { 00773 long next = queue_next(jb); 00774 history_get(jb); 00775 /* shrink during silence */ 00776 if (jb->info.target - jb->info.current < -jb->info.conf.target_extra) 00777 return jb->info.last_adjustment + 10; 00778 return next + jb->info.target; 00779 } 00780 else 00781 return JB_LONGMAX; 00782 } else { 00783 return jb->info.next_voice_ts; 00784 } 00785 }
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
data=frame data, timings (in ms): ms=length of frame (for voice), ts=ts (sender's time) now=now (in receiver's time) return value is one of JB_OK: Frame added. Last call to jb_next() still valid JB_DROP: Drop this frame immediately JB_SCHED: Frame added. Call jb_next() to get a new time for the next frame
Definition at line 527 of file jitterbuf.c.
References check_resync(), jb_info::frames_in, history_put(), jitterbuf::info, jb_dbg2, JB_DROP, JB_OK, JB_SCHED, JB_TYPE_VOICE, queue_put(), and jb_info::resync_offset.
Referenced by jb_put_adaptive(), and schedule_delivery().
00528 { 00529 long delay = now - (ts - jb->info.resync_offset); 00530 jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now); 00531 00532 if (check_resync(jb, ts, now, ms, type, &delay)) { 00533 return JB_DROP; 00534 } 00535 00536 if (type == JB_TYPE_VOICE) { 00537 /* presently, I'm only adding VOICE frames to history and drift calculations; mostly because with the 00538 * IAX integrations, I'm sending retransmitted control frames with their awkward timestamps through */ 00539 history_put(jb, ts, now, ms, delay); 00540 } 00541 00542 jb->info.frames_in++; 00543 00544 /* if put into head of queue, caller needs to reschedule */ 00545 if (queue_put(jb,data,type,ms,ts)) { 00546 return JB_SCHED; 00547 } 00548 return JB_OK; 00549 }
void jb_reset | ( | jitterbuf * | jb | ) |
reset jitterbuf
Definition at line 74 of file jitterbuf.c.
References jb_info::conf, jb_info::current, jitterbuf::free, jitterbuf::info, JB_TARGET_EXTRA, jb_info::silence_begin_ts, jb_info::target, and jb_conf::target_extra.
Referenced by complete_transfer(), jb_empty_and_reset_adaptive(), jb_new(), and schedule_delivery().
00075 { 00076 /* only save settings and free list */ 00077 jb_conf s = jb->info.conf; 00078 jb_frame *fr = jb->free; 00079 memset(jb, 0, sizeof(*jb)); 00080 jb->info.conf = s; 00081 jb->free = fr; 00082 00083 /* initialize length, using the default value */ 00084 jb->info.current = jb->info.target = jb->info.conf.target_extra = JB_TARGET_EXTRA; 00085 jb->info.silence_begin_ts = -1; 00086 }
enum jb_return_code jb_setconf | ( | jitterbuf * | jb, | |
jb_conf * | conf | |||
) |
set jitterbuf conf
Definition at line 827 of file jitterbuf.c.
References jb_info::conf, jb_info::current, jitterbuf::info, JB_OK, JB_TARGET_EXTRA, jb_conf::max_contig_interp, jb_conf::max_jitterbuf, jb_conf::resync_threshold, jb_info::target, and jb_conf::target_extra.
Referenced by jb_create_adaptive(), and new_iax().
00828 { 00829 /* take selected settings from the struct */ 00830 00831 jb->info.conf.max_jitterbuf = conf->max_jitterbuf; 00832 jb->info.conf.resync_threshold = conf->resync_threshold; 00833 jb->info.conf.max_contig_interp = conf->max_contig_interp; 00834 00835 /* -1 indicates use of the default JB_TARGET_EXTRA value */ 00836 jb->info.conf.target_extra = ( conf->target_extra == -1 ) 00837 ? JB_TARGET_EXTRA 00838 : conf->target_extra 00839 ; 00840 00841 /* update these to match new target_extra setting */ 00842 jb->info.current = jb->info.conf.target_extra; 00843 jb->info.target = jb->info.conf.target_extra; 00844 00845 return JB_OK; 00846 }
void jb_setoutput | ( | jb_output_function_t | err, | |
jb_output_function_t | warn, | |||
jb_output_function_t | dbg | |||
) |
Definition at line 57 of file jitterbuf.c.
Referenced by handle_cli_iax2_set_debug_jb(), and load_module().
Definition at line 451 of file jitterbuf.c.
References _queue_get().
Referenced by _jb_get().
00452 { 00453 return _queue_get(jb,ts,0); 00454 }
Definition at line 456 of file jitterbuf.c.
References _queue_get().
Referenced by jb_getall().
00457 { 00458 return _queue_get(jb,0,1); 00459 }
static long queue_last | ( | jitterbuf * | jb | ) | [static] |
Definition at line 408 of file jitterbuf.c.
References jitterbuf::frames, jb_frame::prev, and jb_frame::ts.
Referenced by _jb_get().
static long queue_next | ( | jitterbuf * | jb | ) | [static] |
Definition at line 400 of file jitterbuf.c.
References jitterbuf::frames, and jb_frame::ts.
static int queue_put | ( | jitterbuf * | jb, | |
void * | data, | |||
const enum jb_frame_type | type, | |||
long | ms, | |||
long | ts | |||
) | [static] |
Definition at line 339 of file jitterbuf.c.
References ast_malloc, jb_frame::data, frames, jitterbuf::frames, jb_info::frames_cur, jb_info::frames_ooo, jitterbuf::free, jitterbuf::info, jb_err, jb_frame::ms, jb_frame::next, jb_frame::prev, jb_info::resync_offset, jb_frame::ts, and jb_frame::type.
Referenced by jb_put().
00340 { 00341 jb_frame *frame; 00342 jb_frame *p; 00343 int head = 0; 00344 long resync_ts = ts - jb->info.resync_offset; 00345 00346 if ((frame = jb->free)) { 00347 jb->free = frame->next; 00348 } else if (!(frame = ast_malloc(sizeof(*frame)))) { 00349 jb_err("cannot allocate frame\n"); 00350 return 0; 00351 } 00352 00353 jb->info.frames_cur++; 00354 00355 frame->data = data; 00356 frame->ts = resync_ts; 00357 frame->ms = ms; 00358 frame->type = type; 00359 00360 /* 00361 * frames are a circular list, jb-frames points to to the lowest ts, 00362 * jb->frames->prev points to the highest ts 00363 */ 00364 00365 if (!jb->frames) { /* queue is empty */ 00366 jb->frames = frame; 00367 frame->next = frame; 00368 frame->prev = frame; 00369 head = 1; 00370 } else if (resync_ts < jb->frames->ts) { 00371 frame->next = jb->frames; 00372 frame->prev = jb->frames->prev; 00373 00374 frame->next->prev = frame; 00375 frame->prev->next = frame; 00376 00377 /* frame is out of order */ 00378 jb->info.frames_ooo++; 00379 00380 jb->frames = frame; 00381 head = 1; 00382 } else { 00383 p = jb->frames; 00384 00385 /* frame is out of order */ 00386 if (resync_ts < p->prev->ts) jb->info.frames_ooo++; 00387 00388 while (resync_ts < p->prev->ts && p->prev != jb->frames) 00389 p = p->prev; 00390 00391 frame->next = p; 00392 frame->prev = p->prev; 00393 00394 frame->next->prev = frame; 00395 frame->prev->next = frame; 00396 } 00397 return head; 00398 }
jb_output_function_t dbgf [static] |
Definition at line 55 of file jitterbuf.c.
jb_output_function_t errf [static] |
Definition at line 55 of file jitterbuf.c.
jb_output_function_t warnf [static] |
Definition at line 55 of file jitterbuf.c.