Fixes bug in chan_sip where nativeformats are not set correctly.
[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, 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         struct ast_format tmp_fmt;
126         const struct ast_format_list *f_list = ast_get_format_list(&f_len);
127
128         for (x = 0; x < f_len; x++) {
129                 if (AST_FORMAT_GET_TYPE(f_list[x].id) == type) {
130                         ast_format_cap_add(cap, ast_format_set(&tmp_fmt, f_list[x].id, 0));
131                 }
132         }
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         struct ast_format tmp_fmt;
140         const struct ast_format_list *f_list = ast_get_format_list(&f_len);
141
142         for (x = 0; x < f_len; x++) {
143                 ast_format_cap_add(cap, ast_format_set(&tmp_fmt, f_list[x].id, 0));
144         }
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_iscompatible(const struct ast_format_cap *cap, const struct ast_format *format)
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                 ao2_ref(f, -1);
299                 return 1;
300         }
301
302         return 0;
303 }
304
305 /*! \internal
306  * \brief this struct is just used for the ast_format_cap_joint function so we can provide
307  * both a format and a result ast_format_cap structure as arguments to the find_joint_cb
308  * ao2 callback function.
309  */
310 struct find_joint_data {
311         /*! format to compare to for joint capabilities */
312         struct ast_format *format;
313         /*! if joint formmat exists with above format, add it to the result container */
314         struct ast_format_cap *joint_cap;
315         int joint_found;
316 };
317
318 static int find_joint_cb(void *obj, void *arg, int flag)
319 {
320         struct ast_format *format = obj;
321         struct find_joint_data *data = arg;
322
323         struct ast_format tmp = { 0, };
324         if (!ast_format_joint(format, data->format, &tmp)) {
325                 if (data->joint_cap) {
326                         ast_format_cap_add(data->joint_cap, &tmp);
327                 }
328                 data->joint_found++;
329         }
330
331         return 0;
332 }
333
334 int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
335 {
336         struct ao2_iterator it;
337         struct ast_format *tmp;
338         struct find_joint_data data = {
339                 .joint_found = 0,
340                 .joint_cap = NULL,
341         };
342
343         it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
344         while ((tmp = ao2_iterator_next(&it))) {
345                 data.format = tmp;
346                 ao2_callback(cap2->formats,
347                         OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
348                         find_joint_cb,
349                         &data);
350                 ao2_ref(tmp, -1);
351         }
352         ao2_iterator_destroy(&it);
353
354         return data.joint_found ? 1 : 0;
355 }
356
357 int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
358 {
359         struct ao2_iterator it;
360         struct ast_format *tmp;
361
362         if (ao2_container_count(cap1->formats) != ao2_container_count(cap2->formats)) {
363                 return 0; /* if they are not the same size, they are not identical */
364         }
365
366         it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
367         while ((tmp = ao2_iterator_next(&it))) {
368                 if (!ast_format_cap_iscompatible(cap2, tmp)) {
369                         ao2_ref(tmp, -1);
370                         ao2_iterator_destroy(&it);
371                         return 0;
372                 }
373                 ao2_ref(tmp, -1);
374         }
375         ao2_iterator_destroy(&it);
376
377         return 1;
378 }
379
380 struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
381 {
382         struct ao2_iterator it;
383         struct ast_format_cap *result = ast_format_cap_alloc_nolock();
384         struct ast_format *tmp;
385         struct find_joint_data data = {
386                 .joint_found = 0,
387                 .joint_cap = result,
388         };
389         if (!result) {
390                 return NULL;
391         }
392
393         it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
394         while ((tmp = ao2_iterator_next(&it))) {
395                 data.format = tmp;
396                 ao2_callback(cap2->formats,
397                         OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
398                         find_joint_cb,
399                         &data);
400                 ao2_ref(tmp, -1);
401         }
402         ao2_iterator_destroy(&it);
403
404         if (ao2_container_count(result->formats)) {
405                 return result;
406         }
407
408         result = ast_format_cap_destroy(result);
409         return NULL;
410 }
411
412 static int joint_copy_helper(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result, int append)
413 {
414         struct ao2_iterator it;
415         struct ast_format *tmp;
416         struct find_joint_data data = {
417                 .joint_cap = result,
418                 .joint_found = 0,
419         };
420         if (!append) {
421                 ast_format_cap_remove_all(result);
422         }
423         it = ao2_iterator_init(cap1->formats, cap2->nolock ? AO2_ITERATOR_DONTLOCK : 0);
424         while ((tmp = ao2_iterator_next(&it))) {
425                 data.format = tmp;
426                 ao2_callback(cap2->formats,
427                         OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
428                         find_joint_cb,
429                         &data);
430                 ao2_ref(tmp, -1);
431         }
432         ao2_iterator_destroy(&it);
433
434         return ao2_container_count(result->formats) ? 1 : 0;
435 }
436
437 int ast_format_cap_joint_append(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
438 {
439         return joint_copy_helper(cap1, cap2, result, 1);
440 }
441
442 int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
443 {
444         return joint_copy_helper(cap1, cap2, result, 0);
445 }
446
447 struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype)
448 {
449         struct ao2_iterator it;
450         struct ast_format_cap *result = ast_format_cap_alloc_nolock();
451         struct ast_format *tmp;
452
453         if (!result) {
454                 return NULL;
455         }
456
457         /* for each format in cap1, see if that format is
458          * compatible with cap2. If so copy it to the result */
459         it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
460         while ((tmp = ao2_iterator_next(&it))) {
461                 if (AST_FORMAT_GET_TYPE(tmp->id) == ftype) {
462                         /* copy format */
463                         ast_format_cap_add(result, tmp);
464                 }
465                 ao2_ref(tmp, -1);
466         }
467         ao2_iterator_destroy(&it);
468
469         if (ao2_container_count(result->formats)) {
470                 return result;
471         }
472         result = ast_format_cap_destroy(result);
473
474         /* Remember to always free the NULL before returning it. */
475         ast_free(NULL);
476         return NULL;
477 }
478
479
480 int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type)
481 {
482         struct ao2_iterator it;
483         struct ast_format *tmp;
484
485         it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
486         while ((tmp = ao2_iterator_next(&it))) {
487                 if (AST_FORMAT_GET_TYPE(tmp->id) == type) {
488                         ao2_ref(tmp, -1);
489                         ao2_iterator_destroy(&it);
490                         return 1;
491                 }
492                 ao2_ref(tmp, -1);
493         }
494         ao2_iterator_destroy(&it);
495
496         return 0;
497 }
498
499 void ast_format_cap_iter_start(struct ast_format_cap *cap)
500 {
501         if (!cap->nolock) {
502                 ao2_lock(cap->formats);
503         }
504         cap->it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
505 }
506
507 void ast_format_cap_iter_end(struct ast_format_cap *cap)
508 {
509         ao2_iterator_destroy(&cap->it);
510         if (!cap->nolock) {
511                 ao2_unlock(cap->formats);
512         }
513 }
514
515 int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format)
516 {
517         struct ast_format *tmp = ao2_iterator_next(&cap->it);
518
519         if (!tmp) {
520                 return -1;
521         }
522         ast_format_copy(format, tmp);
523         ao2_ref(tmp, -1);
524
525         return 0;
526 }
527
528 uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap)
529 {
530         uint64_t res = 0;
531         struct ao2_iterator it;
532         struct ast_format *tmp;
533
534         it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
535         while ((tmp = ao2_iterator_next(&it))) {
536                 res |= ast_format_to_old_bitfield(tmp);
537                 ao2_ref(tmp, -1);
538         }
539         ao2_iterator_destroy(&it);
540         return res;
541 }
542
543 void ast_format_cap_from_old_bitfield(struct ast_format_cap *dst, uint64_t src)
544 {
545         uint64_t tmp = 0;
546         int x;
547         struct ast_format tmp_format = { 0, };
548
549         ast_format_cap_remove_all(dst);
550         for (x = 0; x < 64; x++) {
551                 tmp = (1ULL << x);
552                 if (tmp & src) {
553                         ast_format_cap_add(dst, ast_format_from_old_bitfield(&tmp_format, tmp));
554                 }
555         }
556 }