Sun May 20 06:33:54 2012

Asterisk developer's documentation


jitterbuf.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2004-2005, Horizon Wimba, Inc.
00005  *
00006  * Contributors:
00007  * Steve Kann <stevek@stevek.com>
00008  *
00009  * A license has been granted to Digium (via disclaimer) for the use of
00010  * this code.
00011  *
00012  * See http://www.asterisk.org for more information about
00013  * the Asterisk project. Please do not directly contact
00014  * any of the maintainers of this project for assistance;
00015  * the project provides a web site, mailing lists and IRC
00016  * channels for your use.
00017  *
00018  * This program is free software, distributed under the terms of
00019  * the GNU General Public License Version 2. See the LICENSE file
00020  * at the top of the source tree.
00021  */
00022 
00023 /*! \file
00024  *
00025  * \brief jitterbuf: an application-independent jitterbuffer
00026  * \author Steve Kann <stevek@stevek.com>
00027  *
00028  */
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 362497 $")
00033 
00034 #include "jitterbuf.h"
00035 #include "asterisk/utils.h"
00036 
00037 /*! define these here, just for ancient compiler systems */
00038 #define JB_LONGMAX 2147483647L
00039 #define JB_LONGMIN (-JB_LONGMAX - 1L)
00040 
00041 #define jb_warn(...) (warnf ? warnf(__VA_ARGS__) : (void)0)
00042 #define jb_err(...) (errf ? errf(__VA_ARGS__) : (void)0)
00043 #define jb_dbg(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
00044 
00045 #ifdef DEEP_DEBUG
00046 #define jb_dbg2(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
00047 #else
00048 #define jb_dbg2(...) ((void)0)
00049 #endif
00050 
00051 static jb_output_function_t warnf, errf, dbgf;
00052 
00053 void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg)
00054 {
00055    errf = err;
00056    warnf = warn;
00057    dbgf = dbg;
00058 }
00059 
00060 static void increment_losspct(jitterbuf *jb)
00061 {
00062    jb->info.losspct = (100000 + 499 * jb->info.losspct)/500;
00063 }
00064 
00065 static void decrement_losspct(jitterbuf *jb)
00066 {
00067    jb->info.losspct = (499 * jb->info.losspct)/500;
00068 }
00069 
00070 void jb_reset(jitterbuf *jb)
00071 {
00072    /* only save settings */
00073    jb_conf s = jb->info.conf;
00074    memset(jb, 0, sizeof(*jb));
00075    jb->info.conf = s;
00076 
00077    /* initialize length, using the default value */
00078    jb->info.current = jb->info.target = jb->info.conf.target_extra = JB_TARGET_EXTRA;
00079    jb->info.silence_begin_ts = -1;
00080 }
00081 
00082 jitterbuf * jb_new()
00083 {
00084    jitterbuf *jb;
00085 
00086    if (!(jb = ast_malloc(sizeof(*jb))))
00087       return NULL;
00088 
00089    jb_reset(jb);
00090 
00091    jb_dbg2("jb_new() = %x\n", jb);
00092    return jb;
00093 }
00094 
00095 void jb_destroy(jitterbuf *jb)
00096 {
00097    jb_frame *frame;
00098    jb_dbg2("jb_destroy(%x)\n", jb);
00099 
00100    /* free all the frames on the "free list" */
00101    frame = jb->free;
00102    while (frame != NULL) {
00103       jb_frame *next = frame->next;
00104       ast_free(frame);
00105       frame = next;
00106    }
00107 
00108    /* free ourselves! */
00109    ast_free(jb);
00110 }
00111 
00112 static int check_resync(jitterbuf *jb, long ts, long now, long ms, const enum jb_frame_type type, long *delay)
00113 {
00114    long numts = 0;
00115    long threshold = 2 * jb->info.jitter + jb->info.conf.resync_threshold;
00116 
00117    /* Check for overfill of the buffer */
00118    if (jb->frames) {
00119       numts = jb->frames->prev->ts - jb->frames->ts;
00120    }
00121 
00122    if (numts >= (jb->info.conf.max_jitterbuf)) {
00123       if (!jb->dropem) {
00124          ast_debug(1, "Attempting to exceed Jitterbuf max %ld timeslots\n",
00125             jb->info.conf.max_jitterbuf);
00126          jb->dropem = 1;
00127       }
00128       jb->info.frames_dropped++;
00129       return -1;
00130    } else {
00131       jb->dropem = 0;
00132    }
00133 
00134    /* check for drastic change in delay */
00135    if (jb->info.conf.resync_threshold != -1) {
00136       if (abs(*delay - jb->info.last_delay) > threshold) {
00137          jb->info.cnt_delay_discont++;
00138          /* resync the jitterbuffer on 3 consecutive discontinuities,
00139           * or immediately if a control frame */
00140          if ((jb->info.cnt_delay_discont > 3) || (type == JB_TYPE_CONTROL)) {
00141             jb->info.cnt_delay_discont = 0;
00142             jb->hist_ptr = 0;
00143             jb->hist_maxbuf_valid = 0;
00144             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);
00145             jb->info.resync_offset = ts - now;
00146             jb->info.last_delay = *delay = 0; /* after resync, frame is right on time */
00147          } else {
00148             jb->info.frames_dropped++;
00149             return -1;
00150          }
00151       } else {
00152          jb->info.last_delay = *delay;
00153          jb->info.cnt_delay_discont = 0;
00154       }
00155    }
00156    return 0;
00157 }
00158 
00159 static int history_put(jitterbuf *jb, long ts, long now, long ms, long delay)
00160 {
00161    long kicked;
00162 
00163    /* don't add special/negative times to history */
00164    if (ts <= 0)
00165       return 0;
00166 
00167    kicked = jb->history[jb->hist_ptr % JB_HISTORY_SZ];
00168 
00169    jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = delay;
00170 
00171    /* optimization; the max/min buffers don't need to be recalculated, if this packet's
00172     * entry doesn't change them.  This happens if this packet is not involved, _and_ any packet
00173     * that got kicked out of the history is also not involved
00174     * We do a number of comparisons, but it's probably still worthwhile, because it will usually
00175     * succeed, and should be a lot faster than going through all 500 packets in history */
00176    if (!jb->hist_maxbuf_valid)
00177       return 0;
00178 
00179    /* don't do this until we've filled history
00180     * (reduces some edge cases below) */
00181    if (jb->hist_ptr < JB_HISTORY_SZ)
00182       goto invalidate;
00183 
00184    /* if the new delay would go into min */
00185    if (delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
00186       goto invalidate;
00187 
00188    /* or max.. */
00189    if (delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
00190       goto invalidate;
00191 
00192    /* or the kicked delay would be in min */
00193    if (kicked <= jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
00194       goto invalidate;
00195 
00196    if (kicked >= jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
00197       goto invalidate;
00198 
00199    /* if we got here, we don't need to invalidate, 'cause this delay didn't
00200     * affect things */
00201    return 0;
00202    /* end optimization */
00203 
00204 
00205 invalidate:
00206    jb->hist_maxbuf_valid = 0;
00207    return 0;
00208 }
00209 
00210 static void history_calc_maxbuf(jitterbuf *jb)
00211 {
00212    int i,j;
00213 
00214    if (jb->hist_ptr == 0)
00215       return;
00216 
00217 
00218    /* initialize maxbuf/minbuf to the latest value */
00219    for (i=0;i<JB_HISTORY_MAXBUF_SZ;i++) {
00220 /*
00221  * jb->hist_maxbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
00222  * jb->hist_minbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
00223  */
00224       jb->hist_maxbuf[i] = JB_LONGMIN;
00225       jb->hist_minbuf[i] = JB_LONGMAX;
00226    }
00227 
00228    /* use insertion sort to populate maxbuf */
00229    /* we want it to be the top "n" values, in order */
00230 
00231    /* start at the beginning, or JB_HISTORY_SZ frames ago */
00232    i = (jb->hist_ptr > JB_HISTORY_SZ) ? (jb->hist_ptr - JB_HISTORY_SZ) : 0;
00233 
00234    for (;i<jb->hist_ptr;i++) {
00235       long toins = jb->history[i % JB_HISTORY_SZ];
00236 
00237       /* if the maxbuf should get this */
00238       if (toins > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])  {
00239 
00240          /* insertion-sort it into the maxbuf */
00241          for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
00242             /* found where it fits */
00243             if (toins > jb->hist_maxbuf[j]) {
00244                /* move over */
00245                if (j != JB_HISTORY_MAXBUF_SZ - 1) {
00246                   memmove(jb->hist_maxbuf + j + 1, jb->hist_maxbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_maxbuf[0]));
00247                }
00248                /* insert */
00249                jb->hist_maxbuf[j] = toins;
00250 
00251                break;
00252             }
00253          }
00254       }
00255 
00256       /* if the minbuf should get this */
00257       if (toins < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])  {
00258 
00259          /* insertion-sort it into the maxbuf */
00260          for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
00261             /* found where it fits */
00262             if (toins < jb->hist_minbuf[j]) {
00263                /* move over */
00264                if (j != JB_HISTORY_MAXBUF_SZ - 1) {
00265                   memmove(jb->hist_minbuf + j + 1, jb->hist_minbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_minbuf[0]));
00266                }
00267                /* insert */
00268                jb->hist_minbuf[j] = toins;
00269 
00270                break;
00271             }
00272          }
00273       }
00274 
00275       if (0) {
00276          int k;
00277          fprintf(stderr, "toins = %ld\n", toins);
00278          fprintf(stderr, "maxbuf =");
00279          for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++)
00280             fprintf(stderr, "%ld ", jb->hist_maxbuf[k]);
00281          fprintf(stderr, "\nminbuf =");
00282          for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++)
00283             fprintf(stderr, "%ld ", jb->hist_minbuf[k]);
00284          fprintf(stderr, "\n");
00285       }
00286    }
00287 
00288    jb->hist_maxbuf_valid = 1;
00289 }
00290 
00291 static void history_get(jitterbuf *jb)
00292 {
00293    long max, min, jitter;
00294    int idx;
00295    int count;
00296 
00297    if (!jb->hist_maxbuf_valid)
00298       history_calc_maxbuf(jb);
00299 
00300    /* count is how many items in history we're examining */
00301    count = (jb->hist_ptr < JB_HISTORY_SZ) ? jb->hist_ptr : JB_HISTORY_SZ;
00302 
00303    /* idx is the "n"ths highest/lowest that we'll look for */
00304    idx = count * JB_HISTORY_DROPPCT / 100;
00305 
00306    /* sanity checks for idx */
00307    if (idx > (JB_HISTORY_MAXBUF_SZ - 1))
00308       idx = JB_HISTORY_MAXBUF_SZ - 1;
00309 
00310    if (idx < 0) {
00311       jb->info.min = 0;
00312       jb->info.jitter = 0;
00313       return;
00314    }
00315 
00316    max = jb->hist_maxbuf[idx];
00317    min = jb->hist_minbuf[idx];
00318 
00319    jitter = max - min;
00320 
00321    /* these debug stmts compare the difference between looking at the absolute jitter, and the
00322     * values we get by throwing away the outliers */
00323    /*
00324    fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", index, min, max, jitter);
00325    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]);
00326    */
00327 
00328    jb->info.min = min;
00329    jb->info.jitter = jitter;
00330 }
00331 
00332 /* returns 1 if frame was inserted into head of queue, 0 otherwise */
00333 static int queue_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, long ts)
00334 {
00335    jb_frame *frame;
00336    jb_frame *p;
00337    int head = 0;
00338    long resync_ts = ts - jb->info.resync_offset;
00339 
00340    if ((frame = jb->free)) {
00341       jb->free = frame->next;
00342    } else if (!(frame = ast_malloc(sizeof(*frame)))) {
00343       jb_err("cannot allocate frame\n");
00344       return 0;
00345    }
00346 
00347    jb->info.frames_cur++;
00348 
00349    frame->data = data;
00350    frame->ts = resync_ts;
00351    frame->ms = ms;
00352    frame->type = type;
00353 
00354    /*
00355     * frames are a circular list, jb-frames points to to the lowest ts,
00356     * jb->frames->prev points to the highest ts
00357     */
00358 
00359    if (!jb->frames) {  /* queue is empty */
00360       jb->frames = frame;
00361       frame->next = frame;
00362       frame->prev = frame;
00363       head = 1;
00364    } else if (resync_ts < jb->frames->ts) {
00365       frame->next = jb->frames;
00366       frame->prev = jb->frames->prev;
00367 
00368       frame->next->prev = frame;
00369       frame->prev->next = frame;
00370 
00371       /* frame is out of order */
00372       jb->info.frames_ooo++;
00373 
00374       jb->frames = frame;
00375       head = 1;
00376    } else {
00377       p = jb->frames;
00378 
00379       /* frame is out of order */
00380       if (resync_ts < p->prev->ts) jb->info.frames_ooo++;
00381 
00382       while (resync_ts < p->prev->ts && p->prev != jb->frames)
00383          p = p->prev;
00384 
00385       frame->next = p;
00386       frame->prev = p->prev;
00387 
00388       frame->next->prev = frame;
00389       frame->prev->next = frame;
00390    }
00391    return head;
00392 }
00393 
00394 static long queue_next(jitterbuf *jb)
00395 {
00396    if (jb->frames)
00397       return jb->frames->ts;
00398    else
00399       return -1;
00400 }
00401 
00402 static long queue_last(jitterbuf *jb)
00403 {
00404    if (jb->frames)
00405       return jb->frames->prev->ts;
00406    else
00407       return -1;
00408 }
00409 
00410 static jb_frame *_queue_get(jitterbuf *jb, long ts, int all)
00411 {
00412    jb_frame *frame;
00413    frame = jb->frames;
00414 
00415    if (!frame)
00416       return NULL;
00417 
00418    /*jb_warn("queue_get: ASK %ld FIRST %ld\n", ts, frame->ts); */
00419 
00420    if (all || ts >= frame->ts) {
00421       /* remove this frame */
00422       frame->prev->next = frame->next;
00423       frame->next->prev = frame->prev;
00424 
00425       if (frame->next == frame)
00426          jb->frames = NULL;
00427       else
00428          jb->frames = frame->next;
00429 
00430 
00431       /* insert onto "free" single-linked list */
00432       frame->next = jb->free;
00433       jb->free = frame;
00434 
00435       jb->info.frames_cur--;
00436 
00437       /* we return the frame pointer, even though it's on free list,
00438        * but caller must copy data */
00439       return frame;
00440    }
00441 
00442    return NULL;
00443 }
00444 
00445 static jb_frame *queue_get(jitterbuf *jb, long ts)
00446 {
00447    return _queue_get(jb,ts,0);
00448 }
00449 
00450 static jb_frame *queue_getall(jitterbuf *jb)
00451 {
00452    return _queue_get(jb,0,1);
00453 }
00454 
00455 #if 0
00456 /* some diagnostics */
00457 static void jb_dbginfo(jitterbuf *jb)
00458 {
00459    if (dbgf == NULL)
00460       return;
00461 
00462    jb_dbg("\njb info: fin=%ld fout=%ld flate=%ld flost=%ld fdrop=%ld fcur=%ld\n",
00463       jb->info.frames_in, jb->info.frames_out, jb->info.frames_late, jb->info.frames_lost, jb->info.frames_dropped, jb->info.frames_cur);
00464 
00465    jb_dbg("jitter=%ld current=%ld target=%ld min=%ld sil=%d len=%d len/fcur=%ld\n",
00466       jb->info.jitter, jb->info.current, jb->info.target, jb->info.min, jb->info.silence_begin_ts, jb->info.current - jb->info.min,
00467       jb->info.frames_cur ? (jb->info.current - jb->info.min)/jb->info.frames_cur : -8);
00468    if (jb->info.frames_in > 0)
00469       jb_dbg("jb info: Loss PCT = %ld%%, Late PCT = %ld%%\n",
00470          jb->info.frames_lost * 100/(jb->info.frames_in + jb->info.frames_lost),
00471          jb->info.frames_late * 100/jb->info.frames_in);
00472    jb_dbg("jb info: queue %d -> %d.  last_ts %d (queue len: %d) last_ms %d\n",
00473       queue_next(jb),
00474       queue_last(jb),
00475       jb->info.next_voice_ts,
00476       queue_last(jb) - queue_next(jb),
00477       jb->info.last_voice_ms);
00478 }
00479 #endif
00480 
00481 #ifdef DEEP_DEBUG
00482 static void jb_chkqueue(jitterbuf *jb)
00483 {
00484    int i=0;
00485    jb_frame *p = jb->frames;
00486 
00487    if (!p) {
00488       return;
00489    }
00490 
00491    do {
00492       if (p->next == NULL)  {
00493          jb_err("Queue is BROKEN at item [%d]", i);
00494       }
00495       i++;
00496       p=p->next;
00497    } while (p->next != jb->frames);
00498 }
00499 
00500 static void jb_dbgqueue(jitterbuf *jb)
00501 {
00502    int i=0;
00503    jb_frame *p = jb->frames;
00504 
00505    jb_dbg("queue: ");
00506 
00507    if (!p) {
00508       jb_dbg("EMPTY\n");
00509       return;
00510    }
00511 
00512    do {
00513       jb_dbg("[%d]=%ld ", i++, p->ts);
00514       p=p->next;
00515    } while (p->next != jb->frames);
00516 
00517    jb_dbg("\n");
00518 }
00519 #endif
00520 
00521 enum jb_return_code jb_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, long ts, long now)
00522 {
00523    long delay = now - (ts - jb->info.resync_offset);
00524    jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now);
00525 
00526    if (check_resync(jb, ts, now, ms, type, &delay)) {
00527       return JB_DROP;
00528    }
00529 
00530    if (type == JB_TYPE_VOICE) {
00531       /* presently, I'm only adding VOICE frames to history and drift calculations; mostly because with the
00532        * IAX integrations, I'm sending retransmitted control frames with their awkward timestamps through */
00533       history_put(jb, ts, now, ms, delay);
00534    }
00535 
00536    jb->info.frames_in++;
00537 
00538    /* if put into head of queue, caller needs to reschedule */
00539    if (queue_put(jb,data,type,ms,ts)) {
00540       return JB_SCHED;
00541    }
00542    return JB_OK;
00543 }
00544 
00545 
00546 static enum jb_return_code _jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl)
00547 {
00548    jb_frame *frame;
00549    long diff;
00550    static int dbg_cnt = 0;
00551 
00552    /* get jitter info */
00553    history_get(jb);
00554 
00555    if (dbg_cnt && dbg_cnt % 50 == 0) {
00556       jb_dbg("\n");
00557    }
00558    dbg_cnt++;
00559 
00560    /* target */
00561    jb->info.target = jb->info.jitter + jb->info.min + jb->info.conf.target_extra;
00562 
00563    /* if a hard clamp was requested, use it */
00564    if ((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) {
00565       jb_dbg("clamping target from %ld to %ld\n", (jb->info.target - jb->info.min), jb->info.conf.max_jitterbuf);
00566       jb->info.target = jb->info.min + jb->info.conf.max_jitterbuf;
00567    }
00568 
00569    diff = jb->info.target - jb->info.current;
00570 
00571    /* jb_warn("diff = %d lms=%d last = %d now = %d\n", diff,  */
00572    /* jb->info.last_voice_ms, jb->info.last_adjustment, now); */
00573 
00574    /* let's work on non-silent case first */
00575    if (!jb->info.silence_begin_ts) {
00576       /* we want to grow */
00577       if ((diff > 0) &&
00578          /* we haven't grown in the delay length */
00579          (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) ||
00580          /* we need to grow more than the "length" we have left */
00581          (diff > queue_last(jb)  - queue_next(jb)) ) ) {
00582          /* grow by interp frame length */
00583          jb->info.current += interpl;
00584          jb->info.next_voice_ts += interpl;
00585          jb->info.last_voice_ms = interpl;
00586          jb->info.last_adjustment = now;
00587          jb->info.cnt_contig_interp++;
00588          if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) {
00589             jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
00590          }
00591          jb_dbg("G");
00592          return JB_INTERP;
00593       }
00594 
00595       frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current);
00596 
00597       /* not a voice frame; just return it. */
00598       if (frame && frame->type != JB_TYPE_VOICE) {
00599          if (frame->type == JB_TYPE_SILENCE) {
00600             jb->info.silence_begin_ts = frame->ts;
00601             jb->info.cnt_contig_interp = 0;
00602          }
00603 
00604          *frameout = *frame;
00605          jb->info.frames_out++;
00606          jb_dbg("o");
00607          return JB_OK;
00608       }
00609 
00610 
00611       /* voice frame is later than expected */
00612       if (frame && frame->ts + jb->info.current < jb->info.next_voice_ts) {
00613          if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) {
00614             /* either we interpolated past this frame in the last jb_get */
00615             /* or the frame is still in order, but came a little too quick */
00616             *frameout = *frame;
00617             /* reset expectation for next frame */
00618             jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
00619             jb->info.frames_out++;
00620             decrement_losspct(jb);
00621             jb->info.cnt_contig_interp = 0;
00622             jb_dbg("v");
00623             return JB_OK;
00624          } else {
00625             /* voice frame is late */
00626             *frameout = *frame;
00627             jb->info.frames_out++;
00628             decrement_losspct(jb);
00629             jb->info.frames_late++;
00630             jb->info.frames_lost--;
00631             jb_dbg("l");
00632             return JB_DROP;
00633          }
00634       }
00635 
00636       /* keep track of frame sizes, to allow for variable sized-frames */
00637       if (frame && frame->ms > 0) {
00638          jb->info.last_voice_ms = frame->ms;
00639       }
00640 
00641       /* we want to shrink; shrink at 1 frame / 500ms */
00642       /* unless we don't have a frame, then shrink 1 frame */
00643       /* every 80ms (though perhaps we can shrink even faster */
00644       /* in this case) */
00645       if (diff < -jb->info.conf.target_extra &&
00646          ((!frame && jb->info.last_adjustment + 80 < now) ||
00647          (jb->info.last_adjustment + 500 < now))) {
00648 
00649          jb->info.last_adjustment = now;
00650          jb->info.cnt_contig_interp = 0;
00651 
00652          if (frame) {
00653             *frameout = *frame;
00654             /* shrink by frame size we're throwing out */
00655             jb->info.current -= frame->ms;
00656             jb->info.frames_out++;
00657             decrement_losspct(jb);
00658             jb->info.frames_dropped++;
00659             jb_dbg("s");
00660             return JB_DROP;
00661          } else {
00662             /* shrink by last_voice_ms */
00663             jb->info.current -= jb->info.last_voice_ms;
00664             jb->info.frames_lost++;
00665             increment_losspct(jb);
00666             jb_dbg("S");
00667             return JB_NOFRAME;
00668          }
00669       }
00670 
00671       /* lost frame */
00672       if (!frame) {
00673          /* this is a bit of a hack for now, but if we're close to
00674           * target, and we find a missing frame, it makes sense to
00675           * grow, because the frame might just be a bit late;
00676           * otherwise, we presently get into a pattern where we return
00677           * INTERP for the lost frame, then it shows up next, and we
00678           * throw it away because it's late */
00679          /* I've recently only been able to replicate this using
00680           * iaxclient talking to app_echo on asterisk.  In this case,
00681           * my outgoing packets go through asterisk's (old)
00682           * jitterbuffer, and then might get an unusual increasing delay
00683           * there if it decides to grow?? */
00684          /* Update: that might have been a different bug, that has been fixed..
00685           * But, this still seemed like a good idea, except that it ended up making a single actual
00686           * lost frame get interpolated two or more times, when there was "room" to grow, so it might
00687           * be a bit of a bad idea overall */
00688          /*if (diff > -1 * jb->info.last_voice_ms) {
00689             jb->info.current += jb->info.last_voice_ms;
00690             jb->info.last_adjustment = now;
00691             jb_warn("g");
00692             return JB_INTERP;
00693          } */
00694          jb->info.frames_lost++;
00695          increment_losspct(jb);
00696          jb->info.next_voice_ts += interpl;
00697          jb->info.last_voice_ms = interpl;
00698          jb->info.cnt_contig_interp++;
00699          if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) {
00700             jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
00701          }
00702          jb_dbg("L");
00703          return JB_INTERP;
00704       }
00705 
00706       /* normal case; return the frame, increment stuff */
00707       *frameout = *frame;
00708       jb->info.next_voice_ts += frame->ms;
00709       jb->info.frames_out++;
00710       jb->info.cnt_contig_interp = 0;
00711       decrement_losspct(jb);
00712       jb_dbg("v");
00713       return JB_OK;
00714    } else {
00715       /* TODO: after we get the non-silent case down, we'll make the
00716        * silent case -- basically, we'll just grow and shrink faster
00717        * here, plus handle next_voice_ts a bit differently */
00718 
00719       /* to disable silent special case altogether, just uncomment this: */
00720       /* jb->info.silence_begin_ts = 0; */
00721 
00722       /* shrink interpl len every 10ms during silence */
00723       if (diff < -jb->info.conf.target_extra &&
00724          jb->info.last_adjustment + 10 <= now) {
00725          jb->info.current -= interpl;
00726          jb->info.last_adjustment = now;
00727       }
00728 
00729       frame = queue_get(jb, now - jb->info.current);
00730       if (!frame) {
00731          return JB_NOFRAME;
00732       } else if (frame->type != JB_TYPE_VOICE) {
00733          /* normal case; in silent mode, got a non-voice frame */
00734          *frameout = *frame;
00735          jb->info.frames_out++;
00736          return JB_OK;
00737       }
00738       if (frame->ts < jb->info.silence_begin_ts) {
00739          /* voice frame is late */
00740          *frameout = *frame;
00741          jb->info.frames_out++;
00742          decrement_losspct(jb);
00743          jb->info.frames_late++;
00744          jb->info.frames_lost--;
00745          jb_dbg("l");
00746          return JB_DROP;
00747       } else {
00748          /* voice frame */
00749          /* try setting current to target right away here */
00750          jb->info.current = jb->info.target;
00751          jb->info.silence_begin_ts = 0;
00752          jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
00753          jb->info.last_voice_ms = frame->ms;
00754          jb->info.frames_out++;
00755          decrement_losspct(jb);
00756          *frameout = *frame;
00757          jb_dbg("V");
00758          return JB_OK;
00759       }
00760    }
00761 }
00762 
00763 long jb_next(jitterbuf *jb)
00764 {
00765    if (jb->info.silence_begin_ts) {
00766       if (jb->frames) {
00767          long next = queue_next(jb);
00768          history_get(jb);
00769          /* shrink during silence */
00770          if (jb->info.target - jb->info.current < -jb->info.conf.target_extra)
00771             return jb->info.last_adjustment + 10;
00772          return next + jb->info.target;
00773       }
00774       else
00775          return JB_LONGMAX;
00776    } else {
00777       return jb->info.next_voice_ts;
00778    }
00779 }
00780 
00781 enum jb_return_code jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl)
00782 {
00783    enum jb_return_code ret = _jb_get(jb, frameout, now, interpl);
00784 #if 0
00785    static int lastts=0;
00786    int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0;
00787    jb_warn("jb_get(%x,%x,%ld) = %d (%d)\n", jb, frameout, now, ret, thists);
00788    if (thists && thists < lastts) jb_warn("XXXX timestamp roll-back!!!\n");
00789    lastts = thists;
00790 #endif
00791    if (ret == JB_INTERP)
00792       frameout->ms = jb->info.last_voice_ms;
00793 
00794    return ret;
00795 }
00796 
00797 enum jb_return_code jb_getall(jitterbuf *jb, jb_frame *frameout)
00798 {
00799    jb_frame *frame;
00800    frame = queue_getall(jb);
00801 
00802    if (!frame) {
00803       return JB_NOFRAME;
00804    }
00805 
00806    *frameout = *frame;
00807    return JB_OK;
00808 }
00809 
00810 
00811 enum jb_return_code jb_getinfo(jitterbuf *jb, jb_info *stats)
00812 {
00813 
00814    history_get(jb);
00815 
00816    *stats = jb->info;
00817 
00818    return JB_OK;
00819 }
00820 
00821 enum jb_return_code jb_setconf(jitterbuf *jb, jb_conf *conf)
00822 {
00823    /* take selected settings from the struct */
00824 
00825    jb->info.conf.max_jitterbuf = conf->max_jitterbuf;
00826    jb->info.conf.resync_threshold = conf->resync_threshold;
00827    jb->info.conf.max_contig_interp = conf->max_contig_interp;
00828 
00829    /* -1 indicates use of the default JB_TARGET_EXTRA value */
00830    jb->info.conf.target_extra = ( conf->target_extra == -1 )
00831       ? JB_TARGET_EXTRA
00832       : conf->target_extra
00833       ;
00834 
00835    /* update these to match new target_extra setting */
00836    jb->info.current = jb->info.conf.target_extra;
00837    jb->info.target = jb->info.conf.target_extra;
00838 
00839    return JB_OK;
00840 }
00841 
00842 

Generated on Sun May 20 06:33:54 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6