#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 |
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" |
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 |
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 601 of file app_mixmonitor.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 601 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 539 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.
00540 { 00541 struct ast_channel *chan; 00542 00543 switch (cmd) { 00544 case CLI_INIT: 00545 e->command = "mixmonitor [start|stop]"; 00546 e->usage = 00547 "Usage: mixmonitor <start|stop> <chan_name> [args]\n" 00548 " The optional arguments are passed to the MixMonitor\n" 00549 " application when the 'start' command is used.\n"; 00550 return NULL; 00551 case CLI_GENERATE: 00552 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2); 00553 } 00554 00555 if (a->argc < 3) 00556 return CLI_SHOWUSAGE; 00557 00558 if (!(chan = ast_get_channel_by_name_prefix_locked(a->argv[2], strlen(a->argv[2])))) { 00559 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]); 00560 /* Technically this is a failure, but we don't want 2 errors printing out */ 00561 return CLI_SUCCESS; 00562 } 00563 00564 if (!strcasecmp(a->argv[1], "start")) { 00565 mixmonitor_exec(chan, a->argv[3]); 00566 ast_channel_unlock(chan); 00567 } else { 00568 ast_channel_unlock(chan); 00569 ast_audiohook_detach_source(chan, mixmonitor_spy_type); 00570 } 00571 00572 return CLI_SUCCESS; 00573 }
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 350 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, chan, 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().
00352 { 00353 pthread_t thread; 00354 struct mixmonitor *mixmonitor; 00355 char postprocess2[1024] = ""; 00356 size_t len; 00357 00358 len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2; 00359 00360 postprocess2[0] = 0; 00361 /* If a post process system command is given attach it to the structure */ 00362 if (!ast_strlen_zero(post_process)) { 00363 char *p1, *p2; 00364 00365 p1 = ast_strdupa(post_process); 00366 for (p2 = p1; *p2 ; p2++) { 00367 if (*p2 == '^' && *(p2+1) == '{') { 00368 *p2 = '$'; 00369 } 00370 } 00371 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1); 00372 if (!ast_strlen_zero(postprocess2)) 00373 len += strlen(postprocess2) + 1; 00374 } 00375 00376 /* Pre-allocate mixmonitor structure and spy */ 00377 if (!(mixmonitor = ast_calloc(1, len))) { 00378 return; 00379 } 00380 00381 /* Setup the actual spy before creating our thread */ 00382 if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) { 00383 mixmonitor_free(mixmonitor); 00384 return; 00385 } 00386 00387 /* Copy over flags and channel name */ 00388 mixmonitor->flags = flags; 00389 if (setup_mixmonitor_ds(mixmonitor, chan)) { 00390 mixmonitor_free(mixmonitor); 00391 return; 00392 } 00393 mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor); 00394 strcpy(mixmonitor->name, chan->name); 00395 if (!ast_strlen_zero(postprocess2)) { 00396 mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2; 00397 strcpy(mixmonitor->post_process, postprocess2); 00398 } 00399 00400 mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1; 00401 strcpy(mixmonitor->filename, filename); 00402 00403 ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC); 00404 00405 if (readvol) 00406 mixmonitor->audiohook.options.read_volume = readvol; 00407 if (writevol) 00408 mixmonitor->audiohook.options.write_volume = writevol; 00409 00410 if (startmon(chan, &mixmonitor->audiohook)) { 00411 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n", 00412 mixmonitor_spy_type, chan->name); 00413 ast_audiohook_destroy(&mixmonitor->audiohook); 00414 mixmonitor_free(mixmonitor); 00415 return; 00416 } 00417 00418 ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor); 00419 }
static int load_module | ( | void | ) | [static] |
Definition at line 590 of file app_mixmonitor.c.
References ast_cli_register_multiple(), ast_register_application, cli_mixmonitor, mixmonitor_exec(), and stop_mixmonitor_exec().
00591 { 00592 int res; 00593 00594 ast_cli_register_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry)); 00595 res = ast_register_application(app, mixmonitor_exec, synopsis, desc); 00596 res |= ast_register_application(stop_app, stop_mixmonitor_exec, stop_synopsis, stop_desc); 00597 00598 return res; 00599 }
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().
00151 { 00152 if (mixmonitor_ds->fs) { 00153 ast_closestream(mixmonitor_ds->fs); 00154 mixmonitor_ds->fs = NULL; 00155 mixmonitor_ds->fs_quit = 1; 00156 ast_verb(2, "MixMonitor close filestream\n"); 00157 } 00158 }
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 421 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, chan, 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().
00422 { 00423 int x, readvol = 0, writevol = 0; 00424 struct ast_flags flags = {0}; 00425 char *parse, *tmp, *slash; 00426 AST_DECLARE_APP_ARGS(args, 00427 AST_APP_ARG(filename); 00428 AST_APP_ARG(options); 00429 AST_APP_ARG(post_process); 00430 ); 00431 00432 if (ast_strlen_zero(data)) { 00433 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00434 return -1; 00435 } 00436 00437 parse = ast_strdupa(data); 00438 00439 AST_STANDARD_APP_ARGS(args, parse); 00440 00441 if (ast_strlen_zero(args.filename)) { 00442 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00443 return -1; 00444 } 00445 00446 if (args.options) { 00447 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, }; 00448 00449 ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options); 00450 00451 if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) { 00452 if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) { 00453 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n"); 00454 } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00455 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]); 00456 } else { 00457 readvol = get_volfactor(x); 00458 } 00459 } 00460 00461 if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) { 00462 if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) { 00463 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n"); 00464 } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00465 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]); 00466 } else { 00467 writevol = get_volfactor(x); 00468 } 00469 } 00470 00471 if (ast_test_flag(&flags, MUXFLAG_VOLUME)) { 00472 if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) { 00473 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n"); 00474 } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00475 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]); 00476 } else { 00477 readvol = writevol = get_volfactor(x); 00478 } 00479 } 00480 } 00481 00482 /* if not provided an absolute path, use the system-configured monitoring directory */ 00483 if (args.filename[0] != '/') { 00484 char *build; 00485 00486 build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3); 00487 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename); 00488 args.filename = build; 00489 } 00490 00491 tmp = ast_strdupa(args.filename); 00492 if ((slash = strrchr(tmp, '/'))) 00493 *slash = '\0'; 00494 ast_mkdir(tmp, 0777); 00495 00496 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename); 00497 launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process); 00498 00499 return 0; 00500 }
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 if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) { 00249 ast_audiohook_trigger_wait(&mixmonitor->audiohook); 00250 00251 if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { 00252 break; 00253 } 00254 continue; 00255 } 00256 00257 /* audiohook lock is not required for the next block. 00258 * Unlock it, but remember to lock it before looping or exiting */ 00259 ast_audiohook_unlock(&mixmonitor->audiohook); 00260 00261 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00262 if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) { 00263 /* Initialize the file if not already done so */ 00264 if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) { 00265 oflags = O_CREAT | O_WRONLY; 00266 oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC; 00267 00268 if ((ext = strrchr(mixmonitor->filename, '.'))) 00269 *(ext++) = '\0'; 00270 else 00271 ext = "raw"; 00272 00273 if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0666))) { 00274 ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext); 00275 errflag = 1; 00276 } 00277 } 00278 00279 /* Write out the frame(s) */ 00280 if (*fs) { 00281 struct ast_frame *cur; 00282 00283 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) { 00284 ast_writestream(*fs, cur); 00285 } 00286 } 00287 } 00288 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00289 00290 /* All done! free it. */ 00291 ast_frame_free(fr, 0); 00292 ast_audiohook_lock(&mixmonitor->audiohook); 00293 } 00294 00295 ast_audiohook_unlock(&mixmonitor->audiohook); 00296 00297 /* Datastore cleanup. close the filestream and wait for ds destruction */ 00298 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00299 mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds); 00300 if (!mixmonitor->mixmonitor_ds->destruction_ok) { 00301 ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock); 00302 } 00303 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00304 00305 /* kill the audiohook */ 00306 destroy_monitor_audiohook(mixmonitor); 00307 00308 if (mixmonitor->post_process) { 00309 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process); 00310 ast_safe_system(mixmonitor->post_process); 00311 } 00312 00313 ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name); 00314 mixmonitor_free(mixmonitor); 00315 return NULL; 00316 }
static int setup_mixmonitor_ds | ( | struct mixmonitor * | mixmonitor, | |
struct ast_channel * | chan | |||
) | [static] |
Definition at line 318 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, chan, ast_datastore::data, mixmonitor::mixmonitor_ds, and mixmonitor_ds_info.
Referenced by launch_monitor_thread().
00319 { 00320 struct ast_datastore *datastore = NULL; 00321 struct mixmonitor_ds *mixmonitor_ds; 00322 00323 if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) { 00324 return -1; 00325 } 00326 00327 ast_mutex_init(&mixmonitor_ds->lock); 00328 ast_cond_init(&mixmonitor_ds->destruction_condition, NULL); 00329 00330 if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) { 00331 ast_mutex_destroy(&mixmonitor_ds->lock); 00332 ast_cond_destroy(&mixmonitor_ds->destruction_condition); 00333 ast_free(mixmonitor_ds); 00334 return -1; 00335 } 00336 00337 /* No need to lock mixmonitor_ds since this is still operating in the channel's thread */ 00338 mixmonitor_ds->chan = chan; 00339 mixmonitor_ds->audiohook = &mixmonitor->audiohook; 00340 datastore->data = mixmonitor_ds; 00341 00342 ast_channel_lock(chan); 00343 ast_channel_datastore_add(chan, datastore); 00344 ast_channel_unlock(chan); 00345 00346 mixmonitor->mixmonitor_ds = mixmonitor_ds; 00347 return 0; 00348 }
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, ast_test_flag, and chan.
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 502 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, chan, ast_datastore::data, mixmonitor_ds::lock, mixmonitor_ds_close_fs(), mixmonitor_ds_info, and ast_audiohook::trigger.
Referenced by load_module().
00503 { 00504 struct ast_datastore *datastore = NULL; 00505 00506 ast_channel_lock(chan); 00507 ast_audiohook_detach_source(chan, mixmonitor_spy_type); 00508 if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) { 00509 struct mixmonitor_ds *mixmonitor_ds = datastore->data; 00510 00511 ast_mutex_lock(&mixmonitor_ds->lock); 00512 00513 /* closing the filestream here guarantees the file is avaliable to the dialplan 00514 * after calling StopMixMonitor */ 00515 mixmonitor_ds_close_fs(mixmonitor_ds); 00516 00517 /* The mixmonitor thread may be waiting on the audiohook trigger. 00518 * In order to exit from the mixmonitor loop before waiting on channel 00519 * destruction, poke the audiohook trigger. */ 00520 if (mixmonitor_ds->audiohook) { 00521 ast_audiohook_lock(mixmonitor_ds->audiohook); 00522 ast_cond_signal(&mixmonitor_ds->audiohook->trigger); 00523 ast_audiohook_unlock(mixmonitor_ds->audiohook); 00524 mixmonitor_ds->audiohook = NULL; 00525 } 00526 00527 ast_mutex_unlock(&mixmonitor_ds->lock); 00528 00529 /* Remove the datastore so the monitor thread can exit */ 00530 if (!ast_channel_datastore_remove(chan, datastore)) { 00531 ast_datastore_free(datastore); 00532 } 00533 } 00534 ast_channel_unlock(chan); 00535 00536 return 0; 00537 }
static int unload_module | ( | void | ) | [static] |
Definition at line 579 of file app_mixmonitor.c.
References ast_cli_unregister_multiple(), ast_unregister_application(), and cli_mixmonitor.
00580 { 00581 int res; 00582 00583 ast_cli_unregister_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry)); 00584 res = ast_unregister_application(stop_app); 00585 res |= ast_unregister_application(app); 00586 00587 return res; 00588 }
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 601 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 601 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 575 of file app_mixmonitor.c.
Referenced by load_module(), and unload_module().
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] |
Initial value:
{ .type = "mixmonitor", .destroy = mixmonitor_ds_destroy, .chan_fixup = mixmonitor_ds_chan_fixup, }
Definition at line 181 of file app_mixmonitor.c.
Referenced by setup_mixmonitor_ds(), and stop_mixmonitor_exec().
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] |
const char* mixmonitor_spy_type = "MixMonitor" [static] |
const char* stop_app = "StopMixMonitor" [static] |
Definition at line 79 of file app_mixmonitor.c.
const char* stop_desc [static] |
Initial value:
"" " 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.