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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static ast_mutex_t | monitorlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } |
| static unsigned long | seq = 0 |
PBX channel monitoring.
Definition in file res_monitor.c.
| #define AST_API_MODULE |
Definition at line 45 of file res_monitor.c.
| #define LOCK_IF_NEEDED | ( | lock, | |
| needed | |||
| ) |
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 | |||
| ) |
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().
Definition at line 863 of file res_monitor.c.
| static void __reg_module | ( | void | ) | [static] |
Definition at line 945 of file res_monitor.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 945 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.
| chan | |
| fname_base | new filename |
| need_lock |
| 0 | on success. |
| -1 | on failure. |
Remember, also, that we're using the basename of the file (i.e. the file without the format suffix), so it does not already exist and we aren't interfering with the recording itself.
Definition at line 558 of file res_monitor.c.
References ast_config_AST_MONITOR_DIR, ast_copy_string(), ast_debug, ast_log(), ast_mkdir(), ast_strdupa, ast_strlen_zero(), errno, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, LOCK_IF_NEEDED, LOG_ERROR, LOG_WARNING, ast_channel::monitor, 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_OPTIONAL_API_NAME() ast_monitor_pause | ( | struct ast_channel * | chan | ) |
Pause monitoring of channel.
Definition at line 527 of file res_monitor.c.
References AST_MONITOR_PAUSED, and ast_monitor_set_state().
Referenced by do_pause_or_unpause(), and pause_monitor_exec().
{
return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
}
| static int ast_monitor_set_state | ( | struct ast_channel * | chan, |
| int | state | ||
| ) | [static] |
Change state of monitored channel.
| chan | |
| state | monitor state |
| 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, 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_OPTIONAL_API_NAME() ast_monitor_setjoinfiles | ( | struct ast_channel * | chan, |
| int | turnon | ||
| ) |
Definition at line 857 of file res_monitor.c.
References ast_channel_monitor::joinfiles, and ast_channel::monitor.
Referenced by __agent_start_monitoring(), start_monitor_action(), start_monitor_exec(), and try_calling().
| 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.
| 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 |
| 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, ast_channel::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");
ast_manager_event(chan, 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_OPTIONAL_API_NAME() ast_monitor_stop | ( | struct ast_channel * | chan, |
| int | need_lock | ||
| ) |
Stop monitoring channel.
| chan | |
| need_lock | Stop the recording, close any open streams, mix in/out channels if required |
Definition at line 433 of file res_monitor.c.
References ast_closestream(), ast_copy_string(), ast_debug, ast_filedelete(), ast_fileexists(), ast_filerename(), ast_free, ast_log(), ast_manager_event, ast_safe_system(), ast_strlen_zero(), EVENT_FLAG_CALL, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, FILENAME_MAX, ast_channel_monitor::format, format, get_soxmix_format(), ast_channel_monitor::joinfiles, LOCK_IF_NEEDED, LOG_WARNING, ast_channel::monitor, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel_monitor::read_filename, ast_channel_monitor::read_stream, ast_channel::uniqueid, UNLOCK_IF_NEEDED, ast_channel_monitor::write_filename, and ast_channel_monitor::write_stream.
Referenced by ast_monitor_start(), stop_monitor_action(), and stop_monitor_exec().
{
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;
ast_manager_event(chan, 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_OPTIONAL_API_NAME() ast_monitor_unpause | ( | struct ast_channel * | chan | ) |
Unpause monitoring of channel.
Definition at line 533 of file res_monitor.c.
References AST_MONITOR_RUNNING, and ast_monitor_set_state().
Referenced by do_pause_or_unpause(), and unpause_monitor_exec().
{
return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
}
| 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 823 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().
{
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;
}
if (!(c = ast_channel_get_by_name(name))) {
astman_send_error(s, m, "No such channel");
return 0;
}
if (ast_monitor_change_fname(c, fname, 1)) {
c = ast_channel_unref(c);
astman_send_error(s, m, "Could not change monitored filename of channel");
return 0;
}
c = ast_channel_unref(c);
astman_send_ack(s, m, "Changed monitor filename");
return 0;
}
| static int change_monitor_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Wrapper function.
Definition at line 734 of file res_monitor.c.
References ast_monitor_change_fname().
Referenced by load_module().
{
return ast_monitor_change_fname(chan, data, 1);
}
| static int do_pause_or_unpause | ( | struct mansession * | s, |
| const struct message * | m, | ||
| int | action | ||
| ) | [static] |
Definition at line 869 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().
{
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;
}
if (!(c = ast_channel_get_by_name(name))) {
astman_send_error(s, m, "No such channel");
return -1;
}
if (action == MONITOR_ACTION_PAUSE) {
ast_monitor_pause(c);
} else {
ast_monitor_unpause(c);
}
c = ast_channel_unref(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.
| 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 414 of file res_monitor.c.
References format.
Referenced by ast_monitor_stop().
| static int load_module | ( | void | ) | [static] |
Definition at line 908 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().
{
ast_register_application_xml("Monitor", start_monitor_exec);
ast_register_application_xml("StopMonitor", stop_monitor_exec);
ast_register_application_xml("ChangeMonitor", change_monitor_exec);
ast_register_application_xml("PauseMonitor", pause_monitor_exec);
ast_register_application_xml("UnpauseMonitor", unpause_monitor_exec);
ast_manager_register_xml("Monitor", EVENT_FLAG_CALL, start_monitor_action);
ast_manager_register_xml("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action);
ast_manager_register_xml("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action);
ast_manager_register_xml("PauseMonitor", EVENT_FLAG_CALL, pause_monitor_action);
ast_manager_register_xml("UnpauseMonitor", EVENT_FLAG_CALL, unpause_monitor_action);
return AST_MODULE_LOAD_SUCCESS;
}
| static int pause_monitor_action | ( | struct mansession * | s, |
| const struct message * | m | ||
| ) | [static] |
Definition at line 897 of file res_monitor.c.
References do_pause_or_unpause(), and MONITOR_ACTION_PAUSE.
Referenced by load_module().
{
return do_pause_or_unpause(s, m, MONITOR_ACTION_PAUSE);
}
| static int pause_monitor_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Wrapper for ast_monitor_pause.
Definition at line 539 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 740 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, ast_channel::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;
}
if (!(c = ast_channel_get_by_name(name))) {
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 */
ast_channel_lock(c);
fname = ast_strdupa(c->name);
ast_channel_unlock(c);
/* 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");
c = ast_channel_unref(c);
return 0;
}
}
if (ast_true(mix)) {
ast_channel_lock(c);
ast_monitor_setjoinfiles(c, 1);
ast_channel_unlock(c);
}
c = ast_channel_unref(c);
astman_send_ack(s, m, "Started monitoring channel");
return 0;
}
| static int start_monitor_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Start monitor.
| chan | |
| data | arguments passed fname|options |
| 0 | on success. |
| -1 | on failure. |
Definition at line 640 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().
{
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(data)) {
ast_log(LOG_ERROR, "Monitor requires an argument\n");
return 0;
}
parse = ast_strdupa(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"));
ast_channel_lock(chan);
if (!chan->cdr && !(chan->cdr = ast_cdr_alloc())) {
ast_channel_unlock(chan);
return -1;
}
ast_cdr_setuserfield(chan, tmp);
ast_channel_unlock(chan);
}
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 792 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().
{
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;
}
if (!(c = ast_channel_get_by_name(name))) {
astman_send_error(s, m, "No such channel");
return 0;
}
res = ast_monitor_stop(c, 1);
c = ast_channel_unref(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, |
| const char * | data | ||
| ) | [static] |
Wrapper function.
Definition at line 728 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 924 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 902 of file res_monitor.c.
References do_pause_or_unpause(), and MONITOR_ACTION_UNPAUSE.
Referenced by load_module().
{
return do_pause_or_unpause(s, m, MONITOR_ACTION_UNPAUSE);
}
| static int unpause_monitor_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Wrapper for ast_monitor_unpause.
Definition at line 545 of file res_monitor.c.
References ast_monitor_unpause().
Referenced by load_module().
{
return ast_monitor_unpause(chan);
}
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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } [static] |
Definition at line 945 of file res_monitor.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 945 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.