Thu Jul 9 13:41:34 2009

Asterisk developer's documentation


translate.c File Reference

Translate via the use of pseudo channels. More...

#include "asterisk.h"
#include <sys/time.h>
#include <sys/resource.h>
#include <math.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/translate.h"
#include "asterisk/module.h"
#include "asterisk/frame.h"
#include "asterisk/sched.h"
#include "asterisk/cli.h"
#include "asterisk/term.h"

Go to the source code of this file.

Data Structures

struct  translator_path
struct  translators
 the list of translators More...

Defines

#define MAX_RECALC   1000
#define SHOW_TRANS   16

Functions

int __ast_register_translator (struct ast_translator *t, struct ast_module *mod)
 Register a translator This registers a codec translator with asterisk.
ast_frameast_trans_frameout (struct ast_trans_pvt *pvt, int datalen, int samples)
 generic frameout function
ast_frameast_translate (struct ast_trans_pvt *path, struct ast_frame *f, int consume)
 translates one or more frames Apply an input frame into the translator and receive zero or one output frames. Consume determines whether the original frame should be freed
unsigned int ast_translate_available_formats (unsigned int dest, unsigned int src)
 Mask off unavailable formats from a format bitmask.
void ast_translate_frame_freed (struct ast_frame *fr)
 Hint that a frame from a translator has been freed.
unsigned int ast_translate_path_steps (unsigned int dest, unsigned int src)
 Returns the number of steps required to convert from 'src' to 'dest'.
void ast_translator_activate (struct ast_translator *t)
 Activate a previously deactivated translator.
int ast_translator_best_choice (int *dst, int *srcs)
 Chooses the best translation path.
ast_trans_pvtast_translator_build_path (int dest, int source)
 Builds a translator path Build a path (possibly NULL) from source to dest.
void ast_translator_deactivate (struct ast_translator *t)
 Deactivate a translator.
void ast_translator_free_path (struct ast_trans_pvt *p)
 Frees a translator path Frees the given translator path structure.
int ast_unregister_translator (struct ast_translator *t)
 Unregister a translator Unregisters the given tranlator.
static void calc_cost (struct ast_translator *t, int seconds)
 compute the cost of a single translation step
static struct ast_framedefault_frameout (struct ast_trans_pvt *pvt)
static void destroy (struct ast_trans_pvt *pvt)
static int framein (struct ast_trans_pvt *pvt, struct ast_frame *f)
 framein wrapper, deals with plc and bound checks.
