Mon Oct 8 12:39:24 2012

Asterisk developer's documentation


monitor.h File Reference

Channel monitoring. More...

#include "asterisk/channel.h"
#include "asterisk/optional_api.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)
 Change monitored filename of channel.
int ast_monitor_pause (struct ast_channel *chan)
 Pause monitoring of channel.
void ast_monitor_setjoinfiles (struct ast_channel *chan, int turnon)
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.
int ast_monitor_stop (struct ast_channel *chan, int need_lock)
 Stop monitoring channel.
int ast_monitor_unpause (struct ast_channel *chan)
 Unpause monitoring of channel.


Detailed Description

Channel monitoring.

Definition in file monitor.h.


Define Documentation

#define X_JOIN   4

Definition at line 37 of file monitor.h.

Referenced by start_monitor_exec().

#define X_REC_IN   1

Definition at line 35 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 36 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 29 of file monitor.h.

00029                           {
00030    AST_MONITOR_RUNNING,
00031    AST_MONITOR_PAUSED
00032 };


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 562 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, ast_channel::name, name, and UNLOCK_IF_NEEDED.

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

00563 {
00564    if (ast_strlen_zero(fname_base)) {
00565       ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", chan->name);
00566       return -1;
00567    }
00568 
00569    LOCK_IF_NEEDED(chan, need_lock);
00570 
00571    if (chan->monitor) {
00572       int directory = strchr(fname_base, '/') ? 1 : 0;
00573       const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
00574       const char *absolute_suffix = *fname_base == '/' ? "" : "/";
00575       char tmpstring[sizeof(chan->monitor->filename_base)] = "";
00576       int i, fd[2] = { -1, -1 }, doexit = 0;
00577 
00578       /* before continuing, see if we're trying to rename the file to itself... */
00579       snprintf(tmpstring, sizeof(tmpstring), "%s%s%s", absolute, absolute_suffix, fname_base);
00580 
00581       /* try creating the directory just in case it doesn't exist */
00582       if (directory) {
00583          char *name = ast_strdupa(tmpstring);
00584          ast_mkdir(dirname(name), 0777);
00585       }
00586 
00587       /*!
00588        * \note We cannot just compare filenames, due to symlinks, relative
00589        * paths, and other possible filesystem issues.  We could use
00590        * realpath(3), but its use is discouraged.  However, if we try to
00591        * create the same file from two different paths, the second will
00592        * fail, and so we have our notification that the filenames point to
00593        * the same path.
00594        *
00595        * Remember, also, that we're using the basename of the file (i.e.
00596        * the file without the format suffix), so it does not already exist
00597        * and we aren't interfering with the recording itself.
00598        */
00599       ast_debug(2, "comparing tmpstring %s to filename_base %s\n", tmpstring, chan->monitor->filename_base);
00600       
00601       if ((fd[0] = open(tmpstring, O_CREAT | O_WRONLY, 0644)) < 0 ||
00602          (fd[1] = open(chan->monitor->filename_base, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) {
00603          if (fd[0] < 0) {
00604             ast_log(LOG_ERROR, "Unable to compare filenames: %s\n", strerror(errno));
00605          } else {
00606             ast_debug(2, "No need to rename monitor filename to itself\n");
00607          }
00608          doexit = 1;
00609       }
00610 
00611       /* Cleanup temporary files */
00612       for (i = 0; i < 2; i++) {
00613          if (fd[i] >= 0) {
00614             while (close(fd[i]) < 0 && errno == EINTR);
00615          }
00616       }
00617       unlink(tmpstring);
00618       /* if previous monitor file existed in a subdirectory, the directory will not be removed */
00619       unlink(chan->monitor->filename_base);
00620 
00621       if (doexit) {
00622          UNLOCK_IF_NEEDED(chan, need_lock);
00623          return 0;
00624       }
00625 
00626       ast_copy_string(chan->monitor->filename_base, tmpstring, sizeof(chan->monitor->filename_base));
00627       chan->monitor->filename_changed = 1;
00628    } else {
00629       ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", chan->name, fname_base);
00630    }
00631 
00632    UNLOCK_IF_NEEDED(chan, need_lock);
00633 
00634    return 0;
00635 }

int ast_monitor_pause ( struct ast_channel chan  ) 

Pause monitoring of channel.

Definition at line 531 of file res_monitor.c.

References AST_MONITOR_PAUSED, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and pause_monitor_exec().

00532 {
00533    return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
00534 }

void ast_monitor_setjoinfiles ( struct ast_channel chan,
int  turnon 
)

Definition at line 863 of file res_monitor.c.

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

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

00864 {
00865    if (chan->monitor)
00866       chan->monitor->joinfiles = turnon;
00867 }

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 290 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_manager_event, 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, FILENAME_MAX, LOCK_IF_NEEDED, LOG_WARNING, 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().

00292 {
00293    int res = 0;
00294 
00295    LOCK_IF_NEEDED(chan, need_lock);
00296 
00297    if (!(chan->monitor)) {
00298       struct ast_channel_monitor *monitor;
00299       char *channel_name, *p;
00300 
00301       /* Create monitoring directory if needed */
00302       ast_mkdir(ast_config_AST_MONITOR_DIR, 0777);
00303 
00304       if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
00305          UNLOCK_IF_NEEDED(chan, need_lock);
00306          return -1;
00307       }
00308 
00309       /* Determine file names */
00310       if (!ast_strlen_zero(fname_base)) {
00311          int directory = strchr(fname_base, '/') ? 1 : 0;
00312          const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
00313          const char *absolute_suffix = *fname_base == '/' ? "" : "/";
00314 
00315          snprintf(monitor->read_filename, FILENAME_MAX, "%s%s%s-in",
00316                   absolute, absolute_suffix, fname_base);
00317          snprintf(monitor->write_filename, FILENAME_MAX, "%s%s%s-out",
00318                   absolute, absolute_suffix, fname_base);
00319          snprintf(monitor->filename_base, FILENAME_MAX, "%s%s%s",
00320                   absolute, absolute_suffix, fname_base);
00321 
00322          /* try creating the directory just in case it doesn't exist */
00323          if (directory) {
00324             char *name = ast_strdupa(monitor->filename_base);
00325             ast_mkdir(dirname(name), 0777);
00326          }
00327       } else {
00328          ast_mutex_lock(&monitorlock);
00329          snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld",
00330                   ast_config_AST_MONITOR_DIR, seq);
00331          snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld",
00332                   ast_config_AST_MONITOR_DIR, seq);
00333          seq++;
00334          ast_mutex_unlock(&monitorlock);
00335 
00336          /* Replace all '/' chars from the channel name with '-' chars. */
00337          channel_name = ast_strdupa(chan->name);
00338          for (p = channel_name; (p = strchr(p, '/')); ) {
00339             *p = '-';
00340          }
00341 
00342          snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
00343                 ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
00344          monitor->filename_changed = 1;
00345       }
00346 
00347       monitor->stop = ast_monitor_stop;
00348 
00349       /* Determine file format */
00350       if (!ast_strlen_zero(format_spec)) {
00351          monitor->format = ast_strdup(format_spec);
00352       } else {
00353          monitor->format = ast_strdup("wav");
00354       }
00355       
00356       /* open files */
00357       if (stream_action & X_REC_IN) {
00358          if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0)
00359             ast_filedelete(monitor->read_filename, NULL);
00360          if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
00361                      monitor->format, NULL,
00362                      O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
00363             ast_log(LOG_WARNING, "Could not create file %s\n",
00364                      monitor->read_filename);
00365             ast_free(monitor);
00366             UNLOCK_IF_NEEDED(chan, need_lock);
00367             return -1;
00368          }
00369       } else
00370          monitor->read_stream = NULL;
00371 
00372       if (stream_action & X_REC_OUT) {
00373          if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
00374             ast_filedelete(monitor->write_filename, NULL);
00375          }
00376          if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
00377                      monitor->format, NULL,
00378                      O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
00379             ast_log(LOG_WARNING, "Could not create file %s\n",
00380                      monitor->write_filename);
00381             if (monitor->read_stream) {
00382                ast_closestream(monitor->read_stream);
00383             }
00384             ast_free(monitor);
00385             UNLOCK_IF_NEEDED(chan, need_lock);
00386             return -1;
00387          }
00388       } else
00389          monitor->write_stream = NULL;
00390 
00391       chan->monitor = monitor;
00392       ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00393       /* so we know this call has been monitored in case we need to bill for it or something */
00394       pbx_builtin_setvar_helper(chan, "__MONITORED","true");
00395 
00396       ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStart",
00397                          "Channel: %s\r\n"
00398                        "Uniqueid: %s\r\n",
00399                            chan->name,
00400                          chan->uniqueid);
00401    } else {
00402       ast_debug(1,"Cannot start monitoring %s, already monitored\n", chan->name);
00403       res = -1;
00404    }
00405 
00406    UNLOCK_IF_NEEDED(chan, need_lock);
00407 
00408    return res;
00409 }

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

