Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

translate.c

Go to the documentation of this file.
00001 /* 00002 * Asterisk -- A telephony toolkit for Linux. 00003 * 00004 * Translate via the use of pseudo channels 00005 * 00006 * Copyright (C) 1999, Mark Spencer 00007 * 00008 * Mark Spencer <markster@linux-support.net> 00009 * 00010 * This program is free software, distributed under the terms of 00011 * the GNU General Public License 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 /* max sample recalc */ 00033 00034 /* This could all be done more efficiently *IF* we chained packets together 00035 by default, but it would also complicate virtually every application. */ 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; /* Next step translator */ 00042 int cost; /* Complete cost to destination */ 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 /* One of the hardest parts: Build a set of translators based upon 00092 the given source and destination formats */ 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 /* Set the root, if it doesn't exist yet... */ 00119 if (!tmpr) 00120 tmpr = tmp; 00121 /* Keep going if this isn't the final destination */ 00122 source = tmp->step->dstfmt; 00123 } else { 00124 /* XXX This could leak XXX */ 00125 ast_log(LOG_WARNING, "Out of memory\n"); 00126 return NULL; 00127 } 00128 } else { 00129 /* We shouldn't have allocated any memory */ 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 /* Feed the first frame into the first translator */ 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 /* Make sure this is in line with what we were expecting */ 00149 if ((path->nextin.tv_sec != f->delivery.tv_sec) || 00150 (path->nextin.tv_usec != f->delivery.tv_usec)) { 00151 /* The time has changed between what we expected and this 00152 most recent time on the new packet. Adjust our output 00153 time appropriately */ 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 /* This is our first pass. Make sure the timing looks good */ 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 /* Predict next incoming sample */ 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 /* If we get nothing out, return NULL */ 00192 if (!out) 00193 return NULL; 00194 /* If there is a next state, feed it in there. If not, 00195 return this frame */ 00196 if (p->next) 00197 p->next->step->framein(p->next->state, out); 00198 else { 00199 if (delivery.tv_sec || delivery.tv_usec) { 00200 /* Use next predicted outgoing timestamp */ 00201 out->delivery.tv_sec = path->nextout.tv_sec; 00202 out->delivery.tv_usec = path->nextout.tv_usec; 00203 00204 /* Predict next outgoing timestamp from samples in this 00205 frame. */ 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 /* If they don't make samples, give them a terrible score */ 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 /* Call the encoder until we've processed one second of time */ 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 /* Use the list of translators to build a translation matrix */ 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 /* Don't you just love O(N^3) operations? */ 00296 for (x=0; x< MAX_FORMAT; x++) /* For each source format */ 00297 for (y=0; y < MAX_FORMAT; y++) /* And each destination format */ 00298 if (x != y) /* Except ourselves, of course */ 00299 for (z=0; z < MAX_FORMAT; z++) /* And each format it might convert to */ 00300 if ((x!=z) && (y!=z)) /* Don't ever convert back to us */ 00301 if (tr_matrix[x][y].step && /* We can convert from x to y */ 00302 tr_matrix[y][z].step && /* And from y to z and... */ 00303 (!tr_matrix[x][z].step || /* Either there isn't an x->z conversion */ 00304 (tr_matrix[x][y].cost + 00305 tr_matrix[y][z].cost < /* Or we're cheaper than the existing */ 00306 tr_matrix[x][z].cost) /* solution */ 00307 )) { 00308 /* We can get from x to z via y with a cost that 00309 is the sum of the transition from x to y and 00310 from y to z */ 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 /* Calculate our best source format, given costs, and a desired destination */ 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 /* This is a common format to both. Pick it if we don't have one already */ 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 && /* There's a step */ 00457 (tr_matrix[x][y].cost < besttime) && /* We're better than what exists now */ 00458 (*srcs & (1 << x))) /* x is a valid source format */ 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 }

Generated on Sat Jun 12 16:40:59 2004 for Asterisk by doxygen 1.3.7