Wed Apr 6 11:29:48 2011

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: 282047 $")
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 
00049 /*! \brief these values indicate how a translation path will affect the sample rate
00050  *
00051  *  \note These must stay in this order.  They are ordered by most optimal selection first.
00052  */
00053 enum path_samp_change {
00054    RATE_CHANGE_NONE = 0, /*!< path uses the same sample rate consistently */
00055    RATE_CHANGE_UPSAMP = 1, /*!< path will up the sample rate during a translation */
00056    RATE_CHANGE_DOWNSAMP = 2, /*!< path will have to down the sample rate during a translation. */
00057    RATE_CHANGE_UPSAMP_DOWNSAMP = 3, /*!< path will both up and down the sample rate during translation */
00058 };
00059 
00060 struct translator_path {
00061    struct ast_translator *step;  /*!< Next step translator */
00062    unsigned int cost;      /*!< Complete cost to destination */
00063    unsigned int multistep;    /*!< Multiple conversions required for this translation */
00064    enum path_samp_change rate_change; /*!< does this path require a sample rate change, if so what kind. */
00065 };
00066 
00067 /*! \brief a matrix that, for any pair of supported formats,
00068  * indicates the total cost of translation and the first step.
00069  * The full path can be reconstricted iterating on the matrix
00070  * until step->dstfmt == desired_format.
00071  *
00072  * Array indexes are 'src' and 'dest', in that order.
00073  *
00074  * Note: the lock in the 'translators' list is also used to protect
00075  * this structure.
00076  */
00077 static struct translator_path tr_matrix[MAX_FORMAT][MAX_FORMAT];
00078 
00079 /*! \todo
00080  * TODO: sample frames for each supported input format.
00081  * We build this on the fly, by taking an SLIN frame and using
00082  * the existing converter to play with it.
00083  */
00084 
00085 /*! \brief returns the index of the lowest bit set */
00086 static force_inline int powerof(format_t d)
00087 {
00088    int x = ffsll(d);
00089 
00090    if (x)
00091       return x - 1;
00092 
00093    ast_log(LOG_WARNING, "No bits set? %llu\n", (unsigned long long) d);
00094 
00095    return -1;
00096 }
00097 
00098 /*
00099  * wrappers around the translator routines.
00100  */
00101 
00102 /*!
00103  * \brief Allocate the descriptor, required outbuf space,
00104  * and possibly desc.
00105  */
00106 static void *newpvt(struct ast_translator *t)
00107 {
00108    struct ast_trans_pvt *pvt;
00109    int len;
00110    char *ofs;
00111 
00112    /*
00113     * compute the required size adding private descriptor,
00114     * buffer, AST_FRIENDLY_OFFSET.
00115     */
00116    len = sizeof(*pvt) + t->desc_size;
00117    if (t->buf_size)
00118       len += AST_FRIENDLY_OFFSET + t->buf_size;
00119    pvt = ast_calloc(1, len);
00120    if (!pvt)
00121       return NULL;
00122    pvt->t = t;
00123    ofs = (char *)(pvt + 1);   /* pointer to data space */
00124    if (t->desc_size) {     /* first comes the descriptor */
00125       pvt->pvt = ofs;
00126       ofs += t->desc_size;
00127    }
00128    if (t->buf_size)     /* finally buffer and header */
00129       pvt->outbuf.c = ofs + AST_FRIENDLY_OFFSET;
00130    /* call local init routine, if present */
00131    if (t->newpvt && t->newpvt(pvt)) {
00132       ast_free(pvt);
00133       return NULL;
00134    }
00135    ast_module_ref(t->module);
00136    return pvt;
00137 }
00138 
00139 static void destroy(struct ast_trans_pvt *pvt)
00140 {
00141    struct ast_translator *t = pvt->t;
00142 
00143    if (t->destroy)
00144       t->destroy(pvt);
00145    ast_free(pvt);
00146    ast_module_unref(t->module);
00147 }
00148 
00149 /*! \brief framein wrapper, deals with bound checks.  */
00150 static int framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00151 {
00152    int ret;
00153    int samples = pvt->samples;   /* initial value */
00154    
00155    /* Copy the last in jb timing info to the pvt */
00156    ast_copy_flags(&pvt->f, f, AST_FRFLAG_HAS_TIMING_INFO);
00157    pvt->f.ts = f->ts;
00158    pvt->f.len = f->len;
00159    pvt->f.seqno = f->seqno;
00160 
00161    if (f->samples == 0) {
00162       ast_log(LOG_WARNING, "no samples for %s\n", pvt->t->name);
00163    }
00164    if (pvt->t->buffer_samples) { /* do not pass empty frames to callback */
00165       if (f->datalen == 0) { /* perform native PLC if available */
00166          /* If the codec has native PLC, then do that */
00167          if (!pvt->t->native_plc)
00168             return 0;
00169       }
00170       if (pvt->samples + f->samples > pvt->t->buffer_samples) {
00171          ast_log(LOG_WARNING, "Out of buffer space\n");
00172          return -1;
00173       }
00174    }
00175    /* we require a framein routine, wouldn't know how to do
00176     * it otherwise.
00177     */
00178    ret = pvt->t->framein(pvt, f);
00179    /* diagnostic ... */
00180    if (pvt->samples == samples)
00181       ast_log(LOG_WARNING, "%s did not update samples %d\n",
00182          pvt->t->name, pvt->samples);
00183    return ret;
00184 }
00185 
00186 /*! \brief generic frameout routine.
00187  * If samples and datalen are 0, take whatever is in pvt
00188  * and reset them, otherwise take the values in the caller and
00189  * leave alone the pvt values.
00190  */
00191 struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt,
00192    int datalen, int samples)
00193 {
00194    struct ast_frame *f = &pvt->f;
00195 
00196    if (samples)
00197       f->samples = samples;
00198    else {
00199       if (pvt->samples == 0)
00200          return NULL;
00201       f->samples = pvt->samples;
00202       pvt->samples = 0;
00203    }
00204    if (datalen)
00205       f->datalen = datalen;
00206    else {
00207       f->datalen = pvt->datalen;
00208       pvt->datalen = 0;
00209    }
00210 
00211    f->frametype = AST_FRAME_VOICE;
00212    f->subclass.codec = 1LL << (pvt->t->dstfmt);
00213    f->mallocd = 0;
00214    f->offset = AST_FRIENDLY_OFFSET;
00215    f->src = pvt->t->name;
00216    f->data.ptr = pvt->outbuf.c;
00217 
00218    return ast_frisolate(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(format_t dest, format_t 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 %s to %s\n",
00263             ast_getformatname(source), ast_getformatname(dest));
00264          if (head)
00265             ast_translator_free_path(head);  
00266          AST_RWLIST_UNLOCK(&translators);
00267          return NULL;
00268       }
00269       if (!head)
00270          head = cur;
00271       else
00272          tail->next = cur;
00273       tail = cur;
00274       cur->nextin = cur->nextout = ast_tv(0, 0);
00275       /* Keep going if this isn't the final destination */
00276       source = cur->t->dstfmt;
00277    }
00278 
00279    AST_RWLIST_UNLOCK(&translators);
00280    return head;
00281 }
00282 
00283 /*! \brief do the actual translation */
00284 struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume)
00285 {
00286    struct ast_trans_pvt *p = path;
00287    struct ast_frame *out = f;
00288    struct timeval delivery;
00289    int has_timing_info;
00290    long ts;
00291    long len;
00292    int seqno;
00293 
00294    has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO);
00295    ts = f->ts;
00296    len = f->len;
00297    seqno = f->seqno;
00298 
00299    /* XXX hmmm... check this below */
00300    if (!ast_tvzero(f->delivery)) {
00301       if (!ast_tvzero(path->nextin)) {
00302          /* Make sure this is in line with what we were expecting */
00303          if (!ast_tveq(path->nextin, f->delivery)) {
00304             /* The time has changed between what we expected and this
00305                most recent time on the new packet.  If we have a
00306                valid prediction adjust our output time appropriately */
00307             if (!ast_tvzero(path->nextout)) {
00308                path->nextout = ast_tvadd(path->nextout,
00309                           ast_tvsub(f->delivery, path->nextin));
00310             }
00311             path->nextin = f->delivery;
00312          }
00313       } else {
00314          /* This is our first pass.  Make sure the timing looks good */
00315          path->nextin = f->delivery;
00316          path->nextout = f->delivery;
00317       }
00318       /* Predict next incoming sample */
00319       path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(f->subclass.codec)));
00320    }
00321    delivery = f->delivery;
00322    for ( ; out && p ; p = p->next) {
00323       framein(p, out);
00324       if (out != f)
00325          ast_frfree(out);
00326       out = p->t->frameout(p);
00327    }
00328    if (consume)
00329       ast_frfree(f);
00330    if (out == NULL)
00331       return NULL;
00332    /* we have a frame, play with times */
00333    if (!ast_tvzero(delivery)) {
00334       /* Regenerate prediction after a discontinuity */
00335       if (ast_tvzero(path->nextout))
00336          path->nextout = ast_tvnow();
00337 
00338       /* Use next predicted outgoing timestamp */
00339       out->delivery = path->nextout;
00340       
00341       /* Predict next outgoing timestamp from samples in this
00342          frame. */
00343       path->nextout = ast_tvadd(path->nextout, ast_samp2tv(out->samples, ast_format_rate(out->subclass.codec)));
00344    } else {
00345       out->delivery = ast_tv(0, 0);
00346       ast_set2_flag(out, has_timing_info, AST_FRFLAG_HAS_TIMING_INFO);
00347       if (has_timing_info) {
00348          out->ts = ts;
00349          out->len = len;
00350          out->seqno = seqno;
00351       }
00352    }
00353    /* Invalidate prediction if we're entering a silence period */
00354    if (out->frametype == AST_FRAME_CNG)
00355       path->nextout = ast_tv(0, 0);
00356    return out;
00357 }
00358 
00359 /*! \brief compute the cost of a single translation step */
00360 static void calc_cost(struct ast_translator *t, int seconds)
00361 {
00362    int num_samples = 0;
00363    struct ast_trans_pvt *pvt;
00364    struct rusage start;
00365    struct rusage end;
00366    int cost;
00367    int out_rate = ast_format_rate(t->dstfmt);
00368 
00369    if (!seconds)
00370       seconds = 1;
00371    
00372    /* If they don't make samples, give them a terrible score */
00373    if (!t->sample) {
00374       ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
00375       t->cost = 999999;
00376       return;
00377    }
00378 
00379    pvt = newpvt(t);
00380    if (!pvt) {
00381       ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
00382       t->cost = 999999;
00383       return;
00384    }
00385 
00386    getrusage(RUSAGE_SELF, &start);
00387 
00388    /* Call the encoder until we've processed the required number of samples */
00389    while (num_samples < seconds * out_rate) {
00390       struct ast_frame *f = t->sample();
00391       if (!f) {
00392          ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
00393          destroy(pvt);
00394          t->cost = 999999;
00395          return;
00396       }
00397       framein(pvt, f);
00398       ast_frfree(f);
00399       while ((f = t->frameout(pvt))) {
00400          num_samples += f->samples;
00401          ast_frfree(f);
00402       }
00403    }
00404 
00405    getrusage(RUSAGE_SELF, &end);
00406 
00407    cost = ((end.ru_utime.tv_sec - start.ru_utime.tv_sec) * 1000000) + end.ru_utime.tv_usec - start.ru_utime.tv_usec;
00408    cost += ((end.ru_stime.tv_sec - start.ru_stime.tv_sec) * 1000000) + end.ru_stime.tv_usec - start.ru_stime.tv_usec;
00409 
00410    destroy(pvt);
00411 
00412    t->cost = cost / seconds;
00413 
00414    if (!t->cost)
00415       t->cost = 1;
00416 }
00417 
00418 static enum path_samp_change get_rate_change_result(format_t src, format_t dst)
00419 {
00420    int src_rate = ast_format_rate(src);
00421    int dst_rate = ast_format_rate(dst);
00422 
00423    /* if src rate is less than dst rate, a sample upgrade is required */
00424    if (src_rate < dst_rate) {
00425       return RATE_CHANGE_UPSAMP;
00426    }
00427 
00428    /* if src rate is larger than dst rate, a downgrade is required */
00429    if (src_rate > dst_rate) {
00430       return RATE_CHANGE_DOWNSAMP;
00431    }
00432 
00433    return RATE_CHANGE_NONE;
00434 }
00435 
00436 /*!
00437  * \brief rebuild a translation matrix.
00438  * \note This function expects the list of translators to be locked
00439 */
00440 static void rebuild_matrix(int samples)
00441 {
00442    struct ast_translator *t;
00443    int new_rate_change;
00444    int newcost;
00445    int x;      /* source format index */
00446    int y;      /* intermediate format index */
00447    int z;      /* destination format index */
00448 
00449    ast_debug(1, "Resetting translation matrix\n");
00450 
00451    memset(tr_matrix, '\0', sizeof(tr_matrix));
00452 
00453    /* first, compute all direct costs */
00454    AST_RWLIST_TRAVERSE(&translators, t, list) {
00455       if (!t->active)
00456          continue;
00457 
00458       x = t->srcfmt;
00459       z = t->dstfmt;
00460 
00461       if (samples)
00462          calc_cost(t, samples);
00463 
00464       new_rate_change = get_rate_change_result(1LL << t->srcfmt, 1LL << t->dstfmt);
00465 
00466       /* this translator is the best choice if any of the below are true.
00467        * 1. no translation path is set between x and z yet.
00468        * 2. the new translation costs less and sample rate is no worse than old one. 
00469        * 3. the new translation has a better sample rate conversion than the old one.
00470        */
00471       if (!tr_matrix[x][z].step ||
00472          ((t->cost < tr_matrix[x][z].cost) && (new_rate_change <= tr_matrix[x][z].rate_change)) ||
00473          (new_rate_change < tr_matrix[x][z].rate_change)) {
00474 
00475          tr_matrix[x][z].step = t;
00476          tr_matrix[x][z].cost = t->cost;
00477          tr_matrix[x][z].rate_change = new_rate_change;
00478       }
00479    }
00480 
00481    /*
00482     * For each triple x, y, z of distinct formats, check if there is
00483     * a path from x to z through y which is cheaper than what is
00484     * currently known, and in case, update the matrix.
00485     * Repeat until the matrix is stable.
00486     */
00487    for (;;) {
00488       int changed = 0;
00489       int better_choice = 0;
00490       for (x = 0; x < MAX_FORMAT; x++) {      /* source format */
00491          for (y = 0; y < MAX_FORMAT; y++) {    /* intermediate format */
00492             if (x == y)                     /* skip ourselves */
00493                continue;
00494             for (z = 0; z < MAX_FORMAT; z++) {  /* dst format */
00495                if (z == x || z == y)       /* skip null conversions */
00496                   continue;
00497                if (!tr_matrix[x][y].step)  /* no path from x to y */
00498                   continue;
00499                if (!tr_matrix[y][z].step)  /* no path from y to z */
00500                   continue;
00501 
00502                /* Does x->y->z result in a less optimal sample rate change?
00503                 * Never downgrade the sample rate conversion quality regardless
00504                 * of any cost improvements */
00505                if (tr_matrix[x][z].step &&
00506                   ((tr_matrix[x][z].rate_change < tr_matrix[x][y].rate_change) ||
00507                   (tr_matrix[x][z].rate_change < tr_matrix[y][z].rate_change))) {
00508                   continue;
00509                }
00510 
00511                /* is x->y->z a better sample rate confersion that the current x->z? */
00512                new_rate_change = tr_matrix[x][y].rate_change + tr_matrix[y][z].rate_change;
00513 
00514                /* calculate cost from x->y->z */
00515                newcost = tr_matrix[x][y].cost + tr_matrix[y][z].cost;
00516 
00517                /* Is x->y->z a better choice than x->z?
00518                 * There are three conditions for x->y->z to be a better choice than x->z
00519                 * 1. if there is no step directly between x->z then x->y->z is the best and only current option.
00520                 * 2. if x->y->z costs less and the sample rate conversion is no less optimal.
00521                 * 3. if x->y->z results in a more optimal sample rate conversion. */
00522                if (!tr_matrix[x][z].step) {
00523                   better_choice = 1;
00524                } else if ((newcost < tr_matrix[x][z].cost) && (new_rate_change <= tr_matrix[x][z].rate_change)) {
00525                   better_choice = 1;
00526                } else if (new_rate_change < tr_matrix[x][z].rate_change) {
00527                   better_choice = 1;
00528                } else {
00529                   better_choice = 0;
00530                }
00531 
00532                if (!better_choice) {
00533                   continue;
00534                }
00535                /* ok, we can get from x to z via y with a cost that
00536                   is the sum of the transition from x to y and from y to z */
00537                tr_matrix[x][z].step = tr_matrix[x][y].step;
00538                tr_matrix[x][z].cost = newcost;
00539                tr_matrix[x][z].multistep = 1;
00540 
00541                /* now calculate what kind of sample rate change is required for this multi-step path
00542                 * 
00543                 * if both paths require a change in rate, and they are not in the same direction
00544                 * then this is a up sample down sample conversion scenario. */
00545                if ((tr_matrix[x][y].rate_change > RATE_CHANGE_NONE) &&
00546                   (tr_matrix[y][z].rate_change > RATE_CHANGE_NONE) &&
00547                   (tr_matrix[x][y].rate_change != tr_matrix[y][z].rate_change)) {
00548 
00549                   tr_matrix[x][z].rate_change = RATE_CHANGE_UPSAMP_DOWNSAMP;
00550                } else {
00551                   /* else just set the rate change to whichever is worse */
00552                   tr_matrix[x][z].rate_change = tr_matrix[x][y].rate_change > tr_matrix[y][z].rate_change
00553                      ? tr_matrix[x][y].rate_change : tr_matrix[y][z].rate_change;
00554                }
00555 
00556                ast_debug(3, "Discovered %d cost path from %s to %s, via %s\n", tr_matrix[x][z].cost,
00557                     ast_getformatname(1LL << x), ast_getformatname(1LL << z), ast_getformatname(1LL << y));
00558                changed++;
00559             }
00560          }
00561       }
00562       if (!changed)
00563          break;
00564    }
00565 }
00566 
00567 const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str)
00568 {
00569    struct ast_trans_pvt *pn = p;
00570 
00571    if (!p || !p->t) {
00572       return "";
00573    }
00574 
00575    ast_str_set(str, 0, "%s", ast_getformatname(1LL << p->t->srcfmt));
00576 
00577    while ( (p = pn) ) {
00578       pn = p->next;
00579       ast_str_append(str, 0, "->%s", ast_getformatname(1LL << p->t->dstfmt));
00580    }
00581 
00582    return ast_str_buffer(*str);
00583 }
00584 
00585 static char *complete_trans_path_choice(const char *line, const char *word, int pos, int state)
00586 {
00587    int which = 0;
00588    int wordlen = strlen(word);
00589    int i;
00590    char *ret = NULL;
00591    size_t len = 0;
00592    const struct ast_format_list *format_list = ast_get_format_list(&len);
00593 
00594    for (i = 0; i < len; i++) {
00595       if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) {
00596          continue;
00597       }
00598       if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) {
00599          ret = ast_strdup(format_list[i].name);
00600          break;
00601       }
00602    }
00603    return ret;
00604 }
00605 
00606 static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00607 {
00608 #define SHOW_TRANS 64
00609    static const char * const option1[] = { "recalc", "paths", NULL };
00610    int x, y, z;
00611    int curlen = 0, longest = 0, magnitude[SHOW_TRANS] = { 0, };
00612 
00613    switch (cmd) {
00614    case CLI_INIT:
00615       e->command = "core show translation";
00616       e->usage =
00617          "Usage: 'core show translation' can be used in two ways.\n"
00618          "       1. 'core show translation [recalc [<recalc seconds>]]\n"
00619          "          Displays known codec translators and the cost associated\n"
00620          "          with each conversion.  If the argument 'recalc' is supplied along\n"
00621          "          with optional number of seconds to test a new test will be performed\n"
00622          "          as the chart is being displayed.\n"
00623          "       2. 'core show translation paths [codec]'\n"
00624          "           This will display all the translation paths associated with a codec\n";
00625       return NULL;
00626    case CLI_GENERATE:
00627       if (a->pos == 3) {
00628          return ast_cli_complete(a->word, option1, a->n);
00629       }
00630       if (a->pos == 4 && !strcasecmp(a->argv[3], option1[1])) {
00631          return complete_trans_path_choice(a->line, a->word, a->pos, a->n);
00632       }
00633       return NULL;
00634    }
00635 
00636    if (a->argc > 5)
00637       return CLI_SHOWUSAGE;
00638 
00639    if (a->argv[3] && !strcasecmp(a->argv[3], option1[1]) && a->argc == 5) {
00640       format_t input_src = 0;
00641       format_t src = 0;
00642       size_t len = 0;
00643       int dst;
00644       int i;
00645       const struct ast_format_list *format_list = ast_get_format_list(&len);
00646       struct ast_str *str = ast_str_alloca(256);
00647       struct ast_translator *step;
00648 
00649       for (i = 0; i < len; i++) {
00650          if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) {
00651             continue;
00652          }
00653          if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) {
00654             input_src = format_list[i].bits;
00655          }
00656       }
00657 
00658       if (!input_src) {
00659          ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]);
00660          return CLI_FAILURE;
00661       }
00662 
00663       AST_RWLIST_RDLOCK(&translators);
00664       ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(input_src));
00665       for (i = 0; i < len; i++) {
00666          if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK) || (format_list[i].bits == input_src)) {
00667             continue;
00668          }
00669          dst = powerof(format_list[i].bits);
00670          src = powerof(input_src);
00671          ast_str_reset(str);
00672          if (tr_matrix[src][dst].step) {
00673             ast_str_append(&str, 0, "%s", ast_getformatname(1LL << tr_matrix[src][dst].step->srcfmt));
00674             while (src != dst) {
00675                step = tr_matrix[src][dst].step;
00676                if (!step) {
00677                   ast_str_reset(str);
00678                   break;
00679                }
00680                ast_str_append(&str, 0, "->%s", ast_getformatname(1LL << step->dstfmt));
00681                src = step->dstfmt;
00682             }
00683          }
00684 
00685          if (ast_strlen_zero(ast_str_buffer(str))) {
00686             ast_str_set(&str, 0, "No Translation Path");
00687          }
00688 
00689          ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str));
00690       }
00691       AST_RWLIST_UNLOCK(&translators);
00692 
00693       return CLI_SUCCESS;
00694    } else if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) {
00695       z = a->argv[4] ? atoi(a->argv[4]) : 1;
00696 
00697       if (z <= 0) {
00698          ast_cli(a->fd, "         Recalc must be greater than 0.  Defaulting to 1.\n");
00699          z = 1;
00700       }
00701 
00702       if (z > MAX_RECALC) {
00703          ast_cli(a->fd, "         Maximum limit of recalc exceeded by %d, truncating value to %d\n", z - MAX_RECALC, MAX_RECALC);
00704          z = MAX_RECALC;
00705       }
00706       ast_cli(a->fd, "         Recalculating Codec Translation (number of sample seconds: %d)\n\n", z);
00707       AST_RWLIST_WRLOCK(&translators);
00708       rebuild_matrix(z);
00709       AST_RWLIST_UNLOCK(&translators);
00710    } else if (a->argc > 3)
00711       return CLI_SHOWUSAGE;
00712 
00713    AST_RWLIST_RDLOCK(&translators);
00714 
00715    ast_cli(a->fd, "         Translation times between formats (in microseconds) for one second of data\n");
00716    ast_cli(a->fd, "          Source Format (Rows) Destination Format (Columns)\n\n");
00717    /* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */
00718    for (x = 0; x < SHOW_TRANS; x++) {
00719       /* translation only applies to audio right now. */
00720       if (!(AST_FORMAT_AUDIO_MASK & (1LL << (x))))
00721          continue;
00722       curlen = strlen(ast_getformatname(1LL << (x)));
00723       if (curlen > longest)
00724          longest = curlen;
00725       for (y = 0; y < SHOW_TRANS; y++) {
00726          if (!(AST_FORMAT_AUDIO_MASK & (1LL << (y))))
00727             continue;
00728          if (tr_matrix[x][y].cost > pow(10, magnitude[x])) {
00729             magnitude[y] = floor(log10(tr_matrix[x][y].cost));
00730          }
00731       }
00732    }
00733    for (x = -1; x < SHOW_TRANS; x++) {
00734       struct ast_str *out = ast_str_alloca(256);
00735       /* translation only applies to audio right now. */
00736       if (x >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (x))))
00737          continue;
00738       /*Go ahead and move to next iteration if dealing with an unknown codec*/
00739       if(x >= 0 && !strcmp(ast_getformatname(1LL << (x)), "unknown"))
00740          continue;
00741       ast_str_set(&out, -1, " ");
00742       for (y = -1; y < SHOW_TRANS; y++) {
00743          /* translation only applies to audio right now. */
00744          if (y >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (y))))
00745             continue;
00746          /*Go ahead and move to next iteration if dealing with an unknown codec*/
00747          if (y >= 0 && !strcmp(ast_getformatname(1LL << (y)), "unknown"))
00748             continue;
00749          if (y >= 0)
00750             curlen = strlen(ast_getformatname(1LL << (y)));
00751          if (y >= 0 && magnitude[y] + 1 > curlen) {
00752             curlen = magnitude[y] + 1;
00753          }
00754          if (curlen < 5)
00755             curlen = 5;
00756          if (x >= 0 && y >= 0 && tr_matrix[x][y].step) {
00757             /* Actual codec output */
00758             ast_str_append(&out, -1, "%*d", curlen + 1, tr_matrix[x][y].cost);
00759          } else if (x == -1 && y >= 0) {
00760             /* Top row - use a dynamic size */
00761             ast_str_append(&out, -1, "%*s", curlen + 1, ast_getformatname(1LL << (y)) );
00762          } else if (y == -1 && x >= 0) {
00763             /* Left column - use a static size. */
00764             ast_str_append(&out, -1, "%*s", longest, ast_getformatname(1LL << (x)) );
00765          } else if (x >= 0 && y >= 0) {
00766             /* Codec not supported */
00767             ast_str_append(&out, -1, "%*s", curlen + 1, "-");
00768          } else {
00769             /* Upper left hand corner */
00770             ast_str_append(&out, -1, "%*s", longest, "");
00771          }
00772       }
00773       ast_str_append(&out, -1, "\n");
00774       ast_cli(a->fd, "%s", ast_str_buffer(out));
00775    }
00776    AST_RWLIST_UNLOCK(&translators);
00777    return CLI_SUCCESS;
00778 }
00779 
00780 static struct ast_cli_entry cli_translate[] = {
00781    AST_CLI_DEFINE(handle_cli_core_show_translation, "Display translation matrix")
00782 };
00783 
00784 /*! \brief register codec translator */
00785 int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
00786 {
00787    static int added_cli = 0;
00788    struct ast_translator *u;
00789    char tmp[80];
00790 
00791    if (!mod) {
00792       ast_log(LOG_WARNING, "Missing module pointer, you need to supply one\n");
00793       return -1;
00794    }
00795 
00796    if (!t->buf_size) {
00797       ast_log(LOG_WARNING, "empty buf size, you need to supply one\n");
00798       return -1;
00799    }
00800 
00801    t->module = mod;
00802 
00803    t->srcfmt = powerof(t->srcfmt);
00804    t->dstfmt = powerof(t->dstfmt);
00805    t->active = 1;
00806 
00807    if (t->srcfmt == -1 || t->dstfmt == -1) {
00808       ast_log(LOG_WARNING, "Invalid translator path: (%s codec is not valid)\n", t->srcfmt == -1 ? "starting" : "ending");
00809       return -1;
00810    }
00811    if (t->srcfmt >= MAX_FORMAT) {
00812       ast_log(LOG_WARNING, "Source format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt));
00813       return -1;
00814    }
00815 
00816    if (t->dstfmt >= MAX_FORMAT) {
00817       ast_log(LOG_WARNING, "Destination format %s is larger than MAX_FORMAT\n", ast_getformatname(t->dstfmt));
00818       return -1;
00819    }
00820 
00821    if (t->buf_size) {
00822       /*
00823        * Align buf_size properly, rounding up to the machine-specific
00824        * alignment for pointers.
00825        */
00826       struct _test_align { void *a, *b; } p;
00827       int align = (char *)&p.b - (char *)&p.a;
00828 
00829       t->buf_size = ((t->buf_size + align - 1) / align) * align;
00830    }
00831 
00832    if (t->frameout == NULL)
00833       t->frameout = default_frameout;
00834   
00835    calc_cost(t, 1);
00836 
00837    ast_verb(2, "Registered translator '%s' from format %s to %s, cost %d\n",
00838              term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
00839              ast_getformatname(1LL << t->srcfmt), ast_getformatname(1LL << t->dstfmt), t->cost);
00840 
00841    if (!added_cli) {
00842       ast_cli_register_multiple(cli_translate, ARRAY_LEN(cli_translate));
00843       added_cli++;
00844    }
00845 
00846    AST_RWLIST_WRLOCK(&translators);
00847 
00848    /* find any existing translators that provide this same srcfmt/dstfmt,
00849       and put this one in order based on cost */
00850    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
00851       if ((u->srcfmt == t->srcfmt) &&
00852           (u->dstfmt == t->dstfmt) &&
00853           (u->cost > t->cost)) {
00854          AST_RWLIST_INSERT_BEFORE_CURRENT(t, list);
00855          t = NULL;
00856          break;
00857       }
00858    }
00859    AST_RWLIST_TRAVERSE_SAFE_END;
00860 
00861    /* if no existing translator was found for this format combination,
00862       add it to the beginning of the list */
00863    if (t)
00864       AST_RWLIST_INSERT_HEAD(&translators, t, list);
00865 
00866    rebuild_matrix(0);
00867 
00868    AST_RWLIST_UNLOCK(&translators);
00869 
00870    return 0;
00871 }
00872 
00873 /*! \brief unregister codec translator */
00874 int ast_unregister_translator(struct ast_translator *t)
00875 {
00876    char tmp[80];
00877    struct ast_translator *u;
00878    int found = 0;
00879 
00880    AST_RWLIST_WRLOCK(&translators);
00881    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
00882       if (u == t) {
00883          AST_RWLIST_REMOVE_CURRENT(list);
00884          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(1LL << t->srcfmt), ast_getformatname(1LL << t->dstfmt));
00885          found = 1;
00886          break;
00887       }
00888    }
00889    AST_RWLIST_TRAVERSE_SAFE_END;
00890 
00891    if (found)
00892       rebuild_matrix(0);
00893 
00894    AST_RWLIST_UNLOCK(&translators);
00895 
00896    return (u ? 0 : -1);
00897 }
00898 
00899 void ast_translator_activate(struct ast_translator *t)
00900 {
00901    AST_RWLIST_WRLOCK(&translators);
00902    t->active = 1;
00903    rebuild_matrix(0);
00904    AST_RWLIST_UNLOCK(&translators);
00905 }
00906 
00907 void ast_translator_deactivate(struct ast_translator *t)
00908 {
00909    AST_RWLIST_WRLOCK(&translators);
00910    t->active = 0;
00911    rebuild_matrix(0);
00912    AST_RWLIST_UNLOCK(&translators);
00913 }
00914 
00915 /*! \brief Calculate our best translator source format, given costs, and a desired destination */
00916 format_t ast_translator_best_choice(format_t *dst, format_t *srcs)
00917 {
00918    int x,y;
00919    int better = 0;
00920    int besttime = INT_MAX;
00921    int beststeps = INT_MAX;
00922    unsigned int best_rate_change = INT_MAX;
00923    format_t best = -1;
00924    format_t bestdst = 0;
00925    format_t cur, cursrc;
00926    format_t common = ((*dst) & (*srcs)) & AST_FORMAT_AUDIO_MASK;  /* are there common formats ? */
00927 
00928    if (common) { /* yes, pick one and return */
00929       for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
00930          if (!(cur & common)) {
00931             continue;
00932          }
00933 
00934          /* We are guaranteed to find one common format. */
00935          if (best == -1) {
00936             best = cur;
00937             continue;
00938          }
00939          /* If there are multiple common formats, pick the one with the highest sample rate */
00940          if (ast_format_rate(best) < ast_format_rate(cur)) {
00941             best = cur;
00942             continue;
00943          }
00944       }
00945       /* We are done, this is a common format to both. */
00946       *srcs = *dst = best;
00947       return 0;
00948    } else {      /* No, we will need to translate */
00949       AST_RWLIST_RDLOCK(&translators);
00950       for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
00951          if (! (cur & *dst)) {
00952             continue;
00953          }
00954          for (cursrc = 1, x = 0; x <= MAX_AUDIO_FORMAT; cursrc <<= 1, x++) {
00955             if (!(*srcs & cursrc) || !tr_matrix[x][y].step) {
00956                continue;
00957             }
00958 
00959             /* This is a better choice if any of the following are true.
00960              * 1. The sample rate conversion is better than the current pick.
00961              * 2. the sample rate conversion is no worse than the current pick and the cost or multistep is better
00962              */
00963             better = 0;
00964             if (tr_matrix[x][y].rate_change < best_rate_change) {
00965                better = 1; /* this match has a better rate conversion */
00966             }
00967             if ((tr_matrix[x][y].rate_change <= best_rate_change) &&
00968                (tr_matrix[x][y].cost < besttime || tr_matrix[x][y].multistep < beststeps)) {
00969                better = 1; /* this match has no worse rate conversion and the conversion cost is less */
00970             }
00971             if (better) {
00972                /* better than what we have so far */
00973                best = cursrc;
00974                bestdst = cur;
00975                besttime = tr_matrix[x][y].cost;
00976                beststeps = tr_matrix[x][y].multistep;
00977                best_rate_change = tr_matrix[x][y].rate_change;
00978             }
00979          }
00980       }
00981       AST_RWLIST_UNLOCK(&translators);
00982       if (best > -1) {
00983          *srcs = best;
00984          *dst = bestdst;
00985          best = 0;
00986       }
00987       return best;
00988    }
00989 }
00990 
00991 unsigned int ast_translate_path_steps(format_t dest, format_t src)
00992 {
00993    unsigned int res = -1;
00994 
00995    /* convert bitwise format numbers into array indices */
00996    src = powerof(src);
00997    dest = powerof(dest);
00998 
00999    if (src == -1 || dest == -1) {
01000       ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src == -1 ? "starting" : "ending");
01001       return -1;
01002    }
01003    AST_RWLIST_RDLOCK(&translators);
01004 
01005    if (tr_matrix[src][dest].step)
01006       res = tr_matrix[src][dest].multistep + 1;
01007 
01008    AST_RWLIST_UNLOCK(&translators);
01009 
01010    return res;
01011 }
01012 
01013 format_t ast_translate_available_formats(format_t dest, format_t src)
01014 {
01015    format_t res = dest;
01016    format_t x;
01017    format_t src_audio = src & AST_FORMAT_AUDIO_MASK;
01018    format_t src_video = src & AST_FORMAT_VIDEO_MASK;
01019 
01020    /* if we don't have a source format, we just have to try all
01021       possible destination formats */
01022    if (!src)
01023       return dest;
01024 
01025    /* If we have a source audio format, get its format index */
01026    if (src_audio)
01027       src_audio = powerof(src_audio);
01028 
01029    /* If we have a source video format, get its format index */
01030    if (src_video)
01031       src_video = powerof(src_video);
01032 
01033    AST_RWLIST_RDLOCK(&translators);
01034 
01035    /* For a given source audio format, traverse the list of
01036       known audio formats to determine whether there exists
01037       a translation path from the source format to the
01038       destination format. */
01039    for (x = 1LL; src_audio && x > 0; x <<= 1) {
01040       if (!(x & AST_FORMAT_AUDIO_MASK)) {
01041          continue;
01042       }
01043 
01044       /* if this is not a desired format, nothing to do */
01045       if (!(dest & x))
01046          continue;
01047 
01048       /* if the source is supplying this format, then
01049          we can leave it in the result */
01050       if (src & x)
01051          continue;
01052 
01053       /* if we don't have a translation path from the src
01054          to this format, remove it from the result */
01055       if (!tr_matrix[src_audio][powerof(x)].step) {
01056          res &= ~x;
01057          continue;
01058       }
01059 
01060       /* now check the opposite direction */
01061       if (!tr_matrix[powerof(x)][src_audio].step)
01062          res &= ~x;
01063    }
01064 
01065    /* For a given source video format, traverse the list of
01066       known video formats to determine whether there exists
01067       a translation path from the source format to the
01068       destination format. */
01069    for (x = 1LL; src_video && x > 0; x <<= 1) {
01070       if (!(x & AST_FORMAT_VIDEO_MASK)) {
01071          continue;
01072       }
01073 
01074       /* if this is not a desired format, nothing to do */
01075       if (!(dest & x))
01076          continue;
01077 
01078       /* if the source is supplying this format, then
01079          we can leave it in the result */
01080       if (src & x)
01081          continue;
01082 
01083       /* if we don't have a translation path from the src
01084          to this format, remove it from the result */
01085       if (!tr_matrix[src_video][powerof(x)].step) {
01086          res &= ~x;
01087          continue;
01088       }
01089 
01090       /* now check the opposite direction */
01091       if (!tr_matrix[powerof(x)][src_video].step)
01092          res &= ~x;
01093    }
01094 
01095    AST_RWLIST_UNLOCK(&translators);
01096 
01097    return res;
01098 }

Generated on Wed Apr 6 11:29:48 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7