References ast_closestream(), ast_copy_string(), ast_debug, ast_filedelete(), ast_fileexists(), ast_filerename(), ast_free, ast_log(), ast_manager_event, ast_safe_system(), ast_strlen_zero(), 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, 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().

00438 {
00439    int delfiles = 0;
00440 
00441    LOCK_IF_NEEDED(chan, need_lock);
00442 
00443    if (chan->monitor) {
00444       char filename[ FILENAME_MAX ];
00445 
00446       if (chan->monitor->read_stream) {
00447          ast_closestream(chan->monitor->read_stream);
00448       }
00449       if (chan->monitor->write_stream) {
00450          ast_closestream(chan->monitor->write_stream);
00451       }
00452 
00453       if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) {
00454          if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) {
00455             snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base);
00456             if (ast_fileexists(filename, NULL, NULL) > 0) {
00457                ast_filedelete(filename, NULL);
00458             }
00459             ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format);
00460          } else {
00461             ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename);
00462          }
00463 
00464          if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) {
00465             snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base);
00466             if (ast_fileexists(filename, NULL, NULL) > 0) {
00467                ast_filedelete(filename, NULL);
00468             }
00469             ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format);
00470          } else {
00471             ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename);
00472          }
00473       }
00474 
00475       if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) {
00476          char tmp[1024];
00477          char tmp2[1024];
00478          const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
00479          char *fname_base = chan->monitor->filename_base;
00480          const char *execute, *execute_args;
00481          /* at this point, fname_base really is the full path */
00482 
00483          /* Set the execute application */
00484          execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
00485          if (ast_strlen_zero(execute)) {
00486 #ifdef HAVE_SOXMIX
00487             execute = "nice -n 19 soxmix";
00488 #else
00489             execute = "nice -n 19 sox -m";
00490 #endif
00491             format = get_soxmix_format(format);
00492             delfiles = 1;
00493          } 
00494          execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
00495          if (ast_strlen_zero(execute_args)) {
00496             execute_args = "";
00497          }
00498          
00499          snprintf(tmp, sizeof(tmp), "%s \"%s-in.%s\" \"%s-out.%s\" \"%s.%s\" %s &",
00500             execute, fname_base, format, fname_base, format, fname_base, format,execute_args);
00501          if (delfiles) {
00502             snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s-\"* ) &",tmp, fname_base); /* remove legs when done mixing */
00503             ast_copy_string(tmp, tmp2, sizeof(tmp));
00504          }
00505          ast_debug(1,"monitor executing %s\n",tmp);
00506          if (ast_safe_system(tmp) == -1)
00507             ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
00508       }
00509       
00510       ast_free(chan->monitor->format);
00511       ast_free(chan->monitor);
00512       chan->monitor = NULL;
00513 
00514       ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStop",
00515                          "Channel: %s\r\n"
00516                            "Uniqueid: %s\r\n",
00517                            chan->name,
00518                            chan->uniqueid
00519                            );
00520       pbx_builtin_setvar_helper(chan, "MONITORED", NULL);
00521    }
00522    pbx_builtin_setvar_helper(chan, "AUTO_MONITOR", NULL);
00523 
00524    UNLOCK_IF_NEEDED(chan, need_lock);
00525 
00526    return 0;
00527 }

int ast_monitor_unpause ( struct ast_channel chan  ) 

Unpause monitoring of channel.

Definition at line 537 of file res_monitor.c.

References AST_MONITOR_RUNNING, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and unpause_monitor_exec().

00538 {
00539    return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00540 }


Generated on Mon Oct 8 12:39:24 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7