[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