[asterisk-commits] mjordan: branch mjordan/trunk_jitter_tests r358808 - in /team/mjordan/trunk_j...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Mar 12 17:26:02 CDT 2012


Author: mjordan
Date: Mon Mar 12 17:25:59 2012
New Revision: 358808

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=358808
Log:
Add some more unit tests, merge patch for ASTERISK-18964

Put the patch in from ASTERISK-18964, modified it slightly to
keep track of the dropped frames appropriately.  So far so good -
need some more unit tests to cover cases with the CONTROL frame
type.

Modified:
    team/mjordan/trunk_jitter_tests/main/jitterbuf.c
    team/mjordan/trunk_jitter_tests/tests/test_jitterbuffer.c

Modified: team/mjordan/trunk_jitter_tests/main/jitterbuf.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/trunk_jitter_tests/main/jitterbuf.c?view=diff&rev=358808&r1=358807&r2=358808
==============================================================================
--- team/mjordan/trunk_jitter_tests/main/jitterbuf.c (original)
+++ team/mjordan/trunk_jitter_tests/main/jitterbuf.c Mon Mar 12 17:25:59 2012
@@ -118,45 +118,67 @@
 }
 #endif
 
+static int check_resync(jitterbuf *jb, long ts, long now, long ms, const enum jb_frame_type type, long *delay) 
+{
+	long numts = 0;
+	long threshold = 2 * jb->info.jitter + jb->info.conf.resync_threshold;
+
+	/* 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) {
+			jb->info.cnt_delay_discont++;
+			if ((jb->info.cnt_delay_discont > 3) || (type != JB_TYPE_VOICE)) {
+				/* resync the jitterbuffer, immediately if not a voice frame*/
+				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->info.resync_offset = ts - now;
+				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.cnt_delay_discont = 0;
+		}
+	}
+	return 0;
+}
+
 /*!	\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) 
-{
-	long delay = now - (ts - jb->info.resync_offset);
-	long threshold = 2 * jb->info.jitter + jb->info.conf.resync_threshold;
+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;
 
-	/* check for drastic change in delay */
-	if (jb->info.conf.resync_threshold != -1) {
-		if (abs(delay - jb->info.last_delay) > threshold) {
-			jb->info.cnt_delay_discont++;
-			if (jb->info.cnt_delay_discont > 3) {
-				/* resync the jitterbuffer */
-				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->info.resync_offset = ts - now;
-				jb->info.last_delay = delay = 0; /* after resync, frame is right on time */
-			} else {
-				return -1;
-			}
-		} else {
-			jb->info.last_delay = delay;
-			jb->info.cnt_delay_discont = 0;
-		}
-	}
-
 	kicked = jb->history[jb->hist_ptr % JB_HISTORY_SZ];
 
-	jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = delay;
+	jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = *delay;
 
 	/* optimization; the max/min buffers don't need to be recalculated, if this packet's
 	 * entry doesn't change them.  This happens if this packet is not involved, _and_ any packet
@@ -172,11 +194,11 @@
 		goto invalidate;
 
 	/* if the new delay would go into min */
-	if (delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
+	if (*delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
 		goto invalidate;
 
 	/* or max.. */
-	if (delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
+	if (*delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
 		goto invalidate;
 
 	/* or the kicked delay would be in min */
@@ -506,33 +528,17 @@
 
 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++;
@@ -549,16 +555,9 @@
 {
 	jb_frame *frame;
 	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);
-
-	if (dbg_cnt && dbg_cnt % 50 == 0) {
-		jb_dbg("\n");
-	}
-	dbg_cnt++;
 
 	/* target */
 	jb->info.target = jb->info.jitter + jb->info.min + jb->info.conf.target_extra; 
@@ -591,7 +590,7 @@
 			if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) {
 				jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
 			}
-			jb_dbg("G");
+			jb_dbg("Frame at %ld is interpolated\n", now);
 			return JB_INTERP;
 		}
 
@@ -606,7 +605,7 @@
 
 			*frameout = *frame;
 			jb->info.frames_out++;
-			jb_dbg("o");
+			jb_dbg("Returning non-voice frame at %ld\n", now);
 			return JB_OK;
 		}
 
@@ -622,7 +621,7 @@
 				jb->info.frames_out++;
 				decrement_losspct(jb);
 				jb->info.cnt_contig_interp = 0;
-				jb_dbg("v");
+				jb_dbg("Returning frame at %ld\n", now);
 				return JB_OK;
 			} else {
 				/* voice frame is late */
@@ -631,9 +630,7 @@
 				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); */
