Wed Apr 6 11:30:09 2011

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"

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_OPTIONAL_API_NAME() ast_monitor_change_fname (struct ast_channel *chan, const char *fname_base, int need_lock)
 Change monitored filename of channel.
int AST_OPTIONAL_API_NAME() 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_OPTIONAL_API_NAME() ast_monitor_setjoinfiles (struct ast_channel *chan, int turnon)
int AST_OPTIONAL_API_NAME() 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_OPTIONAL_API_NAME() ast_monitor_stop (struct ast_channel *chan, int need_lock)
 Stop monitoring channel.
int AST_OPTIONAL_API_NAME() 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, const char *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, const char *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, const char *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, const char *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, const char *data)
 Wrapper for ast_monitor_unpause.

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Call Monitoring Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
static struct ast_module_infoast_module_info = &__mod_info
static ast_mutex_t monitorlock = { { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } , 1, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP }
static unsigned long seq = 0


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 244 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 249 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

enum MONITOR_PAUSING_ACTION

Enumerator:
MONITOR_ACTION_PAUSE 
MONITOR_ACTION_UNPAUSE 

Definition at line 855 of file res_monitor.c.

00856 {
00857    MONITOR_ACTION_PAUSE,
00858    MONITOR_ACTION_UNPAUSE
00859 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 937 of file res_monitor.c.

static void __unreg_module ( void   )  [static]

Definition at line 937 of file res_monitor.c.

int AST_OPTIONAL_API_NAME() 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, name, ast_channel::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_OPTIONAL_API_NAME() 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 }

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

Change state of monitored channel.

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

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

00264 {
00265    LOCK_IF_NEEDED(chan, 1);
00266    if (!chan->monitor) {
00267       UNLOCK_IF_NEEDED(chan, 1);
00268       return -1;
00269    }
00270    chan->monitor->state = state;
00271    UNLOCK_IF_NEEDED(chan, 1);
00272    return 0;
00273 }

void AST_OPTIONAL_API_NAME() 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_OPTIONAL_API_NAME() 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, monitor, ast_channel::monitor, monitorlock, ast_channel::name, 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_OPTIONAL_API_NAME() 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, format, ast_channel_monitor::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_OPTIONAL_API_NAME() 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 }

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 815 of file res_monitor.c.

