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 = "a9c98e5d177805051735cb5b0b16b0a0" , .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 [] |
| static const char * | desc |
| 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" |
| static const char * | stop_desc |
| static const char * | stop_synopsis = "Stop recording a call through MixMonitor" |
| static const char * | synopsis = "Record a call and mix the audio during the recording" |
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 49 of file app_mixmonitor.c.
Referenced by mixmonitor_exec().
| #define SAMPLES_PER_FRAME 160 |
Definition at line 217 of file app_mixmonitor.c.
Referenced by mixmonitor_thread().
| anonymous enum |
Definition at line 99 of file app_mixmonitor.c.
00099 { 00100 MUXFLAG_APPEND = (1 << 1), 00101 MUXFLAG_BRIDGED = (1 << 2), 00102 MUXFLAG_VOLUME = (1 << 3), 00103 MUXFLAG_READVOLUME = (1 << 4), 00104 MUXFLAG_WRITEVOLUME = (1 << 5), 00105 } mixmonitor_flags;
| anonymous enum |
Definition at line 107 of file app_mixmonitor.c.
00107 { 00108 OPT_ARG_READVOLUME = 0, 00109 OPT_ARG_WRITEVOLUME, 00110 OPT_ARG_VOLUME, 00111 OPT_ARG_ARRAY_SIZE, 00112 } mixmonitor_args;
| static void __reg_module | ( | void | ) | [static] |
Definition at line 600 of file app_mixmonitor.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 600 of file app_mixmonitor.c.
| static void destroy_monitor_audiohook | ( | struct mixmonitor * | mixmonitor | ) | [static] |
Definition at line 187 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().
00188 { 00189 if (mixmonitor->mixmonitor_ds) { 00190 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00191 mixmonitor->mixmonitor_ds->audiohook = NULL; 00192 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00193 } 00194 /* kill the audiohook.*/ 00195 ast_audiohook_lock(&mixmonitor->audiohook); 00196 ast_audiohook_detach(&mixmonitor->audiohook); 00197 ast_audiohook_unlock(&mixmonitor->audiohook); 00198 ast_audiohook_destroy(&mixmonitor->audiohook); 00199 }
| static char* handle_cli_mixmonitor | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 538 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.
00539 { 00540 struct ast_channel *chan; 00541 00542 switch (cmd) { 00543 case CLI_INIT: 00544 e->command = "mixmonitor [start|stop]"; 00545 e->usage = 00546 "Usage: mixmonitor <start|stop> <chan_name> [args]\n" 00547 " The optional arguments are passed to the MixMonitor\n" 00548 " application when the 'start' command is used.\n"; 00549 return NULL; 00550 case CLI_GENERATE: 00551 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2); 00552 } 00553 00554 if (a->argc < 3) 00555 return CLI_SHOWUSAGE; 00556 00557 if (!(chan = ast_get_channel_by_name_prefix_locked(a->argv[2], strlen(a->argv[2])))) { 00558 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]); 00559 /* Technically this is a failure, but we don't want 2 errors printing out */ 00560 return CLI_SUCCESS; 00561 } 00562 00563 if (!strcasecmp(a->argv[1], "start")) { 00564 mixmonitor_exec(chan, a->argv[3]); 00565 ast_channel_unlock(chan); 00566 } else { 00567 ast_channel_unlock(chan); 00568 ast_audiohook_detach_source(chan, mixmonitor_spy_type); 00569 } 00570 00571 return CLI_SUCCESS; 00572 }
| 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 349 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_strdupa, ast_strlen_zero(), mixmonitor::audiohook, 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().
00351 { 00352 pthread_t thread; 00353 struct mixmonitor *mixmonitor; 00354 char postprocess2[1024] = ""; 00355 size_t len; 00356 00357 len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2; 00358 00359 postprocess2[0] = 0; 00360 /* If a post process system command is given attach it to the structure */ 00361 if (!ast_strlen_zero(post_process)) { 00362 char *p1, *p2; 00363 00364 p1 = ast_strdupa(post_process); 00365 for (p2 = p1; *p2 ; p2++) { 00366 if (*p2 == '^' && *(p2+1) == '{') { 00367 *p2 = '$'; 00368 } 00369 } 00370 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1); 00371 if (!ast_strlen_zero(postprocess2)) 00372 len += strlen(postprocess2) + 1; 00373 } 00374 00375 /* Pre-allocate mixmonitor structure and spy */ 00376 if (!(mixmonitor = ast_calloc(1, len))) { 00377 return; 00378 } 00379 00380 /* Setup the actual spy before creating our thread */ 00381 if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) { 00382 mixmonitor_free(mixmonitor); 00383 return; 00384 } 00385 00386 /* Copy over flags and channel name */ 00387 mixmonitor->flags = flags; 00388 if (setup_mixmonitor_ds(mixmonitor, chan)) { 00389 mixmonitor_free(mixmonitor); 00390 return; 00391 } 00392 mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor); 00393 strcpy(mixmonitor->name, chan->name); 00394 if (!ast_strlen_zero(postprocess2)) { 00395 mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2; 00396 strcpy(mixmonitor->post_process, postprocess2); 00397 } 00398 00399 mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1; 00400 strcpy(mixmonitor->filename, filename); 00401 00402 ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC); 00403 00404 if (readvol) 00405 mixmonitor->audiohook.options.read_volume = readvol; 00406 if (writevol) 00407 mixmonitor->audiohook.options.write_volume = writevol; 00408 00409 if (startmon(chan, &mixmonitor->audiohook)) { 00410 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n", 00411 mixmonitor_spy_type, chan->name); 00412 ast_audiohook_destroy(&mixmonitor->audiohook); 00413 mixmonitor_free(mixmonitor); 00414 return; 00415 } 00416 00417 ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor); 00418 }
| static int load_module | ( | void | ) | [static] |
Definition at line 589 of file app_mixmonitor.c.
References ast_cli_register_multiple(), ast_register_application, mixmonitor_exec(), and stop_mixmonitor_exec().
00590 { 00591 int res; 00592 00593 ast_cli_register_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry)); 00594 res = ast_register_application(app, mixmonitor_exec, synopsis, desc); 00595 res |= ast_register_application(stop_app, stop_mixmonitor_exec, stop_synopsis, stop_desc); 00596 00597 return res; 00598 }
| static void mixmonitor_ds_chan_fixup | ( | void * | data, | |
| struct ast_channel * | old_chan, | |||
| struct ast_channel * | new_chan | |||
| ) | [static] |
Definition at line 172 of file app_mixmonitor.c.
References ast_mutex_lock(), ast_mutex_unlock(), mixmonitor_ds::chan, and mixmonitor_ds::lock.
00173 { 00174 struct mixmonitor_ds *mixmonitor_ds = data; 00175 00176 ast_mutex_lock(&mixmonitor_ds->lock); 00177 mixmonitor_ds->chan = new_chan; 00178 ast_mutex_unlock(&mixmonitor_ds->lock); 00179 }
| static void mixmonitor_ds_close_fs | ( | struct mixmonitor_ds * | mixmonitor_ds | ) | [static] |
Definition at line 150 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 160 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.
00161 { 00162 struct mixmonitor_ds *mixmonitor_ds = data; 00163 00164 ast_mutex_lock(&mixmonitor_ds->lock); 00165 mixmonitor_ds->chan = NULL; 00166 mixmonitor_ds->audiohook = NULL; 00167 mixmonitor_ds->destruction_ok = 1; 00168 ast_cond_signal(&mixmonitor_ds->destruction_condition); 00169 ast_mutex_unlock(&mixmonitor_ds->lock); 00170 }
| static int mixmonitor_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 420 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_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().
00421 { 00422 int x, readvol = 0, writevol = 0; 00423 struct ast_flags flags = {0}; 00424 char *parse, *tmp, *slash; 00425 AST_DECLARE_APP_ARGS(args, 00426 AST_APP_ARG(filename); 00427 AST_APP_ARG(options); 00428 AST_APP_ARG(post_process); 00429 ); 00430 00431 if (ast_strlen_zero(data)) { 00432 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00433 return -1; 00434 } 00435 00436 parse = ast_strdupa(data); 00437 00438 AST_STANDARD_APP_ARGS(args, parse); 00439 00440 if (ast_strlen_zero(args.filename)) { 00441 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00442 return -1; 00443 } 00444 00445 if (args.options) { 00446 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, }; 00447 00448 ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options); 00449 00450 if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) { 00451 if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) { 00452 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n"); 00453 } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00454 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]); 00455 } else { 00456 readvol = get_volfactor(x); 00457 } 00458 } 00459 00460 if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) { 00461 if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) { 00462 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n"); 00463 } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00464 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]); 00465 } else { 00466 writevol = get_volfactor(x); 00467 } 00468 } 00469 00470 if (ast_test_flag(&flags, MUXFLAG_VOLUME)) { 00471 if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) { 00472 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n"); 00473 } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00474 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]); 00475 } else { 00476 readvol = writevol = get_volfactor(x); 00477 } 00478 } 00479 } 00480 00481 /* if not provided an absolute path, use the system-configured monitoring directory */ 00482 if (args.filename[0] != '/') { 00483 char *build; 00484 00485 build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3); 00486 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename); 00487 args.filename = build; 00488 } 00489 00490 tmp = ast_strdupa(args.filename); 00491 if ((slash = strrchr(tmp, '/'))) 00492 *slash = '\0'; 00493 ast_mkdir(tmp, 0777); 00494 00495 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename); 00496 launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process); 00497 00498 return 0; 00499 }
| static void mixmonitor_free | ( | struct mixmonitor * | mixmonitor | ) | [static] |
Definition at line 219 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().
00220 { 00221 if (mixmonitor) { 00222 if (mixmonitor->mixmonitor_ds) { 00223 ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock); 00224 ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition); 00225 ast_free(mixmonitor->mixmonitor_ds); 00226 } 00227 ast_free(mixmonitor); 00228 } 00229 }
| static void* mixmonitor_thread | ( | void * | obj | ) | [static] |
Definition at line 231 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, 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().
00232 { 00233 struct mixmonitor *mixmonitor = obj; 00234 struct ast_filestream **fs = NULL; 00235 unsigned int oflags; 00236 char *ext; 00237 int errflag = 0; 00238 00239 ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name); 00240 00241 fs = &mixmonitor->mixmonitor_ds->fs; 00242 00243 /* The audiohook must enter and exit the loop locked */ 00244 ast_audiohook_lock(&mixmonitor->audiohook); 00245 while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) { 00246 struct ast_frame *fr = NULL; 00247 00248 ast_audiohook_trigger_wait(&mixmonitor->audiohook); 00249 00250 if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) 00251 break; 00252 00253 if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) 00254 continue; 00255 00256 /* audiohook lock is not required for the next block. 00257 * Unlock it, but remember to lock it before looping or exiting */ 00258 ast_audiohook_unlock(&mixmonitor->audiohook); 00259 00260 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00261 if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) { 00262 /* Initialize the file if not already done so */ 00263 if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) { 00264 oflags = O_CREAT | O_WRONLY; 00265 oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC; 00266 00267 if ((ext = strrchr(mixmonitor->filename, '.'))) 00268 *(ext++) = '\0'; 00269 else 00270 ext = "raw"; 00271 00272 if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0666))) { 00273 ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext); 00274 errflag = 1; 00275 } 00276 } 00277 00278 /* Write out the frame(s) */ 00279 if (*fs) { 00280 struct ast_frame *cur; 00281 00282 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) { 00283 ast_writestream(*fs, cur); 00284 } 00285 } 00286 } 00287 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00288 00289 /* All done! free it. */ 00290 ast_frame_free(fr, 0); 00291 ast_audiohook_lock(&mixmonitor->audiohook); 00292 } 00293 00294 ast_audiohook_unlock(&mixmonitor->audiohook); 00295 00296 /* Datastore cleanup. close the filestream and wait for ds destruction */ 00297 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00298 mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds); 00299 if (!mixmonitor->mixmonitor_ds->destruction_ok) { 00300 ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock); 00301 } 00302 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00303 00304 /* kill the audiohook */ 00305 destroy_monitor_audiohook(mixmonitor); 00306 00307 if (mixmonitor->post_process) { 00308 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process); 00309 ast_safe_system(mixmonitor->post_process); 00310 } 00311 00312 ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name); 00313 mixmonitor_free(mixmonitor); 00314 return NULL; 00315 }
| static int setup_mixmonitor_ds | ( | struct mixmonitor * | mixmonitor, | |
| struct ast_channel * | chan | |||
| ) | [static] |
Definition at line 317 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().
00318 { 00319 struct ast_datastore *datastore = NULL; 00320 struct mixmonitor_ds *mixmonitor_ds; 00321 00322 if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) { 00323 return -1; 00324 } 00325 00326 ast_mutex_init(&mixmonitor_ds->lock); 00327 ast_cond_init(&mixmonitor_ds->destruction_condition, NULL); 00328 00329 if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) { 00330 ast_mutex_destroy(&mixmonitor_ds->lock); 00331 ast_cond_destroy(&mixmonitor_ds->destruction_condition); 00332 ast_free(mixmonitor_ds); 00333 return -1; 00334 } 00335 00336 /* No need to lock mixmonitor_ds since this is still operating in the channel's thread */ 00337 mixmonitor_ds->chan = chan; 00338 mixmonitor_ds->audiohook = &mixmonitor->audiohook; 00339 datastore->data = mixmonitor_ds; 00340 00341 ast_channel_lock(chan); 00342 ast_channel_datastore_add(chan, datastore); 00343 ast_channel_unlock(chan); 00344 00345 mixmonitor->mixmonitor_ds = mixmonitor_ds; 00346 return 0; 00347 }
| static int startmon | ( | struct ast_channel * | chan, | |
| struct ast_audiohook * | audiohook | |||
| ) | [static] |
Definition at line 201 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().
00202 { 00203 struct ast_channel *peer = NULL; 00204 int res = 0; 00205 00206 if (!chan) 00207 return -1; 00208 00209 ast_audiohook_attach(chan, audiohook); 00210 00211 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) 00212 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00213 00214 return res; 00215 }
| static int stop_mixmonitor_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 501 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().
00502 { 00503 struct ast_datastore *datastore = NULL; 00504 00505 ast_channel_lock(chan); 00506 ast_audiohook_detach_source(chan, mixmonitor_spy_type); 00507 if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) { 00508 struct mixmonitor_ds *mixmonitor_ds = datastore->data; 00509 00510 ast_mutex_lock(&mixmonitor_ds->lock); 00511 00512 /* closing the filestream here guarantees the file is avaliable to the dialplan 00513 * after calling StopMixMonitor */ 00514 mixmonitor_ds_close_fs(mixmonitor_ds); 00515 00516 /* The mixmonitor thread may be waiting on the audiohook trigger. 00517 * In order to exit from the mixmonitor loop before waiting on channel 00518 * destruction, poke the audiohook trigger. */ 00519 if (mixmonitor_ds->audiohook) { 00520 ast_audiohook_lock(mixmonitor_ds->audiohook); 00521 ast_cond_signal(&mixmonitor_ds->audiohook->trigger); 00522 ast_audiohook_unlock(mixmonitor_ds->audiohook); 00523 mixmonitor_ds->audiohook = NULL; 00524 } 00525 00526 ast_mutex_unlock(&mixmonitor_ds->lock); 00527 00528 /* Remove the datastore so the monitor thread can exit */ 00529 if (!ast_channel_datastore_remove(chan, datastore)) { 00530 ast_datastore_free(datastore); 00531 } 00532 } 00533 ast_channel_unlock(chan); 00534 00535 return 0; 00536 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 578 of file app_mixmonitor.c.
References ast_cli_unregister_multiple(), and ast_unregister_application().
00579 { 00580 int res; 00581 00582 ast_cli_unregister_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry)); 00583 res = ast_unregister_application(stop_app); 00584 res |= ast_unregister_application(app); 00585 00586 return res; 00587 }
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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 600 of file app_mixmonitor.c.
const char* app = "MixMonitor" [static] |
Definition at line 51 of file app_mixmonitor.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 600 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 574 of file app_mixmonitor.c.
const char* desc [static] |
Definition at line 53 of file app_mixmonitor.c.
| struct module_symbols* me |
Definition at line 86 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 181 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 120 of file app_mixmonitor.c.
Referenced by mixmonitor_exec().
const char* mixmonitor_spy_type = "MixMonitor" [static] |
Definition at line 88 of file app_mixmonitor.c.
Referenced by builtin_automixmonitor().
const char* stop_app = "StopMixMonitor" [static] |
Definition at line 79 of file app_mixmonitor.c.
const char* stop_desc [static] |
"" " StopMixMonitor():\n" "Stop recording a call through MixMonitor, and free the recording's file handle.\n" ""
Definition at line 81 of file app_mixmonitor.c.
const char* stop_synopsis = "Stop recording a call through MixMonitor" [static] |
Definition at line 80 of file app_mixmonitor.c.
const char* synopsis = "Record a call and mix the audio during the recording" [static] |
Definition at line 52 of file app_mixmonitor.c.
1.6.1