+				jb_dbg("Dropping late frame at %ld\n", now);
 				return JB_DROP;
 			}
 		}
@@ -661,14 +658,14 @@
 				jb->info.frames_out++;
 				decrement_losspct(jb);
 				jb->info.frames_dropped++;
-				jb_dbg("s");
+				jb_dbg("Dropping late frame at %ld\n", now);
 				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");
+				jb_dbg("Frame at %ld is lost\n", now);
 				return JB_NOFRAME;
 			}
 		}
@@ -704,7 +701,7 @@
 			if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) {
 				jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
 			}
-			jb_dbg("L");
+			jb_dbg("Frame at %ld is interpolated\n", now);
 			return JB_INTERP;
 		}
 
@@ -714,7 +711,7 @@
 		jb->info.frames_out++;
 		jb->info.cnt_contig_interp = 0;
 		decrement_losspct(jb);
-		jb_dbg("v");
+		jb_dbg("Returning frame at %ld\n", now);
 		return JB_OK;
 	} else {     
 		/* TODO: after we get the non-silent case down, we'll make the
@@ -733,11 +730,13 @@
 
 		frame = queue_get(jb, now - jb->info.current);
 		if (!frame) {
+			jb_dbg("No frame at %ld\n", now);
 			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++;
+			jb_dbg("Returning non-voice frame at %ld\n", now);
 			return JB_OK;
 		}
 		if (frame->ts < jb->info.silence_begin_ts) {
@@ -747,9 +746,7 @@
 			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); */
+			jb_dbg("Dropping late frame at %ld\n", now);
 			return JB_DROP;
 		} else {
 			/* voice frame */
@@ -761,7 +758,7 @@
 			jb->info.frames_out++;
 			decrement_losspct(jb);
 			*frameout = *frame;
-			jb_dbg("V");
+			jb_dbg("Returning frame at %ld\n", now);
 			return JB_OK;
 		}
 	}

Modified: team/mjordan/trunk_jitter_tests/tests/test_jitterbuffer.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/trunk_jitter_tests/tests/test_jitterbuffer.c?view=diff&rev=358808&r1=358807&r2=358808
==============================================================================
--- team/mjordan/trunk_jitter_tests/tests/test_jitterbuffer.c (original)
+++ team/mjordan/trunk_jitter_tests/tests/test_jitterbuffer.c Mon Mar 12 17:25:59 2012
@@ -46,6 +46,11 @@
 #define DEFAULT_TARGET_EXTRA -1
 #define DEFAULT_CODEC_INTERP_LEN 20
 
+/*! \internal
+ * Test two numeric (long int) values.  It is expected that the attribute value is
+ * some numeric attribute in a jb_info object.  Failure automatically attempts
+ * to jump to a cleanup tag
+ */
 #define JB_INFO_NUMERIC_TEST(attribute, expected) do { \
 	if (attribute != expected) { \
 		ast_test_status_update(test, #attribute ": expected [%ld]; actual [%ld]\n", (long int)expected, attribute); \
@@ -53,14 +58,35 @@
 	} \
 } while (0)
 
+/*! \internal
+ * Print out as debug the frame related contents of a jb_info object
+ */
 #define JB_INFO_PRINT_FRAME_DEBUG(jbinfo) do { \
-	ast_debug(1, "JitterBuffer Frame Info:\n" \
+	ast_verb(1, "JitterBuffer Frame Info:\n" \
 		"\tFrames In: %ld\n\tFrames Out: %ld\n" \
 		"\tDropped Frames: %ld\n\tLate Frames: %ld\n" \
 		"\tLost Frames: %ld\n\tOut of Order Frames: %ld\n" \
 		"\tCurrent Frame: %ld\n", jbinfo.frames_in, jbinfo.frames_out, \
 		jbinfo.frames_dropped, jbinfo.frames_late, jbinfo.frames_lost, \
 		jbinfo.frames_ooo, jbinfo.frames_cur); \
+} while (0)
+
+/*! \internal
+ * This macro installs the error, warning, and debug functions for a test.  It is
+ * expected that at the end of a test, the functions are removed.
+ * Note that the debug statement is in here merely to aid in tracing in a lot where
+ * the jitterbuffer debug begins.
+ */
+#define JB_TEST_BEGIN(test_name) do { \
+	jb_setoutput(test_jb_error_output, test_jb_warn_output, test_jb_debug_output); \
+	ast_debug(1, "Starting %s\n", test_name); \
+} while (0)
+
+/*! \internal
+ * Uninstall the error, warning, and debug functions from a test
+ */
+#define JB_TEST_END do { \
+	jb_setoutput(NULL, NULL, NULL); \
 } while (0)
 
 static const char *jitter_buffer_return_codes[] = {
@@ -72,6 +98,7 @@
 	"JB_SCHED"          /* 5 */
 };
 
