Mon Mar 19 11:30:50 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 558 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().

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

int ast_monitor_pause ( struct ast_channel chan  ) 

Pause monitoring of channel.

Definition at line 527 of file res_monitor.c.

References AST_MONITOR_PAUSED, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and pause_monitor_exec().

00528 {
00529    return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
00530 }

void ast_monitor_setjoinfiles ( struct ast_channel chan,
int  turnon 
)

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

00858 {
00859    if (chan->monitor)
00860       chan->monitor->joinfiles = turnon;
00861 }

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          channel_name = ast_strdupa(chan->name);
00337          while ((p = strchr(channel_name, '/'))) {
00338             *p = '-';
00339          }
00340          snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
00341                 ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
00342          monitor->filename_changed = 1;
00343       }
00344 
00345       monitor->stop = ast_monitor_stop;
00346 
00347       /* Determine file format */
00348       if (!ast_strlen_zero(format_spec)) {
00349          monitor->format = ast_strdup(format_spec);
00350       } else {
00351          monitor->format = ast_strdup("wav");
00352       }
00353       
00354       /* open files */
00355       if (stream_action & X_REC_IN) {
00356          if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0)
00357             ast_filedelete(monitor->read_filename, NULL);
00358          if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
00359                      monitor->format, NULL,
00360                      O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
00361             ast_log(LOG_WARNING, "Could not create file %s\n",
00362                      monitor->read_filename);
00363             ast_free(monitor);
00364             UNLOCK_IF_NEEDED(chan, need_lock);
00365             return -1;
00366          }
00367       } else
00368          monitor->read_stream = NULL;
00369 
00370       if (stream_action & X_REC_OUT) {
00371          if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
00372             ast_filedelete(monitor->write_filename, NULL);
00373          }
00374          if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
00375                      monitor->format, NULL,
00376                      O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
00377             ast_log(LOG_WARNING, "Could not create file %s\n",
00378                      monitor->write_filename);
00379             ast_closestream(monitor->read_stream);
00380             ast_free(monitor);
00381             UNLOCK_IF_NEEDED(chan, need_lock);
00382             return -1;
00383          }
00384       } else
00385          monitor->write_stream = NULL;
00386 
00387       chan->monitor = monitor;
00388       ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00389       /* so we know this call has been monitored in case we need to bill for it or something */
00390       pbx_builtin_setvar_helper(chan, "__MONITORED","true");
00391 
00392       ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStart",
00393                          "Channel: %s\r\n"
00394                        "Uniqueid: %s\r\n",
00395                            chan->name,
00396                          chan->uniqueid);
00397    } else {
00398       ast_debug(1,"Cannot start monitoring %s, already monitored\n", chan->name);
00399       res = -1;
00400    }
00401 
00402    UNLOCK_IF_NEEDED(chan, need_lock);
00403 
00404    return res;
00405 }

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

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

int ast_monitor_unpause ( struct ast_channel chan  ) 

Unpause monitoring of channel.

Definition at line 533 of file res_monitor.c.

References AST_MONITOR_RUNNING, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and unpause_monitor_exec().

00534 {
00535    return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00536 }


Generated on Mon Mar 19 11:30:50 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7