summaryrefslogtreecommitdiff
path: root/main/translate.c
diff options
context:
space:
mode:
authorMatthew Jordan <mjordan@digium.com>2014-07-20 22:06:33 +0000
committerMatthew Jordan <mjordan@digium.com>2014-07-20 22:06:33 +0000
commita2c912e9972c91973ea66902d217746133f96026 (patch)
tree50e01d14ba62950e3f78766d5ba435ba51ca327d /main/translate.c
parentb299052e203807c9a2111eb2cd919246d7589cb3 (diff)
media formats: re-architect handling of media for performance improvements
In the old times media formats were represented using a bit field. This was fast but had a few limitations. 1. Asterisk was limited in how many formats it could handle. 2. Formats, being a bit field, could not include any attribute information. A format was strictly its type, e.g., "this is ulaw". This was changed in Asterisk 10 (see https://wiki.asterisk.org/wiki/display/AST/Media+Architecture+Proposal for notes on that work) which led to the creation of the ast_format structure. This structure allowed Asterisk to handle attributes and bundle information with a format. Additionally, ast_format_cap was created to act as a container for multiple formats that, together, formed the capability of some entity. Another mechanism was added to allow logic to be registered which performed format attribute negotiation. Everywhere throughout the codebase Asterisk was changed to use this strategy. Unfortunately, in software, there is no free lunch. These new capabilities came at a cost. Performance analysis and profiling showed that we spend an inordinate amount of time comparing, copying, and generally manipulating formats and their related structures. Basic prototyping has shown that a reasonably large performance improvement could be made in this area. This patch is the result of that project, which overhauled the media format architecture and its usage in Asterisk to improve performance. Generally, the new philosophy for handling formats is as follows: * The ast_format structure is reference counted. This removed a large amount of the memory allocations and copying that was done in prior versions. * In order to prevent race conditions while keeping things performant, the ast_format structure is immutable by convention and lock-free. Violate this tenet at your peril! * Because formats are reference counted, codecs are also reference counted. The Asterisk core generally provides built-in codecs and caches the ast_format structures created to represent them. Generally, to prevent inordinate amounts of module reference bumping, codecs and formats can be added at run-time but cannot be removed. * All compatibility with the bit field representation of codecs/formats has been moved to a compatibility API. The primary user of this representation is chan_iax2, which must continue to maintain its bit-field usage of formats for interoperability concerns. * When a format is negotiated with attributes, or when a format cannot be represented by one of the cached formats, a new format object is created or cloned from an existing format. That format may have the same codec underlying it, but is a different format than a version of the format with different attributes or without attributes. * While formats are reference counted objects, the reference count maintained on the format should be manipulated with care. Formats are generally cached and will persist for the lifetime of Asterisk and do not explicitly need to have their lifetime modified. An exception to this is when the user of a format does not know where the format came from *and* the user may outlive the provider of the format. This occurs, for example, when a format is read from a channel: the channel may have a format with attributes (hence, non-cached) and the user of the format may last longer than the channel (if the reference to the channel is released prior to the format's reference). For more information on this work, see the API design notes: https://wiki.asterisk.org/wiki/display/AST/Media+Format+Rewrite Finally, this work was the culmination of a large number of developer's efforts. Extra thanks goes to Corey Farrell, who took on a large amount of the work in the Asterisk core, chan_sip, and was an invaluable resource in peer reviews throughout this project. There were a substantial number of patches contributed during this work; the following issues/patch names simply reflect some of the work (and will cause the release scripts to give attribution to the individuals who work on them). Reviews: https://reviewboard.asterisk.org/r/3814 https://reviewboard.asterisk.org/r/3808 https://reviewboard.asterisk.org/r/3805 https://reviewboard.asterisk.org/r/3803 https://reviewboard.asterisk.org/r/3801 https://reviewboard.asterisk.org/r/3798 https://reviewboard.asterisk.org/r/3800 https://reviewboard.asterisk.org/r/3794 https://reviewboard.asterisk.org/r/3793 https://reviewboard.asterisk.org/r/3792 https://reviewboard.asterisk.org/r/3791 https://reviewboard.asterisk.org/r/3790 https://reviewboard.asterisk.org/r/3789 https://reviewboard.asterisk.org/r/3788 https://reviewboard.asterisk.org/r/3787 https://reviewboard.asterisk.org/r/3786 https://reviewboard.asterisk.org/r/3784 https://reviewboard.asterisk.org/r/3783 https://reviewboard.asterisk.org/r/3778 https://reviewboard.asterisk.org/r/3774 https://reviewboard.asterisk.org/r/3775 https://reviewboard.asterisk.org/r/3772 https://reviewboard.asterisk.org/r/3761 https://reviewboard.asterisk.org/r/3754 https://reviewboard.asterisk.org/r/3753 https://reviewboard.asterisk.org/r/3751 https://reviewboard.asterisk.org/r/3750 https://reviewboard.asterisk.org/r/3748 https://reviewboard.asterisk.org/r/3747 https://reviewboard.asterisk.org/r/3746 https://reviewboard.asterisk.org/r/3742 https://reviewboard.asterisk.org/r/3740 https://reviewboard.asterisk.org/r/3739 https://reviewboard.asterisk.org/r/3738 https://reviewboard.asterisk.org/r/3737 https://reviewboard.asterisk.org/r/3736 https://reviewboard.asterisk.org/r/3734 https://reviewboard.asterisk.org/r/3722 https://reviewboard.asterisk.org/r/3713 https://reviewboard.asterisk.org/r/3703 https://reviewboard.asterisk.org/r/3689 https://reviewboard.asterisk.org/r/3687 https://reviewboard.asterisk.org/r/3674 https://reviewboard.asterisk.org/r/3671 https://reviewboard.asterisk.org/r/3667 https://reviewboard.asterisk.org/r/3665 https://reviewboard.asterisk.org/r/3625 https://reviewboard.asterisk.org/r/3602 https://reviewboard.asterisk.org/r/3519 https://reviewboard.asterisk.org/r/3518 https://reviewboard.asterisk.org/r/3516 https://reviewboard.asterisk.org/r/3515 https://reviewboard.asterisk.org/r/3512 https://reviewboard.asterisk.org/r/3506 https://reviewboard.asterisk.org/r/3413 https://reviewboard.asterisk.org/r/3410 https://reviewboard.asterisk.org/r/3387 https://reviewboard.asterisk.org/r/3388 https://reviewboard.asterisk.org/r/3389 https://reviewboard.asterisk.org/r/3390 https://reviewboard.asterisk.org/r/3321 https://reviewboard.asterisk.org/r/3320 https://reviewboard.asterisk.org/r/3319 https://reviewboard.asterisk.org/r/3318 https://reviewboard.asterisk.org/r/3266 https://reviewboard.asterisk.org/r/3265 https://reviewboard.asterisk.org/r/3234 https://reviewboard.asterisk.org/r/3178 ASTERISK-23114 #close Reported by: mjordan media_formats_translation_core.diff uploaded by kharwell (License 6464) rb3506.diff uploaded by mjordan (License 6283) media_format_app_file.diff uploaded by kharwell (License 6464) misc-2.diff uploaded by file (License 5000) chan_mild-3.diff uploaded by file (License 5000) chan_obscure.diff uploaded by file (License 5000) jingle.diff uploaded by file (License 5000) funcs.diff uploaded by file (License 5000) formats.diff uploaded by file (License 5000) core.diff uploaded by file (License 5000) bridges.diff uploaded by file (License 5000) mf-codecs-2.diff uploaded by file (License 5000) mf-app_fax.diff uploaded by file (License 5000) mf-apps-3.diff uploaded by file (License 5000) media-formats-3.diff uploaded by file (License 5000) ASTERISK-23715 rb3713.patch uploaded by coreyfarrell (License 5909) rb3689.patch uploaded by mjordan (License 6283) ASTERISK-23957 rb3722.patch uploaded by mjordan (License 6283) mf-attributes-3.diff uploaded by file (License 5000) ASTERISK-23958 Tested by: jrose rb3822.patch uploaded by coreyfarrell (License 5909) rb3800.patch uploaded by jrose (License 6182) chan_sip.diff uploaded by mjordan (License 6283) rb3747.patch uploaded by jrose (License 6182) ASTERISK-23959 #close Tested by: sgriepentrog, mjordan, coreyfarrell sip_cleanup.diff uploaded by opticron (License 6273) chan_sip_caps.diff uploaded by mjordan (License 6283) rb3751.patch uploaded by coreyfarrell (License 5909) chan_sip-3.diff uploaded by file (License 5000) ASTERISK-23960 #close Tested by: opticron direct_media.diff uploaded by opticron (License 6273) pjsip-direct-media.diff uploaded by file (License 5000) format_cap_remove.diff uploaded by opticron (License 6273) media_format_fixes.diff uploaded by opticron (License 6273) chan_pjsip-2.diff uploaded by file (License 5000) ASTERISK-23966 #close Tested by: rmudgett rb3803.patch uploaded by rmudgetti (License 5621) chan_dahdi.diff uploaded by file (License 5000) ASTERISK-24064 #close Tested by: coreyfarrell, mjordan, opticron, file, rmudgett, sgriepentrog, jrose rb3814.patch uploaded by rmudgett (License 5621) moh_cleanup.diff uploaded by opticron (License 6273) bridge_leak.diff uploaded by opticron (License 6273) translate.diff uploaded by file (License 5000) rb3795.patch uploaded by rmudgett (License 5621) tls_fix.diff uploaded by mjordan (License 6283) fax-mf-fix-2.diff uploaded by file (License 5000) rtp_transfer_stuff uploaded by mjordan (License 6283) rb3787.patch uploaded by rmudgett (License 5621) media-formats-explicit-translate-format-3.diff uploaded by file (License 5000) format_cache_case_fix.diff uploaded by opticron (License 6273) rb3774.patch uploaded by rmudgett (License 5621) rb3775.patch uploaded by rmudgett (License 5621) rtp_engine_fix.diff uploaded by opticron (License 6273) rtp_crash_fix.diff uploaded by opticron (License 6273) rb3753.patch uploaded by mjordan (License 6283) rb3750.patch uploaded by mjordan (License 6283) rb3748.patch uploaded by rmudgett (License 5621) media_format_fixes.diff uploaded by opticron (License 6273) rb3740.patch uploaded by mjordan (License 6283) rb3739.patch uploaded by mjordan (License 6283) rb3734.patch uploaded by mjordan (License 6283) rb3689.patch uploaded by mjordan (License 6283) rb3674.patch uploaded by coreyfarrell (License 5909) rb3671.patch uploaded by coreyfarrell (License 5909) rb3667.patch uploaded by coreyfarrell (License 5909) rb3665.patch uploaded by mjordan (License 6283) rb3625.patch uploaded by coreyfarrell (License 5909) rb3602.patch uploaded by coreyfarrell (License 5909) format_compatibility-2.diff uploaded by file (License 5000) core.diff uploaded by file (License 5000) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/translate.c')
-rw-r--r--main/translate.c775
1 files changed, 421 insertions, 354 deletions
diff --git a/main/translate.c b/main/translate.c
index c24700b45..0696f5d83 100644
--- a/main/translate.c
+++ b/main/translate.c
@@ -43,6 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/sched.h"
#include "asterisk/cli.h"
#include "asterisk/term.h"
+#include "asterisk/format.h"
/*! \todo
* TODO: sample frames for each supported input format.
@@ -76,11 +77,11 @@ struct translator_path {
static struct translator_path **__matrix;
/*!
- * \brief table for converting index to format id values.
+ * \brief table for converting index to format values.
*
* \note this table is protected by the table_lock.
*/
-static int *__indextable;
+static unsigned int *__indextable;
/*! protects the __indextable for resizing */
static ast_rwlock_t tablelock;
@@ -99,9 +100,9 @@ static void matrix_rebuild(int samples);
/*!
* \internal
- * \brief converts format id to index value.
+ * \brief converts codec id to index value.
*/
-static int format2index(enum ast_format_id id)
+static int codec_to_index(unsigned int id)
{
int x;
@@ -119,16 +120,34 @@ static int format2index(enum ast_format_id id)
/*!
* \internal
- * \brief add a new format to the matrix and index table structures.
+ * \brief converts codec to index value.
+ */
+static int codec2index(struct ast_codec *codec)
+{
+ return codec_to_index(codec->id);
+}
+
+/*!
+ * \internal
+ * \brief converts format to codec index value.
+ */
+static int format2index(struct ast_format *format)
+{
+ return codec_to_index(ast_format_get_codec_id(format));
+}
+
+/*!
+ * \internal
+ * \brief add a new codec to the matrix and index table structures.
*
- * \note it is perfectly safe to call this on formats already indexed.
+ * \note it is perfectly safe to call this on codecs already indexed.
*
* \retval 0, success
* \retval -1, matrix and index table need to be resized
*/
-static int add_format2index(enum ast_format_id id)
+static int add_codec2index(struct ast_codec *codec)
{
- if (format2index(id) >= 0) {
+ if (codec2index(codec) != -1) {
/* format is already already indexed */
return 0;
}
@@ -138,7 +157,7 @@ static int add_format2index(enum ast_format_id id)
ast_rwlock_unlock(&tablelock);
return -1; /* hit max length */
}
- __indextable[cur_max_index] = id;
+ __indextable[cur_max_index] = codec->id;
cur_max_index++;
ast_rwlock_unlock(&tablelock);
@@ -147,20 +166,20 @@ static int add_format2index(enum ast_format_id id)
/*!
* \internal
- * \brief converts index value back to format id
+ * \brief converts index value back to codec
*/
-static enum ast_format_id index2format(int index)
+static struct ast_codec *index2codec(int index)
{
- enum ast_format_id format_id;
+ struct ast_codec *codec;
if (index >= cur_max_index) {
return 0;
}
ast_rwlock_rdlock(&tablelock);
- format_id = __indextable[index];
+ codec = ast_codec_get_by_id(__indextable[index]);
ast_rwlock_unlock(&tablelock);
- return format_id;
+ return codec;
}
/*!
@@ -176,7 +195,7 @@ static enum ast_format_id index2format(int index)
static int matrix_resize(int init)
{
struct translator_path **tmp_matrix = NULL;
- int *tmp_table = NULL;
+ unsigned int *tmp_table = NULL;
int old_index;
int x;
@@ -202,7 +221,7 @@ static int matrix_resize(int init)
}
/* make new index table */
- if (!(tmp_table = ast_calloc(1, sizeof(int) * index_size))) {
+ if (!(tmp_table = ast_calloc(1, sizeof(unsigned int) * index_size))) {
goto resize_cleanup;
}
@@ -213,7 +232,7 @@ static int matrix_resize(int init)
}
ast_free(__matrix);
- memcpy(tmp_table, __indextable, sizeof(int) * old_index);
+ memcpy(tmp_table, __indextable, sizeof(unsigned int) * old_index);
ast_free(__indextable);
}
@@ -270,11 +289,23 @@ static struct translator_path *matrix_get(unsigned int x, unsigned int y)
* wrappers around the translator routines.
*/
+static void destroy(struct ast_trans_pvt *pvt)
+{
+ struct ast_translator *t = pvt->t;
+
+ if (t->destroy) {
+ t->destroy(pvt);
+ }
+ ao2_cleanup(pvt->f.subclass.format);
+ ast_free(pvt);
+ ast_module_unref(t->module);
+}
+
/*!
* \brief Allocate the descriptor, required outbuf space,
* and possibly desc.
*/
-static void *newpvt(struct ast_translator *t, const struct ast_format *explicit_dst)
+static struct ast_trans_pvt *newpvt(struct ast_translator *t)
{
struct ast_trans_pvt *pvt;
int len;
@@ -300,28 +331,49 @@ static void *newpvt(struct ast_translator *t, const struct ast_format *explicit_
if (t->buf_size) {/* finally buffer and header */
pvt->outbuf.c = ofs + AST_FRIENDLY_OFFSET;
}
- /* if a explicit destination format is provided, set that on the pvt so the
- * translator will process it. */
- if (explicit_dst) {
- ast_format_copy(&pvt->explicit_dst, explicit_dst);
- }
+
+ ast_module_ref(t->module);
+
/* call local init routine, if present */
if (t->newpvt && t->newpvt(pvt)) {
ast_free(pvt);
+ ast_module_unref(t->module);
return NULL;
}
- ast_module_ref(t->module);
- return pvt;
-}
-static void destroy(struct ast_trans_pvt *pvt)
-{
- struct ast_translator *t = pvt->t;
+ /* Setup normal static translation frame. */
+ pvt->f.frametype = AST_FRAME_VOICE;
+ pvt->f.mallocd = 0;
+ pvt->f.offset = AST_FRIENDLY_OFFSET;
+ pvt->f.src = pvt->t->name;
+ pvt->f.data.ptr = pvt->outbuf.c;
- if (t->destroy)
- t->destroy(pvt);
- ast_free(pvt);
- ast_module_unref(t->module);
+ /* if the translator has not provided a format find one in the cache or create one */
+ if (!pvt->f.subclass.format) {
+ if (!ast_strlen_zero(pvt->t->format)) {
+ pvt->f.subclass.format = ast_format_cache_get(pvt->t->format);
+ }
+
+ if (!pvt->f.subclass.format) {
+ struct ast_codec *codec = ast_codec_get(t->dst_codec.name,
+ t->dst_codec.type, t->dst_codec.sample_rate);
+ if (!codec) {
+ ast_log(LOG_ERROR, "Unable to get destination codec\n");
+ destroy(pvt);
+ return NULL;
+ }
+ pvt->f.subclass.format = ast_format_create(codec);
+ ao2_ref(codec, -1);
+ }
+
+ if (!pvt->f.subclass.format) {
+ ast_log(LOG_ERROR, "Unable to create format\n");
+ destroy(pvt);
+ return NULL;
+ }
+ }
+
+ return pvt;
}
/*! \brief framein wrapper, deals with bound checks. */
@@ -374,8 +426,9 @@ struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt,
if (samples) {
f->samples = samples;
} else {
- if (pvt->samples == 0)
+ if (pvt->samples == 0) {
return NULL;
+ }
f->samples = pvt->samples;
pvt->samples = 0;
}
@@ -386,13 +439,6 @@ struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt,
pvt->datalen = 0;
}
- f->frametype = AST_FRAME_VOICE;
- ast_format_copy(&f->subclass.format, &pvt->t->dst_format);
- f->mallocd = 0;
- f->offset = AST_FRIENDLY_OFFSET;
- f->src = pvt->t->name;
- f->data.ptr = pvt->outbuf.c;
-
return ast_frisolate(f);
}
@@ -417,11 +463,9 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a
{
struct ast_trans_pvt *head = NULL, *tail = NULL;
int src_index, dst_index;
- struct ast_format tmp_fmt1;
- struct ast_format tmp_fmt2;
- src_index = format2index(src->id);
- dst_index = format2index(dst->id);
+ src_index = format2index(src);
+ dst_index = format2index(dst);
if (src_index < 0 || dst_index < 0) {
ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src_index < 0 ? "starting" : "ending");
@@ -432,26 +476,16 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a
while (src_index != dst_index) {
struct ast_trans_pvt *cur;
- struct ast_format *explicit_dst = NULL;
struct ast_translator *t = matrix_get(src_index, dst_index)->step;
if (!t) {
- int src_id = index2format(src_index);
- int dst_id = index2format(dst_index);
ast_log(LOG_WARNING, "No translator path from %s to %s\n",
- ast_getformatname(ast_format_set(&tmp_fmt1, src_id, 0)),
- ast_getformatname(ast_format_set(&tmp_fmt2, dst_id, 0)));
+ ast_format_get_name(src), ast_format_get_name(dst));
AST_RWLIST_UNLOCK(&translators);
return NULL;
}
- if (dst_index == t->dst_fmt_index) {
- explicit_dst = dst;
- }
- if (!(cur = newpvt(t, explicit_dst))) {
- int src_id = index2format(src_index);
- int dst_id = index2format(dst_index);
+ if (!(cur = newpvt(t))) {
ast_log(LOG_WARNING, "Failed to build translator step from %s to %s\n",
- ast_getformatname(ast_format_set(&tmp_fmt1, src_id, 0)),
- ast_getformatname(ast_format_set(&tmp_fmt2, dst_id, 0)));
+ ast_format_get_name(src), ast_format_get_name(dst));
if (head) {
ast_translator_free_path(head);
}
@@ -508,7 +542,8 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f,
path->nextout = f->delivery;
}
/* Predict next incoming sample */
- path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(&f->subclass.format)));
+ path->nextin = ast_tvadd(path->nextin, ast_samp2tv(
+ f->samples, ast_format_get_sample_rate(f->subclass.format)));
}
delivery = f->delivery;
for (out = f; out && p ; p = p->next) {
@@ -531,7 +566,8 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f,
/* Predict next outgoing timestamp from samples in this
frame. */
- path->nextout = ast_tvadd(path->nextout, ast_samp2tv(out->samples, ast_format_rate(&out->subclass.format)));
+ path->nextout = ast_tvadd(path->nextout, ast_samp2tv(
+ out->samples, ast_format_get_sample_rate(out->subclass.format)));
if (f->samples != out->samples && ast_test_flag(out, AST_FRFLAG_HAS_TIMING_INFO)) {
ast_debug(4, "Sample size different %d vs %d\n", f->samples, out->samples);
ast_clear_flag(out, AST_FRFLAG_HAS_TIMING_INFO);
@@ -572,7 +608,7 @@ static void generate_computational_cost(struct ast_translator *t, int seconds)
struct rusage start;
struct rusage end;
int cost;
- int out_rate = ast_format_rate(&t->dst_format);
+ int out_rate = t->dst_codec.sample_rate;
if (!seconds) {
seconds = 1;
@@ -585,7 +621,7 @@ static void generate_computational_cost(struct ast_translator *t, int seconds)
return;
}
- pvt = newpvt(t, NULL);
+ pvt = newpvt(t);
if (!pvt) {
ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
t->comp_cost = 999999;
@@ -643,21 +679,23 @@ static void generate_computational_cost(struct ast_translator *t, int seconds)
* \retval Table Cost value greater than 0.
* \retval 0 on error.
*/
-static int generate_table_cost(struct ast_format *src, struct ast_format *dst)
+static int generate_table_cost(struct ast_codec *src, struct ast_codec *dst)
{
- int src_rate = ast_format_rate(src);
+ int src_rate = src->sample_rate;
int src_ll = 0;
- int dst_rate = ast_format_rate(dst);
+ int dst_rate = dst->sample_rate;
int dst_ll = 0;
- if ((AST_FORMAT_GET_TYPE(src->id) != AST_FORMAT_TYPE_AUDIO) || (AST_FORMAT_GET_TYPE(dst->id) != AST_FORMAT_TYPE_AUDIO)) {
+ if ((src->type != AST_MEDIA_TYPE_AUDIO) ||
+ (dst->type != AST_MEDIA_TYPE_AUDIO)) {
/* This method of generating table cost is limited to audio.
* Translators for media other than audio must manually set their
* table cost. */
return 0;
}
- src_ll = ast_format_is_slinear(src);
- dst_ll = ast_format_is_slinear(dst);
+
+ src_ll = !strcmp(src->name, "slin");
+ dst_ll = !strcmp(dst->name, "slin");
if (src_ll) {
if (dst_ll && (src_rate == dst_rate)) {
return AST_TRANS_COST_LL_LL_ORIGSAMP;
@@ -763,18 +801,25 @@ static void matrix_rebuild(int samples)
/* if no step already exists between x and z OR the new cost of using the intermediate
* step is cheaper, use this step. */
if (!matrix_get(x, z)->step || (newtablecost < matrix_get(x, z)->table_cost)) {
- struct ast_format tmpx;
- struct ast_format tmpy;
- struct ast_format tmpz;
matrix_get(x, z)->step = matrix_get(x, y)->step;
matrix_get(x, z)->table_cost = newtablecost;
matrix_get(x, z)->multistep = 1;
changed++;
- ast_debug(10, "Discovered %u cost path from %s to %s, via %s\n",
- matrix_get(x, z)->table_cost,
- ast_getformatname(ast_format_set(&tmpx, index2format(x), 0)),
- ast_getformatname(ast_format_set(&tmpy, index2format(z), 0)),
- ast_getformatname(ast_format_set(&tmpz, index2format(y), 0)));
+
+ if (DEBUG_ATLEAST(10)) {
+ struct ast_codec *x_codec = index2codec(x);
+ struct ast_codec *y_codec = index2codec(y);
+ struct ast_codec *z_codec = index2codec(z);
+
+ ast_log(LOG_DEBUG,
+ "Discovered %u cost path from %s to %s, via %s\n",
+ matrix_get(x, z)->table_cost, x_codec->name,
+ y_codec->name, z_codec->name);
+
+ ao2_ref(x_codec, -1);
+ ao2_ref(y_codec, -1);
+ ao2_ref(z_codec, -1);
+ }
}
}
}
@@ -785,20 +830,26 @@ static void matrix_rebuild(int samples)
}
}
-const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str)
+static void codec_append_name(const struct ast_codec *codec, struct ast_str **buf)
{
- struct ast_trans_pvt *pn = p;
- char tmp[256];
+ if (codec) {
+ ast_str_append(buf, 0, "(%s@%u)", codec->name, codec->sample_rate);
+ } else {
+ ast_str_append(buf, 0, "(nothing)");
+ }
+}
+const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str)
+{
if (!p || !p->t) {
return "";
}
- ast_str_set(str, 0, "%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), p->t->src_format.id));
-
- while ( (p = pn) ) {
- pn = p->next;
- ast_str_append(str, 0, "->%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), p->t->dst_format.id));
+ codec_append_name(&p->t->src_codec, str);
+ while (p) {
+ ast_str_append(str, 0, "->");
+ codec_append_name(&p->t->dst_codec, str);
+ p = p->next;
}
return ast_str_buffer(*str);
@@ -806,24 +857,24 @@ const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **
static char *complete_trans_path_choice(const char *line, const char *word, int pos, int state)
{
- int which = 0;
+ int i = 1, which = 0;
int wordlen = strlen(word);
- int i;
- char *ret = NULL;
- size_t len = 0;
- const struct ast_format_list *format_list = ast_format_list_get(&len);
+ struct ast_codec *codec;
- for (i = 0; i < len; i++) {
- if (AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) {
+ while ((codec = ast_codec_get_by_id(i))) {
+ ++i;
+ if (codec->type != AST_MEDIA_TYPE_AUDIO) {
+ ao2_ref(codec, -1);
continue;
}
- if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) {
- ret = ast_strdup(format_list[i].name);
- break;
+ if (!strncasecmp(word, codec->name, wordlen) && ++which > state) {
+ char *res = ast_strdup(codec->name);
+ ao2_ref(codec, -1);
+ return res;
}
+ ao2_ref(codec, -1);
}
- ast_format_list_destroy(format_list);
- return ret;
+ return NULL;
}
static void handle_cli_recalc(struct ast_cli_args *a)
@@ -847,63 +898,61 @@ static void handle_cli_recalc(struct ast_cli_args *a)
static char *handle_show_translation_table(struct ast_cli_args *a)
{
- int x;
- int y;
- int i;
- int k;
- int curlen = 0;
- int longest = 0;
- int f_len;
- size_t f_size = 0;
- const struct ast_format_list *f_list = ast_format_list_get(&f_size);
+ int x, y, i, k;
+ int longest = 0, num_codecs = 0, curlen = 0;
struct ast_str *out = ast_str_create(1024);
+ struct ast_codec *codec;
- f_len = f_size;
- AST_RWLIST_RDLOCK(&translators);
- ast_cli(a->fd, " Translation times between formats (in microseconds) for one second of data\n");
- ast_cli(a->fd, " Source Format (Rows) Destination Format (Columns)\n\n");
-
- /* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */
- for (i = 0; i < f_len; i++) {
- /* translation only applies to audio right now. */
- if (AST_FORMAT_GET_TYPE(f_list[i].format.id) != AST_FORMAT_TYPE_AUDIO)
+ /* Get the length of the longest (usable?) codec name,
+ so we know how wide the left side should be */
+ for (i = 1; (codec = ast_codec_get_by_id(i)); ao2_ref(codec, -1), ++i) {
+ ++num_codecs;
+ if (codec->type != AST_MEDIA_TYPE_AUDIO) {
continue;
- curlen = strlen(ast_getformatname(&f_list[i].format));
+ }
+ curlen = strlen(codec->name);
if (curlen > longest) {
longest = curlen;
}
}
- for (i = -1; i < f_len; i++) {
+ AST_RWLIST_RDLOCK(&translators);
+ ast_cli(a->fd, " Translation times between formats (in microseconds) for one second of data\n");
+ ast_cli(a->fd, " Source Format (Rows) Destination Format (Columns)\n\n");
+
+ for (i = 0; i < num_codecs; i++) {
+ struct ast_codec *row = i ? ast_codec_get_by_id(i) : NULL;
+
x = -1;
- if ((i >= 0) && ((x = format2index(f_list[i].format.id)) < 0)) {
- continue;
- }
- /* translation only applies to audio right now. */
- if (i >= 0 && (AST_FORMAT_GET_TYPE(f_list[i].format.id) != AST_FORMAT_TYPE_AUDIO)) {
+ if ((i > 0) && (row->type != AST_MEDIA_TYPE_AUDIO)) {
+ ao2_ref(row, -1);
continue;
}
- /*Go ahead and move to next iteration if dealing with an unknown codec*/
- if (i >= 0 && !strcmp(ast_getformatname(&f_list[i].format), "unknown")) {
+
+ if ((i > 0) && (x = codec2index(row)) == -1) {
+ ao2_ref(row, -1);
continue;
}
+
ast_str_set(&out, 0, " ");
- for (k = -1; k < f_len; k++) {
+ for (k = 0; k < num_codecs; k++) {
+ struct ast_codec *col = k ? ast_codec_get_by_id(k) : NULL;
+
y = -1;
- if ((k >= 0) && ((y = format2index(f_list[k].format.id)) < 0)) {
+ if ((k > 0) && (col->type != AST_MEDIA_TYPE_AUDIO)) {
+ ao2_ref(col, -1);
continue;
}
- /* translation only applies to audio right now. */
- if (k >= 0 && (AST_FORMAT_GET_TYPE(f_list[k].format.id) != AST_FORMAT_TYPE_AUDIO)) {
- continue;
- }
- /*Go ahead and move to next iteration if dealing with an unknown codec*/
- if (k >= 0 && !strcmp(ast_getformatname(&f_list[k].format), "unknown")) {
+
+ if ((k > 0) && (y = codec2index(col)) == -1) {
+ ao2_ref(col, -1);
continue;
}
- if (k >= 0) {
- curlen = strlen(ast_getformatname(&f_list[k].format));
+
+ if (k > 0) {
+ curlen = strlen(col->name);
}
+
if (curlen < 5) {
curlen = 5;
}
@@ -911,12 +960,12 @@ static char *handle_show_translation_table(struct ast_cli_args *a)
if (x >= 0 && y >= 0 && matrix_get(x, y)->step) {
/* Actual codec output */
ast_str_append(&out, 0, "%*u", curlen + 1, (matrix_get(x, y)->table_cost/100));
- } else if (i == -1 && k >= 0) {
+ } else if (i == 0 && k > 0) {
/* Top row - use a dynamic size */
- ast_str_append(&out, 0, "%*s", curlen + 1, ast_getformatname(&f_list[k].format));
- } else if (k == -1 && i >= 0) {
+ ast_str_append(&out, 0, "%*s", curlen + 1, col->name);
+ } else if (k == 0 && i > 0) {
/* Left column - use a static size. */
- ast_str_append(&out, 0, "%*s", longest, ast_getformatname(&f_list[i].format));
+ ast_str_append(&out, 0, "%*s", longest, row->name);
} else if (x >= 0 && y >= 0) {
/* Codec not supported */
ast_str_append(&out, 0, "%*s", curlen + 1, "-");
@@ -924,74 +973,79 @@ static char *handle_show_translation_table(struct ast_cli_args *a)
/* Upper left hand corner */
ast_str_append(&out, 0, "%*s", longest, "");
}
+ ao2_cleanup(col);
}
ast_str_append(&out, 0, "\n");
ast_cli(a->fd, "%s", ast_str_buffer(out));
+ ao2_cleanup(row);
}
ast_free(out);
AST_RWLIST_UNLOCK(&translators);
- ast_format_list_destroy(f_list);
return CLI_SUCCESS;
}
-static char *handle_show_translation_path(struct ast_cli_args *a)
+static char *handle_show_translation_path(struct ast_cli_args *a, const char *codec_name, unsigned int sample_rate)
{
- struct ast_format input_src_format;
- size_t len = 0;
- int i;
- const struct ast_format_list *format_list = ast_format_list_get(&len);
+ int i = 1;
struct ast_str *str = ast_str_alloca(1024);
struct ast_translator *step;
- char tmp[256];
+ struct ast_codec *dst_codec;
+ struct ast_codec *src_codec = ast_codec_get(codec_name, AST_MEDIA_TYPE_AUDIO, sample_rate);
- ast_format_clear(&input_src_format);
- for (i = 0; i < len; i++) {
- if (AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) {
- continue;
- }
- if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) {
- ast_format_copy(&input_src_format, &format_list[i].format);
- }
- }
-
- if (!input_src_format.id) {
- ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]);
- ast_format_list_destroy(format_list);
+ if (!src_codec) {
+ ast_cli(a->fd, "Source codec \"%s\" is not found.\n", codec_name);
return CLI_FAILURE;
}
AST_RWLIST_RDLOCK(&translators);
- ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(&input_src_format));
- for (i = 0; i < len; i++) {
- int src;
- int dst;
- if ((AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) || (format_list[i].format.id == input_src_format.id)) {
+ ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %u ---\n",
+ codec_name, src_codec->sample_rate);
+
+ while ((dst_codec = ast_codec_get_by_id(i))) {
+ int src, dst;
+ char src_buffer[64];
+ char dst_buffer[64];
+
+ ++i;
+ if (src_codec == dst_codec ||
+ dst_codec->type != AST_MEDIA_TYPE_AUDIO) {
+ ao2_ref(dst_codec, -1);
continue;
}
- dst = format2index(format_list[i].format.id);
- src = format2index(input_src_format.id);
- ast_str_reset(str);
- if ((len >= cur_max_index) && (src >= 0) && (dst >= 0) && matrix_get(src, dst)->step) {
- ast_str_append(&str, 0, "%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), matrix_get(src, dst)->step->src_format.id));
- while (src != dst) {
- step = matrix_get(src, dst)->step;
- if (!step) {
- ast_str_reset(str);
- break;
+
+ dst = codec2index(dst_codec);
+ src = codec2index(src_codec);
+
+ if (src < 0 || dst < 0) {
+ ast_str_set(&str, 0, "No Translation Path");
+ } else {
+ step = matrix_get(src, dst)->step;
+
+ if (step) {
+ codec_append_name(&step->src_codec, &str);
+ while (src != dst) {
+ src = step->dst_fmt_index;
+ step = matrix_get(src, dst)->step;
+ if (!step) {
+ ast_str_append(&str, 0, "->");
+ codec_append_name(dst_codec, &str);
+ break;
+ }
+ ast_str_append(&str, 0, "->");
+ codec_append_name(&step->src_codec, &str);
}
- ast_str_append(&str, 0, "->%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), step->dst_format.id));
- src = step->dst_fmt_index;
}
}
- if (ast_strlen_zero(ast_str_buffer(str))) {
- ast_str_set(&str, 0, "No Translation Path");
- }
- ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str));
+ snprintf(src_buffer, sizeof(src_buffer), "%s:%u", src_codec->name, src_codec->sample_rate);
+ snprintf(dst_buffer, sizeof(dst_buffer), "%s:%u", dst_codec->name, dst_codec->sample_rate);
+ ast_cli(a->fd, "\t%-16.16s To %-16.16s: %-60.60s\n",
+ src_buffer, dst_buffer, ast_str_buffer(str));
+ ast_str_reset(str);
+ ao2_ref(dst_codec, -1);
}
AST_RWLIST_UNLOCK(&translators);
-
- ast_format_list_destroy(format_list);
+ ao2_ref(src_codec, -1);
return CLI_SUCCESS;
}
@@ -1009,8 +1063,10 @@ static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd,
" with each conversion. If the argument 'recalc' is supplied along\n"
" with optional number of seconds to test a new test will be performed\n"
" as the chart is being displayed.\n"
- " 2. 'core show translation paths [codec]'\n"
- " This will display all the translation paths associated with a codec\n";
+ " 2. 'core show translation paths [codec [sample_rate]]'\n"
+ " This will display all the translation paths associated with a codec.\n"
+ " If a codec has multiple sample rates, the sample rate must be\n"
+ " provided as well.\n";
return NULL;
case CLI_GENERATE:
if (a->pos == 3) {
@@ -1019,14 +1075,22 @@ static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd,
if (a->pos == 4 && !strcasecmp(a->argv[3], option[1])) {
return complete_trans_path_choice(a->line, a->word, a->pos, a->n);
}
+ /* BUGBUG - add tab completion for sample rates */
return NULL;
}
- if (a->argc > 5)
+ if (a->argc > 6)
return CLI_SHOWUSAGE;
if (a->argv[3] && !strcasecmp(a->argv[3], option[1]) && a->argc == 5) { /* show paths */
- return handle_show_translation_path(a);
+ return handle_show_translation_path(a, a->argv[4], 0);
+ } else if (a->argv[3] && !strcasecmp(a->argv[3], option[1]) && a->argc == 6) {
+ unsigned int sample_rate;
+ if (sscanf(a->argv[5], "%30u", &sample_rate) != 1) {
+ ast_cli(a->fd, "Invalid sample rate: %s.\n", a->argv[5]);
+ return CLI_FAILURE;
+ }
+ return handle_show_translation_path(a, a->argv[4], sample_rate);
} else if (a->argv[3] && !strcasecmp(a->argv[3], option[0])) { /* recalc and then fall through to show table */
handle_cli_recalc(a);
} else if (a->argc > 3) { /* wrong input */
@@ -1045,14 +1109,29 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
{
struct ast_translator *u;
char tmp[80];
+ RAII_VAR(struct ast_codec *, src_codec, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_codec *, dst_codec, NULL, ao2_cleanup);
- if (add_format2index(t->src_format.id) || add_format2index(t->dst_format.id)) {
+ src_codec = ast_codec_get(t->src_codec.name, t->src_codec.type, t->src_codec.sample_rate);
+ if (!src_codec) {
+ ast_assert(0);
+ ast_log(LOG_WARNING, "Failed to register translator: unknown source codec %s\n", t->src_codec.name);
+ return -1;
+ }
+
+ dst_codec = ast_codec_get(t->dst_codec.name, t->dst_codec.type, t->dst_codec.sample_rate);
+ if (!dst_codec) {
+ ast_log(LOG_WARNING, "Failed to register translator: unknown destination codec %s\n", t->dst_codec.name);
+ return -1;
+ }
+
+ if (add_codec2index(src_codec) || add_codec2index(dst_codec)) {
if (matrix_resize(0)) {
ast_log(LOG_WARNING, "Translator matrix can not represent any more translators. Out of resources.\n");
return -1;
}
- add_format2index(t->src_format.id);
- add_format2index(t->dst_format.id);
+ add_codec2index(src_codec);
+ add_codec2index(dst_codec);
}
if (!mod) {
@@ -1064,15 +1143,15 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
ast_log(LOG_WARNING, "empty buf size, you need to supply one\n");
return -1;
}
- if (!t->table_cost && !(t->table_cost = generate_table_cost(&t->src_format, &t->dst_format))) {
+ if (!t->table_cost && !(t->table_cost = generate_table_cost(src_codec, dst_codec))) {
ast_log(LOG_WARNING, "Table cost could not be generated for %s, "
"Please set table_cost variable on translator.\n", t->name);
return -1;
}
t->module = mod;
- t->src_fmt_index = format2index(t->src_format.id);
- t->dst_fmt_index = format2index(t->dst_format.id);
+ t->src_fmt_index = codec2index(src_codec);
+ t->dst_fmt_index = codec2index(dst_codec);
t->active = 1;
if (t->src_fmt_index < 0 || t->dst_fmt_index < 0) {
@@ -1080,12 +1159,12 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
return -1;
}
if (t->src_fmt_index >= cur_max_index) {
- ast_log(LOG_WARNING, "Source format %s is larger than cur_max_index\n", ast_getformatname(&t->src_format));
+ ast_log(LOG_WARNING, "Source codec %s is larger than cur_max_index\n", t->src_codec.name);
return -1;
}
if (t->dst_fmt_index >= cur_max_index) {
- ast_log(LOG_WARNING, "Destination format %s is larger than cur_max_index\n", ast_getformatname(&t->dst_format));
+ ast_log(LOG_WARNING, "Destination codec %s is larger than cur_max_index\n", t->dst_codec.name);
return -1;
}
@@ -1106,9 +1185,9 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
generate_computational_cost(t, 1);
- ast_verb(2, "Registered translator '%s' from format %s to %s, table cost, %d, computational cost %d\n",
- term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
- ast_getformatname(&t->src_format), ast_getformatname(&t->dst_format), t->table_cost, t->comp_cost);
+ ast_verb(2, "Registered translator '%s' from codec %s to %s, table cost, %d, computational cost %d\n",
+ term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
+ t->src_codec.name, t->dst_codec.name, t->table_cost, t->comp_cost);
AST_RWLIST_WRLOCK(&translators);
@@ -1125,7 +1204,7 @@ int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
}
AST_RWLIST_TRAVERSE_SAFE_END;
- /* if no existing translator was found for this format combination,
+ /* if no existing translator was found for this codec combination,
add it to the beginning of the list */
if (t) {
AST_RWLIST_INSERT_HEAD(&translators, t, list);
@@ -1149,10 +1228,9 @@ int ast_unregister_translator(struct ast_translator *t)
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
if (u == t) {
AST_RWLIST_REMOVE_CURRENT(list);
- ast_verb(2, "Unregistered translator '%s' from format %s to %s\n",
+ ast_verb(2, "Unregistered translator '%s' from codec %s to %s\n",
term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
- ast_getformatname(&t->src_format),
- ast_getformatname(&t->dst_format));
+ t->src_codec.name, t->dst_codec.name);
found = 1;
break;
}
@@ -1187,91 +1265,105 @@ void ast_translator_deactivate(struct ast_translator *t)
/*! \brief Calculate our best translator source format, given costs, and a desired destination */
int ast_translator_best_choice(struct ast_format_cap *dst_cap,
struct ast_format_cap *src_cap,
- struct ast_format *dst_fmt_out,
- struct ast_format *src_fmt_out)
+ struct ast_format **dst_fmt_out,
+ struct ast_format **src_fmt_out)
{
- struct ast_format best;
- struct ast_format_cap *joint_cap = ast_format_cap_joint(dst_cap, src_cap);
+ unsigned int besttablecost = INT_MAX;
+ unsigned int beststeps = INT_MAX;
+ RAII_VAR(struct ast_format *, best, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_format *, bestdst, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_format_cap *, joint_cap, NULL, ao2_cleanup);
+ int i;
+ int j;
- ast_format_clear(&best);
+ if (!(joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+ return -1;
+ }
+ ast_format_cap_get_compatible(dst_cap, src_cap, joint_cap);
- if (joint_cap) { /* yes, pick one and return */
- struct ast_format tmp_fmt;
+ for (i = 0; i < ast_format_cap_count(joint_cap); ++i) {
+ struct ast_format *fmt =
+ ast_format_cap_get_format(joint_cap, i);
- ast_format_cap_iter_start(joint_cap);
- while (!ast_format_cap_iter_next(joint_cap, &tmp_fmt)) {
- /* We are guaranteed to find one common format. */
- if (!best.id) {
- ast_format_copy(&best, &tmp_fmt);
- continue;
- }
- /* If there are multiple common formats, pick the one with the highest sample rate */
- if (ast_format_rate(&best) < ast_format_rate(&tmp_fmt)) {
- ast_format_copy(&best, &tmp_fmt);
- continue;
- }
+ if (!fmt) {
+ continue;
+ }
+
+ if (!best) {
+ /* No ao2_ref operations needed, we're done with fmt */
+ best = fmt;
+ continue;
}
- ast_format_cap_iter_end(joint_cap);
- /* We are done, this is a common format to both. */
- ast_format_copy(dst_fmt_out, &best);
- ast_format_copy(src_fmt_out, &best);
- ast_format_cap_destroy(joint_cap);
+ if (ast_format_get_sample_rate(best) <
+ ast_format_get_sample_rate(fmt)) {
+ ao2_replace(best, fmt);
+ }
+ ao2_ref(fmt, -1);
+ }
+
+ if (best) {
+ ao2_replace(*dst_fmt_out, best);
+ ao2_replace(*src_fmt_out, best);
return 0;
- } else { /* No, we will need to translate */
- unsigned int besttablecost = INT_MAX;
- unsigned int beststeps = INT_MAX;
- struct ast_format cur_dst;
- struct ast_format cur_src;
- struct ast_format bestdst;
+ }
+ /* need to translate */
+ AST_RWLIST_RDLOCK(&translators);
- ast_format_clear(&bestdst);
+ for (i = 0; i < ast_format_cap_count(dst_cap); ++i) {
+ struct ast_format *dst =
+ ast_format_cap_get_format(dst_cap, i);
- AST_RWLIST_RDLOCK(&translators);
- ast_format_cap_iter_start(dst_cap);
- while (!ast_format_cap_iter_next(dst_cap, &cur_dst)) {
- ast_format_cap_iter_start(src_cap);
- while (!ast_format_cap_iter_next(src_cap, &cur_src)) {
- int x = format2index(cur_src.id);
- int y = format2index(cur_dst.id);
- struct translator_path *trans;
-
- if (x < 0 || y < 0) {
- continue;
- }
- trans = matrix_get(x, y);
- if (!trans || !trans->step) {
- continue;
- }
- if (trans->table_cost < besttablecost || trans->multistep < beststeps) {
- /* better than what we have so far */
- ast_format_copy(&best, &cur_src);
- ast_format_copy(&bestdst, &cur_dst);
- besttablecost = trans->table_cost;
- beststeps = trans->multistep;
- }
- }
- ast_format_cap_iter_end(src_cap);
+ if (!dst) {
+ continue;
}
- ast_format_cap_iter_end(dst_cap);
- AST_RWLIST_UNLOCK(&translators);
- if (best.id) {
- ast_format_copy(dst_fmt_out, &bestdst);
- ast_format_copy(src_fmt_out, &best);
- return 0;
+ for (j = 0; j < ast_format_cap_count(src_cap); ++j) {
+ struct ast_format *src =
+ ast_format_cap_get_format(src_cap, j);
+ int x, y;
+
+ if (!src) {
+ continue;
+ }
+
+ x = format2index(src);
+ y = format2index(dst);
+ if (x < 0 || y < 0) {
+ ao2_ref(src, -1);
+ continue;
+ }
+ if (!matrix_get(x, y) || !(matrix_get(x, y)->step)) {
+ ao2_ref(src, -1);
+ continue;
+ }
+ if (((matrix_get(x, y)->table_cost < besttablecost) ||
+ (matrix_get(x, y)->multistep < beststeps))) {
+ /* better than what we have so far */
+ ao2_replace(best, src);
+ ao2_replace(bestdst, dst);
+ besttablecost = matrix_get(x, y)->table_cost;
+ beststeps = matrix_get(x, y)->multistep;
+ }
+ ao2_ref(src, -1);
}
+ ao2_ref(dst, -1);
+ }
+ AST_RWLIST_UNLOCK(&translators);
+ if (!best) {
return -1;
}
+ ao2_replace(*dst_fmt_out, bestdst);
+ ao2_replace(*src_fmt_out, best);
+ return 0;
}
unsigned int ast_translate_path_steps(struct ast_format *dst_format, struct ast_format *src_format)
{
unsigned int res = -1;
- int src, dest;
/* convert bitwise format numbers into array indices */
- src = format2index(src_format->id);
- dest = format2index(dst_format->id);
+ int src = format2index(src_format);
+ int dest = format2index(dst_format);
if (src < 0 || dest < 0) {
ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src < 0 ? "starting" : "ending");
@@ -1288,25 +1380,72 @@ unsigned int ast_translate_path_steps(struct ast_format *dst_format, struct ast_
return res;
}
+static void check_translation_path(
+ struct ast_format_cap *dest, struct ast_format_cap *src,
+ struct ast_format_cap *result, struct ast_format *src_fmt,
+ enum ast_media_type type)
+{
+ int index, src_index = format2index(src_fmt);
+ /* For a given source format, traverse the list of
+ known formats to determine whether there exists
+ a translation path from the source format to the
+ destination format. */
+ for (index = 0; (src_index >= 0) && index < cur_max_index; index++) {
+ struct ast_codec *codec = index2codec(index);
+ RAII_VAR(struct ast_format *, fmt, ast_format_create(codec), ao2_cleanup);
+
+ ao2_ref(codec, -1);
+
+ if (ast_format_get_type(fmt) != type) {
+ continue;
+ }
+
+ /* if this is not a desired format, nothing to do */
+ if (ast_format_cap_iscompatible_format(dest, fmt) == AST_FORMAT_CMP_NOT_EQUAL) {
+ continue;
+ }
+
+ /* if the source is supplying this format, then
+ we can leave it in the result */
+ if (ast_format_cap_iscompatible_format(src, fmt) == AST_FORMAT_CMP_EQUAL) {
+ continue;
+ }
+
+ /* if we don't have a translation path from the src
+ to this format, remove it from the result */
+ if (!matrix_get(src_index, index)->step) {
+ ast_format_cap_remove(result, fmt);
+ continue;
+ }
+
+ /* now check the opposite direction */
+ if (!matrix_get(index, src_index)->step) {
+ ast_format_cap_remove(result, fmt);
+ }
+ }
+
+}
+
void ast_translate_available_formats(struct ast_format_cap *dest, struct ast_format_cap *src, struct ast_format_cap *result)
{
- struct ast_format tmp_fmt;
- struct ast_format cur_dest, cur_src;
- int src_audio = 0;
- int src_video = 0;
+ struct ast_format *cur_dest, *cur_src;
int index;
- ast_format_cap_iter_start(dest);
- while (!ast_format_cap_iter_next(dest, &cur_dest)) {
+ for (index = 0; index < ast_format_cap_count(dest); ++index) {
+ if (!(cur_dest = ast_format_cap_get_format(dest, index))) {
+ continue;
+ }
+
/* We give preference to a joint format structure if possible */
- if (ast_format_cap_get_compatible_format(src, &cur_dest, &tmp_fmt)) {
- ast_format_cap_add(result, &tmp_fmt);
+ if ((cur_src = ast_format_cap_get_compatible_format(src, cur_dest))) {
+ ast_format_cap_append(result, cur_src, 0);
+ ao2_ref(cur_src, -1);
} else {
/* Otherwise we just use the destination format */
- ast_format_cap_add(result, &cur_dest);
+ ast_format_cap_append(result, cur_dest, 0);
}
+ ao2_ref(cur_dest, -1);
}
- ast_format_cap_iter_end(dest);
/* if we don't have a source format, we just have to try all
possible destination formats */
@@ -1314,91 +1453,19 @@ void ast_translate_available_formats(struct ast_format_cap *dest, struct ast_for
return;
}
- ast_format_cap_iter_start(src);
- while (!ast_format_cap_iter_next(src, &cur_src)) {
- /* If we have a source audio format, get its format index */
- if (AST_FORMAT_GET_TYPE(cur_src.id) == AST_FORMAT_TYPE_AUDIO) {
- src_audio = format2index(cur_src.id);
- }
-
- /* If we have a source video format, get its format index */
- if (AST_FORMAT_GET_TYPE(cur_src.id) == AST_FORMAT_TYPE_VIDEO) {
- src_video = format2index(cur_src.id);
+ for (index = 0; index < ast_format_cap_count(src); ++index) {
+ if (!(cur_src = ast_format_cap_get_format(src, index))) {
+ continue;
}
AST_RWLIST_RDLOCK(&translators);
-
- /* For a given source audio format, traverse the list of
- known audio formats to determine whether there exists
- a translation path from the source format to the
- destination format. */
- for (index = 0; (src_audio >= 0) && index < cur_max_index; index++) {
- ast_format_set(&tmp_fmt, index2format(index), 0);
-
- if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_AUDIO) {
- continue;
- }
-
- /* if this is not a desired format, nothing to do */
- if (!ast_format_cap_iscompatible(dest, &tmp_fmt)) {
- continue;
- }
-
- /* if the source is supplying this format, then
- we can leave it in the result */
- if (ast_format_cap_iscompatible(src, &tmp_fmt)) {
- continue;
- }
-
- /* if we don't have a translation path from the src
- to this format, remove it from the result */
- if (!matrix_get(src_audio, index)->step) {
- ast_format_cap_remove_byid(result, tmp_fmt.id);
- continue;
- }
-
- /* now check the opposite direction */
- if (!matrix_get(index, src_audio)->step) {
- ast_format_cap_remove_byid(result, tmp_fmt.id);
- }
- }
-
- /* For a given source video format, traverse the list of
- known video formats to determine whether there exists
- a translation path from the source format to the
- destination format. */
- for (index = 0; (src_video >= 0) && index < cur_max_index; index++) {
- ast_format_set(&tmp_fmt, index2format(index), 0);
- if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_VIDEO) {
- continue;
- }
-
- /* if this is not a desired format, nothing to do */
- if (!ast_format_cap_iscompatible(dest, &tmp_fmt)) {
- continue;
- }
-
- /* if the source is supplying this format, then
- we can leave it in the result */
- if (ast_format_cap_iscompatible(src, &tmp_fmt)) {
- continue;
- }
-
- /* if we don't have a translation path from the src
- to this format, remove it from the result */
- if (!matrix_get(src_video, index)->step) {
- ast_format_cap_remove_byid(result, tmp_fmt.id);
- continue;
- }
-
- /* now check the opposite direction */
- if (!matrix_get(index, src_video)->step) {
- ast_format_cap_remove_byid(result, tmp_fmt.id);
- }
- }
+ check_translation_path(dest, src, result,
+ cur_src, AST_MEDIA_TYPE_AUDIO);
+ check_translation_path(dest, src, result,
+ cur_src, AST_MEDIA_TYPE_VIDEO);
AST_RWLIST_UNLOCK(&translators);
+ ao2_ref(cur_src, -1);
}
- ast_format_cap_iter_end(src);
}
static void translate_shutdown(void)