fixes for the new jitter buffer (bug #4249)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5639 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Russell Bryant
2005-05-12 19:01:03 +00:00
parent 1febd6c72d
commit 65a7d2ac76
4 changed files with 76 additions and 43 deletions

View File

@@ -2147,12 +2147,16 @@ static int get_from_jb(void *p) {
pvt->jbid = -1; pvt->jbid = -1;
gettimeofday(&tv,NULL); 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 + now = (tv.tv_sec - pvt->rxcore.tv_sec) * 1000 +
(tv.tv_usec - pvt->rxcore.tv_usec) / 1000; (tv.tv_usec - pvt->rxcore.tv_usec) / 1000;
if(now > (next = jb_next(pvt->jb))) { if(now >= (next = jb_next(pvt->jb))) {
ret = jb_get(pvt->jb,&frame,now); ret = jb_get(pvt->jb,&frame,now,ast_codec_interp_len(pvt->voiceformat));
switch(ret) { switch(ret) {
case JB_OK: 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); */ /*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); */

View File

@@ -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 */ /* 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); 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) #if defined(__cplusplus) || defined(c_plusplus)
} }
#endif #endif

View File

@@ -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); */ /*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 */ /* remove this frame */
frame->prev->next = frame->next; frame->prev->next = frame->next;
frame->next->prev = frame->prev; 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", jb_dbg("jb info: queue %d -> %d. last_ts %d (queue len: %d) last_ms %d\n",
queue_next(jb), queue_next(jb),
queue_last(jb), queue_last(jb),
jb->info.last_voice_ts, jb->info.next_voice_ts,
queue_last(jb) - queue_next(jb), queue_last(jb) - queue_next(jb),
jb->info.last_voice_ms); 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; jb_frame *frame;
long diff; 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 a hard clamp was requested, use it */
if ((jb->info.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.max_jitterbuf)) { 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_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; 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_warn("diff = %d lms=%d last = %d now = %d\n", diff, */
/* jb->info.last_voice_ms, jb->info.last_adjustment, now); */ /* 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 */ /* let's work on non-silent case first */
if (!jb->info.silence_begin_ts) { if (!jb->info.silence_begin_ts) {
/* we want to grow */ /* 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) || (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) ||
/* we need to grow more than the "length" we have left */ /* we need to grow more than the "length" we have left */
(diff > queue_last(jb) - queue_next(jb)) ) ) { (diff > queue_last(jb) - queue_next(jb)) ) ) {
/* grow by interp frame length */
jb->info.current += jb->info.last_voice_ms; jb->info.current += interpl;
jb->info.next_voice_ts += interpl;
jb->info.last_voice_ms = interpl;
jb->info.last_adjustment = now; jb->info.last_adjustment = now;
jb_dbg("G"); jb_dbg("G");
return JB_INTERP; 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. */ /* not a voice frame; just return it. */
if (frame && frame->type != JB_TYPE_VOICE) { 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) if (frame->type == JB_TYPE_SILENCE)
jb->info.silence_begin_ts = frame->ts; 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 */ /* voice frame is later than expected */
if (frame && frame->ts + jb->info.current < jb->info.last_voice_ts - jb->info.last_voice_ms ) { if (frame && frame->ts + jb->info.current < jb->info.next_voice_ts) {
*frameout = *frame; if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) {
/* rewind last_voice, since we're just dumping */ /* either we interpolated past this frame in the last jb_get */
jb->info.last_voice_ts -= jb->info.last_voice_ms; /* or the frame is still in order, but came a little too quick */
jb->info.frames_out++; *frameout = *frame;
decrement_losspct(jb); /* reset expectation for next frame */
jb->info.frames_late++; jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
jb->info.frames_lost--; jb->info.frames_out++;
jb_dbg("l"); decrement_losspct(jb);
/*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.last_voice_ts - jb->info.current, frame->ts, queue_next(jb)); jb_dbg("v");
jb_warninfo(jb); */ return JB_OK;
return JB_DROP; } 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 */ /* 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 */ /* every 80ms (though perhaps we can shrink even faster */
/* in this case) */ /* in this case) */
if (diff < -JB_TARGET_EXTRA && 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))) { (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; jb->info.last_adjustment = now;
if (frame) { if (frame) {
*frameout = *frame; *frameout = *frame;
/* shrink by frame size we're throwing out */
jb->info.current -= frame->ms;
jb->info.frames_out++; jb->info.frames_out++;
decrement_losspct(jb); decrement_losspct(jb);
jb->info.frames_dropped++; jb->info.frames_dropped++;
jb_dbg("s"); jb_dbg("s");
return JB_DROP; return JB_DROP;
} else { } else {
/* shrink by last_voice_ms */
jb->info.current -= jb->info.last_voice_ms;
jb->info.frames_lost++;
increment_losspct(jb); increment_losspct(jb);
jb_dbg("S"); jb_dbg("S");
return JB_NOFRAME; return JB_NOFRAME;
@@ -609,12 +618,15 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now)
} */ } */
jb->info.frames_lost++; jb->info.frames_lost++;
increment_losspct(jb); increment_losspct(jb);
jb->info.next_voice_ts += interpl;
jb->info.last_voice_ms = interpl;
jb_dbg("L"); jb_dbg("L");
return JB_INTERP; return JB_INTERP;
} }
/* normal case; return the frame, increment stuff */ /* normal case; return the frame, increment stuff */
*frameout = *frame; *frameout = *frame;
jb->info.next_voice_ts += frame->ms;
jb->info.frames_out++; jb->info.frames_out++;
decrement_losspct(jb); decrement_losspct(jb);
jb_dbg("v"); jb_dbg("v");
@@ -622,30 +634,36 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now)
} else { } else {
/* TODO: after we get the non-silent case down, we'll make the /* TODO: after we get the non-silent case down, we'll make the
* silent case -- basically, we'll just grow and shrink faster * 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: */ /* to disable silent special case altogether, just uncomment this: */
/* jb->info.silence_begin_ts = 0; */ /* 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); frame = queue_get(jb, now - jb->info.current);
if (!frame) { if (!frame) {
return JB_NOFRAME; return JB_NOFRAME;
} else if (frame->type != JB_TYPE_VOICE) { } else if (frame->type != JB_TYPE_VOICE) {
/* normal case; in silent mode, got a non-voice frame */ /* normal case; in silent mode, got a non-voice frame */
*frameout = *frame; *frameout = *frame;
jb->info.frames_out++;
return JB_OK; return JB_OK;
} }
if (frame->ts < jb->info.silence_begin_ts) { if (frame->ts < jb->info.silence_begin_ts) {
/* voice frame is late */ /* voice frame is late */
*frameout = *frame; *frameout = *frame;
/* rewind last_voice, since we're just dumping */
jb->info.last_voice_ts -= jb->info.last_voice_ms;
jb->info.frames_out++; jb->info.frames_out++;
decrement_losspct(jb); decrement_losspct(jb);
jb->info.frames_late++; jb->info.frames_late++;
jb->info.frames_lost--; jb->info.frames_lost--;
jb_dbg("l"); 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); */ jb_warninfo(jb); */
return JB_DROP; return JB_DROP;
} else { } else {
@@ -653,8 +671,10 @@ static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now)
/* try setting current to target right away here */ /* try setting current to target right away here */
jb->info.current = jb->info.target; jb->info.current = jb->info.target;
jb->info.silence_begin_ts = 0; 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.last_voice_ms = frame->ms;
jb->info.frames_out++;
decrement_losspct(jb);
*frameout = *frame; *frameout = *frame;
jb_dbg("V"); jb_dbg("V");
return JB_OK; return JB_OK;
@@ -668,18 +688,21 @@ long jb_next(jitterbuf *jb)
long next = queue_next(jb); long next = queue_next(jb);
if (next > 0) { if (next > 0) {
history_get(jb); 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; return next + jb->info.target;
} }
else else
return JB_LONGMAX; return JB_LONGMAX;
} else { } 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 #if 0
static int lastts=0; static int lastts=0;
int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0; int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0;

View File

@@ -63,7 +63,7 @@ typedef struct jb_info {
long current; /* the present jitterbuffer adjustment */ long current; /* the present jitterbuffer adjustment */
long target; /* the target jitterbuffer adjustment */ long target; /* the target jitterbuffer adjustment */
long losspct; /* recent lost frame percentage (* 1000) */ 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 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 silence_begin_ts; /* the time of the last CNG frame, when in silence */
long last_adjustment; /* the time of the last adjustment */ 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_OK: You've got frame!
* JB_DROP: Here's an audio frame you should just drop. Ask me again for this time.. * 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_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. * 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 */ /* unconditionally get frames from jitterbuf until empty */
int jb_getall(jitterbuf *jb, jb_frame *frameout); int jb_getall(jitterbuf *jb, jb_frame *frameout);