#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"
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 | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
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 struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Mixed Audio Monitoring Application" , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } |
static const char *const | app = "MixMonitor" |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_cli_entry | cli_mixmonitor [] |
static struct ast_datastore_info | mixmonitor_ds_info |
static struct ast_app_option | mixmonitor_opts [128] = { [ 'a' ] = { .flag = MUXFLAG_APPEND }, [ 'b' ] = { .flag = MUXFLAG_BRIDGED }, [ 'v' ] = { .flag = MUXFLAG_READVOLUME , .arg_index = OPT_ARG_READVOLUME + 1 }, [ 'V' ] = { .flag = MUXFLAG_WRITEVOLUME , .arg_index = OPT_ARG_WRITEVOLUME + 1 }, [ 'W' ] = { .flag = MUXFLAG_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 },} |
static const char *const | mixmonitor_spy_type = "MixMonitor" |
static const char *const | stop_app = "StopMixMonitor" |
Kevin P. Fleming <kpfleming@digium.com>
Definition in file app_mixmonitor.c.
#define get_volfactor | ( | x | ) | x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0 |
#define SAMPLES_PER_FRAME 160 |
enum mixmonitor_args |
Definition at line 177 of file app_mixmonitor.c.
00177 { 00178 OPT_ARG_READVOLUME = 0, 00179 OPT_ARG_WRITEVOLUME, 00180 OPT_ARG_VOLUME, 00181 OPT_ARG_ARRAY_SIZE, 00182 };
enum mixmonitor_flags |
Definition at line 169 of file app_mixmonitor.c.
00169 { 00170 MUXFLAG_APPEND = (1 << 1), 00171 MUXFLAG_BRIDGED = (1 << 2), 00172 MUXFLAG_VOLUME = (1 << 3), 00173 MUXFLAG_READVOLUME = (1 << 4), 00174 MUXFLAG_WRITEVOLUME = (1 << 5), 00175 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 725 of file app_mixmonitor.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 725 of file app_mixmonitor.c.
static void destroy_monitor_audiohook | ( | struct mixmonitor * | mixmonitor | ) | [static] |
Definition at line 234 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().
00235 { 00236 if (mixmonitor->mixmonitor_ds) { 00237 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00238 mixmonitor->mixmonitor_ds->audiohook = NULL; 00239 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00240 } 00241 /* kill the audiohook.*/ 00242 ast_audiohook_lock(&mixmonitor->audiohook); 00243 ast_audiohook_detach(&mixmonitor->audiohook); 00244 ast_audiohook_unlock(&mixmonitor->audiohook); 00245 ast_audiohook_destroy(&mixmonitor->audiohook); 00246 }
static char* handle_cli_mixmonitor | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 590 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.
00591 { 00592 struct ast_channel *chan; 00593 00594 switch (cmd) { 00595 case CLI_INIT: 00596 e->command = "mixmonitor {start|stop}"; 00597 e->usage = 00598 "Usage: mixmonitor <start|stop> <chan_name> [args]\n" 00599 " The optional arguments are passed to the MixMonitor\n" 00600 " application when the 'start' command is used.\n"; 00601 return NULL; 00602 case CLI_GENERATE: 00603 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2); 00604 } 00605 00606 if (a->argc < 3) 00607 return CLI_SHOWUSAGE; 00608 00609 if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) { 00610 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]); 00611 /* Technically this is a failure, but we don't want 2 errors printing out */ 00612 return CLI_SUCCESS; 00613 } 00614 00615 ast_channel_lock(chan); 00616 00617 if (!strcasecmp(a->argv[1], "start")) { 00618 mixmonitor_exec(chan, a->argv[3]); 00619 ast_channel_unlock(chan); 00620 } else { 00621 ast_channel_unlock(chan); 00622 ast_audiohook_detach_source(chan, mixmonitor_spy_type); 00623 } 00624 00625 chan = ast_channel_unref(chan); 00626 00627 return CLI_SUCCESS; 00628 }
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 395 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::flags, len(), LOG_WARNING, mixmonitor_free(), mixmonitor_thread(), mixmonitor::name, ast_channel::name, pbx_substitute_variables_helper(), setup_mixmonitor_ds(), startmon(), and thread.
Referenced by mixmonitor_exec().
00397 { 00398 pthread_t thread; 00399 struct mixmonitor *mixmonitor; 00400 char postprocess2[1024] = ""; 00401 size_t len; 00402 00403 len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2; 00404 00405 postprocess2[0] = 0; 00406 /* If a post process system command is given attach it to the structure */ 00407 if (!ast_strlen_zero(post_process)) { 00408 char *p1, *p2; 00409 00410 p1 = ast_strdupa(post_process); 00411 for (p2 = p1; *p2 ; p2++) { 00412 if (*p2 == '^' && *(p2+1) == '{') { 00413 *p2 = '$'; 00414 } 00415 } 00416 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1); 00417 if (!ast_strlen_zero(postprocess2)) 00418 len += strlen(postprocess2) + 1; 00419 } 00420 00421 /* Pre-allocate mixmonitor structure and spy */ 00422 if (!(mixmonitor = ast_calloc(1, len))) { 00423 return; 00424 } 00425 00426 /* Setup the actual spy before creating our thread */ 00427 if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) { 00428 mixmonitor_free(mixmonitor); 00429 return; 00430 } 00431 00432 /* Copy over flags and channel name */ 00433 mixmonitor->flags = flags; 00434 if (!(mixmonitor->autochan = ast_autochan_setup(chan))) { 00435 mixmonitor_free(mixmonitor); 00436 return; 00437 } 00438 00439 if (setup_mixmonitor_ds(mixmonitor, chan)) { 00440 ast_autochan_destroy(mixmonitor->autochan); 00441 mixmonitor_free(mixmonitor); 00442 return; 00443 } 00444 mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor); 00445 strcpy(mixmonitor->name, chan->name); 00446 if (!ast_strlen_zero(postprocess2)) { 00447 mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2; 00448 strcpy(mixmonitor->post_process, postprocess2); 00449 } 00450 00451 mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1; 00452 strcpy(mixmonitor->filename, filename); 00453 00454 ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC); 00455 00456 if (readvol) 00457 mixmonitor->audiohook.options.read_volume = readvol; 00458 if (writevol) 00459 mixmonitor->audiohook.options.write_volume = writevol; 00460 00461 if (startmon(chan, &mixmonitor->audiohook)) { 00462 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n", 00463 mixmonitor_spy_type, chan->name); 00464 ast_audiohook_destroy(&mixmonitor->audiohook); 00465 mixmonitor_free(mixmonitor); 00466 return; 00467 } 00468 00469 ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor); 00470 }
static int load_module | ( | void | ) | [static] |
Definition at line 713 of file app_mixmonitor.c.
References ARRAY_LEN, ast_cli_register_multiple(), ast_manager_register_xml, ast_register_application_xml, cli_mixmonitor, manager_mute_mixmonitor(), mixmonitor_exec(), and stop_mixmonitor_exec().
00714 { 00715 int res; 00716 00717 ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor)); 00718 res = ast_register_application_xml(app, mixmonitor_exec); 00719 res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec); 00720 res |= ast_manager_register_xml("MixMonitorMute", 0, manager_mute_mixmonitor); 00721 00722 return res; 00723 }
static int manager_mute_mixmonitor | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Mute / unmute a MixMonitor channel.
Definition at line 631 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().
00632 { 00633 struct ast_channel *c = NULL; 00634 00635 const char *name = astman_get_header(m, "Channel"); 00636 const char *id = astman_get_header(m, "ActionID"); 00637 const char *state = astman_get_header(m, "State"); 00638 const char *direction = astman_get_header(m,"Direction"); 00639 00640 int clearmute = 1; 00641 00642 enum ast_audiohook_flags flag; 00643 00644 if (ast_strlen_zero(direction)) { 00645 astman_send_error(s, m, "No direction specified. Must be read, write or both"); 00646 return AMI_SUCCESS; 00647 } 00648 00649 if (!strcasecmp(direction, "read")) { 00650 flag = AST_AUDIOHOOK_MUTE_READ; 00651 } else if (!strcasecmp(direction, "write")) { 00652 flag = AST_AUDIOHOOK_MUTE_WRITE; 00653 } else if (!strcasecmp(direction, "both")) { 00654 flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE; 00655 } else { 00656 astman_send_error(s, m, "Invalid direction specified. Must be read, write or both"); 00657 return AMI_SUCCESS; 00658 } 00659 00660 if (ast_strlen_zero(name)) { 00661 astman_send_error(s, m, "No channel specified"); 00662 return AMI_SUCCESS; 00663 } 00664 00665 if (ast_strlen_zero(state)) { 00666 astman_send_error(s, m, "No state specified"); 00667 return AMI_SUCCESS; 00668 } 00669 00670 clearmute = ast_false(state); 00671 c = ast_channel_get_by_name(name); 00672 00673 if (!c) { 00674 astman_send_error(s, m, "No such channel"); 00675 return AMI_SUCCESS; 00676 } 00677 00678 if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) { 00679 c = ast_channel_unref(c); 00680 astman_send_error(s, m, "Cannot set mute flag"); 00681 return AMI_SUCCESS; 00682 } 00683 00684 astman_append(s, "Response: Success\r\n"); 00685 00686 if (!ast_strlen_zero(id)) { 00687 astman_append(s, "ActionID: %s\r\n", id); 00688 } 00689 00690 astman_append(s, "\r\n"); 00691 00692 c = ast_channel_unref(c); 00693 00694 return AMI_SUCCESS; 00695 }
static void mixmonitor_ds_close_fs | ( | struct mixmonitor_ds * | mixmonitor_ds | ) | [static] |
Definition at line 208 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().
00209 { 00210 if (mixmonitor_ds->fs) { 00211 ast_closestream(mixmonitor_ds->fs); 00212 mixmonitor_ds->fs = NULL; 00213 mixmonitor_ds->fs_quit = 1; 00214 ast_verb(2, "MixMonitor close filestream\n"); 00215 } 00216 }
static void mixmonitor_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 218 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.
00219 { 00220 struct mixmonitor_ds *mixmonitor_ds = data; 00221 00222 ast_mutex_lock(&mixmonitor_ds->lock); 00223 mixmonitor_ds->audiohook = NULL; 00224 mixmonitor_ds->destruction_ok = 1; 00225 ast_cond_signal(&mixmonitor_ds->destruction_condition); 00226 ast_mutex_unlock(&mixmonitor_ds->lock); 00227 }
static int mixmonitor_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 472 of file app_mixmonitor.c.
References args, 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, mixmonitor_opts, 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().
00473 { 00474 int x, readvol = 0, writevol = 0; 00475 struct ast_flags flags = {0}; 00476 char *parse, *tmp, *slash; 00477 AST_DECLARE_APP_ARGS(args, 00478 AST_APP_ARG(filename); 00479 AST_APP_ARG(options); 00480 AST_APP_ARG(post_process); 00481 ); 00482 00483 if (ast_strlen_zero(data)) { 00484 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00485 return -1; 00486 } 00487 00488 parse = ast_strdupa(data); 00489 00490 AST_STANDARD_APP_ARGS(args, parse); 00491 00492 if (ast_strlen_zero(args.filename)) { 00493 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00494 return -1; 00495 } 00496 00497 if (args.options) { 00498 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, }; 00499 00500 ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options); 00501 00502 if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) { 00503 if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) { 00504 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n"); 00505 } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00506 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]); 00507 } else { 00508 readvol = get_volfactor(x); 00509 } 00510 } 00511 00512 if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) { 00513 if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) { 00514 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n"); 00515 } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00516 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]); 00517 } else { 00518 writevol = get_volfactor(x); 00519 } 00520 } 00521 00522 if (ast_test_flag(&flags, MUXFLAG_VOLUME)) { 00523 if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) { 00524 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n"); 00525 } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00526 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]); 00527 } else { 00528 readvol = writevol = get_volfactor(x); 00529 } 00530 } 00531 } 00532 00533 /* if not provided an absolute path, use the system-configured monitoring directory */ 00534 if (args.filename[0] != '/') { 00535 char *build; 00536 00537 build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3); 00538 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename); 00539 args.filename = build; 00540 } 00541 00542 tmp = ast_strdupa(args.filename); 00543 if ((slash = strrchr(tmp, '/'))) 00544 *slash = '\0'; 00545 ast_mkdir(tmp, 0777); 00546 00547 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename); 00548 launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process); 00549 00550 return 0; 00551 }
static void mixmonitor_free | ( | struct mixmonitor * | mixmonitor | ) | [static] |
Definition at line 266 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().
00267 { 00268 if (mixmonitor) { 00269 if (mixmonitor->mixmonitor_ds) { 00270 ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock); 00271 ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition); 00272 ast_free(mixmonitor->mixmonitor_ds); 00273 } 00274 ast_free(mixmonitor); 00275 } 00276 }
static void* mixmonitor_thread | ( | void * | obj | ) | [static] |
Definition at line 277 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_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().
00278 { 00279 struct mixmonitor *mixmonitor = obj; 00280 struct ast_filestream **fs = NULL; 00281 unsigned int oflags; 00282 char *ext; 00283 int errflag = 0; 00284 00285 ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name); 00286 00287 fs = &mixmonitor->mixmonitor_ds->fs; 00288 00289 /* The audiohook must enter and exit the loop locked */ 00290 ast_audiohook_lock(&mixmonitor->audiohook); 00291 while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) { 00292 struct ast_frame *fr = NULL; 00293 00294 if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) { 00295 ast_audiohook_trigger_wait(&mixmonitor->audiohook); 00296 00297 if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { 00298 break; 00299 } 00300 continue; 00301 } 00302 00303 /* audiohook lock is not required for the next block. 00304 * Unlock it, but remember to lock it before looping or exiting */ 00305 ast_audiohook_unlock(&mixmonitor->audiohook); 00306 00307 if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) { 00308 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00309 /* Initialize the file if not already done so */ 00310 if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) { 00311 oflags = O_CREAT | O_WRONLY; 00312 oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC; 00313 00314 if ((ext = strrchr(mixmonitor->filename, '.'))) 00315 *(ext++) = '\0'; 00316 else 00317 ext = "raw"; 00318 00319 if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0666))) { 00320 ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext); 00321 errflag = 1; 00322 } 00323 } 00324 00325 /* Write out the frame(s) */ 00326 if (*fs) { 00327 struct ast_frame *cur; 00328 00329 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) { 00330 ast_writestream(*fs, cur); 00331 } 00332 } 00333 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00334 } 00335 /* All done! free it. */ 00336 ast_frame_free(fr, 0); 00337 00338 ast_audiohook_lock(&mixmonitor->audiohook); 00339 } 00340 ast_audiohook_unlock(&mixmonitor->audiohook); 00341 00342 ast_autochan_destroy(mixmonitor->autochan); 00343 00344 /* Datastore cleanup. close the filestream and wait for ds destruction */ 00345 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00346 mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds); 00347 if (!mixmonitor->mixmonitor_ds->destruction_ok) { 00348 ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock); 00349 } 00350 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00351 00352 /* kill the audiohook */ 00353 destroy_monitor_audiohook(mixmonitor); 00354 00355 if (mixmonitor->post_process) { 00356 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process); 00357 ast_safe_system(mixmonitor->post_process); 00358 } 00359 00360 ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name); 00361 mixmonitor_free(mixmonitor); 00362 return NULL; 00363 }
static int setup_mixmonitor_ds | ( | struct mixmonitor * | mixmonitor, | |
struct ast_channel * | chan | |||
) | [static] |
Definition at line 365 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, ast_datastore::data, mixmonitor::mixmonitor_ds, and mixmonitor_ds_info.
Referenced by launch_monitor_thread().
00366 { 00367 struct ast_datastore *datastore = NULL; 00368 struct mixmonitor_ds *mixmonitor_ds; 00369 00370 if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) { 00371 return -1; 00372 } 00373 00374 ast_mutex_init(&mixmonitor_ds->lock); 00375 ast_cond_init(&mixmonitor_ds->destruction_condition, NULL); 00376 00377 if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) { 00378 ast_mutex_destroy(&mixmonitor_ds->lock); 00379 ast_cond_destroy(&mixmonitor_ds->destruction_condition); 00380 ast_free(mixmonitor_ds); 00381 return -1; 00382 } 00383 00384 mixmonitor_ds->audiohook = &mixmonitor->audiohook; 00385 datastore->data = mixmonitor_ds; 00386 00387 ast_channel_lock(chan); 00388 ast_channel_datastore_add(chan, datastore); 00389 ast_channel_unlock(chan); 00390 00391 mixmonitor->mixmonitor_ds = mixmonitor_ds; 00392 return 0; 00393 }
static int startmon | ( | struct ast_channel * | chan, | |
struct ast_audiohook * | audiohook | |||
) | [static] |
Definition at line 248 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().
00249 { 00250 struct ast_channel *peer = NULL; 00251 int res = 0; 00252 00253 if (!chan) 00254 return -1; 00255 00256 ast_audiohook_attach(chan, audiohook); 00257 00258 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) 00259 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00260 00261 return res; 00262 }
static int stop_mixmonitor_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 553 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(), mixmonitor_ds_info, and ast_audiohook::trigger.
Referenced by load_module().
00554 { 00555 struct ast_datastore *datastore = NULL; 00556 00557 ast_channel_lock(chan); 00558 ast_audiohook_detach_source(chan, mixmonitor_spy_type); 00559 if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) { 00560 struct mixmonitor_ds *mixmonitor_ds = datastore->data; 00561 00562 ast_mutex_lock(&mixmonitor_ds->lock); 00563 00564 /* closing the filestream here guarantees the file is avaliable to the dialplan 00565 * after calling StopMixMonitor */ 00566 mixmonitor_ds_close_fs(mixmonitor_ds); 00567 00568 /* The mixmonitor thread may be waiting on the audiohook trigger. 00569 * In order to exit from the mixmonitor loop before waiting on channel 00570 * destruction, poke the audiohook trigger. */ 00571 if (mixmonitor_ds->audiohook) { 00572 ast_audiohook_lock(mixmonitor_ds->audiohook); 00573 ast_cond_signal(&mixmonitor_ds->audiohook->trigger); 00574 ast_audiohook_unlock(mixmonitor_ds->audiohook); 00575 mixmonitor_ds->audiohook = NULL; 00576 } 00577 00578 ast_mutex_unlock(&mixmonitor_ds->lock); 00579 00580 /* Remove the datastore so the monitor thread can exit */ 00581 if (!ast_channel_datastore_remove(chan, datastore)) { 00582 ast_datastore_free(datastore); 00583 } 00584 } 00585 ast_channel_unlock(chan); 00586 00587 return 0; 00588 }
static int unload_module | ( | void | ) | [static] |
Definition at line 701 of file app_mixmonitor.c.
References ARRAY_LEN, ast_cli_unregister_multiple(), ast_manager_unregister(), ast_unregister_application(), and cli_mixmonitor.
00702 { 00703 int res; 00704 00705 ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor)); 00706 res = ast_unregister_application(stop_app); 00707 res |= ast_unregister_application(app); 00708 res |= ast_manager_unregister("MixMonitorMute"); 00709 00710 return res; 00711 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Mixed Audio Monitoring Application" , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 725 of file app_mixmonitor.c.
const char* const app = "MixMonitor" [static] |
Definition at line 153 of file app_mixmonitor.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 725 of file app_mixmonitor.c.
struct ast_cli_entry cli_mixmonitor[] [static] |
Initial value:
{ { .handler = handle_cli_mixmonitor , .summary = "Execute a MixMonitor command" ,__VA_ARGS__ } }
Definition at line 697 of file app_mixmonitor.c.
Referenced by load_module(), and unload_module().
struct ast_datastore_info mixmonitor_ds_info [static] |
Initial value:
{ .type = "mixmonitor", .destroy = mixmonitor_ds_destroy, }
Definition at line 229 of file app_mixmonitor.c.
Referenced by setup_mixmonitor_ds(), and stop_mixmonitor_exec().
struct ast_app_option mixmonitor_opts[128] = { [ 'a' ] = { .flag = MUXFLAG_APPEND }, [ 'b' ] = { .flag = MUXFLAG_BRIDGED }, [ 'v' ] = { .flag = MUXFLAG_READVOLUME , .arg_index = OPT_ARG_READVOLUME + 1 }, [ 'V' ] = { .flag = MUXFLAG_WRITEVOLUME , .arg_index = OPT_ARG_WRITEVOLUME + 1 }, [ 'W' ] = { .flag = MUXFLAG_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 },} [static] |
const char* const mixmonitor_spy_type = "MixMonitor" [static] |
const char* const stop_app = "StopMixMonitor" [static] |
Definition at line 155 of file app_mixmonitor.c.