Thu Apr 28 2011 17:16:18

Asterisk developer's documentation


res_monitor.c File Reference

PBX channel monitoring. More...

#include "asterisk.h"
#include <sys/stat.h>
#include <libgen.h>
#include "asterisk/paths.h"
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/manager.h"
#include "asterisk/cli.h"
#include "asterisk/monitor.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/config.h"
#include "asterisk/options.h"
Include dependency graph for res_monitor.c:

Go to the source code of this file.

Defines

#define AST_API_MODULE
#define LOCK_IF_NEEDED(lock, needed)
#define UNLOCK_IF_NEEDED(lock, needed)

Enumerations

enum  MONITOR_PAUSING_ACTION { MONITOR_ACTION_PAUSE, MONITOR_ACTION_UNPAUSE }

Functions

static void __reg_module (void)
static void __unreg_module (void)
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.
static int ast_monitor_set_state (struct ast_channel *chan, int state)
 Change state of monitored 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.
static int change_monitor_action (struct mansession *s, const struct message *m)
 Change filename of a monitored channel by manager connection.
static int change_monitor_exec (struct ast_channel *chan, void *data)
 Wrapper function.
static int do_pause_or_unpause (struct mansession *s, const struct message *m, int action)
static const char * get_soxmix_format (const char *format)
 Get audio format.
static int load_module (void)
static int pause_monitor_action (struct mansession *s, const struct message *m)
static int pause_monitor_exec (struct ast_channel *chan, void *data)
 Wrapper for ast_monitor_pause.
static int start_monitor_action (struct mansession *s, const struct message *m)
 Start monitoring a channel by manager connection.
static int start_monitor_exec (struct ast_channel *chan, void *data)
 Start monitor.
static int stop_monitor_action (struct mansession *s, const struct message *m)
 Stop monitoring a channel by manager connection.
static int stop_monitor_exec (struct ast_channel *chan, void *data)
 Wrapper function.
static int unload_module (void)
static int unpause_monitor_action (struct mansession *s, const struct message *m)
static int unpause_monitor_exec (struct ast_channel *chan, void *data)
 Wrapper for ast_monitor_unpause.

Variables

static struct ast_module_info
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .description = "Call Monitoring Resource" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, }
static struct ast_module_infoast_module_info = &__mod_info
static char change_monitor_action_help [] = " monitor spool directory.\n"
static char * changemonitor_descrip = "The argument is the new filename base to use for monitoring this channel.\n"
static char * changemonitor_synopsis = "Change monitoring filename of a channel"
static char * monitor_descrip = "monitored, otherwise 0.\n"
static char * monitor_synopsis = "Monitor a channel"
static ast_mutex_t monitorlock = AST_MUTEX_INIT_VALUE
static char pause_monitor_action_help [] = " Channel - Required. Used to specify the channel to record.\n"
static char * pausemonitor_descrip = "Pauses monitoring of a channel until it is re-enabled by a call to UnpauseMonitor.\n"
static char * pausemonitor_synopsis = "Pause monitoring of a channel"
static unsigned long seq = 0
static char start_monitor_action_help [] = " recording is finished.\n"
static char stop_monitor_action_help [] = " of the channel monitored.\n"
static char * stopmonitor_descrip = "Stops monitoring a channel. Has no effect if the channel is not monitored\n"
static char * stopmonitor_synopsis = "Stop monitoring a channel"
static char unpause_monitor_action_help [] = " Channel - Required. Used to specify the channel to record.\n"
static char * unpausemonitor_descrip = "previously been paused with PauseMonitor.\n"
static char * unpausemonitor_synopsis = "Unpause monitoring of a channel"

Detailed Description

PBX channel monitoring.

Author:
Mark Spencer <markster@digium.com>

Definition in file res_monitor.c.


Define Documentation

#define AST_API_MODULE

Definition at line 41 of file res_monitor.c.

#define LOCK_IF_NEEDED (   lock,
  needed 
)
Value:
do { \
   if (needed) \
      ast_channel_lock(lock); \
   } while(0)

Definition at line 50 of file res_monitor.c.

Referenced by ast_monitor_change_fname(), ast_monitor_set_state(), ast_monitor_start(), and ast_monitor_stop().

