[Asterisk-code-review] abstract/fixed/adpative jitter buffer: disallow frame re-ins... (asterisk[master])

Joshua Colp asteriskteam at digium.com
Fri Jan 20 13:49:13 CST 2017


Joshua Colp has submitted this change and it was merged. ( https://gerrit.asterisk.org/4715 )

Change subject: abstract/fixed/adpative jitter buffer: disallow frame re-inserts
......................................................................


abstract/fixed/adpative jitter buffer: disallow frame re-inserts

It was possible for a frame to be re-inserted into a jitter buffer after it
had been removed from it. A case when this happened was if a frame was read
out of the jitterbuffer, passed to the translation core, and then multiple
frames were returned from said translation core. Upon multiple frames being
returned the first is passed on, but sebsequently "chained" frames are put
back into the read queue. Thus it was possible for a frame to go back into
the jitter buffer where this would cause problems.

This patch adds a flag to frames that are inserted into the channel's read
queue after translation. The abstract jitter buffer code then checks for this
flag and ignores any frames marked as such.

Change-Id: I276c44edc9dcff61e606242f71274265c7779587
---
M include/asterisk/abstract_jb.h
M include/asterisk/frame.h
M include/jitterbuf.h
M main/abstract_jb.c
M main/channel.c
M main/fixedjitterbuf.c
M main/fixedjitterbuf.h
M main/jitterbuf.c
8 files changed, 62 insertions(+), 8 deletions(-)

Approvals:
  Anonymous Coward #1000019: Verified
  Joshua Colp: Looks good to me, approved
  Matthew Fredrickson: Looks good to me, but someone else must approve



diff --git a/include/asterisk/abstract_jb.h b/include/asterisk/abstract_jb.h
index 8a5e3d2..173b22a 100644
--- a/include/asterisk/abstract_jb.h
+++ b/include/asterisk/abstract_jb.h
@@ -109,6 +109,8 @@
 typedef void (*jb_force_resynch_impl)(void *jb);
 /*! \brief Empty and reset jb */
 typedef void (*jb_empty_and_reset_impl)(void *jb);
+/*! \brief Check if late */
+typedef int (*jb_is_late_impl)(void *jb, long ts);
 
 
 /*!
@@ -127,6 +129,7 @@
 	jb_remove_impl remove;
 	jb_force_resynch_impl force_resync;
 	jb_empty_and_reset_impl empty_and_reset;
+	jb_is_late_impl is_late;
 };
 
 /*!
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 20f40f8..108dcaf 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -133,6 +133,8 @@
 enum {
 	/*! This frame contains valid timing information */
 	AST_FRFLAG_HAS_TIMING_INFO = (1 << 0),
+	/*! This frame has been requeued */
+	AST_FRFLAG_REQUEUED = (1 << 1),
 };
 
 struct ast_frame_subclass {
diff --git a/include/jitterbuf.h b/include/jitterbuf.h
index 6da11a6..32579fc 100644
--- a/include/jitterbuf.h
+++ b/include/jitterbuf.h
@@ -166,6 +166,9 @@
 typedef void __attribute__((format(printf, 1, 2))) (*jb_output_function_t)(const char *fmt, ...);
 void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg);
 
+/*! \brief Checks if the given time stamp is late */
+int jb_is_late(jitterbuf *jb, long ts);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/main/abstract_jb.c b/main/abstract_jb.c
index 264ee97..0f0e661 100644
--- a/main/abstract_jb.c
+++ b/main/abstract_jb.c
@@ -65,6 +65,7 @@
 static int jb_remove_fixed(void *jb, struct ast_frame **fout);
 static void jb_force_resynch_fixed(void *jb);
 static void jb_empty_and_reset_fixed(void *jb);
+static int jb_is_late_fixed(void *jb, long ts);
 /* adaptive */
 static void * jb_create_adaptive(struct ast_jb_conf *general_config);
 static void jb_destroy_adaptive(void *jb);
@@ -75,6 +76,7 @@
 static int jb_remove_adaptive(void *jb, struct ast_frame **fout);
 static void jb_force_resynch_adaptive(void *jb);
 static void jb_empty_and_reset_adaptive(void *jb);
+static int jb_is_late_adaptive(void *jb, long ts);
 
 /* Available jb implementations */
 static const struct ast_jb_impl avail_impl[] = {
@@ -90,6 +92,7 @@
 		.remove = jb_remove_fixed,
 		.force_resync = jb_force_resynch_fixed,
 		.empty_and_reset = jb_empty_and_reset_fixed,
+		.is_late = jb_is_late_fixed,
 	},
 	{
 		.name = "adaptive",
@@ -103,6 +106,7 @@
 		.remove = jb_remove_adaptive,
 		.force_resync = jb_force_resynch_adaptive,
 		.empty_and_reset = jb_empty_and_reset_adaptive,
+		.is_late = jb_is_late_adaptive,
 	}
 };
 
@@ -704,6 +708,11 @@
 	}
 }
 
