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-22 13:11:34 +00:00
# include <sys/time.h>
2007-09-29 00:19:15 +00:00
# include <sys/resource.h>
2005-04-22 13:11:34 +00:00
2005-04-21 06:02:45 +00:00
# include "asterisk/lock.h"
# include "asterisk/channel.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/frame.h"
# include "asterisk/sched.h"
# include "asterisk/cli.h"
# include "asterisk/term.h"
1999-12-05 02:03:40 +00:00
2007-08-20 22:53:48 +00:00
# define MAX_RECALC 1000 /* max sample recalc */
2004-05-17 22:59:27 +00:00
2006-04-08 21:40:57 +00:00
/*! \brief the list of translators */
2006-11-02 18:01:10 +00:00
static AST_RWLIST_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-10-25 14:55:11 +00:00
*
* Note : the lock in the ' translators ' list is also used to protect
* this structure .
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 ) ) {
2007-06-06 21:20:11 +00:00
ast_free ( pvt ) ;
2006-04-08 21:40:57 +00:00
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 ) ;
2007-06-06 21:20:11 +00:00
ast_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 ;
2006-11-24 17:40:49 +00:00
pvt - > datalen = pvt - > samples * 2 ; /* SLIN has 2bytes for 1sample */
2006-04-08 21:40:57 +00:00
}
2007-05-24 15:28:29 +00:00
/* We don't want generic PLC. If the codec has native PLC, then do that */
if ( ! pvt - > t - > native_plc )
return 0 ;
2006-04-08 21:40:57 +00:00
}
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-11-02 18:01:10 +00:00
AST_RWLIST_RDLOCK ( & translators ) ;
2006-10-25 14:55:11 +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 ) ) ;
2006-11-02 18:01:10 +00:00
AST_RWLIST_UNLOCK ( & translators ) ;
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 ) ;
2006-11-02 18:01:10 +00:00
AST_RWLIST_UNLOCK ( & translators ) ;
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-10-25 14:55:11 +00:00
2006-11-02 18:01:10 +00:00
AST_RWLIST_UNLOCK ( & translators ) ;
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 ;
2007-09-29 00:19:15 +00:00
struct rusage start ;
struct rusage end ;
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 ) ;
2007-08-20 22:53:48 +00:00
t - > cost = 999999 ;
2004-05-17 22:59:27 +00:00
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 ) ;
2007-08-20 22:53:48 +00:00
t - > cost = 999999 ;
2004-05-17 22:59:27 +00:00
return ;
}
2007-09-29 00:19:15 +00:00
getrusage ( RUSAGE_SELF , & start ) ;
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 ) ;
2007-08-20 22:53:48 +00:00
t - > cost = 999999 ;
2004-05-17 22:59:27 +00:00
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
}
}
2007-09-29 00:19:15 +00:00
getrusage ( RUSAGE_SELF , & end ) ;
cost = ( ( end . ru_utime . tv_sec - start . ru_utime . tv_sec ) * 1000000 ) + end . ru_utime . tv_usec - start . ru_utime . tv_usec ;
cost + = ( ( end . ru_stime . tv_sec - start . ru_stime . tv_sec ) * 1000000 ) + end . ru_stime . tv_usec - start . ru_stime . tv_usec ;
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
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " 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-11-02 18:01:10 +00:00
AST_RWLIST_TRAVERSE ( & translators , t , list ) {
2006-10-31 22:19:08 +00:00
if ( ! t - > active )
continue ;
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 ;
2007-07-25 14:13:17 +00:00
ast_debug ( 3 , " Discovered %d cost path from %s to %s, via %d \n " , tr_matrix [ x ] [ z ] . cost , ast_getformatname ( x ) , ast_getformatname ( z ) , y ) ;
2006-04-08 21:40:57 +00:00
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
}
2007-10-11 19:03:06 +00:00
static char * handle_cli_core_show_translation ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-09-18 19:54:18 +00:00
{
2006-10-25 00:32:23 +00:00
# define SHOW_TRANS 13
2006-09-18 19:54:18 +00:00
int x , y , z ;
int curlen = 0 , longest = 0 ;
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " core show translation [recalc] " ;
e - > usage =
2007-11-20 15:00:41 +00:00
" Usage: core show translation [recalc [<recalc seconds>]] \n "
2007-10-11 19:03:06 +00:00
" Displays known codec translators and the cost associated \n "
" with each conversion. If the argument 'recalc' is supplied along \n "
" with optional number of seconds to test a new test will be performed \n "
" as the chart is being displayed. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
if ( a - > argc > 5 )
return CLI_SHOWUSAGE ;
2006-09-18 19:54:18 +00:00
2007-10-11 19:03:06 +00:00
if ( a - > argv [ 3 ] & & ! strcasecmp ( a - > argv [ 3 ] , " recalc " ) ) {
z = a - > argv [ 4 ] ? atoi ( a - > argv [ 4 ] ) : 1 ;
2006-09-18 19:54:18 +00:00
if ( z < = 0 ) {
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Recalc must be greater than 0. Defaulting to 1. \n " ) ;
2006-09-18 19:54:18 +00:00
z = 1 ;
}
if ( z > MAX_RECALC ) {
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Maximum limit of recalc exceeded by %d, truncating value to %d \n " , z - MAX_RECALC , MAX_RECALC ) ;
2006-09-18 19:54:18 +00:00
z = MAX_RECALC ;
}
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Recalculating Codec Translation (number of sample seconds: %d) \n \n " , z ) ;
2006-11-02 18:01:10 +00:00
AST_RWLIST_WRLOCK ( & translators ) ;
2006-09-18 19:54:18 +00:00
rebuild_matrix ( z ) ;
2006-11-02 18:01:10 +00:00
AST_RWLIST_UNLOCK ( & translators ) ;
2007-11-20 15:00:41 +00:00
} else if ( a - > argc > 3 )
return CLI_SHOWUSAGE ;
2006-09-18 19:54:18 +00:00
2006-11-02 18:01:10 +00:00
AST_RWLIST_RDLOCK ( & translators ) ;
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " Translation times between formats (in microseconds) for one second of data \n " ) ;
ast_cli ( a - > fd , " Source Format (Rows) Destination Format (Columns) \n \n " ) ;
2006-09-18 19:54:18 +00:00
/* 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 + + ) {
2007-12-17 22:50:49 +00:00
curlen = strlen ( ast_getformatname ( 1 < < ( x ) ) ) ;
2006-09-18 19:54:18 +00:00
if ( curlen > longest )
longest = curlen ;
}
for ( x = - 1 ; x < SHOW_TRANS ; x + + ) {
2006-12-16 09:46:20 +00:00
struct ast_str * out = ast_str_alloca ( 120 ) ;
ast_str_set ( & out , - 1 , " " ) ;
2006-09-18 19:54:18 +00:00
for ( y = - 1 ; y < SHOW_TRANS ; y + + ) {
2007-12-17 22:50:49 +00:00
if ( y > = 0 )
curlen = strlen ( ast_getformatname ( 1 < < ( y ) ) ) ;
2007-08-20 22:53:48 +00:00
if ( curlen < 5 )
curlen = 5 ;
2006-09-18 19:54:18 +00:00
if ( x > = 0 & & y > = 0 & & tr_matrix [ x ] [ y ] . step ) {
2007-08-20 22:53:48 +00:00
/* XXX 99999 is a little hackish
2006-09-18 19:54:18 +00:00
We don ' t want this number being larger than the shortest ( or current ) codec
For now , that is " gsm " */
2007-08-20 22:53:48 +00:00
ast_str_append ( & out , - 1 , " %*d " , curlen + 1 , tr_matrix [ x ] [ y ] . cost > 99999 ? 0 : tr_matrix [ x ] [ y ] . cost ) ;
2006-09-18 19:54:18 +00:00
} else if ( x = = - 1 & & y > = 0 ) {
/* Top row - use a dynamic size */
2007-12-17 22:50:49 +00:00
ast_str_append ( & out , - 1 , " %*s " , curlen + 1 , ast_getformatname ( 1 < < ( y ) ) ) ;
2006-09-18 19:54:18 +00:00
} else if ( y = = - 1 & & x > = 0 ) {
/* Left column - use a static size. */
2007-12-17 22:50:49 +00:00
ast_str_append ( & out , - 1 , " %*s " , longest , ast_getformatname ( 1 < < ( x ) ) ) ;
2006-09-18 19:54:18 +00:00
} else if ( x > = 0 & & y > = 0 ) {
2006-12-16 09:46:20 +00:00
ast_str_append ( & out , - 1 , " %*s " , curlen + 1 , " - " ) ;
2006-09-18 19:54:18 +00:00
} else {
2006-12-16 09:46:20 +00:00
ast_str_append ( & out , - 1 , " %*s " , longest , " " ) ;
2006-09-18 19:54:18 +00:00
}
}
2006-12-16 09:46:20 +00:00
ast_str_append ( & out , - 1 , " \n " ) ;
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , out - > str ) ;
2006-09-18 19:54:18 +00:00
}
2006-11-02 18:01:10 +00:00
AST_RWLIST_UNLOCK ( & translators ) ;
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2006-09-18 19:54:18 +00:00
}
2000-01-05 20:03:55 +00:00
2006-09-18 19:54:18 +00:00
static struct ast_cli_entry cli_translate [ ] = {
2007-10-22 20:05:18 +00:00
AST_CLI_DEFINE ( handle_cli_core_show_translation , " Display translation matrix " )
2006-09-18 19:54:18 +00:00
} ;
2000-01-05 20:03:55 +00:00
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-10-25 14:55:11 +00:00
struct ast_translator * u ;
2007-07-26 15:49:18 +00:00
char tmp [ 80 ] ;
2006-04-08 21:40:57 +00:00
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-10-31 22:19:08 +00:00
t - > srcfmt = powerof ( t - > srcfmt ) ;
t - > dstfmt = powerof ( t - > dstfmt ) ;
t - > active = 1 ;
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 ;
}
2007-06-06 13:20:38 +00:00
if ( t - > dstfmt ! = powerof ( AST_FORMAT_SLINEAR ) )
2006-04-08 21:40:57 +00:00
ast_log ( LOG_WARNING , " plc_samples %d format %x \n " ,
t - > plc_samples , t - > dstfmt ) ;
}
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 ;
}
2006-10-31 22:19:08 +00:00
2005-07-05 14:00:03 +00:00
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-10-31 22:19:08 +00:00
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-10-31 22:19:08 +00:00
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
}
2006-10-31 22:19:08 +00:00
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-10-31 22:19:08 +00:00
2007-07-26 15:49:18 +00:00
ast_verb ( 2 , " Registered translator '%s' from format %s to %s, cost %d \n " ,
2006-10-31 22:19:08 +00:00
term_color ( tmp , t - > name , COLOR_MAGENTA , COLOR_BLACK , sizeof ( tmp ) ) ,
ast_getformatname ( 1 < < t - > srcfmt ) , ast_getformatname ( 1 < < t - > dstfmt ) , t - > cost ) ;
2000-01-05 20:03:55 +00:00
if ( ! added_cli ) {
2006-09-18 19:54:18 +00:00
ast_cli_register_multiple ( cli_translate , sizeof ( cli_translate ) / sizeof ( struct ast_cli_entry ) ) ;
2000-01-05 20:03:55 +00:00
added_cli + + ;
}
2006-10-25 14:55:11 +00:00
2006-11-02 18:01:10 +00:00
AST_RWLIST_WRLOCK ( & translators ) ;
2006-10-31 22:19:08 +00:00
2006-10-25 14:55:11 +00:00
/* find any existing translators that provide this same srcfmt/dstfmt,
and put this one in order based on cost */
2006-11-02 18:01:10 +00:00
AST_RWLIST_TRAVERSE_SAFE_BEGIN ( & translators , u , list ) {
2006-10-25 14:55:11 +00:00
if ( ( u - > srcfmt = = t - > srcfmt ) & &
( u - > dstfmt = = t - > dstfmt ) & &
( u - > cost > t - > cost ) ) {
2007-11-08 05:28:47 +00:00
AST_RWLIST_INSERT_BEFORE_CURRENT ( t , list ) ;
2006-10-25 14:55:11 +00:00
t = NULL ;
}
}
2006-11-02 18:01:10 +00:00
AST_RWLIST_TRAVERSE_SAFE_END ;
2006-10-25 14:55:11 +00:00
/* if no existing translator was found for this format combination,
add it to the beginning of the list */
if ( t )
2006-11-02 18:01:10 +00:00
AST_RWLIST_INSERT_HEAD ( & translators , t , list ) ;
2006-10-25 14:55:11 +00:00
2004-05-17 22:59:27 +00:00
rebuild_matrix ( 0 ) ;
2006-10-31 22:19:08 +00:00
2006-11-02 18:01:10 +00:00
AST_RWLIST_UNLOCK ( & translators ) ;
2006-10-31 22:19:08 +00:00
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 ;
2006-10-30 22:27:56 +00:00
int found = 0 ;
2006-11-02 18:01:10 +00:00
AST_RWLIST_WRLOCK ( & translators ) ;
AST_RWLIST_TRAVERSE_SAFE_BEGIN ( & translators , u , list ) {
1999-12-05 02:03:40 +00:00
if ( u = = t ) {
2007-11-08 05:28:47 +00:00
AST_RWLIST_REMOVE_CURRENT ( list ) ;
2007-07-26 15:49:18 +00:00
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 ) ) ;
2006-10-30 22:27:56 +00:00
found = 1 ;
1999-12-05 02:03:40 +00:00
break ;
}
}
2006-11-02 18:01:10 +00:00
AST_RWLIST_TRAVERSE_SAFE_END ;
2006-10-30 22:27:56 +00:00
if ( found )
rebuild_matrix ( 0 ) ;
2006-11-02 18:01:10 +00:00
AST_RWLIST_UNLOCK ( & translators ) ;
2006-10-30 22:27:56 +00:00
1999-12-05 02:03:40 +00:00
return ( u ? 0 : - 1 ) ;
}
2006-10-31 22:19:08 +00:00
void ast_translator_activate ( struct ast_translator * t )
{
2006-11-02 18:01:10 +00:00
AST_RWLIST_WRLOCK ( & translators ) ;
2006-10-31 22:19:08 +00:00
t - > active = 1 ;
rebuild_matrix ( 0 ) ;
2006-11-02 18:01:10 +00:00
AST_RWLIST_UNLOCK ( & translators ) ;
2006-10-31 22:19:08 +00:00
}
void ast_translator_deactivate ( struct ast_translator * t )
{
2006-11-02 18:01:10 +00:00
AST_RWLIST_WRLOCK ( & translators ) ;
2006-10-31 22:19:08 +00:00
t - > active = 0 ;
rebuild_matrix ( 0 ) ;
2006-11-02 18:01:10 +00:00
AST_RWLIST_UNLOCK ( & translators ) ;
2006-10-31 22:19:08 +00:00
}
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-11-02 18:01:10 +00:00
AST_RWLIST_RDLOCK ( & 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-11-02 18:01:10 +00:00
AST_RWLIST_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-10-25 14:55:11 +00:00
unsigned int res = - 1 ;
2006-04-18 21:39:20 +00:00
/* convert bitwise format numbers into array indices */
src = powerof ( src ) ;
dest = powerof ( dest ) ;
2006-10-25 14:55:11 +00:00
2006-11-02 18:01:10 +00:00
AST_RWLIST_RDLOCK ( & translators ) ;
2006-10-25 14:55:11 +00:00
if ( tr_matrix [ src ] [ dest ] . step )
res = tr_matrix [ src ] [ dest ] . multistep + 1 ;
2006-11-02 18:01:10 +00:00
AST_RWLIST_UNLOCK ( & translators ) ;
2006-10-25 14:55:11 +00:00
return res ;
2006-04-17 16:42:03 +00:00
}
2006-07-10 19:05:48 +00:00
2006-10-25 14:55:11 +00:00
unsigned int ast_translate_available_formats ( unsigned int dest , unsigned int src )
{
unsigned int res = dest ;
unsigned int x ;
2006-10-26 16:35:34 +00:00
unsigned int src_audio = src & AST_FORMAT_AUDIO_MASK ;
unsigned int src_video = src & AST_FORMAT_VIDEO_MASK ;
2006-10-25 14:55:11 +00:00
/* if we don't have a source format, we just have to try all
possible destination formats */
if ( ! src )
return dest ;
2006-10-26 16:35:34 +00:00
/* If we have a source audio format, get its format index */
if ( src_audio )
src_audio = powerof ( src_audio ) ;
/* If we have a source video format, get its format index */
if ( src_video )
src_video = powerof ( src_video ) ;
2006-11-02 18:01:10 +00:00
AST_RWLIST_RDLOCK ( & translators ) ;
2006-10-25 14:55:11 +00:00
2006-10-26 16:35:34 +00:00
/* For a given source audio format, traverse the list of
known audio formats to determine whether there exists
a translation path from the source format to the
destination format . */
2007-11-06 22:51:48 +00:00
for ( x = 1 ; src_audio & & ( x & AST_FORMAT_AUDIO_MASK ) ; x < < = 1 ) {
2006-10-25 14:55:11 +00:00
/* if this is not a desired format, nothing to do */
if ( ! dest & x )
continue ;
/* if the source is supplying this format, then
we can leave it in the result */
if ( src & x )
continue ;
/* if we don't have a translation path from the src
to this format , remove it from the result */
2006-10-31 06:10:59 +00:00
if ( ! tr_matrix [ src_audio ] [ powerof ( x ) ] . step ) {
2006-10-25 14:55:11 +00:00
res & = ~ x ;
2006-10-31 06:10:59 +00:00
continue ;
}
2006-10-30 22:27:56 +00:00
/* now check the opposite direction */
if ( ! tr_matrix [ powerof ( x ) ] [ src_audio ] . step )
res & = ~ x ;
2006-10-25 14:55:11 +00:00
}
2006-10-26 16:35:34 +00:00
/* For a given source video format, traverse the list of
known video formats to determine whether there exists
a translation path from the source format to the
destination format . */
2007-11-06 22:51:48 +00:00
for ( ; src_video & & ( x & AST_FORMAT_VIDEO_MASK ) ; x < < = 1 ) {
2006-10-25 14:55:11 +00:00
/* if this is not a desired format, nothing to do */
if ( ! dest & x )
continue ;
/* if the source is supplying this format, then
we can leave it in the result */
if ( src & x )
continue ;
/* if we don't have a translation path from the src
to this format , remove it from the result */
2006-10-31 06:10:59 +00:00
if ( ! tr_matrix [ src_video ] [ powerof ( x ) ] . step ) {
2006-10-25 14:55:11 +00:00
res & = ~ x ;
2006-10-31 06:10:59 +00:00
continue ;
}
2006-10-30 22:27:56 +00:00
/* now check the opposite direction */
if ( ! tr_matrix [ powerof ( x ) ] [ src_video ] . step )
res & = ~ x ;
2006-10-25 14:55:11 +00:00
}
2006-11-02 18:01:10 +00:00
AST_RWLIST_UNLOCK ( & translators ) ;
2006-10-25 14:55:11 +00:00
return res ;
}