Wed Oct 28 15:49:23 2009

Asterisk developer's documentation


translate.c File Reference

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

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/logger.h"
#include "asterisk/translate.h"
#include "asterisk/options.h"
#include "asterisk/frame.h"
#include "asterisk/sched.h"
#include "asterisk/cli.h"
#include "asterisk/term.h"

Include dependency graph for translate.c:

Go to the source code of this file.

Data Structures

struct  ast_frame_delivery
struct  ast_trans_pvt
struct  ast_translator_dir

Defines

#define MAX_RECALC   200
#define SHOW_TRANS   11

Functions

 AST_MUTEX_DEFINE_STATIC (list_lock)
int ast_register_translator (struct ast_translator *t)
struct ast_frameast_translate (struct ast_trans_pvt *path, struct ast_frame *f, int consume)
int ast_translator_best_choice (int *dst, int *srcs)
 Calculate our best translator source format, given costs, and a desired destination.
struct ast_trans_pvtast_translator_build_path (int dest, int source)
void ast_translator_free_path (struct ast_trans_pvt *p)
int ast_unregister_translator (struct ast_translator *t)
 unregister codec translator
static void calc_cost (struct ast_translator *t, int samples)
static int powerof (int d)
static void rebuild_matrix (int samples)
 Use the list of translators to build a translation matrix.
static int show_translation (int fd, int argc, char *argv[])
 CLI "show translation" command handler.

Variables

static int added_cli = 0
static struct ast_translatorlist = NULL
static struct ast_cli_entry show_trans
static char show_trans_usage []
static struct ast_translator_dir tr_matrix [MAX_FORMAT][MAX_FORMAT]


Detailed Description

Translate via the use of pseudo channels.

Definition in file translate.c.


Define Documentation

#define MAX_RECALC   200

Definition at line 47 of file translate.c.

Referenced by show_translation().

#define SHOW_TRANS   11

Referenced by show_translation().


Function Documentation

AST_MUTEX_DEFINE_STATIC ( list_lock   ) 

Note:
This could all be done more efficiently *IF* we chained packets together by default, but it would also complicate virtually every application.

int ast_register_translator ( struct ast_translator t  ) 

Register a translator

Parameters:
t populated ast_translator structure This registers a codec translator with asterisk Returns 0 on success, -1 on failure

Definition at line 396 of file translate.c.

References ast_cli_register(), ast_getformatname(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), calc_cost(), COLOR_BLACK, COLOR_MAGENTA, ast_translator::cost, ast_translator::dstfmt, LOG_WARNING, MAX_FORMAT, ast_translator::name, ast_translator::next, option_verbose, powerof(), rebuild_matrix(), ast_translator::srcfmt, term_color(), and VERBOSE_PREFIX_2.

Referenced by load_module(), and register_translator().

00397 {
00398    char tmp[80];
00399    t->srcfmt = powerof(t->srcfmt);
00400    t->dstfmt = powerof(t->dstfmt);
00401    if (t->srcfmt >= MAX_FORMAT) {
00402       ast_log(LOG_WARNING, "Source format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt));
00403       return -1;
00404    }
00405    if (t->dstfmt >= MAX_FORMAT) {
00406       ast_log(LOG_WARNING, "Destination format %s is larger than MAX_FORMAT\n", ast_getformatname(t->dstfmt));
00407       return -1;
00408    }
00409    calc_cost(t,1);
00410    if (option_verbose > 1)
00411       ast_verbose(VERBOSE_PREFIX_2 "Registered translator '%s' from format %s to %s, cost %d\n", term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), ast_getformatname(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt), t->cost);
00412    ast_mutex_lock(&list_lock);
00413    if (!added_cli) {
00414       ast_cli_register(&show_trans);
00415       added_cli++;
00416    }
00417    t->next = list;
00418    list = t;
00419    rebuild_matrix(0);
00420    ast_mutex_unlock(&list_lock);
00421    return 0;
00422 }

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

translates one or more frames

Parameters:
tr translator structure to use for translation
f frame to translate
consume Whether or not to free the original frame Apply an input frame into the translator and receive zero or one output frames. Consume determines whether the original frame should be freed Returns an ast_frame of the new translation format on success, NULL on failure

Definition at line 155 of file translate.c.

References AST_FRAME_CNG, ast_frfree(), ast_log(), ast_tvadd(), ast_tvsub(), ast_frame::delivery, ast_translator::framein, ast_frame::frametype, LOG_WARNING, ast_frame::next, ast_trans_pvt::nextin, ast_trans_pvt::nextout, ast_frame::samples, and ast_trans_pvt::step.

