Tue Mar 2 17:34:03 2010

Asterisk developer's documentation


monitor.h File Reference

Channel monitoring. More...

#include "asterisk/channel.h"
Include dependency graph for monitor.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ast_channel_monitor

Defines

#define X_JOIN   4
#define X_REC_IN   1
#define X_REC_OUT   2

Enumerations

enum  AST_MONITORING_STATE { AST_MONITOR_RUNNING, AST_MONITOR_PAUSED }

Functions

int ast_monitor_change_fname (struct ast_channel *chan, const char *fname_base, int need_lock) attribute_weak
 Change monitored filename of channel.
int ast_monitor_pause (struct ast_channel *chan) attribute_weak
 Pause monitoring of channel.
void ast_monitor_setjoinfiles (struct ast_channel *chan, int turnon) attribute_weak
int ast_monitor_start (struct ast_channel *chan, const char *format_spec, const char *fname_base, int need_lock, int stream_action) attribute_weak
 Start monitoring a channel.
int ast_monitor_stop (struct ast_channel *chan, int need_lock) attribute_weak
 Stop monitoring channel.
int ast_monitor_unpause (struct ast_channel *chan) attribute_weak
 Unpause monitoring of channel.

Detailed Description

Channel monitoring.

Definition in file monitor.h.


Define Documentation

#define X_JOIN   4

Definition at line 36 of file monitor.h.

Referenced by start_monitor_exec().

#define X_REC_IN   1
#define X_REC_OUT   2

Enumeration Type Documentation

Enumerator:
AST_MONITOR_RUNNING 
AST_MONITOR_PAUSED 

Definition at line 28 of file monitor.h.

00028                           {
00029    AST_MONITOR_RUNNING,
00030    AST_MONITOR_PAUSED
00031 };


Function Documentation

int ast_monitor_change_fname ( struct ast_channel chan,
const char *  fname_base,
int  need_lock 
)

Change monitored filename of channel.

Parameters:
chan 
fname_base new filename
need_lock 
Return values:
0 on success.
-1 on failure.

Note:
We cannot just compare filenames, due to symlinks, relative paths, and other possible filesystem issues. We could use realpath(3), but its use is discouraged. However, if we try to create the same file from two different paths, the second will fail, and so we have our notification that the filenames point to the same path.

Remember, also, that we're using the basename of the file (i.e. the file without the format suffix), so it does not already exist and we aren't interfering with the recording itself.

Definition at line 412 of file res_monitor.c.

References ast_config_AST_MONITOR_DIR, ast_copy_string(), ast_debug, ast_log(), ast_mkdir(), ast_strdupa, ast_strlen_zero(), errno, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, LOCK_IF_NEEDED, LOG_ERROR, LOG_WARNING, ast_channel::monitor, name, and UNLOCK_IF_NEEDED.

Referenced by change_monitor_action(), change_monitor_exec(), start_monitor_action(), and start_monitor_exec().