#define UNLOCK_IF_NEEDED (   lock,
  needed 
)
Value:
do { \
   if (needed) \
      ast_channel_unlock(lock); \
   } while (0)

Definition at line 55 of file res_monitor.c.

Referenced by ast_monitor_change_fname(), ast_monitor_set_state(), ast_monitor_start(), and ast_monitor_stop().


Enumeration Type Documentation

Enumerator:
MONITOR_ACTION_PAUSE 
MONITOR_ACTION_UNPAUSE 

Definition at line 726 of file res_monitor.c.


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 817 of file res_monitor.c.

static void __unreg_module ( void  ) [static]

Definition at line 817 of file res_monitor.c.

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

Change monitored filename of channel.

Parameters:
chan
fname_basenew filename
need_lock
Return values:
0on success.
-1on 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 417 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, name, ast_channel::name, and UNLOCK_IF_NEEDED.

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

{
   if (ast_strlen_zero(fname_base)) {
      ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", chan->name);
      return -1;
   }

   LOCK_IF_NEEDED(chan, need_lock);

   if (chan->monitor) {
      int directory = strchr(fname_base, '/') ? 1 : 0;
      const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
      const char *absolute_suffix = *fname_base == '/' ? "" : "/";
      char tmpstring[sizeof(chan->monitor->filename_base)] = "";
      int i, fd[2] = { -1, -1 }, doexit = 0;

      /* before continuing, see if we're trying to rename the file to itself... */
      snprintf(tmpstring, sizeof(tmpstring), "%s%s%s", absolute, absolute_suffix, fname_base);

      /* try creating the directory just in case it doesn't exist */
      if (directory) {
         char *name = ast_strdupa(tmpstring);
         ast_mkdir(dirname(name), 0777);
      }

      /*!\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.
       */
      ast_debug(2, "comparing tmpstring %s to filename_base %s\n", tmpstring, chan->monitor->filename_base);
      
      if ((fd[0] = open(tmpstring, O_CREAT | O_WRONLY, 0644)) < 0 ||
         (fd[1] = open(chan->monitor->filename_base, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) {
         if (fd[0] < 0) {
            ast_log(LOG_ERROR, "Unable to compare filenames: %s\n", strerror(errno));
         } else {
            ast_debug(2, "No need to rename monitor filename to itself\n");
         }
         doexit = 1;
      }

      /* Cleanup temporary files */
      for (i = 0; i < 2; i++) {
         if (fd[i] >= 0) {
            while (close(fd[i]) < 0 && errno == EINTR);
         }
      }
      unlink(tmpstring);
      /* if previous monitor file existed in a subdirectory, the directory will not be removed */
      unlink(chan->monitor->filename_base);

      if (doexit) {
         UNLOCK_IF_NEEDED(chan, need_lock);
         return 0;
      }

      ast_copy_string(chan->monitor->filename_base, tmpstring, sizeof(chan->monitor->filename_base));
      chan->monitor->filename_changed = 1;
   } else {
      ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", chan->name, fname_base);
   }

   UNLOCK_IF_NEEDED(chan, need_lock);

   return 0;
}
int ast_monitor_pause ( struct ast_channel chan)

Pause monitoring of channel.

Definition at line 386 of file res_monitor.c.

References AST_MONITOR_PAUSED, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and pause_monitor_exec().

static int ast_monitor_set_state ( struct ast_channel chan,
int  state 
) [static]

Change state of monitored channel.

Parameters:
chan
statemonitor state
Return values:
0on success.
-1on failure.

Definition at line 125 of file res_monitor.c.

References LOCK_IF_NEEDED, ast_channel::monitor, ast_channel_monitor::state, and UNLOCK_IF_NEEDED.

Referenced by ast_monitor_pause(), ast_monitor_start(), and ast_monitor_unpause().

{
   LOCK_IF_NEEDED(chan, 1);
   if (!chan->monitor) {
      UNLOCK_IF_NEEDED(chan, 1);
      return -1;
   }
   chan->monitor->state = state;
   UNLOCK_IF_NEEDED(chan, 1);
   return 0;
}
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.

Parameters:
chanast_channel struct to record
format_specfile format to use for recording
fname_basefilename base to record to
need_lockwhether to lock the channel mutex
stream_actionwhether 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:
0on success
-1on failure

Definition at line 148 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_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, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, FILENAME_MAX, ast_channel_monitor::format, LOCK_IF_NEEDED, LOG_WARNING, manager_event, monitor, ast_channel::monitor, monitorlock, ast_channel::name, name, pbx_builtin_setvar_helper(), ast_channel_monitor::read_filename, ast_channel_monitor::read_stream, ast_channel_monitor::stop, ast_channel::uniqueid, UNLOCK_IF_NEEDED, ast_channel_monitor::write_filename, ast_channel_monitor::write_stream, X_REC_IN, and X_REC_OUT.

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

{
   int res = 0;

   LOCK_IF_NEEDED(chan, need_lock);

   if (!(chan->monitor)) {
      struct ast_channel_monitor *monitor;
      char *channel_name, *p;

      /* Create monitoring directory if needed */
      ast_mkdir(ast_config_AST_MONITOR_DIR, 0777);

      if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
         UNLOCK_IF_NEEDED(chan, need_lock);
         return -1;
      }

      /* Determine file names */
      if (!ast_strlen_zero(fname_base)) {
         int directory = strchr(fname_base, '/') ? 1 : 0;
         const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
         const char *absolute_suffix = *fname_base == '/' ? "" : "/";

         snprintf(monitor->read_filename, FILENAME_MAX, "%s%s%s-in",
                  absolute, absolute_suffix, fname_base);
         snprintf(monitor->write_filename, FILENAME_MAX, "%s%s%s-out",
                  absolute, absolute_suffix, fname_base);
         snprintf(monitor->filename_base, FILENAME_MAX, "%s%s%s",
                  absolute, absolute_suffix, fname_base);

         /* try creating the directory just in case it doesn't exist */
         if (directory) {
            char *name = ast_strdupa(monitor->filename_base);
            ast_mkdir(dirname(name), 0777);
         }
      } else {
         ast_mutex_lock(&monitorlock);
         snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld",
                  ast_config_AST_MONITOR_DIR, seq);
         snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld",
                  ast_config_AST_MONITOR_DIR, seq);
         seq++;
         ast_mutex_unlock(&monitorlock);

         channel_name = ast_strdupa(chan->name);
         while ((p = strchr(channel_name, '/'))) {
            *p = '-';
         }
         snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
                ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
         monitor->filename_changed = 1;
      }

      monitor->stop = ast_monitor_stop;

      /* Determine file format */
      if (!ast_strlen_zero(format_spec)) {
         monitor->format = ast_strdup(format_spec);
      } else {
         monitor->format = ast_strdup("wav");
      }
      
      /* open files */
      if (stream_action & X_REC_IN) {
         if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0)
            ast_filedelete(monitor->read_filename, NULL);
         if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
                     monitor->format, NULL,
                     O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
            ast_log(LOG_WARNING, "Could not create file %s\n",
                     monitor->read_filename);
            ast_free(monitor);
            UNLOCK_IF_NEEDED(chan, need_lock);
            return -1;
         }
      } else
         monitor->read_stream = NULL;

      if (stream_action & X_REC_OUT) {
         if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
            ast_filedelete(monitor->write_filename, NULL);
         }
         if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
                     monitor->format, NULL,
                     O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
            ast_log(LOG_WARNING, "Could not create file %s\n",
                     monitor->write_filename);
            ast_closestream(monitor->read_stream);
            ast_free(monitor);
            UNLOCK_IF_NEEDED(chan, need_lock);
            return -1;
         }
      } else
         monitor->write_stream = NULL;

      chan->monitor = monitor;
      ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
      /* so we know this call has been monitored in case we need to bill for it or something */
      pbx_builtin_setvar_helper(chan, "__MONITORED","true");

      manager_event(EVENT_FLAG_CALL, "MonitorStart",
                         "Channel: %s\r\n"
                          "Uniqueid: %s\r\n",                        
                           chan->name,
                         chan->uniqueid                        
                          );
   } else {
      ast_debug(1,"Cannot start monitoring %s, already monitored\n", chan->name);
      res = -1;
   }

   UNLOCK_IF_NEEDED(chan, need_lock);

   return res;
}
int ast_monitor_stop ( struct ast_channel chan,
int  need_lock 
)