Referenced by ast_read(), ast_slinfactory_feed(), ast_write(), ast_writestream(), process_ast_dsp(), and queue_frame_to_spies().

00156 {
00157    struct ast_trans_pvt *p;
00158    struct ast_frame *out;
00159    struct timeval delivery;
00160    p = path;
00161    /* Feed the first frame into the first translator */
00162    p->step->framein(p->state, f);
00163    if (!ast_tvzero(f->delivery)) {
00164       if (!ast_tvzero(path->nextin)) {
00165          /* Make sure this is in line with what we were expecting */
00166          if (!ast_tveq(path->nextin, f->delivery)) {
00167             /* The time has changed between what we expected and this
00168                most recent time on the new packet.  If we have a
00169                valid prediction adjust our output time appropriately */
00170             if (!ast_tvzero(path->nextout)) {
00171                path->nextout = ast_tvadd(path->nextout,
00172                           ast_tvsub(f->delivery, path->nextin));
00173             }
00174             path->nextin = f->delivery;
00175          }
00176       } else {
00177          /* This is our first pass.  Make sure the timing looks good */
00178          path->nextin = f->delivery;
00179          path->nextout = f->delivery;
00180       }
00181       /* Predict next incoming sample */
00182       path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, 8000));
00183    }
00184    delivery = f->delivery;
00185    if (consume)
00186       ast_frfree(f);
00187    while(p) {
00188       out = p->step->frameout(p->state);
00189       /* If we get nothing out, return NULL */
00190       if (!out)
00191          return NULL;
00192       /* If there is a next state, feed it in there.  If not,
00193          return this frame  */
00194       if (p->next) 
00195          p->next->step->framein(p->next->state, out);
00196       else {
00197          if (!ast_tvzero(delivery)) {
00198             /* Regenerate prediction after a discontinuity */
00199             if (ast_tvzero(path->nextout))
00200                path->nextout = ast_tvnow();
00201 
00202             /* Use next predicted outgoing timestamp */
00203             out->delivery = path->nextout;
00204             
00205             /* Predict next outgoing timestamp from samples in this
00206                frame. */
00207             path->nextout = ast_tvadd(path->nextout, ast_samp2tv( out->samples, 8000));
00208          } else {
00209             out->delivery = ast_tv(0, 0);
00210          }
00211          /* Invalidate prediction if we're entering a silence period */
00212          if (out->frametype == AST_FRAME_CNG)
00213             path->nextout = ast_tv(0, 0);
00214          return out;
00215       }
00216       p = p->next;
00217    }
00218    ast_log(LOG_WARNING, "I should never get here...\n");
00219    return NULL;
00220 }

int ast_translator_best_choice ( int *  dsts,
int *  srcs 
)

Calculate our best translator source format, given costs, and a desired destination.

Chooses the best translation path

Given a list of sources, and a designed destination format, which should I choose? Returns 0 on success, -1 if no path could be found. Modifies dests and srcs in place

Definition at line 450 of file translate.c.

References ast_mutex_lock(), ast_mutex_unlock(), ast_translator_dir::cost, ast_translator::cost, MAX_FORMAT, ast_translator_dir::multistep, and tr_matrix.

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

00451 {
00452    int x,y;
00453    int best = -1;
00454    int bestdst = 0;
00455    int cur = 1;
00456    int besttime = INT_MAX;
00457    int beststeps = INT_MAX;
00458    int common;
00459 
00460    if ((common = (*dst) & (*srcs))) {
00461       /* We have a format in common */
00462       for (y = 0; y < MAX_FORMAT; y++) {
00463          if (cur & common) {
00464             /* This is a common format to both.  Pick it if we don't have one already */
00465             bestdst = cur;
00466             best = cur;
00467          }
00468          cur = cur << 1;
00469       }
00470    } else {
00471       /* We will need to translate */
00472       ast_mutex_lock(&list_lock);
00473       for (y = 0; y < MAX_FORMAT; y++) {
00474          if (!(cur & *dst)) {
00475             cur = cur << 1;
00476             continue;
00477          }
00478 
00479          for (x = 0; x < MAX_FORMAT; x++) {
00480             if ((*srcs & (1 << x)) &&        /* x is a valid source format */
00481                 tr_matrix[x][y].step) {         /* There's a step */
00482                if (tr_matrix[x][y].cost > besttime)
00483                   continue;         /* It's more expensive, skip it */
00484                
00485                if (tr_matrix[x][y].cost == besttime &&
00486                    tr_matrix[x][y].multistep >= beststeps)
00487                   continue;         /* It requires the same (or more) steps,
00488                                  skip it */
00489 
00490                /* It's better than what we have so far */
00491                best = 1 << x;
00492                bestdst = cur;
00493                besttime = tr_matrix[x][y].cost;
00494                beststeps = tr_matrix[x][y].multistep;
00495             }
00496          }
00497          cur = cur << 1;
00498       }
00499       ast_mutex_unlock(&list_lock);
00500    }
00501 
00502    if (best > -1) {
00503       *srcs = best;
00504       *dst = bestdst;
00505       best = 0;
00506    }
00507 
00508    return best;
00509 }

