Wed May 16 06:33:33 2012

Asterisk developer's documentation


format_cap.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2010, Digium, Inc.
00005  *
00006  * David Vossel <dvossel@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*!
00020  * \file
00021  * \brief Format Capability API
00022  *
00023  * \author David Vossel <dvossel@digium.com>
00024  */
00025 
00026 #include "asterisk.h"
00027 
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 357272 $");
00029 
00030 #include "asterisk/_private.h"
00031 #include "asterisk/format.h"
00032 #include "asterisk/format_cap.h"
00033 #include "asterisk/frame.h"
00034 #include "asterisk/astobj2.h"
00035 #include "asterisk/utils.h"
00036 
00037 
00038 struct ast_format_cap {
00039    /* The capabilities structure is just an ao2 container of ast_formats */
00040    struct ao2_container *formats;
00041    struct ao2_iterator it;
00042    /*! TRUE if the formats container created without a lock. */
00043    int nolock;
00044 };
00045 
00046 /*! format exists within capabilities structure if it is identical to
00047  * another format, or if the format is a proper subset of another format. */
00048 static int cmp_cb(void *obj, void *arg, int flags)
00049 {
00050    struct ast_format *format1 = arg;
00051    struct ast_format *format2 = obj;
00052    enum ast_format_cmp_res res = ast_format_cmp(format1, format2);
00053 
00054    return ((res == AST_FORMAT_CMP_EQUAL) ||
00055          (res == AST_FORMAT_CMP_SUBSET)) ?
00056             CMP_MATCH | CMP_STOP :
00057             0;
00058 }
00059 
00060 static int hash_cb(const void *obj, const int flags)
00061 {
00062    const struct ast_format *format = obj;
00063    return format->id;
00064 }
00065 
00066 static struct ast_format_cap *cap_alloc_helper(int nolock)
00067 {
00068    struct ast_format_cap *cap = ast_calloc(1, sizeof(*cap));
00069 
00070    if (!cap) {
00071       return NULL;
00072    }
00073    cap->nolock = nolock;
00074    cap->formats = ao2_container_alloc_options(
00075       nolock ? AO2_ALLOC_OPT_LOCK_NOLOCK : AO2_ALLOC_OPT_LOCK_MUTEX,
00076       283, hash_cb, cmp_cb);
00077    if (!cap->formats) {
00078       ast_free(cap);
00079       return NULL;
00080    }
00081 
00082    return cap;
00083 }
00084 
00085 struct ast_format_cap *ast_format_cap_alloc_nolock(void)
00086 {
00087    return cap_alloc_helper(1);
00088 }
00089 
00090 struct ast_format_cap *ast_format_cap_alloc(void)
00091 {
00092    return cap_alloc_helper(0);
00093 }
00094 
00095 void *ast_format_cap_destroy(struct ast_format_cap *cap)
00096 {
00097    if (!cap) {
00098       return NULL;
00099    }
00100    ao2_ref(cap->formats, -1);
00101    ast_free(cap);
00102    return NULL;
00103 }
00104 
00105 void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *format)
00106 {
00107    struct ast_format *fnew;
00108 
00109    if (!format || !format->id) {
00110       return;
00111    }
00112    if (!(fnew = ao2_alloc(sizeof(struct ast_format), NULL))) {
00113       return;
00114    }
00115    ast_format_copy(fnew, format);
00116    ao2_link(cap->formats, fnew);
00117    ao2_ref(fnew, -1);
00118 }
00119 
00120 void ast_format_cap_add_all_by_type(struct ast_format_cap *cap, enum ast_format_type type)
00121 {
00122    int x;
00123    size_t f_len = 0;
00124    const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00125 
00126    for (x = 0; x < f_len; x++) {
00127       if (AST_FORMAT_GET_TYPE(f_list[x].format.id) == type) {
00128          ast_format_cap_add(cap, &f_list[x].format);
00129       }
00130    }
00131    ast_format_list_destroy(f_list);
00132 }
00133 
00134 void ast_format_cap_add_all(struct ast_format_cap *cap)
00135 {
00136    int x;
00137    size_t f_len = 0;
00138    const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00139 
00140    for (x = 0; x < f_len; x++) {
00141       ast_format_cap_add(cap, &f_list[x].format);
00142    }
00143    ast_format_list_destroy(f_list);
00144 }
00145 
00146 static int append_cb(void *obj, void *arg, int flag)
00147 {
00148    struct ast_format_cap *result = (struct ast_format_cap *) arg;
00149    struct ast_format *format = (struct ast_format *) obj;
00150 
00151    if (!ast_format_cap_iscompatible(result, format)) {
00152       ast_format_cap_add(result, format);
00153    }
00154 
00155    return 0;
00156 }
00157 
00158 void ast_format_cap_append(struct ast_format_cap *dst, const struct ast_format_cap *src)
00159 {
00160    ao2_callback(src->formats, OBJ_NODATA, append_cb, dst);
00161 }
00162 
00163 static int copy_cb(void *obj, void *arg, int flag)
00164 {
00165    struct ast_format_cap *result = (struct ast_format_cap *) arg;
00166    struct ast_format *format = (struct ast_format *) obj;
00167 
00168    ast_format_cap_add(result, format);
00169    return 0;
00170 }
00171 
00172 void ast_format_cap_copy(struct ast_format_cap *dst, const struct ast_format_cap *src)
00173 {
00174    ast_format_cap_remove_all(dst);
00175    ao2_callback(src->formats, OBJ_NODATA, copy_cb, dst);
00176 }
00177 
00178 struct ast_format_cap *ast_format_cap_dup(const struct ast_format_cap *cap)
00179 {
00180    struct ast_format_cap *dst;
00181    if (cap->nolock) {
00182       dst = ast_format_cap_alloc_nolock();
00183    } else {
00184       dst = ast_format_cap_alloc();
00185    }
00186    if (!dst) {
00187       return NULL;
00188    }
00189    ao2_callback(cap->formats, OBJ_NODATA, copy_cb, dst);
00190    return dst;
00191 }
00192 
00193 int ast_format_cap_is_empty(const struct ast_format_cap *cap)
00194 {
00195    if (!cap) {
00196       return 1;
00197    }
00198    return ao2_container_count(cap->formats) == 0 ? 1 : 0;
00199 }
00200 
00201 static int find_exact_cb(void *obj, void *arg, int flag)
00202 {
00203    struct ast_format *format1 = (struct ast_format *) arg;
00204    struct ast_format *format2 = (struct ast_format *) obj;
00205 
00206    return (ast_format_cmp(format1, format2) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH : 0;
00207 }
00208 
00209 int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
00210 {
00211    struct ast_format *fremove;
00212 
00213    fremove = ao2_callback(cap->formats, OBJ_POINTER | OBJ_UNLINK, find_exact_cb, format);
00214    if (fremove) {
00215       ao2_ref(fremove, -1);
00216       return 0;
00217    }
00218 
00219    return -1;
00220 }
00221 
00222 struct multiple_by_id_data {
00223    struct ast_format *format;
00224    int match_found;
00225 };
00226 
00227 static int multiple_by_id_cb(void *obj, void *arg, int flag)
00228 {
00229    struct multiple_by_id_data *data = arg;
00230    struct ast_format *format = obj;
00231    int res;
00232 
00233    res = (format->id == data->format->id) ? CMP_MATCH : 0;
00234    if (res) {
00235       data->match_found = 1;
00236    }
00237 
00238    return res;
00239 }
00240 
00241 int ast_format_cap_remove_byid(struct ast_format_cap *cap, enum ast_format_id id)
00242 {
00243    struct ast_format format = {
00244       .id = id,
00245    };
00246    struct multiple_by_id_data data = {
00247       .format = &format,
00248       .match_found = 0,
00249    };
00250 
00251    ao2_callback(cap->formats,
00252       OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
00253       multiple_by_id_cb,
00254       &data);
00255 
00256    /* match_found will be set if at least one item was removed */
00257    if (data.match_found) {
00258       return 0;
00259    }
00260 
00261    return -1;
00262 }
00263 
00264 static int multiple_by_type_cb(void *obj, void *arg, int flag)
00265 {
00266    int *type = arg;
00267    struct ast_format *format = obj;
00268    return ((AST_FORMAT_GET_TYPE(format->id)) == *type) ? CMP_MATCH : 0;
00269 }
00270 
00271 void ast_format_cap_remove_bytype(struct ast_format_cap *cap, enum ast_format_type type)
00272 {
00273    ao2_callback(cap->formats,
00274       OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE,
00275       multiple_by_type_cb,
00276       &type);
00277 }
00278 
00279 void ast_format_cap_remove_all(struct ast_format_cap *cap)
00280 {
00281    ao2_callback(cap->formats, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, NULL, NULL);
00282 }
00283 
00284 void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format)
00285 {
00286    ast_format_cap_remove_all(cap);
00287    ast_format_cap_add(cap, format);
00288 }
00289 
00290 int ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format, struct ast_format *result)
00291 {
00292    struct ast_format *f;
00293    struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
00294 
00295    f = ao2_find(tmp_cap->formats, format, OBJ_POINTER);
00296    if (f) {
00297       ast_format_copy(result, f);
00298       ao2_ref(f, -1);
00299       return 1;
00300    }
00301    ast_format_clear(result);
00302    return 0;
00303 }
00304 
00305 int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct ast_format *format)
00306 {
00307    struct ast_format *f;
00308    struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
00309 
00310    if (!tmp_cap) {
00311       return 0;
00312    }
00313 
00314    f = ao2_find(tmp_cap->formats, format, OBJ_POINTER);
00315    if (f) {
00316       ao2_ref(f, -1);
00317       return 1;
00318    }
00319 
00320    return 0;
00321 }
00322 
00323 struct byid_data {
00324    struct ast_format *result;
00325    enum ast_format_id id;
00326 };
00327 static int find_best_byid_cb(void *obj, void *arg, int flag)
00328 {
00329    struct ast_format *format = obj;
00330    struct byid_data *data = arg;
00331 
00332    if (data->id != format->id) {
00333       return 0;
00334    }
00335    if (!data->result->id || (ast_format_rate(data->result) < ast_format_rate(format))) {
00336       ast_format_copy(data->result, format);
00337    }
00338    return 0;
00339 }
00340 
00341 int ast_format_cap_best_byid(const struct ast_format_cap *cap, enum ast_format_id id, struct ast_format *result)
00342 {
00343    struct byid_data data;
00344    data.result = result;
00345    data.id = id;
00346 
00347    ast_format_clear(result);
00348    ao2_callback(cap->formats,
00349       OBJ_MULTIPLE | OBJ_NODATA,
00350       find_best_byid_cb,
00351       &data);
00352    return result->id ? 1 : 0;
00353 }
00354 
00355 /*! \internal
00356  * \brief this struct is just used for the ast_format_cap_joint function so we can provide
00357  * both a format and a result ast_format_cap structure as arguments to the find_joint_cb
00358  * ao2 callback function.
00359  */
00360 struct find_joint_data {
00361    /*! format to compare to for joint capabilities */
00362    struct ast_format *format;
00363    /*! if joint formmat exists with above format, add it to the result container */
00364    struct ast_format_cap *joint_cap;
00365    int joint_found;
00366 };
00367 
00368 static int find_joint_cb(void *obj, void *arg, int flag)
00369 {
00370    struct ast_format *format = obj;
00371    struct find_joint_data *data = arg;
00372 
00373    struct ast_format tmp = { 0, };
00374    if (!ast_format_joint(format, data->format, &tmp)) {
00375       if (data->joint_cap) {
00376          ast_format_cap_add(data->joint_cap, &tmp);
00377       }
00378       data->joint_found++;
00379    }
00380 
00381    return 0;
00382 }
00383 
00384 int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
00385 {
00386    struct ao2_iterator it;
00387    struct ast_format *tmp;
00388    struct find_joint_data data = {
00389       .joint_found = 0,
00390       .joint_cap = NULL,
00391    };
00392 
00393    it = ao2_iterator_init(cap1->formats, 0);
00394    while ((tmp = ao2_iterator_next(&it))) {
00395       data.format = tmp;
00396       ao2_callback(cap2->formats,
00397          OBJ_MULTIPLE | OBJ_NODATA,
00398          find_joint_cb,
00399          &data);
00400       ao2_ref(tmp, -1);
00401    }
00402    ao2_iterator_destroy(&it);
00403 
00404    return data.joint_found ? 1 : 0;
00405 }
00406 
00407 int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
00408 {
00409    struct ao2_iterator it;
00410    struct ast_format *tmp;
00411 
00412    if (ao2_container_count(cap1->formats) != ao2_container_count(cap2->formats)) {
00413       return 0; /* if they are not the same size, they are not identical */
00414    }
00415 
00416    it = ao2_iterator_init(cap1->formats, 0);
00417    while ((tmp = ao2_iterator_next(&it))) {
00418       if (!ast_format_cap_iscompatible(cap2, tmp)) {
00419          ao2_ref(tmp, -1);
00420          ao2_iterator_destroy(&it);
00421          return 0;
00422       }
00423       ao2_ref(tmp, -1);
00424    }
00425    ao2_iterator_destroy(&it);
00426 
00427    return 1;
00428 }
00429 
00430 struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
00431 {
00432    struct ao2_iterator it;
00433    struct ast_format_cap *result = ast_format_cap_alloc_nolock();
00434    struct ast_format *tmp;
00435    struct find_joint_data data = {
00436       .joint_found = 0,
00437       .joint_cap = result,
00438    };
00439    if (!result) {
00440       return NULL;
00441    }
00442 
00443    it = ao2_iterator_init(cap1->formats, 0);
00444    while ((tmp = ao2_iterator_next(&it))) {
00445       data.format = tmp;
00446       ao2_callback(cap2->formats,
00447          OBJ_MULTIPLE | OBJ_NODATA,
00448          find_joint_cb,
00449          &data);
00450       ao2_ref(tmp, -1);
00451    }
00452    ao2_iterator_destroy(&it);
00453 
00454    if (ao2_container_count(result->formats)) {
00455       return result;
00456    }
00457 
00458    result = ast_format_cap_destroy(result);
00459    return NULL;
00460 }
00461 
00462 static int joint_copy_helper(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result, int append)
00463 {
00464    struct ao2_iterator it;
00465    struct ast_format *tmp;
00466    struct find_joint_data data = {
00467       .joint_cap = result,
00468       .joint_found = 0,
00469    };
00470    if (!append) {
00471       ast_format_cap_remove_all(result);
00472    }
00473    it = ao2_iterator_init(cap1->formats, 0);
00474    while ((tmp = ao2_iterator_next(&it))) {
00475       data.format = tmp;
00476       ao2_callback(cap2->formats,
00477          OBJ_MULTIPLE | OBJ_NODATA,
00478          find_joint_cb,
00479          &data);
00480       ao2_ref(tmp, -1);
00481    }
00482    ao2_iterator_destroy(&it);
00483 
00484    return ao2_container_count(result->formats) ? 1 : 0;
00485 }
00486 
00487 int ast_format_cap_joint_append(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
00488 {
00489    return joint_copy_helper(cap1, cap2, result, 1);
00490 }
00491 
00492 int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
00493 {
00494    return joint_copy_helper(cap1, cap2, result, 0);
00495 }
00496 
00497 struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype)
00498 {
00499    struct ao2_iterator it;
00500    struct ast_format_cap *result = ast_format_cap_alloc_nolock();
00501    struct ast_format *tmp;
00502 
00503    if (!result) {
00504       return NULL;
00505    }
00506 
00507    /* for each format in cap1, see if that format is
00508     * compatible with cap2. If so copy it to the result */
00509    it = ao2_iterator_init(cap->formats, 0);
00510    while ((tmp = ao2_iterator_next(&it))) {
00511       if (AST_FORMAT_GET_TYPE(tmp->id) == ftype) {
00512          /* copy format */
00513          ast_format_cap_add(result, tmp);
00514       }
00515       ao2_ref(tmp, -1);
00516    }
00517    ao2_iterator_destroy(&it);
00518 
00519    if (ao2_container_count(result->formats)) {
00520       return result;
00521    }
00522    result = ast_format_cap_destroy(result);
00523 
00524    return NULL;
00525 }
00526 
00527 
00528 int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type)
00529 {
00530    struct ao2_iterator it;
00531    struct ast_format *tmp;
00532 
00533    it = ao2_iterator_init(cap->formats, 0);
00534    while ((tmp = ao2_iterator_next(&it))) {
00535       if (AST_FORMAT_GET_TYPE(tmp->id) == type) {
00536          ao2_ref(tmp, -1);
00537          ao2_iterator_destroy(&it);
00538          return 1;
00539       }
00540       ao2_ref(tmp, -1);
00541    }
00542    ao2_iterator_destroy(&it);
00543 
00544    return 0;
00545 }
00546 
00547 void ast_format_cap_iter_start(struct ast_format_cap *cap)
00548 {
00549    /* We can unconditionally lock even if the container has no lock. */
00550    ao2_lock(cap->formats);
00551    cap->it = ao2_iterator_init(cap->formats, AO2_ITERATOR_DONTLOCK);
00552 }
00553 
00554 void ast_format_cap_iter_end(struct ast_format_cap *cap)
00555 {
00556    ao2_iterator_destroy(&cap->it);
00557    /* We can unconditionally unlock even if the container has no lock. */
00558    ao2_unlock(cap->formats);
00559 }
00560 
00561 int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format)
00562 {
00563    struct ast_format *tmp = ao2_iterator_next(&cap->it);
00564 
00565    if (!tmp) {
00566       return -1;
00567    }
00568    ast_format_copy(format, tmp);
00569    ao2_ref(tmp, -1);
00570 
00571    return 0;
00572 }
00573 
00574 char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap)
00575 {
00576    int x;
00577    unsigned len;
00578    char *start, *end = buf;
00579    struct ast_format tmp_fmt;
00580    size_t f_len;
00581    const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00582 
00583    if (!size) {
00584       f_list = ast_format_list_destroy(f_list);
00585       return buf;
00586    }
00587    snprintf(end, size, "(");
00588    len = strlen(end);
00589    end += len;
00590    size -= len;
00591    start = end;
00592    for (x = 0; x < f_len; x++) {
00593       ast_format_copy(&tmp_fmt, &f_list[x].format);
00594       if (ast_format_cap_iscompatible(cap, &tmp_fmt)) {
00595          snprintf(end, size, "%s|", f_list[x].name);
00596          len = strlen(end);
00597          end += len;
00598          size -= len;
00599       }
00600    }
00601    if (start == end) {
00602       ast_copy_string(start, "nothing)", size);
00603    } else if (size > 1) {
00604       *(end - 1) = ')';
00605    }
00606    f_list = ast_format_list_destroy(f_list);
00607    return buf;
00608 }
00609 
00610 uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap)
00611 {
00612    uint64_t res = 0;
00613    struct ao2_iterator it;
00614    struct ast_format *tmp;
00615 
00616    it = ao2_iterator_init(cap->formats, 0);
00617    while ((tmp = ao2_iterator_next(&it))) {
00618       res |= ast_format_to_old_bitfield(tmp);
00619       ao2_ref(tmp, -1);
00620    }
00621    ao2_iterator_destroy(&it);
00622    return res;
00623 }
00624 
00625 void ast_format_cap_from_old_bitfield(struct ast_format_cap *dst, uint64_t src)
00626 {
00627    uint64_t tmp = 0;
00628    int x;
00629    struct ast_format tmp_format = { 0, };
00630 
00631    ast_format_cap_remove_all(dst);
00632    for (x = 0; x < 64; x++) {
00633       tmp = (1ULL << x);
00634       if (tmp & src) {
00635          ast_format_cap_add(dst, ast_format_from_old_bitfield(&tmp_format, tmp));
00636       }
00637    }
00638 }

Generated on Wed May 16 06:33:33 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6