Stop monitoring channel.

Parameters:
chan
need_lockStop the recording, close any open streams, mix in/out channels if required
Returns:
Always 0

Definition at line 292 of file res_monitor.c.

References ast_closestream(), ast_copy_string(), ast_debug, ast_filedelete(), ast_fileexists(), ast_filerename(), ast_free, ast_log(), ast_safe_system(), ast_strlen_zero(), EVENT_FLAG_CALL, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, FILENAME_MAX, format, ast_channel_monitor::format, get_soxmix_format(), ast_channel_monitor::joinfiles, LOCK_IF_NEEDED, LOG_WARNING, manager_event, 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().

{
   int delfiles = 0;

   LOCK_IF_NEEDED(chan, need_lock);

   if (chan->monitor) {
      char filename[ FILENAME_MAX ];

      if (chan->monitor->read_stream) {
         ast_closestream(chan->monitor->read_stream);
      }
      if (chan->monitor->write_stream) {
         ast_closestream(chan->monitor->write_stream);
      }

      if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) {
         if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) {
            snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base);
            if (ast_fileexists(filename, NULL, NULL) > 0) {
               ast_filedelete(filename, NULL);
            }
            ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format);
         } else {
            ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename);
         }

         if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) {
            snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base);
            if (ast_fileexists(filename, NULL, NULL) > 0) {
               ast_filedelete(filename, NULL);
            }
            ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format);
         } else {
            ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename);
         }
      }

      if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) {
         char tmp[1024];
         char tmp2[1024];
         const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
         char *fname_base = chan->monitor->filename_base;
         const char *execute, *execute_args;
         /* at this point, fname_base really is the full path */

         /* Set the execute application */
         execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
         if (ast_strlen_zero(execute)) {
#ifdef HAVE_SOXMIX
            execute = "nice -n 19 soxmix";
#else
            execute = "nice -n 19 sox -m";
#endif
            format = get_soxmix_format(format);
            delfiles = 1;
         } 
         execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
         if (ast_strlen_zero(execute_args)) {
            execute_args = "";
         }
         
         snprintf(tmp, sizeof(tmp), "%s \"%s-in.%s\" \"%s-out.%s\" \"%s.%s\" %s &",
            execute, fname_base, format, fname_base, format, fname_base, format,execute_args);
         if (delfiles) {
            snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s-\"* ) &",tmp, fname_base); /* remove legs when done mixing */
            ast_copy_string(tmp, tmp2, sizeof(tmp));
         }
         ast_debug(1,"monitor executing %s\n",tmp);
         if (ast_safe_system(tmp) == -1)
            ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
      }
      
      ast_free(chan->monitor->format);
      ast_free(chan->monitor);
      chan->monitor = NULL;

      manager_event(EVENT_FLAG_CALL, "MonitorStop",
                         "Channel: %s\r\n"
                           "Uniqueid: %s\r\n",
                           chan->name,
                           chan->uniqueid
                           );
      pbx_builtin_setvar_helper(chan, "MONITORED", NULL);
   }
   pbx_builtin_setvar_helper(chan, "AUTO_MONITOR", NULL);

   UNLOCK_IF_NEEDED(chan, need_lock);

   return 0;
}
int ast_monitor_unpause ( struct ast_channel chan)

