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 <pthread.h>
00029
#include <string.h>
00030
#include <stdio.h>
00031
00032 #define MAX_RECALC 200
00033
00034
00035
00036
00037
AST_MUTEX_DEFINE_STATIC(list_lock);
00038
static struct ast_translator *list = NULL;
00039
00040 struct ast_translator_dir {
00041 struct ast_translator *
step;
00042 int cost;
00043 };
00044
00045 struct ast_frame_delivery {
00046 struct ast_frame *
f;
00047 struct ast_channel *
chan;
00048 int fd;
00049 struct translator_pvt *
owner;
00050 struct ast_frame_delivery *
prev;
00051 struct ast_frame_delivery *
next;
00052 };
00053
00054
static struct ast_translator_dir tr_matrix[
MAX_FORMAT][
MAX_FORMAT];
00055
00056 struct ast_trans_pvt {
00057 struct ast_translator *
step;
00058 struct ast_translator_pvt *
state;
00059 struct ast_trans_pvt *
next;
00060 struct timeval nextin;
00061 struct timeval nextout;
00062 };
00063
00064
00065
static int powerof(
int d)
00066 {
00067
int x;
00068
for (x = 0; x < 32; x++)
00069
if ((1 << x) & d)
00070
return x;
00071
ast_log(LOG_WARNING,
"Powerof %d: No power??\n", d);
00072
return -1;
00073 }
00074
00075 void ast_translator_free_path(
struct ast_trans_pvt *p)
00076 {
00077
struct ast_trans_pvt *pl, *pn;
00078 pn = p;
00079
while(pn) {
00080 pl = pn;
00081 pn = pn->
next;
00082
if (pl->state && pl->step->destroy)
00083 pl->
step->
destroy(pl->state);
00084
free(pl);
00085 }
00086 }
00087
00088 struct ast_trans_pvt *
ast_translator_build_path(
int dest,
int source)
00089 {
00090
struct ast_trans_pvt *tmpr = NULL, *tmp = NULL;
00091
00092
00093 source = powerof(source);
00094 dest = powerof(dest);
00095
while(source != dest) {
00096
if (tr_matrix[source][dest].
step) {
00097
if (tmp) {
00098 tmp->next =
malloc(
sizeof(
struct ast_trans_pvt));
00099 tmp = tmp->next;
00100 }
else
00101 tmp =
malloc(
sizeof(
struct ast_trans_pvt));
00102
00103
00104
if (tmp) {
00105 tmp->next = NULL;
00106 tmp->nextin.tv_sec = 0;
00107 tmp->nextin.tv_usec = 0;
00108 tmp->nextout.tv_sec = 0;
00109 tmp->nextout.tv_usec = 0;
00110 tmp->step = tr_matrix[source][dest].
step;
00111 tmp->state = tmp->step->
new();
00112
if (!tmp->state) {
00113
ast_log(
LOG_WARNING,
"Failed to build translator step from %d to %d\n", source, dest);
00114
free(tmp);
00115 tmp = NULL;
00116
return NULL;
00117 }
00118
00119
if (!tmpr)
00120 tmpr = tmp;
00121
00122 source = tmp->step->dstfmt;
00123 }
else {
00124
00125
ast_log(
LOG_WARNING,
"Out of memory\n");
00126
return NULL;
00127 }
00128 }
else {
00129
00130
ast_log(
LOG_WARNING,
"No translator path from %s to %s\n",
00131
ast_getformatname(source),
ast_getformatname(dest));
00132
return NULL;
00133 }
00134 }
00135
return tmpr;
00136 }
00137
00138 struct ast_frame *
ast_translate(
struct ast_trans_pvt *path,
struct ast_frame *f,
int consume)
00139 {
00140
struct ast_trans_pvt *p;
00141
struct ast_frame *out;
00142
struct timeval delivery;
00143 p = path;
00144
00145 p->
step->
framein(p->state, f);
00146
if (f->
delivery.tv_sec || f->
delivery.tv_usec) {
00147
if (path->nextin.tv_sec || path->nextin.tv_usec) {
00148
00149
if ((path->nextin.tv_sec != f->
delivery.tv_sec) ||
00150 (path->nextin.tv_usec != f->
delivery.tv_usec)) {
00151
00152
00153
00154
long sdiff;
00155
long udiff;
00156 sdiff = f->
delivery.tv_sec - path->nextin.tv_sec;
00157 udiff = f->
delivery.tv_usec - path->nextin.tv_usec;
00158 path->nextin.tv_sec = f->
delivery.tv_sec;
00159 path->nextin.tv_usec = f->
delivery.tv_usec;
00160 path->nextout.tv_sec += sdiff;
00161 path->nextout.tv_usec += udiff;
00162
if (path->nextout.tv_usec < 0) {
00163 path->nextout.tv_usec += 1000000;
00164 path->nextout.tv_sec--;
00165 }
else if (path->nextout.tv_usec >= 1000000) {
00166 path->nextout.tv_usec -= 1000000;
00167 path->nextout.tv_sec++;
00168 }
00169 }
00170 }
else {
00171
00172 path->nextin.tv_sec = f->
delivery.tv_sec;
00173 path->nextin.tv_usec = f->
delivery.tv_usec;
00174 path->nextout.tv_sec = f->
delivery.tv_sec;
00175 path->nextout.tv_usec = f->
delivery.tv_usec;
00176 }
00177
00178 path->nextin.tv_sec += (f->
samples / 8000);
00179 path->nextin.tv_usec += ((f->
samples % 8000) * 125);
00180
if (path->nextin.tv_usec >= 1000000) {
00181 path->nextin.tv_usec -= 1000000;
00182 path->nextin.tv_sec++;
00183 }
00184 }
00185 delivery.tv_sec = f->
delivery.tv_sec;
00186 delivery.tv_usec = f->
delivery.tv_usec;
00187
if (consume)
00188
ast_frfree(f);
00189
while(p) {
00190 out = p->step->frameout(p->state);
00191
00192
if (!out)
00193
return NULL;
00194
00195
00196
if (p->next)
00197 p->next->step->framein(p->next->state, out);
00198
else {
00199
if (delivery.tv_sec || delivery.tv_usec) {
00200
00201 out->delivery.tv_sec = path->nextout.tv_sec;
00202 out->delivery.tv_usec = path->nextout.tv_usec;
00203
00204
00205
00206 path->nextout.tv_sec += (out->samples / 8000);
00207 path->nextout.tv_usec += ((out->samples % 8000) * 125);
00208
if (path->nextout.tv_usec >= 1000000) {
00209 path->nextout.tv_sec++;
00210 path->nextout.tv_usec -= 1000000;
00211 }
00212 }
else {
00213 out->delivery.tv_sec = 0;
00214 out->delivery.tv_usec = 0;
00215 }
00216
return out;
00217 }
00218 p = p->next;
00219 }
00220
ast_log(
LOG_WARNING,
"I should never get here...\n");
00221
return NULL;
00222 }
00223
00224
00225
static void calc_cost(
struct ast_translator *t,
int samples)
00226 {
00227
int sofar=0;
00228
struct ast_translator_pvt *pvt;
00229
struct ast_frame *f, *out;
00230
struct timeval start, finish;
00231
int cost;
00232
if(!samples)
00233 samples = 1;
00234
00235
00236
if (!t->
sample) {
00237
ast_log(LOG_WARNING,
"Translator '%s' does not produce sample frames.\n", t->
name);
00238 t->
cost = 99999;
00239
return;
00240 }
00241 pvt = t->
new();
00242
if (!pvt) {
00243
ast_log(LOG_WARNING,
"Translator '%s' appears to be broken and will probably fail.\n", t->
name);
00244 t->
cost = 99999;
00245
return;
00246 }
00247 gettimeofday(&start, NULL);
00248
00249
while(sofar < samples * 8000) {
00250 f = t->
sample();
00251
if (!f) {
00252
ast_log(LOG_WARNING,
"Translator '%s' failed to produce a sample frame.\n", t->
name);
00253 t->
destroy(pvt);
00254 t->
cost = 99999;
00255
return;
00256 }
00257 t->
framein(pvt, f);
00258
ast_frfree(f);
00259
while((out = t->
frameout(pvt))) {
00260 sofar += out->samples;
00261
ast_frfree(out);
00262 }
00263 }
00264 gettimeofday(&finish, NULL);
00265 t->
destroy(pvt);
00266 cost = (finish.tv_sec - start.tv_sec) * 1000 + (finish.tv_usec - start.tv_usec) / 1000;
00267 t->
cost = cost / samples;
00268
if (!t->
cost)
00269 t->
cost = 1;
00270 }
00271
00272
static void rebuild_matrix(
int samples)
00273 {
00274
struct ast_translator *t;
00275
int changed;
00276
int x,y,z;
00277
if (
option_debug)
00278
ast_log(LOG_DEBUG,
"Reseting translation matrix\n");
00279
00280 bzero(tr_matrix,
sizeof(tr_matrix));
00281 t = list;
00282
while(t) {
00283
if(samples)
00284 calc_cost(t,samples);
00285
00286
if (!tr_matrix[t->srcfmt][t->dstfmt].
step ||
00287 tr_matrix[t->srcfmt][t->dstfmt].
cost > t->cost) {
00288 tr_matrix[t->srcfmt][t->dstfmt].
step = t;
00289 tr_matrix[t->srcfmt][t->dstfmt].
cost = t->cost;
00290 }
00291 t = t->next;
00292 }
00293
do {
00294 changed = 0;
00295
00296
for (x=0; x<
MAX_FORMAT; x++)
00297
for (y=0; y <
MAX_FORMAT; y++)
00298
if (x != y)
00299
for (z=0; z <
MAX_FORMAT; z++)
00300
if ((x!=z) && (y!=z))
00301
if (tr_matrix[x][y].
step &&
00302 tr_matrix[y][z].
step &&
00303 (!tr_matrix[x][z].
step ||
00304 (tr_matrix[x][y].
cost +
00305 tr_matrix[y][z].
cost <
00306 tr_matrix[x][z].
cost)
00307 )) {
00308
00309
00310
00311
00312 tr_matrix[x][z].
step = tr_matrix[x][y].
step;
00313 tr_matrix[x][z].
cost = tr_matrix[x][y].
cost +
00314 tr_matrix[y][z].
cost;
00315
if (
option_debug)
00316
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);
00317 changed++;
00318 }
00319
00320 }
while (changed);
00321 }
00322
00323
00324
00325
00326
00327
static int show_translation(
int fd,
int argc,
char *argv[])
00328 {
00329
#define SHOW_TRANS 11
00330
int x,y,z;
00331
char line[80];
00332
if (argc > 4)
00333
return RESULT_SHOWUSAGE;
00334
00335
if(argv[2] && !strcasecmp(argv[2],
"recalc")) {
00336 z = argv[3] ? atoi(argv[3]) : 1;
00337
00338
if(z <= 0) {
00339
ast_cli(fd,
" C'mon let's be serious here... defaulting to 1.\n");
00340 z = 1;
00341 }
00342
00343
if(z >
MAX_RECALC) {
00344
ast_cli(fd,
" Maximum limit of recalc exceeded by %d, truncating value to %d\n",z-MAX_RECALC,MAX_RECALC);
00345 z =
MAX_RECALC;
00346 }
00347
ast_cli(fd,
" Recalculating Codec Translation (number of sample seconds: %d)\n\n",z);
00348 rebuild_matrix(z);
00349
00350 }
00351
00352
ast_cli(fd,
" Translation times between formats (in milliseconds)\n");
00353
ast_cli(fd,
" Source Format (Rows) Destination Format(Columns)\n\n");
00354
ast_mutex_lock(&list_lock);
00355
for (x=-1;x<
SHOW_TRANS; x++) {
00356 strcpy(line,
" ");
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 }