Sat Aug 6 00:39:59 2011

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

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)
int ast_monitor_pause (struct ast_channel *chan)
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 ast_monitor_stop (struct ast_channel *chan, int need_lock)
int ast_monitor_unpause (struct ast_channel *chan)


Detailed Description

Channel monitoring.

Definition in file monitor.h.


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 
)

Definition at line 371 of file res_monitor.c.

References ast_config_AST_MONITOR_DIR, ast_copy_string(), ast_log(), ast_safe_system(), ast_strlen_zero(), errno, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, free, LOCK_IF_NEEDED, LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_channel::monitor, ast_channel::name, name, option_debug, strdup, and UNLOCK_IF_NEEDED.

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

00372 {
00373    char tmp[256];
00374    if (ast_strlen_zero(fname_base)) {
00375       ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", chan->name);
00376       return -1;
00377    }
00378 
00379    LOCK_IF_NEEDED(chan, need_lock);
00380 
00381    if (chan->monitor) {
00382       int directory = strchr(fname_base, '/') ? 1 : 0;
00383       const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
00384       const char *absolute_suffix = *fname_base == '/' ? "" : "/";
00385       char tmpstring[sizeof(chan->monitor->filename_base)] = "";
00386       int i, fd[2] = { -1, -1 }, doexit = 0;
00387 
00388       /* before continuing, see if we're trying to rename the file to itself... */
00389       snprintf(tmpstring, sizeof(tmpstring), "%s%s%s", absolute, absolute_suffix, fname_base);
00390 
00391       /* try creating the directory just in case it doesn't exist */
00392       if (directory) {
00393          char *name = strdup(fname_base);
00394          snprintf(tmp, sizeof(tmp), "mkdir -p \"%s%s%s\"", absolute, absolute_suffix, dirname(name));
00395          free(name);
00396          ast_safe_system(tmp);
00397       }
00398 
00399       /*!\note We cannot just compare filenames, due to symlinks, relative
00400        * paths, and other possible filesystem issues.  We could use
00401        * realpath(3), but its use is discouraged.  However, if we try to
00402        * create the same file from two different paths, the second will
00403        * fail, and so we have our notification that the filenames point to
00404        * the same path.
00405        *
00406        * Remember, also, that we're using the basename of the file (i.e.
00407        * the file without the format suffix), so it does not already exist
00408        * and we aren't interfering with the recording itself.
00409        */
00410       if (option_debug > 2) {
00411          ast_log(LOG_DEBUG, "comparing tmpstring %s to filename_base %s\n", tmpstring, chan->monitor->filename_base);
00412       }
00413       if ((fd[0] = open(tmpstring, O_CREAT | O_WRONLY, 0644)) < 0 ||
00414          (fd[1] = open(chan->monitor->filename_base, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) {
00415          if (fd[0] < 0) {
00416             ast_log(LOG_ERROR, "Unable to compare filenames: %s\n", strerror(errno));
00417          } else {
00418             if (option_debug > 2) {
00419                ast_log(LOG_DEBUG, "No need to rename monitor filename to itself\n");
00420             }
00421          }
00422          doexit = 1;
00423       }
00424 
00425       /* Cleanup temporary files */
00426       for (i = 0; i < 2; i++) {
00427          if (fd[i] >= 0) {
00428             while (close(fd[i]) < 0 && errno == EINTR);
00429          }
00430       }
00431       unlink(tmpstring);
00432       /* if previous monitor file existed in a subdirectory, the directory will not be removed */
00433       unlink(chan->monitor->filename_base);
00434 
00435       if (doexit) {
00436          UNLOCK_IF_NEEDED(chan, need_lock);
00437          return 0;
00438       }
00439 
00440       ast_copy_string(chan->monitor->filename_base, tmpstring, sizeof(chan->monitor->filename_base));
00441       chan->monitor->filename_changed = 1;
00442    } else {
00443       ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", chan->name, fname_base);
00444    }
00445 
00446    UNLOCK_IF_NEEDED(chan, need_lock);
00447 
00448    return 0;
00449 }

int ast_monitor_pause ( struct ast_channel chan  ) 

Definition at line 349 of file res_monitor.c.

References AST_MONITOR_PAUSED, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and pause_monitor_exec().

00350 {
00351    return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
00352 }

void ast_monitor_setjoinfiles ( struct ast_channel chan,
int  turnon 
)

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

00653 {
00654    if (chan->monitor)
00655       chan->monitor->joinfiles = turnon;
00656 }

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

Definition at line 132 of file res_monitor.c.

References ast_calloc, ast_closestream(), ast_config_AST_MONITOR_DIR, ast_filedelete(), ast_fileexists(), ast_log(), AST_MONITOR_RUNNING, ast_monitor_set_state(), ast_monitor_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_safe_system(), ast_strdupa, ast_strlen_zero(), ast_writefile(), errno, FILENAME_MAX, free, LOCK_IF_NEEDED, LOG_DEBUG, LOG_WARNING, ast_channel::monitor, monitor, monitorlock, name, ast_channel::name, pbx_builtin_setvar_helper(), strdup, and UNLOCK_IF_NEEDED.

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

00134 {
00135    int res = 0;
00136    char tmp[256];
00137 
00138    LOCK_IF_NEEDED(chan, need_lock);
00139 
00140    if (!(chan->monitor)) {
00141       struct ast_channel_monitor *monitor;
00142       char *channel_name, *p;
00143 
00144       /* Create monitoring directory if needed */
00145       if (mkdir(ast_config_AST_MONITOR_DIR, 0770) < 0) {
00146          if (errno != EEXIST) {
00147             ast_log(LOG_WARNING, "Unable to create audio monitor directory: %s\n",
00148                strerror(errno));
00149          }
00150       }
00151 
00152       if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
00153          UNLOCK_IF_NEEDED(chan, need_lock);
00154          return -1;
00155       }
00156 
00157       /* Determine file names */
00158       if (!ast_strlen_zero(fname_base)) {
00159          int directory = strchr(fname_base, '/') ? 1 : 0;
00160          const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
00161          const char *absolute_suffix = *fname_base == '/' ? "" : "/";
00162          /* try creating the directory just in case it doesn't exist */
00163          if (directory) {
00164             char *name = strdup(fname_base);
00165             snprintf(tmp, sizeof(tmp), "mkdir -p \"%s%s%s\"",
00166                      absolute, absolute_suffix, dirname(name));
00167             free(name);
00168             ast_safe_system(tmp);
00169          }
00170          snprintf(monitor->read_filename, FILENAME_MAX, "%s%s%s-in",
00171                   absolute, absolute_suffix, fname_base);
00172          snprintf(monitor->write_filename, FILENAME_MAX, "%s%s%s-out",
00173                   absolute, absolute_suffix, fname_base);
00174          snprintf(monitor->filename_base, FILENAME_MAX, "%s%s%s",
00175                   absolute, absolute_suffix, fname_base);
00176       } else {
00177          ast_mutex_lock(&monitorlock);
00178          snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld",
00179                   ast_config_AST_MONITOR_DIR, seq);
00180          snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld",
00181                   ast_config_AST_MONITOR_DIR, seq);
00182          seq++;
00183          ast_mutex_unlock(&monitorlock);
00184 
00185          channel_name = ast_strdupa(chan->name);
00186          while ((p = strchr(channel_name, '/'))) {
00187             *p = '-';
00188          }
00189          snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
00190                 ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
00191          monitor->filename_changed = 1;
00192       }
00193 
00194       monitor->stop = ast_monitor_stop;
00195 
00196       /* Determine file format */
00197       if (!ast_strlen_zero(format_spec)) {
00198          monitor->format = strdup(format_spec);
00199       } else {
00200          monitor->format = strdup("wav");
00201       }
00202       
00203       /* open files */
00204       if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0) {
00205          ast_filedelete(monitor->read_filename, NULL);
00206       }
00207       if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
00208                   monitor->format, NULL,
00209                   O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
00210          ast_log(LOG_WARNING, "Could not create file %s\n",
00211                   monitor->read_filename);
00212          free(monitor);
00213          UNLOCK_IF_NEEDED(chan, need_lock);
00214          return -1;
00215       }
00216       if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
00217          ast_filedelete(monitor->write_filename, NULL);
00218       }
00219       if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
00220                   monitor->format, NULL,
00221                   O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
00222          ast_log(LOG_WARNING, "Could not create file %s\n",
00223                   monitor->write_filename);
00224          ast_closestream(monitor->read_stream);
00225          free(monitor);
00226          UNLOCK_IF_NEEDED(chan, need_lock);
00227          return -1;
00228       }
00229       chan->monitor = monitor;
00230       ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00231       /* so we know this call has been monitored in case we need to bill for it or something */
00232       pbx_builtin_setvar_helper(chan, "__MONITORED","true");
00233    } else {
00234       ast_log(LOG_DEBUG,"Cannot start monitoring %s, already monitored\n",
00235                chan->name);
00236       res = -1;
00237    }
00238 
00239    UNLOCK_IF_NEEDED(chan, need_lock);
00240 
00241    return res;
00242 }

