@ -49,7 +49,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/*** DOCUMENTATION
< application name = " MixMonitor " language = " en_US " >
< synopsis >
Record a call and mix the audio during the recording .
Record a call and mix the audio during the recording . Use of StopMixMonitor is required
to guarantee the audio file is available for processing during dialplan execution .
< / synopsis >
< syntax >
< parameter name = " file " required = " true " argsep = " . " >
@ -111,7 +112,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
< / application >
< application name = " StopMixMonitor " language = " en_US " >
< synopsis >
Stop recording a call through MixMonitor .
Stop recording a call through MixMonitor , and free the recording ' s file handle .
< / synopsis >
< syntax / >
< description >
@ -183,8 +184,25 @@ struct mixmonitor_ds {
unsigned int destruction_ok ;
ast_cond_t destruction_condition ;
ast_mutex_t lock ;
/* The filestream is held in the datastore so it can be stopped
* immediately during stop_mixmonitor or channel destruction . */
int fs_quit ;
struct ast_filestream * fs ;
} ;
static void mixmonitor_ds_close_fs ( struct mixmonitor_ds * mixmonitor_ds )
{
ast_mutex_lock ( & mixmonitor_ds - > lock ) ;
if ( mixmonitor_ds - > fs ) {
ast_closestream ( mixmonitor_ds - > fs ) ;
mixmonitor_ds - > fs = NULL ;
mixmonitor_ds - > fs_quit = 1 ;
ast_verb ( 2 , " MixMonitor close filestream \n " ) ;
}
ast_mutex_unlock ( & mixmonitor_ds - > lock ) ;
}
static void mixmonitor_ds_destroy ( void * data )
{
struct mixmonitor_ds * mixmonitor_ds = data ;
@ -229,19 +247,33 @@ static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
# define SAMPLES_PER_FRAME 160
static void mixmonitor_free ( struct mixmonitor * mixmonitor )
{
if ( mixmonitor ) {
if ( mixmonitor - > mixmonitor_ds ) {
ast_mutex_destroy ( & mixmonitor - > mixmonitor_ds - > lock ) ;
ast_cond_destroy ( & mixmonitor - > mixmonitor_ds - > destruction_condition ) ;
ast_free ( mixmonitor - > mixmonitor_ds ) ;
}
ast_free ( mixmonitor ) ;
}
}
static void * mixmonitor_thread ( void * obj )
{
struct mixmonitor * mixmonitor = obj ;
struct ast_filestream * fs = NULL ;
struct ast_filestream * * fs = NULL ;
unsigned int oflags ;
char * ext ;
int errflag = 0 ;
ast_verb ( 2 , " Begin MixMonitor Recording %s \n " , mixmonitor - > name ) ;
ast_audiohook_lock ( & mixmonitor - > audiohook ) ;
while ( mixmonitor - > audiohook . status = = AST_AUDIOHOOK_STATUS_RUNNING ) {
fs = & mixmonitor - > mixmonitor_ds - > fs ;
while ( mixmonitor - > audiohook . status = = AST_AUDIOHOOK_STATUS_RUNNING & & ! mixmonitor - > mixmonitor_ds - > fs_quit ) {
struct ast_frame * fr = NULL ;
ast_audiohook_trigger_wait ( & mixmonitor - > audiohook ) ;
@ -254,48 +286,43 @@ static void *mixmonitor_thread(void *obj)
ast_mutex_lock ( & mixmonitor - > mixmonitor_ds - > lock ) ;
if ( ! ast_test_flag ( mixmonitor , MUXFLAG_BRIDGED ) | | ( mixmonitor - > mixmonitor_ds - > chan & & ast_bridged_channel ( mixmonitor - > mixmonitor_ds - > chan ) ) ) {
ast_mutex_unlock ( & mixmonitor - > mixmonitor_ds - > lock ) ;
/* Initialize the file if not already done so */
if ( ! fs & & ! errflag ) {
if ( ! * fs & & ! errflag & & ! mixmonitor - > mixmonitor_ds - > fs_quit ) {
oflags = O_CREAT | O_WRONLY ;
oflags | = ast_test_flag ( mixmonitor , MUXFLAG_APPEND ) ? O_APPEND : O_TRUNC ;
if ( ( ext = strrchr ( mixmonitor - > filename , ' . ' ) ) )
* ( ext + + ) = ' \0 ' ;
else
ext = " raw " ;
if ( ! ( fs = ast_writefile ( mixmonitor - > filename , ext , NULL , oflags , 0 , 0666 ) ) ) {
if ( ! ( * fs = ast_writefile ( mixmonitor - > filename , ext , NULL , oflags , 0 , 0666 ) ) ) {
ast_log ( LOG_ERROR , " Cannot open %s.%s \n " , mixmonitor - > filename , ext ) ;
errflag = 1 ;
}
}
/* Write out the frame(s) */
if ( fs ) {
if ( * fs ) {
struct ast_frame * cur ;
for ( cur = fr ; cur ; cur = AST_LIST_NEXT ( cur , frame_list ) ) {
ast_writestream ( fs , cur ) ;
ast_writestream ( * fs , cur ) ;
}
}
} else {
ast_mutex_unlock ( & mixmonitor - > mixmonitor_ds - > lock ) ;
}
ast_mutex_unlock ( & mixmonitor - > mixmonitor_ds - > lock ) ;
/* All done! free it. */
ast_frame_free ( fr , 0 ) ;
}
ast_audiohook_detach ( & mixmonitor - > audiohook ) ;
ast_audiohook_unlock ( & mixmonitor - > audiohook ) ;
ast_audiohook_destroy ( & mixmonitor - > audiohook ) ;
ast_verb ( 2 , " End MixMonitor Recording %s \n " , mixmonitor - > name ) ;
if ( fs )
ast_closestream ( fs ) ;
mixmonitor_ds_close_fs ( mixmonitor - > mixmonitor_ds ) ;
if ( mixmonitor - > post_process ) {
ast_verb ( 2 , " Executing [%s] \n " , mixmonitor - > post_process ) ;
@ -307,11 +334,9 @@ static void *mixmonitor_thread(void *obj)
ast_cond_wait ( & mixmonitor - > mixmonitor_ds - > destruction_condition , & mixmonitor - > mixmonitor_ds - > lock ) ;
}
ast_mutex_unlock ( & mixmonitor - > mixmonitor_ds - > lock ) ;
ast_mutex_destroy ( & mixmonitor - > mixmonitor_ds - > lock ) ;
ast_cond_destroy ( & mixmonitor - > mixmonitor_ds - > destruction_condition ) ;
ast_free ( mixmonitor - > mixmonitor_ds ) ;
ast_free ( mixmonitor ) ;
ast_verb ( 2 , " End MixMonitor Recording %s \n " , mixmonitor - > name ) ;
mixmonitor_free ( mixmonitor ) ;
return NULL ;
}
@ -323,11 +348,13 @@ static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel
if ( ! ( mixmonitor_ds = ast_calloc ( 1 , sizeof ( * mixmonitor_ds ) ) ) ) {
return - 1 ;
}
ast_mutex_init ( & mixmonitor_ds - > lock ) ;
ast_cond_init ( & mixmonitor_ds - > destruction_condition , NULL ) ;
if ( ! ( datastore = ast_datastore_alloc ( & mixmonitor_ds_info , NULL ) ) ) {
ast_mutex_destroy ( & mixmonitor_ds - > lock ) ;
ast_cond_destroy ( & mixmonitor_ds - > destruction_condition ) ;
ast_free ( mixmonitor_ds ) ;
return - 1 ;
}
@ -378,6 +405,7 @@ static void launch_monitor_thread(struct ast_channel *chan, const char *filename
/* Copy over flags and channel name */
mixmonitor - > flags = flags ;
if ( setup_mixmonitor_ds ( mixmonitor , chan ) ) {
mixmonitor_free ( mixmonitor ) ;
return ;
}
mixmonitor - > name = ( char * ) mixmonitor + sizeof ( * mixmonitor ) ;
@ -497,6 +525,14 @@ static int mixmonitor_exec(struct ast_channel *chan, void *data)
static int stop_mixmonitor_exec ( struct ast_channel * chan , void * data )
{
struct ast_datastore * datastore = NULL ;
/* closing the filestream here guarantees the file is avaliable to the dialplan
* after calling StopMixMonitor */
if ( ( datastore = ast_channel_datastore_find ( chan , & mixmonitor_ds_info , NULL ) ) ) {
mixmonitor_ds_close_fs ( datastore - > data ) ;
}
ast_audiohook_detach_source ( chan , mixmonitor_spy_type ) ;
return 0 ;
}