![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
translate.c
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2006, Digium, Inc. 00005 * 00006 * Mark Spencer <markster@digium.com> 00007 * 00008 * See http://www.asterisk.org for more information about 00009 * the Asterisk project. Please do not directly contact 00010 * any of the maintainers of this project for assistance; 00011 * the project provides a web site, mailing lists and IRC 00012 * channels for your use. 00013 * 00014 * This program is free software, distributed under the terms of 00015 * the GNU General Public License Version 2. See the LICENSE file 00016 * at the top of the source tree. 00017 */ 00018 00019 /*! \file 00020 * 00021 * \brief Translate via the use of pseudo channels 00022 * 00023 * \author Mark Spencer <markster@digium.com> 00024 */ 00025 00026 #include "asterisk.h" 00027 00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 48619 $") 00029 00030 #include <sys/types.h> 00031 #include <sys/socket.h> 00032 #include <sys/time.h> 00033 #include <unistd.h> 00034 #include <stdlib.h> 00035 #include <string.h> 00036 #include <stdio.h> 00037 00038 #include "asterisk/lock.h" 00039 #include "asterisk/channel.h" 00040 #include "asterisk/logger.h" 00041 #include "asterisk/translate.h" 00042 #include "asterisk/module.h" 00043 #include "asterisk/options.h" 00044 #include "asterisk/frame.h" 00045 #include "asterisk/sched.h" 00046 #include "asterisk/cli.h" 00047 #include "asterisk/term.h" 00048 00049 #define MAX_RECALC 200 /* max sample recalc */ 00050 00051 /*! \brief the list of translators */ 00052 static AST_RWLIST_HEAD_STATIC(translators, ast_translator); 00053 00054 struct translator_path { 00055 struct ast_translator *step; /*!< Next step translator */ 00056 unsigned int cost; /*!< Complete cost to destination */ 00057 unsigned int multistep; /*!< Multiple conversions required for this translation */ 00058 }; 00059 00060 /*! \brief a matrix that, for any pair of supported formats, 00061 * indicates the total cost of translation and the first step. 00062 * The full path can be reconstricted iterating on the matrix 00063 * until step->dstfmt == desired_format. 00064 * 00065 * Array indexes are 'src' and 'dest', in that order. 00066 * 00067 * Note: the lock in the 'translators' list is also used to protect 00068 * this structure. 00069 */ 00070 static struct translator_path tr_matrix[MAX_FORMAT][MAX_FORMAT]; 00071 00072 /*! \todo 00073 * TODO: sample frames for each supported input format. 00074 * We build this on the fly, by taking an SLIN frame and using 00075 * the existing converter to play with it. 00076 */ 00077 00078 /*! \brief returns the index of the lowest bit set */ 00079 static force_inline int powerof(unsigned int d) 00080 { 00081 int x = ffs(d); 00082 00083 if (x) 00084 return x - 1; 00085 00086 ast_log(LOG_WARNING, "No bits set? %d\n", d); 00087 00088 return -1; 00089 } 00090 00091 /* 00092 * wrappers around the translator routines. 00093 */ 00094 00095 /*! 00096 * \brief Allocate the descriptor, required outbuf space, 00097 * and possibly also plc and desc. 00098 */ 00099 static void *newpvt(struct ast_translator *t) 00100 { 00101 struct ast_trans_pvt *pvt; 00102 int len; 00103 int useplc = t->plc_samples > 0 && t->useplc; /* cache, because it can change on the fly */ 00104 char *ofs; 00105 00106 /* 00107 * compute the required size adding private descriptor, 00108 * plc, buffer, AST_FRIENDLY_OFFSET. 00109 */ 00110 len = sizeof(*pvt) + t->desc_size; 00111 if (useplc) 00112 len += sizeof(plc_state_t); 00113 if (t->buf_size) 00114 len += AST_FRIENDLY_OFFSET + t->buf_size; 00115 pvt = ast_calloc(1, len); 00116 if (!pvt) 00117 return NULL; 00118 pvt->t = t; 00119 ofs = (char *)(pvt + 1); /* pointer to data space */ 00120 if (t->desc_size) { /* first comes the descriptor */ 00121 pvt->pvt = ofs; 00122 ofs += t->desc_size; 00123 } 00124 if (useplc) { /* then plc state */ 00125 pvt->plc = (plc_state_t *)ofs; 00126 ofs += sizeof(plc_state_t); 00127 } 00128 if (t->buf_size) /* finally buffer and header */ 00129 pvt->outbuf = ofs + AST_FRIENDLY_OFFSET; 00130 /* call local init routine, if present */ 00131 if (t->newpvt && t->newpvt(pvt)) { 00132 free(pvt); 00133 return NULL; 00134 } 00135 ast_module_ref(t->module); 00136 return pvt; 00137 } 00138 00139 static void destroy(struct ast_trans_pvt *pvt) 00140 { 00141 struct ast_translator *t = pvt->t; 00142 00143 if (t->destroy) 00144 t->destroy(pvt); 00145 free(pvt); 00146 ast_module_unref(t->module); 00147 } 00148 00149 /*! \brief framein wrapper, deals with plc and bound checks. */ 00150 static int framein(struct ast_trans_pvt *pvt, struct ast_frame *f) 00151 { 00152 int16_t *dst = (int16_t *)pvt->outbuf; 00153 int ret; 00154 int samples = pvt->samples; /* initial value */ 00155 00156 /* Copy the last in jb timing info to the pvt */ 00157 pvt->f.has_timing_info = f->has_timing_info; 00158 pvt->f.ts = f->ts; 00159 pvt->f.len = f->len; 00160 pvt->f.seqno = f->seqno; 00161 00162 if (f->samples == 0) { 00163 ast_log(LOG_WARNING, "no samples for %s\n", pvt->t->name); 00164 } 00165 if (pvt->t->buffer_samples) { /* do not pass empty frames to callback */ 00166 if (f->datalen == 0) { /* perform PLC with nominal framesize of 20ms/160 samples */ 00167 if (pvt->plc) { 00168 int l = pvt->t->plc_samples; 00169 if (pvt->samples + l > pvt->t->buffer_samples) { 00170 ast_log(LOG_WARNING, "Out of buffer space\n"); 00171 return -1; 00172 } 00173 l = plc_fillin(pvt->plc, dst + pvt->samples, l); 00174 pvt->samples += l; 00175 pvt->datalen = pvt->samples * 2; /* SLIN has 2bytes for 1sample */ 00176 } 00177 return 0; 00178 } 00179 if (pvt->samples + f->samples > pvt->t->buffer_samples) { 00180 ast_log(LOG_WARNING, "Out of buffer space\n"); 00181 return -1; 00182 } 00183 } 00184 /* we require a framein routine, wouldn't know how to do 00185 * it otherwise. 00186 */ 00187 ret = pvt->t->framein(pvt, f); 00188 /* possibly store data for plc */ 00189 if (!ret && pvt->plc) { 00190 int l = pvt->t->plc_samples; 00191 if (pvt->samples < l) 00192 l = pvt->samples; 00193 plc_rx(pvt->plc, dst + pvt->samples - l, l); 00194 } 00195 /* diagnostic ... */ 00196 if (pvt->samples == samples) 00197 ast_log(LOG_WARNING, "%s did not update samples %d\n", 00198 pvt->t->name, pvt->samples); 00199 return ret; 00200 } 00201 00202 /*! \brief generic frameout routine. 00203 * If samples and datalen are 0, take whatever is in pvt 00204 * and reset them, otherwise take the values in the caller and 00205 * leave alone the pvt values. 00206 */ 00207 struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt, 00208 int datalen, int samples) 00209 { 00210 struct ast_frame *f = &pvt->f; 00211 00212 if (samples) 00213 f->samples = samples; 00214 else { 00215 if (pvt->samples == 0) 00216 return NULL; 00217 f->samples = pvt->samples; 00218 pvt->samples = 0; 00219 } 00220 if (datalen) 00221 f->datalen = datalen; 00222 else { 00223 f->datalen = pvt->datalen; 00224 pvt->datalen = 0; 00225 } 00226 00227 f->frametype = AST_FRAME_VOICE; 00228 f->subclass = 1 << (pvt->t->dstfmt); 00229 f->mallocd = 0; 00230 f->offset = AST_FRIENDLY_OFFSET; 00231 f->src = pvt->t->name; 00232 f->data = pvt->outbuf; 00233 return f; 00234 } 00235 00236 static struct ast_frame *default_frameout(struct ast_trans_pvt *pvt) 00237 { 00238 return ast_trans_frameout(pvt, 0, 0); 00239 } 00240 00241 /* end of callback wrappers and helpers */ 00242 00243 void ast_translator_free_path(struct ast_trans_pvt *p) 00244 { 00245 struct ast_trans_pvt *pn = p; 00246 while ( (p = pn) ) { 00247 pn = p->next; 00248 destroy(p); 00249 } 00250 } 00251 00252 /*! \brief Build a chain of translators based upon the given source and dest formats */ 00253 struct ast_trans_pvt *ast_translator_build_path(int dest, int source) 00254 { 00255 struct ast_trans_pvt *head = NULL, *tail = NULL; 00256 00257 source = powerof(source); 00258 dest = powerof(dest); 00259 00260 AST_RWLIST_RDLOCK(&translators); 00261 00262 while (source != dest) { 00263 struct ast_trans_pvt *cur; 00264 struct ast_translator *t = tr_matrix[source][dest].step; 00265 if (!t) { 00266 ast_log(LOG_WARNING, "No translator path from %s to %s\n", 00267 ast_getformatname(source), ast_getformatname(dest)); 00268 AST_RWLIST_UNLOCK(&translators); 00269 return NULL; 00270 } 00271 if (!(cur = newpvt(t))) { 00272 ast_log(LOG_WARNING, "Failed to build translator step from %d to %d\n", source, dest); 00273 if (head) 00274 ast_translator_free_path(head); 00275 AST_RWLIST_UNLOCK(&translators); 00276 return NULL; 00277 } 00278 if (!head) 00279 head = cur; 00280 else 00281 tail->next = cur; 00282 tail = cur; 00283 cur->nextin = cur->nextout = ast_tv(0, 0); 00284 /* Keep going if this isn't the final destination */ 00285 source = cur->t->dstfmt; 00286 } 00287 00288 AST_RWLIST_UNLOCK(&translators); 00289 return head; 00290 } 00291 00292 /*! \brief do the actual translation */ 00293 struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume) 00294 { 00295 struct ast_trans_pvt *p = path; 00296 struct ast_frame *out = f; 00297 struct timeval delivery; 00298 int has_timing_info; 00299 long ts; 00300 long len; 00301 int seqno; 00302 00303 has_timing_info = f->has_timing_info; 00304 ts = f->ts; 00305 len = f->len; 00306 seqno = f->seqno; 00307 00308 /* XXX hmmm... check this below */ 00309 if (!ast_tvzero(f->delivery)) { 00310 if (!ast_tvzero(path->nextin)) { 00311 /* Make sure this is in line with what we were expecting */ 00312 if (!ast_tveq(path->nextin, f->delivery)) { 00313 /* The time has changed between what we expected and this 00314 most recent time on the new packet. If we have a 00315 valid prediction adjust our output time appropriately */ 00316 if (!ast_tvzero(path->nextout)) { 00317 path->nextout = ast_tvadd(path->nextout, 00318 ast_tvsub(f->delivery, path->nextin)); 00319 } 00320 path->nextin = f->delivery; 00321 } 00322 } else { 00323 /* This is our first pass. Make sure the timing looks good */ 00324 path->nextin = f->delivery; 00325 path->nextout = f->delivery; 00326 } 00327 /* Predict next incoming sample */ 00328 path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, 8000)); 00329 } 00330 delivery = f->delivery; 00331 for ( ; out && p ; p = p->next) { 00332 framein(p, out); 00333 out = p->t->frameout(p); 00334 } 00335 if (consume) 00336 ast_frfree(f); 00337 if (out == NULL) 00338 return NULL; 00339 /* we have a frame, play with times */ 00340 if (!ast_tvzero(delivery)) { 00341 /* Regenerate prediction after a discontinuity */ 00342 if (ast_tvzero(path->nextout)) 00343 path->nextout = ast_tvnow(); 00344 00345 /* Use next predicted outgoing timestamp */ 00346 out->delivery = path->nextout; 00347 00348 /* Predict next outgoing timestamp from samples in this 00349 frame. */ 00350 path->nextout = ast_tvadd(path->nextout, ast_samp2tv( out->samples, 8000)); 00351 } else { 00352 out->delivery = ast_tv(0, 0); 00353 out->has_timing_info = has_timing_info; 00354 if (has_timing_info) { 00355 out->ts = ts; 00356 out->len = len; 00357 out->seqno = seqno; 00358 } 00359 } 00360 /* Invalidate prediction if we're entering a silence period */ 00361 if (out->frametype == AST_FRAME_CNG) 00362 path->nextout = ast_tv(0, 0); 00363 return out; 00364 } 00365 00366 /*! \brief compute the cost of a single translation step */ 00367 static void calc_cost(struct ast_translator *t, int seconds) 00368 { 00369 int sofar=0; 00370 struct ast_trans_pvt *pvt; 00371 struct timeval start; 00372 int cost; 00373 00374 if (!seconds) 00375 seconds = 1; 00376 00377 /* If they don't make samples, give them a terrible score */ 00378 if (!t->sample) { 00379 ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name); 00380 t->cost = 99999; 00381 return; 00382 } 00383 pvt = newpvt(t); 00384 if (!pvt) { 00385 ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name); 00386 t->cost = 99999; 00387 return; 00388 } 00389 start = ast_tvnow(); 00390 /* Call the encoder until we've processed the required number of samples */ 00391 while (sofar < seconds * 8000) { 00392 struct ast_frame *f = t->sample(); 00393 if (!f) { 00394 ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name); 00395 destroy(pvt); 00396 t->cost = 99999; 00397 return; 00398 } 00399 framein(pvt, f); 00400 ast_frfree(f); 00401 while ((f = t->frameout(pvt))) { 00402 sofar += f->samples; 00403 ast_frfree(f); 00404 } 00405 } 00406 cost = ast_tvdiff_ms(ast_tvnow(), start); 00407 destroy(pvt); 00408 t->cost = cost / seconds; 00409 if (!t->cost) 00410 t->cost = 1; 00411 } 00412 00413 /*! 00414 * \brief rebuild a translation matrix. 00415 * \note This function expects the list of translators to be locked 00416 */ 00417 static void rebuild_matrix(int samples) 00418 { 00419 struct ast_translator *t; 00420 int x; /* source format index */ 00421 int y; /* intermediate format index */ 00422 int z; /* destination format index */ 00423 00424 if (option_debug) 00425 ast_log(LOG_DEBUG, "Resetting translation matrix\n"); 00426 00427 bzero(tr_matrix, sizeof(tr_matrix)); 00428 00429 /* first, compute all direct costs */ 00430 AST_RWLIST_TRAVERSE(&translators, t, list) { 00431 if (!t->active) 00432 continue; 00433 00434 x = t->srcfmt; 00435 z = t->dstfmt; 00436 00437 if (samples) 00438 calc_cost(t, samples); 00439 00440 if (!tr_matrix[x][z].step || t->cost < tr_matrix[x][z].cost) { 00441 tr_matrix[x][z].step = t; 00442 tr_matrix[x][z].cost = t->cost; 00443 } 00444 } 00445 00446 /* 00447 * For each triple x, y, z of distinct formats, check if there is 00448 * a path from x to z through y which is cheaper than what is 00449 * currently known, and in case, update the matrix. 00450 * Repeat until the matrix is stable. 00451 */ 00452 for (;;) { 00453 int changed = 0; 00454 for (x = 0; x < MAX_FORMAT; x++) { /* source format */ 00455 for (y=0; y < MAX_FORMAT; y++) { /* intermediate format */ 00456 if (x == y) /* skip ourselves */ 00457 continue; 00458 00459 for (z=0; z<MAX_FORMAT; z++) { /* dst format */ 00460 int newcost; 00461 00462 if (z == x || z == y) /* skip null conversions */ 00463 continue; 00464 if (!tr_matrix[x][y].step) /* no path from x to y */ 00465 continue; 00466 if (!tr_matrix[y][z].step) /* no path from y to z */ 00467 continue; 00468 newcost = tr_matrix[x][y].cost + tr_matrix[y][z].cost; 00469 if (tr_matrix[x][z].step && newcost >= tr_matrix[x][z].cost) 00470 continue; /* x->y->z is more expensive than 00471 * the existing path */ 00472 /* ok, we can get from x to z via y with a cost that 00473 is the sum of the transition from x to y and 00474 from y to z */ 00475 00476 tr_matrix[x][z].step = tr_matrix[x][y].step; 00477 tr_matrix[x][z].cost = newcost; 00478 tr_matrix[x][z].multistep = 1; 00479 if (option_debug) 00480 ast_log(LOG_DEBUG, "Discovered %d cost path from %s to %s, via %d\n", tr_matrix[x][z].cost, ast_getformatname(x), ast_getformatname(z), y); 00481 changed++; 00482 } 00483 } 00484 } 00485 if (!changed) 00486 break; 00487 } 00488 } 00489 00490 static int show_translation(int fd, int argc, char *argv[]) 00491 { 00492 #define SHOW_TRANS 13 00493 int x, y, z; 00494 int curlen = 0, longest = 0; 00495 00496 if (argc > 5) 00497 return RESULT_SHOWUSAGE; 00498 00499 if (argv[3] && !strcasecmp(argv[3], "recalc")) { 00500 z = argv[4] ? atoi(argv[4]) : 1; 00501 00502 if (z <= 0) { 00503 ast_cli(fd, " C'mon let's be serious here... defaulting to 1.\n"); 00504 z = 1; 00505 } 00506 00507 if (z > MAX_RECALC) { 00508 ast_cli(fd, " Maximum limit of recalc exceeded by %d, truncating value to %d\n", z - MAX_RECALC, MAX_RECALC); 00509 z = MAX_RECALC; 00510 } 00511 ast_cli(fd, " Recalculating Codec Translation (number of sample seconds: %d)\n\n", z); 00512 AST_RWLIST_WRLOCK(&translators); 00513 rebuild_matrix(z); 00514 AST_RWLIST_UNLOCK(&translators); 00515 } 00516 00517 AST_RWLIST_RDLOCK(&translators); 00518 00519 ast_cli(fd, " Translation times between formats (in milliseconds) for one second of data\n"); 00520 ast_cli(fd, " Source Format (Rows) Destination Format (Columns)\n\n"); 00521 /* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */ 00522 for (x = 0; x < SHOW_TRANS; x++) { 00523 curlen = strlen(ast_getformatname(1 << (x + 1))); 00524 if (curlen > longest) 00525 longest = curlen; 00526 } 00527 for (x = -1; x < SHOW_TRANS; x++) { 00528 struct ast_str *out = ast_str_alloca(120); 00529 00530 ast_str_set(&out, -1, " "); 00531 for (y = -1; y < SHOW_TRANS; y++) { 00532 curlen = strlen(ast_getformatname(1 << (y))); 00533 00534 if (x >= 0 && y >= 0 && tr_matrix[x][y].step) { 00535 /* XXX 999 is a little hackish 00536 We don't want this number being larger than the shortest (or current) codec 00537 For now, that is "gsm" */ 00538 ast_str_append(&out, -1, "%*d", curlen + 1, tr_matrix[x][y].cost > 999 ? 0 : tr_matrix[x][y].cost); 00539 } else if (x == -1 && y >= 0) { 00540 /* Top row - use a dynamic size */ 00541 ast_str_append(&out, -1, "%*s", curlen + 1, ast_getformatname(1 << (x + y + 1)) ); 00542 } else if (y == -1 && x >= 0) { 00543 /* Left column - use a static size. */ 00544 ast_str_append(&out, -1, "%*s", longest, ast_getformatname(1 << (x + y + 1)) ); 00545 } else if (x >= 0 && y >= 0) { 00546 ast_str_append(&out, -1, "%*s", curlen + 1, "-"); 00547 } else { 00548 ast_str_append(&out, -1, "%*s", longest, ""); 00549 } 00550 } 00551 ast_str_append(&out, -1, "\n"); 00552 ast_cli(fd, out->str); 00553 } 00554 AST_RWLIST_UNLOCK(&translators); 00555 return RESULT_SUCCESS; 00556 } 00557 00558 static const char show_trans_usage[] = 00559 "Usage: core show translation [recalc] [<recalc seconds>]\n" 00560 " Displays known codec translators and the cost associated\n" 00561 "with each conversion. If the argument 'recalc' is supplied along\n" 00562 "with optional number of seconds to test a new test will be performed\n" 00563 "as the chart is being displayed.\n"; 00564 00565 static struct ast_cli_entry cli_translate[] = { 00566 { { "core", "show", "translation", NULL }, 00567 show_translation, "Display translation matrix", 00568 show_trans_usage, NULL, NULL }, 00569 }; 00570 00571 /*! \brief register codec translator */ 00572 int __ast_register_translator(struct ast_translator *t, struct ast_module *mod) 00573 { 00574 static int added_cli = 0; 00575 struct ast_translator *u; 00576 00577 if (!mod) { 00578 ast_log(LOG_WARNING, "Missing module pointer, you need to supply one\n"); 00579 return -1; 00580 } 00581 00582 if (!t->buf_size) { 00583 ast_log(LOG_WARNING, "empty buf size, you need to supply one\n"); 00584 return -1; 00585 } 00586 00587 t->module = mod; 00588 00589 t->srcfmt = powerof(t->srcfmt); 00590 t->dstfmt = powerof(t->dstfmt); 00591 t->active = 1; 00592 00593 if (t->plc_samples) { 00594 if (t->buffer_samples < t->plc_samples) { 00595 ast_log(LOG_WARNING, "plc_samples %d buffer_samples %d\n", 00596 t->plc_samples, t->buffer_samples); 00597 return -1; 00598 } 00599 if (t->dstfmt != AST_FORMAT_SLINEAR) 00600 ast_log(LOG_WARNING, "plc_samples %d format %x\n", 00601 t->plc_samples, t->dstfmt); 00602 } 00603 if (t->srcfmt >= MAX_FORMAT) { 00604 ast_log(LOG_WARNING, "Source format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt)); 00605 return -1; 00606 } 00607 00608 if (t->dstfmt >= MAX_FORMAT) { 00609 ast_log(LOG_WARNING, "Destination format %s is larger than MAX_FORMAT\n", ast_getformatname(t->dstfmt)); 00610 return -1; 00611 } 00612 00613 if (t->buf_size) { 00614 /* 00615 * Align buf_size properly, rounding up to the machine-specific 00616 * alignment for pointers. 00617 */ 00618 struct _test_align { void *a, *b; } p; 00619 int align = (char *)&p.b - (char *)&p.a; 00620 00621 t->buf_size = ((t->buf_size + align - 1) / align) * align; 00622 } 00623 00624 if (t->frameout == NULL) 00625 t->frameout = default_frameout; 00626 00627 calc_cost(t, 1); 00628 00629 if (option_verbose > 1) { 00630 char tmp[80]; 00631 00632 ast_verbose(VERBOSE_PREFIX_2 "Registered translator '%s' from format %s to %s, cost %d\n", 00633 term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), 00634 ast_getformatname(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt), t->cost); 00635 } 00636 00637 if (!added_cli) { 00638 ast_cli_register_multiple(cli_translate, sizeof(cli_translate) / sizeof(struct ast_cli_entry)); 00639 added_cli++; 00640 } 00641 00642 AST_RWLIST_WRLOCK(&translators); 00643 00644 /* find any existing translators that provide this same srcfmt/dstfmt, 00645 and put this one in order based on cost */ 00646 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) { 00647 if ((u->srcfmt == t->srcfmt) && 00648 (u->dstfmt == t->dstfmt) && 00649 (u->cost > t->cost)) { 00650 AST_RWLIST_INSERT_BEFORE_CURRENT(&translators, t, list); 00651 t = NULL; 00652 } 00653 } 00654 AST_RWLIST_TRAVERSE_SAFE_END; 00655 00656 /* if no existing translator was found for this format combination, 00657 add it to the beginning of the list */ 00658 if (t) 00659 AST_RWLIST_INSERT_HEAD(&translators, t, list); 00660 00661 rebuild_matrix(0); 00662 00663 AST_RWLIST_UNLOCK(&translators); 00664 00665 return 0; 00666 } 00667 00668 /*! \brief unregister codec translator */ 00669 int ast_unregister_translator(struct ast_translator *t) 00670 { 00671 char tmp[80]; 00672 struct ast_translator *u; 00673 int found = 0; 00674 00675 AST_RWLIST_WRLOCK(&translators); 00676 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) { 00677 if (u == t) { 00678 AST_RWLIST_REMOVE_CURRENT(&translators, list); 00679 if (option_verbose > 1) 00680 ast_verbose(VERBOSE_PREFIX_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)); 00681 found = 1; 00682 break; 00683 } 00684 } 00685 AST_RWLIST_TRAVERSE_SAFE_END; 00686 00687 if (found) 00688 rebuild_matrix(0); 00689 00690 AST_RWLIST_UNLOCK(&translators); 00691 00692 return (u ? 0 : -1); 00693 } 00694 00695 void ast_translator_activate(struct ast_translator *t) 00696 { 00697 AST_RWLIST_WRLOCK(&translators); 00698 t->active = 1; 00699 rebuild_matrix(0); 00700 AST_RWLIST_UNLOCK(&translators); 00701 } 00702 00703 void ast_translator_deactivate(struct ast_translator *t) 00704 { 00705 AST_RWLIST_WRLOCK(&translators); 00706 t->active = 0; 00707 rebuild_matrix(0); 00708 AST_RWLIST_UNLOCK(&translators); 00709 } 00710 00711 /*! \brief Calculate our best translator source format, given costs, and a desired destination */ 00712 int ast_translator_best_choice(int *dst, int *srcs) 00713 { 00714 int x,y; 00715 int best = -1; 00716 int bestdst = 0; 00717 int cur, cursrc; 00718 int besttime = INT_MAX; 00719 int beststeps = INT_MAX; 00720 int common = (*dst) & (*srcs); /* are there common formats ? */ 00721 00722 if (common) { /* yes, pick one and return */ 00723 for (cur = 1, y = 0; y < MAX_FORMAT; cur <<= 1, y++) { 00724 if (cur & common) /* guaranteed to find one */ 00725 break; 00726 } 00727 /* We are done, this is a common format to both. */ 00728 *srcs = *dst = cur; 00729 return 0; 00730 } else { /* No, we will need to translate */ 00731 AST_RWLIST_RDLOCK(&translators); 00732 for (cur = 1, y = 0; y < MAX_FORMAT; cur <<= 1, y++) { 00733 if (! (cur & *dst)) 00734 continue; 00735 for (cursrc = 1, x = 0; x < MAX_FORMAT; cursrc <<= 1, x++) { 00736 if (!(*srcs & cursrc) || !tr_matrix[x][y].step || 00737 tr_matrix[x][y].cost > besttime) 00738 continue; /* not existing or no better */ 00739 if (tr_matrix[x][y].cost < besttime || 00740 tr_matrix[x][y].multistep < beststeps) { 00741 /* better than what we have so far */ 00742 best = cursrc; 00743 bestdst = cur; 00744 besttime = tr_matrix[x][y].cost; 00745 beststeps = tr_matrix[x][y].multistep; 00746 } 00747 } 00748 } 00749 AST_RWLIST_UNLOCK(&translators); 00750 if (best > -1) { 00751 *srcs = best; 00752 *dst = bestdst; 00753 best = 0; 00754 } 00755 return best; 00756 } 00757 } 00758 00759 unsigned int ast_translate_path_steps(unsigned int dest, unsigned int src) 00760 { 00761 unsigned int res = -1; 00762 00763 /* convert bitwise format numbers into array indices */ 00764 src = powerof(src); 00765 dest = powerof(dest); 00766 00767 AST_RWLIST_RDLOCK(&translators); 00768 00769 if (tr_matrix[src][dest].step) 00770 res = tr_matrix[src][dest].multistep + 1; 00771 00772 AST_RWLIST_UNLOCK(&translators); 00773 00774 return res; 00775 } 00776 00777 unsigned int ast_translate_available_formats(unsigned int dest, unsigned int src) 00778 { 00779 unsigned int res = dest; 00780 unsigned int x; 00781 unsigned int src_audio = src & AST_FORMAT_AUDIO_MASK; 00782 unsigned int src_video = src & AST_FORMAT_VIDEO_MASK; 00783 00784 /* if we don't have a source format, we just have to try all 00785 possible destination formats */ 00786 if (!src) 00787 return dest; 00788 00789 /* If we have a source audio format, get its format index */ 00790 if (src_audio) 00791 src_audio = powerof(src_audio); 00792 00793 /* If we have a source video format, get its format index */ 00794 if (src_video) 00795 src_video = powerof(src_video); 00796 00797 AST_RWLIST_RDLOCK(&translators); 00798 00799 /* For a given source audio format, traverse the list of 00800 known audio formats to determine whether there exists 00801 a translation path from the source format to the 00802 destination format. */ 00803 for (x = 1; src_audio && x < AST_FORMAT_MAX_AUDIO; x <<= 1) { 00804 /* if this is not a desired format, nothing to do */ 00805 if (!dest & x) 00806 continue; 00807 00808 /* if the source is supplying this format, then 00809 we can leave it in the result */ 00810 if (src & x) 00811 continue; 00812 00813 /* if we don't have a translation path from the src 00814 to this format, remove it from the result */ 00815 if (!tr_matrix[src_audio][powerof(x)].step) { 00816 res &= ~x; 00817 continue; 00818 } 00819 00820 /* now check the opposite direction */ 00821 if (!tr_matrix[powerof(x)][src_audio].step) 00822 res &= ~x; 00823 } 00824 00825 /* For a given source video format, traverse the list of 00826 known video formats to determine whether there exists 00827 a translation path from the source format to the 00828 destination format. */ 00829 for (; src_video && x < AST_FORMAT_MAX_VIDEO; x <<= 1) { 00830 /* if this is not a desired format, nothing to do */ 00831 if (!dest & x) 00832 continue; 00833 00834 /* if the source is supplying this format, then 00835 we can leave it in the result */ 00836 if (src & x) 00837 continue; 00838 00839 /* if we don't have a translation path from the src 00840 to this format, remove it from the result */ 00841 if (!tr_matrix[src_video][powerof(x)].step) { 00842 res &= ~x; 00843 continue; 00844 } 00845 00846 /* now check the opposite direction */ 00847 if (!tr_matrix[powerof(x)][src_video].step) 00848 res &= ~x; 00849 } 00850 00851 AST_RWLIST_UNLOCK(&translators); 00852 00853 return res; 00854 }