Unpause monitoring of channel.

Definition at line 392 of file res_monitor.c.

References AST_MONITOR_RUNNING, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and unpause_monitor_exec().

static int change_monitor_action ( struct mansession s,
const struct message m 
) [static]

Change filename of a monitored channel by manager connection.

Definition at line 692 of file res_monitor.c.

References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_monitor_change_fname(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and name.

Referenced by load_module().

{
   struct ast_channel *c = NULL;
   const char *name = astman_get_header(m, "Channel");
   const char *fname = astman_get_header(m, "File");
   if (ast_strlen_zero(name)) {
      astman_send_error(s, m, "No channel specified");
      return 0;
   }
   if (ast_strlen_zero(fname)) {
      astman_send_error(s, m, "No filename specified");
      return 0;
   }
   c = ast_get_channel_by_name_locked(name);
   if (!c) {
      astman_send_error(s, m, "No such channel");
      return 0;
   }
   if (ast_monitor_change_fname(c, fname, 1)) {
      astman_send_error(s, m, "Could not change monitored filename of channel");
      ast_channel_unlock(c);
      return 0;
   }
   ast_channel_unlock(c);
   astman_send_ack(s, m, "Changed monitor filename");
   return 0;
}
static int change_monitor_exec ( struct ast_channel chan,
void *  data 
) [static]

Wrapper function.

See also:
ast_monitor_change_fname

Definition at line 589 of file res_monitor.c.

References ast_monitor_change_fname().

Referenced by load_module().

{
   return ast_monitor_change_fname(chan, (const char*)data, 1);
}
static int do_pause_or_unpause ( struct mansession s,
const struct message m,
int  action 
) [static]

Definition at line 732 of file res_monitor.c.

References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_monitor_pause(), ast_monitor_unpause(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), MONITOR_ACTION_PAUSE, and name.

Referenced by pause_monitor_action(), and unpause_monitor_action().

{
   struct ast_channel *c = NULL;
   const char *name = astman_get_header(m, "Channel");
   
   if (ast_strlen_zero(name)) {
      astman_send_error(s, m, "No channel specified");
      return -1;
   }
   
   c = ast_get_channel_by_name_locked(name);
   if (!c) {
      astman_send_error(s, m, "No such channel");
      return -1;
   }

   if (action == MONITOR_ACTION_PAUSE)
      ast_monitor_pause(c);
   else
      ast_monitor_unpause(c);
   
   ast_channel_unlock(c);
   astman_send_ack(s, m, (action == MONITOR_ACTION_PAUSE ? "Paused monitoring of the channel" : "Unpaused monitoring of the channel"));
   return 0;   
}
static const char* get_soxmix_format ( const char *  format) [static]

Get audio format.

Parameters:
formatrecording format. The file format extensions that Asterisk uses are not all the same as that which soxmix expects. This function ensures that the format used as the extension on the filename is something soxmix will understand.

Definition at line 273 of file res_monitor.c.

References format.

Referenced by ast_monitor_stop().

{
   const char *res = format;

   if (!strcasecmp(format,"ulaw"))
      res = "ul";
   if (!strcasecmp(format,"alaw"))
      res = "al";
   
   return res;
}
static int load_module ( void  ) [static]

Definition at line 781 of file res_monitor.c.

References ast_manager_register2(), AST_MODULE_LOAD_SUCCESS, ast_register_application, change_monitor_action(), change_monitor_exec(), EVENT_FLAG_CALL, pause_monitor_action(), pause_monitor_exec(), start_monitor_action(), start_monitor_exec(), stop_monitor_action(), stop_monitor_exec(), unpause_monitor_action(), and unpause_monitor_exec().

static int pause_monitor_action ( struct mansession s,
const struct message m 
) [static]

Definition at line 764 of file res_monitor.c.

References do_pause_or_unpause(), and MONITOR_ACTION_PAUSE.

Referenced by load_module().

static int pause_monitor_exec ( struct ast_channel chan,
void *  data 
) [static]

Wrapper for ast_monitor_pause.

Definition at line 398 of file res_monitor.c.

References ast_monitor_pause().

Referenced by load_module().

{
   return ast_monitor_pause(chan);
}
static int start_monitor_action ( struct mansession s,
const struct message m 
) [static]

Start monitoring a channel by manager connection.

Definition at line 609 of file res_monitor.c.

References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_monitor_change_fname(), ast_monitor_setjoinfiles(), ast_monitor_start(), ast_strdupa, ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), format, ast_channel::name, name, X_REC_IN, and X_REC_OUT.

