Wed Aug 18 22:34:27 2010

Asterisk developer's documentation


monitor.h File Reference

Channel monitoring. More...

#include "asterisk/channel.h"

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

Definition at line 34 of file monitor.h.

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

#define X_REC_OUT   2

Definition at line 35 of file monitor.h.

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


Enumeration Type Documentation

enum AST_MONITORING_STATE

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 416 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(), chan, errno, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, LOCK_IF_NEEDED, LOG_ERROR, LOG_WARNING, ast_channel::monitor, ast_channel::name, name, and UNLOCK_IF_NEEDED.

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

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

int ast_monitor_pause ( struct ast_channel chan  ) 

Pause monitoring of channel.

Definition at line 385 of file res_monitor.c.

References AST_MONITOR_PAUSED, ast_monitor_set_state(), and chan.

Referenced by do_pause_or_unpause(), and pause_monitor_exec().

00386 {
00387    return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
00388 }

void ast_monitor_setjoinfiles ( struct ast_channel chan,
int  turnon 
)

Definition at line 719 of file res_monitor.c.

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

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

00720 {
00721    if (chan->monitor)
00722       chan->monitor->joinfiles = turnon;
00723 }

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(), chan, EVENT_FLAG_CALL, FILENAME_MAX, LOCK_IF_NEEDED, LOG_WARNING, manager_event, ast_channel::monitor, monitor, monitorlock, name, ast_channel::name, pbx_builtin_setvar_helper(), ast_channel::uniqueid, UNLOCK_IF_NEEDED, X_REC_IN, and X_REC_OUT.

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

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

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 291 of file res_monitor.c.

References ast_closestream(), ast_copy_string(), ast_debug, ast_filedelete(), ast_fileexists(), ast_filerename(), ast_free, ast_log(), ast_safe_system(), ast_strlen_zero(), chan, EVENT_FLAG_CALL, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, FILENAME_MAX, ast_channel_monitor::format, format, get_soxmix_format(), ast_channel_monitor::joinfiles, LOCK_IF_NEEDED, LOG_WARNING, manager_event, ast_channel::monitor, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel_monitor::read_filename, ast_channel_monitor::read_stream, ast_channel::uniqueid, 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().

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

int ast_monitor_unpause ( struct ast_channel chan  ) 

Unpause monitoring of channel.

Definition at line 391 of file res_monitor.c.

References AST_MONITOR_RUNNING, ast_monitor_set_state(), and chan.

Referenced by do_pause_or_unpause(), and unpause_monitor_exec().

00392 {
00393    return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00394 }


Generated on Wed Aug 18 22:34:27 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7