@ -51,6 +51,7 @@ struct asent {
* channel . It will ensure that it doesn ' t actually get stopped until
* it gets stopped for the last time . */
unsigned int use_count ;
unsigned int orig_end_dtmf_flag : 1 ;
AST_LIST_HEAD_NOLOCK ( , ast_frame ) dtmf_frames ;
AST_LIST_ENTRY ( asent ) list ;
} ;
@ -151,42 +152,50 @@ int ast_autoservice_start(struct ast_channel *chan)
struct asent * as ;
AST_RWLIST_WRLOCK ( & aslist ) ;
/* Check if the channel already has autoservice */
AST_RWLIST_TRAVERSE ( & aslist , as , list ) {
if ( as - > chan = = chan ) {
as - > use_count + + ;
break ;
}
}
AST_RWLIST_UNLOCK ( & aslist ) ;
/* If not, start autoservice on channel */
if ( as ) {
/* Entry extist, autoservice is already handling this channel */
} else if ( ( as = ast_calloc ( 1 , sizeof ( * as ) ) ) = = NULL ) {
/* Memory allocation failed */
res = - 1 ;
} else {
/* New entry created */
as - > chan = chan ;
ast_set_flag ( chan , AST_FLAG_END_DTMF_ONLY ) ;
as - > use_count = 1 ;
AST_RWLIST_INSERT_HEAD ( & aslist , as , list ) ;
if ( asthread = = AST_PTHREADT_NULL ) { /* need start the thread */
if ( ast_pthread_create_background ( & asthread , NULL , autoservice_run , NULL ) ) {
ast_log ( LOG_WARNING , " Unable to create autoservice thread :( \n " ) ;
/* There will only be a single member in the list at this point,
the one we just added . */
AST_RWLIST_REMOVE ( & aslist , as , list ) ;
ast_free ( as ) ;
res = - 1 ;
} else
pthread_kill ( asthread , SIGURG ) ;
}
/* Entry exists, autoservice is already handling this channel */
return 0 ;
}
if ( ! ( as = ast_calloc ( 1 , sizeof ( * as ) ) ) )
return - 1 ;
/* New entry created */
as - > chan = chan ;
as - > use_count = 1 ;
ast_channel_lock ( chan ) ;
as - > orig_end_dtmf_flag = ast_test_flag ( chan , AST_FLAG_END_DTMF_ONLY ) ? 1 : 0 ;
if ( ! as - > orig_end_dtmf_flag )
ast_set_flag ( chan , AST_FLAG_END_DTMF_ONLY ) ;
ast_channel_unlock ( chan ) ;
AST_RWLIST_WRLOCK ( & aslist ) ;
AST_RWLIST_INSERT_HEAD ( & aslist , as , list ) ;
AST_RWLIST_UNLOCK ( & aslist ) ;
if ( asthread = = AST_PTHREADT_NULL ) { /* need start the thread */
if ( ast_pthread_create_background ( & asthread , NULL , autoservice_run , NULL ) ) {
ast_log ( LOG_WARNING , " Unable to create autoservice thread :( \n " ) ;
/* There will only be a single member in the list at this point,
the one we just added . */
AST_RWLIST_WRLOCK ( & aslist ) ;
AST_RWLIST_REMOVE ( & aslist , as , list ) ;
AST_RWLIST_UNLOCK ( & aslist ) ;
free ( as ) ;
res = - 1 ;
} else
pthread_kill ( asthread , SIGURG ) ;
}
return res ;
}
@ -197,6 +206,7 @@ int ast_autoservice_stop(struct ast_channel *chan)
AST_LIST_HEAD_NOLOCK ( , ast_frame ) dtmf_frames ;
struct ast_frame * f ;
int removed = 0 ;
int orig_end_dtmf_flag = 0 ;
AST_LIST_HEAD_INIT_NOLOCK ( & dtmf_frames ) ;
@ -208,11 +218,11 @@ int ast_autoservice_stop(struct ast_channel *chan)
if ( as - > use_count )
break ;
AST_LIST_APPEND_LIST ( & dtmf_frames , & as - > dtmf_frames , frame_list ) ;
orig_end_dtmf_flag = as - > orig_end_dtmf_flag ;
ast_free ( as ) ;
removed = 1 ;
if ( ! ast_check_hangup ( chan ) )
res = 0 ;
ast_clear_flag ( chan , AST_FLAG_END_DTMF_ONLY ) ;
break ;
}
}
@ -226,6 +236,9 @@ int ast_autoservice_stop(struct ast_channel *chan)
if ( ! removed )
return 0 ;
if ( ! orig_end_dtmf_flag )
ast_clear_flag ( chan , AST_FLAG_END_DTMF_ONLY ) ;
/* Wait for it to un-block */
while ( ast_test_flag ( chan , AST_FLAG_BLOCKING ) )
usleep ( 1000 ) ;