+/*! \internal \brief Make a default jitter buffer configuration */
 static void test_jb_populate_config(struct jb_conf *jbconf)
 {
 	if (!jbconf) {
@@ -84,27 +111,68 @@
 	jbconf->target_extra = 0;
 }
 
-AST_TEST_DEFINE(jitterbuffer_nominal_audio_frames)
+/*! \internal \brief Debug callback function for the jitter buffer's jb_dbg function */
+static void __attribute__((format(printf, 1, 2))) test_jb_debug_output(const char *fmt, ...)
+{
+	va_list args;
+	char buf[1024];
+
+	va_start(args, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, args);
+	va_end(args);
+
+	ast_debug(1, "%s", buf);
+}
+
+/*! \internal \brief Warning callback function for the jitter buffer's jb_warn function */
+static void __attribute__((format(printf, 1, 2))) test_jb_warn_output(const char *fmt, ...)
+{
+	va_list args;
+	char buf[1024];
+
+	va_start(args, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, args);
+	va_end(args);
+
+	ast_log(AST_LOG_WARNING, "%s", buf);
+}
+
+/*! \internal \brief Error callback function for the jitter buffer's jb_err function */
+static void __attribute__((format(printf, 1, 2))) test_jb_error_output(const char *fmt, ...)
+{
+	va_list args;
+	char buf[1024];
+
+	va_start(args, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, args);
+	va_end(args);
+
+	ast_log(AST_LOG_ERROR, "%s", buf);
+}
+
+AST_TEST_DEFINE(jitterbuffer_nominal_voice_frames)
 {
 	enum ast_test_result_state result = AST_TEST_FAIL;
 	struct jitterbuf *jb = NULL;
 	struct jb_frame frame;
 	struct jb_conf jbconf;
+	struct jb_info jbinfo;
 	int i;
 
 	switch (cmd) {
 	case TEST_INIT:
-		info->name = "jitterbuffer_nominal_audio_frames";
+		info->name = "jitterbuffer_nominal_voice_frames";
 		info->category = "/main/jitterbuffer/";
 		info->summary = "Nominal operation of jitterbuffer with audio data";
 		info->description =
-			"Tests putting audio data into a jitterbuffer with no out"
-			"of order frames.";
+			"Tests the nominal case of putting audio data into a jitter buffer";
 		return AST_TEST_NOT_RUN;
 	case TEST_EXECUTE:
 		break;
 	}
 
+	JB_TEST_BEGIN("jitterbuffer_nominal_voice_frames");
+
 	if (!(jb = jb_new())) {
 		ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
 		goto cleanup;
@@ -145,6 +213,17 @@
 	}
 
 	result = AST_TEST_PASS;
+
+	if (jb_getinfo(jb, &jbinfo) != JB_OK) {
+		ast_test_status_update(test, "Failed to get jitterbuffer information\n");
+		goto cleanup;
+	}
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_dropped, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_in, 40);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_out, 40);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_late, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_lost, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_ooo, 0);
 
 cleanup:
 	if (jb) {
@@ -153,6 +232,9 @@
 		while (jb_getall(jb, &frame) == JB_OK) { }
 		jb_destroy(jb);
 	}
+
+	JB_TEST_END;
+
 	return result;
 }
 
@@ -162,6 +244,7 @@
 	struct jitterbuf *jb = NULL;
 	struct jb_frame frame;
 	struct jb_conf jbconf;
