format_cap.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2014, Digium, Inc.
00005  *
00006  * Joshua Colp <jcolp@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 /*! \file
00020  *
00021  * \brief Format Capabilities API
00022  *
00023  * \author Joshua Colp <jcolp@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: 432972 $")
00033 
00034 #include "asterisk/logger.h"
00035 #include "asterisk/format.h"
00036 #include "asterisk/format_cap.h"
00037 #include "asterisk/format_cache.h"
00038 #include "asterisk/codec.h"
00039 #include "asterisk/astobj2.h"
00040 #include "asterisk/strings.h"
00041 #include "asterisk/vector.h"
00042 #include "asterisk/linkedlists.h"
00043 #include "asterisk/utils.h"
00044 
00045 /*! \brief Structure used for capability formats, adds framing */
00046 struct format_cap_framed {
00047    /*! \brief A pointer to the format */
00048    struct ast_format *format;
00049    /*! \brief The format framing size */
00050    unsigned int framing;
00051    /*! \brief Linked list information */
00052    AST_LIST_ENTRY(format_cap_framed) entry;
00053 };
00054 
00055 /*! \brief Format capabilities structure, holds formats + preference order + etc */
00056 struct ast_format_cap {
00057    /*! \brief Vector of formats, indexed using the codec identifier */
00058    AST_VECTOR(, struct format_cap_framed_list) formats;
00059    /*! \brief Vector of formats, added in preference order */
00060    AST_VECTOR(, struct format_cap_framed *) preference_order;
00061    /*! \brief Global framing size, applies to all formats if no framing present on format */
00062    unsigned int framing;
00063 };
00064 
00065 /*! \brief Linked list for formats */
00066 AST_LIST_HEAD_NOLOCK(format_cap_framed_list, format_cap_framed);
00067 
00068 /*! \brief Dummy empty list for when we are inserting a new list */
00069 static const struct format_cap_framed_list format_cap_framed_list_empty = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00070 
00071 /*! \brief Destructor for format capabilities structure */
00072 static void format_cap_destroy(void *obj)
00073 {
00074    struct ast_format_cap *cap = obj;
00075    int idx;
00076 
00077    for (idx = 0; idx < AST_VECTOR_SIZE(&cap->formats); idx++) {
00078       struct format_cap_framed_list *list = AST_VECTOR_GET_ADDR(&cap->formats, idx);
00079       struct format_cap_framed *framed;
00080 
00081       while ((framed = AST_LIST_REMOVE_HEAD(list, entry))) {
00082          ao2_ref(framed, -1);
00083       }
00084    }
00085    AST_VECTOR_FREE(&cap->formats);
00086 
00087    for (idx = 0; idx < AST_VECTOR_SIZE(&cap->preference_order); idx++) {
00088       struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, idx);
00089 
00090       /* This will always be non-null, unlike formats */
00091       ao2_ref(framed, -1);
00092    }
00093    AST_VECTOR_FREE(&cap->preference_order);
00094 }
00095 
00096 static inline void format_cap_init(struct ast_format_cap *cap, enum ast_format_cap_flags flags)
00097 {
00098    AST_VECTOR_INIT(&cap->formats, 0);
00099 
00100    /* TODO: Look at common usage of this and determine a good starting point */
00101    AST_VECTOR_INIT(&cap->preference_order, 5);
00102 
00103    cap->framing = UINT_MAX;
00104 }
00105 
00106 struct ast_format_cap *__ast_format_cap_alloc(enum ast_format_cap_flags flags)
00107 {
00108    struct ast_format_cap *cap;
00109 
00110    cap = ao2_alloc_options(sizeof(*cap), format_cap_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
00111    if (!cap) {
00112       return NULL;
00113    }
00114 
00115    format_cap_init(cap, flags);
00116 
00117    return cap;
00118 }
00119 
00120 struct ast_format_cap *__ast_format_cap_alloc_debug(enum ast_format_cap_flags flags, const char *tag, const char *file, int line, const char *func)
00121 {
00122    struct ast_format_cap *cap;
00123 
00124    cap = __ao2_alloc_debug(sizeof(*cap), format_cap_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(tag, "ast_format_cap_alloc"), file, line, func, 1);
00125    if (!cap) {
00126       return NULL;
00127    }
00128 
00129    format_cap_init(cap, flags);
00130 
00131    return cap;
00132 }
00133 
00134 void ast_format_cap_set_framing(struct ast_format_cap *cap, unsigned int framing)
00135 {
00136    cap->framing = framing;
00137 }
00138 
00139 /*! \brief Destructor for format capabilities framed structure */
00140 static void format_cap_framed_destroy(void *obj)
00141 {
00142    struct format_cap_framed *framed = obj;
00143 
00144    ao2_cleanup(framed->format);
00145 }
00146 
00147 static inline int format_cap_framed_init(struct format_cap_framed *framed, struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
00148 {
00149    struct format_cap_framed_list *list;
00150 
00151    framed->framing = framing;
00152 
00153    if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
00154       if (AST_VECTOR_INSERT(&cap->formats, ast_format_get_codec_id(format), format_cap_framed_list_empty)) {
00155          ao2_ref(framed, -1);
00156          return -1;
00157       }
00158    }
00159    list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
00160 
00161    /* Order doesn't matter for formats, so insert at the head for performance reasons */
00162    ao2_ref(framed, +1);
00163    AST_LIST_INSERT_HEAD(list, framed, entry);
00164 
00165    /* This takes the allocation reference */
00166    AST_VECTOR_APPEND(&cap->preference_order, framed);
00167 
00168    cap->framing = MIN(cap->framing, framing ? framing : ast_format_get_default_ms(format));
00169 
00170    return 0;
00171 }
00172 
00173 /*! \internal \brief Determine if \c format is in \c cap */
00174 static int format_in_format_cap(struct ast_format_cap *cap, struct ast_format *format)
00175 {
00176    struct format_cap_framed *framed;
00177    int i;
00178 
00179    for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
00180       framed = AST_VECTOR_GET(&cap->preference_order, i);
00181 
00182       if (ast_format_get_codec_id(format) == ast_format_get_codec_id(framed->format)) {
00183          return 1;
00184       }
00185    }
00186 
00187    return 0;
00188 }
00189 
00190 int __ast_format_cap_append(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
00191 {
00192    struct format_cap_framed *framed;
00193 
00194    ast_assert(format != NULL);
00195 
00196    if (format_in_format_cap(cap, format)) {
00197       return 0;
00198    }
00199 
00200    framed = ao2_alloc_options(sizeof(*framed), format_cap_framed_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
00201    if (!framed) {
00202       return -1;
00203    }
00204    framed->format = ao2_bump(format);
00205 
00206    return format_cap_framed_init(framed, cap, format, framing);
00207 }
00208 
00209 int __ast_format_cap_append_debug(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing, const char *tag, const char *file, int line, const char *func)
00210 {
00211    struct format_cap_framed *framed;
00212 
00213    ast_assert(format != NULL);
00214 
00215    if (format_in_format_cap(cap, format)) {
00216       return 0;
00217    }
00218 
00219    framed = ao2_alloc_options(sizeof(*framed), format_cap_framed_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
00220    if (!framed) {
00221       return -1;
00222    }
00223 
00224    __ao2_ref_debug(format, +1, S_OR(tag, "ast_format_cap_append"), file, line, func);
00225    framed->format = format;
00226 
00227    return format_cap_framed_init(framed, cap, format, framing);
00228 }
00229 
00230 int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_type type)
00231 {
00232    int id;
00233 
00234    for (id = 1; id < ast_codec_get_max(); ++id) {
00235       struct ast_codec *codec = ast_codec_get_by_id(id);
00236       struct ast_format *format;
00237       int res;
00238 
00239       if (!codec) {
00240          continue;
00241       }
00242 
00243       if ((type != AST_MEDIA_TYPE_UNKNOWN) && codec->type != type) {
00244          ao2_ref(codec, -1);
00245          continue;
00246       }
00247 
00248       format = ast_format_create(codec);
00249       ao2_ref(codec, -1);
00250 
00251       if (!format) {
00252          return -1;
00253       }
00254 
00255       /* Use the global framing or default framing of the codec */
00256       res = ast_format_cap_append(cap, format, 0);
00257       ao2_ref(format, -1);
00258 
00259       if (res) {
00260          return -1;
00261       }
00262    }
00263 
00264    return 0;
00265 }
00266 
00267 int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src,
00268    enum ast_media_type type)
00269 {
00270    int idx, res = 0;
00271 
00272    for (idx = 0; (idx < AST_VECTOR_SIZE(&src->preference_order)) && !res; ++idx) {
00273       struct format_cap_framed *framed = AST_VECTOR_GET(&src->preference_order, idx);
00274 
00275       if (type == AST_MEDIA_TYPE_UNKNOWN || ast_format_get_type(framed->format) == type) {
00276          res = ast_format_cap_append(dst, framed->format, framed->framing);
00277       }
00278    }
00279 
00280    return res;
00281 }
00282 
00283 static int format_cap_replace(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
00284 {
00285    struct format_cap_framed *framed;
00286    int i;
00287 
00288    ast_assert(format != NULL);
00289 
00290    for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
00291       framed = AST_VECTOR_GET(&cap->preference_order, i);
00292 
00293       if (ast_format_get_codec_id(format) == ast_format_get_codec_id(framed->format)) {
00294          ao2_t_replace(framed->format, format, "replacing with new format");
00295          framed->framing = framing;
00296          return 0;
00297       }
00298    }
00299 
00300    return -1;
00301 }
00302 
00303 void ast_format_cap_replace_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src,
00304    enum ast_media_type type)
00305 {
00306    int idx;
00307 
00308    for (idx = 0; (idx < AST_VECTOR_SIZE(&src->preference_order)); ++idx) {
00309       struct format_cap_framed *framed = AST_VECTOR_GET(&src->preference_order, idx);
00310 
00311       if (type == AST_MEDIA_TYPE_UNKNOWN || ast_format_get_type(framed->format) == type) {
00312          format_cap_replace(dst, framed->format, framed->framing);
00313       }
00314    }
00315 }
00316 
00317 int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing)
00318 {
00319    int res = 0, all = 0, iter_allowing;
00320    char *parse = NULL, *this = NULL, *psize = NULL;
00321 
00322    if (!allowing && ast_strlen_zero(list)) {
00323       return 0;
00324    }
00325 
00326    parse = ast_strdupa(list);
00327    while ((this = strsep(&parse, ","))) {
00328       int framems = 0;
00329       struct ast_format *format = NULL;
00330 
00331       iter_allowing = allowing;
00332       if (*this == '!') {
00333          this++;
00334          iter_allowing = !allowing;
00335       }
00336       if ((psize = strrchr(this, ':'))) {
00337          *psize++ = '\0';
00338          ast_debug(1, "Packetization for codec: %s is %s\n", this, psize);
00339          if (!sscanf(psize, "%30d", &framems) || (framems < 0)) {
00340             framems = 0;
00341             res = -1;
00342             ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this);
00343             continue;
00344          }
00345       }
00346       all = strcasecmp(this, "all") ? 0 : 1;
00347 
00348       if (!all && !(format = ast_format_cache_get(this))) {
00349          ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", iter_allowing ? "allow" : "disallow", this);
00350          res = -1;
00351          continue;
00352       }
00353 
00354       if (cap) {
00355          if (iter_allowing) {
00356             if (all) {
00357                ast_format_cap_append_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
00358             } else {
00359                ast_format_cap_append(cap, format, framems);
00360             }
00361          } else {
00362             if (all) {
00363                ast_format_cap_remove_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
00364             } else {
00365                ast_format_cap_remove(cap, format);
00366             }
00367          }
00368       }
00369 
00370       ao2_cleanup(format);
00371    }
00372    return res;
00373 }
00374 
00375 size_t ast_format_cap_count(const struct ast_format_cap *cap)
00376 {
00377    return AST_VECTOR_SIZE(&cap->preference_order);
00378 }
00379 
00380 struct ast_format *ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
00381 {
00382    struct format_cap_framed *framed;
00383 
00384    ast_assert(position < AST_VECTOR_SIZE(&cap->preference_order));
00385 
00386    if (position >= AST_VECTOR_SIZE(&cap->preference_order)) {
00387       return NULL;
00388    }
00389 
00390    framed = AST_VECTOR_GET(&cap->preference_order, position);
00391 
00392    ast_assert(framed->format != ast_format_none);
00393    ao2_ref(framed->format, +1);
00394    return framed->format;
00395 }
00396 
00397 struct ast_format *ast_format_cap_get_best_by_type(const struct ast_format_cap *cap, enum ast_media_type type)
00398 {
00399    int i;
00400 
00401    if (type == AST_MEDIA_TYPE_UNKNOWN) {
00402       return ast_format_cap_get_format(cap, 0);
00403    }
00404 
00405    for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
00406       struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, i);
00407 
00408       if (ast_format_get_type(framed->format) == type) {
00409          ao2_ref(framed->format, +1);
00410          ast_assert(framed->format != ast_format_none);
00411          return framed->format;
00412       }
00413    }
00414 
00415    return NULL;
00416 }
00417 
00418 unsigned int ast_format_cap_get_framing(const struct ast_format_cap *cap)
00419 {
00420    return (cap->framing != UINT_MAX) ? cap->framing : 0;
00421 }
00422 
00423 unsigned int ast_format_cap_get_format_framing(const struct ast_format_cap *cap, const struct ast_format *format)
00424 {
00425    unsigned int framing;
00426    struct format_cap_framed_list *list;
00427    struct format_cap_framed *framed, *result = NULL;
00428 
00429    if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
00430       return 0;
00431    }
00432 
00433    framing = cap->framing != UINT_MAX ? cap->framing : ast_format_get_default_ms(format);
00434    list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
00435 
00436    AST_LIST_TRAVERSE(list, framed, entry) {
00437       enum ast_format_cmp_res res = ast_format_cmp(format, framed->format);
00438 
00439       if (res == AST_FORMAT_CMP_NOT_EQUAL) {
00440          continue;
00441       }
00442 
00443       result = framed;
00444 
00445       if (res == AST_FORMAT_CMP_EQUAL) {
00446          break;
00447       }
00448    }
00449 
00450    if (result && result->framing) {
00451       framing = result->framing;
00452    }
00453 
00454    return framing;
00455 }
00456 
00457 /*!
00458  * \brief format_cap_framed comparator for AST_VECTOR_REMOVE_CMP_ORDERED()
00459  *
00460  * \param elem Element to compare against
00461  * \param value Value to compare with the vector element.
00462  *
00463  * \return 0 if element does not match.
00464  * \return Non-zero if element matches.
00465  */
00466 #define FORMAT_CAP_FRAMED_ELEM_CMP(elem, value) ((elem)->format == (value))
00467 
00468 /*!
00469  * \brief format_cap_framed vector element cleanup.
00470  *
00471  * \param elem Element to cleanup
00472  *
00473  * \return Nothing
00474  */
00475 #define FORMAT_CAP_FRAMED_ELEM_CLEANUP(elem)  ao2_cleanup((elem))
00476 
00477 int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
00478 {
00479    struct format_cap_framed_list *list;
00480    struct format_cap_framed *framed;
00481 
00482    ast_assert(format != NULL);
00483 
00484    if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
00485       return -1;
00486    }
00487 
00488    list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
00489 
00490    AST_LIST_TRAVERSE_SAFE_BEGIN(list, framed, entry) {
00491       if (!FORMAT_CAP_FRAMED_ELEM_CMP(framed, format)) {
00492          continue;
00493       }
00494 
00495       AST_LIST_REMOVE_CURRENT(entry);
00496       FORMAT_CAP_FRAMED_ELEM_CLEANUP(framed);
00497       break;
00498    }
00499    AST_LIST_TRAVERSE_SAFE_END;
00500 
00501    return AST_VECTOR_REMOVE_CMP_ORDERED(&cap->preference_order, format,
00502       FORMAT_CAP_FRAMED_ELEM_CMP, FORMAT_CAP_FRAMED_ELEM_CLEANUP);
00503 }
00504 
00505 void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type)
00506 {
00507    int idx;
00508 
00509    for (idx = 0; idx < AST_VECTOR_SIZE(&cap->formats); ++idx) {
00510       struct format_cap_framed_list *list = AST_VECTOR_GET_ADDR(&cap->formats, idx);
00511       struct format_cap_framed *framed;
00512 
00513       AST_LIST_TRAVERSE_SAFE_BEGIN(list, framed, entry) {
00514          if ((type != AST_MEDIA_TYPE_UNKNOWN) &&
00515             ast_format_get_type(framed->format) != type) {
00516             continue;
00517          }
00518 
00519          AST_LIST_REMOVE_CURRENT(entry);
00520          AST_VECTOR_REMOVE_CMP_ORDERED(&cap->preference_order, framed->format,
00521             FORMAT_CAP_FRAMED_ELEM_CMP, FORMAT_CAP_FRAMED_ELEM_CLEANUP);
00522          ao2_ref(framed, -1);
00523       }
00524       AST_LIST_TRAVERSE_SAFE_END;
00525    }
00526 }
00527 
00528 struct ast_format *ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format)
00529 {
00530    struct format_cap_framed_list *list;
00531    struct format_cap_framed *framed;
00532    struct ast_format *result = NULL;
00533 
00534    ast_assert(format != NULL);
00535 
00536    if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
00537       return NULL;
00538    }
00539 
00540    list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
00541 
00542    AST_LIST_TRAVERSE(list, framed, entry) {
00543       enum ast_format_cmp_res res = ast_format_cmp(format, framed->format);
00544 
00545       if (res == AST_FORMAT_CMP_NOT_EQUAL) {
00546          continue;
00547       }
00548 
00549       /* Replace any current result, this one will also be a subset OR an exact match */
00550       ao2_cleanup(result);
00551 
00552       result = ast_format_joint(format, framed->format);
00553 
00554       /* If it's a match we can do no better so return asap */
00555       if (res == AST_FORMAT_CMP_EQUAL) {
00556          break;
00557       }
00558    }
00559 
00560    return result;
00561 }
00562 
00563 enum ast_format_cmp_res ast_format_cap_iscompatible_format(const struct ast_format_cap *cap,
00564    const struct ast_format *format)
00565 {
00566    enum ast_format_cmp_res res = AST_FORMAT_CMP_NOT_EQUAL;
00567    struct format_cap_framed_list *list;
00568    struct format_cap_framed *framed;
00569 
00570    ast_assert(format != NULL);
00571 
00572    if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
00573       return AST_FORMAT_CMP_NOT_EQUAL;
00574    }
00575 
00576    list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
00577 
00578    AST_LIST_TRAVERSE(list, framed, entry) {
00579       enum ast_format_cmp_res cmp = ast_format_cmp(format, framed->format);
00580 
00581       if (cmp == AST_FORMAT_CMP_NOT_EQUAL) {
00582          continue;
00583       }
00584 
00585       res = cmp;
00586 
00587       if (res == AST_FORMAT_CMP_EQUAL) {
00588          break;
00589       }
00590    }
00591 
00592    return res;
00593 }
00594 
00595 int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_media_type type)
00596 {
00597    int idx;
00598 
00599    for (idx = 0; idx < AST_VECTOR_SIZE(&cap->preference_order); ++idx) {
00600       struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, idx);
00601 
00602       if (ast_format_get_type(framed->format) == type) {
00603          return 1;
00604       }
00605    }
00606 
00607    return 0;
00608 }
00609 
00610 int ast_format_cap_get_compatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2,
00611    struct ast_format_cap *result)
00612 {
00613    int idx, res = 0;
00614 
00615    for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
00616       struct format_cap_framed *framed = AST_VECTOR_GET(&cap1->preference_order, idx);
00617       struct ast_format *format;
00618 
00619       format = ast_format_cap_get_compatible_format(cap2, framed->format);
00620       if (!format) {
00621          continue;
00622       }
00623 
00624       res = ast_format_cap_append(result, format, framed->framing);
00625       ao2_ref(format, -1);
00626 
00627       if (res) {
00628          break;
00629       }
00630    }
00631 
00632    return res;
00633 }
00634 
00635 int ast_format_cap_iscompatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
00636 {
00637    int idx;
00638 
00639    for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
00640       struct format_cap_framed *framed = AST_VECTOR_GET(&cap1->preference_order, idx);
00641 
00642       if (ast_format_cap_iscompatible_format(cap2, framed->format) != AST_FORMAT_CMP_NOT_EQUAL) {
00643          return 1;
00644       }
00645    }
00646 
00647    return 0;
00648 }
00649 
00650 static int internal_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
00651 {
00652    int idx;
00653    struct ast_format *tmp;
00654 
00655    for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
00656       tmp = ast_format_cap_get_format(cap1, idx);
00657 
00658       if (ast_format_cap_iscompatible_format(cap2, tmp) != AST_FORMAT_CMP_EQUAL) {
00659          ao2_ref(tmp, -1);
00660          return 0;
00661       }
00662 
00663       ao2_ref(tmp, -1);
00664    }
00665 
00666    return 1;
00667 }
00668 
00669 int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
00670 {
00671    if (AST_VECTOR_SIZE(&cap1->preference_order) != AST_VECTOR_SIZE(&cap2->preference_order)) {
00672       return 0; /* if they are not the same size, they are not identical */
00673    }
00674 
00675    if (!internal_format_cap_identical(cap1, cap2)) {
00676       return 0;
00677    }
00678 
00679    return internal_format_cap_identical(cap2, cap1);
00680 }
00681 
00682 const char *ast_format_cap_get_names(struct ast_format_cap *cap, struct ast_str **buf)
00683 {
00684    int i;
00685 
00686    ast_str_set(buf, 0, "(");
00687 
00688    if (!AST_VECTOR_SIZE(&cap->preference_order)) {
00689       ast_str_append(buf, 0, "nothing)");
00690       return ast_str_buffer(*buf);
00691    }
00692 
00693    for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); ++i) {
00694       int res;
00695       struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, i);
00696 
00697       res = ast_str_append(buf, 0, "%s%s", ast_format_get_name(framed->format),
00698          i < AST_VECTOR_SIZE(&cap->preference_order) - 1 ? "|" : "");
00699       if (res < 0) {
00700          break;
00701       }
00702    }
00703    ast_str_append(buf, 0, ")");
00704 
00705    return ast_str_buffer(*buf);
00706 }
00707 
00708 int ast_format_cap_empty(struct ast_format_cap *cap)
00709 {
00710    int count = ast_format_cap_count(cap);
00711 
00712    if (count > 1) {
00713       return 0;
00714    }
00715 
00716    if (count == 0 || AST_VECTOR_GET(&cap->preference_order, 0)->format == ast_format_none) {
00717       return 1;
00718    }
00719 
00720    return 0;
00721 }

Generated on Thu Apr 16 06:27:34 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6