Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:56 2009

## Asterisk developer's documentation

- Main Page
- Related Pages
- Modules
- Data Structures
- Files
- Directories

# translate.c

Go to the documentation of this file.

    00001 /*
    00002  * Asterisk -- An open source telephony toolkit.
    00003  *
    00004  * Copyright (C) 1999 - 2005, Digium, Inc.
    00005  *
    00006  * Mark Spencer <markster@digium.com>
    00007  *
    00008  * See http://www.asterisk.org for more information about
    00009  * the Asterisk project. Please do not directly contact
    00010  * any of the maintainers of this project for assistance;
    00011  * the project provides a web site, mailing lists and IRC
    00012  * channels for your use.
    00013  *
    00014  * This program is free software, distributed under the terms of
    00015  * the GNU General Public License Version 2. See the LICENSE file
    00016  * at the top of the source tree.
    00017  */
    00018
    00019 /*! \file
    00020  *
    00021  * \brief Translate via the use of pseudo channels
    00022  *
    00023  */
    00024
    00025 #include <sys/types.h>
    00026 #include <sys/socket.h>
    00027 #include <sys/time.h>
    00028 #include <unistd.h>
    00029 #include <stdlib.h>
    00030 #include <string.h>
    00031 #include <stdio.h>
    00032
    00033 #include "asterisk.h"
    00034
    00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 11120 $")
    00036
    00037 #include "asterisk/lock.h"
    00038 #include "asterisk/channel.h"
    00039 #include "asterisk/logger.h"
    00040 #include "asterisk/translate.h"
    00041 #include "asterisk/options.h"
    00042 #include "asterisk/frame.h"
    00043 #include "asterisk/sched.h"
    00044 #include "asterisk/cli.h"
    00045 #include "asterisk/term.h"
    00046
    00047 #define MAX_RECALC 200 /* max sample recalc */
    00048
    00049 /*! \note
    00050    This could all be done more efficiently *IF* we chained packets together
    00051    by default, but it would also complicate virtually every application. */
    00052
    00053 AST_MUTEX_DEFINE_STATIC(list_lock);
    00054 static struct ast_translator *list = NULL;
    00055
    00056 struct ast_translator_dir {
    00057    struct ast_translator *step;  /*!< Next step translator */
    00058    unsigned int cost;      /*!< Complete cost to destination */
    00059    unsigned int multistep;    /*!< Multiple conversions required for this translation */
    00060 };
    00061
    00062 struct ast_frame_delivery {
    00063    struct ast_frame *f;
    00064    struct ast_channel *chan;
    00065    int fd;
    00066    struct translator_pvt *owner;
    00067    struct ast_frame_delivery *prev;
    00068    struct ast_frame_delivery *next;
    00069 };
    00070
    00071 static struct ast_translator_dir tr_matrix[MAX_FORMAT][MAX_FORMAT];
    00072
    00073 struct ast_trans_pvt {
    00074    struct ast_translator *step;
    00075    struct ast_translator_pvt *state;
    00076    struct ast_trans_pvt *next;
    00077    struct timeval nextin;
    00078    struct timeval nextout;
    00079 };
    00080
    00081
    00082 static int powerof(int d)
    00083 {
    00084    int x;
    00085    for (x = 0; x < 32; x++)
    00086       if ((1 << x) & d)
    00087          return x;
    00088    ast_log(LOG_WARNING, "Powerof %d: No power??\n", d);
    00089    return -1;
    00090 }
    00091
    00092 void ast_translator_free_path(struct ast_trans_pvt *p)
    00093 {
    00094    struct ast_trans_pvt *pl, *pn;
    00095    pn = p;
    00096    while(pn) {
    00097       pl = pn;
    00098       pn = pn->next;
    00099       if (pl->state && pl->step->destroy)
    00100          pl->step->destroy(pl->state);
    00101       free(pl);
    00102    }
    00103 }
    00104
    00105 /*! Build a set of translators based upon the given source and destination formats */
    00106 struct ast_trans_pvt *ast_translator_build_path(int dest, int source)
    00107 {
    00108    struct ast_trans_pvt *tmpr = NULL, *tmp = NULL;
    00109
    00110    source = powerof(source);
    00111    dest = powerof(dest);
    00112
    00113    while(source != dest) {
    00114       if (!tr_matrix[source][dest].step) {
    00115          /* We shouldn't have allocated any memory */
    00116          ast_log(LOG_WARNING, "No translator path from %s to %s\n",
    00117             ast_getformatname(source), ast_getformatname(dest));
    00118          return NULL;
    00119       }
    00120
    00121       if (tmp) {
    00122          tmp->next = malloc(sizeof(*tmp));
    00123          tmp = tmp->next;
    00124       } else
    00125          tmp = malloc(sizeof(*tmp));
    00126
    00127       if (!tmp) {
    00128          ast_log(LOG_WARNING, "Out of memory\n");
    00129          if (tmpr)
    00130             ast_translator_free_path(tmpr);
    00131          return NULL;
    00132       }
    00133
    00134       /* Set the root, if it doesn't exist yet... */
    00135       if (!tmpr)
    00136          tmpr = tmp;
    00137
    00138       tmp->next = NULL;
    00139       tmp->nextin = tmp->nextout = ast_tv(0, 0);
    00140       tmp->step = tr_matrix[source][dest].step;
    00141       tmp->state = tmp->step->newpvt();
    00142
    00143       if (!tmp->state) {
    00144          ast_log(LOG_WARNING, "Failed to build translator step from %d to %d\n", source, dest);
    00145          ast_translator_free_path(tmpr);
    00146          return NULL;
    00147       }
    00148
    00149       /* Keep going if this isn't the final destination */
    00150       source = tmp->step->dstfmt;
    00151    }
    00152    return tmpr;
    00153 }
    00154
    00155 struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume)
    00156 {
    00157    struct ast_trans_pvt *p;
    00158    struct ast_frame *out;
    00159    struct timeval delivery;
    00160    p = path;
    00161    /* Feed the first frame into the first translator */
    00162    p->step->framein(p->state, f);
    00163    if (!ast_tvzero(f->delivery)) {
    00164       if (!ast_tvzero(path->nextin)) {
    00165          /* Make sure this is in line with what we were expecting */
    00166          if (!ast_tveq(path->nextin, f->delivery)) {
    00167             /* The time has changed between what we expected and this
    00168                most recent time on the new packet.  If we have a
    00169                valid prediction adjust our output time appropriately */
    00170             if (!ast_tvzero(path->nextout)) {
    00171                path->nextout = ast_tvadd(path->nextout,
    00172                           ast_tvsub(f->delivery, path->nextin));
    00173             }
    00174             path->nextin = f->delivery;
    00175          }
    00176       } else {
    00177          /* This is our first pass.  Make sure the timing looks good */
    00178          path->nextin = f->delivery;
    00179          path->nextout = f->delivery;
    00180       }
    00181       /* Predict next incoming sample */
    00182       path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, 8000));
    00183    }
    00184    delivery = f->delivery;
    00185    if (consume)
    00186       ast_frfree(f);
    00187    while(p) {
    00188       out = p->step->frameout(p->state);
    00189       /* If we get nothing out, return NULL */
    00190       if (!out)
    00191          return NULL;
    00192       /* If there is a next state, feed it in there.  If not,
    00193          return this frame  */
    00194       if (p->next)
    00195          p->next->step->framein(p->next->state, out);
    00196       else {
    00197          if (!ast_tvzero(delivery)) {
    00198             /* Regenerate prediction after a discontinuity */
    00199             if (ast_tvzero(path->nextout))
    00200                path->nextout = ast_tvnow();
    00201
    00202             /* Use next predicted outgoing timestamp */
    00203             out->delivery = path->nextout;
    00204
    00205             /* Predict next outgoing timestamp from samples in this
    00206                frame. */
    00207             path->nextout = ast_tvadd(path->nextout, ast_samp2tv( out->samples, 8000));
    00208          } else {
    00209             out->delivery = ast_tv(0, 0);
    00210          }
    00211          /* Invalidate prediction if we're entering a silence period */
    00212          if (out->frametype == AST_FRAME_CNG)
    00213             path->nextout = ast_tv(0, 0);
    00214          return out;
    00215       }
    00216       p = p->next;
    00217    }
    00218    ast_log(LOG_WARNING, "I should never get here...\n");
    00219    return NULL;
    00220 }
    00221
    00222
    00223 static void calc_cost(struct ast_translator *t, int samples)
    00224 {
    00225    int sofar=0;
    00226    struct ast_translator_pvt *pvt;
    00227    struct ast_frame *f, *out;
    00228    struct timeval start;
    00229    int cost;
    00230
    00231    if(!samples)
    00232       samples = 1;
    00233
    00234    /* If they don't make samples, give them a terrible score */
    00235    if (!t->sample) {
    00236       ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
    00237       t->cost = 99999;
    00238       return;
    00239    }
    00240    pvt = t->newpvt();
    00241    if (!pvt) {
    00242       ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
    00243       t->cost = 99999;
    00244       return;
    00245    }
    00246    start = ast_tvnow();
    00247    /* Call the encoder until we've processed one second of time */
    00248    while(sofar < samples * 8000) {
    00249       f = t->sample();
    00250       if (!f) {
    00251          ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
    00252          t->destroy(pvt);
    00253          t->cost = 99999;
    00254          return;
    00255       }
    00256       t->framein(pvt, f);
    00257       ast_frfree(f);
    00258       while((out = t->frameout(pvt))) {
    00259          sofar += out->samples;
    00260          ast_frfree(out);
    00261       }
    00262    }
    00263    cost = ast_tvdiff_ms(ast_tvnow(), start);
    00264    t->destroy(pvt);
    00265    t->cost = cost / samples;
    00266    if (!t->cost)
    00267       t->cost = 1;
    00268 }
    00269
    00270 /*! \brief Use the list of translators to build a translation matrix */
    00271 static void rebuild_matrix(int samples)
    00272 {
    00273    struct ast_translator *t;
    00274    int changed;
    00275    int x, y, z;
    00276
    00277    if (option_debug)
    00278       ast_log(LOG_DEBUG, "Resetting translation matrix\n");
    00279
    00280    bzero(tr_matrix, sizeof(tr_matrix));
    00281
    00282    for (t = list; t; t = t->next) {
    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    }
    00292
    00293    do {
    00294       changed = 0;
    00295
    00296       /* Don't you just love O(N^3) operations? */
    00297       for (x = 0; x< MAX_FORMAT; x++) {         /* For each source format */
    00298          for (y = 0; y < MAX_FORMAT; y++) {     /* And each destination format */
    00299             if (x == y)          /* Except ourselves, of course */
    00300                continue;
    00301
    00302             for (z=0; z < MAX_FORMAT; z++) {    /* And each format it might convert to */
    00303                if ((x == z) || (y == z))  /* Don't ever convert back to us */
    00304                   continue;
    00305
    00306                if (tr_matrix[x][y].step &&   /* We can convert from x to y */
    00307                    tr_matrix[y][z].step &&   /* And from y to z and... */
    00308                    (!tr_matrix[x][z].step ||    /* Either there isn't an x->z conversion */
    00309                     (tr_matrix[x][y].cost +
    00310                      tr_matrix[y][z].cost <  /* Or we're cheaper than the existing */
    00311                      tr_matrix[x][z].cost)   /* solution */
    00312                       )) {
    00313                   /* We can get from x to z via y with a cost that
    00314                      is the sum of the transition from x to y and
    00315                      from y to z */
    00316
    00317                   tr_matrix[x][z].step = tr_matrix[x][y].step;
    00318                   tr_matrix[x][z].cost = tr_matrix[x][y].cost +
    00319                      tr_matrix[y][z].cost;
    00320                   tr_matrix[x][z].multistep = 1;
    00321                   if (option_debug)
    00322                      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);
    00323                   changed++;
    00324                }
    00325             }
    00326          }
    00327       }
    00328    } while (changed);
    00329 }
    00330
    00331
    00332 /*! \brief CLI "show translation" command handler */
    00333 static int show_translation(int fd, int argc, char *argv[])
    00334 {
    00335 #define SHOW_TRANS 11
    00336    int x, y, z;
    00337    char line[80];
    00338    if (argc > 4)
    00339       return RESULT_SHOWUSAGE;
    00340
    00341    ast_mutex_lock(&list_lock);
    00342    if (argv[2] && !strcasecmp(argv[2],"recalc")) {
    00343       z = argv[3] ? atoi(argv[3]) : 1;
    00344
    00345       if (z <= 0) {
    00346          ast_cli(fd,"         C'mon let's be serious here... defaulting to 1.\n");
    00347          z = 1;
    00348       }
    00349
    00350       if (z > MAX_RECALC) {
    00351          ast_cli(fd,"         Maximum limit of recalc exceeded by %d, truncating value to %d\n",z-MAX_RECALC,MAX_RECALC);
    00352          z = MAX_RECALC;
    00353       }
    00354       ast_cli(fd,"         Recalculating Codec Translation (number of sample seconds: %d)\n\n",z);
    00355       rebuild_matrix(z);
    00356    }
    00357
    00358    ast_cli(fd, "         Translation times between formats (in milliseconds)\n");
    00359    ast_cli(fd, "          Source Format (Rows) Destination Format(Columns)\n\n");
    00360    for (x = -1; x < SHOW_TRANS; x++) {
    00361       /* next 2 lines run faster than using strcpy() */
    00362       line[0] = ' ';
    00363       line[1] = '\0';
    00364       for (y=-1;y<SHOW_TRANS;y++) {
    00365          if (x >= 0 && y >= 0 && tr_matrix[x][y].step)
    00366             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);
    00367          else
    00368             if (((x == -1 && y >= 0) || (y == -1 && x >= 0))) {
    00369                snprintf(line + strlen(line), sizeof(line) - strlen(line),
    00370                   " %5s", ast_getformatname(1<<(x+y+1)) );
    00371             } else if (x != -1 && y != -1) {
    00372                snprintf(line + strlen(line), sizeof(line) - strlen(line), "     -");
    00373             } else {
    00374                snprintf(line + strlen(line), sizeof(line) - strlen(line), "      ");
    00375             }
    00376       }
    00377       snprintf(line + strlen(line), sizeof(line) - strlen(line), "\n");
    00378       ast_cli(fd, line);
    00379    }
    00380    ast_mutex_unlock(&list_lock);
    00381    return RESULT_SUCCESS;
    00382 }
    00383
    00384 static int added_cli = 0;
    00385
    00386 static char show_trans_usage[] =
    00387 "Usage: show translation [recalc] [<recalc seconds>]\n"
    00388 "       Displays known codec translators and the cost associated\n"
    00389 "with each conversion.  If the argument 'recalc' is supplied along\n"
    00390 "with optional number of seconds to test a new test will be performed\n"
    00391 "as the chart is being displayed.\n";
    00392
    00393 static struct ast_cli_entry show_trans =
    00394 { { "show", "translation", NULL }, show_translation, "Display translation matrix", show_trans_usage };
    00395
    00396 int ast_register_translator(struct ast_translator *t)
    00397 {
    00398    char tmp[80];
    00399    t->srcfmt = powerof(t->srcfmt);
    00400    t->dstfmt = powerof(t->dstfmt);
    00401    if (t->srcfmt >= MAX_FORMAT) {
    00402       ast_log(LOG_WARNING, "Source format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt));
    00403       return -1;
    00404    }
    00405    if (t->dstfmt >= MAX_FORMAT) {
    00406       ast_log(LOG_WARNING, "Destination format %s is larger than MAX_FORMAT\n", ast_getformatname(t->dstfmt));
    00407       return -1;
    00408    }
    00409    calc_cost(t,1);
    00410    if (option_verbose > 1)
    00411       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);
    00412    ast_mutex_lock(&list_lock);
    00413    if (!added_cli) {
    00414       ast_cli_register(&show_trans);
    00415       added_cli++;
    00416    }
    00417    t->next = list;
    00418    list = t;
    00419    rebuild_matrix(0);
    00420    ast_mutex_unlock(&list_lock);
    00421    return 0;
    00422 }
    00423
    00424 /*! \brief unregister codec translator */
    00425 int ast_unregister_translator(struct ast_translator *t)
    00426 {
    00427    char tmp[80];
    00428    struct ast_translator *u, *ul = NULL;
    00429    ast_mutex_lock(&list_lock);
    00430    u = list;
    00431    while(u) {
    00432       if (u == t) {
    00433          if (ul)
    00434             ul->next = u->next;
    00435          else
    00436             list = u->next;
    00437          if (option_verbose > 1)
    00438             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));
    00439          break;
    00440       }
    00441       ul = u;
    00442       u = u->next;
    00443    }
    00444    rebuild_matrix(0);
    00445    ast_mutex_unlock(&list_lock);
    00446    return (u ? 0 : -1);
    00447 }
    00448
    00449 /*! \brief Calculate our best translator source format, given costs, and a desired destination */
    00450 int ast_translator_best_choice(int *dst, int *srcs)
    00451 {
    00452    int x,y;
    00453    int best = -1;
    00454    int bestdst = 0;
    00455    int cur = 1;
    00456    int besttime = INT_MAX;
    00457    int beststeps = INT_MAX;
    00458    int common;
    00459
    00460    if ((common = (*dst) & (*srcs))) {
    00461       /* We have a format in common */
    00462       for (y = 0; y < MAX_FORMAT; y++) {
    00463          if (cur & common) {
    00464             /* This is a common format to both.  Pick it if we don't have one already */
    00465             bestdst = cur;
    00466             best = cur;
    00467          }
    00468          cur = cur << 1;
    00469       }
    00470    } else {
    00471       /* We will need to translate */
    00472       ast_mutex_lock(&list_lock);
    00473       for (y = 0; y < MAX_FORMAT; y++) {
    00474          if (!(cur & *dst)) {
    00475             cur = cur << 1;
    00476             continue;
    00477          }
    00478
    00479          for (x = 0; x < MAX_FORMAT; x++) {
    00480             if ((*srcs & (1 << x)) &&        /* x is a valid source format */
    00481                 tr_matrix[x][y].step) {         /* There's a step */
    00482                if (tr_matrix[x][y].cost > besttime)
    00483                   continue;         /* It's more expensive, skip it */
    00484
    00485                if (tr_matrix[x][y].cost == besttime &&
    00486                    tr_matrix[x][y].multistep >= beststeps)
    00487                   continue;         /* It requires the same (or more) steps,
    00488                                  skip it */
    00489
    00490                /* It's better than what we have so far */
    00491                best = 1 << x;
    00492                bestdst = cur;
    00493                besttime = tr_matrix[x][y].cost;
    00494                beststeps = tr_matrix[x][y].multistep;
    00495             }
    00496          }
    00497          cur = cur << 1;
    00498       }
    00499       ast_mutex_unlock(&list_lock);
    00500    }
    00501
    00502    if (best > -1) {
    00503       *srcs = best;
    00504       *dst = bestdst;
    00505       best = 0;
    00506    }
    00507
    00508    return best;
    00509 }