struct ast_trans_pvt* ast_translator_build_path ( int  dest,
int  source 
) [read]

Build a set of translators based upon the given source and destination formats

Definition at line 106 of file translate.c.

References ast_getformatname(), ast_log(), ast_translator_free_path(), LOG_WARNING, malloc, ast_translator::newpvt, ast_trans_pvt::next, ast_trans_pvt::nextin, powerof(), ast_translator_dir::step, ast_trans_pvt::step, and tr_matrix.

Referenced by ast_slinfactory_feed(), ast_writestream(), misdn_set_opt_exec(), queue_frame_to_spies(), and set_format().

00107 {
00108    struct ast_trans_pvt *tmpr = NULL, *tmp = NULL;
00109    
00110    source = powerof(source);
00111    dest = powerof(dest);
00112    
00113    while(source != dest) {
00114       if (!tr_matrix[source][dest].step) {
00115          /* We shouldn't have allocated any memory */
00116          ast_log(LOG_WARNING, "No translator path from %s to %s\n", 
00117             ast_getformatname(source), ast_getformatname(dest));
00118          return NULL;
00119       }
00120 
00121       if (tmp) {
00122          tmp->next = malloc(sizeof(*tmp));
00123          tmp = tmp->next;
00124       } else
00125          tmp = malloc(sizeof(*tmp));
00126          
00127       if (!tmp) {
00128          ast_log(LOG_WARNING, "Out of memory\n");
00129          if (tmpr)
00130             ast_translator_free_path(tmpr);  
00131          return NULL;
00132       }
00133 
00134       /* Set the root, if it doesn't exist yet... */
00135       if (!tmpr)
00136          tmpr = tmp;
00137 
00138       tmp->next = NULL;
00139       tmp->nextin = tmp->nextout = ast_tv(0, 0);
00140       tmp->step = tr_matrix[source][dest].step;
00141       tmp->state = tmp->step->newpvt();
00142       
00143       if (!tmp->state) {
00144          ast_log(LOG_WARNING, "Failed to build translator step from %d to %d\n", source, dest);
00145          ast_translator_free_path(tmpr);  
00146          return NULL;
00147       }
00148       
00149       /* Keep going if this isn't the final destination */
00150       source = tmp->step->dstfmt;
00151    }
00152    return tmpr;
00153 }

void ast_translator_free_path ( struct ast_trans_pvt tr  ) 

Frees a translator path

Parameters:
tr translator path to get rid of Frees the given translator path structure

Definition at line 92 of file translate.c.

References ast_translator::destroy, free, ast_trans_pvt::next, ast_trans_pvt::state, and ast_trans_pvt::step.

Referenced by ast_channel_free(), ast_closestream(), ast_slinfactory_destroy(), ast_slinfactory_feed(), ast_translator_build_path(), ast_writestream(), cl_dequeue_chan(), free_translation(), pvt_destructor(), queue_frame_to_spies(), set_format(), and spy_cleanup().

00093 {
00094    struct ast_trans_pvt *pl, *pn;
00095    pn = p;
00096    while(pn) {
00097       pl = pn;
00098       pn = pn->next;
00099       if (pl->state && pl->step->destroy)
00100          pl->step->destroy(pl->state);
00101       free(pl);
00102    }
00103 }

int ast_unregister_translator ( struct ast_translator t  ) 

unregister codec translator

Unregister a translator

Parameters:
t translator to unregister Unregisters the given tranlator Returns 0 on success, -1 on failure

Definition at line 425 of file translate.c.

References ast_getformatname(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), COLOR_BLACK, COLOR_MAGENTA, ast_translator::dstfmt, ast_translator::name, ast_translator::next, option_verbose, rebuild_matrix(), ast_translator::srcfmt, term_color(), and VERBOSE_PREFIX_2.

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

