Mon Jun 27 16:51:16 2011

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

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

int ast_monitor_pause ( struct ast_channel chan  ) 

Pause monitoring of channel.

Definition at line 523 of file res_monitor.c.

References AST_MONITOR_PAUSED, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and pause_monitor_exec().

00524 {
00525    return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
00526 }

void ast_monitor_setjoinfiles ( struct ast_channel chan,
int  turnon 
)

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

00850 {
00851    if (chan->monitor)
00852       chan->monitor->joinfiles = turnon;
00853 }

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

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

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

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

int ast_monitor_unpause ( struct ast_channel chan  ) 

Unpause monitoring of channel.

Definition at line 529 of file res_monitor.c.

References AST_MONITOR_RUNNING, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and unpause_monitor_exec().

00530 {
00531    return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00532 }


Generated on Mon Jun 27 16:51:16 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7