Thu Apr 28 2011 17:15:25

Asterisk developer's documentation


translate.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, 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  * \author Mark Spencer <markster@digium.com> 
00024  */
00025 
00026 #include "asterisk.h"
00027 
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 277144 $")
00029 
00030 #include <sys/time.h>
00031 #include <sys/resource.h>
00032 #include <math.h>
00033 
00034 #include "asterisk/lock.h"
00035 #include "asterisk/channel.h"
00036 #include "asterisk/translate.h"
00037 #include "asterisk/module.h"
00038 #include "asterisk/frame.h"
00039 #include "asterisk/sched.h"
00040 #include "asterisk/cli.h"
00041 #include "asterisk/term.h"
00042 
00043 #define MAX_RECALC 1000 /* max sample recalc */
00044 
00045 /*! \brief the list of translators */
00046 static AST_RWLIST_HEAD_STATIC(translators, ast_translator);
00047 
00048 struct translator_path {
00049    struct ast_translator *step;  /*!< Next step translator */
00050    unsigned int cost;      /*!< Complete cost to destination */
00051    unsigned int multistep;    /*!< Multiple conversions required for this translation */
00052 };
00053 
00054 /*! \brief a matrix that, for any pair of supported formats,
00055  * indicates the total cost of translation and the first step.
00056  * The full path can be reconstricted iterating on the matrix
00057  * until step->dstfmt == desired_format.
00058  *
00059  * Array indexes are 'src' and 'dest', in that order.
00060  *
00061  * Note: the lock in the 'translators' list is also used to protect
00062  * this structure.
00063  */
00064 static struct translator_path tr_matrix[MAX_FORMAT][MAX_FORMAT];
00065 
00066 /*! \todo
00067  * TODO: sample frames for each supported input format.
00068  * We build this on the fly, by taking an SLIN frame and using
00069  * the existing converter to play with it.
00070  */
00071 
00072 /*! \brief returns the index of the lowest bit set */
00073 static force_inline int powerof(unsigned int d)
00074 {
00075    int x = ffs(d);
00076 
00077    if (x)
00078       return x - 1;
00079 
00080    ast_log(LOG_WARNING, "No bits set? %d\n", d);
00081 
00082    return -1;
00083 }
00084 
00085 /*
00086  * wrappers around the translator routines.
00087  */
00088 
00089 /*!
00090  * \brief Allocate the descriptor, required outbuf space,
00091  * and possibly desc.
00092  */
00093 static void *newpvt(struct ast_translator *t)
00094 {
00095    struct ast_trans_pvt *pvt;
00096    int len;
00097    char *ofs;
00098 
00099    /*
00100     * compute the required size adding private descriptor,
00101     * buffer, AST_FRIENDLY_OFFSET.
00102     */
00103    len = sizeof(*pvt) + t->desc_size;
00104    if (t->buf_size)
00105       len += AST_FRIENDLY_OFFSET + t->buf_size;
00106    pvt = ast_calloc(1, len);
00107    if (!pvt)
00108       return NULL;
00109    pvt->t = t;
00110    ofs = (char *)(pvt + 1);   /* pointer to data space */
00111    if (t->desc_size) {     /* first comes the descriptor */
00112       pvt->pvt = ofs;
00113       ofs += t->desc_size;
00114    }
00115    if (t->buf_size)     /* finally buffer and header */
00116       pvt->outbuf.c = ofs + AST_FRIENDLY_OFFSET;
00117    /* call local init routine, if present */
00118    if (t->newpvt && t->newpvt(pvt)) {
00119       ast_free(pvt);
00120       return NULL;
00121    }
00122    ast_module_ref(t->module);
00123    return pvt;
00124 }
00125 
00126 static void destroy(struct ast_trans_pvt *pvt)
00127 {
00128    struct ast_translator *t = pvt->t;
00129 
00130    if (ast_test_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR)) {
00131       /* If this flag is still set, that means that the translation path has
00132        * been torn down, while we still have a frame out there being used.
00133        * When ast_frfree() gets called on that frame, this ast_trans_pvt
00134        * will get destroyed, too. */
00135 
00136       pvt->destroy = 1;
00137 
00138       return;
00139    }
00140 
00141    if (t->destroy)
00142       t->destroy(pvt);
00143    ast_free(pvt);
00144    ast_module_unref(t->module);
00145 }
00146 
00147 /*! \brief framein wrapper, deals with bound checks.  */
00148 static int framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00149 {
00150    int ret;
00151    int samples = pvt->samples;   /* initial value */
00152    
00153    /* Copy the last in jb timing info to the pvt */
00154    ast_copy_flags(&pvt->f, f, AST_FRFLAG_HAS_TIMING_INFO);
00155    pvt->f.ts = f->ts;
00156    pvt->f.len = f->len;
00157    pvt->f.seqno = f->seqno;
00158 
00159    if (f->samples == 0) {
00160       ast_log(LOG_WARNING, "no samples for %s\n", pvt->t->name);
00161    }
00162    if (pvt->t->buffer_samples) { /* do not pass empty frames to callback */
00163       if (f->datalen == 0) { /* perform native PLC if available */
00164          /* If the codec has native PLC, then do that */
00165          if (!pvt->t->native_plc)
00166             return 0;
00167       }
00168       if (pvt->samples + f->samples > pvt->t->buffer_samples) {
00169          ast_log(LOG_WARNING, "Out of buffer space\n");
00170          return -1;
00171       }
00172    }
00173    /* we require a framein routine, wouldn't know how to do
00174     * it otherwise.
00175     */
00176    ret = pvt->t->framein(pvt, f);
00177    /* diagnostic ... */
00178    if (pvt->samples == samples)
00179       ast_log(LOG_WARNING, "%s did not update samples %d\n",
00180          pvt->t->name, pvt->samples);
00181    return ret;
00182 }
00183 
00184 /*! \brief generic frameout routine.
00185  * If samples and datalen are 0, take whatever is in pvt
00186  * and reset them, otherwise take the values in the caller and
00187  * leave alone the pvt values.
00188  */
00189 struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt,
00190    int datalen, int samples)
00191 {
00192    struct ast_frame *f = &pvt->f;
00193 
00194    if (samples)
00195       f->samples = samples;
00196    else {
00197       if (pvt->samples == 0)
00198          return NULL;
00199       f->samples = pvt->samples;
00200       pvt->samples = 0;
00201    }
00202    if (datalen)
00203       f->datalen = datalen;
00204    else {
00205       f->datalen = pvt->datalen;
00206       pvt->datalen = 0;
00207    }
00208 
00209    f->frametype = AST_FRAME_VOICE;
00210    f->subclass = 1 << (pvt->t->dstfmt);
00211    f->mallocd = 0;
00212    f->offset = AST_FRIENDLY_OFFSET;
00213    f->src = pvt->t->name;
00214    f->data.ptr = pvt->outbuf.c;
00215 
00216    ast_set_flag(f, AST_FRFLAG_FROM_TRANSLATOR);
00217 
00218    return f;
00219 }
00220 
00221 static struct ast_frame *default_frameout(struct ast_trans_pvt *pvt)
00222 {
00223    return ast_trans_frameout(pvt, 0, 0);
00224 }
00225 
00226 /* end of callback wrappers and helpers */
00227 
00228 void ast_translator_free_path(struct ast_trans_pvt *p)
00229 {
00230    struct ast_trans_pvt *pn = p;
00231    while ( (p = pn) ) {
00232       pn = p->next;
00233       destroy(p);
00234    }
00235 }
00236 
00237 /*! \brief Build a chain of translators based upon the given source and dest formats */
00238 struct ast_trans_pvt *ast_translator_build_path(int dest, int source)
00239 {
00240    struct ast_trans_pvt *head = NULL, *tail = NULL;
00241    
00242    source = powerof(source);
00243    dest = powerof(dest);
00244 
00245    if (source == -1 || dest == -1) {
00246       ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", source == -1 ? "starting" : "ending");
00247       return NULL;
00248    }
00249 
00250    AST_RWLIST_RDLOCK(&translators);
00251 
00252    while (source != dest) {
00253       struct ast_trans_pvt *cur;
00254       struct ast_translator *t = tr_matrix[source][dest].step;
00255       if (!t) {
00256          ast_log(LOG_WARNING, "No translator path from %s to %s\n", 
00257             ast_getformatname(source), ast_getformatname(dest));
00258          AST_RWLIST_UNLOCK(&translators);
00259          return NULL;
00260       }
00261       if (!(cur = newpvt(t))) {
00262          ast_log(LOG_WARNING, "Failed to build translator step from %d to %d\n", source, dest);
00263          if (head)
00264             ast_translator_free_path(head);  
00265          AST_RWLIST_UNLOCK(&translators);
00266          return NULL;
00267       }
00268       if (!head)
00269          head = cur;
00270       else
00271          tail->next = cur;
00272       tail = cur;
00273       cur->nextin = cur->nextout = ast_tv(0, 0);
00274       /* Keep going if this isn't the final destination */
00275       source = cur->t->dstfmt;
00276    }
00277 
00278    AST_RWLIST_UNLOCK(&translators);
00279    return head;
00280 }
00281 
00282 /*! \brief do the actual translation */
00283 struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume)
00284 {
00285    struct ast_trans_pvt *p = path;
00286    struct ast_frame *out = f;
00287    struct timeval delivery;
00288    int has_timing_info;
00289    long ts;
00290    long len;
00291    int seqno;
00292 
00293    has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO);
00294    ts = f->ts;
00295    len = f->len;
00296    seqno = f->seqno;
00297 
00298    /* XXX hmmm... check this below */
00299    if (!ast_tvzero(f->delivery)) {
00300       if (!ast_tvzero(path->nextin)) {
00301          /* Make sure this is in line with what we were expecting */
00302          if (!ast_tveq(path->nextin, f->delivery)) {
00303             /* The time has changed between what we expected and this
00304                most recent time on the new packet.  If we have a
00305                valid prediction adjust our output time appropriately */
00306             if (!ast_tvzero(path->nextout)) {
00307                path->nextout = ast_tvadd(path->nextout,
00308                           ast_tvsub(f->delivery, path->nextin));
00309             }
00310             path->nextin = f->delivery;
00311          }
00312       } else {
00313          /* This is our first pass.  Make sure the timing looks good */
00314          path->nextin = f->delivery;
00315          path->nextout = f->delivery;
00316       }
00317       /* Predict next incoming sample */
00318       path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(f->subclass)));
00319    }
00320    delivery = f->delivery;
00321    for ( ; out && p ; p = p->next) {
00322       framein(p, out);
00323       if (out != f)
00324          ast_frfree(out);
00325       out = p->t->frameout(p);
00326    }
00327    if (consume)
00328       ast_frfree(f);
00329    if (out == NULL)
00330       return NULL;
00331    /* we have a frame, play with times */
00332    if (!ast_tvzero(delivery)) {
00333       /* Regenerate prediction after a discontinuity */
00334       if (ast_tvzero(path->nextout))
00335          path->nextout = ast_tvnow();
00336 
00337       /* Use next predicted outgoing timestamp */
00338       out->delivery = path->nextout;
00339       
00340       /* Predict next outgoing timestamp from samples in this
00341          frame. */
00342       path->nextout = ast_tvadd(path->nextout, ast_samp2tv(out->samples, ast_format_rate(out->subclass)));
00343    } else {
00344       out->delivery = ast_tv(0, 0);
00345       ast_set2_flag(out, has_timing_info, AST_FRFLAG_HAS_TIMING_INFO);
00346       if (has_timing_info) {
00347          out->ts = ts;
00348          out->len = len;
00349          out->seqno = seqno;
00350       }
00351    }
00352    /* Invalidate prediction if we're entering a silence period */
00353    if (out->frametype == AST_FRAME_CNG)
00354       path->nextout = ast_tv(0, 0);
00355    return out;
00356 }
00357 
00358 /*! \brief compute the cost of a single translation step */
00359 static void calc_cost(struct ast_translator *t, int seconds)
00360 {
00361    int num_samples = 0;
00362    struct ast_trans_pvt *pvt;
00363    struct rusage start;
00364    struct rusage end;
00365    int cost;
00366    int out_rate = ast_format_rate(t->dstfmt);
00367 
00368    if (!seconds)
00369       seconds = 1;
00370    
00371    /* If they don't make samples, give them a terrible score */
00372    if (!t->sample) {
00373       ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
00374       t->cost = 999999;
00375       return;
00376    }
00377 
00378    pvt = newpvt(t);
00379    if (!pvt) {
00380       ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
00381       t->cost = 999999;
00382       return;
00383    }
00384 
00385    getrusage(RUSAGE_SELF, &start);
00386 
00387    /* Call the encoder until we've processed the required number of samples */
00388    while (num_samples < seconds * out_rate) {
00389       struct ast_frame *f = t->sample();
00390       if (!f) {
00391          ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
00392          destroy(pvt);
00393          t->cost = 999999;
00394          return;
00395       }
00396       framein(pvt, f);
00397       ast_frfree(f);
00398       while ((f = t->frameout(pvt))) {
00399          num_samples += f->samples;
00400          ast_frfree(f);
00401       }
00402    }
00403 
00404    getrusage(RUSAGE_SELF, &end);
00405 
00406    cost = ((end.ru_utime.tv_sec - start.ru_utime.tv_sec) * 1000000) + end.ru_utime.tv_usec - start.ru_utime.tv_usec;
00407    cost += ((end.ru_stime.tv_sec - start.ru_stime.tv_sec) * 1000000) + end.ru_stime.tv_usec - start.ru_stime.tv_usec;
00408 
00409    destroy(pvt);
00410 
00411    t->cost = cost / seconds;
00412 
00413    if (!t->cost)
00414       t->cost = 1;
00415 }
00416 
00417 /*!
00418  * \brief rebuild a translation matrix.
00419  * \note This function expects the list of translators to be locked
00420 */
00421 static void rebuild_matrix(int samples)
00422 {
00423    struct ast_translator *t;
00424    int x;      /* source format index */
00425    int y;      /* intermediate format index */
00426    int z;      /* destination format index */
00427 
00428    ast_debug(1, "Resetting translation matrix\n");
00429 
00430    memset(tr_matrix, '\0', sizeof(tr_matrix));
00431 
00432    /* first, compute all direct costs */
00433    AST_RWLIST_TRAVERSE(&translators, t, list) {
00434       if (!t->active)
00435          continue;
00436 
00437       x = t->srcfmt;
00438       z = t->dstfmt;
00439 
00440       if (samples)
00441          calc_cost(t, samples);
00442      
00443       if (!tr_matrix[x][z].step || t->cost < tr_matrix[x][z].cost) {
00444          tr_matrix[x][z].step = t;
00445          tr_matrix[x][z].cost = t->cost;
00446       }
00447    }
00448 
00449    /*
00450     * For each triple x, y, z of distinct formats, check if there is
00451     * a path from x to z through y which is cheaper than what is
00452     * currently known, and in case, update the matrix.
00453     * Repeat until the matrix is stable.
00454     */
00455    for (;;) {
00456       int changed = 0;
00457       for (x = 0; x < MAX_FORMAT; x++) {      /* source format */
00458          for (y = 0; y < MAX_FORMAT; y++) {    /* intermediate format */
00459             if (x == y)                     /* skip ourselves */
00460                continue;
00461 
00462             for (z = 0; z<MAX_FORMAT; z++) {  /* dst format */
00463                int newcost;
00464 
00465                if (z == x || z == y)       /* skip null conversions */
00466                   continue;
00467                if (!tr_matrix[x][y].step)  /* no path from x to y */
00468                   continue;
00469                if (!tr_matrix[y][z].step)  /* no path from y to z */
00470                   continue;
00471                newcost = tr_matrix[x][y].cost + tr_matrix[y][z].cost;
00472                if (tr_matrix[x][z].step && newcost >= tr_matrix[x][z].cost)
00473                   continue;               /* x->y->z is more expensive than
00474                                            * the existing path */
00475                /* ok, we can get from x to z via y with a cost that
00476                   is the sum of the transition from x to y and
00477                   from y to z */
00478                    
00479                tr_matrix[x][z].step = tr_matrix[x][y].step;
00480                tr_matrix[x][z].cost = newcost;
00481                tr_matrix[x][z].multistep = 1;
00482                ast_debug(3, "Discovered %d cost path from %s to %s, via %s\n", tr_matrix[x][z].cost,
00483                     ast_getformatname(1 << x), ast_getformatname(1 << z), ast_getformatname(1 << y));
00484                changed++;
00485             }
00486          }
00487       }
00488       if (!changed)
00489          break;
00490    }
00491 }
00492 
00493 static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00494 {
00495 #define SHOW_TRANS 16
00496    int x, y, z;
00497    int curlen = 0, longest = 0, magnitude[SHOW_TRANS] = { 0, };
00498 
00499    switch (cmd) {
00500    case CLI_INIT:
00501       e->command = "core show translation [recalc]";
00502       e->usage =
00503          "Usage: core show translation [recalc [<recalc seconds>]]\n"
00504          "       Displays known codec translators and the cost associated\n"
00505          "       with each conversion.  If the argument 'recalc' is supplied along\n"
00506          "       with optional number of seconds to test a new test will be performed\n"
00507          "       as the chart is being displayed.\n";
00508       return NULL;
00509    case CLI_GENERATE:
00510       return NULL;
00511    }
00512 
00513    if (a->argc > 5)
00514       return CLI_SHOWUSAGE;
00515 
00516    if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) {
00517       z = a->argv[4] ? atoi(a->argv[4]) : 1;
00518 
00519       if (z <= 0) {
00520          ast_cli(a->fd, "         Recalc must be greater than 0.  Defaulting to 1.\n");
00521          z = 1;
00522       }
00523 
00524       if (z > MAX_RECALC) {
00525          ast_cli(a->fd, "         Maximum limit of recalc exceeded by %d, truncating value to %d\n", z - MAX_RECALC, MAX_RECALC);
00526          z = MAX_RECALC;
00527       }
00528       ast_cli(a->fd, "         Recalculating Codec Translation (number of sample seconds: %d)\n\n", z);
00529       AST_RWLIST_WRLOCK(&translators);
00530       rebuild_matrix(z);
00531       AST_RWLIST_UNLOCK(&translators);
00532    } else if (a->argc > 3)
00533       return CLI_SHOWUSAGE;
00534 
00535    AST_RWLIST_RDLOCK(&translators);
00536 
00537    ast_cli(a->fd, "         Translation times between formats (in microseconds) for one second of data\n");
00538    ast_cli(a->fd, "          Source Format (Rows) Destination Format (Columns)\n\n");
00539    /* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */
00540    for (x = 0; x < SHOW_TRANS; x++) {
00541       curlen = strlen(ast_getformatname(1 << (x)));
00542       if (curlen > longest)
00543          longest = curlen;
00544       for (y = 0; y < SHOW_TRANS; y++) {
00545          if (tr_matrix[x][y].cost > pow(10, magnitude[x])) {
00546             magnitude[y] = floor(log10(tr_matrix[x][y].cost));
00547          }
00548       }
00549    }
00550    for (x = -1; x < SHOW_TRANS; x++) {
00551       struct ast_str *out = ast_str_alloca(125);
00552       /*Go ahead and move to next iteration if dealing with an unknown codec*/
00553       if(x >= 0 && !strcmp(ast_getformatname(1 << (x)), "unknown"))
00554          continue;
00555       ast_str_set(&out, -1, " ");
00556       for (y = -1; y < SHOW_TRANS; y++) {
00557          /*Go ahead and move to next iteration if dealing with an unknown codec*/
00558          if (y >= 0 && !strcmp(ast_getformatname(1 << (y)), "unknown"))
00559             continue;
00560          if (y >= 0)
00561             curlen = strlen(ast_getformatname(1 << (y)));
00562          if (y >= 0 && magnitude[y] + 1 > curlen) {
00563             curlen = magnitude[y] + 1;
00564          }
00565          if (curlen < 5)
00566             curlen = 5;
00567          if (x >= 0 && y >= 0 && tr_matrix[x][y].step) {
00568             /* Actual codec output */
00569             ast_str_append(&out, -1, "%*d", curlen + 1, tr_matrix[x][y].cost);
00570          } else if (x == -1 && y >= 0) {
00571             /* Top row - use a dynamic size */
00572             ast_str_append(&out, -1, "%*s", curlen + 1, ast_getformatname(1 << (y)) );
00573          } else if (y == -1 && x >= 0) {
00574             /* Left column - use a static size. */
00575             ast_str_append(&out, -1, "%*s", longest, ast_getformatname(1 << (x)) );
00576          } else if (x >= 0 && y >= 0) {
00577             /* Codec not supported */
00578             ast_str_append(&out, -1, "%*s", curlen + 1, "-");
00579          } else {
00580             /* Upper left hand corner */
00581             ast_str_append(&out, -1, "%*s", longest, "");
00582          }
00583       }
00584       ast_str_append(&out, -1, "\n");
00585       ast_cli(a->fd, "%s", ast_str_buffer(out));
00586    }
00587    AST_RWLIST_UNLOCK(&translators);
00588    return CLI_SUCCESS;
00589 }
00590 
00591 static struct ast_cli_entry cli_translate[] = {
00592    AST_CLI_DEFINE(handle_cli_core_show_translation, "Display translation matrix")
00593 };
00594 
00595 /*! \brief register codec translator */
00596 int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
00597 {
00598    static int added_cli = 0;
00599    struct ast_translator *u;
00600    char tmp[80];
00601 
00602    if (!mod) {
00603       ast_log(LOG_WARNING, "Missing module pointer, you need to supply one\n");
00604       return -1;
00605    }
00606 
00607    if (!t->buf_size) {
00608       ast_log(LOG_WARNING, "empty buf size, you need to supply one\n");
00609       return -1;
00610    }
00611 
00612    t->module = mod;
00613 
00614    t->srcfmt = powerof(t->srcfmt);
00615    t->dstfmt = powerof(t->dstfmt);
00616    t->active = 1;
00617 
00618    if (t->srcfmt == -1 || t->dstfmt == -1) {
00619       ast_log(LOG_WARNING, "Invalid translator path: (%s codec is not valid)\n", t->srcfmt == -1 ? "starting" : "ending");
00620       return -1;
00621    }
00622 
00623    if (t->srcfmt >= MAX_FORMAT) {
00624       ast_log(LOG_WARNING, "Source format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt));
00625       return -1;
00626    }
00627 
00628    if (t->dstfmt >= MAX_FORMAT) {
00629       ast_log(LOG_WARNING, "Destination format %s is larger than MAX_FORMAT\n", ast_getformatname(t->dstfmt));
00630       return -1;
00631    }
00632 
00633    if (t->buf_size) {
00634       /*
00635        * Align buf_size properly, rounding up to the machine-specific
00636        * alignment for pointers.
00637        */
00638       struct _test_align { void *a, *b; } p;
00639       int align = (char *)&p.b - (char *)&p.a;
00640 
00641       t->buf_size = ((t->buf_size + align - 1) / align) * align;
00642    }
00643 
00644    if (t->frameout == NULL)
00645       t->frameout = default_frameout;
00646   
00647    calc_cost(t, 1);
00648 
00649    ast_verb(2, "Registered translator '%s' from format %s to %s, cost %d\n",
00650              term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
00651              ast_getformatname(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt), t->cost);
00652 
00653    if (!added_cli) {
00654       ast_cli_register_multiple(cli_translate, ARRAY_LEN(cli_translate));
00655       added_cli++;
00656    }
00657 
00658    AST_RWLIST_WRLOCK(&translators);
00659 
00660    /* find any existing translators that provide this same srcfmt/dstfmt,
00661       and put this one in order based on cost */
00662    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
00663       if ((u->srcfmt == t->srcfmt) &&
00664           (u->dstfmt == t->dstfmt) &&
00665           (u->cost > t->cost)) {
00666          AST_RWLIST_INSERT_BEFORE_CURRENT(t, list);
00667          t = NULL;
00668          break;
00669       }
00670    }
00671    AST_RWLIST_TRAVERSE_SAFE_END;
00672 
00673    /* if no existing translator was found for this format combination,
00674       add it to the beginning of the list */
00675    if (t)
00676       AST_RWLIST_INSERT_HEAD(&translators, t, list);
00677 
00678    rebuild_matrix(0);
00679 
00680    AST_RWLIST_UNLOCK(&translators);
00681 
00682    return 0;
00683 }
00684 
00685 /*! \brief unregister codec translator */
00686 int ast_unregister_translator(struct ast_translator *t)
00687 {
00688    char tmp[80];
00689    struct ast_translator *u;
00690    int found = 0;
00691 
00692    AST_RWLIST_WRLOCK(&translators);
00693    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
00694       if (u == t) {
00695          AST_RWLIST_REMOVE_CURRENT(list);
00696          ast_verb(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));
00697          found = 1;
00698          break;
00699       }
00700    }
00701    AST_RWLIST_TRAVERSE_SAFE_END;
00702 
00703    if (found)
00704       rebuild_matrix(0);
00705 
00706    AST_RWLIST_UNLOCK(&translators);
00707 
00708    return (u ? 0 : -1);
00709 }
00710 
00711 void ast_translator_activate(struct ast_translator *t)
00712 {
00713    AST_RWLIST_WRLOCK(&translators);
00714    t->active = 1;
00715    rebuild_matrix(0);
00716    AST_RWLIST_UNLOCK(&translators);
00717 }
00718 
00719 void ast_translator_deactivate(struct ast_translator *t)
00720 {
00721    AST_RWLIST_WRLOCK(&translators);
00722    t->active = 0;
00723    rebuild_matrix(0);
00724    AST_RWLIST_UNLOCK(&translators);
00725 }
00726 
00727 /*! \brief Calculate our best translator source format, given costs, and a desired destination */
00728 int ast_translator_best_choice(int *dst, int *srcs)
00729 {
00730    int x,y;
00731    int best = -1;
00732    int bestdst = 0;
00733    int cur, cursrc;
00734    int besttime = INT_MAX;
00735    int beststeps = INT_MAX;
00736    int common = ((*dst) & (*srcs)) & AST_FORMAT_AUDIO_MASK; /* are there common formats ? */
00737 
00738    if (common) { /* yes, pick one and return */
00739       for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
00740          if (cur & common) /* guaranteed to find one */
00741             break;
00742       }
00743       /* We are done, this is a common format to both. */
00744       *srcs = *dst = cur;
00745       return 0;
00746    } else { /* No, we will need to translate */
00747       AST_RWLIST_RDLOCK(&translators);
00748       for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
00749          if (! (cur & *dst))
00750             continue;
00751          for (cursrc = 1, x = 0; x <= MAX_AUDIO_FORMAT; cursrc <<= 1, x++) {
00752             if (!(*srcs & cursrc) || !tr_matrix[x][y].step ||
00753                 tr_matrix[x][y].cost >  besttime)
00754                continue;   /* not existing or no better */
00755             if (tr_matrix[x][y].cost < besttime ||
00756                 tr_matrix[x][y].multistep < beststeps) {
00757                /* better than what we have so far */
00758                best = cursrc;
00759                bestdst = cur;
00760                besttime = tr_matrix[x][y].cost;
00761                beststeps = tr_matrix[x][y].multistep;
00762             }
00763          }
00764       }
00765       AST_RWLIST_UNLOCK(&translators);
00766       if (best > -1) {
00767          *srcs = best;
00768          *dst = bestdst;
00769          best = 0;
00770       }
00771       return best;
00772    }
00773 }
00774 
00775 unsigned int ast_translate_path_steps(unsigned int dest, unsigned int src)
00776 {
00777    unsigned int res = -1;
00778 
00779    /* convert bitwise format numbers into array indices */
00780    src = powerof(src);
00781    dest = powerof(dest);
00782 
00783    if (src == -1 || dest == -1) {
00784       ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src == -1 ? "starting" : "ending");
00785       return -1;
00786    }
00787    AST_RWLIST_RDLOCK(&translators);
00788 
00789    if (tr_matrix[src][dest].step)
00790       res = tr_matrix[src][dest].multistep + 1;
00791 
00792    AST_RWLIST_UNLOCK(&translators);
00793 
00794    return res;
00795 }
00796 
00797 unsigned int ast_translate_available_formats(unsigned int dest, unsigned int src)
00798 {
00799    unsigned int res = dest;
00800    unsigned int x;
00801    unsigned int src_audio = src & AST_FORMAT_AUDIO_MASK;
00802    unsigned int src_video = src & AST_FORMAT_VIDEO_MASK;
00803 
00804    /* if we don't have a source format, we just have to try all
00805       possible destination formats */
00806    if (!src)
00807       return dest;
00808 
00809    /* If we have a source audio format, get its format index */
00810    if (src_audio)
00811       src_audio = powerof(src_audio);
00812 
00813    /* If we have a source video format, get its format index */
00814    if (src_video)
00815       src_video = powerof(src_video);
00816 
00817    AST_RWLIST_RDLOCK(&translators);
00818 
00819    /* For a given source audio format, traverse the list of
00820       known audio formats to determine whether there exists
00821       a translation path from the source format to the
00822       destination format. */
00823    for (x = 1; src_audio && (x & AST_FORMAT_AUDIO_MASK); x <<= 1) {
00824       /* if this is not a desired format, nothing to do */
00825       if (!(dest & x))
00826          continue;
00827 
00828       /* if the source is supplying this format, then
00829          we can leave it in the result */
00830       if (src & x)
00831          continue;
00832 
00833       /* if we don't have a translation path from the src
00834          to this format, remove it from the result */
00835       if (!tr_matrix[src_audio][powerof(x)].step) {
00836          res &= ~x;
00837          continue;
00838       }
00839 
00840       /* now check the opposite direction */
00841       if (!tr_matrix[powerof(x)][src_audio].step)
00842          res &= ~x;
00843    }
00844 
00845    /* For a given source video format, traverse the list of
00846       known video formats to determine whether there exists
00847       a translation path from the source format to the
00848       destination format. */
00849    for (; src_video && (x & AST_FORMAT_VIDEO_MASK); x <<= 1) {
00850       /* if this is not a desired format, nothing to do */
00851       if (!(dest & x))
00852          continue;
00853 
00854       /* if the source is supplying this format, then
00855          we can leave it in the result */
00856       if (src & x)
00857          continue;
00858 
00859       /* if we don't have a translation path from the src
00860          to this format, remove it from the result */
00861       if (!tr_matrix[src_video][powerof(x)].step) {
00862          res &= ~x;
00863          continue;
00864       }
00865 
00866       /* now check the opposite direction */
00867       if (!tr_matrix[powerof(x)][src_video].step)
00868          res &= ~x;
00869    }
00870 
00871    AST_RWLIST_UNLOCK(&translators);
00872 
00873    return res;
00874 }
00875 
00876 void ast_translate_frame_freed(struct ast_frame *fr)
00877 {
00878    struct ast_trans_pvt *pvt;
00879 
00880    ast_clear_flag(fr, AST_FRFLAG_FROM_TRANSLATOR);
00881 
00882    pvt = (struct ast_trans_pvt *) (((char *) fr) - offsetof(struct ast_trans_pvt, f));
00883 
00884    if (!pvt->destroy)
00885       return;
00886    
00887    destroy(pvt);
00888 }