00426 {
00427    char tmp[80];
00428    struct ast_translator *u, *ul = NULL;
00429    ast_mutex_lock(&list_lock);
00430    u = list;
00431    while(u) {
00432       if (u == t) {
00433          if (ul)
00434             ul->next = u->next;
00435          else
00436             list = u->next;
00437          if (option_verbose > 1)
00438             ast_verbose(VERBOSE_PREFIX_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));
00439          break;
00440       }
00441       ul = u;
00442       u = u->next;
00443    }
00444    rebuild_matrix(0);
00445    ast_mutex_unlock(&list_lock);
00446    return (u ? 0 : -1);
00447 }

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

Definition at line 223 of file translate.c.

References ast_frfree(), ast_log(), ast_translator::cost, ast_translator::destroy, ast_translator::framein, ast_translator::frameout, LOG_WARNING, ast_translator::name, ast_translator::newpvt, ast_translator::sample, and ast_frame::samples.

Referenced by ast_register_translator(), and rebuild_matrix().

00224 {
00225    int sofar=0;
00226    struct ast_translator_pvt *pvt;
00227    struct ast_frame *f, *out;
00228    struct timeval start;
00229    int cost;
00230 
00231    if(!samples)
00232       samples = 1;
00233    
00234    /* If they don't make samples, give them a terrible score */
00235    if (!t->sample) {
00236       ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
00237       t->cost = 99999;
00238       return;
00239    }
00240    pvt = t->newpvt();
00241    if (!pvt) {
00242       ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
00243       t->cost = 99999;
00244       return;
00245    }
00246    start = ast_tvnow();
00247    /* Call the encoder until we've processed one second of time */
00248    while(sofar < samples * 8000) {
00249       f = t->sample();
00250       if (!f) {
00251          ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
00252          t->destroy(pvt);
00253          t->cost = 99999;
00254          return;
00255       }
00256       t->framein(pvt, f);
00257       ast_frfree(f);
00258       while((out = t->frameout(pvt))) {
00259          sofar += out->samples;
00260          ast_frfree(out);
00261       }
00262    }
00263    cost = ast_tvdiff_ms(ast_tvnow(), start);
00264    t->destroy(pvt);
00265    t->cost = cost / samples;
00266    if (!t->cost)
00267       t->cost = 1;
00268 }

static int powerof ( int  d  )  [static]

Definition at line 82 of file translate.c.

References ast_log(), and LOG_WARNING.

Referenced by agents_show(), ast_register_translator(), and ast_translator_build_path().

00083 {
00084    int x;
00085    for (x = 0; x < 32; x++)
00086       if ((1 << x) & d)
00087          return x;
00088    ast_log(LOG_WARNING, "Powerof %d: No power??\n", d);
00089    return -1;
00090 }

static void rebuild_matrix ( int  samples  )  [static]

Use the list of translators to build a translation matrix.

Definition at line 271 of file translate.c.

References ast_getformatname(), ast_log(), calc_cost(), ast_translator::cost, ast_translator_dir::cost, ast_translator::dstfmt, LOG_DEBUG, MAX_FORMAT, ast_translator_dir::multistep, ast_translator::next, option_debug, ast_translator::srcfmt, ast_translator_dir::step, t, and tr_matrix.

Referenced by ast_register_translator(), ast_unregister_translator(), and show_translation().

00272 {
00273    struct ast_translator *t;
00274    int changed;
00275    int x, y, z;
00276 
00277    if (option_debug)
00278       ast_log(LOG_DEBUG, "Resetting translation matrix\n");
00279 
00280    bzero(tr_matrix, sizeof(tr_matrix));
00281 
00282    for (t = list; t; t = t->next) {
00283       if (samples)
00284          calc_cost(t, samples);
00285      
00286       if (!tr_matrix[t->srcfmt][t->dstfmt].step ||
00287           tr_matrix[t->srcfmt][t->dstfmt].cost > t->cost) {
00288          tr_matrix[t->srcfmt][t->dstfmt].step = t;
00289          tr_matrix[t->srcfmt][t->dstfmt].cost = t->cost;
00290       }
00291    }
00292 
00293    do {
00294       changed = 0;
00295 
00296       /* Don't you just love O(N^3) operations? */
00297       for (x = 0; x< MAX_FORMAT; x++) {         /* For each source format */
00298          for (y = 0; y < MAX_FORMAT; y++) {     /* And each destination format */
00299             if (x == y)          /* Except ourselves, of course */
00300                continue;
00301 
00302             for (z=0; z < MAX_FORMAT; z++) {    /* And each format it might convert to */
00303                if ((x == z) || (y == z))  /* Don't ever convert back to us */
00304                   continue;
00305 
00306                if (tr_matrix[x][y].step &&   /* We can convert from x to y */
00307                    tr_matrix[y][z].step &&   /* And from y to z and... */
00308                    (!tr_matrix[x][z].step ||    /* Either there isn't an x->z conversion */
00309                     (tr_matrix[x][y].cost + 
00310                      tr_matrix[y][z].cost <  /* Or we're cheaper than the existing */
00311                      tr_matrix[x][z].cost)   /* solution */
00312                       )) {
00313                   /* We can get from x to z via y with a cost that
00314                      is the sum of the transition from x to y and
00315                      from y to z */
00316                   
00317                   tr_matrix[x][z].step = tr_matrix[x][y].step;
00318                   tr_matrix[x][z].cost = tr_matrix[x][y].cost + 
00319                      tr_matrix[y][z].cost;
00320                   tr_matrix[x][z].multistep = 1;
00321                   if (option_debug)
00322                      ast_log(LOG_DEBUG, "Discovered %d cost path from %s to %s, via %d\n", tr_matrix[x][z].cost, ast_getformatname(x), ast_getformatname(z), y);
00323                   changed++;
00324                }
00325             }
00326          }
00327       }
00328    } while (changed);
00329 }

