123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <libgen.h> //dirname()
- #include <asterisk/lock.h>
- #include <asterisk/channel.h>
- #include <asterisk/logger.h>
- #include <asterisk/file.h>
- #include <asterisk/pbx.h>
- #include <asterisk/module.h>
- #include <asterisk/manager.h>
- #include <asterisk/cli.h>
- #include <asterisk/monitor.h>
- #define AST_MONITOR_DIR INSTALL_PREFIX "/var/spool/asterisk/monitor"
- static ast_mutex_t monitorlock = AST_MUTEX_INITIALIZER;
- static unsigned long seq = 0;
- static char *monitor_synopsis = "Monitor a channel";
- static char *monitor_descrip = "Monitor\n"
- "Used to start monitoring a channel. The channel's input and output\n"
- "voice packets are logged to files until the channel hangs up or\n"
- "monitoring is stopped by the StopMonitor application.\n"
- "The option string may contain the following arguments: [file_format|[fname_base]]\n"
- " file_format -- optional, if not set, defaults to \"wav\"\n"
- " fname_base -- if set, changes the filename used to the one specified.\n";
- static char *stopmonitor_synopsis = "Stop monitoring a channel";
- static char *stopmonitor_descrip = "StopMonitor\n"
- "Stops monitoring a channel. Has no effect if the channel is not monitored\n";
- static char *changemonitor_synopsis = "Change monitoring filename of a channel";
- static char *changemonitor_descrip = "ChangeMonitor\n"
- "Changes monitoring filename of a channel. Has no effect if the channel is not monitored\n"
- "The option string may contain the following:\n"
- " filename_base -- if set, changes the filename used to the one specified.\n";
- /* Start monitoring a channel */
- int ast_monitor_start( struct ast_channel *chan, const char *format_spec,
- const char *fname_base, int need_lock )
- {
- int res = 0;
- char tmp[256];
- if( need_lock ) {
- if (ast_mutex_lock(&chan->lock)) {
- ast_log(LOG_WARNING, "Unable to lock channel\n");
- return -1;
- }
- }
- if( !(chan->monitor) ) {
- struct ast_channel_monitor *monitor;
- char *channel_name, *p;
- /* Create monitoring directory if needed */
- if( mkdir( AST_MONITOR_DIR, 0770 ) < 0 ) {
- if( errno != EEXIST ) {
- ast_log(LOG_WARNING, "Unable to create audio monitor directory: %s\n",
- strerror( errno ) );
- }
- }
- monitor = malloc( sizeof( struct ast_channel_monitor ) );
- memset( monitor, 0, sizeof( struct ast_channel_monitor ) );
- /* Determine file names */
- if( fname_base && strlen( fname_base ) ) {
- int directory = strchr(fname_base, '/') ? 1 : 0;
- /* try creating the directory just in case it doesn't exist */
- if (directory) {
- char *name = strdup(fname_base);
- snprintf(tmp, sizeof(tmp), "mkdir -p %s",dirname(name));
- free(name);
- system(tmp);
- }
- snprintf( monitor->read_filename, FILENAME_MAX, "%s/%s-in",
- directory ? "" : AST_MONITOR_DIR, fname_base );
- snprintf( monitor->write_filename, FILENAME_MAX, "%s/%s-out",
- directory ? "" : AST_MONITOR_DIR, fname_base );
- strncpy(monitor->filename_base, fname_base, sizeof(monitor->filename_base) - 1);
- } else {
- ast_mutex_lock( &monitorlock );
- snprintf( monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld",
- AST_MONITOR_DIR, seq );
- snprintf( monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld",
- AST_MONITOR_DIR, seq );
- seq++;
- ast_mutex_unlock( &monitorlock );
- channel_name = strdup( chan->name );
- while( ( p = strchr( channel_name, '/' ) ) ) {
- *p = '-';
- }
- snprintf( monitor->filename_base, FILENAME_MAX, "%s/%s",
- AST_MONITOR_DIR, channel_name );
- monitor->filename_changed = 1;
- free( channel_name );
- }
- monitor->stop = ast_monitor_stop;
- // Determine file format
- if( format_spec && strlen( format_spec ) ) {
- monitor->format = strdup( format_spec );
- } else {
- monitor->format = strdup( "wav" );
- }
-
- // open files
- if( ast_fileexists( monitor->read_filename, NULL, NULL ) > 0 ) {
- ast_filedelete( monitor->read_filename, NULL );
- }
- if( !(monitor->read_stream = ast_writefile( monitor->read_filename,
- monitor->format, NULL,
- O_CREAT|O_TRUNC|O_WRONLY, 0, 0644 ) ) ) {
- ast_log( LOG_WARNING, "Could not create file %s\n",
- monitor->read_filename );
- free( monitor );
- ast_mutex_unlock(&chan->lock);
- return -1;
- }
- if( ast_fileexists( monitor->write_filename, NULL, NULL ) > 0 ) {
- ast_filedelete( monitor->write_filename, NULL );
- }
- if( !(monitor->write_stream = ast_writefile( monitor->write_filename,
- monitor->format, NULL,
- O_CREAT|O_TRUNC|O_WRONLY, 0, 0644 ) ) ) {
- ast_log( LOG_WARNING, "Could not create file %s\n",
- monitor->write_filename );
- ast_closestream( monitor->read_stream );
- free( monitor );
- ast_mutex_unlock(&chan->lock);
- return -1;
- }
- chan->monitor = monitor;
- } else {
- ast_log( LOG_DEBUG,"Cannot start monitoring %s, already monitored\n",
- chan->name );
- res = -1;
- }
- if( need_lock ) {
- ast_mutex_unlock(&chan->lock);
- }
- return res;
- }
- /* Stop monitoring a channel */
- int ast_monitor_stop( struct ast_channel *chan, int need_lock )
- {
- if(need_lock) {
- if(ast_mutex_lock(&chan->lock)) {
- ast_log(LOG_WARNING, "Unable to lock channel\n");
- return -1;
- }
- }
- if(chan->monitor) {
- char filename[ FILENAME_MAX ];
- if(chan->monitor->read_stream) {
- ast_closestream( chan->monitor->read_stream );
- }
- if(chan->monitor->write_stream) {
- ast_closestream( chan->monitor->write_stream );
- }
- if(chan->monitor->filename_changed&&strlen(chan->monitor->filename_base)) {
- if( ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0 ) {
- snprintf( filename, FILENAME_MAX, "%s-in",
- chan->monitor->filename_base );
- if(ast_fileexists( filename, NULL, NULL ) > 0) {
- ast_filedelete( filename, NULL );
- }
- ast_filerename( chan->monitor->read_filename, filename,
- chan->monitor->format );
- } else {
- ast_log( LOG_WARNING, "File %s not found\n",
- chan->monitor->read_filename );
- }
- if(ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) {
- snprintf( filename, FILENAME_MAX, "%s-out",
- chan->monitor->filename_base );
- if( ast_fileexists( filename, NULL, NULL ) > 0 ) {
- ast_filedelete( filename, NULL );
- }
- ast_filerename( chan->monitor->write_filename, filename,
- chan->monitor->format );
- } else {
- ast_log( LOG_WARNING, "File %s not found\n",
- chan->monitor->write_filename );
- }
- }
- if (chan->monitor->joinfiles && strlen(chan->monitor->filename_base)) {
- char tmp[1024];
- char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
- char *name = chan->monitor->filename_base;
- int directory = strchr(name, '/') ? 1 : 0;
- char *dir = directory ? "" : AST_MONITOR_DIR;
- snprintf(tmp, sizeof(tmp), "nice -n 19 soxmix %s/%s-in.%s %s/%s-out.%s %s/%s.%s && rm -rf %s/%s-* &", dir, name, format, dir, name, format, dir, name, format, dir, name);
- #if 0
- ast_verbose("executing %s\n",tmp);
- #endif
- if (system(tmp) == -1)
- ast_log(LOG_WARNING, "You might not have the soxmix installed and available in the path, please check.\n");
- }
- free( chan->monitor->format );
- free( chan->monitor );
- chan->monitor = NULL;
- }
- if( need_lock ) {
- ast_mutex_unlock(&chan->lock);
- }
- return 0;
- }
- /* Change monitoring filename of a channel */
- int ast_monitor_change_fname( struct ast_channel *chan,
- const char *fname_base, int need_lock )
- {
- char tmp[256];
- if( (!fname_base) || (!strlen(fname_base)) ) {
- ast_log( LOG_WARNING,
- "Cannot change monitor filename of channel %s to null",
- chan->name );
- return -1;
- }
-
- if( need_lock ) {
- if (ast_mutex_lock(&chan->lock)) {
- ast_log(LOG_WARNING, "Unable to lock channel\n");
- return -1;
- }
- }
- if( chan->monitor ) {
- int directory = strchr(fname_base, '/') ? 1 : 0;
- /* try creating the directory just in case it doesn't exist */
- if (directory) {
- char *name = strdup(fname_base);
- snprintf(tmp, sizeof(tmp), "mkdir -p %s",dirname(name));
- free(name);
- system(tmp);
- }
- snprintf( chan->monitor->filename_base, FILENAME_MAX, "%s/%s",
- directory ? "" : AST_MONITOR_DIR, fname_base );
- } else {
- ast_log( LOG_WARNING,
- "Cannot change monitor filename of channel %s to %s, monitoring not started",
- chan->name, fname_base );
-
- }
- if( need_lock ) {
- ast_mutex_unlock(&chan->lock);
- }
- return 0;
- }
- static int start_monitor_exec(struct ast_channel *chan, void *data)
- {
- char *arg = NULL;
- char *format = NULL;
- char *fname_base = NULL;
- int res;
-
- /* Parse arguments. */
- if( data && strlen((char*)data) ) {
- arg = strdup( (char*)data );
- format = arg;
- fname_base = strchr( arg, '|' );
- if( fname_base ) {
- *fname_base = 0;
- fname_base++;
- }
- }
- res = ast_monitor_start( chan, format, fname_base, 1 );
- if( res < 0 ) {
- res = ast_monitor_change_fname( chan, fname_base, 1 );
- }
- if( arg ) {
- free( arg );
- }
- return res;
- }
- static int stop_monitor_exec(struct ast_channel *chan, void *data)
- {
- return ast_monitor_stop( chan, 1 );
- }
- static int change_monitor_exec(struct ast_channel *chan, void *data)
- {
- return ast_monitor_change_fname( chan, (const char*)data, 1 );
- }
- static int start_monitor_action(struct mansession *s, struct message *m)
- {
- struct ast_channel *c = NULL;
- char *name = astman_get_header(m, "Channel");
- char *fname = astman_get_header(m, "File");
- char *format = astman_get_header(m, "Format");
- char *d;
-
- if((!name)||(!strlen(name))) {
- astman_send_error(s, m, "No channel specified");
- return 0;
- }
- c = ast_channel_walk(NULL);
- while(c) {
- if (!strcasecmp(c->name, name)) {
- break;
- }
- c = ast_channel_walk(c);
- }
- if (!c) {
- astman_send_error(s, m, "No such channel");
- return 0;
- }
-
- if( (!fname) || (!strlen(fname)) ) {
- // No filename base specified, default to channel name as per CLI
- fname = malloc (FILENAME_MAX);
- memset( fname, 0, FILENAME_MAX);
- strncpy( fname, c->name, FILENAME_MAX-1);
- // Channels have the format technology/channel_name - have to replace that /
- if( (d=strchr( fname, '/')) ) *d='-';
- }
-
- if( ast_monitor_start( c, format, fname, 1 ) ) {
- if( ast_monitor_change_fname( c, fname, 1 ) ) {
- astman_send_error(s, m, "Could not start monitoring channel");
- return 0;
- }
- }
- astman_send_ack(s, m, "Started monitoring channel");
- return 0;
- }
- static int stop_monitor_action(struct mansession *s, struct message *m)
- {
- struct ast_channel *c = NULL;
- char *name = astman_get_header(m, "Channel");
- if((!name)||(!strlen(name))) {
- astman_send_error(s, m, "No channel specified");
- return 0;
- }
- c = ast_channel_walk(NULL);
- while(c) {
- if (!strcasecmp(c->name, name)) {
- break;
- }
- c = ast_channel_walk(c);
- }
- if (!c) {
- astman_send_error(s, m, "No such channel");
- return 0;
- }
- if( ast_monitor_stop( c, 1 ) ) {
- astman_send_error(s, m, "Could not stop monitoring channel");
- return 0;
- }
- astman_send_ack(s, m, "Stopped monitoring channel");
- return 0;
- }
- static int change_monitor_action(struct mansession *s, struct message *m)
- {
- struct ast_channel *c = NULL;
- char *name = astman_get_header(m, "Channel");
- char *fname = astman_get_header(m, "File");
- if((!name) || (!strlen(name))) {
- astman_send_error(s, m, "No channel specified");
- return 0;
- }
- if ((!fname)||(!strlen(fname))) {
- astman_send_error(s, m, "No filename specified");
- return 0;
- }
- c = ast_channel_walk(NULL);
- while(c) {
- if (!strcasecmp(c->name, name)) {
- break;
- }
- c = ast_channel_walk(c);
- }
- if (!c) {
- astman_send_error(s, m, "No such channel");
- return 0;
- }
- if( ast_monitor_change_fname( c, fname, 1 ) ) {
- astman_send_error(s, m, "Could not change monitored filename of channel");
- return 0;
- }
- astman_send_ack(s, m, "Stopped monitoring channel");
- return 0;
- }
- void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon)
- {
- if (chan->monitor)
- chan->monitor->joinfiles = turnon;
- }
- int load_module(void)
- {
- ast_register_application( "Monitor", start_monitor_exec, monitor_synopsis, monitor_descrip );
- ast_register_application( "StopMonitor", stop_monitor_exec, stopmonitor_synopsis, stopmonitor_descrip );
- ast_register_application( "ChangeMonitor", change_monitor_exec, changemonitor_synopsis, changemonitor_descrip );
- ast_manager_register( "Monitor", EVENT_FLAG_CALL, start_monitor_action, monitor_synopsis );
- ast_manager_register( "StopMonitor", EVENT_FLAG_CALL, stop_monitor_action, stopmonitor_synopsis );
- ast_manager_register( "ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action, changemonitor_synopsis );
- return 0;
- }
- int unload_module(void)
- {
- ast_unregister_application( "Monitor" );
- ast_unregister_application( "StopMonitor" );
- return 0;
- }
- char *description(void)
- {
- return "Call Monitoring Resource";
- }
- int usecount(void)
- {
- /* Never allow monitor to be unloaded because it will
- unresolve needed symbols in the channel */
- #if 0
- int res;
- STANDARD_USECOUNT(res);
- return res;
- #else
- return 1;
- #endif
- }
- char *key()
- {
- return ASTERISK_GPL_KEY;
- }
|