Wed Aug 7 17:16:11 2019

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 = "ac1f6a56484a8820659555499174e588" , .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 = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
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 45 of file res_monitor.c.

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

Definition at line 248 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 253 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 873 of file res_monitor.c.

00874 {
00875    MONITOR_ACTION_PAUSE,
00876    MONITOR_ACTION_UNPAUSE
00877 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 954 of file res_monitor.c.

static void __unreg_module ( void   )  [static]

Definition at line 954 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 566 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(), doexit, errno, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, LOCK_IF_NEEDED, LOG_ERROR, LOG_WARNING, ast_channel::monitor, name, and UNLOCK_IF_NEEDED.

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

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

int AST_OPTIONAL_API_NAME() ast_monitor_pause ( struct ast_channel chan  ) 

Pause monitoring of channel.

Definition at line 535 of file res_monitor.c.

References AST_MONITOR_PAUSED, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and pause_monitor_exec().

00536 {
00537    return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
00538 }

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

00268 {
00269    LOCK_IF_NEEDED(chan, 1);
00270    if (!chan->monitor) {
00271       UNLOCK_IF_NEEDED(chan, 1);
00272       return -1;
00273    }
00274    chan->monitor->state = state;
00275    UNLOCK_IF_NEEDED(chan, 1);
00276    return 0;
00277 }

void AST_OPTIONAL_API_NAME() ast_monitor_setjoinfiles ( struct ast_channel chan,
int  turnon 
)

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

00868 {
00869    if (chan->monitor)
00870       chan->monitor->joinfiles = turnon;
00871 }

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 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, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, FILENAME_MAX, ast_channel_monitor::format, LOCK_IF_NEEDED, 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, 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().

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

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 437 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, 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(), stop_monitor_action(), and stop_monitor_exec().

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

int AST_OPTIONAL_API_NAME() ast_monitor_unpause ( struct ast_channel chan  ) 

Unpause monitoring of channel.

Definition at line 541 of file res_monitor.c.

References AST_MONITOR_RUNNING, and ast_monitor_set_state().

Referenced by do_pause_or_unpause(), and unpause_monitor_exec().

00542 {
00543    return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00544 }

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

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

00834 {
00835    struct ast_channel *c = NULL;
00836    const char *name = astman_get_header(m, "Channel");
00837    const char *fname = astman_get_header(m, "File");
00838 
00839    if (ast_strlen_zero(name)) {
00840       astman_send_error(s, m, "No channel specified");
00841       return AMI_SUCCESS;
00842    }
00843 
00844    if (ast_strlen_zero(fname)) {
00845       astman_send_error(s, m, "No filename specified");
00846       return AMI_SUCCESS;
00847    }
00848 
00849    if (!(c = ast_channel_get_by_name(name))) {
00850       astman_send_error(s, m, "No such channel");
00851       return AMI_SUCCESS;
00852    }
00853 
00854    if (ast_monitor_change_fname(c, fname, 1)) {
00855       c = ast_channel_unref(c);
00856       astman_send_error(s, m, "Could not change monitored filename of channel");
00857       return AMI_SUCCESS;
00858    }
00859 
00860    c = ast_channel_unref(c);
00861 
00862    astman_send_ack(s, m, "Changed monitor filename");
00863 
00864    return AMI_SUCCESS;
00865 }

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

Wrapper function.

See also:
ast_monitor_change_fname

Definition at line 743 of file res_monitor.c.

References ast_monitor_change_fname().

Referenced by load_module().

00744 {
00745    return ast_monitor_change_fname(chan, data, 1);
00746 }

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

Definition at line 879 of file res_monitor.c.

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

00880 {
00881    struct ast_channel *c = NULL;
00882    const char *name = astman_get_header(m, "Channel");
00883 
00884    if (ast_strlen_zero(name)) {
00885       astman_send_error(s, m, "No channel specified");
00886       return AMI_SUCCESS;
00887    }
00888 
00889    if (!(c = ast_channel_get_by_name(name))) {
00890       astman_send_error(s, m, "No such channel");
00891       return AMI_SUCCESS;
00892    }
00893 
00894    if (action == MONITOR_ACTION_PAUSE) {
00895       ast_monitor_pause(c);
00896    } else {
00897       ast_monitor_unpause(c);
00898    }
00899 
00900    c = ast_channel_unref(c);
00901 
00902    astman_send_ack(s, m, (action == MONITOR_ACTION_PAUSE ? "Paused monitoring of the channel" : "Unpaused monitoring of the channel"));
00903 
00904    return AMI_SUCCESS;
00905 }

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

Referenced by ast_monitor_stop().

00419 {
00420    const char *res = format;
00421 
00422    if (!strcasecmp(format,"ulaw"))
00423       res = "ul";
00424    if (!strcasecmp(format,"alaw"))
00425       res = "al";
00426    
00427    return res;
00428 }

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

Definition at line 907 of file res_monitor.c.

References do_pause_or_unpause(), and MONITOR_ACTION_PAUSE.

Referenced by load_module().

00908 {
00909    return do_pause_or_unpause(s, m, MONITOR_ACTION_PAUSE);
00910 }

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

Wrapper for ast_monitor_pause.

Definition at line 547 of file res_monitor.c.

References ast_monitor_pause().

Referenced by load_module().

00548 {
00549    return ast_monitor_pause(chan);
00550 }

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

Start monitoring a channel by manager connection.

Definition at line 749 of file res_monitor.c.

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

00750 {
00751    struct ast_channel *c = NULL;
00752    const char *name = astman_get_header(m, "Channel");
00753    const char *fname = astman_get_header(m, "File");
00754    const char *format = astman_get_header(m, "Format");
00755    const char *mix = astman_get_header(m, "Mix");
00756    char *d;
00757 
00758    if (ast_strlen_zero(name)) {
00759       astman_send_error(s, m, "No channel specified");
00760       return AMI_SUCCESS;
00761    }
00762 
00763    if (!(c = ast_channel_get_by_name(name))) {
00764       astman_send_error(s, m, "No such channel");
00765       return AMI_SUCCESS;
00766    }
00767 
00768    if (ast_strlen_zero(fname)) {
00769       /* No filename specified, default to the channel name. */
00770       ast_channel_lock(c);
00771       fname = ast_strdupa(c->name);
00772       ast_channel_unlock(c);
00773 
00774       /* Replace all '/' chars from the channel name with '-' chars. */
00775       for (d = (char *) fname; (d = strchr(d, '/')); ) {
00776          *d = '-';
00777       }
00778    }
00779 
00780    if (ast_monitor_start(c, format, fname, 1, X_REC_IN | X_REC_OUT)) {
00781       if (ast_monitor_change_fname(c, fname, 1)) {
00782          astman_send_error(s, m, "Could not start monitoring channel");
00783          c = ast_channel_unref(c);
00784          return AMI_SUCCESS;
00785       }
00786    }
00787 
00788    if (ast_true(mix)) {
00789       ast_channel_lock(c);
00790       ast_monitor_setjoinfiles(c, 1);
00791       ast_channel_unlock(c);
00792    }
00793 
00794    c = ast_channel_unref(c);
00795 
00796    astman_send_ack(s, m, "Started monitoring channel");
00797 
00798    return AMI_SUCCESS;
00799 }

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

References args, AST_APP_ARG, ast_cdr_alloc(), ast_cdr_setuserfield(), ast_channel_lock, ast_channel_unlock, 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().

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

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

Stop monitoring a channel by manager connection.

Definition at line 802 of file res_monitor.c.

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

00803 {
00804    struct ast_channel *c = NULL;
00805    const char *name = astman_get_header(m, "Channel");
00806    int res;
00807 
00808    if (ast_strlen_zero(name)) {
00809       astman_send_error(s, m, "No channel specified");
00810       return AMI_SUCCESS;
00811    }
00812 
00813    if (!(c = ast_channel_get_by_name(name))) {
00814       astman_send_error(s, m, "No such channel");
00815       return AMI_SUCCESS;
00816    }
00817 
00818    res = ast_monitor_stop(c, 1);
00819 
00820    c = ast_channel_unref(c);
00821 
00822    if (res) {
00823       astman_send_error(s, m, "Could not stop monitoring channel");
00824       return AMI_SUCCESS;
00825    }
00826 
00827    astman_send_ack(s, m, "Stopped monitoring channel");
00828 
00829    return AMI_SUCCESS;
00830 }

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

Wrapper function.

See also:
ast_monitor_stop

Definition at line 737 of file res_monitor.c.

References ast_monitor_stop().

Referenced by load_module().

00738 {
00739    return ast_monitor_stop(chan, 1);
00740 }

static int unload_module ( void   )  [static]

Definition at line 933 of file res_monitor.c.

References ast_manager_unregister(), and ast_unregister_application().

00934 {
00935    ast_unregister_application("Monitor");
00936    ast_unregister_application("StopMonitor");
00937    ast_unregister_application("ChangeMonitor");
00938    ast_unregister_application("PauseMonitor");
00939    ast_unregister_application("UnpauseMonitor");
00940    ast_manager_unregister("Monitor");
00941    ast_manager_unregister("StopMonitor");
00942    ast_manager_unregister("ChangeMonitor");
00943    ast_manager_unregister("PauseMonitor");
00944    ast_manager_unregister("UnpauseMonitor");
00945 
00946    return 0;
00947 }

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

Definition at line 912 of file res_monitor.c.

References do_pause_or_unpause(), and MONITOR_ACTION_UNPAUSE.

Referenced by load_module().

00913 {
00914    return do_pause_or_unpause(s, m, MONITOR_ACTION_UNPAUSE);
00915 }

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

Wrapper for ast_monitor_unpause.

Definition at line 553 of file res_monitor.c.

References ast_monitor_unpause().

Referenced by load_module().

00554 {
00555    return ast_monitor_unpause(chan);
00556 }


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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } [static]

Definition at line 954 of file res_monitor.c.

Definition at line 954 of file res_monitor.c.

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

Definition at line 246 of file res_monitor.c.

Referenced by ast_monitor_start().

unsigned long seq = 0 [static]

Definition at line 258 of file res_monitor.c.


Generated on 7 Aug 2019 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1