Sat Feb 11 06:33:25 2012

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

Generated on Sat Feb 11 06:33:25 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6