Referenced by load_module().

{
   struct ast_channel *c = NULL;
   const char *name = astman_get_header(m, "Channel");
   const char *fname = astman_get_header(m, "File");
   const char *format = astman_get_header(m, "Format");
   const char *mix = astman_get_header(m, "Mix");
   char *d;

   if (ast_strlen_zero(name)) {
      astman_send_error(s, m, "No channel specified");
      return 0;
   }
   c = ast_get_channel_by_name_locked(name);
   if (!c) {
      astman_send_error(s, m, "No such channel");
      return 0;
   }

   if (ast_strlen_zero(fname)) {
      /* No filename base specified, default to channel name as per CLI */    
      fname = ast_strdupa(c->name);
      /* Channels have the format technology/channel_name - have to replace that /  */
      if ((d = strchr(fname, '/'))) 
         *d = '-';
   }

   if (ast_monitor_start(c, format, fname, 1, X_REC_IN | X_REC_OUT)) {
      if (ast_monitor_change_fname(c, fname, 1)) {
         astman_send_error(s, m, "Could not start monitoring channel");
         ast_channel_unlock(c);
         return 0;
      }
   }

   if (ast_true(mix)) {
      ast_monitor_setjoinfiles(c, 1);
   }

   ast_channel_unlock(c);
   astman_send_ack(s, m, "Started monitoring channel");
   return 0;
}
static int start_monitor_exec ( struct ast_channel chan,
void *  data 
) [static]