00413 {
00414    if (ast_strlen_zero(fname_base)) {
00415       ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", chan->name);
00416       return -1;
00417    }
00418 
00419    LOCK_IF_NEEDED(chan, need_lock);
00420 
00421    if (chan->monitor) {
00422       int directory = strchr(fname_base, '/') ? 1 : 0;
00423       const char *absolute = *fname_base == '/' ? "" : "/";
00424       char tmpstring[sizeof(chan->monitor->filename_base)] = "";
00425       int i, fd[2] = { -1, -1 }, doexit = 0;
00426 
00427       /* before continuing, see if we're trying to rename the file to itself... */
00428       snprintf(tmpstring, sizeof(tmpstring), "%s%s%s", directory ? "" : ast_config_AST_MONITOR_DIR, absolute, fname_base);
00429 
00430       /*!\note We cannot just compare filenames, due to symlinks, relative
00431        * paths, and other possible filesystem issues.  We could use
00432        * realpath(3), but its use is discouraged.  However, if we try to
00433        * create the same file from two different paths, the second will
00434        * fail, and so we have our notification that the filenames point to
00435        * the same path.
00436        *
00437        * Remember, also, that we're using the basename of the file (i.e.
00438        * the file without the format suffix), so it does not already exist
00439        * and we aren't interfering with the recording itself.
00440        */
00441       ast_debug(2, "comparing tmpstring %s to filename_base %s\n", tmpstring, chan->monitor->filename_base);
00442       
00443       if ((fd[0] = open(tmpstring, O_CREAT | O_WRONLY, 0644)) < 0 ||
00444          (fd[1] = open(chan->monitor->filename_base, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) {
00445          if (fd[0] < 0) {
00446             ast_log(LOG_ERROR, "Unable to compare filenames: %s\n", strerror(errno));
00447          } else {
00448             ast_debug(2, "No need to rename monitor filename to itself\n");
00449          }
00450          doexit = 1;
00451       }
00452 
00453       /* Cleanup temporary files */
00454       for (i = 0; i < 2; i++) {
00455          if (fd[i] >= 0) {
00456             while (close(fd[i]) < 0 && errno == EINTR);
00457          }
00458       }
00459       unlink(tmpstring);
00460       unlink(chan->monitor->filename_base);
00461 
00462       if (doexit) {
00463          UNLOCK_IF_NEEDED(chan, need_lock);
00464          return 0;
00465       }
00466 
00467       /* try creating the directory just in case it doesn't exist */
00468       if (directory) {
00469          char *name = ast_strdupa(fname_base);
00470          ast_mkdir(dirname(name), 0777);
00471       }
00472 
00473       ast_copy_string(chan->monitor->filename_base, tmpstring, sizeof(chan->monitor->filename_base));
00474       chan->monitor->filename_changed = 1;
00475    } else {
00476       ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", chan->name, fname_base);
00477    }
00478 
00479    UNLOCK_IF_NEEDED(chan, need_lock);
00480 
00481    return 0;
00482 }

int ast_monitor_pause ( struct ast_channel chan  ) 

Pause monitoring of channel.

Definition at line 381 of file res_monitor.c.

References AST_MONITOR_PAUSED, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and pause_monitor_exec().

00382 {
00383    return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
00384 }

void ast_monitor_setjoinfiles ( struct ast_channel chan,
int  turnon 
)

Definition at line 713 of file res_monitor.c.

References ast_channel_monitor::joinfiles, and ast_channel::monitor.

Referenced by __agent_start_monitoring(), start_monitor_action(), start_monitor_exec(), and try_calling().

00714 {
00715    if (chan->monitor)
00716       chan->monitor->joinfiles = turnon;
00717 }

int ast_monitor_start ( struct ast_channel chan,
const char *  format_spec,
const char *  fname_base,
int  need_lock,
int  stream_action 
)

Start monitoring a channel.

Parameters:
chan ast_channel struct to record
format_spec file format to use for recording
fname_base filename base to record to
need_lock whether to lock the channel mutex
stream_action whether to record the input and/or output streams. X_REC_IN | X_REC_OUT is most often used Creates the file to record, if no format is specified it assumes WAV It also sets channel variable __MONITORED=yes
Return values:
0 on success
-1 on failure

Definition at line 147 of file res_monitor.c.

References ast_calloc, ast_closestream(), ast_config_AST_MONITOR_DIR, ast_debug, AST_FILE_MODE, ast_filedelete(), ast_fileexists(), ast_free, ast_log(), ast_mkdir(), AST_MONITOR_RUNNING, ast_monitor_set_state(), ast_monitor_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdup, ast_strdupa, ast_strlen_zero(), ast_writefile(), EVENT_FLAG_CALL, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, FILENAME_MAX, ast_channel_monitor::format, LOCK_IF_NEEDED, LOG_WARNING, manager_event, monitor, ast_channel::monitor, monitorlock, name, pbx_builtin_setvar_helper(), ast_channel_monitor::read_filename, ast_channel_monitor::read_stream, ast_channel_monitor::stop, UNLOCK_IF_NEEDED, ast_channel_monitor::write_filename, ast_channel_monitor::write_stream, X_REC_IN, and X_REC_OUT.

Referenced by __agent_start_monitoring(), start_monitor_action(), start_monitor_exec(), and try_calling().

00149 {
00150    int res = 0;
00151 
00152    LOCK_IF_NEEDED(chan, need_lock);
00153 
00154    if (!(chan->monitor)) {
00155       struct ast_channel_monitor *monitor;
00156       char *channel_name, *p;
00157 
00158       /* Create monitoring directory if needed */
00159       ast_mkdir(ast_config_AST_MONITOR_DIR, 0777);
00160 
00161       if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
00162          UNLOCK_IF_NEEDED(chan, need_lock);
00163          return -1;
00164       }
00165 
00166       /* Determine file names */
00167       if (!ast_strlen_zero(fname_base)) {
00168          int directory = strchr(fname_base, '/') ? 1 : 0;
00169          const char *absolute = *fname_base == '/' ? "" : "/";
00170          /* try creating the directory just in case it doesn't exist */
00171          if (directory) {
00172             char *name = ast_strdupa(fname_base);
00173             ast_mkdir(dirname(name), 0777);
00174          }
00175          snprintf(monitor->read_filename, FILENAME_MAX, "%s%s%s-in",
00176                   directory ? "" : ast_config_AST_MONITOR_DIR, absolute, fname_base);
00177          snprintf(monitor->write_filename, FILENAME_MAX, "%s%s%s-out",
00178                   directory ? "" : ast_config_AST_MONITOR_DIR, absolute, fname_base);
00179          snprintf(monitor->filename_base, FILENAME_MAX, "%s%s%s",
00180                   directory ? "" : ast_config_AST_MONITOR_DIR, absolute, fname_base);
00181       } else {
00182          ast_mutex_lock(&monitorlock);
00183          snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld",
00184                   ast_config_AST_MONITOR_DIR, seq);
00185          snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld",
00186                   ast_config_AST_MONITOR_DIR, seq);
00187          seq++;
00188          ast_mutex_unlock(&monitorlock);
00189 
00190          channel_name = ast_strdupa(chan->name);
00191          while ((p = strchr(channel_name, '/'))) {
00192             *p = '-';
00193          }
00194          snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
00195                 ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
00196          monitor->filename_changed = 1;
00197       }
00198 
00199       monitor->stop = ast_monitor_stop;
00200 
00201       /* Determine file format */
00202       if (!ast_strlen_zero(format_spec)) {
00203          monitor->format = ast_strdup(format_spec);
00204       } else {
00205          monitor->format = ast_strdup("wav");
00206       }
00207       
00208       /* open files */
00209       if (stream_action & X_REC_IN) {
00210          if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0)
00211             ast_filedelete(monitor->read_filename, NULL);
00212          if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
00213                      monitor->format, NULL,
00214                      O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
00215             ast_log(LOG_WARNING, "Could not create file %s\n",
00216                      monitor->read_filename);
00217             ast_free(monitor);
00218             UNLOCK_IF_NEEDED(chan, need_lock);
00219             return -1;
00220          }
00221       } else
00222          monitor->read_stream = NULL;
00223 
00224       if (stream_action & X_REC_OUT) {
00225          if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
00226             ast_filedelete(monitor->write_filename, NULL);
00227          }
00228          if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
00229                      monitor->format, NULL,
00230                      O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
00231             ast_log(LOG_WARNING, "Could not create file %s\n",
00232                      monitor->write_filename);
00233             ast_closestream(monitor->read_stream);
00234             ast_free(monitor);
00235             UNLOCK_IF_NEEDED(chan, need_lock);
00236             return -1;
00237          }
00238       } else
00239          monitor->write_stream = NULL;
00240 
00241       chan->monitor = monitor;
00242       ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00243       /* so we know this call has been monitored in case we need to bill for it or something */
00244       pbx_builtin_setvar_helper(chan, "__MONITORED","true");
00245 
00246       manager_event(EVENT_FLAG_CALL, "MonitorStart",
00247                          "Channel: %s\r\n"
00248                           "Uniqueid: %s\r\n",                        
00249                            chan->name,
00250                          chan->uniqueid                        
00251                           );
00252    } else {
00253       ast_debug(1,"Cannot start monitoring %s, already monitored\n", chan->name);
00254       res = -1;
00255    }
00256 
00257    UNLOCK_IF_NEEDED(chan, need_lock);
00258 
00259    return res;
00260 }

