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: 403015 $")
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
00048
00049
00050
00051
00052
00053
00054 #define MAX_RECALC 1000
00055
00056
00057 static AST_RWLIST_HEAD_STATIC(translators, ast_translator);
00058
00059 struct translator_path {
00060 struct ast_translator *step;
00061 uint32_t table_cost;
00062 uint8_t multistep;
00063 };
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 static struct translator_path **__matrix;
00077
00078
00079
00080
00081
00082
00083 static int *__indextable;
00084
00085
00086 static ast_rwlock_t tablelock;
00087
00088
00089 #define INIT_INDEX 32
00090
00091 #define GROW_INDEX 16
00092
00093
00094 static int cur_max_index;
00095
00096 static int index_size;
00097
00098 static void matrix_rebuild(int samples);
00099
00100
00101
00102
00103
00104 static int format2index(enum ast_format_id id)
00105 {
00106 int x;
00107
00108 ast_rwlock_rdlock(&tablelock);
00109 for (x = 0; x < cur_max_index; x++) {
00110 if (__indextable[x] == id) {
00111
00112 ast_rwlock_unlock(&tablelock);
00113 return x;
00114 }
00115 }
00116 ast_rwlock_unlock(&tablelock);
00117 return -1;
00118 }
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 static int add_format2index(enum ast_format_id id)
00130 {
00131 if (format2index(id) != -1) {
00132
00133 return 0;
00134 }
00135
00136 ast_rwlock_wrlock(&tablelock);
00137 if (cur_max_index == (index_size)) {
00138 ast_rwlock_unlock(&tablelock);
00139 return -1;
00140 }
00141 __indextable[cur_max_index] = id;
00142 cur_max_index++;
00143 ast_rwlock_unlock(&tablelock);
00144
00145 return 0;
00146 }
00147
00148
00149
00150
00151
00152 static enum ast_format_id index2format(int index)
00153 {
00154 enum ast_format_id format_id;
00155
00156 if (index >= cur_max_index) {
00157 return 0;
00158 }
00159 ast_rwlock_rdlock(&tablelock);
00160 format_id = __indextable[index];
00161 ast_rwlock_unlock(&tablelock);
00162
00163 return format_id;
00164 }
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 static int matrix_resize(int init)
00177 {
00178 struct translator_path **tmp_matrix = NULL;
00179 int *tmp_table = NULL;
00180 int old_index;
00181 int x;
00182
00183 AST_RWLIST_WRLOCK(&translators);
00184 ast_rwlock_wrlock(&tablelock);
00185
00186 old_index = index_size;
00187 if (init) {
00188 index_size += INIT_INDEX;
00189 } else {
00190 index_size += GROW_INDEX;
00191 }
00192
00193
00194 if (!(tmp_matrix = ast_calloc(1, sizeof(struct translator_path *) * (index_size)))) {
00195 goto resize_cleanup;
00196 }
00197
00198 for (x = 0; x < index_size; x++) {
00199 if (!(tmp_matrix[x] = ast_calloc(1, sizeof(struct translator_path) * (index_size)))) {
00200 goto resize_cleanup;
00201 }
00202 }
00203
00204
00205 if (!(tmp_table = ast_calloc(1, sizeof(int) * index_size))) {
00206 goto resize_cleanup;
00207 }
00208
00209
00210 if (!init) {
00211 for (x = 0; x < old_index; x++) {
00212 ast_free(__matrix[x]);
00213 }
00214 ast_free(__matrix);
00215
00216 memcpy(tmp_table, __indextable, sizeof(int) * old_index);
00217 ast_free(__indextable);
00218 }
00219
00220
00221 __matrix = tmp_matrix;
00222 __indextable = tmp_table;
00223
00224 matrix_rebuild(0);
00225 ast_rwlock_unlock(&tablelock);
00226 AST_RWLIST_UNLOCK(&translators);
00227
00228 return 0;
00229
00230 resize_cleanup:
00231 ast_rwlock_unlock(&tablelock);
00232 AST_RWLIST_UNLOCK(&translators);
00233 if (tmp_matrix) {
00234 for (x = 0; x < index_size; x++) {
00235 ast_free(tmp_matrix[x]);
00236 }
00237 ast_free(tmp_matrix);
00238 }
00239 ast_free(tmp_table);
00240
00241 return -1;
00242 }
00243
00244
00245
00246
00247
00248
00249
00250 static void matrix_clear(void)
00251 {
00252 int x;
00253 for (x = 0; x < index_size; x++) {
00254 memset(__matrix[x], '\0', sizeof(struct translator_path) * (index_size));
00255 }
00256 }
00257
00258
00259
00260
00261
00262
00263
00264 static struct translator_path *matrix_get(unsigned int x, unsigned int y)
00265 {
00266 if (!(x >= 0 && y >= 0)) {
00267 return NULL;
00268 }
00269 return __matrix[x] + y;
00270 }
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 static void *newpvt(struct ast_translator *t, const struct ast_format *explicit_dst)
00281 {
00282 struct ast_trans_pvt *pvt;
00283 int len;
00284 char *ofs;
00285
00286
00287
00288
00289
00290 len = sizeof(*pvt) + t->desc_size;
00291 if (t->buf_size)
00292 len += AST_FRIENDLY_OFFSET + t->buf_size;
00293 pvt = ast_calloc(1, len);
00294 if (!pvt) {
00295 return NULL;
00296 }
00297 pvt->t = t;
00298 ofs = (char *)(pvt + 1);
00299 if (t->desc_size) {
00300 pvt->pvt = ofs;
00301 ofs += t->desc_size;
00302 }
00303 if (t->buf_size) {
00304 pvt->outbuf.c = ofs + AST_FRIENDLY_OFFSET;
00305 }
00306
00307
00308 if (explicit_dst) {
00309 ast_format_copy(&pvt->explicit_dst, explicit_dst);
00310 }
00311
00312 if (t->newpvt && t->newpvt(pvt)) {
00313 ast_free(pvt);
00314 return NULL;
00315 }
00316 ast_module_ref(t->module);
00317 return pvt;
00318 }
00319
00320 static void destroy(struct ast_trans_pvt *pvt)
00321 {
00322 struct ast_translator *t = pvt->t;
00323
00324 if (t->destroy)
00325 t->destroy(pvt);
00326 ast_free(pvt);
00327 ast_module_unref(t->module);
00328 }
00329
00330
00331 static int framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00332 {
00333 int ret;
00334 int samples = pvt->samples;
00335
00336
00337 ast_copy_flags(&pvt->f, f, AST_FRFLAG_HAS_TIMING_INFO);
00338 pvt->f.ts = f->ts;
00339 pvt->f.len = f->len;
00340 pvt->f.seqno = f->seqno;
00341
00342 if (f->samples == 0) {
00343 ast_log(LOG_WARNING, "no samples for %s\n", pvt->t->name);
00344 }
00345 if (pvt->t->buffer_samples) {
00346 if (f->datalen == 0) {
00347
00348 if (!pvt->t->native_plc)
00349 return 0;
00350 }
00351 if (pvt->samples + f->samples > pvt->t->buffer_samples) {
00352 ast_log(LOG_WARNING, "Out of buffer space\n");
00353 return -1;
00354 }
00355 }
00356
00357
00358
00359 ret = pvt->t->framein(pvt, f);
00360
00361 if (pvt->samples == samples)
00362 ast_log(LOG_WARNING, "%s did not update samples %d\n",
00363 pvt->t->name, pvt->samples);
00364 return ret;
00365 }
00366
00367
00368
00369
00370
00371
00372 struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt,
00373 int datalen, int samples)
00374 {
00375 struct ast_frame *f = &pvt->f;
00376
00377 if (samples) {
00378 f->samples = samples;
00379 } else {
00380 if (pvt->samples == 0)
00381 return NULL;
00382 f->samples = pvt->samples;
00383 pvt->samples = 0;
00384 }
00385 if (datalen) {
00386 f->datalen = datalen;
00387 } else {
00388 f->datalen = pvt->datalen;
00389 pvt->datalen = 0;
00390 }
00391
00392 f->frametype = AST_FRAME_VOICE;
00393 ast_format_copy(&f->subclass.format, &pvt->t->dst_format);
00394 f->mallocd = 0;
00395 f->offset = AST_FRIENDLY_OFFSET;
00396 f->src = pvt->t->name;
00397 f->data.ptr = pvt->outbuf.c;
00398
00399 return ast_frisolate(f);
00400 }
00401
00402 static struct ast_frame *default_frameout(struct ast_trans_pvt *pvt)
00403 {
00404 return ast_trans_frameout(pvt, 0, 0);
00405 }
00406
00407
00408
00409 void ast_translator_free_path(struct ast_trans_pvt *p)
00410 {
00411 struct ast_trans_pvt *pn = p;
00412 while ( (p = pn) ) {
00413 pn = p->next;
00414 destroy(p);
00415 }
00416 }
00417
00418
00419 struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct ast_format *src)
00420 {
00421 struct ast_trans_pvt *head = NULL, *tail = NULL;
00422 int src_index, dst_index;
00423 struct ast_format tmp_fmt1;
00424 struct ast_format tmp_fmt2;
00425
00426 src_index = format2index(src->id);
00427 dst_index = format2index(dst->id);
00428
00429 if (src_index == -1 || dst_index == -1) {
00430 ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src_index == -1 ? "starting" : "ending");
00431 return NULL;
00432 }
00433
00434 AST_RWLIST_RDLOCK(&translators);
00435
00436 while (src_index != dst_index) {
00437 struct ast_trans_pvt *cur;
00438 struct ast_format *explicit_dst = NULL;
00439 struct ast_translator *t = matrix_get(src_index, dst_index)->step;
00440 if (!t) {
00441 int src_id = index2format(src_index);
00442 int dst_id = index2format(dst_index);
00443 ast_log(LOG_WARNING, "No translator path from %s to %s\n",
00444 ast_getformatname(ast_format_set(&tmp_fmt1, src_id, 0)),
00445 ast_getformatname(ast_format_set(&tmp_fmt2, dst_id, 0)));
00446 AST_RWLIST_UNLOCK(&translators);
00447 return NULL;
00448 }
00449 if (dst_index == t->dst_fmt_index) {
00450 explicit_dst = dst;
00451 }
00452 if (!(cur = newpvt(t, explicit_dst))) {
00453 int src_id = index2format(src_index);
00454 int dst_id = index2format(dst_index);
00455 ast_log(LOG_WARNING, "Failed to build translator step from %s to %s\n",
00456 ast_getformatname(ast_format_set(&tmp_fmt1, src_id, 0)),
00457 ast_getformatname(ast_format_set(&tmp_fmt2, dst_id, 0)));
00458 if (head) {
00459 ast_translator_free_path(head);
00460 }
00461 AST_RWLIST_UNLOCK(&translators);
00462 return NULL;
00463 }
00464 if (!head) {
00465 head = cur;
00466 } else {
00467 tail->next = cur;
00468 }
00469 tail = cur;
00470 cur->nextin = cur->nextout = ast_tv(0, 0);
00471
00472 src_index = cur->t->dst_fmt_index;
00473 }
00474
00475 AST_RWLIST_UNLOCK(&translators);
00476 return head;
00477 }
00478
00479
00480 struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume)
00481 {
00482 struct ast_trans_pvt *p = path;
00483 struct ast_frame *out;
00484 struct timeval delivery;
00485 int has_timing_info;
00486 long ts;
00487 long len;
00488 int seqno;
00489
00490 has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO);
00491 ts = f->ts;
00492 len = f->len;
00493 seqno = f->seqno;
00494
00495 if (!ast_tvzero(f->delivery)) {
00496 if (!ast_tvzero(path->nextin)) {
00497
00498 if (!ast_tveq(path->nextin, f->delivery)) {
00499
00500
00501
00502 if (!ast_tvzero(path->nextout)) {
00503 path->nextout = ast_tvadd(path->nextout,
00504 ast_tvsub(f->delivery, path->nextin));
00505 }
00506 path->nextin = f->delivery;
00507 }
00508 } else {
00509
00510 path->nextin = f->delivery;
00511 path->nextout = f->delivery;
00512 }
00513
00514 path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(&f->subclass.format)));
00515 }
00516 delivery = f->delivery;
00517 for (out = f; out && p ; p = p->next) {
00518 framein(p, out);
00519 if (out != f) {
00520 ast_frfree(out);
00521 }
00522 out = p->t->frameout(p);
00523 }
00524 if (out) {
00525
00526 if (!ast_tvzero(delivery)) {
00527
00528 if (ast_tvzero(path->nextout)) {
00529 path->nextout = ast_tvnow();
00530 }
00531
00532
00533 out->delivery = path->nextout;
00534
00535
00536
00537 path->nextout = ast_tvadd(path->nextout, ast_samp2tv(out->samples, ast_format_rate(&out->subclass.format)));
00538 if (f->samples != out->samples && ast_test_flag(out, AST_FRFLAG_HAS_TIMING_INFO)) {
00539 ast_debug(4, "Sample size different %u vs %u\n", f->samples, out->samples);
00540 ast_clear_flag(out, AST_FRFLAG_HAS_TIMING_INFO);
00541 }
00542 } else {
00543 out->delivery = ast_tv(0, 0);
00544 ast_set2_flag(out, has_timing_info, AST_FRFLAG_HAS_TIMING_INFO);
00545 if (has_timing_info) {
00546 out->ts = ts;
00547 out->len = len;
00548 out->seqno = seqno;
00549 }
00550 }
00551
00552 if (out->frametype == AST_FRAME_CNG) {
00553 path->nextout = ast_tv(0, 0);
00554 }
00555 }
00556 if (consume) {
00557 ast_frfree(f);
00558 }
00559 return out;
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 static void generate_computational_cost(struct ast_translator *t, int seconds)
00572 {
00573 int num_samples = 0;
00574 struct ast_trans_pvt *pvt;
00575 struct rusage start;
00576 struct rusage end;
00577 int cost;
00578 int out_rate = ast_format_rate(&t->dst_format);
00579
00580 if (!seconds) {
00581 seconds = 1;
00582 }
00583
00584
00585 if (!t->sample) {
00586 ast_debug(3, "Translator '%s' does not produce sample frames.\n", t->name);
00587 t->comp_cost = 999999;
00588 return;
00589 }
00590
00591 pvt = newpvt(t, NULL);
00592 if (!pvt) {
00593 ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
00594 t->comp_cost = 999999;
00595 return;
00596 }
00597
00598 getrusage(RUSAGE_SELF, &start);
00599
00600
00601 while (num_samples < seconds * out_rate) {
00602 struct ast_frame *f = t->sample();
00603 if (!f) {
00604 ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
00605 destroy(pvt);
00606 t->comp_cost = 999999;
00607 return;
00608 }
00609 framein(pvt, f);
00610 ast_frfree(f);
00611 while ((f = t->frameout(pvt))) {
00612 num_samples += f->samples;
00613 ast_frfree(f);
00614 }
00615 }
00616
00617 getrusage(RUSAGE_SELF, &end);
00618
00619 cost = ((end.ru_utime.tv_sec - start.ru_utime.tv_sec) * 1000000) + end.ru_utime.tv_usec - start.ru_utime.tv_usec;
00620 cost += ((end.ru_stime.tv_sec - start.ru_stime.tv_sec) * 1000000) + end.ru_stime.tv_usec - start.ru_stime.tv_usec;
00621
00622 destroy(pvt);
00623
00624 t->comp_cost = cost / seconds;
00625
00626 if (!t->comp_cost) {
00627 t->comp_cost = 1;
00628 }
00629 }
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649 static int generate_table_cost(struct ast_format *src, struct ast_format *dst)
00650 {
00651 int src_rate = ast_format_rate(src);
00652 int src_ll = 0;
00653 int dst_rate = ast_format_rate(dst);
00654 int dst_ll = 0;
00655
00656 if ((AST_FORMAT_GET_TYPE(src->id) != AST_FORMAT_TYPE_AUDIO) || (AST_FORMAT_GET_TYPE(dst->id) != AST_FORMAT_TYPE_AUDIO)) {
00657
00658
00659
00660 return 0;
00661 }
00662 src_ll = ast_format_is_slinear(src);
00663 dst_ll = ast_format_is_slinear(dst);
00664 if (src_ll) {
00665 if (dst_ll && (src_rate == dst_rate)) {
00666 return AST_TRANS_COST_LL_LL_ORIGSAMP;
00667 } else if (!dst_ll && (src_rate == dst_rate)) {
00668 return AST_TRANS_COST_LL_LY_ORIGSAMP;
00669 } else if (dst_ll && (src_rate < dst_rate)) {
00670 return AST_TRANS_COST_LL_LL_UPSAMP;
00671 } else if (!dst_ll && (src_rate < dst_rate)) {
00672 return AST_TRANS_COST_LL_LY_UPSAMP;
00673 } else if (dst_ll && (src_rate > dst_rate)) {
00674 return AST_TRANS_COST_LL_LL_DOWNSAMP;
00675 } else if (!dst_ll && (src_rate > dst_rate)) {
00676 return AST_TRANS_COST_LL_LY_DOWNSAMP;
00677 } else {
00678 return AST_TRANS_COST_LL_UNKNOWN;
00679 }
00680 } else {
00681 if (dst_ll && (src_rate == dst_rate)) {
00682 return AST_TRANS_COST_LY_LL_ORIGSAMP;
00683 } else if (!dst_ll && (src_rate == dst_rate)) {
00684 return AST_TRANS_COST_LY_LY_ORIGSAMP;
00685 } else if (dst_ll && (src_rate < dst_rate)) {
00686 return AST_TRANS_COST_LY_LL_UPSAMP;
00687 } else if (!dst_ll && (src_rate < dst_rate)) {
00688 return AST_TRANS_COST_LY_LY_UPSAMP;
00689 } else if (dst_ll && (src_rate > dst_rate)) {
00690 return AST_TRANS_COST_LY_LL_DOWNSAMP;
00691 } else if (!dst_ll && (src_rate > dst_rate)) {
00692 return AST_TRANS_COST_LY_LY_DOWNSAMP;
00693 } else {
00694 return AST_TRANS_COST_LY_UNKNOWN;
00695 }
00696 }
00697 }
00698
00699
00700
00701
00702
00703 static void matrix_rebuild(int samples)
00704 {
00705 struct ast_translator *t;
00706 int newtablecost;
00707 int x;
00708 int y;
00709 int z;
00710
00711 ast_debug(1, "Resetting translation matrix\n");
00712
00713 matrix_clear();
00714
00715
00716 AST_RWLIST_TRAVERSE(&translators, t, list) {
00717 if (!t->active) {
00718 continue;
00719 }
00720
00721 x = t->src_fmt_index;
00722 z = t->dst_fmt_index;
00723
00724 if (samples) {
00725 generate_computational_cost(t, samples);
00726 }
00727
00728
00729
00730
00731
00732
00733
00734 if (!matrix_get(x, z)->step ||
00735 (t->table_cost < matrix_get(x, z)->step->table_cost) ||
00736 (t->comp_cost < matrix_get(x, z)->step->comp_cost)) {
00737
00738 matrix_get(x, z)->step = t;
00739 matrix_get(x, z)->table_cost = t->table_cost;
00740 }
00741 }
00742
00743
00744
00745
00746
00747
00748
00749 for (;;) {
00750 int changed = 0;
00751 for (x = 0; x < cur_max_index; x++) {
00752 for (y = 0; y < cur_max_index; y++) {
00753 if (x == y) {
00754 continue;
00755 }
00756 for (z = 0; z < cur_max_index; z++) {
00757 if ((z == x || z == y) ||
00758 !matrix_get(x, y)->step ||
00759 !matrix_get(y, z)->step) {
00760 continue;
00761 }
00762
00763
00764 newtablecost = matrix_get(x, y)->table_cost + matrix_get(y, z)->table_cost;
00765
00766
00767
00768 if (!matrix_get(x, z)->step || (newtablecost < matrix_get(x, z)->table_cost)) {
00769 struct ast_format tmpx;
00770 struct ast_format tmpy;
00771 struct ast_format tmpz;
00772 matrix_get(x, z)->step = matrix_get(x, y)->step;
00773 matrix_get(x, z)->table_cost = newtablecost;
00774 matrix_get(x, z)->multistep = 1;
00775 changed++;
00776 ast_debug(10, "Discovered %d cost path from %s to %s, via %s\n",
00777 matrix_get(x, z)->table_cost,
00778 ast_getformatname(ast_format_set(&tmpx, index2format(x), 0)),
00779 ast_getformatname(ast_format_set(&tmpy, index2format(z), 0)),
00780 ast_getformatname(ast_format_set(&tmpz, index2format(y), 0)));
00781 }
00782 }
00783 }
00784 }
00785 if (!changed) {
00786 break;
00787 }
00788 }
00789 }
00790
00791 const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str)
00792 {
00793 struct ast_trans_pvt *pn = p;
00794 char tmp[256];
00795
00796 if (!p || !p->t) {
00797 return "";
00798 }
00799
00800 ast_str_set(str, 0, "%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), p->t->src_format.id));
00801
00802 while ( (p = pn) ) {
00803 pn = p->next;
00804 ast_str_append(str, 0, "->%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), p->t->dst_format.id));
00805 }
00806
00807 return ast_str_buffer(*str);
00808 }
00809
00810 static char *complete_trans_path_choice(const char *line, const char *word, int pos, int state)
00811 {
00812 int which = 0;
00813 int wordlen = strlen(word);
00814 int i;
00815 char *ret = NULL;
00816 size_t len = 0;
00817 const struct ast_format_list *format_list = ast_format_list_get(&len);
00818
00819 for (i = 0; i < len; i++) {
00820 if (AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) {
00821 continue;
00822 }
00823 if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) {
00824 ret = ast_strdup(format_list[i].name);
00825 break;
00826 }
00827 }
00828 ast_format_list_destroy(format_list);
00829 return ret;
00830 }
00831
00832 static void handle_cli_recalc(struct ast_cli_args *a)
00833 {
00834 int time = a->argv[4] ? atoi(a->argv[4]) : 1;
00835
00836 if (time <= 0) {
00837 ast_cli(a->fd, " Recalc must be greater than 0. Defaulting to 1.\n");
00838 time = 1;
00839 }
00840
00841 if (time > MAX_RECALC) {
00842 ast_cli(a->fd, " Maximum limit of recalc exceeded by %d, truncating value to %d\n", time - MAX_RECALC, MAX_RECALC);
00843 time = MAX_RECALC;
00844 }
00845 ast_cli(a->fd, " Recalculating Codec Translation (number of sample seconds: %d)\n\n", time);
00846 AST_RWLIST_WRLOCK(&translators);
00847 matrix_rebuild(time);
00848 AST_RWLIST_UNLOCK(&translators);
00849 }
00850
00851 static char *handle_show_translation_table(struct ast_cli_args *a)
00852 {
00853 int x;
00854 int y;
00855 int i;
00856 int k;
00857 int curlen = 0;
00858 int longest = 0;
00859 int f_len;
00860 size_t f_size = 0;
00861 const struct ast_format_list *f_list = ast_format_list_get(&f_size);
00862 struct ast_str *out = ast_str_create(1024);
00863
00864 f_len = f_size;
00865 AST_RWLIST_RDLOCK(&translators);
00866 ast_cli(a->fd, " Translation times between formats (in microseconds) for one second of data\n");
00867 ast_cli(a->fd, " Source Format (Rows) Destination Format (Columns)\n\n");
00868
00869
00870 for (i = 0; i < f_len; i++) {
00871
00872 if (AST_FORMAT_GET_TYPE(f_list[i].format.id) != AST_FORMAT_TYPE_AUDIO)
00873 continue;
00874 curlen = strlen(ast_getformatname(&f_list[i].format));
00875 if (curlen > longest) {
00876 longest = curlen;
00877 }
00878 }
00879
00880 for (i = -1; i < f_len; i++) {
00881 x = -1;
00882 if ((i >= 0) && ((x = format2index(f_list[i].format.id)) == -1)) {
00883 continue;
00884 }
00885
00886 if (i >= 0 && (AST_FORMAT_GET_TYPE(f_list[i].format.id) != AST_FORMAT_TYPE_AUDIO)) {
00887 continue;
00888 }
00889
00890 if (i >= 0 && !strcmp(ast_getformatname(&f_list[i].format), "unknown")) {
00891 continue;
00892 }
00893 ast_str_set(&out, 0, " ");
00894 for (k = -1; k < f_len; k++) {
00895 y = -1;
00896 if ((k >= 0) && ((y = format2index(f_list[k].format.id)) == -1)) {
00897 continue;
00898 }
00899
00900 if (k >= 0 && (AST_FORMAT_GET_TYPE(f_list[k].format.id) != AST_FORMAT_TYPE_AUDIO)) {
00901 continue;
00902 }
00903
00904 if (k >= 0 && !strcmp(ast_getformatname(&f_list[k].format), "unknown")) {
00905 continue;
00906 }
00907 if (k >= 0) {
00908 curlen = strlen(ast_getformatname(&f_list[k].format));
00909 }
00910 if (curlen < 5) {
00911 curlen = 5;
00912 }
00913
00914 if (x >= 0 && y >= 0 && matrix_get(x, y)->step) {
00915
00916 ast_str_append(&out, 0, "%*d", curlen + 1, (matrix_get(x, y)->table_cost/100));
00917 } else if (i == -1 && k >= 0) {
00918
00919 ast_str_append(&out, 0, "%*s", curlen + 1, ast_getformatname(&f_list[k].format));
00920 } else if (k == -1 && i >= 0) {
00921
00922 ast_str_append(&out, 0, "%*s", longest, ast_getformatname(&f_list[i].format));
00923 } else if (x >= 0 && y >= 0) {
00924
00925 ast_str_append(&out, 0, "%*s", curlen + 1, "-");
00926 } else {
00927
00928 ast_str_append(&out, 0, "%*s", longest, "");
00929 }
00930 }
00931 ast_str_append(&out, 0, "\n");
00932 ast_cli(a->fd, "%s", ast_str_buffer(out));
00933 }
00934 ast_free(out);
00935 AST_RWLIST_UNLOCK(&translators);
00936 ast_format_list_destroy(f_list);
00937 return CLI_SUCCESS;
00938 }
00939
00940 static char *handle_show_translation_path(struct ast_cli_args *a)
00941 {
00942 struct ast_format input_src_format;
00943 size_t len = 0;
00944 int i;
00945 const struct ast_format_list *format_list = ast_format_list_get(&len);
00946 struct ast_str *str = ast_str_alloca(1024);
00947 struct ast_translator *step;
00948 char tmp[256];
00949
00950 ast_format_clear(&input_src_format);
00951 for (i = 0; i < len; i++) {
00952 if (AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) {
00953 continue;
00954 }
00955 if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) {
00956 ast_format_copy(&input_src_format, &format_list[i].format);
00957 }
00958 }
00959
00960 if (!input_src_format.id) {
00961 ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]);
00962 ast_format_list_destroy(format_list);
00963 return CLI_FAILURE;
00964 }
00965
00966 AST_RWLIST_RDLOCK(&translators);
00967 ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(&input_src_format));
00968 for (i = 0; i < len; i++) {
00969 int src;
00970 int dst;
00971 if ((AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) || (format_list[i].format.id == input_src_format.id)) {
00972 continue;
00973 }
00974 dst = format2index(format_list[i].format.id);
00975 src = format2index(input_src_format.id);
00976 ast_str_reset(str);
00977 if ((len >= cur_max_index) && (src != -1) && (dst != -1) && matrix_get(src, dst)->step) {
00978 ast_str_append(&str, 0, "%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), matrix_get(src, dst)->step->src_format.id));
00979 while (src != dst) {
00980 step = matrix_get(src, dst)->step;
00981 if (!step) {
00982 ast_str_reset(str);
00983 break;
00984 }
00985 ast_str_append(&str, 0, "->%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), step->dst_format.id));
00986 src = step->dst_fmt_index;
00987 }
00988 }
00989
00990 if (ast_strlen_zero(ast_str_buffer(str))) {
00991 ast_str_set(&str, 0, "No Translation Path");
00992 }
00993 ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str));
00994 }
00995 AST_RWLIST_UNLOCK(&translators);
00996
00997 ast_format_list_destroy(format_list);
00998 return CLI_SUCCESS;
00999 }
01000
01001 static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01002 {
01003 static const char * const option[] = { "recalc", "paths", NULL };
01004
01005 switch (cmd) {
01006 case CLI_INIT:
01007 e->command = "core show translation";
01008 e->usage =
01009 "Usage: 'core show translation' can be used in two ways.\n"
01010 " 1. 'core show translation [recalc [<recalc seconds>]]\n"
01011 " Displays known codec translators and the cost associated\n"
01012 " with each conversion. If the argument 'recalc' is supplied along\n"
01013 " with optional number of seconds to test a new test will be performed\n"
01014 " as the chart is being displayed.\n"
01015 " 2. 'core show translation paths [codec]'\n"
01016 " This will display all the translation paths associated with a codec\n";
01017 return NULL;
01018 case CLI_GENERATE:
01019 if (a->pos == 3) {
01020 return ast_cli_complete(a->word, option, a->n);
01021 }
01022 if (a->pos == 4 && !strcasecmp(a->argv[3], option[1])) {
01023 return complete_trans_path_choice(a->line, a->word, a->pos, a->n);
01024 }
01025 return NULL;
01026 }
01027
01028 if (a->argc > 5)
01029 return CLI_SHOWUSAGE;
01030
01031 if (a->argv[3] && !strcasecmp(a->argv[3], option[1]) && a->argc == 5) {
01032 return handle_show_translation_path(a);
01033 } else if (a->argv[3] && !strcasecmp(a->argv[3], option[0])) {
01034 handle_cli_recalc(a);
01035 } else if (a->argc > 3) {
01036 return CLI_SHOWUSAGE;
01037 }
01038
01039 return handle_show_translation_table(a);
01040 }
01041
01042 static struct ast_cli_entry cli_translate[] = {
01043 AST_CLI_DEFINE(handle_cli_core_show_translation, "Display translation matrix")
01044 };
01045
01046
01047 int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
01048 {
01049 struct ast_translator *u;
01050 char tmp[80];
01051
01052 if (add_format2index(t->src_format.id) || add_format2index(t->dst_format.id)) {
01053 if (matrix_resize(0)) {
01054 ast_log(LOG_WARNING, "Translator matrix can not represent any more translators. Out of resources.\n");
01055 return -1;
01056 }
01057 add_format2index(t->src_format.id);
01058 add_format2index(t->dst_format.id);
01059 }
01060
01061 if (!mod) {
01062 ast_log(LOG_WARNING, "Missing module pointer, you need to supply one\n");
01063 return -1;
01064 }
01065
01066 if (!t->buf_size) {
01067 ast_log(LOG_WARNING, "empty buf size, you need to supply one\n");
01068 return -1;
01069 }
01070 if (!t->table_cost && !(t->table_cost = generate_table_cost(&t->src_format, &t->dst_format))) {
01071 ast_log(LOG_WARNING, "Table cost could not be generated for %s, "
01072 "Please set table_cost variable on translator.\n", t->name);
01073 return -1;
01074 }
01075
01076 t->module = mod;
01077 t->src_fmt_index = format2index(t->src_format.id);
01078 t->dst_fmt_index = format2index(t->dst_format.id);
01079 t->active = 1;
01080
01081 if (t->src_fmt_index == -1 || t->dst_fmt_index == -1) {
01082 ast_log(LOG_WARNING, "Invalid translator path: (%s codec is not valid)\n", t->src_fmt_index == -1 ? "starting" : "ending");
01083 return -1;
01084 }
01085 if (t->src_fmt_index >= cur_max_index) {
01086 ast_log(LOG_WARNING, "Source format %s is larger than cur_max_index\n", ast_getformatname(&t->src_format));
01087 return -1;
01088 }
01089
01090 if (t->dst_fmt_index >= cur_max_index) {
01091 ast_log(LOG_WARNING, "Destination format %s is larger than cur_max_index\n", ast_getformatname(&t->dst_format));
01092 return -1;
01093 }
01094
01095 if (t->buf_size) {
01096
01097
01098
01099
01100 struct _test_align { void *a, *b; } p;
01101 int align = (char *)&p.b - (char *)&p.a;
01102
01103 t->buf_size = ((t->buf_size + align - 1) / align) * align;
01104 }
01105
01106 if (t->frameout == NULL) {
01107 t->frameout = default_frameout;
01108 }
01109
01110 generate_computational_cost(t, 1);
01111
01112 ast_verb(2, "Registered translator '%s' from format %s to %s, table cost, %d, computational cost %d\n",
01113 term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
01114 ast_getformatname(&t->src_format), ast_getformatname(&t->dst_format), t->table_cost, t->comp_cost);
01115
01116 AST_RWLIST_WRLOCK(&translators);
01117
01118
01119
01120 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
01121 if ((u->src_fmt_index == t->src_fmt_index) &&
01122 (u->dst_fmt_index == t->dst_fmt_index) &&
01123 (u->comp_cost > t->comp_cost)) {
01124 AST_RWLIST_INSERT_BEFORE_CURRENT(t, list);
01125 t = NULL;
01126 break;
01127 }
01128 }
01129 AST_RWLIST_TRAVERSE_SAFE_END;
01130
01131
01132
01133 if (t) {
01134 AST_RWLIST_INSERT_HEAD(&translators, t, list);
01135 }
01136
01137 matrix_rebuild(0);
01138
01139 AST_RWLIST_UNLOCK(&translators);
01140
01141 return 0;
01142 }
01143
01144
01145 int ast_unregister_translator(struct ast_translator *t)
01146 {
01147 char tmp[80];
01148 struct ast_translator *u;
01149 int found = 0;
01150
01151 AST_RWLIST_WRLOCK(&translators);
01152 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
01153 if (u == t) {
01154 AST_RWLIST_REMOVE_CURRENT(list);
01155 ast_verb(2, "Unregistered translator '%s' from format %s to %s\n",
01156 term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
01157 ast_getformatname(&t->src_format),
01158 ast_getformatname(&t->dst_format));
01159 found = 1;
01160 break;
01161 }
01162 }
01163 AST_RWLIST_TRAVERSE_SAFE_END;
01164
01165 if (found) {
01166 matrix_rebuild(0);
01167 }
01168
01169 AST_RWLIST_UNLOCK(&translators);
01170
01171 return (u ? 0 : -1);
01172 }
01173
01174 void ast_translator_activate(struct ast_translator *t)
01175 {
01176 AST_RWLIST_WRLOCK(&translators);
01177 t->active = 1;
01178 matrix_rebuild(0);
01179 AST_RWLIST_UNLOCK(&translators);
01180 }
01181
01182 void ast_translator_deactivate(struct ast_translator *t)
01183 {
01184 AST_RWLIST_WRLOCK(&translators);
01185 t->active = 0;
01186 matrix_rebuild(0);
01187 AST_RWLIST_UNLOCK(&translators);
01188 }
01189
01190
01191 int ast_translator_best_choice(struct ast_format_cap *dst_cap,
01192 struct ast_format_cap *src_cap,
01193 struct ast_format *dst_fmt_out,
01194 struct ast_format *src_fmt_out)
01195 {
01196 unsigned int besttablecost = INT_MAX;
01197 unsigned int beststeps = INT_MAX;
01198 struct ast_format best;
01199 struct ast_format bestdst;
01200 struct ast_format_cap *joint_cap = ast_format_cap_joint(dst_cap, src_cap);
01201 ast_format_clear(&best);
01202 ast_format_clear(&bestdst);
01203
01204 if (joint_cap) {
01205 struct ast_format tmp_fmt;
01206 ast_format_cap_iter_start(joint_cap);
01207 while (!ast_format_cap_iter_next(joint_cap, &tmp_fmt)) {
01208
01209 if (!best.id) {
01210 ast_format_copy(&best, &tmp_fmt);
01211 continue;
01212 }
01213
01214 if (ast_format_rate(&best) < ast_format_rate(&tmp_fmt)) {
01215 ast_format_copy(&best, &tmp_fmt);
01216 continue;
01217 }
01218
01219 }
01220 ast_format_cap_iter_end(joint_cap);
01221
01222
01223 ast_format_copy(dst_fmt_out, &best);
01224 ast_format_copy(src_fmt_out, &best);
01225 ast_format_cap_destroy(joint_cap);
01226 return 0;
01227 } else {
01228 struct ast_format cur_dst;
01229 struct ast_format cur_src;
01230 AST_RWLIST_RDLOCK(&translators);
01231
01232 ast_format_cap_iter_start(dst_cap);
01233 while (!ast_format_cap_iter_next(dst_cap, &cur_dst)) {
01234 ast_format_cap_iter_start(src_cap);
01235 while (!ast_format_cap_iter_next(src_cap, &cur_src)) {
01236 int x = format2index(cur_src.id);
01237 int y = format2index(cur_dst.id);
01238 if (x < 0 || y < 0) {
01239 continue;
01240 }
01241 if (!matrix_get(x, y) || !(matrix_get(x, y)->step)) {
01242 continue;
01243 }
01244 if (((matrix_get(x, y)->table_cost < besttablecost) || (matrix_get(x, y)->multistep < beststeps))) {
01245
01246 ast_format_copy(&best, &cur_src);
01247 ast_format_copy(&bestdst, &cur_dst);
01248 besttablecost = matrix_get(x, y)->table_cost;
01249 beststeps = matrix_get(x, y)->multistep;
01250 }
01251 }
01252 ast_format_cap_iter_end(src_cap);
01253 }
01254
01255 ast_format_cap_iter_end(dst_cap);
01256 AST_RWLIST_UNLOCK(&translators);
01257 if (best.id) {
01258 ast_format_copy(dst_fmt_out, &bestdst);
01259 ast_format_copy(src_fmt_out, &best);
01260 return 0;
01261 }
01262 return -1;
01263 }
01264 }
01265
01266 unsigned int ast_translate_path_steps(struct ast_format *dst_format, struct ast_format *src_format)
01267 {
01268 unsigned int res = -1;
01269 int src, dest;
01270
01271 src = format2index(src_format->id);
01272 dest = format2index(dst_format->id);
01273
01274 if (src == -1 || dest == -1) {
01275 ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src == -1 ? "starting" : "ending");
01276 return -1;
01277 }
01278 AST_RWLIST_RDLOCK(&translators);
01279
01280 if (matrix_get(src, dest)->step) {
01281 res = matrix_get(src, dest)->multistep + 1;
01282 }
01283
01284 AST_RWLIST_UNLOCK(&translators);
01285
01286 return res;
01287 }
01288
01289 void ast_translate_available_formats(struct ast_format_cap *dest, struct ast_format_cap *src, struct ast_format_cap *result)
01290 {
01291 struct ast_format tmp_fmt;
01292 struct ast_format cur_dest, cur_src;
01293 int src_audio = 0;
01294 int src_video = 0;
01295 int index;
01296
01297 ast_format_cap_iter_start(dest);
01298 while (!ast_format_cap_iter_next(dest, &cur_dest)) {
01299
01300 if (ast_format_cap_get_compatible_format(src, &cur_dest, &tmp_fmt)) {
01301 ast_format_cap_add(result, &tmp_fmt);
01302 } else {
01303
01304 ast_format_cap_add(result, &cur_dest);
01305 }
01306 }
01307 ast_format_cap_iter_end(dest);
01308
01309
01310
01311 if (!src) {
01312 return;
01313 }
01314
01315 ast_format_cap_iter_start(src);
01316 while (!ast_format_cap_iter_next(src, &cur_src)) {
01317
01318 if (AST_FORMAT_GET_TYPE(cur_src.id) == AST_FORMAT_TYPE_AUDIO) {
01319 src_audio = format2index(cur_src.id);
01320 }
01321
01322
01323 if (AST_FORMAT_GET_TYPE(cur_src.id) == AST_FORMAT_TYPE_VIDEO) {
01324 src_video = format2index(cur_src.id);
01325 }
01326
01327 AST_RWLIST_RDLOCK(&translators);
01328
01329
01330
01331
01332
01333 for (index = 0; (src_audio >= 0) && index < cur_max_index; index++) {
01334 ast_format_set(&tmp_fmt, index2format(index), 0);
01335
01336 if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_AUDIO) {
01337 continue;
01338 }
01339
01340
01341 if (!ast_format_cap_iscompatible(dest, &tmp_fmt)) {
01342 continue;
01343 }
01344
01345
01346
01347 if (ast_format_cap_iscompatible(src, &tmp_fmt)) {
01348 continue;
01349 }
01350
01351
01352
01353 if (!matrix_get(src_audio, index)->step) {
01354 ast_format_cap_remove_byid(result, tmp_fmt.id);
01355 continue;
01356 }
01357
01358
01359 if (!matrix_get(index, src_audio)->step) {
01360 ast_format_cap_remove_byid(result, tmp_fmt.id);
01361 }
01362 }
01363
01364
01365
01366
01367
01368 for (index = 0; (src_video >= 0) && index < cur_max_index; index++) {
01369 ast_format_set(&tmp_fmt, index2format(index), 0);
01370 if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_VIDEO) {
01371 continue;
01372 }
01373
01374
01375 if (!ast_format_cap_iscompatible(dest, &tmp_fmt)) {
01376 continue;
01377 }
01378
01379
01380
01381 if (ast_format_cap_iscompatible(src, &tmp_fmt)) {
01382 continue;
01383 }
01384
01385
01386
01387 if (!matrix_get(src_video, index)->step) {
01388 ast_format_cap_remove_byid(result, tmp_fmt.id);
01389 continue;
01390 }
01391
01392
01393 if (!matrix_get(index, src_video)->step) {
01394 ast_format_cap_remove_byid(result, tmp_fmt.id);
01395 }
01396 }
01397 AST_RWLIST_UNLOCK(&translators);
01398 }
01399 ast_format_cap_iter_end(src);
01400 }
01401
01402 static void translate_shutdown(void)
01403 {
01404 int x;
01405 ast_cli_unregister_multiple(cli_translate, ARRAY_LEN(cli_translate));
01406
01407 ast_rwlock_wrlock(&tablelock);
01408 for (x = 0; x < index_size; x++) {
01409 ast_free(__matrix[x]);
01410 }
01411 ast_free(__matrix);
01412 ast_free(__indextable);
01413 ast_rwlock_unlock(&tablelock);
01414 ast_rwlock_destroy(&tablelock);
01415 }
01416
01417 int ast_translate_init(void)
01418 {
01419 int res = 0;
01420 ast_rwlock_init(&tablelock);
01421 res = matrix_resize(1);
01422 res |= ast_cli_register_multiple(cli_translate, ARRAY_LEN(cli_translate));
01423 ast_register_atexit(translate_shutdown);
01424 return res;
01425 }