summaryrefslogtreecommitdiff
path: root/main/format.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/format.c')
-rw-r--r--main/format.c1473
1 files changed, 201 insertions, 1272 deletions
diff --git a/main/format.c b/main/format.c
index c4ad45b7f..83206f28c 100644
--- a/main/format.c
+++ b/main/format.c
@@ -1,10 +1,9 @@
/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 2010, Digium, Inc.
+ * Copyright (C) 2014, Digium, Inc.
*
- * David Vossel <dvossel@digium.com>
- * Mark Spencer <markster@digium.com>
+ * Joshua Colp <jcolp@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
@@ -17,12 +16,11 @@
* at the top of the source tree.
*/
-/*!
- * \file
- * \brief Format API
+/*! \file
*
- * \author David Vossel <dvossel@digium.com>
- * \author Mark Spencer <markster@digium.com>
+ * \brief Media Format API
+ *
+ * \author Joshua Colp <jcolp@digium.com>
*/
/*** MODULEINFO
@@ -31,1420 +29,351 @@
#include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-#include "asterisk/_private.h"
+#include "asterisk/logger.h"
+#include "asterisk/codec.h"
#include "asterisk/format.h"
#include "asterisk/astobj2.h"
-#include "asterisk/lock.h"
-#include "asterisk/frame.h"
-#include "asterisk/utils.h"
-#include "asterisk/cli.h"
-#include "asterisk/rtp_engine.h"
-#include "asterisk/config.h"
-
-#define FORMAT_CONFIG "codecs.conf"
-
-/*!
- * \brief Container for all the format attribute interfaces.
- * \note This container uses RWLOCKs instead of MUTEX locks. .
- * \note An ao2 container was chosen for fast lookup.
- */
-static struct ao2_container *interfaces;
-
-/*! a wrapper is used put interfaces into the ao2 container. */
-struct interface_ao2_wrapper {
- enum ast_format_id id;
- const struct ast_format_attr_interface *interface;
+#include "asterisk/strings.h"
+
+/*! \brief Number of buckets to use for format interfaces (should be prime for performance reasons) */
+#define FORMAT_INTERFACE_BUCKETS 53
+
+/*! \brief Definition of a media format */
+struct ast_format {
+ /*! Name of the format */
+ const char *name;
+ /*! \brief Pointer to the codec in use for this format */
+ struct ast_codec *codec;
+ /*! \brief Attribute specific data, implementation specific */
+ void *attribute_data;
+ /*! \brief Pointer to the optional format interface */
+ const struct ast_format_interface *interface;
};
-/*! \brief Format List container, This container is never directly accessed outside
- * of this file, and It only exists for building the format_list_array. */
-static struct ao2_container *format_list;
-/*! \brief Format List array is a read only array protected by a read write lock.
- * This array may be used outside this file with the use of reference counting to
- * guarantee safety for access by multiple threads. */
-static struct ast_format_list *format_list_array;
-static size_t format_list_array_len = 0;
-/*! \brief Locks the format list array so a reference can be taken safely. */
-static ast_rwlock_t format_list_array_lock;
-
-static int interface_cmp_cb(void *obj, void *arg, int flags)
-{
- struct interface_ao2_wrapper *wrapper1 = obj;
- struct interface_ao2_wrapper *wrapper2 = arg;
-
- return (wrapper2->id == wrapper1->id) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-static int interface_hash_cb(const void *obj, const int flags)
-{
- const struct interface_ao2_wrapper *wrapper = obj;
- return wrapper->id;
-}
-
-void ast_format_copy(struct ast_format *dst, const struct ast_format *src)
-{
- *dst = *src;
-}
-
-void ast_format_set_video_mark(struct ast_format *format)
-{
- format->fattr.rtp_marker_bit = 1;
-}
-
-int ast_format_get_video_mark(const struct ast_format *format)
-{
- return format->fattr.rtp_marker_bit;
-}
-
-static struct interface_ao2_wrapper *find_interface(const struct ast_format *format)
-{
- struct interface_ao2_wrapper tmp_wrapper = {
- .id = format->id,
- };
+/*! \brief Structure used when registering a format interface */
+struct format_interface {
+ /*! \brief Pointer to the format interface itself */
+ const struct ast_format_interface *interface;
+ /*! \brief Name of the codec the interface is for */
+ char codec[0];
+};
- return ao2_find(interfaces, &tmp_wrapper, OBJ_POINTER);
-}
+/*! \brief Container for registered format interfaces */
+static struct ao2_container *interfaces;
-static int has_interface(const struct ast_format *format)
+static int format_interface_hash(const void *obj, int flags)
{
- struct interface_ao2_wrapper *wrapper;
+ const struct format_interface *format_interface;
+ const char *key;
- wrapper = find_interface(format);
- if (!wrapper) {
+ switch (flags & OBJ_SEARCH_MASK) {
+ case OBJ_SEARCH_KEY:
+ key = obj;
+ return ast_str_hash(key);
+ case OBJ_SEARCH_OBJECT:
+ format_interface = obj;
+ return ast_str_hash(format_interface->codec);
+ default:
+ /* Hash can only work on something with a full key. */
+ ast_assert(0);
return 0;
}
- ao2_ref(wrapper, -1);
- return 1;
}
-int ast_format_sdp_parse(struct ast_format *format, const char *attributes)
+static int format_interface_cmp(void *obj, void *arg, int flags)
{
- struct interface_ao2_wrapper *wrapper;
- int res;
+ const struct format_interface *left = obj;
+ const struct format_interface *right = arg;
+ const char *right_key = arg;
+ int cmp;
- if (!(wrapper = find_interface(format))) {
- return 0;
+ switch (flags & OBJ_SEARCH_MASK) {
+ case OBJ_SEARCH_OBJECT:
+ cmp = strcmp(left->codec, right->codec);
+ break;
+ case OBJ_SEARCH_KEY:
+ cmp = strcmp(left->codec, right_key);
+ break;
+ case OBJ_SEARCH_PARTIAL_KEY:
+ cmp = strncmp(left->codec, right_key, strlen(right_key));
+ break;
+ default:
+ ast_assert(0);
+ cmp = 0;
+ break;
}
-
- ao2_rdlock(wrapper);
- if (!wrapper->interface || !wrapper->interface->format_attr_sdp_parse) {
- ao2_unlock(wrapper);
- ao2_ref(wrapper, -1);
+ if (cmp) {
return 0;
}
- res = wrapper->interface->format_attr_sdp_parse(&format->fattr, attributes);
-
- ao2_unlock(wrapper);
- ao2_ref(wrapper, -1);
-
- return res;
+ return CMP_MATCH;
}
-void ast_format_sdp_generate(const struct ast_format *format, unsigned int payload, struct ast_str **str)
+/*! \brief Function called when the process is shutting down */
+static void format_shutdown(void)
{
- struct interface_ao2_wrapper *wrapper;
-
- if (!(wrapper = find_interface(format))) {
- return;
- }
-
- ao2_rdlock(wrapper);
- if (!wrapper->interface || !wrapper->interface->format_attr_sdp_generate) {
- ao2_unlock(wrapper);
- ao2_ref(wrapper, -1);
- return;
- }
-
- wrapper->interface->format_attr_sdp_generate(&format->fattr, payload, str);
-
- ao2_unlock(wrapper);
- ao2_ref(wrapper, -1);
+ ao2_cleanup(interfaces);
+ interfaces = NULL;
}
-/*! \internal
- * \brief set format attributes using an interface
- */
-static int format_set_helper(struct ast_format *format, va_list ap)
+int ast_format_init(void)
{
- struct interface_ao2_wrapper *wrapper;
-
- if (!(wrapper = find_interface(format))) {
- ast_log(LOG_WARNING, "Could not find format interface to set.\n");
- return -1;
- }
-
- ao2_rdlock(wrapper);
- if (!wrapper->interface || !wrapper->interface->format_attr_set) {
- ao2_unlock(wrapper);
- ao2_ref(wrapper, -1);
+ interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, FORMAT_INTERFACE_BUCKETS, format_interface_hash,
+ format_interface_cmp);
+ if (!interfaces) {
return -1;
}
- wrapper->interface->format_attr_set(&format->fattr, ap);
-
- ao2_unlock(wrapper);
- ao2_ref(wrapper, -1);
+ ast_register_atexit(format_shutdown);
return 0;
}
-struct ast_format *ast_format_append(struct ast_format *format, ... )
-{
- va_list ap;
- va_start(ap, format);
- format_set_helper(format, ap);
- va_end(ap);
-
- return format;
-}
-
-struct ast_format *ast_format_set(struct ast_format *format, enum ast_format_id id, int set_attributes, ... )
+int __ast_format_interface_register(const char *codec, const struct ast_format_interface *interface, struct ast_module *mod)
{
- /* initialize the structure before setting it. */
- ast_format_clear(format);
-
- format->id = id;
+ SCOPED_AO2WRLOCK(lock, interfaces);
+ struct format_interface *format_interface;
- if (set_attributes) {
- va_list ap;
- va_start(ap, set_attributes);
- format_set_helper(format, ap);
- va_end(ap);
+ if (!interface->format_clone || !interface->format_destroy) {
+ ast_log(LOG_ERROR, "Format interface for codec '%s' does not implement required callbacks\n", codec);
+ return -1;
}
- return format;
-}
-
-void ast_format_clear(struct ast_format *format)
-{
- format->id = 0;
- memset(&format->fattr, 0, sizeof(format->fattr));
-}
-
-/*! \internal
- * \brief determine if a list of attribute key value pairs are set on a format
- */
-static int format_isset_helper(const struct ast_format *format, va_list ap)
-{
- int res;
- struct interface_ao2_wrapper *wrapper;
- struct ast_format tmp = {
- .id = format->id,
- .fattr = { { 0, }, },
- };
-
- if (!(wrapper = find_interface(format))) {
+ format_interface = ao2_find(interfaces, codec, OBJ_SEARCH_KEY | OBJ_NOLOCK);
+ if (format_interface) {
+ ast_log(LOG_ERROR, "A format interface is already present for codec '%s'\n", codec);
+ ao2_ref(format_interface, -1);
return -1;
}
- ao2_rdlock(wrapper);
- if (!wrapper->interface ||
- !wrapper->interface->format_attr_set ||
- !wrapper->interface->format_attr_cmp) {
-
- ao2_unlock(wrapper);
- ao2_ref(wrapper, -1);
+ format_interface = ao2_alloc_options(sizeof(*format_interface) + strlen(codec) + 1,
+ NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+ if (!format_interface) {
return -1;
}
+ format_interface->interface = interface;
+ strcpy(format_interface->codec, codec); /* Safe */
- /* if isset is present, use that function, else just build a new
- * format and use the cmp function */
- if (wrapper->interface->format_attr_isset) {
- res = wrapper->interface->format_attr_isset(&format->fattr, ap);
- } else {
- wrapper->interface->format_attr_set(&tmp.fattr, ap);
- /* use our tmp structure to tell if the attributes are set or not */
- res = wrapper->interface->format_attr_cmp(&tmp.fattr, &format->fattr);
- res = (res == AST_FORMAT_CMP_NOT_EQUAL) ? -1 : 0;
- }
+ ao2_link_flags(interfaces, format_interface, OBJ_NOLOCK);
+ ao2_ref(format_interface, -1);
- ao2_unlock(wrapper);
- ao2_ref(wrapper, -1);
+ ast_verb(2, "Registered format interface for codec '%s'\n", codec);
- return res;
+ return 0;
}
-int ast_format_isset(const struct ast_format *format, ... )
+void *ast_format_get_attribute_data(const struct ast_format *format)
{
- va_list ap;
- int res;
-
- va_start(ap, format);
- res = format_isset_helper(format, ap);
- va_end(ap);
- return res;
+ return format->attribute_data;
}
-int ast_format_get_value(const struct ast_format *format, int key, void *value)
+void ast_format_set_attribute_data(struct ast_format *format, void *attribute_data)
{
- int res = 0;
- struct interface_ao2_wrapper *wrapper;
-
- if (!(wrapper = find_interface(format))) {
- return -1;
- }
- ao2_rdlock(wrapper);
- if (!wrapper->interface ||
- !wrapper->interface->format_attr_get_val) {
-
- ao2_unlock(wrapper);
- ao2_ref(wrapper, -1);
- return -1;
- }
-
- res = wrapper->interface->format_attr_get_val(&format->fattr, key, value);
-
- ao2_unlock(wrapper);
- ao2_ref(wrapper, -1);
-
- return res;
+ format->attribute_data = attribute_data;
}
-/*! \internal
- * \brief cmp format attributes using an interface
- */
-static enum ast_format_cmp_res format_cmp_helper(const struct ast_format *format1, const struct ast_format *format2)
+/*! \brief Destructor for media formats */
+static void format_destroy(void *obj)
{
- enum ast_format_cmp_res res = AST_FORMAT_CMP_EQUAL;
- struct interface_ao2_wrapper *wrapper;
+ struct ast_format *format = obj;
- if (!(wrapper = find_interface(format1))) {
- return res;
+ if (format->interface) {
+ format->interface->format_destroy(format);
}
- ao2_rdlock(wrapper);
- if (!wrapper->interface || !wrapper->interface->format_attr_cmp) {
- ao2_unlock(wrapper);
- ao2_ref(wrapper, -1);
- return res;
- }
-
- res = wrapper->interface->format_attr_cmp(&format1->fattr, &format2->fattr);
-
- ao2_unlock(wrapper);
- ao2_ref(wrapper, -1);
-
- return res;
+ ao2_cleanup(format->codec);
}
-enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
+struct ast_format *ast_format_create_named(const char *format_name, struct ast_codec *codec)
{
- if (format1->id != format2->id) {
- return AST_FORMAT_CMP_NOT_EQUAL;
- }
-
- return format_cmp_helper(format1, format2);
-}
+ struct ast_format *format;
+ struct format_interface *format_interface;
-/*! \internal
- * \brief get joint format attributes using an interface
- */
-static int format_joint_helper(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
-{
- int res = 0;
- struct interface_ao2_wrapper *wrapper;
-
- if (!(wrapper = find_interface(format1))) {
- /* if no interface is present, we assume formats are joint by id alone */
- return res;
+ format = ao2_t_alloc_options(sizeof(*format), format_destroy,
+ AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(codec->description, ""));
+ if (!format) {
+ return NULL;
}
+ format->name = format_name;
+ format->codec = ao2_bump(codec);
- ao2_rdlock(wrapper);
- if (wrapper->interface && wrapper->interface->format_attr_get_joint) {
- res = wrapper->interface->format_attr_get_joint(&format1->fattr, &format2->fattr, &result->fattr);
+ format_interface = ao2_find(interfaces, codec->name, OBJ_SEARCH_KEY);
+ if (format_interface) {
+ format->interface = format_interface->interface;
+ ao2_ref(format_interface, -1);
}
- ao2_unlock(wrapper);
-
- ao2_ref(wrapper, -1);
- return res;
+ return format;
}
-int ast_format_joint(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
+struct ast_format *ast_format_clone(const struct ast_format *format)
{
- if (format1->id != format2->id) {
- return -1;
- }
- result->id = format1->id;
- return format_joint_helper(format1, format2, result);
-}
+ struct ast_format *cloned = ast_format_create_named(format->name, format->codec);
-
-uint64_t ast_format_id_to_old_bitfield(enum ast_format_id id)
-{
- switch (id) {
- /*! G.723.1 compression */
- case AST_FORMAT_G723_1:
- return (1ULL << 0);
- /*! GSM compression */
- case AST_FORMAT_GSM:
- return (1ULL << 1);
- /*! Raw mu-law data (G.711) */
- case AST_FORMAT_ULAW:
- return (1ULL << 2);
- /*! Raw A-law data (G.711) */
- case AST_FORMAT_ALAW:
- return (1ULL << 3);
- /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
- case AST_FORMAT_G726_AAL2:
- return (1ULL << 4);
- /*! ADPCM (IMA) */
- case AST_FORMAT_ADPCM:
- return (1ULL << 5);
- /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
- case AST_FORMAT_SLINEAR:
- return (1ULL << 6);
- /*! LPC10, 180 samples/frame */
- case AST_FORMAT_LPC10:
- return (1ULL << 7);
- /*! G.729A audio */
- case AST_FORMAT_G729A:
- return (1ULL << 8);
- /*! SpeeX Free Compression */
- case AST_FORMAT_SPEEX:
- return (1ULL << 9);
- /*! iLBC Free Compression */
- case AST_FORMAT_ILBC:
- return (1ULL << 10);
- /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
- case AST_FORMAT_G726:
- return (1ULL << 11);
- /*! G.722 */
- case AST_FORMAT_G722:
- return (1ULL << 12);
- /*! G.722.1 (also known as Siren7, 32kbps assumed) */
- case AST_FORMAT_SIREN7:
- return (1ULL << 13);
- /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
- case AST_FORMAT_SIREN14:
- return (1ULL << 14);
- /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
- case AST_FORMAT_SLINEAR16:
- return (1ULL << 15);
- /*! G.719 (64 kbps assumed) */
- case AST_FORMAT_G719:
- return (1ULL << 32);
- /*! SpeeX Wideband (16kHz) Free Compression */
- case AST_FORMAT_SPEEX16:
- return (1ULL << 33);
- /*! Opus audio (8kHz, 16kHz, 24kHz, 48Khz) */
- case AST_FORMAT_OPUS:
- return (1ULL << 34);
- /*! Raw mu-law data (G.711) */
- case AST_FORMAT_TESTLAW:
- return (1ULL << 47);
-
- /*! H.261 Video */
- case AST_FORMAT_H261:
- return (1ULL << 18);
- /*! H.263 Video */
- case AST_FORMAT_H263:
- return (1ULL << 19);
- /*! H.263+ Video */
- case AST_FORMAT_H263_PLUS:
- return (1ULL << 20);
- /*! H.264 Video */
- case AST_FORMAT_H264:
- return (1ULL << 21);
- /*! MPEG4 Video */
- case AST_FORMAT_MP4_VIDEO:
- return (1ULL << 22);
- /*! VP8 Video */
- case AST_FORMAT_VP8:
- return (1ULL << 23);
-
- /*! JPEG Images */
- case AST_FORMAT_JPEG:
- return (1ULL << 16);
- /*! PNG Images */
- case AST_FORMAT_PNG:
- return (1ULL << 17);
-
- /*! T.140 RED Text format RFC 4103 */
- case AST_FORMAT_T140RED:
- return (1ULL << 26);
- /*! T.140 Text format - ITU T.140, RFC 4103 */
- case AST_FORMAT_T140:
- return (1ULL << 27);
- default:
- return 0; /* not supported by old bitfield. */
+ if (!cloned) {
+ return NULL;
}
- return 0;
-
-}
-uint64_t ast_format_to_old_bitfield(const struct ast_format *format)
-{
- return ast_format_id_to_old_bitfield(format->id);
-}
-
-struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t src)
-{
- switch (src) {
- /*! G.723.1 compression */
- case (1ULL << 0):
- return ast_format_set(dst, AST_FORMAT_G723_1, 0);
- /*! GSM compression */
- case (1ULL << 1):
- return ast_format_set(dst, AST_FORMAT_GSM, 0);
- /*! Raw mu-law data (G.711) */
- case (1ULL << 2):
- return ast_format_set(dst, AST_FORMAT_ULAW, 0);
- /*! Raw A-law data (G.711) */
- case (1ULL << 3):
- return ast_format_set(dst, AST_FORMAT_ALAW, 0);
- /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
- case (1ULL << 4):
- return ast_format_set(dst, AST_FORMAT_G726_AAL2, 0);
- /*! ADPCM (IMA) */
- case (1ULL << 5):
- return ast_format_set(dst, AST_FORMAT_ADPCM, 0);
- /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
- case (1ULL << 6):
- return ast_format_set(dst, AST_FORMAT_SLINEAR, 0);
- /*! LPC10, 180 samples/frame */
- case (1ULL << 7):
- return ast_format_set(dst, AST_FORMAT_LPC10, 0);
- /*! G.729A audio */
- case (1ULL << 8):
- return ast_format_set(dst, AST_FORMAT_G729A, 0);
- /*! SpeeX Free Compression */
- case (1ULL << 9):
- return ast_format_set(dst, AST_FORMAT_SPEEX, 0);
- /*! iLBC Free Compression */
- case (1ULL << 10):
- return ast_format_set(dst, AST_FORMAT_ILBC, 0);
- /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
- case (1ULL << 11):
- return ast_format_set(dst, AST_FORMAT_G726, 0);
- /*! G.722 */
- case (1ULL << 12):
- return ast_format_set(dst, AST_FORMAT_G722, 0);
- /*! G.722.1 (also known as Siren7, 32kbps assumed) */
- case (1ULL << 13):
- return ast_format_set(dst, AST_FORMAT_SIREN7, 0);
- /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
- case (1ULL << 14):
- return ast_format_set(dst, AST_FORMAT_SIREN14, 0);
- /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
- case (1ULL << 15):
- return ast_format_set(dst, AST_FORMAT_SLINEAR16, 0);
- /*! G.719 (64 kbps assumed) */
- case (1ULL << 32):
- return ast_format_set(dst, AST_FORMAT_G719, 0);
- /*! SpeeX Wideband (16kHz) Free Compression */
- case (1ULL << 33):
- return ast_format_set(dst, AST_FORMAT_SPEEX16, 0);
- /*! Opus audio (8kHz, 16kHz, 24kHz, 48Khz) */
- case (1ULL << 34):
- return ast_format_set(dst, AST_FORMAT_OPUS, 0);
- /*! Raw mu-law data (G.711) */
- case (1ULL << 47):
- return ast_format_set(dst, AST_FORMAT_TESTLAW, 0);
-
- /*! H.261 Video */
- case (1ULL << 18):
- return ast_format_set(dst, AST_FORMAT_H261, 0);
- /*! H.263 Video */
- case (1ULL << 19):
- return ast_format_set(dst, AST_FORMAT_H263, 0);
- /*! H.263+ Video */
- case (1ULL << 20):
- return ast_format_set(dst, AST_FORMAT_H263_PLUS, 0);
- /*! H.264 Video */
- case (1ULL << 21):
- return ast_format_set(dst, AST_FORMAT_H264, 0);
- /*! MPEG4 Video */
- case (1ULL << 22):
- return ast_format_set(dst, AST_FORMAT_MP4_VIDEO, 0);
- /*! VP8 Video */
- case (1ULL << 23):
- return ast_format_set(dst, AST_FORMAT_VP8, 0);
-
- /*! JPEG Images */
- case (1ULL << 16):
- return ast_format_set(dst, AST_FORMAT_JPEG, 0);
- /*! PNG Images */
- case (1ULL << 17):
- return ast_format_set(dst, AST_FORMAT_PNG, 0);
-
- /*! T.140 RED Text format RFC 4103 */
- case (1ULL << 26):
- return ast_format_set(dst, AST_FORMAT_T140RED, 0);
- /*! T.140 Text format - ITU T.140, RFC 4103 */
- case (1ULL << 27):
- return ast_format_set(dst, AST_FORMAT_T140, 0);
+ if (cloned->interface && cloned->interface->format_clone(format, cloned)) {
+ ao2_ref(cloned, -1);
+ return NULL;
}
- ast_format_clear(dst);
- return NULL;
-}
-enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src)
-{
- struct ast_format dst;
- if (ast_format_from_old_bitfield(&dst, src)) {
- return dst.id;
- }
- return 0;
+ return cloned;
}
-int ast_format_is_slinear(const struct ast_format *format)
+struct ast_format *ast_format_create(struct ast_codec *codec)
{
- if (format->id == AST_FORMAT_SLINEAR ||
- format->id == AST_FORMAT_SLINEAR12 ||
- format->id == AST_FORMAT_SLINEAR16 ||
- format->id == AST_FORMAT_SLINEAR24 ||
- format->id == AST_FORMAT_SLINEAR32 ||
- format->id == AST_FORMAT_SLINEAR44 ||
- format->id == AST_FORMAT_SLINEAR48 ||
- format->id == AST_FORMAT_SLINEAR96 ||
- format->id == AST_FORMAT_SLINEAR192) {
- return 1;
- }
- return 0;
+ return ast_format_create_named(codec->name, codec);
}
-enum ast_format_id ast_format_slin_by_rate(unsigned int rate)
+enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
{
- if (rate >= 192000) {
- return AST_FORMAT_SLINEAR192;
- } else if (rate >= 96000) {
- return AST_FORMAT_SLINEAR96;
- } else if (rate >= 48000) {
- return AST_FORMAT_SLINEAR48;
- } else if (rate >= 44100) {
- return AST_FORMAT_SLINEAR44;
- } else if (rate >= 32000) {
- return AST_FORMAT_SLINEAR32;
- } else if (rate >= 24000) {
- return AST_FORMAT_SLINEAR24;
- } else if (rate >= 16000) {
- return AST_FORMAT_SLINEAR16;
- } else if (rate >= 12000) {
- return AST_FORMAT_SLINEAR12;
- }
- return AST_FORMAT_SLINEAR;
-}
+ const struct ast_format_interface *interface;
-const char* ast_getformatname(const struct ast_format *format)
-{
- int x;
- const char *ret = "unknown";
- size_t f_len;
- 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) {
- ret = f_list[x].name;
- break;
- }
+ if (format1 == NULL || format2 == NULL) {
+ return AST_FORMAT_CMP_NOT_EQUAL;
}
- f_list = ast_format_list_destroy(f_list);
- return ret;
-}
-
-char *ast_getformatname_multiple_byid(char *buf, size_t size, enum ast_format_id id)
-{
- int x;
- unsigned len;
- char *start, *end = buf;
- size_t f_len;
- const struct ast_format_list *f_list = ast_format_list_get(&f_len);
-
- if (!size) {
- f_list = ast_format_list_destroy(f_list);
- return buf;
- }
- snprintf(end, size, "(");
- len = strlen(end);
- end += len;
- size -= len;
- start = end;
- for (x = 0; x < f_len; x++) {
- if (f_list[x].format.id == id) {
- snprintf(end, size, "%s|", f_list[x].name);
- len = strlen(end);
- end += len;
- size -= len;
- }
- }
- if (start == end) {
- ast_copy_string(start, "nothing)", size);
- } else if (size > 1) {
- *(end - 1) = ')';
+ if (format1 == format2) {
+ return AST_FORMAT_CMP_EQUAL;
}
- f_list = ast_format_list_destroy(f_list);
- return buf;
-}
-
-static struct ast_codec_alias_table {
- const char *alias;
- const char *realname;
-} ast_codec_alias_table[] = {
- { "slinear", "slin"},
- { "slinear16", "slin16"},
- { "g723.1", "g723"},
- { "g722.1", "siren7"},
- { "g722.1c", "siren14"},
-};
-static const char *ast_expand_codec_alias(const char *in)
-{
- int x;
-
- for (x = 0; x < ARRAY_LEN(ast_codec_alias_table); x++) {
- if (!strcmp(in,ast_codec_alias_table[x].alias))
- return ast_codec_alias_table[x].realname;
+ if (format1->codec != format2->codec) {
+ return AST_FORMAT_CMP_NOT_EQUAL;
}
- return in;
-}
-
-struct ast_format *ast_getformatbyname(const char *name, struct ast_format *result)
-{
- int x;
- size_t f_len;
- const struct ast_format_list *f_list = ast_format_list_get(&f_len);
- for (x = 0; x < f_len; x++) {
- if (!strcasecmp(f_list[x].name, name) ||
- !strcasecmp(f_list[x].name, ast_expand_codec_alias(name))) {
+ interface = format1->interface ? format1->interface : format2->interface;
- ast_format_copy(result, &f_list[x].format);
- f_list = ast_format_list_destroy(f_list);
- return result;
- }
+ if (interface) {
+ return interface->format_cmp(format1, format2);
}
- f_list = ast_format_list_destroy(f_list);
-
- return NULL;
-}
-const char *ast_codec2str(struct ast_format *format)
-{
- int x;
- const char *ret = "unknown";
- size_t f_len;
- 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) {
- ret = f_list[x].desc;
- break;
- }
- }
- f_list = ast_format_list_destroy(f_list);
- return ret;
+ return AST_FORMAT_CMP_EQUAL;
}
-int ast_format_rate(const struct ast_format *format)
+struct ast_format *ast_format_joint(const struct ast_format *format1, const struct ast_format *format2)
{
- switch (format->id) {
- case AST_FORMAT_SLINEAR12:
- return 12000;
- case AST_FORMAT_SLINEAR24:
- return 24000;
- case AST_FORMAT_SLINEAR32:
- return 32000;
- case AST_FORMAT_SLINEAR44:
- return 44100;
- case AST_FORMAT_SLINEAR48:
- return 48000;
- case AST_FORMAT_SLINEAR96:
- return 96000;
- case AST_FORMAT_SLINEAR192:
- return 192000;
- case AST_FORMAT_G722:
- case AST_FORMAT_SLINEAR16:
- case AST_FORMAT_SIREN7:
- case AST_FORMAT_SPEEX16:
- return 16000;
- case AST_FORMAT_SIREN14:
- case AST_FORMAT_SPEEX32:
- return 32000;
- case AST_FORMAT_G719:
- return 48000;
- case AST_FORMAT_SILK:
- if (!(ast_format_isset(format,
- SILK_ATTR_KEY_SAMP_RATE,
- SILK_ATTR_VAL_SAMP_24KHZ,
- AST_FORMAT_ATTR_END))) {
- return 24000;
- } else if (!(ast_format_isset(format,
- SILK_ATTR_KEY_SAMP_RATE,
- SILK_ATTR_VAL_SAMP_16KHZ,
- AST_FORMAT_ATTR_END))) {
- return 16000;
- } else if (!(ast_format_isset(format,
- SILK_ATTR_KEY_SAMP_RATE,
- SILK_ATTR_VAL_SAMP_12KHZ,
- AST_FORMAT_ATTR_END))) {
- return 12000;
- } else {
- return 8000;
- }
- case AST_FORMAT_CELT:
- {
- int samplerate;
- if (!(ast_format_get_value(format,
- CELT_ATTR_KEY_SAMP_RATE,
- &samplerate))) {
- return samplerate;
- }
- }
- /* Opus */
- case AST_FORMAT_OPUS:
- return 48000;
- default:
- return 8000;
- }
-}
+ const struct ast_format_interface *interface;
-static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
- int x, found=0;
- size_t f_len;
- const struct ast_format_list *f_list;
-
- switch (cmd) {
- case CLI_INIT:
- e->command = "core show codecs [audio|video|image|text]";
- e->usage =
- "Usage: core show codecs [audio|video|image|text]\n"
- " Displays codec mapping\n";
- return NULL;
- case CLI_GENERATE:
+ if (format1->codec != format2->codec) {
return NULL;
}
- if ((a->argc < 3) || (a->argc > 4)) {
- return CLI_SHOWUSAGE;
+ /* If the two formats are the same structure OR if the codec is the same and no attributes
+ * exist we can immediately return a format with reference count bumped up, since they are
+ * the same.
+ */
+ if ((ast_format_cmp(format1, format2) == AST_FORMAT_CMP_EQUAL && !format1->attribute_data && !format2->attribute_data)) {
+ return ao2_bump((struct ast_format*)format1);
}
- f_list = ast_format_list_get(&f_len);
- if (!ast_opt_dont_warn) {
- ast_cli(a->fd, "Disclaimer: this command is for informational purposes only.\n"
- "\tIt does not indicate anything about your configuration.\n");
- }
+ interface = format1->interface ? format1->interface : format2->interface;
- ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION");
- ast_cli(a->fd, "-----------------------------------------------------------------------------------\n");
-
- for (x = 0; x < f_len; x++) {
- if (a->argc == 4) {
- if (!strcasecmp(a->argv[3], "audio")) {
- if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_AUDIO) {
- continue;
- }
- } else if (!strcasecmp(a->argv[3], "video")) {
- if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_VIDEO) {
- continue;
- }
- } else if (!strcasecmp(a->argv[3], "image")) {
- if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_IMAGE) {
- continue;
- }
- } else if (!strcasecmp(a->argv[3], "text")) {
- if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_TEXT) {
- continue;
- }
- } else {
- continue;
- }
- }
-
- ast_cli(a->fd, "%8u %5s %8s (%s)\n",
- f_list[x].format.id,
- (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_AUDIO) ? "audio" :
- (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_IMAGE) ? "image" :
- (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_VIDEO) ? "video" :
- (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_TEXT) ? "text" :
- "(unk)",
- f_list[x].name,
- f_list[x].desc);
- found = 1;
- }
-
- f_list = ast_format_list_destroy(f_list);
- if (!found) {
- return CLI_SHOWUSAGE;
- } else {
- return CLI_SUCCESS;
- }
+ /* If there is attribute data on either there has to be an interface */
+ return interface->format_get_joint(format1, format2);
}
-static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+struct ast_format *ast_format_attribute_set(const struct ast_format *format, const char *name, const char *value)
{
- enum ast_format_id format_id;
- int x, found = 0;
- int type_punned_codec;
- size_t f_len;
- const struct ast_format_list *f_list;
-
- switch (cmd) {
- case CLI_INIT:
- e->command = "core show codec";
- e->usage =
- "Usage: core show codec <number>\n"
- " Displays codec mapping\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
-
- if (a->argc != 4) {
- return CLI_SHOWUSAGE;
- }
+ const struct ast_format_interface *interface = format->interface;
- if (sscanf(a->argv[3], "%30d", &type_punned_codec) != 1) {
- return CLI_SHOWUSAGE;
- }
- format_id = type_punned_codec;
-
- f_list = ast_format_list_get(&f_len);
- for (x = 0; x < f_len; x++) {
- if (f_list[x].format.id == format_id) {
- found = 1;
- ast_cli(a->fd, "%11u %s\n", (unsigned int) format_id, f_list[x].desc);
+ if (!interface) {
+ struct format_interface *format_interface = ao2_find(interfaces, format->codec->name, OBJ_SEARCH_KEY);
+ if (format_interface) {
+ interface = format_interface->interface;
+ ao2_ref(format_interface, -1);
}
}
- if (!found) {
- ast_cli(a->fd, "Codec %u not found\n", format_id);
+ if (!interface || !interface->format_attribute_set) {
+ return ao2_bump((struct ast_format*)format);
}
- f_list = ast_format_list_destroy(f_list);
- return CLI_SUCCESS;
+ return interface->format_attribute_set(format, name, value);
}
-/* Builtin Asterisk CLI-commands for debugging */
-static struct ast_cli_entry my_clis[] = {
- AST_CLI_DEFINE(show_codecs, "Displays a list of codecs"),
- AST_CLI_DEFINE(show_codec_n, "Shows a specific codec"),
-};
-
-static int format_list_add_custom(struct ast_format_list *new)
+struct ast_format *ast_format_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
{
- RAII_VAR(struct ast_format_list *, entry, NULL, ao2_cleanup);
- if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
- return -1;
- }
- memcpy(entry, new, sizeof(struct ast_format_list));
- entry->custom_entry = 1;
- ao2_link(format_list, entry);
- return 0;
-}
-static int format_list_add_static(
- const struct ast_format *format,
- const char *name,
- int samplespersecond,
- const char *description,
- int fr_len,
- int min_ms,
- int max_ms,
- int inc_ms,
- int def_ms,
- unsigned int flags,
- int cur_ms)
-{
- struct ast_format_list *entry;
- if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
- return -1;
- }
- ast_format_copy(&entry->format, format);
- ast_copy_string(entry->name, name, sizeof(entry->name));
- ast_copy_string(entry->desc, description, sizeof(entry->desc));
- entry->samplespersecond = samplespersecond;
- entry->fr_len = fr_len;
- entry->min_ms = min_ms;
- entry->max_ms = max_ms;
- entry->inc_ms = inc_ms;
- entry->def_ms = def_ms;
- entry->flags = flags;
- entry->cur_ms = cur_ms;
- entry->custom_entry = 0;
-
- ao2_link(format_list, entry);
- ao2_ref(entry, -1);
- return 0;
-}
+ const struct ast_format_interface *interface = format->interface;
-static int list_all_custom(void *obj, void *arg, int flag)
-{
- struct ast_format_list *entry = obj;
- return entry->custom_entry ? CMP_MATCH : 0;
-}
-
-static int list_cmp_cb(void *obj, void *arg, int flags)
-{
- struct ast_format_list *entry1 = obj;
- struct ast_format_list *entry2 = arg;
-
- return (ast_format_cmp(&entry1->format, &entry2->format) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH | CMP_STOP : 0;
-}
-
-const struct ast_format_list *ast_format_list_get(size_t *size)
-{
- struct ast_format_list *list;
- ast_rwlock_rdlock(&format_list_array_lock);
- ao2_ref(format_list_array, 1);
- list = format_list_array;
- *size = format_list_array_len;
- ast_rwlock_unlock(&format_list_array_lock);
- return list;
-}
-const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list)
-{
- ao2_ref((void *) list, -1);
- return NULL;
-}
-
-static int build_format_list_array(void)
-{
- struct ast_format_list *tmp;
- size_t arraysize = sizeof(struct ast_format_list) * ao2_container_count(format_list);
- int i = 0;
- struct ao2_iterator it;
-
- ast_rwlock_wrlock(&format_list_array_lock);
- tmp = format_list_array;
- if (!(format_list_array = ao2_alloc(arraysize, NULL))) {
- format_list_array = tmp;
- ast_rwlock_unlock(&format_list_array_lock);
- return -1;
- }
- format_list_array_len = ao2_container_count(format_list);
- if (tmp) {
- ao2_ref(tmp, -1);
+ if (!interface) {
+ struct format_interface *format_interface = ao2_find(interfaces, format->codec->name, OBJ_SEARCH_KEY);
+ if (format_interface) {
+ interface = format_interface->interface;
+ ao2_ref(format_interface, -1);
+ }
}
- /* walk through the container adding elements to the static array */
- it = ao2_iterator_init(format_list, 0);
- while ((tmp = ao2_iterator_next(&it)) && (i < format_list_array_len)) {
- memcpy(&format_list_array[i], tmp, sizeof(struct ast_format_list));
- ao2_ref(tmp, -1);
- i++;
+ if (!interface || !interface->format_parse_sdp_fmtp) {
+ return ao2_bump((struct ast_format*)format);
}
- ao2_iterator_destroy(&it);
- ast_rwlock_unlock(&format_list_array_lock);
- return 0;
+ return interface->format_parse_sdp_fmtp(format, attributes);
}
-static int format_list_init(void)
+void ast_format_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
{
- struct ast_format tmpfmt;
- if (!(format_list = ao2_container_alloc(1, NULL, list_cmp_cb))) {
- return -1;
+ if (!format->interface || !format->interface->format_generate_sdp_fmtp) {
+ return;
}
- /* initiate static entries XXX DO NOT CHANGE THIS ORDER! */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0), "g723", 8000, "G.723.1", 20, 30, 300, 30, 30, 0, 0); /*!< G723.1 */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0), "gsm", 8000, "GSM", 33, 20, 300, 20, 20, 0, 0); /*!< codec_gsm.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), "ulaw", 8000, "G.711 u-law", 80, 10, 150, 10, 20, 0, 0); /*!< codec_ulaw.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0), "alaw", 8000, "G.711 A-law", 80, 10, 150, 10, 20, 0, 0); /*!< codec_alaw.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G726, 0), "g726", 8000, "G.726 RFC3551", 40, 10, 300, 10, 20, 0, 0); /*!< codec_g726.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), "adpcm" , 8000, "Dialogic ADPCM", 40, 10, 300, 10, 20, 0, 0); /*!< codec_adpcm.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0), "slin", 8000, "16 bit Signed Linear PCM", 160, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0); /*!< Signed linear */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_LPC10, 0), "lpc10", 8000, "LPC10", 7, 20, 20, 20, 20, 0, 0); /*!< codec_lpc10.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0), "g729", 8000, "G.729A", 10, 10, 230, 10, 20, AST_SMOOTHER_FLAG_G729, 0); /*!< Binary commercial distribution */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX, 0), "speex", 8000, "SpeeX", 10, 10, 60, 10, 20, 0, 0); /*!< codec_speex.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX16, 0), "speex16", 16000, "SpeeX 16khz", 10, 10, 60, 10, 20, 0, 0); /*!< codec_speex.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ILBC, 0), "ilbc", 8000, "iLBC", 50, 30, 30, 30, 30, 0, 0); /*!< codec_ilbc.c */ /* inc=30ms - workaround */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G726_AAL2, 0), "g726aal2", 8000, "G.726 AAL2", 40, 10, 300, 10, 20, 0, 0); /*!< codec_g726.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G722, 0), "g722", 16000, "G722", 80, 10, 150, 10, 20, 0, 0); /*!< codec_g722.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0), "slin16", 16000, "16 bit Signed Linear PCM (16kHz)", 320, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (16kHz) */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_JPEG, 0), "jpeg", 0, "JPEG image", 0, 0, 0, 0 ,0 ,0 ,0); /*!< See format_jpeg.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_PNG, 0), "png", 0, "PNG image", 0, 0, 0, 0 ,0 ,0 ,0); /*!< PNG Image format */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H261, 0), "h261", 0, "H.261 Video", 0, 0, 0, 0 ,0 ,0 ,0); /*!< H.261 Video Passthrough */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H263, 0), "h263", 0, "H.263 Video", 0, 0, 0, 0 ,0 ,0 ,0); /*!< H.263 Passthrough support, see format_h263.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), "h263p", 0, "H.263+ Video", 0, 0, 0,0 ,0 ,0, 0); /*!< H.263plus passthrough support See format_h263.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), "h264", 0, "H.264 Video", 0, 0, 0, 0 ,0 ,0, 0); /*!< Passthrough support, see format_h263.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_MP4_VIDEO, 0), "mpeg4", 0, "MPEG4 Video", 0, 0, 0, 0, 0 ,0, 0); /*!< Passthrough support for MPEG4 */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_T140RED, 0), "red", 1, "T.140 Realtime Text with redundancy", 0, 0, 0,0 ,0 ,0, 0); /*!< Redundant T.140 Realtime Text */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_T140, 0), "t140", 0, "Passthrough T.140 Realtime Text", 0, 0, 0, 0 ,0 ,0, 0); /*!< Passthrough support for T.140 Realtime Text */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SIREN7, 0), "siren7", 16000, "ITU G.722.1 (Siren7, licensed from Polycom)", 80, 20, 80, 20, 20, 0, 0); /*!< Binary commercial distribution */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SIREN14, 0), "siren14", 32000, "ITU G.722.1 Annex C, (Siren14, licensed from Polycom)", 120, 20, 80, 20, 20, 0, 0); /*!< Binary commercial distribution */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_TESTLAW, 0), "testlaw", 8000, "G.711 test-law", 80, 10, 150, 10, 20, 0, 0); /*!< codec_ulaw.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20, 0, 0);
-
- /* ORDER MAY CHANGE AFTER THIS POINT IN THE LIST */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX32, 0), "speex32", 32000, "SpeeX 32khz", 10, 10, 60, 10, 20, 0, 0); /*!< codec_speex.c */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR12, 0), "slin12", 12000, "16 bit Signed Linear PCM (12kHz)", 240, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (12kHz) */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR24, 0), "slin24", 24000, "16 bit Signed Linear PCM (24kHz)", 480, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (24kHz) */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR32, 0), "slin32", 32000, "16 bit Signed Linear PCM (32kHz)", 640, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (32kHz) */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR44, 0), "slin44", 44100, "16 bit Signed Linear PCM (44kHz)", 882, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (44.1kHz) */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR48, 0), "slin48", 48000, "16 bit Signed Linear PCM (48kHz)", 960, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (48kHz) */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR96, 0), "slin96", 96000, "16 bit Signed Linear PCM (96kHz)", 1920, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (96kHz) */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR192, 0), "slin192", 192000, "16 bit Signed Linear PCM (192kHz)", 3840, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (192kHz) */
- /* Opus (FIXME: real min is 3/5/10, real max is 120...) */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_OPUS, 0), "opus", 48000, "Opus Codec", 10, 20, 60, 20, 20, 0, 0); /*!< codec_opus.c */
- /* VP8 (passthrough) */
- format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_VP8, 0), "vp8", 0, "VP8 Video", 0, 0, 0, 0 ,0 ,0, 0); /*!< Passthrough support, see format_h263.c */
- return 0;
+ format->interface->format_generate_sdp_fmtp(format, payload, str);
}
-/*!
- * \internal
- * \brief Clean up resources on Asterisk shutdown
- */
-static void format_list_shutdown(void)
+unsigned int ast_format_get_codec_id(const struct ast_format *format)
{
- ast_rwlock_destroy(&format_list_array_lock);
- if (format_list) {
- ao2_t_ref(format_list, -1, "Unref format_list container in shutdown");
- format_list = NULL;
- }
- if (format_list_array) {
- ao2_t_ref(format_list_array, -1, "Unref format_list_array in shutdown");
- format_list_array = NULL;
- }
+ return format->codec->id;
}
-int ast_format_list_init(void)
+const char *ast_format_get_name(const struct ast_format *format)
{
- if (ast_rwlock_init(&format_list_array_lock)) {
- return -1;
- }
- if (format_list_init()) {
- goto init_list_cleanup;
- }
- if (build_format_list_array()) {
- goto init_list_cleanup;
- }
-
- ast_register_atexit(format_list_shutdown);
- return 0;
-init_list_cleanup:
-
- format_list_shutdown();
- return -1;
+ return format->name;
}
-/*!
- * \internal
- * \brief Clean up resources on Asterisk shutdown
- */
-static void format_attr_shutdown(void)
+const char *ast_format_get_codec_name(const struct ast_format *format)
{
- ast_cli_unregister_multiple(my_clis, ARRAY_LEN(my_clis));
- if (interfaces) {
- ao2_ref(interfaces, -1);
- interfaces = NULL;
- }
+ return format->codec->name;
}
-int ast_format_attr_init(void)
+int ast_format_can_be_smoothed(const struct ast_format *format)
{
- interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK,
- 283, interface_hash_cb, interface_cmp_cb);
- if (!interfaces) {
- return -1;
- }
-
- ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
- ast_register_cleanup(format_attr_shutdown);
- return 0;
+ return format->codec->smooth;
}
-static int custom_celt_format(struct ast_format_list *entry, unsigned int maxbitrate, unsigned int framesize)
+enum ast_media_type ast_format_get_type(const struct ast_format *format)
{
- if (!entry->samplespersecond) {
- ast_log(LOG_WARNING, "Custom CELT format definition '%s' requires sample rate to be defined.\n", entry->name);
- }
- ast_format_set(&entry->format, AST_FORMAT_CELT, 0);
- if (!has_interface(&entry->format)) {
- return -1;
- }
-
- snprintf(entry->desc, sizeof(entry->desc), "CELT Custom Format %ukhz", entry->samplespersecond/1000);
-
- ast_format_append(&entry->format,
- CELT_ATTR_KEY_SAMP_RATE, entry->samplespersecond,
- CELT_ATTR_KEY_MAX_BITRATE, maxbitrate,
- CELT_ATTR_KEY_FRAME_SIZE, framesize,
- AST_FORMAT_ATTR_END);
-
- entry->fr_len = 80;
- entry->min_ms = 20;
- entry->max_ms = 20;
- entry->inc_ms = 20;
- entry->def_ms = 20;
- return 0;
+ return format->codec->type;
}
-static int custom_silk_format(struct ast_format_list *entry, unsigned int maxbitrate, int usedtx, int usefec, int packetloss_percentage)
+unsigned int ast_format_get_default_ms(const struct ast_format *format)
{
- if (!entry->samplespersecond) {
- ast_log(LOG_WARNING, "Custom SILK format definition '%s' requires sample rate to be defined.\n", entry->name);
- }
- ast_format_set(&entry->format, AST_FORMAT_SILK, 0);
-
- if (!has_interface(&entry->format)) {
- return -1;
- }
-
- switch (entry->samplespersecond) {
- case 8000:
- ast_copy_string(entry->desc, "SILK Custom Format 8khz", sizeof(entry->desc));
- ast_format_append(&entry->format,
- SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_8KHZ,
- AST_FORMAT_ATTR_END);
- break;
- case 12000:
- ast_copy_string(entry->desc, "SILK Custom Format 12khz", sizeof(entry->desc));
- ast_format_append(&entry->format,
- SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_12KHZ,
- AST_FORMAT_ATTR_END);
- break;
- case 16000:
- ast_copy_string(entry->desc, "SILK Custom Format 16khz", sizeof(entry->desc));
- ast_format_append(&entry->format,
- SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_16KHZ,
- AST_FORMAT_ATTR_END);
- break;
- case 24000:
- ast_copy_string(entry->desc, "SILK Custom Format 24khz", sizeof(entry->desc));
- ast_format_append(&entry->format,
- SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_24KHZ,
- AST_FORMAT_ATTR_END);
- break;
- default:
- ast_log(LOG_WARNING, "Custom SILK format definition '%s' can not support sample rate %u\n", entry->name, entry->samplespersecond);
- return -1;
- }
- ast_format_append(&entry->format,
- SILK_ATTR_KEY_MAX_BITRATE, maxbitrate,
- SILK_ATTR_KEY_DTX, usedtx ? 1 : 0,
- SILK_ATTR_KEY_FEC, usefec ? 1 : 0,
- SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE, packetloss_percentage,
- AST_FORMAT_ATTR_END);
-
- entry->fr_len = 80;
- entry->min_ms = 20;
- entry->max_ms = 20;
- entry->inc_ms = 20;
- entry->def_ms = 20;
- return 0;
+ return format->codec->default_ms;
}
-static int conf_process_format_name(const char *name, enum ast_format_id *id)
+unsigned int ast_format_get_minimum_ms(const struct ast_format *format)
{
- if (!strcasecmp(name, "silk")) {
- *id = AST_FORMAT_SILK;
- } else if (!strcasecmp(name, "celt")) {
- *id = AST_FORMAT_CELT;
- } else {
- *id = 0;
- return -1;
- }
- return 0;
+ return format->codec->minimum_ms;
}
-static int conf_process_sample_rate(const char *rate, unsigned int *result)
+unsigned int ast_format_get_maximum_ms(const struct ast_format *format)
{
- if (!strcasecmp(rate, "8000")) {
- *result = 8000;
- } else if (!strcasecmp(rate, "12000")) {
- *result = 12000;
- } else if (!strcasecmp(rate, "16000")) {
- *result = 16000;
- } else if (!strcasecmp(rate, "24000")) {
- *result = 24000;
- } else if (!strcasecmp(rate, "32000")) {
- *result = 32000;
- } else if (!strcasecmp(rate, "44100")) {
- *result = 44100;
- } else if (!strcasecmp(rate, "48000")) {
- *result = 48000;
- } else if (!strcasecmp(rate, "96000")) {
- *result = 96000;
- } else if (!strcasecmp(rate, "192000")) {
- *result = 192000;
- } else {
- *result = 0;
- return -1;
- }
-
- return 0;
+ return format->codec->maximum_ms;
}
-static int load_format_config(void)
-{
- struct ast_flags config_flags = { 0, };
- struct ast_config *cfg = ast_config_load(FORMAT_CONFIG, config_flags);
- struct ast_format_list entry;
- struct ast_variable *var;
- char *cat = NULL;
- int add_it = 0;
-
- struct {
- enum ast_format_id id;
- unsigned int maxbitrate;
- unsigned int framesize;
- unsigned int packetloss_percentage;
- int usefec;
- int usedtx;
- } settings;
-
- if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
- return 0;
- }
-
- /* remove all custom formats from the AO2 Container. Note, this has no affect on the
- * global format list until the list is rebuild. That is why this is okay to do while
- * reloading the config. */
- ao2_callback(format_list, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, list_all_custom, NULL);
- while ((cat = ast_category_browse(cfg, cat))) {
- memset(&entry, 0, sizeof(entry));
- memset(&settings, 0, sizeof(settings));
- add_it = 0;
-
- if (!(ast_variable_retrieve(cfg, cat, "type"))) {
- continue;
- }
- ast_copy_string(entry.name, cat, sizeof(entry.name));
- var = ast_variable_browse(cfg, cat);
- for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
- if (!strcasecmp(var->name, "type") && conf_process_format_name(var->value, &settings.id)) {
- ast_log(LOG_WARNING, "Can not make custom format type for '%s' at line %d of %s\n",
- var->value, var->lineno, FORMAT_CONFIG);
- continue;
- } else if (!strcasecmp(var->name, "samprate") && conf_process_sample_rate(var->value, &entry.samplespersecond)) {
- ast_log(LOG_WARNING, "Sample rate '%s' at line %d of %s is not supported.\n",
- var->value, var->lineno, FORMAT_CONFIG);
- } else if (!strcasecmp(var->name, "maxbitrate")) {
- if (sscanf(var->value, "%30u", &settings.maxbitrate) != 1) {
- ast_log(LOG_WARNING, "maxbitrate '%s' at line %d of %s is not supported.\n",
- var->value, var->lineno, FORMAT_CONFIG);
- }
- } else if (!strcasecmp(var->name, "framesize")) {
- if (sscanf(var->value, "%30u", &settings.framesize) != 1) {
- ast_log(LOG_WARNING, "framesize '%s' at line %d of %s is not supported.\n",
- var->value, var->lineno, FORMAT_CONFIG);
- }
- } else if (!strcasecmp(var->name, "dtx")) {
- settings.usedtx = ast_true(var->value) ? 1 : 0;
- } else if (!strcasecmp(var->name, "fec")) {
- settings.usefec = ast_true(var->value) ? 1 : 0;
- } else if (!strcasecmp(var->name, "packetloss_percentage")) {
- if ((sscanf(var->value, "%30u", &settings.packetloss_percentage) != 1) || (settings.packetloss_percentage > 100)) {
- ast_log(LOG_WARNING, "packetloss_percentage '%s' at line %d of %s is not supported.\n",
- var->value, var->lineno, FORMAT_CONFIG);
- }
- }
- }
-
- switch (settings.id) {
- case AST_FORMAT_SILK:
- if (!(custom_silk_format(&entry, settings.maxbitrate, settings.usedtx, settings.usefec, settings.packetloss_percentage))) {
- add_it = 1;
- }
- break;
- case AST_FORMAT_CELT:
- if (!(custom_celt_format(&entry, settings.maxbitrate, settings.framesize))) {
- add_it = 1;
- }
- break;
- default:
- ast_log(LOG_WARNING, "Can not create custom format %s\n", entry.name);
- }
-
- if (add_it) {
- format_list_add_custom(&entry);
- }
- }
- ast_config_destroy(cfg);
- build_format_list_array();
- return 0;
+unsigned int ast_format_get_minimum_bytes(const struct ast_format *format)
+{
+ return format->codec->minimum_bytes;
}
-int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface)
+unsigned int ast_format_get_sample_rate(const struct ast_format *format)
{
- int x;
- size_t f_len;
- const struct ast_format_list *f_list;
- struct interface_ao2_wrapper *wrapper;
- struct interface_ao2_wrapper tmp_wrapper = {
- .id = interface->id,
- };
-
- /*
- * Grab the write lock before checking for duplicates in
- * anticipation of adding a new interface and to prevent a
- * duplicate from sneaking in between the check and add.
- */
- ao2_wrlock(interfaces);
-
- /* check for duplicates first*/
- if ((wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
- ao2_unlock(interfaces);
- ast_log(LOG_WARNING, "Can not register attribute interface for format id %u, interface already exists.\n", interface->id);
- ao2_ref(wrapper, -1);
- return -1;
- }
-
- wrapper = ao2_alloc_options(sizeof(*wrapper), NULL, AO2_ALLOC_OPT_LOCK_RWLOCK);
- if (!wrapper) {
- ao2_unlock(interfaces);
- return -1;
- }
-
- wrapper->interface = interface;
- wrapper->id = interface->id;
-
- /* The write lock is already held. */
- ao2_link_flags(interfaces, wrapper, OBJ_NOLOCK);
- ao2_unlock(interfaces);
-
- ao2_ref(wrapper, -1);
-
- /* This will find all custom formats in codecs.conf for this new registered interface */
- load_format_config();
-
- /* update the RTP engine to all custom formats created for this interface */
- f_list = ast_format_list_get(&f_len);
- for (x = 0; x < f_len; x++) {
- if (f_list[x].format.id == tmp_wrapper.id) {
- ast_rtp_engine_load_format(&f_list[x].format);
- }
- }
- f_list = ast_format_list_destroy(f_list);
- return 0;
+ return format->codec->sample_rate;
}
-int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface)
+unsigned int ast_format_determine_length(const struct ast_format *format, unsigned int samples)
{
- int x;
- size_t f_len;
- const struct ast_format_list *f_list;
- struct interface_ao2_wrapper *wrapper;
- struct interface_ao2_wrapper tmp_wrapper = {
- .id = interface->id,
- };
-
- if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK)))) {
- return -1;
- }
-
- ao2_wrlock(wrapper);
- wrapper->interface = NULL;
- ao2_unlock(wrapper);
-
- ao2_ref(wrapper, -1);
-
- /* update the RTP engine to remove all custom formats created for this interface */
- f_list = ast_format_list_get(&f_len);
- for (x = 0; x < f_len; x++) {
- if (f_list[x].format.id == tmp_wrapper.id) {
- ast_rtp_engine_unload_format(&f_list[x].format);
- }
- }
-
- /* This will remove all custom formats previously created for this interface */
- load_format_config();
- f_list = ast_format_list_destroy(f_list);
- return 0;
+ return ast_codec_determine_length(format->codec, samples);
}