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 /* This could all be done more efficiently *IF* we chained packets together
00033    by default, but it would also complicate virtually every application. */
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;  /* Next step translator */
00040    int cost;                  /* Complete cost to destination */
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    /* One of the hardest parts:  Build a set of translators based upon
00088       the given source and destination formats */
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             /* Set the root, if it doesn't exist yet... */
00111             if (!tmpr)
00112                tmpr = tmp;
00113             /* Keep going if this isn't the final destination */
00114             source = tmp->step->dstfmt;
00115          } else {
00116             /* XXX This could leak XXX */
00117             ast_log(LOG_WARNING, "Out of memory\n");
00118             return NULL;
00119          }
00120       } else {
00121          /* We shouldn't have allocated any memory */
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    /* Feed the first frame into the first translator */
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       /* If we get nothing out, return NULL */
00142       if (!out)
00143          return NULL;
00144       /* If there is a next state, feed it in there.  If not,
00145          return this frame  */
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    /* Use the list of translators to build a translation matrix */
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       /* Don't you just love O(N^3) operations? */
00177       for (x=0; x< MAX_FORMAT; x++)          /* For each source format */
00178          for (y=0; y < MAX_FORMAT; y++)         /* And each destination format */
00179             if (x != y)                   /* Except ourselves, of course */
00180                for (z=0; z < MAX_FORMAT; z++)   /* And each format it might convert to */
00181                   if ((x!=z) && (y!=z))      /* Don't ever convert back to us */
00182                      if (tr_matrix[x][y].step && /* We can convert from x to y */
00183                         tr_matrix[y][z].step && /* And from y to z and... */
00184                         (!tr_matrix[x][z].step ||  /* Either there isn't an x->z conversion */
00185                         (tr_matrix[x][y].cost + 
00186                          tr_matrix[y][z].cost < /* Or we're cheaper than the existing */
00187                          tr_matrix[x][z].cost)  /* solution */
00188                           )) {
00189                                  /* We can get from x to z via y with a cost that
00190                                     is the sum of the transition from x to y and
00191                                     from y to z */
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    /* If they don't make samples, give them a terrible score */
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    /* Call the encoder until we've processed one second of time */
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    /* Calculate our best source format, given costs, and a desired destination */
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          /* This is a common format to both.  Pick it if we don't have one already */
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 &&   /* There's a step */
00355                 (tr_matrix[x][y].cost < besttime) && /* We're better than what exists now */
00356                (*srcs & (1 << x)))        /* x is a valid source format */
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 }

Generated on Sun Apr 18 23:33:55 2004 for Asterisk by doxygen 1.3.6-20040222