Support for translation of data formats. translate.c. More...


Go to the source code of this file.
Data Structures | |
| struct | ast_trans_pvt |
| Default structure for translators, with the basic fields and buffers, all allocated as part of the same chunk of memory. The buffer is preceded by AST_FRIENDLY_OFFSET bytes in front of the user portion. 'buf' points right after this space. More... | |
| struct | ast_translator |
| Descriptor of a translator. More... | |
Defines | |
| #define | ast_register_translator(t) __ast_register_translator(t, ast_module_info->self) |
| See __ast_register_translator() | |
| #define | MAX_AUDIO_FORMAT 47 |
| #define | MAX_FORMAT 64 |
Functions | |
| int | __ast_register_translator (struct ast_translator *t, struct ast_module *module) |
| Register a translator This registers a codec translator with asterisk. | |
| struct ast_frame * | ast_trans_frameout (struct ast_trans_pvt *pvt, int datalen, int samples) |
| generic frameout function | |
| struct ast_frame * | ast_translate (struct ast_trans_pvt *tr, struct ast_frame *f, int consume) |
| translates one or more frames Apply an input frame into the translator and receive zero or one output frames. Consume determines whether the original frame should be freed | |
| format_t | ast_translate_available_formats (format_t dest, format_t src) |
| Mask off unavailable formats from a format bitmask. | |
| unsigned int | ast_translate_path_steps (format_t dest, format_t src) |
| Returns the number of steps required to convert from 'src' to 'dest'. | |
| const char * | ast_translate_path_to_str (struct ast_trans_pvt *t, struct ast_str **str) |
| Puts a string representation of the translation path into outbuf. | |
| void | ast_translator_activate (struct ast_translator *t) |
| Activate a previously deactivated translator. | |
| format_t | ast_translator_best_choice (format_t *dsts, format_t *srcs) |
| Chooses the best translation path. | |
| struct ast_trans_pvt * | ast_translator_build_path (format_t dest, format_t source) |
| Builds a translator path Build a path (possibly NULL) from source to dest. | |
| void | ast_translator_deactivate (struct ast_translator *t) |
| Deactivate a translator. | |
| void | ast_translator_free_path (struct ast_trans_pvt *tr) |
| Frees a translator path Frees the given translator path structure. | |
| int | ast_unregister_translator (struct ast_translator *t) |
| Unregister a translator Unregisters the given tranlator. | |
Support for translation of data formats. translate.c.
Definition in file translate.h.
| #define ast_register_translator | ( | t | ) | __ast_register_translator(t, ast_module_info->self) |
See __ast_register_translator()
Definition at line 170 of file translate.h.
Referenced by load_module(), and register_translator().
| #define MAX_AUDIO_FORMAT 47 |
Definition at line 27 of file translate.h.
Referenced by ast_translator_best_choice().
| #define MAX_FORMAT 64 |
Definition at line 28 of file translate.h.
Referenced by __ast_register_translator(), and rebuild_matrix().
| int __ast_register_translator | ( | struct ast_translator * | t, |
| struct ast_module * | mod | ||
| ) |
Register a translator This registers a codec translator with asterisk.
| t | populated ast_translator structure |
| module | handle to the module that owns this translator |
Definition at line 785 of file translate.c.
References ast_translator::active, ARRAY_LEN, ast_cli_register_multiple(), ast_getformatname(), ast_log(), AST_RWLIST_INSERT_BEFORE_CURRENT, AST_RWLIST_INSERT_HEAD, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, ast_translator::buf_size, calc_cost(), COLOR_BLACK, COLOR_MAGENTA, ast_translator::cost, default_frameout(), ast_translator::dstfmt, ast_translator::frameout, LOG_WARNING, MAX_FORMAT, ast_translator::module, ast_translator::name, powerof(), rebuild_matrix(), ast_translator::srcfmt, and term_color().
{
static int added_cli = 0;
struct ast_translator *u;
char tmp[80];
if (!mod) {
ast_log(LOG_WARNING, "Missing module pointer, you need to supply one\n");
return -1;
}
if (!t->buf_size) {
ast_log(LOG_WARNING, "empty buf size, you need to supply one\n");
return -1;
}
t->module = mod;
t->srcfmt = powerof(t->srcfmt);
t->dstfmt = powerof(t->dstfmt);
t->active = 1;
if (t->srcfmt == -1 || t->dstfmt == -1) {
ast_log(LOG_WARNING, "Invalid translator path: (%s codec is not valid)\n", t->srcfmt == -1 ? "starting" : "ending");
return -1;
}
if (t->srcfmt >= MAX_FORMAT) {
ast_log(LOG_WARNING, "Source format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt));
return -1;
}
if (t->dstfmt >= MAX_FORMAT) {
ast_log(LOG_WARNING, "Destination format %s is larger than MAX_FORMAT\n", ast_getformatname(t->dstfmt));
return -1;
}
if (t->buf_size) {
/*
* Align buf_size properly, rounding up to the machine-specific
* alignment for pointers.
*/
struct _test_align { void *a, *b; } p;
int align = (char *)&p.b - (char *)&p.a;
t->buf_size = ((t->buf_size + align - 1) / align) * align;
}
if (t->frameout == NULL)
t->frameout = default_frameout;
calc_cost(t, 1);
ast_verb(2, "Registered translator '%s' from format %s to %s, cost %d\n",
term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
ast_getformatname(1LL << t->srcfmt), ast_getformatname(1LL << t->dstfmt), t->cost);
if (!added_cli) {
ast_cli_register_multiple(cli_translate, ARRAY_LEN(cli_translate));
added_cli++;
}
AST_RWLIST_WRLOCK(&translators);
/* find any existing translators that provide this same srcfmt/dstfmt,
and put this one in order based on cost */
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
if ((u->srcfmt == t->srcfmt) &&
(u->dstfmt == t->dstfmt) &&
(u->cost > t->cost)) {
AST_RWLIST_INSERT_BEFORE_CURRENT(t, list);
t = NULL;
break;
}
}
AST_RWLIST_TRAVERSE_SAFE_END;
/* if no existing translator was found for this format combination,
add it to the beginning of the list */
if (t)
AST_RWLIST_INSERT_HEAD(&translators, t, list);
rebuild_matrix(0);
AST_RWLIST_UNLOCK(&translators);
return 0;
}
| struct ast_frame* ast_trans_frameout | ( | struct ast_trans_pvt * | pvt, |
| int | datalen, | ||
| int | samples | ||
| ) | [read] |
generic frameout function
Definition at line 191 of file translate.c.
References AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_frisolate(), ast_trans_pvt::c, ast_frame_subclass::codec, ast_frame::data, ast_trans_pvt::datalen, ast_frame::datalen, ast_translator::dstfmt, ast_trans_pvt::f, f, ast_frame::frametype, ast_frame::mallocd, ast_translator::name, ast_frame::offset, ast_trans_pvt::outbuf, ast_frame::ptr, ast_trans_pvt::samples, ast_frame::samples, ast_frame::src, ast_frame::subclass, and ast_trans_pvt::t.
Referenced by default_frameout(), lintoadpcm_frameout(), lintogsm_frameout(), lintoilbc_frameout(), lintolpc10_frameout(), and lintospeex_frameout().
{
struct ast_frame *f = &pvt->f;
if (samples)
f->samples = samples;
else {
if (pvt->samples == 0)
return NULL;
f->samples = pvt->samples;
pvt->samples = 0;
}
if (datalen)
f->datalen = datalen;
else {
f->datalen = pvt->datalen;
pvt->datalen = 0;
}
f->frametype = AST_FRAME_VOICE;
f->subclass.codec = 1LL << (pvt->t->dstfmt);
f->mallocd = 0;
f->offset = AST_FRIENDLY_OFFSET;
f->src = pvt->t->name;
f->data.ptr = pvt->outbuf.c;
return ast_frisolate(f);
}
| struct ast_frame* ast_translate | ( | struct ast_trans_pvt * | path, |
| struct ast_frame * | f, | ||
| int | consume | ||
| ) | [read] |
translates one or more frames Apply an input frame into the translator and receive zero or one output frames. Consume determines whether the original frame should be freed
| tr | translator structure to use for translation |
| f | frame to translate |
| consume | Whether or not to free the original frame |
Definition at line 284 of file translate.c.
References ast_format_rate(), AST_FRAME_CNG, AST_FRFLAG_HAS_TIMING_INFO, ast_frfree, ast_samp2tv(), ast_set2_flag, ast_test_flag, ast_tv(), ast_tvadd(), ast_tveq(), ast_tvnow(), ast_tvsub(), ast_tvzero(), ast_frame_subclass::codec, ast_frame::delivery, f, framein(), ast_frame::frametype, ast_frame::len, len(), ast_trans_pvt::next, ast_trans_pvt::nextin, ast_trans_pvt::nextout, ast_frame::samples, ast_frame::seqno, ast_frame::subclass, and ast_frame::ts.
Referenced by __ast_read(), ast_audiohook_read_frame(), ast_slinfactory_feed(), ast_write(), ast_writestream(), audio_audiohook_write_list(), and conf_run().
{
struct ast_trans_pvt *p = path;
struct ast_frame *out = f;
struct timeval delivery;
int has_timing_info;
long ts;
long len;
int seqno;
has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO);
ts = f->ts;
len = f->len;
seqno = f->seqno;
/* XXX hmmm... check this below */
if (!ast_tvzero(f->delivery)) {
if (!ast_tvzero(path->nextin)) {
/* Make sure this is in line with what we were expecting */
if (!ast_tveq(path->nextin, f->delivery)) {
/* The time has changed between what we expected and this
most recent time on the new packet. If we have a
valid prediction adjust our output time appropriately */
if (!ast_tvzero(path->nextout)) {
path->nextout = ast_tvadd(path->nextout,
ast_tvsub(f->delivery, path->nextin));
}
path->nextin = f->delivery;
}
} else {
/* This is our first pass. Make sure the timing looks good */
path->nextin = f->delivery;
path->nextout = f->delivery;
}
/* Predict next incoming sample */
path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(f->subclass.codec)));
}
delivery = f->delivery;
for ( ; out && p ; p = p->next) {
framein(p, out);
if (out != f)
ast_frfree(out);
out = p->t->frameout(p);
}
if (consume)
ast_frfree(f);
if (out == NULL)
return NULL;
/* we have a frame, play with times */
if (!ast_tvzero(delivery)) {
/* Regenerate prediction after a discontinuity */
if (ast_tvzero(path->nextout))
path->nextout = ast_tvnow();
/* Use next predicted outgoing timestamp */
out->delivery = path->nextout;
/* Predict next outgoing timestamp from samples in this
frame. */
path->nextout = ast_tvadd(path->nextout, ast_samp2tv(out->samples, ast_format_rate(out->subclass.codec)));
} else {
out->delivery = ast_tv(0, 0);
ast_set2_flag(out, has_timing_info, AST_FRFLAG_HAS_TIMING_INFO);
if (has_timing_info) {
out->ts = ts;
out->len = len;
out->seqno = seqno;
}
}
/* Invalidate prediction if we're entering a silence period */
if (out->frametype == AST_FRAME_CNG)
path->nextout = ast_tv(0, 0);
return out;
}
Mask off unavailable formats from a format bitmask.
| dest | possible destination formats |
| src | source formats |
The result will include all formats from 'dest' that are either present in 'src' or translatable from a format present in 'src'.
Definition at line 1013 of file translate.c.
References AST_FORMAT_AUDIO_MASK, AST_FORMAT_VIDEO_MASK, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, powerof(), and tr_matrix.
Referenced by ast_rtp_instance_available_formats().
{
format_t res = dest;
format_t x;
format_t src_audio = src & AST_FORMAT_AUDIO_MASK;
format_t src_video = src & AST_FORMAT_VIDEO_MASK;
/* if we don't have a source format, we just have to try all
possible destination formats */
if (!src)
return dest;
/* If we have a source audio format, get its format index */
if (src_audio)
src_audio = powerof(src_audio);
/* If we have a source video format, get its format index */
if (src_video)
src_video = powerof(src_video);
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 (x = 1LL; src_audio && x > 0; x <<= 1) {
if (!(x & AST_FORMAT_AUDIO_MASK)) {
continue;
}
/* if this is not a desired format, nothing to do */
if (!(dest & x))
continue;
/* if the source is supplying this format, then
we can leave it in the result */
if (src & x)
continue;
/* if we don't have a translation path from the src
to this format, remove it from the result */
if (!tr_matrix[src_audio][powerof(x)].step) {
res &= ~x;
continue;
}
/* now check the opposite direction */
if (!tr_matrix[powerof(x)][src_audio].step)
res &= ~x;
}
/* 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 (x = 1LL; src_video && x > 0; x <<= 1) {
if (!(x & AST_FORMAT_VIDEO_MASK)) {
continue;
}
/* if this is not a desired format, nothing to do */
if (!(dest & x))
continue;
/* if the source is supplying this format, then
we can leave it in the result */
if (src & x)
continue;
/* if we don't have a translation path from the src
to this format, remove it from the result */
if (!tr_matrix[src_video][powerof(x)].step) {
res &= ~x;
continue;
}
/* now check the opposite direction */
if (!tr_matrix[powerof(x)][src_video].step)
res &= ~x;
}
AST_RWLIST_UNLOCK(&translators);
return res;
}
Returns the number of steps required to convert from 'src' to 'dest'.
| dest | destination format |
| src | source format |
Definition at line 991 of file translate.c.
References ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, LOG_WARNING, translator_path::multistep, powerof(), and tr_matrix.
Referenced by ast_channel_make_compatible_helper().
{
unsigned int res = -1;
/* convert bitwise format numbers into array indices */
src = powerof(src);
dest = powerof(dest);
if (src == -1 || dest == -1) {
ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src == -1 ? "starting" : "ending");
return -1;
}
AST_RWLIST_RDLOCK(&translators);
if (tr_matrix[src][dest].step)
res = tr_matrix[src][dest].multistep + 1;
AST_RWLIST_UNLOCK(&translators);
return res;
}
| const char* ast_translate_path_to_str | ( | struct ast_trans_pvt * | t, |
| struct ast_str ** | str | ||
| ) |
Puts a string representation of the translation path into outbuf.
| translator | structure containing the translation path |
| ast_str | output buffer |
| on | success pointer to beginning of outbuf. on failure "". |
Definition at line 567 of file translate.c.
References ast_getformatname(), ast_str_append(), ast_str_buffer(), ast_str_set(), ast_translator::dstfmt, ast_trans_pvt::next, ast_translator::srcfmt, and ast_trans_pvt::t.
Referenced by handle_showchan(), and serialize_showchan().
{
struct ast_trans_pvt *pn = p;
if (!p || !p->t) {
return "";
}
ast_str_set(str, 0, "%s", ast_getformatname(1LL << p->t->srcfmt));
while ( (p = pn) ) {
pn = p->next;
ast_str_append(str, 0, "->%s", ast_getformatname(1LL << p->t->dstfmt));
}
return ast_str_buffer(*str);
}
| void ast_translator_activate | ( | struct ast_translator * | t | ) |
Activate a previously deactivated translator.
| t | translator to activate |
Enables the specified translator for use.
Definition at line 899 of file translate.c.
References ast_translator::active, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and rebuild_matrix().
{
AST_RWLIST_WRLOCK(&translators);
t->active = 1;
rebuild_matrix(0);
AST_RWLIST_UNLOCK(&translators);
}
Chooses the best translation path.
Given a list of sources, and a designed destination format, which should I choose?
Definition at line 916 of file translate.c.
References AST_FORMAT_AUDIO_MASK, ast_format_rate(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, translator_path::cost, ast_translator::cost, MAX_AUDIO_FORMAT, translator_path::multistep, translator_path::rate_change, and tr_matrix.
Referenced by ast_channel_make_compatible_helper(), ast_request(), iax2_request(), and set_format().
{
int x,y;
int better = 0;
int besttime = INT_MAX;
int beststeps = INT_MAX;
unsigned int best_rate_change = INT_MAX;
format_t best = -1;
format_t bestdst = 0;
format_t cur, cursrc;
format_t common = ((*dst) & (*srcs)) & AST_FORMAT_AUDIO_MASK; /* are there common formats ? */
if (common) { /* yes, pick one and return */
for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
if (!(cur & common)) {
continue;
}
/* We are guaranteed to find one common format. */
if (best == -1) {
best = cur;
continue;
}
/* If there are multiple common formats, pick the one with the highest sample rate */
if (ast_format_rate(best) < ast_format_rate(cur)) {
best = cur;
continue;
}
}
/* We are done, this is a common format to both. */
*srcs = *dst = best;
return 0;
} else { /* No, we will need to translate */
AST_RWLIST_RDLOCK(&translators);
for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
if (! (cur & *dst)) {
continue;
}
for (cursrc = 1, x = 0; x <= MAX_AUDIO_FORMAT; cursrc <<= 1, x++) {
if (!(*srcs & cursrc) || !tr_matrix[x][y].step) {
continue;
}
/* This is a better choice if any of the following are true.
* 1. The sample rate conversion is better than the current pick.
* 2. the sample rate conversion is no worse than the current pick and the cost or multistep is better
*/
better = 0;
if (tr_matrix[x][y].rate_change < best_rate_change) {
better = 1; /* this match has a better rate conversion */
}
if ((tr_matrix[x][y].rate_change <= best_rate_change) &&
(tr_matrix[x][y].cost < besttime || tr_matrix[x][y].multistep < beststeps)) {
better = 1; /* this match has no worse rate conversion and the conversion cost is less */
}
if (better) {
/* better than what we have so far */
best = cursrc;
bestdst = cur;
besttime = tr_matrix[x][y].cost;
beststeps = tr_matrix[x][y].multistep;
best_rate_change = tr_matrix[x][y].rate_change;
}
}
}
AST_RWLIST_UNLOCK(&translators);
if (best > -1) {
*srcs = best;
*dst = bestdst;
best = 0;
}
return best;
}
}
| struct ast_trans_pvt* ast_translator_build_path | ( | format_t | dest, |
| format_t | source | ||
| ) | [read] |
Builds a translator path Build a path (possibly NULL) from source to dest.
| dest | destination format |
| source | source format |
Definition at line 238 of file translate.c.
References ast_getformatname(), ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_translator_free_path(), ast_tv(), ast_translator::dstfmt, LOG_WARNING, newpvt(), ast_trans_pvt::next, ast_trans_pvt::nextin, ast_trans_pvt::nextout, powerof(), translator_path::step, ast_trans_pvt::t, and tr_matrix.
Referenced by ast_audiohook_read_frame(), ast_slinfactory_feed(), ast_writestream(), audio_audiohook_write_list(), conf_run(), and set_format().
{
struct ast_trans_pvt *head = NULL, *tail = NULL;
source = powerof(source);
dest = powerof(dest);
if (source == -1 || dest == -1) {
ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", source == -1 ? "starting" : "ending");
return NULL;
}
AST_RWLIST_RDLOCK(&translators);
while (source != dest) {
struct ast_trans_pvt *cur;
struct ast_translator *t = tr_matrix[source][dest].step;
if (!t) {
ast_log(LOG_WARNING, "No translator path from %s to %s\n",
ast_getformatname(source), ast_getformatname(dest));
AST_RWLIST_UNLOCK(&translators);
return NULL;
}
if (!(cur = newpvt(t))) {
ast_log(LOG_WARNING, "Failed to build translator step from %s to %s\n",
ast_getformatname(source), ast_getformatname(dest));
if (head)
ast_translator_free_path(head);
AST_RWLIST_UNLOCK(&translators);
return NULL;
}
if (!head)
head = cur;
else
tail->next = cur;
tail = cur;
cur->nextin = cur->nextout = ast_tv(0, 0);
/* Keep going if this isn't the final destination */
source = cur->t->dstfmt;
}
AST_RWLIST_UNLOCK(&translators);
return head;
}
| void ast_translator_deactivate | ( | struct ast_translator * | t | ) |
Deactivate a translator.
| t | translator to deactivate |
Disables the specified translator from being used.
Definition at line 907 of file translate.c.
References ast_translator::active, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and rebuild_matrix().
{
AST_RWLIST_WRLOCK(&translators);
t->active = 0;
rebuild_matrix(0);
AST_RWLIST_UNLOCK(&translators);
}
| void ast_translator_free_path | ( | struct ast_trans_pvt * | tr | ) |
Frees a translator path Frees the given translator path structure.
| tr | translator path to get rid of |
Definition at line 228 of file translate.c.
References destroy(), and ast_trans_pvt::next.
Referenced by ast_audiohook_destroy(), ast_audiohook_detach_list(), ast_audiohook_read_frame(), ast_channel_destructor(), ast_slinfactory_destroy(), ast_slinfactory_feed(), ast_slinfactory_flush(), ast_translator_build_path(), ast_writestream(), audio_audiohook_write_list(), conf_free(), filestream_destructor(), free_translation(), and set_format().
{
struct ast_trans_pvt *pn = p;
while ( (p = pn) ) {
pn = p->next;
destroy(p);
}
}
| int ast_unregister_translator | ( | struct ast_translator * | t | ) |
Unregister a translator Unregisters the given tranlator.
| t | translator to unregister |
Definition at line 874 of file translate.c.
References ast_getformatname(), AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, COLOR_BLACK, COLOR_MAGENTA, ast_translator::dstfmt, ast_translator::list, ast_translator::name, rebuild_matrix(), ast_translator::srcfmt, and term_color().
Referenced by drop_translator(), load_module(), unload_module(), and unregister_translators().
{
char tmp[80];
struct ast_translator *u;
int found = 0;
AST_RWLIST_WRLOCK(&translators);
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", term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), ast_getformatname(1LL << t->srcfmt), ast_getformatname(1LL << t->dstfmt));
found = 1;
break;
}
}
AST_RWLIST_TRAVERSE_SAFE_END;
if (found)
rebuild_matrix(0);
AST_RWLIST_UNLOCK(&translators);
return (u ? 0 : -1);
}