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