2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2012, Matt Jordan
6 * Matt Jordan <mjordan@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Unit tests for jitterbuf.c
23 * \author\verbatim Matt Jordan <mjordan@digium.com> \endverbatim
29 <depend>TEST_FRAMEWORK</depend>
30 <support_level>core</support_level>
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37 #include "asterisk/utils.h"
38 #include "asterisk/module.h"
39 #include "asterisk/test.h"
40 #include "jitterbuf.h"
42 #define DEFAULT_MAX_JITTERBUFFER 1000
43 #define DEFAULT_RESYNCH_THRESHOLD 1000
44 #define DEFAULT_MAX_CONTIG_INTERP 10
45 #define DEFAULT_TARGET_EXTRA -1
46 #define DEFAULT_CODEC_INTERP_LEN 20
49 * Test two numeric (long int) values. Failure automatically attempts
50 * to jump to a cleanup tag
52 #define JB_NUMERIC_TEST(attribute, expected) do { \
53 if ((attribute) != (expected)) { \
54 ast_test_status_update(test, #attribute ": expected [%ld]; actual [%ld]\n", (long int)(expected), (attribute)); \
60 * Print out as debug the frame related contents of a jb_info object
62 #define JB_INFO_PRINT_FRAME_DEBUG(jbinfo) do { \
63 ast_debug(1, "JitterBuffer Frame Info:\n" \
64 "\tFrames In: %ld\n\tFrames Out: %ld\n" \
65 "\tDropped Frames: %ld\n\tLate Frames: %ld\n" \
66 "\tLost Frames: %ld\n\tOut of Order Frames: %ld\n" \
67 "\tCurrent Frame: %ld\n", jbinfo.frames_in, jbinfo.frames_out, \
68 jbinfo.frames_dropped, jbinfo.frames_late, jbinfo.frames_lost, \
69 jbinfo.frames_ooo, jbinfo.frames_cur); \
73 * This macro installs the error, warning, and debug functions for a test. It is
74 * expected that at the end of a test, the functions are removed.
75 * Note that the debug statement is in here merely to aid in tracing in a log where
76 * the jitter buffer debug output begins.
78 #define JB_TEST_BEGIN(test_name) do { \
79 jb_setoutput(test_jb_error_output, test_jb_warn_output, test_jb_debug_output); \
80 ast_debug(1, "Starting %s\n", test_name); \
84 * Uninstall the error, warning, and debug functions from a test
86 #define JB_TEST_END do { \
87 jb_setoutput(NULL, NULL, NULL); \
90 static const char *jitter_buffer_return_codes[] = {
99 /*! \internal \brief Make a default jitter buffer configuration */
100 static void test_jb_populate_config(struct jb_conf *jbconf)
106 jbconf->max_jitterbuf = DEFAULT_MAX_JITTERBUFFER;
107 jbconf->resync_threshold = DEFAULT_RESYNCH_THRESHOLD;
108 jbconf->max_contig_interp = DEFAULT_MAX_CONTIG_INTERP;
109 jbconf->target_extra = 0;
112 /*! \internal \brief Debug callback function for the jitter buffer's jb_dbg function */
113 static void __attribute__((format(printf, 1, 2))) test_jb_debug_output(const char *fmt, ...)
119 vsnprintf(buf, sizeof(buf), fmt, args);
122 ast_debug(1, "%s", buf);
125 /*! \internal \brief Warning callback function for the jitter buffer's jb_warn function */
126 static void __attribute__((format(printf, 1, 2))) test_jb_warn_output(const char *fmt, ...)
132 vsnprintf(buf, sizeof(buf), fmt, args);
135 ast_log(AST_LOG_WARNING, "%s", buf);
138 /*! \internal \brief Error callback function for the jitter buffer's jb_err function */
139 static void __attribute__((format(printf, 1, 2))) test_jb_error_output(const char *fmt, ...)
145 vsnprintf(buf, sizeof(buf), fmt, args);
148 ast_log(AST_LOG_ERROR, "%s", buf);
151 /*! \internal \brief Insert frames into the jitter buffer for the nominal tests */
152 static int test_jb_nominal_frame_insertion(struct ast_test *test, struct jitterbuf *jb, enum jb_frame_type frame_type)
156 for (i = 0; i < 40; i++) {
157 if (jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 5) == JB_DROP) {
158 ast_test_status_update(test, "Jitter buffer dropped packet %d\n", i);
167 AST_TEST_DEFINE(jitterbuffer_nominal_voice_frames)
169 enum ast_test_result_state result = AST_TEST_FAIL;
170 struct jitterbuf *jb = NULL;
171 struct jb_frame frame;
172 struct jb_conf jbconf;
173 struct jb_info jbinfo;
178 info->name = "jitterbuffer_nominal_voice_frames";
179 info->category = "/main/jitterbuf/";
180 info->summary = "Nominal operation of jitter buffer with audio data";
182 "Tests the nominal case of putting audio data into a jitter buffer, "
183 "retrieving the frames, and querying for the next frame";
184 return AST_TEST_NOT_RUN;
189 JB_TEST_BEGIN("jitterbuffer_nominal_voice_frames");
191 if (!(jb = jb_new())) {
192 ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
196 test_jb_populate_config(&jbconf);
197 if (jb_setconf(jb, &jbconf) != JB_OK) {
198 ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
202 if (test_jb_nominal_frame_insertion(test, jb, JB_TYPE_VOICE)) {
206 for (i = 0; i < 40; i++) {
207 enum jb_return_code ret;
208 /* We should have a frame for each point in time */
209 if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
210 ast_test_status_update(test,
211 "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
212 jitter_buffer_return_codes[ret], i);
215 JB_NUMERIC_TEST(frame.ms, 20);
216 JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
217 JB_NUMERIC_TEST(jb_next(jb), (i + 1) * 20 + 5);
220 result = AST_TEST_PASS;
222 if (jb_getinfo(jb, &jbinfo) != JB_OK) {
223 ast_test_status_update(test, "Failed to get jitterbuffer information\n");
226 JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
227 JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
228 JB_NUMERIC_TEST(jbinfo.frames_in, 40);
229 JB_NUMERIC_TEST(jbinfo.frames_out, 40);
230 JB_NUMERIC_TEST(jbinfo.frames_late, 0);
231 JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
232 JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
236 /* No need to do anything - this will put all frames on the 'free' list,
237 * so jb_destroy will dispose of them */
238 while (jb_getall(jb, &frame) == JB_OK) { }
247 AST_TEST_DEFINE(jitterbuffer_nominal_control_frames)
249 enum ast_test_result_state result = AST_TEST_FAIL;
250 struct jitterbuf *jb = NULL;
251 struct jb_frame frame;
252 struct jb_conf jbconf;
253 struct jb_info jbinfo;
258 info->name = "jitterbuffer_nominal_control_frames";
259 info->category = "/main/jitterbuf/";
260 info->summary = "Nominal operation of jitter buffer with control frames";
262 "Tests the nominal case of putting control frames into a jitter buffer, "
263 "retrieving the frames, and querying for the next frame";
264 return AST_TEST_NOT_RUN;
269 JB_TEST_BEGIN("jitterbuffer_nominal_control_frames");
271 if (!(jb = jb_new())) {
272 ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
276 test_jb_populate_config(&jbconf);
277 if (jb_setconf(jb, &jbconf) != JB_OK) {
278 ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
282 if (test_jb_nominal_frame_insertion(test, jb, JB_TYPE_CONTROL)) {
286 for (i = 0; i < 40; i++) {
287 enum jb_return_code ret;
288 /* We should have a frame for each point in time */
289 if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
290 ast_test_status_update(test,
291 "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
292 jitter_buffer_return_codes[ret], i);
295 JB_NUMERIC_TEST(frame.ms, 20);
296 JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
299 if (jb_getinfo(jb, &jbinfo) != JB_OK) {
300 ast_test_status_update(test, "Failed to get jitterbuffer information\n");
303 JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
304 JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
305 JB_NUMERIC_TEST(jbinfo.frames_in, 40);
306 JB_NUMERIC_TEST(jbinfo.frames_out, 40);
307 JB_NUMERIC_TEST(jbinfo.frames_late, 0);
308 JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
309 JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
311 result = AST_TEST_PASS;
315 /* No need to do anything - this will put all frames on the 'free' list,
316 * so jb_destroy will dispose of them */
317 while (jb_getall(jb, &frame) == JB_OK) { }
326 /*! \internal \brief Insert frames into the jitter buffer for the out of order tests */
327 static int test_jb_out_of_order_frame_insertion(struct ast_test *test, struct jitterbuf *jb, enum jb_frame_type frame_type)
331 for (i = 0; i < 40; i++) {
333 /* Add the next frame */
334 if (jb_put(jb, NULL, frame_type, 20, (i + 1) * 20, (i + 1) * 20 + 5) == JB_DROP) {
335 ast_test_status_update(test, "Jitter buffer dropped packet %d\n", (i+1));
339 /* Add the current frame */
340 if (jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 5) == JB_DROP) {
341 ast_test_status_update(test, "Jitter buffer dropped packet %d\n", i);
347 if (jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 5) == JB_DROP) {
348 ast_test_status_update(test, "Jitter buffer dropped packet %d\n", i);
358 AST_TEST_DEFINE(jitterbuffer_out_of_order_voice)
360 enum ast_test_result_state result = AST_TEST_FAIL;
361 struct jitterbuf *jb = NULL;
362 struct jb_frame frame;
363 struct jb_info jbinfo;
364 struct jb_conf jbconf;
369 info->name = "jitterbuffer_out_of_order_voice";
370 info->category = "/main/jitterbuf/";
371 info->summary = "Tests sending out of order audio frames to a jitter buffer";
373 "Every 5th frame sent to a jitter buffer is reversed with the previous "
374 "frame. The expected result is to have a jitter buffer with the frames "
375 "in order, while a total of 10 frames should be recorded as having been "
376 "received out of order.";
377 return AST_TEST_NOT_RUN;
382 JB_TEST_BEGIN("jitterbuffer_out_of_order_voice");
384 if (!(jb = jb_new())) {
385 ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
389 test_jb_populate_config(&jbconf);
390 if (jb_setconf(jb, &jbconf) != JB_OK) {
391 ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
395 if (test_jb_out_of_order_frame_insertion(test, jb, JB_TYPE_VOICE)) {
399 for (i = 0; i < 40; i++) {
400 enum jb_return_code ret;
401 /* We should have a frame for each point in time */
402 if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
403 ast_test_status_update(test,
404 "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
405 jitter_buffer_return_codes[ret], i);
408 JB_NUMERIC_TEST(frame.ms, 20);
409 JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
412 if (jb_getinfo(jb, &jbinfo) != JB_OK) {
413 ast_test_status_update(test, "Failed to get jitterbuffer information\n");
416 JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
417 JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
418 JB_NUMERIC_TEST(jbinfo.frames_in, 40);
419 JB_NUMERIC_TEST(jbinfo.frames_out, 40);
420 JB_NUMERIC_TEST(jbinfo.frames_late, 0);
421 JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
422 JB_NUMERIC_TEST(jbinfo.frames_ooo, 10);
424 result = AST_TEST_PASS;
428 /* No need to do anything - this will put all frames on the 'free' list,
429 * so jb_destroy will dispose of them */
430 while (jb_getall(jb, &frame) == JB_OK) { }
439 AST_TEST_DEFINE(jitterbuffer_out_of_order_control)
441 enum ast_test_result_state result = AST_TEST_FAIL;
442 struct jitterbuf *jb = NULL;
443 struct jb_frame frame;
444 struct jb_info jbinfo;
445 struct jb_conf jbconf;
450 info->name = "jitterbuffer_out_of_order_voice";
451 info->category = "/main/jitterbuf/";
452 info->summary = "Tests sending out of order audio frames to a jitter buffer";
454 "Every 5th frame sent to a jitter buffer is reversed with the previous "
455 "frame. The expected result is to have a jitter buffer with the frames "
456 "in order, while a total of 10 frames should be recorded as having been "
457 "received out of order.";
458 return AST_TEST_NOT_RUN;
463 JB_TEST_BEGIN("jitterbuffer_out_of_order_control");
465 if (!(jb = jb_new())) {
466 ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
470 test_jb_populate_config(&jbconf);
471 if (jb_setconf(jb, &jbconf) != JB_OK) {
472 ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
476 if (test_jb_out_of_order_frame_insertion(test, jb, JB_TYPE_CONTROL)) {
480 for (i = 0; i < 40; i++) {
481 enum jb_return_code ret;
482 /* We should have a frame for each point in time */
483 if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
484 ast_test_status_update(test,
485 "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
486 jitter_buffer_return_codes[ret], i);
489 JB_NUMERIC_TEST(frame.ms, 20);
490 JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
493 if (jb_getinfo(jb, &jbinfo) != JB_OK) {
494 ast_test_status_update(test, "Failed to get jitterbuffer information\n");
497 JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
498 JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
499 JB_NUMERIC_TEST(jbinfo.frames_in, 40);
500 JB_NUMERIC_TEST(jbinfo.frames_out, 40);
501 JB_NUMERIC_TEST(jbinfo.frames_late, 0);
502 JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
503 JB_NUMERIC_TEST(jbinfo.frames_ooo, 10);
505 result = AST_TEST_PASS;
509 /* No need to do anything - this will put all frames on the 'free' list,
510 * so jb_destroy will dispose of them */
511 while (jb_getall(jb, &frame) == JB_OK) { }
520 /*! \internal \brief Insert frames into the jitter buffer for the lost frame tests */
521 static int test_jb_lost_frame_insertion(struct ast_test *test, struct jitterbuf *jb, enum jb_frame_type frame_type)
525 for (i = 0; i < 40; i++) {
529 if (jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 5) == JB_DROP) {
530 ast_test_status_update(test, "Jitter buffer dropped packet %d\n", i);
539 AST_TEST_DEFINE(jitterbuffer_lost_voice)
541 enum ast_test_result_state result = AST_TEST_FAIL;
542 struct jitterbuf *jb = NULL;
543 struct jb_frame frame;
544 struct jb_conf jbconf;
545 struct jb_info jbinfo;
550 info->name = "jitterbuffer_lost_voice";
551 info->category = "/main/jitterbuf/";
552 info->summary = "Tests missing frames in the jitterbuffer";
554 "Every 5th frame that would be sent to a jitter buffer is instead"
555 "dropped. When reading data from the jitter buffer, the jitter buffer"
556 "should interpolate the voice frame.";
557 return AST_TEST_NOT_RUN;
562 JB_TEST_BEGIN("jitterbuffer_lost_voice");
564 if (!(jb = jb_new())) {
565 ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
569 test_jb_populate_config(&jbconf);
570 if (jb_setconf(jb, &jbconf) != JB_OK) {
571 ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
575 if (test_jb_lost_frame_insertion(test, jb, JB_TYPE_VOICE)) {
579 for (i = 0; i < 40; i++) {
580 enum jb_return_code ret;
581 if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
582 /* If we didn't get an OK, make sure that it was an expected lost frame */
583 if (!((ret == JB_INTERP && i % 5 == 0) || (ret == JB_NOFRAME && i == 0))) {
584 ast_test_status_update(test,
585 "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
586 jitter_buffer_return_codes[ret], i);
590 JB_NUMERIC_TEST(frame.ms, 20);
591 JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
595 if (jb_getinfo(jb, &jbinfo) != JB_OK) {
596 ast_test_status_update(test, "Failed to get jitterbuffer information\n");
599 JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
600 /* Note: The first frame (at i = 0) never got added, so nothing existed at that point.
601 * Its neither dropped nor lost.
603 JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
604 JB_NUMERIC_TEST(jbinfo.frames_late, 0);
605 JB_NUMERIC_TEST(jbinfo.frames_lost, 7);
606 JB_NUMERIC_TEST(jbinfo.frames_in, 32);
607 JB_NUMERIC_TEST(jbinfo.frames_out, 32);
608 JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
610 result = AST_TEST_PASS;
614 /* No need to do anything - this will put all frames on the 'free' list,
615 * so jb_destroy will dispose of them */
616 while (jb_getall(jb, &frame) == JB_OK) { }
625 AST_TEST_DEFINE(jitterbuffer_lost_control)
627 enum ast_test_result_state result = AST_TEST_FAIL;
628 struct jitterbuf *jb = NULL;
629 struct jb_frame frame;
630 struct jb_conf jbconf;
631 struct jb_info jbinfo;
636 info->name = "jitterbuffer_lost_control";
637 info->category = "/main/jitterbuf/";
638 info->summary = "Tests missing frames in the jitterbuffer";
640 "Every 5th frame that would be sent to a jitter buffer is instead"
641 "dropped. When reading data from the jitter buffer, the jitter buffer"
642 "simply reports that no frame exists for that time slot";
643 return AST_TEST_NOT_RUN;
648 JB_TEST_BEGIN("jitterbuffer_lost_control");
650 if (!(jb = jb_new())) {
651 ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
655 test_jb_populate_config(&jbconf);
656 if (jb_setconf(jb, &jbconf) != JB_OK) {
657 ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
661 if (test_jb_lost_frame_insertion(test, jb, JB_TYPE_CONTROL)) {
665 for (i = 0; i < 40; i++) {
666 enum jb_return_code ret;
667 if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
668 /* If we didn't get an OK, make sure that it was an expected lost frame */
669 if (!(ret == JB_NOFRAME && i % 5 == 0)) {
670 ast_test_status_update(test,
671 "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
672 jitter_buffer_return_codes[ret], i);
676 JB_NUMERIC_TEST(frame.ms, 20);
677 JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
681 if (jb_getinfo(jb, &jbinfo) != JB_OK) {
682 ast_test_status_update(test, "Failed to get jitterbuffer information\n");
685 JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
686 /* Note: The first frame (at i = 0) never got added, so nothing existed at that point.
687 * Its neither dropped nor lost.
689 JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
690 JB_NUMERIC_TEST(jbinfo.frames_late, 0);
691 JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
692 JB_NUMERIC_TEST(jbinfo.frames_in, 32);
693 JB_NUMERIC_TEST(jbinfo.frames_out, 32);
694 JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
696 result = AST_TEST_PASS;
700 /* No need to do anything - this will put all frames on the 'free' list,
701 * so jb_destroy will dispose of them */
702 while (jb_getall(jb, &frame) == JB_OK) { }
711 /*! \internal \brief Insert frames into the jitter buffer for the late frame tests */
712 static int test_jb_late_frame_insertion(struct ast_test *test, struct jitterbuf *jb, enum jb_frame_type frame_type)
716 for (i = 0; i < 40; i++) {
719 if (jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 20) == JB_DROP) {
720 ast_test_status_update(test, "Jitter buffer dropped packet %d\n", (i+1));
725 if (jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 5) == JB_DROP) {
726 ast_test_status_update(test, "Jitter buffer dropped packet %d\n", i);
736 AST_TEST_DEFINE(jitterbuffer_late_voice)
738 enum ast_test_result_state result = AST_TEST_FAIL;
739 struct jitterbuf *jb = NULL;
740 struct jb_frame frame;
741 struct jb_info jbinfo;
742 struct jb_conf jbconf;
747 info->name = "jitterbuffer_late_voice";
748 info->category = "/main/jitterbuf/";
749 info->summary = "Tests sending frames to a jitter buffer that arrive late";
751 "Every 5th frame sent to a jitter buffer arrives late, but still in "
752 "order with respect to the previous and next packet";
753 return AST_TEST_NOT_RUN;
758 JB_TEST_BEGIN("jitterbuffer_late_voice");
760 if (!(jb = jb_new())) {
761 ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
765 test_jb_populate_config(&jbconf);
766 if (jb_setconf(jb, &jbconf) != JB_OK) {
767 ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
771 if (test_jb_late_frame_insertion(test, jb, JB_TYPE_VOICE)) {
775 for (i = 0; i < 40; i++) {
776 enum jb_return_code ret;
777 /* We should have a frame for each point in time */
778 if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
779 ast_test_status_update(test,
780 "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
781 jitter_buffer_return_codes[ret], i);
784 JB_NUMERIC_TEST(frame.ms, 20);
785 JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
788 if (jb_getinfo(jb, &jbinfo) != JB_OK) {
789 ast_test_status_update(test, "Failed to get jitterbuffer information\n");
792 JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
793 JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
794 JB_NUMERIC_TEST(jbinfo.frames_late, 0);
795 JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
796 JB_NUMERIC_TEST(jbinfo.frames_in, 40);
797 JB_NUMERIC_TEST(jbinfo.frames_out, 40);
798 JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
800 result = AST_TEST_PASS;
804 /* No need to do anything - this will put all frames on the 'free' list,
805 * so jb_destroy will dispose of them */
806 while (jb_getall(jb, &frame) == JB_OK) { }
815 AST_TEST_DEFINE(jitterbuffer_late_control)
817 enum ast_test_result_state result = AST_TEST_FAIL;
818 struct jitterbuf *jb = NULL;
819 struct jb_frame frame;
820 struct jb_info jbinfo;
821 struct jb_conf jbconf;
826 info->name = "jitterbuffer_late_control";
827 info->category = "/main/jitterbuf/";
828 info->summary = "Tests sending frames to a jitter buffer that arrive late";
830 "Every 5th frame sent to a jitter buffer arrives late, but still in "
831 "order with respect to the previous and next packet";
832 return AST_TEST_NOT_RUN;
837 JB_TEST_BEGIN("jitterbuffer_late_voice");
839 if (!(jb = jb_new())) {
840 ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
844 test_jb_populate_config(&jbconf);
845 if (jb_setconf(jb, &jbconf) != JB_OK) {
846 ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
850 if (test_jb_late_frame_insertion(test, jb, JB_TYPE_CONTROL)) {
854 for (i = 0; i < 40; i++) {
855 enum jb_return_code ret;
856 /* We should have a frame for each point in time */
857 if ((ret = jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN)) != JB_OK) {
858 ast_test_status_update(test,
859 "Unexpected jitter buffer return code [%s] when retrieving frame %d\n",
860 jitter_buffer_return_codes[ret], i);
863 JB_NUMERIC_TEST(frame.ms, 20);
864 JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
867 if (jb_getinfo(jb, &jbinfo) != JB_OK) {
868 ast_test_status_update(test, "Failed to get jitterbuffer information\n");
871 JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
872 JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
873 JB_NUMERIC_TEST(jbinfo.frames_late, 0);
874 JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
875 JB_NUMERIC_TEST(jbinfo.frames_in, 40);
876 JB_NUMERIC_TEST(jbinfo.frames_out, 40);
877 JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
879 result = AST_TEST_PASS;
883 /* No need to do anything - this will put all frames on the 'free' list,
884 * so jb_destroy will dispose of them */
885 while (jb_getall(jb, &frame) == JB_OK) { }
894 /*! \internal \brief Insert frames into the jitter buffer for the overflow tests */
895 static void test_jb_overflow_frame_insertion(struct jitterbuf *jb, enum jb_frame_type frame_type)
899 for (i = 0; i < 100; i++) {
900 jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 5);
904 AST_TEST_DEFINE(jitterbuffer_overflow_voice)
906 enum ast_test_result_state result = AST_TEST_FAIL;
907 struct jitterbuf *jb = NULL;
908 struct jb_frame frame;
909 struct jb_info jbinfo;
910 struct jb_conf jbconf;
915 info->name = "jitterbuffer_overflow_voice";
916 info->category = "/main/jitterbuf/";
917 info->summary = "Tests overfilling a jitter buffer with voice frames";
918 info->description = "Tests overfilling a jitter buffer with voice frames";
919 return AST_TEST_NOT_RUN;
924 JB_TEST_BEGIN("jitterbuffer_overflow_voice");
926 if (!(jb = jb_new())) {
927 ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
931 test_jb_populate_config(&jbconf);
932 if (jb_setconf(jb, &jbconf) != JB_OK) {
933 ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
937 test_jb_overflow_frame_insertion(jb, JB_TYPE_VOICE);
939 while (jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN) == JB_OK) {
940 JB_NUMERIC_TEST(frame.ms, 20);
941 JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
945 if (jb_getinfo(jb, &jbinfo) != JB_OK) {
946 ast_test_status_update(test, "Failed to get jitterbuffer information\n");
950 JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
951 JB_NUMERIC_TEST(jbinfo.frames_dropped, 49);
952 JB_NUMERIC_TEST(jbinfo.frames_out, 51);
953 JB_NUMERIC_TEST(jbinfo.frames_in, 51);
954 JB_NUMERIC_TEST(jbinfo.frames_late, 0);
955 /* Note that the last frame will be interpolated */
956 JB_NUMERIC_TEST(jbinfo.frames_lost, 1);
957 JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
959 result = AST_TEST_PASS;
963 /* No need to do anything - this will put all frames on the 'free' list,
964 * so jb_destroy will dispose of them */
965 while (jb_getall(jb, &frame) == JB_OK) { }
974 AST_TEST_DEFINE(jitterbuffer_overflow_control)
976 enum ast_test_result_state result = AST_TEST_FAIL;
977 struct jitterbuf *jb = NULL;
978 struct jb_frame frame;
979 struct jb_info jbinfo;
980 struct jb_conf jbconf;
985 info->name = "jitterbuffer_overflow_control";
986 info->category = "/main/jitterbuf/";
987 info->summary = "Tests overfilling a jitter buffer with control frames";
988 info->description = "Tests overfilling a jitter buffer with control frames";
989 return AST_TEST_NOT_RUN;
994 JB_TEST_BEGIN("jitterbuffer_overflow_control");
996 if (!(jb = jb_new())) {
997 ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
1001 test_jb_populate_config(&jbconf);
1002 if (jb_setconf(jb, &jbconf) != JB_OK) {
1003 ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
1007 test_jb_overflow_frame_insertion(jb, JB_TYPE_CONTROL);
1009 while (jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN) == JB_OK) {
1010 JB_NUMERIC_TEST(frame.ms, 20);
1011 JB_NUMERIC_TEST(frame.ts, i * 20 - jb->info.resync_offset);
1015 if (jb_getinfo(jb, &jbinfo) != JB_OK) {
1016 ast_test_status_update(test, "Failed to get jitterbuffer information\n");
1020 JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
1021 JB_NUMERIC_TEST(jbinfo.frames_dropped, 49);
1022 JB_NUMERIC_TEST(jbinfo.frames_out, 51);
1023 JB_NUMERIC_TEST(jbinfo.frames_in, 51);
1024 JB_NUMERIC_TEST(jbinfo.frames_late, 0);
1025 JB_NUMERIC_TEST(jbinfo.frames_lost, 0);
1026 JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
1028 result = AST_TEST_PASS;
1032 /* No need to do anything - this will put all frames on the 'free' list,
1033 * so jb_destroy will dispose of them */
1034 while (jb_getall(jb, &frame) == JB_OK) { }
1043 /*! \internal \brief Insert frames into the jitter buffer for the resynch tests */
1044 static void test_jb_resynch_frame_insertion(struct jitterbuf *jb, enum jb_frame_type frame_type)
1048 for (i = 0; i < 20; i++) {
1049 jb_put(jb, NULL, frame_type, 20, i * 20, i * 20 + 5);
1052 for (i = 20; i < 40; i++) {
1053 jb_put(jb, NULL, frame_type, 20, i * 20 + 500, i * 20 + 5);
1057 AST_TEST_DEFINE(jitterbuffer_resynch_control)
1059 enum ast_test_result_state result = AST_TEST_FAIL;
1060 struct jitterbuf *jb = NULL;
1061 struct jb_frame frame;
1062 struct jb_info jbinfo;
1063 struct jb_conf jbconf;
1064 int interpolated_frames = 0;
1069 info->name = "jitterbuffer_resynch_control";
1070 info->category = "/main/jitterbuf/";
1071 info->summary = "Tests sending control frames that force a resynch";
1072 info->description = "Control frames are sent to a jitter buffer. After some "
1073 "number of frames, the source timestamps jump, forcing a resync of "
1074 "the jitter buffer. Since the frames are control, the resync happens "
1076 return AST_TEST_NOT_RUN;
1081 JB_TEST_BEGIN("jitterbuffer_resynch_control");
1083 if (!(jb = jb_new())) {
1084 ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
1088 test_jb_populate_config(&jbconf);
1089 jbconf.resync_threshold = 200;
1090 if (jb_setconf(jb, &jbconf) != JB_OK) {
1091 ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
1095 test_jb_resynch_frame_insertion(jb, JB_TYPE_CONTROL);
1097 for (i = 0; i <= 40; i++) {
1098 if (jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN) == JB_INTERP) {
1099 ++interpolated_frames;
1103 if (jb_getinfo(jb, &jbinfo) != JB_OK) {
1104 ast_test_status_update(test, "Failed to get jitterbuffer information\n");
1107 /* With control frames, a resync happens automatically */
1108 JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
1109 JB_NUMERIC_TEST(jbinfo.frames_dropped, 0);
1110 JB_NUMERIC_TEST(jbinfo.frames_out, 40);
1111 JB_NUMERIC_TEST(jbinfo.frames_in, 40);
1112 /* Verify that each of the interpolated frames is counted */
1113 JB_NUMERIC_TEST(jbinfo.frames_lost, interpolated_frames);
1114 JB_NUMERIC_TEST(jbinfo.frames_late, 0);
1115 JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
1117 result = AST_TEST_PASS;
1121 /* No need to do anything - this will put all frames on the 'free' list,
1122 * so jb_destroy will dispose of them */
1123 while (jb_getall(jb, &frame) == JB_OK) { }
1132 AST_TEST_DEFINE(jitterbuffer_resynch_voice)
1134 enum ast_test_result_state result = AST_TEST_FAIL;
1135 struct jitterbuf *jb = NULL;
1136 struct jb_frame frame;
1137 struct jb_info jbinfo;
1138 struct jb_conf jbconf;
1139 int interpolated_frames = 0;
1144 info->name = "jitterbuffer_resynch_voice";
1145 info->category = "/main/jitterbuf/";
1146 info->summary = "Tests sending voice frames that force a resynch";
1147 info->description = "Voice frames are sent to a jitter buffer. After some "
1148 "number of frames, the source timestamps jump, forcing a resync of "
1149 "the jitter buffer. Since the frames are voice, the resync happens "
1150 "after observing three packets that break the resync threshold.";
1151 return AST_TEST_NOT_RUN;
1156 JB_TEST_BEGIN("jitterbuffer_resynch_voice");
1158 if (!(jb = jb_new())) {
1159 ast_test_status_update(test, "Failed to allocate memory for jitterbuffer\n");
1163 test_jb_populate_config(&jbconf);
1164 jbconf.resync_threshold = 200;
1165 if (jb_setconf(jb, &jbconf) != JB_OK) {
1166 ast_test_status_update(test, "Failed to set jitterbuffer configuration\n");
1170 test_jb_resynch_frame_insertion(jb, JB_TYPE_VOICE);
1172 for (i = 0; i <= 40; i++) {
1173 if (jb_get(jb, &frame, i * 20 + 5, DEFAULT_CODEC_INTERP_LEN) == JB_INTERP) {
1174 ++interpolated_frames;
1178 if (jb_getinfo(jb, &jbinfo) != JB_OK) {
1179 ast_test_status_update(test, "Failed to get jitterbuffer information\n");
1182 /* The first three packets before the resync should be dropped */
1183 JB_INFO_PRINT_FRAME_DEBUG(jbinfo);
1184 JB_NUMERIC_TEST(jbinfo.frames_dropped, 3);
1185 JB_NUMERIC_TEST(jbinfo.frames_out, 37);
1186 JB_NUMERIC_TEST(jbinfo.frames_in, 37);
1187 /* Verify that each of the interpolated frames is counted */
1188 JB_NUMERIC_TEST(jbinfo.frames_lost, interpolated_frames);
1189 JB_NUMERIC_TEST(jbinfo.frames_late, 0);
1190 JB_NUMERIC_TEST(jbinfo.frames_ooo, 0);
1193 result = AST_TEST_PASS;
1197 /* No need to do anything - this will put all frames on the 'free' list,
1198 * so jb_destroy will dispose of them */
1199 while (jb_getall(jb, &frame) == JB_OK) { }
1208 static int unload_module(void)
1210 AST_TEST_UNREGISTER(jitterbuffer_nominal_voice_frames);
1211 AST_TEST_UNREGISTER(jitterbuffer_nominal_control_frames);
1212 AST_TEST_UNREGISTER(jitterbuffer_out_of_order_voice);
1213 AST_TEST_UNREGISTER(jitterbuffer_out_of_order_control);
1214 AST_TEST_UNREGISTER(jitterbuffer_lost_voice);
1215 AST_TEST_UNREGISTER(jitterbuffer_lost_control);
1216 AST_TEST_UNREGISTER(jitterbuffer_late_voice);
1217 AST_TEST_UNREGISTER(jitterbuffer_late_control);
1218 AST_TEST_UNREGISTER(jitterbuffer_overflow_voice);
1219 AST_TEST_UNREGISTER(jitterbuffer_overflow_control);
1220 AST_TEST_UNREGISTER(jitterbuffer_resynch_voice);
1221 AST_TEST_UNREGISTER(jitterbuffer_resynch_control);
1225 static int load_module(void)
1227 /* Nominal - put / get frames */
1228 AST_TEST_REGISTER(jitterbuffer_nominal_voice_frames);
1229 AST_TEST_REGISTER(jitterbuffer_nominal_control_frames);
1231 /* Out of order frame arrival */
1232 AST_TEST_REGISTER(jitterbuffer_out_of_order_voice);
1233 AST_TEST_REGISTER(jitterbuffer_out_of_order_control);
1235 /* Lost frame arrival */
1236 AST_TEST_REGISTER(jitterbuffer_lost_voice);
1237 AST_TEST_REGISTER(jitterbuffer_lost_control);
1239 /* Late frame arrival */
1240 AST_TEST_REGISTER(jitterbuffer_late_voice);
1241 AST_TEST_REGISTER(jitterbuffer_late_control);
1243 /* Buffer overflow */
1244 AST_TEST_REGISTER(jitterbuffer_overflow_voice);
1245 AST_TEST_REGISTER(jitterbuffer_overflow_control);
1247 /* Buffer resynch */
1248 AST_TEST_REGISTER(jitterbuffer_resynch_voice);
1249 AST_TEST_REGISTER(jitterbuffer_resynch_control);
1251 return AST_MODULE_LOAD_SUCCESS;
1254 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Jitter Buffer Tests");