@ -70,6 +70,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
# include "asterisk/utils.h"
# include "asterisk/cli.h"
# include "asterisk/stringfields.h"
# include "asterisk/linkedlists.h"
# define MAX_MOHFILES 512
# define MAX_MOHFILE_LEN 128
@ -139,24 +140,23 @@ struct mohclass {
int pid ; /* PID of mpg123 */
time_t start ;
pthread_t thread ;
struct mohdata * members ;
/* Source of audio */
int srcfd ;
/* FD for timing source */
int pseudofd ;
struct mohclass * next ;
AST_LIST_HEAD_NOLOCK ( , mohdata ) members ;
AST_LIST_ENTRY ( mohclass ) list ;
} ;
struct mohdata {
int pipe [ 2 ] ;
int origwfmt ;
struct mohclass * parent ;
struct mohdata * next ;
struct ast_frame f ;
AST_LIST_ENTRY ( mohdata ) list ;
} ;
static struct mohclass * mohclasses ;
AST_MUTEX_DEFINE_STATIC ( moh_lock ) ;
AST_LIST_HEAD_STATIC ( mohclasses , mohclass ) ;
# define LOCAL_MPG_123 " / usr / local / bin / mpg123"
# define MPG_123 " / usr / bin / mpg123"
@ -165,18 +165,16 @@ AST_MUTEX_DEFINE_STATIC(moh_lock);
static void ast_moh_free_class ( struct mohclass * * class )
{
struct mohdata * members , * mtmp ;
struct mohdata * member ;
while ( ( member = AST_LIST_REMOVE_HEAD ( & ( ( * class ) - > members ) , list ) ) )
free ( member ) ;
members = ( * class ) - > members ;
while ( members ) {
mtmp = members ;
members = members - > next ;
free ( mtmp ) ;
}
if ( ( * class ) - > thread ) {
pthread_cancel ( ( * class ) - > thread ) ;
( * class ) - > thread = 0 ;
}
free ( * class ) ;
* class = NULL ;
}
@ -515,7 +513,7 @@ static void *monmp3thread(void *data)
}
res = 8 * MOH_MS_INTERVAL ; /* 8 samples per millisecond */
}
if ( ! class - > members )
if ( AST_LIST_EMPTY ( & class - > members ) )
continue ;
/* Read mp3 audio */
len = ast_codec_get_len ( class - > format , res ) ;
@ -538,16 +536,15 @@ static void *monmp3thread(void *data)
continue ;
}
pthread_testcancel ( ) ;
ast_mutex_lock ( & moh_lock ) ;
moh = class - > members ;
while ( moh ) {
AST_LIST_LOCK ( & mohclasses ) ;
AST_LIST_TRAVERSE ( & class - > members , moh , list ) {
/* Write data */
if ( ( res = write ( moh - > pipe [ 1 ] , sbuf , res2 ) ) ! = res2 )
if ( ( res = write ( moh - > pipe [ 1 ] , sbuf , res2 ) ) ! = res2 ) {
if ( option_debug )
ast_log ( LOG_DEBUG , " Only wrote %d of %d bytes to pipe \n " , res , res2 ) ;
moh = moh - > next ;
}
}
ast_mutex_unlock( & moh_lock ) ;
AST_LIST_UNLOCK( & mohclasses ) ;
}
return NULL ;
}
@ -607,60 +604,58 @@ static int moh4_exec(struct ast_channel *chan, void *data)
return 0 ;
}
/*! \note This function should be called with the mohclasses list locked */
static struct mohclass * get_mohbyname ( const char * name )
{
struct mohclass * moh ;
moh = mohclasses ;
while ( moh ) {
struct mohclass * moh = NULL ;
AST_LIST_TRAVERSE ( & mohclasses , moh , list ) {
if ( ! strcasecmp ( name , moh - > name ) )
return moh ;
moh = moh - > next ;
break ;
}
return NULL ;
return moh ;
}
static struct mohdata * mohalloc ( struct mohclass * cl )
{
struct mohdata * moh ;
long flags ;
if ( ! ( moh = ast_calloc ( 1 , sizeof ( * moh ) ) ) )
return NULL ;
if ( pipe ( moh - > pipe ) ) {
ast_log ( LOG_WARNING , " Failed to create pipe: %s \n " , strerror ( errno ) ) ;
free ( moh ) ;
return NULL ;
}
/* Make entirely non-blocking */
flags = fcntl ( moh - > pipe [ 0 ] , F_GETFL ) ;
fcntl ( moh - > pipe [ 0 ] , F_SETFL , flags | O_NONBLOCK ) ;
flags = fcntl ( moh - > pipe [ 1 ] , F_GETFL ) ;
fcntl ( moh - > pipe [ 1 ] , F_SETFL , flags | O_NONBLOCK ) ;
moh - > f . frametype = AST_FRAME_VOICE ;
moh - > f . subclass = cl - > format ;
moh - > f . offset = AST_FRIENDLY_OFFSET ;
moh - > parent = cl ;
moh - > next = cl - > members ;
cl - > members = moh ;
AST_LIST_INSERT_HEAD ( & cl - > members , moh , list ) ;
return moh ;
}
static void moh_release ( struct ast_channel * chan , void * data )
{
struct mohdata * moh = data , * prev , * cur ;
struct mohdata * moh = data ;
int oldwfmt ;
ast_mutex_lock ( & moh_lock ) ;
/* Unlink */
prev = NULL ;
cur = moh - > parent - > members ;
while ( cur ) {
if ( cur = = moh ) {
if ( prev )
prev - > next = cur - > next ;
else
moh - > parent - > members = cur - > next ;
break ;
}
prev = cur ;
cur = cur - > next ;
}
ast_mutex_unlock ( & moh_lock ) ;
AST_LIST_LOCK ( & mohclasses ) ;
AST_LIST_REMOVE ( & moh - > parent - > members , moh , list ) ;
AST_LIST_UNLOCK ( & mohclasses ) ;
close ( moh - > pipe [ 0 ] ) ;
close ( moh - > pipe [ 1 ] ) ;
oldwfmt = moh - > origwfmt ;
@ -693,7 +688,6 @@ static void *moh_alloc(struct ast_channel *chan, void *params)
static int moh_generate ( struct ast_channel * chan , void * data , int len , int samples )
{
struct ast_frame f ;
struct mohdata * moh = data ;
short buf [ 1280 + AST_FRIENDLY_OFFSET / 2 ] ;
int res ;
@ -708,25 +702,14 @@ static int moh_generate(struct ast_channel *chan, void *data, int len, int sampl
len = sizeof ( buf ) - AST_FRIENDLY_OFFSET ;
}
res = read ( moh - > pipe [ 0 ] , buf + AST_FRIENDLY_OFFSET / 2 , len ) ;
#if 0
if ( res ! = len ) {
ast_log ( LOG_WARNING , " Read only %d of %d bytes: %s \n " , res , len , strerror ( errno ) ) ;
}
# endif
if ( res < = 0 )
return 0 ;
memset ( & f , 0 , sizeof ( f ) ) ;
f . frametype = AST_FRAME_VOICE ;
f . subclass = moh - > parent - > format ;
f . mallocd = 0 ;
f . datalen = res ;
f . data = buf + AST_FRIENDLY_OFFSET / 2 ;
f . offset = AST_FRIENDLY_OFFSET ;
f . samples = ast_codec_get_samples ( & f ) ;
if ( ast_write ( chan , & f ) < 0 ) {
moh - > f . datalen = res ;
moh - > f . data = buf + AST_FRIENDLY_OFFSET / 2 ;
moh - > f . samples = ast_codec_get_samples ( & moh - > f ) ;
if ( ast_write ( chan , & moh - > f ) < 0 ) {
ast_log ( LOG_WARNING , " Failed to write frame to '%s': %s \n " , chan - > name , strerror ( errno ) ) ;
return - 1 ;
}
@ -804,7 +787,7 @@ static int moh_register(struct mohclass *moh, int reload)
# ifdef HAVE_ZAPTEL
int x ;
# endif
ast_mutex_lock( & moh_lock ) ;
AST_LIST_LOCK( & mohclasses ) ;
if ( get_mohbyname ( moh - > name ) ) {
if ( reload ) {
ast_log ( LOG_DEBUG , " Music on Hold class '%s' left alone from initial load. \n " , moh - > name ) ;
@ -812,10 +795,10 @@ static int moh_register(struct mohclass *moh, int reload)
ast_log ( LOG_WARNING , " Music on Hold class '%s' already exists \n " , moh - > name ) ;
}
free ( moh ) ;
ast_mutex_unlock( & moh_lock ) ;
AST_LIST_UNLOCK( & mohclasses ) ;
return - 1 ;
}
ast_mutex_unlock( & moh_lock ) ;
AST_LIST_UNLOCK( & mohclasses ) ;
time ( & moh - > start ) ;
moh - > start - = respawn_time ;
@ -864,10 +847,11 @@ static int moh_register(struct mohclass *moh, int reload)
ast_moh_free_class ( & moh ) ;
return - 1 ;
}
ast_mutex_lock ( & moh_lock ) ;
moh - > next = mohclasses ;
mohclasses = moh ;
ast_mutex_unlock ( & moh_lock ) ;
AST_LIST_LOCK ( & mohclasses ) ;
AST_LIST_INSERT_HEAD ( & mohclasses , moh , list ) ;
AST_LIST_UNLOCK ( & mohclasses ) ;
return 0 ;
}
@ -887,9 +871,9 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *class)
class = chan - > musicclass ;
if ( ast_strlen_zero ( class ) )
class = " default " ;
ast_mutex_lock( & moh_lock ) ;
AST_LIST_LOCK( & mohclasses ) ;
mohclass = get_mohbyname ( class ) ;
ast_mutex_unlock( & moh_lock ) ;
AST_LIST_UNLOCK( & mohclasses ) ;
if ( ! mohclass ) {
ast_log ( LOG_WARNING , " No class: %s \n " , ( char * ) class ) ;
@ -1060,16 +1044,15 @@ static int load_moh_classes(int reload)
static void ast_moh_destroy ( void )
{
struct mohclass * moh , * tmp ;
struct mohclass * moh ;
char buff [ 8192 ] ;
int bytes , tbytes = 0 , stime = 0 , pid = 0 ;
int bytes , tbytes = 0 , stime = 0 , pid = 0 ;
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Destroying musiconhold processes \n " ) ;
ast_mutex_lock ( & moh_lock ) ;
moh = mohclasses ;
while ( moh ) {
AST_LIST_LOCK ( & mohclasses ) ;
while ( ( moh = AST_LIST_REMOVE_HEAD ( & mohclasses , list ) ) ) {
if ( moh - > pid ) {
ast_log ( LOG_DEBUG , " killing %d! \n " , moh - > pid ) ;
stime = time ( NULL ) + 2 ;
@ -1083,18 +1066,14 @@ static void ast_moh_destroy(void)
kill ( pid , SIGTERM ) ;
usleep ( 100000 ) ;
kill ( pid , SIGKILL ) ;
while ( ( ast_wait_for_input ( moh - > srcfd , 100 ) > 0 ) & & ( bytes = read ( moh - > srcfd , buff , 8192 ) ) & & time ( NULL ) < stime ) {
while ( ( ast_wait_for_input ( moh - > srcfd , 100 ) > 0 ) & & ( bytes = read ( moh - > srcfd , buff , 8192 ) ) & & time ( NULL ) < stime )
tbytes = tbytes + bytes ;
}
ast_log ( LOG_DEBUG , " mpg123 pid %d and child died after %d bytes read \n " , pid , tbytes ) ;
close ( moh - > srcfd ) ;
}
tmp = moh ;
moh = moh - > next ;
ast_moh_free_class ( & tmp ) ;
ast_moh_free_class ( & moh ) ;
}
mohclasses = NULL ;
ast_mutex_unlock ( & moh_lock ) ;
AST_LIST_UNLOCK ( & mohclasses ) ;
}
static void moh_on_off ( int on )
@ -1108,7 +1087,7 @@ static void moh_on_off(int on)
else
ast_deactivate_generator ( chan ) ;
}
ast_ mutex_unlock( & chan - > lock ) ;
ast_ channel_unlock( chan ) ;
}
}
@ -1129,8 +1108,8 @@ static int cli_files_show(int fd, int argc, char *argv[])
int i ;
struct mohclass * class ;
ast_mutex_lock( & moh_lock ) ;
for ( class = mohclasses ; class ; class = class - > nex t) {
AST_LIST_LOCK( & mohclasses ) ;
AST_LIST_TRAVERSE ( & mohclasses , class , lis t) {
if ( ! class - > total_files )
continue ;
@ -1138,7 +1117,7 @@ static int cli_files_show(int fd, int argc, char *argv[])
for ( i = 0 ; i < class - > total_files ; i + + )
ast_cli ( fd , " \t File: %s \n " , class - > filearray [ i ] ) ;
}
ast_mutex_unlock( & moh_lock ) ;
AST_LIST_UNLOCK( & mohclasses ) ;
return 0 ;
}
@ -1147,8 +1126,8 @@ static int moh_classes_show(int fd, int argc, char *argv[])
{
struct mohclass * class ;
ast_mutex_lock( & moh_lock ) ;
for ( class = mohclasses ; class ; class = class - > nex t) {
AST_LIST_LOCK( & mohclasses ) ;
AST_LIST_TRAVERSE ( & mohclasses , class , lis t) {
ast_cli ( fd , " Class: %s \n " , class - > name ) ;
ast_cli ( fd , " \t Mode: %s \n " , S_OR ( class - > mode , " <none> " ) ) ;
ast_cli ( fd , " \t Directory: %s \n " , S_OR ( class - > dir , " <none> " ) ) ;
@ -1156,7 +1135,7 @@ static int moh_classes_show(int fd, int argc, char *argv[])
ast_cli ( fd , " \t Application: %s \n " , S_OR ( class - > args , " <none> " ) ) ;
ast_cli ( fd , " \t Format: %s \n " , ast_getformatname ( class - > format ) ) ;
}
ast_mutex_unlock( & moh_lock ) ;
AST_LIST_UNLOCK( & mohclasses ) ;
return 0 ;
}
@ -1173,12 +1152,14 @@ static int init_classes(int reload)
if ( ! load_moh_classes ( reload ) ) /* Load classes from config */
return 0 ; /* Return if nothing is found */
moh = mohclasses ;
while ( moh ) {
AST_LIST_LOCK ( & mohclasses ) ;
AST_LIST_TRAVERSE ( & mohclasses , moh , list ) {
if ( moh - > total_files )
moh_scan_files ( moh ) ;
moh = moh - > next ;
}
AST_LIST_UNLOCK ( & mohclasses ) ;
return 1 ;
}