Index: jitterbuf.c =================================================================== RCS file: /usr/cvsroot/asterisk/jitterbuf.c,v retrieving revision 1.11 diff -a -u -r1.11 jitterbuf.c --- jitterbuf.c 15 May 2005 00:03:17 -0000 1.11 +++ jitterbuf.c 17 May 2005 20:37:47 -0000 @@ -106,14 +106,37 @@ } #endif -static void history_put(jitterbuf *jb, long ts, long now) +static int history_put(jitterbuf *jb, long ts, long now, long ms) { - long delay = now - ts; + long delay = now - (ts - jb->info.resync_offset); + long threshold = 2 * jb->info.jitter + jb->info.resync_threshold; long kicked; /* don't add special/negative times to history */ if (ts <= 0) - return; + return 0; + + /* check for drastic change in delay */ + if (jb->info.resync_threshold != -1) { + if (abs(delay - jb->info.last_delay) > threshold) { + jb->info.cnt_delay_discont++; + if (jb->info.cnt_delay_discont > 3) { + /* resync the jitterbuffer */ + jb->info.cnt_delay_discont = 0; + jb->hist_ptr = 0; + jb->hist_maxbuf_valid = 0; + + 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); + jb->info.resync_offset = ts - now; + jb->info.last_delay = 0; /* after resync, frame is right on time */ + } else { + return -1; + } + } else { + jb->info.last_delay = delay; + jb->info.cnt_delay_discont = 0; + } + } kicked = jb->history[jb->hist_ptr & JB_HISTORY_SZ]; @@ -125,7 +148,7 @@ * We do a number of comparisons, but it's probably still worthwhile, because it will usually * succeed, and should be a lot faster than going through all 500 packets in history */ if (!jb->hist_maxbuf_valid) - return; + return 0; /* don't do this until we've filled history * (reduces some edge cases below) */ @@ -149,13 +172,13 @@ /* if we got here, we don't need to invalidate, 'cause this delay didn't * affect things */ - return; + return 0; /* end optimization */ invalidate: jb->hist_maxbuf_valid = 0; - return; + return 0; } static void history_calc_maxbuf(jitterbuf *jb) @@ -281,6 +304,7 @@ { jb_frame *frame; jb_frame *p; + long resync_ts = ts - jb->info.resync_offset; frame = jb->free; if (frame) { @@ -297,7 +321,7 @@ jb->info.frames_cur++; frame->data = data; - frame->ts = ts; + frame->ts = resync_ts; frame->ms = ms; frame->type = type; @@ -310,7 +334,7 @@ jb->frames = frame; frame->next = frame; frame->prev = frame; - } else if (ts < jb->frames->ts) { + } else if (resync_ts < jb->frames->ts) { frame->next = jb->frames; frame->prev = jb->frames->prev; @@ -325,9 +349,9 @@ p = jb->frames; /* frame is out of order */ - if (ts < p->prev->ts) jb->info.frames_ooo++; + if (resync_ts < p->prev->ts) jb->info.frames_ooo++; - while (ts < p->prev->ts && p->prev != jb->frames) + while (resync_ts < p->prev->ts && p->prev != jb->frames) p = p->prev; frame->next = p; @@ -474,7 +498,8 @@ if (type == JB_TYPE_VOICE) { /* presently, I'm only adding VOICE frames to history and drift calculations; mostly because with the * IAX integrations, I'm sending retransmitted control frames with their awkward timestamps through */ - history_put(jb,ts,now); + if (history_put(jb,ts,now,ms)) + return JB_DROP; } queue_put(jb,data,type,ms,ts); @@ -750,6 +775,7 @@ /* take selected settings from the struct */ jb->info.max_jitterbuf = settings->max_jitterbuf; + jb->info.resync_threshold = settings->resync_threshold; return JB_OK; } Index: jitterbuf.h =================================================================== RCS file: /usr/cvsroot/asterisk/jitterbuf.h,v retrieving revision 1.4 diff -a -u -r1.4 jitterbuf.h --- jitterbuf.h 12 May 2005 19:01:03 -0000 1.4 +++ jitterbuf.h 17 May 2005 20:37:47 -0000 @@ -67,9 +67,13 @@ long last_voice_ms; /* the duration of the last voice frame */ long silence_begin_ts; /* the time of the last CNG frame, when in silence */ long last_adjustment; /* the time of the last adjustment */ + long last_delay; /* the last now added to history */ + long cnt_delay_discont; /* the count of discontinuous delays */ + long resync_offset; /* the amount to offset ts to support resyncs */ /* settings */ long max_jitterbuf; /* defines a hard clamp to use in setting the jitter buffer delay */ + long resync_threshold; /* the jb will resync when delay increases to (2 * jitter) + this param */ } jb_info; typedef struct jb_frame { Index: channels/chan_iax2.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_iax2.c,v retrieving revision 1.287 diff -a -u -r1.287 chan_iax2.c --- channels/chan_iax2.c 15 May 2005 23:26:45 -0000 1.287 +++ channels/chan_iax2.c 17 May 2005 20:37:48 -0000 @@ -129,6 +129,9 @@ static int maxtrunkcall = TRUNK_CALL_START; static int maxnontrunkcall = 1; static int maxjitterbuffer=1000; +#ifdef NEWJB +static int resyncthreshold=1000; +#endif static int jittershrinkrate=2; static int trunkfreq = 20; static int send_trunktimestamps = 1; @@ -853,6 +856,7 @@ tmp->jb = jb_new(); tmp->jbid = -1; jbinfo.max_jitterbuf = maxjitterbuffer; + jbinfo.resync_threshold = resyncthreshold; jb_setinfo(tmp->jb,&jbinfo); } #endif @@ -2176,10 +2180,10 @@ * make preprocessor swiss-cheese out of this one. I'm not sure which is less revolting.. */ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int updatehistory, int fromtrunk) { - int x; #ifdef NEWJB int type, len; #else + int x; int ms; int delay; unsigned int orig_ts; @@ -2202,6 +2206,7 @@ unwrap_timestamp(fr); if (updatehistory) { +#ifndef NEWJB /* Attempt to spot a change of timebase on timestamps coming from the other side We detect by noticing a jump in consecutive timestamps that can't reasonably be explained @@ -2223,7 +2228,6 @@ iaxs[fr->callno]->last = 0; /* should we also empty history? */ } -#ifndef NEWJB /* ms is a measure of the "lateness" of the frame relative to the "reference" frame we received. (initially the very first, but also see code just above here). Understand that "ms" can easily be -ve if lag improves since the reference frame. @@ -2346,8 +2350,9 @@ if(jb_put(iaxs[fr->callno]->jb, fr, type, len, fr->ts, calc_rxstamp(iaxs[fr->callno],fr->ts)) == JB_DROP) { iax2_frame_free(fr); + } else { + update_jbsched(iaxs[fr->callno]); } - update_jbsched(iaxs[fr->callno]); #else /* Just for reference, keep the "jitter" value, the difference between the earliest and the latest. */ @@ -8304,6 +8309,10 @@ } else if (!strcasecmp(v->name, "maxjitterbuffer")) maxjitterbuffer = atoi(v->value); +#ifdef NEWJB + else if (!strcasecmp(v->name, "resyncthreshold")) + resyncthreshold = atoi(v->value); +#endif else if (!strcasecmp(v->name, "jittershrinkrate")) jittershrinkrate = atoi(v->value); else if (!strcasecmp(v->name, "maxexcessbuffer")) Index: configs/iax.conf.sample =================================================================== RCS file: /usr/cvsroot/asterisk/configs/iax.conf.sample,v retrieving revision 1.47 diff -a -u -r1.47 iax.conf.sample --- configs/iax.conf.sample 29 Mar 2005 23:20:31 -0000 1.47 +++ configs/iax.conf.sample 17 May 2005 20:37:49 -0000 @@ -99,6 +99,13 @@ ; from rising to silly values in extreme situations; you'll hear ; SOMETHING, even though it will be jittery. ; +; resyncthreshold: when the jitterbuffer notices a significant change in delay +; that continues over a few frames, it will resync, assuming that the change in +; delay was caused by a timestamping mix-up. The threshold for noticing a change +; in delay is measured as twice the measured jitter plus this resync threshold. +; Resycning can be disabled by setting this parameter to -1. +; [This option presently applies only to the new jitterbuffer implementation] +; ; maxexcessbuffer: If conditions improve after a period of high jitter, ; the jitter buffer can end up bigger than necessary. If it ends up ; more than "maxexcessbuffer" bigger than needed, Asterisk will start @@ -120,7 +127,8 @@ jitterbuffer=no forcejitterbuffer=no ;dropcount=2 -;maxjitterbuffer=500 +;maxjitterbuffer=1000 +;resyncthreshold=1000 ;maxexcessbuffer=80 ;minexcessbuffer=10 ;jittershrinkrate=1