static char * handle_cli_core_show_translation (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void * newpvt (struct ast_translator *t)
 Allocate the descriptor, required outbuf space, and possibly also plc and desc.
static force_inline int powerof (unsigned int d)
 returns the index of the lowest bit set
static void rebuild_matrix (int samples)
 rebuild a translation matrix.

Variables

static struct ast_cli_entry cli_translate []
static struct translator_path tr_matrix [MAX_FORMAT][MAX_FORMAT]
 a matrix that, for any pair of supported formats, indicates the total cost of translation and the first step. The full path can be reconstricted iterating on the matrix until step->dstfmt == desired_format.


Detailed Description

Translate via the use of pseudo channels.

Author:
Mark Spencer <markster@digium.com>

Definition in file translate.c.


Define Documentation

#define MAX_RECALC   1000

Definition at line 43 of file translate.c.

Referenced by handle_cli_core_show_translation().

#define SHOW_TRANS   16

Referenced by handle_cli_core_show_translation().


Function Documentation

int __ast_register_translator ( struct ast_translator t,
struct ast_module module 
)

Register a translator This registers a codec translator with asterisk.

Parameters:
t populated ast_translator structure
module handle to the module that owns this translator
Returns:
0 on success, -1 on failure

Definition at line 621 of file translate.c.

References ast_translator::active, ast_cli_register_multiple(), AST_FORMAT_SLINEAR, ast_getformatname(), ast_log(), AST_RWLIST_INSERT_BEFORE_CURRENT, AST_RWLIST_INSERT_HEAD, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, ast_translator::buf_size, ast_translator::buffer_samples, calc_cost(), cli_translate, COLOR_BLACK, COLOR_MAGENTA, ast_translator::cost, default_frameout(), ast_translator::dstfmt, ast_translator::frameout, LOG_WARNING, MAX_FORMAT, ast_translator::module, ast_translator::name, ast_translator::plc_samples, powerof(), rebuild_matrix(), ast_translator::srcfmt, and term_color().

00622 {
00623    static int added_cli = 0;
00624    struct ast_translator *u;
00625    char tmp[80];
00626 
00627    if (!mod) {
00628       ast_log(LOG_WARNING, "Missing module pointer, you need to supply one\n");
00629       return -1;
00630    }
00631 
00632    if (!t->buf_size) {
00633       ast_log(LOG_WARNING, "empty buf size, you need to supply one\n");
00634       return -1;
00635    }
00636 
00637    t->module = mod;
00638 
00639    t->srcfmt = powerof(t->srcfmt);
00640    t->dstfmt = powerof(t->dstfmt);
00641    t->active = 1;
00642 
00643    if (t->srcfmt == -1 || t->dstfmt == -1) {
00644       ast_log(LOG_WARNING, "Invalid translator path: (%s codec is not valid)\n", t->srcfmt == -1 ? "starting" : "ending");
00645       return -1;
00646    }
00647    if (t->plc_samples) {
00648       if (t->buffer_samples < t->plc_samples) {
00649          ast_log(LOG_WARNING, "plc_samples %d buffer_samples %d\n",
00650             t->plc_samples, t->buffer_samples);
00651          return -1;
00652       }
00653       if (t->dstfmt != powerof(AST_FORMAT_SLINEAR))
00654          ast_log(LOG_WARNING, "plc_samples %d format %x\n",
00655             t->plc_samples, t->dstfmt);
00656    }
00657    if (t->srcfmt >= MAX_FORMAT) {
00658       ast_log(LOG_WARNING, "Source format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt));
00659       return -1;
00660    }
00661 
00662    if (t->dstfmt >= MAX_FORMAT) {
00663       ast_log(LOG_WARNING, "Destination format %s is larger than MAX_FORMAT\n", ast_getformatname(t->dstfmt));
00664       return -1;
00665    }
00666 
00667    if (t->buf_size) {
00668       /*
00669        * Align buf_size properly, rounding up to the machine-specific
00670        * alignment for pointers.
00671        */
00672       struct _test_align { void *a, *b; } p;
00673       int align = (char *)&p.b - (char *)&p.a;
00674 
00675       t->buf_size = ((t->buf_size + align - 1) / align) * align;
00676    }
00677 
00678    if (t->frameout == NULL)
00679       t->frameout = default_frameout;
00680   
00681    calc_cost(t, 1);
00682 
00683    ast_verb(2, "Registered translator '%s' from format %s to %s, cost %d\n",
00684              term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
00685              ast_getformatname(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt), t->cost);
00686 
00687    if (!added_cli) {
00688       ast_cli_register_multiple(cli_translate, sizeof(cli_translate) / sizeof(struct ast_cli_entry));
00689       added_cli++;
00690    }
00691 
00692    AST_RWLIST_WRLOCK(&translators);
00693 
00694    /* find any existing translators that provide this same srcfmt/dstfmt,
00695       and put this one in order based on cost */
00696    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
00697       if ((u->srcfmt == t->srcfmt) &&
00698           (u->dstfmt == t->dstfmt) &&
00699           (u->cost > t->cost)) {
00700          AST_RWLIST_INSERT_BEFORE_CURRENT(t, list);
00701          t = NULL;
00702       }
00703    }
00704    AST_RWLIST_TRAVERSE_SAFE_END;
00705 
00706    /* if no existing translator was found for this format combination,
00707       add it to the beginning of the list */
00708    if (t)
00709       AST_RWLIST_INSERT_HEAD(&translators, t, list);
00710 
00711    rebuild_matrix(0);
00712 
00713    AST_RWLIST_UNLOCK(&translators);
00714 
00715    return 0;
00716 }

struct ast_frame* ast_trans_frameout ( struct ast_trans_pvt pvt,
int  datalen,
int  samples 
)

generic frameout function

Definition at line 214 of file translate.c.

References AST_FRAME_VOICE, AST_FRFLAG_FROM_TRANSLATOR, AST_FRIENDLY_OFFSET, ast_set_flag, ast_trans_pvt::datalen, ast_translator::dstfmt, f, ast_trans_pvt::f, ast_translator::name, ast_trans_pvt::outbuf, ast_trans_pvt::samples, and ast_trans_pvt::t.

Referenced by default_frameout(), lintoadpcm_frameout(), lintogsm_frameout(), lintoilbc_frameout(), and lintolpc10_frameout().

00216 {
00217    struct ast_frame *f = &pvt->f;
00218 
00219    if (samples)
00220       f->samples = samples;
00221    else {
00222       if (pvt->samples == 0)
00223          return NULL;
00224       f->samples = pvt->samples;
00225       pvt->samples = 0;
00226    }
00227    if (datalen)
00228       f->datalen = datalen;
00229    else {
00230       f->datalen = pvt->datalen;
00231       pvt->datalen = 0;
00232    }
00233 
00234    f->frametype = AST_FRAME_VOICE;
00235    f->subclass = 1 << (pvt->t->dstfmt);
00236    f->mallocd = 0;
00237    f->offset = AST_FRIENDLY_OFFSET;
00238    f->src = pvt->t->name;
00239    f->data = pvt->outbuf;
00240 
00241    ast_set_flag(f, AST_FRFLAG_FROM_TRANSLATOR);
00242 
00243    return f;
00244 }

struct ast_frame* ast_translate ( struct ast_trans_pvt tr,
struct ast_frame f,
int  consume 
)

translates one or more frames Apply an input frame into the translator and receive zero or one output frames. Consume determines whether the original frame should be freed

Parameters:
tr translator structure to use for translation
f frame to translate
consume Whether or not to free the original frame
Returns:
an ast_frame of the new translation format on success, NULL on failure

Definition at line 308 of file translate.c.

References ast_format_rate(), AST_FRAME_CNG, AST_FRFLAG_HAS_TIMING_INFO, ast_frfree, ast_samp2tv(), ast_set2_flag, ast_test_flag, ast_tv(), ast_tvadd(), ast_tveq(), ast_tvnow(), ast_tvsub(), ast_tvzero(), ast_frame::delivery, f, framein(), ast_frame::frametype, len(), ast_frame::len, ast_trans_pvt::next, ast_trans_pvt::nextin, ast_trans_pvt::nextout, ast_frame::samples, ast_frame::seqno, ast_frame::subclass, and ast_frame::ts.

Referenced by __ast_read(), ast_audiohook_read_frame(), ast_slinfactory_feed(), ast_write(), ast_writestream(), audio_audiohook_write_list(), conf_run(), and process_ast_dsp().

00309 {
00310    struct ast_trans_pvt *p = path;
00311    struct ast_frame *out = f;
00312    struct timeval delivery;
00313    int has_timing_info;
00314    long ts;
00315    long len;
00316    int seqno;
00317 
00318    has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO);
00319    ts = f->ts;
00320    len = f->len;
00321    seqno = f->seqno;
00322 
00323    /* XXX hmmm... check this below */
00324    if (!ast_tvzero(f->delivery)) {
00325       if (!ast_tvzero(path->nextin)) {
00326          /* Make sure this is in line with what we were expecting */
00327          if (!ast_tveq(path->nextin, f->delivery)) {
00328             /* The time has changed between what we expected and this
00329                most recent time on the new packet.  If we have a
00330                valid prediction adjust our output time appropriately */
00331             if (!ast_tvzero(path->nextout)) {
00332                path->nextout = ast_tvadd(path->nextout,
00333                           ast_tvsub(f->delivery, path->nextin));
00334             }
00335             path->nextin = f->delivery;
00336          }
00337       } else {
00338          /* This is our first pass.  Make sure the timing looks good */
00339          path->nextin = f->delivery;
00340          path->nextout = f->delivery;
00341       }
00342       /* Predict next incoming sample */
00343       path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(f->subclass)));
00344    }
00345    delivery = f->delivery;
00346    for ( ; out && p ; p = p->next) {
00347       framein(p, out);
00348       if (out != f)
00349          ast_frfree(out);
00350       out = p->t->frameout(p);
00351    }
00352    if (consume)
00353       ast_frfree(f);
00354    if (out == NULL)
00355       return NULL;
00356    /* we have a frame, play with times */
00357    if (!ast_tvzero(delivery)) {
00358       /* Regenerate prediction after a discontinuity */
00359       if (ast_tvzero(path->nextout))
00360          path->nextout = ast_tvnow();
00361 
00362       /* Use next predicted outgoing timestamp */
00363       out->delivery = path->nextout;
00364       
00365       /* Predict next outgoing timestamp from samples in this
00366          frame. */
00367       path->nextout = ast_tvadd(path->nextout, ast_samp2tv(out->samples, ast_format_rate(out->subclass)));
00368    } else {
00369       out->delivery = ast_tv(0, 0);
00370       ast_set2_flag(out, has_timing_info, AST_FRFLAG_HAS_TIMING_INFO);
00371       if (has_timing_info) {
00372          out->ts = ts;
00373          out->len = len;
00374          out->seqno = seqno;
00375       }
00376    }
00377    /* Invalidate prediction if we're entering a silence period */
00378    if (out->frametype == AST_FRAME_CNG)
00379       path->nextout = ast_tv(0, 0);
00380    return out;
00381 }

