SDP: Rework SDP offer/answer model and update capabilities merges.
[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 (ast_sdp_m_get_payload_count(m_line) != num_payloads) {
92                 ast_test_status_update(test, "Expected %s m-line payload count %d but got %d\n",
93                         media_type, num_payloads, ast_sdp_m_get_payload_count(m_line));
94                 return -1;
95         }
96
97         ast_test_status_update(test, "SDP %s m-line is as expected\n", media_type);
98         return 0;
99 }
100
101 static int validate_m_line_declined(struct ast_test *test,
102         const struct ast_sdp_m_line *m_line, const char *media_type)
103 {
104         if (strcmp(m_line->type, media_type)) {
105                 ast_test_status_update(test, "Expected m-line media type %s but got %s\n",
106                         media_type, m_line->type);
107                 return -1;
108         }
109
110         if (m_line->port != 0) {
111                 ast_test_status_update(test, "Expected %s m-line to be declined but got port %u\n",
112                         media_type, m_line->port);
113                 return -1;
114         }
115
116         ast_test_status_update(test, "SDP %s m-line is as expected\n", media_type);
117         return 0;
118 }
119
120 static int validate_rtpmap(struct ast_test *test, const struct ast_sdp_m_line *m_line,
121         const char *media_name)
122 {
123         struct ast_sdp_a_line *a_line;
124         int i;
125
126         for (i = 0; i < ast_sdp_m_get_a_count(m_line); ++i) {
127                 struct ast_sdp_rtpmap *rtpmap;
128                 int match;
129
130                 a_line = ast_sdp_m_get_a(m_line, i);
131                 if (strcmp(a_line->name, "rtpmap")) {
132                         continue;
133                 }
134
135                 rtpmap = ast_sdp_a_get_rtpmap(a_line);
136                 if (!rtpmap) {
137                         return -1;
138                 }
139
140                 match = !strcmp(rtpmap->encoding_name, media_name);
141
142                 ast_sdp_rtpmap_free(rtpmap);
143                 if (match) {
144                         return 0;
145                 }
146         }
147
148         ast_test_status_update(test, "Could not find rtpmap with encoding name %s\n", media_name);
149
150         return -1;
151 }
152
153 static enum ast_test_result_state validate_t38(struct ast_test *test, const struct ast_sdp_m_line *m_line)
154 {
155         struct ast_sdp_a_line *a_line;
156
157         a_line = ast_sdp_m_find_attribute(m_line, "T38FaxVersion", -1);
158         ast_test_validate(test, a_line && !strcmp(a_line->value, "0"));
159
160         a_line = ast_sdp_m_find_attribute(m_line, "T38FaxMaxBitRate", -1);
161         ast_test_validate(test, a_line && !strcmp(a_line->value, "14400"));
162
163         a_line = ast_sdp_m_find_attribute(m_line, "T38FaxRateManagement", -1);
164         ast_test_validate(test, a_line && !strcmp(a_line->value, "transferredTCF"));
165
166         return AST_TEST_PASS;
167 }
168
169 AST_TEST_DEFINE(invalid_rtpmap)
170 {
171         /* a=rtpmap: is already assumed. This is the part after that */
172         static const char *invalids[] = {
173                 "J PCMU/8000",
174                 "0 PCMU:8000",
175                 "0 PCMU/EIGHT-THOUSAND",
176                 "0 PCMU/8000million/2",
177                 "0 PCMU//2",
178                 "0 /8000/2",
179                 "0 PCMU/8000/",
180                 "0 PCMU/8000million",
181         };
182         int i;
183         enum ast_test_result_state res = AST_TEST_PASS;
184
185         switch(cmd) {
186         case TEST_INIT:
187                 info->name = "invalid_rtpmap";
188                 info->category = "/main/sdp/";
189                 info->summary = "Ensure invalid rtpmaps are rejected";
190                 info->description =
191                         "Try to convert several invalid rtpmap attributes. If\n"
192                         "any succeeds, the test fails.";
193                 return AST_TEST_NOT_RUN;
194         case TEST_EXECUTE:
195                 break;
196         }
197
198         for (i = 0; i < ARRAY_LEN(invalids); ++i) {
199                 struct ast_sdp_a_line *a_line;
200                 struct ast_sdp_rtpmap *rtpmap;
201
202                 a_line = ast_sdp_a_alloc("rtpmap", invalids[i]);
203                 rtpmap = ast_sdp_a_get_rtpmap(a_line);
204                 if (rtpmap) {
205                         ast_test_status_update(test, "Invalid rtpmap '%s' was accepted as valid\n",
206                                 invalids[i]);
207                         res = AST_TEST_FAIL;
208                 }
209                 ast_sdp_a_free(a_line);
210                 ast_sdp_rtpmap_free(rtpmap);
211         }
212
213         return res;
214 }
215
216 AST_TEST_DEFINE(rtpmap)
217 {
218         static const char *valids[] = {
219                 "0 PCMU/8000",
220                 "107 opus/48000/2",
221         };
222         static int payloads[] = {
223                 0,
224                 107,
225         };
226         static const char *encoding_names[] = {
227                 "PCMU",
228                 "opus",
229         };
230         static int clock_rates[] = {
231                 8000,
232                 48000,
233         };
234         static const char *encoding_parameters[] = {
235                 "",
236                 "2",
237         };
238         int i;
239         enum ast_test_result_state res = AST_TEST_PASS;
240
241         switch(cmd) {
242         case TEST_INIT:
243                 info->name = "rtpmap";
244                 info->category = "/main/sdp/";
245                 info->summary = "Ensure rtpmap attribute values are parsed correctly";
246                 info->description =
247                         "Parse several valid rtpmap attributes. Ensure that the parsed values\n"
248                         "are what we expect";
249                 return AST_TEST_NOT_RUN;
250         case TEST_EXECUTE:
251                 break;
252         }
253
254         for (i = 0; i < ARRAY_LEN(valids); ++i) {
255                 struct ast_sdp_a_line *a_line;
256                 struct ast_sdp_rtpmap *rtpmap;
257
258                 a_line = ast_sdp_a_alloc("rtpmap", valids[i]);
259                 rtpmap = ast_sdp_a_get_rtpmap(a_line);
260                 if (!rtpmap) {
261                         ast_test_status_update(test, "Valid rtpmap '%s' was rejected as invalid\n",
262                                 valids[i]);
263                         res = AST_TEST_FAIL;
264                         continue;
265                 }
266                 if (rtpmap->payload != payloads[i]) {
267                         ast_test_status_update(test, "RTPmap payload '%d' does not match expected '%d'\n",
268                                 rtpmap->payload, payloads[i]);
269                         res = AST_TEST_FAIL;
270                 }
271                 if (strcmp(rtpmap->encoding_name, encoding_names[i])) {
272                         ast_test_status_update(test, "RTPmap encoding_name '%s' does not match expected '%s'\n",
273                                 rtpmap->encoding_name, encoding_names[i]);
274                         res = AST_TEST_FAIL;
275                 }
276                 if (rtpmap->clock_rate != clock_rates[i]) {
277                         ast_test_status_update(test, "RTPmap clock rate '%d' does not match expected '%d'\n",
278                                 rtpmap->clock_rate, clock_rates[i]);
279                         res = AST_TEST_FAIL;
280                 }
281                 if (strcmp(rtpmap->encoding_parameters, encoding_parameters[i])) {
282                         ast_test_status_update(test, "RTPmap encoding_parameter '%s' does not match expected '%s'\n",
283                                 rtpmap->encoding_parameters, encoding_parameters[i]);
284                         res = AST_TEST_FAIL;
285                 }
286                 ast_sdp_a_free(a_line);
287                 ast_sdp_rtpmap_free(rtpmap);
288         }
289
290         return res;
291 }
292
293 AST_TEST_DEFINE(find_attr)
294 {
295         enum ast_test_result_state res = AST_TEST_PASS;
296         struct ast_sdp_m_line *m_line;
297         struct ast_sdp_a_line *a_line;
298         int idx;
299
300         switch(cmd) {
301         case TEST_INIT:
302                 info->name = "find_attr";
303                 info->category = "/main/sdp/";
304                 info->summary = "Ensure that finding attributes works as expected";
305                 info->description =
306                         "A SDP m-line is created, and attributes are added.\n"
307                         "We then attempt a series of attribute-finding calls that are expected to work\n"
308                         "followed by a series of attribute-finding calls that are expected fo fail.";
309                 return AST_TEST_NOT_RUN;
310         case TEST_EXECUTE:
311                 break;
312         }
313
314         m_line = ast_sdp_m_alloc("audio", 666, 1, "RTP/AVP", NULL);
315         if (!m_line) {
316                 res = AST_TEST_FAIL;
317                 goto end;
318         }
319         a_line = ast_sdp_a_alloc("foo", "0 bar");
320         if (!a_line) {
321                 res = AST_TEST_FAIL;
322                 goto end;
323         }
324         ast_sdp_m_add_a(m_line, a_line);
325         a_line = ast_sdp_a_alloc("foo", "0 bee");
326         if (!a_line) {
327                 res = AST_TEST_FAIL;
328                 goto end;
329         }
330         ast_sdp_m_add_a(m_line, a_line);
331
332         a_line = ast_sdp_a_alloc("baz", "howdy");
333         if (!a_line) {
334                 res = AST_TEST_FAIL;
335                 goto end;
336         }
337         ast_sdp_m_add_a(m_line, a_line);
338
339         /* These should work */
340         a_line = ast_sdp_m_find_attribute(m_line, "foo", 0);
341         if (!a_line || strcmp(a_line->value, "0 bar")) {
342                 ast_test_status_update(test, "Failed to find attribute 'foo' with payload '0'\n");
343                 res = AST_TEST_FAIL;
344         }
345         a_line = ast_sdp_m_find_attribute(m_line, "foo", -1);
346         if (!a_line || strcmp(a_line->value, "0 bar")) {
347                 ast_test_status_update(test, "Failed to find attribute 'foo' with unspecified payload\n");
348                 res = AST_TEST_FAIL;
349         }
350         a_line = ast_sdp_m_find_attribute(m_line, "baz", -1);
351         if (!a_line || strcmp(a_line->value, "howdy")) {
352                 ast_test_status_update(test, "Failed to find attribute 'baz' with unspecified payload\n");
353                 res = AST_TEST_FAIL;
354         }
355
356         idx = ast_sdp_m_find_a_first(m_line, "foo", 0);
357         if (idx < 0) {
358                 ast_test_status_update(test, "Failed to find first attribute 'foo' with payload '0'\n");
359                 res = AST_TEST_FAIL;
360                 goto end;
361         }
362         a_line = ast_sdp_m_get_a(m_line, idx);
363         if (!a_line || strcmp(a_line->value, "0 bar")) {
364                 ast_test_status_update(test, "Find first attribute 'foo' with payload '0' didn't match\n");
365                 res = AST_TEST_FAIL;
366         }
367         idx = ast_sdp_m_find_a_next(m_line, idx, "foo", 0);
368         if (idx < 0) {
369                 ast_test_status_update(test, "Failed to find next attribute 'foo' with payload '0'\n");
370                 res = AST_TEST_FAIL;
371                 goto end;
372         }
373         a_line = ast_sdp_m_get_a(m_line, idx);
374         if (!a_line || strcmp(a_line->value, "0 bee")) {
375                 ast_test_status_update(test, "Find next attribute 'foo' with payload '0' didn't match\n");
376                 res = AST_TEST_FAIL;
377         }
378         idx = ast_sdp_m_find_a_next(m_line, idx, "foo", 0);
379         if (0 <= idx) {
380                 ast_test_status_update(test, "Find next attribute 'foo' with payload '0' found too many\n");
381                 res = AST_TEST_FAIL;
382         }
383
384         idx = ast_sdp_m_find_a_first(m_line, "foo", -1);
385         if (idx < 0) {
386                 ast_test_status_update(test, "Failed to find first attribute 'foo' with unspecified payload\n");
387                 res = AST_TEST_FAIL;
388                 goto end;
389         }
390         a_line = ast_sdp_m_get_a(m_line, idx);
391         if (!a_line || strcmp(a_line->value, "0 bar")) {
392                 ast_test_status_update(test, "Find first attribute 'foo' with unspecified payload didn't match\n");
393                 res = AST_TEST_FAIL;
394         }
395         idx = ast_sdp_m_find_a_next(m_line, idx, "foo", -1);
396         if (idx < 0) {
397                 ast_test_status_update(test, "Failed to find next attribute 'foo' with unspecified payload\n");
398                 res = AST_TEST_FAIL;
399                 goto end;
400         }
401         a_line = ast_sdp_m_get_a(m_line, idx);
402         if (!a_line || strcmp(a_line->value, "0 bee")) {
403                 ast_test_status_update(test, "Find next attribute 'foo' with unspecified payload didn't match\n");
404                 res = AST_TEST_FAIL;
405         }
406         idx = ast_sdp_m_find_a_next(m_line, idx, "foo", -1);
407         if (0 <= idx) {
408                 ast_test_status_update(test, "Find next attribute 'foo' with unspecified payload found too many\n");
409                 res = AST_TEST_FAIL;
410         }
411
412         /* These should fail */
413         a_line = ast_sdp_m_find_attribute(m_line, "foo", 1);
414         if (a_line) {
415                 ast_test_status_update(test, "Found non-existent attribute 'foo' with payload '1'\n");
416                 res = AST_TEST_FAIL;
417         }
418         a_line = ast_sdp_m_find_attribute(m_line, "baz", 0);
419         if (a_line) {
420                 ast_test_status_update(test, "Found non-existent attribute 'baz' with payload '0'\n");
421                 res = AST_TEST_FAIL;
422         }
423         a_line = ast_sdp_m_find_attribute(m_line, "wibble", 0);
424         if (a_line) {
425                 ast_test_status_update(test, "Found non-existent attribute 'wibble' with payload '0'\n");
426                 res = AST_TEST_FAIL;
427         }
428         a_line = ast_sdp_m_find_attribute(m_line, "wibble", -1);
429         if (a_line) {
430                 ast_test_status_update(test, "Found non-existent attribute 'wibble' with unspecified payload\n");
431                 res = AST_TEST_FAIL;
432         }
433
434 end:
435         ast_sdp_m_free(m_line);
436         return res;
437 }
438
439 static struct ast_sdp_options *sdp_options_common(void)
440 {
441         struct ast_sdp_options *options;
442
443         options = ast_sdp_options_alloc();
444         if (!options) {
445                 return NULL;
446         }
447         ast_sdp_options_set_media_address(options, "127.0.0.1");
448         ast_sdp_options_set_sdpowner(options, "me");
449         ast_sdp_options_set_rtp_engine(options, "asterisk");
450         ast_sdp_options_set_impl(options, AST_SDP_IMPL_PJMEDIA);
451
452         return options;
453 }
454
455 struct sdp_format {
456         enum ast_media_type type;
457         const char *formats;
458 };
459
460 static int build_sdp_option_formats(struct ast_sdp_options *options, int num_streams, const struct sdp_format *formats)
461 {
462         int idx;
463
464         for (idx = 0; idx < num_streams; ++idx) {
465                 RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
466
467                 caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
468                 if (!caps) {
469                         return -1;
470                 }
471
472                 if (ast_format_cap_update_by_allow_disallow(caps, formats[idx].formats, 1) < 0) {
473                         return -1;
474                 }
475                 ast_sdp_options_set_format_cap_type(options, formats[idx].type, caps);
476         }
477         return 0;
478 }
479
480 /*!
481  * \brief Common method to build an SDP state for a test.
482  *
483  * This uses the passed-in formats to create a stream topology, which is then used to create the SDP
484  * state.
485  *
486  * There is an optional test_options field you can use if your test has specific options you need to
487  * set. If your test does not require anything special, it can just pass NULL for this parameter. If
488  * you do pass in test_options, this function steals ownership of those options.
489  *
490  * \param num_streams The number of elements in the formats array.
491  * \param formats Array of media types and formats that will be in the state.
492  * \param opt_num_streams The number of new stream types allowed to create.
493  *           Not used if test_options provided.
494  * \param opt_formats Array of new stream media types and formats allowed to create.
495  *           NULL if use a default stream creation.
496  *           Not used if test_options provided.
497  * \param test_options Optional SDP options.
498  */
499 static struct ast_sdp_state *build_sdp_state(int num_streams, const struct sdp_format *formats,
500         int opt_num_streams, const struct sdp_format *opt_formats,
501         struct ast_sdp_options *test_options)
502 {
503         struct ast_stream_topology *topology = NULL;
504         struct ast_sdp_state *state = NULL;
505         struct ast_sdp_options *options;
506         int i;
507
508         if (!test_options) {
509                 unsigned int max_streams;
510
511                 static const struct sdp_format sdp_formats[] = {
512                         { AST_MEDIA_TYPE_AUDIO, "ulaw" },
513                         { AST_MEDIA_TYPE_VIDEO, "vp8" },
514                         { AST_MEDIA_TYPE_IMAGE, "t38" },
515                 };
516
517                 options = sdp_options_common();
518                 if (!options) {
519                         goto end;
520                 }
521
522                 /* Determine max_streams to allow */
523                 max_streams = ARRAY_LEN(sdp_formats);
524                 if (ARRAY_LEN(sdp_formats) < num_streams) {
525                         max_streams = num_streams;
526                 }
527                 ast_sdp_options_set_max_streams(options, max_streams);
528
529                 /* Determine new stream formats and types allowed */
530                 if (!opt_formats) {
531                         opt_num_streams = ARRAY_LEN(sdp_formats);
532                         opt_formats = sdp_formats;
533                 }
534                 if (build_sdp_option_formats(options, opt_num_streams, opt_formats)) {
535                         goto end;
536                 }
537         } else {
538                 options = test_options;
539         }
540
541         topology = ast_stream_topology_alloc();
542         if (!topology) {
543                 goto end;
544         }
545
546         for (i = 0; i < num_streams; ++i) {
547                 RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
548                 struct ast_stream *stream;
549
550                 caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
551                 if (!caps) {
552                         goto end;
553                 }
554                 if (ast_format_cap_update_by_allow_disallow(caps, formats[i].formats, 1) < 0) {
555                         goto end;
556                 }
557                 stream = ast_stream_alloc("sure_thing", formats[i].type);
558                 if (!stream) {
559                         goto end;
560                 }
561                 ast_stream_set_formats(stream, caps);
562                 if (ast_stream_topology_append_stream(topology, stream) < 0) {
563                         ast_stream_free(stream);
564                         goto end;
565                 }
566         }
567
568         state = ast_sdp_state_alloc(topology, options);
569         if (!state) {
570                 goto end;
571         }
572
573 end:
574         ast_stream_topology_free(topology);
575         if (!state) {
576                 ast_sdp_options_free(options);
577         }
578
579         return state;
580 }
581
582 AST_TEST_DEFINE(topology_to_sdp)
583 {
584         enum ast_test_result_state res = AST_TEST_FAIL;
585         struct ast_sdp_state *sdp_state = NULL;
586         const struct ast_sdp *sdp = NULL;
587         struct ast_sdp_m_line *m_line = NULL;
588         struct sdp_format formats[] = {
589                 { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" },
590                 { AST_MEDIA_TYPE_VIDEO, "h264,vp8" },
591                 { AST_MEDIA_TYPE_IMAGE, "t38" },
592         };
593
594         switch(cmd) {
595         case TEST_INIT:
596                 info->name = "topology_to_sdp";
597                 info->category = "/main/sdp/";
598                 info->summary = "Convert a topology into an SDP";
599                 info->description =
600                         "Ensure SDPs get converted to expected stream topology";
601                 return AST_TEST_NOT_RUN;
602         case TEST_EXECUTE:
603                 break;
604         }
605
606         sdp_state = build_sdp_state(ARRAY_LEN(formats), formats,
607                 ARRAY_LEN(formats), formats, NULL);
608         if (!sdp_state) {
609                 goto end;
610         }
611
612         sdp = ast_sdp_state_get_local_sdp(sdp_state);
613         if (!sdp) {
614                 goto end;
615         }
616
617         if (validate_o_line(test, sdp->o_line, "me", "IP4", "127.0.0.1")) {
618                 goto end;
619         }
620
621         if (validate_c_line(test, sdp->c_line, "IP4", "127.0.0.1")) {
622                 goto end;
623         }
624
625         if (ast_sdp_get_m_count(sdp) != 3) {
626                 ast_test_status_update(test, "Unexpected number of streams in generated SDP: %d\n",
627                         ast_sdp_get_m_count(sdp));
628                 goto end;
629         }
630
631         m_line = ast_sdp_get_m(sdp, 0);
632
633         if (validate_m_line(test, m_line, "audio", 4)) {
634                 goto end;
635         }
636
637         if (validate_rtpmap(test, m_line, "PCMU")) {
638                 goto end;
639         }
640
641         if (validate_rtpmap(test, m_line, "PCMA")) {
642                 goto end;
643         }
644
645         if (validate_rtpmap(test, m_line, "G722")) {
646                 goto end;
647         }
648
649         if (validate_rtpmap(test, m_line, "opus")) {
650                 goto end;
651         }
652
653         m_line = ast_sdp_get_m(sdp, 1);
654         if (validate_m_line(test, m_line, "video", 2)) {
655                 goto end;
656         }
657
658         if (validate_rtpmap(test, m_line, "VP8")) {
659                 goto end;
660         }
661
662         if (validate_rtpmap(test, m_line, "H264")) {
663                 goto end;
664         }
665
666         m_line = ast_sdp_get_m(sdp, 2);
667         if (validate_m_line(test, m_line, "image", 1)) {
668                 goto end;
669         }
670         if (validate_t38(test, m_line) != AST_TEST_PASS) {
671                 goto end;
672         }
673
674         res = AST_TEST_PASS;
675
676 end:
677         ast_sdp_state_free(sdp_state);
678         return res;
679 }
680
681 static int validate_formats(struct ast_test *test, struct ast_stream_topology *topology, int index,
682         enum ast_media_type type, int format_count, const char **expected_formats)
683 {
684         struct ast_stream *stream;
685         struct ast_format_cap *caps;
686         struct ast_format *format;
687         int i;
688
689         stream = ast_stream_topology_get_stream(topology, index);
690         if (ast_stream_get_type(stream) != type) {
691                 ast_test_status_update(test, "Unexpected stream type encountered\n");
692                 return -1;
693         }
694         caps = ast_stream_get_formats(stream);
695
696         if (ast_format_cap_count(caps) != format_count) {
697                 ast_test_status_update(test, "Unexpected format count '%d'. Expecting '%d'\n",
698                         (int) ast_format_cap_count(caps), format_count);
699                 return -1;
700         }
701
702         for (i = 0; i < ast_format_cap_count(caps); ++i) {
703                 format = ast_format_cap_get_format(caps, i);
704                 if (strcmp(ast_format_get_name(format), expected_formats[i])) {
705                         ast_test_status_update(test, "Unexpected format '%s'at index %d. Expected '%s'\n",
706                                 ast_format_get_name(format), i, expected_formats[i]);
707                         return -1;
708                 }
709         }
710
711         return 0;
712 }
713
714 AST_TEST_DEFINE(sdp_to_topology)
715 {
716         enum ast_test_result_state res = AST_TEST_PASS;
717         struct ast_sdp_state *sdp_state;
718         const struct ast_sdp *sdp;
719         struct ast_stream_topology *topology = NULL;
720         struct sdp_format sdp_formats[] = {
721                 { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" },
722                 { AST_MEDIA_TYPE_VIDEO, "h264,vp8" },
723                 { AST_MEDIA_TYPE_IMAGE, "t38" },
724         };
725         static const char *expected_audio_formats[] = {
726                 "ulaw",
727                 "alaw",
728                 "g722",
729                 "opus",
730         };
731         static const char *expected_video_formats[] = {
732                 "h264",
733                 "vp8",
734         };
735         static const char *expected_image_formats[] = {
736                 "t38",
737         };
738
739         switch(cmd) {
740         case TEST_INIT:
741                 info->name = "sdp_to_topology";
742                 info->category = "/main/sdp/";
743                 info->summary = "Convert an SDP into a topology";
744                 info->description =
745                         "Ensure SDPs get converted to expected stream topology";
746                 return AST_TEST_NOT_RUN;
747         case TEST_EXECUTE:
748                 break;
749         }
750
751         sdp_state = build_sdp_state(ARRAY_LEN(sdp_formats), sdp_formats,
752                 ARRAY_LEN(sdp_formats), sdp_formats, NULL);
753         if (!sdp_state) {
754                 res = AST_TEST_FAIL;
755                 goto end;
756         }
757
758         sdp = ast_sdp_state_get_local_sdp(sdp_state);
759         if (!sdp) {
760                 res = AST_TEST_FAIL;
761                 goto end;
762         }
763
764         topology = ast_get_topology_from_sdp(sdp, 0);
765         if (!topology) {
766                 res = AST_TEST_FAIL;
767                 goto end;
768         }
769
770         if (ast_stream_topology_get_count(topology) != 3) {
771                 ast_test_status_update(test, "Unexpected topology count '%d'. Expecting 3\n",
772                         ast_stream_topology_get_count(topology));
773                 res = AST_TEST_FAIL;
774                 goto end;
775         }
776
777         if (validate_formats(test, topology, 0, AST_MEDIA_TYPE_AUDIO,
778                         ARRAY_LEN(expected_audio_formats), expected_audio_formats)) {
779                 res = AST_TEST_FAIL;
780                 goto end;
781         }
782
783         if (validate_formats(test, topology, 1, AST_MEDIA_TYPE_VIDEO,
784                         ARRAY_LEN(expected_video_formats), expected_video_formats)) {
785                 res = AST_TEST_FAIL;
786                 goto end;
787         }
788
789         if (validate_formats(test, topology, 2, AST_MEDIA_TYPE_IMAGE,
790                         ARRAY_LEN(expected_image_formats), expected_image_formats)) {
791                 res = AST_TEST_FAIL;
792                 goto end;
793         }
794
795 end:
796         ast_sdp_state_free(sdp_state);
797         ast_stream_topology_free(topology);
798         return res;
799 }
800
801 static int validate_avi_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp)
802 {
803         struct ast_sdp_m_line *m_line;
804
805         if (!sdp) {
806                 return -1;
807         }
808
809         m_line = ast_sdp_get_m(sdp, 0);
810         if (validate_m_line(test, m_line, "audio", 1)) {
811                 return -1;
812         }
813         if (validate_rtpmap(test, m_line, "PCMU")) {
814                 return -1;
815         }
816
817         /* The other audio formats should *NOT* be present */
818         if (!validate_rtpmap(test, m_line, "PCMA")) {
819                 return -1;
820         }
821         if (!validate_rtpmap(test, m_line, "G722")) {
822                 return -1;
823         }
824         if (!validate_rtpmap(test, m_line, "opus")) {
825                 return -1;
826         }
827
828         m_line = ast_sdp_get_m(sdp, 1);
829         if (validate_m_line(test, m_line, "video", 1)) {
830                 return -1;
831         }
832         if (validate_rtpmap(test, m_line, "VP8")) {
833                 return -1;
834         }
835         if (!validate_rtpmap(test, m_line, "H264")) {
836                 return -1;
837         }
838
839         m_line = ast_sdp_get_m(sdp, 2);
840         if (validate_m_line(test, m_line, "image", 1)) {
841                 return -1;
842         }
843
844         return 0;
845 }
846
847 static enum ast_test_result_state sdp_negotiation_completed_tests(struct ast_test *test,
848         int offer_num_streams, const struct sdp_format *offer_formats,
849         int answer_num_streams, const struct sdp_format *answer_formats,
850         int allowed_ans_num_streams, const struct sdp_format *allowed_ans_formats,
851         int (*validate_sdp)(struct ast_test *test, const struct ast_sdp *sdp))
852 {
853         enum ast_test_result_state res = AST_TEST_PASS;
854         struct ast_sdp_state *sdp_state_offerer = NULL;
855         struct ast_sdp_state *sdp_state_answerer = NULL;
856         const struct ast_sdp *offerer_sdp;
857         const struct ast_sdp *answerer_sdp;
858
859         sdp_state_offerer = build_sdp_state(offer_num_streams, offer_formats,
860                 offer_num_streams, offer_formats, NULL);
861         if (!sdp_state_offerer) {
862                 res = AST_TEST_FAIL;
863                 goto end;
864         }
865
866         sdp_state_answerer = build_sdp_state(answer_num_streams, answer_formats,
867                 allowed_ans_num_streams, allowed_ans_formats, NULL);
868         if (!sdp_state_answerer) {
869                 res = AST_TEST_FAIL;
870                 goto end;
871         }
872
873         offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer);
874         if (!offerer_sdp) {
875                 res = AST_TEST_FAIL;
876                 goto end;
877         }
878
879         if (ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp)) {
880                 res = AST_TEST_FAIL;
881                 goto end;
882         }
883         answerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_answerer);
884         if (!answerer_sdp) {
885                 res = AST_TEST_FAIL;
886                 goto end;
887         }
888
889         if (ast_sdp_state_set_remote_sdp(sdp_state_offerer, answerer_sdp)) {
890                 res = AST_TEST_FAIL;
891                 goto end;
892         }
893
894         /*
895          * Restart SDP negotiations to build the joint SDP on the offerer
896          * side.  Otherwise we will get the original offer for use in
897          * case of retransmissions.
898          */
899         if (ast_sdp_state_restart_negotiations(sdp_state_offerer)) {
900                 ast_test_status_update(test, "Restarting negotiations failed\n");
901                 res = AST_TEST_FAIL;
902                 goto end;
903         }
904         offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer);
905         if (validate_sdp(test, offerer_sdp)) {
906                 res = AST_TEST_FAIL;
907                 goto end;
908         }
909         if (validate_sdp(test, answerer_sdp)) {
910                 res = AST_TEST_FAIL;
911                 goto end;
912         }
913
914 end:
915         ast_sdp_state_free(sdp_state_offerer);
916         ast_sdp_state_free(sdp_state_answerer);
917
918         return res;
919 }
920
921 AST_TEST_DEFINE(sdp_negotiation_initial)
922 {
923         static const struct sdp_format offerer_formats[] = {
924                 { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" },
925                 { AST_MEDIA_TYPE_VIDEO, "h264,vp8" },
926                 { AST_MEDIA_TYPE_IMAGE, "t38" },
927         };
928
929         switch(cmd) {
930         case TEST_INIT:
931                 info->name = "sdp_negotiation_initial";
932                 info->category = "/main/sdp/";
933                 info->summary = "Simulate an initial negotiation";
934                 info->description =
935                         "Initial negotiation tests creating new streams on the answering side.\n"
936                         "After negotiation both offerer and answerer sides should have the same\n"
937                         "expected stream types and formats.";
938                 return AST_TEST_NOT_RUN;
939         case TEST_EXECUTE:
940                 break;
941         }
942
943         return sdp_negotiation_completed_tests(test,
944                 ARRAY_LEN(offerer_formats), offerer_formats,
945                 0, NULL,
946                 0, NULL,
947                 validate_avi_sdp_streams);
948 }
949
950 AST_TEST_DEFINE(sdp_negotiation_type_change)
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         static const struct sdp_format answerer_formats[] = {
958                 { AST_MEDIA_TYPE_IMAGE, "t38" },
959                 { AST_MEDIA_TYPE_VIDEO, "vp8" },
960                 { AST_MEDIA_TYPE_AUDIO, "ulaw" },
961         };
962
963         switch(cmd) {
964         case TEST_INIT:
965                 info->name = "sdp_negotiation_type_change";
966                 info->category = "/main/sdp/";
967                 info->summary = "Simulate a re-negotiation changing stream types";
968                 info->description =
969                         "Reinvite negotiation tests changing stream types on the answering side.\n"
970                         "After negotiation both offerer and answerer sides should have the same\n"
971                         "expected stream types and formats.";
972                 return AST_TEST_NOT_RUN;
973         case TEST_EXECUTE:
974                 break;
975         }
976
977         return sdp_negotiation_completed_tests(test,
978                 ARRAY_LEN(offerer_formats), offerer_formats,
979                 ARRAY_LEN(answerer_formats), answerer_formats,
980                 0, NULL,
981                 validate_avi_sdp_streams);
982 }
983
984 static int validate_ava_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp)
985 {
986         struct ast_sdp_m_line *m_line;
987
988         if (!sdp) {
989                 return -1;
990         }
991
992         m_line = ast_sdp_get_m(sdp, 0);
993         if (validate_m_line_declined(test, m_line, "audio")) {
994                 return -1;
995         }
996
997         m_line = ast_sdp_get_m(sdp, 1);
998         if (validate_m_line_declined(test, m_line, "video")) {
999                 return -1;
1000         }
1001
1002         m_line = ast_sdp_get_m(sdp, 2);
1003         if (validate_m_line(test, m_line, "audio", 1)) {
1004                 return -1;
1005         }
1006         if (validate_rtpmap(test, m_line, "PCMU")) {
1007                 return -1;
1008         }
1009
1010         /* The other audio formats should *NOT* be present */
1011         if (!validate_rtpmap(test, m_line, "PCMA")) {
1012                 return -1;
1013         }
1014
1015         return 0;
1016 }
1017
1018 AST_TEST_DEFINE(sdp_negotiation_decline_incompatible)
1019 {
1020         static const struct sdp_format offerer_formats[] = {
1021                 { AST_MEDIA_TYPE_AUDIO, "alaw" },
1022                 { AST_MEDIA_TYPE_VIDEO, "vp8" },
1023                 { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw" },
1024         };
1025         static const struct sdp_format answerer_formats[] = {
1026                 { AST_MEDIA_TYPE_AUDIO, "ulaw" },
1027         };
1028
1029         switch(cmd) {
1030         case TEST_INIT:
1031                 info->name = "sdp_negotiation_decline_incompatible";
1032                 info->category = "/main/sdp/";
1033                 info->summary = "Simulate an initial negotiation declining streams";
1034                 info->description =
1035                         "Initial negotiation tests declining incompatible streams on the answering side.\n"
1036                         "After negotiation both offerer and answerer sides should have the same\n"
1037                         "expected stream types and formats.";
1038                 return AST_TEST_NOT_RUN;
1039         case TEST_EXECUTE:
1040                 break;
1041         }
1042
1043         return sdp_negotiation_completed_tests(test,
1044                 ARRAY_LEN(offerer_formats), offerer_formats,
1045                 ARRAY_LEN(answerer_formats), answerer_formats,
1046                 ARRAY_LEN(answerer_formats), answerer_formats,
1047                 validate_ava_declined_sdp_streams);
1048 }
1049
1050 static int validate_aaaa_declined_sdp_streams(struct ast_test *test, const struct ast_sdp *sdp)
1051 {
1052         struct ast_sdp_m_line *m_line;
1053
1054         if (!sdp) {
1055                 return -1;
1056         }
1057
1058         m_line = ast_sdp_get_m(sdp, 0);
1059         if (validate_m_line(test, m_line, "audio", 1)) {
1060                 return -1;
1061         }
1062         if (validate_rtpmap(test, m_line, "PCMU")) {
1063                 return -1;
1064         }
1065
1066         m_line = ast_sdp_get_m(sdp, 1);
1067         if (validate_m_line(test, m_line, "audio", 1)) {
1068                 return -1;
1069         }
1070         if (validate_rtpmap(test, m_line, "PCMU")) {
1071                 return -1;
1072         }
1073
1074         m_line = ast_sdp_get_m(sdp, 2);
1075         if (validate_m_line(test, m_line, "audio", 1)) {
1076                 return -1;
1077         }
1078         if (validate_rtpmap(test, m_line, "PCMU")) {
1079                 return -1;
1080         }
1081
1082         m_line = ast_sdp_get_m(sdp, 3);
1083         if (validate_m_line_declined(test, m_line, "audio")) {
1084                 return -1;
1085         }
1086
1087         return 0;
1088 }
1089
1090 AST_TEST_DEFINE(sdp_negotiation_decline_max_streams)
1091 {
1092         static const struct sdp_format offerer_formats[] = {
1093                 { AST_MEDIA_TYPE_AUDIO, "ulaw" },
1094                 { AST_MEDIA_TYPE_AUDIO, "ulaw" },
1095                 { AST_MEDIA_TYPE_AUDIO, "ulaw" },
1096                 { AST_MEDIA_TYPE_AUDIO, "ulaw" },
1097         };
1098
1099         switch(cmd) {
1100         case TEST_INIT:
1101                 info->name = "sdp_negotiation_decline_max_streams";
1102                 info->category = "/main/sdp/";
1103                 info->summary = "Simulate an initial negotiation declining excessive streams";
1104                 info->description =
1105                         "Initial negotiation tests declining too many streams on the answering side.\n"
1106                         "After negotiation both offerer and answerer sides should have the same\n"
1107                         "expected stream types and formats.";
1108                 return AST_TEST_NOT_RUN;
1109         case TEST_EXECUTE:
1110                 break;
1111         }
1112
1113         return sdp_negotiation_completed_tests(test,
1114                 ARRAY_LEN(offerer_formats), offerer_formats,
1115                 0, NULL,
1116                 0, NULL,
1117                 validate_aaaa_declined_sdp_streams);
1118 }
1119
1120 AST_TEST_DEFINE(sdp_negotiation_not_acceptable)
1121 {
1122         enum ast_test_result_state res = AST_TEST_PASS;
1123         struct ast_sdp_state *sdp_state_offerer = NULL;
1124         struct ast_sdp_state *sdp_state_answerer = NULL;
1125         const struct ast_sdp *offerer_sdp;
1126
1127         static const struct sdp_format offerer_formats[] = {
1128                 { AST_MEDIA_TYPE_AUDIO, "alaw" },
1129                 { AST_MEDIA_TYPE_AUDIO, "alaw" },
1130         };
1131
1132         switch(cmd) {
1133         case TEST_INIT:
1134                 info->name = "sdp_negotiation_not_acceptable";
1135                 info->category = "/main/sdp/";
1136                 info->summary = "Simulate an initial negotiation declining all streams";
1137                 info->description =
1138                         "Initial negotiation tests declining all streams for a 488 on the answering side.\n"
1139                         "Negotiations should fail because there are no acceptable streams.";
1140                 return AST_TEST_NOT_RUN;
1141         case TEST_EXECUTE:
1142                 break;
1143         }
1144
1145         sdp_state_offerer = build_sdp_state(ARRAY_LEN(offerer_formats), offerer_formats,
1146                 ARRAY_LEN(offerer_formats), offerer_formats, NULL);
1147         if (!sdp_state_offerer) {
1148                 res = AST_TEST_FAIL;
1149                 goto end;
1150         }
1151
1152         sdp_state_answerer = build_sdp_state(0, NULL, 0, NULL, NULL);
1153         if (!sdp_state_answerer) {
1154                 res = AST_TEST_FAIL;
1155                 goto end;
1156         }
1157
1158         offerer_sdp = ast_sdp_state_get_local_sdp(sdp_state_offerer);
1159         if (!offerer_sdp) {
1160                 res = AST_TEST_FAIL;
1161                 goto end;
1162         }
1163
1164         if (!ast_sdp_state_set_remote_sdp(sdp_state_answerer, offerer_sdp)) {
1165                 ast_test_status_update(test, "Bad.  Setting remote SDP was successful.\n");
1166                 res = AST_TEST_FAIL;
1167                 goto end;
1168         }
1169         if (!ast_sdp_state_is_offer_rejected(sdp_state_answerer)) {
1170                 ast_test_status_update(test, "Bad.  Negotiation failed for some other reason.\n");
1171                 res = AST_TEST_FAIL;
1172                 goto end;
1173         }
1174
1175 end:
1176         ast_sdp_state_free(sdp_state_offerer);
1177         ast_sdp_state_free(sdp_state_answerer);
1178
1179         return res;
1180 }
1181
1182 static int validate_ssrc(struct ast_test *test, struct ast_sdp_m_line *m_line,
1183         struct ast_rtp_instance *rtp)
1184 {
1185         unsigned int ssrc;
1186         const char *cname;
1187         struct ast_sdp_a_line *a_line;
1188         char attr_value[128];
1189
1190         ssrc = ast_rtp_instance_get_ssrc(rtp);
1191         cname = ast_rtp_instance_get_cname(rtp);
1192
1193         snprintf(attr_value, sizeof(attr_value), "%u cname:%s", ssrc, cname);
1194
1195         a_line = ast_sdp_m_find_attribute(m_line, "ssrc", -1);
1196         if (!a_line) {
1197                 ast_test_status_update(test, "Could not find 'ssrc' attribute\n");
1198                 return -1;
1199         }
1200
1201         if (strcmp(a_line->value, attr_value)) {
1202                 ast_test_status_update(test, "SDP attribute '%s' did not match expected attribute '%s'\n",
1203                         a_line->value, attr_value);
1204                 return -1;
1205         }
1206
1207         return 0;
1208 }
1209
1210 AST_TEST_DEFINE(sdp_ssrc_attributes)
1211 {
1212         enum ast_test_result_state res;
1213         struct ast_sdp_state *test_state = NULL;
1214         struct ast_sdp_options *options;
1215         struct sdp_format formats[] = {
1216                 { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,opus" },
1217         };
1218         const struct ast_sdp *sdp;
1219         struct ast_sdp_m_line *m_line;
1220         struct ast_rtp_instance *rtp;
1221
1222         switch(cmd) {
1223         case TEST_INIT:
1224                 info->name = "sdp_ssrc_attributes";
1225                 info->category = "/main/sdp/";
1226                 info->summary = "Ensure SSRC-level attributes are added to local SDPs";
1227                 info->description =
1228                         "An SDP is created and is instructed to include SSRC-level attributes.\n"
1229                         "This test ensures that the CNAME SSRC-level attribute is present and\n"
1230                         "that the values match what the RTP instance reports";
1231                 return AST_TEST_NOT_RUN;
1232         case TEST_EXECUTE:
1233                 break;
1234         }
1235
1236         res = AST_TEST_FAIL;
1237
1238         options = sdp_options_common();
1239         if (!options) {
1240                 ast_test_status_update(test, "Failed to allocate SDP options\n");
1241                 goto end;
1242         }
1243         if (build_sdp_option_formats(options, ARRAY_LEN(formats), formats)) {
1244                 goto end;
1245         }
1246         ast_sdp_options_set_ssrc(options, 1);
1247
1248         test_state = build_sdp_state(ARRAY_LEN(formats), formats, 0, NULL, options);
1249         if (!test_state) {
1250                 ast_test_status_update(test, "Failed to create SDP state\n");
1251                 goto end;
1252         }
1253
1254         sdp = ast_sdp_state_get_local_sdp(test_state);
1255         if (!sdp) {
1256                 ast_test_status_update(test, "Failed to get local SDP\n");
1257                 goto end;
1258         }
1259
1260         /* Need a couple of sanity checks */
1261         if (ast_sdp_get_m_count(sdp) != ARRAY_LEN(formats)) {
1262                 ast_test_status_update(test, "SDP m count is %d instead of %zu\n",
1263                         ast_sdp_get_m_count(sdp), ARRAY_LEN(formats));
1264                 goto end;
1265         }
1266
1267         m_line = ast_sdp_get_m(sdp, 0);
1268         if (!m_line) {
1269                 ast_test_status_update(test, "Failed to get SDP m-line\n");
1270                 goto end;
1271         }
1272
1273         rtp = ast_sdp_state_get_rtp_instance(test_state, 0);
1274         if (!rtp) {
1275                 ast_test_status_update(test, "Failed to get the RTP instance\n");
1276                 goto end;
1277         }
1278
1279         if (validate_ssrc(test, m_line, rtp)) {
1280                 goto end;
1281         }
1282
1283         res = AST_TEST_PASS;
1284
1285 end:
1286         ast_sdp_state_free(test_state);
1287         return res;
1288 }
1289
1290 struct sdp_topology_stream {
1291         /*! Media stream type: audio, video, image */
1292         enum ast_media_type type;
1293         /*! Media stream state: removed/declined, sendrecv */
1294         enum ast_stream_state state;
1295         /*! Comma separated list of formats allowed on the stream.  Can be NULL if stream is removed/declined. */
1296         const char *formats;
1297         /*! Optional name of stream.  NULL for default name. */
1298         const char *name;
1299 };
1300
1301 struct sdp_update_test {
1302         /*! Maximum number of streams.  (0 if default) */
1303         int max_streams;
1304         /*! Optional initial SDP state topology (NULL if not present) */
1305         const struct sdp_topology_stream * const *initial;
1306         /*! Required first topology update */
1307         const struct sdp_topology_stream * const *update_1;
1308         /*! Optional second topology update (NULL if not present) */
1309         const struct sdp_topology_stream * const *update_2;
1310         /*! Expected topology to be offered */
1311         const struct sdp_topology_stream * const *expected;
1312 };
1313
1314 static struct ast_stream_topology *build_update_topology(const struct sdp_topology_stream * const *spec)
1315 {
1316         struct ast_stream_topology *topology;
1317         const struct sdp_topology_stream *desc;
1318
1319         topology = ast_stream_topology_alloc();
1320         if (!topology) {
1321                 return NULL;
1322         }
1323
1324         for (desc = *spec; desc; ++spec, desc = *spec) {
1325                 struct ast_stream *stream;
1326                 const char *name;
1327
1328                 name = desc->name ?: ast_codec_media_type2str(desc->type);
1329                 stream = ast_stream_alloc(name, desc->type);
1330                 if (!stream) {
1331                         goto fail;
1332                 }
1333                 ast_stream_set_state(stream, desc->state);
1334                 if (desc->formats) {
1335                         struct ast_format_cap *caps;
1336
1337                         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
1338                         if (!caps) {
1339                                 goto fail;
1340                         }
1341                         if (ast_format_cap_update_by_allow_disallow(caps, desc->formats, 1) < 0) {
1342                                 ao2_ref(caps, -1);
1343                                 goto fail;
1344                         }
1345                         ast_stream_set_formats(stream, caps);
1346                         ao2_ref(caps, -1);
1347                 }
1348                 if (ast_stream_topology_append_stream(topology, stream) < 0) {
1349                         ast_stream_free(stream);
1350                         goto fail;
1351                 }
1352         }
1353         return topology;
1354
1355 fail:
1356         ast_stream_topology_free(topology);
1357         return NULL;
1358 }
1359
1360 static int cmp_update_topology(struct ast_test *test,
1361         const struct ast_stream_topology *expected, const struct ast_stream_topology *merged)
1362 {
1363         int status = 0;
1364         int idx;
1365         int max_streams;
1366         struct ast_stream *exp_stream;
1367         struct ast_stream *mrg_stream;
1368
1369         idx = ast_stream_topology_get_count(expected);
1370         max_streams = ast_stream_topology_get_count(merged);
1371         if (idx != max_streams) {
1372                 ast_test_status_update(test, "Expected %d streams got %d streams\n",
1373                         idx, max_streams);
1374                 status = -1;
1375         }
1376         if (idx < max_streams) {
1377                 max_streams = idx;
1378         }
1379
1380         /* Compare common streams by position */
1381         for (idx = 0; idx < max_streams; ++idx) {
1382                 exp_stream = ast_stream_topology_get_stream(expected, idx);
1383                 mrg_stream = ast_stream_topology_get_stream(merged, idx);
1384
1385                 if (strcmp(ast_stream_get_name(exp_stream), ast_stream_get_name(mrg_stream))) {
1386                         ast_test_status_update(test,
1387                                 "Stream %d: Expected stream name '%s' got stream name '%s'\n",
1388                                 idx,
1389                                 ast_stream_get_name(exp_stream),
1390                                 ast_stream_get_name(mrg_stream));
1391                         status = -1;
1392                 }
1393
1394                 if (ast_stream_get_state(exp_stream) != ast_stream_get_state(mrg_stream)) {
1395                         ast_test_status_update(test,
1396                                 "Stream %d: Expected stream state '%s' got stream state '%s'\n",
1397                                 idx,
1398                                 ast_stream_state2str(ast_stream_get_state(exp_stream)),
1399                                 ast_stream_state2str(ast_stream_get_state(mrg_stream)));
1400                         status = -1;
1401                 }
1402
1403                 if (ast_stream_get_type(exp_stream) != ast_stream_get_type(mrg_stream)) {
1404                         ast_test_status_update(test,
1405                                 "Stream %d: Expected stream type '%s' got stream type '%s'\n",
1406                                 idx,
1407                                 ast_codec_media_type2str(ast_stream_get_type(exp_stream)),
1408                                 ast_codec_media_type2str(ast_stream_get_type(mrg_stream)));
1409                         status = -1;
1410                         continue;
1411                 }
1412
1413                 if (ast_stream_get_state(exp_stream) == AST_STREAM_STATE_REMOVED
1414                         || ast_stream_get_state(mrg_stream) == AST_STREAM_STATE_REMOVED) {
1415                         /*
1416                          * Cannot compare formats if one of the streams is
1417                          * declined because there may not be any on the declined
1418                          * stream.
1419                          */
1420                         continue;
1421                 }
1422                 if (!ast_format_cap_identical(ast_stream_get_formats(exp_stream),
1423                         ast_stream_get_formats(mrg_stream))) {
1424                         ast_test_status_update(test,
1425                                 "Stream %d: Expected formats do not match merged formats\n",
1426                                 idx);
1427                         status = -1;
1428                 }
1429         }
1430
1431         return status;
1432 }
1433
1434
1435 static const struct sdp_topology_stream audio_declined_no_name = {
1436         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_REMOVED, NULL, NULL
1437 };
1438
1439 static const struct sdp_topology_stream audio_ulaw_no_name = {
1440         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "ulaw", NULL
1441 };
1442
1443 static const struct sdp_topology_stream audio_alaw_no_name = {
1444         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "alaw", NULL
1445 };
1446
1447 static const struct sdp_topology_stream audio_g722_no_name = {
1448         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g722", NULL
1449 };
1450
1451 static const struct sdp_topology_stream audio_g723_no_name = {
1452         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g723", NULL
1453 };
1454
1455 static const struct sdp_topology_stream video_declined_no_name = {
1456         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, NULL, NULL
1457 };
1458
1459 static const struct sdp_topology_stream video_h261_no_name = {
1460         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h261", NULL
1461 };
1462
1463 static const struct sdp_topology_stream video_h263_no_name = {
1464         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h263", NULL
1465 };
1466
1467 static const struct sdp_topology_stream video_h264_no_name = {
1468         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h264", NULL
1469 };
1470
1471 static const struct sdp_topology_stream video_vp8_no_name = {
1472         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "vp8", NULL
1473 };
1474
1475 static const struct sdp_topology_stream image_declined_no_name = {
1476         AST_MEDIA_TYPE_IMAGE, AST_STREAM_STATE_REMOVED, NULL, NULL
1477 };
1478
1479 static const struct sdp_topology_stream image_t38_no_name = {
1480         AST_MEDIA_TYPE_IMAGE, AST_STREAM_STATE_SENDRECV, "t38", NULL
1481 };
1482
1483
1484 static const struct sdp_topology_stream *top_ulaw_alaw_h264__vp8[] = {
1485         &audio_ulaw_no_name,
1486         &audio_alaw_no_name,
1487         &video_h264_no_name,
1488         &video_vp8_no_name,
1489         NULL
1490 };
1491
1492 static const struct sdp_topology_stream *top__vp8_alaw_h264_ulaw[] = {
1493         &video_vp8_no_name,
1494         &audio_alaw_no_name,
1495         &video_h264_no_name,
1496         &audio_ulaw_no_name,
1497         NULL
1498 };
1499
1500 static const struct sdp_topology_stream *top_alaw_ulaw__vp8_h264[] = {
1501         &audio_alaw_no_name,
1502         &audio_ulaw_no_name,
1503         &video_vp8_no_name,
1504         &video_h264_no_name,
1505         NULL
1506 };
1507
1508 /* Sorting by type with no new or deleted streams */
1509 static const struct sdp_update_test mrg_by_type_00 = {
1510         .initial  = top_ulaw_alaw_h264__vp8,
1511         .update_1 = top__vp8_alaw_h264_ulaw,
1512         .expected = top_alaw_ulaw__vp8_h264,
1513 };
1514
1515
1516 static const struct sdp_topology_stream *top_alaw__vp8[] = {
1517         &audio_alaw_no_name,
1518         &video_vp8_no_name,
1519         NULL
1520 };
1521
1522 static const struct sdp_topology_stream *top_h264__vp8_ulaw[] = {
1523         &video_h264_no_name,
1524         &video_vp8_no_name,
1525         &audio_ulaw_no_name,
1526         NULL
1527 };
1528
1529 static const struct sdp_topology_stream *top_ulaw_h264__vp8[] = {
1530         &audio_ulaw_no_name,
1531         &video_h264_no_name,
1532         &video_vp8_no_name,
1533         NULL
1534 };
1535
1536 /* Sorting by type and adding a stream */
1537 static const struct sdp_update_test mrg_by_type_01 = {
1538         .initial  = top_alaw__vp8,
1539         .update_1 = top_h264__vp8_ulaw,
1540         .expected = top_ulaw_h264__vp8,
1541 };
1542
1543
1544 static const struct sdp_topology_stream *top_alaw__vp8_vdec[] = {
1545         &audio_alaw_no_name,
1546         &video_vp8_no_name,
1547         &video_declined_no_name,
1548         NULL
1549 };
1550
1551 /* Sorting by type and deleting a stream */
1552 static const struct sdp_update_test mrg_by_type_02 = {
1553         .initial  = top_ulaw_h264__vp8,
1554         .update_1 = top_alaw__vp8,
1555         .expected = top_alaw__vp8_vdec,
1556 };
1557
1558
1559 static const struct sdp_topology_stream *top_h264_alaw_ulaw[] = {
1560         &video_h264_no_name,
1561         &audio_alaw_no_name,
1562         &audio_ulaw_no_name,
1563         NULL
1564 };
1565
1566 static const struct sdp_topology_stream *top__t38[] = {
1567         &image_t38_no_name,
1568         NULL
1569 };
1570
1571 static const struct sdp_topology_stream *top_vdec__t38_adec[] = {
1572         &video_declined_no_name,
1573         &image_t38_no_name,
1574         &audio_declined_no_name,
1575         NULL
1576 };
1577
1578 /* Sorting by type changing stream types for T.38 */
1579 static const struct sdp_update_test mrg_by_type_03 = {
1580         .initial  = top_h264_alaw_ulaw,
1581         .update_1 = top__t38,
1582         .expected = top_vdec__t38_adec,
1583 };
1584
1585
1586 /* Sorting by type changing stream types back from T.38 */
1587 static const struct sdp_update_test mrg_by_type_04 = {
1588         .initial  = top_vdec__t38_adec,
1589         .update_1 = top_h264_alaw_ulaw,
1590         .expected = top_h264_alaw_ulaw,
1591 };
1592
1593
1594 static const struct sdp_topology_stream *top_h264[] = {
1595         &video_h264_no_name,
1596         NULL
1597 };
1598
1599 static const struct sdp_topology_stream *top_vdec__t38[] = {
1600         &video_declined_no_name,
1601         &image_t38_no_name,
1602         NULL
1603 };
1604
1605 /* Sorting by type changing stream types for T.38 */
1606 static const struct sdp_update_test mrg_by_type_05 = {
1607         .initial  = top_h264,
1608         .update_1 = top__t38,
1609         .expected = top_vdec__t38,
1610 };
1611
1612
1613 static const struct sdp_topology_stream *top_h264_idec[] = {
1614         &video_h264_no_name,
1615         &image_declined_no_name,
1616         NULL
1617 };
1618
1619 /* Sorting by type changing stream types back from T.38 */
1620 static const struct sdp_update_test mrg_by_type_06 = {
1621         .initial  = top_vdec__t38,
1622         .update_1 = top_h264,
1623         .expected = top_h264_idec,
1624 };
1625
1626
1627 static const struct sdp_topology_stream *top_ulaw_adec_h264__vp8[] = {
1628         &audio_ulaw_no_name,
1629         &audio_declined_no_name,
1630         &video_h264_no_name,
1631         &video_vp8_no_name,
1632         NULL
1633 };
1634
1635 static const struct sdp_topology_stream *top_h263_alaw_h261_h264_vp8[] = {
1636         &video_h263_no_name,
1637         &audio_alaw_no_name,
1638         &video_h261_no_name,
1639         &video_h264_no_name,
1640         &video_vp8_no_name,
1641         NULL
1642 };
1643
1644 static const struct sdp_topology_stream *top_alaw_h264_h263_h261_vp8[] = {
1645         &audio_alaw_no_name,
1646         &video_h264_no_name,
1647         &video_h263_no_name,
1648         &video_h261_no_name,
1649         &video_vp8_no_name,
1650         NULL
1651 };
1652
1653 /* Sorting by type with backfill and adding streams */
1654 static const struct sdp_update_test mrg_by_type_07 = {
1655         .initial  = top_ulaw_adec_h264__vp8,
1656         .update_1 = top_h263_alaw_h261_h264_vp8,
1657         .expected = top_alaw_h264_h263_h261_vp8,
1658 };
1659
1660
1661 static const struct sdp_topology_stream *top_ulaw_alaw_h264__vp8_h261[] = {
1662         &audio_ulaw_no_name,
1663         &audio_alaw_no_name,
1664         &video_h264_no_name,
1665         &video_vp8_no_name,
1666         &video_h261_no_name,
1667         NULL
1668 };
1669
1670 /* Sorting by type overlimit of 4 and drop */
1671 static const struct sdp_update_test mrg_by_type_08 = {
1672         .max_streams = 4,
1673         .initial  = top_ulaw_alaw_h264__vp8,
1674         .update_1 = top_ulaw_alaw_h264__vp8_h261,
1675         .expected = top_ulaw_alaw_h264__vp8,
1676 };
1677
1678
1679 static const struct sdp_topology_stream *top_ulaw_alaw_h264[] = {
1680         &audio_ulaw_no_name,
1681         &audio_alaw_no_name,
1682         &video_h264_no_name,
1683         NULL
1684 };
1685
1686 static const struct sdp_topology_stream *top_alaw_h261__vp8[] = {
1687         &audio_alaw_no_name,
1688         &video_h261_no_name,
1689         &video_vp8_no_name,
1690         NULL
1691 };
1692
1693 static const struct sdp_topology_stream *top_alaw_adec_h261__vp8[] = {
1694         &audio_alaw_no_name,
1695         &audio_declined_no_name,
1696         &video_h261_no_name,
1697         &video_vp8_no_name,
1698         NULL
1699 };
1700
1701 /* Sorting by type with delete and add of streams */
1702 static const struct sdp_update_test mrg_by_type_09 = {
1703         .initial  = top_ulaw_alaw_h264,
1704         .update_1 = top_alaw_h261__vp8,
1705         .expected = top_alaw_adec_h261__vp8,
1706 };
1707
1708
1709 static const struct sdp_topology_stream *top_ulaw_adec_h264[] = {
1710         &audio_ulaw_no_name,
1711         &audio_declined_no_name,
1712         &video_h264_no_name,
1713         NULL
1714 };
1715
1716 /* Sorting by type and adding streams */
1717 static const struct sdp_update_test mrg_by_type_10 = {
1718         .initial  = top_ulaw_adec_h264,
1719         .update_1 = top_alaw_ulaw__vp8_h264,
1720         .expected = top_alaw_ulaw__vp8_h264,
1721 };
1722
1723
1724 static const struct sdp_topology_stream *top_adec_g722_h261[] = {
1725         &audio_declined_no_name,
1726         &audio_g722_no_name,
1727         &video_h261_no_name,
1728         NULL
1729 };
1730
1731 /* Sorting by type and deleting old streams */
1732 static const struct sdp_update_test mrg_by_type_11 = {
1733         .initial  = top_ulaw_alaw_h264,
1734         .update_1 = top_adec_g722_h261,
1735         .expected = top_adec_g722_h261,
1736 };
1737
1738
1739 static const struct sdp_topology_stream audio_alaw4dave = {
1740         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "alaw", "dave"
1741 };
1742
1743 static const struct sdp_topology_stream audio_g7224dave = {
1744         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g722", "dave"
1745 };
1746
1747 static const struct sdp_topology_stream audio_ulaw4fred = {
1748         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "ulaw", "fred"
1749 };
1750
1751 static const struct sdp_topology_stream audio_alaw4fred = {
1752         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "alaw", "fred"
1753 };
1754
1755 static const struct sdp_topology_stream audio_ulaw4rose = {
1756         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "ulaw", "rose"
1757 };
1758
1759 static const struct sdp_topology_stream audio_g7224rose = {
1760         AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, "g722", "rose"
1761 };
1762
1763
1764 static const struct sdp_topology_stream video_h2614dave = {
1765         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h261", "dave"
1766 };
1767
1768 static const struct sdp_topology_stream video_h2634dave = {
1769         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h263", "dave"
1770 };
1771
1772 static const struct sdp_topology_stream video_h2634fred = {
1773         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h263", "fred"
1774 };
1775
1776 static const struct sdp_topology_stream video_h2644fred = {
1777         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h264", "fred"
1778 };
1779
1780 static const struct sdp_topology_stream video_h2644rose = {
1781         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h264", "rose"
1782 };
1783
1784 static const struct sdp_topology_stream video_h2614rose = {
1785         AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, "h261", "rose"
1786 };
1787
1788
1789 static const struct sdp_topology_stream *top_adave_alaw_afred_ulaw_arose_g722_vdave_h261_vfred_h263_vrose_h264[] = {
1790         &audio_alaw4dave,
1791         &audio_alaw_no_name,
1792         &audio_ulaw4fred,
1793         &audio_ulaw_no_name,
1794         &audio_g7224rose,
1795         &audio_g722_no_name,
1796         &video_h2614dave,
1797         &video_h261_no_name,
1798         &video_h2634fred,
1799         &video_h263_no_name,
1800         &video_h2644rose,
1801         &video_h264_no_name,
1802         NULL
1803 };
1804
1805 static const struct sdp_topology_stream *top_vfred_vrose_vdave_h263_h264_h261_afred_ulaw_arose_g722_adave_alaw[] = {
1806         &video_h2644fred,
1807         &video_h2614rose,
1808         &video_h2634dave,
1809         &video_h263_no_name,
1810         &video_h264_no_name,
1811         &video_h261_no_name,
1812         &audio_alaw4fred,
1813         &audio_ulaw_no_name,
1814         &audio_ulaw4rose,
1815         &audio_g722_no_name,
1816         &audio_g7224dave,
1817         &audio_alaw_no_name,
1818         NULL
1819 };
1820
1821 static const struct sdp_topology_stream *top_adave_ulaw_afred_g722_arose_alaw_vdave_h263_vfred_h264_vrose_h261[] = {
1822         &audio_g7224dave,
1823         &audio_ulaw_no_name,
1824         &audio_alaw4fred,
1825         &audio_g722_no_name,
1826         &audio_ulaw4rose,
1827         &audio_alaw_no_name,
1828         &video_h2634dave,
1829         &video_h263_no_name,
1830         &video_h2644fred,
1831         &video_h264_no_name,
1832         &video_h2614rose,
1833         &video_h261_no_name,
1834         NULL
1835 };
1836
1837 /* Sorting by name and type with no new or deleted streams */
1838 static const struct sdp_update_test mrg_by_name_00 = {
1839         .initial  = top_adave_alaw_afred_ulaw_arose_g722_vdave_h261_vfred_h263_vrose_h264,
1840         .update_1 = top_vfred_vrose_vdave_h263_h264_h261_afred_ulaw_arose_g722_adave_alaw,
1841         .expected = top_adave_ulaw_afred_g722_arose_alaw_vdave_h263_vfred_h264_vrose_h261,
1842 };
1843
1844
1845 static const struct sdp_topology_stream *top_adave_g723_h261[] = {
1846         &audio_g7224dave,
1847         &audio_g723_no_name,
1848         &video_h261_no_name,
1849         NULL
1850 };
1851
1852 /* Sorting by name and type adding names to streams */
1853 static const struct sdp_update_test mrg_by_name_01 = {
1854         .initial  = top_ulaw_alaw_h264,
1855         .update_1 = top_adave_g723_h261,
1856         .expected = top_adave_g723_h261,
1857 };
1858
1859
1860 /* Sorting by name and type removing names from streams */
1861 static const struct sdp_update_test mrg_by_name_02 = {
1862         .initial  = top_adave_g723_h261,
1863         .update_1 = top_ulaw_alaw_h264,
1864         .expected = top_ulaw_alaw_h264,
1865 };
1866
1867
1868 static const struct sdp_update_test *sdp_update_cases[] = {
1869         /* Merging by type */
1870         /* 00 */ &mrg_by_type_00,
1871         /* 01 */ &mrg_by_type_01,
1872         /* 02 */ &mrg_by_type_02,
1873         /* 03 */ &mrg_by_type_03,
1874         /* 04 */ &mrg_by_type_04,
1875         /* 05 */ &mrg_by_type_05,
1876         /* 06 */ &mrg_by_type_06,
1877         /* 07 */ &mrg_by_type_07,
1878         /* 08 */ &mrg_by_type_08,
1879         /* 09 */ &mrg_by_type_09,
1880         /* 10 */ &mrg_by_type_10,
1881         /* 11 */ &mrg_by_type_11,
1882
1883         /* Merging by name and type */
1884         /* 12 */ &mrg_by_name_00,
1885         /* 13 */ &mrg_by_name_01,
1886         /* 14 */ &mrg_by_name_02,
1887 };
1888
1889 AST_TEST_DEFINE(sdp_update_topology)
1890 {
1891         enum ast_test_result_state res;
1892         unsigned int idx;
1893         int status;
1894         struct ast_sdp_options *options;
1895         struct ast_stream_topology *topology;
1896         struct ast_sdp_state *test_state = NULL;
1897
1898         static const struct sdp_format sdp_formats[] = {
1899                 { AST_MEDIA_TYPE_AUDIO, "ulaw,alaw,g722,g723" },
1900                 { AST_MEDIA_TYPE_VIDEO, "h261,h263,h264,vp8" },
1901                 { AST_MEDIA_TYPE_IMAGE, "t38" },
1902         };
1903
1904         switch(cmd) {
1905         case TEST_INIT:
1906                 info->name = "sdp_update_topology";
1907                 info->category = "/main/sdp/";
1908                 info->summary = "Merge topology updates from the system";
1909                 info->description =
1910                         "1) Create a SDP state with an optional initial topology.\n"
1911                         "2) Update the initial topology with one or two new topologies.\n"
1912                         "3) Get the SDP offer to merge the updates into the initial topology.\n"
1913                         "4) Check that the offered topology matches the expected topology.\n"
1914                         "5) Repeat these steps for each test case defined.";
1915                 return AST_TEST_NOT_RUN;
1916         case TEST_EXECUTE:
1917                 break;
1918         }
1919
1920         res = AST_TEST_FAIL;
1921         for (idx = 0; idx < ARRAY_LEN(sdp_update_cases); ++idx) {
1922                 ast_test_status_update(test, "Starting update case %d\n", idx);
1923
1924                 /* Create a SDP state with an optional initial topology. */
1925                 options = sdp_options_common();
1926                 if (!options) {
1927                         ast_test_status_update(test, "Failed to allocate SDP options\n");
1928                         goto end;
1929                 }
1930                 if (sdp_update_cases[idx]->max_streams) {
1931                         ast_sdp_options_set_max_streams(options, sdp_update_cases[idx]->max_streams);
1932                 }
1933                 if (build_sdp_option_formats(options, ARRAY_LEN(sdp_formats), sdp_formats)) {
1934                         ast_test_status_update(test, "Failed to setup SDP options new stream formats\n");
1935                         goto end;
1936                 }
1937                 if (sdp_update_cases[idx]->initial) {
1938                         topology = build_update_topology(sdp_update_cases[idx]->initial);
1939                         if (!topology) {
1940                                 ast_test_status_update(test, "Failed to build initial SDP state topology\n");
1941                                 goto end;
1942                         }
1943                 } else {
1944                         topology = NULL;
1945                 }
1946                 test_state = ast_sdp_state_alloc(topology, options);
1947                 ast_stream_topology_free(topology);
1948                 if (!test_state) {
1949                         ast_test_status_update(test, "Failed to build SDP state\n");
1950                         goto end;
1951                 }
1952
1953                 /* Update the initial topology with one or two new topologies. */
1954                 topology = build_update_topology(sdp_update_cases[idx]->update_1);
1955                 if (!topology) {
1956                         ast_test_status_update(test, "Failed to build first update SDP state topology\n");
1957                         goto end;
1958                 }
1959                 status = ast_sdp_state_update_local_topology(test_state, topology);
1960                 ast_stream_topology_free(topology);
1961                 if (status) {
1962                         ast_test_status_update(test, "Failed to update first update SDP state topology\n");
1963                         goto end;
1964                 }
1965                 if (sdp_update_cases[idx]->update_2) {
1966                         topology = build_update_topology(sdp_update_cases[idx]->update_2);
1967                         if (!topology) {
1968                                 ast_test_status_update(test, "Failed to build second update SDP state topology\n");
1969                                 goto end;
1970                         }
1971                         status = ast_sdp_state_update_local_topology(test_state, topology);
1972                         ast_stream_topology_free(topology);
1973                         if (status) {
1974                                 ast_test_status_update(test, "Failed to update second update SDP state topology\n");
1975                                 goto end;
1976                         }
1977                 }
1978
1979                 /* Get the SDP offer to merge the updates into the initial topology. */
1980                 if (!ast_sdp_state_get_local_sdp(test_state)) {
1981                         ast_test_status_update(test, "Failed to create offer SDP\n");
1982                         goto end;
1983                 }
1984
1985                 /* Check that the offered topology matches the expected topology. */
1986                 topology = build_update_topology(sdp_update_cases[idx]->expected);
1987                 if (!topology) {
1988                         ast_test_status_update(test, "Failed to build expected topology\n");
1989                         goto end;
1990                 }
1991                 status = cmp_update_topology(test, topology,
1992                         ast_sdp_state_get_local_topology(test_state));
1993                 ast_stream_topology_free(topology);
1994                 if (status) {
1995                         ast_test_status_update(test, "Failed to match expected topology\n");
1996                         goto end;
1997                 }
1998
1999                 /* Repeat for each test case defined. */
2000                 ast_sdp_state_free(test_state);
2001                 test_state = NULL;
2002         }
2003         res = AST_TEST_PASS;
2004
2005 end:
2006         ast_sdp_state_free(test_state);
2007         return res;
2008 }
2009
2010 static int unload_module(void)
2011 {
2012         AST_TEST_UNREGISTER(invalid_rtpmap);
2013         AST_TEST_UNREGISTER(rtpmap);
2014         AST_TEST_UNREGISTER(find_attr);
2015         AST_TEST_UNREGISTER(topology_to_sdp);
2016         AST_TEST_UNREGISTER(sdp_to_topology);
2017         AST_TEST_UNREGISTER(sdp_negotiation_initial);
2018         AST_TEST_UNREGISTER(sdp_negotiation_type_change);
2019         AST_TEST_UNREGISTER(sdp_negotiation_decline_incompatible);
2020         AST_TEST_UNREGISTER(sdp_negotiation_decline_max_streams);
2021         AST_TEST_UNREGISTER(sdp_negotiation_not_acceptable);
2022         AST_TEST_UNREGISTER(sdp_ssrc_attributes);
2023         AST_TEST_UNREGISTER(sdp_update_topology);
2024
2025         return 0;
2026 }
2027
2028 static int load_module(void)
2029 {
2030         AST_TEST_REGISTER(invalid_rtpmap);
2031         AST_TEST_REGISTER(rtpmap);
2032         AST_TEST_REGISTER(find_attr);
2033         AST_TEST_REGISTER(topology_to_sdp);
2034         AST_TEST_REGISTER(sdp_to_topology);
2035         AST_TEST_REGISTER(sdp_negotiation_initial);
2036         AST_TEST_REGISTER(sdp_negotiation_type_change);
2037         AST_TEST_REGISTER(sdp_negotiation_decline_incompatible);
2038         AST_TEST_REGISTER(sdp_negotiation_decline_max_streams);
2039         AST_TEST_REGISTER(sdp_negotiation_not_acceptable);
2040         AST_TEST_REGISTER(sdp_ssrc_attributes);
2041         AST_TEST_REGISTER(sdp_update_topology);
2042
2043         return AST_MODULE_LOAD_SUCCESS;
2044 }
2045
2046 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SDP tests");