static int show_translation ( int  fd,
int  argc,
char *  argv[] 
) [static]

CLI "show translation" command handler.

Definition at line 333 of file translate.c.

References ast_cli(), ast_getformatname(), ast_mutex_lock(), ast_mutex_unlock(), ast_translator::cost, MAX_RECALC, rebuild_matrix(), RESULT_SHOWUSAGE, RESULT_SUCCESS, SHOW_TRANS, and tr_matrix.

00334 {
00335 #define SHOW_TRANS 11
00336    int x, y, z;
00337    char line[80];
00338    if (argc > 4) 
00339       return RESULT_SHOWUSAGE;
00340 
00341    ast_mutex_lock(&list_lock);
00342    if (argv[2] && !strcasecmp(argv[2],"recalc")) {
00343       z = argv[3] ? atoi(argv[3]) : 1;
00344 
00345       if (z <= 0) {
00346          ast_cli(fd,"         C'mon let's be serious here... defaulting to 1.\n");
00347          z = 1;
00348       }
00349 
00350       if (z > MAX_RECALC) {
00351          ast_cli(fd,"         Maximum limit of recalc exceeded by %d, truncating value to %d\n",z-MAX_RECALC,MAX_RECALC);
00352          z = MAX_RECALC;
00353       }
00354       ast_cli(fd,"         Recalculating Codec Translation (number of sample seconds: %d)\n\n",z);
00355       rebuild_matrix(z);
00356    }
00357 
00358    ast_cli(fd, "         Translation times between formats (in milliseconds)\n");
00359    ast_cli(fd, "          Source Format (Rows) Destination Format(Columns)\n\n");
00360    for (x = -1; x < SHOW_TRANS; x++) {
00361       /* next 2 lines run faster than using strcpy() */
00362       line[0] = ' ';
00363       line[1] = '\0';
00364       for (y=-1;y<SHOW_TRANS;y++) {
00365          if (x >= 0 && y >= 0 && tr_matrix[x][y].step)
00366             snprintf(line + strlen(line), sizeof(line) - strlen(line), " %5d", tr_matrix[x][y].cost >= 99999 ? tr_matrix[x][y].cost-99999 : tr_matrix[x][y].cost);
00367          else
00368             if (((x == -1 && y >= 0) || (y == -1 && x >= 0))) {
00369                snprintf(line + strlen(line), sizeof(line) - strlen(line), 
00370                   " %5s", ast_getformatname(1<<(x+y+1)) );
00371             } else if (x != -1 && y != -1) {
00372                snprintf(line + strlen(line), sizeof(line) - strlen(line), "     -");
00373             } else {
00374                snprintf(line + strlen(line), sizeof(line) - strlen(line), "      ");
00375             }
00376       }
00377       snprintf(line + strlen(line), sizeof(line) - strlen(line), "\n");
00378       ast_cli(fd, line);         
00379    }
00380    ast_mutex_unlock(&list_lock);
00381    return RESULT_SUCCESS;
00382 }


Variable Documentation

int added_cli = 0 [static]

Definition at line 384 of file translate.c.

struct ast_translator* list = NULL [static]

Definition at line 54 of file translate.c.

struct ast_cli_entry show_trans [static]

Initial value:

{ { "show", "translation", NULL }, show_translation, "Display translation matrix", show_trans_usage }

Definition at line 393 of file translate.c.

char show_trans_usage[] [static]

Definition at line 386 of file translate.c.

struct ast_translator_dir tr_matrix[MAX_FORMAT][MAX_FORMAT] [static]


Generated on Wed Oct 28 15:49:23 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6