00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <asterisk/lock.h>
00015 #include <asterisk/channel.h>
00016 #include <asterisk/channel_pvt.h>
00017 #include <asterisk/logger.h>
00018 #include <asterisk/translate.h>
00019 #include <asterisk/options.h>
00020 #include <asterisk/frame.h>
00021 #include <asterisk/sched.h>
00022 #include <asterisk/cli.h>
00023 #include <asterisk/term.h>
00024 #include <sys/socket.h>
00025 #include <sys/time.h>
00026 #include <unistd.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <stdio.h>
00030
00031 #define MAX_RECALC 200
00032
00033
00034
00035
00036 AST_MUTEX_DEFINE_STATIC(list_lock);
00037 static struct ast_translator *list = NULL;
00038
00039 struct ast_translator_dir {
00040 struct ast_translator *step;
00041 int cost;
00042 };
00043
00044 struct ast_frame_delivery {
00045 struct ast_frame *f;
00046 struct ast_channel *chan;
00047 int fd;
00048 struct translator_pvt *owner;
00049 struct ast_frame_delivery *prev;
00050 struct ast_frame_delivery *next;
00051 };
00052
00053 static struct ast_translator_dir tr_matrix[MAX_FORMAT][MAX_FORMAT];
00054
00055 struct ast_trans_pvt {
00056 struct ast_translator *step;
00057 struct ast_translator_pvt *state;
00058 struct ast_trans_pvt *next;
00059 struct timeval nextin;
00060 struct timeval nextout;
00061 };
00062
00063
00064 static int powerof(int d)
00065 {
00066 int x;
00067 for (x = 0; x < 32; x++)
00068 if ((1 << x) & d)
00069 return x;
00070 ast_log(LOG_WARNING, "Powerof %d: No power??\n", d);
00071 return -1;
00072 }
00073
00074 void ast_translator_free_path(struct ast_trans_pvt *p)
00075 {
00076 struct ast_trans_pvt *pl, *pn;
00077 pn = p;
00078 while(pn) {
00079 pl = pn;
00080 pn = pn->next;
00081 if (pl->state && pl->step->destroy)
00082 pl->step->destroy(pl->state);
00083 free(pl);
00084 }
00085 }
00086
00087 struct ast_trans_pvt *ast_translator_build_path(int dest, int source)
00088 {
00089 struct ast_trans_pvt *tmpr = NULL, *tmp = NULL;
00090
00091
00092 source = powerof(source);
00093 dest = powerof(dest);
00094 while(source != dest) {
00095 if (tr_matrix[source][dest].step) {
00096 if (tmp) {
00097 tmp->next = malloc(sizeof(struct ast_trans_pvt));
00098 tmp = tmp->next;
00099 } else
00100 tmp = malloc(sizeof(struct ast_trans_pvt));
00101
00102
00103 if (tmp) {
00104 tmp->next = NULL;
00105 tmp->nextin.tv_sec = 0;
00106 tmp->nextin.tv_usec = 0;
00107 tmp->nextout.tv_sec = 0;
00108 tmp->nextout.tv_usec = 0;
00109 tmp->step = tr_matrix[source][dest].step;
00110 tmp->state = tmp->step->newpvt();
00111 if (!tmp->state) {
00112 ast_log(LOG_WARNING, "Failed to build translator step from %d to %d\n", source, dest);
00113 free(tmp);
00114 tmp = NULL;
00115 return NULL;
00116 }
00117
00118 if (!tmpr)
00119 tmpr = tmp;
00120
00121 source = tmp->step->dstfmt;
00122 } else {
00123
00124 ast_log(LOG_WARNING, "Out of memory\n");
00125 return NULL;
00126 }
00127 } else {
00128
00129 ast_log(LOG_WARNING, "No translator path from %s to %s\n",
00130 ast_getformatname(source), ast_getformatname(dest));
00131 return NULL;
00132 }
00133 }
00134 return tmpr;
00135 }
00136
00137 struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume)
00138 {
00139 struct ast_trans_pvt *p;
00140 struct ast_frame *out;
00141 struct timeval delivery;
00142 p = path;
00143
00144 p->step->framein(p->state, f);
00145 if (f->delivery.tv_sec || f->delivery.tv_usec) {
00146 if (path->nextin.tv_sec || path->nextin.tv_usec) {
00147
00148 if ((path->nextin.tv_sec != f->delivery.tv_sec) ||
00149 (path->nextin.tv_usec != f->delivery.tv_usec)) {
00150
00151
00152
00153 long sdiff;
00154 long udiff;
00155 sdiff = f->delivery.tv_sec - path->nextin.tv_sec;
00156 udiff = f->delivery.tv_usec - path->nextin.tv_usec;
00157 path->nextin.tv_sec = f->delivery.tv_sec;
00158 path->nextin.tv_usec = f->delivery.tv_usec;
00159 path->nextout.tv_sec += sdiff;
00160 path->nextout.tv_usec += udiff;
00161 if (path->nextout.tv_usec < 0) {
00162 path->nextout.tv_usec += 1000000;
00163 path->nextout.tv_sec--;
00164 } else if (path->nextout.tv_usec >= 1000000) {
00165 path->nextout.tv_usec -= 1000000;
00166 path->nextout.tv_sec++;
00167 }
00168 }
00169 } else {
00170
00171 path->nextin.tv_sec = f->delivery.tv_sec;
00172 path->nextin.tv_usec = f->delivery.tv_usec;
00173 path->nextout.tv_sec = f->delivery.tv_sec;
00174 path->nextout.tv_usec = f->delivery.tv_usec;
00175 }
00176
00177 path->nextin.tv_sec += (f->samples / 8000);
00178 path->nextin.tv_usec += ((f->samples % 8000) * 125);
00179 if (path->nextin.tv_usec >= 1000000) {
00180 path->nextin.tv_usec -= 1000000;
00181 path->nextin.tv_sec++;
00182 }
00183 }
00184 delivery.tv_sec = f->delivery.tv_sec;
00185 delivery.tv_usec = f->delivery.tv_usec;
00186 if (consume)
00187 ast_frfree(f);
00188 while(p) {
00189 out = p->step->frameout(p->state);
00190
00191 if (!out)
00192 return NULL;
00193
00194
00195 if (p->next)
00196 p->next->step->framein(p->next->state, out);
00197 else {
00198 if (delivery.tv_sec || delivery.tv_usec) {
00199
00200 out->delivery.tv_sec = path->nextout.tv_sec;
00201 out->delivery.tv_usec = path->nextout.tv_usec;
00202
00203
00204
00205 path->nextout.tv_sec += (out->samples / 8000);
00206 path->nextout.tv_usec += ((out->samples % 8000) * 125);
00207 if (path->nextout.tv_usec >= 1000000) {
00208 path->nextout.tv_sec++;
00209 path->nextout.tv_usec -= 1000000;
00210 }
00211 } else {
00212 out->delivery.tv_sec = 0;
00213 out->delivery.tv_usec = 0;
00214 }
00215 return out;
00216 }
00217 p = p->next;
00218 }
00219 ast_log(LOG_WARNING, "I should never get here...\n");
00220 return NULL;
00221 }
00222
00223
00224 static void calc_cost(struct ast_translator *t,int samples)
00225 {
00226 int sofar=0;
00227 struct ast_translator_pvt *pvt;
00228 struct ast_frame *f, *out;
00229 struct timeval start, finish;
00230 int cost;
00231 if(!samples)
00232 samples = 1;
00233
00234
00235 if (!t->sample) {
00236 ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
00237 t->cost = 99999;
00238 return;
00239 }
00240 pvt = t->newpvt();
00241 if (!pvt) {
00242 ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
00243 t->cost = 99999;
00244 return;
00245 }
00246 gettimeofday(&start, NULL);
00247
00248 while(sofar < samples * 8000) {
00249 f = t->sample();
00250 if (!f) {
00251 ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
00252 t->destroy(pvt);
00253 t->cost = 99999;
00254 return;
00255 }
00256 t->framein(pvt, f);
00257 ast_frfree(f);
00258 while((out = t->frameout(pvt))) {
00259 sofar += out->samples;
00260 ast_frfree(out);
00261 }
00262 }
00263 gettimeofday(&finish, NULL);
00264 t->destroy(pvt);
00265 cost = (finish.tv_sec - start.tv_sec) * 1000 + (finish.tv_usec - start.tv_usec) / 1000;
00266 t->cost = cost / samples;
00267 if (!t->cost)
00268 t->cost = 1;
00269 }
00270
00271 static void rebuild_matrix(int samples)
00272 {
00273 struct ast_translator *t;
00274 int changed;
00275 int x,y,z;
00276 if (option_debug)
00277 ast_log(LOG_DEBUG, "Reseting translation matrix\n");
00278
00279 bzero(tr_matrix, sizeof(tr_matrix));
00280 t = list;
00281 while(t) {
00282 if(samples)
00283 calc_cost(t,samples);
00284
00285 if (!tr_matrix[t->srcfmt][t->dstfmt].step ||
00286 tr_matrix[t->srcfmt][t->dstfmt].cost > t->cost) {
00287 tr_matrix[t->srcfmt][t->dstfmt].step = t;
00288 tr_matrix[t->srcfmt][t->dstfmt].cost = t->cost;
00289 }
00290 t = t->next;
00291 }
00292 do {
00293 changed = 0;
00294
00295 for (x=0; x< MAX_FORMAT; x++)
00296 for (y=0; y < MAX_FORMAT; y++)
00297 if (x != y)
00298 for (z=0; z < MAX_FORMAT; z++)
00299 if ((x!=z) && (y!=z))
00300 if (tr_matrix[x][y].step &&
00301 tr_matrix[y][z].step &&
00302 (!tr_matrix[x][z].step ||
00303 (tr_matrix[x][y].cost +
00304 tr_matrix[y][z].cost <
00305 tr_matrix[x][z].cost)
00306 )) {
00307
00308
00309
00310
00311 tr_matrix[x][z].step = tr_matrix[x][y].step;
00312 tr_matrix[x][z].cost = tr_matrix[x][y].cost +
00313 tr_matrix[y][z].cost;
00314 if (option_debug)
00315 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);
00316 changed++;
00317 }
00318
00319 } while (changed);
00320 }
00321
00322
00323
00324
00325
00326 static int show_translation(int fd, int argc, char *argv[])
00327 {
00328 #define SHOW_TRANS 11
00329 int x, y, z;
00330 char line[80];
00331 if (argc > 4)
00332 return RESULT_SHOWUSAGE;
00333
00334 if (argv[2] && !strcasecmp(argv[2],"recalc")) {
00335 z = argv[3] ? atoi(argv[3]) : 1;
00336
00337 if (z <= 0) {
00338 ast_cli(fd," C'mon let's be serious here... defaulting to 1.\n");
00339 z = 1;
00340 }
00341
00342 if (z > MAX_RECALC) {
00343 ast_cli(fd," Maximum limit of recalc exceeded by %d, truncating value to %d\n",z-MAX_RECALC,MAX_RECALC);
00344 z = MAX_RECALC;
00345 }
00346 ast_cli(fd," Recalculating Codec Translation (number of sample seconds: %d)\n\n",z);
00347 rebuild_matrix(z);
00348 }
00349
00350 ast_cli(fd, " Translation times between formats (in milliseconds)\n");
00351 ast_cli(fd, " Source Format (Rows) Destination Format(Columns)\n\n");
00352 ast_mutex_lock(&list_lock);
00353 for (x=-1;x<SHOW_TRANS; x++) {
00354
00355 line[0] = ' ';
00356 line[1] = '\0';
00357 for (y=-1;y<SHOW_TRANS;y++) {
00358 if (x >= 0 && y >= 0 && tr_matrix[x][y].step)
00359 snprintf(line + strlen(line), sizeof(line) - strlen(line), " %5d", tr_matrix[x][y].cost >= 99999 ? tr_matrix[x][y].cost-99999 : tr_matrix[x][y].cost);
00360 else
00361 if (((x == -1 && y >= 0) || (y == -1 && x >= 0))) {
00362 snprintf(line + strlen(line), sizeof(line) - strlen(line),
00363 " %5s", ast_getformatname(1<<(x+y+1)) );
00364 } else if (x != -1 && y != -1) {
00365 snprintf(line + strlen(line), sizeof(line) - strlen(line), " -");
00366 } else {
00367 snprintf(line + strlen(line), sizeof(line) - strlen(line), " ");
00368 }
00369 }
00370 snprintf(line + strlen(line), sizeof(line) - strlen(line), "\n");
00371 ast_cli(fd, line);
00372 }
00373 ast_mutex_unlock(&list_lock);
00374 return RESULT_SUCCESS;
00375 }
00376
00377 static int added_cli = 0;
00378
00379 static char show_trans_usage[] =
00380 "Usage: show translation [recalc] [<recalc seconds>]\n"
00381 " Displays known codec translators and the cost associated\n"
00382 "with each conversion. if the arguement 'recalc' is supplied along\n"
00383 "with optional number of seconds to test a new test will be performed\n"
00384 "as the chart is being displayed.\n";
00385
00386 static struct ast_cli_entry show_trans =
00387 { { "show", "translation", NULL }, show_translation, "Display translation matrix", show_trans_usage };
00388
00389 int ast_register_translator(struct ast_translator *t)
00390 {
00391 char tmp[80];
00392 t->srcfmt = powerof(t->srcfmt);
00393 t->dstfmt = powerof(t->dstfmt);
00394 if ((t->srcfmt >= MAX_FORMAT) || (t->dstfmt >= MAX_FORMAT)) {
00395 ast_log(LOG_WARNING, "Format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt));
00396 return -1;
00397 }
00398 calc_cost(t,1);
00399 if (option_verbose > 1)
00400 ast_verbose(VERBOSE_PREFIX_2 "Registered translator '%s' from format %s to %s, cost %d\n", term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), ast_getformatname(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt), t->cost);
00401 ast_mutex_lock(&list_lock);
00402 if (!added_cli) {
00403 ast_cli_register(&show_trans);
00404 added_cli++;
00405 }
00406 t->next = list;
00407 list = t;
00408 rebuild_matrix(0);
00409 ast_mutex_unlock(&list_lock);
00410 return 0;
00411 }
00412
00413 int ast_unregister_translator(struct ast_translator *t)
00414 {
00415 char tmp[80];
00416 struct ast_translator *u, *ul = NULL;
00417 ast_mutex_lock(&list_lock);
00418 u = list;
00419 while(u) {
00420 if (u == t) {
00421 if (ul)
00422 ul->next = u->next;
00423 else
00424 list = u->next;
00425 if (option_verbose > 1)
00426 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));
00427 break;
00428 }
00429 ul = u;
00430 u = u->next;
00431 }
00432 rebuild_matrix(0);
00433 ast_mutex_unlock(&list_lock);
00434 return (u ? 0 : -1);
00435 }
00436
00437 int ast_translator_best_choice(int *dst, int *srcs)
00438 {
00439
00440 int x,y;
00441 int best=-1;
00442 int bestdst=0;
00443 int cur = 1;
00444 int besttime=999999999;
00445 ast_mutex_lock(&list_lock);
00446 for (y=0;y<MAX_FORMAT;y++) {
00447 if ((cur & *dst) && (cur & *srcs)) {
00448
00449 besttime=0;
00450 bestdst = cur;
00451 best = cur;
00452 break;
00453 }
00454 if (cur & *dst)
00455 for (x=0;x<MAX_FORMAT;x++) {
00456 if (tr_matrix[x][y].step &&
00457 (tr_matrix[x][y].cost < besttime) &&
00458 (*srcs & (1 << x)))
00459 {
00460 best = 1 << x;
00461 bestdst = cur;
00462 besttime = tr_matrix[x][y].cost;
00463 }
00464 }
00465 cur = cur << 1;
00466 }
00467 if (best > -1) {
00468 *srcs = best;
00469 *dst = bestdst;
00470 best = 0;
00471 }
00472 ast_mutex_unlock(&list_lock);
00473 return best;
00474 }