+	struct jb_info jbinfo;
 	int i;
 
 	switch (cmd) {
@@ -170,13 +253,14 @@
 		info->category = "/main/jitterbuffer/";
 		info->summary = "Nominal operation of jitterbuffer with control frames";
 		info->description =
-			"Tests putting control frames into a jitterbuffer with no out"
-			"of order frames.";
+			"Tests the nominal case of putting control frames into a jitter buffer";
 		return AST_TEST_NOT_RUN;
 	case TEST_EXECUTE:
 		break;
 	}
 
+	JB_TEST_BEGIN("jitterbuffer_nominal_control_frames");
+
 	if (!(jb = jb_new())) {
 		ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
 		goto cleanup;
@@ -215,6 +299,17 @@
 			goto cleanup;
 		}
 	}
+
+	if (jb_getinfo(jb, &jbinfo) != JB_OK) {
+		ast_test_status_update(test, "Failed to get jitterbuffer information\n");
+		goto cleanup;
+	}
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_dropped, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_in, 40);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_out, 40);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_late, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_lost, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_ooo, 0);
 
 	result = AST_TEST_PASS;
 
@@ -225,10 +320,13 @@
 		while (jb_getall(jb, &frame) == JB_OK) { }
 		jb_destroy(jb);
 	}
+
+	JB_TEST_END;
+
 	return result;
 }
 
-AST_TEST_DEFINE(jitterbuffer_out_of_order)
+AST_TEST_DEFINE(jitterbuffer_out_of_order_voice)
 {
 	enum ast_test_result_state result = AST_TEST_FAIL;
 	struct jitterbuf *jb = NULL;
@@ -239,18 +337,21 @@
 
 	switch (cmd) {
 	case TEST_INIT:
-		info->name = "jitterbuffer_out_of_order";
+		info->name = "jitterbuffer_out_of_order_voice";
 		info->category = "/main/jitterbuffer/";
-		info->summary = "Tests sending out of order frames to a jitterbuffer";
+		info->summary = "Tests sending out of order audio frames to a jitter buffer";
 		info->description =
-			"Every 5th frame sent to a jitter buffer is reversed with the previous"
-			"frame.  The expected result is to have a jitter buffer with the frames"
-			"in order, while a total of 10 frames should be out of order.";
+			"Every 5th frame sent to a jitter buffer is reversed with the previous "
+			"frame.  The expected result is to have a jitter buffer with the frames "
+			"in order, while a total of 10 frames should be recorded as having been "
+			"received out of order.";
 		return AST_TEST_NOT_RUN;
 	case TEST_EXECUTE:
 		break;
 	}
 
+	JB_TEST_BEGIN("jitterbuffer_out_of_order_voice");
+
 	if (!(jb = jb_new())) {
 		ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
 		goto cleanup;
@@ -265,18 +366,18 @@
 	for (i = 0; i < 40; i++) {
 		if (i % 4 == 0) {
 			/* Add 5th frame */
-			if (jb_put(jb, NULL, JB_TYPE_CONTROL, 20, (i + 1) * 20, (i + 1) * 20 + 5) == JB_DROP) {
+			if (jb_put(jb, NULL, JB_TYPE_VOICE, 20, (i + 1) * 20, (i + 1) * 20 + 5) == JB_DROP) {
 				ast_test_status_update(test, "Jitter buffer dropped packet %d\n", (i+1));
 				goto cleanup;
 			}
 			/* Add 4th frame */
-			if (jb_put(jb, NULL, JB_TYPE_CONTROL, 20, i * 20, i * 20 + 5) == JB_DROP) {
+			if (jb_put(jb, NULL, JB_TYPE_VOICE, 20, i * 20, i * 20 + 5) == JB_DROP) {
 				ast_test_status_update(test, "Jitter buffer dropped packet %d\n", i);
 				goto cleanup;
 			}
 			i++;
 		} else {
-			if (jb_put(jb, NULL, JB_TYPE_CONTROL, 20, i * 20, i * 20 + 5) == JB_DROP) {
+			if (jb_put(jb, NULL, JB_TYPE_VOICE, 20, i * 20, i * 20 + 5) == JB_DROP) {
 				ast_test_status_update(test, "Jitter buffer dropped packet %d\n", i);
 				goto cleanup;
 			}
@@ -308,9 +409,16 @@
 		ast_test_status_update(test, "Failed to get jitterbuffer information\n");
 		goto cleanup;
 	}
-	if (jbinfo.frames_ooo != 10) {
-		ast_test_status_update(test, "Out of order frames: expected [%d]; actual [%ld]\n", 10, jbinfo.frames_ooo);
-	}
+	if (jb_getinfo(jb, &jbinfo) != JB_OK) {
+		ast_test_status_update(test, "Failed to get jitterbuffer information\n");
+		goto cleanup;
+	}
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_dropped, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_in, 40);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_out, 40);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_late, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_lost, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_ooo, 10);
 
 	result = AST_TEST_PASS;
 
@@ -321,30 +429,36 @@
 		while (jb_getall(jb, &frame) == JB_OK) { }
 		jb_destroy(jb);
 	}
+
+	JB_TEST_END;
+
 	return result;
 }
 
-AST_TEST_DEFINE(jitterbuffer_lost)
+AST_TEST_DEFINE(jitterbuffer_lost_voice)
 {
 	enum ast_test_result_state result = AST_TEST_FAIL;
 	struct jitterbuf *jb = NULL;
 	struct jb_frame frame;
 	struct jb_conf jbconf;
+	struct jb_info jbinfo;
 	int i;
 
 	switch (cmd) {
 	case TEST_INIT:
-		info->name = "jitterbuffer_lost";
+		info->name = "jitterbuffer_lost_voice";
 		info->category = "/main/jitterbuffer/";
 		info->summary = "Tests missing frames in the jitterbuffer";
 		info->description =
 			"Every 5th frame that would be sent to a jitter buffer is instead"
-			"dropped.  The jitterbuffer is expected to interpolate every 5th"
-			"frame.  A total of 10 frames should be lost.";
+			"dropped.  When reading data from the jitter buffer, the jitter buffer"
+			"should interpolate the voice frame.";
 		return AST_TEST_NOT_RUN;
 	case TEST_EXECUTE:
 		break;
 	}
+
+	JB_TEST_BEGIN("jitterbuffer_lost_voice");
 
 	if (!(jb = jb_new())) {
 		ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
@@ -391,6 +505,21 @@
 		}
 	}
 
+	if (jb_getinfo(jb, &jbinfo) != JB_OK) {
+		ast_test_status_update(test, "Failed to get jitterbuffer information\n");
+		goto cleanup;
+	}
+	JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
+	/* Note: The first frame (at i = 0) never got added, so nothing existed at that point.
+	 * Its neither dropped nor lost.
+	 */
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_ooo, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_late, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_lost, 7);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_in, 32);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_out, 32);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_dropped, 0);
+
 	result = AST_TEST_PASS;
 
 cleanup:
