diff options
Diffstat (limited to 'channels/iax2')
-rw-r--r-- | channels/iax2/codec_pref.c | 333 | ||||
-rw-r--r-- | channels/iax2/format_compatibility.c | 73 | ||||
-rw-r--r-- | channels/iax2/include/codec_pref.h | 123 | ||||
-rw-r--r-- | channels/iax2/include/format_compatibility.h | 55 | ||||
-rw-r--r-- | channels/iax2/parser.c | 15 | ||||
-rw-r--r-- | channels/iax2/provision.c | 9 |
6 files changed, 600 insertions, 8 deletions
diff --git a/channels/iax2/codec_pref.c b/channels/iax2/codec_pref.c new file mode 100644 index 000000000..903dca4cc --- /dev/null +++ b/channels/iax2/codec_pref.c @@ -0,0 +1,333 @@ +/* + * 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; +} diff --git a/channels/iax2/format_compatibility.c b/channels/iax2/format_compatibility.c new file mode 100644 index 000000000..8085c2c26 --- /dev/null +++ b/channels/iax2/format_compatibility.c @@ -0,0 +1,73 @@ +/* + * 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/format_compatibility.h" + +uint64_t iax2_format_compatibility_cap2bitfield(const struct ast_format_cap *cap) +{ + uint64_t bitfield = 0; + int x; + + for (x = 0; x < ast_format_cap_count(cap); x++) { + struct ast_format *format = ast_format_cap_get_format(cap, x); + + bitfield |= ast_format_compatibility_format2bitfield(format); + + ao2_ref(format, -1); + } + + return bitfield; +} + +int iax2_format_compatibility_bitfield2cap(uint64_t bitfield, struct ast_format_cap *cap) +{ + int x; + + for (x = 0; x < 64; x++) { + uint64_t tmp = (1ULL << x); + + if ((tmp & bitfield) && ast_format_cap_append(cap, ast_format_compatibility_bitfield2format(tmp), 0)) { + return -1; + } + } + + return 0; +} diff --git a/channels/iax2/include/codec_pref.h b/channels/iax2/include/codec_pref.h new file mode 100644 index 000000000..bfb889164 --- /dev/null +++ b/channels/iax2/include/codec_pref.h @@ -0,0 +1,123 @@ +/* + * 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> + */ + +#ifndef _IAX2_CODEC_PREF_H_ +#define _IAX2_CODEC_PREF_H_ + +struct ast_format; +struct ast_codec; +struct ast_format_cap; + +#define IAX2_CODEC_PREF_SIZE 64 +struct iax2_codec_pref { + /*! This array is ordered by preference and contains the codec bitfield. */ + uint64_t order[IAX2_CODEC_PREF_SIZE]; + /*! Framing size of the codec */ + unsigned int framing[IAX2_CODEC_PREF_SIZE]; +}; + +/*! + * \brief Convert an iax2_codec_pref order value into a format bitfield + * + * \param order_value value being converted + * + * \return the bitfield value of the order_value format + */ +uint64_t iax2_codec_pref_order_value_to_format_bitfield(uint64_t order_value); + +/*! + * \brief Convert a format bitfield into an iax2_codec_pref order value + * + * \param bitfield value being converted + * + * \return the iax2_codec_pref order value of the most significant format + * in the bitfield. + * + * \note This is really meant to be used on single format bitfields. + * It will work with multiformat bitfields, but it can only return the + * index of the most significant one if that is the case. + */ +uint64_t iax2_codec_pref_format_bitfield_to_order_value(uint64_t bitfield); + +/*! + * \brief Codec located at a particular place in the preference index. + * \param pref preference structure to get the codec out of + * \param index to retrieve from + * \param result ast_format structure to store the index value in + * \return pointer to input ast_format on success, NULL on failure +*/ +struct ast_format *iax2_codec_pref_index(struct iax2_codec_pref *pref, int index, struct ast_format **result); + +/*! \brief Convert a preference structure to a capabilities structure */ +void iax2_codec_pref_to_cap(struct iax2_codec_pref *pref, struct ast_format_cap *cap); + +/*! \brief Removes format from the pref list that aren't in the bitfield */ +void iax2_codec_pref_remove_missing(struct iax2_codec_pref *pref, uint64_t bitfield); + +/*! + * \brief Dump audio codec preference list into a string + * + * \param pref preference structure to dump string representation of order for + * \param buf character buffer to put string into + * \param size size of the character buffer + * + * \return -1 on error. Otherwise returns the remaining spaaaaaace in the buffer. + * + * \note Format is (codec1|codec2|codec3|...) -- if the list is too long for the + * size of the buffer, codecs will be written until they exceed the length + * remaining in which case the list will be closed with '...)' after the last + * writable codec. + */ +int iax2_codec_pref_string(struct iax2_codec_pref *pref, char *buf, size_t size); + +/*! \brief Append a audio codec to a preference list, removing it first if it was already there +*/ +int iax2_codec_pref_append(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing); + +/*! \brief Prepend an audio codec to a preference list, removing it first if it was already there +*/ +void iax2_codec_pref_prepend(struct iax2_codec_pref *pref, struct ast_format *format, unsigned int framing, + int only_if_existing); + +/*! \brief Get packet size for codec +*/ +unsigned int iax2_codec_pref_getsize(struct iax2_codec_pref *pref, int index); + +/*! \brief Set packet size for codec +*/ +int iax2_codec_pref_setsize(struct iax2_codec_pref *pref, struct ast_format *format, int framems); + +/*! \brief Shift an audio codec preference list up or down 65 bytes so that it becomes an ASCII string + * \note Due to a misunderstanding in how codec preferences are stored, this + * list starts at 'B', not 'A'. For backwards compatibility reasons, this + * cannot change. + * \param pref A codec preference list structure + * \param buf A string denoting codec preference, appropriate for use in line transmission + * \param size Size of \a buf + * \param right Boolean: if 0, convert from \a buf to \a pref; if 1, convert from \a pref to \a buf. + */ +void iax2_codec_pref_convert(struct iax2_codec_pref *pref, char *buf, size_t size, int right); + +#endif /* _IAX2_CODEC_PREF_H_ */ diff --git a/channels/iax2/include/format_compatibility.h b/channels/iax2/include/format_compatibility.h new file mode 100644 index 000000000..aa29cfa2c --- /dev/null +++ b/channels/iax2/include/format_compatibility.h @@ -0,0 +1,55 @@ +/* + * 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> + */ + +#ifndef _IAX2_FORMAT_COMPATIBILITY_H_ +#define _IAX2_FORMAT_COMPATIBILITY_H_ + +struct ast_format; +struct ast_format_cap; + +/*! + * \brief Convert a format capabilities structure to a bitfield + * + * \param cap Capabilities structure containing formats + * + * \retval non-zero success + * \retval zero no formats present or no formats supported + */ +uint64_t iax2_format_compatibility_cap2bitfield(const struct ast_format_cap *cap); + +/*! + * \brief Convert a bitfield to a format capabilities structure + * + * \param bitfield The bitfield for the media formats + * \param cap Capabilities structure to place formats into + * + * \retval non-NULL success + * \retval NULL failure + * + * \note If failure occurs the capabilities structure may contain a partial set of formats + */ +int iax2_format_compatibility_bitfield2cap(uint64_t bitfield, struct ast_format_cap *cap); + +#endif /* _IAX2_FORMAT_COMPATIBILITY_H */ diff --git a/channels/iax2/parser.c b/channels/iax2/parser.c index f5c7ba05d..f1fc8f82d 100644 --- a/channels/iax2/parser.c +++ b/channels/iax2/parser.c @@ -42,10 +42,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/lock.h" #include "asterisk/threadstorage.h" #include "asterisk/netsock2.h" +#include "asterisk/format_cache.h" +#include "asterisk/format_compatibility.h" #include "include/iax2.h" #include "include/parser.h" #include "include/provision.h" +#include "include/codec_pref.h" static int frames = 0; static int iframes = 0; @@ -124,7 +127,7 @@ static void dump_string(char *output, int maxlen, void *value, int len) static void dump_prefs(char *output, int maxlen, void *value, int len) { - struct ast_codec_pref pref; + struct iax2_codec_pref pref; int total_len = 0; maxlen--; @@ -136,9 +139,9 @@ static void dump_prefs(char *output, int maxlen, void *value, int len) strncpy(output, value, maxlen); output[maxlen] = '\0'; - ast_codec_pref_convert(&pref, output, total_len, 0); + iax2_codec_pref_convert(&pref, output, total_len, 0); memset(output,0,total_len); - ast_codec_pref_string(&pref, output, total_len); + iax2_codec_pref_string(&pref, output, total_len); } static void dump_int(char *output, int maxlen, void *value, int len) @@ -1180,7 +1183,8 @@ int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen) void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f) { fr->af.frametype = f->frametype; - ast_format_copy(&fr->af.subclass.format, &f->subclass.format); + fr->af.subclass.format = f->subclass.format; + fr->af.subclass.integer = f->subclass.integer; fr->af.mallocd = 0; /* Our frame is static relative to the container */ fr->af.datalen = f->datalen; fr->af.samples = f->samples; @@ -1199,7 +1203,8 @@ void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f) } #if __BYTE_ORDER == __LITTLE_ENDIAN /* We need to byte-swap slinear samples from network byte order */ - if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass.format.id == AST_FORMAT_SLINEAR)) { + if ((fr->af.frametype == AST_FRAME_VOICE) && + (ast_format_cmp(fr->af.subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) { /* 2 bytes / sample for SLINEAR */ ast_swapcopy_samples(fr->af.data.ptr, f->data.ptr, copy_len / 2); } else diff --git a/channels/iax2/provision.c b/channels/iax2/provision.c index 78e0b1b3d..85dfe9448 100644 --- a/channels/iax2/provision.c +++ b/channels/iax2/provision.c @@ -45,6 +45,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astdb.h" #include "asterisk/utils.h" #include "asterisk/acl.h" +#include "asterisk/format_cache.h" +#include "asterisk/format_compatibility.h" #include "include/iax2.h" #include "include/provision.h" @@ -345,9 +347,10 @@ static int iax_template_parse(struct iax_template *cur, struct ast_config *cfg, } else ast_log(LOG_WARNING, "Ignoring invalid %s '%s' for '%s' at line %d\n", v->name, v->value, s, v->lineno); } else if (!strcasecmp(v->name, "codec")) { - struct ast_format tmpfmt; - if ((ast_getformatbyname(v->value, &tmpfmt)) > 0) { - cur->format = ast_format_to_old_bitfield(&tmpfmt); + struct ast_format *tmpfmt; + if ((tmpfmt = ast_format_cache_get(v->value))) { + cur->format = ast_format_compatibility_format2bitfield(tmpfmt); + ao2_ref(tmpfmt, -1); } else ast_log(LOG_WARNING, "Ignoring invalid codec '%s' for '%s' at line %d\n", v->value, s, v->lineno); } else if (!strcasecmp(v->name, "tos")) { |