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_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 873 of file res_monitor.c.
00874 { 00875 MONITOR_ACTION_PAUSE, 00876 MONITOR_ACTION_UNPAUSE 00877 };
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.
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 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.
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().
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, 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-%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 /* 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.
chan | ||
need_lock | Stop the recording, close any open streams, mix in/out channels if required |
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.
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.
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().
static int load_module | ( | void | ) | [static] |
Definition at line 917 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().
00918 { 00919 ast_register_application_xml("Monitor", start_monitor_exec); 00920 ast_register_application_xml("StopMonitor", stop_monitor_exec); 00921 ast_register_application_xml("ChangeMonitor", change_monitor_exec); 00922 ast_register_application_xml("PauseMonitor", pause_monitor_exec); 00923 ast_register_application_xml("UnpauseMonitor", unpause_monitor_exec); 00924 ast_manager_register_xml("Monitor", EVENT_FLAG_CALL, start_monitor_action); 00925 ast_manager_register_xml("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action); 00926 ast_manager_register_xml("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action); 00927 ast_manager_register_xml("PauseMonitor", EVENT_FLAG_CALL, pause_monitor_action); 00928 ast_manager_register_xml("UnpauseMonitor", EVENT_FLAG_CALL, unpause_monitor_action); 00929 00930 return AST_MODULE_LOAD_SUCCESS; 00931 }
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.
chan | ||
data | arguments passed fname|options |
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.
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 }
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.
struct ast_module_info* ast_module_info = &__mod_info [static] |
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.