media formats: re-architect handling of media for performance improvements
[asterisk/asterisk.git] / tests / test_core_format.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2014, 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 Core Format 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 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include "asterisk/test.h"
37 #include "asterisk/module.h"
38 #include "asterisk/codec.h"
39 #include "asterisk/format.h"
40
41 #define TEST_CATEGORY "/main/core_format/"
42
43 static void test_core_format_destroy(struct ast_format *format);
44 static int test_core_format_clone(const struct ast_format *src, struct ast_format *dst);
45 static enum ast_format_cmp_res test_core_format_cmp(const struct ast_format *format1, const struct ast_format *format2);
46 static struct ast_format *test_core_format_get_joint(const struct ast_format *format1, const struct ast_format *format2);
47 static struct ast_format *test_core_format_attribute_set(const struct ast_format *format, const char *name, const char *value);
48 static struct ast_format *test_core_format_parse_sdp_fmtp(const struct ast_format *format, const char *attributes);
49 static void test_core_format_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str);
50
51 /*! \brief A format attribute 'module' used by the unit tests */
52 static struct ast_format_interface test_core_format_attr = {
53         .format_destroy = &test_core_format_destroy,
54         .format_clone = &test_core_format_clone,
55         .format_cmp = &test_core_format_cmp,
56         .format_get_joint = &test_core_format_get_joint,
57         .format_attribute_set = &test_core_format_attribute_set,
58         .format_parse_sdp_fmtp = &test_core_format_parse_sdp_fmtp,
59         .format_generate_sdp_fmtp = &test_core_format_generate_sdp_fmtp,
60 };
61
62 /*! \brief A test piece of data to associate with \ref test_core_format_attr */
63 struct test_core_format_pvt {
64         /*! Some data field */
65         int field_one;
66         /*! Another arbitrary data field */
67         int field_two;
68 };
69
70 /*! \brief A test codec for these unit tests. Should be used with \c test_core_format */
71 static struct ast_codec test_core_format_codec = {
72         .name = "test_core_format_codec",
73         .description = "Unit test codec used by test_core_format",
74         .type = AST_MEDIA_TYPE_AUDIO,
75         .sample_rate = 8000,
76         .minimum_ms = 10,
77         .maximum_ms = 150,
78         .default_ms = 20,
79 };
80
81 /*! \brief Tracking object used to verify format attribute callbacks */
82 struct callbacks_called {
83         /*! Number of times \ref test_core_format_destroy was called */
84         int format_destroy;
85         /*! Number of times \ref test_core_format_clone was called */
86         int format_clone;
87         /*! Number of times \ref test_core_format_cmp was called */
88         int format_cmp;
89         /*! Number of times \ref test_core_format_get_joint was called */
90         int format_get_joint;
91         /*! Number of times \ref test_core_format_attribute_set was called */
92         int format_attribute_set;
93         /*! Number of times \ref test_core_format_parse_sdp_fmtp was called */
94         int format_parse_sdp_fmtp;
95         /*! Number of times \ref test_core_format_generate_sdp_fmtp was called */
96         int format_generate_sdp_fmtp;
97 };
98
99 /*! \brief A global tracking object. Cleared out by the test init cb */
100 static struct callbacks_called test_callbacks_called;
101
102 /*! \brief Format attribute callback for when format attributes are to be destroyed */
103 static void test_core_format_destroy(struct ast_format *format)
104 {
105         struct test_core_format_pvt *pvt = ast_format_get_attribute_data(format);
106
107         ast_free(pvt);
108         ++test_callbacks_called.format_destroy;
109 }
110
111 /*! \brief Format attribute callback called during format cloning */
112 static int test_core_format_clone(const struct ast_format *src, struct ast_format *dst)
113 {
114         struct test_core_format_pvt *pvt = ast_format_get_attribute_data(src);
115         struct test_core_format_pvt *new_pvt;
116
117         new_pvt = ast_calloc(1, sizeof(*new_pvt));
118         if (!new_pvt) {
119                 return -1;
120         }
121
122         if (pvt) {
123                 *new_pvt = *pvt;
124         }
125         ast_format_set_attribute_data(dst, new_pvt);
126
127         ++test_callbacks_called.format_clone;
128
129         return 0;
130 }
131
132 /*! \brief Format attribute callback called during format comparison */
133 static enum ast_format_cmp_res test_core_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
134 {
135         struct test_core_format_pvt *pvt1 = ast_format_get_attribute_data(format1);
136         struct test_core_format_pvt *pvt2 = ast_format_get_attribute_data(format2);
137
138         ++test_callbacks_called.format_cmp;
139         if (pvt1 == pvt2) {
140                 return AST_FORMAT_CMP_EQUAL;
141         }
142
143         if ((!pvt1 && pvt2 && (pvt2->field_one != 0 || pvt2->field_two != 0))
144                 || (pvt1 && !pvt2 && (pvt1->field_one != 0 || pvt1->field_two != 0))) {
145                 return AST_FORMAT_CMP_NOT_EQUAL;
146         }
147
148         if (pvt1 && pvt2) {
149                 if (!memcmp(pvt1, pvt2, sizeof(*pvt1))) {
150                         return AST_FORMAT_CMP_EQUAL;
151                 } else {
152                         return AST_FORMAT_CMP_NOT_EQUAL;
153                 }
154         }
155
156         return AST_FORMAT_CMP_EQUAL;
157 }
158
159 /*!
160  * \brief Format attribute callback called during joint format capability
161  * \note Our test will assume the max of attributes \c field_one and \c field_two
162  */
163 static struct ast_format *test_core_format_get_joint(const struct ast_format *format1, const struct ast_format *format2)
164 {
165         struct test_core_format_pvt *pvt1 = ast_format_get_attribute_data(format1);
166         struct test_core_format_pvt *pvt2 = ast_format_get_attribute_data(format2);
167         struct ast_format *joint;
168         struct test_core_format_pvt *joint_pvt;
169
170         joint = ast_format_clone(format1);
171         if (!joint) {
172                 return NULL;
173         }
174         joint_pvt = ast_format_get_attribute_data(joint);
175
176         joint_pvt->field_one = MAX(pvt1 ? pvt1->field_one : 0, pvt2 ? pvt2->field_one : 0);
177         joint_pvt->field_two = MAX(pvt2 ? pvt2->field_two : 0, pvt2 ? pvt2->field_two : 0);
178
179         ++test_callbacks_called.format_get_joint;
180
181         return joint;
182 }
183
184 /*! \brief Format attribute callback for setting an attribute on a format */
185 static struct ast_format *test_core_format_attribute_set(const struct ast_format *format, const char *name, const char *value)
186 {
187         struct ast_format *clone = ast_format_clone(format);
188         struct test_core_format_pvt *clone_pvt;
189
190         if (!clone) {
191                 return NULL;
192         }
193         clone_pvt = ast_format_get_attribute_data(clone);
194
195         if (!strcmp(name, "one")) {
196                 clone_pvt->field_one = atoi(value);
197         } else if (!strcmp(name, "two")) {
198                 clone_pvt->field_two = atoi(value);
199         }
200         ++test_callbacks_called.format_attribute_set;
201
202         return clone;
203 }
204
205 /*! \brief Format attribute callback to construct a format from an SDP fmtp line */
206 static struct ast_format *test_core_format_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
207 {
208         struct ast_format *clone = ast_format_clone(format);
209         struct test_core_format_pvt *pvt;
210
211         if (!clone) {
212                 return NULL;
213         }
214
215         pvt = ast_format_get_attribute_data(clone);
216
217         if (sscanf(attributes, "one=%d;two=%d", &pvt->field_one, &pvt->field_two) != 2) {
218                 ao2_ref(clone, -1);
219                 return NULL;
220         }
221
222         ++test_callbacks_called.format_parse_sdp_fmtp;
223         return clone;
224 }
225
226 /*! \brief Format attribute callback to generate an SDP fmtp line from a format */
227 static void test_core_format_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
228 {
229         struct test_core_format_pvt *pvt = ast_format_get_attribute_data(format);
230
231         if (!pvt) {
232                 return;
233         }
234
235         ast_str_append(str, 0, "a=fmtp:%d one=%d;two=%d\r\n", payload, pvt->field_one, pvt->field_two);
236
237         ++test_callbacks_called.format_generate_sdp_fmtp;
238 }
239
240 AST_TEST_DEFINE(format_create)
241 {
242         RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
243         RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
244
245         switch (cmd) {
246         case TEST_INIT:
247                 info->name = __PRETTY_FUNCTION__;
248                 info->category = TEST_CATEGORY;
249                 info->summary = "Format creation unit test";
250                 info->description =
251                         "Test creation of a format";
252                 return AST_TEST_NOT_RUN;
253         case TEST_EXECUTE:
254                 break;
255         }
256
257         codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
258         if (!codec) {
259                 ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
260                 return AST_TEST_FAIL;
261         }
262
263         format = ast_format_create(codec);
264         if (!format) {
265                 ast_test_status_update(test, "Could not create format using built-in codec\n");
266                 return AST_TEST_FAIL;
267         } else if (ast_format_get_codec_id(format) != codec->id) {
268                 ast_test_status_update(test, "Created format does not contain provided codec\n");
269                 return AST_TEST_FAIL;
270         }
271
272         ao2_ref(format, -1);
273         format = ast_format_create_named("super_ulaw", codec);
274         if (!format) {
275                 ast_test_status_update(test, "Could not create format using built-in codec\n");
276                 return AST_TEST_FAIL;
277         } else if (ast_format_get_codec_id(format) != codec->id) {
278                 ast_test_status_update(test, "Created format does not contain provided codec\n");
279                 return AST_TEST_FAIL;
280         }
281
282         return AST_TEST_PASS;
283 }
284
285 AST_TEST_DEFINE(format_create_attr)
286 {
287         RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
288         RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
289         RAII_VAR(struct ast_format *, format_w_attr, NULL, ao2_cleanup);
290
291         switch (cmd) {
292         case TEST_INIT:
293                 info->name = __PRETTY_FUNCTION__;
294                 info->category = TEST_CATEGORY;
295                 info->summary = "Format creation w/ attributes unit test";
296                 info->description =
297                         "Test creation of a format with attributes";
298                 return AST_TEST_NOT_RUN;
299         case TEST_EXECUTE:
300                 break;
301         }
302
303         codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000);
304         if (!codec) {
305                 ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n");
306                 return AST_TEST_FAIL;
307         }
308
309         format = ast_format_create(codec);
310         if (!format) {
311                 ast_test_status_update(test, "Could not create format using test_core_format_codec codec\n");
312                 return AST_TEST_FAIL;
313         } else if (ast_format_get_codec_id(format) != codec->id) {
314                 ast_test_status_update(test, "Created format does not contain provided codec\n");
315                 return AST_TEST_FAIL;
316         }
317
318         format_w_attr = ast_format_attribute_set(format, "one", "1");
319         if (!format_w_attr) {
320                 ast_test_status_update(test, "Could not create format with attributes using test_core_format_codec codec\n");
321                 return AST_TEST_FAIL;
322         } else if (ast_format_get_codec_id(format_w_attr) != codec->id) {
323                 ast_test_status_update(test, "Created format does not contain provided codec\n");
324                 return AST_TEST_FAIL;
325         } else if (ast_format_cmp(format, format_w_attr) == AST_FORMAT_CMP_EQUAL) {
326                 ast_test_status_update(test, "Format with attributes should not be equal to format without attributes\n");
327                 return AST_TEST_FAIL;
328         }
329
330         ast_test_validate(test, test_callbacks_called.format_attribute_set == 1);
331         ast_test_validate(test, test_callbacks_called.format_cmp == 1);
332
333         return AST_TEST_PASS;
334 }
335
336 AST_TEST_DEFINE(format_clone)
337 {
338         RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
339         RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
340         RAII_VAR(struct ast_format *, format_w_attr, NULL, ao2_cleanup);
341         RAII_VAR(struct ast_format *, clone, NULL, ao2_cleanup);
342
343         switch (cmd) {
344         case TEST_INIT:
345                 info->name = __PRETTY_FUNCTION__;
346                 info->category = TEST_CATEGORY;
347                 info->summary = "Format cloning unit test";
348                 info->description =
349                         "Test cloning of a format";
350                 return AST_TEST_NOT_RUN;
351         case TEST_EXECUTE:
352                 break;
353         }
354
355         codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000);
356         if (!codec) {
357                 ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n");
358                 return AST_TEST_FAIL;
359         }
360
361         format = ast_format_create(codec);
362         if (!format) {
363                 ast_test_status_update(test, "Could not create format using test_core_format_codec codec\n");
364                 return AST_TEST_FAIL;
365         } else if (ast_format_get_codec_id(format) != codec->id) {
366                 ast_test_status_update(test, "Created format does not contain provided codec\n");
367                 return AST_TEST_FAIL;
368         }
369
370         format_w_attr = ast_format_attribute_set(format, "one", "1");
371         if (!format_w_attr) {
372                 ast_test_status_update(test, "Could not create format with attributes using test_core_format_codec codec\n");
373                 return AST_TEST_FAIL;
374         } else if (ast_format_get_codec_id(format_w_attr) != codec->id) {
375                 ast_test_status_update(test, "Created format does not contain provided codec\n");
376                 return AST_TEST_FAIL;
377         }
378
379         /* Test cloning a format without attributes */
380         clone = ast_format_clone(format);
381         if (!clone) {
382                 ast_test_status_update(test, "Could not create cloned format\n");
383                 return AST_TEST_FAIL;
384         } else if (ast_format_get_codec_id(clone) != codec->id) {
385                 ast_test_status_update(test, "Cloned format does not contain provided codec\n");
386                 return AST_TEST_FAIL;
387         } else if (clone == format) {
388                 ast_test_status_update(test, "Cloned format pointer is the same as original format pointer\n");
389                 return AST_TEST_FAIL;
390         } else if (ast_format_cmp(clone, format) != AST_FORMAT_CMP_EQUAL) {
391                 ast_test_status_update(test, "Cloned format is not the same as its original format\n");
392                 return AST_TEST_FAIL;
393         }
394         ao2_ref(clone, -1);
395
396         /* Test cloning a format with attributes */
397         clone = ast_format_clone(format_w_attr);
398         if (!clone) {
399                 ast_test_status_update(test, "Could not create cloned format\n");
400                 return AST_TEST_FAIL;
401         } else if (ast_format_get_codec_id(clone) != codec->id) {
402                 ast_test_status_update(test, "Cloned format does not contain provided codec\n");
403                 return AST_TEST_FAIL;
404         } else if (clone == format_w_attr) {
405                 ast_test_status_update(test, "Cloned format pointer is the same as original format pointer\n");
406                 return AST_TEST_FAIL;
407         } else if (ast_format_cmp(clone, format_w_attr) != AST_FORMAT_CMP_EQUAL) {
408                 ast_test_status_update(test, "Cloned format is not the same as its original format\n");
409                 return AST_TEST_FAIL;
410         }
411         ast_test_validate(test, test_callbacks_called.format_attribute_set == 1);
412         ast_test_validate(test, test_callbacks_called.format_clone == 3);
413         ast_test_validate(test, test_callbacks_called.format_cmp == 2);
414
415         return AST_TEST_PASS;
416 }
417
418 AST_TEST_DEFINE(format_cmp_same_codec)
419 {
420         RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
421         RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup);
422         RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup);
423         RAII_VAR(struct ast_format *, named, NULL, ao2_cleanup);
424
425         switch (cmd) {
426         case TEST_INIT:
427                 info->name = __PRETTY_FUNCTION__;
428                 info->category = TEST_CATEGORY;
429                 info->summary = "Format comparison unit test";
430                 info->description =
431                         "Test comparison of two different formats with same codec";
432                 return AST_TEST_NOT_RUN;
433         case TEST_EXECUTE:
434                 break;
435         }
436
437         codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
438         if (!codec) {
439                 ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
440                 return AST_TEST_FAIL;
441         }
442
443         first = ast_format_create(codec);
444         if (!first) {
445                 ast_test_status_update(test, "Could not create first format using built-in codec\n");
446                 return AST_TEST_FAIL;
447         }
448
449         second = ast_format_create(codec);
450         if (!second) {
451                 ast_test_status_update(test, "Could not create second format using built-in codec\n");
452                 return AST_TEST_FAIL;
453         }
454
455         named = ast_format_create_named("super_ulaw", codec);
456         if (!named) {
457                 ast_test_status_update(test, "Could not create named format using built-in codec\n");
458                 return AST_TEST_FAIL;
459         }
460
461         if (ast_format_cmp(first, second) != AST_FORMAT_CMP_EQUAL) {
462                 ast_test_status_update(test, "Two formats that are the same compared as not being equal\n");
463                 return AST_TEST_FAIL;
464         }
465
466         if (ast_format_cmp(first, named) != AST_FORMAT_CMP_EQUAL) {
467                 ast_test_status_update(test, "Two formats that are the same compared as not being equal\n");
468                 return AST_TEST_FAIL;
469         }
470
471         return AST_TEST_PASS;
472 }
473
474 AST_TEST_DEFINE(format_cmp_different_codec)
475 {
476         RAII_VAR(struct ast_codec *, first_codec, NULL, ao2_cleanup);
477         RAII_VAR(struct ast_codec *, second_codec, NULL, ao2_cleanup);
478         RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup);
479         RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup);
480
481         switch (cmd) {
482         case TEST_INIT:
483                 info->name = __PRETTY_FUNCTION__;
484                 info->category = TEST_CATEGORY;
485                 info->summary = "Format comparison unit test";
486                 info->description =
487                         "Test comparison of two different formats with different codec";
488                 return AST_TEST_NOT_RUN;
489         case TEST_EXECUTE:
490                 break;
491         }
492
493         first_codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
494         if (!first_codec) {
495                 ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
496                 return AST_TEST_FAIL;
497         }
498
499         first = ast_format_create(first_codec);
500         if (!first) {
501                 ast_test_status_update(test, "Could not create first format using built-in codec\n");
502                 return AST_TEST_FAIL;
503         }
504
505         second_codec = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000);
506         if (!second_codec) {
507                 ast_test_status_update(test, "Could not retrieve built-in alaw codec\n");
508                 return AST_TEST_FAIL;
509         }
510
511         second = ast_format_create(second_codec);
512         if (!second) {
513                 ast_test_status_update(test, "Could not create second format using built-in codec\n");
514                 return AST_TEST_FAIL;
515         }
516
517         if (ast_format_cmp(first, second) != AST_FORMAT_CMP_NOT_EQUAL) {
518                 ast_test_status_update(test, "Two formats that have different codecs did not compare as being not equal\n");
519                 return AST_TEST_FAIL;
520         }
521
522         return AST_TEST_PASS;
523 }
524
525 AST_TEST_DEFINE(format_attr_cmp_same_codec)
526 {
527         RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
528         RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup);
529         RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup);
530         RAII_VAR(struct ast_format *, original, NULL, ao2_cleanup);
531
532         switch (cmd) {
533         case TEST_INIT:
534                 info->name = __PRETTY_FUNCTION__;
535                 info->category = TEST_CATEGORY;
536                 info->summary = "Format with attributes comparison unit test";
537                 info->description =
538                         "Test comparison of two different formats with attributes with same codec";
539                 return AST_TEST_NOT_RUN;
540         case TEST_EXECUTE:
541                 break;
542         }
543
544         codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000);
545         if (!codec) {
546                 ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n");
547                 return AST_TEST_FAIL;
548         }
549
550         original = ast_format_create(codec);
551         if (!original) {
552                 ast_test_status_update(test, "Could not create format using test_core_format_codec codec\n");
553                 return AST_TEST_FAIL;
554         }
555
556         first = ast_format_attribute_set(original, "one", "1");
557         if (!first) {
558                 ast_test_status_update(test, "Could not create first format with attributes\n");
559                 return AST_TEST_FAIL;
560         }
561
562         second = ast_format_attribute_set(original, "two", "1");
563         if (!second) {
564                 ast_test_status_update(test, "Could not create second format with attributes\n");
565                 return AST_TEST_FAIL;
566         }
567
568         if (ast_format_cmp(first, second) == AST_FORMAT_CMP_EQUAL) {
569                 ast_test_status_update(test, "Formats with different attributes were compared to be equal when they should not\n");
570                 return AST_TEST_FAIL;
571         }
572
573         ao2_ref(second, -1);
574         second = ast_format_attribute_set(original, "one", "1");
575
576         if (ast_format_cmp(first, second) != AST_FORMAT_CMP_EQUAL) {
577                 ast_test_status_update(test, "Formats with the same attributes should be equal\n");
578                 return AST_TEST_FAIL;
579         }
580
581         ast_test_validate(test, test_callbacks_called.format_attribute_set == 3);
582         ast_test_validate(test, test_callbacks_called.format_cmp == 2);
583
584         return AST_TEST_PASS;
585 }
586
587 AST_TEST_DEFINE(format_joint_same_codec)
588 {
589         RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
590         RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup);
591         RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup);
592         RAII_VAR(struct ast_format *, joint, NULL, ao2_cleanup);
593
594         switch (cmd) {
595         case TEST_INIT:
596                 info->name = __PRETTY_FUNCTION__;
597                 info->category = TEST_CATEGORY;
598                 info->summary = "Joint format unit test";
599                 info->description =
600                         "Test joint format creation using two different formats with same codec";
601                 return AST_TEST_NOT_RUN;
602         case TEST_EXECUTE:
603                 break;
604         }
605
606         codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
607         if (!codec) {
608                 ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
609                 return AST_TEST_FAIL;
610         }
611
612         first = ast_format_create(codec);
613         if (!first) {
614                 ast_test_status_update(test, "Could not create first format using built-in codec\n");
615                 return AST_TEST_FAIL;
616         }
617
618         second = ast_format_create(codec);
619         if (!second) {
620                 ast_test_status_update(test, "Could not create second format using built-in codec\n");
621                 return AST_TEST_FAIL;
622         }
623
624         joint = ast_format_joint(first, second);
625         if (!joint) {
626                 ast_test_status_update(test, "Failed to create a joint format using two formats of same codec\n");
627                 return AST_TEST_FAIL;
628         } else if (ast_format_get_codec_id(joint) != codec->id) {
629                 ast_test_status_update(test, "Returned joint format does not contain expected codec\n");
630                 return AST_TEST_FAIL;
631         }
632
633         return AST_TEST_PASS;
634 }
635
636 AST_TEST_DEFINE(format_attr_joint_same_codec)
637 {
638         RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
639         RAII_VAR(struct ast_format *, original, NULL, ao2_cleanup);
640         RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup);
641         RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup);
642         RAII_VAR(struct ast_format *, joint, NULL, ao2_cleanup);
643         struct ast_str *fmtp = ast_str_alloca(64);
644
645         switch (cmd) {
646         case TEST_INIT:
647                 info->name = __PRETTY_FUNCTION__;
648                 info->category = TEST_CATEGORY;
649                 info->summary = "Joint format attribute unit test";
650                 info->description =
651                         "Test joint format creation using two different formats with attributes and with same codec";
652                 return AST_TEST_NOT_RUN;
653         case TEST_EXECUTE:
654                 break;
655         }
656
657         codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000);
658         if (!codec) {
659                 ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n");
660                 return AST_TEST_FAIL;
661         }
662
663         original = ast_format_create(codec);
664         if (!original) {
665                 ast_test_status_update(test, "Could not create format from test_core_format_codec codec\n");
666                 return AST_TEST_FAIL;
667         }
668
669         first = ast_format_attribute_set(original, "one", "2");
670         if (!first) {
671                 ast_test_status_update(test, "Could not create first format using test_core_format_codec codec\n");
672                 return AST_TEST_FAIL;
673         }
674
675         second = ast_format_attribute_set(original, "one", "5");
676         if (!second) {
677                 ast_test_status_update(test, "Could not create second format using test_core_format_codec codec\n");
678                 return AST_TEST_FAIL;
679         }
680
681         joint = ast_format_joint(first, second);
682         if (!joint) {
683                 ast_test_status_update(test, "Failed to create a joint format using two formats of same codec\n");
684                 return AST_TEST_FAIL;
685         } else if (ast_format_get_codec_id(joint) != codec->id) {
686                 ast_test_status_update(test, "Returned joint format does not contain expected codec\n");
687                 return AST_TEST_FAIL;
688         }
689
690         ast_format_generate_sdp_fmtp(joint, 100, &fmtp);
691         ast_test_validate(test, strcmp("a=fmtp:100 one=5;two=0\r\n", ast_str_buffer(fmtp)) == 0);
692
693         ast_test_validate(test, test_callbacks_called.format_attribute_set == 2);
694         ast_test_validate(test, test_callbacks_called.format_get_joint == 1);
695         ast_test_validate(test, test_callbacks_called.format_generate_sdp_fmtp == 1);
696
697         return AST_TEST_PASS;
698 }
699
700 AST_TEST_DEFINE(format_joint_different_codec)
701 {
702         RAII_VAR(struct ast_codec *, first_codec, NULL, ao2_cleanup);
703         RAII_VAR(struct ast_codec *, second_codec, NULL, ao2_cleanup);
704         RAII_VAR(struct ast_format *, first, NULL, ao2_cleanup);
705         RAII_VAR(struct ast_format *, second, NULL, ao2_cleanup);
706         RAII_VAR(struct ast_format *, joint, NULL, ao2_cleanup);
707
708         switch (cmd) {
709         case TEST_INIT:
710                 info->name = __PRETTY_FUNCTION__;
711                 info->category = TEST_CATEGORY;
712                 info->summary = "Joint format unit test";
713                 info->description =
714                         "Test that there is no joint format between two different formats with different codec";
715                 return AST_TEST_NOT_RUN;
716         case TEST_EXECUTE:
717                 break;
718         }
719
720         first_codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
721         if (!first_codec) {
722                 ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
723                 return AST_TEST_FAIL;
724         }
725
726         first = ast_format_create(first_codec);
727         if (!first) {
728                 ast_test_status_update(test, "Could not create first format using built-in codec\n");
729                 return AST_TEST_FAIL;
730         }
731
732         second_codec = ast_codec_get("alaw", AST_MEDIA_TYPE_AUDIO, 8000);
733         if (!second_codec) {
734                 ast_test_status_update(test, "Could not retrieve built-in alaw codec\n");
735                 return AST_TEST_FAIL;
736         }
737
738         second = ast_format_create(second_codec);
739         if (!second) {
740                 ast_test_status_update(test, "Could not create second format using built-in codec\n");
741                 return AST_TEST_FAIL;
742         }
743
744         joint = ast_format_joint(first, second);
745         if (joint) {
746                 ast_test_status_update(test, "Got a joint format between two formats with different codecs\n");
747                 return AST_TEST_FAIL;
748         }
749
750         return AST_TEST_PASS;
751 }
752
753 AST_TEST_DEFINE(format_copy)
754 {
755         RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
756         RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
757         RAII_VAR(struct ast_format *, copy, NULL, ao2_cleanup);
758
759         switch (cmd) {
760         case TEST_INIT:
761                 info->name = __PRETTY_FUNCTION__;
762                 info->category = TEST_CATEGORY;
763                 info->summary = "Format copying unit test";
764                 info->description =
765                         "Test copying of a format";
766                 return AST_TEST_NOT_RUN;
767         case TEST_EXECUTE:
768                 break;
769         }
770
771         codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
772         if (!codec) {
773                 ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
774                 return AST_TEST_FAIL;
775         }
776
777         format = ast_format_create(codec);
778         if (!format) {
779                 ast_test_status_update(test, "Could not create format using built-in codec\n");
780                 return AST_TEST_FAIL;
781         }
782
783         copy = ao2_bump(format);
784         if (!copy) {
785                 ast_test_status_update(test, "Copying of a just created format failed\n");
786                 return AST_TEST_FAIL;
787         } else if (copy != format) {
788                 ast_test_status_update(test, "Copying of a format returned a new format instead of the same one\n");
789                 return AST_TEST_FAIL;
790         }
791
792         return AST_TEST_PASS;
793 }
794
795 AST_TEST_DEFINE(format_attribute_set_without_interface)
796 {
797         RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
798         RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
799
800         switch (cmd) {
801         case TEST_INIT:
802                 info->name = __PRETTY_FUNCTION__;
803                 info->category = TEST_CATEGORY;
804                 info->summary = "Format attribute setting unit test";
805                 info->description =
806                         "Test that attribute setting on a format without an interface fails";
807                 return AST_TEST_NOT_RUN;
808         case TEST_EXECUTE:
809                 break;
810         }
811
812         codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
813         if (!codec) {
814                 ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
815                 return AST_TEST_FAIL;
816         }
817
818         format = ast_format_create(codec);
819         if (!format) {
820                 ast_test_status_update(test, "Could not create format using built-in codec\n");
821                 return AST_TEST_FAIL;
822         }
823
824         if (!ast_format_attribute_set(format, "bees", "cool")) {
825                 ast_test_status_update(test, "Successfully set an attribute on a format without an interface\n");
826                 return AST_TEST_FAIL;
827         }
828
829         return AST_TEST_PASS;
830 }
831
832 AST_TEST_DEFINE(format_parse_sdp_fmtp_without_interface)
833 {
834         RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
835         RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
836         RAII_VAR(struct ast_format *, generated, NULL, ao2_cleanup);
837
838         switch (cmd) {
839         case TEST_INIT:
840                 info->name = __PRETTY_FUNCTION__;
841                 info->category = TEST_CATEGORY;
842                 info->summary = "Format sdp parse unit test";
843                 info->description =
844                         "Test that sdp parsing on a format without an interface fails";
845                 return AST_TEST_NOT_RUN;
846         case TEST_EXECUTE:
847                 break;
848         }
849
850         codec = ast_codec_get("ulaw", AST_MEDIA_TYPE_AUDIO, 8000);
851         if (!codec) {
852                 ast_test_status_update(test, "Could not retrieve built-in ulaw codec\n");
853                 return AST_TEST_FAIL;
854         }
855
856         format = ast_format_create(codec);
857         if (!format) {
858                 ast_test_status_update(test, "Could not create format using built-in codec\n");
859                 return AST_TEST_FAIL;
860         }
861
862         generated = ast_format_parse_sdp_fmtp(format, "tacos");
863         if (generated != format) {
864                 ast_test_status_update(test, "Successfully parsed SDP on a format without an interface\n");
865                 return AST_TEST_FAIL;
866         }
867
868         return AST_TEST_PASS;
869 }
870
871 AST_TEST_DEFINE(format_parse_and_generate_sdp_fmtp)
872 {
873         RAII_VAR(struct ast_codec *, codec, NULL, ao2_cleanup);
874         RAII_VAR(struct ast_format *, format, NULL, ao2_cleanup);
875         RAII_VAR(struct ast_format *, generated, NULL, ao2_cleanup);
876         struct ast_str *fmtp = ast_str_alloca(64);
877
878         switch (cmd) {
879         case TEST_INIT:
880                 info->name = __PRETTY_FUNCTION__;
881                 info->category = TEST_CATEGORY;
882                 info->summary = "Format sdp parse/generate unit test";
883                 info->description =
884                         "Test that sdp parsing and generation on a format with an interface succeeds";
885                 return AST_TEST_NOT_RUN;
886         case TEST_EXECUTE:
887                 break;
888         }
889
890         codec = ast_codec_get("test_core_format_codec", AST_MEDIA_TYPE_AUDIO, 8000);
891         if (!codec) {
892                 ast_test_status_update(test, "Could not retrieve test_core_format_codec codec\n");
893                 return AST_TEST_FAIL;
894         }
895
896         format = ast_format_create(codec);
897         if (!format) {
898                 ast_test_status_update(test, "Could not create format using test_core_format_codec codec\n");
899                 return AST_TEST_FAIL;
900         }
901
902         generated = ast_format_parse_sdp_fmtp(format, "one=1000;two=256");
903         if (format == generated) {
904                 ast_test_status_update(test, "Failed to parse SDP on a format without an interface\n");
905                 return AST_TEST_FAIL;
906         }
907
908         ast_format_generate_sdp_fmtp(generated, 8, &fmtp);
909
910         ast_test_validate(test, strcmp("a=fmtp:8 one=1000;two=256\r\n", ast_str_buffer(fmtp)) == 0);
911         ast_test_validate(test, test_callbacks_called.format_parse_sdp_fmtp == 1);
912         ast_test_validate(test, test_callbacks_called.format_generate_sdp_fmtp == 1);
913
914         return AST_TEST_PASS;
915 }
916
917 static int test_core_format_init(struct ast_test_info *info, struct ast_test *test)
918 {
919         memset(&test_callbacks_called, 0, sizeof(test_callbacks_called));
920
921         return 0;
922 }
923
924 static int unload_module(void)
925 {
926         AST_TEST_UNREGISTER(format_create);
927         AST_TEST_UNREGISTER(format_create_attr);
928         AST_TEST_UNREGISTER(format_clone);
929         AST_TEST_UNREGISTER(format_cmp_same_codec);
930         AST_TEST_UNREGISTER(format_attr_cmp_same_codec);
931         AST_TEST_UNREGISTER(format_cmp_different_codec);
932         AST_TEST_UNREGISTER(format_joint_same_codec);
933         AST_TEST_UNREGISTER(format_attr_joint_same_codec);
934         AST_TEST_UNREGISTER(format_joint_different_codec);
935         AST_TEST_UNREGISTER(format_copy);
936         AST_TEST_UNREGISTER(format_attribute_set_without_interface);
937         AST_TEST_UNREGISTER(format_parse_sdp_fmtp_without_interface);
938         AST_TEST_UNREGISTER(format_parse_and_generate_sdp_fmtp);
939
940         return 0;
941 }
942
943 static int load_module(void)
944 {
945         /* Test codec/format interface used by this module */
946         if (ast_codec_register(&test_core_format_codec)) {
947                 ast_log(AST_LOG_ERROR, "Failed to register test_core_format_codec\n");
948                 return AST_MODULE_LOAD_DECLINE;
949         }
950
951         if (ast_format_interface_register("test_core_format_codec", &test_core_format_attr)) {
952                 ast_log(AST_LOG_ERROR, "Failed to register format interface for test_core_format_codec\n");
953                 return AST_MODULE_LOAD_DECLINE;
954         }
955
956         AST_TEST_REGISTER(format_create);
957         AST_TEST_REGISTER(format_create_attr);
958         AST_TEST_REGISTER(format_clone);
959         AST_TEST_REGISTER(format_cmp_same_codec);
960         AST_TEST_REGISTER(format_attr_cmp_same_codec);
961         AST_TEST_REGISTER(format_cmp_different_codec);
962         AST_TEST_REGISTER(format_joint_same_codec);
963         AST_TEST_REGISTER(format_attr_joint_same_codec);
964         AST_TEST_REGISTER(format_joint_different_codec);
965         AST_TEST_REGISTER(format_copy);
966         AST_TEST_REGISTER(format_attribute_set_without_interface);
967         AST_TEST_REGISTER(format_parse_sdp_fmtp_without_interface);
968         AST_TEST_REGISTER(format_parse_and_generate_sdp_fmtp);
969
970         ast_test_register_init(TEST_CATEGORY, &test_core_format_init);
971
972         return AST_MODULE_LOAD_SUCCESS;
973 }
974
975 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Core format API test module");