Mon Jun 18 2012 03:55:35

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: 359356 $")
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                memmove(jb->hist_maxbuf + j + 1, jb->hist_maxbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_maxbuf[0]));
00246                /* insert */
00247                jb->hist_maxbuf[j] = toins;
00248 
00249                break;
00250             }
00251          }
00252       }
00253 
00254       /* if the minbuf should get this */
00255       if (toins < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])  {
00256 
00257          /* insertion-sort it into the maxbuf */
00258          for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
00259             /* found where it fits */
00260             if (toins < jb->hist_minbuf[j]) {
00261                /* move over */
00262                memmove(jb->hist_minbuf + j + 1, jb->hist_minbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_minbuf[0]));
00263                /* insert */
00264                jb->hist_minbuf[j] = toins;
00265 
00266                break;
00267             }
00268          }
00269       }
00270 
00271       if (0) { 
00272          int k;
00273          fprintf(stderr, "toins = %ld\n", toins);
00274          fprintf(stderr, "maxbuf =");
00275          for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++) 
00276             fprintf(stderr, "%ld ", jb->hist_maxbuf[k]);
00277          fprintf(stderr, "\nminbuf =");
00278          for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++) 
00279             fprintf(stderr, "%ld ", jb->hist_minbuf[k]);
00280          fprintf(stderr, "\n");
00281       }
00282    }
00283 
00284    jb->hist_maxbuf_valid = 1;
00285 }
00286 
00287 static void history_get(jitterbuf *jb) 
00288 {
00289    long max, min, jitter;
00290    int idx;
00291    int count;
00292 
00293    if (!jb->hist_maxbuf_valid) 
00294       history_calc_maxbuf(jb);
00295 
00296    /* count is how many items in history we're examining */
00297    count = (jb->hist_ptr < JB_HISTORY_SZ) ? jb->hist_ptr : JB_HISTORY_SZ;
00298 
00299    /* idx is the "n"ths highest/lowest that we'll look for */
00300    idx = count * JB_HISTORY_DROPPCT / 100;
00301 
00302    /* sanity checks for idx */
00303    if (idx > (JB_HISTORY_MAXBUF_SZ - 1)) 
00304       idx = JB_HISTORY_MAXBUF_SZ - 1;
00305 
00306    if (idx < 0) {
00307       jb->info.min = 0;
00308       jb->info.jitter = 0;
00309       return;
00310    }
00311 
00312    max = jb->hist_maxbuf[idx];
00313    min = jb->hist_minbuf[idx];
00314 
00315    jitter = max - min;
00316 
00317    /* these debug stmts compare the difference between looking at the absolute jitter, and the
00318     * values we get by throwing away the outliers */
00319    /*
00320    fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", index, min, max, jitter);
00321    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]);
00322    */
00323 
00324    jb->info.min = min;
00325    jb->info.jitter = jitter;
00326 }
00327 
00328 /* returns 1 if frame was inserted into head of queue, 0 otherwise */
00329 static int queue_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, long ts) 
00330 {
00331    jb_frame *frame;
00332    jb_frame *p;
00333    int head = 0;
00334    long resync_ts = ts - jb->info.resync_offset;
00335 
00336    if ((frame = jb->free)) {
00337       jb->free = frame->next;
00338    } else if (!(frame = ast_malloc(sizeof(*frame)))) {
00339       jb_err("cannot allocate frame\n");
00340       return 0;
00341    }
00342 
00343    jb->info.frames_cur++;
00344 
00345    frame->data = data;
00346    frame->ts = resync_ts;
00347    frame->ms = ms;
00348    frame->type = type;
00349 
00350    /* 
00351     * frames are a circular list, jb-frames points to to the lowest ts, 
00352     * jb->frames->prev points to the highest ts
00353     */
00354 
00355    if (!jb->frames) {  /* queue is empty */
00356       jb->frames = frame;
00357       frame->next = frame;
00358       frame->prev = frame;
00359       head = 1;
00360    } else if (resync_ts < jb->frames->ts) {
00361       frame->next = jb->frames;
00362       frame->prev = jb->frames->prev;
00363 
00364       frame->next->prev = frame;
00365       frame->prev->next = frame;
00366 
00367       /* frame is out of order */
00368       jb->info.frames_ooo++;
00369 
00370       jb->frames = frame;
00371       head = 1;
00372    } else { 
00373       p = jb->frames;
00374 
00375       /* frame is out of order */
00376       if (resync_ts < p->prev->ts) jb->info.frames_ooo++;
00377 
00378       while (resync_ts < p->prev->ts && p->prev != jb->frames) 
00379          p = p->prev;
00380 
00381       frame->next = p;
00382       frame->prev = p->prev;
00383 
00384       frame->next->prev = frame;
00385       frame->prev->next = frame;
00386    }
00387    return head;
00388 }
00389 
00390 static long queue_next(jitterbuf *jb) 
00391 {
00392    if (jb->frames) 
00393       return jb->frames->ts;
00394    else 
00395       return -1;
00396 }
00397 
00398 static long queue_last(jitterbuf *jb) 
00399 {
00400    if (jb->frames) 
00401       return jb->frames->prev->ts;
00402    else 
00403       return -1;
00404 }
00405 
00406 static jb_frame *_queue_get(jitterbuf *jb, long ts, int all) 
00407 {
00408    jb_frame *frame;
00409    frame = jb->frames;
00410 
00411    if (!frame)
00412       return NULL;
00413 
00414    /*jb_warn("queue_get: ASK %ld FIRST %ld\n", ts, frame->ts); */
00415 
00416    if (all || ts >= frame->ts) {
00417       /* remove this frame */
00418       frame->prev->next = frame->next;
00419       frame->next->prev = frame->prev;
00420 
00421       if (frame->next == frame)
00422          jb->frames = NULL;
00423       else
00424          jb->frames = frame->next;
00425 
00426 
00427       /* insert onto "free" single-linked list */
00428       frame->next = jb->free;
00429       jb->free = frame;
00430 
00431       jb->info.frames_cur--;
00432 
00433       /* we return the frame pointer, even though it's on free list, 
00434        * but caller must copy data */
00435       return frame;
00436    } 
00437 
00438    return NULL;
00439 }
00440 
00441 static jb_frame *queue_get(jitterbuf *jb, long ts) 
00442 {
00443    return _queue_get(jb,ts,0);
00444 }
00445 
00446 static jb_frame *queue_getall(jitterbuf *jb) 
00447 {
00448    return _queue_get(jb,0,1);
00449 }
00450 
00451 #if 0
00452 /* some diagnostics */
00453 static void jb_dbginfo(jitterbuf *jb) 
00454 {
00455    if (dbgf == NULL) 
00456       return;
00457 
00458    jb_dbg("\njb info: fin=%ld fout=%ld flate=%ld flost=%ld fdrop=%ld fcur=%ld\n",
00459       jb->info.frames_in, jb->info.frames_out, jb->info.frames_late, jb->info.frames_lost, jb->info.frames_dropped, jb->info.frames_cur);
00460    
00461    jb_dbg("jitter=%ld current=%ld target=%ld min=%ld sil=%d len=%d len/fcur=%ld\n",
00462       jb->info.jitter, jb->info.current, jb->info.target, jb->info.min, jb->info.silence_begin_ts, jb->info.current - jb->info.min, 
00463       jb->info.frames_cur ? (jb->info.current - jb->info.min)/jb->info.frames_cur : -8);
00464    if (jb->info.frames_in > 0) 
00465       jb_dbg("jb info: Loss PCT = %ld%%, Late PCT = %ld%%\n",
00466          jb->info.frames_lost * 100/(jb->info.frames_in + jb->info.frames_lost), 
00467          jb->info.frames_late * 100/jb->info.frames_in);
00468    jb_dbg("jb info: queue %d -> %d.  last_ts %d (queue len: %d) last_ms %d\n",
00469       queue_next(jb), 
00470       queue_last(jb),
00471       jb->info.next_voice_ts, 
00472       queue_last(jb) - queue_next(jb),
00473       jb->info.last_voice_ms);
00474 }
00475 #endif
00476 
00477 #ifdef DEEP_DEBUG
00478 static void jb_chkqueue(jitterbuf *jb) 
00479 {
00480    int i=0;
00481    jb_frame *p = jb->frames;
00482 
00483    if (!p) {
00484       return;
00485    }
00486 
00487    do {
00488       if (p->next == NULL)  {
00489          jb_err("Queue is BROKEN at item [%d]", i);   
00490       }
00491       i++;
00492       p=p->next;
00493    } while (p->next != jb->frames);
00494 }
00495 
00496 static void jb_dbgqueue(jitterbuf *jb) 
00497 {
00498    int i=0;
00499    jb_frame *p = jb->frames;
00500 
00501    jb_dbg("queue: ");
00502 
00503    if (!p) {
00504       jb_dbg("EMPTY\n");
00505       return;
00506    }
00507 
00508    do {
00509       jb_dbg("[%d]=%ld ", i++, p->ts);
00510       p=p->next;
00511    } while (p->next != jb->frames);
00512 
00513    jb_dbg("\n");
00514 }
00515 #endif
00516 
00517 enum jb_return_code jb_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, long ts, long now) 
00518 {
00519    long delay = now - (ts - jb->info.resync_offset);
00520    jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now);
00521 
00522    if (check_resync(jb, ts, now, ms, type, &delay)) {
00523       return JB_DROP;
00524    }
00525 
00526    if (type == JB_TYPE_VOICE) {
00527       /* presently, I'm only adding VOICE frames to history and drift calculations; mostly because with the
00528        * IAX integrations, I'm sending retransmitted control frames with their awkward timestamps through */
00529       history_put(jb, ts, now, ms, delay);
00530    }
00531 
00532    jb->info.frames_in++;
00533 
00534    /* if put into head of queue, caller needs to reschedule */
00535    if (queue_put(jb,data,type,ms,ts)) {
00536       return JB_SCHED;
00537    }
00538    return JB_OK;
00539 }
00540 
00541 
00542 static enum jb_return_code _jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) 
00543 {
00544    jb_frame *frame;
00545    long diff;
00546    static int dbg_cnt = 0;
00547 
00548    /* get jitter info */
00549    history_get(jb);
00550 
00551    if (dbg_cnt && dbg_cnt % 50 == 0) {
00552       jb_dbg("\n");
00553    }
00554    dbg_cnt++;
00555 
00556    /* target */
00557    jb->info.target = jb->info.jitter + jb->info.min + jb->info.conf.target_extra; 
00558 
00559    /* if a hard clamp was requested, use it */
00560    if ((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) {
00561       jb_dbg("clamping target from %ld to %ld\n", (jb->info.target - jb->info.min), jb->info.conf.max_jitterbuf);
00562       jb->info.target = jb->info.min + jb->info.conf.max_jitterbuf;
00563    }
00564 
00565    diff = jb->info.target - jb->info.current;
00566 
00567    /* jb_warn("diff = %d lms=%d last = %d now = %d\n", diff,  */
00568    /* jb->info.last_voice_ms, jb->info.last_adjustment, now); */
00569 
00570    /* let's work on non-silent case first */
00571    if (!jb->info.silence_begin_ts) { 
00572       /* we want to grow */
00573       if ((diff > 0) && 
00574          /* we haven't grown in the delay length */
00575          (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) || 
00576          /* we need to grow more than the "length" we have left */
00577          (diff > queue_last(jb)  - queue_next(jb)) ) ) {
00578          /* grow by interp frame length */
00579          jb->info.current += interpl;
00580          jb->info.next_voice_ts += interpl;
00581          jb->info.last_voice_ms = interpl;
00582          jb->info.last_adjustment = now;
00583          jb->info.cnt_contig_interp++;
00584          if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) {
00585             jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
00586          }
00587          jb_dbg("G");
00588          return JB_INTERP;
00589       }
00590 
00591       frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current);
00592 
00593       /* not a voice frame; just return it. */
00594       if (frame && frame->type != JB_TYPE_VOICE) {
00595          if (frame->type == JB_TYPE_SILENCE) {
00596             jb->info.silence_begin_ts = frame->ts;
00597             jb->info.cnt_contig_interp = 0;
00598          }
00599 
00600          *frameout = *frame;
00601          jb->info.frames_out++;
00602          jb_dbg("o");
00603          return JB_OK;
00604       }
00605 
00606 
00607       /* voice frame is later than expected */
00608       if (frame && frame->ts + jb->info.current < jb->info.next_voice_ts) {
00609          if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) {
00610             /* either we interpolated past this frame in the last jb_get */
00611             /* or the frame is still in order, but came a little too quick */ 
00612             *frameout = *frame;
00613             /* reset expectation for next frame */
00614             jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
00615             jb->info.frames_out++;
00616             decrement_losspct(jb);
00617             jb->info.cnt_contig_interp = 0;
00618             jb_dbg("v");
00619             return JB_OK;
00620          } else {
00621             /* voice frame is late */
00622             *frameout = *frame;
00623             jb->info.frames_out++;
00624             decrement_losspct(jb);
00625             jb->info.frames_late++;
00626             jb->info.frames_lost--;
00627             jb_dbg("l");
00628             return JB_DROP;
00629          }
00630       }
00631 
00632       /* keep track of frame sizes, to allow for variable sized-frames */
00633       if (frame && frame->ms > 0) {
00634          jb->info.last_voice_ms = frame->ms;
00635       }
00636 
00637       /* we want to shrink; shrink at 1 frame / 500ms */
00638       /* unless we don't have a frame, then shrink 1 frame */
00639       /* every 80ms (though perhaps we can shrink even faster */
00640       /* in this case) */
00641       if (diff < -jb->info.conf.target_extra && 
00642          ((!frame && jb->info.last_adjustment + 80 < now) || 
00643          (jb->info.last_adjustment + 500 < now))) {
00644 
00645          jb->info.last_adjustment = now;
00646          jb->info.cnt_contig_interp = 0;
00647 
00648          if (frame) {
00649             *frameout = *frame;
00650             /* shrink by frame size we're throwing out */
00651             jb->info.current -= frame->ms;
00652             jb->info.frames_out++;
00653             decrement_losspct(jb);
00654             jb->info.frames_dropped++;
00655             jb_dbg("s");
00656             return JB_DROP;
00657          } else {
00658             /* shrink by last_voice_ms */
00659             jb->info.current -= jb->info.last_voice_ms;
00660             jb->info.frames_lost++;
00661             increment_losspct(jb);
00662             jb_dbg("S");
00663             return JB_NOFRAME;
00664          }
00665       }
00666 
00667       /* lost frame */
00668       if (!frame) {
00669          /* this is a bit of a hack for now, but if we're close to
00670           * target, and we find a missing frame, it makes sense to
00671           * grow, because the frame might just be a bit late;
00672           * otherwise, we presently get into a pattern where we return
00673           * INTERP for the lost frame, then it shows up next, and we
00674           * throw it away because it's late */
00675          /* I've recently only been able to replicate this using
00676           * iaxclient talking to app_echo on asterisk.  In this case,
00677           * my outgoing packets go through asterisk's (old)
00678           * jitterbuffer, and then might get an unusual increasing delay 
00679           * there if it decides to grow?? */
00680          /* Update: that might have been a different bug, that has been fixed..
00681           * But, this still seemed like a good idea, except that it ended up making a single actual
00682           * lost frame get interpolated two or more times, when there was "room" to grow, so it might
00683           * be a bit of a bad idea overall */
00684          /*if (diff > -1 * jb->info.last_voice_ms) { 
00685             jb->info.current += jb->info.last_voice_ms;
00686             jb->info.last_adjustment = now;
00687             jb_warn("g");
00688             return JB_INTERP;
00689          } */
00690          jb->info.frames_lost++;
00691          increment_losspct(jb);
00692          jb->info.next_voice_ts += interpl;
00693          jb->info.last_voice_ms = interpl;
00694          jb->info.cnt_contig_interp++;
00695          if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) {
00696             jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
00697          }
00698          jb_dbg("L");
00699          return JB_INTERP;
00700       }
00701 
00702       /* normal case; return the frame, increment stuff */
00703       *frameout = *frame;
00704       jb->info.next_voice_ts += frame->ms;
00705       jb->info.frames_out++;
00706       jb->info.cnt_contig_interp = 0;
00707       decrement_losspct(jb);
00708       jb_dbg("v");
00709       return JB_OK;
00710    } else {     
00711       /* TODO: after we get the non-silent case down, we'll make the
00712        * silent case -- basically, we'll just grow and shrink faster
00713        * here, plus handle next_voice_ts a bit differently */
00714 
00715       /* to disable silent special case altogether, just uncomment this: */
00716       /* jb->info.silence_begin_ts = 0; */
00717 
00718       /* shrink interpl len every 10ms during silence */
00719       if (diff < -jb->info.conf.target_extra &&
00720          jb->info.last_adjustment + 10 <= now) {
00721          jb->info.current -= interpl;
00722          jb->info.last_adjustment = now;
00723       }
00724 
00725       frame = queue_get(jb, now - jb->info.current);
00726       if (!frame) {
00727          return JB_NOFRAME;
00728       } else if (frame->type != JB_TYPE_VOICE) {
00729          /* normal case; in silent mode, got a non-voice frame */
00730          *frameout = *frame;
00731          jb->info.frames_out++;
00732          return JB_OK;
00733       }
00734       if (frame->ts < jb->info.silence_begin_ts) {
00735          /* voice frame is late */
00736          *frameout = *frame;
00737          jb->info.frames_out++;
00738          decrement_losspct(jb);
00739          jb->info.frames_late++;
00740          jb->info.frames_lost--;
00741          jb_dbg("l");
00742          return JB_DROP;
00743       } else {
00744          /* voice frame */
00745          /* try setting current to target right away here */
00746          jb->info.current = jb->info.target;
00747          jb->info.silence_begin_ts = 0;
00748          jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
00749          jb->info.last_voice_ms = frame->ms;
00750          jb->info.frames_out++;
00751          decrement_losspct(jb);
00752          *frameout = *frame;
00753          jb_dbg("V");
00754          return JB_OK;
00755       }
00756    }
00757 }
00758 
00759 long jb_next(jitterbuf *jb) 
00760 {
00761    if (jb->info.silence_begin_ts) {
00762       if (jb->frames) {
00763          long next = queue_next(jb);
00764          history_get(jb);
00765          /* shrink during silence */
00766          if (jb->info.target - jb->info.current < -jb->info.conf.target_extra)
00767             return jb->info.last_adjustment + 10;
00768          return next + jb->info.target;
00769       }
00770       else 
00771          return JB_LONGMAX;
00772    } else {
00773       return jb->info.next_voice_ts;
00774    }
00775 }
00776 
00777 enum jb_return_code jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) 
00778 {
00779    enum jb_return_code ret = _jb_get(jb, frameout, now, interpl);
00780 #if 0
00781    static int lastts=0;
00782    int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0;
00783    jb_warn("jb_get(%x,%x,%ld) = %d (%d)\n", jb, frameout, now, ret, thists);
00784    if (thists && thists < lastts) jb_warn("XXXX timestamp roll-back!!!\n");
00785    lastts = thists;
00786 #endif
00787    if (ret == JB_INTERP) 
00788       frameout->ms = jb->info.last_voice_ms;
00789    
00790    return ret;
00791 }
00792 
00793 enum jb_return_code jb_getall(jitterbuf *jb, jb_frame *frameout) 
00794 {
00795    jb_frame *frame;
00796    frame = queue_getall(jb);
00797 
00798    if (!frame) {
00799       return JB_NOFRAME;
00800    }
00801 
00802    *frameout = *frame;
00803    return JB_OK;
00804 }
00805 
00806 
00807 enum jb_return_code jb_getinfo(jitterbuf *jb, jb_info *stats) 
00808 {
00809 
00810    history_get(jb);
00811 
00812    *stats = jb->info;
00813 
00814    return JB_OK;
00815 }
00816 
00817 enum jb_return_code jb_setconf(jitterbuf *jb, jb_conf *conf) 
00818 {
00819    /* take selected settings from the struct */
00820 
00821    jb->info.conf.max_jitterbuf = conf->max_jitterbuf;
00822    jb->info.conf.resync_threshold = conf->resync_threshold;
00823    jb->info.conf.max_contig_interp = conf->max_contig_interp;
00824 
00825    /* -1 indicates use of the default JB_TARGET_EXTRA value */
00826    jb->info.conf.target_extra = ( conf->target_extra == -1 )
00827       ? JB_TARGET_EXTRA
00828       : conf->target_extra
00829       ;
00830       
00831    /* update these to match new target_extra setting */
00832    jb->info.current = jb->info.conf.target_extra;
00833    jb->info.target = jb->info.conf.target_extra;
00834 
00835    return JB_OK;
00836 }
00837 
00838