Thu Apr 8 01:23:10 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 414 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().

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

int ast_monitor_pause ( struct ast_channel chan  ) 

Pause monitoring of channel.

Definition at line 383 of file res_monitor.c.

References AST_MONITOR_PAUSED, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and pause_monitor_exec().

00384 {
00385    return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
00386 }

void ast_monitor_setjoinfiles ( struct ast_channel chan,
int  turnon 
)

Definition at line 715 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().

00716 {
00717    if (chan->monitor)
00718       chan->monitor->joinfiles = turnon;
00719 }

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

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 290 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().

00291 {
00292    int delfiles = 0;
00293 
00294    LOCK_IF_NEEDED(chan, need_lock);
00295 
00296    if (chan->monitor) {
00297       char filename[ FILENAME_MAX ];
00298 
00299       if (chan->monitor->read_stream) {
00300          ast_closestream(chan->monitor->read_stream);
00301       }
00302       if (chan->monitor->write_stream) {
00303          ast_closestream(chan->monitor->write_stream);
00304       }
00305 
00306       if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) {
00307          if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) {
00308             snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base);
00309             if (ast_fileexists(filename, NULL, NULL) > 0) {
00310                ast_filedelete(filename, NULL);
00311             }
00312             ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format);
00313          } else {
00314             ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename);
00315          }
00316 
00317          if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) {
00318             snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base);
00319             if (ast_fileexists(filename, NULL, NULL) > 0) {
00320                ast_filedelete(filename, NULL);
00321             }
00322             ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format);
00323          } else {
00324             ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename);
00325          }
00326       }
00327 
00328       if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) {
00329          char tmp[1024];
00330          char tmp2[1024];
00331          const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
00332          char *name = chan->monitor->filename_base;
00333          int directory = strchr(name, '/') ? 1 : 0;
00334          const char *dir = directory ? "" : ast_config_AST_MONITOR_DIR;
00335          const char *execute, *execute_args;
00336          const char *absolute = *name == '/' ? "" : "/";
00337 
00338          /* Set the execute application */
00339          execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
00340          if (ast_strlen_zero(execute)) {
00341 #ifdef HAVE_SOXMIX
00342             execute = "nice -n 19 soxmix";
00343 #else
00344             execute = "nice -n 19 sox -m";
00345 #endif
00346             format = get_soxmix_format(format);
00347             delfiles = 1;
00348          } 
00349          execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
00350          if (ast_strlen_zero(execute_args)) {
00351             execute_args = "";
00352          }
00353          
00354          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);
00355          if (delfiles) {
00356             snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s%s%s-\"* ) &",tmp, dir, absolute, name); /* 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    }
00375 
00376    UNLOCK_IF_NEEDED(chan, need_lock);
00377 
00378    return 0;
00379 }

int ast_monitor_unpause ( struct ast_channel chan  ) 

Unpause monitoring of channel.

Definition at line 389 of file res_monitor.c.

References AST_MONITOR_RUNNING, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and unpause_monitor_exec().

00390 {
00391    return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00392 }


Generated on 8 Apr 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1