#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 16 |
Functions | |
int | __ast_register_translator (struct ast_translator *t, struct ast_module *mod) |
Register a translator This registers a codec translator with asterisk. | |
ast_frame * | ast_trans_frameout (struct ast_trans_pvt *pvt, int datalen, int samples) |
generic frameout function | |
ast_frame * | ast_translate (struct ast_trans_pvt *path, 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 *dst, int *srcs) |
Chooses the best translation path. | |
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 *p) |
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. | |
static void | calc_cost (struct ast_translator *t, int seconds) |
compute the cost of a single translation step | |
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 plc and bound checks. | |
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 also plc and desc. | |
static force_inline int | powerof (unsigned int 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. |
Definition in file translate.c.
#define MAX_RECALC 1000 |
#define SHOW_TRANS 16 |
Referenced by handle_cli_core_show_translation().
int __ast_register_translator | ( | struct ast_translator * | t, | |
struct ast_module * | module | |||
) |
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 621 of file translate.c.
References ast_translator::active, ast_cli_register_multiple(), AST_FORMAT_SLINEAR, 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, ast_translator::buffer_samples, calc_cost(), cli_translate, 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, ast_translator::plc_samples, powerof(), rebuild_matrix(), ast_translator::srcfmt, and term_color().
00622 { 00623 static int added_cli = 0; 00624 struct ast_translator *u; 00625 char tmp[80]; 00626 00627 if (!mod) { 00628 ast_log(LOG_WARNING, "Missing module pointer, you need to supply one\n"); 00629 return -1; 00630 } 00631 00632 if (!t->buf_size) { 00633 ast_log(LOG_WARNING, "empty buf size, you need to supply one\n"); 00634 return -1; 00635 } 00636 00637 t->module = mod; 00638 00639 t->srcfmt = powerof(t->srcfmt); 00640 t->dstfmt = powerof(t->dstfmt); 00641 t->active = 1; 00642 00643 if (t->srcfmt == -1 || t->dstfmt == -1) { 00644 ast_log(LOG_WARNING, "Invalid translator path: (%s codec is not valid)\n", t->srcfmt == -1 ? "starting" : "ending"); 00645 return -1; 00646 } 00647 if (t->plc_samples) { 00648 if (t->buffer_samples < t->plc_samples) { 00649 ast_log(LOG_WARNING, "plc_samples %d buffer_samples %d\n", 00650 t->plc_samples, t->buffer_samples); 00651 return -1; 00652 } 00653 if (t->dstfmt != powerof(AST_FORMAT_SLINEAR)) 00654 ast_log(LOG_WARNING, "plc_samples %d format %x\n", 00655 t->plc_samples, t->dstfmt); 00656 } 00657 if (t->srcfmt >= MAX_FORMAT) { 00658 ast_log(LOG_WARNING, "Source format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt)); 00659 return -1; 00660 } 00661 00662 if (t->dstfmt >= MAX_FORMAT) { 00663 ast_log(LOG_WARNING, "Destination format %s is larger than MAX_FORMAT\n", ast_getformatname(t->dstfmt)); 00664 return -1; 00665 } 00666 00667 if (t->buf_size) { 00668 /* 00669 * Align buf_size properly, rounding up to the machine-specific 00670 * alignment for pointers. 00671 */ 00672 struct _test_align { void *a, *b; } p; 00673 int align = (char *)&p.b - (char *)&p.a; 00674 00675 t->buf_size = ((t->buf_size + align - 1) / align) * align; 00676 } 00677 00678 if (t->frameout == NULL) 00679 t->frameout = default_frameout; 00680 00681 calc_cost(t, 1); 00682 00683 ast_verb(2, "Registered translator '%s' from format %s to %s, cost %d\n", 00684 term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), 00685 ast_getformatname(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt), t->cost); 00686 00687 if (!added_cli) { 00688 ast_cli_register_multiple(cli_translate, sizeof(cli_translate) / sizeof(struct ast_cli_entry)); 00689 added_cli++; 00690 } 00691 00692 AST_RWLIST_WRLOCK(&translators); 00693 00694 /* find any existing translators that provide this same srcfmt/dstfmt, 00695 and put this one in order based on cost */ 00696 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) { 00697 if ((u->srcfmt == t->srcfmt) && 00698 (u->dstfmt == t->dstfmt) && 00699 (u->cost > t->cost)) { 00700 AST_RWLIST_INSERT_BEFORE_CURRENT(t, list); 00701 t = NULL; 00702 } 00703 } 00704 AST_RWLIST_TRAVERSE_SAFE_END; 00705 00706 /* if no existing translator was found for this format combination, 00707 add it to the beginning of the list */ 00708 if (t) 00709 AST_RWLIST_INSERT_HEAD(&translators, t, list); 00710 00711 rebuild_matrix(0); 00712 00713 AST_RWLIST_UNLOCK(&translators); 00714 00715 return 0; 00716 }
struct ast_frame* ast_trans_frameout | ( | struct ast_trans_pvt * | pvt, | |
int | datalen, | |||
int | samples | |||
) |
generic frameout function
Definition at line 214 of file translate.c.
References AST_FRAME_VOICE, AST_FRFLAG_FROM_TRANSLATOR, AST_FRIENDLY_OFFSET, ast_set_flag, ast_trans_pvt::c, ast_trans_pvt::datalen, ast_translator::dstfmt, f, ast_trans_pvt::f, ast_translator::name, ast_trans_pvt::outbuf, ast_trans_pvt::samples, and ast_trans_pvt::t.
Referenced by default_frameout(), lintoadpcm_frameout(), lintogsm_frameout(), lintoilbc_frameout(), and lintolpc10_frameout().
00216 { 00217 struct ast_frame *f = &pvt->f; 00218 00219 if (samples) 00220 f->samples = samples; 00221 else { 00222 if (pvt->samples == 0) 00223 return NULL; 00224 f->samples = pvt->samples; 00225 pvt->samples = 0; 00226 } 00227 if (datalen) 00228 f->datalen = datalen; 00229 else { 00230 f->datalen = pvt->datalen; 00231 pvt->datalen = 0; 00232 } 00233 00234 f->frametype = AST_FRAME_VOICE; 00235 f->subclass = 1 << (pvt->t->dstfmt); 00236 f->mallocd = 0; 00237 f->offset = AST_FRIENDLY_OFFSET; 00238 f->src = pvt->t->name; 00239 f->data.ptr = pvt->outbuf.c; 00240 00241 ast_set_flag(f, AST_FRFLAG_FROM_TRANSLATOR); 00242 00243 return f; 00244 }
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
tr | translator structure to use for translation | |
f | frame to translate | |
consume | Whether or not to free the original frame |
Definition at line 308 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, len(), ast_frame::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(), conf_run(), and process_ast_dsp().
00309 { 00310 struct ast_trans_pvt *p = path; 00311 struct ast_frame *out = f; 00312 struct timeval delivery; 00313 int has_timing_info; 00314 long ts; 00315 long len; 00316 int seqno; 00317 00318 has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO); 00319 ts = f->ts; 00320 len = f->len; 00321 seqno = f->seqno; 00322 00323 /* XXX hmmm... check this below */ 00324 if (!ast_tvzero(f->delivery)) { 00325 if (!ast_tvzero(path->nextin)) { 00326 /* Make sure this is in line with what we were expecting */ 00327 if (!ast_tveq(path->nextin, f->delivery)) { 00328 /* The time has changed between what we expected and this 00329 most recent time on the new packet. If we have a 00330 valid prediction adjust our output time appropriately */ 00331 if (!ast_tvzero(path->nextout)) { 00332 path->nextout = ast_tvadd(path->nextout, 00333 ast_tvsub(f->delivery, path->nextin)); 00334 } 00335 path->nextin = f->delivery; 00336 } 00337 } else { 00338 /* This is our first pass. Make sure the timing looks good */ 00339 path->nextin = f->delivery; 00340 path->nextout = f->delivery; 00341 } 00342 /* Predict next incoming sample */ 00343 path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(f->subclass))); 00344 } 00345 delivery = f->delivery; 00346 for ( ; out && p ; p = p->next) { 00347 framein(p, out); 00348 if (out != f) 00349 ast_frfree(out); 00350 out = p->t->frameout(p); 00351 } 00352 if (consume) 00353 ast_frfree(f); 00354 if (out == NULL) 00355 return NULL; 00356 /* we have a frame, play with times */ 00357 if (!ast_tvzero(delivery)) { 00358 /* Regenerate prediction after a discontinuity */ 00359 if (ast_tvzero(path->nextout)) 00360 path->nextout = ast_tvnow(); 00361 00362 /* Use next predicted outgoing timestamp */ 00363 out->delivery = path->nextout; 00364 00365 /* Predict next outgoing timestamp from samples in this 00366 frame. */ 00367 path->nextout = ast_tvadd(path->nextout, ast_samp2tv(out->samples, ast_format_rate(out->subclass))); 00368 } else { 00369 out->delivery = ast_tv(0, 0); 00370 ast_set2_flag(out, has_timing_info, AST_FRFLAG_HAS_TIMING_INFO); 00371 if (has_timing_info) { 00372 out->ts = ts; 00373 out->len = len; 00374 out->seqno = seqno; 00375 } 00376 } 00377 /* Invalidate prediction if we're entering a silence period */ 00378 if (out->frametype == AST_FRAME_CNG) 00379 path->nextout = ast_tv(0, 0); 00380 return out; 00381 }
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 |
Definition at line 830 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 sip_call().
00831 { 00832 unsigned int res = dest; 00833 unsigned int x; 00834 unsigned int src_audio = src & AST_FORMAT_AUDIO_MASK; 00835 unsigned int src_video = src & AST_FORMAT_VIDEO_MASK; 00836 00837 /* if we don't have a source format, we just have to try all 00838 possible destination formats */ 00839 if (!src) 00840 return dest; 00841 00842 /* If we have a source audio format, get its format index */ 00843 if (src_audio) 00844 src_audio = powerof(src_audio); 00845 00846 /* If we have a source video format, get its format index */ 00847 if (src_video) 00848 src_video = powerof(src_video); 00849 00850 AST_RWLIST_RDLOCK(&translators); 00851 00852 /* For a given source audio format, traverse the list of 00853 known audio formats to determine whether there exists 00854 a translation path from the source format to the 00855 destination format. */ 00856 for (x = 1; src_audio && (x & AST_FORMAT_AUDIO_MASK); x <<= 1) { 00857 /* if this is not a desired format, nothing to do */ 00858 if (!dest & x) 00859 continue; 00860 00861 /* if the source is supplying this format, then 00862 we can leave it in the result */ 00863 if (src & x) 00864 continue; 00865 00866 /* if we don't have a translation path from the src 00867 to this format, remove it from the result */ 00868 if (!tr_matrix[src_audio][powerof(x)].step) { 00869 res &= ~x; 00870 continue; 00871 } 00872 00873 /* now check the opposite direction */ 00874 if (!tr_matrix[powerof(x)][src_audio].step) 00875 res &= ~x; 00876 } 00877 00878 /* For a given source video format, traverse the list of 00879 known video formats to determine whether there exists 00880 a translation path from the source format to the 00881 destination format. */ 00882 for (; src_video && (x & AST_FORMAT_VIDEO_MASK); x <<= 1) { 00883 /* if this is not a desired format, nothing to do */ 00884 if (!dest & x) 00885 continue; 00886 00887 /* if the source is supplying this format, then 00888 we can leave it in the result */ 00889 if (src & x) 00890 continue; 00891 00892 /* if we don't have a translation path from the src 00893 to this format, remove it from the result */ 00894 if (!tr_matrix[src_video][powerof(x)].step) { 00895 res &= ~x; 00896 continue; 00897 } 00898 00899 /* now check the opposite direction */ 00900 if (!tr_matrix[powerof(x)][src_video].step) 00901 res &= ~x; 00902 } 00903 00904 AST_RWLIST_UNLOCK(&translators); 00905 00906 return res; 00907 }
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 909 of file translate.c.
References ast_clear_flag, AST_FRFLAG_FROM_TRANSLATOR, destroy(), f, and ast_trans_pvt::pvt.
Referenced by ast_frame_free().
00910 { 00911 struct ast_trans_pvt *pvt; 00912 00913 ast_clear_flag(fr, AST_FRFLAG_FROM_TRANSLATOR); 00914 00915 pvt = (struct ast_trans_pvt *) (((char *) fr) - offsetof(struct ast_trans_pvt, f)); 00916 00917 if (!pvt->destroy) 00918 return; 00919 00920 destroy(pvt); 00921 }
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 808 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().
00809 { 00810 unsigned int res = -1; 00811 00812 /* convert bitwise format numbers into array indices */ 00813 src = powerof(src); 00814 dest = powerof(dest); 00815 00816 if (src == -1 || dest == -1) { 00817 ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src == -1 ? "starting" : "ending"); 00818 return -1; 00819 } 00820 AST_RWLIST_RDLOCK(&translators); 00821 00822 if (tr_matrix[src][dest].step) 00823 res = tr_matrix[src][dest].multistep + 1; 00824 00825 AST_RWLIST_UNLOCK(&translators); 00826 00827 return res; 00828 }
void ast_translator_activate | ( | struct ast_translator * | t | ) |
Activate a previously deactivated translator.
t | translator to activate |
Definition at line 744 of file translate.c.
References ast_translator::active, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and rebuild_matrix().
00745 { 00746 AST_RWLIST_WRLOCK(&translators); 00747 t->active = 1; 00748 rebuild_matrix(0); 00749 AST_RWLIST_UNLOCK(&translators); 00750 }
int ast_translator_best_choice | ( | int * | dsts, | |
int * | srcs | |||
) |
Chooses the best translation path.
Given a list of sources, and a designed destination format, which should I choose?
Definition at line 761 of file translate.c.
References AST_FORMAT_AUDIO_MASK, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_translator::cost, translator_path::cost, MAX_AUDIO_FORMAT, translator_path::multistep, and tr_matrix.
Referenced by ast_channel_make_compatible_helper(), ast_request(), iax2_request(), and set_format().
00762 { 00763 int x,y; 00764 int best = -1; 00765 int bestdst = 0; 00766 int cur, cursrc; 00767 int besttime = INT_MAX; 00768 int beststeps = INT_MAX; 00769 int common = ((*dst) & (*srcs)) & AST_FORMAT_AUDIO_MASK; /* are there common formats ? */ 00770 00771 if (common) { /* yes, pick one and return */ 00772 for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) { 00773 if (cur & common) /* guaranteed to find one */ 00774 break; 00775 } 00776 /* We are done, this is a common format to both. */ 00777 *srcs = *dst = cur; 00778 return 0; 00779 } else { /* No, we will need to translate */ 00780 AST_RWLIST_RDLOCK(&translators); 00781 for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) { 00782 if (! (cur & *dst)) 00783 continue; 00784 for (cursrc = 1, x = 0; x <= MAX_AUDIO_FORMAT; cursrc <<= 1, x++) { 00785 if (!(*srcs & cursrc) || !tr_matrix[x][y].step || 00786 tr_matrix[x][y].cost > besttime) 00787 continue; /* not existing or no better */ 00788 if (tr_matrix[x][y].cost < besttime || 00789 tr_matrix[x][y].multistep < beststeps) { 00790 /* better than what we have so far */ 00791 best = cursrc; 00792 bestdst = cur; 00793 besttime = tr_matrix[x][y].cost; 00794 beststeps = tr_matrix[x][y].multistep; 00795 } 00796 } 00797 } 00798 AST_RWLIST_UNLOCK(&translators); 00799 if (best > -1) { 00800 *srcs = best; 00801 *dst = bestdst; 00802 best = 0; 00803 } 00804 return best; 00805 } 00806 }
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.
dest | destination format | |
source | source format |
Definition at line 263 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(), misdn_set_opt_exec(), read_config(), and set_format().
00264 { 00265 struct ast_trans_pvt *head = NULL, *tail = NULL; 00266 00267 source = powerof(source); 00268 dest = powerof(dest); 00269 00270 if (source == -1 || dest == -1) { 00271 ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", source == -1 ? "starting" : "ending"); 00272 return NULL; 00273 } 00274 00275 AST_RWLIST_RDLOCK(&translators); 00276 00277 while (source != dest) { 00278 struct ast_trans_pvt *cur; 00279 struct ast_translator *t = tr_matrix[source][dest].step; 00280 if (!t) { 00281 ast_log(LOG_WARNING, "No translator path from %s to %s\n", 00282 ast_getformatname(source), ast_getformatname(dest)); 00283 AST_RWLIST_UNLOCK(&translators); 00284 return NULL; 00285 } 00286 if (!(cur = newpvt(t))) { 00287 ast_log(LOG_WARNING, "Failed to build translator step from %d to %d\n", source, dest); 00288 if (head) 00289 ast_translator_free_path(head); 00290 AST_RWLIST_UNLOCK(&translators); 00291 return NULL; 00292 } 00293 if (!head) 00294 head = cur; 00295 else 00296 tail->next = cur; 00297 tail = cur; 00298 cur->nextin = cur->nextout = ast_tv(0, 0); 00299 /* Keep going if this isn't the final destination */ 00300 source = cur->t->dstfmt; 00301 } 00302 00303 AST_RWLIST_UNLOCK(&translators); 00304 return head; 00305 }
void ast_translator_deactivate | ( | struct ast_translator * | t | ) |
Deactivate a translator.
t | translator to deactivate |
Definition at line 752 of file translate.c.
References ast_translator::active, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and rebuild_matrix().
00753 { 00754 AST_RWLIST_WRLOCK(&translators); 00755 t->active = 0; 00756 rebuild_matrix(0); 00757 AST_RWLIST_UNLOCK(&translators); 00758 }
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 253 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(), cl_dequeue_chan(), conf_free(), filestream_destructor(), free_translation(), and set_format().
00254 { 00255 struct ast_trans_pvt *pn = p; 00256 while ( (p = pn) ) { 00257 pn = p->next; 00258 destroy(p); 00259 } 00260 }
int ast_unregister_translator | ( | struct ast_translator * | t | ) |
Unregister a translator Unregisters the given tranlator.
t | translator to unregister |
Definition at line 719 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().
00720 { 00721 char tmp[80]; 00722 struct ast_translator *u; 00723 int found = 0; 00724 00725 AST_RWLIST_WRLOCK(&translators); 00726 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) { 00727 if (u == t) { 00728 AST_RWLIST_REMOVE_CURRENT(list); 00729 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)); 00730 found = 1; 00731 break; 00732 } 00733 } 00734 AST_RWLIST_TRAVERSE_SAFE_END; 00735 00736 if (found) 00737 rebuild_matrix(0); 00738 00739 AST_RWLIST_UNLOCK(&translators); 00740 00741 return (u ? 0 : -1); 00742 }
static void calc_cost | ( | struct ast_translator * | t, | |
int | seconds | |||
) | [static] |
compute the cost of a single translation step
Definition at line 384 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, and ast_translator::sample.
Referenced by __ast_register_translator(), and rebuild_matrix().
00385 { 00386 int num_samples = 0; 00387 struct ast_trans_pvt *pvt; 00388 struct rusage start; 00389 struct rusage end; 00390 int cost; 00391 int out_rate = ast_format_rate(t->dstfmt); 00392 00393 if (!seconds) 00394 seconds = 1; 00395 00396 /* If they don't make samples, give them a terrible score */ 00397 if (!t->sample) { 00398 ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name); 00399 t->cost = 999999; 00400 return; 00401 } 00402 00403 pvt = newpvt(t); 00404 if (!pvt) { 00405 ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name); 00406 t->cost = 999999; 00407 return; 00408 } 00409 00410 getrusage(RUSAGE_SELF, &start); 00411 00412 /* Call the encoder until we've processed the required number of samples */ 00413 while (num_samples < seconds * out_rate) { 00414 struct ast_frame *f = t->sample(); 00415 if (!f) { 00416 ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name); 00417 destroy(pvt); 00418 t->cost = 999999; 00419 return; 00420 } 00421 framein(pvt, f); 00422 ast_frfree(f); 00423 while ((f = t->frameout(pvt))) { 00424 num_samples += f->samples; 00425 ast_frfree(f); 00426 } 00427 } 00428 00429 getrusage(RUSAGE_SELF, &end); 00430 00431 cost = ((end.ru_utime.tv_sec - start.ru_utime.tv_sec) * 1000000) + end.ru_utime.tv_usec - start.ru_utime.tv_usec; 00432 cost += ((end.ru_stime.tv_sec - start.ru_stime.tv_sec) * 1000000) + end.ru_stime.tv_usec - start.ru_stime.tv_usec; 00433 00434 destroy(pvt); 00435 00436 t->cost = cost / seconds; 00437 00438 if (!t->cost) 00439 t->cost = 1; 00440 }
static struct ast_frame* default_frameout | ( | struct ast_trans_pvt * | pvt | ) | [static] |
Definition at line 246 of file translate.c.
References ast_trans_frameout().
Referenced by __ast_register_translator().
00247 { 00248 return ast_trans_frameout(pvt, 0, 0); 00249 }
static void destroy | ( | struct ast_trans_pvt * | pvt | ) | [static] |
Definition at line 133 of file translate.c.
References ast_free, AST_FRFLAG_FROM_TRANSLATOR, ast_module_unref(), ast_test_flag, ast_translator::destroy, ast_trans_pvt::destroy, ast_trans_pvt::f, ast_translator::module, and ast_trans_pvt::t.
Referenced by ast_translate_frame_freed(), ast_translator_free_path(), and calc_cost().
00134 { 00135 struct ast_translator *t = pvt->t; 00136 00137 if (ast_test_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR)) { 00138 /* If this flag is still set, that means that the translation path has 00139 * been torn down, while we still have a frame out there being used. 00140 * When ast_frfree() gets called on that frame, this ast_trans_pvt 00141 * will get destroyed, too. */ 00142 00143 pvt->destroy = 1; 00144 00145 return; 00146 } 00147 00148 if (t->destroy) 00149 t->destroy(pvt); 00150 ast_free(pvt); 00151 ast_module_unref(t->module); 00152 }
static int framein | ( | struct ast_trans_pvt * | pvt, | |
struct ast_frame * | f | |||
) | [static] |
framein wrapper, deals with plc and bound checks.
Definition at line 155 of file translate.c.
References ast_copy_flags, AST_FRFLAG_HAS_TIMING_INFO, ast_log(), ast_translator::buffer_samples, ast_trans_pvt::datalen, f, ast_trans_pvt::f, ast_translator::framein, ast_trans_pvt::i16, ast_frame::len, LOG_WARNING, ast_translator::name, ast_translator::native_plc, ast_trans_pvt::outbuf, ast_trans_pvt::plc, plc_fillin(), plc_rx(), ast_translator::plc_samples, ast_trans_pvt::samples, ast_frame::seqno, ast_trans_pvt::t, and ast_frame::ts.
Referenced by ast_translate(), and calc_cost().
00156 { 00157 int16_t *dst = pvt->outbuf.i16; 00158 int ret; 00159 int samples = pvt->samples; /* initial value */ 00160 00161 /* Copy the last in jb timing info to the pvt */ 00162 ast_copy_flags(&pvt->f, f, AST_FRFLAG_HAS_TIMING_INFO); 00163 pvt->f.ts = f->ts; 00164 pvt->f.len = f->len; 00165 pvt->f.seqno = f->seqno; 00166 00167 if (f->samples == 0) { 00168 ast_log(LOG_WARNING, "no samples for %s\n", pvt->t->name); 00169 } 00170 if (pvt->t->buffer_samples) { /* do not pass empty frames to callback */ 00171 if (f->datalen == 0) { /* perform PLC with nominal framesize of 20ms/160 samples */ 00172 if (pvt->plc) { 00173 int l = pvt->t->plc_samples; 00174 if (pvt->samples + l > pvt->t->buffer_samples) { 00175 ast_log(LOG_WARNING, "Out of buffer space\n"); 00176 return -1; 00177 } 00178 l = plc_fillin(pvt->plc, dst + pvt->samples, l); 00179 pvt->samples += l; 00180 pvt->datalen = pvt->samples * 2; /* SLIN has 2bytes for 1sample */ 00181 } 00182 /* We don't want generic PLC. If the codec has native PLC, then do that */ 00183 if (!pvt->t->native_plc) 00184 return 0; 00185 } 00186 if (pvt->samples + f->samples > pvt->t->buffer_samples) { 00187 ast_log(LOG_WARNING, "Out of buffer space\n"); 00188 return -1; 00189 } 00190 } 00191 /* we require a framein routine, wouldn't know how to do 00192 * it otherwise. 00193 */ 00194 ret = pvt->t->framein(pvt, f); 00195 /* possibly store data for plc */ 00196 if (!ret && pvt->plc) { 00197 int l = pvt->t->plc_samples; 00198 if (pvt->samples < l) 00199 l = pvt->samples; 00200 plc_rx(pvt->plc, dst + pvt->samples - l, l); 00201 } 00202 /* diagnostic ... */ 00203 if (pvt->samples == samples) 00204 ast_log(LOG_WARNING, "%s did not update samples %d\n", 00205 pvt->t->name, pvt->samples); 00206 return ret; 00207 }
static char* handle_cli_core_show_translation | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 518 of file translate.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_getformatname(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_str_alloca, ast_str_append(), ast_str_buffer, ast_str_set(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_translator::cost, ast_cli_args::fd, MAX_RECALC, rebuild_matrix(), SHOW_TRANS, tr_matrix, and ast_cli_entry::usage.
00519 { 00520 #define SHOW_TRANS 16 00521 int x, y, z; 00522 int curlen = 0, longest = 0, magnitude[SHOW_TRANS] = { 0, }; 00523 00524 switch (cmd) { 00525 case CLI_INIT: 00526 e->command = "core show translation [recalc]"; 00527 e->usage = 00528 "Usage: core show translation [recalc [<recalc seconds>]]\n" 00529 " Displays known codec translators and the cost associated\n" 00530 " with each conversion. If the argument 'recalc' is supplied along\n" 00531 " with optional number of seconds to test a new test will be performed\n" 00532 " as the chart is being displayed.\n"; 00533 return NULL; 00534 case CLI_GENERATE: 00535 return NULL; 00536 } 00537 00538 if (a->argc > 5) 00539 return CLI_SHOWUSAGE; 00540 00541 if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) { 00542 z = a->argv[4] ? atoi(a->argv[4]) : 1; 00543 00544 if (z <= 0) { 00545 ast_cli(a->fd, " Recalc must be greater than 0. Defaulting to 1.\n"); 00546 z = 1; 00547 } 00548 00549 if (z > MAX_RECALC) { 00550 ast_cli(a->fd, " Maximum limit of recalc exceeded by %d, truncating value to %d\n", z - MAX_RECALC, MAX_RECALC); 00551 z = MAX_RECALC; 00552 } 00553 ast_cli(a->fd, " Recalculating Codec Translation (number of sample seconds: %d)\n\n", z); 00554 AST_RWLIST_WRLOCK(&translators); 00555 rebuild_matrix(z); 00556 AST_RWLIST_UNLOCK(&translators); 00557 } else if (a->argc > 3) 00558 return CLI_SHOWUSAGE; 00559 00560 AST_RWLIST_RDLOCK(&translators); 00561 00562 ast_cli(a->fd, " Translation times between formats (in microseconds) for one second of data\n"); 00563 ast_cli(a->fd, " Source Format (Rows) Destination Format (Columns)\n\n"); 00564 /* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */ 00565 for (x = 0; x < SHOW_TRANS; x++) { 00566 curlen = strlen(ast_getformatname(1 << (x))); 00567 if (curlen > longest) 00568 longest = curlen; 00569 for (y = 0; y < SHOW_TRANS; y++) { 00570 if (tr_matrix[x][y].cost > pow(10, magnitude[x])) { 00571 magnitude[y] = floor(log10(tr_matrix[x][y].cost)); 00572 } 00573 } 00574 } 00575 for (x = -1; x < SHOW_TRANS; x++) { 00576 struct ast_str *out = ast_str_alloca(125); 00577 /*Go ahead and move to next iteration if dealing with an unknown codec*/ 00578 if(x >= 0 && !strcmp(ast_getformatname(1 << (x)), "unknown")) 00579 continue; 00580 ast_str_set(&out, -1, " "); 00581 for (y = -1; y < SHOW_TRANS; y++) { 00582 /*Go ahead and move to next iteration if dealing with an unknown codec*/ 00583 if (y >= 0 && !strcmp(ast_getformatname(1 << (y)), "unknown")) 00584 continue; 00585 if (y >= 0) 00586 curlen = strlen(ast_getformatname(1 << (y))); 00587 if (y >= 0 && magnitude[y] + 1 > curlen) { 00588 curlen = magnitude[y] + 1; 00589 } 00590 if (curlen < 5) 00591 curlen = 5; 00592 if (x >= 0 && y >= 0 && tr_matrix[x][y].step) { 00593 /* Actual codec output */ 00594 ast_str_append(&out, -1, "%*d", curlen + 1, tr_matrix[x][y].cost); 00595 } else if (x == -1 && y >= 0) { 00596 /* Top row - use a dynamic size */ 00597 ast_str_append(&out, -1, "%*s", curlen + 1, ast_getformatname(1 << (y)) ); 00598 } else if (y == -1 && x >= 0) { 00599 /* Left column - use a static size. */ 00600 ast_str_append(&out, -1, "%*s", longest, ast_getformatname(1 << (x)) ); 00601 } else if (x >= 0 && y >= 0) { 00602 /* Codec not supported */ 00603 ast_str_append(&out, -1, "%*s", curlen + 1, "-"); 00604 } else { 00605 /* Upper left hand corner */ 00606 ast_str_append(&out, -1, "%*s", longest, ""); 00607 } 00608 } 00609 ast_str_append(&out, -1, "\n"); 00610 ast_cli(a->fd, "%s", ast_str_buffer(out)); 00611 } 00612 AST_RWLIST_UNLOCK(&translators); 00613 return CLI_SUCCESS; 00614 }
static void* newpvt | ( | struct ast_translator * | t | ) | [static] |
Allocate the descriptor, required outbuf space, and possibly also plc and desc.
Definition at line 93 of file translate.c.
References ast_calloc, ast_free, AST_FRIENDLY_OFFSET, ast_module_ref(), ast_translator::buf_size, ast_translator::desc_size, len(), ast_translator::module, ast_translator::newpvt, ast_translator::plc_samples, ast_trans_pvt::pvt, ast_trans_pvt::t, and ast_translator::useplc.
Referenced by ast_translator_build_path(), and calc_cost().
00094 { 00095 struct ast_trans_pvt *pvt; 00096 int len; 00097 int useplc = t->plc_samples > 0 && t->useplc; /* cache, because it can change on the fly */ 00098 char *ofs; 00099 00100 /* 00101 * compute the required size adding private descriptor, 00102 * plc, buffer, AST_FRIENDLY_OFFSET. 00103 */ 00104 len = sizeof(*pvt) + t->desc_size; 00105 if (useplc) 00106 len += sizeof(plc_state_t); 00107 if (t->buf_size) 00108 len += AST_FRIENDLY_OFFSET + t->buf_size; 00109 pvt = ast_calloc(1, len); 00110 if (!pvt) 00111 return NULL; 00112 pvt->t = t; 00113 ofs = (char *)(pvt + 1); /* pointer to data space */ 00114 if (t->desc_size) { /* first comes the descriptor */ 00115 pvt->pvt = ofs; 00116 ofs += t->desc_size; 00117 } 00118 if (useplc) { /* then plc state */ 00119 pvt->plc = (plc_state_t *)ofs; 00120 ofs += sizeof(plc_state_t); 00121 } 00122 if (t->buf_size) /* finally buffer and header */ 00123 pvt->outbuf.c = ofs + AST_FRIENDLY_OFFSET; 00124 /* call local init routine, if present */ 00125 if (t->newpvt && t->newpvt(pvt)) { 00126 ast_free(pvt); 00127 return NULL; 00128 } 00129 ast_module_ref(t->module); 00130 return pvt; 00131 }
static force_inline int powerof | ( | unsigned int | d | ) | [static] |
returns the index of the lowest bit set
Definition at line 73 of file translate.c.
References ast_log(), and LOG_WARNING.
Referenced by __ast_register_translator(), agents_show(), ast_translate_available_formats(), ast_translate_path_steps(), and ast_translator_build_path().
00074 { 00075 int x = ffs(d); 00076 00077 if (x) 00078 return x - 1; 00079 00080 ast_log(LOG_WARNING, "No bits set? %d\n", d); 00081 00082 return -1; 00083 }
static void rebuild_matrix | ( | int | samples | ) | [static] |
rebuild a translation matrix.
Definition at line 446 of file translate.c.
References ast_translator::active, ast_debug, ast_getformatname(), AST_RWLIST_TRAVERSE, calc_cost(), ast_translator::cost, ast_translator::dstfmt, ast_translator::list, MAX_FORMAT, ast_translator::srcfmt, and tr_matrix.
Referenced by __ast_register_translator(), ast_translator_activate(), ast_translator_deactivate(), ast_unregister_translator(), and handle_cli_core_show_translation().
00447 { 00448 struct ast_translator *t; 00449 int x; /* source format index */ 00450 int y; /* intermediate format index */ 00451 int z; /* destination format index */ 00452 00453 ast_debug(1, "Resetting translation matrix\n"); 00454 00455 memset(tr_matrix, '\0', sizeof(tr_matrix)); 00456 00457 /* first, compute all direct costs */ 00458 AST_RWLIST_TRAVERSE(&translators, t, list) { 00459 if (!t->active) 00460 continue; 00461 00462 x = t->srcfmt; 00463 z = t->dstfmt; 00464 00465 if (samples) 00466 calc_cost(t, samples); 00467 00468 if (!tr_matrix[x][z].step || t->cost < tr_matrix[x][z].cost) { 00469 tr_matrix[x][z].step = t; 00470 tr_matrix[x][z].cost = t->cost; 00471 } 00472 } 00473 00474 /* 00475 * For each triple x, y, z of distinct formats, check if there is 00476 * a path from x to z through y which is cheaper than what is 00477 * currently known, and in case, update the matrix. 00478 * Repeat until the matrix is stable. 00479 */ 00480 for (;;) { 00481 int changed = 0; 00482 for (x = 0; x < MAX_FORMAT; x++) { /* source format */ 00483 for (y = 0; y < MAX_FORMAT; y++) { /* intermediate format */ 00484 if (x == y) /* skip ourselves */ 00485 continue; 00486 00487 for (z = 0; z<MAX_FORMAT; z++) { /* dst format */ 00488 int newcost; 00489 00490 if (z == x || z == y) /* skip null conversions */ 00491 continue; 00492 if (!tr_matrix[x][y].step) /* no path from x to y */ 00493 continue; 00494 if (!tr_matrix[y][z].step) /* no path from y to z */ 00495 continue; 00496 newcost = tr_matrix[x][y].cost + tr_matrix[y][z].cost; 00497 if (tr_matrix[x][z].step && newcost >= tr_matrix[x][z].cost) 00498 continue; /* x->y->z is more expensive than 00499 * the existing path */ 00500 /* ok, we can get from x to z via y with a cost that 00501 is the sum of the transition from x to y and 00502 from y to z */ 00503 00504 tr_matrix[x][z].step = tr_matrix[x][y].step; 00505 tr_matrix[x][z].cost = newcost; 00506 tr_matrix[x][z].multistep = 1; 00507 ast_debug(3, "Discovered %d cost path from %s to %s, via %s\n", tr_matrix[x][z].cost, 00508 ast_getformatname(1 << x), ast_getformatname(1 << z), ast_getformatname(1 << y)); 00509 changed++; 00510 } 00511 } 00512 } 00513 if (!changed) 00514 break; 00515 } 00516 }
struct ast_cli_entry cli_translate[] [static] |
Initial value:
{ { .handler = handle_cli_core_show_translation , .summary = "Display translation matrix" ,__VA_ARGS__ } }
Definition at line 616 of file translate.c.
Referenced by __ast_register_translator().
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 64 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().