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