unsigned int ast_translate_available_formats ( unsigned int  dest,
unsigned int  src 
)

Mask off unavailable formats from a format bitmask.

Parameters:
dest possible destination formats
src source formats
Returns:
the destination formats that are available in the source or translatable
The result will include all formats from 'dest' that are either present in 'src' or translatable from a format present in 'src'.

Note:
Only a single audio format and a single video format can be present in 'src', or the function will produce unexpected results.

Definition at line 830 of file translate.c.

References AST_FORMAT_AUDIO_MASK, AST_FORMAT_VIDEO_MASK, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, powerof(), and tr_matrix.

Referenced by sip_call().

00831 {
00832    unsigned int res = dest;
00833    unsigned int x;
00834    unsigned int src_audio = src & AST_FORMAT_AUDIO_MASK;
00835    unsigned int src_video = src & AST_FORMAT_VIDEO_MASK;
00836 
00837    /* if we don't have a source format, we just have to try all
00838       possible destination formats */
00839    if (!src)
00840       return dest;
00841 
00842    /* If we have a source audio format, get its format index */
00843    if (src_audio)
00844       src_audio = powerof(src_audio);
00845 
00846    /* If we have a source video format, get its format index */
00847    if (src_video)
00848       src_video = powerof(src_video);
00849 
00850    AST_RWLIST_RDLOCK(&translators);
00851 
00852    /* For a given source audio format, traverse the list of
00853       known audio formats to determine whether there exists
00854       a translation path from the source format to the
00855       destination format. */
00856    for (x = 1; src_audio && (x & AST_FORMAT_AUDIO_MASK); x <<= 1) {
00857       /* if this is not a desired format, nothing to do */
00858       if (!dest & x)
00859          continue;
00860 
00861       /* if the source is supplying this format, then
00862          we can leave it in the result */
00863       if (src & x)
00864          continue;
00865 
00866       /* if we don't have a translation path from the src
00867          to this format, remove it from the result */
00868       if (!tr_matrix[src_audio][powerof(x)].step) {
00869          res &= ~x;
00870          continue;
00871       }
00872 
00873       /* now check the opposite direction */
00874       if (!tr_matrix[powerof(x)][src_audio].step)
00875          res &= ~x;
00876    }
00877 
00878    /* For a given source video format, traverse the list of
00879       known video formats to determine whether there exists
00880       a translation path from the source format to the
00881       destination format. */
00882    for (; src_video && (x & AST_FORMAT_VIDEO_MASK); x <<= 1) {
00883       /* if this is not a desired format, nothing to do */
00884       if (!dest & x)
00885          continue;
00886 
00887       /* if the source is supplying this format, then
00888          we can leave it in the result */
00889       if (src & x)
00890          continue;
00891 
00892       /* if we don't have a translation path from the src
00893          to this format, remove it from the result */
00894       if (!tr_matrix[src_video][powerof(x)].step) {
00895          res &= ~x;
00896          continue;
00897       }
00898 
00899       /* now check the opposite direction */
00900       if (!tr_matrix[powerof(x)][src_video].step)
00901          res &= ~x;
00902    }
00903 
00904    AST_RWLIST_UNLOCK(&translators);
00905 
00906    return res;
00907 }

void ast_translate_frame_freed ( struct ast_frame fr  ) 

Hint that a frame from a translator has been freed.

