Loader: Remove unneeded load_pri declarations.
[asterisk/asterisk.git] / tests / test_stream.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2017, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@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 /*!
20  * \file
21  * \brief Media Stream API Unit Tests
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  *
25  */
26
27 /*** MODULEINFO
28         <depend>TEST_FRAMEWORK</depend>
29         <support_level>core</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 #include "asterisk/test.h"
35 #include "asterisk/module.h"
36 #include "asterisk/stream.h"
37 #include "asterisk/format.h"
38 #include "asterisk/format_cap.h"
39 #include "asterisk/format_cache.h"
40 #include "asterisk/channel.h"
41
42 AST_TEST_DEFINE(stream_create)
43 {
44         RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_free);
45
46         switch (cmd) {
47         case TEST_INIT:
48                 info->name = "stream_create";
49                 info->category = "/main/stream/";
50                 info->summary = "stream create unit test";
51                 info->description =
52                         "Test that creating a stream results in a stream with the expected values";
53                 return AST_TEST_NOT_RUN;
54         case TEST_EXECUTE:
55                 break;
56         }
57
58         stream = ast_stream_alloc("test", AST_MEDIA_TYPE_AUDIO);
59         if (!stream) {
60                 ast_test_status_update(test, "Failed to create media stream given proper arguments\n");
61                 return AST_TEST_FAIL;
62         }
63
64         if (ast_stream_get_state(stream) != AST_STREAM_STATE_INACTIVE) {
65                 ast_test_status_update(test, "Newly created stream does not have expected inactive stream state\n");
66                 return AST_TEST_FAIL;
67         }
68
69         if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO) {
70                 ast_test_status_update(test, "Newly created stream does not have expected audio media type\n");
71                 return AST_TEST_FAIL;
72         }
73
74         if (strcmp(ast_stream_get_name(stream), "test")) {
75                 ast_test_status_update(test, "Newly created stream does not have expected name of test\n");
76                 return AST_TEST_FAIL;
77         }
78
79         return AST_TEST_PASS;
80 }
81
82 AST_TEST_DEFINE(stream_create_no_name)
83 {
84         RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_free);
85
86         switch (cmd) {
87         case TEST_INIT:
88                 info->name = "stream_create_no_name";
89                 info->category = "/main/stream/";
90                 info->summary = "stream create (without a name) unit test";
91                 info->description =
92                         "Test that creating a stream with no name works";
93                 return AST_TEST_NOT_RUN;
94         case TEST_EXECUTE:
95                 break;
96         }
97
98         stream = ast_stream_alloc(NULL, AST_MEDIA_TYPE_AUDIO);
99         if (!stream) {
100                 ast_test_status_update(test, "Failed to create media stream given proper arguments\n");
101                 return AST_TEST_FAIL;
102         }
103
104         return AST_TEST_PASS;
105 }
106
107 AST_TEST_DEFINE(stream_set_type)
108 {
109         RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_free);
110
111         switch (cmd) {
112         case TEST_INIT:
113                 info->name = "stream_set_type";
114                 info->category = "/main/stream/";
115                 info->summary = "stream type setting unit test";
116                 info->description =
117                         "Test that changing the type of a stream works";
118                 return AST_TEST_NOT_RUN;
119         case TEST_EXECUTE:
120                 break;
121         }
122
123         stream = ast_stream_alloc("test", AST_MEDIA_TYPE_AUDIO);
124         if (!stream) {
125                 ast_test_status_update(test, "Failed to create media stream given proper arguments\n");
126                 return AST_TEST_FAIL;
127         }
128
129         if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO) {
130                 ast_test_status_update(test, "Newly created stream does not have expected audio media type\n");
131                 return AST_TEST_FAIL;
132         }
133
134         ast_stream_set_type(stream, AST_MEDIA_TYPE_VIDEO);
135
136         if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_VIDEO) {
137                 ast_test_status_update(test, "Changed stream does not have expected video media type\n");
138                 return AST_TEST_FAIL;
139         }
140
141         return AST_TEST_PASS;
142 }
143
144 AST_TEST_DEFINE(stream_set_formats)
145 {
146         RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_free);
147         RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
148
149         switch (cmd) {
150         case TEST_INIT:
151                 info->name = "stream_set_formats";
152                 info->category = "/main/stream/";
153                 info->summary = "stream formats setting unit test";
154                 info->description =
155                         "Test that changing the formats of a stream works";
156                 return AST_TEST_NOT_RUN;
157         case TEST_EXECUTE:
158                 break;
159         }
160
161         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
162         if (!caps) {
163                 ast_test_status_update(test, "Failed to create a format capabilities structure for testing\n");
164                 return AST_TEST_FAIL;
165         }
166
167         stream = ast_stream_alloc("test", AST_MEDIA_TYPE_AUDIO);
168         if (!stream) {
169                 ast_test_status_update(test, "Failed to create media stream given proper arguments\n");
170                 return AST_TEST_FAIL;
171         }
172
173         ast_stream_set_formats(stream, caps);
174
175         if (ast_stream_get_formats(stream) != caps) {
176                 ast_test_status_update(test, "Changed stream does not have expected formats\n");
177                 return AST_TEST_FAIL;
178         }
179
180         ast_stream_set_formats(stream, NULL);
181
182         if (ast_stream_get_formats(stream)) {
183                 ast_test_status_update(test, "Retrieved formats from stream despite removing them\n");
184                 return AST_TEST_FAIL;
185         }
186
187         return AST_TEST_PASS;
188 }
189
190 AST_TEST_DEFINE(stream_set_state)
191 {
192         RAII_VAR(struct ast_stream *, stream, NULL, ast_stream_free);
193
194         switch (cmd) {
195         case TEST_INIT:
196                 info->name = "stream_set_state";
197                 info->category = "/main/stream/";
198                 info->summary = "stream state setting unit test";
199                 info->description =
200                         "Test that changing the state of a stream works";
201                 return AST_TEST_NOT_RUN;
202         case TEST_EXECUTE:
203                 break;
204         }
205
206         stream = ast_stream_alloc("test", AST_MEDIA_TYPE_AUDIO);
207         if (!stream) {
208                 ast_test_status_update(test, "Failed to create media stream given proper arguments\n");
209                 return AST_TEST_FAIL;
210         }
211
212         if (ast_stream_get_state(stream) != AST_STREAM_STATE_INACTIVE) {
213                 ast_test_status_update(test, "Newly created stream does not have expected inactive stream state\n");
214                 return AST_TEST_FAIL;
215         }
216
217         ast_stream_set_state(stream, AST_STREAM_STATE_SENDRECV);
218
219         if (ast_stream_get_state(stream) != AST_STREAM_STATE_SENDRECV) {
220                 ast_test_status_update(test, "Changed stream does not have expected sendrecv state\n");
221                 return AST_TEST_FAIL;
222         }
223
224         return AST_TEST_PASS;
225 }
226
227 AST_TEST_DEFINE(stream_topology_create)
228 {
229         RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
230
231         switch (cmd) {
232         case TEST_INIT:
233                 info->name = "stream_topology_create";
234                 info->category = "/main/stream/";
235                 info->summary = "stream topology creation unit test";
236                 info->description =
237                         "Test that creating a stream topology works";
238                 return AST_TEST_NOT_RUN;
239         case TEST_EXECUTE:
240                 break;
241         }
242
243         topology = ast_stream_topology_alloc();
244         if (!topology) {
245                 ast_test_status_update(test, "Failed to create media stream topology\n");
246                 return AST_TEST_FAIL;
247         }
248
249         return AST_TEST_PASS;
250 }
251
252 AST_TEST_DEFINE(stream_topology_clone)
253 {
254         RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
255         RAII_VAR(struct ast_stream_topology *, cloned, NULL, ast_stream_topology_free);
256         struct ast_stream *audio_stream, *video_stream;
257
258         switch (cmd) {
259         case TEST_INIT:
260                 info->name = "stream_topology_clone";
261                 info->category = "/main/stream/";
262                 info->summary = "stream topology cloning unit test";
263                 info->description =
264                         "Test that cloning a stream topology results in a clone with the same contents";
265                 return AST_TEST_NOT_RUN;
266         case TEST_EXECUTE:
267                 break;
268         }
269
270         topology = ast_stream_topology_alloc();
271         if (!topology) {
272                 ast_test_status_update(test, "Failed to create media stream topology\n");
273                 return AST_TEST_FAIL;
274         }
275
276         audio_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO);
277         if (!audio_stream) {
278                 ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n");
279                 return AST_TEST_FAIL;
280         }
281
282         if (ast_stream_topology_append_stream(topology, audio_stream) == -1) {
283                 ast_test_status_update(test, "Failed to append valid audio stream to stream topology\n");
284                 ast_stream_free(audio_stream);
285                 return AST_TEST_FAIL;
286         }
287
288         video_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO);
289         if (!video_stream) {
290                 ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n");
291                 return AST_TEST_FAIL;
292         }
293
294         if (ast_stream_topology_append_stream(topology, video_stream) == -1) {
295                 ast_test_status_update(test, "Failed to append valid video stream to stream topology\n");
296                 ast_stream_free(video_stream);
297                 return AST_TEST_FAIL;
298         }
299
300         cloned = ast_stream_topology_clone(topology);
301         if (!cloned) {
302                 ast_test_status_update(test, "Failed to clone a perfectly good stream topology\n");
303                 return AST_TEST_FAIL;
304         }
305
306         if (ast_stream_topology_get_count(cloned) != ast_stream_topology_get_count(topology)) {
307                 ast_test_status_update(test, "Cloned stream topology does not contain same number of streams as original\n");
308                 return AST_TEST_FAIL;
309         }
310
311         if (ast_stream_get_type(ast_stream_topology_get_stream(cloned, 0)) != ast_stream_get_type(ast_stream_topology_get_stream(topology, 0))) {
312                 ast_test_status_update(test, "Cloned audio stream does not contain same type as original\n");
313                 return AST_TEST_FAIL;
314         }
315
316         if (ast_stream_get_type(ast_stream_topology_get_stream(cloned, 1)) != ast_stream_get_type(ast_stream_topology_get_stream(topology, 1))) {
317                 ast_test_status_update(test, "Cloned video stream does not contain same type as original\n");
318                 return AST_TEST_FAIL;
319         }
320
321         return AST_TEST_PASS;
322 }
323
324 AST_TEST_DEFINE(stream_topology_append_stream)
325 {
326         RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
327         struct ast_stream *audio_stream, *video_stream;
328         int position;
329
330         switch (cmd) {
331         case TEST_INIT:
332                 info->name = "stream_topology_append_stream";
333                 info->category = "/main/stream/";
334                 info->summary = "stream topology stream appending unit test";
335                 info->description =
336                         "Test that appending streams to a stream topology works";
337                 return AST_TEST_NOT_RUN;
338         case TEST_EXECUTE:
339                 break;
340         }
341
342         topology = ast_stream_topology_alloc();
343         if (!topology) {
344                 ast_test_status_update(test, "Failed to create media stream topology\n");
345                 return AST_TEST_FAIL;
346         }
347
348         audio_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO);
349         if (!audio_stream) {
350                 ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n");
351                 return AST_TEST_FAIL;
352         }
353
354         position = ast_stream_topology_append_stream(topology, audio_stream);
355         if (position == -1) {
356                 ast_test_status_update(test, "Failed to append valid audio stream to stream topology\n");
357                 ast_stream_free(audio_stream);
358                 return AST_TEST_FAIL;
359         } else if (position != 0) {
360                 ast_test_status_update(test, "Appended audio stream to stream topology but position is '%d' instead of 0\n",
361                         position);
362                 return AST_TEST_FAIL;
363         }
364
365         if (ast_stream_topology_get_count(topology) != 1) {
366                 ast_test_status_update(test, "Appended an audio stream to the stream topology but stream count is '%d' on it, not 1\n",
367                         ast_stream_topology_get_count(topology));
368                 return AST_TEST_FAIL;
369         }
370
371         if (ast_stream_topology_get_stream(topology, 0) != audio_stream) {
372                 ast_test_status_update(test, "Appended an audio stream to the stream topology but returned stream doesn't match\n");
373                 return AST_TEST_FAIL;
374         }
375
376         if (ast_stream_get_position(audio_stream) != 0) {
377                 ast_test_status_update(test, "Appended audio stream says it is at position '%d' instead of 0\n",
378                         ast_stream_get_position(audio_stream));
379                 return AST_TEST_FAIL;
380         }
381
382         video_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO);
383         if (!video_stream) {
384                 ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n");
385                 return AST_TEST_FAIL;
386         }
387
388         position = ast_stream_topology_append_stream(topology, video_stream);
389         if (position == -1) {
390                 ast_test_status_update(test, "Failed to append valid video stream to stream topology\n");
391                 ast_stream_free(video_stream);
392                 return AST_TEST_FAIL;
393         } else if (position != 1) {
394                 ast_test_status_update(test, "Appended video stream to stream topology but position is '%d' instead of 1\n",
395                         position);
396                 return AST_TEST_FAIL;
397         }
398
399         if (ast_stream_topology_get_count(topology) != 2) {
400                 ast_test_status_update(test, "Appended a video stream to the stream topology but stream count is '%d' on it, not 2\n",
401                         ast_stream_topology_get_count(topology));
402                 return AST_TEST_FAIL;
403         }
404
405         if (ast_stream_topology_get_stream(topology, 1) != video_stream) {
406                 ast_test_status_update(test, "Appended a video stream to the stream topology but returned stream doesn't match\n");
407                 return AST_TEST_FAIL;
408         }
409
410         if (ast_stream_get_position(video_stream) != 1) {
411                 ast_test_status_update(test, "Appended video stream says it is at position '%d' instead of 1\n",
412                         ast_stream_get_position(video_stream));
413                 return AST_TEST_FAIL;
414         }
415
416         return AST_TEST_PASS;
417 }
418
419 AST_TEST_DEFINE(stream_topology_set_stream)
420 {
421         RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
422         struct ast_stream *audio_stream, *video_stream;
423
424         switch (cmd) {
425         case TEST_INIT:
426                 info->name = "stream_topology_set_stream";
427                 info->category = "/main/stream/";
428                 info->summary = "stream topology stream setting unit test";
429                 info->description =
430                         "Test that setting streams at a specific position in a topology works";
431                 return AST_TEST_NOT_RUN;
432         case TEST_EXECUTE:
433                 break;
434         }
435
436         topology = ast_stream_topology_alloc();
437         if (!topology) {
438                 ast_test_status_update(test, "Failed to create media stream topology\n");
439                 return AST_TEST_FAIL;
440         }
441
442         audio_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO);
443         if (!audio_stream) {
444                 ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n");
445                 return AST_TEST_FAIL;
446         }
447
448         if (ast_stream_topology_set_stream(topology, 0, audio_stream)) {
449                 ast_test_status_update(test, "Failed to set an audio stream to a position where it is permitted\n");
450                 ast_stream_free(audio_stream);
451                 return AST_TEST_FAIL;
452         }
453
454         if (ast_stream_topology_get_count(topology) != 1) {
455                 ast_test_status_update(test, "Set an audio stream on the stream topology but stream count is '%d' on it, not 1\n",
456                         ast_stream_topology_get_count(topology));
457                 return AST_TEST_FAIL;
458         }
459
460         if (ast_stream_topology_get_stream(topology, 0) != audio_stream) {
461                 ast_test_status_update(test, "Set an audio stream on the stream topology but returned stream doesn't match\n");
462                 return AST_TEST_FAIL;
463         }
464
465         if (ast_stream_get_position(audio_stream) != 0) {
466                 ast_test_status_update(test, "Set audio stream says it is at position '%d' instead of 0\n",
467                         ast_stream_get_position(audio_stream));
468                 return AST_TEST_FAIL;
469         }
470
471         video_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO);
472         if (!video_stream) {
473                 ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n");
474                 return AST_TEST_FAIL;
475         }
476
477         if (ast_stream_topology_set_stream(topology, 0, video_stream)) {
478                 ast_test_status_update(test, "Failed to set a video stream to a position where it is permitted\n");
479                 ast_stream_free(video_stream);
480                 return AST_TEST_FAIL;
481         }
482
483         if (ast_stream_topology_get_count(topology) != 1) {
484                 ast_test_status_update(test, "Set a video stream on the stream topology but stream count is '%d' on it, not 1\n",
485                         ast_stream_topology_get_count(topology));
486                 return AST_TEST_FAIL;
487         }
488
489         if (ast_stream_topology_get_stream(topology, 0) != video_stream) {
490                 ast_test_status_update(test, "Set a video stream on the stream topology but returned stream doesn't match\n");
491                 return AST_TEST_FAIL;
492         }
493
494         if (ast_stream_get_position(video_stream) != 0) {
495                 ast_test_status_update(test, "Set video stream says it is at position '%d' instead of 0\n",
496                         ast_stream_get_position(video_stream));
497                 return AST_TEST_FAIL;
498         }
499
500         audio_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO);
501         if (!audio_stream) {
502                 ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n");
503                 return AST_TEST_FAIL;
504         }
505
506         if (ast_stream_topology_set_stream(topology, 1, audio_stream)) {
507                 ast_test_status_update(test, "Failed to set an audio stream to a position where it is permitted\n");
508                 ast_stream_free(audio_stream);
509                 return AST_TEST_FAIL;
510         }
511
512         if (ast_stream_topology_get_count(topology) != 2) {
513                 ast_test_status_update(test, "Set an audio stream on the stream topology but stream count is '%d' on it, not 2\n",
514                         ast_stream_topology_get_count(topology));
515                 return AST_TEST_FAIL;
516         }
517
518         if (ast_stream_topology_get_stream(topology, 1) != audio_stream) {
519                 ast_test_status_update(test, "Set an audio stream on the stream topology but returned stream doesn't match\n");
520                 return AST_TEST_FAIL;
521         }
522
523         if (ast_stream_get_position(audio_stream) != 1) {
524                 ast_test_status_update(test, "Set audio stream says it is at position '%d' instead of 1\n",
525                         ast_stream_get_position(audio_stream));
526                 return AST_TEST_FAIL;
527         }
528
529         return AST_TEST_PASS;
530 }
531
532 static int check_stream_positions(struct ast_test *test, const struct ast_stream_topology *topology)
533 {
534         const struct ast_stream *stream;
535         int idx;
536         int pos;
537         enum ast_media_type type;
538
539         for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx) {
540                 stream = ast_stream_topology_get_stream(topology, idx);
541                 pos = ast_stream_get_position(stream);
542                 if (idx != pos) {
543                         type = ast_stream_get_type(stream);
544                         ast_test_status_update(test, "Failed: '%s' stream says it is at position %d instead of %d\n",
545                                 ast_codec_media_type2str(type), pos, idx);
546                         return -1;
547                 }
548         }
549         return 0;
550 }
551
552 AST_TEST_DEFINE(stream_topology_del_stream)
553 {
554         RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
555         struct ast_stream *stream;
556         enum ast_media_type type;
557         int idx;
558
559         switch (cmd) {
560         case TEST_INIT:
561                 info->name = "stream_topology_del_stream";
562                 info->category = "/main/stream/";
563                 info->summary = "stream topology stream delete unit test";
564                 info->description =
565                         "Test that deleting streams at a specific position in a topology works";
566                 return AST_TEST_NOT_RUN;
567         case TEST_EXECUTE:
568                 break;
569         }
570
571         topology = ast_stream_topology_alloc();
572         if (!topology) {
573                 ast_test_status_update(test, "Failed to create media stream topology\n");
574                 return AST_TEST_FAIL;
575         }
576
577         /* Create streams */
578         for (type = AST_MEDIA_TYPE_UNKNOWN; type < AST_MEDIA_TYPE_END; ++type) {
579                 stream = ast_stream_alloc(ast_codec_media_type2str(type), type);
580                 if (!stream) {
581                         ast_test_status_update(test, "Failed to create '%s' stream for testing stream topology\n",
582                                 ast_codec_media_type2str(type));
583                         return AST_TEST_FAIL;
584                 }
585                 if (ast_stream_topology_append_stream(topology, stream) == -1) {
586                         ast_test_status_update(test, "Failed to append '%s' stream to topology\n",
587                                 ast_codec_media_type2str(type));
588                         ast_stream_free(stream);
589                         return AST_TEST_FAIL;
590                 }
591         }
592
593         /* Check initial stream positions and types for sanity. */
594         type = AST_MEDIA_TYPE_UNKNOWN;
595         for (idx = 0; idx < ast_stream_topology_get_count(topology); ++idx, ++type) {
596                 stream = ast_stream_topology_get_stream(topology, idx);
597                 if (type != ast_stream_get_type(stream)) {
598                         ast_test_status_update(test, "Initial topology types failed: Expected:%s Got:%s\n",
599                                 ast_codec_media_type2str(type),
600                                 ast_codec_media_type2str(ast_stream_get_type(stream)));
601                         return AST_TEST_FAIL;
602                 }
603         }
604         if (check_stream_positions(test, topology)) {
605                 ast_test_status_update(test, "Initial topology positions failed.\n");
606                 return AST_TEST_FAIL;
607         }
608
609         /* Try to delete outside of topology size */
610         if (!ast_stream_topology_del_stream(topology, ast_stream_topology_get_count(topology))) {
611                 ast_test_status_update(test, "Deleting stream outside of topology succeeded!\n");
612                 return AST_TEST_FAIL;
613         }
614
615         /* Try to delete the last topology stream */
616         if (ast_stream_topology_del_stream(topology, ast_stream_topology_get_count(topology) - 1)) {
617                 ast_test_status_update(test, "Failed deleting last stream of topology.\n");
618                 return AST_TEST_FAIL;
619         }
620         if (check_stream_positions(test, topology)) {
621                 ast_test_status_update(test, "Last stream delete topology positions failed.\n");
622                 return AST_TEST_FAIL;
623         }
624         stream = ast_stream_topology_get_stream(topology, ast_stream_topology_get_count(topology) - 1);
625         type = ast_stream_get_type(stream);
626         if (type != AST_MEDIA_TYPE_END - 2) {
627                 ast_test_status_update(test, "Last stream delete types failed: Expected:%s Got:%s\n",
628                         ast_codec_media_type2str(AST_MEDIA_TYPE_END - 2),
629                         ast_codec_media_type2str(type));
630                 return AST_TEST_FAIL;
631         }
632
633         /* Try to delete the second stream in the topology */
634         if (ast_stream_topology_del_stream(topology, 1)) {
635                 ast_test_status_update(test, "Failed deleting second stream in topology.\n");
636                 return AST_TEST_FAIL;
637         }
638         if (check_stream_positions(test, topology)) {
639                 ast_test_status_update(test, "Second stream delete topology positions failed.\n");
640                 return AST_TEST_FAIL;
641         }
642         stream = ast_stream_topology_get_stream(topology, 1);
643         type = ast_stream_get_type(stream);
644         if (type != AST_MEDIA_TYPE_UNKNOWN + 2) {
645                 ast_test_status_update(test, "Second stream delete types failed: Expected:%s Got:%s\n",
646                         ast_codec_media_type2str(AST_MEDIA_TYPE_UNKNOWN + 2),
647                         ast_codec_media_type2str(type));
648                 return AST_TEST_FAIL;
649         }
650
651         /* Try to delete the first stream in the topology */
652         if (ast_stream_topology_del_stream(topology, 0)) {
653                 ast_test_status_update(test, "Failed deleting first stream in topology.\n");
654                 return AST_TEST_FAIL;
655         }
656         if (check_stream_positions(test, topology)) {
657                 ast_test_status_update(test, "First stream delete topology positions failed.\n");
658                 return AST_TEST_FAIL;
659         }
660         stream = ast_stream_topology_get_stream(topology, 0);
661         type = ast_stream_get_type(stream);
662         if (type != AST_MEDIA_TYPE_UNKNOWN + 2) {
663                 ast_test_status_update(test, "First stream delete types failed: Expected:%s Got:%s\n",
664                         ast_codec_media_type2str(AST_MEDIA_TYPE_UNKNOWN + 2),
665                         ast_codec_media_type2str(type));
666                 return AST_TEST_FAIL;
667         }
668
669         return AST_TEST_PASS;
670 }
671
672 AST_TEST_DEFINE(stream_topology_create_from_format_cap)
673 {
674         RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
675         RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
676
677         switch (cmd) {
678         case TEST_INIT:
679                 info->name = "stream_topology_create_from_format_cap";
680                 info->category = "/main/stream/";
681                 info->summary = "stream topology creation from format capabilities unit test";
682                 info->description =
683                         "Test that creating a stream topology from format capabilities results in the expected streams";
684                 return AST_TEST_NOT_RUN;
685         case TEST_EXECUTE:
686                 break;
687         }
688
689         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
690         if (!caps) {
691                 ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
692                 return AST_TEST_FAIL;
693         }
694
695         if (ast_format_cap_append(caps, ast_format_ulaw, 0)) {
696                 ast_test_status_update(test, "Failed to append a ulaw format to capabilities for stream topology creation\n");
697                 return AST_TEST_FAIL;
698         }
699
700         if (ast_format_cap_append(caps, ast_format_alaw, 0)) {
701                 ast_test_status_update(test, "Failed to append an alaw format to capabilities for stream topology creation\n");
702                 return AST_TEST_FAIL;
703         }
704
705         topology = ast_stream_topology_create_from_format_cap(caps);
706         if (!topology) {
707                 ast_test_status_update(test, "Failed to create a stream topology using a perfectly good format capabilities\n");
708                 return AST_TEST_FAIL;
709         }
710
711         if (ast_stream_topology_get_count(topology) != 1) {
712                 ast_test_status_update(test, "Expected a stream topology with 1 stream but it has %d streams\n",
713                         ast_stream_topology_get_count(topology));
714                 return AST_TEST_FAIL;
715         }
716
717         if (ast_stream_get_type(ast_stream_topology_get_stream(topology, 0)) != AST_MEDIA_TYPE_AUDIO) {
718                 ast_test_status_update(test, "Produced stream topology has a single stream of type %s instead of audio\n",
719                         ast_codec_media_type2str(ast_stream_get_type(ast_stream_topology_get_stream(topology, 0))));
720                 return AST_TEST_FAIL;
721         }
722
723         ast_stream_topology_free(topology);
724         topology = NULL;
725
726         ast_format_cap_append(caps, ast_format_h264, 0);
727
728         topology = ast_stream_topology_create_from_format_cap(caps);
729         if (!topology) {
730                 ast_test_status_update(test, "Failed to create a stream topology using a perfectly good format capabilities\n");
731                 return AST_TEST_FAIL;
732         }
733
734         if (ast_stream_topology_get_count(topology) != 2) {
735                 ast_test_status_update(test, "Expected a stream topology with 2 streams but it has %d streams\n",
736                         ast_stream_topology_get_count(topology));
737                 return AST_TEST_FAIL;
738         }
739
740         if (ast_stream_get_type(ast_stream_topology_get_stream(topology, 0)) != AST_MEDIA_TYPE_AUDIO) {
741                 ast_test_status_update(test, "Produced stream topology has a first stream of type %s instead of audio\n",
742                         ast_codec_media_type2str(ast_stream_get_type(ast_stream_topology_get_stream(topology, 0))));
743                 return AST_TEST_FAIL;
744         }
745
746         if (ast_stream_get_type(ast_stream_topology_get_stream(topology, 1)) != AST_MEDIA_TYPE_VIDEO) {
747                 ast_test_status_update(test, "Produced stream topology has a second stream of type %s instead of video\n",
748                         ast_codec_media_type2str(ast_stream_get_type(ast_stream_topology_get_stream(topology, 1))));
749                 return AST_TEST_FAIL;
750         }
751
752         return AST_TEST_PASS;
753 }
754
755 AST_TEST_DEFINE(stream_topology_get_first_stream_by_type)
756 {
757         RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
758         struct ast_stream *first_stream;
759         struct ast_stream *second_stream;
760         struct ast_stream *third_stream;
761         struct ast_stream *fourth_stream;
762         struct ast_stream *fifth_stream;
763         struct ast_stream *sixth_stream;
764
765         switch (cmd) {
766         case TEST_INIT:
767                 info->name = "stream_topology_get_first_stream_by_type";
768                 info->category = "/main/stream/";
769                 info->summary = "stream topology getting first stream by type unit test";
770                 info->description =
771                         "Test that getting the first stream by type from a topology actually returns the first stream";
772                 return AST_TEST_NOT_RUN;
773         case TEST_EXECUTE:
774                 break;
775         }
776
777         topology = ast_stream_topology_alloc();
778         if (!topology) {
779                 ast_test_status_update(test, "Failed to create media stream topology\n");
780                 return AST_TEST_FAIL;
781         }
782
783         first_stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO);
784         if (!first_stream) {
785                 ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n");
786                 return AST_TEST_FAIL;
787         }
788         ast_stream_set_state(first_stream, AST_STREAM_STATE_REMOVED);
789
790         if (ast_stream_topology_append_stream(topology, first_stream) == -1) {
791                 ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
792                 ast_stream_free(first_stream);
793                 return AST_TEST_FAIL;
794         }
795
796         second_stream = ast_stream_alloc("audio2", AST_MEDIA_TYPE_AUDIO);
797         if (!second_stream) {
798                 ast_test_status_update(test, "Failed to create a second audio stream for testing stream topology\n");
799                 return AST_TEST_FAIL;
800         }
801
802         if (ast_stream_topology_append_stream(topology, second_stream) == -1) {
803                 ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
804                 ast_stream_free(second_stream);
805                 return AST_TEST_FAIL;
806         }
807
808         third_stream = ast_stream_alloc("audio3", AST_MEDIA_TYPE_AUDIO);
809         if (!third_stream) {
810                 ast_test_status_update(test, "Failed to create a third audio stream for testing stream topology\n");
811                 return AST_TEST_FAIL;
812         }
813
814         if (ast_stream_topology_append_stream(topology, third_stream) == -1) {
815                 ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
816                 ast_stream_free(third_stream);
817                 return AST_TEST_FAIL;
818         }
819
820         fourth_stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO);
821         if (!fourth_stream) {
822                 ast_test_status_update(test, "Failed to create a video stream for testing stream topology\n");
823                 return AST_TEST_FAIL;
824         }
825         ast_stream_set_state(fourth_stream, AST_STREAM_STATE_REMOVED);
826
827         if (ast_stream_topology_append_stream(topology, fourth_stream) == -1) {
828                 ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
829                 ast_stream_free(fourth_stream);
830                 return AST_TEST_FAIL;
831         }
832
833         fifth_stream = ast_stream_alloc("video2", AST_MEDIA_TYPE_VIDEO);
834         if (!fifth_stream) {
835                 ast_test_status_update(test, "Failed to create a second video stream for testing stream topology\n");
836                 return AST_TEST_FAIL;
837         }
838
839         if (ast_stream_topology_append_stream(topology, fifth_stream) == -1) {
840                 ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
841                 ast_stream_free(fifth_stream);
842                 return AST_TEST_FAIL;
843         }
844
845         sixth_stream = ast_stream_alloc("video3", AST_MEDIA_TYPE_VIDEO);
846         if (!sixth_stream) {
847                 ast_test_status_update(test, "Failed to create a third video stream for testing stream topology\n");
848                 return AST_TEST_FAIL;
849         }
850
851         if (ast_stream_topology_append_stream(topology, sixth_stream) == -1) {
852                 ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
853                 ast_stream_free(sixth_stream);
854                 return AST_TEST_FAIL;
855         }
856
857         if (ast_stream_topology_get_first_stream_by_type(topology, AST_MEDIA_TYPE_AUDIO) != second_stream) {
858                 ast_test_status_update(test, "Retrieved first audio stream from topology but it is not the correct one\n");
859                 return AST_TEST_FAIL;
860         }
861
862         if (ast_stream_topology_get_first_stream_by_type(topology, AST_MEDIA_TYPE_VIDEO) != fifth_stream) {
863                 ast_test_status_update(test, "Retrieved first video stream from topology but it is not the correct one\n");
864                 return AST_TEST_FAIL;
865         }
866
867         return AST_TEST_PASS;
868 }
869
870 static const struct ast_channel_tech mock_channel_tech = {
871 };
872
873 AST_TEST_DEFINE(stream_topology_create_from_channel_nativeformats)
874 {
875         RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
876         RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
877         struct ast_channel *mock_channel;
878         enum ast_test_result_state res = AST_TEST_FAIL;
879         struct ast_str *codec_have_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
880         struct ast_str *codec_wanted_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
881
882         switch (cmd) {
883         case TEST_INIT:
884                 info->name = "stream_topology_create_from_channel_nativeformats";
885                 info->category = "/main/stream/";
886                 info->summary = "stream topology creation from channel native formats unit test";
887                 info->description =
888                         "Test that creating a stream topology from the setting of channel nativeformats results in the expected streams";
889                 return AST_TEST_NOT_RUN;
890         case TEST_EXECUTE:
891                 break;
892         }
893
894         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
895         if (!caps) {
896                 ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
897                 return AST_TEST_FAIL;
898         }
899
900         if (ast_format_cap_append(caps, ast_format_ulaw, 0)) {
901                 ast_test_status_update(test, "Failed to append a ulaw format to capabilities for channel nativeformats\n");
902                 return AST_TEST_FAIL;
903         }
904
905         if (ast_format_cap_append(caps, ast_format_alaw, 0)) {
906                 ast_test_status_update(test, "Failed to append an alaw format to capabilities for channel nativeformats\n");
907                 return AST_TEST_FAIL;
908         }
909
910         if (ast_format_cap_append(caps, ast_format_h264, 0)) {
911                 ast_test_status_update(test, "Failed to append an h264 format to capabilities for channel nativeformats\n");
912                 return AST_TEST_FAIL;
913         }
914
915         mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel");
916         if (!mock_channel) {
917                 ast_test_status_update(test, "Failed to create a mock channel for testing\n");
918                 return AST_TEST_FAIL;
919         }
920
921         ast_channel_tech_set(mock_channel, &mock_channel_tech);
922         ast_channel_nativeformats_set(mock_channel, caps);
923
924         if (!ast_channel_get_stream_topology(mock_channel)) {
925                 ast_test_status_update(test, "Set nativeformats with ulaw, alaw, and h264 on channel but it did not create a topology\n");
926                 goto end;
927         }
928
929         if (ast_stream_topology_get_count(ast_channel_get_stream_topology(mock_channel)) != 2) {
930                 ast_test_status_update(test, "Set nativeformats on a channel to ulaw, alaw, and h264 and received '%d' streams instead of expected 2\n",
931                         ast_stream_topology_get_count(ast_channel_get_stream_topology(mock_channel)));
932                 goto end;
933         }
934
935         if (ast_stream_get_type(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 0)) != AST_MEDIA_TYPE_AUDIO) {
936                 ast_test_status_update(test, "First stream on channel is of %s when it should be audio\n",
937                         ast_codec_media_type2str(ast_stream_get_type(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 0))));
938                 goto end;
939         }
940
941         ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_VIDEO);
942         if (!ast_format_cap_identical(ast_stream_get_formats(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 0)), caps)) {
943                 ast_test_status_update(test, "Formats on audio stream of channel are '%s' when they should be '%s'\n",
944                         ast_format_cap_get_names(ast_stream_get_formats(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 0)), &codec_have_buf),
945                         ast_format_cap_get_names(caps, &codec_wanted_buf));
946                 goto end;
947         }
948
949         if (ast_stream_get_type(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 1)) != AST_MEDIA_TYPE_VIDEO) {
950                 ast_test_status_update(test, "Second stream on channel is of type %s when it should be video\n",
951                         ast_codec_media_type2str(ast_stream_get_type(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 1))));
952                 goto end;
953         }
954
955         ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_AUDIO);
956
957         if (ast_format_cap_append(caps, ast_format_h264, 0)) {
958                 ast_test_status_update(test, "Failed to append h264 video codec to capabilities for capabilities comparison\n");
959                 goto end;
960         }
961
962         if (!ast_format_cap_identical(ast_stream_get_formats(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 1)), caps)) {
963                 ast_test_status_update(test, "Formats on video stream of channel are '%s' when they should be '%s'\n",
964                         ast_format_cap_get_names(ast_stream_get_formats(ast_stream_topology_get_stream(ast_channel_get_stream_topology(mock_channel), 1)), &codec_wanted_buf),
965                         ast_format_cap_get_names(caps, &codec_wanted_buf));
966                 goto end;
967         }
968
969         res = AST_TEST_PASS;
970
971 end:
972         ast_channel_unlock(mock_channel);
973         ast_hangup(mock_channel);
974
975         return res;
976 }
977
978 struct mock_channel_pvt {
979         int mallocd;
980         unsigned int wrote;
981         unsigned int wrote_stream;
982         int stream_num;
983         int frame_limit;
984         int frame_count;
985         int streams;
986         int frames_per_read;
987         unsigned int indicated_change_request;
988         unsigned int indicated_changed;
989 };
990
991 static struct ast_frame *mock_channel_read(struct ast_channel *chan)
992 {
993         struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan);
994         struct ast_frame f = { 0, };
995         struct ast_frame *head_frame = NULL;
996         struct ast_frame *tail_frame = NULL;
997         int i;
998
999         if (pvt->frames_per_read == 0) {
1000                 pvt->frames_per_read = 1;
1001         }
1002         for (i = 0; i < pvt->frames_per_read && pvt->frame_count < pvt->frame_limit; i++) {
1003                 struct ast_frame *fr;
1004
1005                 if (pvt->frame_count % 2 == 0) {
1006                         f.frametype = AST_FRAME_VOICE;
1007                         f.subclass.format = ast_format_ulaw;
1008                 } else {
1009                         f.frametype = AST_FRAME_VIDEO;
1010                         f.subclass.format = ast_format_h264;
1011                 }
1012                 f.seqno = pvt->frame_count;
1013                 f.stream_num = pvt->frame_count % pvt->streams;
1014                 pvt->frame_count++;
1015                 fr = ast_frdup(&f);
1016                 if (!head_frame) {
1017                         head_frame = fr;
1018                 } else  {
1019                         tail_frame->frame_list.next = fr;
1020                 }
1021                 tail_frame = fr;
1022         }
1023
1024         return(head_frame);
1025 }
1026
1027 static int mock_channel_write(struct ast_channel *chan, struct ast_frame *fr)
1028 {
1029         struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan);
1030
1031         pvt->wrote = 1;
1032
1033         return 0;
1034 }
1035
1036 static int mock_channel_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
1037 {
1038         struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan);
1039
1040         if (condition == AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE) {
1041                 pvt->indicated_change_request = 1;
1042         } else if (condition == AST_CONTROL_STREAM_TOPOLOGY_CHANGED) {
1043                 pvt->indicated_changed = 1;
1044         }
1045
1046         return 0;
1047 }
1048
1049 static int mock_channel_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame *fr)
1050 {
1051         struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan);
1052
1053         pvt->wrote_stream = 1;
1054         pvt->stream_num = stream_num;
1055
1056         return 0;
1057 }
1058
1059 static const struct ast_channel_tech mock_stream_channel_tech = {
1060         .read_stream = mock_channel_read,
1061         .write_stream = mock_channel_write_stream,
1062 };
1063
1064 AST_TEST_DEFINE(stream_topology_channel_set)
1065 {
1066         RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
1067         struct ast_channel *mock_channel;
1068         enum ast_test_result_state res = AST_TEST_PASS;
1069
1070         switch (cmd) {
1071         case TEST_INIT:
1072                 info->name = "stream_topology_channel_set";
1073                 info->category = "/main/stream/";
1074                 info->summary = "stream topology setting on a channel unit test";
1075                 info->description =
1076                         "Test that setting a stream topology on a channel works";
1077                 return AST_TEST_NOT_RUN;
1078         case TEST_EXECUTE:
1079                 break;
1080         }
1081
1082         topology = ast_stream_topology_alloc();
1083         if (!topology) {
1084                 ast_test_status_update(test, "Failed to create media stream topology\n");
1085                 return AST_TEST_FAIL;
1086         }
1087
1088         mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel");
1089         if (!mock_channel) {
1090                 ast_test_status_update(test, "Failed to create a mock channel for testing\n");
1091                 return AST_TEST_FAIL;
1092         }
1093
1094         ast_channel_tech_set(mock_channel, &mock_stream_channel_tech);
1095         ast_channel_set_stream_topology(mock_channel, topology);
1096
1097         if (ast_channel_get_stream_topology(mock_channel) != topology) {
1098                 ast_test_status_update(test, "Set an explicit stream topology on a channel but the returned one did not match it\n");
1099                 res = AST_TEST_FAIL;
1100         }
1101
1102         topology = NULL;
1103         ast_channel_unlock(mock_channel);
1104         ast_hangup(mock_channel);
1105
1106         return res;
1107 }
1108
1109 static int mock_channel_hangup(struct ast_channel *chan)
1110 {
1111         struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan);
1112
1113         if (pvt->mallocd) {
1114                 ast_free(pvt);
1115         }
1116
1117         ast_channel_tech_pvt_set(chan, NULL);
1118         return 0;
1119 }
1120
1121 static const struct ast_channel_tech mock_channel_old_write_tech = {
1122         .write = mock_channel_write,
1123         .write_video = mock_channel_write,
1124         .hangup = mock_channel_hangup,
1125 };
1126
1127 AST_TEST_DEFINE(stream_write_non_multistream)
1128 {
1129         RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
1130         struct ast_channel *mock_channel;
1131         struct mock_channel_pvt pvt = { 0, };
1132         enum ast_test_result_state res = AST_TEST_FAIL;
1133         struct ast_frame frame = { 0, };
1134
1135         switch (cmd) {
1136         case TEST_INIT:
1137                 info->name = "stream_write_non_multistream";
1138                 info->category = "/main/stream/";
1139                 info->summary = "stream writing to non-multistream capable channel test";
1140                 info->description =
1141                         "Test that writing frames to a non-multistream channel works as expected";
1142                 return AST_TEST_NOT_RUN;
1143         case TEST_EXECUTE:
1144                 break;
1145         }
1146
1147         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
1148         if (!caps) {
1149                 ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
1150                 return AST_TEST_FAIL;
1151         }
1152
1153         if (ast_format_cap_append(caps, ast_format_ulaw, 0)) {
1154                 ast_test_status_update(test, "Failed to append a ulaw format to capabilities for channel nativeformats\n");
1155                 return AST_TEST_FAIL;
1156         }
1157
1158         if (ast_format_cap_append(caps, ast_format_h264, 0)) {
1159                 ast_test_status_update(test, "Failed to append an h264 format to capabilities for channel nativeformats\n");
1160                 return AST_TEST_FAIL;
1161         }
1162
1163         mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel");
1164         if (!mock_channel) {
1165                 ast_test_status_update(test, "Failed to create a mock channel for testing\n");
1166                 return AST_TEST_FAIL;
1167         }
1168
1169         ast_channel_tech_set(mock_channel, &mock_channel_old_write_tech);
1170         ast_channel_nativeformats_set(mock_channel, caps);
1171
1172         pvt.wrote = 0;
1173         ast_channel_tech_pvt_set(mock_channel, &pvt);
1174         ast_channel_unlock(mock_channel);
1175
1176         frame.frametype = AST_FRAME_VOICE;
1177         frame.subclass.format = ast_format_ulaw;
1178
1179         if (ast_write(mock_channel, &frame)) {
1180                 ast_test_status_update(test, "Failed to write a ulaw frame to the mock channel when it should be fine\n");
1181                 goto end;
1182         }
1183
1184         if (!pvt.wrote) {
1185                 ast_test_status_update(test, "Successfully wrote a frame of ulaw but it never reached the channel driver\n");
1186                 goto end;
1187         }
1188
1189         pvt.wrote = 0;
1190
1191         if (!ast_write_stream(mock_channel, 2, &frame) || pvt.wrote) {
1192                 ast_test_status_update(test, "Successfully wrote a frame of ulaw to a non-existent stream\n");
1193                 goto end;
1194         }
1195
1196         frame.frametype = AST_FRAME_VIDEO;
1197         frame.subclass.format = ast_format_h264;
1198
1199         if (ast_write(mock_channel, &frame)) {
1200                 ast_test_status_update(test, "Failed to write an h264 frame to the mock channel when it should be fine\n");
1201                 goto end;
1202         }
1203
1204         if (!pvt.wrote) {
1205                 ast_test_status_update(test, "Successfully wrote a frame of h264 but it never reached the channel driver\n");
1206                 goto end;
1207         }
1208
1209         res = AST_TEST_PASS;
1210
1211 end:
1212         ast_hangup(mock_channel);
1213
1214         return res;
1215 }
1216
1217 static const struct ast_channel_tech mock_channel_write_stream_tech = {
1218         .write = mock_channel_write,
1219         .write_video = mock_channel_write,
1220         .write_stream = mock_channel_write_stream,
1221         .read_stream = mock_channel_read,
1222         .hangup = mock_channel_hangup,
1223 };
1224
1225 AST_TEST_DEFINE(stream_write_multistream)
1226 {
1227         RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
1228         RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
1229         struct ast_stream *stream;
1230         struct ast_channel *mock_channel;
1231         struct mock_channel_pvt pvt = { 0, };
1232         enum ast_test_result_state res = AST_TEST_FAIL;
1233         struct ast_frame frame = { 0, };
1234
1235         switch (cmd) {
1236         case TEST_INIT:
1237                 info->name = "stream_write_multistream";
1238                 info->category = "/main/stream/";
1239                 info->summary = "stream writing to multistream capable channel test";
1240                 info->description =
1241                         "Test that writing frames to a multistream channel works as expected";
1242                 return AST_TEST_NOT_RUN;
1243         case TEST_EXECUTE:
1244                 break;
1245         }
1246
1247         topology = ast_stream_topology_alloc();
1248         if (!topology) {
1249                 ast_test_status_update(test, "Failed to create media stream topology\n");
1250                 return AST_TEST_FAIL;
1251         }
1252
1253         stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO);
1254         if (!stream) {
1255                 ast_test_status_update(test, "Failed to create an audio stream for testing multistream writing\n");
1256                 return AST_TEST_FAIL;
1257         }
1258
1259         if (ast_stream_topology_append_stream(topology, stream) == -1) {
1260                 ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
1261                 ast_stream_free(stream);
1262                 return AST_TEST_FAIL;
1263         }
1264
1265         stream = ast_stream_alloc("audio2", AST_MEDIA_TYPE_AUDIO);
1266         if (!stream) {
1267                 ast_test_status_update(test, "Failed to create an audio stream for testing multistream writing\n");
1268                 return AST_TEST_FAIL;
1269         }
1270
1271         if (ast_stream_topology_append_stream(topology, stream) == -1) {
1272                 ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
1273                 ast_stream_free(stream);
1274                 return AST_TEST_FAIL;
1275         }
1276
1277         stream = ast_stream_alloc("video", AST_MEDIA_TYPE_VIDEO);
1278         if (!stream) {
1279                 ast_test_status_update(test, "Failed to create a video stream for testing multistream writing\n");
1280                 return AST_TEST_FAIL;
1281         }
1282
1283         if (ast_stream_topology_append_stream(topology, stream) == -1) {
1284                 ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
1285                 ast_stream_free(stream);
1286                 return AST_TEST_FAIL;
1287         }
1288
1289         stream = ast_stream_alloc("video2", AST_MEDIA_TYPE_VIDEO);
1290         if (!stream) {
1291                 ast_test_status_update(test, "Failed to create a video stream for testing multistream writing\n");
1292                 return AST_TEST_FAIL;
1293         }
1294
1295         if (ast_stream_topology_append_stream(topology, stream) == -1) {
1296                 ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
1297                 ast_stream_free(stream);
1298                 return AST_TEST_FAIL;
1299         }
1300
1301         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
1302         if (!caps) {
1303                 ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
1304                 return AST_TEST_FAIL;
1305         }
1306
1307         if (ast_format_cap_append(caps, ast_format_ulaw, 0)) {
1308                 ast_test_status_update(test, "Failed to append a ulaw format to capabilities for channel nativeformats\n");
1309                 return AST_TEST_FAIL;
1310         }
1311
1312         if (ast_format_cap_append(caps, ast_format_h264, 0)) {
1313                 ast_test_status_update(test, "Failed to append an h264 format to capabilities for channel nativeformats\n");
1314                 return AST_TEST_FAIL;
1315         }
1316
1317         mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel");
1318         if (!mock_channel) {
1319                 ast_test_status_update(test, "Failed to create a mock channel for testing\n");
1320                 return AST_TEST_FAIL;
1321         }
1322
1323         ast_channel_tech_set(mock_channel, &mock_channel_write_stream_tech);
1324         ast_channel_set_stream_topology(mock_channel, topology);
1325         ast_channel_nativeformats_set(mock_channel, caps);
1326         topology = NULL;
1327
1328         ast_channel_tech_pvt_set(mock_channel, &pvt);
1329         ast_channel_unlock(mock_channel);
1330
1331         frame.frametype = AST_FRAME_VOICE;
1332         frame.subclass.format = ast_format_ulaw;
1333         pvt.stream_num = -1;
1334
1335         if (ast_write(mock_channel, &frame)) {
1336                 ast_test_status_update(test, "Failed to write a ulaw frame to the mock channel when it should be fine\n");
1337                 goto end;
1338         }
1339
1340         if (pvt.wrote) {
1341                 ast_test_status_update(test, "Successfully wrote a frame of ulaw but it ended up on the old write callback instead of write_stream\n");
1342                 goto end;
1343         }
1344
1345         if (!pvt.wrote_stream) {
1346                 ast_test_status_update(test, "Successfully wrote a frame of ulaw but it never reached the channel driver\n");
1347                 goto end;
1348         }
1349
1350         if (pvt.stream_num != 0) {
1351                 ast_test_status_update(test, "Successfully wrote a frame of ulaw to the default stream but it ended up on stream %d and not 0\n",
1352                         pvt.stream_num);
1353                 goto end;
1354         }
1355
1356         pvt.wrote_stream = 0;
1357         pvt.stream_num = -1;
1358
1359         if (ast_write_stream(mock_channel, 0, &frame)) {
1360                 ast_test_status_update(test, "Failed to write a ulaw frame to the first audio stream\n");
1361                 goto end;
1362         }
1363
1364         if (pvt.wrote) {
1365                 ast_test_status_update(test, "Successfully wrote a frame of ulaw to the first audio stream but it ended up on the old write callback instead of write_stream\n");
1366                 goto end;
1367         }
1368
1369         if (!pvt.wrote_stream) {
1370                 ast_test_status_update(test, "Successfully wrote a frame of ulaw to the first audio stream but it never reached the channel driver\n");
1371                 goto end;
1372         }
1373
1374         if (pvt.stream_num != 0) {
1375                 ast_test_status_update(test, "Successfully wrote a frame of ulaw to the first audio stream but it ended up on stream %d and not 0\n",
1376                         pvt.stream_num);
1377                 goto end;
1378         }
1379
1380         pvt.wrote_stream = 0;
1381         pvt.stream_num = -1;
1382
1383         if (ast_write_stream(mock_channel, 1, &frame)) {
1384                 ast_test_status_update(test, "Failed to write a ulaw frame to the second audio stream\n");
1385                 goto end;
1386         }
1387
1388         if (pvt.wrote) {
1389                 ast_test_status_update(test, "Successfully wrote a frame of ulaw to the second audio stream but it ended up on the old write callback instead of write_stream\n");
1390                 goto end;
1391         }
1392
1393         if (!pvt.wrote_stream) {
1394                 ast_test_status_update(test, "Successfully wrote a frame of ulaw to the second audio stream but it never reached the channel driver\n");
1395                 goto end;
1396         }
1397
1398         if (pvt.stream_num != 1) {
1399                 ast_test_status_update(test, "Successfully wrote a frame of ulaw to the second audio stream but it ended up on stream %d and not 1\n",
1400                         pvt.stream_num);
1401                 goto end;
1402         }
1403
1404         pvt.wrote_stream = 0;
1405         pvt.stream_num = -1;
1406
1407         frame.frametype = AST_FRAME_VIDEO;
1408         frame.subclass.format = ast_format_h264;
1409
1410         if (ast_write(mock_channel, &frame)) {
1411                 ast_test_status_update(test, "Failed to write an h264 frame to the mock channel when it should be fine\n");
1412                 goto end;
1413         }
1414
1415         if (pvt.wrote) {
1416                 ast_test_status_update(test, "Successfully wrote a frame of h264 but it ended up on the old write callback instead of write_stream\n");
1417                 goto end;
1418         }
1419
1420         if (!pvt.wrote_stream) {
1421                 ast_test_status_update(test, "Successfully wrote a frame of h264 but it never reached the channel driver\n");
1422                 goto end;
1423         }
1424
1425         if (pvt.stream_num != 2) {
1426                 ast_test_status_update(test, "Successfully wrote a frame of h264 to the default stream but it ended up on stream %d and not 2\n",
1427                         pvt.stream_num);
1428                 goto end;
1429         }
1430
1431         pvt.wrote_stream = 0;
1432         pvt.stream_num = -1;
1433
1434         if (ast_write_stream(mock_channel, 2, &frame)) {
1435                 ast_test_status_update(test, "Failed to write an h264 frame to the first video stream\n");
1436                 goto end;
1437         }
1438
1439         if (pvt.wrote) {
1440                 ast_test_status_update(test, "Successfully wrote a frame of h264 to the first video stream but it ended up on the old write callback instead of write_stream\n");
1441                 goto end;
1442         }
1443
1444         if (!pvt.wrote_stream) {
1445                 ast_test_status_update(test, "Successfully wrote a frame of h264 to the first video stream but it never reached the channel driver\n");
1446                 goto end;
1447         }
1448
1449         if (pvt.stream_num != 2) {
1450                 ast_test_status_update(test, "Successfully wrote a frame of h264 to the first video stream but it ended up on stream %d and not 2\n",
1451                         pvt.stream_num);
1452                 goto end;
1453         }
1454
1455         pvt.wrote_stream = 0;
1456         pvt.stream_num = -1;
1457
1458         if (ast_write_stream(mock_channel, 3, &frame)) {
1459                 ast_test_status_update(test, "Failed to write an h264 frame to the second video stream\n");
1460                 goto end;
1461         }
1462
1463         if (pvt.wrote) {
1464                 ast_test_status_update(test, "Successfully wrote a frame of h264 to the second video stream but it ended up on the old write callback instead of write_stream\n");
1465                 goto end;
1466         }
1467
1468         if (!pvt.wrote_stream) {
1469                 ast_test_status_update(test, "Successfully wrote a frame of h264 to the second video stream but it never reached the channel driver\n");
1470                 goto end;
1471         }
1472
1473         if (pvt.stream_num != 3) {
1474                 ast_test_status_update(test, "Successfully wrote a frame of h264 to the second video stream but it ended up on stream %d and not 3\n",
1475                         pvt.stream_num);
1476                 goto end;
1477         }
1478
1479         pvt.wrote_stream = 0;
1480         pvt.stream_num = -1;
1481
1482         if (!ast_write_stream(mock_channel, 9, &frame)) {
1483                 ast_test_status_update(test, "Successfully wrote a frame of h264 to a non-existent stream\n");
1484                 goto end;
1485         }
1486
1487         if (pvt.wrote) {
1488                 ast_test_status_update(test, "Successfully wrote a frame of h264 to a non-existent stream and it ended up on the old write callback\n");
1489                 goto end;
1490         }
1491
1492         if (pvt.wrote_stream) {
1493                 ast_test_status_update(test, "Successfully wrote a frame of h264 to a non-existent stream and it ended up on the write_stream callback\n");
1494                 goto end;
1495         }
1496
1497         res = AST_TEST_PASS;
1498
1499 end:
1500         ast_hangup(mock_channel);
1501
1502         return res;
1503 }
1504
1505 static int load_stream_readqueue(struct ast_channel *chan, int frames)
1506 {
1507         struct mock_channel_pvt *pvt = ast_channel_tech_pvt(chan);
1508         struct ast_frame f = { 0, };
1509         struct ast_frame *frame = NULL;
1510         int i;
1511
1512         while ((frame = AST_LIST_REMOVE_HEAD(ast_channel_readq(chan), frame_list)))
1513                         ast_frfree(frame);
1514
1515         for (i = 0; i < frames; i++) {
1516                 if (pvt->frame_count % 2 == 0) {
1517                         f.frametype = AST_FRAME_VOICE;
1518                         f.subclass.format = ast_format_ulaw;
1519                 } else {
1520                         f.frametype = AST_FRAME_VIDEO;
1521                         f.subclass.format = ast_format_h264;
1522                 }
1523                 f.stream_num = pvt->frame_count % pvt->streams;
1524                 f.seqno = pvt->frame_count;
1525                 ast_queue_frame(chan, &f);
1526                 pvt->frame_count++;
1527         }
1528
1529         return 0;
1530 }
1531
1532 static struct ast_channel *make_channel(struct ast_test *test, int streams,
1533                 struct ast_channel_tech *tech)
1534 {
1535         RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
1536         struct ast_channel *mock_channel = NULL;
1537         struct mock_channel_pvt *pvt = NULL;
1538         struct ast_stream_topology *topology = NULL;
1539         struct ast_stream *stream;
1540         enum ast_test_result_state res = AST_TEST_PASS;
1541         int i;
1542
1543         mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel");
1544         ast_test_validate_cleanup(test, mock_channel, res, done);
1545         ast_channel_tech_set(mock_channel, tech);
1546
1547         if (tech->read_stream) {
1548                 topology = ast_stream_topology_alloc();
1549                 ast_test_validate_cleanup(test, topology, res, done);
1550
1551                 for (i = 0; i < streams; i++) {
1552                         stream = ast_stream_alloc((i % 2 ? "video": "audio"), (i % 2 ? AST_MEDIA_TYPE_VIDEO : AST_MEDIA_TYPE_AUDIO));
1553                         ast_test_validate_cleanup(test, stream, res, done);
1554                         ast_test_validate_cleanup(test, ast_stream_topology_append_stream(topology, stream) == i, res, done);
1555                 }
1556                 ast_test_validate_cleanup(test, ast_stream_topology_get_count(topology) == streams, res, done);
1557                 ast_channel_set_stream_topology(mock_channel, topology);
1558                 topology = NULL;
1559         } else {
1560                 caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
1561                 ast_test_validate_cleanup(test, caps, res, done);
1562
1563                 ast_test_validate_cleanup(test, ast_format_cap_append(caps, ast_format_ulaw, 0) == 0, res, done);
1564                 ast_test_validate_cleanup(test, ast_format_cap_append(caps, ast_format_h264, 0) == 0, res, done);
1565                 ast_channel_nativeformats_set(mock_channel, caps);
1566         }
1567
1568         pvt = ast_calloc(1, sizeof(*pvt));
1569         ast_test_validate_cleanup(test, pvt, res, done);
1570         pvt->mallocd = 1;
1571         ast_channel_tech_pvt_set(mock_channel, pvt);
1572
1573         ast_channel_unlock(mock_channel);
1574
1575 done:
1576         ast_stream_topology_free(topology);
1577         if (res == AST_TEST_FAIL && mock_channel) {
1578                 ast_hangup(mock_channel);
1579         }
1580
1581         return mock_channel;
1582 }
1583
1584 enum CHANNEL_READ_TYPE {
1585         CHANNEL_READ,
1586         CHANNEL_READ_STREAM
1587 };
1588
1589 static struct ast_frame *read_from_chan(enum CHANNEL_READ_TYPE rt, struct ast_channel *chan)
1590 {
1591         if (rt == CHANNEL_READ_STREAM) {
1592                 return ast_read_stream(chan);
1593         } else {
1594                 return ast_read(chan);
1595         }
1596 }
1597
1598 static enum ast_test_result_state read_test(struct ast_test *test, struct ast_channel_tech *tech,
1599                 enum CHANNEL_READ_TYPE rt, int streams, int frames, int frames_per_read, int expected_nulls)
1600 {
1601         struct ast_channel *mock_channel;
1602         struct mock_channel_pvt *pvt;
1603         struct ast_frame *fr = NULL;
1604         enum ast_test_result_state res = AST_TEST_PASS;
1605         int i = 0;
1606         int null_frames = 0;
1607
1608         ast_test_status_update(test, "ChanType: %s ReadType: %s Streams: %d Frames: %d Frames per read: %d Expected Nulls: %d\n",
1609                         tech->read_stream ? "MULTI" : "NON-MULTI",
1610                         rt == CHANNEL_READ_STREAM ? "STREAM" : "NON-STREAM",
1611                         streams, frames, frames_per_read, expected_nulls);
1612         mock_channel = make_channel(test, 4, tech);
1613         ast_test_validate_cleanup(test, mock_channel, res, done);
1614
1615         pvt = ast_channel_tech_pvt(mock_channel);
1616         pvt->frame_count = 0;
1617         pvt->frame_limit = frames;
1618         pvt->streams = streams;
1619         pvt->frames_per_read = frames_per_read;
1620
1621         load_stream_readqueue(mock_channel, frames / 2);
1622         ast_channel_fdno_set(mock_channel, 0);
1623
1624         while ((fr = read_from_chan(rt, mock_channel))) {
1625                 ast_channel_fdno_set(mock_channel, 0);
1626                 if (fr->frametype != AST_FRAME_NULL) {
1627                         ast_test_validate_cleanup(test, i == fr->seqno, res, done);
1628                         ast_test_validate_cleanup(test, fr->frametype == ( i % 2 ? AST_FRAME_VIDEO : AST_FRAME_VOICE), res, done);
1629                         ast_test_validate_cleanup(test, fr->stream_num == ( i % streams ), res, done);
1630                         ast_frfree(fr);
1631                 } else {
1632                         null_frames++;
1633                 }
1634                 fr = NULL;
1635                 i++;
1636         }
1637         ast_test_validate_cleanup(test, i == frames, res, done);
1638         ast_test_validate_cleanup(test, null_frames == expected_nulls, res, done);
1639
1640 done:
1641         ast_test_status_update(test, "    Frames read: %d NULL frames: %d\n", i, null_frames);
1642         ast_hangup(mock_channel);
1643
1644         return res;
1645 }
1646
1647 AST_TEST_DEFINE(stream_read_non_multistream)
1648 {
1649         struct ast_channel_tech tech = {
1650                 .read = mock_channel_read,
1651                 .hangup = mock_channel_hangup,
1652         };
1653
1654         enum ast_test_result_state res = AST_TEST_PASS;
1655
1656         switch (cmd) {
1657         case TEST_INIT:
1658                 info->name = "stream_read_non_multistream";
1659                 info->category = "/main/stream/";
1660                 info->summary = "stream reading from non-multistream capable channel test";
1661                 info->description =
1662                         "Test that reading frames from a non-multistream channel works as expected";
1663                 return AST_TEST_NOT_RUN;
1664         case TEST_EXECUTE:
1665                 break;
1666         }
1667
1668         res = read_test(test, &tech, CHANNEL_READ, 2, 16, 1, 0);
1669         ast_test_validate(test, res == AST_TEST_PASS, "non multi, non read stream, 2 stream");
1670
1671         res = read_test(test, &tech, CHANNEL_READ_STREAM, 2, 16, 1, 0);
1672         ast_test_validate(test, res == AST_TEST_PASS, "non multi, read stream, 2 stream");
1673
1674         res = read_test(test, &tech, CHANNEL_READ, 2, 16, 3, 0);
1675         ast_test_validate(test, res == AST_TEST_PASS, "non multi, non read stream, 2 stream, 3 frames per read");
1676
1677         res = read_test(test, &tech, CHANNEL_READ_STREAM, 2, 16, 3, 0);
1678         ast_test_validate(test, res == AST_TEST_PASS, "non multi, read stream, 2 stream, 3 frames per read");
1679
1680         return res;
1681 }
1682
1683 AST_TEST_DEFINE(stream_read_multistream)
1684 {
1685         struct ast_channel_tech tech = {
1686                 .read_stream = mock_channel_read,
1687                 .write_stream = mock_channel_write_stream,
1688                 .hangup = mock_channel_hangup,
1689         };
1690         enum ast_test_result_state res = AST_TEST_PASS;
1691
1692         switch (cmd) {
1693         case TEST_INIT:
1694                 info->name = "stream_read_multistream";
1695                 info->category = "/main/stream/";
1696                 info->summary = "stream reading from multistream capable channel test";
1697                 info->description =
1698                         "Test that reading frames from a multistream channel works as expected";
1699                 return AST_TEST_NOT_RUN;
1700         case TEST_EXECUTE:
1701                 break;
1702         }
1703
1704         res = read_test(test, &tech, CHANNEL_READ, 2, 16, 1, 0);
1705         ast_test_validate(test, res == AST_TEST_PASS, "multi, non read stream, 2 stream");
1706
1707         res = read_test(test, &tech, CHANNEL_READ_STREAM, 2, 16, 1, 0);
1708         ast_test_validate(test, res == AST_TEST_PASS, "multi, read stream, 2 stream");
1709
1710         res = read_test(test, &tech, CHANNEL_READ, 4, 16, 1, 8);
1711         ast_test_validate(test, res == AST_TEST_PASS, "multi, non read stream, 4 stream");
1712
1713         res = read_test(test, &tech, CHANNEL_READ_STREAM, 4, 16, 1, 0);
1714         ast_test_validate(test, res == AST_TEST_PASS, "multi, read stream, 4 stream");
1715
1716         res = read_test(test, &tech, CHANNEL_READ, 2, 16, 3, 0);
1717         ast_test_validate(test, res == AST_TEST_PASS, "multi, non read stream, 2 stream, 3 frames per read");
1718
1719         res = read_test(test, &tech, CHANNEL_READ_STREAM, 2, 16, 3, 0);
1720         ast_test_validate(test, res == AST_TEST_PASS, "multi, read stream, 2 stream, 3 frames per read");
1721
1722         res = read_test(test, &tech, CHANNEL_READ, 4, 16, 3, 8);
1723         ast_test_validate(test, res == AST_TEST_PASS, "multi, non read stream, 4 stream, 3 frames per read");
1724
1725         res = read_test(test, &tech, CHANNEL_READ_STREAM, 4, 16, 3, 0);
1726         ast_test_validate(test, res == AST_TEST_PASS, "multi, read stream, 4 stream, 3 frames per read");
1727
1728         return res;
1729 }
1730
1731 AST_TEST_DEFINE(stream_topology_change_request_from_application_non_multistream)
1732 {
1733         struct ast_channel_tech tech = {
1734                 .read = mock_channel_read,
1735                 .indicate = mock_channel_indicate,
1736                 .hangup = mock_channel_hangup,
1737         };
1738         struct ast_channel *mock_channel;
1739         struct mock_channel_pvt *pvt;
1740         enum ast_test_result_state res = AST_TEST_PASS;
1741         int change_res;
1742         RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
1743
1744         switch (cmd) {
1745         case TEST_INIT:
1746                 info->name = "stream_topology_change_request_from_application_non_multistream";
1747                 info->category = "/main/stream/";
1748                 info->summary = "stream topology changing on non-multistream channel test";
1749                 info->description =
1750                         "Test that an application trying to change the stream topology of a non-multistream channel gets a failure";
1751                 return AST_TEST_NOT_RUN;
1752         case TEST_EXECUTE:
1753                 break;
1754         }
1755
1756         mock_channel = make_channel(test, 1, &tech);
1757         ast_test_validate_cleanup(test, mock_channel, res, done);
1758
1759         pvt = ast_channel_tech_pvt(mock_channel);
1760         pvt->indicated_change_request = 0;
1761         pvt->indicated_changed = 0;
1762
1763         topology = ast_stream_topology_alloc();
1764         ast_test_validate_cleanup(test, topology, res, done);
1765
1766         change_res = ast_channel_request_stream_topology_change(mock_channel, topology, NULL);
1767
1768         ast_test_validate_cleanup(test, change_res == -1, res, done);
1769         ast_test_validate_cleanup(test, !pvt->indicated_change_request, res, done);
1770
1771         ast_channel_lock(mock_channel);
1772         change_res = ast_channel_stream_topology_changed(mock_channel, topology);
1773         ast_channel_unlock(mock_channel);
1774
1775         ast_test_validate_cleanup(test, change_res == -1, res, done);
1776         ast_test_validate_cleanup(test, !pvt->indicated_changed, res, done);
1777
1778 done:
1779         ast_hangup(mock_channel);
1780
1781         return res;
1782 }
1783
1784 AST_TEST_DEFINE(stream_topology_change_request_from_channel_non_multistream)
1785 {
1786         struct ast_channel_tech tech = {
1787                 .read_stream = mock_channel_read,
1788                 .write_stream = mock_channel_write_stream,
1789                 .indicate = mock_channel_indicate,
1790                 .hangup = mock_channel_hangup,
1791         };
1792         struct ast_channel *mock_channel;
1793         struct mock_channel_pvt *pvt;
1794         enum ast_test_result_state res = AST_TEST_PASS;
1795         RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
1796         struct ast_frame request_change = {
1797                 .frametype = AST_FRAME_CONTROL,
1798                 .subclass.integer = AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE,
1799         };
1800         struct ast_frame *fr = NULL;
1801
1802         switch (cmd) {
1803         case TEST_INIT:
1804                 info->name = "stream_topology_change_request_from_channel_non_multistream";
1805                 info->category = "/main/stream/";
1806                 info->summary = "channel requesting stream topology change to non-multistream application test";
1807                 info->description =
1808                         "Test that a channel requesting a stream topology change from a non-multistream application does not work";
1809                 return AST_TEST_NOT_RUN;
1810         case TEST_EXECUTE:
1811                 break;
1812         }
1813
1814         mock_channel = make_channel(test, 1, &tech);
1815         ast_test_validate_cleanup(test, mock_channel, res, done);
1816
1817         pvt = ast_channel_tech_pvt(mock_channel);
1818         pvt->indicated_changed = 0;
1819
1820         topology = ast_stream_topology_alloc();
1821         ast_test_validate_cleanup(test, topology, res, done);
1822
1823         request_change.data.ptr = topology;
1824         ast_queue_frame(mock_channel, &request_change);
1825
1826         fr = ast_read(mock_channel);
1827         ast_test_validate_cleanup(test, fr, res, done);
1828         ast_test_validate_cleanup(test, fr == &ast_null_frame, res, done);
1829         ast_test_validate_cleanup(test, pvt->indicated_changed, res, done);
1830
1831 done:
1832         if (fr) {
1833                 ast_frfree(fr);
1834         }
1835         ast_hangup(mock_channel);
1836
1837         return res;
1838 }
1839
1840 AST_TEST_DEFINE(stream_topology_change_request_from_application)
1841 {
1842         struct ast_channel_tech tech = {
1843                 .read_stream = mock_channel_read,
1844                 .write_stream = mock_channel_write_stream,
1845                 .indicate = mock_channel_indicate,
1846                 .hangup = mock_channel_hangup,
1847         };
1848         struct ast_channel *mock_channel;
1849         struct mock_channel_pvt *pvt;
1850         enum ast_test_result_state res = AST_TEST_PASS;
1851         int change_res;
1852         RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
1853
1854         switch (cmd) {
1855         case TEST_INIT:
1856                 info->name = "stream_topology_change_request_from_application";
1857                 info->category = "/main/stream/";
1858                 info->summary = "stream topology change request from application test";
1859                 info->description =
1860                         "Test that an application changing the stream topology of a multistream capable channel receives success";
1861                 return AST_TEST_NOT_RUN;
1862         case TEST_EXECUTE:
1863                 break;
1864         }
1865
1866         mock_channel = make_channel(test, 1, &tech);
1867         ast_test_validate_cleanup(test, mock_channel, res, done);
1868
1869         pvt = ast_channel_tech_pvt(mock_channel);
1870         pvt->indicated_change_request = 0;
1871         pvt->indicated_changed = 0;
1872
1873         topology = ast_stream_topology_alloc();
1874         ast_test_validate_cleanup(test, topology, res, done);
1875
1876         change_res = ast_channel_request_stream_topology_change(mock_channel, topology, NULL);
1877
1878         ast_test_validate_cleanup(test, !change_res, res, done);
1879         ast_test_validate_cleanup(test, pvt->indicated_change_request, res, done);
1880
1881         ast_channel_lock(mock_channel);
1882         change_res = ast_channel_stream_topology_changed(mock_channel, topology);
1883         ast_channel_unlock(mock_channel);
1884
1885         ast_test_validate_cleanup(test, !change_res, res, done);
1886         ast_test_validate_cleanup(test, pvt->indicated_changed, res, done);
1887
1888 done:
1889         ast_hangup(mock_channel);
1890
1891         return res;
1892 }
1893
1894 AST_TEST_DEFINE(stream_topology_change_request_from_channel)
1895 {
1896         struct ast_channel_tech tech = {
1897                 .read_stream = mock_channel_read,
1898                 .write_stream = mock_channel_write_stream,
1899                 .indicate = mock_channel_indicate,
1900                 .hangup = mock_channel_hangup,
1901         };
1902         struct ast_channel *mock_channel;
1903         struct mock_channel_pvt *pvt;
1904         enum ast_test_result_state res = AST_TEST_PASS;
1905         RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
1906         struct ast_frame request_change = {
1907                 .frametype = AST_FRAME_CONTROL,
1908                 .subclass.integer = AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE,
1909         };
1910         struct ast_frame *fr = NULL;
1911
1912         switch (cmd) {
1913         case TEST_INIT:
1914                 info->name = "stream_topology_change_request_from_channel";
1915                 info->category = "/main/stream/";
1916                 info->summary = "channel requesting stream topology change to multistream application test";
1917                 info->description =
1918                         "Test that a channel requesting a stream topology change from a multistream application works";
1919                 return AST_TEST_NOT_RUN;
1920         case TEST_EXECUTE:
1921                 break;
1922         }
1923
1924         mock_channel = make_channel(test, 1, &tech);
1925         ast_test_validate_cleanup(test, mock_channel, res, done);
1926
1927         pvt = ast_channel_tech_pvt(mock_channel);
1928         pvt->indicated_changed = 0;
1929
1930         topology = ast_stream_topology_alloc();
1931         ast_test_validate_cleanup(test, topology, res, done);
1932
1933         request_change.data.ptr = topology;
1934         ast_queue_frame(mock_channel, &request_change);
1935
1936         fr = ast_read_stream(mock_channel);
1937         ast_test_validate_cleanup(test, fr, res, done);
1938         ast_test_validate_cleanup(test, fr->frametype == AST_FRAME_CONTROL, res, done);
1939         ast_test_validate_cleanup(test, fr->subclass.integer == AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE, res, done);
1940         ast_test_validate_cleanup(test, !pvt->indicated_changed, res, done);
1941
1942 done:
1943         if (fr) {
1944                 ast_frfree(fr);
1945         }
1946         ast_hangup(mock_channel);
1947
1948         return res;
1949 }
1950
1951 AST_TEST_DEFINE(format_cap_from_stream_topology)
1952 {
1953         RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
1954         RAII_VAR(struct ast_format_cap *, stream_caps, NULL, ao2_cleanup);
1955         struct ast_stream_topology *topology;
1956         struct ast_stream *stream;
1957         struct ast_format_cap *new_cap;
1958
1959         switch (cmd) {
1960         case TEST_INIT:
1961                 info->name = "format_cap_from_stream_topology";
1962                 info->category = "/main/stream/";
1963                 info->summary = "stream topology to format capabilities conversion test";
1964                 info->description =
1965                         "Test that converting a stream topology to format capabilities results in expected formats";
1966                 return AST_TEST_NOT_RUN;
1967         case TEST_EXECUTE:
1968                 break;
1969         }
1970
1971         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
1972         if (!caps) {
1973                 ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
1974                 return AST_TEST_FAIL;
1975         }
1976
1977         if (ast_format_cap_append(caps, ast_format_ulaw, 0)) {
1978                 ast_test_status_update(test, "Failed to append ulaw format to capabilities\n");
1979                 return AST_TEST_FAIL;
1980         }
1981
1982         if (ast_format_cap_append(caps, ast_format_h264, 0)) {
1983                 ast_test_status_update(test, "Failed to append h264 format to capabilities\n");
1984                 return AST_TEST_FAIL;
1985         }
1986
1987         topology = ast_stream_topology_create_from_format_cap(caps);
1988         if (!topology) {
1989                 ast_test_status_update(test, "Failed to create a stream topology from format capabilities of ulaw and h264\n");
1990                 return AST_TEST_FAIL;
1991         }
1992
1993         /*
1994          * Append declined stream with formats that should not be included
1995          * in combined topology caps.
1996          */
1997         stream = ast_stream_alloc("audio", AST_MEDIA_TYPE_AUDIO);
1998         if (!stream) {
1999                 ast_test_status_update(test, "Failed to create an audio stream for testing stream topology\n");
2000                 ast_stream_topology_free(topology);
2001                 return AST_TEST_FAIL;
2002         }
2003         ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED);
2004         new_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
2005         if (!new_cap) {
2006                 ast_test_status_update(test, "Could not allocate an empty format capabilities structure\n");
2007                 ast_stream_free(stream);
2008                 ast_stream_topology_free(topology);
2009                 return AST_TEST_FAIL;
2010         }
2011         if (ast_format_cap_append(new_cap, ast_format_alaw, 0)) {
2012                 ast_test_status_update(test, "Failed to append alaw format to capabilities\n");
2013                 ao2_cleanup(new_cap);
2014                 ast_stream_free(stream);
2015                 ast_stream_topology_free(topology);
2016                 return AST_TEST_FAIL;
2017         }
2018         ast_stream_set_formats(stream, new_cap);
2019         ao2_cleanup(new_cap);
2020         if (ast_stream_topology_append_stream(topology, stream) == -1) {
2021                 ast_test_status_update(test, "Failed to append a perfectly good stream to a topology\n");
2022                 ast_stream_free(stream);
2023                 ast_stream_topology_free(topology);
2024                 return AST_TEST_FAIL;
2025         }
2026
2027         stream_caps = ast_format_cap_from_stream_topology(topology);
2028         if (!stream_caps) {
2029                 ast_test_status_update(test, "Failed to create a format capabilities from a stream topology\n");
2030                 ast_stream_topology_free(topology);
2031                 return AST_TEST_FAIL;
2032         }
2033
2034         ast_stream_topology_free(topology);
2035
2036         if (!ast_format_cap_identical(caps, stream_caps)) {
2037                 ast_test_status_update(test, "Converting format capabilities into topology and back resulted in different formats\n");
2038                 return AST_TEST_FAIL;
2039         }
2040
2041         return AST_TEST_PASS;
2042 }
2043
2044 #define topology_append_stream(topology, name, type, res, label) \
2045         do { \
2046                 struct ast_stream *__stream = ast_stream_alloc((name), (type)); \
2047                 ast_test_validate_cleanup(test, __stream, res, label); \
2048                 if (ast_stream_topology_append_stream((topology), __stream) < 0) { \
2049                         ast_stream_free(__stream); \
2050                         res = AST_TEST_FAIL; \
2051                         goto label;          \
2052                 } \
2053         } while(0)
2054
2055 AST_TEST_DEFINE(stream_topology_map_create)
2056 {
2057         RAII_VAR(struct ast_stream_topology *, t0, NULL, ast_stream_topology_free);
2058
2059         struct ast_vector_int types = { NULL };
2060         struct ast_vector_int v0 = { NULL };
2061         struct ast_vector_int v1 = { NULL };
2062
2063         enum ast_test_result_state res = AST_TEST_PASS;
2064
2065         switch (cmd) {
2066         case TEST_INIT:
2067                 info->name = "stream_topology_map_create";
2068                 info->category = "/main/stream/";
2069                 info->summary = "stream topology map creation unit test";
2070                 info->description =
2071                         "Test that creating a stream topology map works";
2072                 return AST_TEST_NOT_RUN;
2073         case TEST_EXECUTE:
2074                 break;
2075         }
2076
2077         ast_test_validate(test, AST_VECTOR_INIT(&types, 5) == 0);
2078
2079         /* Map a first topology and check that it mapped one to one */
2080         ast_test_validate_cleanup(test, (t0 = ast_stream_topology_alloc()), res, done);
2081         topology_append_stream(t0, "audio", AST_MEDIA_TYPE_AUDIO, res, done);
2082         topology_append_stream(t0, "video", AST_MEDIA_TYPE_VIDEO, res, done);
2083
2084         ast_stream_topology_map(t0, &types, &v0, &v1);
2085         ast_test_validate_cleanup(test, AST_VECTOR_SIZE(&types) == 2, res, done);
2086         ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 0) == AST_MEDIA_TYPE_AUDIO, res, done);
2087         ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 1) == AST_MEDIA_TYPE_VIDEO, res, done);
2088         ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 0) == 0, res, done);
2089         ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 1) == 1, res, done);
2090         ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 0) == 0, res, done);
2091         ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 1) == 1, res, done);
2092
2093         /* Map a second topology and check that it merged */
2094         ast_stream_topology_free(t0);
2095         ast_test_validate_cleanup(test, (t0 = ast_stream_topology_alloc()), res, done);
2096         topology_append_stream(t0, "video", AST_MEDIA_TYPE_VIDEO, res, done);
2097         topology_append_stream(t0, "audio", AST_MEDIA_TYPE_AUDIO, res, done);
2098
2099         ast_stream_topology_map(t0, &types, &v0, &v1);
2100         ast_test_validate_cleanup(test, AST_VECTOR_SIZE(&types) == 2, res, done);
2101         ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 0) == AST_MEDIA_TYPE_AUDIO, res, done);
2102         ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 1) == AST_MEDIA_TYPE_VIDEO, res, done);
2103         ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 0) == 1, res, done);
2104         ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 1) == 0, res, done);
2105         ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 0) == 1, res, done);
2106         ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 1) == 0, res, done);
2107
2108         /* Map a third topology with more streams and check that it merged */
2109         ast_stream_topology_free(t0);
2110         ast_test_validate_cleanup(test, (t0 = ast_stream_topology_alloc()), res, done);
2111         topology_append_stream(t0, "video", AST_MEDIA_TYPE_VIDEO, res, done);
2112         topology_append_stream(t0, "audio", AST_MEDIA_TYPE_AUDIO, res, done);
2113         topology_append_stream(t0, "audio", AST_MEDIA_TYPE_AUDIO, res, done);
2114
2115         ast_stream_topology_map(t0, &types, &v0, &v1);
2116         ast_test_validate_cleanup(test, AST_VECTOR_SIZE(&types) == 3, res, done);
2117         ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 0) == AST_MEDIA_TYPE_AUDIO, res, done);
2118         ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 1) == AST_MEDIA_TYPE_VIDEO, res, done);
2119         ast_test_validate_cleanup(test, AST_VECTOR_GET(&types, 2) == AST_MEDIA_TYPE_AUDIO, res, done);
2120         ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 0) == 1, res, done);
2121         ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 1) == 0, res, done);
2122         ast_test_validate_cleanup(test, AST_VECTOR_GET(&v0, 2) == 2, res, done);
2123         ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 0) == 1, res, done);
2124         ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 1) == 0, res, done);
2125         ast_test_validate_cleanup(test, AST_VECTOR_GET(&v1, 2) == 2, res, done);
2126
2127 done:
2128         AST_VECTOR_FREE(&v1);
2129         AST_VECTOR_FREE(&v0);
2130         AST_VECTOR_FREE(&types);
2131
2132         return res;
2133 }
2134
2135 static int unload_module(void)
2136 {
2137         AST_TEST_UNREGISTER(stream_create);
2138         AST_TEST_UNREGISTER(stream_create_no_name);
2139         AST_TEST_UNREGISTER(stream_set_type);
2140         AST_TEST_UNREGISTER(stream_set_formats);
2141         AST_TEST_UNREGISTER(stream_set_state);
2142         AST_TEST_UNREGISTER(stream_topology_create);
2143         AST_TEST_UNREGISTER(stream_topology_clone);
2144         AST_TEST_UNREGISTER(stream_topology_clone);
2145         AST_TEST_UNREGISTER(stream_topology_append_stream);
2146         AST_TEST_UNREGISTER(stream_topology_set_stream);
2147         AST_TEST_UNREGISTER(stream_topology_del_stream);
2148         AST_TEST_UNREGISTER(stream_topology_create_from_format_cap);
2149         AST_TEST_UNREGISTER(stream_topology_get_first_stream_by_type);
2150         AST_TEST_UNREGISTER(stream_topology_create_from_channel_nativeformats);
2151         AST_TEST_UNREGISTER(stream_topology_channel_set);
2152         AST_TEST_UNREGISTER(stream_write_non_multistream);
2153         AST_TEST_UNREGISTER(stream_write_multistream);
2154         AST_TEST_UNREGISTER(stream_read_non_multistream);
2155         AST_TEST_UNREGISTER(stream_read_multistream);
2156         AST_TEST_UNREGISTER(stream_topology_change_request_from_application_non_multistream);
2157         AST_TEST_UNREGISTER(stream_topology_change_request_from_channel_non_multistream);
2158         AST_TEST_UNREGISTER(stream_topology_change_request_from_application);
2159         AST_TEST_UNREGISTER(stream_topology_change_request_from_channel);
2160         AST_TEST_UNREGISTER(format_cap_from_stream_topology);
2161         AST_TEST_UNREGISTER(stream_topology_map_create);
2162         return 0;
2163 }
2164
2165 static int load_module(void)
2166 {
2167         AST_TEST_REGISTER(stream_create);
2168         AST_TEST_REGISTER(stream_create_no_name);
2169         AST_TEST_REGISTER(stream_set_type);
2170         AST_TEST_REGISTER(stream_set_formats);
2171         AST_TEST_REGISTER(stream_set_state);
2172         AST_TEST_REGISTER(stream_topology_create);
2173         AST_TEST_REGISTER(stream_topology_clone);
2174         AST_TEST_REGISTER(stream_topology_append_stream);
2175         AST_TEST_REGISTER(stream_topology_set_stream);
2176         AST_TEST_REGISTER(stream_topology_del_stream);
2177         AST_TEST_REGISTER(stream_topology_create_from_format_cap);
2178         AST_TEST_REGISTER(stream_topology_get_first_stream_by_type);
2179         AST_TEST_REGISTER(stream_topology_create_from_channel_nativeformats);
2180         AST_TEST_REGISTER(stream_topology_channel_set);
2181         AST_TEST_REGISTER(stream_write_non_multistream);
2182         AST_TEST_REGISTER(stream_write_multistream);
2183         AST_TEST_REGISTER(stream_read_non_multistream);
2184         AST_TEST_REGISTER(stream_read_multistream);
2185         AST_TEST_REGISTER(stream_topology_change_request_from_application_non_multistream);
2186         AST_TEST_REGISTER(stream_topology_change_request_from_channel_non_multistream);
2187         AST_TEST_REGISTER(stream_topology_change_request_from_application);
2188         AST_TEST_REGISTER(stream_topology_change_request_from_channel);
2189         AST_TEST_REGISTER(format_cap_from_stream_topology);
2190         AST_TEST_REGISTER(stream_topology_map_create);
2191         return AST_MODULE_LOAD_SUCCESS;
2192 }
2193
2194 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Media Stream API test module");