summaryrefslogtreecommitdiff
path: root/main/jitterbuf.c
diff options
context:
space:
mode:
authorMatthew Jordan <mjordan@digium.com>2012-03-14 17:48:40 +0000
committerMatthew Jordan <mjordan@digium.com>2012-03-14 17:48:40 +0000
commit40289b63db97e0dc4fa239cd0ebb3a59644ba2ee (patch)
treef6459240ce7ceeb6a6760bc49947bf1f5d6babee /main/jitterbuf.c
parent2019a7e6b9672af4f560b5e2c087c6301beb4537 (diff)
Fix incorrect jitter buffer overflow due to missed resynchronizations
When a change in time occurs, such that the timestamps associated with frames being placed into an adaptive jitter buffer (implemented in jitterbuf.c) are significantly different then the previously inserted frames, the jitter buffer checks to see if it needs to be resynched to the new time frame. If three consecutive packets break the threshold, the jitter buffer resynchs itself to the new timestamps. This currently only occurs when history is calculated, and hence only on JB_TYPE_VOICE frames. JB_TYPE_CONTROL frames, on the other hand, are never passed to the history calculations. Because of this, if the jump in time is greater then the maximum allowed length of the jitter buffer, the JB_TYPE_CONTROL frames are dropped and no resynchronization occurs. Alterntively, if the overfill logic is not triggered, the JB_TYPE_CONTROL frame will be placed into the buffer, but with a time reference that is not applicable. Subsequent JB_TYPE_VOICE frames will quickly trigger the overflow logic until reads from the jitter buffer reach the errant JB_TYPE_CONTROL frame. This patch allows JB_TYPE_CONTROL frames to resynch the jitter buffer. As JB_TYPE_CONTROL frames are unlikely to occur in multiples, it perform the resynchronization on any JB_TYPE_CONTROL frame that breaks the resynch threshold. Note that this only impacts chan_iax2, as other consumers of the adaptive jitter buffer use the abstract jitter buffer API, which does not use JB_TYPE_CONTROL frames. Review: https://reviewboard.asterisk.org/r/1814/ (closes issue ASTERISK-18964) Reported by: Kris Shaw Tested by: Kris Shaw, Matt Jordan Patches: jitterbuffer-2012-2-26.diff uploaded by Kris Shaw (license 5722) ........ Merged revisions 359356 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 359358 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@359359 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/jitterbuf.c')
-rw-r--r--main/jitterbuf.c89
1 files changed, 39 insertions, 50 deletions
diff --git a/main/jitterbuf.c b/main/jitterbuf.c
index 867b6948b..a49d04e64 100644
--- a/main/jitterbuf.c
+++ b/main/jitterbuf.c
@@ -109,50 +109,60 @@ void jb_destroy(jitterbuf *jb)
ast_free(jb);
}
-
-
-#if 0
-static int longcmp(const void *a, const void *b)
-{
- return *(long *)a - *(long *)b;
-}
-#endif
-
-/*! \brief simple history manipulation
- \note maybe later we can make the history buckets variable size, or something? */
-/* drop parameter determines whether we will drop outliers to minimize
- * delay */
-static int history_put(jitterbuf *jb, long ts, long now, long ms)
+static int check_resync(jitterbuf *jb, long ts, long now, long ms, const enum jb_frame_type type, long *delay)
{
- long delay = now - (ts - jb->info.resync_offset);
+ long numts = 0;
long threshold = 2 * jb->info.jitter + jb->info.conf.resync_threshold;
- long kicked;
- /* don't add special/negative times to history */
- if (ts <= 0)
- return 0;
+ /* Check for overfill of the buffer */
+ if (jb->frames) {
+ numts = jb->frames->prev->ts - jb->frames->ts;
+ }
+
+ if (numts >= (jb->info.conf.max_jitterbuf)) {
+ if (!jb->dropem) {
+ ast_debug(1, "Attempting to exceed Jitterbuf max %ld timeslots\n",
+ jb->info.conf.max_jitterbuf);
+ jb->dropem = 1;
+ }
+ jb->info.frames_dropped++;
+ return -1;
+ } else {
+ jb->dropem = 0;
+ }
/* check for drastic change in delay */
if (jb->info.conf.resync_threshold != -1) {
- if (abs(delay - jb->info.last_delay) > threshold) {
+ if (abs(*delay - jb->info.last_delay) > threshold) {
jb->info.cnt_delay_discont++;
- if (jb->info.cnt_delay_discont > 3) {
- /* resync the jitterbuffer */
+ /* resync the jitterbuffer on 3 consecutive discontinuities,
+ * or immediately if a control frame */
+ if ((jb->info.cnt_delay_discont > 3) || (type == JB_TYPE_CONTROL)) {
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_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 = delay = 0; /* after resync, frame is right on time */
+ jb->info.last_delay = *delay = 0; /* after resync, frame is right on time */
} else {
+ jb->info.frames_dropped++;
return -1;
}
} else {
- jb->info.last_delay = delay;
+ jb->info.last_delay = *delay;
jb->info.cnt_delay_discont = 0;
}
}
+ return 0;
+}
+
+static int history_put(jitterbuf *jb, long ts, long now, long ms, long delay)
+{
+ long kicked;
+
+ /* don't add special/negative times to history */
+ if (ts <= 0)
+ return 0;
kicked = jb->history[jb->hist_ptr % JB_HISTORY_SZ];
@@ -506,33 +516,17 @@ static void jb_dbgqueue(jitterbuf *jb)
enum jb_return_code jb_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, long ts, long now)
{
- long numts;
-
+ long delay = now - (ts - jb->info.resync_offset);
jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now);
- numts = 0;
- if (jb->frames)
- numts = jb->frames->prev->ts - jb->frames->ts;
-
- if (numts >= jb->info.conf.max_jitterbuf) {
- if (!jb->dropem) {
- ast_debug(1, "Attempting to exceed Jitterbuf max %ld timeslots\n",
- jb->info.conf.max_jitterbuf);
- jb->dropem = 1;
- }
- jb->info.frames_dropped++;
+ if (check_resync(jb, ts, now, ms, type, &delay)) {
return JB_DROP;
- } else {
- jb->dropem = 0;
}
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 */
- if (history_put(jb,ts,now,ms)) {
- jb->info.frames_dropped++;
- return JB_DROP;
- }
+ history_put(jb, ts, now, ms, delay);
}
jb->info.frames_in++;
@@ -551,7 +545,6 @@ static enum jb_return_code _jb_get(jitterbuf *jb, jb_frame *frameout, long now,
long diff;
static int dbg_cnt = 0;
- /*if ((now - jb_next(jb)) > 2 * jb->info.last_voice_ms) jb_warn("SCHED: %ld", (now - jb_next(jb))); */
/* get jitter info */
history_get(jb);
@@ -632,8 +625,6 @@ static enum jb_return_code _jb_get(jitterbuf *jb, jb_frame *frameout, long now,
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;
}
}
@@ -748,8 +739,6 @@ static enum jb_return_code _jb_get(jitterbuf *jb, jb_frame *frameout, long now,
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;
} else {
/* voice frame */