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 /* Uncomment the EXPERIMENTAL_TRANSLATION to enable a more complicated, but probably more
00033    correct way of handling full duplex translation */
00034 
00035 /*
00036 #define EXPERIMENTAL_TRANSLATION
00037 */
00038 
00039 /* This could all be done more efficiently *IF* we chained packets together
00040    by default, but it would also complicate virtually every application. */
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;  /* Next step translator */
00047    int cost;                  /* Complete cost to destination */
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    /* One of the hardest parts:  Build a set of translators based upon
00094       the given source and destination formats */
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             /* Set the root, if it doesn't exist yet... */
00117             if (!tmpr)
00118                tmpr = tmp;
00119             /* Keep going if this isn't the final destination */
00120             source = tmp->step->dstfmt;
00121          } else {
00122             /* XXX This could leak XXX */
00123             ast_log(LOG_WARNING, "Out of memory\n");
00124             return NULL;
00125          }
00126       } else {
00127          /* We shouldn't have allocated any memory */
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    /* Feed the first frame into the first translator */
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       /* If we get nothing out, return NULL */
00148       if (!out)
00149          return NULL;
00150       /* If there is a next state, feed it in there.  If not,
00151          return this frame  */
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    /* Use the list of translators to build a translation matrix */
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       /* Don't you just love O(N^3) operations? */
00183       for (x=0; x< MAX_FORMAT; x++)          /* For each source format */
00184          for (y=0; y < MAX_FORMAT; y++)         /* And each destination format */
00185             if (x != y)                   /* Except ourselves, of course */
00186                for (z=0; z < MAX_FORMAT; z++)   /* And each format it might convert to */
00187                   if ((x!=z) && (y!=z))      /* Don't ever convert back to us */
00188                      if (tr_matrix[x][y].step && /* We can convert from x to y */
00189                         tr_matrix[y][z].step && /* And from y to z and... */
00190                         (!tr_matrix[x][z].step ||  /* Either there isn't an x->z conversion */
00191                         (tr_matrix[x][y].cost + 
00192                          tr_matrix[y][z].cost < /* Or we're cheaper than the existing */
00193                          tr_matrix[x][z].cost)  /* solution */
00194                           )) {
00195                                  /* We can get from x to z via y with a cost that
00196                                     is the sum of the transition from x to y and
00197                                     from y to z */
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    /* If they don't make samples, give them a terrible score */
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    /* Call the encoder until we've processed one second of time */
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          /* Skip MP3 (y = 4) as Destination format */
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    /* Calculate our best source format, given costs, and a desired destination */
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          /* This is a common format to both.  Pick it if we don't have one already */
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 &&   /* There's a step */
00362                 (tr_matrix[x][y].cost < besttime) && /* We're better than what exists now */
00363                (*srcs & (1 << x)))        /* x is a valid source format */
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 }

Generated on Fri Oct 31 07:05:08 2003 for Asterisk by doxygen 1.3.4