Sat Apr 26 2014 22:01:36

Asterisk developer's documentation


format_pref.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  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*!
00020  * \file
00021  * \brief Format Preference API
00022  */
00023 
00024 /*** MODULEINFO
00025    <support_level>core</support_level>
00026  ***/
00027 
00028 #include "asterisk.h"
00029 
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 384163 $");
00031 
00032 #include "asterisk/_private.h"
00033 #include "asterisk/frame.h"
00034 #include "asterisk/channel.h"
00035 #include "asterisk/utils.h"
00036 
00037 void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
00038 {
00039    size_t f_len;
00040    const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00041    int x, differential = (int) 'A', mem;
00042    char *from, *to;
00043 
00044    /* TODO re-evaluate this function.  It is using the order of the formats specified
00045     * in the global format list in a way that may not be safe. */
00046    if (right) {
00047       from = pref->order;
00048       to = buf;
00049       mem = size;
00050    } else {
00051       to = pref->order;
00052       from = buf;
00053       mem = AST_CODEC_PREF_SIZE;
00054    }
00055 
00056    memset(to, 0, mem);
00057    for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
00058       if (!from[x]) {
00059          break;
00060       }
00061       to[x] = right ? (from[x] + differential) : (from[x] - differential);
00062       if (!right && to[x] && (to[x] < f_len)) {
00063          ast_format_copy(&pref->formats[x], &f_list[to[x]-1].format);
00064       }
00065    }
00066    ast_format_list_destroy(f_list);
00067 }
00068 
00069 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
00070 {
00071    int x;
00072    struct ast_format format;
00073    size_t total_len, slen;
00074    const char *formatname;
00075 
00076    memset(buf, 0, size);
00077    total_len = size;
00078    buf[0] = '(';
00079    total_len--;
00080    for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
00081       if (total_len <= 0)
00082          break;
00083       if (!(ast_codec_pref_index(pref, x, &format)))
00084          break;
00085       if ((formatname = ast_getformatname(&format))) {
00086          slen = strlen(formatname);
00087          if (slen > total_len)
00088             break;
00089          strncat(buf, formatname, total_len - 1); /* safe */
00090          total_len -= slen;
00091       }
00092       if (total_len && x < AST_CODEC_PREF_SIZE - 1 && ast_codec_pref_index(pref, x + 1, &format)) {
00093          strncat(buf, "|", total_len - 1); /* safe */
00094          total_len--;
00095       }
00096    }
00097    if (total_len) {
00098       strncat(buf, ")", total_len - 1); /* safe */
00099       total_len--;
00100    }
00101 
00102    return size - total_len;
00103 }
00104 
00105 struct ast_format *ast_codec_pref_index(struct ast_codec_pref *pref, int idx, struct ast_format *result)
00106 {
00107    if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->formats[idx].id) {
00108       ast_format_copy(result, &pref->formats[idx]);
00109    } else {
00110       ast_format_clear(result);
00111       return NULL;
00112    }
00113 
00114    return result;
00115 }
00116 
00117 /*! \brief Remove codec from pref list */
00118 void ast_codec_pref_remove(struct ast_codec_pref *pref, struct ast_format *format)
00119 {
00120    struct ast_codec_pref oldorder;
00121    int x, y = 0;
00122    size_t f_len = 0;
00123    const struct ast_format_list *f_list;
00124 
00125    if (!pref->order[0]) {
00126       return;
00127    }
00128 
00129    f_list = ast_format_list_get(&f_len);
00130    memcpy(&oldorder, pref, sizeof(oldorder));
00131    memset(pref, 0, sizeof(*pref));
00132 
00133    for (x = 0; x < f_len; x++) {
00134       if (!oldorder.order[x]) {
00135          break;
00136       }
00137       if (ast_format_cmp(&f_list[oldorder.order[x]-1].format, format) == AST_FORMAT_CMP_NOT_EQUAL) {
00138          pref->order[y] = oldorder.order[x];
00139          ast_format_copy(&pref->formats[y], &oldorder.formats[x]);
00140          pref->framing[y++] = oldorder.framing[x];
00141       }
00142    }
00143    ast_format_list_destroy(f_list);
00144 }
00145 
00146 /*! \brief Append codec to list */
00147 int ast_codec_pref_append(struct ast_codec_pref *pref, struct ast_format *format)
00148 {
00149    int x, newindex = 0;
00150    size_t f_len = 0;
00151    const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00152 
00153    ast_codec_pref_remove(pref, format);
00154 
00155    for (x = 0; x < f_len; x++) {
00156       if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
00157          newindex = x + 1;
00158          break;
00159       }
00160    }
00161 
00162    if (newindex) {
00163       for (x = 0; x < f_len; x++) {
00164          if (!pref->order[x]) {
00165             pref->order[x] = newindex;
00166             ast_format_copy(&pref->formats[x], format);
00167             break;
00168          }
00169       }
00170    }
00171 
00172    ast_format_list_destroy(f_list);
00173    return x;
00174 }
00175 
00176 /*! \brief Prepend codec to list */
00177 void ast_codec_pref_prepend(struct ast_codec_pref *pref, struct ast_format *format, int only_if_existing)
00178 {
00179    int x, newindex = 0;
00180    size_t f_len = 0;
00181    const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00182 
00183    /* First step is to get the codecs "index number" */
00184    for (x = 0; x < f_len; x++) {
00185       if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
00186          newindex = x + 1;
00187          break;
00188       }
00189    }
00190    /* Done if its unknown */
00191    if (!newindex) {
00192       ast_format_list_destroy(f_list);
00193       return;
00194    }
00195 
00196    /* Now find any existing occurrence, or the end */
00197    for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
00198       if (!pref->order[x] || pref->order[x] == newindex)
00199          break;
00200    }
00201 
00202    /* If we failed to find any occurrence, set to the end */
00203    if (x == AST_CODEC_PREF_SIZE) {
00204       --x;
00205    }
00206 
00207    if (only_if_existing && !pref->order[x]) {
00208       ast_format_list_destroy(f_list);
00209       return;
00210    }
00211 
00212    /* Move down to make space to insert - either all the way to the end,
00213       or as far as the existing location (which will be overwritten) */
00214    for (; x > 0; x--) {
00215       pref->order[x] = pref->order[x - 1];
00216       pref->framing[x] = pref->framing[x - 1];
00217       ast_format_copy(&pref->formats[x], &pref->formats[x - 1]);
00218    }
00219 
00220    /* And insert the new entry */
00221    pref->order[0] = newindex;
00222    pref->framing[0] = 0; /* ? */
00223    ast_format_copy(&pref->formats[0], format);
00224    ast_format_list_destroy(f_list);
00225 }
00226 
00227 /*! \brief Set packet size for codec */
00228 int ast_codec_pref_setsize(struct ast_codec_pref *pref, struct ast_format *format, int framems)
00229 {
00230    int x, idx = -1;
00231    size_t f_len = 0;
00232    const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00233 
00234    for (x = 0; x < f_len; x++) {
00235       if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
00236          idx = x;
00237          break;
00238       }
00239    }
00240 
00241    if (idx < 0) {
00242       ast_format_list_destroy(f_list);
00243       return -1;
00244    }
00245 
00246    /* size validation */
00247    if (!framems)
00248       framems = f_list[idx].def_ms;
00249 
00250    if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */
00251       framems -= framems % f_list[idx].inc_ms;
00252 
00253    if (framems < f_list[idx].min_ms)
00254       framems = f_list[idx].min_ms;
00255 
00256    if (framems > f_list[idx].max_ms)
00257       framems = f_list[idx].max_ms;
00258 
00259    for (x = 0; x < f_len; x++) {
00260       if (pref->order[x] == (idx + 1)) {
00261          pref->framing[x] = framems;
00262          break;
00263       }
00264    }
00265 
00266    ast_format_list_destroy(f_list);
00267    return x;
00268 }
00269 
00270 /*! \brief Get packet size for codec */
00271 struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, struct ast_format *format)
00272 {
00273    int x, idx = -1, framems = 0;
00274    struct ast_format_list fmt = { { 0, }, };
00275    size_t f_len = 0;
00276    const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00277 
00278    for (x = 0; x < f_len; x++) {
00279       if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
00280          fmt = f_list[x];
00281          idx = x;
00282          break;
00283       }
00284    }
00285 
00286    if (idx < 0) {
00287       ast_log(AST_LOG_WARNING, "Format %s unknown; unable to get preferred codec packet size\n", ast_getformatname(format));
00288       ast_format_list_destroy(f_list);
00289       return fmt;
00290    }
00291 
00292    for (x = 0; x < f_len; x++) {
00293       if (pref->order[x] == (idx + 1)) {
00294          framems = pref->framing[x];
00295          break;
00296       }
00297    }
00298 
00299    /* size validation */
00300    if (!framems)
00301       framems = f_list[idx].def_ms;
00302 
00303    if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */
00304       framems -= framems % f_list[idx].inc_ms;
00305 
00306    if (framems < f_list[idx].min_ms)
00307       framems = f_list[idx].min_ms;
00308 
00309    if (framems > f_list[idx].max_ms)
00310       framems = f_list[idx].max_ms;
00311 
00312    fmt.cur_ms = framems;
00313    ast_format_list_destroy(f_list);
00314    return fmt;
00315 }
00316 
00317 /*! \brief Pick a codec */
00318 struct ast_format *ast_codec_choose(struct ast_codec_pref *pref, struct ast_format_cap *cap, int find_best, struct ast_format *result)
00319 {
00320    int x, slot, found = 0;
00321    size_t f_len = 0;
00322    const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00323 
00324    for (x = 0; x < f_len; x++) {
00325       slot = pref->order[x];
00326 
00327       if (!slot)
00328          break;
00329       if (ast_format_cap_get_compatible_format(cap, &f_list[slot-1].format, result)) {
00330          found = 1; /*format is found and stored in result */
00331          break;
00332       }
00333    }
00334    ast_format_list_destroy(f_list);
00335    if (found && (AST_FORMAT_GET_TYPE(result->id) == AST_FORMAT_TYPE_AUDIO)) {
00336       return result;
00337    }
00338    ast_format_clear(result);
00339    ast_debug(4, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
00340 
00341    return find_best ? ast_best_codec(cap, result) : NULL;
00342 }
00343 
00344