@@ -400,10 +529,13 @@
 		while (jb_getall(jb, &frame) == JB_OK) { }
 		jb_destroy(jb);
 	}
+
+	JB_TEST_END;
+
 	return result;
 }
 
-AST_TEST_DEFINE(jitterbuffer_late)
+AST_TEST_DEFINE(jitterbuffer_late_voice)
 {
 	enum ast_test_result_state result = AST_TEST_FAIL;
 	struct jitterbuf *jb = NULL;
@@ -414,7 +546,7 @@
 
 	switch (cmd) {
 	case TEST_INIT:
-		info->name = "jitterbuffer_late";
+		info->name = "jitterbuffer_late_voice";
 		info->category = "/main/jitterbuffer/";
 		info->summary = "Tests sending frames to a jitterbuffer that are late";
 		info->description =
@@ -426,6 +558,8 @@
 		break;
 	}
 
+	JB_TEST_BEGIN("jitterbuffer_late_audio");
+
 	if (!(jb = jb_new())) {
 		ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
 		goto cleanup;
@@ -438,23 +572,17 @@
 	}
 
 	for (i = 0; i < 40; i++) {
-		if (i % 4 == 0) {
+		if (i % 5 == 0) {
 			/* Add 5th frame */
-			if (jb_put(jb, NULL, JB_TYPE_CONTROL, 20, (i + 1) * 20, (i + 1) * 20 + 5) == JB_DROP) {
+			if (jb_put(jb, NULL, JB_TYPE_VOICE, 20, i * 20, i * 20 + 20) == JB_DROP) {
 				ast_test_status_update(test, "Jitter buffer dropped packet %d\n", (i+1));
 				goto cleanup;
 			}
-			/* Add 4th frame */
-			if (jb_put(jb, NULL, JB_TYPE_CONTROL, 20, i * 20, i * 20 + 5) == JB_DROP) {
+		} else {
+			if (jb_put(jb, NULL, JB_TYPE_VOICE, 20, i * 20, i * 20 + 5) == JB_DROP) {
 				ast_test_status_update(test, "Jitter buffer dropped packet %d\n", i);
 				goto cleanup;
 			}
-			i++;
-		} else {
-			if (jb_put(jb, NULL, JB_TYPE_CONTROL, 20, i * 20, i * 20 + 5) == JB_DROP) {
-				ast_test_status_update(test, "Jitter buffer dropped packet %d\n", i);
-				goto cleanup;
-			}
 		}
 	}
 
@@ -484,7 +612,12 @@
 		goto cleanup;
 	}
 	JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
-	JB_INFO_NUMERIC_TEST(jbinfo.frames_ooo, 10);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_ooo, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_late, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_lost, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_in, 40);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_out, 40);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_dropped, 0);
 
 	result = AST_TEST_PASS;
 
