Mon Mar 20 08:20:12 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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  * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
00010  *
00011  * See http://www.asterisk.org for more information about
00012  * the Asterisk project. Please do not directly contact
00013  * any of the maintainers of this project for assistance;
00014  * the project provides a web site, mailing lists and IRC
00015  * channels for your use.
00016  *
00017  * This program is free software, distributed under the terms of
00018  * the GNU General Public License Version 2. See the LICENSE file
00019  * at the top of the source tree.
00020  */
00021 
00022 /*! \file
00023  *
00024  * \brief jitterbuf: an application-independent jitterbuffer
00025  * \author Steve Kann <stevek@stevek.com>
00026  *
00027  */
00028 
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 
00033 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 10368 $")
00036 
00037 #include "jitterbuf.h"
00038 
00039 /*! define these here, just for ancient compiler systems */
00040 #define JB_LONGMAX 2147483647L
00041 #define JB_LONGMIN (-JB_LONGMAX - 1L)
00042 
00043 #define jb_warn(...) (warnf ? warnf(__VA_ARGS__) : (void)0)
00044 #define jb_err(...) (errf ? errf(__VA_ARGS__) : (void)0)
00045 #define jb_dbg(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
00046 
00047 #ifdef DEEP_DEBUG
00048 #define jb_dbg2(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
00049 #else
00050 #define jb_dbg2(...) ((void)0)
00051 #endif
00052 
00053 static jb_output_function_t warnf, errf, dbgf;
00054 
00055 void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg) 
00056 {
00057    errf = err;
00058    warnf = warn;
00059    dbgf = dbg;
00060 }
00061 
00062 static void increment_losspct(jitterbuf *jb) 
00063 {
00064    jb->info.losspct = (100000 + 499 * jb->info.losspct)/500;    
00065 }
00066 
00067 static void decrement_losspct(jitterbuf *jb) 
00068 {
00069    jb->info.losspct = (499 * jb->info.losspct)/500;    
00070 }
00071 
00072 void jb_reset(jitterbuf *jb) 
00073 {
00074    /* only save settings */
00075    jb_conf s = jb->info.conf;
00076    memset(jb,0,sizeof(jitterbuf));
00077    jb->info.conf = s;
00078 
00079    /* initialize length */
00080    jb->info.current = jb->info.target = JB_TARGET_EXTRA; 
00081    jb->info.silence_begin_ts = -1; 
00082 }
00083 
00084 jitterbuf * jb_new() 
00085 {
00086    jitterbuf *jb;
00087 
00088 
00089    jb = malloc(sizeof(jitterbuf));
00090    if (!jb) 
00091       return NULL;
00092 
00093    jb_reset(jb);
00094 
00095    jb_dbg2("jb_new() = %x\n", jb);
00096    return jb;
00097 }
00098 
00099 void jb_destroy(jitterbuf *jb) 
00100 {
00101    jb_frame *frame; 
00102    jb_dbg2("jb_destroy(%x)\n", jb);
00103 
00104    /* free all the frames on the "free list" */
00105    frame = jb->free;
00106    while (frame != NULL) {
00107       jb_frame *next = frame->next;
00108       free(frame);
00109       frame = next;
00110    }
00111 
00112    /* free ourselves! */ 
00113    free(jb);
00114 }
00115 
00116 
00117 
00118 #if 0
00119 static int longcmp(const void *a, const void *b) 
00120 {
00121    return *(long *)a - *(long *)b;
00122 }
00123 #endif
00124 
00125 /*!   \brief simple history manipulation 
00126    \note maybe later we can make the history buckets variable size, or something? */
00127 /* drop parameter determines whether we will drop outliers to minimize
00128  * delay */
00129 static int history_put(jitterbuf *jb, long ts, long now, long ms) 
00130 {
00131    long delay = now - (ts - jb->info.resync_offset);
00132    long threshold = 2 * jb->info.jitter + jb->info.conf.resync_threshold;
00133    long kicked;
00134 
00135    /* don't add special/negative times to history */
00136    if (ts <= 0) 
00137       return 0;
00138 
00139    /* check for drastic change in delay */
00140    if (jb->info.conf.resync_threshold != -1) {
00141       if (abs(delay - jb->info.last_delay) > threshold) {
00142          jb->info.cnt_delay_discont++;
00143          if (jb->info.cnt_delay_discont > 3) {
00144             /* resync the jitterbuffer */
00145             jb->info.cnt_delay_discont = 0;
00146             jb->hist_ptr = 0;
00147             jb->hist_maxbuf_valid = 0;
00148 
00149             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);
00150             jb->info.resync_offset = ts - now;
00151             jb->info.last_delay = delay = 0; /* after resync, frame is right on time */
00152          } else {
00153             return -1;
00154          }
00155       } else {
00156          jb->info.last_delay = delay;
00157          jb->info.cnt_delay_discont = 0;
00158       }
00159    }
00160 
00161    kicked = jb->history[jb->hist_ptr % JB_HISTORY_SZ];
00162 
00163    jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = delay;
00164 
00165    /* optimization; the max/min buffers don't need to be recalculated, if this packet's
00166     * entry doesn't change them.  This happens if this packet is not involved, _and_ any packet
00167     * that got kicked out of the history is also not involved 
00168     * We do a number of comparisons, but it's probably still worthwhile, because it will usually
00169     * succeed, and should be a lot faster than going through all 500 packets in history */
00170    if (!jb->hist_maxbuf_valid)
00171       return 0;
00172 
00173    /* don't do this until we've filled history 
00174     * (reduces some edge cases below) */
00175    if (jb->hist_ptr < JB_HISTORY_SZ)
00176       goto invalidate;
00177 
00178    /* if the new delay would go into min */
00179    if (delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
00180       goto invalidate;
00181     
00182    /* or max.. */
00183    if (delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
00184       goto invalidate;
00185 
00186    /* or the kicked delay would be in min */
00187    if (kicked <= jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) 
00188       goto invalidate;
00189 
00190    if (kicked >= jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) 
00191       goto invalidate;
00192 
00193    /* if we got here, we don't need to invalidate, 'cause this delay didn't 
00194     * affect things */
00195    return 0;
00196    /* end optimization */
00197 
00198 
00199 invalidate:
00200    jb->hist_maxbuf_valid = 0;
00201    return 0;
00202 }
00203 
00204 static void history_calc_maxbuf(jitterbuf *jb) 
00205 {
00206    int i,j;
00207 
00208    if (jb->hist_ptr == 0) 
00209       return;
00210 
00211 
00212    /* initialize maxbuf/minbuf to the latest value */
00213    for (i=0;i<JB_HISTORY_MAXBUF_SZ;i++) {
00214 /*
00215  * jb->hist_maxbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
00216  * jb->hist_minbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
00217  */
00218       jb->hist_maxbuf[i] = JB_LONGMIN;
00219       jb->hist_minbuf[i] = JB_LONGMAX;
00220    }
00221 
00222    /* use insertion sort to populate maxbuf */
00223    /* we want it to be the top "n" values, in order */
00224 
00225    /* start at the beginning, or JB_HISTORY_SZ frames ago */
00226    i = (jb->hist_ptr > JB_HISTORY_SZ) ? (jb->hist_ptr - JB_HISTORY_SZ) : 0; 
00227 
00228    for (;i<jb->hist_ptr;i++) {
00229       long toins = jb->history[i % JB_HISTORY_SZ];
00230 
00231       /* if the maxbuf should get this */
00232       if (toins > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])  {
00233 
00234          /* insertion-sort it into the maxbuf */
00235          for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
00236             /* found where it fits */
00237             if (toins > jb->hist_maxbuf[j]) {
00238                /* move over */
00239                memmove(jb->hist_maxbuf+j+1,jb->hist_maxbuf+j, (JB_HISTORY_MAXBUF_SZ-(j+1)) * sizeof(long));
00240                /* insert */
00241                jb->hist_maxbuf[j] = toins;
00242 
00243                break;
00244             }
00245          }
00246       }
00247 
00248       /* if the minbuf should get this */
00249       if (toins < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])  {
00250 
00251          /* insertion-sort it into the maxbuf */
00252          for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
00253             /* found where it fits */
00254             if (toins < jb->hist_minbuf[j]) {
00255                /* move over */
00256                memmove(jb->hist_minbuf+j+1,jb->hist_minbuf+j, (JB_HISTORY_MAXBUF_SZ-(j+1)) * sizeof(long));
00257                /* insert */
00258                jb->hist_minbuf[j] = toins;
00259 
00260                break;
00261             }
00262          }
00263       }
00264 
00265       if (0) { 
00266          int k;
00267          fprintf(stderr, "toins = %ld\n", toins);
00268          fprintf(stderr, "maxbuf =");
00269          for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++) 
00270             fprintf(stderr, "%ld ", jb->hist_maxbuf[k]);
00271          fprintf(stderr, "\nminbuf =");
00272          for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++) 
00273             fprintf(stderr, "%ld ", jb->hist_minbuf[k]);
00274          fprintf(stderr, "\n");
00275       }
00276    }
00277 
00278    jb->hist_maxbuf_valid = 1;
00279 }
00280 
00281 static void history_get(jitterbuf *jb) 
00282 {
00283    long max, min, jitter;
00284    int index;
00285    int count;
00286 
00287    if (!jb->hist_maxbuf_valid) 
00288       history_calc_maxbuf(jb);
00289 
00290    /* count is how many items in history we're examining */
00291    count = (jb->hist_ptr < JB_HISTORY_SZ) ? jb->hist_ptr : JB_HISTORY_SZ;
00292 
00293    /* index is the "n"ths highest/lowest that we'll look for */
00294    index = count * JB_HISTORY_DROPPCT / 100;
00295 
00296    /* sanity checks for index */
00297    if (index > (JB_HISTORY_MAXBUF_SZ - 1)) 
00298       index = JB_HISTORY_MAXBUF_SZ - 1;
00299 
00300 
00301    if (index < 0) {
00302       jb->info.min = 0;
00303       jb->info.jitter = 0;
00304       return;
00305    }
00306 
00307    max = jb->hist_maxbuf[index];
00308    min = jb->hist_minbuf[index];
00309 
00310    jitter = max - min;
00311 
00312    /* these debug stmts compare the difference between looking at the absolute jitter, and the
00313     * values we get by throwing away the outliers */
00314    /*
00315    fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", index, min, max, jitter);
00316    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]);
00317    */
00318 
00319    jb->info.min = min;
00320    jb->info.jitter = jitter;
00321 }
00322 
00323 /* returns 1 if frame was inserted into head of queue, 0 otherwise */
00324 static int queue_put(jitterbuf *jb, void *data, int type, long ms, long ts) 
00325 {
00326    jb_frame *frame;
00327    jb_frame *p;
00328    int head = 0;
00329    long resync_ts = ts - jb->info.resync_offset;
00330 
00331    frame = jb->free;
00332    if (frame) {
00333       jb->free = frame->next;
00334    } else {
00335       frame = malloc(sizeof(jb_frame));
00336    }
00337 
00338    if (!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 int jb_put(jitterbuf *jb, void *data, int type, long ms, long ts, long now) 
00518 {
00519    jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now);
00520 
00521    jb->info.frames_in++;
00522 
00523    if (type == JB_TYPE_VOICE) {
00524       /* presently, I'm only adding VOICE frames to history and drift calculations; mostly because with the
00525        * IAX integrations, I'm sending retransmitted control frames with their awkward timestamps through */
00526       if (history_put(jb,ts,now,ms))
00527          return JB_DROP;
00528    }
00529 
00530    /* if put into head of queue, caller needs to reschedule */
00531    if (queue_put(jb,data,type,ms,ts)) {
00532       return JB_SCHED;
00533    }
00534    return JB_OK;
00535 }
00536 
00537 
00538 static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) 
00539 {
00540    jb_frame *frame;
00541    long diff;
00542    static int dbg_cnt = 0;
00543 
00544    /*if ((now - jb_next(jb)) > 2 * jb->info.last_voice_ms) jb_warn("SCHED: %ld", (now - jb_next(jb))); */
00545    /* get jitter info */
00546    history_get(jb);
00547 
00548    if (dbg_cnt && dbg_cnt % 50 == 0) {
00549       jb_dbg("\n");
00550    }
00551    dbg_cnt++;
00552 
00553    /* target */
00554    jb->info.target = jb->info.jitter + jb->info.min + JB_TARGET_EXTRA; 
00555 
00556    /* if a hard clamp was requested, use it */
00557    if ((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) {
00558       jb_dbg("clamping target from %d to %d\n", (jb->info.target - jb->info.min), jb->info.conf.max_jitterbuf);
00559       jb->info.target = jb->info.min + jb->info.conf.max_jitterbuf;
00560    }
00561 
00562    diff = jb->info.target - jb->info.current;
00563 
00564    /* jb_warn("diff = %d lms=%d last = %d now = %d\n", diff,  */
00565    /* jb->info.last_voice_ms, jb->info.last_adjustment, now); */
00566 
00567    /* let's work on non-silent case first */
00568    if (!jb->info.silence_begin_ts) { 
00569       /* we want to grow */
00570       if ((diff > 0) && 
00571          /* we haven't grown in the delay length */
00572          (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) || 
00573          /* we need to grow more than the "length" we have left */
00574          (diff > queue_last(jb)  - queue_next(jb)) ) ) {
00575          /* grow by interp frame length */
00576          jb->info.current += interpl;
00577          jb->info.next_voice_ts += interpl;
00578          jb->info.last_voice_ms = interpl;
00579          jb->info.last_adjustment = now;
00580          jb->info.cnt_contig_interp++;
00581          if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) {
00582             jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
00583          }
00584          jb_dbg("G");
00585          return JB_INTERP;
00586       }
00587 
00588       frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current);
00589 
00590       /* not a voice frame; just return it. */
00591       if (frame && frame->type != JB_TYPE_VOICE) {
00592          if (frame->type == JB_TYPE_SILENCE) {
00593             jb->info.silence_begin_ts = frame->ts;
00594             jb->info.cnt_contig_interp = 0;
00595          }
00596 
00597          *frameout = *frame;
00598          jb->info.frames_out++;
00599          jb_dbg("o");
00600          return JB_OK;
00601       }
00602 
00603 
00604       /* voice frame is later than expected */
00605       if (frame && frame->ts + jb->info.current < jb->info.next_voice_ts) {
00606          if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) {
00607             /* either we interpolated past this frame in the last jb_get */
00608             /* or the frame is still in order, but came a little too quick */ 
00609             *frameout = *frame;
00610             /* reset expectation for next frame */
00611             jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
00612             jb->info.frames_out++;
00613             decrement_losspct(jb);
00614             jb->info.cnt_contig_interp = 0;
00615             jb_dbg("v");
00616             return JB_OK;
00617          } else {
00618             /* voice frame is late */
00619             *frameout = *frame;
00620             jb->info.frames_out++;
00621             decrement_losspct(jb);
00622             jb->info.frames_late++;
00623             jb->info.frames_lost--;
00624             jb_dbg("l");
00625             /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb));
00626             jb_warninfo(jb); */
00627             return JB_DROP;
00628          }
00629       }
00630 
00631       /* keep track of frame sizes, to allow for variable sized-frames */
00632       if (frame && frame->ms > 0) {
00633          jb->info.last_voice_ms = frame->ms;
00634       }
00635 
00636       /* we want to shrink; shrink at 1 frame / 500ms */
00637       /* unless we don't have a frame, then shrink 1 frame */
00638       /* every 80ms (though perhaps we can shrink even faster */
00639       /* in this case) */
00640       if (diff < -JB_TARGET_EXTRA && 
00641          ((!frame && jb->info.last_adjustment + 80 < now) || 
00642          (jb->info.last_adjustment + 500 < now))) {
00643 
00644          jb->info.last_adjustment = now;
00645          jb->info.cnt_contig_interp = 0;
00646 
00647          if (frame) {
00648             *frameout = *frame;
00649             /* shrink by frame size we're throwing out */
00650             jb->info.current -= frame->ms;
00651             jb->info.frames_out++;
00652             decrement_losspct(jb);
00653             jb->info.frames_dropped++;
00654             jb_dbg("s");
00655             return JB_DROP;
00656          } else {
00657             /* shrink by last_voice_ms */
00658             jb->info.current -= jb->info.last_voice_ms;
00659             jb->info.frames_lost++;
00660             increment_losspct(jb);
00661             jb_dbg("S");
00662             return JB_NOFRAME;
00663          }
00664       }
00665 
00666       /* lost frame */
00667       if (!frame) {
00668          /* this is a bit of a hack for now, but if we're close to
00669           * target, and we find a missing frame, it makes sense to
00670           * grow, because the frame might just be a bit late;
00671           * otherwise, we presently get into a pattern where we return
00672           * INTERP for the lost frame, then it shows up next, and we
00673           * throw it away because it's late */
00674          /* I've recently only been able to replicate this using
00675           * iaxclient talking to app_echo on asterisk.  In this case,
00676           * my outgoing packets go through asterisk's (old)
00677           * jitterbuffer, and then might get an unusual increasing delay 
00678           * there if it decides to grow?? */
00679          /* Update: that might have been a different bug, that has been fixed..
00680           * But, this still seemed like a good idea, except that it ended up making a single actual
00681           * lost frame get interpolated two or more times, when there was "room" to grow, so it might
00682           * be a bit of a bad idea overall */
00683          /*if (diff > -1 * jb->info.last_voice_ms) { 
00684             jb->info.current += jb->info.last_voice_ms;
00685             jb->info.last_adjustment = now;
00686             jb_warn("g");
00687             return JB_INTERP;
00688          } */
00689          jb->info.frames_lost++;
00690          increment_losspct(jb);
00691          jb->info.next_voice_ts += interpl;
00692          jb->info.last_voice_ms = interpl;
00693          jb->info.cnt_contig_interp++;
00694          if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) {
00695             jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
00696          }
00697          jb_dbg("L");
00698          return JB_INTERP;
00699       }
00700 
00701       /* normal case; return the frame, increment stuff */
00702       *frameout = *frame;
00703       jb->info.next_voice_ts += frame->ms;
00704       jb->info.frames_out++;
00705       jb->info.cnt_contig_interp = 0;
00706       decrement_losspct(jb);
00707       jb_dbg("v");
00708       return JB_OK;
00709    } else {     
00710       /* TODO: after we get the non-silent case down, we'll make the
00711        * silent case -- basically, we'll just grow and shrink faster
00712        * here, plus handle next_voice_ts a bit differently */
00713       
00714       /* to disable silent special case altogether, just uncomment this: */
00715       /* jb->info.silence_begin_ts = 0; */
00716 
00717       /* shrink interpl len every 10ms during silence */
00718       if (diff < -JB_TARGET_EXTRA &&
00719          jb->info.last_adjustment + 10 <= now) {
00720          jb->info.current -= interpl;
00721          jb->info.last_adjustment = now;
00722       }
00723 
00724       frame = queue_get(jb, now - jb->info.current);
00725       if (!frame) {
00726          return JB_NOFRAME;
00727       } else if (frame->type != JB_TYPE_VOICE) {
00728          /* normal case; in silent mode, got a non-voice frame */
00729          *frameout = *frame;
00730          jb->info.frames_out++;
00731          return JB_OK;
00732       }
00733       if (frame->ts < jb->info.silence_begin_ts) {
00734          /* voice frame is late */
00735          *frameout = *frame;
00736          jb->info.frames_out++;
00737          decrement_losspct(jb);
00738          jb->info.frames_late++;
00739          jb->info.frames_lost--;
00740          jb_dbg("l");
00741          /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb));
00742          jb_warninfo(jb); */
00743          return JB_DROP;
00744       } else {
00745          /* voice frame */
00746          /* try setting current to target right away here */
00747          jb->info.current = jb->info.target;
00748          jb->info.silence_begin_ts = 0;
00749          jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
00750          jb->info.last_voice_ms = frame->ms;
00751          jb->info.frames_out++;
00752          decrement_losspct(jb);
00753          *frameout = *frame;
00754          jb_dbg("V");
00755          return JB_OK;
00756       }
00757    }
00758 }
00759 
00760 long jb_next(jitterbuf *jb) 
00761 {
00762    if (jb->info.silence_begin_ts) {
00763       long next = queue_next(jb);
00764       if (next > 0) { 
00765          history_get(jb);
00766          /* shrink during silence */
00767          if (jb->info.target - jb->info.current < -JB_TARGET_EXTRA)
00768             return jb->info.last_adjustment + 10;
00769          return next + jb->info.target;
00770       }
00771       else 
00772          return JB_LONGMAX;
00773    } else {
00774       return jb->info.next_voice_ts;
00775    }
00776 }
00777 
00778 int jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) 
00779 {
00780    int ret = _jb_get(jb,frameout,now,interpl);
00781 #if 0
00782    static int lastts=0;
00783    int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0;
00784    jb_warn("jb_get(%x,%x,%ld) = %d (%d)\n", jb, frameout, now, ret, thists);
00785    if (thists && thists < lastts) jb_warn("XXXX timestamp roll-back!!!\n");
00786    lastts = thists;
00787 #endif
00788    if(ret == JB_INTERP) 
00789       frameout->ms = jb->info.last_voice_ms;
00790    
00791    return ret;
00792 }
00793 
00794 int jb_getall(jitterbuf *jb, jb_frame *frameout) 
00795 {
00796    jb_frame *frame;
00797    frame = queue_getall(jb);
00798 
00799    if (!frame) {
00800       return JB_NOFRAME;
00801    }
00802 
00803    *frameout = *frame;
00804    return JB_OK;
00805 }
00806 
00807 
00808 int jb_getinfo(jitterbuf *jb, jb_info *stats) 
00809 {
00810 
00811    history_get(jb);
00812 
00813    *stats = jb->info;
00814 
00815    return JB_OK;
00816 }
00817 
00818 int jb_setconf(jitterbuf *jb, jb_conf *conf) 
00819 {
00820    /* take selected settings from the struct */
00821 
00822    jb->info.conf.max_jitterbuf = conf->max_jitterbuf;
00823    jb->info.conf.resync_threshold = conf->resync_threshold;
00824    jb->info.conf.max_contig_interp = conf->max_contig_interp;
00825 
00826    return JB_OK;
00827 }
00828 
00829 

Generated on Mon Mar 20 08:20:12 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1