#include "asterisk/channel.h"
#include "asterisk/optional_api.h"
Go to the source code of this file.
Data Structures | |
struct | ast_channel_monitor |
Defines | |
#define | X_JOIN 4 |
#define | X_REC_IN 1 |
#define | X_REC_OUT 2 |
Enumerations | |
enum | AST_MONITORING_STATE { AST_MONITOR_RUNNING, AST_MONITOR_PAUSED } |
Functions | |
int | ast_monitor_change_fname (struct ast_channel *chan, const char *fname_base, int need_lock) |
Change monitored filename of channel. | |
int | ast_monitor_pause (struct ast_channel *chan) |
Pause monitoring of channel. | |
void | ast_monitor_setjoinfiles (struct ast_channel *chan, int turnon) |
int | 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_monitor_stop (struct ast_channel *chan, int need_lock) |
Stop monitoring channel. | |
int | ast_monitor_unpause (struct ast_channel *chan) |
Unpause monitoring of channel. |
Definition in file monitor.h.
#define X_JOIN 4 |
#define X_REC_IN 1 |
Definition at line 35 of file monitor.h.
Referenced by __agent_start_monitoring(), ast_monitor_start(), start_monitor_action(), and start_monitor_exec().
#define X_REC_OUT 2 |
Definition at line 36 of file monitor.h.
Referenced by __agent_start_monitoring(), ast_monitor_start(), start_monitor_action(), and start_monitor_exec().
enum AST_MONITORING_STATE |
Definition at line 29 of file monitor.h.
00029 { 00030 AST_MONITOR_RUNNING, 00031 AST_MONITOR_PAUSED 00032 };
int 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 562 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, ast_channel::name, name, and UNLOCK_IF_NEEDED.
Referenced by change_monitor_action(), change_monitor_exec(), start_monitor_action(), and start_monitor_exec().
00563 { 00564 if (ast_strlen_zero(fname_base)) { 00565 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", chan->name); 00566 return -1; 00567 } 00568 00569 LOCK_IF_NEEDED(chan, need_lock); 00570 00571 if (chan->monitor) { 00572 int directory = strchr(fname_base, '/') ? 1 : 0; 00573 const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR; 00574 const char *absolute_suffix = *fname_base == '/' ? "" : "/"; 00575 char tmpstring[sizeof(chan->monitor->filename_base)] = ""; 00576 int i, fd[2] = { -1, -1 }, doexit = 0; 00577 00578 /* before continuing, see if we're trying to rename the file to itself... */ 00579 snprintf(tmpstring, sizeof(tmpstring), "%s%s%s", absolute, absolute_suffix, fname_base); 00580 00581 /* try creating the directory just in case it doesn't exist */ 00582 if (directory) { 00583 char *name = ast_strdupa(tmpstring); 00584 ast_mkdir(dirname(name), 0777); 00585 } 00586 00587 /*! 00588 * \note We cannot just compare filenames, due to symlinks, relative 00589 * paths, and other possible filesystem issues. We could use 00590 * realpath(3), but its use is discouraged. However, if we try to 00591 * create the same file from two different paths, the second will 00592 * fail, and so we have our notification that the filenames point to 00593 * the same path. 00594 * 00595 * Remember, also, that we're using the basename of the file (i.e. 00596 * the file without the format suffix), so it does not already exist 00597 * and we aren't interfering with the recording itself. 00598 */ 00599 ast_debug(2, "comparing tmpstring %s to filename_base %s\n", tmpstring, chan->monitor->filename_base); 00600 00601 if ((fd[0] = open(tmpstring, O_CREAT | O_WRONLY, 0644)) < 0 || 00602 (fd[1] = open(chan->monitor->filename_base, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) { 00603 if (fd[0] < 0) { 00604 ast_log(LOG_ERROR, "Unable to compare filenames: %s\n", strerror(errno)); 00605 } else { 00606 ast_debug(2, "No need to rename monitor filename to itself\n"); 00607 } 00608 doexit = 1; 00609 } 00610 00611 /* Cleanup temporary files */ 00612 for (i = 0; i < 2; i++) { 00613 if (fd[i] >= 0) { 00614 while (close(fd[i]) < 0 && errno == EINTR); 00615 } 00616 } 00617 unlink(tmpstring); 00618 /* if previous monitor file existed in a subdirectory, the directory will not be removed */ 00619 unlink(chan->monitor->filename_base); 00620 00621 if (doexit) { 00622 UNLOCK_IF_NEEDED(chan, need_lock); 00623 return 0; 00624 } 00625 00626 ast_copy_string(chan->monitor->filename_base, tmpstring, sizeof(chan->monitor->filename_base)); 00627 chan->monitor->filename_changed = 1; 00628 } else { 00629 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", chan->name, fname_base); 00630 } 00631 00632 UNLOCK_IF_NEEDED(chan, need_lock); 00633 00634 return 0; 00635 }
int ast_monitor_pause | ( | struct ast_channel * | chan | ) |
Pause monitoring of channel.
Definition at line 531 of file res_monitor.c.
References AST_MONITOR_PAUSED, and ast_monitor_set_state().
Referenced by do_pause_or_unpause(), and pause_monitor_exec().
00532 { 00533 return ast_monitor_set_state(chan, AST_MONITOR_PAUSED); 00534 }
void ast_monitor_setjoinfiles | ( | struct ast_channel * | chan, | |
int | turnon | |||
) |
Definition at line 863 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_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, ast_channel::monitor, monitor, monitorlock, name, ast_channel::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 /* 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_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, 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().
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 (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) { 00455 snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base); 00456 if (ast_fileexists(filename, NULL, NULL) > 0) { 00457 ast_filedelete(filename, NULL); 00458 } 00459 ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format); 00460 } else { 00461 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename); 00462 } 00463 00464 if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) { 00465 snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base); 00466 if (ast_fileexists(filename, NULL, NULL) > 0) { 00467 ast_filedelete(filename, NULL); 00468 } 00469 ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format); 00470 } else { 00471 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename); 00472 } 00473 } 00474 00475 if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) { 00476 char tmp[1024]; 00477 char tmp2[1024]; 00478 const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format; 00479 char *fname_base = chan->monitor->filename_base; 00480 const char *execute, *execute_args; 00481 /* at this point, fname_base really is the full path */ 00482 00483 /* Set the execute application */ 00484 execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC"); 00485 if (ast_strlen_zero(execute)) { 00486 #ifdef HAVE_SOXMIX 00487 execute = "nice -n 19 soxmix"; 00488 #else 00489 execute = "nice -n 19 sox -m"; 00490 #endif 00491 format = get_soxmix_format(format); 00492 delfiles = 1; 00493 } 00494 execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS"); 00495 if (ast_strlen_zero(execute_args)) { 00496 execute_args = ""; 00497 } 00498 00499 snprintf(tmp, sizeof(tmp), "%s \"%s-in.%s\" \"%s-out.%s\" \"%s.%s\" %s &", 00500 execute, fname_base, format, fname_base, format, fname_base, format,execute_args); 00501 if (delfiles) { 00502 snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s-\"* ) &",tmp, fname_base); /* remove legs when done mixing */ 00503 ast_copy_string(tmp, tmp2, sizeof(tmp)); 00504 } 00505 ast_debug(1,"monitor executing %s\n",tmp); 00506 if (ast_safe_system(tmp) == -1) 00507 ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp); 00508 } 00509 00510 ast_free(chan->monitor->format); 00511 ast_free(chan->monitor); 00512 chan->monitor = NULL; 00513 00514 ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStop", 00515 "Channel: %s\r\n" 00516 "Uniqueid: %s\r\n", 00517 chan->name, 00518 chan->uniqueid 00519 ); 00520 pbx_builtin_setvar_helper(chan, "MONITORED", NULL); 00521 } 00522 pbx_builtin_setvar_helper(chan, "AUTO_MONITOR", NULL); 00523 00524 UNLOCK_IF_NEEDED(chan, need_lock); 00525 00526 return 0; 00527 }
int ast_monitor_unpause | ( | struct ast_channel * | chan | ) |
Unpause monitoring of channel.
Definition at line 537 of file res_monitor.c.
References AST_MONITOR_RUNNING, and ast_monitor_set_state().
Referenced by do_pause_or_unpause(), and unpause_monitor_exec().
00538 { 00539 return ast_monitor_set_state(chan, AST_MONITOR_RUNNING); 00540 }