References ast_channel_get_by_name(), ast_channel_unref, ast_monitor_change_fname(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and name.

Referenced by load_module().

00816 {
00817    struct ast_channel *c = NULL;
00818    const char *name = astman_get_header(m, "Channel");
00819    const char *fname = astman_get_header(m, "File");
00820 
00821    if (ast_strlen_zero(name)) {
00822       astman_send_error(s, m, "No channel specified");
00823       return 0;
00824    }
00825 
00826    if (ast_strlen_zero(fname)) {
00827       astman_send_error(s, m, "No filename specified");
00828       return 0;
00829    }
00830 
00831    if (!(c = ast_channel_get_by_name(name))) {
00832       astman_send_error(s, m, "No such channel");
00833       return 0;
00834    }
00835 
00836    if (ast_monitor_change_fname(c, fname, 1)) {
00837       c = ast_channel_unref(c);
00838       astman_send_error(s, m, "Could not change monitored filename of channel");
00839       return 0;
00840    }
00841 
00842    c = ast_channel_unref(c);
00843 
00844    astman_send_ack(s, m, "Changed monitor filename");
00845 
00846    return 0;
00847 }

static int change_monitor_exec ( struct ast_channel chan,
const char *  data 
) [static]

Wrapper function.

See also:
ast_monitor_change_fname

Definition at line 726 of file res_monitor.c.

References ast_monitor_change_fname().

Referenced by load_module().

00727 {
00728    return ast_monitor_change_fname(chan, data, 1);
00729 }

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

Definition at line 861 of file res_monitor.c.

References ast_channel_get_by_name(), ast_channel_unref, 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().

00862 {
00863    struct ast_channel *c = NULL;
00864    const char *name = astman_get_header(m, "Channel");
00865 
00866    if (ast_strlen_zero(name)) {
00867       astman_send_error(s, m, "No channel specified");
00868       return -1;
00869    }
00870 
00871    if (!(c = ast_channel_get_by_name(name))) {
00872       astman_send_error(s, m, "No such channel");
00873       return -1;
00874    }
00875 
00876    if (action == MONITOR_ACTION_PAUSE) {
00877       ast_monitor_pause(c);
00878    } else {
00879       ast_monitor_unpause(c);
00880    }
00881 
00882    c = ast_channel_unref(c);
00883 
00884    astman_send_ack(s, m, (action == MONITOR_ACTION_PAUSE ? "Paused monitoring of the channel" : "Unpaused monitoring of the channel"));
00885 
00886    return 0;
00887 }

static const char* get_soxmix_format ( const char *  format  )  [static]

Get audio format.

Parameters:
format recording 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 410 of file res_monitor.c.

Referenced by ast_monitor_stop().

00411 {
00412    const char *res = format;
00413 
00414    if (!strcasecmp(format,"ulaw"))
00415       res = "ul";
00416    if (!strcasecmp(format,"alaw"))
00417       res = "al";
00418    
00419    return res;
00420 }

static int load_module ( void   )  [static]

Definition at line 900 of file res_monitor.c.

References ast_manager_register_xml, AST_MODULE_LOAD_SUCCESS, ast_register_application_xml, 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 889 of file res_monitor.c.

References do_pause_or_unpause(), and MONITOR_ACTION_PAUSE.

Referenced by load_module().

00890 {
00891    return do_pause_or_unpause(s, m, MONITOR_ACTION_PAUSE);
00892 }

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

Wrapper for ast_monitor_pause.

Definition at line 535 of file res_monitor.c.

References ast_monitor_pause().

Referenced by load_module().

00536 {
00537    return ast_monitor_pause(chan);
00538 }

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

Start monitoring a channel by manager connection.

Definition at line 732 of file res_monitor.c.

References ast_channel_get_by_name(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, 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, name, X_REC_IN, and X_REC_OUT.

Referenced by load_module().

00733 {
00734    struct ast_channel *c = NULL;
00735    const char *name = astman_get_header(m, "Channel");
00736    const char *fname = astman_get_header(m, "File");
00737    const char *format = astman_get_header(m, "Format");
00738    const char *mix = astman_get_header(m, "Mix");
00739    char *d;
00740 
00741    if (ast_strlen_zero(name)) {
00742       astman_send_error(s, m, "No channel specified");
00743       return 0;
00744    }
00745 
00746    if (!(c = ast_channel_get_by_name(name))) {
00747       astman_send_error(s, m, "No such channel");
00748       return 0;
00749    }
00750 
00751    if (ast_strlen_zero(fname)) {
00752       /* No filename base specified, default to channel name as per CLI */
00753       ast_channel_lock(c);
00754       fname = ast_strdupa(c->name);
00755       ast_channel_unlock(c);
00756       /* Channels have the format technology/channel_name - have to replace that /  */
00757       if ((d = strchr(fname, '/'))) {
00758          *d = '-';
00759       }
00760    }
00761 
00762    if (ast_monitor_start(c, format, fname, 1, X_REC_IN | X_REC_OUT)) {
00763       if (ast_monitor_change_fname(c, fname, 1)) {
00764          astman_send_error(s, m, "Could not start monitoring channel");
00765          c = ast_channel_unref(c);
00766          return 0;
00767       }
00768    }
00769 
00770    if (ast_true(mix)) {
00771       ast_channel_lock(c);
00772       ast_monitor_setjoinfiles(c, 1);
00773       ast_channel_unlock(c);
00774    }
00775 
00776    c = ast_channel_unref(c);
00777 
00778    astman_send_ack(s, m, "Started monitoring channel");
00779 
00780    return 0;
00781 }

static int start_monitor_exec ( struct ast_channel chan,
const char *  data 
) [static]

Start monitor.

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

Definition at line 636 of file res_monitor.c.

References args, 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, LOG_ERROR, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), urlprefix, X_JOIN, X_REC_IN, and X_REC_OUT.

Referenced by load_module().

00637 {
00638    char *arg = NULL;
00639    char *options = NULL;
00640    char *delay = NULL;
00641    char *urlprefix = NULL;
00642    char tmp[256];
00643    int stream_action = X_REC_IN | X_REC_OUT;
00644    int joinfiles = 0;
00645    int waitforbridge = 0;
00646    int res = 0;
00647    char *parse;
00648    AST_DECLARE_APP_ARGS(args,
00649       AST_APP_ARG(format);
00650       AST_APP_ARG(fname_base);
00651       AST_APP_ARG(options);
00652    );
00653    
00654    /* Parse arguments. */
00655    if (ast_strlen_zero(data)) {
00656       ast_log(LOG_ERROR, "Monitor requires an argument\n");
00657       return 0;
00658    }
00659 
00660    parse = ast_strdupa(data);
00661    AST_STANDARD_APP_ARGS(args, parse);
00662 
00663    if (!ast_strlen_zero(args.options)) {
00664       if (strchr(args.options, 'm'))
00665          stream_action |= X_JOIN;
00666       if (strchr(args.options, 'b'))
00667          waitforbridge = 1;
00668       if (strchr(args.options, 'i'))
00669          stream_action &= ~X_REC_IN;
00670       if (strchr(args.options, 'o'))
00671          stream_action &= ~X_REC_OUT;
00672    }
00673 
00674    arg = strchr(args.format, ':');
00675    if (arg) {
00676       *arg++ = 0;
00677       urlprefix = arg;
00678    }
00679 
00680    if (urlprefix) {
00681       snprintf(tmp, sizeof(tmp), "%s/%s.%s", urlprefix, args.fname_base,
00682          ((strcmp(args.format, "gsm")) ? "wav" : "gsm"));
00683       if (!chan->cdr && !(chan->cdr = ast_cdr_alloc()))
00684          return -1;
00685       ast_cdr_setuserfield(chan, tmp);
00686    }
00687    if (waitforbridge) {
00688       /* We must remove the "b" option if listed.  In principle none of
00689          the following could give NULL results, but we check just to
00690          be pedantic. Reconstructing with checks for 'm' option does not
00691          work if we end up adding more options than 'm' in the future. */
00692       delay = ast_strdupa(data);
00693       options = strrchr(delay, ',');
00694       if (options) {
00695          arg = strchr(options, 'b');
00696          if (arg) {
00697             *arg = 'X';
00698             pbx_builtin_setvar_helper(chan,"AUTO_MONITOR", delay);
00699          }
00700       }
00701       return 0;
00702    }
00703 
00704    res = ast_monitor_start(chan, args.format, args.fname_base, 1, stream_action);
00705    if (res < 0)
00706       res = ast_monitor_change_fname(chan, args.fname_base, 1);
00707 
00708    if (stream_action & X_JOIN) {
00709       if ((stream_action & X_REC_IN) && (stream_action & X_REC_OUT))
00710          joinfiles = 1;
00711       else
00712          ast_log(LOG_WARNING, "Won't mix streams unless both input and output streams are recorded\n");
00713    }
00714    ast_monitor_setjoinfiles(chan, joinfiles);
00715 
00716    return res;
00717 }

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

Stop monitoring a channel by manager connection.

Definition at line 784 of file res_monitor.c.

References ast_channel_get_by_name(), ast_channel_unref, ast_monitor_stop(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and name.

Referenced by load_module().

00785 {
00786    struct ast_channel *c = NULL;
00787    const char *name = astman_get_header(m, "Channel");
00788    int res;
00789 
00790    if (ast_strlen_zero(name)) {
00791       astman_send_error(s, m, "No channel specified");
00792       return 0;
00793    }
00794 
00795    if (!(c = ast_channel_get_by_name(name))) {
00796       astman_send_error(s, m, "No such channel");
00797       return 0;
00798    }
00799 
00800    res = ast_monitor_stop(c, 1);
00801 
00802    c = ast_channel_unref(c);
00803 
00804    if (res) {
00805       astman_send_error(s, m, "Could not stop monitoring channel");
00806       return 0;
00807    }
00808 
00809    astman_send_ack(s, m, "Stopped monitoring channel");
00810 
00811    return 0;
00812 }

static int stop_monitor_exec ( struct ast_channel chan,
const char *  data 
) [static]

Wrapper function.

See also:
ast_monitor_stop

Definition at line 720 of file res_monitor.c.

References ast_monitor_stop().

Referenced by load_module().

00721 {
00722    return ast_monitor_stop(chan, 1);
00723 }

static int unload_module ( void   )  [static]

Definition at line 916 of file res_monitor.c.

References ast_manager_unregister(), and ast_unregister_application().

00917 {
00918    ast_unregister_application("Monitor");
00919    ast_unregister_application("StopMonitor");
00920    ast_unregister_application("ChangeMonitor");
00921    ast_unregister_application("PauseMonitor");
00922    ast_unregister_application("UnpauseMonitor");
00923    ast_manager_unregister("Monitor");
00924    ast_manager_unregister("StopMonitor");
00925    ast_manager_unregister("ChangeMonitor");
00926    ast_manager_unregister("PauseMonitor");
00927    ast_manager_unregister("UnpauseMonitor");
00928 
00929    return 0;
00930 }

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

Definition at line 894 of file res_monitor.c.

References do_pause_or_unpause().

Referenced by load_module().

00895 {
00896    return do_pause_or_unpause(s, m, MONITOR_ACTION_UNPAUSE);
00897 }

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

Wrapper for ast_monitor_unpause.

Definition at line 541 of file res_monitor.c.

References ast_monitor_unpause().

Referenced by load_module().

00542 {
00543    return ast_monitor_unpause(chan);
00544 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Call Monitoring Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } [static]

Definition at line 937 of file res_monitor.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 937 of file res_monitor.c.

ast_mutex_t monitorlock = { { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } , 1, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } [static]

Definition at line 242 of file res_monitor.c.

Referenced by ast_monitor_start().

unsigned long seq = 0 [static]

Definition at line 254 of file res_monitor.c.


Generated on Wed Apr 6 11:30:09 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7