00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $")
00033
00034 #include <sys/time.h>
00035 #include <sys/resource.h>
00036 #include <math.h>
00037
00038 #include "asterisk/lock.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/translate.h"
00041 #include "asterisk/module.h"
00042 #include "asterisk/frame.h"
00043 #include "asterisk/sched.h"
00044 #include "asterisk/cli.h"
00045 #include "asterisk/term.h"
00046
00047 #define MAX_RECALC 1000
00048
00049
00050 static AST_RWLIST_HEAD_STATIC(translators, ast_translator);
00051
00052
00053
00054
00055
00056
00057 enum path_samp_change {
00058
00059
00060
00061
00062 AST_TRANS_COST_LL_LL_ORIGSAMP = 400000,
00063
00064 AST_TRANS_COST_LL_LY_ORIGSAMP = 600000,
00065
00066
00067 AST_TRANS_COST_LL_LL_UPSAMP = 800000,
00068
00069 AST_TRANS_COST_LL_LY_UPSAMP = 825000,
00070
00071
00072 AST_TRANS_COST_LL_LL_DOWNSAMP = 850000,
00073
00074 AST_TRANS_COST_LL_LY_DOWNSAMP = 875000,
00075
00076
00077
00078
00079 AST_TRANS_COST_LL_UNKNOWN = 885000,
00080
00081
00082
00083
00084 AST_TRANS_COST_LY_LL_ORIGSAMP = 900000,
00085
00086 AST_TRANS_COST_LY_LY_ORIGSAMP = 915000,
00087
00088
00089 AST_TRANS_COST_LY_LL_UPSAMP = 930000,
00090
00091 AST_TRANS_COST_LY_LY_UPSAMP = 945000,
00092
00093
00094 AST_TRANS_COST_LY_LL_DOWNSAMP = 960000,
00095
00096 AST_TRANS_COST_LY_LY_DOWNSAMP = 975000,
00097
00098
00099
00100
00101 AST_TRANS_COST_LY_UNKNOWN = 985000,
00102 };
00103
00104 struct translator_path {
00105 struct ast_translator *step;
00106 unsigned int cost;
00107 unsigned int multistep;
00108 enum path_samp_change rate_change;
00109 };
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 static struct translator_path tr_matrix[MAX_FORMAT][MAX_FORMAT];
00122
00123
00124
00125
00126
00127
00128
00129
00130 static force_inline int powerof(format_t d)
00131 {
00132 int x = ffsll(d);
00133
00134 if (x)
00135 return x - 1;
00136
00137 ast_log(LOG_WARNING, "No bits set? %llu\n", (unsigned long long) d);
00138
00139 return -1;
00140 }
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 static void *newpvt(struct ast_translator *t)
00151 {
00152 struct ast_trans_pvt *pvt;
00153 int len;
00154 char *ofs;
00155
00156
00157
00158
00159
00160 len = sizeof(*pvt) + t->desc_size;
00161 if (t->buf_size)
00162 len += AST_FRIENDLY_OFFSET + t->buf_size;
00163 pvt = ast_calloc(1, len);
00164 if (!pvt)
00165 return NULL;
00166 pvt->t = t;
00167 ofs = (char *)(pvt + 1);
00168 if (t->desc_size) {
00169 pvt->pvt = ofs;
00170 ofs += t->desc_size;
00171 }
00172 if (t->buf_size)
00173 pvt->outbuf.c = ofs + AST_FRIENDLY_OFFSET;
00174
00175 if (t->newpvt && t->newpvt(pvt)) {
00176 ast_free(pvt);
00177 return NULL;
00178 }
00179 ast_module_ref(t->module);
00180 return pvt;
00181 }
00182
00183 static void destroy(struct ast_trans_pvt *pvt)
00184 {
00185 struct ast_translator *t = pvt->t;
00186
00187 if (t->destroy)
00188 t->destroy(pvt);
00189 ast_free(pvt);
00190 ast_module_unref(t->module);
00191 }
00192
00193
00194 static int framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00195 {
00196 int ret;
00197 int samples = pvt->samples;
00198
00199
00200 ast_copy_flags(&pvt->f, f, AST_FRFLAG_HAS_TIMING_INFO);
00201 pvt->f.ts = f->ts;
00202 pvt->f.len = f->len;
00203 pvt->f.seqno = f->seqno;
00204
00205 if (f->samples == 0) {
00206 ast_log(LOG_WARNING, "no samples for %s\n", pvt->t->name);
00207 }
00208 if (pvt->t->buffer_samples) {
00209 if (f->datalen == 0) {
00210
00211 if (!pvt->t->native_plc)
00212 return 0;
00213 }
00214 if (pvt->samples + f->samples > pvt->t->buffer_samples) {
00215 ast_log(LOG_WARNING, "Out of buffer space\n");
00216 return -1;
00217 }
00218 }
00219
00220
00221
00222 ret = pvt->t->framein(pvt, f);
00223
00224 if (pvt->samples == samples)
00225 ast_log(LOG_WARNING, "%s did not update samples %d\n",
00226 pvt->t->name, pvt->samples);
00227 return ret;
00228 }
00229
00230
00231
00232
00233
00234
00235 struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt,
00236 int datalen, int samples)
00237 {
00238 struct ast_frame *f = &pvt->f;
00239
00240 if (samples)
00241 f->samples = samples;
00242 else {
00243 if (pvt->samples == 0)
00244 return NULL;
00245 f->samples = pvt->samples;
00246 pvt->samples = 0;
00247 }
00248 if (datalen)
00249 f->datalen = datalen;
00250 else {
00251 f->datalen = pvt->datalen;
00252 pvt->datalen = 0;
00253 }
00254
00255 f->frametype = AST_FRAME_VOICE;
00256 f->subclass.codec = 1LL << (pvt->t->dstfmt);
00257 f->mallocd = 0;
00258 f->offset = AST_FRIENDLY_OFFSET;
00259 f->src = pvt->t->name;
00260 f->data.ptr = pvt->outbuf.c;
00261
00262 return ast_frisolate(f);
00263 }
00264
00265 static struct ast_frame *default_frameout(struct ast_trans_pvt *pvt)
00266 {
00267 return ast_trans_frameout(pvt, 0, 0);
00268 }
00269
00270
00271
00272 void ast_translator_free_path(struct ast_trans_pvt *p)
00273 {
00274 struct ast_trans_pvt *pn = p;
00275 while ( (p = pn) ) {
00276 pn = p->next;
00277 destroy(p);
00278 }
00279 }
00280
00281
00282 struct ast_trans_pvt *ast_translator_build_path(format_t dest, format_t source)
00283 {
00284 struct ast_trans_pvt *head = NULL, *tail = NULL;
00285
00286 source = powerof(source);
00287 dest = powerof(dest);
00288
00289 if (source == -1 || dest == -1) {
00290 ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", source == -1 ? "starting" : "ending");
00291 return NULL;
00292 }
00293
00294 AST_RWLIST_RDLOCK(&translators);
00295
00296 while (source != dest) {
00297 struct ast_trans_pvt *cur;
00298 struct ast_translator *t = tr_matrix[source][dest].step;
00299 if (!t) {
00300 ast_log(LOG_WARNING, "No translator path from %s to %s\n",
00301 ast_getformatname(source), ast_getformatname(dest));
00302 AST_RWLIST_UNLOCK(&translators);
00303 return NULL;
00304 }
00305 if (!(cur = newpvt(t))) {
00306 ast_log(LOG_WARNING, "Failed to build translator step from %s to %s\n",
00307 ast_getformatname(source), ast_getformatname(dest));
00308 if (head)
00309 ast_translator_free_path(head);
00310 AST_RWLIST_UNLOCK(&translators);
00311 return NULL;
00312 }
00313 if (!head)
00314 head = cur;
00315 else
00316 tail->next = cur;
00317 tail = cur;
00318 cur->nextin = cur->nextout = ast_tv(0, 0);
00319
00320 source = cur->t->dstfmt;
00321 }
00322
00323 AST_RWLIST_UNLOCK(&translators);
00324 return head;
00325 }
00326
00327
00328 struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume)
00329 {
00330 struct ast_trans_pvt *p = path;
00331 struct ast_frame *out = f;
00332 struct timeval delivery;
00333 int has_timing_info;
00334 long ts;
00335 long len;
00336 int seqno;
00337
00338 has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO);
00339 ts = f->ts;
00340 len = f->len;
00341 seqno = f->seqno;
00342
00343
00344 if (!ast_tvzero(f->delivery)) {
00345 if (!ast_tvzero(path->nextin)) {
00346
00347 if (!ast_tveq(path->nextin, f->delivery)) {
00348
00349
00350
00351 if (!ast_tvzero(path->nextout)) {
00352 path->nextout = ast_tvadd(path->nextout,
00353 ast_tvsub(f->delivery, path->nextin));
00354 }
00355 path->nextin = f->delivery;
00356 }
00357 } else {
00358
00359 path->nextin = f->delivery;
00360 path->nextout = f->delivery;
00361 }
00362
00363 path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(f->subclass.codec)));
00364 }
00365 delivery = f->delivery;
00366 for ( ; out && p ; p = p->next) {
00367 framein(p, out);
00368 if (out != f)
00369 ast_frfree(out);
00370 out = p->t->frameout(p);
00371 }
00372 if (out) {
00373
00374 if (!ast_tvzero(delivery)) {
00375
00376 if (ast_tvzero(path->nextout)) {
00377 path->nextout = ast_tvnow();
00378 }
00379
00380
00381 out->delivery = path->nextout;
00382
00383
00384
00385 path->nextout = ast_tvadd(path->nextout, ast_samp2tv(out->samples, ast_format_rate(out->subclass.codec)));
00386 if (f->samples != out->samples && ast_test_flag(out, AST_FRFLAG_HAS_TIMING_INFO)) {
00387 ast_debug(4, "Sample size different %d vs %d\n", f->samples, out->samples);
00388 ast_clear_flag(out, AST_FRFLAG_HAS_TIMING_INFO);
00389 }
00390 } else {
00391 out->delivery = ast_tv(0, 0);
00392 ast_set2_flag(out, has_timing_info, AST_FRFLAG_HAS_TIMING_INFO);
00393 if (has_timing_info) {
00394 out->ts = ts;
00395 out->len = len;
00396 out->seqno = seqno;
00397 }
00398 }
00399
00400 if (out->frametype == AST_FRAME_CNG) {
00401 path->nextout = ast_tv(0, 0);
00402 }
00403 }
00404 if (consume) {
00405 ast_frfree(f);
00406 }
00407 return out;
00408 }
00409
00410
00411 static void calc_cost(struct ast_translator *t, int seconds)
00412 {
00413 int num_samples = 0;
00414 struct ast_trans_pvt *pvt;
00415 struct rusage start;
00416 struct rusage end;
00417 int cost;
00418 int out_rate = ast_format_rate(t->dstfmt);
00419
00420 if (!seconds)
00421 seconds = 1;
00422
00423
00424 if (!t->sample) {
00425 ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
00426 t->cost = 999999;
00427 return;
00428 }
00429
00430 pvt = newpvt(t);
00431 if (!pvt) {
00432 ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
00433 t->cost = 999999;
00434 return;
00435 }
00436
00437 getrusage(RUSAGE_SELF, &start);
00438
00439
00440 while (num_samples < seconds * out_rate) {
00441 struct ast_frame *f = t->sample();
00442 if (!f) {
00443 ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
00444 destroy(pvt);
00445 t->cost = 999999;
00446 return;
00447 }
00448 framein(pvt, f);
00449 ast_frfree(f);
00450 while ((f = t->frameout(pvt))) {
00451 num_samples += f->samples;
00452 ast_frfree(f);
00453 }
00454 }
00455
00456 getrusage(RUSAGE_SELF, &end);
00457
00458 cost = ((end.ru_utime.tv_sec - start.ru_utime.tv_sec) * 1000000) + end.ru_utime.tv_usec - start.ru_utime.tv_usec;
00459 cost += ((end.ru_stime.tv_sec - start.ru_stime.tv_sec) * 1000000) + end.ru_stime.tv_usec - start.ru_stime.tv_usec;
00460
00461 destroy(pvt);
00462
00463 t->cost = cost / seconds;
00464
00465 if (!t->cost)
00466 t->cost = 1;
00467 }
00468
00469 static enum path_samp_change get_rate_change_result(format_t src, format_t dst)
00470 {
00471 int src_ll = src == AST_FORMAT_SLINEAR || src == AST_FORMAT_SLINEAR16;
00472 int dst_ll = dst == AST_FORMAT_SLINEAR || src == AST_FORMAT_SLINEAR16;
00473 int src_rate = ast_format_rate(src);
00474 int dst_rate = ast_format_rate(dst);
00475
00476 if (src_ll) {
00477 if (dst_ll && (src_rate == dst_rate)) {
00478 return AST_TRANS_COST_LL_LL_ORIGSAMP;
00479 } else if (!dst_ll && (src_rate == dst_rate)) {
00480 return AST_TRANS_COST_LL_LY_ORIGSAMP;
00481 } else if (dst_ll && (src_rate < dst_rate)) {
00482 return AST_TRANS_COST_LL_LL_UPSAMP;
00483 } else if (!dst_ll && (src_rate < dst_rate)) {
00484 return AST_TRANS_COST_LL_LY_UPSAMP;
00485 } else if (dst_ll && (src_rate > dst_rate)) {
00486 return AST_TRANS_COST_LL_LL_DOWNSAMP;
00487 } else if (!dst_ll && (src_rate > dst_rate)) {
00488 return AST_TRANS_COST_LL_LY_DOWNSAMP;
00489 } else {
00490 return AST_TRANS_COST_LL_UNKNOWN;
00491 }
00492 } else {
00493 if (dst_ll && (src_rate == dst_rate)) {
00494 return AST_TRANS_COST_LY_LL_ORIGSAMP;
00495 } else if (!dst_ll && (src_rate == dst_rate)) {
00496 return AST_TRANS_COST_LY_LY_ORIGSAMP;
00497 } else if (dst_ll && (src_rate < dst_rate)) {
00498 return AST_TRANS_COST_LY_LL_UPSAMP;
00499 } else if (!dst_ll && (src_rate < dst_rate)) {
00500 return AST_TRANS_COST_LY_LY_UPSAMP;
00501 } else if (dst_ll && (src_rate > dst_rate)) {
00502 return AST_TRANS_COST_LY_LL_DOWNSAMP;
00503 } else if (!dst_ll && (src_rate > dst_rate)) {
00504 return AST_TRANS_COST_LY_LY_DOWNSAMP;
00505 } else {
00506 return AST_TRANS_COST_LY_UNKNOWN;
00507 }
00508 }
00509 }
00510
00511
00512
00513
00514
00515 static void rebuild_matrix(int samples)
00516 {
00517 struct ast_translator *t;
00518 int new_rate_change;
00519 int newcost;
00520 int x;
00521 int y;
00522 int z;
00523
00524 ast_debug(1, "Resetting translation matrix\n");
00525
00526 memset(tr_matrix, '\0', sizeof(tr_matrix));
00527
00528
00529 AST_RWLIST_TRAVERSE(&translators, t, list) {
00530 if (!t->active)
00531 continue;
00532
00533 x = t->srcfmt;
00534 z = t->dstfmt;
00535
00536 if (samples)
00537 calc_cost(t, samples);
00538
00539 new_rate_change = get_rate_change_result(1LL << t->srcfmt, 1LL << t->dstfmt);
00540
00541
00542
00543
00544
00545
00546 if (!tr_matrix[x][z].step ||
00547 ((t->cost < tr_matrix[x][z].cost) && (new_rate_change <= tr_matrix[x][z].rate_change)) ||
00548 (new_rate_change < tr_matrix[x][z].rate_change)) {
00549
00550 tr_matrix[x][z].step = t;
00551 tr_matrix[x][z].cost = t->cost;
00552 tr_matrix[x][z].rate_change = new_rate_change;
00553 }
00554 }
00555
00556
00557
00558
00559
00560
00561
00562 for (;;) {
00563 int changed = 0;
00564 int better_choice = 0;
00565 for (x = 0; x < MAX_FORMAT; x++) {
00566 for (y = 0; y < MAX_FORMAT; y++) {
00567 if (x == y)
00568 continue;
00569 for (z = 0; z < MAX_FORMAT; z++) {
00570 if (z == x || z == y)
00571 continue;
00572 if (!tr_matrix[x][y].step)
00573 continue;
00574 if (!tr_matrix[y][z].step)
00575 continue;
00576
00577
00578
00579
00580 if (tr_matrix[x][z].step &&
00581 ((tr_matrix[x][z].rate_change < tr_matrix[x][y].rate_change) ||
00582 (tr_matrix[x][z].rate_change < tr_matrix[y][z].rate_change))) {
00583 continue;
00584 }
00585
00586
00587 new_rate_change = tr_matrix[x][y].rate_change + tr_matrix[y][z].rate_change;
00588
00589
00590 newcost = tr_matrix[x][y].cost + tr_matrix[y][z].cost;
00591
00592
00593
00594
00595
00596 if (!tr_matrix[x][z].step) {
00597 better_choice = 1;
00598 } else if (new_rate_change < tr_matrix[x][z].rate_change) {
00599 better_choice = 1;
00600 } else {
00601 better_choice = 0;
00602 }
00603
00604 if (!better_choice) {
00605 continue;
00606 }
00607
00608
00609 tr_matrix[x][z].step = tr_matrix[x][y].step;
00610 tr_matrix[x][z].cost = newcost;
00611 tr_matrix[x][z].multistep = 1;
00612
00613
00614
00615
00616
00617 tr_matrix[x][z].rate_change = tr_matrix[x][y].rate_change + tr_matrix[y][z].rate_change;
00618
00619 ast_debug(10, "Discovered %u cost path from %s to %s, via %s\n", tr_matrix[x][z].cost,
00620 ast_getformatname(1LL << x), ast_getformatname(1LL << z), ast_getformatname(1LL << y));
00621 changed++;
00622 }
00623 }
00624 }
00625 if (!changed)
00626 break;
00627 }
00628 }
00629
00630 const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str)
00631 {
00632 struct ast_trans_pvt *pn = p;
00633
00634 if (!p || !p->t) {
00635 return "";
00636 }
00637
00638 ast_str_set(str, 0, "%s", ast_getformatname(1LL << p->t->srcfmt));
00639
00640 while ( (p = pn) ) {
00641 pn = p->next;
00642 ast_str_append(str, 0, "->%s", ast_getformatname(1LL << p->t->dstfmt));
00643 }
00644
00645 return ast_str_buffer(*str);
00646 }
00647
00648 static char *complete_trans_path_choice(const char *line, const char *word, int pos, int state)
00649 {
00650 int which = 0;
00651 int wordlen = strlen(word);
00652 int i;
00653 char *ret = NULL;
00654 size_t len = 0;
00655 const struct ast_format_list *format_list = ast_get_format_list(&len);
00656
00657 for (i = 0; i < len; i++) {
00658 if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) {
00659 continue;
00660 }
00661 if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) {
00662 ret = ast_strdup(format_list[i].name);
00663 break;
00664 }
00665 }
00666 return ret;
00667 }
00668
00669 static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00670 {
00671 #define SHOW_TRANS 64
00672 static const char * const option1[] = { "recalc", "paths", NULL };
00673 int x, y, z;
00674 int curlen = 0, longest = 0, magnitude[SHOW_TRANS] = { 0, };
00675
00676 switch (cmd) {
00677 case CLI_INIT:
00678 e->command = "core show translation";
00679 e->usage =
00680 "Usage: 'core show translation' can be used in two ways.\n"
00681 " 1. 'core show translation [recalc [<recalc seconds>]]\n"
00682 " Displays known codec translators and the cost associated\n"
00683 " with each conversion. If the argument 'recalc' is supplied along\n"
00684 " with optional number of seconds to test a new test will be performed\n"
00685 " as the chart is being displayed.\n"
00686 " 2. 'core show translation paths [codec]'\n"
00687 " This will display all the translation paths associated with a codec\n";
00688 return NULL;
00689 case CLI_GENERATE:
00690 if (a->pos == 3) {
00691 return ast_cli_complete(a->word, option1, a->n);
00692 }
00693 if (a->pos == 4 && !strcasecmp(a->argv[3], option1[1])) {
00694 return complete_trans_path_choice(a->line, a->word, a->pos, a->n);
00695 }
00696 return NULL;
00697 }
00698
00699 if (a->argc > 5)
00700 return CLI_SHOWUSAGE;
00701
00702 if (a->argv[3] && !strcasecmp(a->argv[3], option1[1]) && a->argc == 5) {
00703 format_t input_src = 0;
00704 format_t src = 0;
00705 size_t len = 0;
00706 int dst;
00707 int i;
00708 const struct ast_format_list *format_list = ast_get_format_list(&len);
00709 struct ast_str *str = ast_str_alloca(256);
00710 struct ast_translator *step;
00711
00712 for (i = 0; i < len; i++) {
00713 if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) {
00714 continue;
00715 }
00716 if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) {
00717 input_src = format_list[i].bits;
00718 }
00719 }
00720
00721 if (!input_src) {
00722 ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]);
00723 return CLI_FAILURE;
00724 }
00725
00726 AST_RWLIST_RDLOCK(&translators);
00727 ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(input_src));
00728 for (i = 0; i < len; i++) {
00729 if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK) || (format_list[i].bits == input_src)) {
00730 continue;
00731 }
00732
00733
00734
00735
00736
00737 dst = powerof(format_list[i].bits);
00738 src = powerof(input_src);
00739 ast_str_reset(str);
00740 if (tr_matrix[src][dst].step) {
00741 ast_str_append(&str, 0, "%s", ast_getformatname(1LL << tr_matrix[src][dst].step->srcfmt));
00742 while (src != dst) {
00743 step = tr_matrix[src][dst].step;
00744 if (!step) {
00745 ast_str_reset(str);
00746 break;
00747 }
00748 ast_str_append(&str, 0, "->%s", ast_getformatname(1LL << step->dstfmt));
00749 src = step->dstfmt;
00750 }
00751 }
00752
00753 if (ast_strlen_zero(ast_str_buffer(str))) {
00754 ast_str_set(&str, 0, "No Translation Path");
00755 }
00756
00757 ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str));
00758 }
00759 AST_RWLIST_UNLOCK(&translators);
00760
00761 return CLI_SUCCESS;
00762 } else if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) {
00763 z = a->argv[4] ? atoi(a->argv[4]) : 1;
00764
00765 if (z <= 0) {
00766 ast_cli(a->fd, " Recalc must be greater than 0. Defaulting to 1.\n");
00767 z = 1;
00768 }
00769
00770 if (z > MAX_RECALC) {
00771 ast_cli(a->fd, " Maximum limit of recalc exceeded by %d, truncating value to %d\n", z - MAX_RECALC, MAX_RECALC);
00772 z = MAX_RECALC;
00773 }
00774 ast_cli(a->fd, " Recalculating Codec Translation (number of sample seconds: %d)\n\n", z);
00775 AST_RWLIST_WRLOCK(&translators);
00776 rebuild_matrix(z);
00777 AST_RWLIST_UNLOCK(&translators);
00778 } else if (a->argc > 3)
00779 return CLI_SHOWUSAGE;
00780
00781 AST_RWLIST_RDLOCK(&translators);
00782
00783 ast_cli(a->fd, " Translation times between formats (in microseconds) for one second of data\n");
00784 ast_cli(a->fd, " Source Format (Rows) Destination Format (Columns)\n\n");
00785
00786 for (x = 0; x < SHOW_TRANS; x++) {
00787
00788 if (!(AST_FORMAT_AUDIO_MASK & (1LL << (x))))
00789 continue;
00790 curlen = strlen(ast_getformatname(1LL << (x)));
00791 if (curlen > longest)
00792 longest = curlen;
00793 for (y = 0; y < SHOW_TRANS; y++) {
00794 if (!(AST_FORMAT_AUDIO_MASK & (1LL << (y))))
00795 continue;
00796 if (tr_matrix[x][y].cost > pow(10, magnitude[x])) {
00797 magnitude[y] = floor(log10(tr_matrix[x][y].cost));
00798 }
00799 }
00800 }
00801 for (x = -1; x < SHOW_TRANS; x++) {
00802 struct ast_str *out = ast_str_alloca(256);
00803
00804 if (x >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (x))))
00805 continue;
00806
00807 if(x >= 0 && !strcmp(ast_getformatname(1LL << (x)), "unknown"))
00808 continue;
00809 ast_str_set(&out, -1, " ");
00810 for (y = -1; y < SHOW_TRANS; y++) {
00811
00812 if (y >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (y))))
00813 continue;
00814
00815 if (y >= 0 && !strcmp(ast_getformatname(1LL << (y)), "unknown"))
00816 continue;
00817 if (y >= 0)
00818 curlen = strlen(ast_getformatname(1LL << (y)));
00819 if (y >= 0 && magnitude[y] + 1 > curlen) {
00820 curlen = magnitude[y] + 1;
00821 }
00822 if (curlen < 5)
00823 curlen = 5;
00824 if (x >= 0 && y >= 0 && tr_matrix[x][y].step) {
00825
00826 ast_str_append(&out, -1, "%*u", curlen + 1, tr_matrix[x][y].cost);
00827 } else if (x == -1 && y >= 0) {
00828
00829 ast_str_append(&out, -1, "%*s", curlen + 1, ast_getformatname(1LL << (y)) );
00830 } else if (y == -1 && x >= 0) {
00831
00832 ast_str_append(&out, -1, "%*s", longest, ast_getformatname(1LL << (x)) );
00833 } else if (x >= 0 && y >= 0) {
00834
00835 ast_str_append(&out, -1, "%*s", curlen + 1, "-");
00836 } else {
00837
00838 ast_str_append(&out, -1, "%*s", longest, "");
00839 }
00840 }
00841 ast_str_append(&out, -1, "\n");
00842 ast_cli(a->fd, "%s", ast_str_buffer(out));
00843 }
00844 AST_RWLIST_UNLOCK(&translators);
00845 return CLI_SUCCESS;
00846 }
00847
00848 static struct ast_cli_entry cli_translate[] = {
00849 AST_CLI_DEFINE(handle_cli_core_show_translation, "Display translation matrix")
00850 };
00851
00852
00853 int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
00854 {
00855 static int added_cli = 0;
00856 struct ast_translator *u;
00857 char tmp[80];
00858
00859 if (!mod) {
00860 ast_log(LOG_WARNING, "Missing module pointer, you need to supply one\n");
00861 return -1;
00862 }
00863
00864 if (!t->buf_size) {
00865 ast_log(LOG_WARNING, "empty buf size, you need to supply one\n");
00866 return -1;
00867 }
00868
00869 t->module = mod;
00870
00871 t->srcfmt = powerof(t->srcfmt);
00872 t->dstfmt = powerof(t->dstfmt);
00873 t->active = 1;
00874
00875 if (t->srcfmt == -1 || t->dstfmt == -1) {
00876 ast_log(LOG_WARNING, "Invalid translator path: (%s codec is not valid)\n", t->srcfmt == -1 ? "starting" : "ending");
00877 return -1;
00878 }
00879 if (t->srcfmt >= MAX_FORMAT) {
00880 ast_log(LOG_WARNING, "Source format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt));
00881 return -1;
00882 }
00883
00884 if (t->dstfmt >= MAX_FORMAT) {
00885 ast_log(LOG_WARNING, "Destination format %s is larger than MAX_FORMAT\n", ast_getformatname(t->dstfmt));
00886 return -1;
00887 }
00888
00889 if (t->buf_size) {
00890
00891
00892
00893
00894 struct _test_align { void *a, *b; } p;
00895 int align = (char *)&p.b - (char *)&p.a;
00896
00897 t->buf_size = ((t->buf_size + align - 1) / align) * align;
00898 }
00899
00900 if (t->frameout == NULL)
00901 t->frameout = default_frameout;
00902
00903 calc_cost(t, 1);
00904
00905 ast_verb(2, "Registered translator '%s' from format %s to %s, cost %d\n",
00906 term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
00907 ast_getformatname(1LL << t->srcfmt), ast_getformatname(1LL << t->dstfmt), t->cost);
00908
00909 if (!added_cli) {
00910 ast_cli_register_multiple(cli_translate, ARRAY_LEN(cli_translate));
00911 added_cli++;
00912 }
00913
00914 AST_RWLIST_WRLOCK(&translators);
00915
00916
00917
00918 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
00919 if ((u->srcfmt == t->srcfmt) &&
00920 (u->dstfmt == t->dstfmt) &&
00921 (u->cost > t->cost)) {
00922 AST_RWLIST_INSERT_BEFORE_CURRENT(t, list);
00923 t = NULL;
00924 break;
00925 }
00926 }
00927 AST_RWLIST_TRAVERSE_SAFE_END;
00928
00929
00930
00931 if (t)
00932 AST_RWLIST_INSERT_HEAD(&translators, t, list);
00933
00934 rebuild_matrix(0);
00935
00936 AST_RWLIST_UNLOCK(&translators);
00937
00938 return 0;
00939 }
00940
00941
00942 int ast_unregister_translator(struct ast_translator *t)
00943 {
00944 char tmp[80];
00945 struct ast_translator *u;
00946 int found = 0;
00947
00948 AST_RWLIST_WRLOCK(&translators);
00949 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
00950 if (u == t) {
00951 AST_RWLIST_REMOVE_CURRENT(list);
00952 ast_verb(2, "Unregistered translator '%s' from format %s to %s\n", term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), ast_getformatname(1LL << t->srcfmt), ast_getformatname(1LL << t->dstfmt));
00953 found = 1;
00954 break;
00955 }
00956 }
00957 AST_RWLIST_TRAVERSE_SAFE_END;
00958
00959 if (found)
00960 rebuild_matrix(0);
00961
00962 AST_RWLIST_UNLOCK(&translators);
00963
00964 return (u ? 0 : -1);
00965 }
00966
00967 void ast_translator_activate(struct ast_translator *t)
00968 {
00969 AST_RWLIST_WRLOCK(&translators);
00970 t->active = 1;
00971 rebuild_matrix(0);
00972 AST_RWLIST_UNLOCK(&translators);
00973 }
00974
00975 void ast_translator_deactivate(struct ast_translator *t)
00976 {
00977 AST_RWLIST_WRLOCK(&translators);
00978 t->active = 0;
00979 rebuild_matrix(0);
00980 AST_RWLIST_UNLOCK(&translators);
00981 }
00982
00983
00984 format_t ast_translator_best_choice(format_t *dst, format_t *srcs)
00985 {
00986 int x,y;
00987 int better = 0;
00988 int besttime = INT_MAX;
00989 int beststeps = INT_MAX;
00990 unsigned int best_rate_change = INT_MAX;
00991 format_t best = -1;
00992 format_t bestdst = 0;
00993 format_t cur, cursrc;
00994 format_t common = ((*dst) & (*srcs)) & AST_FORMAT_AUDIO_MASK;
00995
00996 if (common) {
00997 for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
00998 if (!(cur & common)) {
00999 continue;
01000 }
01001
01002
01003 if (best == -1) {
01004 best = cur;
01005 continue;
01006 }
01007
01008 if (ast_format_rate(best) < ast_format_rate(cur)) {
01009 best = cur;
01010 continue;
01011 }
01012 }
01013
01014 *srcs = *dst = best;
01015 return 0;
01016 } else {
01017 AST_RWLIST_RDLOCK(&translators);
01018 for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
01019 if (! (cur & *dst)) {
01020 continue;
01021 }
01022 for (cursrc = 1, x = 0; x <= MAX_AUDIO_FORMAT; cursrc <<= 1, x++) {
01023 if (!(*srcs & cursrc) || !tr_matrix[x][y].step) {
01024 continue;
01025 }
01026
01027
01028
01029
01030
01031 better = 0;
01032 if (tr_matrix[x][y].rate_change < best_rate_change) {
01033 better = 1;
01034 }
01035 if ((tr_matrix[x][y].rate_change <= best_rate_change) &&
01036 (tr_matrix[x][y].cost < besttime || tr_matrix[x][y].multistep < beststeps)) {
01037 better = 1;
01038 }
01039 if (better) {
01040
01041 best = cursrc;
01042 bestdst = cur;
01043 besttime = tr_matrix[x][y].cost;
01044 beststeps = tr_matrix[x][y].multistep;
01045 best_rate_change = tr_matrix[x][y].rate_change;
01046 }
01047 }
01048 }
01049 AST_RWLIST_UNLOCK(&translators);
01050 if (best > -1) {
01051 *srcs = best;
01052 *dst = bestdst;
01053 best = 0;
01054 }
01055 return best;
01056 }
01057 }
01058
01059 unsigned int ast_translate_path_steps(format_t dest, format_t src)
01060 {
01061 unsigned int res = -1;
01062
01063
01064 src = powerof(src);
01065 dest = powerof(dest);
01066
01067 if (src == -1 || dest == -1) {
01068 ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src == -1 ? "starting" : "ending");
01069 return -1;
01070 }
01071 AST_RWLIST_RDLOCK(&translators);
01072
01073 if (tr_matrix[src][dest].step)
01074 res = tr_matrix[src][dest].multistep + 1;
01075
01076 AST_RWLIST_UNLOCK(&translators);
01077
01078 return res;
01079 }
01080
01081 format_t ast_translate_available_formats(format_t dest, format_t src)
01082 {
01083 format_t res = dest;
01084 format_t x;
01085 format_t src_audio = src & AST_FORMAT_AUDIO_MASK;
01086 format_t src_video = src & AST_FORMAT_VIDEO_MASK;
01087 format_t x_bits;
01088
01089
01090
01091 if (!src)
01092 return dest;
01093
01094
01095 if (src_audio) {
01096 src_audio = powerof(src_audio);
01097 }
01098
01099
01100 if (src_video) {
01101 src_video = powerof(src_video);
01102 }
01103
01104
01105
01106
01107
01108
01109 AST_RWLIST_RDLOCK(&translators);
01110
01111
01112
01113
01114
01115 for (x = 1LL; src_audio && x > 0; x <<= 1) {
01116 if (!(x & AST_FORMAT_AUDIO_MASK)) {
01117 continue;
01118 }
01119
01120
01121 if (!(dest & x))
01122 continue;
01123
01124
01125
01126 if (src & x)
01127 continue;
01128
01129
01130
01131
01132 x_bits = powerof(x);
01133 if (!tr_matrix[src_audio][x_bits].step) {
01134 res &= ~x;
01135 continue;
01136 }
01137
01138
01139 if (!tr_matrix[x_bits][src_audio].step)
01140 res &= ~x;
01141 }
01142
01143
01144
01145
01146
01147 for (x = 1LL; src_video && x > 0; x <<= 1) {
01148 if (!(x & AST_FORMAT_VIDEO_MASK)) {
01149 continue;
01150 }
01151
01152
01153 if (!(dest & x))
01154 continue;
01155
01156
01157
01158 if (src & x)
01159 continue;
01160
01161
01162
01163
01164 x_bits = powerof(x);
01165 if (!tr_matrix[src_video][x_bits].step) {
01166 res &= ~x;
01167 continue;
01168 }
01169
01170
01171 if (!tr_matrix[x_bits][src_video].step)
01172 res &= ~x;
01173 }
01174
01175 AST_RWLIST_UNLOCK(&translators);
01176
01177 return res;
01178 }