Start monitor.

Parameters:
chan
dataarguments passed fname|options
Return values:
0on success.
-1on failure.

Definition at line 499 of file res_monitor.c.

References AST_APP_ARG, ast_cdr_alloc(), ast_cdr_setuserfield(), AST_DECLARE_APP_ARGS, ast_log(), ast_monitor_change_fname(), ast_monitor_setjoinfiles(), ast_monitor_start(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_channel::cdr, format, ast_channel_monitor::joinfiles, LOG_ERROR, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), urlprefix, X_JOIN, X_REC_IN, and X_REC_OUT.

Referenced by load_module().

{
   char *arg = NULL;
   char *options = NULL;
   char *delay = NULL;
   char *urlprefix = NULL;
   char tmp[256];
   int stream_action = X_REC_IN | X_REC_OUT;
   int joinfiles = 0;
   int waitforbridge = 0;
   int res = 0;
   char *parse;
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(format);
      AST_APP_ARG(fname_base);
      AST_APP_ARG(options);
   );
   
   /* Parse arguments. */
   if (ast_strlen_zero((char*)data)) {
      ast_log(LOG_ERROR, "Monitor requires an argument\n");
      return 0;
   }

   parse = ast_strdupa((char*)data);
   AST_STANDARD_APP_ARGS(args, parse);

   if (!ast_strlen_zero(args.options)) {
      if (strchr(args.options, 'm'))
         stream_action |= X_JOIN;
      if (strchr(args.options, 'b'))
         waitforbridge = 1;
      if (strchr(args.options, 'i'))
         stream_action &= ~X_REC_IN;
      if (strchr(args.options, 'o'))
         stream_action &= ~X_REC_OUT;
   }

   arg = strchr(args.format, ':');
   if (arg) {
      *arg++ = 0;
      urlprefix = arg;
   }

   if (urlprefix) {
      snprintf(tmp, sizeof(tmp), "%s/%s.%s", urlprefix, args.fname_base,
         ((strcmp(args.format, "gsm")) ? "wav" : "gsm"));
      if (!chan->cdr && !(chan->cdr = ast_cdr_alloc()))
         return -1;
      ast_cdr_setuserfield(chan, tmp);
   }
   if (waitforbridge) {
      /* We must remove the "b" option if listed.  In principle none of
         the following could give NULL results, but we check just to
         be pedantic. Reconstructing with checks for 'm' option does not
         work if we end up adding more options than 'm' in the future. */
      delay = ast_strdupa(data);
      options = strrchr(delay, ',');
      if (options) {
         arg = strchr(options, 'b');
         if (arg) {
            *arg = 'X';
            pbx_builtin_setvar_helper(chan,"AUTO_MONITOR", delay);
         }
      }
      return 0;
   }

   res = ast_monitor_start(chan, args.format, args.fname_base, 1, stream_action);
   if (res < 0)
      res = ast_monitor_change_fname(chan, args.fname_base, 1);

   if (stream_action & X_JOIN) {
      if ((stream_action & X_REC_IN) && (stream_action & X_REC_OUT))
         joinfiles = 1;
      else
         ast_log(LOG_WARNING, "Won't mix streams unless both input and output streams are recorded\n");
   }
   ast_monitor_setjoinfiles(chan, joinfiles);

   return res;
}
static int stop_monitor_action ( struct mansession s,
const struct message m 
) [static]

Stop monitoring a channel by manager connection.

Definition at line 659 of file res_monitor.c.

