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>
27 <support_level>core</support_level>
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
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"
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. */
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)
54 struct ast_format *format1 = arg;
55 struct ast_format *format2 = obj;
56 enum ast_format_cmp_res res = ast_format_cmp(format1, format2);
58 return ((res == AST_FORMAT_CMP_EQUAL) ||
59 (res == AST_FORMAT_CMP_SUBSET)) ?
60 CMP_MATCH | CMP_STOP :
64 static int hash_cb(const void *obj, const int flags)
66 const struct ast_format *format = obj;
70 static struct ast_format_cap *cap_alloc_helper(int nolock)
72 struct ast_format_cap *cap = ast_calloc(1, sizeof(*cap));
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);
89 struct ast_format_cap *ast_format_cap_alloc_nolock(void)
91 return cap_alloc_helper(1);
94 struct ast_format_cap *ast_format_cap_alloc(void)
96 return cap_alloc_helper(0);
99 void *ast_format_cap_destroy(struct ast_format_cap *cap)
104 ao2_ref(cap->formats, -1);
109 void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *format)
111 struct ast_format *fnew;
113 if (!format || !format->id) {
116 if (!(fnew = ao2_alloc(sizeof(struct ast_format), NULL))) {
119 ast_format_copy(fnew, format);
120 ao2_link(cap->formats, fnew);
124 void ast_format_cap_add_all_by_type(struct ast_format_cap *cap, enum ast_format_type type)
128 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
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);
135 ast_format_list_destroy(f_list);
138 void ast_format_cap_add_all(struct ast_format_cap *cap)
142 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
144 for (x = 0; x < f_len; x++) {
145 ast_format_cap_add(cap, &f_list[x].format);
147 ast_format_list_destroy(f_list);
150 static int append_cb(void *obj, void *arg, int flag)
152 struct ast_format_cap *result = (struct ast_format_cap *) arg;
153 struct ast_format *format = (struct ast_format *) obj;
155 if (!ast_format_cap_iscompatible(result, format)) {
156 ast_format_cap_add(result, format);
162 void ast_format_cap_append(struct ast_format_cap *dst, const struct ast_format_cap *src)
164 ao2_callback(src->formats, OBJ_NODATA, append_cb, dst);
167 static int copy_cb(void *obj, void *arg, int flag)
169 struct ast_format_cap *result = (struct ast_format_cap *) arg;
170 struct ast_format *format = (struct ast_format *) obj;
172 ast_format_cap_add(result, format);
176 void ast_format_cap_copy(struct ast_format_cap *dst, const struct ast_format_cap *src)
178 ast_format_cap_remove_all(dst);
179 ao2_callback(src->formats, OBJ_NODATA, copy_cb, dst);
182 struct ast_format_cap *ast_format_cap_dup(const struct ast_format_cap *cap)
184 struct ast_format_cap *dst;
186 dst = ast_format_cap_alloc_nolock();
188 dst = ast_format_cap_alloc();
193 ao2_callback(cap->formats, OBJ_NODATA, copy_cb, dst);
197 int ast_format_cap_is_empty(const struct ast_format_cap *cap)
202 return ao2_container_count(cap->formats) == 0 ? 1 : 0;
205 static int find_exact_cb(void *obj, void *arg, int flag)
207 struct ast_format *format1 = (struct ast_format *) arg;
208 struct ast_format *format2 = (struct ast_format *) obj;
210 return (ast_format_cmp(format1, format2) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH : 0;
213 int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
215 struct ast_format *fremove;
217 fremove = ao2_callback(cap->formats, OBJ_POINTER | OBJ_UNLINK, find_exact_cb, format);
219 ao2_ref(fremove, -1);
226 struct multiple_by_id_data {
227 struct ast_format *format;
231 static int multiple_by_id_cb(void *obj, void *arg, int flag)
233 struct multiple_by_id_data *data = arg;
234 struct ast_format *format = obj;
237 res = (format->id == data->format->id) ? CMP_MATCH : 0;
239 data->match_found = 1;
245 int ast_format_cap_remove_byid(struct ast_format_cap *cap, enum ast_format_id id)
247 struct ast_format format = {
250 struct multiple_by_id_data data = {
255 ao2_callback(cap->formats,
256 OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
260 /* match_found will be set if at least one item was removed */
261 if (data.match_found) {
268 static int multiple_by_type_cb(void *obj, void *arg, int flag)
271 struct ast_format *format = obj;
272 return ((AST_FORMAT_GET_TYPE(format->id)) == *type) ? CMP_MATCH : 0;
275 void ast_format_cap_remove_bytype(struct ast_format_cap *cap, enum ast_format_type type)
277 ao2_callback(cap->formats,
278 OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE,
283 void ast_format_cap_remove_all(struct ast_format_cap *cap)
285 ao2_callback(cap->formats, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, NULL, NULL);
288 void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format)
290 ast_format_cap_remove_all(cap);
291 ast_format_cap_add(cap, format);
294 int ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format, struct ast_format *result)
296 struct ast_format *f;
297 struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
299 f = ao2_find(tmp_cap->formats, format, OBJ_POINTER);
301 ast_format_copy(result, f);
305 ast_format_clear(result);
309 int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct ast_format *format)
311 struct ast_format *f;
312 struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
318 f = ao2_find(tmp_cap->formats, format, OBJ_POINTER);
328 struct ast_format *result;
329 enum ast_format_id id;
331 static int find_best_byid_cb(void *obj, void *arg, int flag)
333 struct ast_format *format = obj;
334 struct byid_data *data = arg;
336 if (data->id != format->id) {
339 if (!data->result->id || (ast_format_rate(data->result) < ast_format_rate(format))) {
340 ast_format_copy(data->result, format);
345 int ast_format_cap_best_byid(const struct ast_format_cap *cap, enum ast_format_id id, struct ast_format *result)
347 struct byid_data data;
348 data.result = result;
351 ast_format_clear(result);
352 ao2_callback(cap->formats,
353 OBJ_MULTIPLE | OBJ_NODATA,
356 return result->id ? 1 : 0;
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.
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;
372 static int find_joint_cb(void *obj, void *arg, int flag)
374 struct ast_format *format = obj;
375 struct find_joint_data *data = arg;
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);
388 int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
390 struct ao2_iterator it;
391 struct ast_format *tmp;
392 struct find_joint_data data = {
397 it = ao2_iterator_init(cap1->formats, 0);
398 while ((tmp = ao2_iterator_next(&it))) {
400 ao2_callback(cap2->formats,
401 OBJ_MULTIPLE | OBJ_NODATA,
406 ao2_iterator_destroy(&it);
408 return data.joint_found ? 1 : 0;
411 int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
413 struct ao2_iterator it;
414 struct ast_format *tmp;
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 */
420 it = ao2_iterator_init(cap1->formats, 0);
421 while ((tmp = ao2_iterator_next(&it))) {
422 if (!ast_format_cap_iscompatible(cap2, tmp)) {
424 ao2_iterator_destroy(&it);
429 ao2_iterator_destroy(&it);
434 struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
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 = {
447 it = ao2_iterator_init(cap1->formats, 0);
448 while ((tmp = ao2_iterator_next(&it))) {
450 ao2_callback(cap2->formats,
451 OBJ_MULTIPLE | OBJ_NODATA,
456 ao2_iterator_destroy(&it);
458 if (ao2_container_count(result->formats)) {
462 result = ast_format_cap_destroy(result);
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)
468 struct ao2_iterator it;
469 struct ast_format *tmp;
470 struct find_joint_data data = {
475 ast_format_cap_remove_all(result);
477 it = ao2_iterator_init(cap1->formats, 0);
478 while ((tmp = ao2_iterator_next(&it))) {
480 ao2_callback(cap2->formats,
481 OBJ_MULTIPLE | OBJ_NODATA,
486 ao2_iterator_destroy(&it);
488 return ao2_container_count(result->formats) ? 1 : 0;
491 int ast_format_cap_joint_append(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
493 return joint_copy_helper(cap1, cap2, result, 1);
496 int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
498 return joint_copy_helper(cap1, cap2, result, 0);
501 struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype)
503 struct ao2_iterator it;
504 struct ast_format_cap *result = ast_format_cap_alloc_nolock();
505 struct ast_format *tmp;
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) {
517 ast_format_cap_add(result, tmp);
521 ao2_iterator_destroy(&it);
523 if (ao2_container_count(result->formats)) {
526 result = ast_format_cap_destroy(result);
532 int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type)
534 struct ao2_iterator it;
535 struct ast_format *tmp;
537 it = ao2_iterator_init(cap->formats, 0);
538 while ((tmp = ao2_iterator_next(&it))) {
539 if (AST_FORMAT_GET_TYPE(tmp->id) == type) {
541 ao2_iterator_destroy(&it);
546 ao2_iterator_destroy(&it);
551 void ast_format_cap_iter_start(struct ast_format_cap *cap)
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);
558 void ast_format_cap_iter_end(struct ast_format_cap *cap)
560 ao2_iterator_destroy(&cap->it);
561 /* We can unconditionally unlock even if the container has no lock. */
562 ao2_unlock(cap->formats);
565 int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format)
567 struct ast_format *tmp = ao2_iterator_next(&cap->it);
572 ast_format_copy(format, tmp);
578 char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap)
582 char *start, *end = buf;
583 struct ast_format tmp_fmt;
585 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
588 f_list = ast_format_list_destroy(f_list);
591 snprintf(end, size, "(");
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);
606 ast_copy_string(start, "nothing)", size);
607 } else if (size > 1) {
610 f_list = ast_format_list_destroy(f_list);
614 uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap)
617 struct ao2_iterator it;
618 struct ast_format *tmp;
620 it = ao2_iterator_init(cap->formats, 0);
621 while ((tmp = ao2_iterator_next(&it))) {
622 res |= ast_format_to_old_bitfield(tmp);
625 ao2_iterator_destroy(&it);
629 void ast_format_cap_from_old_bitfield(struct ast_format_cap *dst, uint64_t src)
633 struct ast_format tmp_format = { 0, };
635 ast_format_cap_remove_all(dst);
636 for (x = 0; x < 64; x++) {
639 ast_format_cap_add(dst, ast_format_from_old_bitfield(&tmp_format, tmp));