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