MixMonitor() - Record a call and mix the audio during the recording. More...
#include "asterisk.h"
#include "asterisk/paths.h"
#include "asterisk/file.h"
#include "asterisk/audiohook.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/channel.h"
#include "asterisk/autochan.h"
#include "asterisk/manager.h"
#include "asterisk/test.h"
Go to the source code of this file.
Data Structures | |
struct | mixmonitor |
struct | mixmonitor_ds |
Defines | |
#define | get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0 |
#define | SAMPLES_PER_FRAME 160 |
Enumerations | |
enum | mixmonitor_args { OPT_ARG_READVOLUME = 0, OPT_ARG_WRITEVOLUME, OPT_ARG_VOLUME, OPT_ARG_ARRAY_SIZE } |
enum | mixmonitor_flags { MUXFLAG_APPEND = (1 << 1), MUXFLAG_BRIDGED = (1 << 2), MUXFLAG_VOLUME = (1 << 3), MUXFLAG_READVOLUME = (1 << 4), MUXFLAG_WRITEVOLUME = (1 << 5) } |
Functions | |
AST_APP_OPTIONS (mixmonitor_opts,{AST_APP_OPTION('a', MUXFLAG_APPEND), AST_APP_OPTION('b', MUXFLAG_BRIDGED), AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME), AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME), AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),}) | |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Mixed Audio Monitoring Application") | |
static void | destroy_monitor_audiohook (struct mixmonitor *mixmonitor) |
static char * | handle_cli_mixmonitor (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static void | launch_monitor_thread (struct ast_channel *chan, const char *filename, unsigned int flags, int readvol, int writevol, const char *post_process) |
static int | load_module (void) |
static int | manager_mute_mixmonitor (struct mansession *s, const struct message *m) |
Mute / unmute a MixMonitor channel. | |
static void | mixmonitor_ds_close_fs (struct mixmonitor_ds *mixmonitor_ds) |
static void | mixmonitor_ds_destroy (void *data) |
static int | mixmonitor_exec (struct ast_channel *chan, const char *data) |
static void | mixmonitor_free (struct mixmonitor *mixmonitor) |
static void * | mixmonitor_thread (void *obj) |
static int | setup_mixmonitor_ds (struct mixmonitor *mixmonitor, struct ast_channel *chan) |
static int | startmon (struct ast_channel *chan, struct ast_audiohook *audiohook) |
static int | stop_mixmonitor_exec (struct ast_channel *chan, const char *data) |
static int | unload_module (void) |
Variables | |
static const char *const | app = "MixMonitor" |
static struct ast_cli_entry | cli_mixmonitor [] |
static struct ast_datastore_info | mixmonitor_ds_info |
static const char *const | mixmonitor_spy_type = "MixMonitor" |
static const char *const | stop_app = "StopMixMonitor" |
MixMonitor() - Record a call and mix the audio during the recording.
Definition in file app_mixmonitor.c.
#define get_volfactor | ( | x | ) | x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0 |
Definition at line 164 of file app_mixmonitor.c.
Referenced by mixmonitor_exec().
#define SAMPLES_PER_FRAME 160 |
Definition at line 277 of file app_mixmonitor.c.
Referenced by mixmonitor_thread().
enum mixmonitor_args |
Definition at line 190 of file app_mixmonitor.c.
00190 { 00191 OPT_ARG_READVOLUME = 0, 00192 OPT_ARG_WRITEVOLUME, 00193 OPT_ARG_VOLUME, 00194 OPT_ARG_ARRAY_SIZE, 00195 };
enum mixmonitor_flags |
Definition at line 182 of file app_mixmonitor.c.
00182 { 00183 MUXFLAG_APPEND = (1 << 1), 00184 MUXFLAG_BRIDGED = (1 << 2), 00185 MUXFLAG_VOLUME = (1 << 3), 00186 MUXFLAG_READVOLUME = (1 << 4), 00187 MUXFLAG_WRITEVOLUME = (1 << 5), 00188 };
AST_APP_OPTIONS | ( | mixmonitor_opts | ) |
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"Mixed Audio Monitoring Application" | ||||
) |
static void destroy_monitor_audiohook | ( | struct mixmonitor * | mixmonitor | ) | [static] |
Definition at line 247 of file app_mixmonitor.c.
References ast_audiohook_destroy(), ast_audiohook_detach(), ast_audiohook_lock, ast_audiohook_unlock, ast_mutex_lock, ast_mutex_unlock, mixmonitor::audiohook, mixmonitor_ds::audiohook, mixmonitor_ds::lock, and mixmonitor::mixmonitor_ds.
Referenced by mixmonitor_thread().
00248 { 00249 if (mixmonitor->mixmonitor_ds) { 00250 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00251 mixmonitor->mixmonitor_ds->audiohook = NULL; 00252 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00253 } 00254 /* kill the audiohook.*/ 00255 ast_audiohook_lock(&mixmonitor->audiohook); 00256 ast_audiohook_detach(&mixmonitor->audiohook); 00257 ast_audiohook_unlock(&mixmonitor->audiohook); 00258 ast_audiohook_destroy(&mixmonitor->audiohook); 00259 }
static char* handle_cli_mixmonitor | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 612 of file app_mixmonitor.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_audiohook_detach_source(), ast_channel_get_by_name_prefix(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_cli(), ast_complete_channels(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, ast_cli_args::line, mixmonitor_exec(), ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.
00613 { 00614 struct ast_channel *chan; 00615 00616 switch (cmd) { 00617 case CLI_INIT: 00618 e->command = "mixmonitor {start|stop}"; 00619 e->usage = 00620 "Usage: mixmonitor <start|stop> <chan_name> [args]\n" 00621 " The optional arguments are passed to the MixMonitor\n" 00622 " application when the 'start' command is used.\n"; 00623 return NULL; 00624 case CLI_GENERATE: 00625 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2); 00626 } 00627 00628 if (a->argc < 3) 00629 return CLI_SHOWUSAGE; 00630 00631 if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) { 00632 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]); 00633 /* Technically this is a failure, but we don't want 2 errors printing out */ 00634 return CLI_SUCCESS; 00635 } 00636 00637 ast_channel_lock(chan); 00638 00639 if (!strcasecmp(a->argv[1], "start")) { 00640 mixmonitor_exec(chan, a->argv[3]); 00641 ast_channel_unlock(chan); 00642 } else { 00643 ast_channel_unlock(chan); 00644 ast_audiohook_detach_source(chan, mixmonitor_spy_type); 00645 } 00646 00647 chan = ast_channel_unref(chan); 00648 00649 return CLI_SUCCESS; 00650 }
static void launch_monitor_thread | ( | struct ast_channel * | chan, | |
const char * | filename, | |||
unsigned int | flags, | |||
int | readvol, | |||
int | writevol, | |||
const char * | post_process | |||
) | [static] |
Definition at line 417 of file app_mixmonitor.c.
References ast_audiohook_destroy(), ast_audiohook_init(), AST_AUDIOHOOK_TRIGGER_SYNC, AST_AUDIOHOOK_TYPE_SPY, ast_autochan_destroy(), ast_autochan_setup(), ast_calloc, ast_log(), ast_pthread_create_detached_background, ast_set_flag, ast_strdupa, ast_strlen_zero(), mixmonitor::audiohook, mixmonitor::autochan, mixmonitor::filename, mixmonitor::flags, len(), LOG_WARNING, mixmonitor_free(), mixmonitor_thread(), mixmonitor::name, ast_audiohook::options, pbx_substitute_variables_helper(), mixmonitor::post_process, ast_audiohook_options::read_volume, setup_mixmonitor_ds(), startmon(), thread, and ast_audiohook_options::write_volume.
Referenced by mixmonitor_exec().
00419 { 00420 pthread_t thread; 00421 struct mixmonitor *mixmonitor; 00422 char postprocess2[1024] = ""; 00423 size_t len; 00424 00425 len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2; 00426 00427 postprocess2[0] = 0; 00428 /* If a post process system command is given attach it to the structure */ 00429 if (!ast_strlen_zero(post_process)) { 00430 char *p1, *p2; 00431 00432 p1 = ast_strdupa(post_process); 00433 for (p2 = p1; *p2 ; p2++) { 00434 if (*p2 == '^' && *(p2+1) == '{') { 00435 *p2 = '$'; 00436 } 00437 } 00438 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1); 00439 if (!ast_strlen_zero(postprocess2)) 00440 len += strlen(postprocess2) + 1; 00441 } 00442 00443 /* Pre-allocate mixmonitor structure and spy */ 00444 if (!(mixmonitor = ast_calloc(1, len))) { 00445 return; 00446 } 00447 00448 /* Setup the actual spy before creating our thread */ 00449 if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) { 00450 mixmonitor_free(mixmonitor); 00451 return; 00452 } 00453 00454 /* Copy over flags and channel name */ 00455 mixmonitor->flags = flags; 00456 if (!(mixmonitor->autochan = ast_autochan_setup(chan))) { 00457 mixmonitor_free(mixmonitor); 00458 return; 00459 } 00460 00461 if (setup_mixmonitor_ds(mixmonitor, chan)) { 00462 ast_autochan_destroy(mixmonitor->autochan); 00463 mixmonitor_free(mixmonitor); 00464 return; 00465 } 00466 mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor); 00467 strcpy(mixmonitor->name, chan->name); 00468 if (!ast_strlen_zero(postprocess2)) { 00469 mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2; 00470 strcpy(mixmonitor->post_process, postprocess2); 00471 } 00472 00473 mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1; 00474 strcpy(mixmonitor->filename, filename); 00475 00476 ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC); 00477 00478 if (readvol) 00479 mixmonitor->audiohook.options.read_volume = readvol; 00480 if (writevol) 00481 mixmonitor->audiohook.options.write_volume = writevol; 00482 00483 if (startmon(chan, &mixmonitor->audiohook)) { 00484 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n", 00485 mixmonitor_spy_type, chan->name); 00486 ast_audiohook_destroy(&mixmonitor->audiohook); 00487 mixmonitor_free(mixmonitor); 00488 return; 00489 } 00490 00491 ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor); 00492 }
static int load_module | ( | void | ) | [static] |
Definition at line 735 of file app_mixmonitor.c.
References ARRAY_LEN, ast_cli_register_multiple(), ast_manager_register_xml, ast_register_application_xml, manager_mute_mixmonitor(), mixmonitor_exec(), and stop_mixmonitor_exec().
00736 { 00737 int res; 00738 00739 ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor)); 00740 res = ast_register_application_xml(app, mixmonitor_exec); 00741 res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec); 00742 res |= ast_manager_register_xml("MixMonitorMute", 0, manager_mute_mixmonitor); 00743 00744 return res; 00745 }
static int manager_mute_mixmonitor | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Mute / unmute a MixMonitor channel.
Definition at line 653 of file app_mixmonitor.c.
References AMI_SUCCESS, AST_AUDIOHOOK_MUTE_READ, AST_AUDIOHOOK_MUTE_WRITE, ast_audiohook_set_mute(), ast_channel_get_by_name(), ast_channel_unref, ast_false(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_error(), and name.
Referenced by load_module().
00654 { 00655 struct ast_channel *c = NULL; 00656 00657 const char *name = astman_get_header(m, "Channel"); 00658 const char *id = astman_get_header(m, "ActionID"); 00659 const char *state = astman_get_header(m, "State"); 00660 const char *direction = astman_get_header(m,"Direction"); 00661 00662 int clearmute = 1; 00663 00664 enum ast_audiohook_flags flag; 00665 00666 if (ast_strlen_zero(direction)) { 00667 astman_send_error(s, m, "No direction specified. Must be read, write or both"); 00668 return AMI_SUCCESS; 00669 } 00670 00671 if (!strcasecmp(direction, "read")) { 00672 flag = AST_AUDIOHOOK_MUTE_READ; 00673 } else if (!strcasecmp(direction, "write")) { 00674 flag = AST_AUDIOHOOK_MUTE_WRITE; 00675 } else if (!strcasecmp(direction, "both")) { 00676 flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE; 00677 } else { 00678 astman_send_error(s, m, "Invalid direction specified. Must be read, write or both"); 00679 return AMI_SUCCESS; 00680 } 00681 00682 if (ast_strlen_zero(name)) { 00683 astman_send_error(s, m, "No channel specified"); 00684 return AMI_SUCCESS; 00685 } 00686 00687 if (ast_strlen_zero(state)) { 00688 astman_send_error(s, m, "No state specified"); 00689 return AMI_SUCCESS; 00690 } 00691 00692 clearmute = ast_false(state); 00693 c = ast_channel_get_by_name(name); 00694 00695 if (!c) { 00696 astman_send_error(s, m, "No such channel"); 00697 return AMI_SUCCESS; 00698 } 00699 00700 if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) { 00701 c = ast_channel_unref(c); 00702 astman_send_error(s, m, "Cannot set mute flag"); 00703 return AMI_SUCCESS; 00704 } 00705 00706 astman_append(s, "Response: Success\r\n"); 00707 00708 if (!ast_strlen_zero(id)) { 00709 astman_append(s, "ActionID: %s\r\n", id); 00710 } 00711 00712 astman_append(s, "\r\n"); 00713 00714 c = ast_channel_unref(c); 00715 00716 return AMI_SUCCESS; 00717 }
static void mixmonitor_ds_close_fs | ( | struct mixmonitor_ds * | mixmonitor_ds | ) | [static] |
Definition at line 221 of file app_mixmonitor.c.
References ast_closestream(), ast_verb, mixmonitor_ds::fs, and mixmonitor_ds::fs_quit.
Referenced by mixmonitor_thread(), and stop_mixmonitor_exec().
static void mixmonitor_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 231 of file app_mixmonitor.c.
References ast_cond_signal, ast_mutex_lock, ast_mutex_unlock, mixmonitor_ds::audiohook, mixmonitor_ds::destruction_condition, mixmonitor_ds::destruction_ok, and mixmonitor_ds::lock.
00232 { 00233 struct mixmonitor_ds *mixmonitor_ds = data; 00234 00235 ast_mutex_lock(&mixmonitor_ds->lock); 00236 mixmonitor_ds->audiohook = NULL; 00237 mixmonitor_ds->destruction_ok = 1; 00238 ast_cond_signal(&mixmonitor_ds->destruction_condition); 00239 ast_mutex_unlock(&mixmonitor_ds->lock); 00240 }
static int mixmonitor_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 494 of file app_mixmonitor.c.
References args, ast_alloca, AST_APP_ARG, ast_app_parse_options(), ast_config_AST_MONITOR_DIR, AST_DECLARE_APP_ARGS, ast_log(), ast_mkdir(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_flags::flags, get_volfactor, launch_monitor_thread(), LOG_NOTICE, LOG_WARNING, MUXFLAG_READVOLUME, MUXFLAG_VOLUME, MUXFLAG_WRITEVOLUME, OPT_ARG_ARRAY_SIZE, OPT_ARG_READVOLUME, OPT_ARG_VOLUME, OPT_ARG_WRITEVOLUME, parse(), and pbx_builtin_setvar_helper().
Referenced by handle_cli_mixmonitor(), and load_module().
00495 { 00496 int x, readvol = 0, writevol = 0; 00497 struct ast_flags flags = {0}; 00498 char *parse, *tmp, *slash; 00499 AST_DECLARE_APP_ARGS(args, 00500 AST_APP_ARG(filename); 00501 AST_APP_ARG(options); 00502 AST_APP_ARG(post_process); 00503 ); 00504 00505 if (ast_strlen_zero(data)) { 00506 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00507 return -1; 00508 } 00509 00510 parse = ast_strdupa(data); 00511 00512 AST_STANDARD_APP_ARGS(args, parse); 00513 00514 if (ast_strlen_zero(args.filename)) { 00515 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00516 return -1; 00517 } 00518 00519 if (args.options) { 00520 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, }; 00521 00522 ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options); 00523 00524 if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) { 00525 if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) { 00526 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n"); 00527 } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00528 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]); 00529 } else { 00530 readvol = get_volfactor(x); 00531 } 00532 } 00533 00534 if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) { 00535 if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) { 00536 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n"); 00537 } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00538 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]); 00539 } else { 00540 writevol = get_volfactor(x); 00541 } 00542 } 00543 00544 if (ast_test_flag(&flags, MUXFLAG_VOLUME)) { 00545 if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) { 00546 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n"); 00547 } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00548 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]); 00549 } else { 00550 readvol = writevol = get_volfactor(x); 00551 } 00552 } 00553 } 00554 00555 /* if not provided an absolute path, use the system-configured monitoring directory */ 00556 if (args.filename[0] != '/') { 00557 char *build; 00558 00559 build = ast_alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3); 00560 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename); 00561 args.filename = build; 00562 } 00563 00564 tmp = ast_strdupa(args.filename); 00565 if ((slash = strrchr(tmp, '/'))) 00566 *slash = '\0'; 00567 ast_mkdir(tmp, 0777); 00568 00569 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename); 00570 launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process); 00571 00572 return 0; 00573 }
static void mixmonitor_free | ( | struct mixmonitor * | mixmonitor | ) | [static] |
Definition at line 279 of file app_mixmonitor.c.
References ast_cond_destroy, ast_free, ast_mutex_destroy, mixmonitor_ds::destruction_condition, mixmonitor_ds::lock, and mixmonitor::mixmonitor_ds.
Referenced by launch_monitor_thread(), and mixmonitor_thread().
00280 { 00281 if (mixmonitor) { 00282 if (mixmonitor->mixmonitor_ds) { 00283 ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock); 00284 ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition); 00285 ast_free(mixmonitor->mixmonitor_ds); 00286 } 00287 ast_free(mixmonitor); 00288 } 00289 }
static void* mixmonitor_thread | ( | void * | obj | ) | [static] |
Definition at line 290 of file app_mixmonitor.c.
References AST_AUDIOHOOK_DIRECTION_BOTH, ast_audiohook_lock, ast_audiohook_read_frame(), AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_trigger_wait(), ast_audiohook_unlock, ast_autochan_destroy(), ast_bridged_channel(), ast_cond_wait, AST_FORMAT_SLINEAR, ast_frame_free(), AST_LIST_NEXT, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_safe_system(), ast_test_flag, ast_test_suite_event_notify, ast_verb, ast_writefile(), ast_writestream(), mixmonitor::audiohook, mixmonitor::autochan, ast_autochan::chan, destroy_monitor_audiohook(), mixmonitor_ds::destruction_condition, mixmonitor_ds::destruction_ok, ext, mixmonitor::filename, mixmonitor_ds::fs, mixmonitor_ds::fs_quit, mixmonitor_ds::lock, LOG_ERROR, mixmonitor::mixmonitor_ds, mixmonitor_ds_close_fs(), mixmonitor_free(), MUXFLAG_APPEND, MUXFLAG_BRIDGED, mixmonitor::name, mixmonitor::post_process, SAMPLES_PER_FRAME, and ast_audiohook::status.
Referenced by launch_monitor_thread().
00291 { 00292 struct mixmonitor *mixmonitor = obj; 00293 struct ast_filestream **fs = NULL; 00294 unsigned int oflags; 00295 char *ext; 00296 char *last_slash; 00297 int errflag = 0; 00298 00299 ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name); 00300 00301 fs = &mixmonitor->mixmonitor_ds->fs; 00302 00303 /* The audiohook must enter and exit the loop locked */ 00304 ast_audiohook_lock(&mixmonitor->audiohook); 00305 while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) { 00306 struct ast_frame *fr = NULL; 00307 00308 if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) { 00309 ast_audiohook_trigger_wait(&mixmonitor->audiohook); 00310 00311 if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { 00312 break; 00313 } 00314 continue; 00315 } 00316 00317 /* audiohook lock is not required for the next block. 00318 * Unlock it, but remember to lock it before looping or exiting */ 00319 ast_audiohook_unlock(&mixmonitor->audiohook); 00320 00321 if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) { 00322 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00323 /* Initialize the file if not already done so */ 00324 if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) { 00325 oflags = O_CREAT | O_WRONLY; 00326 oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC; 00327 00328 last_slash = strrchr(mixmonitor->filename, '/'); 00329 if ((ext = strrchr(mixmonitor->filename, '.')) && (ext > last_slash)) 00330 *(ext++) = '\0'; 00331 else 00332 ext = "raw"; 00333 00334 if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0666))) { 00335 ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext); 00336 errflag = 1; 00337 } 00338 } 00339 00340 /* Write out the frame(s) */ 00341 if (*fs) { 00342 struct ast_frame *cur; 00343 00344 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) { 00345 ast_writestream(*fs, cur); 00346 } 00347 } 00348 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00349 } 00350 /* All done! free it. */ 00351 ast_frame_free(fr, 0); 00352 00353 ast_audiohook_lock(&mixmonitor->audiohook); 00354 } 00355 00356 /* Test Event */ 00357 ast_test_suite_event_notify("MIXMONITOR_END", "Channel: %s\r\n" 00358 "File: %s\r\n", 00359 mixmonitor->autochan->chan->name, 00360 mixmonitor->filename); 00361 00362 ast_audiohook_unlock(&mixmonitor->audiohook); 00363 00364 ast_autochan_destroy(mixmonitor->autochan); 00365 00366 /* Datastore cleanup. close the filestream and wait for ds destruction */ 00367 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00368 mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds); 00369 if (!mixmonitor->mixmonitor_ds->destruction_ok) { 00370 ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock); 00371 } 00372 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00373 00374 /* kill the audiohook */ 00375 destroy_monitor_audiohook(mixmonitor); 00376 00377 if (mixmonitor->post_process) { 00378 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process); 00379 ast_safe_system(mixmonitor->post_process); 00380 } 00381 00382 ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name); 00383 mixmonitor_free(mixmonitor); 00384 return NULL; 00385 }
static int setup_mixmonitor_ds | ( | struct mixmonitor * | mixmonitor, | |
struct ast_channel * | chan | |||
) | [static] |
Definition at line 387 of file app_mixmonitor.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy, ast_cond_init, ast_datastore_alloc, ast_free, ast_mutex_destroy, ast_mutex_init, mixmonitor::audiohook, mixmonitor_ds::audiohook, ast_datastore::data, mixmonitor_ds::destruction_condition, mixmonitor_ds::lock, and mixmonitor::mixmonitor_ds.
Referenced by launch_monitor_thread().
00388 { 00389 struct ast_datastore *datastore = NULL; 00390 struct mixmonitor_ds *mixmonitor_ds; 00391 00392 if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) { 00393 return -1; 00394 } 00395 00396 ast_mutex_init(&mixmonitor_ds->lock); 00397 ast_cond_init(&mixmonitor_ds->destruction_condition, NULL); 00398 00399 if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) { 00400 ast_mutex_destroy(&mixmonitor_ds->lock); 00401 ast_cond_destroy(&mixmonitor_ds->destruction_condition); 00402 ast_free(mixmonitor_ds); 00403 return -1; 00404 } 00405 00406 mixmonitor_ds->audiohook = &mixmonitor->audiohook; 00407 datastore->data = mixmonitor_ds; 00408 00409 ast_channel_lock(chan); 00410 ast_channel_datastore_add(chan, datastore); 00411 ast_channel_unlock(chan); 00412 00413 mixmonitor->mixmonitor_ds = mixmonitor_ds; 00414 return 0; 00415 }
static int startmon | ( | struct ast_channel * | chan, | |
struct ast_audiohook * | audiohook | |||
) | [static] |
Definition at line 261 of file app_mixmonitor.c.
References ast_audiohook_attach(), ast_bridged_channel(), AST_FLAG_NBRIDGE, ast_softhangup(), AST_SOFTHANGUP_UNBRIDGE, and ast_test_flag.
Referenced by launch_monitor_thread().
00262 { 00263 struct ast_channel *peer = NULL; 00264 int res = 0; 00265 00266 if (!chan) 00267 return -1; 00268 00269 ast_audiohook_attach(chan, audiohook); 00270 00271 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) 00272 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00273 00274 return res; 00275 }
static int stop_mixmonitor_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 575 of file app_mixmonitor.c.
References ast_audiohook_detach_source(), ast_audiohook_lock, ast_audiohook_unlock, ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_cond_signal, ast_datastore_free(), ast_mutex_lock, ast_mutex_unlock, mixmonitor_ds::audiohook, ast_datastore::data, mixmonitor_ds::lock, mixmonitor_ds_close_fs(), and ast_audiohook::trigger.
Referenced by load_module().
00576 { 00577 struct ast_datastore *datastore = NULL; 00578 00579 ast_channel_lock(chan); 00580 ast_audiohook_detach_source(chan, mixmonitor_spy_type); 00581 if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) { 00582 struct mixmonitor_ds *mixmonitor_ds = datastore->data; 00583 00584 ast_mutex_lock(&mixmonitor_ds->lock); 00585 00586 /* closing the filestream here guarantees the file is avaliable to the dialplan 00587 * after calling StopMixMonitor */ 00588 mixmonitor_ds_close_fs(mixmonitor_ds); 00589 00590 /* The mixmonitor thread may be waiting on the audiohook trigger. 00591 * In order to exit from the mixmonitor loop before waiting on channel 00592 * destruction, poke the audiohook trigger. */ 00593 if (mixmonitor_ds->audiohook) { 00594 ast_audiohook_lock(mixmonitor_ds->audiohook); 00595 ast_cond_signal(&mixmonitor_ds->audiohook->trigger); 00596 ast_audiohook_unlock(mixmonitor_ds->audiohook); 00597 mixmonitor_ds->audiohook = NULL; 00598 } 00599 00600 ast_mutex_unlock(&mixmonitor_ds->lock); 00601 00602 /* Remove the datastore so the monitor thread can exit */ 00603 if (!ast_channel_datastore_remove(chan, datastore)) { 00604 ast_datastore_free(datastore); 00605 } 00606 } 00607 ast_channel_unlock(chan); 00608 00609 return 0; 00610 }
static int unload_module | ( | void | ) | [static] |
Definition at line 723 of file app_mixmonitor.c.
References ARRAY_LEN, ast_cli_unregister_multiple(), ast_manager_unregister(), and ast_unregister_application().
00724 { 00725 int res; 00726 00727 ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor)); 00728 res = ast_unregister_application(stop_app); 00729 res |= ast_unregister_application(app); 00730 res |= ast_manager_unregister("MixMonitorMute"); 00731 00732 return res; 00733 }
const char* const app = "MixMonitor" [static] |
Definition at line 166 of file app_mixmonitor.c.
struct ast_cli_entry cli_mixmonitor[] [static] |
{ }
Definition at line 719 of file app_mixmonitor.c.
struct ast_datastore_info mixmonitor_ds_info [static] |
{ .type = "mixmonitor", .destroy = mixmonitor_ds_destroy, }
Definition at line 242 of file app_mixmonitor.c.
const char* const mixmonitor_spy_type = "MixMonitor" [static] |
Definition at line 170 of file app_mixmonitor.c.
Referenced by builtin_automixmonitor().
const char* const stop_app = "StopMixMonitor" [static] |
Definition at line 168 of file app_mixmonitor.c.