This is sort of a hack. This function gets called when ast_frame_free() gets called on a frame that has the AST_FRFLAG_FROM_TRANSLATOR flag set. This is because it is possible for a translation path to be destroyed while a frame from a translator is still in use. Specifically, this happens if a masquerade happens after a call to ast_read() but before the frame is done being processed, since the frame processing is generally done without the channel lock held.

Returns:
nothing

Definition at line 909 of file translate.c.

References ast_clear_flag, AST_FRFLAG_FROM_TRANSLATOR, destroy(), f, and ast_trans_pvt::pvt.

Referenced by __frame_free().

00910 {
00911    struct ast_trans_pvt *pvt;
00912 
00913    ast_clear_flag(fr, AST_FRFLAG_FROM_TRANSLATOR);
00914 
00915    pvt = (struct ast_trans_pvt *) (((char *) fr) - offsetof(struct ast_trans_pvt, f));
00916 
00917    if (!pvt->destroy)
00918       return;
00919    
00920    destroy(pvt);
00921 }

unsigned int ast_translate_path_steps ( unsigned int  dest,
unsigned int  src 
)

Returns the number of steps required to convert from 'src' to 'dest'.

Parameters:
dest destination format
src source format
Returns:
the number of translation steps required, or -1 if no path is available

Definition at line 808 of file translate.c.

References ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, LOG_WARNING, translator_path::multistep, powerof(), and tr_matrix.

Referenced by ast_channel_make_compatible_helper().

00809 {
00810    unsigned int res = -1;
00811 
00812    /* convert bitwise format numbers into array indices */
00813    src = powerof(src);
00814    dest = powerof(dest);
00815 
00816    if (src == -1 || dest == -1) {
00817       ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src == -1 ? "starting" : "ending");
00818       return -1;
00819    }
00820    AST_RWLIST_RDLOCK(&translators);
00821 
00822    if (tr_matrix[src][dest].step)
00823       res = tr_matrix[src][dest].multistep + 1;
00824 
00825    AST_RWLIST_UNLOCK(&translators);
00826 
00827    return res;
00828 }

void ast_translator_activate ( struct ast_translator t  ) 

Activate a previously deactivated translator.

Parameters:
t translator to activate
Returns:
nothing
Enables the specified translator for use.

Definition at line 744 of file translate.c.

References ast_translator::active, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and rebuild_matrix().

00745 {
00746    AST_RWLIST_WRLOCK(&translators);
00747    t->active = 1;
00748    rebuild_matrix(0);
00749    AST_RWLIST_UNLOCK(&translators);
00750 }

int ast_translator_best_choice ( int *  dsts,
int *  srcs 
)

Chooses the best translation path.

Given a list of sources, and a designed destination format, which should I choose?

Returns:
Returns 0 on success, -1 if no path could be found.
Note:
Modifies dests and srcs in place

Definition at line 761 of file translate.c.

References AST_FORMAT_AUDIO_MASK, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_translator::cost, translator_path::cost, MAX_AUDIO_FORMAT, translator_path::multistep, and tr_matrix.

Referenced by ast_channel_make_compatible_helper(), ast_request(), iax2_request(), and set_format().

00762 {
00763    int x,y;
00764    int best = -1;
00765    int bestdst = 0;
00766    int cur, cursrc;
00767    int besttime = INT_MAX;
00768    int beststeps = INT_MAX;
00769    int common = ((*dst) & (*srcs)) & AST_FORMAT_AUDIO_MASK; /* are there common formats ? */
00770 
00771    if (common) { /* yes, pick one and return */
00772       for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
00773          if (cur & common) /* guaranteed to find one */
00774             break;
00775       }
00776       /* We are done, this is a common format to both. */
00777       *srcs = *dst = cur;
00778       return 0;
00779    } else { /* No, we will need to translate */
00780       AST_RWLIST_RDLOCK(&translators);
00781       for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) {
00782          if (! (cur & *dst))
00783             continue;
00784          for (cursrc = 1, x = 0; x <= MAX_AUDIO_FORMAT; cursrc <<= 1, x++) {
00785             if (!(*srcs & cursrc) || !tr_matrix[x][y].step ||
00786                 tr_matrix[x][y].cost >  besttime)
00787                continue;   /* not existing or no better */
00788             if (tr_matrix[x][y].cost < besttime ||
00789                 tr_matrix[x][y].multistep < beststeps) {
00790                /* better than what we have so far */
00791                best = cursrc;
00792                bestdst = cur;
00793                besttime = tr_matrix[x][y].cost;
00794                beststeps = tr_matrix[x][y].multistep;
00795             }
00796          }
00797       }
00798       AST_RWLIST_UNLOCK(&translators);
00799       if (best > -1) {
00800          *srcs = best;
00801          *dst = bestdst;
00802          best = 0;
00803       }
00804       return best;
00805    }
00806 }

struct ast_trans_pvt* ast_translator_build_path ( int  dest,
int  source 
)

Builds a translator path Build a path (possibly NULL) from source to dest.

Parameters:
dest destination format
source source format
Returns:
ast_trans_pvt on success, NULL on failure

Definition at line 263 of file translate.c.

References ast_getformatname(), ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_translator_free_path(), ast_tv(), ast_translator::dstfmt, LOG_WARNING, newpvt(), ast_trans_pvt::next, ast_trans_pvt::nextin, ast_trans_pvt::nextout, powerof(), translator_path::step, ast_trans_pvt::t, and tr_matrix.

Referenced by ast_audiohook_read_frame(), ast_slinfactory_feed(), ast_writestream(), audio_audiohook_write_list(), conf_run(), misdn_set_opt_exec(), read_config(), and set_format().

