Support for translation of data formats. translate.c. More...
#include "asterisk/frame.h"
#include "asterisk/plc.h"
#include "asterisk/linkedlists.h"
#include "asterisk/plc.h"
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 15 |
#define | MAX_FORMAT 32 |
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 | |
unsigned int | ast_translate_available_formats (unsigned int dest, unsigned int src) |
Mask off unavailable formats from a format bitmask. | |
void | ast_translate_frame_freed (struct ast_frame *fr) |
Hint that a frame from a translator has been freed. | |
unsigned int | ast_translate_path_steps (unsigned int dest, unsigned int src) |
Returns the number of steps required to convert from 'src' to 'dest'. | |
void | ast_translator_activate (struct ast_translator *t) |
Activate a previously deactivated translator. | |
int | ast_translator_best_choice (int *dsts, int *srcs) |
Chooses the best translation path. | |
struct ast_trans_pvt * | ast_translator_build_path (int dest, int 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 173 of file translate.h.
Referenced by load_module(), and register_translator().
#define MAX_AUDIO_FORMAT 15 |
Definition at line 27 of file translate.h.
Referenced by ast_translator_best_choice().
#define MAX_FORMAT 32 |
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 596 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(1 << t->srcfmt), ast_getformatname(1 << 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 189 of file translate.c.
References AST_FRAME_VOICE, AST_FRFLAG_FROM_TRANSLATOR, AST_FRIENDLY_OFFSET, ast_set_flag, ast_trans_pvt::c, 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 = 1 << (pvt->t->dstfmt); f->mallocd = 0; f->offset = AST_FRIENDLY_OFFSET; f->src = pvt->t->name; f->data.ptr = pvt->outbuf.c; ast_set_flag(f, AST_FRFLAG_FROM_TRANSLATOR); return 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 283 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::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))); } 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))); } 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; }
unsigned int ast_translate_available_formats | ( | unsigned int | dest, |
unsigned int | src | ||
) |
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 797 of file translate.c.
References AST_FORMAT_AUDIO_MASK, AST_FORMAT_VIDEO_MASK, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, powerof(), translator_path::step, and tr_matrix.
Referenced by sip_call().
{ unsigned int res = dest; unsigned int x; unsigned int src_audio = src & AST_FORMAT_AUDIO_MASK; unsigned int 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 = 1; src_audio && (x & AST_FORMAT_AUDIO_MASK); x <<= 1) { /* 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 (; src_video && (x & AST_FORMAT_VIDEO_MASK); x <<= 1) { /* 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; }
void ast_translate_frame_freed | ( | struct ast_frame * | fr | ) |
Hint that a frame from a translator has been freed.
This is sort of a hack. This function gets called when ast_frame_free() gets called on a frame that has the AST_FRFLAG_FROM_TRANSLATOR flag set. This is because it is possible for a translation path to be destroyed while a frame from a translator is still in use. Specifically, this happens if a masquerade happens after a call to ast_read() but before the frame is done being processed, since the frame processing is generally done without the channel lock held.
Definition at line 876 of file translate.c.
References ast_clear_flag, AST_FRFLAG_FROM_TRANSLATOR, destroy(), ast_trans_pvt::destroy, f, and ast_trans_pvt::pvt.
Referenced by __frame_free().
{ struct ast_trans_pvt *pvt; ast_clear_flag(fr, AST_FRFLAG_FROM_TRANSLATOR); pvt = (struct ast_trans_pvt *) (((char *) fr) - offsetof(struct ast_trans_pvt, f)); if (!pvt->destroy) return; destroy(pvt); }
unsigned int ast_translate_path_steps | ( | unsigned int | dest, |
unsigned int | src | ||
) |
Returns the number of steps required to convert from 'src' to 'dest'.
dest | destination format |
src | source format |
Definition at line 775 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; }
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 711 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); }
int ast_translator_best_choice | ( | int * | dst, |
int * | srcs | ||
) |
Chooses the best translation path.
Given a list of sources, and a designed destination format, which should I choose?
Definition at line 728 of file translate.c.
References AST_FORMAT_AUDIO_MASK, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, translator_path::cost, ast_translator::cost, MAX_AUDIO_FORMAT, translator_path::multistep, and tr_matrix.
Referenced by ast_channel_make_compatible_helper(), ast_request(), iax2_request(), and set_format().
{ int x,y; int best = -1; int bestdst = 0; int cur, cursrc; int besttime = INT_MAX; int beststeps = INT_MAX; int 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) /* guaranteed to find one */ break; } /* We are done, this is a common format to both. */ *srcs = *dst = cur; 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 || tr_matrix[x][y].cost > besttime) continue; /* not existing or no better */ if (tr_matrix[x][y].cost < besttime || tr_matrix[x][y].multistep < beststeps) { /* better than what we have so far */ best = cursrc; bestdst = cur; besttime = tr_matrix[x][y].cost; beststeps = tr_matrix[x][y].multistep; } } } AST_RWLIST_UNLOCK(&translators); if (best > -1) { *srcs = best; *dst = bestdst; best = 0; } return best; } }
struct ast_trans_pvt* ast_translator_build_path | ( | int | dest, |
int | 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 %d to %d\n", source, 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 719 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_free(), 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 686 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(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt)); found = 1; break; } } AST_RWLIST_TRAVERSE_SAFE_END; if (found) rebuild_matrix(0); AST_RWLIST_UNLOCK(&translators); return (u ? 0 : -1); }