@@ -495,6 +628,9 @@
 		while (jb_getall(jb, &frame) == JB_OK) { }
 		jb_destroy(jb);
 	}
+
+	JB_TEST_END;
+
 	return result;
 }
 
@@ -506,7 +642,6 @@
 	struct jb_info jbinfo;
 	struct jb_conf jbconf;
 	int i;
-	int queued_frames = 0;
 
 	switch (cmd) {
 	case TEST_INIT:
@@ -535,8 +670,9 @@
 		jb_put(jb, NULL, JB_TYPE_VOICE, 20, i * 20, i * 20 + 5);
 	}
 
+	i = 0;
 	while (jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN) == JB_OK) {
-		++queued_frames;
+		++i;
 	}
 
 
@@ -561,18 +697,19 @@
 	return result;
 }
 
-AST_TEST_DEFINE(jitterbuffer_resynch)
+AST_TEST_DEFINE(jitterbuffer_resynch_control)
 {
 	enum ast_test_result_state result = AST_TEST_FAIL;
 	struct jitterbuf *jb = NULL;
 	struct jb_frame frame;
 	struct jb_info jbinfo;
 	struct jb_conf jbconf;
+	int interpolated_frames = 0;
 	int i;
 
 	switch (cmd) {
 	case TEST_INIT:
-		info->name = "jitterbuffer_resynch";
+		info->name = "jitterbuffer_resynch_control";
 		info->category = "/main/jitterbuffer/";
 		info->summary = "Tests sending frames to a jitterbuffer that are late";
 		info->description = "Blahblah";
@@ -588,23 +725,37 @@
 	}
 
 	test_jb_populate_config(&jbconf);
+	jbconf.resync_threshold = 200;
 	if (jb_setconf(jb, &jbconf) != JB_OK) {
 		ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
 		goto cleanup;
 	}
 
 	for (i = 0; i < 20; i++) {
-		jb_put(jb, NULL, JB_TYPE_VOICE, 20, i * 20, i * 20 + 5);
-	}
-
-	for (i = 0; i < 20; i++) {
-		jb_put(jb, NULL, JB_TYPE_VOICE, 20, i * 20 + 2000, i * 20 + 2005);
+		jb_put(jb, NULL, JB_TYPE_CONTROL, 20, i * 20, i * 20 + 5);
+	}
+
+	for (i = 20; i < 40; i++) {
+		jb_put(jb, NULL, JB_TYPE_CONTROL, 20, i * 20 + 500, i * 20 + 5);
+	}
+
+	for (i = 0; i <= 40; i++) {
+		if (jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN) == JB_INTERP) {
+			++interpolated_frames;
+		}
 	}
 
 	if (jb_getinfo(jb, &jbinfo) != JB_OK) {
 		ast_test_status_update(test, "Failed to get jitterbuffer information\n");
 		goto cleanup;
 	}
+	/* With control frames, a resync happens automatically */
+	JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_dropped, 0);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_out, 40);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_in, 40);
+	/* Verify that each of the interpolated frames is counted */
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_lost, interpolated_frames);
 
 	result = AST_TEST_PASS;
 
@@ -618,28 +769,102 @@
 	return result;
 }
 