References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_monitor_stop(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and name.

Referenced by load_module().

{
   struct ast_channel *c = NULL;
   const char *name = astman_get_header(m, "Channel");
   int res;
   if (ast_strlen_zero(name)) {
      astman_send_error(s, m, "No channel specified");
      return 0;
   }
   c = ast_get_channel_by_name_locked(name);
   if (!c) {
      astman_send_error(s, m, "No such channel");
      return 0;
   }
   res = ast_monitor_stop(c, 1);
   ast_channel_unlock(c);
   if (res) {
      astman_send_error(s, m, "Could not stop monitoring channel");
      return 0;
   }
   astman_send_ack(s, m, "Stopped monitoring channel");
   return 0;
}
static int stop_monitor_exec ( struct ast_channel chan,
void *  data 
) [static]

Wrapper function.

See also:
ast_monitor_stop

Definition at line 583 of file res_monitor.c.

References ast_monitor_stop().

Referenced by load_module().

{
   return ast_monitor_stop(chan, 1);
}
static int unload_module ( void  ) [static]

Definition at line 797 of file res_monitor.c.

References ast_manager_unregister(), and ast_unregister_application().

{
   ast_unregister_application("Monitor");
   ast_unregister_application("StopMonitor");
   ast_unregister_application("ChangeMonitor");
   ast_unregister_application("PauseMonitor");
   ast_unregister_application("UnpauseMonitor");
   ast_manager_unregister("Monitor");
   ast_manager_unregister("StopMonitor");
   ast_manager_unregister("ChangeMonitor");
   ast_manager_unregister("PauseMonitor");
   ast_manager_unregister("UnpauseMonitor");

   return 0;
}
static int unpause_monitor_action ( struct mansession s,
const struct message m 
) [static]

Definition at line 775 of file res_monitor.c.

References do_pause_or_unpause(), and MONITOR_ACTION_UNPAUSE.

Referenced by load_module().

static int unpause_monitor_exec ( struct ast_channel chan,
void *  data 
) [static]

Wrapper for ast_monitor_unpause.

Definition at line 404 of file res_monitor.c.

References ast_monitor_unpause().

Referenced by load_module().

{
   return ast_monitor_unpause(chan);
}

Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .description = "Call Monitoring Resource" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static]

Definition at line 817 of file res_monitor.c.

Definition at line 817 of file res_monitor.c.

char change_monitor_action_help[] = " monitor spool directory.\n" [static]

Definition at line 683 of file res_monitor.c.

char* changemonitor_descrip = "The argument is the new filename base to use for monitoring this channel.\n" [static]

Definition at line 103 of file res_monitor.c.

char* changemonitor_synopsis = "Change monitoring filename of a channel" [static]

Definition at line 101 of file res_monitor.c.

char* monitor_descrip = "monitored, otherwise 0.\n" [static]

Definition at line 64 of file res_monitor.c.

char* monitor_synopsis = "Monitor a channel" [static]

Definition at line 62 of file res_monitor.c.

ast_mutex_t monitorlock = AST_MUTEX_INIT_VALUE [static]

Definition at line 48 of file res_monitor.c.

Referenced by ast_monitor_start().

char pause_monitor_action_help[] = " Channel - Required. Used to specify the channel to record.\n" [static]

Definition at line 758 of file res_monitor.c.

char* pausemonitor_descrip = "Pauses monitoring of a channel until it is re-enabled by a call to UnpauseMonitor.\n" [static]

Definition at line 109 of file res_monitor.c.

char* pausemonitor_synopsis = "Pause monitoring of a channel" [static]

Definition at line 107 of file res_monitor.c.

unsigned long seq = 0 [static]

Definition at line 60 of file res_monitor.c.

char start_monitor_action_help[] = " recording is finished.\n" [static]

Definition at line 594 of file res_monitor.c.

char stop_monitor_action_help[] = " of the channel monitored.\n" [static]

Definition at line 653 of file res_monitor.c.

char* stopmonitor_descrip = "Stops monitoring a channel. Has no effect if the channel is not monitored\n" [static]

Definition at line 98 of file res_monitor.c.

char* stopmonitor_synopsis = "Stop monitoring a channel" [static]

Definition at line 96 of file res_monitor.c.

char unpause_monitor_action_help[] = " Channel - Required. Used to specify the channel to record.\n" [static]

Definition at line 769 of file res_monitor.c.

char* unpausemonitor_descrip = "previously been paused with PauseMonitor.\n" [static]

Definition at line 114 of file res_monitor.c.

char* unpausemonitor_synopsis = "Unpause monitoring of a channel" [static]

Definition at line 112 of file res_monitor.c.