00264 {
00265    struct ast_trans_pvt *head = NULL, *tail = NULL;
00266    
00267    source = powerof(source);
00268    dest = powerof(dest);
00269 
00270    if (source == -1 || dest == -1) {
00271       ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", source == -1 ? "starting" : "ending");
00272       return NULL;
00273    }
00274 
00275    AST_RWLIST_RDLOCK(&translators);
00276 
00277    while (source != dest) {
00278       struct ast_trans_pvt *cur;
00279       struct ast_translator *t = tr_matrix[source][dest].step;
00280       if (!t) {
00281          ast_log(LOG_WARNING, "No translator path from %s to %s\n", 
00282             ast_getformatname(source), ast_getformatname(dest));
00283          AST_RWLIST_UNLOCK(&translators);
00284          return NULL;
00285       }
00286       if (!(cur = newpvt(t))) {
00287          ast_log(LOG_WARNING, "Failed to build translator step from %d to %d\n", source, dest);
00288          if (head)
00289             ast_translator_free_path(head);  
00290          AST_RWLIST_UNLOCK(&translators);
00291          return NULL;
00292       }
00293       if (!head)
00294          head = cur;
00295       else
00296          tail->next = cur;
00297       tail = cur;
00298       cur->nextin = cur->nextout = ast_tv(0, 0);
00299       /* Keep going if this isn't the final destination */
00300       source = cur->t->dstfmt;
00301    }
00302 
00303    AST_RWLIST_UNLOCK(&translators);
00304    return head;
00305 }

void ast_translator_deactivate ( struct ast_translator t  ) 

Deactivate a translator.

Parameters:
t translator to deactivate
Returns:
nothing
Disables the specified translator from being used.

Definition at line 752 of file translate.c.

References ast_translator::active, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and rebuild_matrix().

00753 {
00754    AST_RWLIST_WRLOCK(&translators);
00755    t->active = 0;
00756    rebuild_matrix(0);
00757    AST_RWLIST_UNLOCK(&translators);
00758 }

void ast_translator_free_path ( struct ast_trans_pvt tr  ) 

Frees a translator path Frees the given translator path structure.

Parameters:
tr translator path to get rid of

Definition at line 253 of file translate.c.

References destroy(), and ast_trans_pvt::next.

Referenced by ast_audiohook_destroy(), ast_audiohook_detach_list(), ast_audiohook_read_frame(), ast_channel_free(), ast_slinfactory_destroy(), ast_slinfactory_feed(), ast_slinfactory_flush(), ast_translator_build_path(), ast_writestream(), audio_audiohook_write_list(), cl_dequeue_chan(), conf_free(), filestream_destructor(), free_translation(), and set_format().

00254 {
00255    struct ast_trans_pvt *pn = p;
00256    while ( (p = pn) ) {
00257       pn = p->next;
00258       destroy(p);
00259    }
00260 }

int ast_unregister_translator ( struct ast_translator t  ) 

Unregister a translator Unregisters the given tranlator.

Parameters:
t translator to unregister
Returns:
0 on success, -1 on failure

Definition at line 719 of file translate.c.

References ast_getformatname(), AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, COLOR_BLACK, COLOR_MAGENTA, ast_translator::dstfmt, ast_translator::list, ast_translator::name, rebuild_matrix(), ast_translator::srcfmt, and term_color().

Referenced by drop_translator(), load_module(), unload_module(), and unregister_translators().

00720 {
00721    char tmp[80];
00722    struct ast_translator *u;
00723    int found = 0;
00724 
00725    AST_RWLIST_WRLOCK(&translators);
00726    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
00727       if (u == t) {
00728          AST_RWLIST_REMOVE_CURRENT(list);
00729          ast_verb(2, "Unregistered translator '%s' from format %s to %s\n", term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), ast_getformatname(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt));
00730          found = 1;
00731          break;
00732       }
00733    }
00734    AST_RWLIST_TRAVERSE_SAFE_END;
00735 
00736    if (found)
00737       rebuild_matrix(0);
00738 
00739    AST_RWLIST_UNLOCK(&translators);
00740 
00741    return (u ? 0 : -1);
00742 }

static void calc_cost ( struct ast_translator t,
int  seconds 
) [static]

compute the cost of a single translation step

Definition at line 384 of file translate.c.

References ast_format_rate(), ast_frfree, ast_log(), ast_translator::cost, destroy(), ast_translator::dstfmt, f, framein(), ast_translator::frameout, LOG_WARNING, ast_translator::name, newpvt(), ast_trans_pvt::pvt, and ast_translator::sample.

Referenced by __ast_register_translator(), and rebuild_matrix().

00385 {
00386    int num_samples = 0;
00387    struct ast_trans_pvt *pvt;
00388    struct rusage start;
00389    struct rusage end;
00390    int cost;
00391    int out_rate = ast_format_rate(t->dstfmt);
00392 
00393    if (!seconds)
00394       seconds = 1;
00395    
00396    /* If they don't make samples, give them a terrible score */
00397    if (!t->sample) {
00398       ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
00399       t->cost = 999999;
00400       return;
00401    }
00402 
00403    pvt = newpvt(t);
00404    if (!pvt) {
00405       ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
00406       t->cost = 999999;
00407       return;
00408    }
00409 
00410    getrusage(RUSAGE_SELF, &start);
00411 
00412    /* Call the encoder until we've processed the required number of samples */
00413    while (num_samples < seconds * out_rate) {
00414       struct ast_frame *f = t->sample();
00415       if (!f) {
00416          ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
00417          destroy(pvt);
00418          t->cost = 999999;
00419          return;
00420       }
00421       framein(pvt, f);
00422       ast_frfree(f);
00423       while ((f = t->frameout(pvt))) {
00424          num_samples += f->samples;
00425          ast_frfree(f);
00426       }
00427    }
00428 
00429    getrusage(RUSAGE_SELF, &end);
00430 
00431    cost = ((end.ru_utime.tv_sec - start.ru_utime.tv_sec) * 1000000) + end.ru_utime.tv_usec - start.ru_utime.tv_usec;
00432    cost += ((end.ru_stime.tv_sec - start.ru_stime.tv_sec) * 1000000) + end.ru_stime.tv_usec - start.ru_stime.tv_usec;
00433 
00434    destroy(pvt);
00435 
00436    t->cost = cost / seconds;
00437 
00438    if (!t->cost)
00439       t->cost = 1;
00440 }

