Wed May 16 06:33:33 2012

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

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