Sat Apr 26 2014 22:01:36

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