static struct ast_frame* default_frameout ( struct ast_trans_pvt pvt  )  [static]

Definition at line 246 of file translate.c.

References ast_trans_frameout().

Referenced by __ast_register_translator().

00247 {
00248    return ast_trans_frameout(pvt, 0, 0);
00249 }

static void destroy ( struct ast_trans_pvt pvt  )  [static]

Definition at line 133 of file translate.c.

References ast_free, AST_FRFLAG_FROM_TRANSLATOR, ast_module_unref(), ast_test_flag, ast_translator::destroy, ast_trans_pvt::destroy, ast_trans_pvt::f, ast_translator::module, and ast_trans_pvt::t.

Referenced by ast_translate_frame_freed(), ast_translator_free_path(), and calc_cost().

00134 {
00135    struct ast_translator *t = pvt->t;
00136 
00137    if (ast_test_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR)) {
00138       /* If this flag is still set, that means that the translation path has
00139        * been torn down, while we still have a frame out there being used.
00140        * When ast_frfree() gets called on that frame, this ast_trans_pvt
00141        * will get destroyed, too. */
00142 
00143       pvt->destroy = 1;
00144 
00145       return;
00146    }
00147 
00148    if (t->destroy)
00149       t->destroy(pvt);
00150    ast_free(pvt);
00151    ast_module_unref(t->module);
00152 }

static int framein ( struct ast_trans_pvt pvt,
struct ast_frame f 
) [static]

framein wrapper, deals with plc and bound checks.

Definition at line 155 of file translate.c.

References ast_copy_flags, AST_FRFLAG_HAS_TIMING_INFO, ast_log(), ast_translator::buffer_samples, ast_trans_pvt::datalen, f, ast_trans_pvt::f, ast_translator::framein, ast_frame::len, LOG_WARNING, ast_translator::name, ast_translator::native_plc, ast_trans_pvt::outbuf, ast_trans_pvt::plc, plc_fillin(), plc_rx(), ast_translator::plc_samples, ast_trans_pvt::samples, ast_frame::seqno, ast_trans_pvt::t, and ast_frame::ts.

Referenced by ast_translate(), and calc_cost().

00156 {
00157    int16_t *dst = (int16_t *)pvt->outbuf;
00158    int ret;
00159    int samples = pvt->samples;   /* initial value */
00160    
00161    /* Copy the last in jb timing info to the pvt */
00162    ast_copy_flags(&pvt->f, f, AST_FRFLAG_HAS_TIMING_INFO);
00163    pvt->f.ts = f->ts;
00164    pvt->f.len = f->len;
00165    pvt->f.seqno = f->seqno;
00166 
00167    if (f->samples == 0) {
00168       ast_log(LOG_WARNING, "no samples for %s\n", pvt->t->name);
00169    }
00170    if (pvt->t->buffer_samples) { /* do not pass empty frames to callback */
00171       if (f->datalen == 0) { /* perform PLC with nominal framesize of 20ms/160 samples */
00172          if (pvt->plc) {
00173             int l = pvt->t->plc_samples;
00174             if (pvt->samples + l > pvt->t->buffer_samples) {
00175                ast_log(LOG_WARNING, "Out of buffer space\n");
00176                return -1;
00177             }
00178             l = plc_fillin(pvt->plc, dst + pvt->samples, l);
00179             pvt->samples += l;
00180             pvt->datalen = pvt->samples * 2; /* SLIN has 2bytes for 1sample */
00181          }
00182          /* We don't want generic PLC. If the codec has native PLC, then do that */
00183          if (!pvt->t->native_plc)
00184             return 0;
00185       }
00186       if (pvt->samples + f->samples > pvt->t->buffer_samples) {
00187          ast_log(LOG_WARNING, "Out of buffer space\n");
00188          return -1;
00189       }
00190    }
00191    /* we require a framein routine, wouldn't know how to do
00192     * it otherwise.
00193     */
00194    ret = pvt->t->framein(pvt, f);
00195    /* possibly store data for plc */
00196    if (!ret && pvt->plc) {
00197       int l = pvt->t->plc_samples;
00198       if (pvt->samples < l)
00199          l = pvt->samples;
00200       plc_rx(pvt->plc, dst + pvt->samples - l, l);
00201    }
00202    /* diagnostic ... */
00203    if (pvt->samples == samples)
00204       ast_log(LOG_WARNING, "%s did not update samples %d\n",
00205          pvt->t->name, pvt->samples);
00206    return ret;
00207 }

