Sat Apr 26 2014 22:01:36

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: 411310 $");
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 %d 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 static int list_hash_cb(const void *obj, const int flags)
00977 {
00978    return ao2_container_count(format_list);
00979 }
00980 
00981 const struct ast_format_list *ast_format_list_get(size_t *size)
00982 {
00983    struct ast_format_list *list;
00984    ast_rwlock_rdlock(&format_list_array_lock);
00985    ao2_ref(format_list_array, 1);
00986    list = format_list_array;
00987    *size = format_list_array_len;
00988    ast_rwlock_unlock(&format_list_array_lock);
00989    return list;
00990 }
00991 const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list)
00992 {
00993    ao2_ref((void *) list, -1);
00994    return NULL;
00995 }
00996 
00997 static int build_format_list_array(void)
00998 {
00999    struct ast_format_list *tmp;
01000    size_t arraysize = sizeof(struct ast_format_list) * ao2_container_count(format_list);
01001    int i = 0;
01002    struct ao2_iterator it;
01003 
01004    ast_rwlock_wrlock(&format_list_array_lock);
01005    tmp = format_list_array;
01006    if (!(format_list_array = ao2_alloc(arraysize, NULL))) {
01007       format_list_array = tmp;
01008       ast_rwlock_unlock(&format_list_array_lock);
01009       return -1;
01010    }
01011    format_list_array_len = ao2_container_count(format_list);
01012    if (tmp) {
01013       ao2_ref(tmp, -1);
01014    }
01015 
01016    /* walk through the container adding elements to the static array */
01017    it = ao2_iterator_init(format_list, 0);
01018    while ((tmp = ao2_iterator_next(&it)) && (i < format_list_array_len)) {
01019       memcpy(&format_list_array[i], tmp, sizeof(struct ast_format_list));
01020       ao2_ref(tmp, -1);
01021       i++;
01022    }
01023    ao2_iterator_destroy(&it);
01024 
01025    ast_rwlock_unlock(&format_list_array_lock);
01026    return 0;
01027 }
01028 
01029 static int format_list_init(void)
01030 {
01031    struct ast_format tmpfmt;
01032    if (!(format_list = ao2_container_alloc(283, list_hash_cb, list_cmp_cb))) {
01033       return -1;
01034    }
01035    /* initiate static entries XXX DO NOT CHANGE THIS ORDER! */
01036    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 */
01037    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 */
01038    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 */
01039    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 */
01040    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 */
01041    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 */
01042    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 */
01043    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 */
01044    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 */
01045    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 */
01046    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 */
01047    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 */
01048    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 */
01049    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 */
01050    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) */
01051    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 */
01052    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 */
01053    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 */
01054    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 */
01055    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 */
01056    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 */
01057    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 */
01058    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 */
01059    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 */
01060    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 */
01061    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 */
01062    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 */
01063    format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20, 0, 0);
01064 
01065    /* ORDER MAY CHANGE AFTER THIS POINT IN THE LIST */
01066    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 */
01067    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) */
01068    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) */
01069    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) */
01070    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) */
01071    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) */
01072    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) */
01073    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) */
01074 
01075    return 0;
01076 }
01077 
01078 /*! \internal \brief Clean up resources on Asterisk shutdown */
01079 static void format_list_shutdown(void)
01080 {
01081    ast_rwlock_destroy(&format_list_array_lock);
01082    if (format_list) {
01083       ao2_t_ref(format_list, -1, "Unref format_list container in shutdown");
01084       format_list = NULL;
01085    }
01086    if (format_list_array) {
01087       ao2_t_ref(format_list_array, -1, "Unref format_list_array in shutdown");
01088       format_list_array = NULL;
01089    }
01090 }
01091 
01092 int ast_format_list_init(void)
01093 {
01094    if (ast_rwlock_init(&format_list_array_lock)) {
01095       return -1;
01096    }
01097    if (format_list_init()) {
01098       goto init_list_cleanup;
01099    }
01100    if (build_format_list_array()) {
01101       goto init_list_cleanup;
01102    }
01103 
01104    ast_register_atexit(format_list_shutdown);
01105    return 0;
01106 init_list_cleanup:
01107 
01108    format_list_shutdown();
01109    return -1;
01110 }
01111 
01112 /*! \internal \brief Clean up resources on Asterisk shutdown */
01113 static void format_attr_shutdown(void)
01114 {
01115    ast_cli_unregister_multiple(my_clis, ARRAY_LEN(my_clis));
01116    if (interfaces) {
01117       ao2_ref(interfaces, -1);
01118       interfaces = NULL;
01119    }
01120 }
01121 
01122 int ast_format_attr_init(void)
01123 {
01124    interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK,
01125       283, interface_hash_cb, interface_cmp_cb);
01126    if (!interfaces) {
01127       return -1;
01128    }
01129 
01130    ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
01131    ast_register_cleanup(format_attr_shutdown);
01132    return 0;
01133 }
01134 
01135 static int custom_celt_format(struct ast_format_list *entry, unsigned int maxbitrate, unsigned int framesize)
01136 {
01137    if (!entry->samplespersecond) {
01138       ast_log(LOG_WARNING, "Custom CELT format definition '%s' requires sample rate to be defined.\n", entry->name);
01139    }
01140    ast_format_set(&entry->format, AST_FORMAT_CELT, 0);
01141    if (!has_interface(&entry->format)) {
01142       return -1;
01143    }
01144 
01145    snprintf(entry->desc, sizeof(entry->desc), "CELT Custom Format %dkhz", entry->samplespersecond/1000);
01146 
01147    ast_format_append(&entry->format,
01148       CELT_ATTR_KEY_SAMP_RATE, entry->samplespersecond,
01149       CELT_ATTR_KEY_MAX_BITRATE, maxbitrate,
01150       CELT_ATTR_KEY_FRAME_SIZE, framesize,
01151       AST_FORMAT_ATTR_END);
01152 
01153    entry->fr_len = 80;
01154    entry->min_ms = 20;
01155    entry->max_ms = 20;
01156    entry->inc_ms = 20;
01157    entry->def_ms = 20;
01158    return 0;
01159 }
01160 
01161 static int custom_silk_format(struct ast_format_list *entry, unsigned int maxbitrate, int usedtx, int usefec, int packetloss_percentage)
01162 {
01163    if (!entry->samplespersecond) {
01164       ast_log(LOG_WARNING, "Custom SILK format definition '%s' requires sample rate to be defined.\n", entry->name);
01165    }
01166    ast_format_set(&entry->format, AST_FORMAT_SILK, 0);
01167 
01168    if (!has_interface(&entry->format)) {
01169       return -1;
01170    }
01171 
01172    switch (entry->samplespersecond) {
01173    case 8000:
01174       ast_copy_string(entry->desc, "SILK Custom Format 8khz", sizeof(entry->desc));
01175       ast_format_append(&entry->format,
01176          SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_8KHZ,
01177          AST_FORMAT_ATTR_END);
01178       break;
01179    case 12000:
01180       ast_copy_string(entry->desc, "SILK Custom Format 12khz", sizeof(entry->desc));
01181       ast_format_append(&entry->format,
01182          SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_12KHZ,
01183          AST_FORMAT_ATTR_END);
01184       break;
01185    case 16000:
01186       ast_copy_string(entry->desc, "SILK Custom Format 16khz", sizeof(entry->desc));
01187       ast_format_append(&entry->format,
01188          SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_16KHZ,
01189          AST_FORMAT_ATTR_END);
01190       break;
01191    case 24000:
01192       ast_copy_string(entry->desc, "SILK Custom Format 24khz", sizeof(entry->desc));
01193       ast_format_append(&entry->format,
01194          SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_24KHZ,
01195          AST_FORMAT_ATTR_END);
01196       break;
01197    default:
01198       ast_log(LOG_WARNING, "Custom SILK format definition '%s' can not support sample rate %d\n", entry->name, entry->samplespersecond);
01199       return -1;
01200    }
01201    ast_format_append(&entry->format,
01202          SILK_ATTR_KEY_MAX_BITRATE, maxbitrate,
01203          SILK_ATTR_KEY_DTX, usedtx ? 1 : 0,
01204          SILK_ATTR_KEY_FEC, usefec ? 1 : 0,
01205          SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE, packetloss_percentage,
01206          AST_FORMAT_ATTR_END);
01207 
01208    entry->fr_len = 80;
01209    entry->min_ms = 20;
01210    entry->max_ms = 20;
01211    entry->inc_ms = 20;
01212    entry->def_ms = 20;
01213    return 0;
01214 }
01215 
01216 static int conf_process_format_name(const char *name, enum ast_format_id *id)
01217 {
01218    if (!strcasecmp(name, "silk")) {
01219       *id = AST_FORMAT_SILK;
01220    } else if (!strcasecmp(name, "celt")) {
01221       *id = AST_FORMAT_CELT;
01222    } else {
01223       *id = 0;
01224       return -1;
01225    }
01226    return 0;
01227 }
01228 
01229 static int conf_process_sample_rate(const char *rate, unsigned int *result)
01230 {
01231    if (!strcasecmp(rate, "8000")) {
01232       *result = 8000;
01233    } else if (!strcasecmp(rate, "12000")) {
01234       *result = 12000;
01235    } else if (!strcasecmp(rate, "16000")) {
01236       *result = 16000;
01237    } else if (!strcasecmp(rate, "24000")) {
01238       *result = 24000;
01239    } else if (!strcasecmp(rate, "32000")) {
01240       *result = 32000;
01241    } else if (!strcasecmp(rate, "44100")) {
01242       *result = 44100;
01243    } else if (!strcasecmp(rate, "48000")) {
01244       *result = 48000;
01245    } else if (!strcasecmp(rate, "96000")) {
01246       *result = 96000;
01247    } else if (!strcasecmp(rate, "192000")) {
01248       *result = 192000;
01249    } else {
01250       *result = 0;
01251       return -1;
01252    }
01253 
01254    return 0;
01255 }
01256 static int load_format_config(void)
01257 {
01258    struct ast_flags config_flags = { 0, };
01259    struct ast_config *cfg = ast_config_load(FORMAT_CONFIG, config_flags);
01260    struct ast_format_list entry;
01261    struct ast_variable *var;
01262    char *cat = NULL;
01263    int add_it = 0;
01264 
01265    struct {
01266       enum ast_format_id id;
01267       unsigned int maxbitrate;
01268       unsigned int framesize;
01269       unsigned int packetloss_percentage;
01270       int usefec;
01271       int usedtx;
01272    } settings;
01273 
01274    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
01275       return 0;
01276    }
01277 
01278    /* remove all custom formats from the AO2 Container. Note, this has no affect on the
01279     * global format list until the list is rebuild.  That is why this is okay to do while
01280     * reloading the config. */
01281    ao2_callback(format_list, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, list_all_custom, NULL);
01282 
01283    while ((cat = ast_category_browse(cfg, cat))) {
01284       memset(&entry, 0, sizeof(entry));
01285       memset(&settings, 0, sizeof(settings));
01286       add_it = 0;
01287 
01288       if (!(ast_variable_retrieve(cfg, cat, "type"))) {
01289          continue;
01290       }
01291       ast_copy_string(entry.name, cat, sizeof(entry.name));
01292       var = ast_variable_browse(cfg, cat);
01293       for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
01294          if (!strcasecmp(var->name, "type") && conf_process_format_name(var->value, &settings.id)) {
01295             ast_log(LOG_WARNING, "Can not make custom format type for '%s' at line %d of %s\n",
01296                var->value, var->lineno, FORMAT_CONFIG);
01297             continue;
01298          } else if (!strcasecmp(var->name, "samprate") && conf_process_sample_rate(var->value, &entry.samplespersecond)) {
01299             ast_log(LOG_WARNING, "Sample rate '%s' at line %d of %s is not supported.\n",
01300                   var->value, var->lineno, FORMAT_CONFIG);
01301          } else if (!strcasecmp(var->name, "maxbitrate")) {
01302             if (sscanf(var->value, "%30u", &settings.maxbitrate) != 1) {
01303                ast_log(LOG_WARNING, "maxbitrate '%s' at line %d of %s is not supported.\n",
01304                   var->value, var->lineno, FORMAT_CONFIG);
01305             }
01306          } else if (!strcasecmp(var->name, "framesize")) {
01307             if (sscanf(var->value, "%30u", &settings.framesize) != 1) {
01308                ast_log(LOG_WARNING, "framesize '%s' at line %d of %s is not supported.\n",
01309                   var->value, var->lineno, FORMAT_CONFIG);
01310             }
01311          } else if (!strcasecmp(var->name, "dtx")) {
01312             settings.usedtx = ast_true(var->value) ? 1 : 0;
01313          } else if (!strcasecmp(var->name, "fec")) {
01314             settings.usefec = ast_true(var->value) ? 1 : 0;
01315          } else if (!strcasecmp(var->name, "packetloss_percentage")) {
01316             if ((sscanf(var->value, "%30u", &settings.packetloss_percentage) != 1) || (settings.packetloss_percentage > 100)) {
01317                ast_log(LOG_WARNING, "packetloss_percentage '%s' at line %d of %s is not supported.\n",
01318                   var->value, var->lineno, FORMAT_CONFIG);
01319             }
01320          }
01321       }
01322 
01323       switch (settings.id) {
01324       case AST_FORMAT_SILK:
01325          if (!(custom_silk_format(&entry, settings.maxbitrate, settings.usedtx, settings.usefec, settings.packetloss_percentage))) {
01326             add_it = 1;
01327          }
01328          break;
01329       case AST_FORMAT_CELT:
01330          if (!(custom_celt_format(&entry, settings.maxbitrate, settings.framesize))) {
01331             add_it = 1;
01332          }
01333          break;
01334       default:
01335          ast_log(LOG_WARNING, "Can not create custom format %s\n", entry.name);
01336       }
01337 
01338       if (add_it) {
01339          format_list_add_custom(&entry);
01340       }
01341    }
01342    ast_config_destroy(cfg);
01343    build_format_list_array();
01344    return 0;
01345 }
01346 
01347 int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface)
01348 {
01349    int x;
01350    size_t f_len;
01351    const struct ast_format_list *f_list;
01352    struct interface_ao2_wrapper *wrapper;
01353    struct interface_ao2_wrapper tmp_wrapper = {
01354       .id = interface->id,
01355    };
01356 
01357    /*
01358     * Grab the write lock before checking for duplicates in
01359     * anticipation of adding a new interface and to prevent a
01360     * duplicate from sneaking in between the check and add.
01361     */
01362    ao2_wrlock(interfaces);
01363 
01364    /* check for duplicates first*/
01365    if ((wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
01366       ao2_unlock(interfaces);
01367       ast_log(LOG_WARNING, "Can not register attribute interface for format id %d, interface already exists.\n", interface->id);
01368       ao2_ref(wrapper, -1);
01369       return -1;
01370    }
01371 
01372    wrapper = ao2_alloc_options(sizeof(*wrapper), NULL, AO2_ALLOC_OPT_LOCK_RWLOCK);
01373    if (!wrapper) {
01374       ao2_unlock(interfaces);
01375       return -1;
01376    }
01377 
01378    wrapper->interface = interface;
01379    wrapper->id = interface->id;
01380 
01381    /* The write lock is already held. */
01382    ao2_link_flags(interfaces, wrapper, OBJ_NOLOCK);
01383    ao2_unlock(interfaces);
01384 
01385    ao2_ref(wrapper, -1);
01386 
01387    /* This will find all custom formats in codecs.conf for this new registered interface */
01388    load_format_config();
01389 
01390    /* update the RTP engine to all custom formats created for this interface */
01391    f_list = ast_format_list_get(&f_len);
01392    for (x = 0; x < f_len; x++) {
01393       if (f_list[x].format.id == tmp_wrapper.id) {
01394          ast_rtp_engine_load_format(&f_list[x].format);
01395       }
01396    }
01397    f_list = ast_format_list_destroy(f_list);
01398    return 0;
01399 }
01400 
01401 int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface)
01402 {
01403    int x;
01404    size_t f_len;
01405    const struct ast_format_list *f_list;
01406    struct interface_ao2_wrapper *wrapper;
01407    struct interface_ao2_wrapper tmp_wrapper = {
01408       .id = interface->id,
01409    };
01410 
01411    if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK)))) {
01412       return -1;
01413    }
01414 
01415    ao2_wrlock(wrapper);
01416    wrapper->interface = NULL;
01417    ao2_unlock(wrapper);
01418 
01419    ao2_ref(wrapper, -1);
01420 
01421    /* update the RTP engine to remove all custom formats created for this interface */
01422    f_list = ast_format_list_get(&f_len);
01423    for (x = 0; x < f_len; x++) {
01424       if (f_list[x].format.id == tmp_wrapper.id) {
01425          ast_rtp_engine_unload_format(&f_list[x].format);
01426       }
01427    }
01428 
01429    /* This will remove all custom formats previously created for this interface */
01430    load_format_config();
01431    f_list = ast_format_list_destroy(f_list);
01432    return 0;
01433 }