@ -2943,12 +2943,13 @@ int ast_channel_get_up_time(struct ast_channel *chan)
return ( ast_tvdiff_ms ( ast_tvnow ( ) , ast_channel_answertime ( chan ) ) / 1000 ) ;
}
void ast_ deactivate_generator( struct ast_channel * chan )
static void deactivate_generator_nolock ( struct ast_channel * chan )
{
ast_channel_lock ( chan ) ;
if ( ast_channel_generatordata ( chan ) ) {
if ( ast_channel_generator ( chan ) & & ast_channel_generator ( chan ) - > release ) {
ast_channel_generator ( chan ) - > release ( chan , ast_channel_generatordata ( chan ) ) ;
struct ast_generator * generator = ast_channel_generator ( chan ) ;
if ( generator & & generator - > release ) {
generator - > release ( chan , ast_channel_generatordata ( chan ) ) ;
}
ast_channel_generatordata_set ( chan , NULL ) ;
ast_channel_generator_set ( chan , NULL ) ;
@ -2956,14 +2957,23 @@ void ast_deactivate_generator(struct ast_channel *chan)
ast_clear_flag ( ast_channel_flags ( chan ) , AST_FLAG_WRITE_INT ) ;
ast_settimeout ( chan , 0 , NULL , NULL ) ;
}
}
void ast_deactivate_generator ( struct ast_channel * chan )
{
ast_channel_lock ( chan ) ;
deactivate_generator_nolock ( chan ) ;
ast_channel_unlock ( chan ) ;
}
static void generator_write_format_change ( struct ast_channel * chan )
{
struct ast_generator * generator ;
ast_channel_lock ( chan ) ;
if ( ast_channel_generator ( chan ) & & ast_channel_generator ( chan ) - > write_format_change ) {
ast_channel_generator ( chan ) - > write_format_change ( chan , ast_channel_generatordata ( chan ) ) ;
generator = ast_channel_generator ( chan ) ;
if ( generator & & generator - > write_format_change ) {
generator - > write_format_change ( chan , ast_channel_generatordata ( chan ) ) ;
}
ast_channel_unlock ( chan ) ;
}
@ -3009,8 +3019,10 @@ int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen,
ast_channel_lock ( chan ) ;
if ( ast_channel_generatordata ( chan ) ) {
if ( ast_channel_generator ( chan ) & & ast_channel_generator ( chan ) - > release ) {
ast_channel_generator ( chan ) - > release ( chan , ast_channel_generatordata ( chan ) ) ;
struct ast_generator * generator_old = ast_channel_generator ( chan ) ;
if ( generator_old & & generator_old - > release ) {
generator_old - > release ( chan , ast_channel_generatordata ( chan ) ) ;
}
}
if ( gen - > alloc & & ! ( generatordata = gen - > alloc ( chan , params ) ) ) {
@ -3642,49 +3654,57 @@ static void send_dtmf_end_event(struct ast_channel *chan,
static void ast_read_generator_actions ( struct ast_channel * chan , struct ast_frame * f )
{
if ( ast_channel_generator ( chan ) & & ast_channel_generator ( chan ) - > generate & & ast_channel_generatordata ( chan ) & & ! ast_internal_timing_enabled ( chan ) ) {
void * tmp = ast_channel_generatordata ( chan ) ;
int ( * generate ) ( struct ast_channel * chan , void * tmp , int datalen , int samples ) = ast_channel_generator ( chan ) - > generate ;
int res ;
int samples ;
struct ast_generator * generator ;
void * gendata ;
int res ;
int samples ;
generator = ast_channel_generator ( chan ) ;
if ( ! generator
| | ! generator - > generate
| | f - > frametype ! = AST_FRAME_VOICE
| | ! ast_channel_generatordata ( chan )
| | ast_channel_timingfunc ( chan ) ) {
return ;
}
if ( ast_channel_timingfunc ( chan ) ) {
ast_debug ( 1 , " Generator got voice, switching to phase locked mode \n " ) ;
ast_settimeout ( chan , 0 , NULL , NULL ) ;
}
/*
* We must generate frames in phase locked mode since
* we have no internal timer available .
*/
ast_channel_generatordata_set ( chan , NULL ) ; /* reset, to let writes go through */
if ( ast_format_cmp ( & f - > subclass . format , ast_channel_writeformat ( chan ) ) = = AST_FORMAT_CMP_NOT_EQUAL ) {
float factor ;
if ( ast_format_cmp ( & f - > subclass . format , ast_channel_writeformat ( chan ) ) = = AST_FORMAT_CMP_NOT_EQUAL ) {
float factor ;
factor = ( ( float ) ast_format_rate ( ast_channel_writeformat ( chan ) ) ) / ( ( float ) ast_format_rate ( & f - > subclass . format ) ) ;
samples = ( int ) ( ( ( float ) f - > samples ) * factor ) ;
} else {
samples = f - > samples ;
}
factor = ( ( float ) ast_format_rate ( ast_channel_writeformat ( chan ) ) ) / ( ( float ) ast_format_rate ( & f - > subclass . format ) ) ;
samples = ( int ) ( ( ( float ) f - > samples ) * factor ) ;
} else {
samples = f - > samples ;
}
/* This unlock is here based on two assumptions that hold true at this point in the
* code . 1 ) this function is only called from within __ast_read ( ) and 2 ) all generators
* call ast_write ( ) in their generate callback .
*
* The reason this is added is so that when ast_write is called , the lock that occurs
* there will not recursively lock the channel . Doing this will cause intended deadlock
* avoidance not to work in deeper functions
*/
ast_channel_unlock ( chan ) ;
res = generate ( chan , tmp , f - > datalen , samples ) ;
ast_channel_lock ( chan ) ;
ast_channel_generatordata_set ( chan , tmp ) ;
gendata = ast_channel_generatordata ( chan ) ;
ast_channel_generatordata_set ( chan , NULL ) ; /* reset, to let writes go through */
/*
* This unlock is here based on two assumptions that hold true at
* this point in the code . 1 ) this function is only called from
* within __ast_read ( ) and 2 ) all generators call ast_write ( ) in
* their generate callback .
*
* The reason this is added is so that when ast_write is called ,
* the lock that occurs there will not recursively lock the
* channel . Doing this will allow deadlock avoidance to work in
* deeper functions .
*/
ast_channel_unlock ( chan ) ;
res = generator - > generate ( chan , gendata , f - > datalen , samples ) ;
ast_channel_lock ( chan ) ;
if ( generator = = ast_channel_generator ( chan ) ) {
ast_channel_generatordata_set ( chan , gendata ) ;
if ( res ) {
ast_debug ( 1 , " Auto-deactivating generator \n " ) ;
ast_deactivate_generator ( chan ) ;
}
} else if ( f - > frametype = = AST_FRAME_CNG ) {
if ( ast_channel_generator ( chan ) & & ! ast_channel_timingfunc ( chan ) & & ( ast_channel_timingfd ( chan ) > - 1 ) ) {
ast_debug ( 1 , " Generator got CNG, switching to timed mode \n " ) ;
ast_settimeout ( chan , 50 , generator_force , chan ) ;
}
}
}
@ -4265,11 +4285,6 @@ done:
return f ;
}
int ast_internal_timing_enabled ( struct ast_channel * chan )
{
return ( ast_opt_internal_timing & & ast_channel_timingfd ( chan ) > - 1 ) ;
}
struct ast_frame * ast_read ( struct ast_channel * chan )
{
return __ast_read ( chan , 0 ) ;
@ -7693,30 +7708,24 @@ struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_cha
return state ;
}
static int internal_ deactivate_generator( struct ast_channel * chan , void * generator )
static int deactivate_silenc e_generator( struct ast_channel * chan )
{
ast_channel_lock ( chan ) ;
if ( ! ast_channel_generatordata ( chan ) ) {
ast_debug ( 1 , " Trying to stop silence generator when there is no "
" generator on '%s' \n " , ast_channel_name ( chan ) ) ;
ast_debug ( 1 , " Trying to stop silence generator when there is no generator on '%s'\n " ,
ast_channel_name ( chan ) ) ;
ast_channel_unlock ( chan ) ;
return 0 ;
}
if ( ast_channel_generator ( chan ) ! = generator) {
ast_debug ( 1 , " Trying to stop silence generator when it is not the current "
" generator on '%s' \n " , ast_channel_name ( chan ) ) ;
if ( ast_channel_generator ( chan ) ! = & silence_ generator) {
ast_debug ( 1 , " Trying to stop silence generator when it is not the current generator on '%s'\n " ,
ast_channel_name ( chan ) ) ;
ast_channel_unlock ( chan ) ;
return 0 ;
}
if ( ast_channel_generator ( chan ) & & ast_channel_generator ( chan ) - > release ) {
ast_channel_generator ( chan ) - > release ( chan , ast_channel_generatordata ( chan ) ) ;
}
ast_channel_generatordata_set ( chan , NULL ) ;
ast_channel_generator_set ( chan , NULL ) ;
ast_channel_set_fd ( chan , AST_GENERATOR_FD , - 1 ) ;
ast_clear_flag ( ast_channel_flags ( chan ) , AST_FLAG_WRITE_INT ) ;
ast_settimeout ( chan , 0 , NULL , NULL ) ;
deactivate_generator_nolock ( chan ) ;
ast_channel_unlock ( chan ) ;
return 1 ;
@ -7724,10 +7733,11 @@ static int internal_deactivate_generator(struct ast_channel *chan, void* generat
void ast_channel_stop_silence_generator ( struct ast_channel * chan , struct ast_silence_generator * state )
{
if ( ! state )
if ( ! state ) {
return ;
}
if ( internal_ deactivate_generator( chan , & silence_generator ) ) {
if ( deactivate_silence_ generator( chan ) ) {
ast_debug ( 1 , " Stopped silence generator on '%s' \n " , ast_channel_name ( chan ) ) ;
if ( ast_set_write_format ( chan , & state - > old_write_format ) < 0 )
ast_log ( LOG_ERROR , " Could not return write format to its original state \n " ) ;