static char* handle_cli_core_show_translation ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 518 of file translate.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_getformatname(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_str_alloca, ast_str_append(), ast_str_buffer, ast_str_set(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_translator::cost, ast_cli_args::fd, MAX_RECALC, rebuild_matrix(), SHOW_TRANS, tr_matrix, and ast_cli_entry::usage.

00519 {
00520 #define SHOW_TRANS 16
00521    int x, y, z;
00522    int curlen = 0, longest = 0, magnitude[SHOW_TRANS] = { 0, };
00523 
00524    switch (cmd) {
00525    case CLI_INIT:
00526       e->command = "core show translation [recalc]";
00527       e->usage =
00528          "Usage: core show translation [recalc [<recalc seconds>]]\n"
00529          "       Displays known codec translators and the cost associated\n"
00530          "       with each conversion.  If the argument 'recalc' is supplied along\n"
00531          "       with optional number of seconds to test a new test will be performed\n"
00532          "       as the chart is being displayed.\n";
00533       return NULL;
00534    case CLI_GENERATE:
00535       return NULL;
00536    }
00537 
00538    if (a->argc > 5)
00539       return CLI_SHOWUSAGE;
00540 
00541    if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) {
00542       z = a->argv[4] ? atoi(a->argv[4]) : 1;
00543 
00544       if (z <= 0) {
00545          ast_cli(a->fd, "         Recalc must be greater than 0.  Defaulting to 1.\n");
00546          z = 1;
00547       }
00548 
00549       if (z > MAX_RECALC) {
00550          ast_cli(a->fd, "         Maximum limit of recalc exceeded by %d, truncating value to %d\n", z - MAX_RECALC, MAX_RECALC);
00551          z = MAX_RECALC;
00552       }
00553       ast_cli(a->fd, "         Recalculating Codec Translation (number of sample seconds: %d)\n\n", z);
00554       AST_RWLIST_WRLOCK(&translators);
00555       rebuild_matrix(z);
00556       AST_RWLIST_UNLOCK(&translators);
00557    } else if (a->argc > 3)
00558       return CLI_SHOWUSAGE;
00559 
00560    AST_RWLIST_RDLOCK(&translators);
00561 
00562    ast_cli(a->fd, "         Translation times between formats (in microseconds) for one second of data\n");
00563    ast_cli(a->fd, "          Source Format (Rows) Destination Format (Columns)\n\n");
00564    /* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */
00565    for (x = 0; x < SHOW_TRANS; x++) {
00566       curlen = strlen(ast_getformatname(1 << (x)));
00567       if (curlen > longest)
00568          longest = curlen;
00569       for (y = 0; y < SHOW_TRANS; y++) {
00570          if (tr_matrix[x][y].cost > pow(10, magnitude[x])) {
00571             magnitude[y] = floor(log10(tr_matrix[x][y].cost));
00572          }
00573       }
00574    }
00575    for (x = -1; x < SHOW_TRANS; x++) {
00576       struct ast_str *out = ast_str_alloca(125);
00577       /*Go ahead and move to next iteration if dealing with an unknown codec*/
00578       if(x >= 0 && !strcmp(ast_getformatname(1 << (x)), "unknown"))
00579          continue;
00580       ast_str_set(&out, -1, " ");
00581       for (y = -1; y < SHOW_TRANS; y++) {
00582          /*Go ahead and move to next iteration if dealing with an unknown codec*/
00583          if (y >= 0 && !strcmp(ast_getformatname(1 << (y)), "unknown"))
00584             continue;
00585          if (y >= 0)
00586             curlen = strlen(ast_getformatname(1 << (y)));
00587          if (y >= 0 && magnitude[y] + 1 > curlen) {
00588             curlen = magnitude[y] + 1;
00589          }
00590          if (curlen < 5)
00591             curlen = 5;
00592          if (x >= 0 && y >= 0 && tr_matrix[x][y].step) {
00593             /* Actual codec output */
00594             ast_str_append(&out, -1, "%*d", curlen + 1, tr_matrix[x][y].cost);
00595          } else if (x == -1 && y >= 0) {
00596             /* Top row - use a dynamic size */
00597             ast_str_append(&out, -1, "%*s", curlen + 1, ast_getformatname(1 << (y)) );
00598          } else if (y == -1 && x >= 0) {
00599             /* Left column - use a static size. */
00600             ast_str_append(&out, -1, "%*s", longest, ast_getformatname(1 << (x)) );
00601          } else if (x >= 0 && y >= 0) {
00602             /* Codec not supported */
00603             ast_str_append(&out, -1, "%*s", curlen + 1, "-");
00604          } else {
00605             /* Upper left hand corner */
00606             ast_str_append(&out, -1, "%*s", longest, "");
00607          }
00608       }
00609       ast_str_append(&out, -1, "\n");
00610       ast_cli(a->fd, "%s", ast_str_buffer(out));
00611    }
00612    AST_RWLIST_UNLOCK(&translators);
00613    return CLI_SUCCESS;
00614 }

static void* newpvt ( struct ast_translator t  )  [static]

Allocate the descriptor, required outbuf space, and possibly also plc and desc.

Definition at line 93 of file translate.c.

References ast_calloc, ast_free, AST_FRIENDLY_OFFSET, ast_module_ref(), ast_translator::buf_size, ast_translator::desc_size, len(), ast_translator::module, ast_translator::newpvt, ast_translator::plc_samples, ast_trans_pvt::pvt, ast_trans_pvt::t, and ast_translator::useplc.

Referenced by ast_translator_build_path(), and calc_cost().

00094 {
00095    struct ast_trans_pvt *pvt;
00096    int len;
00097    int useplc = t->plc_samples > 0 && t->useplc;   /* cache, because it can change on the fly */
00098    char *ofs;
00099 
00100    /*
00101     * compute the required size adding private descriptor,
00102     * plc, buffer, AST_FRIENDLY_OFFSET.
00103     */
00104    len = sizeof(*pvt) + t->desc_size;
00105    if (useplc)
00106       len += sizeof(plc_state_t);
00107    if (t->buf_size)
00108       len += AST_FRIENDLY_OFFSET + t->buf_size;
00109    pvt = ast_calloc(1, len);
00110    if (!pvt)
00111       return NULL;
00112    pvt->t = t;
00113    ofs = (char *)(pvt + 1);   /* pointer to data space */
00114    if (t->desc_size) {     /* first comes the descriptor */
00115       pvt->pvt = ofs;
00116       ofs += t->desc_size;
00117    }
00118    if (useplc) {        /* then plc state */
00119       pvt->plc = (plc_state_t *)ofs;
00120       ofs += sizeof(plc_state_t);
00121    }
00122    if (t->buf_size)     /* finally buffer and header */
00123       pvt->outbuf = ofs + AST_FRIENDLY_OFFSET;
00124    /* call local init routine, if present */
00125    if (t->newpvt && t->newpvt(pvt)) {
00126       ast_free(pvt);
00127       return NULL;
00128    }
00129    ast_module_ref(t->module);
00130    return pvt;
00131 }

static force_inline int powerof ( unsigned int  d  )  [static]

returns the index of the lowest bit set

Definition at line 73 of file translate.c.

References ast_log(), and LOG_WARNING.

Referenced by __ast_register_translator(), agents_show(), ast_translate_available_formats(), ast_translate_path_steps(), and ast_translator_build_path().

00074 {
00075    int x = ffs(d);
00076 
00077    if (x)
00078       return x - 1;
00079 
00080    ast_log(LOG_WARNING, "No bits set? %d\n", d);
00081 
00082    return -1;
00083 }

static void rebuild_matrix ( int  samples  )  [static]

rebuild a translation matrix.

Note:
This function expects the list of translators to be locked

Definition at line 446 of file translate.c.

References ast_translator::active, ast_debug, ast_getformatname(), AST_RWLIST_TRAVERSE, calc_cost(), ast_translator::cost, ast_translator::dstfmt, ast_translator::list, MAX_FORMAT, ast_translator::srcfmt, and tr_matrix.

Referenced by __ast_register_translator(), ast_translator_activate(), ast_translator_deactivate(), ast_unregister_translator(), and handle_cli_core_show_translation().

00447 {
00448    struct ast_translator *t;
00449    int x;      /* source format index */
00450    int y;      /* intermediate format index */
00451    int z;      /* destination format index */
00452 
00453    ast_debug(1, "Resetting translation matrix\n");
00454 
00455    memset(tr_matrix, '\0', sizeof(tr_matrix));
00456 
00457    /* first, compute all direct costs */
00458    AST_RWLIST_TRAVERSE(&translators, t, list) {
00459       if (!t->active)
00460          continue;
00461 
00462       x = t->srcfmt;
00463       z = t->dstfmt;
00464 
00465       if (samples)
00466          calc_cost(t, samples);
00467      
00468       if (!tr_matrix[x][z].step || t->cost < tr_matrix[x][z].cost) {
00469          tr_matrix[x][z].step = t;
00470          tr_matrix[x][z].cost = t->cost;
00471       }
00472    }
00473 
00474    /*
00475     * For each triple x, y, z of distinct formats, check if there is
00476     * a path from x to z through y which is cheaper than what is
00477     * currently known, and in case, update the matrix.
00478     * Repeat until the matrix is stable.
00479     */
00480    for (;;) {
00481       int changed = 0;
00482       for (x = 0; x < MAX_FORMAT; x++) {      /* source format */
00483          for (y = 0; y < MAX_FORMAT; y++) {    /* intermediate format */
00484             if (x == y)                     /* skip ourselves */
00485                continue;
00486 
00487             for (z = 0; z<MAX_FORMAT; z++) {  /* dst format */
00488                int newcost;
00489 
00490                if (z == x || z == y)       /* skip null conversions */
00491                   continue;
00492                if (!tr_matrix[x][y].step)  /* no path from x to y */
00493                   continue;
00494                if (!tr_matrix[y][z].step)  /* no path from y to z */
00495                   continue;
00496                newcost = tr_matrix[x][y].cost + tr_matrix[y][z].cost;
00497                if (tr_matrix[x][z].step && newcost >= tr_matrix[x][z].cost)
00498                   continue;               /* x->y->z is more expensive than
00499                                            * the existing path */
00500                /* ok, we can get from x to z via y with a cost that
00501                   is the sum of the transition from x to y and
00502                   from y to z */
00503                    
00504                tr_matrix[x][z].step = tr_matrix[x][y].step;
00505                tr_matrix[x][z].cost = newcost;
00506                tr_matrix[x][z].multistep = 1;
00507                ast_debug(3, "Discovered %d cost path from %s to %s, via %s\n", tr_matrix[x][z].cost,
00508                     ast_getformatname(1 << x), ast_getformatname(1 << z), ast_getformatname(1 << y));
00509                changed++;
00510             }
00511          }
00512       }
00513       if (!changed)
00514          break;
00515    }
00516 }


Variable Documentation

struct ast_cli_entry cli_translate[] [static]

Initial value:

 {
   { .handler =  handle_cli_core_show_translation , .summary =  "Display translation matrix" ,__VA_ARGS__ }
}

Definition at line 616 of file translate.c.

Referenced by __ast_register_translator().

struct translator_path tr_matrix[MAX_FORMAT][MAX_FORMAT] [static]

a matrix that, for any pair of supported formats, indicates the total cost of translation and the first step. The full path can be reconstricted iterating on the matrix until step->dstfmt == desired_format.

Array indexes are 'src' and 'dest', in that order.

Note: the lock in the 'translators' list is also used to protect this structure.

Definition at line 64 of file translate.c.

Referenced by ast_translate_available_formats(), ast_translate_path_steps(), ast_translator_best_choice(), ast_translator_build_path(), handle_cli_core_show_translation(), and rebuild_matrix().


Generated on Thu Jul 9 13:41:34 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7