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