diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 1cb3b589ae4cfd3ebabdd982d48eef2a1a801bac..29cf3cd05b4d85ef94a643584b85aa98105904d7 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 5ca3376ce3003fa146eac698762341caa837f01e..695333514b1b697249ee15b681577c88e854620d 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 2c31007402e63dec0d25311373db4a4fdf011107..3bdd3b5335c6daaeca24f609e3db3e814e5d8cb4 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 224751630019ecec38f29f8bece22ce70cf06d76..8391202908f1a44440b5bc720de732043c3b8350 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);