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 |
Defines | |
| #define | MAX_RECALC 1000 |
| #define | SHOW_TRANS 16 |
Functions | |
| int | __ast_register_translator (struct ast_translator *t, struct ast_module *mod) |
| register codec translator | |
| static | AST_RWLIST_HEAD_STATIC (translators, ast_translator) |
| the list of translators | |
| 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 | |
| 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) |
| Calculate our best translator source format, given costs, and a desired destination. | |
| struct ast_trans_pvt * | ast_translator_build_path (int dest, int 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 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. | |
Translate via the use of pseudo channels.
Definition in file translate.c.
| #define MAX_RECALC 1000 |
Definition at line 43 of file translate.c.
Referenced by handle_cli_core_show_translation().
| #define SHOW_TRANS 16 |
Referenced by handle_cli_core_show_translation().
| 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 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(), 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 }
| static AST_RWLIST_HEAD_STATIC | ( | translators | , | |
| ast_translator | ||||
| ) | [static] |
the list of translators
| 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 214 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().
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 * | 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 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, 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(), 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 |
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 830 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().
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(), ast_trans_pvt::destroy, f, and ast_trans_pvt::pvt.
Referenced by __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 |
Enables the specified translator for use.
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 * | dst, | |
| int * | srcs | |||
| ) |
Calculate our best translator source format, given costs, and a desired destination.
Chooses the best translation path.
Definition at line 761 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().
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 | |||
| ) | [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 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 |
Disables the specified translator from being used.
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 codec translator
Unregister a translator Unregisters the given tranlator.
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, ast_translator::sample, and ast_frame::samples.
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, read] |
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, ast_frame::datalen, 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_frame::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_trans_pvt::c, ast_translator::desc_size, len(), ast_translator::module, ast_translator::newpvt, ast_trans_pvt::outbuf, ast_trans_pvt::plc, 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(), 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(), translator_path::cost, ast_translator::cost, ast_translator::dstfmt, ast_translator::list, MAX_FORMAT, translator_path::multistep, 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().
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] |
{
}
Definition at line 616 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 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().
1.6.1