Astobj2: Allow reference debugging to be enabled/disabled by config.
[asterisk/asterisk.git] / main / format_cap.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 /*! \file
20  *
21  * \brief Format Capabilities API
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 ASTERISK_REGISTER_FILE()
33
34 #include "asterisk/logger.h"
35 #include "asterisk/format.h"
36 #include "asterisk/format_cap.h"
37 #include "asterisk/format_cache.h"
38 #include "asterisk/codec.h"
39 #include "asterisk/astobj2.h"
40 #include "asterisk/strings.h"
41 #include "asterisk/vector.h"
42 #include "asterisk/linkedlists.h"
43 #include "asterisk/utils.h"
44
45 /*! \brief Structure used for capability formats, adds framing */
46 struct format_cap_framed {
47         /*! \brief A pointer to the format */
48         struct ast_format *format;
49         /*! \brief The format framing size */
50         unsigned int framing;
51         /*! \brief Linked list information */
52         AST_LIST_ENTRY(format_cap_framed) entry;
53 };
54
55 /*! \brief Format capabilities structure, holds formats + preference order + etc */
56 struct ast_format_cap {
57         /*! \brief Vector of formats, indexed using the codec identifier */
58         AST_VECTOR(, struct format_cap_framed_list) formats;
59         /*! \brief Vector of formats, added in preference order */
60         AST_VECTOR(, struct format_cap_framed *) preference_order;
61         /*! \brief Global framing size, applies to all formats if no framing present on format */
62         unsigned int framing;
63 };
64
65 /*! \brief Linked list for formats */
66 AST_LIST_HEAD_NOLOCK(format_cap_framed_list, format_cap_framed);
67
68 /*! \brief Dummy empty list for when we are inserting a new list */
69 static const struct format_cap_framed_list format_cap_framed_list_empty = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
70
71 /*! \brief Destructor for format capabilities structure */
72 static void format_cap_destroy(void *obj)
73 {
74         struct ast_format_cap *cap = obj;
75         int idx;
76
77         for (idx = 0; idx < AST_VECTOR_SIZE(&cap->formats); idx++) {
78                 struct format_cap_framed_list *list = AST_VECTOR_GET_ADDR(&cap->formats, idx);
79                 struct format_cap_framed *framed;
80
81                 while ((framed = AST_LIST_REMOVE_HEAD(list, entry))) {
82                         ao2_ref(framed, -1);
83                 }
84         }
85         AST_VECTOR_FREE(&cap->formats);
86
87         for (idx = 0; idx < AST_VECTOR_SIZE(&cap->preference_order); idx++) {
88                 struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, idx);
89
90                 /* This will always be non-null, unlike formats */
91                 ao2_ref(framed, -1);
92         }
93         AST_VECTOR_FREE(&cap->preference_order);
94 }
95
96 static inline void format_cap_init(struct ast_format_cap *cap, enum ast_format_cap_flags flags)
97 {
98         AST_VECTOR_INIT(&cap->formats, 0);
99
100         /* TODO: Look at common usage of this and determine a good starting point */
101         AST_VECTOR_INIT(&cap->preference_order, 5);
102
103         cap->framing = UINT_MAX;
104 }
105
106 struct ast_format_cap *__ast_format_cap_alloc(enum ast_format_cap_flags flags,
107         const char *tag, const char *file, int line, const char *func)
108 {
109         struct ast_format_cap *cap;
110
111         cap = __ao2_alloc(sizeof(*cap), format_cap_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK,
112                 tag, file, line, func);
113         if (!cap) {
114                 return NULL;
115         }
116
117         format_cap_init(cap, flags);
118
119         return cap;
120 }
121
122 void ast_format_cap_set_framing(struct ast_format_cap *cap, unsigned int framing)
123 {
124         cap->framing = framing;
125 }
126
127 /*! \brief Destructor for format capabilities framed structure */
128 static void format_cap_framed_destroy(void *obj)
129 {
130         struct format_cap_framed *framed = obj;
131
132         ao2_cleanup(framed->format);
133 }
134
135 static inline int format_cap_framed_init(struct format_cap_framed *framed, struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
136 {
137         struct format_cap_framed_list *list;
138
139         framed->framing = framing;
140
141         if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
142                 if (AST_VECTOR_INSERT(&cap->formats, ast_format_get_codec_id(format), format_cap_framed_list_empty)) {
143                         ao2_ref(framed, -1);
144                         return -1;
145                 }
146         }
147         list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
148
149         /* Order doesn't matter for formats, so insert at the head for performance reasons */
150         ao2_ref(framed, +1);
151         AST_LIST_INSERT_HEAD(list, framed, entry);
152
153         /* This takes the allocation reference */
154         AST_VECTOR_APPEND(&cap->preference_order, framed);
155
156         cap->framing = MIN(cap->framing, framing ? framing : ast_format_get_default_ms(format));
157
158         return 0;
159 }
160
161 /*! \internal \brief Determine if \c format is in \c cap */
162 static int format_in_format_cap(struct ast_format_cap *cap, struct ast_format *format)
163 {
164         struct format_cap_framed *framed;
165         int i;
166
167         for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
168                 framed = AST_VECTOR_GET(&cap->preference_order, i);
169
170                 if (ast_format_get_codec_id(format) == ast_format_get_codec_id(framed->format)) {
171                         return 1;
172                 }
173         }
174
175         return 0;
176 }
177
178 int __ast_format_cap_append(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing, const char *tag, const char *file, int line, const char *func)
179 {
180         struct format_cap_framed *framed;
181
182         ast_assert(format != NULL);
183
184         if (format_in_format_cap(cap, format)) {
185                 return 0;
186         }
187
188         framed = ao2_alloc_options(sizeof(*framed), format_cap_framed_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
189         if (!framed) {
190                 return -1;
191         }
192
193         __ao2_ref(format, +1, tag, file, line, func);
194         framed->format = format;
195
196         return format_cap_framed_init(framed, cap, format, framing);
197 }
198
199 int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_type type)
200 {
201         int id;
202
203         for (id = 1; id < ast_codec_get_max(); ++id) {
204                 struct ast_codec *codec = ast_codec_get_by_id(id);
205                 struct ast_format *format;
206                 int res;
207
208                 if (!codec) {
209                         continue;
210                 }
211
212                 if ((type != AST_MEDIA_TYPE_UNKNOWN) && codec->type != type) {
213                         ao2_ref(codec, -1);
214                         continue;
215                 }
216
217                 format = ast_format_create(codec);
218                 ao2_ref(codec, -1);
219
220                 if (!format) {
221                         return -1;
222                 }
223
224                 /* Use the global framing or default framing of the codec */
225                 res = ast_format_cap_append(cap, format, 0);
226                 ao2_ref(format, -1);
227
228                 if (res) {
229                         return -1;
230                 }
231         }
232
233         return 0;
234 }
235
236 int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src,
237         enum ast_media_type type)
238 {
239         int idx, res = 0;
240
241         for (idx = 0; (idx < AST_VECTOR_SIZE(&src->preference_order)) && !res; ++idx) {
242                 struct format_cap_framed *framed = AST_VECTOR_GET(&src->preference_order, idx);
243
244                 if (type == AST_MEDIA_TYPE_UNKNOWN || ast_format_get_type(framed->format) == type) {
245                         res = ast_format_cap_append(dst, framed->format, framed->framing);
246                 }
247         }
248
249         return res;
250 }
251
252 static int format_cap_replace(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
253 {
254         struct format_cap_framed *framed;
255         int i;
256
257         ast_assert(format != NULL);
258
259         for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
260                 framed = AST_VECTOR_GET(&cap->preference_order, i);
261
262                 if (ast_format_get_codec_id(format) == ast_format_get_codec_id(framed->format)) {
263                         ao2_t_replace(framed->format, format, "replacing with new format");
264                         framed->framing = framing;
265                         return 0;
266                 }
267         }
268
269         return -1;
270 }
271
272 void ast_format_cap_replace_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src,
273         enum ast_media_type type)
274 {
275         int idx;
276
277         for (idx = 0; (idx < AST_VECTOR_SIZE(&src->preference_order)); ++idx) {
278                 struct format_cap_framed *framed = AST_VECTOR_GET(&src->preference_order, idx);
279
280                 if (type == AST_MEDIA_TYPE_UNKNOWN || ast_format_get_type(framed->format) == type) {
281                         format_cap_replace(dst, framed->format, framed->framing);
282                 }
283         }
284 }
285
286 int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing)
287 {
288         int res = 0, all = 0, iter_allowing;
289         char *parse = NULL, *this = NULL, *psize = NULL;
290
291         if (!allowing && ast_strlen_zero(list)) {
292                 return 0;
293         }
294
295         parse = ast_strdupa(list);
296         while ((this = strsep(&parse, ","))) {
297                 int framems = 0;
298                 struct ast_format *format = NULL;
299
300                 iter_allowing = allowing;
301                 if (*this == '!') {
302                         this++;
303                         iter_allowing = !allowing;
304                 }
305                 if ((psize = strrchr(this, ':'))) {
306                         *psize++ = '\0';
307                         ast_debug(1, "Packetization for codec: %s is %s\n", this, psize);
308                         if (!sscanf(psize, "%30d", &framems) || (framems < 0)) {
309                                 framems = 0;
310                                 res = -1;
311                                 ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this);
312                                 continue;
313                         }
314                 }
315                 all = strcasecmp(this, "all") ? 0 : 1;
316
317                 if (!all && !(format = ast_format_cache_get(this))) {
318                         ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", iter_allowing ? "allow" : "disallow", this);
319                         res = -1;
320                         continue;
321                 }
322
323                 if (cap) {
324                         if (iter_allowing) {
325                                 if (all) {
326                                         ast_format_cap_append_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
327                                 } else {
328                                         ast_format_cap_append(cap, format, framems);
329                                 }
330                         } else {
331                                 if (all) {
332                                         ast_format_cap_remove_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
333                                 } else {
334                                         ast_format_cap_remove(cap, format);
335                                 }
336                         }
337                 }
338
339                 ao2_cleanup(format);
340         }
341         return res;
342 }
343
344 size_t ast_format_cap_count(const struct ast_format_cap *cap)
345 {
346         return AST_VECTOR_SIZE(&cap->preference_order);
347 }
348
349 struct ast_format *ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
350 {
351         struct format_cap_framed *framed;
352
353         ast_assert(position < AST_VECTOR_SIZE(&cap->preference_order));
354
355         if (position >= AST_VECTOR_SIZE(&cap->preference_order)) {
356                 return NULL;
357         }
358
359         framed = AST_VECTOR_GET(&cap->preference_order, position);
360
361         ast_assert(framed->format != ast_format_none);
362         ao2_ref(framed->format, +1);
363         return framed->format;
364 }
365
366 struct ast_format *ast_format_cap_get_best_by_type(const struct ast_format_cap *cap, enum ast_media_type type)
367 {
368         int i;
369
370         if (type == AST_MEDIA_TYPE_UNKNOWN) {
371                 return ast_format_cap_get_format(cap, 0);
372         }
373
374         for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
375                 struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, i);
376
377                 if (ast_format_get_type(framed->format) == type) {
378                         ao2_ref(framed->format, +1);
379                         ast_assert(framed->format != ast_format_none);
380                         return framed->format;
381                 }
382         }
383
384         return NULL;
385 }
386
387 unsigned int ast_format_cap_get_framing(const struct ast_format_cap *cap)
388 {
389         return (cap->framing != UINT_MAX) ? cap->framing : 0;
390 }
391
392 unsigned int ast_format_cap_get_format_framing(const struct ast_format_cap *cap, const struct ast_format *format)
393 {
394         unsigned int framing;
395         struct format_cap_framed_list *list;
396         struct format_cap_framed *framed, *result = NULL;
397
398         if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
399                 return 0;
400         }
401
402         framing = cap->framing != UINT_MAX ? cap->framing : ast_format_get_default_ms(format);
403         list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
404
405         AST_LIST_TRAVERSE(list, framed, entry) {
406                 enum ast_format_cmp_res res = ast_format_cmp(format, framed->format);
407
408                 if (res == AST_FORMAT_CMP_NOT_EQUAL) {
409                         continue;
410                 }
411
412                 result = framed;
413
414                 if (res == AST_FORMAT_CMP_EQUAL) {
415                         break;
416                 }
417         }
418
419         if (result && result->framing) {
420                 framing = result->framing;
421         }
422
423         return framing;
424 }
425
426 /*!
427  * \brief format_cap_framed comparator for AST_VECTOR_REMOVE_CMP_ORDERED()
428  *
429  * \param elem Element to compare against
430  * \param value Value to compare with the vector element.
431  *
432  * \return 0 if element does not match.
433  * \return Non-zero if element matches.
434  */
435 #define FORMAT_CAP_FRAMED_ELEM_CMP(elem, value) ((elem)->format == (value))
436
437 /*!
438  * \brief format_cap_framed vector element cleanup.
439  *
440  * \param elem Element to cleanup
441  *
442  * \return Nothing
443  */
444 #define FORMAT_CAP_FRAMED_ELEM_CLEANUP(elem)  ao2_cleanup((elem))
445
446 int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
447 {
448         struct format_cap_framed_list *list;
449         struct format_cap_framed *framed;
450
451         ast_assert(format != NULL);
452
453         if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
454                 return -1;
455         }
456
457         list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
458
459         AST_LIST_TRAVERSE_SAFE_BEGIN(list, framed, entry) {
460                 if (!FORMAT_CAP_FRAMED_ELEM_CMP(framed, format)) {
461                         continue;
462                 }
463
464                 AST_LIST_REMOVE_CURRENT(entry);
465                 FORMAT_CAP_FRAMED_ELEM_CLEANUP(framed);
466                 break;
467         }
468         AST_LIST_TRAVERSE_SAFE_END;
469
470         return AST_VECTOR_REMOVE_CMP_ORDERED(&cap->preference_order, format,
471                 FORMAT_CAP_FRAMED_ELEM_CMP, FORMAT_CAP_FRAMED_ELEM_CLEANUP);
472 }
473
474 void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type)
475 {
476         int idx;
477
478         for (idx = 0; idx < AST_VECTOR_SIZE(&cap->formats); ++idx) {
479                 struct format_cap_framed_list *list = AST_VECTOR_GET_ADDR(&cap->formats, idx);
480                 struct format_cap_framed *framed;
481
482                 AST_LIST_TRAVERSE_SAFE_BEGIN(list, framed, entry) {
483                         if ((type != AST_MEDIA_TYPE_UNKNOWN) &&
484                                 ast_format_get_type(framed->format) != type) {
485                                 continue;
486                         }
487
488                         AST_LIST_REMOVE_CURRENT(entry);
489                         AST_VECTOR_REMOVE_CMP_ORDERED(&cap->preference_order, framed->format,
490                                 FORMAT_CAP_FRAMED_ELEM_CMP, FORMAT_CAP_FRAMED_ELEM_CLEANUP);
491                         ao2_ref(framed, -1);
492                 }
493                 AST_LIST_TRAVERSE_SAFE_END;
494         }
495 }
496
497 struct ast_format *ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format)
498 {
499         struct format_cap_framed_list *list;
500         struct format_cap_framed *framed;
501         struct ast_format *result = NULL;
502
503         ast_assert(format != NULL);
504
505         if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
506                 return NULL;
507         }
508
509         list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
510
511         AST_LIST_TRAVERSE(list, framed, entry) {
512                 enum ast_format_cmp_res res = ast_format_cmp(format, framed->format);
513
514                 if (res == AST_FORMAT_CMP_NOT_EQUAL) {
515                         continue;
516                 }
517
518                 /* Replace any current result, this one will also be a subset OR an exact match */
519                 ao2_cleanup(result);
520
521                 result = ast_format_joint(format, framed->format);
522
523                 /* If it's a match we can do no better so return asap */
524                 if (res == AST_FORMAT_CMP_EQUAL) {
525                         break;
526                 }
527         }
528
529         return result;
530 }
531
532 enum ast_format_cmp_res ast_format_cap_iscompatible_format(const struct ast_format_cap *cap,
533         const struct ast_format *format)
534 {
535         enum ast_format_cmp_res res = AST_FORMAT_CMP_NOT_EQUAL;
536         struct format_cap_framed_list *list;
537         struct format_cap_framed *framed;
538
539         ast_assert(format != NULL);
540
541         if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
542                 return AST_FORMAT_CMP_NOT_EQUAL;
543         }
544
545         list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
546
547         AST_LIST_TRAVERSE(list, framed, entry) {
548                 enum ast_format_cmp_res cmp = ast_format_cmp(format, framed->format);
549
550                 if (cmp == AST_FORMAT_CMP_NOT_EQUAL) {
551                         continue;
552                 }
553
554                 res = cmp;
555
556                 if (res == AST_FORMAT_CMP_EQUAL) {
557                         break;
558                 }
559         }
560
561         return res;
562 }
563
564 int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_media_type type)
565 {
566         int idx;
567
568         for (idx = 0; idx < AST_VECTOR_SIZE(&cap->preference_order); ++idx) {
569                 struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, idx);
570
571                 if (ast_format_get_type(framed->format) == type) {
572                         return 1;
573                 }
574         }
575
576         return 0;
577 }
578
579 int ast_format_cap_get_compatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2,
580         struct ast_format_cap *result)
581 {
582         int idx, res = 0;
583
584         for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
585                 struct format_cap_framed *framed = AST_VECTOR_GET(&cap1->preference_order, idx);
586                 struct ast_format *format;
587
588                 format = ast_format_cap_get_compatible_format(cap2, framed->format);
589                 if (!format) {
590                         continue;
591                 }
592
593                 res = ast_format_cap_append(result, format, framed->framing);
594                 ao2_ref(format, -1);
595
596                 if (res) {
597                         break;
598                 }
599         }
600
601         return res;
602 }
603
604 int ast_format_cap_iscompatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
605 {
606         int idx;
607
608         for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
609                 struct format_cap_framed *framed = AST_VECTOR_GET(&cap1->preference_order, idx);
610
611                 if (ast_format_cap_iscompatible_format(cap2, framed->format) != AST_FORMAT_CMP_NOT_EQUAL) {
612                         return 1;
613                 }
614         }
615
616         return 0;
617 }
618
619 static int internal_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
620 {
621         int idx;
622         struct ast_format *tmp;
623
624         for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
625                 tmp = ast_format_cap_get_format(cap1, idx);
626
627                 if (ast_format_cap_iscompatible_format(cap2, tmp) != AST_FORMAT_CMP_EQUAL) {
628                         ao2_ref(tmp, -1);
629                         return 0;
630                 }
631
632                 ao2_ref(tmp, -1);
633         }
634
635         return 1;
636 }
637
638 int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
639 {
640         if (AST_VECTOR_SIZE(&cap1->preference_order) != AST_VECTOR_SIZE(&cap2->preference_order)) {
641                 return 0; /* if they are not the same size, they are not identical */
642         }
643
644         if (!internal_format_cap_identical(cap1, cap2)) {
645                 return 0;
646         }
647
648         return internal_format_cap_identical(cap2, cap1);
649 }
650
651 const char *ast_format_cap_get_names(struct ast_format_cap *cap, struct ast_str **buf)
652 {
653         int i;
654
655         ast_str_set(buf, 0, "(");
656
657         if (!AST_VECTOR_SIZE(&cap->preference_order)) {
658                 ast_str_append(buf, 0, "nothing)");
659                 return ast_str_buffer(*buf);
660         }
661
662         for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); ++i) {
663                 int res;
664                 struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, i);
665
666                 res = ast_str_append(buf, 0, "%s%s", ast_format_get_name(framed->format),
667                         i < AST_VECTOR_SIZE(&cap->preference_order) - 1 ? "|" : "");
668                 if (res < 0) {
669                         break;
670                 }
671         }
672         ast_str_append(buf, 0, ")");
673
674         return ast_str_buffer(*buf);
675 }
676
677 int ast_format_cap_empty(struct ast_format_cap *cap)
678 {
679         int count = ast_format_cap_count(cap);
680
681         if (count > 1) {
682                 return 0;
683         }
684
685         if (count == 0 || AST_VECTOR_GET(&cap->preference_order, 0)->format == ast_format_none) {
686                 return 1;
687         }
688
689         return 0;
690 }