#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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 |
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 | ) |
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().
Definition at line 863 of file res_monitor.c.
00864 { 00865 MONITOR_ACTION_PAUSE, 00866 MONITOR_ACTION_UNPAUSE 00867 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 944 of file res_monitor.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 944 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. |
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().
00559 { 00560 if (ast_strlen_zero(fname_base)) { 00561 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", chan->name); 00562 return -1; 00563 } 00564 00565 LOCK_IF_NEEDED(chan, need_lock); 00566 00567 if (chan->monitor) { 00568 int directory = strchr(fname_base, '/') ? 1 : 0; 00569 const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR; 00570 const char *absolute_suffix = *fname_base == '/' ? "" : "/"; 00571 char tmpstring[sizeof(chan->monitor->filename_base)] = ""; 00572 int i, fd[2] = { -1, -1 }, doexit = 0; 00573 00574 /* before continuing, see if we're trying to rename the file to itself... */ 00575 snprintf(tmpstring, sizeof(tmpstring), "%s%s%s", absolute, absolute_suffix, fname_base); 00576 00577 /* try creating the directory just in case it doesn't exist */ 00578 if (directory) { 00579 char *name = ast_strdupa(tmpstring); 00580 ast_mkdir(dirname(name), 0777); 00581 } 00582 00583 /*!\note We cannot just compare filenames, due to symlinks, relative 00584 * paths, and other possible filesystem issues. We could use 00585 * realpath(3), but its use is discouraged. However, if we try to 00586 * create the same file from two different paths, the second will 00587 * fail, and so we have our notification that the filenames point to 00588 * the same path. 00589 * 00590 * Remember, also, that we're using the basename of the file (i.e. 00591 * the file without the format suffix), so it does not already exist 00592 * and we aren't interfering with the recording itself. 00593 */ 00594 ast_debug(2, "comparing tmpstring %s to filename_base %s\n", tmpstring, chan->monitor->filename_base); 00595 00596 if ((fd[0] = open(tmpstring, O_CREAT | O_WRONLY, 0644)) < 0 || 00597 (fd[1] = open(chan->monitor->filename_base, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) { 00598 if (fd[0] < 0) { 00599 ast_log(LOG_ERROR, "Unable to compare filenames: %s\n", strerror(errno)); 00600 } else { 00601 ast_debug(2, "No need to rename monitor filename to itself\n"); 00602 } 00603 doexit = 1; 00604 } 00605 00606 /* Cleanup temporary files */ 00607 for (i = 0; i < 2; i++) { 00608 if (fd[i] >= 0) { 00609 while (close(fd[i]) < 0 && errno == EINTR); 00610 } 00611 } 00612 unlink(tmpstring); 00613 /* if previous monitor file existed in a subdirectory, the directory will not be removed */ 00614 unlink(chan->monitor->filename_base); 00615 00616 if (doexit) { 00617 UNLOCK_IF_NEEDED(chan, need_lock); 00618 return 0; 00619 } 00620 00621 ast_copy_string(chan->monitor->filename_base, tmpstring, sizeof(chan->monitor->filename_base)); 00622 chan->monitor->filename_changed = 1; 00623 } else { 00624 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", chan->name, fname_base); 00625 } 00626 00627 UNLOCK_IF_NEEDED(chan, need_lock); 00628 00629 return 0; 00630 }
int AST_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().
00528 { 00529 return ast_monitor_set_state(chan, AST_MONITOR_PAUSED); 00530 }
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, 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 857 of file res_monitor.c.
References ast_channel_monitor::joinfiles, and ast_channel::monitor.
Referenced by __agent_start_monitoring(), start_monitor_action(), and start_monitor_exec().
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, 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().
00292 { 00293 int res = 0; 00294 00295 LOCK_IF_NEEDED(chan, need_lock); 00296 00297 if (!(chan->monitor)) { 00298 struct ast_channel_monitor *monitor; 00299 char *channel_name, *p; 00300 00301 /* Create monitoring directory if needed */ 00302 ast_mkdir(ast_config_AST_MONITOR_DIR, 0777); 00303 00304 if (!(monitor = ast_calloc(1, sizeof(*monitor)))) { 00305 UNLOCK_IF_NEEDED(chan, need_lock); 00306 return -1; 00307 } 00308 00309 /* Determine file names */ 00310 if (!ast_strlen_zero(fname_base)) { 00311 int directory = strchr(fname_base, '/') ? 1 : 0; 00312 const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR; 00313 const char *absolute_suffix = *fname_base == '/' ? "" : "/"; 00314 00315 snprintf(monitor->read_filename, FILENAME_MAX, "%s%s%s-in", 00316 absolute, absolute_suffix, fname_base); 00317 snprintf(monitor->write_filename, FILENAME_MAX, "%s%s%s-out", 00318 absolute, absolute_suffix, fname_base); 00319 snprintf(monitor->filename_base, FILENAME_MAX, "%s%s%s", 00320 absolute, absolute_suffix, fname_base); 00321 00322 /* try creating the directory just in case it doesn't exist */ 00323 if (directory) { 00324 char *name = ast_strdupa(monitor->filename_base); 00325 ast_mkdir(dirname(name), 0777); 00326 } 00327 } else { 00328 ast_mutex_lock(&monitorlock); 00329 snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld", 00330 ast_config_AST_MONITOR_DIR, seq); 00331 snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld", 00332 ast_config_AST_MONITOR_DIR, seq); 00333 seq++; 00334 ast_mutex_unlock(&monitorlock); 00335 00336 channel_name = ast_strdupa(chan->name); 00337 while ((p = strchr(channel_name, '/'))) { 00338 *p = '-'; 00339 } 00340 snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s", 00341 ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name); 00342 monitor->filename_changed = 1; 00343 } 00344 00345 monitor->stop = ast_monitor_stop; 00346 00347 /* Determine file format */ 00348 if (!ast_strlen_zero(format_spec)) { 00349 monitor->format = ast_strdup(format_spec); 00350 } else { 00351 monitor->format = ast_strdup("wav"); 00352 } 00353 00354 /* open files */ 00355 if (stream_action & X_REC_IN) { 00356 if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0) 00357 ast_filedelete(monitor->read_filename, NULL); 00358 if (!(monitor->read_stream = ast_writefile(monitor->read_filename, 00359 monitor->format, NULL, 00360 O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) { 00361 ast_log(LOG_WARNING, "Could not create file %s\n", 00362 monitor->read_filename); 00363 ast_free(monitor); 00364 UNLOCK_IF_NEEDED(chan, need_lock); 00365 return -1; 00366 } 00367 } else 00368 monitor->read_stream = NULL; 00369 00370 if (stream_action & X_REC_OUT) { 00371 if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) { 00372 ast_filedelete(monitor->write_filename, NULL); 00373 } 00374 if (!(monitor->write_stream = ast_writefile(monitor->write_filename, 00375 monitor->format, NULL, 00376 O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) { 00377 ast_log(LOG_WARNING, "Could not create file %s\n", 00378 monitor->write_filename); 00379 ast_closestream(monitor->read_stream); 00380 ast_free(monitor); 00381 UNLOCK_IF_NEEDED(chan, need_lock); 00382 return -1; 00383 } 00384 } else 00385 monitor->write_stream = NULL; 00386 00387 chan->monitor = monitor; 00388 ast_monitor_set_state(chan, AST_MONITOR_RUNNING); 00389 /* so we know this call has been monitored in case we need to bill for it or something */ 00390 pbx_builtin_setvar_helper(chan, "__MONITORED","true"); 00391 00392 ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStart", 00393 "Channel: %s\r\n" 00394 "Uniqueid: %s\r\n", 00395 chan->name, 00396 chan->uniqueid); 00397 } else { 00398 ast_debug(1,"Cannot start monitoring %s, already monitored\n", chan->name); 00399 res = -1; 00400 } 00401 00402 UNLOCK_IF_NEEDED(chan, need_lock); 00403 00404 return res; 00405 }
int AST_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, 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().
00434 { 00435 int delfiles = 0; 00436 00437 LOCK_IF_NEEDED(chan, need_lock); 00438 00439 if (chan->monitor) { 00440 char filename[ FILENAME_MAX ]; 00441 00442 if (chan->monitor->read_stream) { 00443 ast_closestream(chan->monitor->read_stream); 00444 } 00445 if (chan->monitor->write_stream) { 00446 ast_closestream(chan->monitor->write_stream); 00447 } 00448 00449 if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) { 00450 if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) { 00451 snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base); 00452 if (ast_fileexists(filename, NULL, NULL) > 0) { 00453 ast_filedelete(filename, NULL); 00454 } 00455 ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format); 00456 } else { 00457 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename); 00458 } 00459 00460 if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) { 00461 snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base); 00462 if (ast_fileexists(filename, NULL, NULL) > 0) { 00463 ast_filedelete(filename, NULL); 00464 } 00465 ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format); 00466 } else { 00467 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename); 00468 } 00469 } 00470 00471 if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) { 00472 char tmp[1024]; 00473 char tmp2[1024]; 00474 const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format; 00475 char *fname_base = chan->monitor->filename_base; 00476 const char *execute, *execute_args; 00477 /* at this point, fname_base really is the full path */ 00478 00479 /* Set the execute application */ 00480 execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC"); 00481 if (ast_strlen_zero(execute)) { 00482 #ifdef HAVE_SOXMIX 00483 execute = "nice -n 19 soxmix"; 00484 #else 00485 execute = "nice -n 19 sox -m"; 00486 #endif 00487 format = get_soxmix_format(format); 00488 delfiles = 1; 00489 } 00490 execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS"); 00491 if (ast_strlen_zero(execute_args)) { 00492 execute_args = ""; 00493 } 00494 00495 snprintf(tmp, sizeof(tmp), "%s \"%s-in.%s\" \"%s-out.%s\" \"%s.%s\" %s &", 00496 execute, fname_base, format, fname_base, format, fname_base, format,execute_args); 00497 if (delfiles) { 00498 snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s-\"* ) &",tmp, fname_base); /* remove legs when done mixing */ 00499 ast_copy_string(tmp, tmp2, sizeof(tmp)); 00500 } 00501 ast_debug(1,"monitor executing %s\n",tmp); 00502 if (ast_safe_system(tmp) == -1) 00503 ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp); 00504 } 00505 00506 ast_free(chan->monitor->format); 00507 ast_free(chan->monitor); 00508 chan->monitor = NULL; 00509 00510 ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStop", 00511 "Channel: %s\r\n" 00512 "Uniqueid: %s\r\n", 00513 chan->name, 00514 chan->uniqueid 00515 ); 00516 pbx_builtin_setvar_helper(chan, "MONITORED", NULL); 00517 } 00518 pbx_builtin_setvar_helper(chan, "AUTO_MONITOR", NULL); 00519 00520 UNLOCK_IF_NEEDED(chan, need_lock); 00521 00522 return 0; 00523 }
int AST_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().
00534 { 00535 return ast_monitor_set_state(chan, AST_MONITOR_RUNNING); 00536 }
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 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().
00824 { 00825 struct ast_channel *c = NULL; 00826 const char *name = astman_get_header(m, "Channel"); 00827 const char *fname = astman_get_header(m, "File"); 00828 00829 if (ast_strlen_zero(name)) { 00830 astman_send_error(s, m, "No channel specified"); 00831 return AMI_SUCCESS; 00832 } 00833 00834 if (ast_strlen_zero(fname)) { 00835 astman_send_error(s, m, "No filename specified"); 00836 return AMI_SUCCESS; 00837 } 00838 00839 if (!(c = ast_channel_get_by_name(name))) { 00840 astman_send_error(s, m, "No such channel"); 00841 return AMI_SUCCESS; 00842 } 00843 00844 if (ast_monitor_change_fname(c, fname, 1)) { 00845 c = ast_channel_unref(c); 00846 astman_send_error(s, m, "Could not change monitored filename of channel"); 00847 return AMI_SUCCESS; 00848 } 00849 00850 c = ast_channel_unref(c); 00851 00852 astman_send_ack(s, m, "Changed monitor filename"); 00853 00854 return AMI_SUCCESS; 00855 }
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().
00735 { 00736 return ast_monitor_change_fname(chan, data, 1); 00737 }
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 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().
00870 { 00871 struct ast_channel *c = NULL; 00872 const char *name = astman_get_header(m, "Channel"); 00873 00874 if (ast_strlen_zero(name)) { 00875 astman_send_error(s, m, "No channel specified"); 00876 return AMI_SUCCESS; 00877 } 00878 00879 if (!(c = ast_channel_get_by_name(name))) { 00880 astman_send_error(s, m, "No such channel"); 00881 return AMI_SUCCESS; 00882 } 00883 00884 if (action == MONITOR_ACTION_PAUSE) { 00885 ast_monitor_pause(c); 00886 } else { 00887 ast_monitor_unpause(c); 00888 } 00889 00890 c = ast_channel_unref(c); 00891 00892 astman_send_ack(s, m, (action == MONITOR_ACTION_PAUSE ? "Paused monitoring of the channel" : "Unpaused monitoring of the channel")); 00893 00894 return AMI_SUCCESS; 00895 }
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.
Referenced by ast_monitor_stop().
00415 { 00416 const char *res = format; 00417 00418 if (!strcasecmp(format,"ulaw")) 00419 res = "ul"; 00420 if (!strcasecmp(format,"alaw")) 00421 res = "al"; 00422 00423 return res; 00424 }
static int load_module | ( | void | ) | [static] |
Definition at line 907 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().
00908 { 00909 ast_register_application_xml("Monitor", start_monitor_exec); 00910 ast_register_application_xml("StopMonitor", stop_monitor_exec); 00911 ast_register_application_xml("ChangeMonitor", change_monitor_exec); 00912 ast_register_application_xml("PauseMonitor", pause_monitor_exec); 00913 ast_register_application_xml("UnpauseMonitor", unpause_monitor_exec); 00914 ast_manager_register_xml("Monitor", EVENT_FLAG_CALL, start_monitor_action); 00915 ast_manager_register_xml("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action); 00916 ast_manager_register_xml("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action); 00917 ast_manager_register_xml("PauseMonitor", EVENT_FLAG_CALL, pause_monitor_action); 00918 ast_manager_register_xml("UnpauseMonitor", EVENT_FLAG_CALL, unpause_monitor_action); 00919 00920 return AST_MODULE_LOAD_SUCCESS; 00921 }
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().
00898 { 00899 return do_pause_or_unpause(s, m, MONITOR_ACTION_PAUSE); 00900 }
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().
00540 { 00541 return ast_monitor_pause(chan); 00542 }
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 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().
00741 { 00742 struct ast_channel *c = NULL; 00743 const char *name = astman_get_header(m, "Channel"); 00744 const char *fname = astman_get_header(m, "File"); 00745 const char *format = astman_get_header(m, "Format"); 00746 const char *mix = astman_get_header(m, "Mix"); 00747 char *d; 00748 00749 if (ast_strlen_zero(name)) { 00750 astman_send_error(s, m, "No channel specified"); 00751 return AMI_SUCCESS; 00752 } 00753 00754 if (!(c = ast_channel_get_by_name(name))) { 00755 astman_send_error(s, m, "No such channel"); 00756 return AMI_SUCCESS; 00757 } 00758 00759 if (ast_strlen_zero(fname)) { 00760 /* No filename base specified, default to channel name as per CLI */ 00761 ast_channel_lock(c); 00762 fname = ast_strdupa(c->name); 00763 ast_channel_unlock(c); 00764 /* Channels have the format technology/channel_name - have to replace that / */ 00765 if ((d = strchr(fname, '/'))) { 00766 *d = '-'; 00767 } 00768 } 00769 00770 if (ast_monitor_start(c, format, fname, 1, X_REC_IN | X_REC_OUT)) { 00771 if (ast_monitor_change_fname(c, fname, 1)) { 00772 astman_send_error(s, m, "Could not start monitoring channel"); 00773 c = ast_channel_unref(c); 00774 return AMI_SUCCESS; 00775 } 00776 } 00777 00778 if (ast_true(mix)) { 00779 ast_channel_lock(c); 00780 ast_monitor_setjoinfiles(c, 1); 00781 ast_channel_unlock(c); 00782 } 00783 00784 c = ast_channel_unref(c); 00785 00786 astman_send_ack(s, m, "Started monitoring channel"); 00787 00788 return AMI_SUCCESS; 00789 }
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().
00641 { 00642 char *arg = NULL; 00643 char *options = NULL; 00644 char *delay = NULL; 00645 char *urlprefix = NULL; 00646 char tmp[256]; 00647 int stream_action = X_REC_IN | X_REC_OUT; 00648 int joinfiles = 0; 00649 int waitforbridge = 0; 00650 int res = 0; 00651 char *parse; 00652 AST_DECLARE_APP_ARGS(args, 00653 AST_APP_ARG(format); 00654 AST_APP_ARG(fname_base); 00655 AST_APP_ARG(options); 00656 ); 00657 00658 /* Parse arguments. */ 00659 if (ast_strlen_zero(data)) { 00660 ast_log(LOG_ERROR, "Monitor requires an argument\n"); 00661 return 0; 00662 } 00663 00664 parse = ast_strdupa(data); 00665 AST_STANDARD_APP_ARGS(args, parse); 00666 00667 if (!ast_strlen_zero(args.options)) { 00668 if (strchr(args.options, 'm')) 00669 stream_action |= X_JOIN; 00670 if (strchr(args.options, 'b')) 00671 waitforbridge = 1; 00672 if (strchr(args.options, 'i')) 00673 stream_action &= ~X_REC_IN; 00674 if (strchr(args.options, 'o')) 00675 stream_action &= ~X_REC_OUT; 00676 } 00677 00678 arg = strchr(args.format, ':'); 00679 if (arg) { 00680 *arg++ = 0; 00681 urlprefix = arg; 00682 } 00683 00684 if (urlprefix) { 00685 snprintf(tmp, sizeof(tmp), "%s/%s.%s", urlprefix, args.fname_base, 00686 ((strcmp(args.format, "gsm")) ? "wav" : "gsm")); 00687 ast_channel_lock(chan); 00688 if (!chan->cdr && !(chan->cdr = ast_cdr_alloc())) { 00689 ast_channel_unlock(chan); 00690 return -1; 00691 } 00692 ast_cdr_setuserfield(chan, tmp); 00693 ast_channel_unlock(chan); 00694 } 00695 if (waitforbridge) { 00696 /* We must remove the "b" option if listed. In principle none of 00697 the following could give NULL results, but we check just to 00698 be pedantic. Reconstructing with checks for 'm' option does not 00699 work if we end up adding more options than 'm' in the future. */ 00700 delay = ast_strdupa(data); 00701 options = strrchr(delay, ','); 00702 if (options) { 00703 arg = strchr(options, 'b'); 00704 if (arg) { 00705 *arg = 'X'; 00706 pbx_builtin_setvar_helper(chan,"AUTO_MONITOR", delay); 00707 } 00708 } 00709 return 0; 00710 } 00711 00712 res = ast_monitor_start(chan, args.format, args.fname_base, 1, stream_action); 00713 if (res < 0) 00714 res = ast_monitor_change_fname(chan, args.fname_base, 1); 00715 00716 if (stream_action & X_JOIN) { 00717 if ((stream_action & X_REC_IN) && (stream_action & X_REC_OUT)) 00718 joinfiles = 1; 00719 else 00720 ast_log(LOG_WARNING, "Won't mix streams unless both input and output streams are recorded\n"); 00721 } 00722 ast_monitor_setjoinfiles(chan, joinfiles); 00723 00724 return res; 00725 }
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 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().
00793 { 00794 struct ast_channel *c = NULL; 00795 const char *name = astman_get_header(m, "Channel"); 00796 int res; 00797 00798 if (ast_strlen_zero(name)) { 00799 astman_send_error(s, m, "No channel specified"); 00800 return AMI_SUCCESS; 00801 } 00802 00803 if (!(c = ast_channel_get_by_name(name))) { 00804 astman_send_error(s, m, "No such channel"); 00805 return AMI_SUCCESS; 00806 } 00807 00808 res = ast_monitor_stop(c, 1); 00809 00810 c = ast_channel_unref(c); 00811 00812 if (res) { 00813 astman_send_error(s, m, "Could not stop monitoring channel"); 00814 return AMI_SUCCESS; 00815 } 00816 00817 astman_send_ack(s, m, "Stopped monitoring channel"); 00818 00819 return AMI_SUCCESS; 00820 }
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().
00729 { 00730 return ast_monitor_stop(chan, 1); 00731 }
static int unload_module | ( | void | ) | [static] |
Definition at line 923 of file res_monitor.c.
References ast_manager_unregister(), and ast_unregister_application().
00924 { 00925 ast_unregister_application("Monitor"); 00926 ast_unregister_application("StopMonitor"); 00927 ast_unregister_application("ChangeMonitor"); 00928 ast_unregister_application("PauseMonitor"); 00929 ast_unregister_application("UnpauseMonitor"); 00930 ast_manager_unregister("Monitor"); 00931 ast_manager_unregister("StopMonitor"); 00932 ast_manager_unregister("ChangeMonitor"); 00933 ast_manager_unregister("PauseMonitor"); 00934 ast_manager_unregister("UnpauseMonitor"); 00935 00936 return 0; 00937 }
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().
Referenced by load_module().
00903 { 00904 return do_pause_or_unpause(s, m, MONITOR_ACTION_UNPAUSE); 00905 }
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().
00546 { 00547 return ast_monitor_unpause(chan); 00548 }
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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } [static] |
Definition at line 944 of file res_monitor.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 944 of file res_monitor.c.
ast_mutex_t monitorlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static] |
unsigned long seq = 0 [static] |
Definition at line 258 of file res_monitor.c.