2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2010, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Format Preference API
25 <support_level>core</support_level>
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
32 #include "asterisk/_private.h"
33 #include "asterisk/frame.h"
34 #include "asterisk/channel.h"
35 #include "asterisk/utils.h"
37 void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
40 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
41 int x, differential = (int) 'A', mem;
44 /* TODO re-evaluate this function. It is using the order of the formats specified
45 * in the global format list in a way that may not be safe. */
53 mem = AST_CODEC_PREF_SIZE;
57 for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
61 to[x] = right ? (from[x] + differential) : (from[x] - differential);
62 if (!right && to[x] && (to[x] < f_len)) {
63 ast_format_copy(&pref->formats[x], &f_list[to[x]-1].format);
66 ast_format_list_destroy(f_list);
69 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
72 struct ast_format format;
73 size_t total_len, slen;
74 const char *formatname;
80 for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
83 if (!(ast_codec_pref_index(pref, x, &format)))
85 if ((formatname = ast_getformatname(&format))) {
86 slen = strlen(formatname);
89 strncat(buf, formatname, total_len - 1); /* safe */
92 if (total_len && x < AST_CODEC_PREF_SIZE - 1 && ast_codec_pref_index(pref, x + 1, &format)) {
93 strncat(buf, "|", total_len - 1); /* safe */
98 strncat(buf, ")", total_len - 1); /* safe */
102 return size - total_len;
105 struct ast_format *ast_codec_pref_index(struct ast_codec_pref *pref, int idx, struct ast_format *result)
107 if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->formats[idx].id) {
108 ast_format_copy(result, &pref->formats[idx]);
110 ast_format_clear(result);
117 /*! \brief Remove codec from pref list */
118 void ast_codec_pref_remove(struct ast_codec_pref *pref, struct ast_format *format)
120 struct ast_codec_pref oldorder;
123 const struct ast_format_list *f_list;
125 if (!pref->order[0]) {
129 f_list = ast_format_list_get(&f_len);
130 memcpy(&oldorder, pref, sizeof(oldorder));
131 memset(pref, 0, sizeof(*pref));
133 for (x = 0; x < f_len; x++) {
134 if (!oldorder.order[x]) {
137 if (ast_format_cmp(&f_list[oldorder.order[x]-1].format, format) == AST_FORMAT_CMP_NOT_EQUAL) {
138 pref->order[y] = oldorder.order[x];
139 ast_format_copy(&pref->formats[y], &oldorder.formats[x]);
140 pref->framing[y++] = oldorder.framing[x];
143 ast_format_list_destroy(f_list);
146 /*! \brief Append codec to list */
147 int ast_codec_pref_append(struct ast_codec_pref *pref, struct ast_format *format)
151 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
153 ast_codec_pref_remove(pref, format);
155 for (x = 0; x < f_len; x++) {
156 if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
163 for (x = 0; x < f_len; x++) {
164 if (!pref->order[x]) {
165 pref->order[x] = newindex;
166 ast_format_copy(&pref->formats[x], format);
172 ast_format_list_destroy(f_list);
176 /*! \brief Prepend codec to list */
177 void ast_codec_pref_prepend(struct ast_codec_pref *pref, struct ast_format *format, int only_if_existing)
181 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
183 /* First step is to get the codecs "index number" */
184 for (x = 0; x < f_len; x++) {
185 if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
190 /* Done if its unknown */
192 ast_format_list_destroy(f_list);
196 /* Now find any existing occurrence, or the end */
197 for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
198 if (!pref->order[x] || pref->order[x] == newindex)
202 /* If we failed to find any occurrence, set to the end */
203 if (x == AST_CODEC_PREF_SIZE) {
207 if (only_if_existing && !pref->order[x]) {
208 ast_format_list_destroy(f_list);
212 /* Move down to make space to insert - either all the way to the end,
213 or as far as the existing location (which will be overwritten) */
215 pref->order[x] = pref->order[x - 1];
216 pref->framing[x] = pref->framing[x - 1];
217 ast_format_copy(&pref->formats[x], &pref->formats[x - 1]);
220 /* And insert the new entry */
221 pref->order[0] = newindex;
222 pref->framing[0] = 0; /* ? */
223 ast_format_copy(&pref->formats[0], format);
224 ast_format_list_destroy(f_list);
227 /*! \brief Set packet size for codec */
228 int ast_codec_pref_setsize(struct ast_codec_pref *pref, struct ast_format *format, int framems)
232 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
234 for (x = 0; x < f_len; x++) {
235 if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
242 ast_format_list_destroy(f_list);
246 /* size validation */
248 framems = f_list[idx].def_ms;
250 if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */
251 framems -= framems % f_list[idx].inc_ms;
253 if (framems < f_list[idx].min_ms)
254 framems = f_list[idx].min_ms;
256 if (framems > f_list[idx].max_ms)
257 framems = f_list[idx].max_ms;
259 for (x = 0; x < f_len; x++) {
260 if (pref->order[x] == (idx + 1)) {
261 pref->framing[x] = framems;
266 ast_format_list_destroy(f_list);
270 /*! \brief Get packet size for codec */
271 struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, struct ast_format *format)
273 int x, idx = -1, framems = 0;
274 struct ast_format_list fmt = { { 0, }, };
276 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
278 for (x = 0; x < f_len; x++) {
279 if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
287 ast_log(AST_LOG_WARNING, "Format %s unknown; unable to get preferred codec packet size\n", ast_getformatname(format));
288 ast_format_list_destroy(f_list);
292 for (x = 0; x < f_len; x++) {
293 if (pref->order[x] == (idx + 1)) {
294 framems = pref->framing[x];
299 /* size validation */
301 framems = f_list[idx].def_ms;
303 if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */
304 framems -= framems % f_list[idx].inc_ms;
306 if (framems < f_list[idx].min_ms)
307 framems = f_list[idx].min_ms;
309 if (framems > f_list[idx].max_ms)
310 framems = f_list[idx].max_ms;
312 fmt.cur_ms = framems;
313 ast_format_list_destroy(f_list);
317 /*! \brief Pick a codec */
318 struct ast_format *ast_codec_choose(struct ast_codec_pref *pref, struct ast_format_cap *cap, int find_best, struct ast_format *result)
322 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
324 for (x = 0; x < f_len; x++) {
325 slot = pref->order[x];
329 if (ast_format_cap_get_compatible_format(cap, &f_list[slot-1].format, result)) {
330 found = 1; /*format is found and stored in result */
334 ast_format_list_destroy(f_list);
335 if (found && (AST_FORMAT_GET_TYPE(result->id) == AST_FORMAT_TYPE_AUDIO)) {
338 ast_format_clear(result);
339 ast_debug(4, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
341 return find_best ? ast_best_codec(cap, result) : NULL;