2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2017, Digium Inc.
6 * Mark Michelson <mmmichelson@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.
20 <depend>TEST_FRAMEWORK</depend>
21 <support_level>core</support_level>
25 #include "asterisk/test.h"
26 #include "asterisk/module.h"
27 #include "asterisk/sdp.h"
28 #include "asterisk/stream.h"
29 #include "asterisk/format.h"
30 #include "asterisk/format_cache.h"
31 #include "asterisk/format_cap.h"
32 #include "asterisk/rtp_engine.h"
34 static int validate_o_line(struct ast_test *test, const struct ast_sdp_o_line *o_line,
35 const char *sdpowner, const char *address_type, const char *address)
41 if (strcmp(o_line->username, sdpowner)) {
42 ast_test_status_update(test, "Expected o-line SDP owner %s but got %s\n",
43 sdpowner, o_line->username);
47 if (strcmp(o_line->address_type, address_type)) {
48 ast_test_status_update(test, "Expected o-line SDP address type %s but got %s\n",
49 address_type, o_line->address_type);
53 if (strcmp(o_line->address, address)) {
54 ast_test_status_update(test, "Expected o-line SDP address %s but got %s\n",
55 address, o_line->address);
59 ast_test_status_update(test, "SDP o-line is as expected!\n");
63 static int validate_c_line(struct ast_test *test, const struct ast_sdp_c_line *c_line,
64 const char *address_type, const char *address)
66 if (strcmp(c_line->address_type, address_type)) {
67 ast_test_status_update(test, "Expected c-line SDP address type %s but got %s\n",
68 address_type, c_line->address_type);
72 if (strcmp(c_line->address, address)) {
73 ast_test_status_update(test, "Expected c-line SDP address %s but got %s\n",
74 address, c_line->address);
78 ast_test_status_update(test, "SDP c-line is as expected!\n");
82 static int validate_m_line(struct ast_test *test, const struct ast_sdp_m_line *m_line,
83 const char *media_type, int num_payloads)
85 if (strcmp(m_line->type, media_type)) {
86 ast_test_status_update(test, "Expected m-line media type %s but got %s\n",
87 media_type, m_line->type);
91 if (m_line->port == 0) {
92 ast_test_status_update(test, "Expected %s m-line to not be declined\n",
97 if (ast_sdp_m_get_payload_count(m_line) != num_payloads) {
98 ast_test_status_update(test, "Expected %s m-line payload count %d but got %d\n",
99 media_type, num_payloads, ast_sdp_m_get_payload_count(m_line));
103 ast_test_status_update(test, "SDP %s m-line is as expected\n", media_type);
107 static int validate_m_line_declined(struct ast_test *test,
108 const struct ast_sdp_m_line *m_line, const char *media_type)
110 if (strcmp(m_line->type, media_type)) {
111 ast_test_status_update(test, "Expected m-line media type %s but got %s\n",
112 media_type, m_line->type);
116 if (m_line->port != 0) {
117 ast_test_status_update(test, "Expected %s m-line to be declined but got port %u\n",
118 media_type, m_line->port);
122 ast_test_status_update(test, "SDP %s m-line is as expected\n", media_type);
126 static int validate_rtpmap(struct ast_test *test, const struct ast_sdp_m_line *m_line,
127 const char *media_name)
129 struct ast_sdp_a_line *a_line;
132 for (i = 0; i < ast_sdp_m_get_a_count(m_line); ++i) {
133 struct ast_sdp_rtpmap *rtpmap;
136 a_line = ast_sdp_m_get_a(m_line, i);
137 if (strcmp(a_line->name, "rtpmap")) {
141 rtpmap = ast_sdp_a_get_rtpmap(a_line);
146 match = !strcmp(rtpmap->encoding_name, media_name);
148 ast_sdp_rtpmap_free(rtpmap);
154 ast_test_status_update(test, "Could not find rtpmap with encoding name %s\n", media_name);
159 static enum ast_test_result_state validate_t38(struct ast_test *test, const struct ast_sdp_m_line *m_line)
161 struct ast_sdp_a_line *a_line;
163 a_line = ast_sdp_m_find_attribute(m_line, "T38FaxVersion", -1);
164 ast_test_validate(test, a_line && !strcmp(a_line->value, "0"));
166 a_line = ast_sdp_m_find_attribute(m_line, "T38FaxMaxBitRate", -1);
167 ast_test_validate(test, a_line && !strcmp(a_line->value, "14400"));
169 a_line = ast_sdp_m_find_attribute(m_line, "T38FaxRateManagement", -1);
170 ast_test_validate(test, a_line && !strcmp(a_line->value, "transferredTCF"));
172 return AST_TEST_PASS;
175 AST_TEST_DEFINE(invalid_rtpmap)
177 /* a=rtpmap: is already assumed. This is the part after that */
178 static const char *invalids[] = {
181 "0 PCMU/EIGHT-THOUSAND",
182 "0 PCMU/8000million/2",
186 "0 PCMU/8000million",
189 enum ast_test_result_state res = AST_TEST_PASS;
193 info->name = "invalid_rtpmap";
194 info->category = "/main/sdp/";
195 info->summary = "Ensure invalid rtpmaps are rejected";
197 "Try to convert several invalid rtpmap attributes. If\n"
198 "any succeeds, the test fails.";
199 return AST_TEST_NOT_RUN;
204 for (i = 0; i < ARRAY_LEN(invalids); ++i) {
205 struct ast_sdp_a_line *a_line;
206 struct ast_sdp_rtpmap *rtpmap;
208 a_line = ast_sdp_a_alloc("rtpmap", invalids[i]);
209 rtpmap = ast_sdp_a_get_rtpmap(a_line);
211 ast_test_status_update(test, "Invalid rtpmap '%s' was accepted as valid\n",
215 ast_sdp_a_free(a_line);
216 ast_sdp_rtpmap_free(rtpmap);
222 AST_TEST_DEFINE(rtpmap)
224 static const char *valids[] = {
228 static int payloads[] = {
232 static const char *encoding_names[] = {
236 static int clock_rates[] = {
240 static const char *encoding_parameters[] = {
245 enum ast_test_result_state res = AST_TEST_PASS;
249 info->name = "rtpmap";
250 info->category = "/main/sdp/";
251 info->summary = "Ensure rtpmap attribute values are parsed correctly";
253 "Parse several valid rtpmap attributes. Ensure that the parsed values\n"
254 "are what we expect";
255 return AST_TEST_NOT_RUN;
260 for (i = 0; i < ARRAY_LEN(valids); ++i) {
261 struct ast_sdp_a_line *a_line;
262 struct ast_sdp_rtpmap *rtpmap;
264 a_line = ast_sdp_a_alloc("rtpmap", valids[i]);
265 rtpmap = ast_sdp_a_get_rtpmap(a_line);
267 ast_test_status_update(test, "Valid rtpmap '%s' was rejected as invalid\n",
272 if (rtpmap->payload != payloads[i]) {
273 ast_test_status_update(test, "RTPmap payload '%d' does not match expected '%d'\n",
274 rtpmap->payload, payloads[i]);
277 if (strcmp(rtpmap->encoding_name, encoding_names[i])) {
278 ast_test_status_update(test, "RTPmap encoding_name '%s' does not match expected '%s'\n",
279 rtpmap->encoding_name, encoding_names[i]);
282 if (rtpmap->clock_rate != clock_rates[i]) {
283 ast_test_status_update(test, "RTPmap clock rate '%d' does not match expected '%d'\n",
284 rtpmap->clock_rate, clock_rates[i]);
287 if (strcmp(rtpmap->encoding_parameters, encoding_parameters[i])) {
288 ast_test_status_update(test, "RTPmap encoding_parameter '%s' does not match expected '%s'\n",
289 rtpmap->encoding_parameters, encoding_parameters[i]);
292 ast_sdp_a_free(a_line);
293 ast_sdp_rtpmap_free(rtpmap);
299 AST_TEST_DEFINE(find_attr)
301 enum ast_test_result_state res = AST_TEST_PASS;
302 struct ast_sdp_m_line *m_line;
303 struct ast_sdp_a_line *a_line;
308 info->name = "find_attr";
309 info->category = "/main/sdp/";
310 info->summary = "Ensure that finding attributes works as expected";
312 "A SDP m-line is created, and attributes are added.\n"
313 "We then attempt a series of attribute-finding calls that are expected to work\n"
314 "followed by a series of attribute-finding calls that are expected fo fail.";
315 return AST_TEST_NOT_RUN;
320 m_line = ast_sdp_m_alloc("audio", 666, 1, "RTP/AVP", NULL);
325 a_line = ast_sdp_a_alloc("foo", "0 bar");
330 ast_sdp_m_add_a(m_line, a_line);
331 a_line = ast_sdp_a_alloc("foo", "0 bee");
336 ast_sdp_m_add_a(m_line, a_line);
338 a_line = ast_sdp_a_alloc("baz", "howdy");
343 ast_sdp_m_add_a(m_line, a_line);
345 /* These should work */
346 a_line = ast_sdp_m_find_attribute(m_line, "foo", 0);
347 if (!a_line || strcmp(a_line->value, "0 bar")) {
348 ast_test_status_update(test, "Failed to find attribute 'foo' with payload '0'\n");
351 a_line = ast_sdp_m_find_attribute(m_line, "foo", -1);
352 if (!a_line || strcmp(a_line->value, "0 bar")) {
353 ast_test_status_update(test, "Failed to find attribute 'foo' with unspecified payload\n");
356 a_line = ast_sdp_m_find_attribute(m_line, "baz", -1);
357 if (!a_line || strcmp(a_line->value, "howdy")) {
358 ast_test_status_update(test, "Failed to find attribute 'baz' with unspecified payload\n");
362 idx = ast_sdp_m_find_a_first(m_line, "foo", 0);
364 ast_test_status_update(test, "Failed to find first attribute 'foo' with payload '0'\n");
368 a_line = ast_sdp_m_get_a(m_line, idx);
369 if (!a_line || strcmp(a_line->value, "0 bar")) {
370 ast_test_status_update(test, "Find first attribute 'foo' with payload '0' didn't match\n");
373 idx = ast_sdp_m_find_a_next(m_line, idx, "foo", 0);
375 ast_test_status_update(test, "Failed to find next attribute 'foo' with payload '0'\n");
379 a_line = ast_sdp_m_get_a(m_line, idx);
380 if (!a_line || strcmp(a_line->value, "0 bee")) {
381 ast_test_status_update(test, "Find next attribute 'foo' with payload '0' didn't match\n");
384 idx = ast_sdp_m_find_a_next(m_line, idx, "foo", 0);
386 ast_test_status_update(test, "Find next attribute 'foo' with payload '0' found too many\n");
390 idx = ast_sdp_m_find_a_first(m_line, "foo", -1);
392 ast_test_status_update(test, "Failed to find first attribute 'foo' with unspecified payload\n");
396 a_line = ast_sdp_m_get_a(m_line, idx);
397 if (!a_line || strcmp(a_line->value, "0 bar")) {
398 ast_test_status_update(test, "Find first attribute 'foo' with unspecified payload didn't match\n");
401 idx = ast_sdp_m_find_a_next(m_line, idx, "foo", -1);
403 ast_test_status_update(test, "Failed to find next attribute 'foo' with unspecified payload\n");
407 a_line = ast_sdp_m_get_a(m_line, idx);
408 if (!a_line || strcmp(a_line->value, "0 bee")) {
409 ast_test_status_update(test, "Find next attribute 'foo' with unspecified payload didn't match\n");
412 idx = ast_sdp_m_find_a_next(m_line, idx, "foo", -1);
414 ast_test_status_update(test, "Find next attribute 'foo' with unspecified payload found too many\n");
418 /* These should fail */
419 a_line = ast_sdp_m_find_attribute(m_line, "foo", 1);
421 ast_test_status_update(test, "Found non-existent attribute 'foo' with payload '1'\n");
424 a_line = ast_sdp_m_find_attribute(m_line, "baz", 0);
426 ast_test_status_update(test, "Found non-existent attribute 'baz' with payload '0'\n");
429 a_line = ast_sdp_m_find_attribute(m_line, "wibble", 0);
431 ast_test_status_update(test, "Found non-existent attribute 'wibble' with payload '0'\n");
434 a_line = ast_sdp_m_find_attribute(m_line, "wibble", -1);
436 ast_test_status_update(test, "Found non-existent attribute 'wibble' with unspecified payload\n");
441 ast_sdp_m_free(m_line);
445 static struct ast_sdp_options *sdp_options_common(void)
447 struct ast_sdp_options *options;
449 options = ast_sdp_options_alloc();
453 ast_sdp_options_set_media_address(options, "127.0.0.1");
454 ast_sdp_options_set_sdpowner(options, "me");
455 ast_sdp_options_set_rtp_engine(options, "asterisk");
456 ast_sdp_options_set_impl(options, AST_SDP_IMPL_PJMEDIA);
462 enum ast_media_type type;
466 static int build_sdp_option_formats(struct ast_sdp_options *options, int num_streams, const struct sdp_format *formats)
470 for (idx = 0; idx < num_streams; ++idx) {
471 struct ast_format_cap *caps;
473 if (ast_strlen_zero(formats[idx].formats)) {
477 caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
479 || ast_format_cap_update_by_allow_disallow(caps, formats[idx].formats, 1) < 0) {
483 ast_sdp_options_set_format_cap_type(options, formats[idx].type, caps);
490 * \brief Common method to build an SDP state for a test.
492 * This uses the passed-in formats to create a stream topology, which is then used to create the SDP
495 * There is an optional test_options field you can use if your test has specific options you need to
496 * set. If your test does not require anything special, it can just pass NULL for this parameter. If
497 * you do pass in test_options, this function steals ownership of those options.
499 * \param num_streams The number of elements in the formats array.
500 * \param formats Array of media types and formats that will be in the state.
501 * \param opt_num_streams The number of new stream types allowed to create.
502 * Not used if test_options provided.
503 * \param opt_formats Array of new stream media types and formats allowed to create.
504 * NULL if use a default stream creation.
505 * Not used if test_options provided.
506 * \param max_streams 0 if set max to max(3, num_streams) else max(max_streams, num_streams)
507 * Not used if test_options provided.
508 * \param test_options Optional SDP options.
510 static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_format *formats,
511 int opt_num_streams, const struct sdp_format *opt_formats, unsigned int max_streams,
512 struct ast_sdp_options *test_options)
514 struct ast_stream_topology *topology = NULL;
515 struct ast_sdp_state *state = NULL;
516 struct ast_sdp_options *options;
520 static const struct sdp_format sdp_formats[] = {
521 { AST_MEDIA_TYPE_AUDIO, "ulaw" },
522 { AST_MEDIA_TYPE_VIDEO, "vp8" },
523 { AST_MEDIA_TYPE_IMAGE, "t38" },
526 options = sdp_options_common();
531 /* Determine max_streams to allow */
533 max_streams = ARRAY_LEN(sdp_formats);
535 if (max_streams < num_streams) {
536 max_streams = num_streams;
538 ast_sdp_options_set_max_streams(options, max_streams);
540 /* Determine new stream formats and types allowed */
542 opt_num_streams = ARRAY_LEN(sdp_formats);
543 opt_formats = sdp_formats;
545 if (build_sdp_option_formats(options, opt_num_streams, opt_formats)) {
549 options = test_options;
552 topology = ast_stream_topology_alloc();
557 for (i = 0; i < num_streams; ++i) {
558 struct ast_stream *stream;
560 stream = ast_stream_alloc("sure_thing", formats[i].type);
564 if (!ast_strlen_zero(formats[i].formats)) {
565 struct ast_format_cap *caps;
567 caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
569 || ast_format_cap_update_by_allow_disallow(caps, formats[i].formats, 1) < 0) {
571 ast_stream_free(stream);
574 ast_stream_set_formats(stream, caps);
577 ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED);
579 if (ast_stream_topology_append_stream(topology, stream) < 0) {
580 ast_stream_free(stream);
585 state = ast_sdp_state_alloc(topology, options);
591 ast_stream_topology_free(topology);
593 ast_sdp_options_free(options);
599 AST_TEST_DEFINE(topology_to_sdp)
601 enum ast_test_result_state res = AST_TEST_FAIL;
602 struct ast_sdp_state *sdp_state = NULL;
603 const struct ast_sdp *sdp = NULL;
604 struct ast_sdp_m_line *m_line = NULL;
605 struct sdp_format formats[] = {
606 { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" },
607 { AST_MEDIA_TYPE_VIDEO, "h264,vp8" },
608 { AST_MEDIA_TYPE_IMAGE, "t38" },
613 info->name = "topology_to_sdp";
614 info->category = "/main/sdp/";
615 info->summary = "Convert a topology into an SDP";
617 "Ensure SDPs get converted to expected stream topology";
618 return AST_TEST_NOT_RUN;
623 sdp_state = build_sdp_state(ARRAY_LEN(formats), formats,
624 ARRAY_LEN(formats), formats, 0, NULL);
629 sdp = ast_sdp_state_get_local_sdp(sdp_state);
634 if (validate_o_line(test, sdp->o_line, "me", "IP4", "127.0.0.1")) {
638 if (validate_c_line(test, sdp->c_line, "IP4", "127.0.0.1")) {
642 if (ast_sdp_get_m_count(sdp) != 3) {
643 ast_test_status_update(test, "Unexpected number of streams in generated SDP: %d\n",
644 ast_sdp_get_m_count(sdp));
648 m_line = ast_sdp_get_m(sdp, 0);
650 if (validate_m_line(test, m_line, "audio", 4)) {
654 if (validate_rtpmap(test, m_line, "PCMU")) {
658 if (validate_rtpmap(test, m_line, "PCMA")) {
662 if (validate_rtpmap(test, m_line, "G722")) {
666 if (validate_rtpmap(test, m_line, "opus")) {
670 m_line = ast_sdp_get_m(sdp, 1);
671 if (validate_m_line(test, m_line, "video", 2)) {
675 if (validate_rtpmap(test, m_line, "VP8")) {
679 if (validate_rtpmap(test, m_line, "H264")) {
683 m_line = ast_sdp_get_m(sdp, 2);
684 if (validate_m_line(test, m_line, "image", 1)) {
687 if (validate_t38(test, m_line) != AST_TEST_PASS) {
694 ast_sdp_state_free(sdp_state);
698 static int validate_formats(struct ast_test *test, struct ast_stream_topology *topology, int index,
699 enum ast_media_type type, int format_count, const char **expected_formats)
701 struct ast_stream *stream;
702 struct ast_format_cap *caps;
703 struct ast_format *format;
706 stream = ast_stream_topology_get_stream(topology, index);
707 if (ast_stream_get_type(stream) != type) {
708 ast_test_status_update(test, "Unexpected stream type encountered\n");
711 caps = ast_stream_get_formats(stream);
713 if (ast_format_cap_count(caps) != format_count) {
714 ast_test_status_update(test, "Unexpected format count '%d'. Expecting '%d'\n",
715 (int) ast_format_cap_count(caps), format_count);
719 for (i = 0; i < ast_format_cap_count(caps); ++i) {
720 format = ast_format_cap_get_format(caps, i);
721 if (strcmp(ast_format_get_name(format), expected_formats[i])) {
722 ast_test_status_update(test, "Unexpected format '%s'at index %d. Expected '%s'\n",
723 ast_format_get_name(format), i, expected_formats[i]);
731 AST_TEST_DEFINE(sdp_to_topology)
733 enum ast_test_result_state res = AST_TEST_PASS;
734 struct ast_sdp_state *sdp_state;
735 const struct ast_sdp *sdp;
736 struct ast_stream_topology *topology = NULL;
737 struct sdp_format sdp_formats[] = {
738 { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" },
739 { AST_MEDIA_TYPE_VIDEO, "h264,vp8" },
740 { AST_MEDIA_TYPE_IMAGE, "t38" },
742 static const char *expected_audio_formats[] = {
748 static const char *expected_video_formats[] = {
752 static const char *expected_image_formats[] = {
758 info->name = "sdp_to_topology";
759 info->category = "/main/sdp/";
760 info->summary = "Convert an SDP into a topology";
762 "Ensure SDPs get converted to expected stream topology";
763 return AST_TEST_NOT_RUN;
768 sdp_state = build_sdp_state(ARRAY_LEN(sdp_formats), sdp_formats,
769 ARRAY_LEN(sdp_formats), sdp_formats, 0, NULL);
775 sdp = ast_sdp_state_get_local_sdp(sdp_state);
781 topology = ast_get_topology_from_sdp(sdp, 0);
787 if (ast_stream_topology_get_count(topology) != 3) {
788 ast_test_status_update(test, "Unexpected topology count '%d'. Expecting 3\n",
789 ast_stream_topology_get_count(topology));
794 if (validate_formats(test, topology, 0, AST_MEDIA_TYPE_AUDIO,
795 ARRAY_LEN(expected_audio_formats), expected_audio_formats)) {
800 if (validate_formats(test, topology, 1, AST_MEDIA_TYPE_VIDEO,
801 ARRAY_LEN(expected_video_formats), expected_video_formats)) {
806 if (validate_formats(test, topology, 2, AST_MEDIA_TYPE_IMAGE,
807 ARRAY_LEN(expected_image_formats), expected_image_formats)) {
813 ast_sdp_state_free(sdp_state);
814 ast_stream_topology_free(topology);
818 static int validate_avi_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp)
820 struct ast_sdp_m_line *m_line;
826 m_line = ast_sdp_get_m(sdp, 0);
827 if (validate_m_line(test, m_line, "audio", 1)) {
830 if (validate_rtpmap(test, m_line, "PCMU")) {
834 /* The other audio formats should *NOT* be present */
835 if (!validate_rtpmap(test, m_line, "PCMA")) {
838 if (!validate_rtpmap(test, m_line, "G722")) {
841 if (!validate_rtpmap(test, m_line, "opus")) {
845 m_line = ast_sdp_get_m(sdp, 1);
846 if (validate_m_line(test, m_line, "video", 1)) {
849 if (validate_rtpmap(test, m_line, "VP8")) {
852 if (!validate_rtpmap(test, m_line, "H264")) {
856 m_line = ast_sdp_get_m(sdp, 2);
857 if (validate_m_line(test, m_line, "image", 1)) {
864 static enum ast_test_result_state sdp_negotiation_completed_tests(struct ast_test *test,
865 int offer_num_streams, const struct sdp_format *offer_formats,
866 int answer_num_streams, const struct sdp_format *answer_formats,
867 int allowed_ans_num_streams, const struct sdp_format *allowed_ans_formats,
868 unsigned int max_streams,
869 int (*validate_sdp)(struct ast_test *test, const struct ast_sdp *sdp))
871 enum ast_test_result_state res = AST_TEST_PASS;
872 struct ast_sdp_state *sdp_state_offerer = NULL;
873 struct ast_sdp_state *sdp_state_answerer = NULL;
874 const struct ast_sdp *offerer_sdp;
875 const struct ast_sdp *answerer_sdp;
877 sdp_state_offerer = build_sdp_state(offer_num_streams, offer_formats,
878 offer_num_streams, offer_formats, max_streams, NULL);
879 if (!sdp_state_offerer) {
880 ast_test_status_update(test, "Building offerer SDP state failed\n");
885 sdp_state_answerer = build_sdp_state(answer_num_streams, answer_formats,
886 allowed_ans_num_streams, allowed_ans_formats, max_streams, NULL);
887 if (!sdp_state_answerer) {
888 ast_test_status_update(test, "Building answerer SDP state failed\n");
893 offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer);
895 ast_test_status_update(test, "Building offerer offer failed\n");
900 if (ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp)) {
901 ast_test_status_update(test, "Setting answerer offer failed\n");
905 answerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_answerer);
907 ast_test_status_update(test, "Building answerer answer failed\n");
912 if (ast_sdp_state_set_remote_sdp(sdp_state_offerer, answerer_sdp)) {
913 ast_test_status_update(test, "Setting offerer answer failed\n");
919 * Restart SDP negotiations to build the joint SDP on the offerer
920 * side. Otherwise we will get the original offer for use in
921 * case of retransmissions.
923 if (ast_sdp_state_restart_negotiations(sdp_state_offerer)) {
924 ast_test_status_update(test, "Restarting negotiations failed\n");
928 offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer);
930 ast_test_status_update(test, "Building offerer current sdp failed\n");
934 if (validate_sdp(test, offerer_sdp)) {
938 if (validate_sdp(test, answerer_sdp)) {
944 ast_sdp_state_free(sdp_state_offerer);
945 ast_sdp_state_free(sdp_state_answerer);
950 AST_TEST_DEFINE(sdp_negotiation_initial)
952 static const struct sdp_format offerer_formats[] = {
953 { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" },
954 { AST_MEDIA_TYPE_VIDEO, "h264,vp8" },
955 { AST_MEDIA_TYPE_IMAGE, "t38" },
960 info->name = "sdp_negotiation_initial";
961 info->category = "/main/sdp/";
962 info->summary = "Simulate an initial negotiation";
964 "Initial negotiation tests creating new streams on the answering side.\n"
965 "After negotiation both offerer and answerer sides should have the same\n"
966 "expected stream types and formats.";
967 return AST_TEST_NOT_RUN;
972 return sdp_negotiation_completed_tests(test,
973 ARRAY_LEN(offerer_formats), offerer_formats,
977 validate_avi_sdp_streams);
980 AST_TEST_DEFINE(sdp_negotiation_type_change)
982 static const struct sdp_format offerer_formats[] = {
983 { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" },
984 { AST_MEDIA_TYPE_VIDEO, "h264,vp8" },
985 { AST_MEDIA_TYPE_IMAGE, "t38" },
987 static const struct sdp_format answerer_formats[] = {
988 { AST_MEDIA_TYPE_IMAGE, "t38" },
989 { AST_MEDIA_TYPE_VIDEO, "vp8" },
990 { AST_MEDIA_TYPE_AUDIO, "ulaw" },
995 info->name = "sdp_negotiation_type_change";
996 info->category = "/main/sdp/";
997 info->summary = "Simulate a re-negotiation changing stream types";
999 "Reinvite negotiation tests changing stream types on the answering side.\n"
1000 "After negotiation both offerer and answerer sides should have the same\n"
1001 "expected stream types and formats.";
1002 return AST_TEST_NOT_RUN;
1007 return sdp_negotiation_completed_tests(test,
1008 ARRAY_LEN(offerer_formats), offerer_formats,
1009 ARRAY_LEN(answerer_formats), answerer_formats,
1012 validate_avi_sdp_streams);
1015 static int validate_aviavia_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp)
1017 struct ast_sdp_m_line *m_line;
1023 m_line = ast_sdp_get_m(sdp, 0);
1024 if (validate_m_line_declined(test, m_line, "audio")) {
1028 m_line = ast_sdp_get_m(sdp, 1);
1029 if (validate_m_line_declined(test, m_line, "video")) {
1033 m_line = ast_sdp_get_m(sdp, 2);
1034 if (validate_m_line_declined(test, m_line, "image")) {
1038 m_line = ast_sdp_get_m(sdp, 3);
1039 if (validate_m_line_declined(test, m_line, "audio")) {
1043 m_line = ast_sdp_get_m(sdp, 4);
1044 if (validate_m_line_declined(test, m_line, "video")) {
1048 m_line = ast_sdp_get_m(sdp, 5);
1049 if (validate_m_line_declined(test, m_line, "image")) {
1053 m_line = ast_sdp_get_m(sdp, 6);
1054 if (validate_m_line(test, m_line, "audio", 1)) {
1057 if (validate_rtpmap(test, m_line, "PCMU")) {
1061 /* The other audio formats should *NOT* be present */
1062 if (!validate_rtpmap(test, m_line, "PCMA")) {
1069 AST_TEST_DEFINE(sdp_negotiation_decline_incompatible)
1071 static const struct sdp_format offerer_formats[] = {
1072 /* Incompatible declined streams */
1073 { AST_MEDIA_TYPE_AUDIO, "alaw" },
1074 { AST_MEDIA_TYPE_VIDEO, "vp8" },
1075 { AST_MEDIA_TYPE_IMAGE, "t38" },
1076 /* Initially declined streams */
1077 { AST_MEDIA_TYPE_AUDIO, "" },
1078 { AST_MEDIA_TYPE_VIDEO, "" },
1079 { AST_MEDIA_TYPE_IMAGE, "" },
1080 /* Compatible stream so not all are declined */
1081 { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw" },
1083 static const struct sdp_format allowed_formats[] = {
1084 { AST_MEDIA_TYPE_AUDIO, "ulaw" },
1089 info->name = "sdp_negotiation_decline_incompatible";
1090 info->category = "/main/sdp/";
1091 info->summary = "Simulate an initial negotiation declining streams";
1093 "Initial negotiation tests declining incompatible streams.\n"
1094 "After negotiation both offerer and answerer sides should have\n"
1095 "the same expected stream types and formats.";
1096 return AST_TEST_NOT_RUN;
1101 return sdp_negotiation_completed_tests(test,
1102 ARRAY_LEN(offerer_formats), offerer_formats,
1104 ARRAY_LEN(allowed_formats), allowed_formats,
1105 ARRAY_LEN(offerer_formats),
1106 validate_aviavia_declined_sdp_streams);
1109 static int validate_aaaa_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp)
1111 struct ast_sdp_m_line *m_line;
1117 m_line = ast_sdp_get_m(sdp, 0);
1118 if (validate_m_line(test, m_line, "audio", 1)) {
1121 if (validate_rtpmap(test, m_line, "PCMU")) {
1125 m_line = ast_sdp_get_m(sdp, 1);
1126 if (validate_m_line(test, m_line, "audio", 1)) {
1129 if (validate_rtpmap(test, m_line, "PCMU")) {
1133 m_line = ast_sdp_get_m(sdp, 2);
1134 if (validate_m_line(test, m_line, "audio", 1)) {
1137 if (validate_rtpmap(test, m_line, "PCMU")) {
1141 m_line = ast_sdp_get_m(sdp, 3);
1142 if (validate_m_line_declined(test, m_line, "audio")) {
1149 AST_TEST_DEFINE(sdp_negotiation_decline_max_streams)
1151 static const struct sdp_format offerer_formats[] = {
1152 { AST_MEDIA_TYPE_AUDIO, "ulaw" },
1153 { AST_MEDIA_TYPE_AUDIO, "ulaw" },
1154 { AST_MEDIA_TYPE_AUDIO, "ulaw" },
1155 { AST_MEDIA_TYPE_AUDIO, "ulaw" },
1160 info->name = "sdp_negotiation_decline_max_streams";
1161 info->category = "/main/sdp/";
1162 info->summary = "Simulate an initial negotiation declining excessive streams";
1164 "Initial negotiation tests declining too many streams on the answering side.\n"
1165 "After negotiation both offerer and answerer sides should have the same\n"
1166 "expected stream types and formats.";
1167 return AST_TEST_NOT_RUN;
1172 return sdp_negotiation_completed_tests(test,
1173 ARRAY_LEN(offerer_formats), offerer_formats,
1177 validate_aaaa_declined_sdp_streams);
1180 AST_TEST_DEFINE(sdp_negotiation_not_acceptable)
1182 enum ast_test_result_state res = AST_TEST_PASS;
1183 struct ast_sdp_state *sdp_state_offerer = NULL;
1184 struct ast_sdp_state *sdp_state_answerer = NULL;
1185 const struct ast_sdp *offerer_sdp;
1187 static const struct sdp_format offerer_formats[] = {
1188 { AST_MEDIA_TYPE_AUDIO, "alaw" },
1189 { AST_MEDIA_TYPE_AUDIO, "alaw" },
1194 info->name = "sdp_negotiation_not_acceptable";
1195 info->category = "/main/sdp/";
1196 info->summary = "Simulate an initial negotiation declining all streams";
1198 "Initial negotiation tests declining all streams for a 488 on the answering side.\n"
1199 "Negotiations should fail because there are no acceptable streams.";
1200 return AST_TEST_NOT_RUN;
1205 sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats,
1206 ARRAY_LEN(offerer_formats), offerer_formats, 0, NULL);
1207 if (!sdp_state_offerer) {
1208 res = AST_TEST_FAIL;
1212 sdp_state_answerer = build_sdp_state(0, NULL, 0, NULL, 0, NULL);
1213 if (!sdp_state_answerer) {
1214 res = AST_TEST_FAIL;
1218 offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer);
1220 res = AST_TEST_FAIL;
1224 if (!ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp)) {
1225 ast_test_status_update(test, "Bad. Setting remote SDP was successful.\n");
1226 res = AST_TEST_FAIL;
1229 if (!ast_sdp_state_is_offer_rejected(sdp_state_answerer)) {
1230 ast_test_status_update(test, "Bad. Negotiation failed for some other reason.\n");
1231 res = AST_TEST_FAIL;
1236 ast_sdp_state_free(sdp_state_offerer);
1237 ast_sdp_state_free(sdp_state_answerer);
1242 static int validate_ssrc(struct ast_test *test, struct ast_sdp_m_line *m_line,
1243 struct ast_rtp_instance *rtp)
1247 struct ast_sdp_a_line *a_line;
1248 char attr_value[128];
1250 ssrc = ast_rtp_instance_get_ssrc(rtp);
1251 cname = ast_rtp_instance_get_cname(rtp);
1253 snprintf(attr_value, sizeof(attr_value), "%u cname:%s", ssrc, cname);
1255 a_line = ast_sdp_m_find_attribute(m_line, "ssrc", -1);
1257 ast_test_status_update(test, "Could not find 'ssrc' attribute\n");
1261 if (strcmp(a_line->value, attr_value)) {
1262 ast_test_status_update(test, "SDP attribute '%s' did not match expected attribute '%s'\n",
1263 a_line->value, attr_value);
1270 AST_TEST_DEFINE(sdp_ssrc_attributes)
1272 enum ast_test_result_state res;
1273 struct ast_sdp_state *test_state = NULL;
1274 struct ast_sdp_options *options;
1275 struct sdp_format formats[] = {
1276 { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" },
1278 const struct ast_sdp *sdp;
1279 struct ast_sdp_m_line *m_line;
1280 struct ast_rtp_instance *rtp;
1284 info->name = "sdp_ssrc_attributes";
1285 info->category = "/main/sdp/";
1286 info->summary = "Ensure SSRC-level attributes are added to local SDPs";
1288 "An SDP is created and is instructed to include SSRC-level attributes.\n"
1289 "This test ensures that the CNAME SSRC-level attribute is present and\n"
1290 "that the values match what the RTP instance reports";
1291 return AST_TEST_NOT_RUN;
1296 res = AST_TEST_FAIL;
1298 options = sdp_options_common();
1300 ast_test_status_update(test, "Failed to allocate SDP options\n");
1303 if (build_sdp_option_formats(options, ARRAY_LEN(formats), formats)) {
1306 ast_sdp_options_set_ssrc(options, 1);
1308 test_state = build_sdp_state(ARRAY_LEN(formats), formats, 0, NULL, 0, options);
1310 ast_test_status_update(test, "Failed to create SDP state\n");
1314 sdp = ast_sdp_state_get_local_sdp(test_state);
1316 ast_test_status_update(test, "Failed to get local SDP\n");
1320 /* Need a couple of sanity checks */
1321 if (ast_sdp_get_m_count(sdp) != ARRAY_LEN(formats)) {
1322 ast_test_status_update(test, "SDP m count is %d instead of %zu\n",
1323 ast_sdp_get_m_count(sdp), ARRAY_LEN(formats));
1327 m_line = ast_sdp_get_m(sdp, 0);
1329 ast_test_status_update(test, "Failed to get SDP m-line\n");
1333 rtp = ast_sdp_state_get_rtp_instance(test_state, 0);
1335 ast_test_status_update(test, "Failed to get the RTP instance\n");
1339 if (validate_ssrc(test, m_line, rtp)) {
1343 res = AST_TEST_PASS;
1346 ast_sdp_state_free(test_state);
1350 struct sdp_topology_stream {
1351 /*! Media stream type: audio, video, image */
1352 enum ast_media_type type;
1353 /*! Media stream state: removed/declined, sendrecv */
1354 enum ast_stream_state state;
1355 /*! Comma separated list of formats allowed on the stream. Can be NULL if stream is removed/declined. */
1356 const char *formats;
1357 /*! Optional name of stream. NULL for default name. */
1361 struct sdp_update_test {
1362 /*! Maximum number of streams. (0 if default) */
1364 /*! Optional initial SDP state topology (NULL if not present) */
1365 const struct sdp_topology_stream * const *initial;
1366 /*! Required first topology update */
1367 const struct sdp_topology_stream * const *update_1;
1368 /*! Optional second topology update (NULL if not present) */
1369 const struct sdp_topology_stream * const *update_2;
1370 /*! Expected topology to be offered */
1371 const struct sdp_topology_stream * const *expected;
1374 static struct ast_stream_topology *build_update_topology(const struct sdp_topology_stream * const *spec)
1376 struct ast_stream_topology *topology;
1377 const struct sdp_topology_stream *desc;
1379 topology = ast_stream_topology_alloc();
1384 for (desc = *spec; desc; ++spec, desc = *spec) {
1385 struct ast_stream *stream;
1388 name = desc->name ?: ast_codec_media_type2str(desc->type);
1389 stream = ast_stream_alloc(name, desc->type);
1393 ast_stream_set_state(stream, desc->state);
1394 if (desc->formats) {
1395 struct ast_format_cap *caps;
1397 caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
1399 || ast_format_cap_update_by_allow_disallow(caps, desc->formats, 1) < 0) {
1401 ast_stream_free(stream);
1404 ast_stream_set_formats(stream, caps);
1407 if (ast_stream_topology_append_stream(topology, stream) < 0) {
1408 ast_stream_free(stream);
1415 ast_stream_topology_free(topology);
1419 static int cmp_update_topology(struct ast_test *test,
1420 const struct ast_stream_topology *expected, const struct ast_stream_topology *merged)
1425 struct ast_stream *exp_stream;
1426 struct ast_stream *mrg_stream;
1428 idx = ast_stream_topology_get_count(expected);
1429 max_streams = ast_stream_topology_get_count(merged);
1430 if (idx != max_streams) {
1431 ast_test_status_update(test, "Expected %d streams got %d streams\n",
1435 if (idx < max_streams) {
1439 /* Compare common streams by position */
1440 for (idx = 0; idx < max_streams; ++idx) {
1441 exp_stream = ast_stream_topology_get_stream(expected, idx);
1442 mrg_stream = ast_stream_topology_get_stream(merged, idx);
1444 if (strcmp(ast_stream_get_name(exp_stream), ast_stream_get_name(mrg_stream))) {
1445 ast_test_status_update(test,
1446 "Stream %d: Expected stream name '%s' got stream name '%s'\n",
1448 ast_stream_get_name(exp_stream),
1449 ast_stream_get_name(mrg_stream));
1453 if (ast_stream_get_state(exp_stream) != ast_stream_get_state(mrg_stream)) {
1454 ast_test_status_update(test,
1455 "Stream %d: Expected stream state '%s' got stream state '%s'\n",
1457 ast_stream_state2str(ast_stream_get_state(exp_stream)),
1458 ast_stream_state2str(ast_stream_get_state(mrg_stream)));
1462 if (ast_stream_get_type(exp_stream) != ast_stream_get_type(mrg_stream)) {
1463 ast_test_status_update(test,
1464 "Stream %d: Expected stream type '%s' got stream type '%s'\n",
1466 ast_codec_media_type2str(ast_stream_get_type(exp_stream)),
1467 ast_codec_media_type2str(ast_stream_get_type(mrg_stream)));
1472 if (ast_stream_get_state(exp_stream) == AST_STREAM_STATE_REMOVED
1473 || ast_stream_get_state(mrg_stream) == AST_STREAM_STATE_REMOVED) {
1475 * Cannot compare formats if one of the streams is
1476 * declined because there may not be any on the declined
1481 if (!ast_format_cap_identical(ast_stream_get_formats(exp_stream),
1482 ast_stream_get_formats(mrg_stream))) {
1483 ast_test_status_update(test,
1484 "Stream %d: Expected formats do not match merged formats\n",
1494 static const struct sdp_topology_stream audio_declined_no_name = {
1495 AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_REMOVED, NULL, NULL
1498 static const struct sdp_topology_stream audio_ulaw_no_name = {
1499 AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "ulaw", NULL
1502 static const struct sdp_topology_stream audio_alaw_no_name = {
1503 AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "alaw", NULL
1506 static const struct sdp_topology_stream audio_g722_no_name = {
1507 AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g722", NULL
1510 static const struct sdp_topology_stream audio_g723_no_name = {
1511 AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g723", NULL
1514 static const struct sdp_topology_stream video_declined_no_name = {
1515 AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, NULL, NULL
1518 static const struct sdp_topology_stream video_h261_no_name = {
1519 AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h261", NULL
1522 static const struct sdp_topology_stream video_h263_no_name = {
1523 AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h263", NULL
1526 static const struct sdp_topology_stream video_h264_no_name = {
1527 AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h264", NULL
1530 static const struct sdp_topology_stream video_vp8_no_name = {
1531 AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "vp8", NULL
1534 static const struct sdp_topology_stream image_declined_no_name = {
1535 AST_MEDIA_TYPE_IMAGE, AST_STREAM_STATE_REMOVED, NULL, NULL
1538 static const struct sdp_topology_stream image_t38_no_name = {
1539 AST_MEDIA_TYPE_IMAGE, AST_STREAM_STATE_SENDRECV, "t38", NULL
1543 static const struct sdp_topology_stream *top_ulaw_alaw_h264__vp8[] = {
1544 &audio_ulaw_no_name,
1545 &audio_alaw_no_name,
1546 &video_h264_no_name,
1551 static const struct sdp_topology_stream *top__vp8_alaw_h264_ulaw[] = {
1553 &audio_alaw_no_name,
1554 &video_h264_no_name,
1555 &audio_ulaw_no_name,
1559 static const struct sdp_topology_stream *top_alaw_ulaw__vp8_h264[] = {
1560 &audio_alaw_no_name,
1561 &audio_ulaw_no_name,
1563 &video_h264_no_name,
1567 /* Sorting by type with no new or deleted streams */
1568 static const struct sdp_update_test mrg_by_type_00 = {
1569 .initial = top_ulaw_alaw_h264__vp8,
1570 .update_1 = top__vp8_alaw_h264_ulaw,
1571 .expected = top_alaw_ulaw__vp8_h264,
1575 static const struct sdp_topology_stream *top_alaw__vp8[] = {
1576 &audio_alaw_no_name,
1581 static const struct sdp_topology_stream *top_h264__vp8_ulaw[] = {
1582 &video_h264_no_name,
1584 &audio_ulaw_no_name,
1588 static const struct sdp_topology_stream *top_ulaw_h264__vp8[] = {
1589 &audio_ulaw_no_name,
1590 &video_h264_no_name,
1595 /* Sorting by type and adding a stream */
1596 static const struct sdp_update_test mrg_by_type_01 = {
1597 .initial = top_alaw__vp8,
1598 .update_1 = top_h264__vp8_ulaw,
1599 .expected = top_ulaw_h264__vp8,
1603 static const struct sdp_topology_stream *top_alaw__vp8_vdec[] = {
1604 &audio_alaw_no_name,
1606 &video_declined_no_name,
1610 /* Sorting by type and deleting a stream */
1611 static const struct sdp_update_test mrg_by_type_02 = {
1612 .initial = top_ulaw_h264__vp8,
1613 .update_1 = top_alaw__vp8,
1614 .expected = top_alaw__vp8_vdec,
1618 static const struct sdp_topology_stream *top_h264_alaw_ulaw[] = {
1619 &video_h264_no_name,
1620 &audio_alaw_no_name,
1621 &audio_ulaw_no_name,
1625 static const struct sdp_topology_stream *top__t38[] = {
1630 static const struct sdp_topology_stream *top_vdec__t38_adec[] = {
1631 &video_declined_no_name,
1633 &audio_declined_no_name,
1637 /* Sorting by type changing stream types for T.38 */
1638 static const struct sdp_update_test mrg_by_type_03 = {
1639 .initial = top_h264_alaw_ulaw,
1640 .update_1 = top__t38,
1641 .expected = top_vdec__t38_adec,
1645 /* Sorting by type changing stream types back from T.38 */
1646 static const struct sdp_update_test mrg_by_type_04 = {
1647 .initial = top_vdec__t38_adec,
1648 .update_1 = top_h264_alaw_ulaw,
1649 .expected = top_h264_alaw_ulaw,
1653 static const struct sdp_topology_stream *top_h264[] = {
1654 &video_h264_no_name,
1658 static const struct sdp_topology_stream *top_vdec__t38[] = {
1659 &video_declined_no_name,
1664 /* Sorting by type changing stream types for T.38 */
1665 static const struct sdp_update_test mrg_by_type_05 = {
1666 .initial = top_h264,
1667 .update_1 = top__t38,
1668 .expected = top_vdec__t38,
1672 static const struct sdp_topology_stream *top_h264_idec[] = {
1673 &video_h264_no_name,
1674 &image_declined_no_name,
1678 /* Sorting by type changing stream types back from T.38 */
1679 static const struct sdp_update_test mrg_by_type_06 = {
1680 .initial = top_vdec__t38,
1681 .update_1 = top_h264,
1682 .expected = top_h264_idec,
1686 static const struct sdp_topology_stream *top_ulaw_adec_h264__vp8[] = {
1687 &audio_ulaw_no_name,
1688 &audio_declined_no_name,
1689 &video_h264_no_name,
1694 static const struct sdp_topology_stream *top_h263_alaw_h261_h264_vp8[] = {
1695 &video_h263_no_name,
1696 &audio_alaw_no_name,
1697 &video_h261_no_name,
1698 &video_h264_no_name,
1703 static const struct sdp_topology_stream *top_alaw_h264_h263_h261_vp8[] = {
1704 &audio_alaw_no_name,
1705 &video_h264_no_name,
1706 &video_h263_no_name,
1707 &video_h261_no_name,
1712 /* Sorting by type with backfill and adding streams */
1713 static const struct sdp_update_test mrg_by_type_07 = {
1714 .initial = top_ulaw_adec_h264__vp8,
1715 .update_1 = top_h263_alaw_h261_h264_vp8,
1716 .expected = top_alaw_h264_h263_h261_vp8,
1720 static const struct sdp_topology_stream *top_ulaw_alaw_h264__vp8_h261[] = {
1721 &audio_ulaw_no_name,
1722 &audio_alaw_no_name,
1723 &video_h264_no_name,
1725 &video_h261_no_name,
1729 /* Sorting by type overlimit of 4 and drop */
1730 static const struct sdp_update_test mrg_by_type_08 = {
1732 .initial = top_ulaw_alaw_h264__vp8,
1733 .update_1 = top_ulaw_alaw_h264__vp8_h261,
1734 .expected = top_ulaw_alaw_h264__vp8,
1738 static const struct sdp_topology_stream *top_ulaw_alaw_h264[] = {
1739 &audio_ulaw_no_name,
1740 &audio_alaw_no_name,
1741 &video_h264_no_name,
1745 static const struct sdp_topology_stream *top_alaw_h261__vp8[] = {
1746 &audio_alaw_no_name,
1747 &video_h261_no_name,
1752 static const struct sdp_topology_stream *top_alaw_adec_h261__vp8[] = {
1753 &audio_alaw_no_name,
1754 &audio_declined_no_name,
1755 &video_h261_no_name,
1760 /* Sorting by type with delete and add of streams */
1761 static const struct sdp_update_test mrg_by_type_09 = {
1762 .initial = top_ulaw_alaw_h264,
1763 .update_1 = top_alaw_h261__vp8,
1764 .expected = top_alaw_adec_h261__vp8,
1768 static const struct sdp_topology_stream *top_ulaw_adec_h264[] = {
1769 &audio_ulaw_no_name,
1770 &audio_declined_no_name,
1771 &video_h264_no_name,
1775 /* Sorting by type and adding streams */
1776 static const struct sdp_update_test mrg_by_type_10 = {
1777 .initial = top_ulaw_adec_h264,
1778 .update_1 = top_alaw_ulaw__vp8_h264,
1779 .expected = top_alaw_ulaw__vp8_h264,
1783 static const struct sdp_topology_stream *top_adec_g722_h261[] = {
1784 &audio_declined_no_name,
1785 &audio_g722_no_name,
1786 &video_h261_no_name,
1790 /* Sorting by type and deleting old streams */
1791 static const struct sdp_update_test mrg_by_type_11 = {
1792 .initial = top_ulaw_alaw_h264,
1793 .update_1 = top_adec_g722_h261,
1794 .expected = top_adec_g722_h261,
1798 static const struct sdp_topology_stream audio_alaw4dave = {
1799 AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "alaw", "dave"
1802 static const struct sdp_topology_stream audio_g7224dave = {
1803 AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g722", "dave"
1806 static const struct sdp_topology_stream audio_ulaw4fred = {
1807 AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "ulaw", "fred"
1810 static const struct sdp_topology_stream audio_alaw4fred = {
1811 AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "alaw", "fred"
1814 static const struct sdp_topology_stream audio_ulaw4rose = {
1815 AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "ulaw", "rose"
1818 static const struct sdp_topology_stream audio_g7224rose = {
1819 AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g722", "rose"
1823 static const struct sdp_topology_stream video_h2614dave = {
1824 AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h261", "dave"
1827 static const struct sdp_topology_stream video_h2634dave = {
1828 AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h263", "dave"
1831 static const struct sdp_topology_stream video_h2634fred = {
1832 AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h263", "fred"
1835 static const struct sdp_topology_stream video_h2644fred = {
1836 AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h264", "fred"
1839 static const struct sdp_topology_stream video_h2644rose = {
1840 AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h264", "rose"
1843 static const struct sdp_topology_stream video_h2614rose = {
1844 AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h261", "rose"
1848 static const struct sdp_topology_stream *top_adave_alaw_afred_ulaw_arose_g722_vdave_h261_vfred_h263_vrose_h264[] = {
1850 &audio_alaw_no_name,
1852 &audio_ulaw_no_name,
1854 &audio_g722_no_name,
1856 &video_h261_no_name,
1858 &video_h263_no_name,
1860 &video_h264_no_name,
1864 static const struct sdp_topology_stream *top_vfred_vrose_vdave_h263_h264_h261_afred_ulaw_arose_g722_adave_alaw[] = {
1868 &video_h263_no_name,
1869 &video_h264_no_name,
1870 &video_h261_no_name,
1872 &audio_ulaw_no_name,
1874 &audio_g722_no_name,
1876 &audio_alaw_no_name,
1880 static const struct sdp_topology_stream *top_adave_ulaw_afred_g722_arose_alaw_vdave_h263_vfred_h264_vrose_h261[] = {
1882 &audio_ulaw_no_name,
1884 &audio_g722_no_name,
1886 &audio_alaw_no_name,
1888 &video_h263_no_name,
1890 &video_h264_no_name,
1892 &video_h261_no_name,
1896 /* Sorting by name and type with no new or deleted streams */
1897 static const struct sdp_update_test mrg_by_name_00 = {
1898 .initial = top_adave_alaw_afred_ulaw_arose_g722_vdave_h261_vfred_h263_vrose_h264,
1899 .update_1 = top_vfred_vrose_vdave_h263_h264_h261_afred_ulaw_arose_g722_adave_alaw,
1900 .expected = top_adave_ulaw_afred_g722_arose_alaw_vdave_h263_vfred_h264_vrose_h261,
1904 static const struct sdp_topology_stream *top_adave_g723_h261[] = {
1906 &audio_g723_no_name,
1907 &video_h261_no_name,
1911 /* Sorting by name and type adding names to streams */
1912 static const struct sdp_update_test mrg_by_name_01 = {
1913 .initial = top_ulaw_alaw_h264,
1914 .update_1 = top_adave_g723_h261,
1915 .expected = top_adave_g723_h261,
1919 /* Sorting by name and type removing names from streams */
1920 static const struct sdp_update_test mrg_by_name_02 = {
1921 .initial = top_adave_g723_h261,
1922 .update_1 = top_ulaw_alaw_h264,
1923 .expected = top_ulaw_alaw_h264,
1927 static const struct sdp_update_test *sdp_update_cases[] = {
1928 /* Merging by type */
1929 /* 00 */ &mrg_by_type_00,
1930 /* 01 */ &mrg_by_type_01,
1931 /* 02 */ &mrg_by_type_02,
1932 /* 03 */ &mrg_by_type_03,
1933 /* 04 */ &mrg_by_type_04,
1934 /* 05 */ &mrg_by_type_05,
1935 /* 06 */ &mrg_by_type_06,
1936 /* 07 */ &mrg_by_type_07,
1937 /* 08 */ &mrg_by_type_08,
1938 /* 09 */ &mrg_by_type_09,
1939 /* 10 */ &mrg_by_type_10,
1940 /* 11 */ &mrg_by_type_11,
1942 /* Merging by name and type */
1943 /* 12 */ &mrg_by_name_00,
1944 /* 13 */ &mrg_by_name_01,
1945 /* 14 */ &mrg_by_name_02,
1948 AST_TEST_DEFINE(sdp_update_topology)
1950 enum ast_test_result_state res;
1953 struct ast_sdp_options *options;
1954 struct ast_stream_topology *topology;
1955 struct ast_sdp_state *test_state = NULL;
1957 static const struct sdp_format sdp_formats[] = {
1958 { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,g723" },
1959 { AST_MEDIA_TYPE_VIDEO, "h261,h263,h264,vp8" },
1960 { AST_MEDIA_TYPE_IMAGE, "t38" },
1965 info->name = "sdp_update_topology";
1966 info->category = "/main/sdp/";
1967 info->summary = "Merge topology updates from the system";
1969 "1) Create a SDP state with an optional initial topology.\n"
1970 "2) Update the initial topology with one or two new topologies.\n"
1971 "3) Get the SDP offer to merge the updates into the initial topology.\n"
1972 "4) Check that the offered topology matches the expected topology.\n"
1973 "5) Repeat these steps for each test case defined.";
1974 return AST_TEST_NOT_RUN;
1979 res = AST_TEST_FAIL;
1980 for (idx = 0; idx < ARRAY_LEN(sdp_update_cases); ++idx) {
1981 ast_test_status_update(test, "Starting update case %d\n", idx);
1983 /* Create a SDP state with an optional initial topology. */
1984 options = sdp_options_common();
1986 ast_test_status_update(test, "Failed to allocate SDP options\n");
1989 if (sdp_update_cases[idx]->max_streams) {
1990 ast_sdp_options_set_max_streams(options, sdp_update_cases[idx]->max_streams);
1992 if (build_sdp_option_formats(options, ARRAY_LEN(sdp_formats), sdp_formats)) {
1993 ast_test_status_update(test, "Failed to setup SDP options new stream formats\n");
1996 if (sdp_update_cases[idx]->initial) {
1997 topology = build_update_topology(sdp_update_cases[idx]->initial);
1999 ast_test_status_update(test, "Failed to build initial SDP state topology\n");
2005 test_state = ast_sdp_state_alloc(topology, options);
2006 ast_stream_topology_free(topology);
2008 ast_test_status_update(test, "Failed to build SDP state\n");
2012 /* Update the initial topology with one or two new topologies. */
2013 topology = build_update_topology(sdp_update_cases[idx]->update_1);
2015 ast_test_status_update(test, "Failed to build first update SDP state topology\n");
2018 status = ast_sdp_state_update_local_topology(test_state, topology);
2019 ast_stream_topology_free(topology);
2021 ast_test_status_update(test, "Failed to update first update SDP state topology\n");
2024 if (sdp_update_cases[idx]->update_2) {
2025 topology = build_update_topology(sdp_update_cases[idx]->update_2);
2027 ast_test_status_update(test, "Failed to build second update SDP state topology\n");
2030 status = ast_sdp_state_update_local_topology(test_state, topology);
2031 ast_stream_topology_free(topology);
2033 ast_test_status_update(test, "Failed to update second update SDP state topology\n");
2038 /* Get the SDP offer to merge the updates into the initial topology. */
2039 if (!ast_sdp_state_get_local_sdp(test_state)) {
2040 ast_test_status_update(test, "Failed to create offer SDP\n");
2044 /* Check that the offered topology matches the expected topology. */
2045 topology = build_update_topology(sdp_update_cases[idx]->expected);
2047 ast_test_status_update(test, "Failed to build expected topology\n");
2050 status = cmp_update_topology(test, topology,
2051 ast_sdp_state_get_local_topology(test_state));
2052 ast_stream_topology_free(topology);
2054 ast_test_status_update(test, "Failed to match expected topology\n");
2058 /* Repeat for each test case defined. */
2059 ast_sdp_state_free(test_state);
2062 res = AST_TEST_PASS;
2065 ast_sdp_state_free(test_state);
2069 static int unload_module(void)
2071 AST_TEST_UNREGISTER(invalid_rtpmap);
2072 AST_TEST_UNREGISTER(rtpmap);
2073 AST_TEST_UNREGISTER(find_attr);
2074 AST_TEST_UNREGISTER(topology_to_sdp);
2075 AST_TEST_UNREGISTER(sdp_to_topology);
2076 AST_TEST_UNREGISTER(sdp_negotiation_initial);
2077 AST_TEST_UNREGISTER(sdp_negotiation_type_change);
2078 AST_TEST_UNREGISTER(sdp_negotiation_decline_incompatible);
2079 AST_TEST_UNREGISTER(sdp_negotiation_decline_max_streams);
2080 AST_TEST_UNREGISTER(sdp_negotiation_not_acceptable);
2081 AST_TEST_UNREGISTER(sdp_ssrc_attributes);
2082 AST_TEST_UNREGISTER(sdp_update_topology);
2087 static int load_module(void)
2089 AST_TEST_REGISTER(invalid_rtpmap);
2090 AST_TEST_REGISTER(rtpmap);
2091 AST_TEST_REGISTER(find_attr);
2092 AST_TEST_REGISTER(topology_to_sdp);
2093 AST_TEST_REGISTER(sdp_to_topology);
2094 AST_TEST_REGISTER(sdp_negotiation_initial);
2095 AST_TEST_REGISTER(sdp_negotiation_type_change);
2096 AST_TEST_REGISTER(sdp_negotiation_decline_incompatible);
2097 AST_TEST_REGISTER(sdp_negotiation_decline_max_streams);
2098 AST_TEST_REGISTER(sdp_negotiation_not_acceptable);
2099 AST_TEST_REGISTER(sdp_ssrc_attributes);
2100 AST_TEST_REGISTER(sdp_update_topology);
2102 return AST_MODULE_LOAD_SUCCESS;
2105 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SDP tests");