You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
asterisk/channels/iax2/codec_pref.c

334 lines
7.6 KiB

/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2014, Digium, Inc.
*
* Joshua Colp <jcolp@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 Media Format Bitfield Compatibility API
*
* \author Joshua Colp <jcolp@digium.com>
*/
/*** MODULEINFO
<support_level>core</support_level>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/logger.h"
#include "asterisk/astobj2.h"
#include "asterisk/codec.h"
#include "asterisk/format.h"
#include "asterisk/format_compatibility.h"
#include "asterisk/format_cache.h"
#include "asterisk/format_cap.h"
#include "include/codec_pref.h"
#include "include/format_compatibility.h"
void iax2_codec_pref_convert(struct iax2_codec_pref *pref, char *buf, size_t size, int right)
{
static int differential = (int) 'A';
int x;
if (right) {
for (x = 0; x < IAX2_CODEC_PREF_SIZE && x < size; x++) {
if (!pref->order[x]) {
break;
}
buf[x] = pref->order[x] + differential;
}
buf[x] = '\0';
} else {
for (x = 0; x < IAX2_CODEC_PREF_SIZE && x < size; x++) {
if (buf[x] == '\0') {
break;
}
pref->order[x] = buf[x] - differential;
}
if (x < size) {
pref->order[x] = 0;
}
}
}
struct ast_format *iax2_codec_pref_index(struct iax2_codec_pref *pref, int idx, struct ast_format **result)
{
if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->order[idx]) {
*result = ast_format_compatibility_bitfield2format(pref->order[idx]);
} else {
*result = NULL;
}
return *result;
}
void iax2_codec_pref_to_cap(struct iax2_codec_pref *pref, struct ast_format_cap *cap)
{
int idx;
for (idx = 0; idx < sizeof(pref->order); idx++) {
if (!pref->order[idx]) {
break;
}
ast_format_cap_append(cap, ast_format_compatibility_bitfield2format(pref->order[idx]), pref->framing[idx]);
}
}
int iax2_codec_pref_string(struct iax2_codec_pref *pref, char *buf, size_t size)
{
int x;
struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
size_t total_len;
char *cur;
if (!cap) {
return -1;
}
/* This function is useless if you have less than a 6 character buffer.
* '(...)' is six characters. */
if (size < 6) {
return -1;
}
/* Convert the preferences into a format cap so that we can read the formst names */
for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) {
uint64_t bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[x]);
if (!bitfield) {
break;
}
iax2_format_compatibility_bitfield2cap(bitfield, cap);
}
/* We know that at a minimum, 3 characters are used - (, ), and \0 */
total_len = size - 3;
memset(buf, 0, size);
/* This character has already been accounted for total_len purposes */
buf[0] = '(';
cur = buf + 1;
/* Loop through the formats and write as many into the buffer as we can */
for (x = 0; x < ast_format_cap_count(cap); x++) {
size_t name_len;
struct ast_format *fmt = ast_format_cap_get_format(cap, x);
const char *name = ast_format_get_name(fmt);
name_len = strlen(name);
/* all entries after the first need a delimiter character */
if (x) {
name_len++;
}
/* Terminate the list early if we don't have room for the entry.
* If it's not the last entry in the list, save enough room to write '...'.
*/
if (((x == ast_format_cap_count(cap) - 1) && (total_len < name_len)) ||
((x < ast_format_cap_count(cap) - 1) && (total_len < name_len + 3))) {
strcpy(cur, "...");
cur += 3;
total_len -= 3;
ao2_ref(fmt, -1);
break;
}
sprintf(cur, "%s%s", x ? "|" : "", name);
cur += name_len;
total_len -= name_len;
ao2_ref(fmt, -1);
}
ao2_ref(cap, -1);
/* These two characters have already been accounted for total_len purposes */
cur[0] = ')';
cur[1] = '\0';
return size - total_len;
}
static void codec_pref_remove_index(struct iax2_codec_pref *pref, int codec_pref_index)
{
int x;
for (x = codec_pref_index; x < IAX2_CODEC_PREF_SIZE; x++) {
pref->order[x] = pref->order[x + 1];
pref->framing[x] = pref->framing[x + 1];
if (!pref->order[x]) {
return;
}
}
}
/*! \brief Remove codec from pref list */
static void codec_pref_remove(struct iax2_codec_pref *pref, int format_index)
{
int x;
if (!pref->order[0]) {
return;
}
for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) {
if (!pref->order[x]) {
break;
}
if (pref->order[x] == format_index) {
codec_pref_remove_index(pref, x);
break;
}
}
}
void iax2_codec_pref_remove_missing(struct iax2_codec_pref *pref, uint64_t bitfield)
{
int x;
if (!pref->order[0]) {
return;
}
for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) {
uint64_t format_as_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[x]);
if (!pref->order[x]) {
break;
}
/* If this format isn't in the bitfield, remove it from the prefs. */
if (!(format_as_bitfield & bitfield)) {
codec_pref_remove_index(pref, x);
}
}
}
uint64_t iax2_codec_pref_order_value_to_format_bitfield(uint64_t order_value)
{
if (!order_value) {
return 0;
}
return 1 << (order_value - 1);
}
uint64_t iax2_codec_pref_format_bitfield_to_order_value(uint64_t bitfield)
{
int format_index = 1;
if (!bitfield) {
return 0;
}
while (bitfield > 1) {
bitfield = bitfield >> 1;
format_index++;
}
return format_index;
}
/*! \brief Append codec to list */
int iax2_codec_pref_append(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing)
{
uint64_t bitfield = ast_format_compatibility_format2bitfield(format);
int format_index = iax2_codec_pref_format_bitfield_to_order_value(bitfield);
int x;
codec_pref_remove(pref, format_index);
for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) {
if (!pref->order[x]) {
pref->order[x] = format_index;
pref->framing[x] = framing;
break;
}
}
return x;
}
/*! \brief Prepend codec to list */
void iax2_codec_pref_prepend(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing,
int only_if_existing)
{
uint64_t bitfield = ast_format_compatibility_format2bitfield(format);
int x;
/* Now find any existing occurrence, or the end */
for (x = 0; x < IAX2_CODEC_PREF_SIZE; x++) {
if (!pref->order[x] || pref->order[x] == bitfield)
break;
}
/* If we failed to find any occurrence, set to the end */
if (x == IAX2_CODEC_PREF_SIZE) {
--x;
}
if (only_if_existing && !pref->order[x]) {
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];
}
/* And insert the new entry */
pref->order[0] = bitfield;
pref->framing[0] = framing;
}
unsigned int iax2_codec_pref_getsize(struct iax2_codec_pref *pref, int idx)
{
if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->order[idx]) {
return pref->framing[idx];
} else {
return 0;
}
}
int iax2_codec_pref_setsize(struct iax2_codec_pref *pref, struct ast_format *format, int framems)
{
int idx;
for (idx = 0; idx < sizeof(pref->order); idx++) {
if (!pref->order[idx]) {
break;
} else if (ast_format_cmp(ast_format_compatibility_bitfield2format(pref->order[idx]),
format) != AST_FORMAT_CMP_EQUAL) {
continue;
}
pref->framing[idx] = framems;
return 0;
}
return -1;
}