Mon Mar 31 17:30:10 2014

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

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 
)

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 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, 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(), start_monitor_exec(), and try_calling().

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, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, FILENAME_MAX, ast_channel_monitor::format, free, LOCK_IF_NEEDED, LOG_DEBUG, LOG_WARNING, monitor, ast_channel::monitor, monitorlock, name, pbx_builtin_setvar_helper(), ast_channel_monitor::read_filename, ast_channel_monitor::read_stream, ast_channel_monitor::stop, strdup, UNLOCK_IF_NEEDED, ast_channel_monitor::write_filename, and ast_channel_monitor::write_stream.

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

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, format, ast_channel_monitor::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 31 Mar 2014 for Asterisk - the Open Source PBX by  doxygen 1.6.1