+AST_TEST_DEFINE(jitterbuffer_resynch_audio)
+{
+	enum ast_test_result_state result = AST_TEST_FAIL;
+	struct jitterbuf *jb = NULL;
+	struct jb_frame frame;
+	struct jb_info jbinfo;
+	struct jb_conf jbconf;
+	int interpolated_frames = 0;
+	int i;
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "jitterbuffer_resynch_audio";
+		info->category = "/main/jitterbuffer/";
+		info->summary = "Tests sending frames to a jitterbuffer that are late";
+		info->description = "Blahblah";
+		/* TODO: */
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	if (!(jb = jb_new())) {
+		ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
+		goto cleanup;
+	}
+
+	test_jb_populate_config(&jbconf);
+	jbconf.resync_threshold = 200;
+	if (jb_setconf(jb, &jbconf) != JB_OK) {
+		ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
+		goto cleanup;
+	}
+
+	for (i = 0; i < 20; i++) {
+		jb_put(jb, NULL, JB_TYPE_VOICE, 20, i * 20, i * 20 + 5);
+	}
+
+	for (i = 20; i < 40; i++) {
+		jb_put(jb, NULL, JB_TYPE_VOICE, 20, i * 20 + 500, i * 20 + 5);
+	}
+
+	for (i = 0; i <= 40; i++) {
+		if (jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN) == JB_INTERP) {
+			++interpolated_frames;
+		}
+	}
+
+	if (jb_getinfo(jb, &jbinfo) != JB_OK) {
+		ast_test_status_update(test, "Failed to get jitterbuffer information\n");
+		goto cleanup;
+	}
+	/* The first three packets before the resync should be dropped */
+	JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_dropped, 3);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_out, 37);
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_in, 37);
+	/* Verify that each of the interpolated frames is counted */
+	JB_INFO_NUMERIC_TEST(jbinfo.frames_lost, interpolated_frames);
+
+
+	result = AST_TEST_PASS;
+
+cleanup:
+	if (jb) {
+		/* No need to do anything - this will put all frames on the 'free' list,
+		 * so jb_destroy will dispose of them */
+		while (jb_getall(jb, &frame) == JB_OK) { }
+		jb_destroy(jb);
+	}
+	return result;
+}
 
 static int unload_module(void)
 {
-	AST_TEST_UNREGISTER(jitterbuffer_nominal_audio_frames);
+	AST_TEST_UNREGISTER(jitterbuffer_nominal_voice_frames);
 	AST_TEST_UNREGISTER(jitterbuffer_nominal_control_frames);
-	AST_TEST_UNREGISTER(jitterbuffer_out_of_order);
-	AST_TEST_UNREGISTER(jitterbuffer_lost);
-	AST_TEST_UNREGISTER(jitterbuffer_late);
+	AST_TEST_UNREGISTER(jitterbuffer_out_of_order_audio);
+	AST_TEST_UNREGISTER(jitterbuffer_lost_audio);
+	AST_TEST_UNREGISTER(jitterbuffer_late_audio);
 	AST_TEST_UNREGISTER(jitterbuffer_overflow);
-	AST_TEST_UNREGISTER(jitterbuffer_resynch);
+	AST_TEST_UNREGISTER(jitterbuffer_resynch_audio);
+	AST_TEST_UNREGISTER(jitterbuffer_resynch_control);
 	return 0;
 }
 
 static int load_module(void)
 {
-	AST_TEST_REGISTER(jitterbuffer_nominal_audio_frames);
+	AST_TEST_REGISTER(jitterbuffer_nominal_voice_frames);
 	AST_TEST_REGISTER(jitterbuffer_nominal_control_frames);
-	AST_TEST_REGISTER(jitterbuffer_out_of_order);
-	AST_TEST_REGISTER(jitterbuffer_lost);
-	AST_TEST_REGISTER(jitterbuffer_late);
+	AST_TEST_REGISTER(jitterbuffer_out_of_order_audio);
+	AST_TEST_REGISTER(jitterbuffer_lost_audio);
+	AST_TEST_REGISTER(jitterbuffer_late_audio);
 	AST_TEST_REGISTER(jitterbuffer_overflow);
-	AST_TEST_REGISTER(jitterbuffer_resynch);
+	AST_TEST_REGISTER(jitterbuffer_resynch_audio);
+	AST_TEST_REGISTER(jitterbuffer_resynch_control);
 	return AST_MODULE_LOAD_SUCCESS;
 }
 




More information about the asterisk-commits mailing list