Merge "lpc10: Avoid compiler warning when DONT_OPTIMIZE/COMPILE_DOUBLE."
[asterisk/asterisk.git] / tests / test_sdp.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2017, Digium Inc.
5  *
6  * Mark Michelson <mmmichelson@digium.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 /*** MODULEINFO
20         <depend>TEST_FRAMEWORK</depend>
21         <support_level>core</support_level>
22  ***/
23
24 #include "asterisk.h"
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"
33
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)
36 {
37         if (!o_line) {
38                 return -1;
39         }
40
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);
44                 return -1;
45         }
46
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);
50                 return -1;
51         }
52
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);
56                 return -1;
57         }
58
59         ast_test_status_update(test, "SDP o-line is as expected!\n");
60         return 0;
61 }
62
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)
65 {
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);
69                 return -1;
70         }
71
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);
75                 return -1;
76         }
77
78         ast_test_status_update(test, "SDP c-line is as expected!\n");
79         return 0;
80 }
81
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)
84 {
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);
88                 return -1;
89         }
90
91         if (m_line->port == 0) {
92                 ast_test_status_update(test, "Expected %s m-line to not be declined\n",
93                         media_type);
94                 return -1;
95         }
96
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));
100                 return -1;
101         }
102
103         ast_test_status_update(test, "SDP %s m-line is as expected\n", media_type);
104         return 0;
105 }
106
107 static int validate_m_line_declined(struct ast_test *test,
108         const struct ast_sdp_m_line *m_line, const char *media_type)
109 {
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);
113                 return -1;
114         }
115
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);
119                 return -1;
120         }
121
122         ast_test_status_update(test, "SDP %s m-line is as expected\n", media_type);
123         return 0;
124 }
125
126 static int validate_rtpmap(struct ast_test *test, const struct ast_sdp_m_line *m_line,
127         const char *media_name)
128 {
129         struct ast_sdp_a_line *a_line;
130         int i;
131
132         for (i = 0; i < ast_sdp_m_get_a_count(m_line); ++i) {
133                 struct ast_sdp_rtpmap *rtpmap;
134                 int match;
135
136                 a_line = ast_sdp_m_get_a(m_line, i);
137                 if (strcmp(a_line->name, "rtpmap")) {
138                         continue;
139                 }
140
141                 rtpmap = ast_sdp_a_get_rtpmap(a_line);
142                 if (!rtpmap) {
143                         return -1;
144                 }
145
146                 match = !strcmp(rtpmap->encoding_name, media_name);
147
148                 ast_sdp_rtpmap_free(rtpmap);
149                 if (match) {
150                         return 0;
151                 }
152         }
153
154         ast_test_status_update(test, "Could not find rtpmap with encoding name %s\n", media_name);
155
156         return -1;
157 }
158
159 static enum ast_test_result_state validate_t38(struct ast_test *test, const struct ast_sdp_m_line *m_line)
160 {
161         struct ast_sdp_a_line *a_line;
162
163         a_line = ast_sdp_m_find_attribute(m_line, "T38FaxVersion", -1);
164         ast_test_validate(test, a_line && !strcmp(a_line->value, "0"));
165
166         a_line = ast_sdp_m_find_attribute(m_line, "T38FaxMaxBitRate", -1);
167         ast_test_validate(test, a_line && !strcmp(a_line->value, "14400"));
168
169         a_line = ast_sdp_m_find_attribute(m_line, "T38FaxRateManagement", -1);
170         ast_test_validate(test, a_line && !strcmp(a_line->value, "transferredTCF"));
171
172         return AST_TEST_PASS;
173 }
174
175 AST_TEST_DEFINE(invalid_rtpmap)
176 {
177         /* a=rtpmap: is already assumed. This is the part after that */
178         static const char *invalids[] = {
179                 "J PCMU/8000",
180                 "0 PCMU:8000",
181                 "0 PCMU/EIGHT-THOUSAND",
182                 "0 PCMU/8000million/2",
183                 "0 PCMU//2",
184                 "0 /8000/2",
185                 "0 PCMU/8000/",
186                 "0 PCMU/8000million",
187         };
188         int i;
189         enum ast_test_result_state res = AST_TEST_PASS;
190
191         switch(cmd) {
192         case TEST_INIT:
193                 info->name = "invalid_rtpmap";
194                 info->category = "/main/sdp/";
195                 info->summary = "Ensure invalid rtpmaps are rejected";
196                 info->description =
197                         "Try to convert several invalid rtpmap attributes. If\n"
198                         "any succeeds, the test fails.";
199                 return AST_TEST_NOT_RUN;
200         case TEST_EXECUTE:
201                 break;
202         }
203
204         for (i = 0; i < ARRAY_LEN(invalids); ++i) {
205                 struct ast_sdp_a_line *a_line;
206                 struct ast_sdp_rtpmap *rtpmap;
207
208                 a_line = ast_sdp_a_alloc("rtpmap", invalids[i]);
209                 rtpmap = ast_sdp_a_get_rtpmap(a_line);
210                 if (rtpmap) {
211                         ast_test_status_update(test, "Invalid rtpmap '%s' was accepted as valid\n",
212                                 invalids[i]);
213                         res = AST_TEST_FAIL;
214                 }
215                 ast_sdp_a_free(a_line);
216                 ast_sdp_rtpmap_free(rtpmap);
217         }
218
219         return res;
220 }
221
222 AST_TEST_DEFINE(rtpmap)
223 {
224         static const char *valids[] = {
225                 "0 PCMU/8000",
226                 "107 opus/48000/2",
227         };
228         static int payloads[] = {
229                 0,
230                 107,
231         };
232         static const char *encoding_names[] = {
233                 "PCMU",
234                 "opus",
235         };
236         static int clock_rates[] = {
237                 8000,
238                 48000,
239         };
240         static const char *encoding_parameters[] = {
241                 "",
242                 "2",
243         };
244         int i;
245         enum ast_test_result_state res = AST_TEST_PASS;
246
247         switch(cmd) {
248         case TEST_INIT:
249                 info->name = "rtpmap";
250                 info->category = "/main/sdp/";
251                 info->summary = "Ensure rtpmap attribute values are parsed correctly";
252                 info->description =
253                         "Parse several valid rtpmap attributes. Ensure that the parsed values\n"
254                         "are what we expect";
255                 return AST_TEST_NOT_RUN;
256         case TEST_EXECUTE:
257                 break;
258         }
259
260         for (i = 0; i < ARRAY_LEN(valids); ++i) {
261                 struct ast_sdp_a_line *a_line;
262                 struct ast_sdp_rtpmap *rtpmap;
263
264                 a_line = ast_sdp_a_alloc("rtpmap", valids[i]);
265                 rtpmap = ast_sdp_a_get_rtpmap(a_line);
266                 if (!rtpmap) {
267                         ast_test_status_update(test, "Valid rtpmap '%s' was rejected as invalid\n",
268                                 valids[i]);
269                         res = AST_TEST_FAIL;
270                         continue;
271                 }
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]);
275                         res = AST_TEST_FAIL;
276                 }
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]);
280                         res = AST_TEST_FAIL;
281                 }
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]);
285                         res = AST_TEST_FAIL;
286                 }
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]);
290                         res = AST_TEST_FAIL;
291                 }
292                 ast_sdp_a_free(a_line);
293                 ast_sdp_rtpmap_free(rtpmap);
294         }
295
296         return res;
297 }
298
299 AST_TEST_DEFINE(find_attr)
300 {
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;
304         int idx;
305
306         switch(cmd) {
307         case TEST_INIT:
308                 info->name = "find_attr";
309                 info->category = "/main/sdp/";
310                 info->summary = "Ensure that finding attributes works as expected";
311                 info->description =
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;
316         case TEST_EXECUTE:
317                 break;
318         }
319
320         m_line = ast_sdp_m_alloc("audio", 666, 1, "RTP/AVP", NULL);
321         if (!m_line) {
322                 res = AST_TEST_FAIL;
323                 goto end;
324         }
325         a_line = ast_sdp_a_alloc("foo", "0 bar");
326         if (!a_line) {
327                 res = AST_TEST_FAIL;
328                 goto end;
329         }
330         ast_sdp_m_add_a(m_line, a_line);
331         a_line = ast_sdp_a_alloc("foo", "0 bee");
332         if (!a_line) {
333                 res = AST_TEST_FAIL;
334                 goto end;
335         }
336         ast_sdp_m_add_a(m_line, a_line);
337
338         a_line = ast_sdp_a_alloc("baz", "howdy");
339         if (!a_line) {
340                 res = AST_TEST_FAIL;
341                 goto end;
342         }
343         ast_sdp_m_add_a(m_line, a_line);
344
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");
349                 res = AST_TEST_FAIL;
350         }
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");
354                 res = AST_TEST_FAIL;
355         }
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");
359                 res = AST_TEST_FAIL;
360         }
361
362         idx = ast_sdp_m_find_a_first(m_line, "foo", 0);
363         if (idx < 0) {
364                 ast_test_status_update(test, "Failed to find first attribute 'foo' with payload '0'\n");
365                 res = AST_TEST_FAIL;
366                 goto end;
367         }
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");
371                 res = AST_TEST_FAIL;
372         }
373         idx = ast_sdp_m_find_a_next(m_line, idx, "foo", 0);
374         if (idx < 0) {
375                 ast_test_status_update(test, "Failed to find next attribute 'foo' with payload '0'\n");
376                 res = AST_TEST_FAIL;
377                 goto end;
378         }
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");
382                 res = AST_TEST_FAIL;
383         }
384         idx = ast_sdp_m_find_a_next(m_line, idx, "foo", 0);
385         if (0 <= idx) {
386                 ast_test_status_update(test, "Find next attribute 'foo' with payload '0' found too many\n");
387                 res = AST_TEST_FAIL;
388         }
389
390         idx = ast_sdp_m_find_a_first(m_line, "foo", -1);
391         if (idx < 0) {
392                 ast_test_status_update(test, "Failed to find first attribute 'foo' with unspecified payload\n");
393                 res = AST_TEST_FAIL;
394                 goto end;
395         }
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");
399                 res = AST_TEST_FAIL;
400         }
401         idx = ast_sdp_m_find_a_next(m_line, idx, "foo", -1);
402         if (idx < 0) {
403                 ast_test_status_update(test, "Failed to find next attribute 'foo' with unspecified payload\n");
404                 res = AST_TEST_FAIL;
405                 goto end;
406         }
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");
410                 res = AST_TEST_FAIL;
411         }
412         idx = ast_sdp_m_find_a_next(m_line, idx, "foo", -1);
413         if (0 <= idx) {
414                 ast_test_status_update(test, "Find next attribute 'foo' with unspecified payload found too many\n");
415                 res = AST_TEST_FAIL;
416         }
417
418         /* These should fail */
419         a_line = ast_sdp_m_find_attribute(m_line, "foo", 1);
420         if (a_line) {
421                 ast_test_status_update(test, "Found non-existent attribute 'foo' with payload '1'\n");
422                 res = AST_TEST_FAIL;
423         }
424         a_line = ast_sdp_m_find_attribute(m_line, "baz", 0);
425         if (a_line) {
426                 ast_test_status_update(test, "Found non-existent attribute 'baz' with payload '0'\n");
427                 res = AST_TEST_FAIL;
428         }
429         a_line = ast_sdp_m_find_attribute(m_line, "wibble", 0);
430         if (a_line) {
431                 ast_test_status_update(test, "Found non-existent attribute 'wibble' with payload '0'\n");
432                 res = AST_TEST_FAIL;
433         }
434         a_line = ast_sdp_m_find_attribute(m_line, "wibble", -1);
435         if (a_line) {
436                 ast_test_status_update(test, "Found non-existent attribute 'wibble' with unspecified payload\n");
437                 res = AST_TEST_FAIL;
438         }
439
440 end:
441         ast_sdp_m_free(m_line);
442         return res;
443 }
444
445 static struct ast_sdp_options *sdp_options_common(void)
446 {
447         struct ast_sdp_options *options;
448
449         options = ast_sdp_options_alloc();
450         if (!options) {
451                 return NULL;
452         }
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);
457
458         return options;
459 }
460
461 struct sdp_format {
462         enum ast_media_type type;
463         const char *formats;
464 };
465
466 static int build_sdp_option_formats(struct ast_sdp_options *options, int num_streams, const struct sdp_format *formats)
467 {
468         int idx;
469
470         for (idx = 0; idx < num_streams; ++idx) {
471                 struct ast_format_cap *caps;
472
473                 if (ast_strlen_zero(formats[idx].formats)) {
474                         continue;
475                 }
476
477                 caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
478                 if (!caps
479                         || ast_format_cap_update_by_allow_disallow(caps, formats[idx].formats, 1) < 0) {
480                         ao2_cleanup(caps);
481                         return -1;
482                 }
483                 ast_sdp_options_set_format_cap_type(options, formats[idx].type, caps);
484                 ao2_cleanup(caps);
485         }
486         return 0;
487 }
488
489 /*!
490  * \brief Common method to build an SDP state for a test.
491  *
492  * This uses the passed-in formats to create a stream topology, which is then used to create the SDP
493  * state.
494  *
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.
498  *
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.
509  */
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)
513 {
514         struct ast_stream_topology *topology = NULL;
515         struct ast_sdp_state *state = NULL;
516         struct ast_sdp_options *options;
517         int i;
518
519         if (!test_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" },
524                 };
525
526                 options = sdp_options_common();
527                 if (!options) {
528                         goto end;
529                 }
530
531                 /* Determine max_streams to allow */
532                 if (!max_streams) {
533                         max_streams = ARRAY_LEN(sdp_formats);
534                 }
535                 if (max_streams < num_streams) {
536                         max_streams = num_streams;
537                 }
538                 ast_sdp_options_set_max_streams(options, max_streams);
539
540                 /* Determine new stream formats and types allowed */
541                 if (!opt_formats) {
542                         opt_num_streams = ARRAY_LEN(sdp_formats);
543                         opt_formats = sdp_formats;
544                 }
545                 if (build_sdp_option_formats(options, opt_num_streams, opt_formats)) {
546                         goto end;
547                 }
548         } else {
549                 options = test_options;
550         }
551
552         topology = ast_stream_topology_alloc();
553         if (!topology) {
554                 goto end;
555         }
556
557         for (i = 0; i < num_streams; ++i) {
558                 struct ast_stream *stream;
559
560                 stream = ast_stream_alloc("sure_thing", formats[i].type);
561                 if (!stream) {
562                         goto end;
563                 }
564                 if (!ast_strlen_zero(formats[i].formats)) {
565                         struct ast_format_cap *caps;
566
567                         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
568                         if (!caps
569                                 || ast_format_cap_update_by_allow_disallow(caps, formats[i].formats, 1) < 0) {
570                                 ao2_cleanup(caps);
571                                 ast_stream_free(stream);
572                                 goto end;
573                         }
574                         ast_stream_set_formats(stream, caps);
575                         ao2_cleanup(caps);
576                 } else {
577                         ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED);
578                 }
579                 if (ast_stream_topology_append_stream(topology, stream) < 0) {
580                         ast_stream_free(stream);
581                         goto end;
582                 }
583         }
584
585         state = ast_sdp_state_alloc(topology, options);
586         if (!state) {
587                 goto end;
588         }
589
590 end:
591         ast_stream_topology_free(topology);
592         if (!state) {
593                 ast_sdp_options_free(options);
594         }
595
596         return state;
597 }
598
599 AST_TEST_DEFINE(topology_to_sdp)
600 {
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" },
609         };
610
611         switch(cmd) {
612         case TEST_INIT:
613                 info->name = "topology_to_sdp";
614                 info->category = "/main/sdp/";
615                 info->summary = "Convert a topology into an SDP";
616                 info->description =
617                         "Ensure SDPs get converted to expected stream topology";
618                 return AST_TEST_NOT_RUN;
619         case TEST_EXECUTE:
620                 break;
621         }
622
623         sdp_state = build_sdp_state(ARRAY_LEN(formats), formats,
624                 ARRAY_LEN(formats), formats, 0, NULL);
625         if (!sdp_state) {
626                 goto end;
627         }
628
629         sdp = ast_sdp_state_get_local_sdp(sdp_state);
630         if (!sdp) {
631                 goto end;
632         }
633
634         if (validate_o_line(test, sdp->o_line, "me", "IP4", "127.0.0.1")) {
635                 goto end;
636         }
637
638         if (validate_c_line(test, sdp->c_line, "IP4", "127.0.0.1")) {
639                 goto end;
640         }
641
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));
645                 goto end;
646         }
647
648         m_line = ast_sdp_get_m(sdp, 0);
649
650         if (validate_m_line(test, m_line, "audio", 4)) {
651                 goto end;
652         }
653
654         if (validate_rtpmap(test, m_line, "PCMU")) {
655                 goto end;
656         }
657
658         if (validate_rtpmap(test, m_line, "PCMA")) {
659                 goto end;
660         }
661
662         if (validate_rtpmap(test, m_line, "G722")) {
663                 goto end;
664         }
665
666         if (validate_rtpmap(test, m_line, "opus")) {
667                 goto end;
668         }
669
670         m_line = ast_sdp_get_m(sdp, 1);
671         if (validate_m_line(test, m_line, "video", 2)) {
672                 goto end;
673         }
674
675         if (validate_rtpmap(test, m_line, "VP8")) {
676                 goto end;
677         }
678
679         if (validate_rtpmap(test, m_line, "H264")) {
680                 goto end;
681         }
682
683         m_line = ast_sdp_get_m(sdp, 2);
684         if (validate_m_line(test, m_line, "image", 1)) {
685                 goto end;
686         }
687         if (validate_t38(test, m_line) != AST_TEST_PASS) {
688                 goto end;
689         }
690
691         res = AST_TEST_PASS;
692
693 end:
694         ast_sdp_state_free(sdp_state);
695         return res;
696 }
697
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)
700 {
701         struct ast_stream *stream;
702         struct ast_format_cap *caps;
703         struct ast_format *format;
704         int i;
705
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");
709                 return -1;
710         }
711         caps = ast_stream_get_formats(stream);
712
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);
716                 return -1;
717         }
718
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]);
724                         return -1;
725                 }
726         }
727
728         return 0;
729 }
730
731 AST_TEST_DEFINE(sdp_to_topology)
732 {
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" },
741         };
742         static const char *expected_audio_formats[] = {
743                 "ulaw",
744                 "alaw",
745                 "g722",
746                 "opus",
747         };
748         static const char *expected_video_formats[] = {
749                 "h264",
750                 "vp8",
751         };
752         static const char *expected_image_formats[] = {
753                 "t38",
754         };
755
756         switch(cmd) {
757         case TEST_INIT:
758                 info->name = "sdp_to_topology";
759                 info->category = "/main/sdp/";
760                 info->summary = "Convert an SDP into a topology";
761                 info->description =
762                         "Ensure SDPs get converted to expected stream topology";
763                 return AST_TEST_NOT_RUN;
764         case TEST_EXECUTE:
765                 break;
766         }
767
768         sdp_state = build_sdp_state(ARRAY_LEN(sdp_formats), sdp_formats,
769                 ARRAY_LEN(sdp_formats), sdp_formats, 0, NULL);
770         if (!sdp_state) {
771                 res = AST_TEST_FAIL;
772                 goto end;
773         }
774
775         sdp = ast_sdp_state_get_local_sdp(sdp_state);
776         if (!sdp) {
777                 res = AST_TEST_FAIL;
778                 goto end;
779         }
780
781         topology = ast_get_topology_from_sdp(sdp, 0);
782         if (!topology) {
783                 res = AST_TEST_FAIL;
784                 goto end;
785         }
786
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));
790                 res = AST_TEST_FAIL;
791                 goto end;
792         }
793
794         if (validate_formats(test, topology, 0, AST_MEDIA_TYPE_AUDIO,
795                         ARRAY_LEN(expected_audio_formats), expected_audio_formats)) {
796                 res = AST_TEST_FAIL;
797                 goto end;
798         }
799
800         if (validate_formats(test, topology, 1, AST_MEDIA_TYPE_VIDEO,
801                         ARRAY_LEN(expected_video_formats), expected_video_formats)) {
802                 res = AST_TEST_FAIL;
803                 goto end;
804         }
805
806         if (validate_formats(test, topology, 2, AST_MEDIA_TYPE_IMAGE,
807                         ARRAY_LEN(expected_image_formats), expected_image_formats)) {
808                 res = AST_TEST_FAIL;
809                 goto end;
810         }
811
812 end:
813         ast_sdp_state_free(sdp_state);
814         ast_stream_topology_free(topology);
815         return res;
816 }
817
818 static int validate_avi_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp)
819 {
820         struct ast_sdp_m_line *m_line;
821
822         if (!sdp) {
823                 return -1;
824         }
825
826         m_line = ast_sdp_get_m(sdp, 0);
827         if (validate_m_line(test, m_line, "audio", 1)) {
828                 return -1;
829         }
830         if (validate_rtpmap(test, m_line, "PCMU")) {
831                 return -1;
832         }
833
834         /* The other audio formats should *NOT* be present */
835         if (!validate_rtpmap(test, m_line, "PCMA")) {
836                 return -1;
837         }
838         if (!validate_rtpmap(test, m_line, "G722")) {
839                 return -1;
840         }
841         if (!validate_rtpmap(test, m_line, "opus")) {
842                 return -1;
843         }
844
845         m_line = ast_sdp_get_m(sdp, 1);
846         if (validate_m_line(test, m_line, "video", 1)) {
847                 return -1;
848         }
849         if (validate_rtpmap(test, m_line, "VP8")) {
850                 return -1;
851         }
852         if (!validate_rtpmap(test, m_line, "H264")) {
853                 return -1;
854         }
855
856         m_line = ast_sdp_get_m(sdp, 2);
857         if (validate_m_line(test, m_line, "image", 1)) {
858                 return -1;
859         }
860
861         return 0;
862 }
863
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))
870 {
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;
876
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");
881                 res = AST_TEST_FAIL;
882                 goto end;
883         }
884
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");
889                 res = AST_TEST_FAIL;
890                 goto end;
891         }
892
893         offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer);
894         if (!offerer_sdp) {
895                 ast_test_status_update(test, "Building offerer offer failed\n");
896                 res = AST_TEST_FAIL;
897                 goto end;
898         }
899
900         if (ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp)) {
901                 ast_test_status_update(test, "Setting answerer offer failed\n");
902                 res = AST_TEST_FAIL;
903                 goto end;
904         }
905         answerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_answerer);
906         if (!answerer_sdp) {
907                 ast_test_status_update(test, "Building answerer answer failed\n");
908                 res = AST_TEST_FAIL;
909                 goto end;
910         }
911
912         if (ast_sdp_state_set_remote_sdp(sdp_state_offerer, answerer_sdp)) {
913                 ast_test_status_update(test, "Setting offerer answer failed\n");
914                 res = AST_TEST_FAIL;
915                 goto end;
916         }
917
918         /*
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.
922          */
923         if (ast_sdp_state_restart_negotiations(sdp_state_offerer)) {
924                 ast_test_status_update(test, "Restarting negotiations failed\n");
925                 res = AST_TEST_FAIL;
926                 goto end;
927         }
928         offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer);
929         if (!offerer_sdp) {
930                 ast_test_status_update(test, "Building offerer current sdp failed\n");
931                 res = AST_TEST_FAIL;
932                 goto end;
933         }
934         if (validate_sdp(test, offerer_sdp)) {
935                 res = AST_TEST_FAIL;
936                 goto end;
937         }
938         if (validate_sdp(test, answerer_sdp)) {
939                 res = AST_TEST_FAIL;
940                 goto end;
941         }
942
943 end:
944         ast_sdp_state_free(sdp_state_offerer);
945         ast_sdp_state_free(sdp_state_answerer);
946
947         return res;
948 }
949
950 AST_TEST_DEFINE(sdp_negotiation_initial)
951 {
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" },
956         };
957
958         switch(cmd) {
959         case TEST_INIT:
960                 info->name = "sdp_negotiation_initial";
961                 info->category = "/main/sdp/";
962                 info->summary = "Simulate an initial negotiation";
963                 info->description =
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;
968         case TEST_EXECUTE:
969                 break;
970         }
971
972         return sdp_negotiation_completed_tests(test,
973                 ARRAY_LEN(offerer_formats), offerer_formats,
974                 0, NULL,
975                 0, NULL,
976                 0,
977                 validate_avi_sdp_streams);
978 }
979
980 AST_TEST_DEFINE(sdp_negotiation_type_change)
981 {
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" },
986         };
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" },
991         };
992
993         switch(cmd) {
994         case TEST_INIT:
995                 info->name = "sdp_negotiation_type_change";
996                 info->category = "/main/sdp/";
997                 info->summary = "Simulate a re-negotiation changing stream types";
998                 info->description =
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;
1003         case TEST_EXECUTE:
1004                 break;
1005         }
1006
1007         return sdp_negotiation_completed_tests(test,
1008                 ARRAY_LEN(offerer_formats), offerer_formats,
1009                 ARRAY_LEN(answerer_formats), answerer_formats,
1010                 0, NULL,
1011                 0,
1012                 validate_avi_sdp_streams);
1013 }
1014
1015 static int validate_aviavia_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp)
1016 {
1017         struct ast_sdp_m_line *m_line;
1018
1019         if (!sdp) {
1020                 return -1;
1021         }
1022
1023         m_line = ast_sdp_get_m(sdp, 0);
1024         if (validate_m_line_declined(test, m_line, "audio")) {
1025                 return -1;
1026         }
1027
1028         m_line = ast_sdp_get_m(sdp, 1);
1029         if (validate_m_line_declined(test, m_line, "video")) {
1030                 return -1;
1031         }
1032
1033         m_line = ast_sdp_get_m(sdp, 2);
1034         if (validate_m_line_declined(test, m_line, "image")) {
1035                 return -1;
1036         }
1037
1038         m_line = ast_sdp_get_m(sdp, 3);
1039         if (validate_m_line_declined(test, m_line, "audio")) {
1040                 return -1;
1041         }
1042
1043         m_line = ast_sdp_get_m(sdp, 4);
1044         if (validate_m_line_declined(test, m_line, "video")) {
1045                 return -1;
1046         }
1047
1048         m_line = ast_sdp_get_m(sdp, 5);
1049         if (validate_m_line_declined(test, m_line, "image")) {
1050                 return -1;
1051         }
1052
1053         m_line = ast_sdp_get_m(sdp, 6);
1054         if (validate_m_line(test, m_line, "audio", 1)) {
1055                 return -1;
1056         }
1057         if (validate_rtpmap(test, m_line, "PCMU")) {
1058                 return -1;
1059         }
1060
1061         /* The other audio formats should *NOT* be present */
1062         if (!validate_rtpmap(test, m_line, "PCMA")) {
1063                 return -1;
1064         }
1065
1066         return 0;
1067 }
1068
1069 AST_TEST_DEFINE(sdp_negotiation_decline_incompatible)
1070 {
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" },
1082         };
1083         static const struct sdp_format allowed_formats[] = {
1084                 { AST_MEDIA_TYPE_AUDIO, "ulaw" },
1085         };
1086
1087         switch(cmd) {
1088         case TEST_INIT:
1089                 info->name = "sdp_negotiation_decline_incompatible";
1090                 info->category = "/main/sdp/";
1091                 info->summary = "Simulate an initial negotiation declining streams";
1092                 info->description =
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;
1097         case TEST_EXECUTE:
1098                 break;
1099         }
1100
1101         return sdp_negotiation_completed_tests(test,
1102                 ARRAY_LEN(offerer_formats), offerer_formats,
1103                 0, NULL,
1104                 ARRAY_LEN(allowed_formats), allowed_formats,
1105                 ARRAY_LEN(offerer_formats),
1106                 validate_aviavia_declined_sdp_streams);
1107 }
1108
1109 static int validate_aaaa_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp)
1110 {
1111         struct ast_sdp_m_line *m_line;
1112
1113         if (!sdp) {
1114                 return -1;
1115         }
1116
1117         m_line = ast_sdp_get_m(sdp, 0);
1118         if (validate_m_line(test, m_line, "audio", 1)) {
1119                 return -1;
1120         }
1121         if (validate_rtpmap(test, m_line, "PCMU")) {
1122                 return -1;
1123         }
1124
1125         m_line = ast_sdp_get_m(sdp, 1);
1126         if (validate_m_line(test, m_line, "audio", 1)) {
1127                 return -1;
1128         }
1129         if (validate_rtpmap(test, m_line, "PCMU")) {
1130                 return -1;
1131         }
1132
1133         m_line = ast_sdp_get_m(sdp, 2);
1134         if (validate_m_line(test, m_line, "audio", 1)) {
1135                 return -1;
1136         }
1137         if (validate_rtpmap(test, m_line, "PCMU")) {
1138                 return -1;
1139         }
1140
1141         m_line = ast_sdp_get_m(sdp, 3);
1142         if (validate_m_line_declined(test, m_line, "audio")) {
1143                 return -1;
1144         }
1145
1146         return 0;
1147 }
1148
1149 AST_TEST_DEFINE(sdp_negotiation_decline_max_streams)
1150 {
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" },
1156         };
1157
1158         switch(cmd) {
1159         case TEST_INIT:
1160                 info->name = "sdp_negotiation_decline_max_streams";
1161                 info->category = "/main/sdp/";
1162                 info->summary = "Simulate an initial negotiation declining excessive streams";
1163                 info->description =
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;
1168         case TEST_EXECUTE:
1169                 break;
1170         }
1171
1172         return sdp_negotiation_completed_tests(test,
1173                 ARRAY_LEN(offerer_formats), offerer_formats,
1174                 0, NULL,
1175                 0, NULL,
1176                 0,
1177                 validate_aaaa_declined_sdp_streams);
1178 }
1179
1180 AST_TEST_DEFINE(sdp_negotiation_not_acceptable)
1181 {
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;
1186
1187         static const struct sdp_format offerer_formats[] = {
1188                 { AST_MEDIA_TYPE_AUDIO, "alaw" },
1189                 { AST_MEDIA_TYPE_AUDIO, "alaw" },
1190         };
1191
1192         switch(cmd) {
1193         case TEST_INIT:
1194                 info->name = "sdp_negotiation_not_acceptable";
1195                 info->category = "/main/sdp/";
1196                 info->summary = "Simulate an initial negotiation declining all streams";
1197                 info->description =
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;
1201         case TEST_EXECUTE:
1202                 break;
1203         }
1204
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;
1209                 goto end;
1210         }
1211
1212         sdp_state_answerer = build_sdp_state(0, NULL, 0, NULL, 0, NULL);
1213         if (!sdp_state_answerer) {
1214                 res = AST_TEST_FAIL;
1215                 goto end;
1216         }
1217
1218         offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer);
1219         if (!offerer_sdp) {
1220                 res = AST_TEST_FAIL;
1221                 goto end;
1222         }
1223
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;
1227                 goto end;
1228         }
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;
1232                 goto end;
1233         }
1234
1235 end:
1236         ast_sdp_state_free(sdp_state_offerer);
1237         ast_sdp_state_free(sdp_state_answerer);
1238
1239         return res;
1240 }
1241
1242 static int validate_ssrc(struct ast_test *test, struct ast_sdp_m_line *m_line,
1243         struct ast_rtp_instance *rtp)
1244 {
1245         unsigned int ssrc;
1246         const char *cname;
1247         struct ast_sdp_a_line *a_line;
1248         char attr_value[128];
1249
1250         ssrc = ast_rtp_instance_get_ssrc(rtp);
1251         cname = ast_rtp_instance_get_cname(rtp);
1252
1253         snprintf(attr_value, sizeof(attr_value), "%u cname:%s", ssrc, cname);
1254
1255         a_line = ast_sdp_m_find_attribute(m_line, "ssrc", -1);
1256         if (!a_line) {
1257                 ast_test_status_update(test, "Could not find 'ssrc' attribute\n");
1258                 return -1;
1259         }
1260
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);
1264                 return -1;
1265         }
1266
1267         return 0;
1268 }
1269
1270 AST_TEST_DEFINE(sdp_ssrc_attributes)
1271 {
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" },
1277         };
1278         const struct ast_sdp *sdp;
1279         struct ast_sdp_m_line *m_line;
1280         struct ast_rtp_instance *rtp;
1281
1282         switch(cmd) {
1283         case TEST_INIT:
1284                 info->name = "sdp_ssrc_attributes";
1285                 info->category = "/main/sdp/";
1286                 info->summary = "Ensure SSRC-level attributes are added to local SDPs";
1287                 info->description =
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;
1292         case TEST_EXECUTE:
1293                 break;
1294         }
1295
1296         res = AST_TEST_FAIL;
1297
1298         options = sdp_options_common();
1299         if (!options) {
1300                 ast_test_status_update(test, "Failed to allocate SDP options\n");
1301                 goto end;
1302         }
1303         if (build_sdp_option_formats(options, ARRAY_LEN(formats), formats)) {
1304                 goto end;
1305         }
1306         ast_sdp_options_set_ssrc(options, 1);
1307
1308         test_state = build_sdp_state(ARRAY_LEN(formats), formats, 0, NULL, 0, options);
1309         if (!test_state) {
1310                 ast_test_status_update(test, "Failed to create SDP state\n");
1311                 goto end;
1312         }
1313
1314         sdp = ast_sdp_state_get_local_sdp(test_state);
1315         if (!sdp) {
1316                 ast_test_status_update(test, "Failed to get local SDP\n");
1317                 goto end;
1318         }
1319
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));
1324                 goto end;
1325         }
1326
1327         m_line = ast_sdp_get_m(sdp, 0);
1328         if (!m_line) {
1329                 ast_test_status_update(test, "Failed to get SDP m-line\n");
1330                 goto end;
1331         }
1332
1333         rtp = ast_sdp_state_get_rtp_instance(test_state, 0);
1334         if (!rtp) {
1335                 ast_test_status_update(test, "Failed to get the RTP instance\n");
1336                 goto end;
1337         }
1338
1339         if (validate_ssrc(test, m_line, rtp)) {
1340                 goto end;
1341         }
1342
1343         res = AST_TEST_PASS;
1344
1345 end:
1346         ast_sdp_state_free(test_state);
1347         return res;
1348 }
1349
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. */
1358         const char *name;
1359 };
1360
1361 struct sdp_update_test {
1362         /*! Maximum number of streams.  (0 if default) */
1363         int max_streams;
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;
1372 };
1373
1374 static struct ast_stream_topology *build_update_topology(const struct sdp_topology_stream * const *spec)
1375 {
1376         struct ast_stream_topology *topology;
1377         const struct sdp_topology_stream *desc;
1378
1379         topology = ast_stream_topology_alloc();
1380         if (!topology) {
1381                 return NULL;
1382         }
1383
1384         for (desc = *spec; desc; ++spec, desc = *spec) {
1385                 struct ast_stream *stream;
1386                 const char *name;
1387
1388                 name = desc->name ?: ast_codec_media_type2str(desc->type);
1389                 stream = ast_stream_alloc(name, desc->type);
1390                 if (!stream) {
1391                         goto fail;
1392                 }
1393                 ast_stream_set_state(stream, desc->state);
1394                 if (desc->formats) {
1395                         struct ast_format_cap *caps;
1396
1397                         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
1398                         if (!caps
1399                                 || ast_format_cap_update_by_allow_disallow(caps, desc->formats, 1) < 0) {
1400                                 ao2_cleanup(caps);
1401                                 ast_stream_free(stream);
1402                                 goto fail;
1403                         }
1404                         ast_stream_set_formats(stream, caps);
1405                         ao2_ref(caps, -1);
1406                 }
1407                 if (ast_stream_topology_append_stream(topology, stream) < 0) {
1408                         ast_stream_free(stream);
1409                         goto fail;
1410                 }
1411         }
1412         return topology;
1413
1414 fail:
1415         ast_stream_topology_free(topology);
1416         return NULL;
1417 }
1418
1419 static int cmp_update_topology(struct ast_test *test,
1420         const struct ast_stream_topology *expected, const struct ast_stream_topology *merged)
1421 {
1422         int status = 0;
1423         int idx;
1424         int max_streams;
1425         struct ast_stream *exp_stream;
1426         struct ast_stream *mrg_stream;
1427
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",
1432                         idx, max_streams);
1433                 status = -1;
1434         }
1435         if (idx < max_streams) {
1436                 max_streams = idx;
1437         }
1438
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);
1443
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",
1447                                 idx,
1448                                 ast_stream_get_name(exp_stream),
1449                                 ast_stream_get_name(mrg_stream));
1450                         status = -1;
1451                 }
1452
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",
1456                                 idx,
1457                                 ast_stream_state2str(ast_stream_get_state(exp_stream)),
1458                                 ast_stream_state2str(ast_stream_get_state(mrg_stream)));
1459                         status = -1;
1460                 }
1461
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",
1465                                 idx,
1466                                 ast_codec_media_type2str(ast_stream_get_type(exp_stream)),
1467                                 ast_codec_media_type2str(ast_stream_get_type(mrg_stream)));
1468                         status = -1;
1469                         continue;
1470                 }
1471
1472                 if (ast_stream_get_state(exp_stream) == AST_STREAM_STATE_REMOVED
1473                         || ast_stream_get_state(mrg_stream) == AST_STREAM_STATE_REMOVED) {
1474                         /*
1475                          * Cannot compare formats if one of the streams is
1476                          * declined because there may not be any on the declined
1477                          * stream.
1478                          */
1479                         continue;
1480                 }
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",
1485                                 idx);
1486                         status = -1;
1487                 }
1488         }
1489
1490         return status;
1491 }
1492
1493
1494 static const struct sdp_topology_stream audio_declined_no_name = {
1495         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_REMOVED, NULL, NULL
1496 };
1497
1498 static const struct sdp_topology_stream audio_ulaw_no_name = {
1499         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "ulaw", NULL
1500 };
1501
1502 static const struct sdp_topology_stream audio_alaw_no_name = {
1503         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "alaw", NULL
1504 };
1505
1506 static const struct sdp_topology_stream audio_g722_no_name = {
1507         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g722", NULL
1508 };
1509
1510 static const struct sdp_topology_stream audio_g723_no_name = {
1511         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g723", NULL
1512 };
1513
1514 static const struct sdp_topology_stream video_declined_no_name = {
1515         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, NULL, NULL
1516 };
1517
1518 static const struct sdp_topology_stream video_h261_no_name = {
1519         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h261", NULL
1520 };
1521
1522 static const struct sdp_topology_stream video_h263_no_name = {
1523         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h263", NULL
1524 };
1525
1526 static const struct sdp_topology_stream video_h264_no_name = {
1527         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h264", NULL
1528 };
1529
1530 static const struct sdp_topology_stream video_vp8_no_name = {
1531         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "vp8", NULL
1532 };
1533
1534 static const struct sdp_topology_stream image_declined_no_name = {
1535         AST_MEDIA_TYPE_IMAGE, AST_STREAM_STATE_REMOVED, NULL, NULL
1536 };
1537
1538 static const struct sdp_topology_stream image_t38_no_name = {
1539         AST_MEDIA_TYPE_IMAGE, AST_STREAM_STATE_SENDRECV, "t38", NULL
1540 };
1541
1542
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,
1547         &video_vp8_no_name,
1548         NULL
1549 };
1550
1551 static const struct sdp_topology_stream *top__vp8_alaw_h264_ulaw[] = {
1552         &video_vp8_no_name,
1553         &audio_alaw_no_name,
1554         &video_h264_no_name,
1555         &audio_ulaw_no_name,
1556         NULL
1557 };
1558
1559 static const struct sdp_topology_stream *top_alaw_ulaw__vp8_h264[] = {
1560         &audio_alaw_no_name,
1561         &audio_ulaw_no_name,
1562         &video_vp8_no_name,
1563         &video_h264_no_name,
1564         NULL
1565 };
1566
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,
1572 };
1573
1574
1575 static const struct sdp_topology_stream *top_alaw__vp8[] = {
1576         &audio_alaw_no_name,
1577         &video_vp8_no_name,
1578         NULL
1579 };
1580
1581 static const struct sdp_topology_stream *top_h264__vp8_ulaw[] = {
1582         &video_h264_no_name,
1583         &video_vp8_no_name,
1584         &audio_ulaw_no_name,
1585         NULL
1586 };
1587
1588 static const struct sdp_topology_stream *top_ulaw_h264__vp8[] = {
1589         &audio_ulaw_no_name,
1590         &video_h264_no_name,
1591         &video_vp8_no_name,
1592         NULL
1593 };
1594
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,
1600 };
1601
1602
1603 static const struct sdp_topology_stream *top_alaw__vp8_vdec[] = {
1604         &audio_alaw_no_name,
1605         &video_vp8_no_name,
1606         &video_declined_no_name,
1607         NULL
1608 };
1609
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,
1615 };
1616
1617
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,
1622         NULL
1623 };
1624
1625 static const struct sdp_topology_stream *top__t38[] = {
1626         &image_t38_no_name,
1627         NULL
1628 };
1629
1630 static const struct sdp_topology_stream *top_vdec__t38_adec[] = {
1631         &video_declined_no_name,
1632         &image_t38_no_name,
1633         &audio_declined_no_name,
1634         NULL
1635 };
1636
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,
1642 };
1643
1644
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,
1650 };
1651
1652
1653 static const struct sdp_topology_stream *top_h264[] = {
1654         &video_h264_no_name,
1655         NULL
1656 };
1657
1658 static const struct sdp_topology_stream *top_vdec__t38[] = {
1659         &video_declined_no_name,
1660         &image_t38_no_name,
1661         NULL
1662 };
1663
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,
1669 };
1670
1671
1672 static const struct sdp_topology_stream *top_h264_idec[] = {
1673         &video_h264_no_name,
1674         &image_declined_no_name,
1675         NULL
1676 };
1677
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,
1683 };
1684
1685
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,
1690         &video_vp8_no_name,
1691         NULL
1692 };
1693
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,
1699         &video_vp8_no_name,
1700         NULL
1701 };
1702
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,
1708         &video_vp8_no_name,
1709         NULL
1710 };
1711
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,
1717 };
1718
1719
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,
1724         &video_vp8_no_name,
1725         &video_h261_no_name,
1726         NULL
1727 };
1728
1729 /* Sorting by type overlimit of 4 and drop */
1730 static const struct sdp_update_test mrg_by_type_08 = {
1731         .max_streams = 4,
1732         .initial  = top_ulaw_alaw_h264__vp8,
1733         .update_1 = top_ulaw_alaw_h264__vp8_h261,
1734         .expected = top_ulaw_alaw_h264__vp8,
1735 };
1736
1737
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,
1742         NULL
1743 };
1744
1745 static const struct sdp_topology_stream *top_alaw_h261__vp8[] = {
1746         &audio_alaw_no_name,
1747         &video_h261_no_name,
1748         &video_vp8_no_name,
1749         NULL
1750 };
1751
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,
1756         &video_vp8_no_name,
1757         NULL
1758 };
1759
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,
1765 };
1766
1767
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,
1772         NULL
1773 };
1774
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,
1780 };
1781
1782
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,
1787         NULL
1788 };
1789
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,
1795 };
1796
1797
1798 static const struct sdp_topology_stream audio_alaw4dave = {
1799         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "alaw", "dave"
1800 };
1801
1802 static const struct sdp_topology_stream audio_g7224dave = {
1803         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g722", "dave"
1804 };
1805
1806 static const struct sdp_topology_stream audio_ulaw4fred = {
1807         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "ulaw", "fred"
1808 };
1809
1810 static const struct sdp_topology_stream audio_alaw4fred = {
1811         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "alaw", "fred"
1812 };
1813
1814 static const struct sdp_topology_stream audio_ulaw4rose = {
1815         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "ulaw", "rose"
1816 };
1817
1818 static const struct sdp_topology_stream audio_g7224rose = {
1819         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g722", "rose"
1820 };
1821
1822
1823 static const struct sdp_topology_stream video_h2614dave = {
1824         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h261", "dave"
1825 };
1826
1827 static const struct sdp_topology_stream video_h2634dave = {
1828         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h263", "dave"
1829 };
1830
1831 static const struct sdp_topology_stream video_h2634fred = {
1832         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h263", "fred"
1833 };
1834
1835 static const struct sdp_topology_stream video_h2644fred = {
1836         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h264", "fred"
1837 };
1838
1839 static const struct sdp_topology_stream video_h2644rose = {
1840         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h264", "rose"
1841 };
1842
1843 static const struct sdp_topology_stream video_h2614rose = {
1844         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h261", "rose"
1845 };
1846
1847
1848 static const struct sdp_topology_stream *top_adave_alaw_afred_ulaw_arose_g722_vdave_h261_vfred_h263_vrose_h264[] = {
1849         &audio_alaw4dave,
1850         &audio_alaw_no_name,
1851         &audio_ulaw4fred,
1852         &audio_ulaw_no_name,
1853         &audio_g7224rose,
1854         &audio_g722_no_name,
1855         &video_h2614dave,
1856         &video_h261_no_name,
1857         &video_h2634fred,
1858         &video_h263_no_name,
1859         &video_h2644rose,
1860         &video_h264_no_name,
1861         NULL
1862 };
1863
1864 static const struct sdp_topology_stream *top_vfred_vrose_vdave_h263_h264_h261_afred_ulaw_arose_g722_adave_alaw[] = {
1865         &video_h2644fred,
1866         &video_h2614rose,
1867         &video_h2634dave,
1868         &video_h263_no_name,
1869         &video_h264_no_name,
1870         &video_h261_no_name,
1871         &audio_alaw4fred,
1872         &audio_ulaw_no_name,
1873         &audio_ulaw4rose,
1874         &audio_g722_no_name,
1875         &audio_g7224dave,
1876         &audio_alaw_no_name,
1877         NULL
1878 };
1879
1880 static const struct sdp_topology_stream *top_adave_ulaw_afred_g722_arose_alaw_vdave_h263_vfred_h264_vrose_h261[] = {
1881         &audio_g7224dave,
1882         &audio_ulaw_no_name,
1883         &audio_alaw4fred,
1884         &audio_g722_no_name,
1885         &audio_ulaw4rose,
1886         &audio_alaw_no_name,
1887         &video_h2634dave,
1888         &video_h263_no_name,
1889         &video_h2644fred,
1890         &video_h264_no_name,
1891         &video_h2614rose,
1892         &video_h261_no_name,
1893         NULL
1894 };
1895
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,
1901 };
1902
1903
1904 static const struct sdp_topology_stream *top_adave_g723_h261[] = {
1905         &audio_g7224dave,
1906         &audio_g723_no_name,
1907         &video_h261_no_name,
1908         NULL
1909 };
1910
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,
1916 };
1917
1918
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,
1924 };
1925
1926
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,
1941
1942         /* Merging by name and type */
1943         /* 12 */ &mrg_by_name_00,
1944         /* 13 */ &mrg_by_name_01,
1945         /* 14 */ &mrg_by_name_02,
1946 };
1947
1948 AST_TEST_DEFINE(sdp_update_topology)
1949 {
1950         enum ast_test_result_state res;
1951         unsigned int idx;
1952         int status;
1953         struct ast_sdp_options *options;
1954         struct ast_stream_topology *topology;
1955         struct ast_sdp_state *test_state = NULL;
1956
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" },
1961         };
1962
1963         switch(cmd) {
1964         case TEST_INIT:
1965                 info->name = "sdp_update_topology";
1966                 info->category = "/main/sdp/";
1967                 info->summary = "Merge topology updates from the system";
1968                 info->description =
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;
1975         case TEST_EXECUTE:
1976                 break;
1977         }
1978
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);
1982
1983                 /* Create a SDP state with an optional initial topology. */
1984                 options = sdp_options_common();
1985                 if (!options) {
1986                         ast_test_status_update(test, "Failed to allocate SDP options\n");
1987                         goto end;
1988                 }
1989                 if (sdp_update_cases[idx]->max_streams) {
1990                         ast_sdp_options_set_max_streams(options, sdp_update_cases[idx]->max_streams);
1991                 }
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");
1994                         goto end;
1995                 }
1996                 if (sdp_update_cases[idx]->initial) {
1997                         topology = build_update_topology(sdp_update_cases[idx]->initial);
1998                         if (!topology) {
1999                                 ast_test_status_update(test, "Failed to build initial SDP state topology\n");
2000                                 goto end;
2001                         }
2002                 } else {
2003                         topology = NULL;
2004                 }
2005                 test_state = ast_sdp_state_alloc(topology, options);
2006                 ast_stream_topology_free(topology);
2007                 if (!test_state) {
2008                         ast_test_status_update(test, "Failed to build SDP state\n");
2009                         goto end;
2010                 }
2011
2012                 /* Update the initial topology with one or two new topologies. */
2013                 topology = build_update_topology(sdp_update_cases[idx]->update_1);
2014                 if (!topology) {
2015                         ast_test_status_update(test, "Failed to build first update SDP state topology\n");
2016                         goto end;
2017                 }
2018                 status = ast_sdp_state_update_local_topology(test_state, topology);
2019                 ast_stream_topology_free(topology);
2020                 if (status) {
2021                         ast_test_status_update(test, "Failed to update first update SDP state topology\n");
2022                         goto end;
2023                 }
2024                 if (sdp_update_cases[idx]->update_2) {
2025                         topology = build_update_topology(sdp_update_cases[idx]->update_2);
2026                         if (!topology) {
2027                                 ast_test_status_update(test, "Failed to build second update SDP state topology\n");
2028                                 goto end;
2029                         }
2030                         status = ast_sdp_state_update_local_topology(test_state, topology);
2031                         ast_stream_topology_free(topology);
2032                         if (status) {
2033                                 ast_test_status_update(test, "Failed to update second update SDP state topology\n");
2034                                 goto end;
2035                         }
2036                 }
2037
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");
2041                         goto end;
2042                 }
2043
2044                 /* Check that the offered topology matches the expected topology. */
2045                 topology = build_update_topology(sdp_update_cases[idx]->expected);
2046                 if (!topology) {
2047                         ast_test_status_update(test, "Failed to build expected topology\n");
2048                         goto end;
2049                 }
2050                 status = cmp_update_topology(test, topology,
2051                         ast_sdp_state_get_local_topology(test_state));
2052                 ast_stream_topology_free(topology);
2053                 if (status) {
2054                         ast_test_status_update(test, "Failed to match expected topology\n");
2055                         goto end;
2056                 }
2057
2058                 /* Repeat for each test case defined. */
2059                 ast_sdp_state_free(test_state);
2060                 test_state = NULL;
2061         }
2062         res = AST_TEST_PASS;
2063
2064 end:
2065         ast_sdp_state_free(test_state);
2066         return res;
2067 }
2068
2069 static int unload_module(void)
2070 {
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);
2083
2084         return 0;
2085 }
2086
2087 static int load_module(void)
2088 {
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);
2101
2102         return AST_MODULE_LOAD_SUCCESS;
2103 }
2104
2105 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SDP tests");