fixes for the new jitter buffer (bug #4249)
authorRussell Bryant <russell@russellbryant.com>
Thu, 12 May 2005 19:01:03 +0000 (19:01 +0000)
committerRussell Bryant <russell@russellbryant.com>
Thu, 12 May 2005 19:01:03 +0000 (19:01 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5639 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_iax2.c
include/asterisk/frame.h
jitterbuf.c
jitterbuf.h

index 1cb3b58..29cf3cd 100755 (executable)
@@ -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); */
index 5ca3376..6953335 100755 (executable)
@@ -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
index 2c31007..3bdd3b5 100755 (executable)
@@ -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;
index 2247516..8391202 100755 (executable)
@@ -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);