123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- /*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2010, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
- /*!
- * \file
- * \brief Format Preference API
- */
- /*** MODULEINFO
- <support_level>core</support_level>
- ***/
- #include "asterisk.h"
- ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
- #include "asterisk/_private.h"
- #include "asterisk/frame.h"
- #include "asterisk/channel.h"
- #include "asterisk/utils.h"
- void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
- {
- size_t f_len;
- const struct ast_format_list *f_list = ast_format_list_get(&f_len);
- int x, differential = (int) 'A', mem;
- char *from, *to;
- /* TODO re-evaluate this function. It is using the order of the formats specified
- * in the global format list in a way that may not be safe. */
- if (right) {
- from = pref->order;
- to = buf;
- mem = size;
- } else {
- to = pref->order;
- from = buf;
- mem = AST_CODEC_PREF_SIZE;
- }
- memset(to, 0, mem);
- for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
- if (!from[x]) {
- break;
- }
- to[x] = right ? (from[x] + differential) : (from[x] - differential);
- if (!right && to[x] && (to[x] < f_len)) {
- ast_format_copy(&pref->formats[x], &f_list[to[x]-1].format);
- }
- }
- ast_format_list_destroy(f_list);
- }
- int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
- {
- int x;
- struct ast_format format;
- size_t total_len, slen;
- const char *formatname;
- memset(buf, 0, size);
- total_len = size;
- buf[0] = '(';
- total_len--;
- for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
- if (total_len <= 0)
- break;
- if (!(ast_codec_pref_index(pref, x, &format)))
- break;
- if ((formatname = ast_getformatname(&format))) {
- slen = strlen(formatname);
- if (slen > total_len)
- break;
- strncat(buf, formatname, total_len - 1); /* safe */
- total_len -= slen;
- }
- if (total_len && x < AST_CODEC_PREF_SIZE - 1 && ast_codec_pref_index(pref, x + 1, &format)) {
- strncat(buf, "|", total_len - 1); /* safe */
- total_len--;
- }
- }
- if (total_len) {
- strncat(buf, ")", total_len - 1); /* safe */
- total_len--;
- }
- return size - total_len;
- }
- struct ast_format *ast_codec_pref_index(struct ast_codec_pref *pref, int idx, struct ast_format *result)
- {
- if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->formats[idx].id) {
- ast_format_copy(result, &pref->formats[idx]);
- } else {
- ast_format_clear(result);
- return NULL;
- }
- return result;
- }
- /*! \brief Remove codec from pref list */
- void ast_codec_pref_remove(struct ast_codec_pref *pref, struct ast_format *format)
- {
- struct ast_codec_pref oldorder;
- int x, y = 0;
- size_t f_len = 0;
- const struct ast_format_list *f_list;
- if (!pref->order[0]) {
- return;
- }
- f_list = ast_format_list_get(&f_len);
- memcpy(&oldorder, pref, sizeof(oldorder));
- memset(pref, 0, sizeof(*pref));
- for (x = 0; x < f_len; x++) {
- if (!oldorder.order[x]) {
- break;
- }
- if (ast_format_cmp(&f_list[oldorder.order[x]-1].format, format) == AST_FORMAT_CMP_NOT_EQUAL) {
- pref->order[y] = oldorder.order[x];
- ast_format_copy(&pref->formats[y], &oldorder.formats[x]);
- pref->framing[y++] = oldorder.framing[x];
- }
- }
- ast_format_list_destroy(f_list);
- }
- /*! \brief Append codec to list */
- int ast_codec_pref_append(struct ast_codec_pref *pref, struct ast_format *format)
- {
- int x, newindex = 0;
- size_t f_len = 0;
- const struct ast_format_list *f_list = ast_format_list_get(&f_len);
- ast_codec_pref_remove(pref, format);
- for (x = 0; x < f_len; x++) {
- if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
- newindex = x + 1;
- break;
- }
- }
- if (newindex) {
- for (x = 0; x < f_len; x++) {
- if (!pref->order[x]) {
- pref->order[x] = newindex;
- ast_format_copy(&pref->formats[x], format);
- break;
- }
- }
- }
- ast_format_list_destroy(f_list);
- return x;
- }
- /*! \brief Prepend codec to list */
- void ast_codec_pref_prepend(struct ast_codec_pref *pref, struct ast_format *format, int only_if_existing)
- {
- int x, newindex = 0;
- size_t f_len = 0;
- const struct ast_format_list *f_list = ast_format_list_get(&f_len);
- /* First step is to get the codecs "index number" */
- for (x = 0; x < f_len; x++) {
- if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
- newindex = x + 1;
- break;
- }
- }
- /* Done if its unknown */
- if (!newindex) {
- ast_format_list_destroy(f_list);
- return;
- }
- /* Now find any existing occurrence, or the end */
- for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
- if (!pref->order[x] || pref->order[x] == newindex)
- break;
- }
- /* If we failed to find any occurrence, set to the end */
- if (x == AST_CODEC_PREF_SIZE) {
- --x;
- }
- if (only_if_existing && !pref->order[x]) {
- ast_format_list_destroy(f_list);
- return;
- }
- /* Move down to make space to insert - either all the way to the end,
- or as far as the existing location (which will be overwritten) */
- for (; x > 0; x--) {
- pref->order[x] = pref->order[x - 1];
- pref->framing[x] = pref->framing[x - 1];
- ast_format_copy(&pref->formats[x], &pref->formats[x - 1]);
- }
- /* And insert the new entry */
- pref->order[0] = newindex;
- pref->framing[0] = 0; /* ? */
- ast_format_copy(&pref->formats[0], format);
- ast_format_list_destroy(f_list);
- }
- /*! \brief Set packet size for codec */
- int ast_codec_pref_setsize(struct ast_codec_pref *pref, struct ast_format *format, int framems)
- {
- int x, idx = -1;
- size_t f_len = 0;
- const struct ast_format_list *f_list = ast_format_list_get(&f_len);
- for (x = 0; x < f_len; x++) {
- if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
- idx = x;
- break;
- }
- }
- if (idx < 0) {
- ast_format_list_destroy(f_list);
- return -1;
- }
- /* size validation */
- if (!framems)
- framems = f_list[idx].def_ms;
- if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */
- framems -= framems % f_list[idx].inc_ms;
- if (framems < f_list[idx].min_ms)
- framems = f_list[idx].min_ms;
- if (framems > f_list[idx].max_ms)
- framems = f_list[idx].max_ms;
- for (x = 0; x < f_len; x++) {
- if (pref->order[x] == (idx + 1)) {
- pref->framing[x] = framems;
- break;
- }
- }
- ast_format_list_destroy(f_list);
- return x;
- }
- /*! \brief Get packet size for codec */
- struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, struct ast_format *format)
- {
- int x, idx = -1, framems = 0;
- struct ast_format_list fmt = { { 0, }, };
- size_t f_len = 0;
- const struct ast_format_list *f_list = ast_format_list_get(&f_len);
- for (x = 0; x < f_len; x++) {
- if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
- fmt = f_list[x];
- idx = x;
- break;
- }
- }
- if (idx < 0) {
- ast_log(AST_LOG_WARNING, "Format %s unknown; unable to get preferred codec packet size\n", ast_getformatname(format));
- ast_format_list_destroy(f_list);
- return fmt;
- }
- for (x = 0; x < f_len; x++) {
- if (pref->order[x] == (idx + 1)) {
- framems = pref->framing[x];
- break;
- }
- }
- /* size validation */
- if (!framems)
- framems = f_list[idx].def_ms;
- if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */
- framems -= framems % f_list[idx].inc_ms;
- if (framems < f_list[idx].min_ms)
- framems = f_list[idx].min_ms;
- if (framems > f_list[idx].max_ms)
- framems = f_list[idx].max_ms;
- fmt.cur_ms = framems;
- ast_format_list_destroy(f_list);
- return fmt;
- }
- /*! \brief Pick a codec */
- struct ast_format *ast_codec_choose(struct ast_codec_pref *pref, struct ast_format_cap *cap, int find_best, struct ast_format *result)
- {
- int x, slot, found = 0;
- size_t f_len = 0;
- const struct ast_format_list *f_list = ast_format_list_get(&f_len);
- for (x = 0; x < f_len; x++) {
- slot = pref->order[x];
- if (!slot)
- break;
- if (ast_format_cap_get_compatible_format(cap, &f_list[slot-1].format, result)) {
- found = 1; /*format is found and stored in result */
- break;
- }
- }
- ast_format_list_destroy(f_list);
- if (found && (AST_FORMAT_GET_TYPE(result->id) == AST_FORMAT_TYPE_AUDIO)) {
- return result;
- }
- ast_format_clear(result);
- ast_debug(4, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
- return find_best ? ast_best_codec(cap, result) : NULL;
- }
|