ARI: Add ability to raise arbitrary User Events
[asterisk/asterisk.git] / main / format_cap.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2010, Digium, Inc.
5  *
6  * David Vossel <dvossel@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 Format Capability API
22  *
23  * \author David Vossel <dvossel@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
33
34 #include "asterisk/_private.h"
35 #include "asterisk/format.h"
36 #include "asterisk/format_cap.h"
37 #include "asterisk/frame.h"
38 #include "asterisk/astobj2.h"
39 #include "asterisk/utils.h"
40
41 #define FORMAT_STR_BUFSIZE 256
42
43 struct ast_format_cap {
44         /* The capabilities structure is just an ao2 container of ast_formats */
45         struct ao2_container *formats;
46         struct ao2_iterator it;
47         /*! TRUE if the formats container created without a lock. */
48         struct ast_flags flags;
49         unsigned int string_cache_valid;
50         char format_strs[0];
51 };
52
53 /*! format exists within capabilities structure if it is identical to
54  * another format, or if the format is a proper subset of another format. */
55 static int cmp_cb(void *obj, void *arg, int flags)
56 {
57         struct ast_format *format1 = arg;
58         struct ast_format *format2 = obj;
59         enum ast_format_cmp_res res = ast_format_cmp(format1, format2);
60
61         return ((res == AST_FORMAT_CMP_EQUAL) ||
62                         (res == AST_FORMAT_CMP_SUBSET)) ?
63                                 CMP_MATCH | CMP_STOP :
64                                 0;
65 }
66
67 static int hash_cb(const void *obj, const int flags)
68 {
69         const struct ast_format *format = obj;
70         return format->id;
71 }
72
73 struct ast_format_cap *ast_format_cap_alloc(enum ast_format_cap_flags flags)
74 {
75         struct ast_format_cap *cap;
76         unsigned int alloc_size;
77         
78         alloc_size = sizeof(*cap);
79         if (flags & AST_FORMAT_CAP_FLAG_CACHE_STRINGS) {
80                 alloc_size += FORMAT_STR_BUFSIZE;
81         }
82
83         cap = ast_calloc(1, alloc_size);
84         if (!cap) {
85                 return NULL;
86         }
87
88         ast_set_flag(&cap->flags, flags);
89         cap->formats = ao2_container_alloc_options(
90                 (flags & AST_FORMAT_CAP_FLAG_NOLOCK) ?
91                 AO2_ALLOC_OPT_LOCK_NOLOCK :
92                 AO2_ALLOC_OPT_LOCK_MUTEX,
93                 11, hash_cb, cmp_cb);
94         if (!cap->formats) {
95                 ast_free(cap);
96                 return NULL;
97         }
98
99         return cap;
100 }
101
102 void *ast_format_cap_destroy(struct ast_format_cap *cap)
103 {
104         if (!cap) {
105                 return NULL;
106         }
107         ao2_ref(cap->formats, -1);
108         ast_free(cap);
109         return NULL;
110 }
111
112 static void format_cap_add(struct ast_format_cap *cap, const struct ast_format *format)
113 {
114         struct ast_format *fnew;
115
116         if (!format || !format->id) {
117                 return;
118         }
119         if (!(fnew = ao2_alloc(sizeof(struct ast_format), NULL))) {
120                 return;
121         }
122         ast_format_copy(fnew, format);
123         ao2_link(cap->formats, fnew);
124
125         ao2_ref(fnew, -1);
126 }
127
128 void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *format)
129 {
130         format_cap_add(cap, format);
131         cap->string_cache_valid = 0;
132 }
133
134 void ast_format_cap_add_all_by_type(struct ast_format_cap *cap, enum ast_format_type type)
135 {
136         int x;
137         size_t f_len = 0;
138         const struct ast_format_list *f_list = ast_format_list_get(&f_len);
139
140         for (x = 0; x < f_len; x++) {
141                 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) == type) {
142                         format_cap_add(cap, &f_list[x].format);
143                 }
144         }
145         cap->string_cache_valid = 0;
146         ast_format_list_destroy(f_list);
147 }
148
149 void ast_format_cap_add_all(struct ast_format_cap *cap)
150 {
151         int x;
152         size_t f_len = 0;
153         const struct ast_format_list *f_list = ast_format_list_get(&f_len);
154
155         for (x = 0; x < f_len; x++) {
156                 format_cap_add(cap, &f_list[x].format);
157         }
158         cap->string_cache_valid = 0;
159         ast_format_list_destroy(f_list);
160 }
161
162 static int append_cb(void *obj, void *arg, int flag)
163 {
164         struct ast_format_cap *result = (struct ast_format_cap *) arg;
165         struct ast_format *format = (struct ast_format *) obj;
166
167         if (!ast_format_cap_iscompatible(result, format)) {
168                 format_cap_add(result, format);
169         }
170
171         return 0;
172 }
173
174 void ast_format_cap_append(struct ast_format_cap *dst, const struct ast_format_cap *src)
175 {
176         ao2_callback(src->formats, OBJ_NODATA, append_cb, dst);
177         dst->string_cache_valid = 0;
178 }
179
180 static int copy_cb(void *obj, void *arg, int flag)
181 {
182         struct ast_format_cap *result = (struct ast_format_cap *) arg;
183         struct ast_format *format = (struct ast_format *) obj;
184
185         format_cap_add(result, format);
186         return 0;
187 }
188
189 static void format_cap_remove_all(struct ast_format_cap *cap)
190 {
191         ao2_callback(cap->formats, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, NULL, NULL);
192 }
193
194 void ast_format_cap_copy(struct ast_format_cap *dst, const struct ast_format_cap *src)
195 {
196         format_cap_remove_all(dst);
197         ao2_callback(src->formats, OBJ_NODATA, copy_cb, dst);
198         dst->string_cache_valid = 0;
199 }
200
201 struct ast_format_cap *ast_format_cap_dup(const struct ast_format_cap *cap)
202 {
203         struct ast_format_cap *dst;
204
205         dst = ast_format_cap_alloc(ast_test_flag(&cap->flags, AST_FLAGS_ALL));
206         if (!dst) {
207                 return NULL;
208         }
209         ao2_callback(cap->formats, OBJ_NODATA, copy_cb, dst);
210         dst->string_cache_valid = 0;
211         return dst;
212 }
213
214 int ast_format_cap_is_empty(const struct ast_format_cap *cap)
215 {
216         if (!cap) {
217                 return 1;
218         }
219         return ao2_container_count(cap->formats) == 0 ? 1 : 0;
220 }
221
222 static int find_exact_cb(void *obj, void *arg, int flag)
223 {
224         struct ast_format *format1 = (struct ast_format *) arg;
225         struct ast_format *format2 = (struct ast_format *) obj;
226
227         return (ast_format_cmp(format1, format2) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH : 0;
228 }
229
230 int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
231 {
232         struct ast_format *fremove;
233
234         fremove = ao2_callback(cap->formats, OBJ_POINTER | OBJ_UNLINK, find_exact_cb, format);
235         if (fremove) {
236                 ao2_ref(fremove, -1);
237                 cap->string_cache_valid = 0;
238                 return 0;
239         }
240
241         return -1;
242 }
243
244 struct multiple_by_id_data {
245         struct ast_format *format;
246         int match_found;
247 };
248
249 static int multiple_by_id_cb(void *obj, void *arg, int flag)
250 {
251         struct multiple_by_id_data *data = arg;
252         struct ast_format *format = obj;
253         int res;
254
255         res = (format->id == data->format->id) ? CMP_MATCH : 0;
256         if (res) {
257                 data->match_found = 1;
258         }
259
260         return res;
261 }
262
263 int ast_format_cap_remove_byid(struct ast_format_cap *cap, enum ast_format_id id)
264 {
265         struct ast_format format = {
266                 .id = id,
267         };
268         struct multiple_by_id_data data = {
269                 .format = &format,
270                 .match_found = 0,
271         };
272
273         ao2_callback(cap->formats,
274                 OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
275                 multiple_by_id_cb,
276                 &data);
277
278         /* match_found will be set if at least one item was removed */
279         if (data.match_found) {
280                 cap->string_cache_valid = 0;
281                 return 0;
282         }
283
284         return -1;
285 }
286
287 static int multiple_by_type_cb(void *obj, void *arg, int flag)
288 {
289         int *type = arg;
290         struct ast_format *format = obj;
291         return ((AST_FORMAT_GET_TYPE(format->id)) == *type) ? CMP_MATCH : 0;
292 }
293
294 void ast_format_cap_remove_bytype(struct ast_format_cap *cap, enum ast_format_type type)
295 {
296         ao2_callback(cap->formats,
297                 OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE,
298                 multiple_by_type_cb,
299                 &type);
300         cap->string_cache_valid = 0;
301 }
302
303 void ast_format_cap_remove_all(struct ast_format_cap *cap)
304 {
305         format_cap_remove_all(cap);
306         cap->string_cache_valid = 0;
307 }
308
309 void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format)
310 {
311         format_cap_remove_all(cap);
312         format_cap_add(cap, format);
313         cap->string_cache_valid = 0;
314 }
315
316 int ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format, struct ast_format *result)
317 {
318         struct ast_format *f;
319         struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
320
321         f = ao2_find(tmp_cap->formats, format, OBJ_POINTER);
322         if (f) {
323                 ast_format_copy(result, f);
324                 ao2_ref(f, -1);
325                 return 1;
326         }
327         ast_format_clear(result);
328         return 0;
329 }
330
331 int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct ast_format *format)
332 {
333         struct ast_format *f;
334         struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
335
336         if (!tmp_cap) {
337                 return 0;
338         }
339
340         f = ao2_find(tmp_cap->formats, format, OBJ_POINTER);
341         if (f) {
342                 ao2_ref(f, -1);
343                 return 1;
344         }
345
346         return 0;
347 }
348
349 struct byid_data {
350         struct ast_format *result;
351         enum ast_format_id id;
352 };
353 static int find_best_byid_cb(void *obj, void *arg, int flag)
354 {
355         struct ast_format *format = obj;
356         struct byid_data *data = arg;
357
358         if (data->id != format->id) {
359                 return 0;
360         }
361         if (!data->result->id || (ast_format_rate(data->result) < ast_format_rate(format))) {
362                 ast_format_copy(data->result, format);
363         }
364         return 0;
365 }
366
367 int ast_format_cap_best_byid(const struct ast_format_cap *cap, enum ast_format_id id, struct ast_format *result)
368 {
369         struct byid_data data;
370         data.result = result;
371         data.id = id;
372
373         ast_format_clear(result);
374         ao2_callback(cap->formats,
375                 OBJ_MULTIPLE | OBJ_NODATA,
376                 find_best_byid_cb,
377                 &data);
378         return result->id ? 1 : 0;
379 }
380
381 /*! \internal
382  * \brief this struct is just used for the ast_format_cap_joint function so we can provide
383  * both a format and a result ast_format_cap structure as arguments to the find_joint_cb
384  * ao2 callback function.
385  */
386 struct find_joint_data {
387         /*! format to compare to for joint capabilities */
388         struct ast_format *format;
389         /*! if joint formmat exists with above format, add it to the result container */
390         struct ast_format_cap *joint_cap;
391         int joint_found;
392 };
393
394 static int find_joint_cb(void *obj, void *arg, int flag)
395 {
396         struct ast_format *format = obj;
397         struct find_joint_data *data = arg;
398
399         struct ast_format tmp = { 0, };
400         if (!ast_format_joint(format, data->format, &tmp)) {
401                 if (data->joint_cap) {
402                         ast_format_cap_add(data->joint_cap, &tmp);
403                 }
404                 data->joint_found++;
405         }
406
407         return 0;
408 }
409
410 int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
411 {
412         struct ao2_iterator it;
413         struct ast_format *tmp;
414         struct find_joint_data data = {
415                 .joint_found = 0,
416                 .joint_cap = NULL,
417         };
418
419         it = ao2_iterator_init(cap1->formats, 0);
420         while ((tmp = ao2_iterator_next(&it))) {
421                 data.format = tmp;
422                 ao2_callback(cap2->formats,
423                         OBJ_MULTIPLE | OBJ_NODATA,
424                         find_joint_cb,
425                         &data);
426                 ao2_ref(tmp, -1);
427         }
428         ao2_iterator_destroy(&it);
429
430         return data.joint_found ? 1 : 0;
431 }
432
433 int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
434 {
435         struct ao2_iterator it;
436         struct ast_format *tmp;
437
438         if (ao2_container_count(cap1->formats) != ao2_container_count(cap2->formats)) {
439                 return 0; /* if they are not the same size, they are not identical */
440         }
441
442         it = ao2_iterator_init(cap1->formats, 0);
443         while ((tmp = ao2_iterator_next(&it))) {
444                 if (!ast_format_cap_iscompatible(cap2, tmp)) {
445                         ao2_ref(tmp, -1);
446                         ao2_iterator_destroy(&it);
447                         return 0;
448                 }
449                 ao2_ref(tmp, -1);
450         }
451         ao2_iterator_destroy(&it);
452
453         return 1;
454 }
455
456 struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
457 {
458         struct ao2_iterator it;
459         struct ast_format_cap *result = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK);
460         struct ast_format *tmp;
461         struct find_joint_data data = {
462                 .joint_found = 0,
463                 .joint_cap = result,
464         };
465         if (!result) {
466                 return NULL;
467         }
468
469         it = ao2_iterator_init(cap1->formats, 0);
470         while ((tmp = ao2_iterator_next(&it))) {
471                 data.format = tmp;
472                 ao2_callback(cap2->formats,
473                         OBJ_MULTIPLE | OBJ_NODATA,
474                         find_joint_cb,
475                         &data);
476                 ao2_ref(tmp, -1);
477         }
478         ao2_iterator_destroy(&it);
479
480         if (ao2_container_count(result->formats)) {
481                 return result;
482         }
483
484         result = ast_format_cap_destroy(result);
485         return NULL;
486 }
487
488 static int joint_copy_helper(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result, int append)
489 {
490         struct ao2_iterator it;
491         struct ast_format *tmp;
492         struct find_joint_data data = {
493                 .joint_cap = result,
494                 .joint_found = 0,
495         };
496         if (!append) {
497                 format_cap_remove_all(result);
498         }
499         it = ao2_iterator_init(cap1->formats, 0);
500         while ((tmp = ao2_iterator_next(&it))) {
501                 data.format = tmp;
502                 ao2_callback(cap2->formats,
503                         OBJ_MULTIPLE | OBJ_NODATA,
504                         find_joint_cb,
505                         &data);
506                 ao2_ref(tmp, -1);
507         }
508         ao2_iterator_destroy(&it);
509
510         result->string_cache_valid = 0;
511
512         return ao2_container_count(result->formats) ? 1 : 0;
513 }
514
515 int ast_format_cap_joint_append(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
516 {
517         return joint_copy_helper(cap1, cap2, result, 1);
518 }
519
520 int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
521 {
522         return joint_copy_helper(cap1, cap2, result, 0);
523 }
524
525 struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype)
526 {
527         struct ao2_iterator it;
528         struct ast_format_cap *result = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK);
529         struct ast_format *tmp;
530
531         if (!result) {
532                 return NULL;
533         }
534
535         /* for each format in cap1, see if that format is
536          * compatible with cap2. If so copy it to the result */
537         it = ao2_iterator_init(cap->formats, 0);
538         while ((tmp = ao2_iterator_next(&it))) {
539                 if (AST_FORMAT_GET_TYPE(tmp->id) == ftype) {
540                         /* copy format */
541                         ast_format_cap_add(result, tmp);
542                 }
543                 ao2_ref(tmp, -1);
544         }
545         ao2_iterator_destroy(&it);
546
547         if (ao2_container_count(result->formats)) {
548                 return result;
549         }
550         result = ast_format_cap_destroy(result);
551
552         return NULL;
553 }
554
555
556 int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type)
557 {
558         struct ao2_iterator it;
559         struct ast_format *tmp;
560
561         it = ao2_iterator_init(cap->formats, 0);
562         while ((tmp = ao2_iterator_next(&it))) {
563                 if (AST_FORMAT_GET_TYPE(tmp->id) == type) {
564                         ao2_ref(tmp, -1);
565                         ao2_iterator_destroy(&it);
566                         return 1;
567                 }
568                 ao2_ref(tmp, -1);
569         }
570         ao2_iterator_destroy(&it);
571
572         return 0;
573 }
574
575 void ast_format_cap_iter_start(struct ast_format_cap *cap)
576 {
577         /* We can unconditionally lock even if the container has no lock. */
578         ao2_lock(cap->formats);
579         cap->it = ao2_iterator_init(cap->formats, AO2_ITERATOR_DONTLOCK);
580 }
581
582 void ast_format_cap_iter_end(struct ast_format_cap *cap)
583 {
584         ao2_iterator_destroy(&cap->it);
585         /* We can unconditionally unlock even if the container has no lock. */
586         ao2_unlock(cap->formats);
587 }
588
589 int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format)
590 {
591         struct ast_format *tmp = ao2_iterator_next(&cap->it);
592
593         if (!tmp) {
594                 return -1;
595         }
596         ast_format_copy(format, tmp);
597         ao2_ref(tmp, -1);
598
599         return 0;
600 }
601
602 static char *getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap)
603 {
604         int x;
605         unsigned len;
606         char *start, *end = buf;
607         struct ast_format tmp_fmt;
608         size_t f_len;
609         const struct ast_format_list *f_list = ast_format_list_get(&f_len);
610
611         if (!size) {
612                 f_list = ast_format_list_destroy(f_list);
613                 return buf;
614         }
615         snprintf(end, size, "(");
616         len = strlen(end);
617         end += len;
618         size -= len;
619         start = end;
620         for (x = 0; x < f_len; x++) {
621                 ast_format_copy(&tmp_fmt, &f_list[x].format);
622                 if (ast_format_cap_iscompatible(cap, &tmp_fmt)) {
623                         snprintf(end, size, "%s|", f_list[x].name);
624                         len = strlen(end);
625                         end += len;
626                         size -= len;
627                 }
628         }
629         if (start == end) {
630                 ast_copy_string(start, "nothing)", size);
631         } else if (size > 1) {
632                 *(end - 1) = ')';
633         }
634         f_list = ast_format_list_destroy(f_list);
635         return buf;
636 }
637
638 char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap)
639 {
640         if (ast_test_flag(&cap->flags, AST_FORMAT_CAP_FLAG_CACHE_STRINGS)) {
641                 if (!cap->string_cache_valid) {
642                         getformatname_multiple(cap->format_strs, FORMAT_STR_BUFSIZE, cap);
643                         cap->string_cache_valid = 1;
644                 }
645                 ast_copy_string(buf, cap->format_strs, size);
646                 return buf;
647         }
648
649         return getformatname_multiple(buf, size, cap);
650 }
651
652 uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap)
653 {
654         uint64_t res = 0;
655         struct ao2_iterator it;
656         struct ast_format *tmp;
657
658         it = ao2_iterator_init(cap->formats, 0);
659         while ((tmp = ao2_iterator_next(&it))) {
660                 res |= ast_format_to_old_bitfield(tmp);
661                 ao2_ref(tmp, -1);
662         }
663         ao2_iterator_destroy(&it);
664         return res;
665 }
666
667 void ast_format_cap_from_old_bitfield(struct ast_format_cap *dst, uint64_t src)
668 {
669         uint64_t tmp = 0;
670         int x;
671         struct ast_format tmp_format = { 0, };
672
673         format_cap_remove_all(dst);
674         for (x = 0; x < 64; x++) {
675                 tmp = (1ULL << x);
676                 if (tmp & src) {
677                         format_cap_add(dst, ast_format_from_old_bitfield(&tmp_format, tmp));
678                 }
679         }
680         dst->string_cache_valid = 0;
681 }