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"
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 | { MUXFLAG_APPEND = (1 << 1), MUXFLAG_BRIDGED = (1 << 2), MUXFLAG_VOLUME = (1 << 3), MUXFLAG_READVOLUME = (1 << 4), MUXFLAG_WRITEVOLUME = (1 << 5) } |
| enum | { OPT_ARG_READVOLUME = 0, OPT_ARG_WRITEVOLUME, OPT_ARG_VOLUME, OPT_ARG_ARRAY_SIZE } |
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 void | mixmonitor_ds_chan_fixup (void *data, struct ast_channel *old_chan, struct ast_channel *new_chan) |
| 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, void *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, void *data) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, } |
| static const char * | app = "MixMonitor" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_cli_entry | cli_mixmonitor [] |
| struct module_symbols * | me |
| enum { ... } | mixmonitor_args |
| static struct ast_datastore_info | mixmonitor_ds_info |
| enum { ... } | mixmonitor_flags |
| 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 * | mixmonitor_spy_type = "MixMonitor" |
| static const char * | 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 129 of file app_mixmonitor.c.
Referenced by mixmonitor_exec().
| #define SAMPLES_PER_FRAME 160 |
Definition at line 266 of file app_mixmonitor.c.
Referenced by mixmonitor_thread().
| anonymous enum |
Definition at line 148 of file app_mixmonitor.c.
00148 { 00149 MUXFLAG_APPEND = (1 << 1), 00150 MUXFLAG_BRIDGED = (1 << 2), 00151 MUXFLAG_VOLUME = (1 << 3), 00152 MUXFLAG_READVOLUME = (1 << 4), 00153 MUXFLAG_WRITEVOLUME = (1 << 5), 00154 } mixmonitor_flags;
| anonymous enum |
Definition at line 156 of file app_mixmonitor.c.
00156 { 00157 OPT_ARG_READVOLUME = 0, 00158 OPT_ARG_WRITEVOLUME, 00159 OPT_ARG_VOLUME, 00160 OPT_ARG_ARRAY_SIZE, 00161 } mixmonitor_args;
| static void __reg_module | ( | void | ) | [static] |
Definition at line 649 of file app_mixmonitor.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 649 of file app_mixmonitor.c.
| static void destroy_monitor_audiohook | ( | struct mixmonitor * | mixmonitor | ) | [static] |
Definition at line 236 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().
00237 { 00238 if (mixmonitor->mixmonitor_ds) { 00239 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00240 mixmonitor->mixmonitor_ds->audiohook = NULL; 00241 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00242 } 00243 /* kill the audiohook.*/ 00244 ast_audiohook_lock(&mixmonitor->audiohook); 00245 ast_audiohook_detach(&mixmonitor->audiohook); 00246 ast_audiohook_unlock(&mixmonitor->audiohook); 00247 ast_audiohook_destroy(&mixmonitor->audiohook); 00248 }
| static char* handle_cli_mixmonitor | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 587 of file app_mixmonitor.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_audiohook_detach_source(), ast_channel_unlock, ast_cli(), ast_complete_channels(), ast_get_channel_by_name_prefix_locked(), chan, 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.
00588 { 00589 struct ast_channel *chan; 00590 00591 switch (cmd) { 00592 case CLI_INIT: 00593 e->command = "mixmonitor {start|stop}"; 00594 e->usage = 00595 "Usage: mixmonitor <start|stop> <chan_name> [args]\n" 00596 " The optional arguments are passed to the MixMonitor\n" 00597 " application when the 'start' command is used.\n"; 00598 return NULL; 00599 case CLI_GENERATE: 00600 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2); 00601 } 00602 00603 if (a->argc < 3) 00604 return CLI_SHOWUSAGE; 00605 00606 if (!(chan = ast_get_channel_by_name_prefix_locked(a->argv[2], strlen(a->argv[2])))) { 00607 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]); 00608 /* Technically this is a failure, but we don't want 2 errors printing out */ 00609 return CLI_SUCCESS; 00610 } 00611 00612 if (!strcasecmp(a->argv[1], "start")) { 00613 mixmonitor_exec(chan, a->argv[3]); 00614 ast_channel_unlock(chan); 00615 } else { 00616 ast_channel_unlock(chan); 00617 ast_audiohook_detach_source(chan, mixmonitor_spy_type); 00618 } 00619 00620 return CLI_SUCCESS; 00621 }
| 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 398 of file app_mixmonitor.c.
References ast_audiohook_destroy(), ast_audiohook_init(), AST_AUDIOHOOK_TRIGGER_SYNC, AST_AUDIOHOOK_TYPE_SPY, ast_calloc, ast_log(), ast_pthread_create_detached_background, ast_set_flag, ast_strlen_zero(), mixmonitor::audiohook, mixmonitor::filename, mixmonitor::flags, len(), LOG_WARNING, mixmonitor_free(), mixmonitor_thread(), mixmonitor::name, ast_channel::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().
00400 { 00401 pthread_t thread; 00402 struct mixmonitor *mixmonitor; 00403 char postprocess2[1024] = ""; 00404 size_t len; 00405 00406 len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2; 00407 00408 postprocess2[0] = 0; 00409 /* If a post process system command is given attach it to the structure */ 00410 if (!ast_strlen_zero(post_process)) { 00411 char *p1, *p2; 00412 00413 p1 = ast_strdupa(post_process); 00414 for (p2 = p1; *p2 ; p2++) { 00415 if (*p2 == '^' && *(p2+1) == '{') { 00416 *p2 = '$'; 00417 } 00418 } 00419 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1); 00420 if (!ast_strlen_zero(postprocess2)) 00421 len += strlen(postprocess2) + 1; 00422 } 00423 00424 /* Pre-allocate mixmonitor structure and spy */ 00425 if (!(mixmonitor = ast_calloc(1, len))) { 00426 return; 00427 } 00428 00429 /* Setup the actual spy before creating our thread */ 00430 if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) { 00431 mixmonitor_free(mixmonitor); 00432 return; 00433 } 00434 00435 /* Copy over flags and channel name */ 00436 mixmonitor->flags = flags; 00437 if (setup_mixmonitor_ds(mixmonitor, chan)) { 00438 mixmonitor_free(mixmonitor); 00439 return; 00440 } 00441 mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor); 00442 strcpy(mixmonitor->name, chan->name); 00443 if (!ast_strlen_zero(postprocess2)) { 00444 mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2; 00445 strcpy(mixmonitor->post_process, postprocess2); 00446 } 00447 00448 mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1; 00449 strcpy(mixmonitor->filename, filename); 00450 00451 ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC); 00452 00453 if (readvol) 00454 mixmonitor->audiohook.options.read_volume = readvol; 00455 if (writevol) 00456 mixmonitor->audiohook.options.write_volume = writevol; 00457 00458 if (startmon(chan, &mixmonitor->audiohook)) { 00459 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n", 00460 mixmonitor_spy_type, chan->name); 00461 ast_audiohook_destroy(&mixmonitor->audiohook); 00462 mixmonitor_free(mixmonitor); 00463 return; 00464 } 00465 00466 ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor); 00467 }
| static int load_module | ( | void | ) | [static] |
Definition at line 638 of file app_mixmonitor.c.
References ARRAY_LEN, ast_cli_register_multiple(), ast_register_application_xml, mixmonitor_exec(), and stop_mixmonitor_exec().
00639 { 00640 int res; 00641 00642 ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor)); 00643 res = ast_register_application_xml(app, mixmonitor_exec); 00644 res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec); 00645 00646 return res; 00647 }
| static void mixmonitor_ds_chan_fixup | ( | void * | data, | |
| struct ast_channel * | old_chan, | |||
| struct ast_channel * | new_chan | |||
| ) | [static] |
Definition at line 221 of file app_mixmonitor.c.
References ast_mutex_lock(), ast_mutex_unlock(), mixmonitor_ds::chan, and mixmonitor_ds::lock.
00222 { 00223 struct mixmonitor_ds *mixmonitor_ds = data; 00224 00225 ast_mutex_lock(&mixmonitor_ds->lock); 00226 mixmonitor_ds->chan = new_chan; 00227 ast_mutex_unlock(&mixmonitor_ds->lock); 00228 }
| static void mixmonitor_ds_close_fs | ( | struct mixmonitor_ds * | mixmonitor_ds | ) | [static] |
Definition at line 199 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 209 of file app_mixmonitor.c.
References ast_cond_signal(), ast_mutex_lock(), ast_mutex_unlock(), mixmonitor_ds::audiohook, mixmonitor_ds::chan, mixmonitor_ds::destruction_condition, mixmonitor_ds::destruction_ok, and mixmonitor_ds::lock.
00210 { 00211 struct mixmonitor_ds *mixmonitor_ds = data; 00212 00213 ast_mutex_lock(&mixmonitor_ds->lock); 00214 mixmonitor_ds->chan = NULL; 00215 mixmonitor_ds->audiohook = NULL; 00216 mixmonitor_ds->destruction_ok = 1; 00217 ast_cond_signal(&mixmonitor_ds->destruction_condition); 00218 ast_mutex_unlock(&mixmonitor_ds->lock); 00219 }
| static int mixmonitor_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 469 of file app_mixmonitor.c.
References 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_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().
00470 { 00471 int x, readvol = 0, writevol = 0; 00472 struct ast_flags flags = {0}; 00473 char *parse, *tmp, *slash; 00474 AST_DECLARE_APP_ARGS(args, 00475 AST_APP_ARG(filename); 00476 AST_APP_ARG(options); 00477 AST_APP_ARG(post_process); 00478 ); 00479 00480 if (ast_strlen_zero(data)) { 00481 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00482 return -1; 00483 } 00484 00485 parse = ast_strdupa(data); 00486 00487 AST_STANDARD_APP_ARGS(args, parse); 00488 00489 if (ast_strlen_zero(args.filename)) { 00490 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00491 return -1; 00492 } 00493 00494 if (args.options) { 00495 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, }; 00496 00497 ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options); 00498 00499 if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) { 00500 if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) { 00501 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n"); 00502 } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00503 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]); 00504 } else { 00505 readvol = get_volfactor(x); 00506 } 00507 } 00508 00509 if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) { 00510 if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) { 00511 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n"); 00512 } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00513 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]); 00514 } else { 00515 writevol = get_volfactor(x); 00516 } 00517 } 00518 00519 if (ast_test_flag(&flags, MUXFLAG_VOLUME)) { 00520 if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) { 00521 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n"); 00522 } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00523 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]); 00524 } else { 00525 readvol = writevol = get_volfactor(x); 00526 } 00527 } 00528 } 00529 00530 /* if not provided an absolute path, use the system-configured monitoring directory */ 00531 if (args.filename[0] != '/') { 00532 char *build; 00533 00534 build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3); 00535 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename); 00536 args.filename = build; 00537 } 00538 00539 tmp = ast_strdupa(args.filename); 00540 if ((slash = strrchr(tmp, '/'))) 00541 *slash = '\0'; 00542 ast_mkdir(tmp, 0777); 00543 00544 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename); 00545 launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process); 00546 00547 return 0; 00548 }
| static void mixmonitor_free | ( | struct mixmonitor * | mixmonitor | ) | [static] |
Definition at line 268 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().
00269 { 00270 if (mixmonitor) { 00271 if (mixmonitor->mixmonitor_ds) { 00272 ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock); 00273 ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition); 00274 ast_free(mixmonitor->mixmonitor_ds); 00275 } 00276 ast_free(mixmonitor); 00277 } 00278 }
| static void* mixmonitor_thread | ( | void * | obj | ) | [static] |
Definition at line 280 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_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_ds::chan, destroy_monitor_audiohook(), mixmonitor_ds::destruction_condition, mixmonitor_ds::destruction_ok, ext, mixmonitor::filename, ast_frame::frame_list, 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().
00281 { 00282 struct mixmonitor *mixmonitor = obj; 00283 struct ast_filestream **fs = NULL; 00284 unsigned int oflags; 00285 char *ext; 00286 int errflag = 0; 00287 00288 ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name); 00289 00290 fs = &mixmonitor->mixmonitor_ds->fs; 00291 00292 /* The audiohook must enter and exit the loop locked */ 00293 ast_audiohook_lock(&mixmonitor->audiohook); 00294 while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) { 00295 struct ast_frame *fr = NULL; 00296 00297 ast_audiohook_trigger_wait(&mixmonitor->audiohook); 00298 00299 if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) 00300 break; 00301 00302 if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) 00303 continue; 00304 00305 /* audiohook lock is not required for the next block. 00306 * Unlock it, but remember to lock it before looping or exiting */ 00307 ast_audiohook_unlock(&mixmonitor->audiohook); 00308 00309 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00310 if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) { 00311 /* Initialize the file if not already done so */ 00312 if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) { 00313 oflags = O_CREAT | O_WRONLY; 00314 oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC; 00315 00316 if ((ext = strrchr(mixmonitor->filename, '.'))) 00317 *(ext++) = '\0'; 00318 else 00319 ext = "raw"; 00320 00321 if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0666))) { 00322 ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext); 00323 errflag = 1; 00324 } 00325 } 00326 00327 /* Write out the frame(s) */ 00328 if (*fs) { 00329 struct ast_frame *cur; 00330 00331 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) { 00332 ast_writestream(*fs, cur); 00333 } 00334 } 00335 } 00336 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00337 00338 /* All done! free it. */ 00339 ast_frame_free(fr, 0); 00340 ast_audiohook_lock(&mixmonitor->audiohook); 00341 } 00342 00343 ast_audiohook_unlock(&mixmonitor->audiohook); 00344 00345 /* Datastore cleanup. close the filestream and wait for ds destruction */ 00346 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00347 mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds); 00348 if (!mixmonitor->mixmonitor_ds->destruction_ok) { 00349 ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock); 00350 } 00351 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00352 00353 /* kill the audiohook */ 00354 destroy_monitor_audiohook(mixmonitor); 00355 00356 if (mixmonitor->post_process) { 00357 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process); 00358 ast_safe_system(mixmonitor->post_process); 00359 } 00360 00361 ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name); 00362 mixmonitor_free(mixmonitor); 00363 return NULL; 00364 }
| static int setup_mixmonitor_ds | ( | struct mixmonitor * | mixmonitor, | |
| struct ast_channel * | chan | |||
| ) | [static] |
Definition at line 366 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, mixmonitor_ds::chan, ast_datastore::data, mixmonitor_ds::destruction_condition, mixmonitor_ds::lock, and mixmonitor::mixmonitor_ds.
Referenced by launch_monitor_thread().
00367 { 00368 struct ast_datastore *datastore = NULL; 00369 struct mixmonitor_ds *mixmonitor_ds; 00370 00371 if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) { 00372 return -1; 00373 } 00374 00375 ast_mutex_init(&mixmonitor_ds->lock); 00376 ast_cond_init(&mixmonitor_ds->destruction_condition, NULL); 00377 00378 if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) { 00379 ast_mutex_destroy(&mixmonitor_ds->lock); 00380 ast_cond_destroy(&mixmonitor_ds->destruction_condition); 00381 ast_free(mixmonitor_ds); 00382 return -1; 00383 } 00384 00385 /* No need to lock mixmonitor_ds since this is still operating in the channel's thread */ 00386 mixmonitor_ds->chan = chan; 00387 mixmonitor_ds->audiohook = &mixmonitor->audiohook; 00388 datastore->data = mixmonitor_ds; 00389 00390 ast_channel_lock(chan); 00391 ast_channel_datastore_add(chan, datastore); 00392 ast_channel_unlock(chan); 00393 00394 mixmonitor->mixmonitor_ds = mixmonitor_ds; 00395 return 0; 00396 }
| static int startmon | ( | struct ast_channel * | chan, | |
| struct ast_audiohook * | audiohook | |||
| ) | [static] |
Definition at line 250 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().
00251 { 00252 struct ast_channel *peer = NULL; 00253 int res = 0; 00254 00255 if (!chan) 00256 return -1; 00257 00258 ast_audiohook_attach(chan, audiohook); 00259 00260 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) 00261 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00262 00263 return res; 00264 }
| static int stop_mixmonitor_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 550 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().
00551 { 00552 struct ast_datastore *datastore = NULL; 00553 00554 ast_channel_lock(chan); 00555 ast_audiohook_detach_source(chan, mixmonitor_spy_type); 00556 if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) { 00557 struct mixmonitor_ds *mixmonitor_ds = datastore->data; 00558 00559 ast_mutex_lock(&mixmonitor_ds->lock); 00560 00561 /* closing the filestream here guarantees the file is avaliable to the dialplan 00562 * after calling StopMixMonitor */ 00563 mixmonitor_ds_close_fs(mixmonitor_ds); 00564 00565 /* The mixmonitor thread may be waiting on the audiohook trigger. 00566 * In order to exit from the mixmonitor loop before waiting on channel 00567 * destruction, poke the audiohook trigger. */ 00568 if (mixmonitor_ds->audiohook) { 00569 ast_audiohook_lock(mixmonitor_ds->audiohook); 00570 ast_cond_signal(&mixmonitor_ds->audiohook->trigger); 00571 ast_audiohook_unlock(mixmonitor_ds->audiohook); 00572 mixmonitor_ds->audiohook = NULL; 00573 } 00574 00575 ast_mutex_unlock(&mixmonitor_ds->lock); 00576 00577 /* Remove the datastore so the monitor thread can exit */ 00578 if (!ast_channel_datastore_remove(chan, datastore)) { 00579 ast_datastore_free(datastore); 00580 } 00581 } 00582 ast_channel_unlock(chan); 00583 00584 return 0; 00585 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 627 of file app_mixmonitor.c.
References ARRAY_LEN, ast_cli_unregister_multiple(), and ast_unregister_application().
00628 { 00629 int res; 00630 00631 ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor)); 00632 res = ast_unregister_application(stop_app); 00633 res |= ast_unregister_application(app); 00634 00635 return res; 00636 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 649 of file app_mixmonitor.c.
const char* app = "MixMonitor" [static] |
Definition at line 131 of file app_mixmonitor.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 649 of file app_mixmonitor.c.
struct ast_cli_entry cli_mixmonitor[] [static] |
{
AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
}
Definition at line 623 of file app_mixmonitor.c.
| struct module_symbols* me |
Definition at line 135 of file app_mixmonitor.c.
Referenced by _sip_tcp_helper_thread(), handle_mgcp_audit_endpoint(), and handle_mgcp_show_endpoints().
| enum { ... } mixmonitor_args |
struct ast_datastore_info mixmonitor_ds_info [static] |
{
.type = "mixmonitor",
.destroy = mixmonitor_ds_destroy,
.chan_fixup = mixmonitor_ds_chan_fixup,
}
Definition at line 230 of file app_mixmonitor.c.
| enum { ... } mixmonitor_flags |
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] |
Definition at line 169 of file app_mixmonitor.c.
Referenced by mixmonitor_exec().
const char* mixmonitor_spy_type = "MixMonitor" [static] |
Definition at line 137 of file app_mixmonitor.c.
Referenced by builtin_automixmonitor().
const char* stop_app = "StopMixMonitor" [static] |
Definition at line 133 of file app_mixmonitor.c.
1.6.2