Sat Jul 12 2014 17:18:33

Asterisk developer's documentation


format.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  * Mark Spencer <markster@digium.com>
00008  *
00009  * See http://www.asterisk.org for more information about
00010  * the Asterisk project. Please do not directly contact
00011  * any of the maintainers of this project for assistance;
00012  * the project provides a web site, mailing lists and IRC
00013  * channels for your use.
00014  *
00015  * This program is free software, distributed under the terms of
00016  * the GNU General Public License Version 2. See the LICENSE file
00017  * at the top of the source tree.
00018  */
00019 
00020 /*!
00021  * \file
00022  * \brief Format API
00023  *
00024  * \author David Vossel <dvossel@digium.com>
00025  * \author Mark Spencer <markster@digium.com>
00026  */
00027 
00028 /*** MODULEINFO
00029    <support_level>core</support_level>
00030  ***/
00031 
00032 #include "asterisk.h"
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 415728 $");
00035 
00036 #include "asterisk/_private.h"
00037 #include "asterisk/format.h"
00038 #include "asterisk/astobj2.h"
00039 #include "asterisk/lock.h"
00040 #include "asterisk/frame.h"
00041 #include "asterisk/utils.h"
00042 #include "asterisk/cli.h"
00043 #include "asterisk/rtp_engine.h"
00044 #include "asterisk/config.h"
00045 
00046 #define FORMAT_CONFIG "codecs.conf"
00047 
00048 /*!
00049  * \brief Container for all the format attribute interfaces.
00050  * \note This container uses RWLOCKs instead of MUTEX locks.                                                             .
00051  * \note An ao2 container was chosen for fast lookup.
00052  */
00053 static struct ao2_container *interfaces;
00054 
00055 /*! a wrapper is used put interfaces into the ao2 container. */
00056 struct interface_ao2_wrapper {
00057    enum ast_format_id id;
00058    const struct ast_format_attr_interface *interface;
00059 };
00060 
00061 /*! \brief Format List container, This container is never directly accessed outside
00062  * of this file, and It only exists for building the format_list_array. */
00063 static struct ao2_container *format_list;
00064 /*! \brief Format List array is a read only array protected by a read write lock.
00065  * This array may be used outside this file with the use of reference counting to
00066  * guarantee safety for access by multiple threads. */
00067 static struct ast_format_list *format_list_array;
00068 static size_t format_list_array_len = 0;
00069 /*! \brief Locks the format list array so a reference can be taken safely. */
00070 static ast_rwlock_t format_list_array_lock;
00071 
00072 static int interface_cmp_cb(void *obj, void *arg, int flags)
00073 {
00074    struct interface_ao2_wrapper *wrapper1 = obj;
00075    struct interface_ao2_wrapper *wrapper2 = arg;
00076 
00077    return (wrapper2->id == wrapper1->id) ? CMP_MATCH | CMP_STOP : 0;
00078 }
00079 
00080 static int interface_hash_cb(const void *obj, const int flags)
00081 {
00082    const struct interface_ao2_wrapper *wrapper = obj;
00083    return wrapper->id;
00084 }
00085 
00086 void ast_format_copy(struct ast_format *dst, const struct ast_format *src)
00087 {
00088    *dst = *src;
00089 }
00090 
00091 void ast_format_set_video_mark(struct ast_format *format)
00092 {
00093    format->fattr.rtp_marker_bit = 1;
00094 }
00095 
00096 int ast_format_get_video_mark(const struct ast_format *format)
00097 {
00098    return format->fattr.rtp_marker_bit;
00099 }
00100 
00101 static struct interface_ao2_wrapper *find_interface(const struct ast_format *format)
00102 {
00103    struct interface_ao2_wrapper tmp_wrapper = {
00104       .id = format->id,
00105    };
00106 
00107    return ao2_find(interfaces, &tmp_wrapper, OBJ_POINTER);
00108 }
00109 
00110 static int has_interface(const struct ast_format *format)
00111 {
00112    struct interface_ao2_wrapper *wrapper;
00113 
00114    wrapper = find_interface(format);
00115    if (!wrapper) {
00116       return 0;
00117    }
00118    ao2_ref(wrapper, -1);
00119    return 1;
00120 }
00121 
00122 int ast_format_sdp_parse(struct ast_format *format, const char *attributes)
00123 {
00124    struct interface_ao2_wrapper *wrapper;
00125    int res;
00126 
00127    if (!(wrapper = find_interface(format))) {
00128       return 0;
00129    }
00130 
00131    ao2_rdlock(wrapper);
00132    if (!wrapper->interface || !wrapper->interface->format_attr_sdp_parse) {
00133       ao2_unlock(wrapper);
00134       ao2_ref(wrapper, -1);
00135       return 0;
00136    }
00137 
00138    res = wrapper->interface->format_attr_sdp_parse(&format->fattr, attributes);
00139 
00140    ao2_unlock(wrapper);
00141    ao2_ref(wrapper, -1);
00142 
00143    return res;
00144 }
00145 
00146 void ast_format_sdp_generate(const struct ast_format *format, unsigned int payload, struct ast_str **str)
00147 {
00148    struct interface_ao2_wrapper *wrapper;
00149 
00150    if (!(wrapper = find_interface(format))) {
00151       return;
00152    }
00153 
00154    ao2_rdlock(wrapper);
00155    if (!wrapper->interface || !wrapper->interface->format_attr_sdp_generate) {
00156       ao2_unlock(wrapper);
00157       ao2_ref(wrapper, -1);
00158       return;
00159    }
00160 
00161    wrapper->interface->format_attr_sdp_generate(&format->fattr, payload, str);
00162 
00163    ao2_unlock(wrapper);
00164    ao2_ref(wrapper, -1);
00165 }
00166 
00167 /*! \internal
00168  * \brief set format attributes using an interface
00169  */
00170 static int format_set_helper(struct ast_format *format, va_list ap)
00171 {
00172    struct interface_ao2_wrapper *wrapper;
00173 
00174    if (!(wrapper = find_interface(format))) {
00175       ast_log(LOG_WARNING, "Could not find format interface to set.\n");
00176       return -1;
00177    }
00178 
00179    ao2_rdlock(wrapper);
00180    if (!wrapper->interface || !wrapper->interface->format_attr_set) {
00181       ao2_unlock(wrapper);
00182       ao2_ref(wrapper, -1);
00183       return -1;
00184    }
00185 
00186    wrapper->interface->format_attr_set(&format->fattr, ap);
00187 
00188    ao2_unlock(wrapper);
00189    ao2_ref(wrapper, -1);
00190 
00191    return 0;
00192 }
00193 
00194 struct ast_format *ast_format_append(struct ast_format *format, ... )
00195 {
00196    va_list ap;
00197    va_start(ap, format);
00198    format_set_helper(format, ap);
00199    va_end(ap);
00200 
00201    return format;
00202 }
00203 
00204 struct ast_format *ast_format_set(struct ast_format *format, enum ast_format_id id, int set_attributes, ... )
00205 {
00206    /* initialize the structure before setting it. */
00207    ast_format_clear(format);
00208 
00209    format->id = id;
00210 
00211    if (set_attributes) {
00212       va_list ap;
00213       va_start(ap, set_attributes);
00214       format_set_helper(format, ap);
00215       va_end(ap);
00216    }
00217 
00218    return format;
00219 }
00220 
00221 void ast_format_clear(struct ast_format *format)
00222 {
00223    format->id = 0;
00224    memset(&format->fattr, 0, sizeof(format->fattr));
00225 }
00226 
00227 /*! \internal
00228  * \brief determine if a list of attribute key value pairs are set on a format
00229  */
00230 static int format_isset_helper(const struct ast_format *format, va_list ap)
00231 {
00232    int res;
00233    struct interface_ao2_wrapper *wrapper;
00234    struct ast_format tmp = {
00235       .id = format->id,
00236       .fattr = { { 0, }, },
00237    };
00238 
00239    if (!(wrapper = find_interface(format))) {
00240       return -1;
00241    }
00242 
00243    ao2_rdlock(wrapper);
00244    if (!wrapper->interface ||
00245       !wrapper->interface->format_attr_set ||
00246       !wrapper->interface->format_attr_cmp) {
00247 
00248       ao2_unlock(wrapper);
00249       ao2_ref(wrapper, -1);
00250       return -1;
00251    }
00252 
00253    /* if isset is present, use that function, else just build a new
00254     * format and use the cmp function */
00255    if (wrapper->interface->format_attr_isset) {
00256       res = wrapper->interface->format_attr_isset(&format->fattr, ap);
00257    } else {
00258       wrapper->interface->format_attr_set(&tmp.fattr, ap);
00259       /* use our tmp structure to tell if the attributes are set or not */
00260       res = wrapper->interface->format_attr_cmp(&tmp.fattr, &format->fattr);
00261       res = (res == AST_FORMAT_CMP_NOT_EQUAL) ? -1 : 0;
00262    }
00263 
00264    ao2_unlock(wrapper);
00265    ao2_ref(wrapper, -1);
00266 
00267    return res;
00268 }
00269 
00270 int ast_format_isset(const struct ast_format *format, ... )
00271 {
00272    va_list ap;
00273    int res;
00274 
00275    va_start(ap, format);
00276    res = format_isset_helper(format, ap);
00277    va_end(ap);
00278    return res;
00279 }
00280 
00281 int ast_format_get_value(const struct ast_format *format, int key, void *value)
00282 {
00283    int res = 0;
00284    struct interface_ao2_wrapper *wrapper;
00285 
00286    if (!(wrapper = find_interface(format))) {
00287       return -1;
00288    }
00289    ao2_rdlock(wrapper);
00290    if (!wrapper->interface ||
00291       !wrapper->interface->format_attr_get_val) {
00292 
00293       ao2_unlock(wrapper);
00294       ao2_ref(wrapper, -1);
00295       return -1;
00296    }
00297 
00298    res = wrapper->interface->format_attr_get_val(&format->fattr, key, value);
00299 
00300    ao2_unlock(wrapper);
00301    ao2_ref(wrapper, -1);
00302 
00303    return res;
00304 }
00305 
00306 /*! \internal
00307  * \brief cmp format attributes using an interface
00308  */
00309 static enum ast_format_cmp_res format_cmp_helper(const struct ast_format *format1, const struct ast_format *format2)
00310 {
00311    enum ast_format_cmp_res res = AST_FORMAT_CMP_EQUAL;
00312    struct interface_ao2_wrapper *wrapper;
00313 
00314    if (!(wrapper = find_interface(format1))) {
00315       return res;
00316    }
00317 
00318    ao2_rdlock(wrapper);
00319    if (!wrapper->interface || !wrapper->interface->format_attr_cmp) {
00320       ao2_unlock(wrapper);
00321       ao2_ref(wrapper, -1);
00322       return res;
00323    }
00324 
00325    res = wrapper->interface->format_attr_cmp(&format1->fattr, &format2->fattr);
00326 
00327    ao2_unlock(wrapper);
00328    ao2_ref(wrapper, -1);
00329 
00330    return res;
00331 }
00332 
00333 enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
00334 {
00335    if (format1->id != format2->id) {
00336       return AST_FORMAT_CMP_NOT_EQUAL;
00337    }
00338 
00339    return format_cmp_helper(format1, format2);
00340 }
00341 
00342 /*! \internal
00343  * \brief get joint format attributes using an interface
00344  */
00345 static int format_joint_helper(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
00346 {
00347    int res = 0;
00348    struct interface_ao2_wrapper *wrapper;
00349 
00350    if (!(wrapper = find_interface(format1))) {
00351       /* if no interface is present, we assume formats are joint by id alone */
00352       return res;
00353    }
00354 
00355    ao2_rdlock(wrapper);
00356    if (wrapper->interface && wrapper->interface->format_attr_get_joint) {
00357       res = wrapper->interface->format_attr_get_joint(&format1->fattr, &format2->fattr, &result->fattr);
00358    }
00359    ao2_unlock(wrapper);
00360 
00361    ao2_ref(wrapper, -1);
00362 
00363    return res;
00364 }
00365 
00366 int ast_format_joint(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
00367 {
00368    if (format1->id != format2->id) {
00369       return -1;
00370    }
00371    result->id = format1->id;
00372    return format_joint_helper(format1, format2, result);
00373 }
00374 
00375 
00376 uint64_t ast_format_id_to_old_bitfield(enum ast_format_id id)
00377 {
00378    switch (id) {
00379    /*! G.723.1 compression */
00380    case AST_FORMAT_G723_1:
00381       return (1ULL << 0);
00382    /*! GSM compression */
00383    case AST_FORMAT_GSM:
00384       return (1ULL << 1);
00385    /*! Raw mu-law data (G.711) */
00386    case AST_FORMAT_ULAW:
00387       return (1ULL << 2);
00388    /*! Raw A-law data (G.711) */
00389    case AST_FORMAT_ALAW:
00390       return (1ULL << 3);
00391    /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
00392    case AST_FORMAT_G726_AAL2:
00393       return (1ULL << 4);
00394    /*! ADPCM (IMA) */
00395    case AST_FORMAT_ADPCM:
00396       return (1ULL << 5);
00397    /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
00398    case AST_FORMAT_SLINEAR:
00399       return (1ULL << 6);
00400    /*! LPC10, 180 samples/frame */
00401    case AST_FORMAT_LPC10:
00402       return (1ULL << 7);
00403    /*! G.729A audio */
00404    case AST_FORMAT_G729A:
00405       return (1ULL << 8);
00406    /*! SpeeX Free Compression */
00407    case AST_FORMAT_SPEEX:
00408       return (1ULL << 9);
00409    /*! iLBC Free Compression */
00410    case AST_FORMAT_ILBC:
00411       return (1ULL << 10);
00412    /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
00413    case AST_FORMAT_G726:
00414       return (1ULL << 11);
00415    /*! G.722 */
00416    case AST_FORMAT_G722:
00417       return (1ULL << 12);
00418    /*! G.722.1 (also known as Siren7, 32kbps assumed) */
00419    case AST_FORMAT_SIREN7:
00420       return (1ULL << 13);
00421    /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
00422    case AST_FORMAT_SIREN14:
00423       return (1ULL << 14);
00424    /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
00425    case AST_FORMAT_SLINEAR16:
00426       return (1ULL << 15);
00427    /*! G.719 (64 kbps assumed) */
00428    case AST_FORMAT_G719:
00429       return (1ULL << 32);
00430    /*! SpeeX Wideband (16kHz) Free Compression */
00431    case AST_FORMAT_SPEEX16:
00432       return (1ULL << 33);
00433    /*! Raw mu-law data (G.711) */
00434    case AST_FORMAT_TESTLAW:
00435       return (1ULL << 47);
00436 
00437    /*! H.261 Video */
00438    case AST_FORMAT_H261:
00439       return (1ULL << 18);
00440    /*! H.263 Video */
00441    case AST_FORMAT_H263:
00442       return (1ULL << 19);
00443    /*! H.263+ Video */
00444    case AST_FORMAT_H263_PLUS:
00445       return (1ULL << 20);
00446    /*! H.264 Video */
00447    case AST_FORMAT_H264:
00448       return (1ULL << 21);
00449    /*! MPEG4 Video */
00450    case AST_FORMAT_MP4_VIDEO:
00451       return (1ULL << 22);
00452 
00453    /*! JPEG Images */
00454    case AST_FORMAT_JPEG:
00455       return (1ULL << 16);
00456    /*! PNG Images */
00457    case AST_FORMAT_PNG:
00458       return (1ULL << 17);
00459 
00460    /*! T.140 RED Text format RFC 4103 */
00461    case AST_FORMAT_T140RED:
00462       return (1ULL << 26);
00463    /*! T.140 Text format - ITU T.140, RFC 4103 */
00464    case AST_FORMAT_T140:
00465       return (1ULL << 27);
00466    default:
00467       return 0; /* not supported by old bitfield. */
00468    }
00469 
00470    return 0;
00471 
00472 }
00473 uint64_t ast_format_to_old_bitfield(const struct ast_format *format)
00474 {
00475    return ast_format_id_to_old_bitfield(format->id);
00476 }
00477 
00478 struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t src)
00479 {
00480    switch (src) {
00481    /*! G.723.1 compression */
00482    case (1ULL << 0):
00483       return ast_format_set(dst, AST_FORMAT_G723_1, 0);
00484    /*! GSM compression */
00485    case (1ULL << 1):
00486       return ast_format_set(dst, AST_FORMAT_GSM, 0);
00487    /*! Raw mu-law data (G.711) */
00488    case (1ULL << 2):
00489       return ast_format_set(dst, AST_FORMAT_ULAW, 0);
00490    /*! Raw A-law data (G.711) */
00491    case (1ULL << 3):
00492       return ast_format_set(dst, AST_FORMAT_ALAW, 0);
00493    /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
00494    case (1ULL << 4):
00495       return ast_format_set(dst, AST_FORMAT_G726_AAL2, 0);
00496    /*! ADPCM (IMA) */
00497    case (1ULL << 5):
00498       return ast_format_set(dst, AST_FORMAT_ADPCM, 0);
00499    /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
00500    case (1ULL << 6):
00501       return ast_format_set(dst, AST_FORMAT_SLINEAR, 0);
00502    /*! LPC10, 180 samples/frame */
00503    case (1ULL << 7):
00504       return ast_format_set(dst, AST_FORMAT_LPC10, 0);
00505    /*! G.729A audio */
00506    case (1ULL << 8):
00507       return ast_format_set(dst, AST_FORMAT_G729A, 0);
00508    /*! SpeeX Free Compression */
00509    case (1ULL << 9):
00510       return ast_format_set(dst, AST_FORMAT_SPEEX, 0);
00511    /*! iLBC Free Compression */
00512    case (1ULL << 10):
00513       return ast_format_set(dst, AST_FORMAT_ILBC, 0);
00514    /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
00515    case (1ULL << 11):
00516       return ast_format_set(dst, AST_FORMAT_G726, 0);
00517    /*! G.722 */
00518    case (1ULL << 12):
00519       return ast_format_set(dst, AST_FORMAT_G722, 0);
00520    /*! G.722.1 (also known as Siren7, 32kbps assumed) */
00521    case (1ULL << 13):
00522       return ast_format_set(dst, AST_FORMAT_SIREN7, 0);
00523    /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
00524    case (1ULL << 14):
00525       return ast_format_set(dst, AST_FORMAT_SIREN14, 0);
00526    /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
00527    case (1ULL << 15):
00528       return ast_format_set(dst, AST_FORMAT_SLINEAR16, 0);
00529    /*! G.719 (64 kbps assumed) */
00530    case (1ULL << 32):
00531       return ast_format_set(dst, AST_FORMAT_G719, 0);
00532    /*! SpeeX Wideband (16kHz) Free Compression */
00533    case (1ULL << 33):
00534       return ast_format_set(dst, AST_FORMAT_SPEEX16, 0);
00535    /*! Raw mu-law data (G.711) */
00536    case (1ULL << 47):
00537       return ast_format_set(dst, AST_FORMAT_TESTLAW, 0);
00538 
00539    /*! H.261 Video */
00540    case (1ULL << 18):
00541       return ast_format_set(dst, AST_FORMAT_H261, 0);
00542    /*! H.263 Video */
00543    case (1ULL << 19):
00544       return ast_format_set(dst, AST_FORMAT_H263, 0);
00545    /*! H.263+ Video */
00546    case (1ULL << 20):
00547       return ast_format_set(dst, AST_FORMAT_H263_PLUS, 0);
00548    /*! H.264 Video */
00549    case (1ULL << 21):
00550       return ast_format_set(dst, AST_FORMAT_H264, 0);
00551    /*! MPEG4 Video */
00552    case (1ULL << 22):
00553       return ast_format_set(dst, AST_FORMAT_MP4_VIDEO, 0);
00554 
00555    /*! JPEG Images */
00556    case (1ULL << 16):
00557       return ast_format_set(dst, AST_FORMAT_JPEG, 0);
00558    /*! PNG Images */
00559    case (1ULL << 17):
00560       return ast_format_set(dst, AST_FORMAT_PNG, 0);
00561 
00562    /*! T.140 RED Text format RFC 4103 */
00563    case (1ULL << 26):
00564       return ast_format_set(dst, AST_FORMAT_T140RED, 0);
00565    /*! T.140 Text format - ITU T.140, RFC 4103 */
00566    case (1ULL << 27):
00567       return ast_format_set(dst, AST_FORMAT_T140, 0);
00568    }
00569    ast_format_clear(dst);
00570    return NULL;
00571 }
00572 
00573 enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src)
00574 {
00575    struct ast_format dst;
00576    if (ast_format_from_old_bitfield(&dst, src)) {
00577       return dst.id;
00578    }
00579    return 0;
00580 }
00581 
00582 int ast_format_is_slinear(const struct ast_format *format)
00583 {
00584    if (format->id == AST_FORMAT_SLINEAR ||
00585       format->id == AST_FORMAT_SLINEAR12 ||
00586       format->id == AST_FORMAT_SLINEAR16 ||
00587       format->id == AST_FORMAT_SLINEAR24 ||
00588       format->id == AST_FORMAT_SLINEAR32 ||
00589       format->id == AST_FORMAT_SLINEAR44 ||
00590       format->id == AST_FORMAT_SLINEAR48 ||
00591       format->id == AST_FORMAT_SLINEAR96 ||
00592       format->id == AST_FORMAT_SLINEAR192) {
00593       return 1;
00594    }
00595    return 0;
00596 }
00597 
00598 enum ast_format_id ast_format_slin_by_rate(unsigned int rate)
00599 {
00600    if (rate >= 192000) {
00601       return AST_FORMAT_SLINEAR192;
00602    } else if (rate >= 96000) {
00603       return AST_FORMAT_SLINEAR96;
00604    } else if (rate >= 48000) {
00605       return AST_FORMAT_SLINEAR48;
00606    } else if (rate >= 44100) {
00607       return AST_FORMAT_SLINEAR44;
00608    } else if (rate >= 32000) {
00609       return AST_FORMAT_SLINEAR32;
00610    } else if (rate >= 24000) {
00611       return AST_FORMAT_SLINEAR24;
00612    } else if (rate >= 16000) {
00613       return AST_FORMAT_SLINEAR16;
00614    } else if (rate >= 12000) {
00615       return AST_FORMAT_SLINEAR12;
00616    }
00617    return AST_FORMAT_SLINEAR;
00618 }
00619 
00620 const char* ast_getformatname(const struct ast_format *format)
00621 {
00622    int x;
00623    const char *ret = "unknown";
00624    size_t f_len;
00625    const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00626    for (x = 0; x < f_len; x++) {
00627       if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
00628          ret = f_list[x].name;
00629          break;
00630       }
00631    }
00632    f_list = ast_format_list_destroy(f_list);
00633    return ret;
00634 }
00635 
00636 
00637 char *ast_getformatname_multiple_byid(char *buf, size_t size, enum ast_format_id id)
00638 {
00639    int x;
00640    unsigned len;
00641    char *start, *end = buf;
00642    size_t f_len;
00643    const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00644 
00645    if (!size) {
00646       f_list = ast_format_list_destroy(f_list);
00647       return buf;
00648    }
00649    snprintf(end, size, "(");
00650    len = strlen(end);
00651    end += len;
00652    size -= len;
00653    start = end;
00654    for (x = 0; x < f_len; x++) {
00655       if (f_list[x].format.id == id) {
00656          snprintf(end, size, "%s|", f_list[x].name);
00657          len = strlen(end);
00658          end += len;
00659          size -= len;
00660       }
00661    }
00662    if (start == end) {
00663       ast_copy_string(start, "nothing)", size);
00664    } else if (size > 1) {
00665       *(end - 1) = ')';
00666    }
00667    f_list = ast_format_list_destroy(f_list);
00668    return buf;
00669 }
00670 
00671 static struct ast_codec_alias_table {
00672    const char *alias;
00673    const char *realname;
00674 } ast_codec_alias_table[] = {
00675    { "slinear", "slin"},
00676    { "slinear16", "slin16"},
00677    { "g723.1", "g723"},
00678    { "g722.1", "siren7"},
00679    { "g722.1c", "siren14"},
00680 };
00681 
00682 static const char *ast_expand_codec_alias(const char *in)
00683 {
00684    int x;
00685 
00686    for (x = 0; x < ARRAY_LEN(ast_codec_alias_table); x++) {
00687       if (!strcmp(in,ast_codec_alias_table[x].alias))
00688          return ast_codec_alias_table[x].realname;
00689    }
00690    return in;
00691 }
00692 
00693 struct ast_format *ast_getformatbyname(const char *name, struct ast_format *result)
00694 {
00695    int x;
00696    size_t f_len;
00697    const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00698 
00699    for (x = 0; x < f_len; x++) {
00700       if (!strcasecmp(f_list[x].name, name) ||
00701           !strcasecmp(f_list[x].name, ast_expand_codec_alias(name))) {
00702 
00703          ast_format_copy(result, &f_list[x].format);
00704          f_list = ast_format_list_destroy(f_list);
00705          return result;
00706       }
00707    }
00708    f_list = ast_format_list_destroy(f_list);
00709 
00710    return NULL;
00711 }
00712 
00713 const char *ast_codec2str(struct ast_format *format)
00714 {
00715    int x;
00716    const char *ret = "unknown";
00717    size_t f_len;
00718    const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00719 
00720    for (x = 0; x < f_len; x++) {
00721       if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
00722          ret = f_list[x].desc;
00723          break;
00724       }
00725    }
00726    f_list = ast_format_list_destroy(f_list);
00727    return ret;
00728 }
00729 
00730 int ast_format_rate(const struct ast_format *format)
00731 {
00732    switch (format->id) {
00733    case AST_FORMAT_SLINEAR12:
00734       return 12000;
00735    case AST_FORMAT_SLINEAR24:
00736       return 24000;
00737    case AST_FORMAT_SLINEAR32:
00738       return 32000;
00739    case AST_FORMAT_SLINEAR44:
00740       return 44100;
00741    case AST_FORMAT_SLINEAR48:
00742       return 48000;
00743    case AST_FORMAT_SLINEAR96:
00744       return 96000;
00745    case AST_FORMAT_SLINEAR192:
00746       return 192000;
00747    case AST_FORMAT_G722:
00748    case AST_FORMAT_SLINEAR16:
00749    case AST_FORMAT_SIREN7:
00750    case AST_FORMAT_SPEEX16:
00751       return 16000;
00752    case AST_FORMAT_SIREN14:
00753    case AST_FORMAT_SPEEX32:
00754       return 32000;
00755    case AST_FORMAT_G719:
00756       return 48000;
00757    case AST_FORMAT_SILK:
00758       if (!(ast_format_isset(format,
00759          SILK_ATTR_KEY_SAMP_RATE,
00760          SILK_ATTR_VAL_SAMP_24KHZ,
00761          AST_FORMAT_ATTR_END))) {
00762          return 24000;
00763       } else if (!(ast_format_isset(format,
00764          SILK_ATTR_KEY_SAMP_RATE,
00765          SILK_ATTR_VAL_SAMP_16KHZ,
00766          AST_FORMAT_ATTR_END))) {
00767          return 16000;
00768       } else if (!(ast_format_isset(format,
00769          SILK_ATTR_KEY_SAMP_RATE,
00770          SILK_ATTR_VAL_SAMP_12KHZ,
00771          AST_FORMAT_ATTR_END))) {
00772          return 12000;
00773       } else {
00774          return 8000;
00775       }
00776    case AST_FORMAT_CELT:
00777    {
00778       int samplerate;
00779       if (!(ast_format_get_value(format,
00780          CELT_ATTR_KEY_SAMP_RATE,
00781          &samplerate))) {
00782          return samplerate;
00783       }
00784    }
00785    default:
00786       return 8000;
00787    }
00788 }
00789 
00790 static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00791 {
00792    int x, found=0;
00793    size_t f_len;
00794    const struct ast_format_list *f_list;
00795 
00796    switch (cmd) {
00797    case CLI_INIT:
00798       e->command = "core show codecs [audio|video|image|text]";
00799       e->usage =
00800          "Usage: core show codecs [audio|video|image|text]\n"
00801          "       Displays codec mapping\n";
00802       return NULL;
00803    case CLI_GENERATE:
00804       return NULL;
00805    }
00806 
00807    if ((a->argc < 3) || (a->argc > 4)) {
00808       return CLI_SHOWUSAGE;
00809    }
00810 
00811    f_list = ast_format_list_get(&f_len);
00812    if (!ast_opt_dont_warn) {
00813       ast_cli(a->fd, "Disclaimer: this command is for informational purposes only.\n"
00814             "\tIt does not indicate anything about your configuration.\n");
00815    }
00816 
00817    ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION");
00818    ast_cli(a->fd, "-----------------------------------------------------------------------------------\n");
00819 
00820    for (x = 0; x < f_len; x++) {
00821       if (a->argc == 4) {
00822          if (!strcasecmp(a->argv[3], "audio")) {
00823             if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_AUDIO) {
00824                continue;
00825             }
00826          } else if (!strcasecmp(a->argv[3], "video")) {
00827             if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_VIDEO) {
00828                continue;
00829             }
00830          } else if (!strcasecmp(a->argv[3], "image")) {
00831             if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_IMAGE) {
00832                continue;
00833             }
00834          } else if (!strcasecmp(a->argv[3], "text")) {
00835             if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_TEXT) {
00836                continue;
00837             }
00838          } else {
00839             continue;
00840          }
00841       }
00842 
00843       ast_cli(a->fd, "%8u %5s %8s (%s)\n",
00844          f_list[x].format.id,
00845          (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_AUDIO) ? "audio" :
00846          (AST_FORMAT_GET_TYPE(f_list[x].format.id)  == AST_FORMAT_TYPE_IMAGE)  ? "image" :
00847          (AST_FORMAT_GET_TYPE(f_list[x].format.id)  == AST_FORMAT_TYPE_VIDEO) ? "video" :
00848          (AST_FORMAT_GET_TYPE(f_list[x].format.id)  == AST_FORMAT_TYPE_TEXT)  ? "text"  :
00849          "(unk)",
00850          f_list[x].name,
00851          f_list[x].desc);
00852       found = 1;
00853    }
00854 
00855    f_list = ast_format_list_destroy(f_list);
00856    if (!found) {
00857       return CLI_SHOWUSAGE;
00858    } else {
00859       return CLI_SUCCESS;
00860    }
00861 }
00862 
00863 static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00864 {
00865    enum ast_format_id format_id;
00866    int x, found = 0;
00867    int type_punned_codec;
00868    size_t f_len;
00869    const struct ast_format_list *f_list;
00870 
00871    switch (cmd) {
00872    case CLI_INIT:
00873       e->command = "core show codec";
00874       e->usage =
00875          "Usage: core show codec <number>\n"
00876          "       Displays codec mapping\n";
00877       return NULL;
00878    case CLI_GENERATE:
00879       return NULL;
00880    }
00881 
00882    if (a->argc != 4) {
00883       return CLI_SHOWUSAGE;
00884    }
00885 
00886    if (sscanf(a->argv[3], "%30d", &type_punned_codec) != 1) {
00887       return CLI_SHOWUSAGE;
00888    }
00889    format_id = type_punned_codec;
00890 
00891    f_list = ast_format_list_get(&f_len);
00892    for (x = 0; x < f_len; x++) {
00893       if (f_list[x].format.id == format_id) {
00894          found = 1;
00895          ast_cli(a->fd, "%11u %s\n", (unsigned int) format_id, f_list[x].desc);
00896       }
00897    }
00898 
00899    if (!found) {
00900       ast_cli(a->fd, "Codec %u not found\n", format_id);
00901    }
00902 
00903    f_list = ast_format_list_destroy(f_list);
00904    return CLI_SUCCESS;
00905 }
00906 
00907 /* Builtin Asterisk CLI-commands for debugging */
00908 static struct ast_cli_entry my_clis[] = {
00909    AST_CLI_DEFINE(show_codecs, "Displays a list of codecs"),
00910    AST_CLI_DEFINE(show_codec_n, "Shows a specific codec"),
00911 };
00912 int init_framer(void)
00913 {
00914    return 0;
00915 }
00916 
00917 static int format_list_add_custom(struct ast_format_list *new)
00918 {
00919    RAII_VAR(struct ast_format_list *, entry, NULL, ao2_cleanup);
00920    if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
00921       return -1;
00922    }
00923    memcpy(entry, new, sizeof(struct ast_format_list));
00924    entry->custom_entry = 1;
00925    ao2_link(format_list, entry);
00926    return 0;
00927 }
00928 static int format_list_add_static(
00929    const struct ast_format *format,
00930    const char *name,
00931    int samplespersecond,
00932    const char *description,
00933    int fr_len,
00934    int min_ms,
00935    int max_ms,
00936    int inc_ms,
00937    int def_ms,
00938    unsigned int flags,
00939    int cur_ms)
00940 {
00941    struct ast_format_list *entry;
00942    if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
00943       return -1;
00944    }
00945    ast_format_copy(&entry->format, format);
00946    ast_copy_string(entry->name, name, sizeof(entry->name));
00947    ast_copy_string(entry->desc, description, sizeof(entry->desc));
00948    entry->samplespersecond = samplespersecond;
00949    entry->fr_len = fr_len;
00950    entry->min_ms = min_ms;
00951    entry->max_ms = max_ms;
00952    entry->inc_ms = inc_ms;
00953    entry->def_ms = def_ms;
00954    entry->flags = flags;
00955    entry->cur_ms = cur_ms;
00956    entry->custom_entry = 0;
00957 
00958    ao2_link(format_list, entry);
00959    ao2_ref(entry, -1);
00960    return 0;
00961 }
00962 
00963 static int list_all_custom(void *obj, void *arg, int flag)
00964 {
00965    struct ast_format_list *entry = obj;
00966    return entry->custom_entry ? CMP_MATCH : 0;
00967 }
00968 
00969 static int list_cmp_cb(void *obj, void *arg, int flags)
00970 {
00971    struct ast_format_list *entry1 = obj;
00972    struct ast_format_list *entry2 = arg;
00973 
00974    return (ast_format_cmp(&entry1->format, &entry2->format) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH | CMP_STOP : 0;
00975 }
00976 
00977 const struct ast_format_list *ast_format_list_get(size_t *size)
00978 {
00979    struct ast_format_list *list;
00980    ast_rwlock_rdlock(&format_list_array_lock);
00981    ao2_ref(format_list_array, 1);
00982    list = format_list_array;
00983    *size = format_list_array_len;
00984    ast_rwlock_unlock(&format_list_array_lock);
00985    return list;
00986 }
00987 const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list)
00988 {
00989    ao2_ref((void *) list, -1);
00990    return NULL;
00991 }
00992 
00993 static int build_format_list_array(void)
00994 {
00995    struct ast_format_list *tmp;
00996    size_t arraysize = sizeof(struct ast_format_list) * ao2_container_count(format_list);
00997    int i = 0;
00998    struct ao2_iterator it;
00999 
01000    ast_rwlock_wrlock(&format_list_array_lock);
01001    tmp = format_list_array;
01002    if (!(format_list_array = ao2_alloc(arraysize, NULL))) {
01003       format_list_array = tmp;
01004       ast_rwlock_unlock(&format_list_array_lock);
01005       return -1;
01006    }
01007    format_list_array_len = ao2_container_count(format_list);
01008    if (tmp) {
01009       ao2_ref(tmp, -1);
01010    }
01011 
01012    /* walk through the container adding elements to the static array */
01013    it = ao2_iterator_init(format_list, 0);
01014    while ((tmp = ao2_iterator_next(&it)) && (i < format_list_array_len)) {
01015       memcpy(&format_list_array[i], tmp, sizeof(struct ast_format_list));
01016       ao2_ref(tmp, -1);
01017       i++;
01018    }
01019    ao2_iterator_destroy(&it);
01020 
01021    ast_rwlock_unlock(&format_list_array_lock);
01022    return 0;
01023 }
01024 
01025 static int format_list_init(void)
01026 {
01027    struct ast_format tmpfmt;
01028    if (!(format_list = ao2_container_alloc(1, NULL, list_cmp_cb))) {
01029       return -1;
01030    }
01031    /* initiate static entries XXX DO NOT CHANGE THIS ORDER! */
01032    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0), "g723", 8000, "G.723.1", 20, 30, 300, 30, 30, 0, 0);       /*!< G723.1 */
01033    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0), "gsm",  8000, "GSM", 33, 20, 300, 20, 20, 0, 0);              /*!< codec_gsm.c */
01034    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), "ulaw", 8000, "G.711 u-law", 80, 10, 150, 10, 20, 0, 0);     /*!< codec_ulaw.c */
01035    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0), "alaw", 8000, "G.711 A-law", 80, 10, 150, 10, 20, 0, 0);     /*!< codec_alaw.c */
01036    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G726, 0), "g726", 8000, "G.726 RFC3551", 40, 10, 300, 10, 20, 0, 0);   /*!< codec_g726.c */
01037    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), "adpcm" , 8000, "ADPCM", 40, 10, 300, 10, 20, 0, 0);        /*!< codec_adpcm.c */
01038    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0), "slin", 8000, "16 bit Signed Linear PCM", 160, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0); /*!< Signed linear */
01039    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_LPC10, 0), "lpc10", 8000, "LPC10", 7, 20, 20, 20, 20, 0, 0);           /*!< codec_lpc10.c */
01040    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0), "g729", 8000, "G.729A", 10, 10, 230, 10, 20, AST_SMOOTHER_FLAG_G729, 0);   /*!< Binary commercial distribution */
01041    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX, 0), "speex", 8000, "SpeeX", 10, 10, 60, 10, 20, 0, 0);          /*!< codec_speex.c */
01042    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX16, 0), "speex16", 16000, "SpeeX 16khz", 10, 10, 60, 10, 20, 0, 0);   /*!< codec_speex.c */
01043    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ILBC, 0), "ilbc", 8000, "iLBC", 50, 30, 30, 30, 30, 0, 0);                 /*!< codec_ilbc.c */ /* inc=30ms - workaround */
01044    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G726_AAL2, 0), "g726aal2", 8000, "G.726 AAL2", 40, 10, 300, 10, 20, 0, 0); /*!< codec_g726.c */
01045    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G722, 0), "g722", 16000, "G722", 80, 10, 150, 10, 20, 0, 0);               /*!< codec_g722.c */
01046    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0), "slin16", 16000, "16 bit Signed Linear PCM (16kHz)", 320, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (16kHz) */
01047    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_JPEG, 0), "jpeg", 0, "JPEG image", 0, 0, 0, 0 ,0 ,0 ,0);          /*!< See format_jpeg.c */
01048    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_PNG, 0), "png", 0, "PNG image", 0, 0, 0, 0 ,0 ,0 ,0);             /*!< PNG Image format */
01049    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H261, 0), "h261", 0, "H.261 Video", 0, 0, 0, 0 ,0 ,0 ,0);         /*!< H.261 Video Passthrough */
01050    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H263, 0), "h263", 0, "H.263 Video", 0, 0, 0, 0 ,0 ,0 ,0);         /*!< H.263 Passthrough support, see format_h263.c */
01051    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), "h263p", 0, "H.263+ Video", 0, 0, 0,0 ,0 ,0, 0);  /*!< H.263plus passthrough support See format_h263.c */
01052    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), "h264", 0, "H.264 Video", 0, 0, 0, 0 ,0 ,0, 0);         /*!< Passthrough support, see format_h263.c */
01053    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_MP4_VIDEO, 0), "mpeg4", 0, "MPEG4 Video", 0, 0, 0, 0, 0 ,0, 0);   /*!< Passthrough support for MPEG4 */
01054    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_T140RED, 0), "red", 1, "T.140 Realtime Text with redundancy", 0, 0, 0,0 ,0 ,0, 0);     /*!< Redundant T.140 Realtime Text */
01055    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_T140, 0), "t140", 0, "Passthrough T.140 Realtime Text", 0, 0, 0, 0 ,0 ,0, 0);      /*!< Passthrough support for T.140 Realtime Text */
01056    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SIREN7, 0), "siren7", 16000, "ITU G.722.1 (Siren7, licensed from Polycom)", 80, 20, 80, 20, 20, 0, 0); /*!< Binary commercial distribution */
01057    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SIREN14, 0), "siren14", 32000, "ITU G.722.1 Annex C, (Siren14, licensed from Polycom)", 120, 20, 80, 20, 20, 0, 0); /*!< Binary commercial distribution */
01058    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_TESTLAW, 0), "testlaw", 8000, "G.711 test-law", 80, 10, 150, 10, 20, 0, 0);    /*!< codec_ulaw.c */
01059    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20, 0, 0);
01060 
01061    /* ORDER MAY CHANGE AFTER THIS POINT IN THE LIST */
01062    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX32, 0), "speex32", 32000, "SpeeX 32khz", 10, 10, 60, 10, 20, 0, 0);   /*!< codec_speex.c */
01063    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR12, 0), "slin12", 12000, "16 bit Signed Linear PCM (12kHz)", 240, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (12kHz) */
01064    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR24, 0), "slin24", 24000, "16 bit Signed Linear PCM (24kHz)", 480, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (24kHz) */
01065    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR32, 0), "slin32", 32000, "16 bit Signed Linear PCM (32kHz)", 640, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (32kHz) */
01066    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR44, 0), "slin44", 44100, "16 bit Signed Linear PCM (44kHz)", 882, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (44.1kHz) */
01067    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR48, 0), "slin48", 48000, "16 bit Signed Linear PCM (48kHz)", 960, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (48kHz) */
01068    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR96, 0), "slin96", 96000, "16 bit Signed Linear PCM (96kHz)", 1920, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (96kHz) */
01069    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR192, 0), "slin192", 192000, "16 bit Signed Linear PCM (192kHz)", 3840, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (192kHz) */
01070 
01071    return 0;
01072 }
01073 
01074 /*! \internal \brief Clean up resources on Asterisk shutdown */
01075 static void format_list_shutdown(void)
01076 {
01077    ast_rwlock_destroy(&format_list_array_lock);
01078    if (format_list) {
01079       ao2_t_ref(format_list, -1, "Unref format_list container in shutdown");
01080       format_list = NULL;
01081    }
01082    if (format_list_array) {
01083       ao2_t_ref(format_list_array, -1, "Unref format_list_array in shutdown");
01084       format_list_array = NULL;
01085    }
01086 }
01087 
01088 int ast_format_list_init(void)
01089 {
01090    if (ast_rwlock_init(&format_list_array_lock)) {
01091       return -1;
01092    }
01093    if (format_list_init()) {
01094       goto init_list_cleanup;
01095    }
01096    if (build_format_list_array()) {
01097       goto init_list_cleanup;
01098    }
01099 
01100    ast_register_atexit(format_list_shutdown);
01101    return 0;
01102 init_list_cleanup:
01103 
01104    format_list_shutdown();
01105    return -1;
01106 }
01107 
01108 /*! \internal \brief Clean up resources on Asterisk shutdown */
01109 static void format_attr_shutdown(void)
01110 {
01111    ast_cli_unregister_multiple(my_clis, ARRAY_LEN(my_clis));
01112    if (interfaces) {
01113       ao2_ref(interfaces, -1);
01114       interfaces = NULL;
01115    }
01116 }
01117 
01118 int ast_format_attr_init(void)
01119 {
01120    interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK,
01121       283, interface_hash_cb, interface_cmp_cb);
01122    if (!interfaces) {
01123       return -1;
01124    }
01125 
01126    ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
01127    ast_register_cleanup(format_attr_shutdown);
01128    return 0;
01129 }
01130 
01131 static int custom_celt_format(struct ast_format_list *entry, unsigned int maxbitrate, unsigned int framesize)
01132 {
01133    if (!entry->samplespersecond) {
01134       ast_log(LOG_WARNING, "Custom CELT format definition '%s' requires sample rate to be defined.\n", entry->name);
01135    }
01136    ast_format_set(&entry->format, AST_FORMAT_CELT, 0);
01137    if (!has_interface(&entry->format)) {
01138       return -1;
01139    }
01140 
01141    snprintf(entry->desc, sizeof(entry->desc), "CELT Custom Format %ukhz", entry->samplespersecond/1000);
01142 
01143    ast_format_append(&entry->format,
01144       CELT_ATTR_KEY_SAMP_RATE, entry->samplespersecond,
01145       CELT_ATTR_KEY_MAX_BITRATE, maxbitrate,
01146       CELT_ATTR_KEY_FRAME_SIZE, framesize,
01147       AST_FORMAT_ATTR_END);
01148 
01149    entry->fr_len = 80;
01150    entry->min_ms = 20;
01151    entry->max_ms = 20;
01152    entry->inc_ms = 20;
01153    entry->def_ms = 20;
01154    return 0;
01155 }
01156 
01157 static int custom_silk_format(struct ast_format_list *entry, unsigned int maxbitrate, int usedtx, int usefec, int packetloss_percentage)
01158 {
01159    if (!entry->samplespersecond) {
01160       ast_log(LOG_WARNING, "Custom SILK format definition '%s' requires sample rate to be defined.\n", entry->name);
01161    }
01162    ast_format_set(&entry->format, AST_FORMAT_SILK, 0);
01163 
01164    if (!has_interface(&entry->format)) {
01165       return -1;
01166    }
01167 
01168    switch (entry->samplespersecond) {
01169    case 8000:
01170       ast_copy_string(entry->desc, "SILK Custom Format 8khz", sizeof(entry->desc));
01171       ast_format_append(&entry->format,
01172          SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_8KHZ,
01173          AST_FORMAT_ATTR_END);
01174       break;
01175    case 12000:
01176       ast_copy_string(entry->desc, "SILK Custom Format 12khz", sizeof(entry->desc));
01177       ast_format_append(&entry->format,
01178          SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_12KHZ,
01179          AST_FORMAT_ATTR_END);
01180       break;
01181    case 16000:
01182       ast_copy_string(entry->desc, "SILK Custom Format 16khz", sizeof(entry->desc));
01183       ast_format_append(&entry->format,
01184          SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_16KHZ,
01185          AST_FORMAT_ATTR_END);
01186       break;
01187    case 24000:
01188       ast_copy_string(entry->desc, "SILK Custom Format 24khz", sizeof(entry->desc));
01189       ast_format_append(&entry->format,
01190          SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_24KHZ,
01191          AST_FORMAT_ATTR_END);
01192       break;
01193    default:
01194       ast_log(LOG_WARNING, "Custom SILK format definition '%s' can not support sample rate %u\n", entry->name, entry->samplespersecond);
01195       return -1;
01196    }
01197    ast_format_append(&entry->format,
01198          SILK_ATTR_KEY_MAX_BITRATE, maxbitrate,
01199          SILK_ATTR_KEY_DTX, usedtx ? 1 : 0,
01200          SILK_ATTR_KEY_FEC, usefec ? 1 : 0,
01201          SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE, packetloss_percentage,
01202          AST_FORMAT_ATTR_END);
01203 
01204    entry->fr_len = 80;
01205    entry->min_ms = 20;
01206    entry->max_ms = 20;
01207    entry->inc_ms = 20;
01208    entry->def_ms = 20;
01209    return 0;
01210 }
01211 
01212 static int conf_process_format_name(const char *name, enum ast_format_id *id)
01213 {
01214    if (!strcasecmp(name, "silk")) {
01215       *id = AST_FORMAT_SILK;
01216    } else if (!strcasecmp(name, "celt")) {
01217       *id = AST_FORMAT_CELT;
01218    } else {
01219       *id = 0;
01220       return -1;
01221    }
01222    return 0;
01223 }
01224 
01225 static int conf_process_sample_rate(const char *rate, unsigned int *result)
01226 {
01227    if (!strcasecmp(rate, "8000")) {
01228       *result = 8000;
01229    } else if (!strcasecmp(rate, "12000")) {
01230       *result = 12000;
01231    } else if (!strcasecmp(rate, "16000")) {
01232       *result = 16000;
01233    } else if (!strcasecmp(rate, "24000")) {
01234       *result = 24000;
01235    } else if (!strcasecmp(rate, "32000")) {
01236       *result = 32000;
01237    } else if (!strcasecmp(rate, "44100")) {
01238       *result = 44100;
01239    } else if (!strcasecmp(rate, "48000")) {
01240       *result = 48000;
01241    } else if (!strcasecmp(rate, "96000")) {
01242       *result = 96000;
01243    } else if (!strcasecmp(rate, "192000")) {
01244       *result = 192000;
01245    } else {
01246       *result = 0;
01247       return -1;
01248    }
01249 
01250    return 0;
01251 }
01252 static int load_format_config(void)
01253 {
01254    struct ast_flags config_flags = { 0, };
01255    struct ast_config *cfg = ast_config_load(FORMAT_CONFIG, config_flags);
01256    struct ast_format_list entry;
01257    struct ast_variable *var;
01258    char *cat = NULL;
01259    int add_it = 0;
01260 
01261    struct {
01262       enum ast_format_id id;
01263       unsigned int maxbitrate;
01264       unsigned int framesize;
01265       unsigned int packetloss_percentage;
01266       int usefec;
01267       int usedtx;
01268    } settings;
01269 
01270    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
01271       return 0;
01272    }
01273 
01274    /* remove all custom formats from the AO2 Container. Note, this has no affect on the
01275     * global format list until the list is rebuild.  That is why this is okay to do while
01276     * reloading the config. */
01277    ao2_callback(format_list, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, list_all_custom, NULL);
01278 
01279    while ((cat = ast_category_browse(cfg, cat))) {
01280       memset(&entry, 0, sizeof(entry));
01281       memset(&settings, 0, sizeof(settings));
01282       add_it = 0;
01283 
01284       if (!(ast_variable_retrieve(cfg, cat, "type"))) {
01285          continue;
01286       }
01287       ast_copy_string(entry.name, cat, sizeof(entry.name));
01288       var = ast_variable_browse(cfg, cat);
01289       for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
01290          if (!strcasecmp(var->name, "type") && conf_process_format_name(var->value, &settings.id)) {
01291             ast_log(LOG_WARNING, "Can not make custom format type for '%s' at line %d of %s\n",
01292                var->value, var->lineno, FORMAT_CONFIG);
01293             continue;
01294          } else if (!strcasecmp(var->name, "samprate") && conf_process_sample_rate(var->value, &entry.samplespersecond)) {
01295             ast_log(LOG_WARNING, "Sample rate '%s' at line %d of %s is not supported.\n",
01296                   var->value, var->lineno, FORMAT_CONFIG);
01297          } else if (!strcasecmp(var->name, "maxbitrate")) {
01298             if (sscanf(var->value, "%30u", &settings.maxbitrate) != 1) {
01299                ast_log(LOG_WARNING, "maxbitrate '%s' at line %d of %s is not supported.\n",
01300                   var->value, var->lineno, FORMAT_CONFIG);
01301             }
01302          } else if (!strcasecmp(var->name, "framesize")) {
01303             if (sscanf(var->value, "%30u", &settings.framesize) != 1) {
01304                ast_log(LOG_WARNING, "framesize '%s' at line %d of %s is not supported.\n",
01305                   var->value, var->lineno, FORMAT_CONFIG);
01306             }
01307          } else if (!strcasecmp(var->name, "dtx")) {
01308             settings.usedtx = ast_true(var->value) ? 1 : 0;
01309          } else if (!strcasecmp(var->name, "fec")) {
01310             settings.usefec = ast_true(var->value) ? 1 : 0;
01311          } else if (!strcasecmp(var->name, "packetloss_percentage")) {
01312             if ((sscanf(var->value, "%30u", &settings.packetloss_percentage) != 1) || (settings.packetloss_percentage > 100)) {
01313                ast_log(LOG_WARNING, "packetloss_percentage '%s' at line %d of %s is not supported.\n",
01314                   var->value, var->lineno, FORMAT_CONFIG);
01315             }
01316          }
01317       }
01318 
01319       switch (settings.id) {
01320       case AST_FORMAT_SILK:
01321          if (!(custom_silk_format(&entry, settings.maxbitrate, settings.usedtx, settings.usefec, settings.packetloss_percentage))) {
01322             add_it = 1;
01323          }
01324          break;
01325       case AST_FORMAT_CELT:
01326          if (!(custom_celt_format(&entry, settings.maxbitrate, settings.framesize))) {
01327             add_it = 1;
01328          }
01329          break;
01330       default:
01331          ast_log(LOG_WARNING, "Can not create custom format %s\n", entry.name);
01332       }
01333 
01334       if (add_it) {
01335          format_list_add_custom(&entry);
01336       }
01337    }
01338    ast_config_destroy(cfg);
01339    build_format_list_array();
01340    return 0;
01341 }
01342 
01343 int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface)
01344 {
01345    int x;
01346    size_t f_len;
01347    const struct ast_format_list *f_list;
01348    struct interface_ao2_wrapper *wrapper;
01349    struct interface_ao2_wrapper tmp_wrapper = {
01350       .id = interface->id,
01351    };
01352 
01353    /*
01354     * Grab the write lock before checking for duplicates in
01355     * anticipation of adding a new interface and to prevent a
01356     * duplicate from sneaking in between the check and add.
01357     */
01358    ao2_wrlock(interfaces);
01359 
01360    /* check for duplicates first*/
01361    if ((wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
01362       ao2_unlock(interfaces);
01363       ast_log(LOG_WARNING, "Can not register attribute interface for format id %u, interface already exists.\n", interface->id);
01364       ao2_ref(wrapper, -1);
01365       return -1;
01366    }
01367 
01368    wrapper = ao2_alloc_options(sizeof(*wrapper), NULL, AO2_ALLOC_OPT_LOCK_RWLOCK);
01369    if (!wrapper) {
01370       ao2_unlock(interfaces);
01371       return -1;
01372    }
01373 
01374    wrapper->interface = interface;
01375    wrapper->id = interface->id;
01376 
01377    /* The write lock is already held. */
01378    ao2_link_flags(interfaces, wrapper, OBJ_NOLOCK);
01379    ao2_unlock(interfaces);
01380 
01381    ao2_ref(wrapper, -1);
01382 
01383    /* This will find all custom formats in codecs.conf for this new registered interface */
01384    load_format_config();
01385 
01386    /* update the RTP engine to all custom formats created for this interface */
01387    f_list = ast_format_list_get(&f_len);
01388    for (x = 0; x < f_len; x++) {
01389       if (f_list[x].format.id == tmp_wrapper.id) {
01390          ast_rtp_engine_load_format(&f_list[x].format);
01391       }
01392    }
01393    f_list = ast_format_list_destroy(f_list);
01394    return 0;
01395 }
01396 
01397 int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface)
01398 {
01399    int x;
01400    size_t f_len;
01401    const struct ast_format_list *f_list;
01402    struct interface_ao2_wrapper *wrapper;
01403    struct interface_ao2_wrapper tmp_wrapper = {
01404       .id = interface->id,
01405    };
01406 
01407    if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK)))) {
01408       return -1;
01409    }
01410 
01411    ao2_wrlock(wrapper);
01412    wrapper->interface = NULL;
01413    ao2_unlock(wrapper);
01414 
01415    ao2_ref(wrapper, -1);
01416 
01417    /* update the RTP engine to remove all custom formats created for this interface */
01418    f_list = ast_format_list_get(&f_len);
01419    for (x = 0; x < f_len; x++) {
01420       if (f_list[x].format.id == tmp_wrapper.id) {
01421          ast_rtp_engine_unload_format(&f_list[x].format);
01422       }
01423    }
01424 
01425    /* This will remove all custom formats previously created for this interface */
01426    load_format_config();
01427    f_list = ast_format_list_destroy(f_list);
01428    return 0;
01429 }