+static int jb_is_late_fixed(void *jb, long ts)
+{
+	return fixed_jb_is_late(jb, ts);
+}
+
 /* adaptive */
 
 static void *jb_create_adaptive(struct ast_jb_conf *general_config)
@@ -810,6 +819,11 @@
 	return NULL;
 }
 
+static int jb_is_late_adaptive(void *jb, long ts)
+{
+	return jb_is_late(jb, ts);
+}
+
 #define DEFAULT_TIMER_INTERVAL 20
 #define DEFAULT_SIZE  200
 #define DEFAULT_TARGET_EXTRA  40
@@ -893,7 +907,22 @@
 		}
 	}
 
-	if (!frame) {
+	/*
+	 * If the frame has been requeued (for instance when the translate core returns
+	 * more than one frame) then if the frame is late we want to immediately return
+	 * it. Otherwise attempt to insert it into the jitterbuffer.
+	 *
+	 * If the frame is requeued and late then in all likely hood it's a frame that
+	 * that was previously retrieved from the jitterbuffer, passed to the translate
+	 * core, and then put back into the channel read queue. Even if it had not been
+	 * in the jitterbuffer prior to now it needs to be the next frame "out".
+	 *
+	 * However late arriving frames that have not been requeued (i.e. regular frames)
+	 * need to be passed to the jitterbuffer so they can be appropriately dropped. As
+	 * well any requeued frames that are not late should be put into the jitterbuffer.
+	 */
+	if (!frame || (ast_test_flag(frame, AST_FRFLAG_REQUEUED) &&
+		       framedata->jb_impl->is_late(framedata->jb_obj, frame->ts))) {
 		return frame;
 	}
 
diff --git a/main/channel.c b/main/channel.c
index 00cfa31..4f84717 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -4333,12 +4333,19 @@
 			 * at the end of the queue.
 			 */
 			if (AST_LIST_NEXT(f, frame_list)) {
-				if (!readq_tail) {
-					ast_queue_frame_head(chan, AST_LIST_NEXT(f, frame_list));
-				} else {
-					__ast_queue_frame(chan, AST_LIST_NEXT(f, frame_list), 0, readq_tail);
+				struct ast_frame *cur, *multi_frame = AST_LIST_NEXT(f, frame_list);
+
+				/* Mark these frames as being re-queued */
+				for (cur = multi_frame; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
+					ast_set_flag(cur, AST_FRFLAG_REQUEUED);
 				}
-				ast_frfree(AST_LIST_NEXT(f, frame_list));
+
+				if (!readq_tail) {
+					ast_queue_frame_head(chan, multi_frame);
+				} else {
+					__ast_queue_frame(chan, multi_frame, 0, readq_tail);
+				}
+				ast_frfree(multi_frame);
 				AST_LIST_NEXT(f, frame_list) = NULL;
 			}
 
diff --git a/main/fixedjitterbuf.c b/main/fixedjitterbuf.c
index fc3e8cb..3c350b4 100644
--- a/main/fixedjitterbuf.c
+++ b/main/fixedjitterbuf.c
@@ -194,7 +194,6 @@
 	return fixed_jb_put(jb, data, ms, ts, now);
 }
 
-
 int fixed_jb_put(struct fixed_jb *jb, void *data, long ms, long ts, long now)
 {
 	struct fixed_jb_frame *frame, *next, *newframe;
@@ -347,3 +346,8 @@
 
 	return FIXED_JB_OK;
 }
+
+int fixed_jb_is_late(struct fixed_jb *jb, long ts)
+{
+	return jb->rxcore + jb->delay + ts < jb->next_delivery;
+}
diff --git a/main/fixedjitterbuf.h b/main/fixedjitterbuf.h
index df9bbac..ab8e5e2 100644
--- a/main/fixedjitterbuf.h
+++ b/main/fixedjitterbuf.h
@@ -85,6 +85,9 @@
 
 void fixed_jb_set_force_resynch(struct fixed_jb *jb);
 
+/*! \brief Checks if the given time stamp is late */
+int fixed_jb_is_late(struct fixed_jb *jb, long ts);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
diff --git a/main/jitterbuf.c b/main/jitterbuf.c
index 4795b6d..a4d1971 100644
--- a/main/jitterbuf.c
+++ b/main/jitterbuf.c
@@ -843,4 +843,7 @@
 	return JB_OK;
 }
 
-
+int jb_is_late(jitterbuf *jb, long ts)
+{
+	return ts + jb->info.current < jb->info.next_voice_ts;
+}

-- 
To view, visit https://gerrit.asterisk.org/4715
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I276c44edc9dcff61e606242f71274265c7779587
Gerrit-PatchSet: 2
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Kevin Harwell <kharwell at digium.com>
Gerrit-Reviewer: Anonymous Coward #1000019
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Mark Michelson <mmichelson at digium.com>
Gerrit-Reviewer: Matthew Fredrickson <creslin at digium.com>



More information about the asterisk-code-review mailing list