int ast_monitor_stop ( struct ast_channel chan,
int  need_lock 
)

Stop monitoring channel.

Parameters:
chan 
need_lock Stop the recording, close any open streams, mix in/out channels if required
Returns:
Always 0

Definition at line 288 of file res_monitor.c.

References ast_closestream(), ast_config_AST_MONITOR_DIR, ast_copy_string(), ast_debug, ast_filedelete(), ast_fileexists(), ast_filerename(), ast_free, ast_log(), ast_safe_system(), ast_strlen_zero(), dir, EVENT_FLAG_CALL, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, FILENAME_MAX, format, ast_channel_monitor::format, get_soxmix_format(), ast_channel_monitor::joinfiles, LOCK_IF_NEEDED, LOG_WARNING, manager_event, ast_channel::monitor, name, pbx_builtin_getvar_helper(), ast_channel_monitor::read_filename, ast_channel_monitor::read_stream, UNLOCK_IF_NEEDED, ast_channel_monitor::write_filename, and ast_channel_monitor::write_stream.

Referenced by ast_monitor_start(), stop_monitor_action(), and stop_monitor_exec().

00289 {
00290    int delfiles = 0;
00291 
00292    LOCK_IF_NEEDED(chan, need_lock);
00293 
00294    if (chan->monitor) {
00295       char filename[ FILENAME_MAX ];
00296 
00297       if (chan->monitor->read_stream) {
00298          ast_closestream(chan->monitor->read_stream);
00299       }
00300       if (chan->monitor->write_stream) {
00301          ast_closestream(chan->monitor->write_stream);
00302       }
00303 
00304       if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) {
00305          if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) {
00306             snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base);
00307             if (ast_fileexists(filename, NULL, NULL) > 0) {
00308                ast_filedelete(filename, NULL);
00309             }
00310             ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format);
00311          } else {
00312             ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename);
00313          }
00314 
00315          if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) {
00316             snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base);
00317             if (ast_fileexists(filename, NULL, NULL) > 0) {
00318                ast_filedelete(filename, NULL);
00319             }
00320             ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format);
00321          } else {
00322             ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename);
00323          }
00324       }
00325 
00326       if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) {
00327          char tmp[1024];
00328          char tmp2[1024];
00329          const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
00330          char *name = chan->monitor->filename_base;
00331          int directory = strchr(name, '/') ? 1 : 0;
00332          const char *dir = directory ? "" : ast_config_AST_MONITOR_DIR;
00333          const char *execute, *execute_args;
00334          const char *absolute = *name == '/' ? "" : "/";
00335 
00336          /* Set the execute application */
00337          execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
00338          if (ast_strlen_zero(execute)) {
00339 #ifdef HAVE_SOXMIX
00340             execute = "nice -n 19 soxmix";
00341 #else
00342             execute = "nice -n 19 sox -m";
00343 #endif
00344             format = get_soxmix_format(format);
00345             delfiles = 1;
00346          } 
00347          execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
00348          if (ast_strlen_zero(execute_args)) {
00349             execute_args = "";
00350          }
00351          
00352          snprintf(tmp, sizeof(tmp), "%s \"%s%s%s-in.%s\" \"%s%s%s-out.%s\" \"%s%s%s.%s\" %s &", execute, dir, absolute, name, format, dir, absolute, name, format, dir, absolute, name, format,execute_args);
00353          if (delfiles) {
00354             snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s%s%s-\"* ) &",tmp, dir, absolute, name); /* remove legs when done mixing */
00355             ast_copy_string(tmp, tmp2, sizeof(tmp));
00356          }
00357          ast_debug(1,"monitor executing %s\n",tmp);
00358          if (ast_safe_system(tmp) == -1)
00359             ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
00360       }
00361       
00362       ast_free(chan->monitor->format);
00363       ast_free(chan->monitor);
00364       chan->monitor = NULL;
00365 
00366       manager_event(EVENT_FLAG_CALL, "MonitorStop",
00367                          "Channel: %s\r\n"
00368                            "Uniqueid: %s\r\n",
00369                            chan->name,
00370                            chan->uniqueid
00371                            );
00372    }
00373 
00374    UNLOCK_IF_NEEDED(chan, need_lock);
00375 
00376    return 0;
00377 }

int ast_monitor_unpause ( struct ast_channel chan  ) 

Unpause monitoring of channel.

Definition at line 387 of file res_monitor.c.

References AST_MONITOR_RUNNING, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and unpause_monitor_exec().

00388 {
00389    return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00390 }


Generated on 2 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1