int ast_monitor_stop ( struct ast_channel chan,
int  need_lock 
)

Definition at line 262 of file res_monitor.c.

References ast_closestream(), ast_copy_string(), ast_filedelete(), ast_fileexists(), ast_filerename(), ast_log(), ast_safe_system(), ast_strlen_zero(), ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, FILENAME_MAX, ast_channel_monitor::format, format, free, get_soxmix_format(), ast_channel_monitor::joinfiles, LOCK_IF_NEEDED, LOG_DEBUG, LOG_WARNING, ast_channel::monitor, pbx_builtin_getvar_helper(), pbx_builtin_setvar_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(), builtin_automonitor(), stop_monitor_action(), and stop_monitor_exec().

00263 {
00264    int delfiles = 0;
00265 
00266    LOCK_IF_NEEDED(chan, need_lock);
00267 
00268    if (chan->monitor) {
00269       char filename[ FILENAME_MAX ];
00270 
00271       if (chan->monitor->read_stream) {
00272          ast_closestream(chan->monitor->read_stream);
00273       }
00274       if (chan->monitor->write_stream) {
00275          ast_closestream(chan->monitor->write_stream);
00276       }
00277 
00278       if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) {
00279          if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) {
00280             snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base);
00281             if (ast_fileexists(filename, NULL, NULL) > 0) {
00282                ast_filedelete(filename, NULL);
00283             }
00284             ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format);
00285          } else {
00286             ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename);
00287          }
00288 
00289          if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) {
00290             snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base);
00291             if (ast_fileexists(filename, NULL, NULL) > 0) {
00292                ast_filedelete(filename, NULL);
00293             }
00294             ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format);
00295          } else {
00296             ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename);
00297          }
00298       }
00299 
00300       if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) {
00301          char tmp[1024];
00302          char tmp2[1024];
00303          const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
00304          char *fname_base = chan->monitor->filename_base;
00305          const char *execute, *execute_args;
00306          /* at this point, fname_base really is the full path */
00307 
00308          /* Set the execute application */
00309          execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
00310          if (ast_strlen_zero(execute)) {
00311 #ifdef HAVE_SOXMIX
00312             execute = "nice -n 19 soxmix";
00313 #else
00314             execute = "nice -n 19 sox -m";
00315 #endif
00316             format = get_soxmix_format(format);
00317             delfiles = 1;
00318          } 
00319          execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
00320          if (ast_strlen_zero(execute_args)) {
00321             execute_args = "";
00322          }
00323          
00324          snprintf(tmp, sizeof(tmp), "%s \"%s-in.%s\" \"%s-out.%s\" \"%s.%s\" %s &",
00325             execute, fname_base, format, fname_base, format, fname_base, format,execute_args);
00326          if (delfiles) {
00327             snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s-\"* ) &",tmp, fname_base); /* remove legs when done mixing */
00328             ast_copy_string(tmp, tmp2, sizeof(tmp));
00329          }
00330          ast_log(LOG_DEBUG,"monitor executing %s\n",tmp);
00331          if (ast_safe_system(tmp) == -1)
00332             ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
00333       }
00334       
00335       free(chan->monitor->format);
00336       free(chan->monitor);
00337       chan->monitor = NULL;
00338       pbx_builtin_setvar_helper(chan, "MONITORED", NULL);
00339    }
00340    pbx_builtin_setvar_helper(chan, "AUTO_MONITOR", NULL);
00341 
00342    UNLOCK_IF_NEEDED(chan, need_lock);
00343 
00344    return 0;
00345 }

int ast_monitor_unpause ( struct ast_channel chan  ) 

Definition at line 355 of file res_monitor.c.

References AST_MONITOR_RUNNING, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and unpause_monitor_exec().

00356 {
00357    return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00358 }


Generated on Sat Aug 6 00:39:59 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7