@ -151,6 +151,7 @@ static const char stop_moh[] = "StopMusicOnHold";
static int respawn_time = 20 ;
static int respawn_time = 20 ;
struct moh_files_state {
struct moh_files_state {
/*! Holds a reference to the MOH class. */
struct mohclass * class ;
struct mohclass * class ;
char name [ MAX_MUSICCLASS ] ;
char name [ MAX_MUSICCLASS ] ;
struct ast_format origwfmt ;
struct ast_format origwfmt ;
@ -232,7 +233,7 @@ static struct mohclass *_mohclass_unref(struct mohclass *class, const char *tag,
{
{
struct mohclass * dup ;
struct mohclass * dup ;
if ( ( dup = ao2_find ( mohclasses , class , OBJ_POINTER ) ) ) {
if ( ( dup = ao2_find ( mohclasses , class , OBJ_POINTER ) ) ) {
if ( _ ao2_ref_debug( dup , - 1 , ( char * ) tag , ( char * ) file , line , funcname ) = = 2 ) {
if ( _ _ ao2_ref_debug( dup , - 1 , ( char * ) tag , ( char * ) file , line , funcname ) = = 2 ) {
FILE * ref = fopen ( " /tmp/refs " , " a " ) ;
FILE * ref = fopen ( " /tmp/refs " , " a " ) ;
if ( ref ) {
if ( ref ) {
fprintf ( ref , " %p =1 %s:%d:%s (%s) BAD ATTEMPT! \n " , class , file , line , funcname , tag ) ;
fprintf ( ref , " %p =1 %s:%d:%s (%s) BAD ATTEMPT! \n " , class , file , line , funcname , tag ) ;
@ -433,10 +434,13 @@ static void *moh_files_alloc(struct ast_channel *chan, void *params)
ast_module_ref ( ast_module_info - > self ) ;
ast_module_ref ( ast_module_info - > self ) ;
} else {
} else {
state = chan - > music_state ;
state = chan - > music_state ;
}
if ( ! state ) {
return NULL ;
if ( ! state ) {
}
return NULL ;
if ( state - > class ) {
mohclass_unref ( state - > class , " Uh Oh. Restarting MOH with an active class " ) ;
ast_log ( LOG_WARNING , " Uh Oh. Restarting MOH with an active class \n " ) ;
}
}
}
/* LOGIC: Comparing an unrefcounted pointer is a really bad idea, because
/* LOGIC: Comparing an unrefcounted pointer is a really bad idea, because
@ -936,6 +940,12 @@ static void moh_release(struct ast_channel *chan, void *data)
ast_free ( moh ) ;
ast_free ( moh ) ;
if ( chan ) {
if ( chan ) {
struct moh_files_state * state ;
state = chan - > music_state ;
if ( state & & state - > class ) {
state - > class = mohclass_unref ( state - > class , " Unreffing channel's music class upon deactivation of generator " ) ;
}
if ( oldwfmt . id & & ast_set_write_format ( chan , & oldwfmt ) ) {
if ( oldwfmt . id & & ast_set_write_format ( chan , & oldwfmt ) ) {
ast_log ( LOG_WARNING , " Unable to restore channel '%s' to format %s \n " ,
ast_log ( LOG_WARNING , " Unable to restore channel '%s' to format %s \n " ,
chan - > name , ast_getformatname ( & oldwfmt ) ) ;
chan - > name , ast_getformatname ( & oldwfmt ) ) ;
@ -954,13 +964,17 @@ static void *moh_alloc(struct ast_channel *chan, void *params)
/* Initiating music_state for current channel. Channel should know name of moh class */
/* Initiating music_state for current channel. Channel should know name of moh class */
if ( ! chan - > music_state & & ( state = ast_calloc ( 1 , sizeof ( * state ) ) ) ) {
if ( ! chan - > music_state & & ( state = ast_calloc ( 1 , sizeof ( * state ) ) ) ) {
chan - > music_state = state ;
chan - > music_state = state ;
state - > class = mohclass_ref ( class , " Copying reference into state container " ) ;
ast_module_ref ( ast_module_info - > self ) ;
ast_module_ref ( ast_module_info - > self ) ;
} else
} else {
state = chan - > music_state ;
state = chan - > music_state ;
if ( state & & state - > class ! = class ) {
if ( ! state ) {
return NULL ;
}
if ( state - > class ) {
mohclass_unref ( state - > class , " Uh Oh. Restarting MOH with an active class " ) ;
ast_log ( LOG_WARNING , " Uh Oh. Restarting MOH with an active class \n " ) ;
}
memset ( state , 0 , sizeof ( * state ) ) ;
memset ( state , 0 , sizeof ( * state ) ) ;
state - > class = class ;
}
}
if ( ( res = mohalloc ( class ) ) ) {
if ( ( res = mohalloc ( class ) ) ) {
@ -969,6 +983,8 @@ static void *moh_alloc(struct ast_channel *chan, void *params)
ast_log ( LOG_WARNING , " Unable to set channel '%s' to format '%s' \n " , chan - > name , ast_codec2str ( & class - > format ) ) ;
ast_log ( LOG_WARNING , " Unable to set channel '%s' to format '%s' \n " , chan - > name , ast_codec2str ( & class - > format ) ) ;
moh_release ( NULL , res ) ;
moh_release ( NULL , res ) ;
res = NULL ;
res = NULL ;
} else {
state - > class = mohclass_ref ( class , " Placing reference into state container " ) ;
}
}
ast_verb ( 3 , " Started music on hold, class '%s', on channel '%s' \n " , class - > name , chan - > name ) ;
ast_verb ( 3 , " Started music on hold, class '%s', on channel '%s' \n " , class - > name , chan - > name ) ;
}
}
@ -1285,7 +1301,10 @@ static void local_ast_moh_cleanup(struct ast_channel *chan)
if ( state ) {
if ( state ) {
if ( state - > class ) {
if ( state - > class ) {
state - > class = mohclass_unref ( state - > class , " Channel MOH state destruction " ) ;
/* This should never happen. We likely just leaked some resource. */
state - > class =
mohclass_unref ( state - > class , " Uh Oh. Cleaning up MOH with an active class " ) ;
ast_log ( LOG_WARNING , " Uh Oh. Cleaning up MOH with an active class \n " ) ;
}
}
ast_free ( chan - > music_state ) ;
ast_free ( chan - > music_state ) ;
chan - > music_state = NULL ;
chan - > music_state = NULL ;