2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2010, Digium, Inc.
6 * David Vossel <dvossel@digium.com>
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.
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.
21 * \brief Format Capability API
23 * \author David Vossel <dvossel@digium.com>
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
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"
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;
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)
50 struct ast_format *format1 = arg;
51 struct ast_format *format2 = obj;
52 enum ast_format_cmp_res res = ast_format_cmp(format1, format2);
54 return ((res == AST_FORMAT_CMP_EQUAL) ||
55 (res == AST_FORMAT_CMP_SUBSET)) ?
56 CMP_MATCH | CMP_STOP :
60 static int hash_cb(const void *obj, const int flags)
62 const struct ast_format *format = obj;
66 static struct ast_format_cap *cap_alloc_helper(int nolock)
68 struct ast_format_cap *cap = ast_calloc(1, sizeof(*cap));
73 cap->nolock = nolock ? OBJ_NOLOCK : 0;
74 if (!(cap->formats = ao2_container_alloc(283, hash_cb, cmp_cb))) {
82 struct ast_format_cap *ast_format_cap_alloc_nolock(void)
84 return cap_alloc_helper(1);
87 struct ast_format_cap *ast_format_cap_alloc(void)
89 return cap_alloc_helper(0);
92 void *ast_format_cap_destroy(struct ast_format_cap *cap)
97 ao2_ref(cap->formats, -1);
102 void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *format)
104 struct ast_format *fnew;
106 if (!format || !format->id) {
109 if (!(fnew = ao2_alloc(sizeof(struct ast_format), NULL))) {
112 ast_format_copy(fnew, format);
114 ao2_link_nolock(cap->formats, fnew);
116 ao2_link(cap->formats, fnew);
121 void ast_format_cap_add_all_by_type(struct ast_format_cap *cap, enum ast_format_type type)
125 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
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);
132 ast_format_list_destroy(f_list);
135 void ast_format_cap_add_all(struct ast_format_cap *cap)
139 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
141 for (x = 0; x < f_len; x++) {
142 ast_format_cap_add(cap, &f_list[x].format);
144 ast_format_list_destroy(f_list);
147 static int append_cb(void *obj, void *arg, int flag)
149 struct ast_format_cap *result = (struct ast_format_cap *) arg;
150 struct ast_format *format = (struct ast_format *) obj;
152 if (!ast_format_cap_iscompatible(result, format)) {
153 ast_format_cap_add(result, format);
159 void ast_format_cap_append(struct ast_format_cap *dst, const struct ast_format_cap *src)
161 ao2_callback(src->formats, OBJ_NODATA | src->nolock, append_cb, dst);
164 static int copy_cb(void *obj, void *arg, int flag)
166 struct ast_format_cap *result = (struct ast_format_cap *) arg;
167 struct ast_format *format = (struct ast_format *) obj;
169 ast_format_cap_add(result, format);
173 void ast_format_cap_copy(struct ast_format_cap *dst, const struct ast_format_cap *src)
175 ast_format_cap_remove_all(dst);
176 ao2_callback(src->formats, OBJ_NODATA | src->nolock, copy_cb, dst);
179 struct ast_format_cap *ast_format_cap_dup(const struct ast_format_cap *cap)
181 struct ast_format_cap *dst;
183 dst = ast_format_cap_alloc_nolock();
185 dst = ast_format_cap_alloc();
190 ao2_callback(cap->formats, OBJ_NODATA | cap->nolock, copy_cb, dst);
194 int ast_format_cap_is_empty(const struct ast_format_cap *cap)
199 return ao2_container_count(cap->formats) == 0 ? 1 : 0;
202 static int find_exact_cb(void *obj, void *arg, int flag)
204 struct ast_format *format1 = (struct ast_format *) arg;
205 struct ast_format *format2 = (struct ast_format *) obj;
207 return (ast_format_cmp(format1, format2) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH : 0;
210 int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
212 struct ast_format *fremove;
213 fremove = ao2_callback(cap->formats, OBJ_POINTER | OBJ_UNLINK | cap->nolock, find_exact_cb, format);
216 ao2_ref(fremove, -1);
223 struct multiple_by_id_data {
224 struct ast_format *format;
228 static int multiple_by_id_cb(void *obj, void *arg, int flag)
230 struct multiple_by_id_data *data = arg;
231 struct ast_format *format = obj;
234 res = (format->id == data->format->id) ? CMP_MATCH : 0;
236 data->match_found = 1;
242 int ast_format_cap_remove_byid(struct ast_format_cap *cap, enum ast_format_id id)
244 struct ast_format format = {
247 struct multiple_by_id_data data = {
252 ao2_callback(cap->formats,
253 OBJ_NODATA | cap->nolock | OBJ_MULTIPLE | OBJ_UNLINK,
257 /* match_found will be set if at least one item was removed */
258 if (data.match_found) {
265 static int multiple_by_type_cb(void *obj, void *arg, int flag)
268 struct ast_format *format = obj;
269 return ((AST_FORMAT_GET_TYPE(format->id)) == *type) ? CMP_MATCH : 0;
272 void ast_format_cap_remove_bytype(struct ast_format_cap *cap, enum ast_format_type type)
274 ao2_callback(cap->formats,
275 OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE | cap->nolock,
280 void ast_format_cap_remove_all(struct ast_format_cap *cap)
282 ao2_callback(cap->formats, OBJ_NODATA | cap->nolock | OBJ_MULTIPLE | OBJ_UNLINK, NULL, NULL);
285 void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format)
287 ast_format_cap_remove_all(cap);
288 ast_format_cap_add(cap, format);
291 int ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format, struct ast_format *result)
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);
298 ast_format_copy(result, f);
302 ast_format_clear(result);
306 int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct ast_format *format)
308 struct ast_format *f;
309 struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
314 f = ao2_find(tmp_cap->formats, (struct ast_format *) format, OBJ_POINTER | tmp_cap->nolock);
324 struct ast_format *result;
325 enum ast_format_id id;
327 static int find_best_byid_cb(void *obj, void *arg, int flag)
329 struct ast_format *format = obj;
330 struct byid_data *data = arg;
332 if (data->id != format->id) {
335 if (!data->result->id || (ast_format_rate(data->result) < ast_format_rate(format))) {
336 ast_format_copy(data->result, format);
341 int ast_format_cap_best_byid(const struct ast_format_cap *cap, enum ast_format_id id, struct ast_format *result)
343 struct byid_data data;
344 data.result = result;
347 ast_format_clear(result);
348 ao2_callback(cap->formats,
349 OBJ_MULTIPLE | OBJ_NODATA | cap->nolock,
352 return result->id ? 1 : 0;
356 * \brief this struct is just used for the ast_format_cap_joint function so we can provide
357 * both a format and a result ast_format_cap structure as arguments to the find_joint_cb
358 * ao2 callback function.
360 struct find_joint_data {
361 /*! format to compare to for joint capabilities */
362 struct ast_format *format;
363 /*! if joint formmat exists with above format, add it to the result container */
364 struct ast_format_cap *joint_cap;
368 static int find_joint_cb(void *obj, void *arg, int flag)
370 struct ast_format *format = obj;
371 struct find_joint_data *data = arg;
373 struct ast_format tmp = { 0, };
374 if (!ast_format_joint(format, data->format, &tmp)) {
375 if (data->joint_cap) {
376 ast_format_cap_add(data->joint_cap, &tmp);
384 int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
386 struct ao2_iterator it;
387 struct ast_format *tmp;
388 struct find_joint_data data = {
393 it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
394 while ((tmp = ao2_iterator_next(&it))) {
396 ao2_callback(cap2->formats,
397 OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
402 ao2_iterator_destroy(&it);
404 return data.joint_found ? 1 : 0;
407 int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
409 struct ao2_iterator it;
410 struct ast_format *tmp;
412 if (ao2_container_count(cap1->formats) != ao2_container_count(cap2->formats)) {
413 return 0; /* if they are not the same size, they are not identical */
416 it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
417 while ((tmp = ao2_iterator_next(&it))) {
418 if (!ast_format_cap_iscompatible(cap2, tmp)) {
420 ao2_iterator_destroy(&it);
425 ao2_iterator_destroy(&it);
430 struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
432 struct ao2_iterator it;
433 struct ast_format_cap *result = ast_format_cap_alloc_nolock();
434 struct ast_format *tmp;
435 struct find_joint_data data = {
443 it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
444 while ((tmp = ao2_iterator_next(&it))) {
446 ao2_callback(cap2->formats,
447 OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
452 ao2_iterator_destroy(&it);
454 if (ao2_container_count(result->formats)) {
458 result = ast_format_cap_destroy(result);
462 static int joint_copy_helper(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result, int append)
464 struct ao2_iterator it;
465 struct ast_format *tmp;
466 struct find_joint_data data = {
471 ast_format_cap_remove_all(result);
473 it = ao2_iterator_init(cap1->formats, cap2->nolock ? AO2_ITERATOR_DONTLOCK : 0);
474 while ((tmp = ao2_iterator_next(&it))) {
476 ao2_callback(cap2->formats,
477 OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
482 ao2_iterator_destroy(&it);
484 return ao2_container_count(result->formats) ? 1 : 0;
487 int ast_format_cap_joint_append(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
489 return joint_copy_helper(cap1, cap2, result, 1);
492 int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
494 return joint_copy_helper(cap1, cap2, result, 0);
497 struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype)
499 struct ao2_iterator it;
500 struct ast_format_cap *result = ast_format_cap_alloc_nolock();
501 struct ast_format *tmp;
507 /* for each format in cap1, see if that format is
508 * compatible with cap2. If so copy it to the result */
509 it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
510 while ((tmp = ao2_iterator_next(&it))) {
511 if (AST_FORMAT_GET_TYPE(tmp->id) == ftype) {
513 ast_format_cap_add(result, tmp);
517 ao2_iterator_destroy(&it);
519 if (ao2_container_count(result->formats)) {
522 result = ast_format_cap_destroy(result);
528 int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type)
530 struct ao2_iterator it;
531 struct ast_format *tmp;
533 it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
534 while ((tmp = ao2_iterator_next(&it))) {
535 if (AST_FORMAT_GET_TYPE(tmp->id) == type) {
537 ao2_iterator_destroy(&it);
542 ao2_iterator_destroy(&it);
547 void ast_format_cap_iter_start(struct ast_format_cap *cap)
550 ao2_lock(cap->formats);
552 cap->it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
555 void ast_format_cap_iter_end(struct ast_format_cap *cap)
557 ao2_iterator_destroy(&cap->it);
559 ao2_unlock(cap->formats);
563 int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format)
565 struct ast_format *tmp = ao2_iterator_next(&cap->it);
570 ast_format_copy(format, tmp);
576 char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap)
580 char *start, *end = buf;
581 struct ast_format tmp_fmt;
583 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
586 f_list = ast_format_list_destroy(f_list);
589 snprintf(end, size, "(");
594 for (x = 0; x < f_len; x++) {
595 ast_format_copy(&tmp_fmt, &f_list[x].format);
596 if (ast_format_cap_iscompatible(cap, &tmp_fmt)) {
597 snprintf(end, size, "%s|", f_list[x].name);
604 ast_copy_string(start, "nothing)", size);
605 } else if (size > 1) {
608 f_list = ast_format_list_destroy(f_list);
612 uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap)
615 struct ao2_iterator it;
616 struct ast_format *tmp;
618 it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
619 while ((tmp = ao2_iterator_next(&it))) {
620 res |= ast_format_to_old_bitfield(tmp);
623 ao2_iterator_destroy(&it);
627 void ast_format_cap_from_old_bitfield(struct ast_format_cap *dst, uint64_t src)
631 struct ast_format tmp_format = { 0, };
633 ast_format_cap_remove_all(dst);
634 for (x = 0; x < 64; x++) {
637 ast_format_cap_add(dst, ast_format_from_old_bitfield(&tmp_format, tmp));