Sat Apr 26 2014 22:01:42

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 /*** MODULEINFO
00027    <support_level>core</support_level>
00028  ***/
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 403015 $")
00033 
00034 #include <sys/time.h>
00035 #include <sys/resource.h>
00036 #include <math.h>
00037 
00038 #include "asterisk/lock.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/translate.h"
00041 #include "asterisk/module.h"
00042 #include "asterisk/frame.h"
00043 #include "asterisk/sched.h"
00044 #include "asterisk/cli.h"
00045 #include "asterisk/term.h"
00046 
00047 /*! \todo
00048  * TODO: sample frames for each supported input format.
00049  * We build this on the fly, by taking an SLIN frame and using
00050  * the existing converter to play with it.
00051  */
00052 
00053 /*! max sample recalc */
00054 #define MAX_RECALC 1000
00055 
00056 /*! \brief the list of translators */
00057 static AST_RWLIST_HEAD_STATIC(translators, ast_translator);
00058 
00059 struct translator_path {
00060    struct ast_translator *step;       /*!< Next step translator */
00061    uint32_t table_cost;               /*!< Complete table cost to destination */
00062    uint8_t multistep;                 /*!< Multiple conversions required for this translation */
00063 };
00064 
00065 /*!
00066  * \brief a matrix that, for any pair of supported formats,
00067  * indicates the total cost of translation and the first step.
00068  * The full path can be reconstricted iterating on the matrix
00069  * until step->dstfmt == desired_format.
00070  *
00071  * Array indexes are 'src' and 'dest', in that order.
00072  *
00073  * Note: the lock in the 'translators' list is also used to protect
00074  * this structure.
00075  */
00076 static struct translator_path **__matrix;
00077 
00078 /*!
00079  * \brief table for converting index to format id values.
00080  *
00081  * \note this table is protected by the table_lock.
00082  */
00083 static int *__indextable;
00084 
00085 /*! protects the __indextable for resizing */
00086 static ast_rwlock_t tablelock;
00087 
00088 /* index size starts at this*/
00089 #define INIT_INDEX 32
00090 /* index size grows by this as necessary */
00091 #define GROW_INDEX 16
00092 
00093 /*! the current largest index used by the __matrix and __indextable arrays*/
00094 static int cur_max_index;
00095 /*! the largest index that can be used in either the __indextable or __matrix before resize must occur */
00096 static int index_size;
00097 
00098 static void matrix_rebuild(int samples);
00099 
00100 /*!
00101  * \internal
00102  * \brief converts format id to index value.
00103  */
00104 static int format2index(enum ast_format_id id)
00105 {
00106    int x;
00107 
00108    ast_rwlock_rdlock(&tablelock);
00109    for (x = 0; x < cur_max_index; x++) {
00110       if (__indextable[x] == id) {
00111          /* format already exists in index2format table */
00112          ast_rwlock_unlock(&tablelock);
00113          return x;
00114       }
00115    }
00116    ast_rwlock_unlock(&tablelock);
00117    return -1; /* not found */
00118 }
00119 
00120 /*!
00121  * \internal
00122  * \brief add a new format to the matrix and index table structures.
00123  *
00124  * \note it is perfectly safe to call this on formats already indexed.
00125  *
00126  * \retval 0, success
00127  * \retval -1, matrix and index table need to be resized
00128  */
00129 static int add_format2index(enum ast_format_id id)
00130 {
00131    if (format2index(id) != -1) {
00132       /* format is already already indexed */
00133       return 0;
00134    }
00135 
00136    ast_rwlock_wrlock(&tablelock);
00137    if (cur_max_index == (index_size)) {
00138       ast_rwlock_unlock(&tablelock);
00139       return -1; /* hit max length */
00140    }
00141    __indextable[cur_max_index] = id;
00142    cur_max_index++;
00143    ast_rwlock_unlock(&tablelock);
00144 
00145    return 0;
00146 }
00147 
00148 /*!
00149  * \internal
00150  * \brief converts index value back to format id
00151  */
00152 static enum ast_format_id index2format(int index)
00153 {
00154    enum ast_format_id format_id;
00155 
00156    if (index >= cur_max_index) {
00157       return 0;
00158    }
00159    ast_rwlock_rdlock(&tablelock);
00160    format_id = __indextable[index];
00161    ast_rwlock_unlock(&tablelock);
00162 
00163    return format_id;
00164 }
00165 
00166 /*!
00167  * \internal
00168  * \brief resize both the matrix and index table so they can represent
00169  * more translators
00170  *
00171  * \note _NO_ locks can be held prior to calling this function
00172  *
00173  * \retval 0, success
00174  * \retval -1, failure.  Old matrix and index table can still be used though
00175  */
00176 static int matrix_resize(int init)
00177 {
00178    struct translator_path **tmp_matrix = NULL;
00179    int *tmp_table = NULL;
00180    int old_index;
00181    int x;
00182 
00183    AST_RWLIST_WRLOCK(&translators);
00184    ast_rwlock_wrlock(&tablelock);
00185 
00186    old_index = index_size;
00187    if (init) {
00188       index_size += INIT_INDEX;
00189    } else {
00190       index_size += GROW_INDEX;
00191    }
00192 
00193    /* make new 2d array of translator_path structures */
00194    if (!(tmp_matrix = ast_calloc(1, sizeof(struct translator_path *) * (index_size)))) {
00195       goto resize_cleanup;
00196    }
00197 
00198    for (x = 0; x < index_size; x++) {
00199       if (!(tmp_matrix[x] = ast_calloc(1, sizeof(struct translator_path) * (index_size)))) {
00200          goto resize_cleanup;
00201       }
00202    }
00203 
00204    /* make new index table */
00205    if (!(tmp_table = ast_calloc(1, sizeof(int) * index_size))) {
00206       goto resize_cleanup;
00207    }
00208 
00209    /* if everything went well this far, free the old and use the new */
00210    if (!init) {
00211       for (x = 0; x < old_index; x++) {
00212          ast_free(__matrix[x]);
00213       }
00214       ast_free(__matrix);
00215 
00216       memcpy(tmp_table, __indextable, sizeof(int) * old_index);
00217       ast_free(__indextable);
00218    }
00219 
00220    /* now copy them over */
00221    __matrix = tmp_matrix;
00222    __indextable = tmp_table;
00223 
00224    matrix_rebuild(0);
00225    ast_rwlock_unlock(&tablelock);
00226    AST_RWLIST_UNLOCK(&translators);
00227 
00228    return 0;
00229 
00230 resize_cleanup:
00231    ast_rwlock_unlock(&tablelock);
00232    AST_RWLIST_UNLOCK(&translators);
00233    if (tmp_matrix) {
00234       for (x = 0; x < index_size; x++) {
00235          ast_free(tmp_matrix[x]);
00236       }
00237       ast_free(tmp_matrix);
00238    }
00239    ast_free(tmp_table);
00240 
00241    return -1;
00242 }
00243 
00244 /*!
00245  * \internal
00246  * \brief reinitialize the __matrix during matrix rebuild
00247  *
00248  * \note must be protected by the translators list lock
00249  */
00250 static void matrix_clear(void)
00251 {
00252    int x;
00253    for (x = 0; x < index_size; x++) {
00254       memset(__matrix[x], '\0', sizeof(struct translator_path) * (index_size));
00255    }
00256 }
00257 
00258 /*!
00259  * \internal
00260  * \brief get a matrix entry
00261  *
00262  * \note This function must be protected by the translators list lock
00263  */
00264 static struct translator_path *matrix_get(unsigned int x, unsigned int y)
00265 {
00266    if (!(x >= 0 && y >= 0)) {
00267       return NULL;
00268    }
00269    return __matrix[x] + y;
00270 }
00271 
00272 /*
00273  * wrappers around the translator routines.
00274  */
00275 
00276 /*!
00277  * \brief Allocate the descriptor, required outbuf space,
00278  * and possibly desc.
00279  */
00280 static void *newpvt(struct ast_translator *t, const struct ast_format *explicit_dst)
00281 {
00282    struct ast_trans_pvt *pvt;
00283    int len;
00284    char *ofs;
00285 
00286    /*
00287     * compute the required size adding private descriptor,
00288     * buffer, AST_FRIENDLY_OFFSET.
00289     */
00290    len = sizeof(*pvt) + t->desc_size;
00291    if (t->buf_size)
00292       len += AST_FRIENDLY_OFFSET + t->buf_size;
00293    pvt = ast_calloc(1, len);
00294    if (!pvt) {
00295       return NULL;
00296    }
00297    pvt->t = t;
00298    ofs = (char *)(pvt + 1);   /* pointer to data space */
00299    if (t->desc_size) {     /* first comes the descriptor */
00300       pvt->pvt = ofs;
00301       ofs += t->desc_size;
00302    }
00303    if (t->buf_size) {/* finally buffer and header */
00304       pvt->outbuf.c = ofs + AST_FRIENDLY_OFFSET;
00305    }
00306    /* if a explicit destination format is provided, set that on the pvt so the
00307     * translator will process it. */
00308    if (explicit_dst) {
00309       ast_format_copy(&pvt->explicit_dst, explicit_dst);
00310    }
00311    /* call local init routine, if present */
00312    if (t->newpvt && t->newpvt(pvt)) {
00313       ast_free(pvt);
00314       return NULL;
00315    }
00316    ast_module_ref(t->module);
00317    return pvt;
00318 }
00319 
00320 static void destroy(struct ast_trans_pvt *pvt)
00321 {
00322    struct ast_translator *t = pvt->t;
00323 
00324    if (t->destroy)
00325       t->destroy(pvt);
00326    ast_free(pvt);
00327    ast_module_unref(t->module);
00328 }
00329 
00330 /*! \brief framein wrapper, deals with bound checks.  */
00331 static int framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00332 {
00333    int ret;
00334    int samples = pvt->samples;   /* initial value */
00335 
00336    /* Copy the last in jb timing info to the pvt */
00337    ast_copy_flags(&pvt->f, f, AST_FRFLAG_HAS_TIMING_INFO);
00338    pvt->f.ts = f->ts;
00339    pvt->f.len = f->len;
00340    pvt->f.seqno = f->seqno;
00341 
00342    if (f->samples == 0) {
00343       ast_log(LOG_WARNING, "no samples for %s\n", pvt->t->name);
00344    }
00345    if (pvt->t->buffer_samples) { /* do not pass empty frames to callback */
00346       if (f->datalen == 0) { /* perform native PLC if available */
00347          /* If the codec has native PLC, then do that */
00348          if (!pvt->t->native_plc)
00349             return 0;
00350       }
00351       if (pvt->samples + f->samples > pvt->t->buffer_samples) {
00352          ast_log(LOG_WARNING, "Out of buffer space\n");
00353          return -1;
00354       }
00355    }
00356    /* we require a framein routine, wouldn't know how to do
00357     * it otherwise.
00358     */
00359    ret = pvt->t->framein(pvt, f);
00360    /* diagnostic ... */
00361    if (pvt->samples == samples)
00362       ast_log(LOG_WARNING, "%s did not update samples %d\n",
00363          pvt->t->name, pvt->samples);
00364    return ret;
00365 }
00366 
00367 /*! \brief generic frameout routine.
00368  * If samples and datalen are 0, take whatever is in pvt
00369  * and reset them, otherwise take the values in the caller and
00370  * leave alone the pvt values.
00371  */
00372 struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt,
00373    int datalen, int samples)
00374 {
00375    struct ast_frame *f = &pvt->f;
00376 
00377    if (samples) {
00378       f->samples = samples;
00379    } else {
00380       if (pvt->samples == 0)
00381          return NULL;
00382       f->samples = pvt->samples;
00383       pvt->samples = 0;
00384    }
00385    if (datalen) {
00386       f->datalen = datalen;
00387    } else {
00388       f->datalen = pvt->datalen;
00389       pvt->datalen = 0;
00390    }
00391 
00392    f->frametype = AST_FRAME_VOICE;
00393    ast_format_copy(&f->subclass.format, &pvt->t->dst_format);
00394    f->mallocd = 0;
00395    f->offset = AST_FRIENDLY_OFFSET;
00396    f->src = pvt->t->name;
00397    f->data.ptr = pvt->outbuf.c;
00398 
00399    return ast_frisolate(f);
00400 }
00401 
00402 static struct ast_frame *default_frameout(struct ast_trans_pvt *pvt)
00403 {
00404    return ast_trans_frameout(pvt, 0, 0);
00405 }
00406 
00407 /* end of callback wrappers and helpers */
00408 
00409 void ast_translator_free_path(struct ast_trans_pvt *p)
00410 {
00411    struct ast_trans_pvt *pn = p;
00412    while ( (p = pn) ) {
00413       pn = p->next;
00414       destroy(p);
00415    }
00416 }
00417 
00418 /*! \brief Build a chain of translators based upon the given source and dest formats */
00419 struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct ast_format *src)
00420 {
00421    struct ast_trans_pvt *head = NULL, *tail = NULL;
00422    int src_index, dst_index;
00423    struct ast_format tmp_fmt1;
00424    struct ast_format tmp_fmt2;
00425 
00426    src_index = format2index(src->id);
00427    dst_index = format2index(dst->id);
00428 
00429    if (src_index == -1 || dst_index == -1) {
00430       ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src_index == -1 ? "starting" : "ending");
00431       return NULL;
00432    }
00433 
00434    AST_RWLIST_RDLOCK(&translators);
00435 
00436    while (src_index != dst_index) {
00437       struct ast_trans_pvt *cur;
00438       struct ast_format *explicit_dst = NULL;
00439       struct ast_translator *t = matrix_get(src_index, dst_index)->step;
00440       if (!t) {
00441          int src_id = index2format(src_index);
00442          int dst_id = index2format(dst_index);
00443          ast_log(LOG_WARNING, "No translator path from %s to %s\n",
00444             ast_getformatname(ast_format_set(&tmp_fmt1, src_id, 0)),
00445             ast_getformatname(ast_format_set(&tmp_fmt2, dst_id, 0)));
00446          AST_RWLIST_UNLOCK(&translators);
00447          return NULL;
00448       }
00449       if (dst_index == t->dst_fmt_index) {
00450          explicit_dst = dst;
00451       }
00452       if (!(cur = newpvt(t, explicit_dst))) {
00453          int src_id = index2format(src_index);
00454          int dst_id = index2format(dst_index);
00455          ast_log(LOG_WARNING, "Failed to build translator step from %s to %s\n",
00456             ast_getformatname(ast_format_set(&tmp_fmt1, src_id, 0)),
00457             ast_getformatname(ast_format_set(&tmp_fmt2, dst_id, 0)));
00458          if (head) {
00459             ast_translator_free_path(head);
00460          }
00461          AST_RWLIST_UNLOCK(&translators);
00462          return NULL;
00463       }
00464       if (!head) {
00465          head = cur;
00466       } else {
00467          tail->next = cur;
00468       }
00469       tail = cur;
00470       cur->nextin = cur->nextout = ast_tv(0, 0);
00471       /* Keep going if this isn't the final destination */
00472       src_index = cur->t->dst_fmt_index;
00473    }
00474 
00475    AST_RWLIST_UNLOCK(&translators);
00476    return head;
00477 }
00478 
00479 /*! \brief do the actual translation */
00480 struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume)
00481 {
00482    struct ast_trans_pvt *p = path;
00483    struct ast_frame *out;
00484    struct timeval delivery;
00485    int has_timing_info;
00486    long ts;
00487    long len;
00488    int seqno;
00489 
00490    has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO);
00491    ts = f->ts;
00492    len = f->len;
00493    seqno = f->seqno;
00494 
00495    if (!ast_tvzero(f->delivery)) {
00496       if (!ast_tvzero(path->nextin)) {
00497          /* Make sure this is in line with what we were expecting */
00498          if (!ast_tveq(path->nextin, f->delivery)) {
00499             /* The time has changed between what we expected and this
00500                most recent time on the new packet.  If we have a
00501                valid prediction adjust our output time appropriately */
00502             if (!ast_tvzero(path->nextout)) {
00503                path->nextout = ast_tvadd(path->nextout,
00504                           ast_tvsub(f->delivery, path->nextin));
00505             }
00506             path->nextin = f->delivery;
00507          }
00508       } else {
00509          /* This is our first pass.  Make sure the timing looks good */
00510          path->nextin = f->delivery;
00511          path->nextout = f->delivery;
00512       }
00513       /* Predict next incoming sample */
00514       path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(&f->subclass.format)));
00515    }
00516    delivery = f->delivery;
00517    for (out = f; out && p ; p = p->next) {
00518       framein(p, out);
00519       if (out != f) {
00520          ast_frfree(out);
00521       }
00522       out = p->t->frameout(p);
00523    }
00524    if (out) {
00525       /* we have a frame, play with times */
00526       if (!ast_tvzero(delivery)) {
00527          /* Regenerate prediction after a discontinuity */
00528          if (ast_tvzero(path->nextout)) {
00529             path->nextout = ast_tvnow();
00530          }
00531 
00532          /* Use next predicted outgoing timestamp */
00533          out->delivery = path->nextout;
00534 
00535          /* Predict next outgoing timestamp from samples in this
00536             frame. */
00537          path->nextout = ast_tvadd(path->nextout, ast_samp2tv(out->samples, ast_format_rate(&out->subclass.format)));
00538          if (f->samples != out->samples && ast_test_flag(out, AST_FRFLAG_HAS_TIMING_INFO)) {
00539             ast_debug(4, "Sample size different %u vs %u\n", f->samples, out->samples);
00540             ast_clear_flag(out, AST_FRFLAG_HAS_TIMING_INFO);
00541          }
00542       } else {
00543          out->delivery = ast_tv(0, 0);
00544          ast_set2_flag(out, has_timing_info, AST_FRFLAG_HAS_TIMING_INFO);
00545          if (has_timing_info) {
00546             out->ts = ts;
00547             out->len = len;
00548             out->seqno = seqno;
00549          }
00550       }
00551       /* Invalidate prediction if we're entering a silence period */
00552       if (out->frametype == AST_FRAME_CNG) {
00553          path->nextout = ast_tv(0, 0);
00554       }
00555    }
00556    if (consume) {
00557       ast_frfree(f);
00558    }
00559    return out;
00560 }
00561 
00562 /*!
00563  * \internal
00564  * \brief Compute the computational cost of a single translation step.
00565  *
00566  * \note This function is only used to decide which translation path to
00567  * use between two translators with identical src and dst formats.  Computational
00568  * cost acts only as a tie breaker. This is done so hardware translators
00569  * can naturally have precedence over software translators.
00570  */
00571 static void generate_computational_cost(struct ast_translator *t, int seconds)
00572 {
00573    int num_samples = 0;
00574    struct ast_trans_pvt *pvt;
00575    struct rusage start;
00576    struct rusage end;
00577    int cost;
00578    int out_rate = ast_format_rate(&t->dst_format);
00579 
00580    if (!seconds) {
00581       seconds = 1;
00582    }
00583 
00584    /* If they don't make samples, give them a terrible score */
00585    if (!t->sample) {
00586       ast_debug(3, "Translator '%s' does not produce sample frames.\n", t->name);
00587       t->comp_cost = 999999;
00588       return;
00589    }
00590 
00591    pvt = newpvt(t, NULL);
00592    if (!pvt) {
00593       ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
00594       t->comp_cost = 999999;
00595       return;
00596    }
00597 
00598    getrusage(RUSAGE_SELF, &start);
00599 
00600    /* Call the encoder until we've processed the required number of samples */
00601    while (num_samples < seconds * out_rate) {
00602       struct ast_frame *f = t->sample();
00603       if (!f) {
00604          ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
00605          destroy(pvt);
00606          t->comp_cost = 999999;
00607          return;
00608       }
00609       framein(pvt, f);
00610       ast_frfree(f);
00611       while ((f = t->frameout(pvt))) {
00612          num_samples += f->samples;
00613          ast_frfree(f);
00614       }
00615    }
00616 
00617    getrusage(RUSAGE_SELF, &end);
00618 
00619    cost = ((end.ru_utime.tv_sec - start.ru_utime.tv_sec) * 1000000) + end.ru_utime.tv_usec - start.ru_utime.tv_usec;
00620    cost += ((end.ru_stime.tv_sec - start.ru_stime.tv_sec) * 1000000) + end.ru_stime.tv_usec - start.ru_stime.tv_usec;
00621 
00622    destroy(pvt);
00623 
00624    t->comp_cost = cost / seconds;
00625 
00626    if (!t->comp_cost) {
00627       t->comp_cost = 1;
00628    }
00629 }
00630 
00631 /*!
00632  * \internal
00633  *
00634  * \brief If no table cost value was pre set by the translator.  An attempt is made to
00635  * automatically generate that cost value from the cost table based on our src and
00636  * dst formats.
00637  *
00638  * \note This function allows older translators built before the translation cost
00639  * changed away from using onely computational time to continue to be registered
00640  * correctly.  It is expected that translators built after the introduction of this
00641  * function will manually assign their own table cost value.
00642  *
00643  * \note This function is safe to use on any audio formats that used to be defined in the
00644  * first 64 bits of the old bit field codec representation.
00645  *
00646  * \retval Table Cost value greater than 0.
00647  * \retval 0 on error.
00648  */
00649 static int generate_table_cost(struct ast_format *src, struct ast_format *dst)
00650 {
00651    int src_rate = ast_format_rate(src);
00652    int src_ll = 0;
00653    int dst_rate = ast_format_rate(dst);
00654    int dst_ll = 0;
00655 
00656    if ((AST_FORMAT_GET_TYPE(src->id) != AST_FORMAT_TYPE_AUDIO) || (AST_FORMAT_GET_TYPE(dst->id) != AST_FORMAT_TYPE_AUDIO)) {
00657       /* This method of generating table cost is limited to audio.
00658        * Translators for media other than audio must manually set their
00659        * table cost. */
00660       return 0;
00661    }
00662    src_ll = ast_format_is_slinear(src);
00663    dst_ll = ast_format_is_slinear(dst);
00664    if (src_ll) {
00665       if (dst_ll && (src_rate == dst_rate)) {
00666          return AST_TRANS_COST_LL_LL_ORIGSAMP;
00667       } else if (!dst_ll && (src_rate == dst_rate)) {
00668          return AST_TRANS_COST_LL_LY_ORIGSAMP;
00669       } else if (dst_ll && (src_rate < dst_rate)) {
00670          return AST_TRANS_COST_LL_LL_UPSAMP;
00671       } else if (!dst_ll && (src_rate < dst_rate)) {
00672          return AST_TRANS_COST_LL_LY_UPSAMP;
00673       } else if (dst_ll && (src_rate > dst_rate)) {
00674          return AST_TRANS_COST_LL_LL_DOWNSAMP;
00675       } else if (!dst_ll && (src_rate > dst_rate)) {
00676          return AST_TRANS_COST_LL_LY_DOWNSAMP;
00677       } else {
00678          return AST_TRANS_COST_LL_UNKNOWN;
00679       }
00680    } else {
00681       if (dst_ll && (src_rate == dst_rate)) {
00682          return AST_TRANS_COST_LY_LL_ORIGSAMP;
00683       } else if (!dst_ll && (src_rate == dst_rate)) {
00684          return AST_TRANS_COST_LY_LY_ORIGSAMP;
00685       } else if (dst_ll && (src_rate < dst_rate)) {
00686          return AST_TRANS_COST_LY_LL_UPSAMP;
00687       } else if (!dst_ll && (src_rate < dst_rate)) {
00688          return AST_TRANS_COST_LY_LY_UPSAMP;
00689       } else if (dst_ll && (src_rate > dst_rate)) {
00690          return AST_TRANS_COST_LY_LL_DOWNSAMP;
00691       } else if (!dst_ll && (src_rate > dst_rate)) {
00692          return AST_TRANS_COST_LY_LY_DOWNSAMP;
00693       } else {
00694          return AST_TRANS_COST_LY_UNKNOWN;
00695       }
00696    }
00697 }
00698 
00699 /*!
00700  * \brief rebuild a translation matrix.
00701  * \note This function expects the list of translators to be locked
00702 */
00703 static void matrix_rebuild(int samples)
00704 {
00705    struct ast_translator *t;
00706    int newtablecost;
00707    int x;      /* source format index */
00708    int y;      /* intermediate format index */
00709    int z;      /* destination format index */
00710 
00711    ast_debug(1, "Resetting translation matrix\n");
00712 
00713    matrix_clear();
00714 
00715    /* first, compute all direct costs */
00716    AST_RWLIST_TRAVERSE(&translators, t, list) {
00717       if (!t->active) {
00718          continue;
00719       }
00720 
00721       x = t->src_fmt_index;
00722       z = t->dst_fmt_index;
00723 
00724       if (samples) {
00725          generate_computational_cost(t, samples);
00726       }
00727 
00728       /* This new translator is the best choice if any of the below are true.
00729        * 1. no translation path is set between x and z yet.
00730        * 2. the new table cost is less.
00731        * 3. the new computational cost is less.  Computational cost is only used
00732        *    to break a tie between two identical translation paths.
00733        */
00734       if (!matrix_get(x, z)->step ||
00735          (t->table_cost < matrix_get(x, z)->step->table_cost) ||
00736          (t->comp_cost < matrix_get(x, z)->step->comp_cost)) {
00737 
00738          matrix_get(x, z)->step = t;
00739          matrix_get(x, z)->table_cost = t->table_cost;
00740       }
00741    }
00742 
00743    /*
00744     * For each triple x, y, z of distinct formats, check if there is
00745     * a path from x to z through y which is cheaper than what is
00746     * currently known, and in case, update the matrix.
00747     * Repeat until the matrix is stable.
00748     */
00749    for (;;) {
00750       int changed = 0;
00751       for (x = 0; x < cur_max_index; x++) {      /* source format */
00752          for (y = 0; y < cur_max_index; y++) {  /* intermediate format */
00753             if (x == y) {                      /* skip ourselves */
00754                continue;
00755             }
00756             for (z = 0; z < cur_max_index; z++) {  /* dst format */
00757                if ((z == x || z == y) ||        /* skip null conversions */
00758                   !matrix_get(x, y)->step ||   /* no path from x to y */
00759                   !matrix_get(y, z)->step) {   /* no path from y to z */
00760                   continue;
00761                }
00762 
00763                /* calculate table cost from x->y->z */
00764                newtablecost = matrix_get(x, y)->table_cost + matrix_get(y, z)->table_cost;
00765 
00766                /* if no step already exists between x and z OR the new cost of using the intermediate
00767                 * step is cheaper, use this step. */
00768                if (!matrix_get(x, z)->step || (newtablecost < matrix_get(x, z)->table_cost)) {
00769                   struct ast_format tmpx;
00770                   struct ast_format tmpy;
00771                   struct ast_format tmpz;
00772                   matrix_get(x, z)->step = matrix_get(x, y)->step;
00773                   matrix_get(x, z)->table_cost = newtablecost;
00774                   matrix_get(x, z)->multistep = 1;
00775                   changed++;
00776                   ast_debug(10, "Discovered %d cost path from %s to %s, via %s\n",
00777                      matrix_get(x, z)->table_cost,
00778                      ast_getformatname(ast_format_set(&tmpx, index2format(x), 0)),
00779                      ast_getformatname(ast_format_set(&tmpy, index2format(z), 0)),
00780                      ast_getformatname(ast_format_set(&tmpz, index2format(y), 0)));
00781                }
00782             }
00783          }
00784       }
00785       if (!changed) {
00786          break;
00787       }
00788    }
00789 }
00790 
00791 const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str)
00792 {
00793    struct ast_trans_pvt *pn = p;
00794    char tmp[256];
00795 
00796    if (!p || !p->t) {
00797       return "";
00798    }
00799 
00800    ast_str_set(str, 0, "%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), p->t->src_format.id));
00801 
00802    while ( (p = pn) ) {
00803       pn = p->next;
00804       ast_str_append(str, 0, "->%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), p->t->dst_format.id));
00805    }
00806 
00807    return ast_str_buffer(*str);
00808 }
00809 
00810 static char *complete_trans_path_choice(const char *line, const char *word, int pos, int state)
00811 {
00812    int which = 0;
00813    int wordlen = strlen(word);
00814    int i;
00815    char *ret = NULL;
00816    size_t len = 0;
00817    const struct ast_format_list *format_list = ast_format_list_get(&len);
00818 
00819    for (i = 0; i < len; i++) {
00820       if (AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) {
00821          continue;
00822       }
00823       if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) {
00824          ret = ast_strdup(format_list[i].name);
00825          break;
00826       }
00827    }
00828    ast_format_list_destroy(format_list);
00829    return ret;
00830 }
00831 
00832 static void handle_cli_recalc(struct ast_cli_args *a)
00833 {
00834    int time = a->argv[4] ? atoi(a->argv[4]) : 1;
00835 
00836    if (time <= 0) {
00837       ast_cli(a->fd, "         Recalc must be greater than 0.  Defaulting to 1.\n");
00838       time = 1;
00839    }
00840 
00841    if (time > MAX_RECALC) {
00842       ast_cli(a->fd, "         Maximum limit of recalc exceeded by %d, truncating value to %d\n", time - MAX_RECALC, MAX_RECALC);
00843       time = MAX_RECALC;
00844    }
00845    ast_cli(a->fd, "         Recalculating Codec Translation (number of sample seconds: %d)\n\n", time);
00846    AST_RWLIST_WRLOCK(&translators);
00847    matrix_rebuild(time);
00848    AST_RWLIST_UNLOCK(&translators);
00849 }
00850 
00851 static char *handle_show_translation_table(struct ast_cli_args *a)
00852 {
00853    int x;
00854    int y;
00855    int i;
00856    int k;
00857    int curlen = 0;
00858    int longest = 0;
00859    int f_len;
00860    size_t f_size = 0;
00861    const struct ast_format_list *f_list = ast_format_list_get(&f_size);
00862    struct ast_str *out = ast_str_create(1024);
00863 
00864    f_len = f_size;
00865    AST_RWLIST_RDLOCK(&translators);
00866    ast_cli(a->fd, "         Translation times between formats (in microseconds) for one second of data\n");
00867    ast_cli(a->fd, "          Source Format (Rows) Destination Format (Columns)\n\n");
00868 
00869    /* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */
00870    for (i = 0; i < f_len; i++) {
00871       /* translation only applies to audio right now. */
00872       if (AST_FORMAT_GET_TYPE(f_list[i].format.id) != AST_FORMAT_TYPE_AUDIO)
00873          continue;
00874       curlen = strlen(ast_getformatname(&f_list[i].format));
00875       if (curlen > longest) {
00876          longest = curlen;
00877       }
00878    }
00879 
00880    for (i = -1; i < f_len; i++) {
00881       x = -1;
00882       if ((i >= 0) && ((x = format2index(f_list[i].format.id)) == -1)) {
00883          continue;
00884       }
00885       /* translation only applies to audio right now. */
00886       if (i >= 0 && (AST_FORMAT_GET_TYPE(f_list[i].format.id) != AST_FORMAT_TYPE_AUDIO)) {
00887          continue;
00888       }
00889       /*Go ahead and move to next iteration if dealing with an unknown codec*/
00890       if (i >= 0 && !strcmp(ast_getformatname(&f_list[i].format), "unknown")) {
00891          continue;
00892       }
00893       ast_str_set(&out, 0, " ");
00894       for (k = -1; k < f_len; k++) {
00895          y = -1;
00896          if ((k >= 0) && ((y = format2index(f_list[k].format.id)) == -1)) {
00897             continue;
00898          }
00899          /* translation only applies to audio right now. */
00900          if (k >= 0 && (AST_FORMAT_GET_TYPE(f_list[k].format.id) != AST_FORMAT_TYPE_AUDIO)) {
00901             continue;
00902          }
00903          /*Go ahead and move to next iteration if dealing with an unknown codec*/
00904          if (k >= 0 && !strcmp(ast_getformatname(&f_list[k].format), "unknown")) {
00905             continue;
00906          }
00907          if (k >= 0) {
00908             curlen = strlen(ast_getformatname(&f_list[k].format));
00909          }
00910          if (curlen < 5) {
00911             curlen = 5;
00912          }
00913 
00914          if (x >= 0 && y >= 0 && matrix_get(x, y)->step) {
00915             /* Actual codec output */
00916             ast_str_append(&out, 0, "%*d", curlen + 1, (matrix_get(x, y)->table_cost/100));
00917          } else if (i == -1 && k >= 0) {
00918             /* Top row - use a dynamic size */
00919             ast_str_append(&out, 0, "%*s", curlen + 1, ast_getformatname(&f_list[k].format));
00920          } else if (k == -1 && i >= 0) {
00921             /* Left column - use a static size. */
00922             ast_str_append(&out, 0, "%*s", longest, ast_getformatname(&f_list[i].format));
00923          } else if (x >= 0 && y >= 0) {
00924             /* Codec not supported */
00925             ast_str_append(&out, 0, "%*s", curlen + 1, "-");
00926          } else {
00927             /* Upper left hand corner */
00928             ast_str_append(&out, 0, "%*s", longest, "");
00929          }
00930       }
00931       ast_str_append(&out, 0, "\n");
00932       ast_cli(a->fd, "%s", ast_str_buffer(out));
00933    }
00934    ast_free(out);
00935    AST_RWLIST_UNLOCK(&translators);
00936    ast_format_list_destroy(f_list);
00937    return CLI_SUCCESS;
00938 }
00939 
00940 static char *handle_show_translation_path(struct ast_cli_args *a)
00941 {
00942    struct ast_format input_src_format;
00943    size_t len = 0;
00944    int i;
00945    const struct ast_format_list *format_list = ast_format_list_get(&len);
00946    struct ast_str *str = ast_str_alloca(1024);
00947    struct ast_translator *step;
00948    char tmp[256];
00949 
00950    ast_format_clear(&input_src_format);
00951    for (i = 0; i < len; i++) {
00952       if (AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) {
00953          continue;
00954       }
00955       if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) {
00956          ast_format_copy(&input_src_format, &format_list[i].format);
00957       }
00958    }
00959 
00960    if (!input_src_format.id) {
00961       ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]);
00962       ast_format_list_destroy(format_list);
00963       return CLI_FAILURE;
00964    }
00965 
00966    AST_RWLIST_RDLOCK(&translators);
00967    ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(&input_src_format));
00968    for (i = 0; i < len; i++) {
00969       int src;
00970       int dst;
00971       if ((AST_FORMAT_GET_TYPE(format_list[i].format.id) != AST_FORMAT_TYPE_AUDIO) || (format_list[i].format.id == input_src_format.id)) {
00972          continue;
00973       }
00974       dst = format2index(format_list[i].format.id);
00975       src = format2index(input_src_format.id);
00976       ast_str_reset(str);
00977       if ((len >= cur_max_index) && (src != -1) && (dst != -1) && matrix_get(src, dst)->step) {
00978          ast_str_append(&str, 0, "%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), matrix_get(src, dst)->step->src_format.id));
00979          while (src != dst) {
00980             step = matrix_get(src, dst)->step;
00981             if (!step) {
00982                ast_str_reset(str);
00983                break;
00984             }
00985             ast_str_append(&str, 0, "->%s", ast_getformatname_multiple_byid(tmp, sizeof(tmp), step->dst_format.id));
00986             src = step->dst_fmt_index;
00987          }
00988       }
00989 
00990       if (ast_strlen_zero(ast_str_buffer(str))) {
00991          ast_str_set(&str, 0, "No Translation Path");
00992       }
00993       ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str));
00994    }
00995    AST_RWLIST_UNLOCK(&translators);
00996 
00997    ast_format_list_destroy(format_list);
00998    return CLI_SUCCESS;
00999 }
01000 
01001 static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01002 {
01003    static const char * const option[] = { "recalc", "paths", NULL };
01004 
01005    switch (cmd) {
01006    case CLI_INIT:
01007       e->command = "core show translation";
01008       e->usage =
01009          "Usage: 'core show translation' can be used in two ways.\n"
01010          "       1. 'core show translation [recalc [<recalc seconds>]]\n"
01011          "          Displays known codec translators and the cost associated\n"
01012          "          with each conversion.  If the argument 'recalc' is supplied along\n"
01013          "          with optional number of seconds to test a new test will be performed\n"
01014          "          as the chart is being displayed.\n"
01015          "       2. 'core show translation paths [codec]'\n"
01016          "           This will display all the translation paths associated with a codec\n";
01017       return NULL;
01018    case CLI_GENERATE:
01019       if (a->pos == 3) {
01020          return ast_cli_complete(a->word, option, a->n);
01021       }
01022       if (a->pos == 4 && !strcasecmp(a->argv[3], option[1])) {
01023          return complete_trans_path_choice(a->line, a->word, a->pos, a->n);
01024       }
01025       return NULL;
01026    }
01027 
01028    if (a->argc > 5)
01029       return CLI_SHOWUSAGE;
01030 
01031    if (a->argv[3] && !strcasecmp(a->argv[3], option[1]) && a->argc == 5) { /* show paths */
01032       return handle_show_translation_path(a);
01033    } else if (a->argv[3] && !strcasecmp(a->argv[3], option[0])) { /* recalc and then fall through to show table */
01034       handle_cli_recalc(a);
01035    } else if (a->argc > 3) { /* wrong input */
01036       return CLI_SHOWUSAGE;
01037    }
01038 
01039    return handle_show_translation_table(a);
01040 }
01041 
01042 static struct ast_cli_entry cli_translate[] = {
01043    AST_CLI_DEFINE(handle_cli_core_show_translation, "Display translation matrix")
01044 };
01045 
01046 /*! \brief register codec translator */
01047 int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
01048 {
01049    struct ast_translator *u;
01050    char tmp[80];
01051 
01052    if (add_format2index(t->src_format.id) || add_format2index(t->dst_format.id)) {
01053       if (matrix_resize(0)) {
01054          ast_log(LOG_WARNING, "Translator matrix can not represent any more translators.  Out of resources.\n");
01055          return -1;
01056       }
01057       add_format2index(t->src_format.id);
01058       add_format2index(t->dst_format.id);
01059    }
01060 
01061    if (!mod) {
01062       ast_log(LOG_WARNING, "Missing module pointer, you need to supply one\n");
01063       return -1;
01064    }
01065 
01066    if (!t->buf_size) {
01067       ast_log(LOG_WARNING, "empty buf size, you need to supply one\n");
01068       return -1;
01069    }
01070    if (!t->table_cost && !(t->table_cost = generate_table_cost(&t->src_format, &t->dst_format))) {
01071       ast_log(LOG_WARNING, "Table cost could not be generated for %s, "
01072          "Please set table_cost variable on translator.\n", t->name);
01073       return -1;
01074    }
01075 
01076    t->module = mod;
01077    t->src_fmt_index = format2index(t->src_format.id);
01078    t->dst_fmt_index = format2index(t->dst_format.id);
01079    t->active = 1;
01080 
01081    if (t->src_fmt_index == -1 || t->dst_fmt_index == -1) {
01082       ast_log(LOG_WARNING, "Invalid translator path: (%s codec is not valid)\n", t->src_fmt_index == -1 ? "starting" : "ending");
01083       return -1;
01084    }
01085    if (t->src_fmt_index >= cur_max_index) {
01086       ast_log(LOG_WARNING, "Source format %s is larger than cur_max_index\n", ast_getformatname(&t->src_format));
01087       return -1;
01088    }
01089 
01090    if (t->dst_fmt_index >= cur_max_index) {
01091       ast_log(LOG_WARNING, "Destination format %s is larger than cur_max_index\n", ast_getformatname(&t->dst_format));
01092       return -1;
01093    }
01094 
01095    if (t->buf_size) {
01096       /*
01097        * Align buf_size properly, rounding up to the machine-specific
01098        * alignment for pointers.
01099        */
01100       struct _test_align { void *a, *b; } p;
01101       int align = (char *)&p.b - (char *)&p.a;
01102 
01103       t->buf_size = ((t->buf_size + align - 1) / align) * align;
01104    }
01105 
01106    if (t->frameout == NULL) {
01107       t->frameout = default_frameout;
01108    }
01109 
01110    generate_computational_cost(t, 1);
01111 
01112    ast_verb(2, "Registered translator '%s' from format %s to %s, table cost, %d, computational cost %d\n",
01113              term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
01114              ast_getformatname(&t->src_format), ast_getformatname(&t->dst_format), t->table_cost, t->comp_cost);
01115 
01116    AST_RWLIST_WRLOCK(&translators);
01117 
01118    /* find any existing translators that provide this same srcfmt/dstfmt,
01119       and put this one in order based on computational cost */
01120    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
01121       if ((u->src_fmt_index == t->src_fmt_index) &&
01122           (u->dst_fmt_index == t->dst_fmt_index) &&
01123           (u->comp_cost > t->comp_cost)) {
01124          AST_RWLIST_INSERT_BEFORE_CURRENT(t, list);
01125          t = NULL;
01126          break;
01127       }
01128    }
01129    AST_RWLIST_TRAVERSE_SAFE_END;
01130 
01131    /* if no existing translator was found for this format combination,
01132       add it to the beginning of the list */
01133    if (t) {
01134       AST_RWLIST_INSERT_HEAD(&translators, t, list);
01135    }
01136 
01137    matrix_rebuild(0);
01138 
01139    AST_RWLIST_UNLOCK(&translators);
01140 
01141    return 0;
01142 }
01143 
01144 /*! \brief unregister codec translator */
01145 int ast_unregister_translator(struct ast_translator *t)
01146 {
01147    char tmp[80];
01148    struct ast_translator *u;
01149    int found = 0;
01150 
01151    AST_RWLIST_WRLOCK(&translators);
01152    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
01153       if (u == t) {
01154          AST_RWLIST_REMOVE_CURRENT(list);
01155          ast_verb(2, "Unregistered translator '%s' from format %s to %s\n",
01156             term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
01157             ast_getformatname(&t->src_format),
01158             ast_getformatname(&t->dst_format));
01159          found = 1;
01160          break;
01161       }
01162    }
01163    AST_RWLIST_TRAVERSE_SAFE_END;
01164 
01165    if (found) {
01166       matrix_rebuild(0);
01167    }
01168 
01169    AST_RWLIST_UNLOCK(&translators);
01170 
01171    return (u ? 0 : -1);
01172 }
01173 
01174 void ast_translator_activate(struct ast_translator *t)
01175 {
01176    AST_RWLIST_WRLOCK(&translators);
01177    t->active = 1;
01178    matrix_rebuild(0);
01179    AST_RWLIST_UNLOCK(&translators);
01180 }
01181 
01182 void ast_translator_deactivate(struct ast_translator *t)
01183 {
01184    AST_RWLIST_WRLOCK(&translators);
01185    t->active = 0;
01186    matrix_rebuild(0);
01187    AST_RWLIST_UNLOCK(&translators);
01188 }
01189 
01190 /*! \brief Calculate our best translator source format, given costs, and a desired destination */
01191 int ast_translator_best_choice(struct ast_format_cap *dst_cap,
01192    struct ast_format_cap *src_cap,
01193    struct ast_format *dst_fmt_out,
01194    struct ast_format *src_fmt_out)
01195 {
01196    unsigned int besttablecost = INT_MAX;
01197    unsigned int beststeps = INT_MAX;
01198    struct ast_format best;
01199    struct ast_format bestdst;
01200    struct ast_format_cap *joint_cap = ast_format_cap_joint(dst_cap, src_cap);
01201    ast_format_clear(&best);
01202    ast_format_clear(&bestdst);
01203 
01204    if (joint_cap) { /* yes, pick one and return */
01205       struct ast_format tmp_fmt;
01206       ast_format_cap_iter_start(joint_cap);
01207       while (!ast_format_cap_iter_next(joint_cap, &tmp_fmt)) {
01208          /* We are guaranteed to find one common format. */
01209          if (!best.id) {
01210             ast_format_copy(&best, &tmp_fmt);
01211             continue;
01212          }
01213          /* If there are multiple common formats, pick the one with the highest sample rate */
01214          if (ast_format_rate(&best) < ast_format_rate(&tmp_fmt)) {
01215             ast_format_copy(&best, &tmp_fmt);
01216             continue;
01217          }
01218 
01219       }
01220       ast_format_cap_iter_end(joint_cap);
01221 
01222       /* We are done, this is a common format to both. */
01223       ast_format_copy(dst_fmt_out, &best);
01224       ast_format_copy(src_fmt_out, &best);
01225       ast_format_cap_destroy(joint_cap);
01226       return 0;
01227    } else {      /* No, we will need to translate */
01228       struct ast_format cur_dst;
01229       struct ast_format cur_src;
01230       AST_RWLIST_RDLOCK(&translators);
01231 
01232       ast_format_cap_iter_start(dst_cap);
01233       while (!ast_format_cap_iter_next(dst_cap, &cur_dst)) {
01234          ast_format_cap_iter_start(src_cap);
01235          while (!ast_format_cap_iter_next(src_cap, &cur_src)) {
01236             int x = format2index(cur_src.id);
01237             int y = format2index(cur_dst.id);
01238             if (x < 0 || y < 0) {
01239                continue;
01240             }
01241             if (!matrix_get(x, y) || !(matrix_get(x, y)->step)) {
01242                continue;
01243             }
01244             if (((matrix_get(x, y)->table_cost < besttablecost) || (matrix_get(x, y)->multistep < beststeps))) {
01245                /* better than what we have so far */
01246                ast_format_copy(&best, &cur_src);
01247                ast_format_copy(&bestdst, &cur_dst);
01248                besttablecost = matrix_get(x, y)->table_cost;
01249                beststeps = matrix_get(x, y)->multistep;
01250             }
01251          }
01252          ast_format_cap_iter_end(src_cap);
01253       }
01254 
01255       ast_format_cap_iter_end(dst_cap);
01256       AST_RWLIST_UNLOCK(&translators);
01257       if (best.id) {
01258          ast_format_copy(dst_fmt_out, &bestdst);
01259          ast_format_copy(src_fmt_out, &best);
01260          return 0;
01261       }
01262       return -1;
01263    }
01264 }
01265 
01266 unsigned int ast_translate_path_steps(struct ast_format *dst_format, struct ast_format *src_format)
01267 {
01268    unsigned int res = -1;
01269    int src, dest;
01270    /* convert bitwise format numbers into array indices */
01271    src = format2index(src_format->id);
01272    dest = format2index(dst_format->id);
01273 
01274    if (src == -1 || dest == -1) {
01275       ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src == -1 ? "starting" : "ending");
01276       return -1;
01277    }
01278    AST_RWLIST_RDLOCK(&translators);
01279 
01280    if (matrix_get(src, dest)->step) {
01281       res = matrix_get(src, dest)->multistep + 1;
01282    }
01283 
01284    AST_RWLIST_UNLOCK(&translators);
01285 
01286    return res;
01287 }
01288 
01289 void ast_translate_available_formats(struct ast_format_cap *dest, struct ast_format_cap *src, struct ast_format_cap *result)
01290 {
01291    struct ast_format tmp_fmt;
01292    struct ast_format cur_dest, cur_src;
01293    int src_audio = 0;
01294    int src_video = 0;
01295    int index;
01296 
01297    ast_format_cap_iter_start(dest);
01298    while (!ast_format_cap_iter_next(dest, &cur_dest)) {
01299       /* We give preference to a joint format structure if possible */
01300       if (ast_format_cap_get_compatible_format(src, &cur_dest, &tmp_fmt)) {
01301          ast_format_cap_add(result, &tmp_fmt);
01302       } else {
01303          /* Otherwise we just use the destination format */
01304          ast_format_cap_add(result, &cur_dest);
01305       }
01306    }
01307    ast_format_cap_iter_end(dest);
01308 
01309    /* if we don't have a source format, we just have to try all
01310       possible destination formats */
01311    if (!src) {
01312       return;
01313    }
01314 
01315    ast_format_cap_iter_start(src);
01316    while (!ast_format_cap_iter_next(src, &cur_src)) {
01317       /* If we have a source audio format, get its format index */
01318       if (AST_FORMAT_GET_TYPE(cur_src.id) == AST_FORMAT_TYPE_AUDIO) {
01319          src_audio = format2index(cur_src.id);
01320       }
01321 
01322       /* If we have a source video format, get its format index */
01323       if (AST_FORMAT_GET_TYPE(cur_src.id) == AST_FORMAT_TYPE_VIDEO) {
01324          src_video = format2index(cur_src.id);
01325       }
01326 
01327       AST_RWLIST_RDLOCK(&translators);
01328 
01329       /* For a given source audio format, traverse the list of
01330          known audio formats to determine whether there exists
01331          a translation path from the source format to the
01332          destination format. */
01333       for (index = 0; (src_audio >= 0) && index < cur_max_index; index++) {
01334          ast_format_set(&tmp_fmt, index2format(index), 0);
01335 
01336          if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_AUDIO) {
01337             continue;
01338          }
01339 
01340          /* if this is not a desired format, nothing to do */
01341          if (!ast_format_cap_iscompatible(dest, &tmp_fmt)) {
01342             continue;
01343          }
01344 
01345          /* if the source is supplying this format, then
01346             we can leave it in the result */
01347          if (ast_format_cap_iscompatible(src, &tmp_fmt)) {
01348             continue;
01349          }
01350 
01351          /* if we don't have a translation path from the src
01352             to this format, remove it from the result */
01353          if (!matrix_get(src_audio, index)->step) {
01354             ast_format_cap_remove_byid(result, tmp_fmt.id);
01355             continue;
01356          }
01357 
01358          /* now check the opposite direction */
01359          if (!matrix_get(index, src_audio)->step) {
01360             ast_format_cap_remove_byid(result, tmp_fmt.id);
01361          }
01362       }
01363 
01364       /* For a given source video format, traverse the list of
01365          known video formats to determine whether there exists
01366          a translation path from the source format to the
01367          destination format. */
01368       for (index = 0; (src_video >= 0) && index < cur_max_index; index++) {
01369          ast_format_set(&tmp_fmt, index2format(index), 0);
01370          if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_VIDEO) {
01371             continue;
01372          }
01373 
01374          /* if this is not a desired format, nothing to do */
01375          if (!ast_format_cap_iscompatible(dest, &tmp_fmt)) {
01376             continue;
01377          }
01378 
01379          /* if the source is supplying this format, then
01380             we can leave it in the result */
01381          if (ast_format_cap_iscompatible(src, &tmp_fmt)) {
01382             continue;
01383          }
01384 
01385          /* if we don't have a translation path from the src
01386             to this format, remove it from the result */
01387          if (!matrix_get(src_video, index)->step) {
01388             ast_format_cap_remove_byid(result, tmp_fmt.id);
01389             continue;
01390          }
01391 
01392          /* now check the opposite direction */
01393          if (!matrix_get(index, src_video)->step) {
01394             ast_format_cap_remove_byid(result, tmp_fmt.id);
01395          }
01396       }
01397       AST_RWLIST_UNLOCK(&translators);
01398    }
01399    ast_format_cap_iter_end(src);
01400 }
01401 
01402 static void translate_shutdown(void)
01403 {
01404    int x;
01405    ast_cli_unregister_multiple(cli_translate, ARRAY_LEN(cli_translate));
01406 
01407    ast_rwlock_wrlock(&tablelock);
01408    for (x = 0; x < index_size; x++) {
01409       ast_free(__matrix[x]);
01410    }
01411    ast_free(__matrix);
01412    ast_free(__indextable);
01413    ast_rwlock_unlock(&tablelock);
01414    ast_rwlock_destroy(&tablelock);
01415 }
01416 
01417 int ast_translate_init(void)
01418 {
01419    int res = 0;
01420    ast_rwlock_init(&tablelock);
01421    res = matrix_resize(1);
01422    res |= ast_cli_register_multiple(cli_translate, ARRAY_LEN(cli_translate));
01423    ast_register_atexit(translate_shutdown);
01424    return res;
01425 }