summaryrefslogtreecommitdiff
path: root/tests/test_jitterbuf.c
diff options
context:
space:
mode:
authorMatthew Jordan <mjordan@digium.com>2012-03-14 18:56:15 +0000
committerMatthew Jordan <mjordan@digium.com>2012-03-14 18:56:15 +0000
commita699bb72ad8d255c84998e97addd2e20ab3f6b7b (patch)
tree46e9a4a5333a9fbb37db219e234ef252aa99df57 /tests/test_jitterbuf.c
parenta22b6f6e4b8722ce8c2a174b2e883f0f6ba1f33d (diff)
Add tests for main/jitterbuf.c
This patch adds unit tests for main/jitterbuf.c. This includes checking for the following: * Nominal insertion and retrieval of frames * Insertion and retrieval of frames where the frames are inserted out of order with respect to the previous frame * Insertion and retrieval of frames where some number of frames that would occur in the expected sequence are instead dropped * Insertion and retrieval of frames with an arrival time that does not occur at the same rate as the surrounding frames * Resynchronization of the jitter buffer when an inserted frame breaks the resynchronization threshold * Overfilling of the jitter buffer For each of the tests, both JB_TYPE_VOICE and JB_TYPE_CONTROL permutations exist. Review: https://reviewboard.asterisk.org/r/1815 (issue: ASTERISK-18964) Reported by: Kris Shaw Tested by: Kris Shaw, Matt Jordan git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@359406 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'tests/test_jitterbuf.c')
-rw-r--r--tests/test_jitterbuf.c1254
1 files changed, 1254 insertions, 0 deletions
diff --git a/tests/test_jitterbuf.c b/tests/test_jitterbuf.c
new file mode 100644
index 000000000..65e7d4dcd
--- /dev/null
+++ b/tests/test_jitterbuf.c
@@ -0,0 +1,1254 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012, Matt Jordan
+ *
+ * Matt Jordan <mjordan@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Unit tests for jitterbuf.c
+ *
+ * \author\verbatim Matt Jordan <mjordan@digium.com> \endverbatim
+ *
+ * \ingroup tests
+ */
+
+/*** MODULEINFO
+ <depend>TEST_FRAMEWORK</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/utils.h"
+#include "asterisk/module.h"
+#include "asterisk/test.h"
+#include "jitterbuf.h"
+
+#define DEFAULT_MAX_JITTERBUFFER 1000
+#define DEFAULT_RESYNCH_THRESHOLD 1000
+#define DEFAULT_MAX_CONTIG_INTERP 10
+#define DEFAULT_TARGET_EXTRA -1
+#define DEFAULT_CODEC_INTERP_LEN 20
+
+/*! \internal
+ * Test two numeric (long int) values. Failure automatically attempts
+ * to jump to a cleanup tag
+ */
+#define JB_NUMERIC_TEST(attribute, expected) do { \
+ if ((attribute) != (expected)) { \
+ ast_test_status_update(test, #attribute ": expected [%ld]; actual [%ld]\n", (long int)(expected), (attribute)); \
+ goto cleanup; \
+ } \
+} 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" \
+ "\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 log where
+ * the jitter buffer debug output 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[] = {
+ "JB_OK", /* 0 */
+ "JB_EMPTY", /* 1 */
+ "JB_NOFRAME", /* 2 */
+ "JB_INTERP", /* 3 */
+ "JB_DROP", /* 4 */
+ "JB_SCHED" /* 5 */
+};
+
+/*! \internal \brief Make a default jitter buffer configuration */
+static void test_jb_populate_config(struct jb_conf *jbconf)
+{
+ if (!jbconf) {
+ return;
+ }
+
+ jbconf->max_jitterbuf = DEFAULT_MAX_JITTERBUFFER;
+ jbconf->resync_threshold = DEFAULT_RESYNCH_THRESHOLD;
+ jbconf->max_contig_interp = DEFAULT_MAX_CONTIG_INTERP;
+ jbconf->target_extra = 0;
+}
+
+/*! \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);
+}
+
+/*! \internal \brief Insert frames into the jitter buffer for the nominal tests */
+static int test_jb_nominal_frame_insertion(struct ast_test *test, struct jitterbuf *jb, enum jb_frame_type frame_type)
+{
+ int i = 0, ret = 0;
+
+ for (i = 0; i < 40; i++) {
+ if (jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 5) == JB_DROP) {
+ ast_test_status_update(test, "Jitter buffer dropped packet %d\n", i);
+ ret = 1;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+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 = 0;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "jitterbuffer_nominal_voice_frames";
+ info->category = "/main/jitterbuf/";
+ info->summary = "Nominal operation of jitter buffer with audio data";
+ info->description =
+ "Tests the nominal case of putting audio data into a jitter buffer, "
+ "retrieving the frames, and querying for the next frame";
+ 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;
+ }
+
+ test_jb_populate_config(&jbconf);
+ if (jb_setconf(jb, &jbconf) != JB_OK) {
+ ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
+ goto cleanup;
+ }
+
+ if (test_jb_nominal_frame_insertion(test, jb, JB_TYPE_VOICE)) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < 40; i++) {
+ enum jb_return_code ret;
+ /* We should have a frame for each point in time */
+ if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
+ ast_test_status_update(test,
+ "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
+ jitter_buffer_return_codes[ret], i);
+ goto cleanup;
+ }
+ JB_NUMERIC_TEST(frame.ms, 20);
+ JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
+ JB_NUMERIC_TEST(jb_next(jb), (i + 1) * 20 + 5);
+ }
+
+ 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_PRINT_FRAME_DEBUG(jbinfo);
+ JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_in, 40);
+ JB_NUMERIC_TEST(jbinfo.frames_out, 40);
+ JB_NUMERIC_TEST(jbinfo.frames_late, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
+
+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);
+ }
+
+ JB_TEST_END;
+
+ return result;
+}
+
+AST_TEST_DEFINE(jitterbuffer_nominal_control_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 = 0;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "jitterbuffer_nominal_control_frames";
+ info->category = "/main/jitterbuf/";
+ info->summary = "Nominal operation of jitter buffer with control frames";
+ info->description =
+ "Tests the nominal case of putting control frames into a jitter buffer, "
+ "retrieving the frames, and querying for the next frame";
+ 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;
+ }
+
+ test_jb_populate_config(&jbconf);
+ if (jb_setconf(jb, &jbconf) != JB_OK) {
+ ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
+ goto cleanup;
+ }
+
+ if (test_jb_nominal_frame_insertion(test, jb, JB_TYPE_CONTROL)) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < 40; i++) {
+ enum jb_return_code ret;
+ /* We should have a frame for each point in time */
+ if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
+ ast_test_status_update(test,
+ "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
+ jitter_buffer_return_codes[ret], i);
+ goto cleanup;
+ }
+ JB_NUMERIC_TEST(frame.ms, 20);
+ JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
+ }
+
+ 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);
+ JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_in, 40);
+ JB_NUMERIC_TEST(jbinfo.frames_out, 40);
+ JB_NUMERIC_TEST(jbinfo.frames_late, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
+
+ 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);
+ }
+
+ JB_TEST_END;
+
+ return result;
+}
+
+/*! \internal \brief Insert frames into the jitter buffer for the out of order tests */
+static int test_jb_out_of_order_frame_insertion(struct ast_test *test, struct jitterbuf *jb, enum jb_frame_type frame_type)
+{
+ int i = 0, ret = 0;
+
+ for (i = 0; i < 40; i++) {
+ if (i % 4 == 0) {
+ /* Add the next frame */
+ if (jb_put(jb, NULL, frame_type, 20, (i + 1) * 20, (i + 1) * 20 + 5) == JB_DROP) {
+ ast_test_status_update(test, "Jitter buffer dropped packet %d\n", (i+1));
+ ret = 1;
+ break;
+ }
+ /* Add the current frame */
+ if (jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 5) == JB_DROP) {
+ ast_test_status_update(test, "Jitter buffer dropped packet %d\n", i);
+ ret = 1;
+ break;
+ }
+ i++;
+ } else {
+ if (jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 5) == JB_DROP) {
+ ast_test_status_update(test, "Jitter buffer dropped packet %d\n", i);
+ ret = 1;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+AST_TEST_DEFINE(jitterbuffer_out_of_order_voice)
+{
+ 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 i;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "jitterbuffer_out_of_order_voice";
+ info->category = "/main/jitterbuf/";
+ 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 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;
+ }
+
+ test_jb_populate_config(&jbconf);
+ if (jb_setconf(jb, &jbconf) != JB_OK) {
+ ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
+ goto cleanup;
+ }
+
+ if (test_jb_out_of_order_frame_insertion(test, jb, JB_TYPE_VOICE)) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < 40; i++) {
+ enum jb_return_code ret;
+ /* We should have a frame for each point in time */
+ if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
+ ast_test_status_update(test,
+ "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
+ jitter_buffer_return_codes[ret], i);
+ goto cleanup;
+ }
+ JB_NUMERIC_TEST(frame.ms, 20);
+ JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
+ }
+
+ 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);
+ JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_in, 40);
+ JB_NUMERIC_TEST(jbinfo.frames_out, 40);
+ JB_NUMERIC_TEST(jbinfo.frames_late, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_ooo, 10);
+
+ 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);
+ }
+
+ JB_TEST_END;
+
+ return result;
+}
+
+AST_TEST_DEFINE(jitterbuffer_out_of_order_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 i;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "jitterbuffer_out_of_order_voice";
+ info->category = "/main/jitterbuf/";
+ 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 recorded as having been "
+ "received out of order.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ JB_TEST_BEGIN("jitterbuffer_out_of_order_control");
+
+ if (!(jb = jb_new())) {
+ ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
+ goto cleanup;
+ }
+
+ test_jb_populate_config(&jbconf);
+ if (jb_setconf(jb, &jbconf) != JB_OK) {
+ ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
+ goto cleanup;
+ }
+
+ if (test_jb_out_of_order_frame_insertion(test, jb, JB_TYPE_CONTROL)) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < 40; i++) {
+ enum jb_return_code ret;
+ /* We should have a frame for each point in time */
+ if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
+ ast_test_status_update(test,
+ "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
+ jitter_buffer_return_codes[ret], i);
+ goto cleanup;
+ }
+ JB_NUMERIC_TEST(frame.ms, 20);
+ JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
+ }
+
+ 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);
+ JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_in, 40);
+ JB_NUMERIC_TEST(jbinfo.frames_out, 40);
+ JB_NUMERIC_TEST(jbinfo.frames_late, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_ooo, 10);
+
+ 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);
+ }
+
+ JB_TEST_END;
+
+ return result;
+}
+
+/*! \internal \brief Insert frames into the jitter buffer for the lost frame tests */
+static int test_jb_lost_frame_insertion(struct ast_test *test, struct jitterbuf *jb, enum jb_frame_type frame_type)
+{
+ int i = 0, ret = 0;
+
+ for (i = 0; i < 40; i++) {
+ if (i % 5 == 0) {
+ i++;
+ }
+ if (jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 5) == JB_DROP) {
+ ast_test_status_update(test, "Jitter buffer dropped packet %d\n", i);
+ ret = 1;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+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_voice";
+ info->category = "/main/jitterbuf/";
+ info->summary = "Tests missing frames in the jitterbuffer";
+ info->description =
+ "Every 5th frame that would be sent to a jitter buffer is instead"
+ "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");
+ goto cleanup;
+ }
+
+ test_jb_populate_config(&jbconf);
+ if (jb_setconf(jb, &jbconf) != JB_OK) {
+ ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
+ goto cleanup;
+ }
+
+ if (test_jb_lost_frame_insertion(test, jb, JB_TYPE_VOICE)) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < 40; i++) {
+ enum jb_return_code ret;
+ if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
+ /* If we didn't get an OK, make sure that it was an expected lost frame */
+ if (!((ret == JB_INTERP && i % 5 == 0) || (ret == JB_NOFRAME && i == 0))) {
+ ast_test_status_update(test,
+ "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
+ jitter_buffer_return_codes[ret], i);
+ goto cleanup;
+ }
+ } else {
+ JB_NUMERIC_TEST(frame.ms, 20);
+ JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
+ }
+ }
+
+ 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_NUMERIC_TEST(jbinfo.frames_ooo, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_late, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_lost, 7);
+ JB_NUMERIC_TEST(jbinfo.frames_in, 32);
+ JB_NUMERIC_TEST(jbinfo.frames_out, 32);
+ JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
+
+ 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);
+ }
+
+ JB_TEST_END;
+
+ return result;
+}
+
+AST_TEST_DEFINE(jitterbuffer_lost_control)
+{
+ 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_control";
+ info->category = "/main/jitterbuf/";
+ info->summary = "Tests missing frames in the jitterbuffer";
+ info->description =
+ "Every 5th frame that would be sent to a jitter buffer is instead"
+ "dropped. When reading data from the jitter buffer, the jitter buffer"
+ "simply reports that no frame exists for that time slot";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ JB_TEST_BEGIN("jitterbuffer_lost_control");
+
+ if (!(jb = jb_new())) {
+ ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
+ goto cleanup;
+ }
+
+ test_jb_populate_config(&jbconf);
+ if (jb_setconf(jb, &jbconf) != JB_OK) {
+ ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
+ goto cleanup;
+ }
+
+ if (test_jb_lost_frame_insertion(test, jb, JB_TYPE_CONTROL)) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < 40; i++) {
+ enum jb_return_code ret;
+ if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
+ /* If we didn't get an OK, make sure that it was an expected lost frame */
+ if (!(ret == JB_NOFRAME && i % 5 == 0)) {
+ ast_test_status_update(test,
+ "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
+ jitter_buffer_return_codes[ret], i);
+ goto cleanup;
+ }
+ } else {
+ JB_NUMERIC_TEST(frame.ms, 20);
+ JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
+ }
+ }
+
+ 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_NUMERIC_TEST(jbinfo.frames_ooo, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_late, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_in, 32);
+ JB_NUMERIC_TEST(jbinfo.frames_out, 32);
+ JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
+
+ 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);
+ }
+
+ JB_TEST_END;
+
+ return result;
+}
+
+/*! \internal \brief Insert frames into the jitter buffer for the late frame tests */
+static int test_jb_late_frame_insertion(struct ast_test *test, struct jitterbuf *jb, enum jb_frame_type frame_type)
+{
+ int i = 0, ret = 0;
+
+ for (i = 0; i < 40; i++) {
+ if (i % 5 == 0) {
+ /* Add 5th frame */
+ if (jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 20) == JB_DROP) {
+ ast_test_status_update(test, "Jitter buffer dropped packet %d\n", (i+1));
+ ret = 1;
+ break;
+ }
+ } else {
+ if (jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 5) == JB_DROP) {
+ ast_test_status_update(test, "Jitter buffer dropped packet %d\n", i);
+ ret = 1;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+AST_TEST_DEFINE(jitterbuffer_late_voice)
+{
+ 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 i;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "jitterbuffer_late_voice";
+ info->category = "/main/jitterbuf/";
+ info->summary = "Tests sending frames to a jitter buffer that arrive late";
+ info->description =
+ "Every 5th frame sent to a jitter buffer arrives late, but still in "
+ "order with respect to the previous and next packet";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ JB_TEST_BEGIN("jitterbuffer_late_voice");
+
+ if (!(jb = jb_new())) {
+ ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
+ goto cleanup;
+ }
+
+ test_jb_populate_config(&jbconf);
+ if (jb_setconf(jb, &jbconf) != JB_OK) {
+ ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
+ goto cleanup;
+ }
+
+ if (test_jb_late_frame_insertion(test, jb, JB_TYPE_VOICE)) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < 40; i++) {
+ enum jb_return_code ret;
+ /* We should have a frame for each point in time */
+ if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
+ ast_test_status_update(test,
+ "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
+ jitter_buffer_return_codes[ret], i);
+ goto cleanup;
+ }
+ JB_NUMERIC_TEST(frame.ms, 20);
+ JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
+ }
+
+ 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);
+ JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_late, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_in, 40);
+ JB_NUMERIC_TEST(jbinfo.frames_out, 40);
+ JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
+
+ 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);
+ }
+
+ JB_TEST_END;
+
+ return result;
+}
+
+AST_TEST_DEFINE(jitterbuffer_late_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 i;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "jitterbuffer_late_control";
+ info->category = "/main/jitterbuf/";
+ info->summary = "Tests sending frames to a jitter buffer that arrive late";
+ info->description =
+ "Every 5th frame sent to a jitter buffer arrives late, but still in "
+ "order with respect to the previous and next packet";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ JB_TEST_BEGIN("jitterbuffer_late_voice");
+
+ if (!(jb = jb_new())) {
+ ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
+ goto cleanup;
+ }
+
+ test_jb_populate_config(&jbconf);
+ if (jb_setconf(jb, &jbconf) != JB_OK) {
+ ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
+ goto cleanup;
+ }
+
+ if (test_jb_late_frame_insertion(test, jb, JB_TYPE_CONTROL)) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < 40; i++) {
+ enum jb_return_code ret;
+ /* We should have a frame for each point in time */
+ if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
+ ast_test_status_update(test,
+ "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
+ jitter_buffer_return_codes[ret], i);
+ goto cleanup;
+ }
+ JB_NUMERIC_TEST(frame.ms, 20);
+ JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
+ }
+
+ 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);
+ JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_late, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_in, 40);
+ JB_NUMERIC_TEST(jbinfo.frames_out, 40);
+ JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
+
+ 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);
+ }
+
+ JB_TEST_END;
+
+ return result;
+}
+
+/*! \internal \brief Insert frames into the jitter buffer for the overflow tests */
+static void test_jb_overflow_frame_insertion(struct jitterbuf *jb, enum jb_frame_type frame_type)
+{
+ int i = 0;
+
+ for (i = 0; i < 100; i++) {
+ jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 5);
+ }
+}
+
+AST_TEST_DEFINE(jitterbuffer_overflow_voice)
+{
+ 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 i = 0;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "jitterbuffer_overflow_voice";
+ info->category = "/main/jitterbuf/";
+ info->summary = "Tests overfilling a jitter buffer with voice frames";
+ info->description = "Tests overfilling a jitter buffer with voice frames";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ JB_TEST_BEGIN("jitterbuffer_overflow_voice");
+
+ if (!(jb = jb_new())) {
+ ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
+ goto cleanup;
+ }
+
+ test_jb_populate_config(&jbconf);
+ if (jb_setconf(jb, &jbconf) != JB_OK) {
+ ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
+ goto cleanup;
+ }
+
+ test_jb_overflow_frame_insertion(jb, JB_TYPE_VOICE);
+
+ while (jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN) == JB_OK) {
+ JB_NUMERIC_TEST(frame.ms, 20);
+ JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
+ ++i;
+ }
+
+ 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);
+ JB_NUMERIC_TEST(jbinfo.frames_dropped, 49);
+ JB_NUMERIC_TEST(jbinfo.frames_out, 51);
+ JB_NUMERIC_TEST(jbinfo.frames_in, 51);
+ JB_NUMERIC_TEST(jbinfo.frames_late, 0);
+ /* Note that the last frame will be interpolated */
+ JB_NUMERIC_TEST(jbinfo.frames_lost, 1);
+ JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
+
+ 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);
+ }
+
+ JB_TEST_END;
+
+ return result;
+}
+
+AST_TEST_DEFINE(jitterbuffer_overflow_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 i = 0;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "jitterbuffer_overflow_control";
+ info->category = "/main/jitterbuf/";
+ info->summary = "Tests overfilling a jitter buffer with control frames";
+ info->description = "Tests overfilling a jitter buffer with control frames";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ JB_TEST_BEGIN("jitterbuffer_overflow_control");
+
+ if (!(jb = jb_new())) {
+ ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
+ goto cleanup;
+ }
+
+ test_jb_populate_config(&jbconf);
+ if (jb_setconf(jb, &jbconf) != JB_OK) {
+ ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
+ goto cleanup;
+ }
+
+ test_jb_overflow_frame_insertion(jb, JB_TYPE_CONTROL);
+
+ while (jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN) == JB_OK) {
+ JB_NUMERIC_TEST(frame.ms, 20);
+ JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
+ ++i;
+ }
+
+ 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);
+ JB_NUMERIC_TEST(jbinfo.frames_dropped, 49);
+ JB_NUMERIC_TEST(jbinfo.frames_out, 51);
+ JB_NUMERIC_TEST(jbinfo.frames_in, 51);
+ JB_NUMERIC_TEST(jbinfo.frames_late, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
+
+ 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);
+ }
+
+ JB_TEST_END;
+
+ return result;
+}
+
+/*! \internal \brief Insert frames into the jitter buffer for the resynch tests */
+static void test_jb_resynch_frame_insertion(struct jitterbuf *jb, enum jb_frame_type frame_type)
+{
+ int i = 0;
+
+ for (i = 0; i < 20; i++) {
+ jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 5);
+ }
+
+ for (i = 20; i < 40; i++) {
+ jb_put(jb, NULL, frame_type, 20, i * 20 + 500, i * 20 + 5);
+ }
+}
+
+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_control";
+ info->category = "/main/jitterbuf/";
+ info->summary = "Tests sending control frames that force a resynch";
+ info->description = "Control frames are sent to a jitter buffer. After some "
+ "number of frames, the source timestamps jump, forcing a resync of "
+ "the jitter buffer. Since the frames are control, the resync happens "
+ "immediately.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ JB_TEST_BEGIN("jitterbuffer_resynch_control");
+
+ 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;
+ }
+
+ test_jb_resynch_frame_insertion(jb, JB_TYPE_CONTROL);
+
+ 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_NUMERIC_TEST(jbinfo.frames_dropped, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_out, 40);
+ JB_NUMERIC_TEST(jbinfo.frames_in, 40);
+ /* Verify that each of the interpolated frames is counted */
+ JB_NUMERIC_TEST(jbinfo.frames_lost, interpolated_frames);
+ JB_NUMERIC_TEST(jbinfo.frames_late, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
+
+ 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);
+ }
+
+ JB_TEST_END;
+
+ return result;
+}
+
+AST_TEST_DEFINE(jitterbuffer_resynch_voice)
+{
+ 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_voice";
+ info->category = "/main/jitterbuf/";
+ info->summary = "Tests sending voice frames that force a resynch";
+ info->description = "Voice frames are sent to a jitter buffer. After some "
+ "number of frames, the source timestamps jump, forcing a resync of "
+ "the jitter buffer. Since the frames are voice, the resync happens "
+ "after observing three packets that break the resync threshold.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ JB_TEST_BEGIN("jitterbuffer_resynch_voice");
+
+ 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;
+ }
+
+ test_jb_resynch_frame_insertion(jb, JB_TYPE_VOICE);
+
+ 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_NUMERIC_TEST(jbinfo.frames_dropped, 3);
+ JB_NUMERIC_TEST(jbinfo.frames_out, 37);
+ JB_NUMERIC_TEST(jbinfo.frames_in, 37);
+ /* Verify that each of the interpolated frames is counted */
+ JB_NUMERIC_TEST(jbinfo.frames_lost, interpolated_frames);
+ JB_NUMERIC_TEST(jbinfo.frames_late, 0);
+ JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
+
+
+ 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);
+ }
+
+ JB_TEST_END;
+
+ return result;
+}
+
+static int unload_module(void)
+{
+ AST_TEST_UNREGISTER(jitterbuffer_nominal_voice_frames);
+ AST_TEST_UNREGISTER(jitterbuffer_nominal_control_frames);
+ AST_TEST_UNREGISTER(jitterbuffer_out_of_order_voice);
+ AST_TEST_UNREGISTER(jitterbuffer_out_of_order_control);
+ AST_TEST_UNREGISTER(jitterbuffer_lost_voice);
+ AST_TEST_UNREGISTER(jitterbuffer_lost_control);
+ AST_TEST_UNREGISTER(jitterbuffer_late_voice);
+ AST_TEST_UNREGISTER(jitterbuffer_late_control);
+ AST_TEST_UNREGISTER(jitterbuffer_overflow_voice);
+ AST_TEST_UNREGISTER(jitterbuffer_overflow_control);
+ AST_TEST_UNREGISTER(jitterbuffer_resynch_voice);
+ AST_TEST_UNREGISTER(jitterbuffer_resynch_control);
+ return 0;
+}
+
+static int load_module(void)
+{
+ /* Nominal - put / get frames */
+ AST_TEST_REGISTER(jitterbuffer_nominal_voice_frames);
+ AST_TEST_REGISTER(jitterbuffer_nominal_control_frames);
+
+ /* Out of order frame arrival */
+ AST_TEST_REGISTER(jitterbuffer_out_of_order_voice);
+ AST_TEST_REGISTER(jitterbuffer_out_of_order_control);
+
+ /* Lost frame arrival */
+ AST_TEST_REGISTER(jitterbuffer_lost_voice);
+ AST_TEST_REGISTER(jitterbuffer_lost_control);
+
+ /* Late frame arrival */
+ AST_TEST_REGISTER(jitterbuffer_late_voice);
+ AST_TEST_REGISTER(jitterbuffer_late_control);
+
+ /* Buffer overflow */
+ AST_TEST_REGISTER(jitterbuffer_overflow_voice);
+ AST_TEST_REGISTER(jitterbuffer_overflow_control);
+
+ /* Buffer resynch */
+ AST_TEST_REGISTER(jitterbuffer_resynch_voice);
+ AST_TEST_REGISTER(jitterbuffer_resynch_control);
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Jitter Buffer Tests");