1999-12-05 02:03:40 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
1999-12-05 02:03:40 +00:00
*
2006-02-25 05:11:44 +00:00
* Copyright ( C ) 1999 - 2006 , Digium , Inc .
1999-12-05 02:03:40 +00:00
*
2004-12-06 21:53:57 +00:00
* Mark Spencer < markster @ digium . com >
1999-12-05 02:03:40 +00:00
*
2005-09-14 20:46:50 +00:00
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
1999-12-05 02:03:40 +00:00
* This program is free software , distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
2005-10-24 20:12:06 +00:00
/*! \file
2005-09-14 20:46:50 +00:00
*
2005-10-24 20:12:06 +00:00
* \ brief Translate via the use of pseudo channels
2005-12-30 21:18:06 +00:00
*
* \ author Mark Spencer < markster @ digium . com >
1999-12-05 02:03:40 +00:00
*/
2006-06-07 18:54:56 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2005-04-29 17:24:58 +00:00
# include <sys/types.h>
2005-04-22 13:11:34 +00:00
# include <sys/socket.h>
# include <sys/time.h>
# include <unistd.h>
# include <stdlib.h>
# include <string.h>
# include <stdio.h>
2005-04-21 06:02:45 +00:00
# include "asterisk/lock.h"
# include "asterisk/channel.h"
# include "asterisk/logger.h"
# include "asterisk/translate.h"
2006-04-14 14:08:19 +00:00
# include "asterisk/module.h"
2005-04-21 06:02:45 +00:00
# include "asterisk/options.h"
# include "asterisk/frame.h"
# include "asterisk/sched.h"
# include "asterisk/cli.h"
# include "asterisk/term.h"
1999-12-05 02:03:40 +00:00
2004-05-17 22:59:27 +00:00
# define MAX_RECALC 200 /* max sample recalc */
2006-04-08 21:40:57 +00:00
/*! \brief the list of translators */
2006-01-11 05:00:45 +00:00
static AST_LIST_HEAD_STATIC ( translators , ast_translator ) ;
1999-12-05 02:03:40 +00:00
2006-04-08 21:40:57 +00:00
struct translator_path {
2005-11-14 19:00:38 +00:00
struct ast_translator * step ; /*!< Next step translator */
2006-02-25 05:11:44 +00:00
unsigned int cost ; /*!< Complete cost to destination */
unsigned int multistep ; /*!< Multiple conversions required for this translation */
1999-12-05 02:03:40 +00:00
} ;
2006-04-08 21:40:57 +00:00
/*! \brief 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 .
2006-04-17 16:42:03 +00:00
*
* Array indexes are ' src ' and ' dest ' , in that order .
2006-04-08 21:40:57 +00:00
*/
static struct translator_path tr_matrix [ MAX_FORMAT ] [ MAX_FORMAT ] ;
1999-12-05 02:03:40 +00:00
2006-06-04 08:15:41 +00:00
/*! \todo
2006-04-08 21:40:57 +00:00
* TODO : sample frames for each supported input format .
* We build this on the fly , by taking an SLIN frame and using
* the existing converter to play with it .
*/
1999-12-05 02:03:40 +00:00
2006-06-04 08:15:41 +00:00
/*! \brief returns the index of the lowest bit set */
2006-06-13 20:59:15 +00:00
static force_inline int powerof ( unsigned int d )
1999-12-05 02:03:40 +00:00
{
2006-06-13 20:59:15 +00:00
int x = ffs ( d ) ;
if ( x )
return x - 1 ;
ast_log ( LOG_WARNING , " No bits set? %d \n " , d ) ;
1999-12-05 02:03:40 +00:00
return - 1 ;
}
2006-04-08 21:40:57 +00:00
/*
* wrappers around the translator routines .
*/
/*!
* \ brief Allocate the descriptor , required outbuf space ,
* and possibly also plc and desc .
*/
static void * newpvt ( struct ast_translator * t )
{
struct ast_trans_pvt * pvt ;
int len ;
int useplc = t - > plc_samples > 0 & & t - > useplc ; /* cache, because it can change on the fly */
char * ofs ;
2006-04-14 14:08:19 +00:00
2006-04-08 21:40:57 +00:00
/*
* compute the required size adding private descriptor ,
* plc , buffer , AST_FRIENDLY_OFFSET .
*/
len = sizeof ( * pvt ) + t - > desc_size ;
if ( useplc )
len + = sizeof ( plc_state_t ) ;
if ( t - > buf_size )
len + = AST_FRIENDLY_OFFSET + t - > buf_size ;
pvt = ast_calloc ( 1 , len ) ;
if ( ! pvt )
return NULL ;
pvt - > t = t ;
ofs = ( char * ) ( pvt + 1 ) ; /* pointer to data space */
if ( t - > desc_size ) { /* first comes the descriptor */
pvt - > pvt = ofs ;
ofs + = t - > desc_size ;
}
if ( useplc ) { /* then plc state */
pvt - > plc = ( plc_state_t * ) ofs ;
ofs + = sizeof ( plc_state_t ) ;
}
if ( t - > buf_size ) /* finally buffer and header */
pvt - > outbuf = ofs + AST_FRIENDLY_OFFSET ;
/* call local init routine, if present */
2006-06-24 19:43:31 +00:00
if ( t - > newpvt & & t - > newpvt ( pvt ) ) {
2006-04-08 21:40:57 +00:00
free ( pvt ) ;
return NULL ;
}
2006-08-21 02:11:39 +00:00
ast_module_ref ( t - > module ) ;
2006-04-08 21:40:57 +00:00
return pvt ;
}
static void destroy ( struct ast_trans_pvt * pvt )
{
struct ast_translator * t = pvt - > t ;
if ( t - > destroy )
t - > destroy ( pvt ) ;
free ( pvt ) ;
2006-08-21 02:11:39 +00:00
ast_module_unref ( t - > module ) ;
2006-04-08 21:40:57 +00:00
}
2006-06-04 08:15:41 +00:00
/*! \brief framein wrapper, deals with plc and bound checks. */
2006-04-08 21:40:57 +00:00
static int framein ( struct ast_trans_pvt * pvt , struct ast_frame * f )
{
int16_t * dst = ( int16_t * ) pvt - > outbuf ;
int ret ;
int samples = pvt - > samples ; /* initial value */
2006-05-31 16:56:50 +00:00
/* Copy the last in jb timing info to the pvt */
pvt - > f . has_timing_info = f - > has_timing_info ;
pvt - > f . ts = f - > ts ;
pvt - > f . len = f - > len ;
pvt - > f . seqno = f - > seqno ;
2006-04-08 21:40:57 +00:00
if ( f - > samples = = 0 ) {
ast_log ( LOG_WARNING , " no samples for %s \n " , pvt - > t - > name ) ;
}
if ( pvt - > t - > buffer_samples ) { /* do not pass empty frames to callback */
if ( f - > datalen = = 0 ) { /* perform PLC with nominal framesize of 20ms/160 samples */
if ( pvt - > plc ) {
int l = pvt - > t - > plc_samples ;
if ( pvt - > samples + l > pvt - > t - > buffer_samples ) {
ast_log ( LOG_WARNING , " Out of buffer space \n " ) ;
return - 1 ;
}
l = plc_fillin ( pvt - > plc , dst + pvt - > samples , l ) ;
pvt - > samples + = l ;
}
return 0 ;
}
if ( pvt - > samples + f - > samples > pvt - > t - > buffer_samples ) {
ast_log ( LOG_WARNING , " Out of buffer space \n " ) ;
return - 1 ;
}
}
/* we require a framein routine, wouldn't know how to do
* it otherwise .
*/
ret = pvt - > t - > framein ( pvt , f ) ;
/* possibly store data for plc */
if ( ! ret & & pvt - > plc ) {
int l = pvt - > t - > plc_samples ;
if ( pvt - > samples < l )
l = pvt - > samples ;
plc_rx ( pvt - > plc , dst + pvt - > samples - l , l ) ;
}
/* diagnostic ... */
if ( pvt - > samples = = samples )
ast_log ( LOG_WARNING , " %s did not update samples %d \n " ,
pvt - > t - > name , pvt - > samples ) ;
return ret ;
}
2006-06-04 08:15:41 +00:00
/*! \brief generic frameout routine.
2006-04-08 21:40:57 +00:00
* If samples and datalen are 0 , take whatever is in pvt
* and reset them , otherwise take the values in the caller and
* leave alone the pvt values .
*/
struct ast_frame * ast_trans_frameout ( struct ast_trans_pvt * pvt ,
int datalen , int samples )
{
struct ast_frame * f = & pvt - > f ;
if ( samples )
f - > samples = samples ;
else {
if ( pvt - > samples = = 0 )
return NULL ;
f - > samples = pvt - > samples ;
pvt - > samples = 0 ;
}
if ( datalen )
f - > datalen = datalen ;
else {
f - > datalen = pvt - > datalen ;
pvt - > datalen = 0 ;
}
f - > frametype = AST_FRAME_VOICE ;
f - > subclass = 1 < < ( pvt - > t - > dstfmt ) ;
f - > mallocd = 0 ;
f - > offset = AST_FRIENDLY_OFFSET ;
f - > src = pvt - > t - > name ;
f - > data = pvt - > outbuf ;
return f ;
}
static struct ast_frame * default_frameout ( struct ast_trans_pvt * pvt )
{
return ast_trans_frameout ( pvt , 0 , 0 ) ;
}
/* end of callback wrappers and helpers */
1999-12-05 02:03:40 +00:00
void ast_translator_free_path ( struct ast_trans_pvt * p )
{
2006-04-08 21:40:57 +00:00
struct ast_trans_pvt * pn = p ;
while ( ( p = pn ) ) {
pn = p - > next ;
destroy ( p ) ;
1999-12-05 02:03:40 +00:00
}
}
2006-06-04 08:15:41 +00:00
/*! \brief Build a chain of translators based upon the given source and dest formats */
2001-03-22 04:20:13 +00:00
struct ast_trans_pvt * ast_translator_build_path ( int dest , int source )
1999-12-05 02:03:40 +00:00
{
2006-04-08 21:40:57 +00:00
struct ast_trans_pvt * head = NULL , * tail = NULL ;
2005-07-25 19:10:38 +00:00
1999-12-05 02:03:40 +00:00
source = powerof ( source ) ;
dest = powerof ( dest ) ;
2005-07-25 19:10:38 +00:00
2006-03-29 04:09:31 +00:00
while ( source ! = dest ) {
2006-04-08 21:40:57 +00:00
struct ast_trans_pvt * cur ;
struct ast_translator * t = tr_matrix [ source ] [ dest ] . step ;
if ( ! t ) {
2003-08-16 05:10:35 +00:00
ast_log ( LOG_WARNING , " No translator path from %s to %s \n " ,
ast_getformatname ( source ) , ast_getformatname ( dest ) ) ;
2000-01-05 20:03:55 +00:00
return NULL ;
1999-12-05 02:03:40 +00:00
}
2006-04-08 21:40:57 +00:00
if ( ! ( cur = newpvt ( t ) ) ) {
2005-07-25 19:10:38 +00:00
ast_log ( LOG_WARNING , " Failed to build translator step from %d to %d \n " , source , dest ) ;
2006-04-08 21:40:57 +00:00
if ( head )
ast_translator_free_path ( head ) ;
2005-07-25 19:10:38 +00:00
return NULL ;
}
2006-04-08 21:40:57 +00:00
if ( ! head )
head = cur ;
else
tail - > next = cur ;
tail = cur ;
cur - > nextin = cur - > nextout = ast_tv ( 0 , 0 ) ;
2005-07-25 19:10:38 +00:00
/* Keep going if this isn't the final destination */
2006-04-08 21:40:57 +00:00
source = cur - > t - > dstfmt ;
1999-12-05 02:03:40 +00:00
}
2006-04-08 21:40:57 +00:00
return head ;
1999-12-05 02:03:40 +00:00
}
2006-04-08 21:40:57 +00:00
/*! \brief do the actual translation */
2001-03-22 04:20:13 +00:00
struct ast_frame * ast_translate ( struct ast_trans_pvt * path , struct ast_frame * f , int consume )
1999-12-05 02:03:40 +00:00
{
2006-04-08 21:40:57 +00:00
struct ast_trans_pvt * p = path ;
struct ast_frame * out = f ;
2004-04-20 15:28:58 +00:00
struct timeval delivery ;
2006-05-31 16:56:50 +00:00
int has_timing_info ;
long ts ;
long len ;
int seqno ;
has_timing_info = f - > has_timing_info ;
ts = f - > ts ;
len = f - > len ;
seqno = f - > seqno ;
2006-04-08 21:40:57 +00:00
/* XXX hmmm... check this below */
2005-07-15 23:00:47 +00:00
if ( ! ast_tvzero ( f - > delivery ) ) {
if ( ! ast_tvzero ( path - > nextin ) ) {
2004-04-05 20:47:44 +00:00
/* Make sure this is in line with what we were expecting */
2005-07-15 23:00:47 +00:00
if ( ! ast_tveq ( path - > nextin , f - > delivery ) ) {
2004-04-05 20:47:44 +00:00
/* The time has changed between what we expected and this
2005-07-25 19:41:39 +00:00
most recent time on the new packet . If we have a
valid prediction adjust our output time appropriately */
if ( ! ast_tvzero ( path - > nextout ) ) {
path - > nextout = ast_tvadd ( path - > nextout ,
ast_tvsub ( f - > delivery , path - > nextin ) ) ;
}
2005-07-15 23:00:47 +00:00
path - > nextin = f - > delivery ;
2004-04-05 20:47:44 +00:00
}
} else {
/* This is our first pass. Make sure the timing looks good */
2005-07-15 23:00:47 +00:00
path - > nextin = f - > delivery ;
path - > nextout = f - > delivery ;
2004-04-05 20:47:44 +00:00
}
/* Predict next incoming sample */
2005-07-15 23:00:47 +00:00
path - > nextin = ast_tvadd ( path - > nextin , ast_samp2tv ( f - > samples , 8000 ) ) ;
2004-04-05 19:45:53 +00:00
}
2005-07-15 23:00:47 +00:00
delivery = f - > delivery ;
2006-04-08 21:40:57 +00:00
for ( ; out & & p ; p = p - > next ) {
framein ( p , out ) ;
out = p - > t - > frameout ( p ) ;
}
2001-03-22 04:20:13 +00:00
if ( consume )
ast_frfree ( f ) ;
2006-04-08 21:40:57 +00:00
if ( out = = NULL )
return NULL ;
/* we have a frame, play with times */
if ( ! ast_tvzero ( delivery ) ) {
/* Regenerate prediction after a discontinuity */
if ( ast_tvzero ( path - > nextout ) )
path - > nextout = ast_tvnow ( ) ;
/* Use next predicted outgoing timestamp */
out - > delivery = path - > nextout ;
/* Predict next outgoing timestamp from samples in this
frame . */
path - > nextout = ast_tvadd ( path - > nextout , ast_samp2tv ( out - > samples , 8000 ) ) ;
} else {
out - > delivery = ast_tv ( 0 , 0 ) ;
2006-05-31 16:56:50 +00:00
out - > has_timing_info = has_timing_info ;
if ( has_timing_info ) {
out - > ts = ts ;
out - > len = len ;
out - > seqno = seqno ;
}
1999-12-05 02:03:40 +00:00
}
2006-04-08 21:40:57 +00:00
/* Invalidate prediction if we're entering a silence period */
if ( out - > frametype = = AST_FRAME_CNG )
path - > nextout = ast_tv ( 0 , 0 ) ;
return out ;
1999-12-05 02:03:40 +00:00
}
2006-04-08 21:40:57 +00:00
/*! \brief compute the cost of a single translation step */
static void calc_cost ( struct ast_translator * t , int seconds )
2004-05-17 22:59:27 +00:00
{
int sofar = 0 ;
2006-04-08 21:40:57 +00:00
struct ast_trans_pvt * pvt ;
2005-07-15 23:00:47 +00:00
struct timeval start ;
2004-05-17 22:59:27 +00:00
int cost ;
2005-11-14 19:00:38 +00:00
2006-04-08 21:40:57 +00:00
if ( ! seconds )
seconds = 1 ;
2004-05-17 22:59:27 +00:00
/* If they don't make samples, give them a terrible score */
if ( ! t - > sample ) {
ast_log ( LOG_WARNING , " Translator '%s' does not produce sample frames. \n " , t - > name ) ;
t - > cost = 99999 ;
return ;
}
2006-04-08 21:40:57 +00:00
pvt = newpvt ( t ) ;
2004-05-17 22:59:27 +00:00
if ( ! pvt ) {
ast_log ( LOG_WARNING , " Translator '%s' appears to be broken and will probably fail. \n " , t - > name ) ;
t - > cost = 99999 ;
return ;
}
2005-07-15 23:00:47 +00:00
start = ast_tvnow ( ) ;
2006-04-08 21:40:57 +00:00
/* Call the encoder until we've processed the required number of samples */
while ( sofar < seconds * 8000 ) {
struct ast_frame * f = t - > sample ( ) ;
2004-05-17 22:59:27 +00:00
if ( ! f ) {
ast_log ( LOG_WARNING , " Translator '%s' failed to produce a sample frame. \n " , t - > name ) ;
2006-04-08 21:40:57 +00:00
destroy ( pvt ) ;
2004-05-17 22:59:27 +00:00
t - > cost = 99999 ;
return ;
}
2006-04-08 21:40:57 +00:00
framein ( pvt , f ) ;
2004-05-17 22:59:27 +00:00
ast_frfree ( f ) ;
2006-07-10 19:05:48 +00:00
while ( ( f = t - > frameout ( pvt ) ) ) {
2006-04-08 21:40:57 +00:00
sofar + = f - > samples ;
ast_frfree ( f ) ;
2004-05-17 22:59:27 +00:00
}
}
2005-07-15 23:00:47 +00:00
cost = ast_tvdiff_ms ( ast_tvnow ( ) , start ) ;
2006-04-08 21:40:57 +00:00
destroy ( pvt ) ;
t - > cost = cost / seconds ;
2004-05-17 22:59:27 +00:00
if ( ! t - > cost )
t - > cost = 1 ;
}
2006-04-08 21:40:57 +00:00
/*!
* \ brief rebuild a translation matrix .
* \ note This function expects the list of translators to be locked
2006-01-11 05:00:45 +00:00
*/
2004-05-17 22:59:27 +00:00
static void rebuild_matrix ( int samples )
1999-12-05 02:03:40 +00:00
{
struct ast_translator * t ;
2006-07-10 19:05:48 +00:00
int x ; /* source format index */
int y ; /* intermediate format index */
int z ; /* destination format index */
2005-11-14 19:00:38 +00:00
1999-12-05 02:03:40 +00:00
if ( option_debug )
2005-11-14 19:00:38 +00:00
ast_log ( LOG_DEBUG , " Resetting translation matrix \n " ) ;
2006-02-25 05:11:44 +00:00
1999-12-05 02:03:40 +00:00
bzero ( tr_matrix , sizeof ( tr_matrix ) ) ;
2006-04-18 21:39:20 +00:00
2006-04-08 21:40:57 +00:00
/* first, compute all direct costs */
2006-01-11 05:00:45 +00:00
AST_LIST_TRAVERSE ( & translators , t , list ) {
2006-04-08 21:40:57 +00:00
x = t - > srcfmt ;
z = t - > dstfmt ;
2006-02-25 05:11:44 +00:00
if ( samples )
2005-11-14 19:00:38 +00:00
calc_cost ( t , samples ) ;
2004-05-17 22:59:27 +00:00
2006-04-08 21:40:57 +00:00
if ( ! tr_matrix [ x ] [ z ] . step | | t - > cost < tr_matrix [ x ] [ z ] . cost ) {
tr_matrix [ x ] [ z ] . step = t ;
tr_matrix [ x ] [ z ] . cost = t - > cost ;
1999-12-05 02:03:40 +00:00
}
}
2006-04-18 21:39:20 +00:00
2006-04-08 21:40:57 +00:00
/*
* For each triple x , y , z of distinct formats , check if there is
* a path from x to z through y which is cheaper than what is
* currently known , and in case , update the matrix .
* Repeat until the matrix is stable .
*/
for ( ; ; ) {
int changed = 0 ;
2006-07-10 19:05:48 +00:00
for ( x = 0 ; x < MAX_FORMAT ; x + + ) { /* source format */
for ( y = 0 ; y < MAX_FORMAT ; y + + ) { /* intermediate format */
if ( x = = y ) /* skip ourselves */
2006-02-25 05:11:44 +00:00
continue ;
2006-07-10 19:05:48 +00:00
for ( z = 0 ; z < MAX_FORMAT ; z + + ) { /* dst format */
2006-04-08 21:40:57 +00:00
int newcost ;
2006-02-25 05:11:44 +00:00
2006-07-10 19:05:48 +00:00
if ( z = = x | | z = = y ) /* skip null conversions */
2006-04-08 21:40:57 +00:00
continue ;
2006-07-10 19:05:48 +00:00
if ( ! tr_matrix [ x ] [ y ] . step ) /* no path from x to y */
2006-04-08 21:40:57 +00:00
continue ;
2006-07-10 19:05:48 +00:00
if ( ! tr_matrix [ y ] [ z ] . step ) /* no path from y to z */
2006-04-08 21:40:57 +00:00
continue ;
newcost = tr_matrix [ x ] [ y ] . cost + tr_matrix [ y ] [ z ] . cost ;
if ( tr_matrix [ x ] [ z ] . step & & newcost > = tr_matrix [ x ] [ z ] . cost )
2006-07-10 19:05:48 +00:00
continue ; /* x->y->z is more expensive than
* the existing path */
2006-04-08 21:40:57 +00:00
/* ok, we can get from x to z via y with a cost that
is the sum of the transition from x to y and
from y to z */
tr_matrix [ x ] [ z ] . step = tr_matrix [ x ] [ y ] . step ;
tr_matrix [ x ] [ z ] . cost = newcost ;
tr_matrix [ x ] [ z ] . multistep = 1 ;
if ( option_debug )
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 ) ;
changed + + ;
2006-02-25 05:11:44 +00:00
}
}
}
2006-04-08 21:40:57 +00:00
if ( ! changed )
break ;
}
1999-12-05 02:03:40 +00:00
}
2005-11-14 19:00:38 +00:00
/*! \brief CLI "show translation" command handler */
2000-01-05 20:03:55 +00:00
static int show_translation ( int fd , int argc , char * argv [ ] )
{
2006-08-16 03:48:36 +00:00
# define SHOW_TRANS 12
2004-06-22 20:11:15 +00:00
int x , y , z ;
2006-08-16 03:48:36 +00:00
int curlen = 0 , longest = 0 ;
2006-04-08 21:40:57 +00:00
2004-05-17 22:59:27 +00:00
if ( argc > 4 )
2000-01-05 20:03:55 +00:00
return RESULT_SHOWUSAGE ;
2004-05-17 22:59:27 +00:00
2006-01-11 05:00:45 +00:00
AST_LIST_LOCK ( & translators ) ;
2006-07-10 19:05:48 +00:00
if ( argv [ 2 ] & & ! strcasecmp ( argv [ 2 ] , " recalc " ) ) {
2004-06-22 20:11:15 +00:00
z = argv [ 3 ] ? atoi ( argv [ 3 ] ) : 1 ;
2004-05-17 22:59:27 +00:00
2004-06-22 20:11:15 +00:00
if ( z < = 0 ) {
2006-07-10 19:05:48 +00:00
ast_cli ( fd , " C'mon let's be serious here... defaulting to 1. \n " ) ;
2004-06-22 20:11:15 +00:00
z = 1 ;
}
2004-05-17 22:59:27 +00:00
2004-06-22 20:11:15 +00:00
if ( z > MAX_RECALC ) {
2006-07-10 19:05:48 +00:00
ast_cli ( fd , " Maximum limit of recalc exceeded by %d, truncating value to %d \n " , z - MAX_RECALC , MAX_RECALC ) ;
2004-06-22 20:11:15 +00:00
z = MAX_RECALC ;
}
2006-07-10 19:05:48 +00:00
ast_cli ( fd , " Recalculating Codec Translation (number of sample seconds: %d) \n \n " , z ) ;
2004-06-22 20:11:15 +00:00
rebuild_matrix ( z ) ;
2004-05-17 22:59:27 +00:00
}
2003-08-16 05:10:35 +00:00
ast_cli ( fd , " Translation times between formats (in milliseconds) \n " ) ;
2006-08-16 03:48:36 +00:00
ast_cli ( fd , " Source Format (Rows) Destination Format (Columns) \n \n " ) ;
/* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */
for ( x = 0 ; x < SHOW_TRANS ; x + + ) {
curlen = strlen ( ast_getformatname ( 1 < < ( x + 1 ) ) ) ;
if ( curlen > longest )
longest = curlen ;
}
2005-11-14 19:00:38 +00:00
for ( x = - 1 ; x < SHOW_TRANS ; x + + ) {
2006-04-08 21:40:57 +00:00
char line [ 80 ] ;
char * buf = line ;
2006-04-11 15:52:06 +00:00
size_t left = sizeof ( line ) - 1 ; /* one initial space */
2006-04-08 21:40:57 +00:00
/* next 2 lines run faster than using ast_build_string() */
* buf + + = ' ' ;
* buf = ' \0 ' ;
2006-07-10 19:05:48 +00:00
for ( y = - 1 ; y < SHOW_TRANS ; y + + ) {
2006-08-16 03:48:36 +00:00
curlen = strlen ( ast_getformatname ( 1 < < ( y ) ) ) ;
if ( x > = 0 & & y > = 0 & & tr_matrix [ x ] [ y ] . step ) {
/* XXX 999 is a little hackish
We don ' t want this number being larger than the shortest ( or current ) codec
For now , that is " gsm " */
ast_build_string ( & buf , & left , " %*d " , curlen + 1 , tr_matrix [ x ] [ y ] . cost > 999 ? 0 : tr_matrix [ x ] [ y ] . cost ) ;
} else if ( x = = - 1 & & y > = 0 ) {
/* Top row - use a dynamic size */
ast_build_string ( & buf , & left , " %*s " , curlen + 1 , ast_getformatname ( 1 < < ( x + y + 1 ) ) ) ;
} else if ( y = = - 1 & & x > = 0 ) {
/* Left column - use a static size. */
ast_build_string ( & buf , & left , " %*s " , longest , ast_getformatname ( 1 < < ( x + y + 1 ) ) ) ;
} else if ( x > = 0 & & y > = 0 ) {
ast_build_string ( & buf , & left , " %*s " , curlen + 1 , " - " ) ;
2006-04-08 21:40:57 +00:00
} else {
2006-08-16 03:48:36 +00:00
ast_build_string ( & buf , & left , " %*s " , longest , " " ) ;
2006-04-08 21:40:57 +00:00
}
2000-01-05 20:03:55 +00:00
}
2006-04-08 21:40:57 +00:00
ast_build_string ( & buf , & left , " \n " ) ;
2000-01-05 20:03:55 +00:00
ast_cli ( fd , line ) ;
}
2006-01-11 05:00:45 +00:00
AST_LIST_UNLOCK ( & translators ) ;
2000-01-05 20:03:55 +00:00
return RESULT_SUCCESS ;
}
static char show_trans_usage [ ] =
2004-05-17 22:59:27 +00:00
" Usage: show translation [recalc] [<recalc seconds>] \n "
2000-01-05 20:03:55 +00:00
" Displays known codec translators and the cost associated \n "
2005-11-14 19:00:38 +00:00
" with each conversion. If the argument 'recalc' is supplied along \n "
2004-05-17 22:59:27 +00:00
" with optional number of seconds to test a new test will be performed \n "
" as the chart is being displayed. \n " ;
2000-01-05 20:03:55 +00:00
static struct ast_cli_entry show_trans =
{ { " show " , " translation " , NULL } , show_translation , " Display translation matrix " , show_trans_usage } ;
2006-06-04 08:15:41 +00:00
/*! \brief register codec translator */
2006-08-21 02:11:39 +00:00
int __ast_register_translator ( struct ast_translator * t , struct ast_module * mod )
1999-12-05 02:03:40 +00:00
{
2006-04-08 21:40:57 +00:00
static int added_cli = 0 ;
2006-08-21 02:11:39 +00:00
if ( ! mod ) {
2006-04-14 14:08:19 +00:00
ast_log ( LOG_WARNING , " Missing module pointer, you need to supply one \n " ) ;
2006-04-08 21:40:57 +00:00
return - 1 ;
}
2006-08-21 02:11:39 +00:00
if ( ! t - > buf_size ) {
2006-04-08 21:40:57 +00:00
ast_log ( LOG_WARNING , " empty buf size, you need to supply one \n " ) ;
return - 1 ;
}
2006-08-21 02:11:39 +00:00
t - > module = mod ;
2006-04-08 21:40:57 +00:00
if ( t - > plc_samples ) {
if ( t - > buffer_samples < t - > plc_samples ) {
ast_log ( LOG_WARNING , " plc_samples %d buffer_samples %d \n " ,
t - > plc_samples , t - > buffer_samples ) ;
return - 1 ;
}
if ( t - > dstfmt ! = AST_FORMAT_SLINEAR )
ast_log ( LOG_WARNING , " plc_samples %d format %x \n " ,
t - > plc_samples , t - > dstfmt ) ;
}
1999-12-05 02:03:40 +00:00
t - > srcfmt = powerof ( t - > srcfmt ) ;
t - > dstfmt = powerof ( t - > dstfmt ) ;
2006-04-08 21:40:57 +00:00
/* XXX maybe check that it is not existing yet ? */
2005-07-05 14:00:03 +00:00
if ( t - > srcfmt > = MAX_FORMAT ) {
ast_log ( LOG_WARNING , " Source format %s is larger than MAX_FORMAT \n " , ast_getformatname ( t - > srcfmt ) ) ;
return - 1 ;
}
if ( t - > dstfmt > = MAX_FORMAT ) {
ast_log ( LOG_WARNING , " Destination format %s is larger than MAX_FORMAT \n " , ast_getformatname ( t - > dstfmt ) ) ;
1999-12-05 02:03:40 +00:00
return - 1 ;
}
2006-04-08 21:40:57 +00:00
if ( t - > buf_size ) {
/*
* Align buf_size properly , rounding up to the machine - specific
* alignment for pointers .
*/
struct _test_align { void * a , * b ; } p ;
int align = ( char * ) & p . b - ( char * ) & p . a ;
2006-07-10 19:05:48 +00:00
t - > buf_size = ( ( t - > buf_size + align - 1 ) / align ) * align ;
2006-04-08 21:40:57 +00:00
}
if ( t - > frameout = = NULL )
t - > frameout = default_frameout ;
2006-07-10 19:05:48 +00:00
calc_cost ( t , 1 ) ;
2006-04-08 21:40:57 +00:00
if ( option_verbose > 1 ) {
char tmp [ 80 ] ;
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 ) ;
}
2006-01-11 05:00:45 +00:00
AST_LIST_LOCK ( & translators ) ;
2000-01-05 20:03:55 +00:00
if ( ! added_cli ) {
ast_cli_register ( & show_trans ) ;
added_cli + + ;
}
2006-01-11 05:00:45 +00:00
AST_LIST_INSERT_HEAD ( & translators , t , list ) ;
2004-05-17 22:59:27 +00:00
rebuild_matrix ( 0 ) ;
2006-01-11 05:00:45 +00:00
AST_LIST_UNLOCK ( & translators ) ;
1999-12-05 02:03:40 +00:00
return 0 ;
}
2005-11-14 19:00:38 +00:00
/*! \brief unregister codec translator */
1999-12-05 02:03:40 +00:00
int ast_unregister_translator ( struct ast_translator * t )
{
2004-04-21 04:26:38 +00:00
char tmp [ 80 ] ;
2006-01-11 05:00:45 +00:00
struct ast_translator * u ;
AST_LIST_LOCK ( & translators ) ;
AST_LIST_TRAVERSE_SAFE_BEGIN ( & translators , u , list ) {
1999-12-05 02:03:40 +00:00
if ( u = = t ) {
2006-01-11 05:00:45 +00:00
AST_LIST_REMOVE_CURRENT ( & translators , list ) ;
2004-04-21 04:26:38 +00:00
if ( option_verbose > 1 )
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 ) ) ;
1999-12-05 02:03:40 +00:00
break ;
}
}
2006-01-11 05:00:45 +00:00
AST_LIST_TRAVERSE_SAFE_END
2004-05-17 22:59:27 +00:00
rebuild_matrix ( 0 ) ;
2006-01-11 05:00:45 +00:00
AST_LIST_UNLOCK ( & translators ) ;
1999-12-05 02:03:40 +00:00
return ( u ? 0 : - 1 ) ;
}
2005-11-14 19:00:38 +00:00
/*! \brief Calculate our best translator source format, given costs, and a desired destination */
2001-03-22 04:20:13 +00:00
int ast_translator_best_choice ( int * dst , int * srcs )
1999-12-05 02:03:40 +00:00
{
2000-01-05 20:03:55 +00:00
int x , y ;
2005-04-04 03:28:38 +00:00
int best = - 1 ;
int bestdst = 0 ;
2006-04-08 21:40:57 +00:00
int cur , cursrc ;
2005-04-04 03:28:38 +00:00
int besttime = INT_MAX ;
2006-02-25 05:11:44 +00:00
int beststeps = INT_MAX ;
2006-04-08 21:40:57 +00:00
int common = ( * dst ) & ( * srcs ) ; /* are there common formats ? */
if ( common ) { /* yes, pick one and return */
2006-07-10 19:05:48 +00:00
for ( cur = 1 , y = 0 ; y < MAX_FORMAT ; cur < < = 1 , y + + ) {
2006-04-08 21:40:57 +00:00
if ( cur & common ) /* guaranteed to find one */
break ;
2004-12-06 21:53:57 +00:00
}
2006-04-08 21:40:57 +00:00
/* We are done, this is a common format to both. */
2006-07-10 19:05:48 +00:00
* srcs = * dst = cur ;
2006-04-08 21:40:57 +00:00
return 0 ;
} else { /* No, we will need to translate */
2006-01-11 05:00:45 +00:00
AST_LIST_LOCK ( & translators ) ;
2006-07-10 19:05:48 +00:00
for ( cur = 1 , y = 0 ; y < MAX_FORMAT ; cur < < = 1 , y + + ) {
2006-04-08 21:40:57 +00:00
if ( ! ( cur & * dst ) )
2006-02-25 05:11:44 +00:00
continue ;
2006-07-10 19:05:48 +00:00
for ( cursrc = 1 , x = 0 ; x < MAX_FORMAT ; cursrc < < = 1 , x + + ) {
2006-04-08 21:40:57 +00:00
if ( ! ( * srcs & cursrc ) | | ! tr_matrix [ x ] [ y ] . step | |
tr_matrix [ x ] [ y ] . cost > besttime )
continue ; /* not existing or no better */
if ( tr_matrix [ x ] [ y ] . cost < besttime | |
tr_matrix [ x ] [ y ] . multistep < beststeps ) {
/* better than what we have so far */
best = cursrc ;
2006-02-25 05:11:44 +00:00
bestdst = cur ;
besttime = tr_matrix [ x ] [ y ] . cost ;
beststeps = tr_matrix [ x ] [ y ] . multistep ;
2004-12-06 21:53:57 +00:00
}
2006-02-25 05:11:44 +00:00
}
2004-12-06 21:53:57 +00:00
}
2006-01-11 05:00:45 +00:00
AST_LIST_UNLOCK ( & translators ) ;
2006-04-08 21:40:57 +00:00
if ( best > - 1 ) {
* srcs = best ;
* dst = bestdst ;
best = 0 ;
}
return best ;
1999-12-05 02:03:40 +00:00
}
}
2006-04-17 16:42:03 +00:00
unsigned int ast_translate_path_steps ( unsigned int dest , unsigned int src )
{
2006-04-18 21:39:20 +00:00
/* convert bitwise format numbers into array indices */
src = powerof ( src ) ;
dest = powerof ( dest ) ;
2006-04-17 16:42:03 +00:00
if ( ! tr_matrix [ src ] [ dest ] . step )
return - 1 ;
else
2006-04-17 16:43:55 +00:00
return tr_matrix [ src ] [ dest ] . multistep + 1 ;
2006-04-17 16:42:03 +00:00
}
2006-07-10 19:05:48 +00:00