diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 1cb3b589ae..29cf3cd05b 100755 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -2147,12 +2147,16 @@ static int get_from_jb(void *p) { pvt->jbid = -1; gettimeofday(&tv,NULL); + /* round up a millisecond since ast_sched_runq does; */ + /* prevents us from spinning while waiting for our now */ + /* to catch up with runq's now */ + tv.tv_usec += 1000; now = (tv.tv_sec - pvt->rxcore.tv_sec) * 1000 + (tv.tv_usec - pvt->rxcore.tv_usec) / 1000; - if(now > (next = jb_next(pvt->jb))) { - ret = jb_get(pvt->jb,&frame,now); + if(now >= (next = jb_next(pvt->jb))) { + ret = jb_get(pvt->jb,&frame,now,ast_codec_interp_len(pvt->voiceformat)); switch(ret) { case JB_OK: /*if(frame.type == JB_TYPE_VOICE && next + 20 != jb_next(pvt->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(pvt->jb), next); */ diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 5ca3376ce3..695333514b 100755 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -399,6 +399,12 @@ extern int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t /* Shift a codec preference list up or down 65 bytes so that it becomes an ASCII string */ extern void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right); +/* Gets duration in ms of interpolation frame for a format */ +static inline int ast_codec_interp_len(int format) +{ + return (format == AST_FORMAT_ILBC) ? 30 : 20; +} + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/jitterbuf.c b/jitterbuf.c index 2c31007402..3bdd3b5335 100755 --- a/jitterbuf.c +++ b/jitterbuf.c @@ -359,7 +359,7 @@ static jb_frame *_queue_get(jitterbuf *jb, long ts, int all) /*jb_warn("queue_get: ASK %ld FIRST %ld\n", ts, frame->ts); */ - if (all || ts > frame->ts) { + if (all || ts >= frame->ts) { /* remove this frame */ frame->prev->next = frame->next; frame->next->prev = frame->prev; @@ -414,7 +414,7 @@ static void jb_dbginfo(jitterbuf *jb) jb_dbg("jb info: queue %d -> %d. last_ts %d (queue len: %d) last_ms %d\n", queue_next(jb), queue_last(jb), - jb->info.last_voice_ts, + jb->info.next_voice_ts, queue_last(jb) - queue_next(jb), jb->info.last_voice_ms); } @@ -478,7 +478,7 @@ int jb_put(jitterbuf *jb, void *data, int type, long ms, long ts, long now) } -static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now) +static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) { jb_frame *frame; long diff; @@ -494,7 +494,7 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now) /* if a hard clamp was requested, use it */ if ((jb->info.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.max_jitterbuf)) { jb_dbg("clamping target from %d to %d\n", (jb->info.target - jb->info.min), jb->info.max_jitterbuf); - jb->info.target = jb->info.min + jb->info.max_jitterbuf; + jb->info.target = jb->info.min + jb->info.max_jitterbuf; } diff = jb->info.target - jb->info.current; @@ -502,9 +502,6 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now) /* jb_warn("diff = %d lms=%d last = %d now = %d\n", diff, */ /* jb->info.last_voice_ms, jb->info.last_adjustment, now); */ - /* move up last_voice_ts; it is now the expected voice ts */ - jb->info.last_voice_ts += jb->info.last_voice_ms; - /* let's work on non-silent case first */ if (!jb->info.silence_begin_ts) { /* we want to grow */ @@ -513,20 +510,19 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now) (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) || /* we need to grow more than the "length" we have left */ (diff > queue_last(jb) - queue_next(jb)) ) ) { - - jb->info.current += jb->info.last_voice_ms; + /* grow by interp frame length */ + jb->info.current += interpl; + jb->info.next_voice_ts += interpl; + jb->info.last_voice_ms = interpl; jb->info.last_adjustment = now; jb_dbg("G"); return JB_INTERP; } - frame = queue_get(jb, jb->info.last_voice_ts - jb->info.current); + frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current); /* not a voice frame; just return it. */ if (frame && frame->type != JB_TYPE_VOICE) { - /* rewind last_voice_ts, since this isn't voice */ - jb->info.last_voice_ts -= jb->info.last_voice_ms; - if (frame->type == JB_TYPE_SILENCE) jb->info.silence_begin_ts = frame->ts; @@ -537,19 +533,30 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now) } - /* voice frame is late */ - if (frame && frame->ts + jb->info.current < jb->info.last_voice_ts - jb->info.last_voice_ms ) { - *frameout = *frame; - /* rewind last_voice, since we're just dumping */ - jb->info.last_voice_ts -= jb->info.last_voice_ms; - jb->info.frames_out++; - decrement_losspct(jb); - jb->info.frames_late++; - jb->info.frames_lost--; - jb_dbg("l"); - /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.last_voice_ts - jb->info.current, frame->ts, queue_next(jb)); - jb_warninfo(jb); */ - return JB_DROP; + /* voice frame is later than expected */ + if (frame && frame->ts + jb->info.current < jb->info.next_voice_ts) { + if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) { + /* either we interpolated past this frame in the last jb_get */ + /* or the frame is still in order, but came a little too quick */ + *frameout = *frame; + /* reset expectation for next frame */ + jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms; + jb->info.frames_out++; + decrement_losspct(jb); + jb_dbg("v"); + return JB_OK; + } else { + /* voice frame is late */ + *frameout = *frame; + jb->info.frames_out++; + decrement_losspct(jb); + jb->info.frames_late++; + jb->info.frames_lost--; + jb_dbg("l"); + /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb)); + jb_warninfo(jb); */ + return JB_DROP; + } } /* keep track of frame sizes, to allow for variable sized-frames */ @@ -562,22 +569,24 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now) /* every 80ms (though perhaps we can shrink even faster */ /* in this case) */ if (diff < -JB_TARGET_EXTRA && - ((!frame && jb->info.last_adjustment + 80 < now) || + ((!frame && jb->info.last_adjustment + 80 < now) || (jb->info.last_adjustment + 500 < now))) { - /* don't increment last_ts ?? */ - jb->info.last_voice_ts -= jb->info.last_voice_ms; - jb->info.current -= jb->info.last_voice_ms; jb->info.last_adjustment = now; if (frame) { *frameout = *frame; + /* shrink by frame size we're throwing out */ + jb->info.current -= frame->ms; jb->info.frames_out++; decrement_losspct(jb); jb->info.frames_dropped++; jb_dbg("s"); return JB_DROP; } else { + /* shrink by last_voice_ms */ + jb->info.current -= jb->info.last_voice_ms; + jb->info.frames_lost++; increment_losspct(jb); jb_dbg("S"); return JB_NOFRAME; @@ -609,12 +618,15 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now) } */ jb->info.frames_lost++; increment_losspct(jb); + jb->info.next_voice_ts += interpl; + jb->info.last_voice_ms = interpl; jb_dbg("L"); return JB_INTERP; } /* normal case; return the frame, increment stuff */ *frameout = *frame; + jb->info.next_voice_ts += frame->ms; jb->info.frames_out++; decrement_losspct(jb); jb_dbg("v"); @@ -622,30 +634,36 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now) } else { /* TODO: after we get the non-silent case down, we'll make the * silent case -- basically, we'll just grow and shrink faster - * here, plus handle last_voice_ts a bit differently */ + * here, plus handle next_voice_ts a bit differently */ /* to disable silent special case altogether, just uncomment this: */ /* jb->info.silence_begin_ts = 0; */ + /* shrink interpl len every 10ms during silence */ + if (diff < -JB_TARGET_EXTRA && + jb->info.last_adjustment + 10 <= now) { + jb->info.current -= interpl; + jb->info.last_adjustment = now; + } + frame = queue_get(jb, now - jb->info.current); if (!frame) { return JB_NOFRAME; } else if (frame->type != JB_TYPE_VOICE) { /* normal case; in silent mode, got a non-voice frame */ *frameout = *frame; + jb->info.frames_out++; return JB_OK; } if (frame->ts < jb->info.silence_begin_ts) { /* voice frame is late */ *frameout = *frame; - /* rewind last_voice, since we're just dumping */ - jb->info.last_voice_ts -= jb->info.last_voice_ms; jb->info.frames_out++; decrement_losspct(jb); jb->info.frames_late++; jb->info.frames_lost--; jb_dbg("l"); - /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.last_voice_ts - jb->info.current, frame->ts, queue_next(jb)); + /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb)); jb_warninfo(jb); */ return JB_DROP; } else { @@ -653,8 +671,10 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now) /* try setting current to target right away here */ jb->info.current = jb->info.target; jb->info.silence_begin_ts = 0; - jb->info.last_voice_ts = frame->ts + jb->info.current + frame->ms; + jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms; jb->info.last_voice_ms = frame->ms; + jb->info.frames_out++; + decrement_losspct(jb); *frameout = *frame; jb_dbg("V"); return JB_OK; @@ -668,18 +688,21 @@ long jb_next(jitterbuf *jb) long next = queue_next(jb); if (next > 0) { history_get(jb); + /* shrink during silence */ + if (jb->info.target - jb->info.current < -JB_TARGET_EXTRA) + return jb->info.last_adjustment + 10; return next + jb->info.target; } else return JB_LONGMAX; } else { - return jb->info.last_voice_ts + jb->info.last_voice_ms; + return jb->info.next_voice_ts; } } -int jb_get(jitterbuf *jb, jb_frame *frameout, long now) +int jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) { - int ret = _jb_get(jb,frameout,now); + int ret = _jb_get(jb,frameout,now,interpl); #if 0 static int lastts=0; int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0; diff --git a/jitterbuf.h b/jitterbuf.h index 2247516300..8391202908 100755 --- a/jitterbuf.h +++ b/jitterbuf.h @@ -63,7 +63,7 @@ typedef struct jb_info { long current; /* the present jitterbuffer adjustment */ long target; /* the target jitterbuffer adjustment */ long losspct; /* recent lost frame percentage (* 1000) */ - long last_voice_ts; /* the last ts that was read from the jb - in receiver's time */ + long next_voice_ts; /* the ts of the next frame to be read from the jb - in receiver's time */ 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 */ @@ -115,10 +115,10 @@ int jb_put(jitterbuf *jb, void *data, int type, long ms, long ts, long now); * JB_OK: You've got frame! * JB_DROP: Here's an audio frame you should just drop. Ask me again for this time.. * JB_NOFRAME: There's no frame scheduled for this time. - * JB_INTERP: Please interpolate an audio frame for this time (either we need to grow, or there was a lost frame + * JB_INTERP: Please interpolate an interpl-length frame for this time (either we need to grow, or there was a lost frame) * JB_EMPTY: The jb is empty. */ -int jb_get(jitterbuf *jb, jb_frame *frame, long now); +int jb_get(jitterbuf *jb, jb_frame *frame, long now, long interpl); /* unconditionally get frames from jitterbuf until empty */ int jb_getall(jitterbuf *jb, jb_frame *frameout);