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