[asterisk-commits] file: branch file/media_formats-impl r407440 - in /team/file/media_formats-im...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Feb 5 12:44:38 CST 2014
Author: file
Date: Wed Feb 5 12:44:31 2014
New Revision: 407440
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=407440
Log:
Add media formats API, implementation, and unit tests that are currently up for review.
Added:
team/file/media_formats-impl/include/asterisk/codec.h
- copied unchanged from r407196, team/group/media_formats/include/asterisk/codec.h
team/file/media_formats-impl/include/asterisk/format_cache.h
- copied unchanged from r407196, team/group/media_formats/include/asterisk/format_cache.h
team/file/media_formats-impl/include/asterisk/format_cap_ng.h
- copied unchanged from r407196, team/group/media_formats/include/asterisk/format_cap_ng.h
team/file/media_formats-impl/include/asterisk/format_ng.h
- copied unchanged from r407196, team/group/media_formats/include/asterisk/format_ng.h
team/file/media_formats-impl/include/asterisk/smoother.h
- copied unchanged from r407196, team/group/media_formats/include/asterisk/smoother.h
team/file/media_formats-impl/main/codec.c
- copied unchanged from r407196, team/group/media_formats/main/codec.c
team/file/media_formats-impl/main/codec_builtin.c
- copied unchanged from r407196, team/group/media_formats/main/codec_builtin.c
team/file/media_formats-impl/main/format_cache.c
- copied unchanged from r407196, team/group/media_formats/main/format_cache.c
team/file/media_formats-impl/main/format_cap_ng.c
- copied unchanged from r407196, team/group/media_formats/main/format_cap_ng.c
team/file/media_formats-impl/main/format_ng.c
- copied unchanged from r407196, team/group/media_formats/main/format_ng.c
team/file/media_formats-impl/main/smoother.c
- copied unchanged from r407196, team/group/media_formats/main/smoother.c
team/file/media_formats-impl/tests/test_core_codec.c
- copied unchanged from r407196, team/group/media_formats/tests/test_core_codec.c
team/file/media_formats-impl/tests/test_core_format.c
- copied unchanged from r407196, team/group/media_formats/tests/test_core_format.c
team/file/media_formats-impl/tests/test_format_cache.c
- copied unchanged from r407196, team/group/media_formats/tests/test_format_cache.c
team/file/media_formats-impl/tests/test_format_cap.c
- copied unchanged from r407196, team/group/media_formats/tests/test_format_cap.c
Modified:
team/file/media_formats-impl/include/asterisk/format.h
team/file/media_formats-impl/include/asterisk/frame.h
team/file/media_formats-impl/include/asterisk/vector.h
team/file/media_formats-impl/main/asterisk.c
team/file/media_formats-impl/main/format.c
team/file/media_formats-impl/main/frame.c
team/file/media_formats-impl/res/res_fax.c
team/file/media_formats-impl/res/res_rtp_asterisk.c
Modified: team/file/media_formats-impl/include/asterisk/format.h
URL: http://svnview.digium.com/svn/asterisk/team/file/media_formats-impl/include/asterisk/format.h?view=diff&rev=407440&r1=407439&r2=407440
==============================================================================
--- team/file/media_formats-impl/include/asterisk/format.h (original)
+++ team/file/media_formats-impl/include/asterisk/format.h Wed Feb 5 12:44:31 2014
@@ -30,6 +30,10 @@
#include "asterisk/silk.h"
#include "asterisk/celt.h"
#include "asterisk/opus.h"
+
+struct ast_format_cap;
+struct ast_codec_pref;
+
#define AST_FORMAT_ATTR_SIZE 64
#define AST_FORMAT_INC 100000
@@ -451,6 +455,18 @@
*/
int ast_format_rate(const struct ast_format *format);
+/*! \brief Returns the number of samples contained in the frame */
+int ast_codec_get_samples(struct ast_frame *f);
+
+/*! \brief Returns the number of bytes for the number of samples of the given format */
+int ast_codec_get_len(struct ast_format *format, int samples);
+
+/*! \brief Gets duration in ms of interpolation frame for a format */
+static inline int ast_codec_interp_len(struct ast_format *format)
+{
+ return (format->id == AST_FORMAT_ILBC) ? 30 : 20;
+}
+
/*!
* \brief register ast_format_attr_interface with core.
*
@@ -477,6 +493,13 @@
*/
enum ast_format_id ast_format_slin_by_rate(unsigned int rate);
+/*! \brief Parse an "allow" or "deny" line in a channel or device configuration
+ and update the capabilities and pref if provided.
+ Video codecs are not added to codec preference lists, since we can not transcode
+ \return Returns number of errors encountered during parsing
+ */
+int ast_parse_allow_disallow(struct ast_codec_pref *pref, struct ast_format_cap *cap, const char *list, int allowing);
+
/*!
* \since 12
* \brief Get the message type used for signaling a format registration
Modified: team/file/media_formats-impl/include/asterisk/frame.h
URL: http://svnview.digium.com/svn/asterisk/team/file/media_formats-impl/include/asterisk/frame.h?view=diff&rev=407440&r1=407439&r2=407440
==============================================================================
--- team/file/media_formats-impl/include/asterisk/frame.h (original)
+++ team/file/media_formats-impl/include/asterisk/frame.h Wed Feb 5 12:44:31 2014
@@ -352,9 +352,6 @@
char code[1]; /*!< Tech-specific cause code information, beginning with the name of the tech */
};
-#define AST_SMOOTHER_FLAG_G729 (1 << 0)
-#define AST_SMOOTHER_FLAG_BE (1 << 1)
-
/* Option identifiers and flags */
#define AST_OPTION_FLAG_REQUEST 0
#define AST_OPTION_FLAG_ACCEPT 1
@@ -533,76 +530,10 @@
#define ast_frame_byteswap_be(fr) do { ; } while(0)
#endif
-/*! \brief Parse an "allow" or "deny" line in a channel or device configuration
- and update the capabilities and pref if provided.
- Video codecs are not added to codec preference lists, since we can not transcode
- \return Returns number of errors encountered during parsing
- */
-int ast_parse_allow_disallow(struct ast_codec_pref *pref, struct ast_format_cap *cap, const char *list, int allowing);
-
-/*! \name AST_Smoother
-*/
-/*@{ */
-/*! \page ast_smooth The AST Frame Smoother
-The ast_smoother interface was designed specifically
-to take frames of variant sizes and produce frames of a single expected
-size, precisely what you want to do.
-
-The basic interface is:
-
-- Initialize with ast_smoother_new()
-- Queue input frames with ast_smoother_feed()
-- Get output frames with ast_smoother_read()
-- when you're done, free the structure with ast_smoother_free()
-- Also see ast_smoother_test_flag(), ast_smoother_set_flags(), ast_smoother_get_flags(), ast_smoother_reset()
-*/
-struct ast_smoother;
-
-struct ast_smoother *ast_smoother_new(int bytes);
-void ast_smoother_set_flags(struct ast_smoother *smoother, int flags);
-int ast_smoother_get_flags(struct ast_smoother *smoother);
-int ast_smoother_test_flag(struct ast_smoother *s, int flag);
-void ast_smoother_free(struct ast_smoother *s);
-void ast_smoother_reset(struct ast_smoother *s, int bytes);
-
-/*!
- * \brief Reconfigure an existing smoother to output a different number of bytes per frame
- * \param s the smoother to reconfigure
- * \param bytes the desired number of bytes per output frame
- * \return nothing
- *
- */
-void ast_smoother_reconfigure(struct ast_smoother *s, int bytes);
-
-int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap);
-struct ast_frame *ast_smoother_read(struct ast_smoother *s);
-#define ast_smoother_feed(s,f) __ast_smoother_feed(s, f, 0)
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define ast_smoother_feed_be(s,f) __ast_smoother_feed(s, f, 1)
-#define ast_smoother_feed_le(s,f) __ast_smoother_feed(s, f, 0)
-#else
-#define ast_smoother_feed_be(s,f) __ast_smoother_feed(s, f, 0)
-#define ast_smoother_feed_le(s,f) __ast_smoother_feed(s, f, 1)
-#endif
-/*@} Doxygen marker */
-
void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix);
-
-/*! \brief Returns the number of samples contained in the frame */
-int ast_codec_get_samples(struct ast_frame *f);
-
-/*! \brief Returns the number of bytes for the number of samples of the given format */
-int ast_codec_get_len(struct ast_format *format, int samples);
/*! \brief Appends a frame to the end of a list of frames, truncating the maximum length of the list */
struct ast_frame *ast_frame_enqueue(struct ast_frame *head, struct ast_frame *f, int maxlen, int dupe);
-
-
-/*! \brief Gets duration in ms of interpolation frame for a format */
-static inline int ast_codec_interp_len(struct ast_format *format)
-{
- return (format->id == AST_FORMAT_ILBC) ? 30 : 20;
-}
/*!
\brief Adjusts the volume of the audio samples contained in a frame.
Modified: team/file/media_formats-impl/include/asterisk/vector.h
URL: http://svnview.digium.com/svn/asterisk/team/file/media_formats-impl/include/asterisk/vector.h?view=diff&rev=407440&r1=407439&r2=407440
==============================================================================
--- team/file/media_formats-impl/include/asterisk/vector.h (original)
+++ team/file/media_formats-impl/include/asterisk/vector.h Wed Feb 5 12:44:31 2014
@@ -116,6 +116,42 @@
})
/*!
+ * \brief Insert an element at a specific position in a vector, growing the vector if needed.
+ *
+ * \param vec Vector to insert into.
+ * \param idx Position to insert at.
+ * \param elem Element to insert.
+ *
+ * \return 0 on success.
+ * \return Non-zero on failure.
+ */
+#define AST_VECTOR_INSERT(vec, idx, elem) ({ \
+ int res = 0; \
+ do { \
+ if ((idx + 1) > (vec)->max) { \
+ size_t new_max = (idx + 1) * 2; \
+ typeof((vec)->elems) new_elems = ast_calloc(1, \
+ new_max * sizeof(*new_elems)); \
+ if (new_elems) { \
+ memcpy(new_elems, (vec)->elems, \
+ (vec)->current * sizeof(*new_elems)); \
+ ast_free((vec)->elems); \
+ (vec)->elems = new_elems; \
+ (vec)->max = new_max; \
+ } else { \
+ res = -1; \
+ break; \
+ } \
+ } \
+ (vec)->elems[(idx)] = (elem); \
+ if ((idx + 1) > (vec)->current) { \
+ (vec)->current = (idx) + 1; \
+ } \
+ } while(0); \
+ res; \
+})
+
+/*!
* \brief Remove an element from a vector by index.
*
* Note that elements in the vector may be reordered, so that the remove can
@@ -131,6 +167,25 @@
ast_assert(__idx < (vec)->current); \
res = (vec)->elems[__idx]; \
(vec)->elems[__idx] = (vec)->elems[--(vec)->current]; \
+ res; \
+})
+
+/*!
+ * \brief Remove an element from a vector by index while maintaining order.
+ *
+ * \param vec Vector to remove from.
+ * \param idx Index of the element to remove.
+ * \return The element that was removed.
+ */
+#define AST_VECTOR_REMOVE_ORDERED(vec, idx) ({ \
+ typeof((vec)->elems[0]) res; \
+ size_t __idx = (idx); \
+ size_t __move; \
+ ast_assert(__idx < (vec)->current); \
+ res = (vec)->elems[__idx]; \
+ __move = ((vec)->current - (__idx) - 1) * sizeof(typeof((vec)->elems[0])); \
+ memmove(&(vec)->elems[__idx], &(vec)->elems[__idx + 1], __move); \
+ (vec)->current--; \
res; \
})
@@ -162,6 +217,32 @@
})
/*!
+ * \brief Remove an element from a vector that matches the given comparison while maintaining order
+ *
+ * \param vec Vector to remove from.
+ * \param value Value to pass into comparator.
+ * \param cmp Comparator function/macros (called as \c cmp(elem, value))
+ * \param cleanup How to cleanup a removed element macro/function.
+ *
+ * \return 0 if element was removed.
+ * \return Non-zero if element was not in the vector.
+ */
+#define AST_VECTOR_REMOVE_CMP_ORDERED(vec, value, cmp, cleanup) ({ \
+ int res = -1; \
+ size_t idx; \
+ typeof(value) __value = (value); \
+ for (idx = 0; idx < (vec)->current; ++idx) { \
+ if (cmp((vec)->elems[idx], __value)) { \
+ cleanup((vec)->elems[idx]); \
+ AST_VECTOR_REMOVE_ORDERED((vec), idx); \
+ res = 0; \
+ break; \
+ } \
+ } \
+ res; \
+})
+
+/*!
* \brief Default comparator for AST_VECTOR_REMOVE_ELEM_UNORDERED()
*
* \param elem Element to compare against
@@ -193,6 +274,21 @@
*/
#define AST_VECTOR_REMOVE_ELEM_UNORDERED(vec, elem, cleanup) ({ \
AST_VECTOR_REMOVE_CMP_UNORDERED((vec), (elem), \
+ AST_VECTOR_ELEM_DEFAULT_CMP, cleanup); \
+})
+
+/*!
+ * \brief Remove an element from a vector while maintaining order.
+ *
+ * \param vec Vector to remove from.
+ * \param elem Element to remove
+ * \param cleanup How to cleanup a removed element macro/function.
+ *
+ * \return 0 if element was removed.
+ * \return Non-zero if element was not in the vector.
+ */
+#define AST_VECTOR_REMOVE_ELEM_ORDERED(vec, elem, cleanup) ({ \
+ AST_VECTOR_REMOVE_CMP_ORDERED((vec), (elem), \
AST_VECTOR_ELEM_DEFAULT_CMP, cleanup); \
})
Modified: team/file/media_formats-impl/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/team/file/media_formats-impl/main/asterisk.c?view=diff&rev=407440&r1=407439&r2=407440
==============================================================================
--- team/file/media_formats-impl/main/asterisk.c (original)
+++ team/file/media_formats-impl/main/asterisk.c Wed Feb 5 12:44:31 2014
@@ -248,6 +248,8 @@
#include "asterisk/stasis_system.h"
#include "asterisk/security_events.h"
#include "asterisk/endpoints.h"
+#include "asterisk/codec.h"
+#include "asterisk/format_cache.h"
#include "../defaults.h"
@@ -4319,6 +4321,21 @@
exit(1);
}
+ if (ast_codec_init()) {
+ printf("%s", term_quit());
+ exit(1);
+ }
+
+ if (ast_format_cache_init()) {
+ printf("%s", term_quit());
+ exit(1);
+ }
+
+ if (ast_codec_builtin_init()) {
+ printf("%s", term_quit());
+ exit(1);
+ }
+
#ifdef AST_XML_DOCS
/* Load XML documentation. */
ast_xmldoc_load_documentation();
Modified: team/file/media_formats-impl/main/format.c
URL: http://svnview.digium.com/svn/asterisk/team/file/media_formats-impl/main/format.c?view=diff&rev=407440&r1=407439&r2=407440
==============================================================================
--- team/file/media_formats-impl/main/format.c (original)
+++ team/file/media_formats-impl/main/format.c Wed Feb 5 12:44:31 2014
@@ -42,8 +42,18 @@
#include "asterisk/cli.h"
#include "asterisk/rtp_engine.h"
#include "asterisk/config.h"
+#include "asterisk/smoother.h"
#define FORMAT_CONFIG "codecs.conf"
+
+enum frame_type {
+ TYPE_HIGH, /* 0x0 */
+ TYPE_LOW, /* 0x1 */
+ TYPE_SILENCE, /* 0x2 */
+ TYPE_DONTSEND /* 0x3 */
+};
+
+#define TYPE_MASK 0x3
/*!
* \brief Container for all the format attribute interfaces.
@@ -802,129 +812,6 @@
}
}
-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:
- return NULL;
- }
-
- if ((a->argc < 3) || (a->argc > 4)) {
- return CLI_SHOWUSAGE;
- }
-
- 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");
- }
-
- 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;
- }
-}
-
-static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
- 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;
- }
-
- 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 (!found) {
- ast_cli(a->fd, "Codec %d not found\n", format_id);
- }
-
- f_list = ast_format_list_destroy(f_list);
- return CLI_SUCCESS;
-}
-
-/* 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)
{
RAII_VAR(struct ast_format_list *, entry, NULL, ao2_cleanup);
@@ -1133,7 +1020,6 @@
*/
static void format_attr_shutdown(void)
{
- ast_cli_unregister_multiple(my_clis, ARRAY_LEN(my_clis));
if (interfaces) {
ao2_ref(interfaces, -1);
interfaces = NULL;
@@ -1148,7 +1034,6 @@
return -1;
}
- ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
ast_register_atexit(format_attr_shutdown);
return 0;
}
@@ -1452,3 +1337,360 @@
f_list = ast_format_list_destroy(f_list);
return 0;
}
+
+int ast_parse_allow_disallow(struct ast_codec_pref *pref, struct ast_format_cap *cap, const char *list, int allowing)
+{
+ int errors = 0, framems = 0, all = 0, iter_allowing;
+ char *parse = NULL, *this = NULL, *psize = NULL;
+ struct ast_format format;
+
+ parse = ast_strdupa(list);
+ while ((this = strsep(&parse, ","))) {
+ iter_allowing = allowing;
+ framems = 0;
+ if (*this == '!') {
+ this++;
+ iter_allowing = !allowing;
+ }
+ if ((psize = strrchr(this, ':'))) {
+ *psize++ = '\0';
+ ast_debug(1, "Packetization for codec: %s is %s\n", this, psize);
+ framems = atoi(psize);
+ if (framems < 0) {
+ framems = 0;
+ errors++;
+ ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this);
+ }
+ }
+ all = strcasecmp(this, "all") ? 0 : 1;
+
+ if (!all && !ast_getformatbyname(this, &format)) {
+ ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", iter_allowing ? "allow" : "disallow", this);
+ errors++;
+ continue;
+ }
+
+ if (cap) {
+ if (iter_allowing) {
+ if (all) {
+ ast_format_cap_add_all(cap);
+ } else {
+ ast_format_cap_add(cap, &format);
+ }
+ } else {
+ if (all) {
+ ast_format_cap_remove_all(cap);
+ } else {
+ ast_format_cap_remove(cap, &format);
+ }
+ }
+ }
+
+ if (pref) {
+ if (!all) {
+ if (iter_allowing) {
+ ast_codec_pref_append(pref, &format);
+ ast_codec_pref_setsize(pref, &format, framems);
+ } else {
+ ast_codec_pref_remove(pref, &format);
+ }
+ } else if (!iter_allowing) {
+ memset(pref, 0, sizeof(*pref));
+ } else {
+ ast_codec_pref_append_all(pref);
+ }
+ }
+ }
+ return errors;
+}
+
+
+static int g723_len(unsigned char buf)
+{
+ enum frame_type type = buf & TYPE_MASK;
+
+ switch(type) {
+ case TYPE_DONTSEND:
+ return 0;
+ break;
+ case TYPE_SILENCE:
+ return 4;
+ break;
+ case TYPE_HIGH:
+ return 24;
+ break;
+ case TYPE_LOW:
+ return 20;
+ break;
+ default:
+ ast_log(LOG_WARNING, "Badly encoded frame (%d)\n", type);
+ }
+ return -1;
+}
+
+static int g723_samples(unsigned char *buf, int maxlen)
+{
+ int pos = 0;
+ int samples = 0;
+ int res;
+ while(pos < maxlen) {
+ res = g723_len(buf[pos]);
+ if (res <= 0)
+ break;
+ samples += 240;
+ pos += res;
+ }
+ return samples;
+}
+
+static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
+{
+ int byte = bit / 8; /* byte containing first bit */
+ int rem = 8 - (bit % 8); /* remaining bits in first byte */
+ unsigned char ret = 0;
+
+ if (n <= 0 || n > 8)
+ return 0;
+
+ if (rem < n) {
+ ret = (data[byte] << (n - rem));
+ ret |= (data[byte + 1] >> (8 - n + rem));
+ } else {
+ ret = (data[byte] >> (rem - n));
+ }
+
+ return (ret & (0xff >> (8 - n)));
+}
+
+static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
+{
+ static const int SpeexWBSubModeSz[] = {
+ 4, 36, 112, 192,
+ 352, 0, 0, 0 };
+ int off = bit;
+ unsigned char c;
+
+ /* skip up to two wideband frames */
+ if (((len * 8 - off) >= 5) &&
+ get_n_bits_at(data, 1, off)) {
+ c = get_n_bits_at(data, 3, off + 1);
+ off += SpeexWBSubModeSz[c];
+
+ if (((len * 8 - off) >= 5) &&
+ get_n_bits_at(data, 1, off)) {
+ c = get_n_bits_at(data, 3, off + 1);
+ off += SpeexWBSubModeSz[c];
+
+ if (((len * 8 - off) >= 5) &&
+ get_n_bits_at(data, 1, off)) {
+ ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
+ return -1;
+ }
+ }
+
+ }
+ return off - bit;
+}
+
+static int speex_samples(unsigned char *data, int len)
+{
+ static const int SpeexSubModeSz[] = {
+ 5, 43, 119, 160,
+ 220, 300, 364, 492,
+ 79, 0, 0, 0,
+ 0, 0, 0, 0 };
+ static const int SpeexInBandSz[] = {
+ 1, 1, 4, 4,
+ 4, 4, 4, 4,
+ 8, 8, 16, 16,
+ 32, 32, 64, 64 };
+ int bit = 0;
+ int cnt = 0;
+ int off;
+ unsigned char c;
+
+ while ((len * 8 - bit) >= 5) {
+ /* skip wideband frames */
+ off = speex_get_wb_sz_at(data, len, bit);
+ if (off < 0) {
+ ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n");
+ break;
+ }
+ bit += off;
+
+ if ((len * 8 - bit) < 5)
+ break;
+
+ /* get control bits */
+ c = get_n_bits_at(data, 5, bit);
+ bit += 5;
+
+ if (c == 15) {
+ /* terminator */
+ break;
+ } else if (c == 14) {
+ /* in-band signal; next 4 bits contain signal id */
+ c = get_n_bits_at(data, 4, bit);
+ bit += 4;
+ bit += SpeexInBandSz[c];
+ } else if (c == 13) {
+ /* user in-band; next 4 bits contain msg len */
+ c = get_n_bits_at(data, 4, bit);
+ bit += 4;
+ /* after which it's 5-bit signal id + c bytes of data */
+ bit += 5 + c * 8;
+ } else if (c > 8) {
+ /* unknown */
+ ast_log(LOG_WARNING, "Unknown speex control frame %d\n", c);
+ break;
+ } else {
+ /* skip number bits for submode (less the 5 control bits) */
+ bit += SpeexSubModeSz[c] - 5;
+ cnt += 160; /* new frame */
+ }
+ }
+ return cnt;
+}
+
+int ast_codec_get_samples(struct ast_frame *f)
+{
+ int samples = 0;
+
+ switch (f->subclass.format.id) {
+ case AST_FORMAT_SPEEX:
+ samples = speex_samples(f->data.ptr, f->datalen);
+ break;
+ case AST_FORMAT_SPEEX16:
+ samples = 2 * speex_samples(f->data.ptr, f->datalen);
+ break;
+ case AST_FORMAT_SPEEX32:
+ samples = 4 * speex_samples(f->data.ptr, f->datalen);
+ break;
+ case AST_FORMAT_G723_1:
+ samples = g723_samples(f->data.ptr, f->datalen);
+ break;
+ case AST_FORMAT_ILBC:
+ samples = 240 * (f->datalen / 50);
+ break;
+ case AST_FORMAT_GSM:
+ samples = 160 * (f->datalen / 33);
+ break;
+ case AST_FORMAT_G729A:
+ samples = f->datalen * 8;
+ break;
+ case AST_FORMAT_SLINEAR:
+ case AST_FORMAT_SLINEAR16:
+ samples = f->datalen / 2;
+ break;
+ case AST_FORMAT_LPC10:
+ /* assumes that the RTP packet contains one LPC10 frame */
+ samples = 22 * 8;
+ samples += (((char *)(f->data.ptr))[7] & 0x1) * 8;
+ break;
+ case AST_FORMAT_ULAW:
+ case AST_FORMAT_ALAW:
+ case AST_FORMAT_TESTLAW:
+ samples = f->datalen;
+ break;
+ case AST_FORMAT_G722:
+ case AST_FORMAT_ADPCM:
+ case AST_FORMAT_G726:
+ case AST_FORMAT_G726_AAL2:
+ samples = f->datalen * 2;
+ break;
+ case AST_FORMAT_SIREN7:
+ /* 16,000 samples per second at 32kbps is 4,000 bytes per second */
+ samples = f->datalen * (16000 / 4000);
+ break;
+ case AST_FORMAT_SIREN14:
+ /* 32,000 samples per second at 48kbps is 6,000 bytes per second */
+ samples = (int) f->datalen * ((float) 32000 / 6000);
+ break;
+ case AST_FORMAT_G719:
+ /* 48,000 samples per second at 64kbps is 8,000 bytes per second */
+ samples = (int) f->datalen * ((float) 48000 / 8000);
+ break;
+ case AST_FORMAT_SILK:
+ if (!(ast_format_isset(&f->subclass.format,
+ SILK_ATTR_KEY_SAMP_RATE,
+ SILK_ATTR_VAL_SAMP_24KHZ,
+ AST_FORMAT_ATTR_END))) {
+ return 480;
+ } else if (!(ast_format_isset(&f->subclass.format,
+ SILK_ATTR_KEY_SAMP_RATE,
+ SILK_ATTR_VAL_SAMP_16KHZ,
+ AST_FORMAT_ATTR_END))) {
+ return 320;
+ } else if (!(ast_format_isset(&f->subclass.format,
+ SILK_ATTR_KEY_SAMP_RATE,
+ SILK_ATTR_VAL_SAMP_12KHZ,
+ AST_FORMAT_ATTR_END))) {
+ return 240;
+ } else {
+ return 160;
+ }
+ case AST_FORMAT_CELT:
+ /* TODO This assumes 20ms delivery right now, which is incorrect */
+ samples = ast_format_rate(&f->subclass.format) / 50;
+ break;
+ case AST_FORMAT_OPUS:
+ /* TODO This assumes 20ms delivery right now, which is incorrect */
+ samples = 960;
+ break;
+ default:
+ ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(&f->subclass.format));
+ }
+ return samples;
+}
+
+int ast_codec_get_len(struct ast_format *format, int samples)
+{
+ int len = 0;
+
+ /* XXX Still need speex, and lpc10 XXX */
+ switch(format->id) {
+ case AST_FORMAT_G723_1:
+ len = (samples / 240) * 20;
+ break;
+ case AST_FORMAT_ILBC:
+ len = (samples / 240) * 50;
+ break;
+ case AST_FORMAT_GSM:
+ len = (samples / 160) * 33;
+ break;
+ case AST_FORMAT_G729A:
+ len = samples / 8;
+ break;
+ case AST_FORMAT_SLINEAR:
+ case AST_FORMAT_SLINEAR16:
+ len = samples * 2;
+ break;
+ case AST_FORMAT_ULAW:
+ case AST_FORMAT_ALAW:
+ case AST_FORMAT_TESTLAW:
+ len = samples;
+ break;
+ case AST_FORMAT_G722:
+ case AST_FORMAT_ADPCM:
+ case AST_FORMAT_G726:
+ case AST_FORMAT_G726_AAL2:
+ len = samples / 2;
+ break;
+ case AST_FORMAT_SIREN7:
+ /* 16,000 samples per second at 32kbps is 4,000 bytes per second */
+ len = samples / (16000 / 4000);
+ break;
+ case AST_FORMAT_SIREN14:
+ /* 32,000 samples per second at 48kbps is 6,000 bytes per second */
+ len = (int) samples / ((float) 32000 / 6000);
+ break;
+ case AST_FORMAT_G719:
+ /* 48,000 samples per second at 64kbps is 8,000 bytes per second */
+ len = (int) samples / ((float) 48000 / 8000);
+ break;
+ default:
+ ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format));
+ }
+
+ return len;
+}
Modified: team/file/media_formats-impl/main/frame.c
URL: http://svnview.digium.com/svn/asterisk/team/file/media_formats-impl/main/frame.c?view=diff&rev=407440&r1=407439&r2=407440
==============================================================================
--- team/file/media_formats-impl/main/frame.c (original)
+++ team/file/media_formats-impl/main/frame.c Wed Feb 5 12:44:31 2014
@@ -71,198 +71,7 @@
};
#endif
-#define SMOOTHER_SIZE 8000
-
-enum frame_type {
- TYPE_HIGH, /* 0x0 */
- TYPE_LOW, /* 0x1 */
- TYPE_SILENCE, /* 0x2 */
- TYPE_DONTSEND /* 0x3 */
-};
-
-#define TYPE_MASK 0x3
-
-struct ast_smoother {
- int size;
- struct ast_format format;
- int flags;
- float samplesperbyte;
- unsigned int opt_needs_swap:1;
- struct ast_frame f;
- struct timeval delivery;
- char data[SMOOTHER_SIZE];
- char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
- struct ast_frame *opt;
- int len;
-};
-
struct ast_frame ast_null_frame = { AST_FRAME_NULL, };
-
-static int smoother_frame_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
-{
- if (s->flags & AST_SMOOTHER_FLAG_G729) {
- if (s->len % 10) {
- ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
- return 0;
- }
- }
- if (swap) {
- ast_swapcopy_samples(s->data + s->len, f->data.ptr, f->samples);
- } else {
- memcpy(s->data + s->len, f->data.ptr, f->datalen);
- }
- /* If either side is empty, reset the delivery time */
- if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery)) { /* XXX really ? */
- s->delivery = f->delivery;
- }
- s->len += f->datalen;
-
- return 0;
-}
-
-void ast_smoother_reset(struct ast_smoother *s, int bytes)
-{
- memset(s, 0, sizeof(*s));
- s->size = bytes;
-}
-
-void ast_smoother_reconfigure(struct ast_smoother *s, int bytes)
-{
- /* if there is no change, then nothing to do */
- if (s->size == bytes) {
- return;
- }
- /* set the new desired output size */
- s->size = bytes;
- /* if there is no 'optimized' frame in the smoother,
- * then there is nothing left to do
- */
- if (!s->opt) {
- return;
- }
- /* there is an 'optimized' frame here at the old size,
- * but it must now be put into the buffer so the data
- * can be extracted at the new size
- */
- smoother_frame_feed(s, s->opt, s->opt_needs_swap);
- s->opt = NULL;
-}
-
-struct ast_smoother *ast_smoother_new(int size)
-{
- struct ast_smoother *s;
- if (size < 1)
- return NULL;
- if ((s = ast_malloc(sizeof(*s))))
- ast_smoother_reset(s, size);
- return s;
-}
-
-int ast_smoother_get_flags(struct ast_smoother *s)
-{
- return s->flags;
-}
-
-void ast_smoother_set_flags(struct ast_smoother *s, int flags)
-{
- s->flags = flags;
-}
-
-int ast_smoother_test_flag(struct ast_smoother *s, int flag)
-{
- return (s->flags & flag);
-}
-
-int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
-{
- if (f->frametype != AST_FRAME_VOICE) {
- ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n");
- return -1;
- }
- if (!s->format.id) {
- ast_format_copy(&s->format, &f->subclass.format);
- s->samplesperbyte = (float)f->samples / (float)f->datalen;
- } else if (ast_format_cmp(&s->format, &f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
- ast_log(LOG_WARNING, "Smoother was working on %s format frames, now trying to feed %s?\n",
- ast_getformatname(&s->format), ast_getformatname(&f->subclass.format));
- return -1;
- }
- if (s->len + f->datalen > SMOOTHER_SIZE) {
- ast_log(LOG_WARNING, "Out of smoother space\n");
- return -1;
- }
- if (((f->datalen == s->size) ||
- ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729))) &&
- !s->opt &&
- !s->len &&
- (f->offset >= AST_MIN_OFFSET)) {
- /* Optimize by sending the frame we just got
- on the next read, thus eliminating the douple
- copy */
- if (swap)
- ast_swapcopy_samples(f->data.ptr, f->data.ptr, f->samples);
- s->opt = f;
- s->opt_needs_swap = swap ? 1 : 0;
- return 0;
- }
-
- return smoother_frame_feed(s, f, swap);
-}
-
-struct ast_frame *ast_smoother_read(struct ast_smoother *s)
-{
- struct ast_frame *opt;
- int len;
-
- /* IF we have an optimization frame, send it */
- if (s->opt) {
- if (s->opt->offset < AST_FRIENDLY_OFFSET)
- ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).\n",
- s->opt->offset);
- opt = s->opt;
- s->opt = NULL;
- return opt;
- }
-
- /* Make sure we have enough data */
- if (s->len < s->size) {
- /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
- if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->len % 10)))
- return NULL;
- }
- len = s->size;
- if (len > s->len)
- len = s->len;
- /* Make frame */
- s->f.frametype = AST_FRAME_VOICE;
- ast_format_copy(&s->f.subclass.format, &s->format);
- s->f.data.ptr = s->framedata + AST_FRIENDLY_OFFSET;
- s->f.offset = AST_FRIENDLY_OFFSET;
- s->f.datalen = len;
- /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
- s->f.samples = len * s->samplesperbyte; /* XXX rounding */
- s->f.delivery = s->delivery;
- /* Fill Data */
- memcpy(s->f.data.ptr, s->data, len);
- s->len -= len;
- /* Move remaining data to the front if applicable */
- if (s->len) {
- /* In principle this should all be fine because if we are sending
- G.729 VAD, the next timestamp will take over anyawy */
- memmove(s->data, s->data + len, s->len);
- if (!ast_tvzero(s->delivery)) {
- /* If we have delivery time, increment it, otherwise, leave it at 0 */
- s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, ast_format_rate(&s->format)));
- }
- }
- /* Return frame */
- return &s->f;
-}
-
-void ast_smoother_free(struct ast_smoother *s)
-{
- ast_free(s);
-}
static struct ast_frame *ast_frame_header_new(void)
{
@@ -808,362 +617,6 @@
term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
}
-int ast_parse_allow_disallow(struct ast_codec_pref *pref, struct ast_format_cap *cap, const char *list, int allowing)
-{
- int errors = 0, framems = 0, all = 0, iter_allowing;
- char *parse = NULL, *this = NULL, *psize = NULL;
- struct ast_format format;
-
- parse = ast_strdupa(list);
- while ((this = strsep(&parse, ","))) {
- iter_allowing = allowing;
- framems = 0;
- if (*this == '!') {
- this++;
- iter_allowing = !allowing;
- }
- if ((psize = strrchr(this, ':'))) {
- *psize++ = '\0';
- ast_debug(1, "Packetization for codec: %s is %s\n", this, psize);
- framems = atoi(psize);
- if (framems < 0) {
- framems = 0;
- errors++;
- ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this);
- }
- }
- all = strcasecmp(this, "all") ? 0 : 1;
-
- if (!all && !ast_getformatbyname(this, &format)) {
- ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", iter_allowing ? "allow" : "disallow", this);
- errors++;
- continue;
- }
-
- if (cap) {
- if (iter_allowing) {
- if (all) {
- ast_format_cap_add_all(cap);
- } else {
- ast_format_cap_add(cap, &format);
- }
- } else {
- if (all) {
- ast_format_cap_remove_all(cap);
- } else {
- ast_format_cap_remove(cap, &format);
- }
- }
- }
-
- if (pref) {
- if (!all) {
- if (iter_allowing) {
- ast_codec_pref_append(pref, &format);
- ast_codec_pref_setsize(pref, &format, framems);
- } else {
- ast_codec_pref_remove(pref, &format);
- }
- } else if (!iter_allowing) {
- memset(pref, 0, sizeof(*pref));
- } else {
- ast_codec_pref_append_all(pref);
- }
- }
- }
- return errors;
-}
-
-static int g723_len(unsigned char buf)
-{
- enum frame_type type = buf & TYPE_MASK;
-
- switch(type) {
- case TYPE_DONTSEND:
- return 0;
- break;
- case TYPE_SILENCE:
- return 4;
- break;
- case TYPE_HIGH:
- return 24;
- break;
- case TYPE_LOW:
- return 20;
- break;
- default:
- ast_log(LOG_WARNING, "Badly encoded frame (%d)\n", type);
- }
- return -1;
-}
-
-static int g723_samples(unsigned char *buf, int maxlen)
-{
- int pos = 0;
- int samples = 0;
- int res;
- while(pos < maxlen) {
- res = g723_len(buf[pos]);
- if (res <= 0)
- break;
- samples += 240;
- pos += res;
- }
- return samples;
-}
-
-static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
-{
- int byte = bit / 8; /* byte containing first bit */
- int rem = 8 - (bit % 8); /* remaining bits in first byte */
- unsigned char ret = 0;
-
- if (n <= 0 || n > 8)
- return 0;
-
- if (rem < n) {
- ret = (data[byte] << (n - rem));
- ret |= (data[byte + 1] >> (8 - n + rem));
- } else {
- ret = (data[byte] >> (rem - n));
- }
-
- return (ret & (0xff >> (8 - n)));
-}
-
-static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
-{
- static const int SpeexWBSubModeSz[] = {
- 4, 36, 112, 192,
- 352, 0, 0, 0 };
- int off = bit;
- unsigned char c;
-
- /* skip up to two wideband frames */
- if (((len * 8 - off) >= 5) &&
- get_n_bits_at(data, 1, off)) {
- c = get_n_bits_at(data, 3, off + 1);
- off += SpeexWBSubModeSz[c];
-
- if (((len * 8 - off) >= 5) &&
- get_n_bits_at(data, 1, off)) {
- c = get_n_bits_at(data, 3, off + 1);
- off += SpeexWBSubModeSz[c];
-
- if (((len * 8 - off) >= 5) &&
- get_n_bits_at(data, 1, off)) {
- ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
- return -1;
- }
- }
-
- }
- return off - bit;
-}
-
-static int speex_samples(unsigned char *data, int len)
-{
- static const int SpeexSubModeSz[] = {
- 5, 43, 119, 160,
- 220, 300, 364, 492,
- 79, 0, 0, 0,
- 0, 0, 0, 0 };
- static const int SpeexInBandSz[] = {
- 1, 1, 4, 4,
- 4, 4, 4, 4,
- 8, 8, 16, 16,
- 32, 32, 64, 64 };
- int bit = 0;
- int cnt = 0;
- int off;
- unsigned char c;
-
- while ((len * 8 - bit) >= 5) {
- /* skip wideband frames */
- off = speex_get_wb_sz_at(data, len, bit);
- if (off < 0) {
- ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n");
- break;
- }
- bit += off;
-
- if ((len * 8 - bit) < 5)
- break;
-
- /* get control bits */
- c = get_n_bits_at(data, 5, bit);
- bit += 5;
-
- if (c == 15) {
- /* terminator */
- break;
- } else if (c == 14) {
- /* in-band signal; next 4 bits contain signal id */
- c = get_n_bits_at(data, 4, bit);
- bit += 4;
- bit += SpeexInBandSz[c];
- } else if (c == 13) {
- /* user in-band; next 4 bits contain msg len */
- c = get_n_bits_at(data, 4, bit);
- bit += 4;
- /* after which it's 5-bit signal id + c bytes of data */
- bit += 5 + c * 8;
- } else if (c > 8) {
- /* unknown */
- ast_log(LOG_WARNING, "Unknown speex control frame %d\n", c);
- break;
- } else {
- /* skip number bits for submode (less the 5 control bits) */
- bit += SpeexSubModeSz[c] - 5;
- cnt += 160; /* new frame */
- }
- }
- return cnt;
-}
-
-int ast_codec_get_samples(struct ast_frame *f)
-{
- int samples = 0;
-
- switch (f->subclass.format.id) {
- case AST_FORMAT_SPEEX:
- samples = speex_samples(f->data.ptr, f->datalen);
- break;
- case AST_FORMAT_SPEEX16:
- samples = 2 * speex_samples(f->data.ptr, f->datalen);
- break;
- case AST_FORMAT_SPEEX32:
- samples = 4 * speex_samples(f->data.ptr, f->datalen);
- break;
- case AST_FORMAT_G723_1:
- samples = g723_samples(f->data.ptr, f->datalen);
- break;
- case AST_FORMAT_ILBC:
- samples = 240 * (f->datalen / 50);
- break;
- case AST_FORMAT_GSM:
- samples = 160 * (f->datalen / 33);
- break;
- case AST_FORMAT_G729A:
- samples = f->datalen * 8;
- break;
- case AST_FORMAT_SLINEAR:
- case AST_FORMAT_SLINEAR16:
- samples = f->datalen / 2;
- break;
- case AST_FORMAT_LPC10:
- /* assumes that the RTP packet contains one LPC10 frame */
- samples = 22 * 8;
- samples += (((char *)(f->data.ptr))[7] & 0x1) * 8;
- break;
- case AST_FORMAT_ULAW:
- case AST_FORMAT_ALAW:
- case AST_FORMAT_TESTLAW:
- samples = f->datalen;
- break;
- case AST_FORMAT_G722:
- case AST_FORMAT_ADPCM:
- case AST_FORMAT_G726:
- case AST_FORMAT_G726_AAL2:
- samples = f->datalen * 2;
- break;
- case AST_FORMAT_SIREN7:
- /* 16,000 samples per second at 32kbps is 4,000 bytes per second */
- samples = f->datalen * (16000 / 4000);
- break;
- case AST_FORMAT_SIREN14:
- /* 32,000 samples per second at 48kbps is 6,000 bytes per second */
- samples = (int) f->datalen * ((float) 32000 / 6000);
- break;
- case AST_FORMAT_G719:
- /* 48,000 samples per second at 64kbps is 8,000 bytes per second */
- samples = (int) f->datalen * ((float) 48000 / 8000);
- break;
- case AST_FORMAT_SILK:
- if (!(ast_format_isset(&f->subclass.format,
[... 115 lines stripped ...]
More information about the asterisk-commits
mailing list