Asterisk - The Open Source Telephony Project GIT-master-70eff7f
Loading...
Searching...
No Matches
test_res_rtp.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2019, Sangoma, Inc.
5 *
6 * Ben Ford <bford@sangoma.com>
7 *
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.
13 *
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.
17 */
18
19/*!
20 * \file
21 * \brief RTP/RTCP Unit Tests
22 *
23 * \author Ben Ford <bford@digium.com>
24 *
25 */
26
27/*** MODULEINFO
28 <depend>TEST_FRAMEWORK</depend>
29 <support_level>core</support_level>
30 ***/
31
32#include "asterisk.h"
33
34#include "asterisk/module.h"
35#include "asterisk/test.h"
36#include "asterisk/rtp_engine.h"
39#include <assert.h>
40#include <sched.h>
41
43 TEST_TYPE_NONE = 0, /* No special setup required */
44 TEST_TYPE_NACK, /* Enable NACK */
45 TEST_TYPE_REMB, /* Enable REMB */
46 TEST_TYPE_STD_RTCP, /* Let the stack do RTCP */
47};
48
55
56static int test_init_rtp_instances(struct ast_rtp_instance **instance1,
57 struct ast_rtp_instance **instance2, struct ast_sched_context *test_sched,
58 enum test_type type)
59{
60 struct ast_sockaddr addr1;
61 struct ast_sockaddr addr2;
63
64 ast_sockaddr_parse(&addr1, "127.0.0.1", 0);
65 ast_sockaddr_parse(&addr2, "127.0.0.1", 0);
66
67 *instance1 = ast_rtp_instance_new("asterisk", test_sched, &addr1, "instance1");
68 *instance2 = ast_rtp_instance_new("asterisk", test_sched, &addr2, "instance2");
69 if (!instance1 || !instance2) {
70 return -1;
71 }
72
73 ast_rtp_instance_set_channel_id(*instance1, "instance1");
74 ast_rtp_instance_set_channel_id(*instance2, "instance2");
75
76 if (type == TEST_TYPE_STD_RTCP) {
78 }
79
81 AST_RTP_PROPERTY_RTCP, rtcp_type);
83 AST_RTP_PROPERTY_RTCP, rtcp_type);
84
85 if (type == TEST_TYPE_NACK) {
90 } else if (type == TEST_TYPE_REMB) {
93 }
94
95 ast_rtp_instance_get_local_address(*instance1, &addr1);
96 ast_rtp_instance_set_remote_address(*instance2, &addr1);
97
98 ast_rtp_instance_get_local_address(*instance2, &addr2);
99 ast_rtp_instance_set_remote_address(*instance1, &addr2);
100
101 ast_rtp_instance_reset_test_engine(*instance1);
102
103 ast_rtp_instance_activate(*instance1);
104 ast_rtp_instance_activate(*instance2);
105
106 return 0;
107}
108
109static void test_write_frames(struct ast_rtp_instance *instance, int seqno, int num)
110{
111 char data[320] = "";
112 struct ast_frame frame_out = {
114 .subclass.format = ast_format_ulaw,
115 .data.ptr = data,
116 .datalen = 160,
117 };
118 int index;
119
121
122 for (index = 0; index < num; index++) {
123 frame_out.seqno = seqno + index;
124 ast_rtp_instance_write(instance, &frame_out);
125 }
126}
127
128static void test_read_frames(struct ast_rtp_instance *instance, int num)
129{
130 struct ast_frame *frame_in;
131 int index;
132
133 for (index = 0; index < num; index++) {
134 frame_in = ast_rtp_instance_read(instance, 0);
135 if (frame_in) {
136 ast_frfree(frame_in);
137 }
138 }
139}
140
141static void test_write_and_read_frames(struct ast_rtp_instance *instance1,
142 struct ast_rtp_instance *instance2, int seqno, int num)
143{
144 test_write_frames(instance1, seqno, num);
145 test_read_frames(instance2, num);
146}
147
148
149/*
150 * Unfortunately, we can't use usleep() to create
151 * packet spacing because there are signals in use
152 * which cause usleep to immediately return. Instead
153 * we have to spin. :(
154 */
155static void SLEEP_SPINNER(int ms)
156{
157 struct timeval a = ast_tvnow();
158
159 while(1) {
160 sched_yield();
161 if (ast_remaining_ms(a, ms) <= 0) {
162 break;
163 }
164 }
165}
166
167/*
168 * This function is NOT really a reliable implementation.
169 * Its purpose is only to aid in code development in res_rtp_asterisk.
170 */
172 struct ast_rtp_instance *instance2, int howlong, int rtcp_interval)
173{
174 char data[320] = "";
175 int pktinterval = 20;
176
177 struct ast_frame frame_out1 = {
179 .subclass.format = ast_format_ulaw,
180 .seqno = 4556,
181 .data.ptr = data,
182 .datalen = 160,
183 .samples = 1,
184 .len = pktinterval,
185 .ts = 4622295,
186 };
187 struct ast_frame frame_out2 = {
189 .subclass.format = ast_format_ulaw,
190 .seqno = 6554,
191 .data.ptr = data,
192 .datalen = 160,
193 .samples = 1,
194 .len = pktinterval,
195 .ts = 8622295,
196 };
197 struct ast_frame *frame_in1;
198 struct ast_frame *frame_in2;
199 int index;
200 int num;
201 int rtcpnum;
202 int reverse = 1;
203 int send_rtcp = 0;
204
205 num = howlong / pktinterval;
206
207 rtcpnum = rtcp_interval / pktinterval;
208
213
214 for (index = 0; index < num; index++) {
215 struct timeval start = ast_tvnow();
216 time_t ms;
217
218 if (index == 1) {
223 }
224 frame_out1.seqno += index;
225 frame_out1.delivery = start;
226 frame_out1.ts += frame_out1.len;
227 ast_rtp_instance_write(instance1, &frame_out1);
228
229 if (send_rtcp && index && (index % rtcpnum == 0)) {
230 ast_rtp_instance_queue_report(instance1);
231 }
232
233 frame_in2 = ast_rtp_instance_read(instance2, 0);
234 ast_frfree(frame_in2);
235 frame_in2 = ast_rtp_instance_read(instance2, 1);
236 ast_frfree(frame_in2);
237
238 if (reverse) {
239 frame_out2.seqno += index;
240 frame_out2.delivery = ast_tvnow();
241 frame_out2.ts += frame_out2.len;
242 ast_rtp_instance_write(instance2, &frame_out2);
243
244 if (send_rtcp && index && (index % rtcpnum == 0)) {
245 ast_rtp_instance_queue_report(instance2);
246 }
247
248 frame_in1 = ast_rtp_instance_read(instance1, 0);
249 ast_frfree(frame_in1);
250 frame_in1 = ast_rtp_instance_read(instance1, 1);
251 ast_frfree(frame_in1);
252
253 }
254
255 ms = frame_out1.len - ast_tvdiff_ms(ast_tvnow(),start);
256 ms += (index % 2 ? 5 : 12);
257 ms += (index % 3 ? 2 : 30);
258 SLEEP_SPINNER(ms);
259 }
260}
261
262AST_TEST_DEFINE(nack_no_packet_loss)
263{
267
268 switch (cmd) {
269 case TEST_INIT:
270 info->name = "nack_no_packet_loss";
271 info->category = "/res/res_rtp/";
272 info->summary = "nack no packet loss unit test";
273 info->description =
274 "Tests sending packets with no packet loss and "
275 "validates that the send buffer stores sent packets "
276 "and the receive buffer is empty";
277 return AST_TEST_NOT_RUN;
278 case TEST_EXECUTE:
279 break;
280 }
281
282 test_sched = ast_sched_context_create();
283
284 if ((test_init_rtp_instances(&instance1, &instance2, test_sched, TEST_TYPE_NACK)) < 0) {
285 ast_log(LOG_ERROR, "Failed to initialize test!\n");
286 return AST_TEST_FAIL;
287 }
288
289 test_write_and_read_frames(instance1, instance2, 1000, 10);
290
291 ast_test_validate(test, ast_rtp_instance_get_send_buffer_count(instance1) == 10,
292 "Send buffer did not have the expected count of 10");
293
294 ast_test_validate(test, ast_rtp_instance_get_recv_buffer_count(instance2) == 0,
295 "Receive buffer did not have the expected count of 0");
296
297 return AST_TEST_PASS;
298}
299
300AST_TEST_DEFINE(nack_nominal)
301{
305
306 switch (cmd) {
307 case TEST_INIT:
308 info->name = "nack_nominal";
309 info->category = "/res/res_rtp/";
310 info->summary = "nack nominal unit test";
311 info->description =
312 "Tests sending packets with some packet loss and "
313 "validates that a NACK request is sent on reaching "
314 "the triggering amount of lost packets";
315 return AST_TEST_NOT_RUN;
316 case TEST_EXECUTE:
317 break;
318 }
319
320 test_sched = ast_sched_context_create();
321
322 if ((test_init_rtp_instances(&instance1, &instance2, test_sched, TEST_TYPE_NACK)) < 0) {
323 ast_log(LOG_ERROR, "Failed to initialize test!\n");
324 return AST_TEST_FAIL;
325 }
326
327 /* Start normally */
328 test_write_and_read_frames(instance1, instance2, 1000, 10);
329
330 /* Set the number of packets to drop when we send them next */
331 ast_rtp_instance_drop_packets(instance2, 10);
332 test_write_and_read_frames(instance1, instance2, 1010, 10);
333
334 /* Send enough packets to reach the NACK trigger */
335 test_write_and_read_frames(instance1, instance2, 1020, ast_rtp_instance_get_recv_buffer_max(instance2) / 2);
336
337 /* This needs to be read as RTCP */
338 test_read_frames(instance1, 1);
339
340 /* We should have the missing packets to read now */
341 test_read_frames(instance2, 10);
342
343 ast_test_validate(test, ast_rtp_instance_get_recv_buffer_count(instance2) == 0,
344 "Receive buffer did not have the expected count of 0");
345
346 return AST_TEST_PASS;
347}
348
349AST_TEST_DEFINE(nack_overflow)
350{
354 int max_packets;
355
356 switch (cmd) {
357 case TEST_INIT:
358 info->name = "nack_overflow";
359 info->category = "/res/res_rtp/";
360 info->summary = "nack overflow unit test";
361 info->description =
362 "Tests that when the buffer hits its capacity, we "
363 "queue all the packets we currently have stored";
364 return AST_TEST_NOT_RUN;
365 case TEST_EXECUTE:
366 break;
367 }
368
369 test_sched = ast_sched_context_create();
370
371 if ((test_init_rtp_instances(&instance1, &instance2, test_sched, TEST_TYPE_NACK)) < 0) {
372 ast_log(LOG_ERROR, "Failed to initialize test!\n");
373 return AST_TEST_FAIL;
374 }
375
376 /* Start normally */
377 test_write_and_read_frames(instance1, instance2, 1000, 10);
378
379 /* Send enough packets to fill the buffer */
380 max_packets = ast_rtp_instance_get_recv_buffer_max(instance2);
381 test_write_and_read_frames(instance1, instance2, 1020, max_packets);
382
383 ast_test_validate(test, ast_rtp_instance_get_recv_buffer_count(instance2) == max_packets,
384 "Receive buffer did not have the expected count of max buffer size");
385
386 /* Send the packet that will overflow the buffer */
387 test_write_and_read_frames(instance1, instance2, 1020 + max_packets, 1);
388
389 ast_test_validate(test, ast_rtp_instance_get_recv_buffer_count(instance2) == 0,
390 "Receive buffer did not have the expected count of 0");
391
392 return AST_TEST_PASS;
393}
394
395AST_TEST_DEFINE(lost_packet_stats_nominal)
396{
400 struct ast_rtp_instance_stats stats = { 0, };
402
403 switch (cmd) {
404 case TEST_INIT:
405 info->name = "lost_packet_stats_nominal";
406 info->category = "/res/res_rtp/";
407 info->summary = "lost packet stats nominal unit test";
408 info->description =
409 "Tests that when some packets are lost, we calculate that "
410 "loss correctly when doing lost packet statistics";
411 return AST_TEST_NOT_RUN;
412 case TEST_EXECUTE:
413 break;
414 }
415
416 test_sched = ast_sched_context_create();
417
418 if ((test_init_rtp_instances(&instance1, &instance2, test_sched, TEST_TYPE_NONE)) < 0) {
419 ast_log(LOG_ERROR, "Failed to initialize test!\n");
420 return AST_TEST_FAIL;
421 }
422
423 /* Start normally */
424 test_write_and_read_frames(instance1, instance2, 1000, 10);
425
426 /* Send some more packets, but with a gap */
427 test_write_and_read_frames(instance1, instance2, 1015, 5);
428
429 /* Send a RR to calculate lost packet statistics. We should be missing 5 packets */
430 ast_rtp_instance_queue_report(instance1);
431 test_write_frames(instance2, 1000, 1);
432
433 /* Check RTCP stats to see if we got the expected packet loss count */
434 ast_rtp_instance_get_stats(instance2, &stats, stat);
435 ast_test_validate(test, stats.rxploss == 5 && stats.local_minrxploss == 5 &&
436 stats.local_maxrxploss == 5, "Condition of 5 lost packets was not met");
437
438 /* Drop 3 before writing 5 more */
439 test_write_and_read_frames(instance1, instance2, 1023, 5);
440
441 ast_rtp_instance_queue_report(instance1);
442 test_write_frames(instance2, 1001, 1);
443 ast_rtp_instance_get_stats(instance2, &stats, stat);
444
445 /* Should now be missing 8 total packets with a change in min */
446 ast_test_validate(test, stats.rxploss == 8 && stats.local_minrxploss == 3 &&
447 stats.local_maxrxploss == 5);
448
449 /* Write 5 more with no gaps */
450 test_write_and_read_frames(instance1, instance2, 1028, 5);
451
452 ast_rtp_instance_queue_report(instance1);
453 test_write_frames(instance2, 1002, 1);
454 ast_rtp_instance_get_stats(instance2, &stats, stat);
455
456 /* Should still only be missing 8 total packets */
457 ast_test_validate(test, stats.rxploss == 8 && stats.local_minrxploss == 3 &&
458 stats.local_maxrxploss == 5);
459
460 /* Now drop 1, write another 5, drop 8, and then write 5 */
461 test_write_and_read_frames(instance1, instance2, 1034, 5);
462 test_write_and_read_frames(instance1, instance2, 1047, 5);
463
464 ast_rtp_instance_queue_report(instance1);
465 test_write_frames(instance2, 1003, 1);
466 ast_rtp_instance_get_stats(instance2, &stats, stat);
467
468 /* Now it should be missing 17 total packets, with a change in max */
469 ast_test_validate(test, stats.rxploss == 17 && stats.local_minrxploss == 3 &&
470 stats.local_maxrxploss == 9);
471
472 return AST_TEST_PASS;
473}
474
475AST_TEST_DEFINE(remb_nominal)
476{
480 RAII_VAR(struct ast_frame *, frame_in, NULL, ast_frfree);
481 /* Use the structure softmix_remb_collector uses to store information for REMB */
482 struct ast_rtp_rtcp_feedback feedback = {
484 .remb.br_exp = 0,
485 .remb.br_mantissa = 1000,
486 };
487 struct ast_frame frame_out = {
489 .subclass.integer = AST_RTP_RTCP_PSFB,
490 .data.ptr = &feedback,
491 .datalen = sizeof(feedback),
492 };
493 struct ast_rtp_rtcp_feedback *received_feedback;
494
495 switch (cmd) {
496 case TEST_INIT:
497 info->name = "remb_nominal";
498 info->category = "/res/res_rtp/";
499 info->summary = "remb nominal unit test";
500 info->description =
501 "Tests sending and receiving a REMB packet";
502 return AST_TEST_NOT_RUN;
503 case TEST_EXECUTE:
504 break;
505 }
506
507 test_sched = ast_sched_context_create();
508
509 if ((test_init_rtp_instances(&instance1, &instance2, test_sched, TEST_TYPE_REMB)) < 0) {
510 ast_log(LOG_ERROR, "Failed to initialize test!\n");
511 return AST_TEST_FAIL;
512 }
513
514 /* The schedid must be 0 or greater, so let's do that now */
515 ast_rtp_instance_set_schedid(instance1, 0);
516
517 ast_rtp_instance_write(instance1, &frame_out);
518
519 /* Verify the high level aspects of the frame */
520 frame_in = ast_rtp_instance_read(instance2, 0);
521 ast_test_validate(test, frame_in != NULL, "Did not receive a REMB frame");
522 ast_test_validate(test, frame_in->frametype == AST_FRAME_RTCP,
523 "REMB frame did not have the expected frametype");
524 ast_test_validate(test, frame_in->subclass.integer == AST_RTP_RTCP_PSFB,
525 "REMB frame did not have the expected subclass integer");
526
527 /* Verify the actual REMB information itself */
528 received_feedback = frame_in->data.ptr;
529 ast_test_validate(test, received_feedback->fmt == AST_RTP_RTCP_FMT_REMB,
530 "REMB frame did not have the expected feedback format");
531 ast_test_validate(test, received_feedback->remb.br_exp == feedback.remb.br_exp,
532 "REMB received exponent did not match sent exponent");
533 ast_test_validate(test, received_feedback->remb.br_mantissa == feedback.remb.br_mantissa,
534 "REMB received mantissa did not match sent mantissa");
535
536 return AST_TEST_PASS;
537}
538
539AST_TEST_DEFINE(sr_rr_nominal)
540{
544 RAII_VAR(struct ast_frame *, frame_in, NULL, ast_frfree);
545
546 switch (cmd) {
547 case TEST_INIT:
548 info->name = "sr_rr_nominal";
549 info->category = "/res/res_rtp/";
550 info->summary = "SR/RR nominal unit test";
551 info->description =
552 "Tests sending SR/RR and receiving it; includes SDES";
553 return AST_TEST_NOT_RUN;
554 case TEST_EXECUTE:
555 break;
556 }
557
558 test_sched = ast_sched_context_create();
559
560 if ((test_init_rtp_instances(&instance1, &instance2, test_sched, TEST_TYPE_NONE)) < 0) {
561 ast_log(LOG_ERROR, "Failed to initialize test!\n");
562 return AST_TEST_FAIL;
563 }
564
565 test_write_and_read_frames(instance1, instance2, 1000, 10);
566
567 /*
568 * Set the send_report flag so we send a sender report instead of normal RTP. We
569 * also need to ensure that SDES processed.
570 */
571 ast_rtp_instance_queue_report(instance1);
572 test_write_frames(instance1, 1010, 1);
573
574 frame_in = ast_rtp_instance_read(instance2, 0);
575 ast_test_validate(test, frame_in->frametype == AST_FRAME_RTCP,
576 "Sender report frame did not have the expected frametype");
577 ast_test_validate(test, frame_in->subclass.integer == AST_RTP_RTCP_SR,
578 "Sender report frame did not have the expected subclass integer");
579 ast_test_validate(test, ast_rtp_instance_get_sdes_received(instance2) == 1,
580 "SDES was never processed for sender report");
581
582 ast_frfree(frame_in);
583
584 /* Set the send_report flag so we send a receiver report instead of normal RTP */
585 ast_rtp_instance_queue_report(instance1);
586 test_write_frames(instance1, 1010, 1);
587
588 frame_in = ast_rtp_instance_read(instance2, 0);
589 ast_test_validate(test, frame_in->frametype == AST_FRAME_RTCP,
590 "Receiver report frame did not have the expected frametype");
591 ast_test_validate(test, frame_in->subclass.integer == AST_RTP_RTCP_RR,
592 "Receiver report frame did not have the expected subclass integer");
593
594 return AST_TEST_PASS;
595}
596
597AST_TEST_DEFINE(fir_nominal)
598{
602 RAII_VAR(struct ast_frame *, frame_in, NULL, ast_frfree);
603 struct ast_frame frame_out = {
605 .subclass.integer = AST_CONTROL_VIDUPDATE,
606 };
607
608 switch (cmd) {
609 case TEST_INIT:
610 info->name = "fir_nominal";
611 info->category = "/res/res_rtp/";
612 info->summary = "fir nominal unit test";
613 info->description =
614 "Tests sending and receiving a FIR packet";
615 return AST_TEST_NOT_RUN;
616 case TEST_EXECUTE:
617 break;
618 }
619
620 test_sched = ast_sched_context_create();
621
622 if ((test_init_rtp_instances(&instance1, &instance2, test_sched, TEST_TYPE_NONE)) < 0) {
623 ast_log(LOG_ERROR, "Failed to initialize test!\n");
624 return AST_TEST_FAIL;
625 }
626
627 /* Send some packets to learn SSRC */
628 test_write_and_read_frames(instance2, instance1, 1000, 10);
629
630 /* The schedid must be 0 or greater, so let's do that now */
631 ast_rtp_instance_set_schedid(instance1, 0);
632
633 /*
634 * This will not directly write a frame out, but cause Asterisk to see it as a FIR
635 * request, which will then trigger rtp_write_rtcp_fir, which will send out the
636 * appropriate packet.
637 */
638 ast_rtp_instance_write(instance1, &frame_out);
639
640 /*
641 * We only receive one frame, the FIR request. It won't have a subclass integer of
642 * 206 (PSFB) because ast_rtcp_interpret sets it to 18 (AST_CONTROL_VIDUPDATE), so
643 * check for that.
644 */
645 frame_in = ast_rtp_instance_read(instance2, 0);
646 ast_test_validate(test, frame_in != NULL, "Did not receive a FIR frame");
647 ast_test_validate(test, frame_in->frametype == AST_FRAME_CONTROL,
648 "FIR frame did not have the expected frametype");
649 ast_test_validate(test, frame_in->subclass.integer == AST_CONTROL_VIDUPDATE,
650 "FIR frame did not have the expected subclass integer");
651
652 return AST_TEST_PASS;
653}
654
655/*
656 * This test should not normally be run. Its only purpose is to
657 * aid in code development.
658 */
660{
664
665 switch (cmd) {
666 case TEST_INIT:
667 info->name = "mes";
668 info->category = "/res/res_rtp/";
669 info->summary = "Media Experience Score";
670 info->description =
671 "Tests calculation of Media Experience Score (only run by explicit request)";
672 info->explicit_only = 1;
673 return AST_TEST_NOT_RUN;
674 case TEST_EXECUTE:
675 break;
676 }
677
678 test_sched = ast_sched_context_create();
679 ast_sched_start_thread(test_sched);
680
681 if ((test_init_rtp_instances(&instance1, &instance2,
682 test_sched, TEST_TYPE_NONE)) < 0) {
683 ast_log(LOG_ERROR, "Failed to initialize test!\n");
684 return AST_TEST_FAIL;
685 }
686
688 instance1, instance2, 1000, 5000);
689
690 return AST_TEST_PASS;
691}
692
693AST_TEST_DEFINE(payload_merge_abandoned_offer)
694{
699 int offered_initialized = 0;
700 int active_initialized = 0;
701
702 switch (cmd) {
703 case TEST_INIT:
704 info->name = "payload_merge_abandoned_offer";
705 info->category = "/res/res_rtp/";
706 info->summary = "Verify mappings retained after an uncommitted payload merge";
707 info->description =
708 "Characterizes the state left behind when an SDP offer's payloads "
709 "are merged into an active RTP mapping but no later copy commits "
710 "or rolls back that offer.";
711 return AST_TEST_NOT_RUN;
712 case TEST_EXECUTE:
713 break;
714 }
715
717 ast_test_status_update(test, "Unable to initialize RTP codecs\n");
719 goto cleanup;
720 }
721 offered_initialized = 1;
723 ast_test_status_update(test, "Unable to initialize RTP codecs\n");
725 goto cleanup;
726 }
727 active_initialized = 1;
728
729 /* Use dynamic PTs so lookup cannot fall back to the global static table. */
731 &active, NULL, 96, "audio", "PCMU", 0)
733 &offered, NULL, 97, "audio", "PCMA", 0)) {
734 ast_test_status_update(test, "Unable to create dynamic RTP mappings\n");
736 goto cleanup;
737 }
738 ast_rtp_codecs_payloads_xover(&active, &active, NULL);
739 ast_rtp_codecs_payloads_xover(&offered, &offered, NULL);
740
741 ast_rtp_codecs_payloads_merge(&offered, &active, NULL);
742
743 payload = ast_rtp_codecs_get_payload(&active, 96);
744 if (!payload || !payload->asterisk_format
746 ast_test_status_update(test, "Active PCMU payload 96 was not retained by merge\n");
748 }
750
751 payload = ast_rtp_codecs_get_payload(&active, 97);
752 if (!payload || !payload->asterisk_format
754 ast_test_status_update(test, "Offered PCMA payload 97 was not retained after merge\n");
756 }
758
759cleanup:
760 if (active_initialized) {
762 }
763 if (offered_initialized) {
765 }
766 return result;
767}
768
769AST_TEST_DEFINE(payload_merge_preserves_preferences)
770{
773 RAII_VAR(struct ast_format *, preferred, NULL, ao2_cleanup);
775 int offered_initialized = 0;
776 int active_initialized = 0;
777
778 switch (cmd) {
779 case TEST_INIT:
780 info->name = "payload_merge_preserves_preferences";
781 info->category = "/res/res_rtp/";
782 info->summary = "Verify a payload merge preserves active preferences";
783 info->description =
784 "Verifies that merging an SDP offer's provisional payload mappings "
785 "updates framing needed to generate the SDP answer without changing "
786 "the active preferred format or preferred DTMF metadata before the "
787 "offer is committed.";
788 return AST_TEST_NOT_RUN;
789 case TEST_EXECUTE:
790 break;
791 }
792
794 ast_test_status_update(test, "Unable to initialize RTP codecs\n");
796 goto cleanup;
797 }
798 offered_initialized = 1;
800 ast_test_status_update(test, "Unable to initialize RTP codecs\n");
802 goto cleanup;
803 }
804 active_initialized = 1;
805
808 ast_rtp_codecs_set_framing(&active, 20);
810 ast_rtp_codecs_set_preferred_dtmf_format(&offered, 110, 16000);
811 ast_rtp_codecs_set_framing(&offered, 30);
812
813 ast_rtp_codecs_payloads_merge(&offered, &active, NULL);
814
815 preferred = ast_rtp_codecs_get_preferred_format(&active);
816 if (!preferred
818 ast_test_status_update(test, "Payload merge changed the active preferred format\n");
820 }
824 "Payload merge changed the active preferred DTMF metadata\n");
826 }
827 if (ast_rtp_codecs_get_framing(&active) != 30) {
828 ast_test_status_update(test, "Payload merge did not update offered framing\n");
830 }
831
832cleanup:
833 if (active_initialized) {
835 }
836 if (offered_initialized) {
838 }
839 return result;
840}
841
842static int unload_module(void)
843{
844 AST_TEST_UNREGISTER(payload_merge_preserves_preferences);
845 AST_TEST_UNREGISTER(payload_merge_abandoned_offer);
847 AST_TEST_UNREGISTER(nack_no_packet_loss);
848 AST_TEST_UNREGISTER(nack_nominal);
849 AST_TEST_UNREGISTER(nack_overflow);
850 AST_TEST_UNREGISTER(lost_packet_stats_nominal);
851 AST_TEST_UNREGISTER(remb_nominal);
852 AST_TEST_UNREGISTER(sr_rr_nominal);
853 AST_TEST_UNREGISTER(fir_nominal);
854 return 0;
855}
856
857static int load_module(void)
858{
859 AST_TEST_REGISTER(nack_no_packet_loss);
860 AST_TEST_REGISTER(nack_nominal);
861 AST_TEST_REGISTER(nack_overflow);
862 AST_TEST_REGISTER(lost_packet_stats_nominal);
863 AST_TEST_REGISTER(remb_nominal);
864 AST_TEST_REGISTER(sr_rr_nominal);
865 AST_TEST_REGISTER(fir_nominal);
867 AST_TEST_REGISTER(payload_merge_abandoned_offer);
868 AST_TEST_REGISTER(payload_merge_preserves_preferences);
870}
871
Asterisk main include file. File version handling, generic pbx functions.
#define ast_log
Definition astobj2.c:42
#define ao2_cleanup(obj)
Definition astobj2.h:1934
static PGresult * result
Definition cel_pgsql.c:84
static const char type[]
Data Buffer API.
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition format.c:201
@ AST_FORMAT_CMP_EQUAL
Definition format.h:36
Media Format Cache API.
struct ast_format * ast_format_ulaw
Built-in cached ulaw format.
struct ast_format * ast_format_alaw
Built-in cached alaw format.
@ AST_FRFLAG_HAS_SEQUENCE_NUMBER
@ AST_FRFLAG_HAS_TIMING_INFO
#define ast_frfree(fr)
@ AST_FRAME_CONTROL
@ AST_CONTROL_VIDUPDATE
#define LOG_ERROR
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition module.h:581
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition netsock2.c:230
static void cleanup(void)
Clean up any old apps that we don't need any more.
Definition res_stasis.c:327
#define NULL
Definition resample.c:96
Pluggable RTP Architecture.
#define AST_RTP_RTCP_PSFB
Definition rtp_engine.h:329
void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs)
Destroy the contents of an RTP codecs structure (but not the structure itself)
int ast_rtp_instance_destroy(struct ast_rtp_instance *instance)
Destroy an RTP instance.
Definition rtp_engine.c:468
struct ast_format * ast_rtp_codecs_get_preferred_format(struct ast_rtp_codecs *codecs)
Retrieve rx preferred format.
struct ast_rtp_instance * ast_rtp_instance_new(const char *engine_name, struct ast_sched_context *sched, const struct ast_sockaddr *sa, void *data)
Create a new RTP instance.
Definition rtp_engine.c:497
struct ast_rtp_payload_type * ast_rtp_codecs_get_payload(struct ast_rtp_codecs *codecs, int payload)
Retrieve rx payload mapped information by payload type.
#define AST_RTP_RTCP_SR
Definition rtp_engine.h:323
ast_rtp_instance_rtcp
Definition rtp_engine.h:283
@ AST_RTP_INSTANCE_RTCP_MUX
Definition rtp_engine.h:289
@ AST_RTP_INSTANCE_RTCP_STANDARD
Definition rtp_engine.h:287
ast_rtp_instance_stat
Definition rtp_engine.h:185
@ AST_RTP_INSTANCE_STAT_ALL
Definition rtp_engine.h:187
struct ast_frame * ast_rtp_instance_read(struct ast_rtp_instance *instance, int rtcp)
Receive a frame over RTP.
Definition rtp_engine.c:629
void ast_rtp_codecs_set_framing(struct ast_rtp_codecs *codecs, unsigned int framing)
Set the framing used for a set of codecs.
#define AST_RTP_RTCP_RR
Definition rtp_engine.h:325
void ast_rtp_instance_set_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value)
Set the value of an RTP instance property.
Definition rtp_engine.c:756
int ast_rtp_codecs_get_preferred_dtmf_format_rate(struct ast_rtp_codecs *codecs)
Retrieve rx preferred dtmf format sample rate.
void ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address)
Get the local address that we are expecting RTP on.
Definition rtp_engine.c:694
int ast_rtp_instance_get_stats(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat)
Retrieve statistics about an RTP instance.
int ast_rtp_instance_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
Send a frame out over RTP.
Definition rtp_engine.c:619
#define ast_rtp_instance_set_remote_address(instance, address)
Set the address of the remote endpoint that we are sending RTP to.
#define AST_RTP_RTCP_FMT_REMB
Definition rtp_engine.h:339
void ast_rtp_codecs_payloads_merge(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
Merge payload information from one RTP instance into another.
int ast_rtp_codecs_payloads_initialize(struct ast_rtp_codecs *codecs)
Initialize an RTP codecs structure.
@ AST_RTP_PROPERTY_RETRANS_RECV
Definition rtp_engine.h:130
@ AST_RTP_PROPERTY_RETRANS_SEND
Definition rtp_engine.h:132
@ AST_RTP_PROPERTY_RTCP
Definition rtp_engine.h:126
@ AST_RTP_PROPERTY_REMB
Definition rtp_engine.h:134
int ast_rtp_instance_activate(struct ast_rtp_instance *instance)
Indicate to the RTP engine that packets are now expected to be sent/received on the RTP instance.
int ast_rtp_codecs_payloads_set_rtpmap_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload, char *mimetype, char *mimesubtype, enum ast_rtp_options options)
Record tx payload type information that was seen in an a=rtpmap: SDP line.
void ast_rtp_instance_set_channel_id(struct ast_rtp_instance *instance, const char *uniqueid)
Set the channel that owns this RTP instance.
Definition rtp_engine.c:604
int ast_rtp_codecs_set_preferred_dtmf_format(struct ast_rtp_codecs *codecs, int pt, int rate)
Set the preferred dtmf format pt and sample rate.
#define AST_RTP_CODECS_NULL_INIT
Definition rtp_engine.h:773
int ast_rtp_codecs_get_preferred_dtmf_format_pt(struct ast_rtp_codecs *codecs)
Retrieve rx preferred dtmf format payload type.
unsigned int ast_rtp_codecs_get_framing(struct ast_rtp_codecs *codecs)
Get the framing used for a set of codecs.
void ast_rtp_codecs_payloads_xover(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
Crossover copy the tx payload mapping of src to the rx payload mapping of dest.
int ast_rtp_codecs_set_preferred_format(struct ast_rtp_codecs *codecs, struct ast_format *format)
Set the preferred format.
Scheduler Routines (derived from cheops)
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition sched.c:271
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
Definition sched.c:197
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition sched.c:238
Definition of a media format.
Definition format.c:43
Data structure associated with a single frame of data.
struct timeval delivery
enum ast_frame_type frametype
union ast_frame::@237 data
An object that represents data received in a feedback report.
Definition rtp_engine.h:388
struct ast_rtp_rtcp_feedback_remb remb
Definition rtp_engine.h:391
Socket address structure.
Definition netsock2.h:97
Definition sched.c:76
Test Framework API.
@ TEST_INIT
Definition test.h:200
@ TEST_EXECUTE
Definition test.h:201
#define AST_TEST_REGISTER(cb)
Definition test.h:127
#define ast_test_status_update(a, b, c...)
Definition test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition test.h:128
#define AST_TEST_DEFINE(hdr)
Definition test.h:126
ast_test_result_state
Definition test.h:193
@ AST_TEST_PASS
Definition test.h:195
@ AST_TEST_FAIL
Definition test.h:196
@ AST_TEST_NOT_RUN
Definition test.h:194
static struct test_val a
static void SLEEP_SPINNER(int ms)
static void test_write_and_read_interleaved_frames(struct ast_rtp_instance *instance1, struct ast_rtp_instance *instance2, int howlong, int rtcp_interval)
static int test_init_rtp_instances(struct ast_rtp_instance **instance1, struct ast_rtp_instance **instance2, struct ast_sched_context *test_sched, enum test_type type)
static void test_read_frames(struct ast_rtp_instance *instance, int num)
test_type
@ TEST_TYPE_NACK
@ TEST_TYPE_NONE
@ TEST_TYPE_STD_RTCP
@ TEST_TYPE_REMB
static void ast_sched_context_destroy_wrapper(struct ast_sched_context *sched)
static int load_module(void)
static void test_write_and_read_frames(struct ast_rtp_instance *instance1, struct ast_rtp_instance *instance2, int seqno, int num)
static int unload_module(void)
static void test_write_frames(struct ast_rtp_instance *instance, int seqno, int num)
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition utils.c:2315
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_clear_flag(p, flag)
Definition utils.h:78
#define ast_set_flag(p, flag)
Definition utils.h:71