Translate via the use of pseudo channels. More...
#include "asterisk.h"
#include <sys/time.h>
#include <sys/resource.h>
#include <math.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/translate.h"
#include "asterisk/module.h"
#include "asterisk/frame.h"
#include "asterisk/sched.h"
#include "asterisk/cli.h"
#include "asterisk/term.h"
Go to the source code of this file.
Data Structures | |
struct | translator_path |
struct | translators |
the list of translators More... | |
Defines | |
#define | MAX_RECALC 1000 |
#define | SHOW_TRANS 64 |
Enumerations | |
enum | path_samp_change { AST_TRANS_COST_LL_LL_ORIGSAMP = 400000, AST_TRANS_COST_LL_LY_ORIGSAMP = 600000, AST_TRANS_COST_LL_LL_UPSAMP = 800000, AST_TRANS_COST_LL_LY_UPSAMP = 825000, AST_TRANS_COST_LL_LL_DOWNSAMP = 850000, AST_TRANS_COST_LL_LY_DOWNSAMP = 875000, AST_TRANS_COST_LL_UNKNOWN = 885000, AST_TRANS_COST_LY_LL_ORIGSAMP = 900000, AST_TRANS_COST_LY_LY_ORIGSAMP = 915000, AST_TRANS_COST_LY_LL_UPSAMP = 930000, AST_TRANS_COST_LY_LY_UPSAMP = 945000, AST_TRANS_COST_LY_LL_DOWNSAMP = 960000, AST_TRANS_COST_LY_LY_DOWNSAMP = 975000, AST_TRANS_COST_LY_UNKNOWN = 985000 } |
these values indicate how a translation path will affect the sample rate More... | |
Functions | |
int | __ast_register_translator (struct ast_translator *t, struct ast_module *mod) |
register codec translator | |
struct ast_frame * | ast_trans_frameout (struct ast_trans_pvt *pvt, int datalen, int samples) |
generic frameout routine. If samples and datalen are 0, take whatever is in pvt and reset them, otherwise take the values in the caller and leave alone the pvt values. | |
struct ast_frame * | ast_translate (struct ast_trans_pvt *path, struct ast_frame *f, int consume) |
do the actual translation | |
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 *p, 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 *dst, format_t *srcs) |
Calculate our best translator source format, given costs, and a desired destination. | |
struct ast_trans_pvt * | ast_translator_build_path (format_t dest, format_t source) |
Build a chain of translators based upon the given source and dest formats. | |
void | ast_translator_deactivate (struct ast_translator *t) |
Deactivate a translator. | |
void | ast_translator_free_path (struct ast_trans_pvt *p) |
Frees a translator path Frees the given translator path structure. | |
int | ast_unregister_translator (struct ast_translator *t) |
unregister codec translator | |
static void | calc_cost (struct ast_translator *t, int seconds) |
compute the cost of a single translation step | |
static char * | complete_trans_path_choice (const char *line, const char *word, int pos, int state) |
static struct ast_frame * | default_frameout (struct ast_trans_pvt *pvt) |
static void | destroy (struct ast_trans_pvt *pvt) |
static int | framein (struct ast_trans_pvt *pvt, struct ast_frame *f) |
framein wrapper, deals with bound checks. | |
static enum path_samp_change | get_rate_change_result (format_t src, format_t dst) |
static char * | handle_cli_core_show_translation (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static void * | newpvt (struct ast_translator *t) |
Allocate the descriptor, required outbuf space, and possibly desc. | |
static force_inline int | powerof (format_t d) |
returns the index of the lowest bit set | |
static void | rebuild_matrix (int samples) |
rebuild a translation matrix. | |
Variables | |
static struct ast_cli_entry | cli_translate [] |
static struct translator_path | tr_matrix [MAX_FORMAT][MAX_FORMAT] |
a matrix that, for any pair of supported formats, indicates the total cost of translation and the first step. The full path can be reconstricted iterating on the matrix until step->dstfmt == desired_format. |
Translate via the use of pseudo channels.
Definition in file translate.c.
#define MAX_RECALC 1000 |
Definition at line 47 of file translate.c.
Referenced by handle_cli_core_show_translation().
#define SHOW_TRANS 64 |
Referenced by handle_cli_core_show_translation().
enum path_samp_change |
these values indicate how a translation path will affect the sample rate
Definition at line 57 of file translate.c.
00057 { 00058 00059 /* Lossless Source Translation Costs */ 00060 00061 /*! [lossless -> lossless] original sampling */ 00062 AST_TRANS_COST_LL_LL_ORIGSAMP = 400000, 00063 /*! [lossless -> lossy] original sampling */ 00064 AST_TRANS_COST_LL_LY_ORIGSAMP = 600000, 00065 00066 /*! [lossless -> lossless] up sample */ 00067 AST_TRANS_COST_LL_LL_UPSAMP = 800000, 00068 /*! [lossless -> lossy] up sample */ 00069 AST_TRANS_COST_LL_LY_UPSAMP = 825000, 00070 00071 /*! [lossless -> lossless] down sample */ 00072 AST_TRANS_COST_LL_LL_DOWNSAMP = 850000, 00073 /*! [lossless -> lossy] down sample */ 00074 AST_TRANS_COST_LL_LY_DOWNSAMP = 875000, 00075 00076 /*! [lossless -> unknown] unknown. 00077 * This value is for a lossless source translation 00078 * with an unknown destination and or sample rate conversion. */ 00079 AST_TRANS_COST_LL_UNKNOWN = 885000, 00080 00081 /* Lossy Source Translation Costs */ 00082 00083 /*! [lossy -> lossless] original sampling */ 00084 AST_TRANS_COST_LY_LL_ORIGSAMP = 900000, 00085 /*! [lossy -> lossy] original sampling */ 00086 AST_TRANS_COST_LY_LY_ORIGSAMP = 915000, 00087 00088 /*! [lossy -> lossless] up sample */ 00089 AST_TRANS_COST_LY_LL_UPSAMP = 930000, 00090 /*! [lossy -> lossy] up sample */ 00091 AST_TRANS_COST_LY_LY_UPSAMP = 945000, 00092 00093 /*! [lossy -> lossless] down sample */ 00094 AST_TRANS_COST_LY_LL_DOWNSAMP = 960000, 00095 /*! [lossy -> lossy] down sample */ 00096 AST_TRANS_COST_LY_LY_DOWNSAMP = 975000, 00097 00098 /*! [lossy -> unknown] unknown. 00099 * This value is for a lossy source translation 00100 * with an unknown destination and or sample rate conversion. */ 00101 AST_TRANS_COST_LY_UNKNOWN = 985000, 00102 };
int __ast_register_translator | ( | struct ast_translator * | t, | |
struct ast_module * | mod | |||
) |
register codec translator
Register a translator This registers a codec translator with asterisk.
Definition at line 853 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().
00854 { 00855 static int added_cli = 0; 00856 struct ast_translator *u; 00857 char tmp[80]; 00858 00859 if (!mod) { 00860 ast_log(LOG_WARNING, "Missing module pointer, you need to supply one\n"); 00861 return -1; 00862 } 00863 00864 if (!t->buf_size) { 00865 ast_log(LOG_WARNING, "empty buf size, you need to supply one\n"); 00866 return -1; 00867 } 00868 00869 t->module = mod; 00870 00871 t->srcfmt = powerof(t->srcfmt); 00872 t->dstfmt = powerof(t->dstfmt); 00873 t->active = 1; 00874 00875 if (t->srcfmt == -1 || t->dstfmt == -1) { 00876 ast_log(LOG_WARNING, "Invalid translator path: (%s codec is not valid)\n", t->srcfmt == -1 ? "starting" : "ending"); 00877 return -1; 00878 } 00879 if (t->srcfmt >= MAX_FORMAT) { 00880 ast_log(LOG_WARNING, "Source format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt)); 00881 return -1; 00882 } 00883 00884 if (t->dstfmt >= MAX_FORMAT) { 00885 ast_log(LOG_WARNING, "Destination format %s is larger than MAX_FORMAT\n", ast_getformatname(t->dstfmt)); 00886 return -1; 00887 } 00888 00889 if (t->buf_size) { 00890 /* 00891 * Align buf_size properly, rounding up to the machine-specific 00892 * alignment for pointers. 00893 */ 00894 struct _test_align { void *a, *b; } p; 00895 int align = (char *)&p.b - (char *)&p.a; 00896 00897 t->buf_size = ((t->buf_size + align - 1) / align) * align; 00898 } 00899 00900 if (t->frameout == NULL) 00901 t->frameout = default_frameout; 00902 00903 calc_cost(t, 1); 00904 00905 ast_verb(2, "Registered translator '%s' from format %s to %s, cost %d\n", 00906 term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), 00907 ast_getformatname(1LL << t->srcfmt), ast_getformatname(1LL << t->dstfmt), t->cost); 00908 00909 if (!added_cli) { 00910 ast_cli_register_multiple(cli_translate, ARRAY_LEN(cli_translate)); 00911 added_cli++; 00912 } 00913 00914 AST_RWLIST_WRLOCK(&translators); 00915 00916 /* find any existing translators that provide this same srcfmt/dstfmt, 00917 and put this one in order based on cost */ 00918 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) { 00919 if ((u->srcfmt == t->srcfmt) && 00920 (u->dstfmt == t->dstfmt) && 00921 (u->cost > t->cost)) { 00922 AST_RWLIST_INSERT_BEFORE_CURRENT(t, list); 00923 t = NULL; 00924 break; 00925 } 00926 } 00927 AST_RWLIST_TRAVERSE_SAFE_END; 00928 00929 /* if no existing translator was found for this format combination, 00930 add it to the beginning of the list */ 00931 if (t) 00932 AST_RWLIST_INSERT_HEAD(&translators, t, list); 00933 00934 rebuild_matrix(0); 00935 00936 AST_RWLIST_UNLOCK(&translators); 00937 00938 return 0; 00939 }
struct ast_frame* ast_trans_frameout | ( | struct ast_trans_pvt * | pvt, | |
int | datalen, | |||
int | samples | |||
) | [read] |
generic frameout routine. If samples and datalen are 0, take whatever is in pvt and reset them, otherwise take the values in the caller and leave alone the pvt values.
generic frameout function
Definition at line 235 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().
00237 { 00238 struct ast_frame *f = &pvt->f; 00239 00240 if (samples) 00241 f->samples = samples; 00242 else { 00243 if (pvt->samples == 0) 00244 return NULL; 00245 f->samples = pvt->samples; 00246 pvt->samples = 0; 00247 } 00248 if (datalen) 00249 f->datalen = datalen; 00250 else { 00251 f->datalen = pvt->datalen; 00252 pvt->datalen = 0; 00253 } 00254 00255 f->frametype = AST_FRAME_VOICE; 00256 f->subclass.codec = 1LL << (pvt->t->dstfmt); 00257 f->mallocd = 0; 00258 f->offset = AST_FRIENDLY_OFFSET; 00259 f->src = pvt->t->name; 00260 f->data.ptr = pvt->outbuf.c; 00261 00262 return ast_frisolate(f); 00263 }
struct ast_frame* ast_translate | ( | struct ast_trans_pvt * | path, | |
struct ast_frame * | f, | |||
int | consume | |||
) | [read] |
do the actual translation
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
Definition at line 328 of file translate.c.
References ast_clear_flag, ast_debug, 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, 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().
00329 { 00330 struct ast_trans_pvt *p = path; 00331 struct ast_frame *out = f; 00332 struct timeval delivery; 00333 int has_timing_info; 00334 long ts; 00335 long len; 00336 int seqno; 00337 00338 has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO); 00339 ts = f->ts; 00340 len = f->len; 00341 seqno = f->seqno; 00342 00343 /* XXX hmmm... check this below */ 00344 if (!ast_tvzero(f->delivery)) { 00345 if (!ast_tvzero(path->nextin)) { 00346 /* Make sure this is in line with what we were expecting */ 00347 if (!ast_tveq(path->nextin, f->delivery)) { 00348 /* The time has changed between what we expected and this 00349 most recent time on the new packet. If we have a 00350 valid prediction adjust our output time appropriately */ 00351 if (!ast_tvzero(path->nextout)) { 00352 path->nextout = ast_tvadd(path->nextout, 00353 ast_tvsub(f->delivery, path->nextin)); 00354 } 00355 path->nextin = f->delivery; 00356 } 00357 } else { 00358 /* This is our first pass. Make sure the timing looks good */ 00359 path->nextin = f->delivery; 00360 path->nextout = f->delivery; 00361 } 00362 /* Predict next incoming sample */ 00363 path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(f->subclass.codec))); 00364 } 00365 delivery = f->delivery; 00366 for ( ; out && p ; p = p->next) { 00367 framein(p, out); 00368 if (out != f) 00369 ast_frfree(out); 00370 out = p->t->frameout(p); 00371 } 00372 if (out) { 00373 /* we have a frame, play with times */ 00374 if (!ast_tvzero(delivery)) { 00375 /* Regenerate prediction after a discontinuity */ 00376 if (ast_tvzero(path->nextout)) { 00377 path->nextout = ast_tvnow(); 00378 } 00379 00380 /* Use next predicted outgoing timestamp */ 00381 out->delivery = path->nextout; 00382 00383 /* Predict next outgoing timestamp from samples in this 00384 frame. */ 00385 path->nextout = ast_tvadd(path->nextout, ast_samp2tv(out->samples, ast_format_rate(out->subclass.codec))); 00386 if (f->samples != out->samples && ast_test_flag(out, AST_FRFLAG_HAS_TIMING_INFO)) { 00387 ast_debug(4, "Sample size different %d vs %d\n", f->samples, out->samples); 00388 ast_clear_flag(out, AST_FRFLAG_HAS_TIMING_INFO); 00389 } 00390 } else { 00391 out->delivery = ast_tv(0, 0); 00392 ast_set2_flag(out, has_timing_info, AST_FRFLAG_HAS_TIMING_INFO); 00393 if (has_timing_info) { 00394 out->ts = ts; 00395 out->len = len; 00396 out->seqno = seqno; 00397 } 00398 } 00399 /* Invalidate prediction if we're entering a silence period */ 00400 if (out->frametype == AST_FRAME_CNG) { 00401 path->nextout = ast_tv(0, 0); 00402 } 00403 } 00404 if (consume) { 00405 ast_frfree(f); 00406 } 00407 return out; 00408 }
Mask off unavailable formats from a format bitmask.
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 1081 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().
01082 { 01083 format_t res = dest; 01084 format_t x; 01085 format_t src_audio = src & AST_FORMAT_AUDIO_MASK; 01086 format_t src_video = src & AST_FORMAT_VIDEO_MASK; 01087 format_t x_bits; 01088 01089 /* if we don't have a source format, we just have to try all 01090 possible destination formats */ 01091 if (!src) 01092 return dest; 01093 01094 /* If we have a source audio format, get its format index */ 01095 if (src_audio) { 01096 src_audio = powerof(src_audio); 01097 } 01098 01099 /* If we have a source video format, get its format index */ 01100 if (src_video) { 01101 src_video = powerof(src_video); 01102 } 01103 01104 /* Note that src_audio and src_video are guaranteed to not be 01105 * negative at this point, as we ensured they were non-zero. It is 01106 * safe to use the return value of powerof as an index into tr_matrix. 01107 */ 01108 01109 AST_RWLIST_RDLOCK(&translators); 01110 01111 /* For a given source audio format, traverse the list of 01112 known audio formats to determine whether there exists 01113 a translation path from the source format to the 01114 destination format. */ 01115 for (x = 1LL; src_audio && x > 0; x <<= 1) { 01116 if (!(x & AST_FORMAT_AUDIO_MASK)) { 01117 continue; 01118 } 01119 01120 /* if this is not a desired format, nothing to do */ 01121 if (!(dest & x)) 01122 continue; 01123 01124 /* if the source is supplying this format, then 01125 we can leave it in the result */ 01126 if (src & x) 01127 continue; 01128 01129 /* if we don't have a translation path from the src 01130 to this format, remove it from the result. Note that x_bits 01131 cannot be less than 0 as x will always have one bit set to 1 */ 01132 x_bits = powerof(x); 01133 if (!tr_matrix[src_audio][x_bits].step) { 01134 res &= ~x; 01135 continue; 01136 } 01137 01138 /* now check the opposite direction */ 01139 if (!tr_matrix[x_bits][src_audio].step) 01140 res &= ~x; 01141 } 01142 01143 /* For a given source video format, traverse the list of 01144 known video formats to determine whether there exists 01145 a translation path from the source format to the 01146 destination format. */ 01147 for (x = 1LL; src_video && x > 0; x <<= 1) { 01148 if (!(x & AST_FORMAT_VIDEO_MASK)) { 01149 continue; 01150 } 01151 01152 /* if this is not a desired format, nothing to do */ 01153 if (!(dest & x)) 01154 continue; 01155 01156 /* if the source is supplying this format, then 01157 we can leave it in the result */ 01158 if (src & x) 01159 continue; 01160 01161 /* if we don't have a translation path from the src 01162 to this format, remove it from the result. Note that x_bits 01163 cannot be less than 0 as x will always have one bit set to 1 */ 01164 x_bits = powerof(x); 01165 if (!tr_matrix[src_video][x_bits].step) { 01166 res &= ~x; 01167 continue; 01168 } 01169 01170 /* now check the opposite direction */ 01171 if (!tr_matrix[x_bits][src_video].step) 01172 res &= ~x; 01173 } 01174 01175 AST_RWLIST_UNLOCK(&translators); 01176 01177 return res; 01178 }
Returns the number of steps required to convert from 'src' to 'dest'.
dest | destination format | |
src | source format |
Definition at line 1059 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().
01060 { 01061 unsigned int res = -1; 01062 01063 /* convert bitwise format numbers into array indices */ 01064 src = powerof(src); 01065 dest = powerof(dest); 01066 01067 if (src == -1 || dest == -1) { 01068 ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src == -1 ? "starting" : "ending"); 01069 return -1; 01070 } 01071 AST_RWLIST_RDLOCK(&translators); 01072 01073 if (tr_matrix[src][dest].step) 01074 res = tr_matrix[src][dest].multistep + 1; 01075 01076 AST_RWLIST_UNLOCK(&translators); 01077 01078 return res; 01079 }
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 630 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().
00631 { 00632 struct ast_trans_pvt *pn = p; 00633 00634 if (!p || !p->t) { 00635 return ""; 00636 } 00637 00638 ast_str_set(str, 0, "%s", ast_getformatname(1LL << p->t->srcfmt)); 00639 00640 while ( (p = pn) ) { 00641 pn = p->next; 00642 ast_str_append(str, 0, "->%s", ast_getformatname(1LL << p->t->dstfmt)); 00643 } 00644 00645 return ast_str_buffer(*str); 00646 }
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 967 of file translate.c.
References ast_translator::active, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and rebuild_matrix().
00968 { 00969 AST_RWLIST_WRLOCK(&translators); 00970 t->active = 1; 00971 rebuild_matrix(0); 00972 AST_RWLIST_UNLOCK(&translators); 00973 }
Calculate our best translator source format, given costs, and a desired destination.
Chooses the best translation path.
Definition at line 984 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().
00985 { 00986 int x,y; 00987 int better = 0; 00988 int besttime = INT_MAX; 00989 int beststeps = INT_MAX; 00990 unsigned int best_rate_change = INT_MAX; 00991 format_t best = -1; 00992 format_t bestdst = 0; 00993 format_t cur, cursrc; 00994 format_t common = ((*dst) & (*srcs)) & AST_FORMAT_AUDIO_MASK; /* are there common formats ? */ 00995 00996 if (common) { /* yes, pick one and return */ 00997 for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) { 00998 if (!(cur & common)) { 00999 continue; 01000 } 01001 01002 /* We are guaranteed to find one common format. */ 01003 if (best == -1) { 01004 best = cur; 01005 continue; 01006 } 01007 /* If there are multiple common formats, pick the one with the highest sample rate */ 01008 if (ast_format_rate(best) < ast_format_rate(cur)) { 01009 best = cur; 01010 continue; 01011 } 01012 } 01013 /* We are done, this is a common format to both. */ 01014 *srcs = *dst = best; 01015 return 0; 01016 } else { /* No, we will need to translate */ 01017 AST_RWLIST_RDLOCK(&translators); 01018 for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) { 01019 if (! (cur & *dst)) { 01020 continue; 01021 } 01022 for (cursrc = 1, x = 0; x <= MAX_AUDIO_FORMAT; cursrc <<= 1, x++) { 01023 if (!(*srcs & cursrc) || !tr_matrix[x][y].step) { 01024 continue; 01025 } 01026 01027 /* This is a better choice if any of the following are true. 01028 * 1. The sample rate conversion is better than the current pick. 01029 * 2. the sample rate conversion is no worse than the current pick and the cost or multistep is better 01030 */ 01031 better = 0; 01032 if (tr_matrix[x][y].rate_change < best_rate_change) { 01033 better = 1; /* this match has a better rate conversion */ 01034 } 01035 if ((tr_matrix[x][y].rate_change <= best_rate_change) && 01036 (tr_matrix[x][y].cost < besttime || tr_matrix[x][y].multistep < beststeps)) { 01037 better = 1; /* this match has no worse rate conversion and the conversion cost is less */ 01038 } 01039 if (better) { 01040 /* better than what we have so far */ 01041 best = cursrc; 01042 bestdst = cur; 01043 besttime = tr_matrix[x][y].cost; 01044 beststeps = tr_matrix[x][y].multistep; 01045 best_rate_change = tr_matrix[x][y].rate_change; 01046 } 01047 } 01048 } 01049 AST_RWLIST_UNLOCK(&translators); 01050 if (best > -1) { 01051 *srcs = best; 01052 *dst = bestdst; 01053 best = 0; 01054 } 01055 return best; 01056 } 01057 }
struct ast_trans_pvt* ast_translator_build_path | ( | format_t | dest, | |
format_t | source | |||
) | [read] |
Build a chain of translators based upon the given source and dest formats.
Builds a translator path Build a path (possibly NULL) from source to dest.
Definition at line 282 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().
00283 { 00284 struct ast_trans_pvt *head = NULL, *tail = NULL; 00285 00286 source = powerof(source); 00287 dest = powerof(dest); 00288 00289 if (source == -1 || dest == -1) { 00290 ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", source == -1 ? "starting" : "ending"); 00291 return NULL; 00292 } 00293 00294 AST_RWLIST_RDLOCK(&translators); 00295 00296 while (source != dest) { 00297 struct ast_trans_pvt *cur; 00298 struct ast_translator *t = tr_matrix[source][dest].step; 00299 if (!t) { 00300 ast_log(LOG_WARNING, "No translator path from %s to %s\n", 00301 ast_getformatname(source), ast_getformatname(dest)); 00302 AST_RWLIST_UNLOCK(&translators); 00303 return NULL; 00304 } 00305 if (!(cur = newpvt(t))) { 00306 ast_log(LOG_WARNING, "Failed to build translator step from %s to %s\n", 00307 ast_getformatname(source), ast_getformatname(dest)); 00308 if (head) 00309 ast_translator_free_path(head); 00310 AST_RWLIST_UNLOCK(&translators); 00311 return NULL; 00312 } 00313 if (!head) 00314 head = cur; 00315 else 00316 tail->next = cur; 00317 tail = cur; 00318 cur->nextin = cur->nextout = ast_tv(0, 0); 00319 /* Keep going if this isn't the final destination */ 00320 source = cur->t->dstfmt; 00321 } 00322 00323 AST_RWLIST_UNLOCK(&translators); 00324 return head; 00325 }
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 975 of file translate.c.
References ast_translator::active, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and rebuild_matrix().
00976 { 00977 AST_RWLIST_WRLOCK(&translators); 00978 t->active = 0; 00979 rebuild_matrix(0); 00980 AST_RWLIST_UNLOCK(&translators); 00981 }
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 272 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().
00273 { 00274 struct ast_trans_pvt *pn = p; 00275 while ( (p = pn) ) { 00276 pn = p->next; 00277 destroy(p); 00278 } 00279 }
int ast_unregister_translator | ( | struct ast_translator * | t | ) |
unregister codec translator
Unregister a translator Unregisters the given tranlator.
Definition at line 942 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().
00943 { 00944 char tmp[80]; 00945 struct ast_translator *u; 00946 int found = 0; 00947 00948 AST_RWLIST_WRLOCK(&translators); 00949 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) { 00950 if (u == t) { 00951 AST_RWLIST_REMOVE_CURRENT(list); 00952 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)); 00953 found = 1; 00954 break; 00955 } 00956 } 00957 AST_RWLIST_TRAVERSE_SAFE_END; 00958 00959 if (found) 00960 rebuild_matrix(0); 00961 00962 AST_RWLIST_UNLOCK(&translators); 00963 00964 return (u ? 0 : -1); 00965 }
static void calc_cost | ( | struct ast_translator * | t, | |
int | seconds | |||
) | [static] |
compute the cost of a single translation step
Definition at line 411 of file translate.c.
References ast_format_rate(), ast_frfree, ast_log(), ast_translator::cost, destroy(), ast_translator::dstfmt, f, framein(), ast_translator::frameout, LOG_WARNING, ast_translator::name, newpvt(), ast_trans_pvt::pvt, ast_translator::sample, and ast_frame::samples.
Referenced by __ast_register_translator(), and rebuild_matrix().
00412 { 00413 int num_samples = 0; 00414 struct ast_trans_pvt *pvt; 00415 struct rusage start; 00416 struct rusage end; 00417 int cost; 00418 int out_rate = ast_format_rate(t->dstfmt); 00419 00420 if (!seconds) 00421 seconds = 1; 00422 00423 /* If they don't make samples, give them a terrible score */ 00424 if (!t->sample) { 00425 ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name); 00426 t->cost = 999999; 00427 return; 00428 } 00429 00430 pvt = newpvt(t); 00431 if (!pvt) { 00432 ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name); 00433 t->cost = 999999; 00434 return; 00435 } 00436 00437 getrusage(RUSAGE_SELF, &start); 00438 00439 /* Call the encoder until we've processed the required number of samples */ 00440 while (num_samples < seconds * out_rate) { 00441 struct ast_frame *f = t->sample(); 00442 if (!f) { 00443 ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name); 00444 destroy(pvt); 00445 t->cost = 999999; 00446 return; 00447 } 00448 framein(pvt, f); 00449 ast_frfree(f); 00450 while ((f = t->frameout(pvt))) { 00451 num_samples += f->samples; 00452 ast_frfree(f); 00453 } 00454 } 00455 00456 getrusage(RUSAGE_SELF, &end); 00457 00458 cost = ((end.ru_utime.tv_sec - start.ru_utime.tv_sec) * 1000000) + end.ru_utime.tv_usec - start.ru_utime.tv_usec; 00459 cost += ((end.ru_stime.tv_sec - start.ru_stime.tv_sec) * 1000000) + end.ru_stime.tv_usec - start.ru_stime.tv_usec; 00460 00461 destroy(pvt); 00462 00463 t->cost = cost / seconds; 00464 00465 if (!t->cost) 00466 t->cost = 1; 00467 }
static char* complete_trans_path_choice | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 648 of file translate.c.
References AST_FORMAT_AUDIO_MASK, ast_get_format_list(), ast_strdup, ast_format_list::bits, len(), and name.
Referenced by handle_cli_core_show_translation().
00649 { 00650 int which = 0; 00651 int wordlen = strlen(word); 00652 int i; 00653 char *ret = NULL; 00654 size_t len = 0; 00655 const struct ast_format_list *format_list = ast_get_format_list(&len); 00656 00657 for (i = 0; i < len; i++) { 00658 if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) { 00659 continue; 00660 } 00661 if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) { 00662 ret = ast_strdup(format_list[i].name); 00663 break; 00664 } 00665 } 00666 return ret; 00667 }
static struct ast_frame* default_frameout | ( | struct ast_trans_pvt * | pvt | ) | [static, read] |
Definition at line 265 of file translate.c.
References ast_trans_frameout().
Referenced by __ast_register_translator().
00266 { 00267 return ast_trans_frameout(pvt, 0, 0); 00268 }
static void destroy | ( | struct ast_trans_pvt * | pvt | ) | [static] |
Definition at line 183 of file translate.c.
References ast_free, ast_module_unref(), ast_translator::destroy, ast_translator::module, and ast_trans_pvt::t.
Referenced by ast_translator_free_path(), and calc_cost().
00184 { 00185 struct ast_translator *t = pvt->t; 00186 00187 if (t->destroy) 00188 t->destroy(pvt); 00189 ast_free(pvt); 00190 ast_module_unref(t->module); 00191 }
static int framein | ( | struct ast_trans_pvt * | pvt, | |
struct ast_frame * | f | |||
) | [static] |
framein wrapper, deals with bound checks.
Definition at line 194 of file translate.c.
References ast_copy_flags, AST_FRFLAG_HAS_TIMING_INFO, ast_log(), ast_translator::buffer_samples, ast_frame::datalen, ast_trans_pvt::f, ast_translator::framein, ast_frame::len, LOG_WARNING, ast_translator::name, ast_translator::native_plc, ast_frame::samples, ast_trans_pvt::samples, ast_frame::seqno, ast_trans_pvt::t, and ast_frame::ts.
Referenced by ast_translate(), and calc_cost().
00195 { 00196 int ret; 00197 int samples = pvt->samples; /* initial value */ 00198 00199 /* Copy the last in jb timing info to the pvt */ 00200 ast_copy_flags(&pvt->f, f, AST_FRFLAG_HAS_TIMING_INFO); 00201 pvt->f.ts = f->ts; 00202 pvt->f.len = f->len; 00203 pvt->f.seqno = f->seqno; 00204 00205 if (f->samples == 0) { 00206 ast_log(LOG_WARNING, "no samples for %s\n", pvt->t->name); 00207 } 00208 if (pvt->t->buffer_samples) { /* do not pass empty frames to callback */ 00209 if (f->datalen == 0) { /* perform native PLC if available */ 00210 /* If the codec has native PLC, then do that */ 00211 if (!pvt->t->native_plc) 00212 return 0; 00213 } 00214 if (pvt->samples + f->samples > pvt->t->buffer_samples) { 00215 ast_log(LOG_WARNING, "Out of buffer space\n"); 00216 return -1; 00217 } 00218 } 00219 /* we require a framein routine, wouldn't know how to do 00220 * it otherwise. 00221 */ 00222 ret = pvt->t->framein(pvt, f); 00223 /* diagnostic ... */ 00224 if (pvt->samples == samples) 00225 ast_log(LOG_WARNING, "%s did not update samples %d\n", 00226 pvt->t->name, pvt->samples); 00227 return ret; 00228 }
static enum path_samp_change get_rate_change_result | ( | format_t | src, | |
format_t | dst | |||
) | [static] |
Definition at line 469 of file translate.c.
References ast_format_rate(), AST_FORMAT_SLINEAR, AST_FORMAT_SLINEAR16, AST_TRANS_COST_LL_LL_DOWNSAMP, AST_TRANS_COST_LL_LL_ORIGSAMP, AST_TRANS_COST_LL_LL_UPSAMP, AST_TRANS_COST_LL_LY_DOWNSAMP, AST_TRANS_COST_LL_LY_ORIGSAMP, AST_TRANS_COST_LL_LY_UPSAMP, AST_TRANS_COST_LL_UNKNOWN, AST_TRANS_COST_LY_LL_DOWNSAMP, AST_TRANS_COST_LY_LL_ORIGSAMP, AST_TRANS_COST_LY_LL_UPSAMP, AST_TRANS_COST_LY_LY_DOWNSAMP, AST_TRANS_COST_LY_LY_ORIGSAMP, AST_TRANS_COST_LY_LY_UPSAMP, and AST_TRANS_COST_LY_UNKNOWN.
Referenced by rebuild_matrix().
00470 { 00471 int src_ll = src == AST_FORMAT_SLINEAR || src == AST_FORMAT_SLINEAR16; 00472 int dst_ll = dst == AST_FORMAT_SLINEAR || src == AST_FORMAT_SLINEAR16; 00473 int src_rate = ast_format_rate(src); 00474 int dst_rate = ast_format_rate(dst); 00475 00476 if (src_ll) { 00477 if (dst_ll && (src_rate == dst_rate)) { 00478 return AST_TRANS_COST_LL_LL_ORIGSAMP; 00479 } else if (!dst_ll && (src_rate == dst_rate)) { 00480 return AST_TRANS_COST_LL_LY_ORIGSAMP; 00481 } else if (dst_ll && (src_rate < dst_rate)) { 00482 return AST_TRANS_COST_LL_LL_UPSAMP; 00483 } else if (!dst_ll && (src_rate < dst_rate)) { 00484 return AST_TRANS_COST_LL_LY_UPSAMP; 00485 } else if (dst_ll && (src_rate > dst_rate)) { 00486 return AST_TRANS_COST_LL_LL_DOWNSAMP; 00487 } else if (!dst_ll && (src_rate > dst_rate)) { 00488 return AST_TRANS_COST_LL_LY_DOWNSAMP; 00489 } else { 00490 return AST_TRANS_COST_LL_UNKNOWN; 00491 } 00492 } else { 00493 if (dst_ll && (src_rate == dst_rate)) { 00494 return AST_TRANS_COST_LY_LL_ORIGSAMP; 00495 } else if (!dst_ll && (src_rate == dst_rate)) { 00496 return AST_TRANS_COST_LY_LY_ORIGSAMP; 00497 } else if (dst_ll && (src_rate < dst_rate)) { 00498 return AST_TRANS_COST_LY_LL_UPSAMP; 00499 } else if (!dst_ll && (src_rate < dst_rate)) { 00500 return AST_TRANS_COST_LY_LY_UPSAMP; 00501 } else if (dst_ll && (src_rate > dst_rate)) { 00502 return AST_TRANS_COST_LY_LL_DOWNSAMP; 00503 } else if (!dst_ll && (src_rate > dst_rate)) { 00504 return AST_TRANS_COST_LY_LY_DOWNSAMP; 00505 } else { 00506 return AST_TRANS_COST_LY_UNKNOWN; 00507 } 00508 } 00509 }
static char* handle_cli_core_show_translation | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 669 of file translate.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_cli_complete(), AST_FORMAT_AUDIO_MASK, ast_format_rate(), ast_get_format_list(), ast_getformatname(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_reset(), ast_str_set(), ast_strlen_zero(), ast_format_list::bits, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_trans_path_choice(), ast_translator::cost, ast_cli_args::fd, len(), ast_cli_args::line, MAX_RECALC, ast_cli_args::n, ast_format_list::name, name, ast_cli_args::pos, powerof(), rebuild_matrix(), SHOW_TRANS, translator_path::step, str, tr_matrix, ast_cli_entry::usage, and ast_cli_args::word.
00670 { 00671 #define SHOW_TRANS 64 00672 static const char * const option1[] = { "recalc", "paths", NULL }; 00673 int x, y, z; 00674 int curlen = 0, longest = 0, magnitude[SHOW_TRANS] = { 0, }; 00675 00676 switch (cmd) { 00677 case CLI_INIT: 00678 e->command = "core show translation"; 00679 e->usage = 00680 "Usage: 'core show translation' can be used in two ways.\n" 00681 " 1. 'core show translation [recalc [<recalc seconds>]]\n" 00682 " Displays known codec translators and the cost associated\n" 00683 " with each conversion. If the argument 'recalc' is supplied along\n" 00684 " with optional number of seconds to test a new test will be performed\n" 00685 " as the chart is being displayed.\n" 00686 " 2. 'core show translation paths [codec]'\n" 00687 " This will display all the translation paths associated with a codec\n"; 00688 return NULL; 00689 case CLI_GENERATE: 00690 if (a->pos == 3) { 00691 return ast_cli_complete(a->word, option1, a->n); 00692 } 00693 if (a->pos == 4 && !strcasecmp(a->argv[3], option1[1])) { 00694 return complete_trans_path_choice(a->line, a->word, a->pos, a->n); 00695 } 00696 return NULL; 00697 } 00698 00699 if (a->argc > 5) 00700 return CLI_SHOWUSAGE; 00701 00702 if (a->argv[3] && !strcasecmp(a->argv[3], option1[1]) && a->argc == 5) { 00703 format_t input_src = 0; 00704 format_t src = 0; 00705 size_t len = 0; 00706 int dst; 00707 int i; 00708 const struct ast_format_list *format_list = ast_get_format_list(&len); 00709 struct ast_str *str = ast_str_alloca(256); 00710 struct ast_translator *step; 00711 00712 for (i = 0; i < len; i++) { 00713 if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) { 00714 continue; 00715 } 00716 if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) { 00717 input_src = format_list[i].bits; 00718 } 00719 } 00720 00721 if (!input_src) { 00722 ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]); 00723 return CLI_FAILURE; 00724 } 00725 00726 AST_RWLIST_RDLOCK(&translators); 00727 ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(input_src)); 00728 for (i = 0; i < len; i++) { 00729 if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK) || (format_list[i].bits == input_src)) { 00730 continue; 00731 } 00732 /* Note that dst can never be -1, as an element of format_list will have 00733 * at least one bit set. src cannot be -1 as well, as it is previously 00734 * sanitized - hence it is safe to directly index tr_matrix with the results 00735 * of powerof. 00736 */ 00737 dst = powerof(format_list[i].bits); 00738 src = powerof(input_src); 00739 ast_str_reset(str); 00740 if (tr_matrix[src][dst].step) { 00741 ast_str_append(&str, 0, "%s", ast_getformatname(1LL << tr_matrix[src][dst].step->srcfmt)); 00742 while (src != dst) { 00743 step = tr_matrix[src][dst].step; 00744 if (!step) { 00745 ast_str_reset(str); 00746 break; 00747 } 00748 ast_str_append(&str, 0, "->%s", ast_getformatname(1LL << step->dstfmt)); 00749 src = step->dstfmt; 00750 } 00751 } 00752 00753 if (ast_strlen_zero(ast_str_buffer(str))) { 00754 ast_str_set(&str, 0, "No Translation Path"); 00755 } 00756 00757 ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str)); 00758 } 00759 AST_RWLIST_UNLOCK(&translators); 00760 00761 return CLI_SUCCESS; 00762 } else if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) { 00763 z = a->argv[4] ? atoi(a->argv[4]) : 1; 00764 00765 if (z <= 0) { 00766 ast_cli(a->fd, " Recalc must be greater than 0. Defaulting to 1.\n"); 00767 z = 1; 00768 } 00769 00770 if (z > MAX_RECALC) { 00771 ast_cli(a->fd, " Maximum limit of recalc exceeded by %d, truncating value to %d\n", z - MAX_RECALC, MAX_RECALC); 00772 z = MAX_RECALC; 00773 } 00774 ast_cli(a->fd, " Recalculating Codec Translation (number of sample seconds: %d)\n\n", z); 00775 AST_RWLIST_WRLOCK(&translators); 00776 rebuild_matrix(z); 00777 AST_RWLIST_UNLOCK(&translators); 00778 } else if (a->argc > 3) 00779 return CLI_SHOWUSAGE; 00780 00781 AST_RWLIST_RDLOCK(&translators); 00782 00783 ast_cli(a->fd, " Translation times between formats (in microseconds) for one second of data\n"); 00784 ast_cli(a->fd, " Source Format (Rows) Destination Format (Columns)\n\n"); 00785 /* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */ 00786 for (x = 0; x < SHOW_TRANS; x++) { 00787 /* translation only applies to audio right now. */ 00788 if (!(AST_FORMAT_AUDIO_MASK & (1LL << (x)))) 00789 continue; 00790 curlen = strlen(ast_getformatname(1LL << (x))); 00791 if (curlen > longest) 00792 longest = curlen; 00793 for (y = 0; y < SHOW_TRANS; y++) { 00794 if (!(AST_FORMAT_AUDIO_MASK & (1LL << (y)))) 00795 continue; 00796 if (tr_matrix[x][y].cost > pow(10, magnitude[x])) { 00797 magnitude[y] = floor(log10(tr_matrix[x][y].cost)); 00798 } 00799 } 00800 } 00801 for (x = -1; x < SHOW_TRANS; x++) { 00802 struct ast_str *out = ast_str_alloca(256); 00803 /* translation only applies to audio right now. */ 00804 if (x >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (x)))) 00805 continue; 00806 /*Go ahead and move to next iteration if dealing with an unknown codec*/ 00807 if(x >= 0 && !strcmp(ast_getformatname(1LL << (x)), "unknown")) 00808 continue; 00809 ast_str_set(&out, -1, " "); 00810 for (y = -1; y < SHOW_TRANS; y++) { 00811 /* translation only applies to audio right now. */ 00812 if (y >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (y)))) 00813 continue; 00814 /*Go ahead and move to next iteration if dealing with an unknown codec*/ 00815 if (y >= 0 && !strcmp(ast_getformatname(1LL << (y)), "unknown")) 00816 continue; 00817 if (y >= 0) 00818 curlen = strlen(ast_getformatname(1LL << (y))); 00819 if (y >= 0 && magnitude[y] + 1 > curlen) { 00820 curlen = magnitude[y] + 1; 00821 } 00822 if (curlen < 5) 00823 curlen = 5; 00824 if (x >= 0 && y >= 0 && tr_matrix[x][y].step) { 00825 /* Actual codec output */ 00826 ast_str_append(&out, -1, "%*u", curlen + 1, tr_matrix[x][y].cost); 00827 } else if (x == -1 && y >= 0) { 00828 /* Top row - use a dynamic size */ 00829 ast_str_append(&out, -1, "%*s", curlen + 1, ast_getformatname(1LL << (y)) ); 00830 } else if (y == -1 && x >= 0) { 00831 /* Left column - use a static size. */ 00832 ast_str_append(&out, -1, "%*s", longest, ast_getformatname(1LL << (x)) ); 00833 } else if (x >= 0 && y >= 0) { 00834 /* Codec not supported */ 00835 ast_str_append(&out, -1, "%*s", curlen + 1, "-"); 00836 } else { 00837 /* Upper left hand corner */ 00838 ast_str_append(&out, -1, "%*s", longest, ""); 00839 } 00840 } 00841 ast_str_append(&out, -1, "\n"); 00842 ast_cli(a->fd, "%s", ast_str_buffer(out)); 00843 } 00844 AST_RWLIST_UNLOCK(&translators); 00845 return CLI_SUCCESS; 00846 }
static void* newpvt | ( | struct ast_translator * | t | ) | [static] |
Allocate the descriptor, required outbuf space, and possibly desc.
Definition at line 150 of file translate.c.
References ast_calloc, ast_free, AST_FRIENDLY_OFFSET, ast_module_ref(), ast_translator::buf_size, ast_trans_pvt::c, ast_translator::desc_size, len(), ast_translator::module, ast_translator::newpvt, ast_trans_pvt::outbuf, ast_trans_pvt::pvt, and ast_trans_pvt::t.
Referenced by ast_translator_build_path(), and calc_cost().
00151 { 00152 struct ast_trans_pvt *pvt; 00153 int len; 00154 char *ofs; 00155 00156 /* 00157 * compute the required size adding private descriptor, 00158 * buffer, AST_FRIENDLY_OFFSET. 00159 */ 00160 len = sizeof(*pvt) + t->desc_size; 00161 if (t->buf_size) 00162 len += AST_FRIENDLY_OFFSET + t->buf_size; 00163 pvt = ast_calloc(1, len); 00164 if (!pvt) 00165 return NULL; 00166 pvt->t = t; 00167 ofs = (char *)(pvt + 1); /* pointer to data space */ 00168 if (t->desc_size) { /* first comes the descriptor */ 00169 pvt->pvt = ofs; 00170 ofs += t->desc_size; 00171 } 00172 if (t->buf_size) /* finally buffer and header */ 00173 pvt->outbuf.c = ofs + AST_FRIENDLY_OFFSET; 00174 /* call local init routine, if present */ 00175 if (t->newpvt && t->newpvt(pvt)) { 00176 ast_free(pvt); 00177 return NULL; 00178 } 00179 ast_module_ref(t->module); 00180 return pvt; 00181 }
static force_inline int powerof | ( | format_t | d | ) | [static] |
returns the index of the lowest bit set
Definition at line 130 of file translate.c.
References ast_log(), and LOG_WARNING.
Referenced by __ast_register_translator(), ast_translate_available_formats(), ast_translate_path_steps(), ast_translator_build_path(), and handle_cli_core_show_translation().
00131 { 00132 int x = ffsll(d); 00133 00134 if (x) 00135 return x - 1; 00136 00137 ast_log(LOG_WARNING, "No bits set? %llu\n", (unsigned long long) d); 00138 00139 return -1; 00140 }
static void rebuild_matrix | ( | int | samples | ) | [static] |
rebuild a translation matrix.
Definition at line 515 of file translate.c.
References ast_translator::active, ast_debug, ast_getformatname(), AST_RWLIST_TRAVERSE, calc_cost(), translator_path::cost, ast_translator::cost, ast_translator::dstfmt, get_rate_change_result(), ast_translator::list, MAX_FORMAT, translator_path::multistep, translator_path::rate_change, ast_translator::srcfmt, translator_path::step, and tr_matrix.
Referenced by __ast_register_translator(), ast_translator_activate(), ast_translator_deactivate(), ast_unregister_translator(), and handle_cli_core_show_translation().
00516 { 00517 struct ast_translator *t; 00518 int new_rate_change; 00519 int newcost; 00520 int x; /* source format index */ 00521 int y; /* intermediate format index */ 00522 int z; /* destination format index */ 00523 00524 ast_debug(1, "Resetting translation matrix\n"); 00525 00526 memset(tr_matrix, '\0', sizeof(tr_matrix)); 00527 00528 /* first, compute all direct costs */ 00529 AST_RWLIST_TRAVERSE(&translators, t, list) { 00530 if (!t->active) 00531 continue; 00532 00533 x = t->srcfmt; 00534 z = t->dstfmt; 00535 00536 if (samples) 00537 calc_cost(t, samples); 00538 00539 new_rate_change = get_rate_change_result(1LL << t->srcfmt, 1LL << t->dstfmt); 00540 00541 /* this translator is the best choice if any of the below are true. 00542 * 1. no translation path is set between x and z yet. 00543 * 2. the new translation costs less and sample rate is no worse than old one. 00544 * 3. the new translation has a better sample rate conversion than the old one. 00545 */ 00546 if (!tr_matrix[x][z].step || 00547 ((t->cost < tr_matrix[x][z].cost) && (new_rate_change <= tr_matrix[x][z].rate_change)) || 00548 (new_rate_change < tr_matrix[x][z].rate_change)) { 00549 00550 tr_matrix[x][z].step = t; 00551 tr_matrix[x][z].cost = t->cost; 00552 tr_matrix[x][z].rate_change = new_rate_change; 00553 } 00554 } 00555 00556 /* 00557 * For each triple x, y, z of distinct formats, check if there is 00558 * a path from x to z through y which is cheaper than what is 00559 * currently known, and in case, update the matrix. 00560 * Repeat until the matrix is stable. 00561 */ 00562 for (;;) { 00563 int changed = 0; 00564 int better_choice = 0; 00565 for (x = 0; x < MAX_FORMAT; x++) { /* source format */ 00566 for (y = 0; y < MAX_FORMAT; y++) { /* intermediate format */ 00567 if (x == y) /* skip ourselves */ 00568 continue; 00569 for (z = 0; z < MAX_FORMAT; z++) { /* dst format */ 00570 if (z == x || z == y) /* skip null conversions */ 00571 continue; 00572 if (!tr_matrix[x][y].step) /* no path from x to y */ 00573 continue; 00574 if (!tr_matrix[y][z].step) /* no path from y to z */ 00575 continue; 00576 00577 /* Does x->y->z result in a less optimal sample rate change? 00578 * Never downgrade the sample rate conversion quality regardless 00579 * of any cost improvements */ 00580 if (tr_matrix[x][z].step && 00581 ((tr_matrix[x][z].rate_change < tr_matrix[x][y].rate_change) || 00582 (tr_matrix[x][z].rate_change < tr_matrix[y][z].rate_change))) { 00583 continue; 00584 } 00585 00586 /* is x->y->z a better sample rate confersion that the current x->z? */ 00587 new_rate_change = tr_matrix[x][y].rate_change + tr_matrix[y][z].rate_change; 00588 00589 /* calculate cost from x->y->z */ 00590 newcost = tr_matrix[x][y].cost + tr_matrix[y][z].cost; 00591 00592 /* Is x->y->z a better choice than x->z? 00593 * There are three conditions for x->y->z to be a better choice than x->z 00594 * 1. if there is no step directly between x->z then x->y->z is the best and only current option. 00595 * 2. if x->y->z results in a more optimal sample rate conversion. */ 00596 if (!tr_matrix[x][z].step) { 00597 better_choice = 1; 00598 } else if (new_rate_change < tr_matrix[x][z].rate_change) { 00599 better_choice = 1; 00600 } else { 00601 better_choice = 0; 00602 } 00603 00604 if (!better_choice) { 00605 continue; 00606 } 00607 /* ok, we can get from x to z via y with a cost that 00608 is the sum of the transition from x to y and from y to z */ 00609 tr_matrix[x][z].step = tr_matrix[x][y].step; 00610 tr_matrix[x][z].cost = newcost; 00611 tr_matrix[x][z].multistep = 1; 00612 00613 /* now calculate what kind of sample rate change is required for this multi-step path 00614 * 00615 * if both paths require a change in rate, and they are not in the same direction 00616 * then this is a up sample down sample conversion scenario. */ 00617 tr_matrix[x][z].rate_change = tr_matrix[x][y].rate_change + tr_matrix[y][z].rate_change; 00618 00619 ast_debug(10, "Discovered %u cost path from %s to %s, via %s\n", tr_matrix[x][z].cost, 00620 ast_getformatname(1LL << x), ast_getformatname(1LL << z), ast_getformatname(1LL << y)); 00621 changed++; 00622 } 00623 } 00624 } 00625 if (!changed) 00626 break; 00627 } 00628 }
struct ast_cli_entry cli_translate[] [static] |
{ AST_CLI_DEFINE(handle_cli_core_show_translation, "Display translation matrix") }
Definition at line 848 of file translate.c.
struct translator_path tr_matrix[MAX_FORMAT][MAX_FORMAT] [static] |
a matrix that, for any pair of supported formats, indicates the total cost of translation and the first step. The full path can be reconstricted iterating on the matrix until step->dstfmt == desired_format.
Array indexes are 'src' and 'dest', in that order.
Note: the lock in the 'translators' list is also used to protect this structure.
Definition at line 121 of file translate.c.
Referenced by ast_translate_available_formats(), ast_translate_path_steps(), ast_translator_best_choice(), ast_translator_build_path(), handle_cli_core_show_translation(), and rebuild_matrix().