#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/audiohook.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/cli.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
#include "asterisk/linkedlists.h"
#include "asterisk/utils.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 char * | complete_mixmonitor_cli (const char *line, const char *word, int pos, int state) |
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 | mixmonitor_cli (int fd, int argc, char **argv) |
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 | AST_MODFLAG_BUILDSUM, .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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } |
static const char * | app = "MixMonitor" |
static const 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 108 of file app_mixmonitor.c.
00108 { 00109 MUXFLAG_APPEND = (1 << 1), 00110 MUXFLAG_BRIDGED = (1 << 2), 00111 MUXFLAG_VOLUME = (1 << 3), 00112 MUXFLAG_READVOLUME = (1 << 4), 00113 MUXFLAG_WRITEVOLUME = (1 << 5), 00114 } mixmonitor_flags;
anonymous enum |
Definition at line 116 of file app_mixmonitor.c.
00116 { 00117 OPT_ARG_READVOLUME = 0, 00118 OPT_ARG_WRITEVOLUME, 00119 OPT_ARG_VOLUME, 00120 OPT_ARG_ARRAY_SIZE, 00121 } mixmonitor_args;
static void __reg_module | ( | void | ) | [static] |
Definition at line 579 of file app_mixmonitor.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 579 of file app_mixmonitor.c.
static char* complete_mixmonitor_cli | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 541 of file app_mixmonitor.c.
References ast_complete_channels().
00542 { 00543 return ast_complete_channels(line, word, pos, state, 2); 00544 }
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 341 of file app_mixmonitor.c.
References ast_audiohook_destroy(), ast_audiohook_init(), AST_AUDIOHOOK_TRIGGER_SYNC, AST_AUDIOHOOK_TYPE_SPY, ast_log(), ast_pthread_create_background, ast_set_flag, ast_strdupa, ast_strlen_zero(), calloc, mixmonitor::flags, free, 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().
00343 { 00344 pthread_attr_t attr; 00345 pthread_t thread; 00346 struct mixmonitor *mixmonitor; 00347 char postprocess2[1024] = ""; 00348 size_t len; 00349 00350 len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2; 00351 00352 /* If a post process system command is given attach it to the structure */ 00353 if (!ast_strlen_zero(post_process)) { 00354 char *p1, *p2; 00355 00356 p1 = ast_strdupa(post_process); 00357 for (p2 = p1; *p2 ; p2++) { 00358 if (*p2 == '^' && *(p2+1) == '{') { 00359 *p2 = '$'; 00360 } 00361 } 00362 00363 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1); 00364 if (!ast_strlen_zero(postprocess2)) 00365 len += strlen(postprocess2) + 1; 00366 } 00367 00368 /* Pre-allocate mixmonitor structure and spy */ 00369 if (!(mixmonitor = calloc(1, len))) { 00370 return; 00371 } 00372 00373 /* Copy over flags and channel name */ 00374 mixmonitor->flags = flags; 00375 if (setup_mixmonitor_ds(mixmonitor, chan)) { 00376 mixmonitor_free(mixmonitor); 00377 return; 00378 } 00379 mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor); 00380 strcpy(mixmonitor->name, chan->name); 00381 if (!ast_strlen_zero(postprocess2)) { 00382 mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2; 00383 strcpy(mixmonitor->post_process, postprocess2); 00384 } 00385 00386 mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1; 00387 strcpy(mixmonitor->filename, filename); 00388 00389 /* Setup the actual spy before creating our thread */ 00390 if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) { 00391 free(mixmonitor); 00392 return; 00393 } 00394 00395 ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC); 00396 00397 if (readvol) 00398 mixmonitor->audiohook.options.read_volume = readvol; 00399 if (writevol) 00400 mixmonitor->audiohook.options.write_volume = writevol; 00401 00402 if (startmon(chan, &mixmonitor->audiohook)) { 00403 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n", 00404 mixmonitor_spy_type, chan->name); 00405 /* Since we couldn't add ourselves - bail out! */ 00406 ast_audiohook_destroy(&mixmonitor->audiohook); 00407 free(mixmonitor); 00408 return; 00409 } 00410 00411 pthread_attr_init(&attr); 00412 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00413 ast_pthread_create_background(&thread, &attr, mixmonitor_thread, mixmonitor); 00414 pthread_attr_destroy(&attr); 00415 }
static int load_module | ( | void | ) | [static] |
Definition at line 568 of file app_mixmonitor.c.
References ast_cli_register_multiple(), ast_register_application(), cli_mixmonitor, mixmonitor_exec(), and stop_mixmonitor_exec().
00569 { 00570 int res; 00571 00572 ast_cli_register_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry)); 00573 res = ast_register_application(app, mixmonitor_exec, synopsis, desc); 00574 res |= ast_register_application(stop_app, stop_mixmonitor_exec, stop_synopsis, stop_desc); 00575 00576 return res; 00577 }
static int mixmonitor_cli | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 519 of file app_mixmonitor.c.
References ast_audiohook_detach_source(), ast_channel_unlock, ast_cli(), ast_get_channel_by_name_prefix_locked(), mixmonitor_exec(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00520 { 00521 struct ast_channel *chan; 00522 00523 if (argc < 3) 00524 return RESULT_SHOWUSAGE; 00525 00526 if (!(chan = ast_get_channel_by_name_prefix_locked(argv[2], strlen(argv[2])))) { 00527 ast_cli(fd, "No channel matching '%s' found.\n", argv[2]); 00528 return RESULT_SUCCESS; 00529 } 00530 00531 if (!strcasecmp(argv[1], "start")) 00532 mixmonitor_exec(chan, argv[3]); 00533 else if (!strcasecmp(argv[1], "stop")) 00534 ast_audiohook_detach_source(chan, mixmonitor_spy_type); 00535 00536 ast_channel_unlock(chan); 00537 00538 return RESULT_SUCCESS; 00539 }
static void mixmonitor_ds_chan_fixup | ( | void * | data, | |
struct ast_channel * | old_chan, | |||
struct ast_channel * | new_chan | |||
) | [static] |
Definition at line 178 of file app_mixmonitor.c.
References ast_mutex_lock(), ast_mutex_unlock(), mixmonitor_ds::chan, and mixmonitor_ds::lock.
00179 { 00180 struct mixmonitor_ds *mixmonitor_ds = data; 00181 00182 ast_mutex_lock(&mixmonitor_ds->lock); 00183 mixmonitor_ds->chan = new_chan; 00184 ast_mutex_unlock(&mixmonitor_ds->lock); 00185 }
static void mixmonitor_ds_close_fs | ( | struct mixmonitor_ds * | mixmonitor_ds | ) | [static] |
Definition at line 154 of file app_mixmonitor.c.
References ast_closestream(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), mixmonitor_ds::fs, mixmonitor_ds::fs_quit, mixmonitor_ds::lock, option_verbose, and VERBOSE_PREFIX_2.
Referenced by mixmonitor_thread(), and stop_mixmonitor_exec().
00155 { 00156 ast_mutex_lock(&mixmonitor_ds->lock); 00157 if (mixmonitor_ds->fs) { 00158 ast_closestream(mixmonitor_ds->fs); 00159 mixmonitor_ds->fs = NULL; 00160 mixmonitor_ds->fs_quit = 1; 00161 if (option_verbose > 1) 00162 ast_verbose(VERBOSE_PREFIX_2 "MixMonitor close filestream\n"); 00163 } 00164 ast_mutex_unlock(&mixmonitor_ds->lock); 00165 }
static void mixmonitor_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 167 of file app_mixmonitor.c.
References ast_cond_signal(), ast_mutex_lock(), ast_mutex_unlock(), mixmonitor_ds::chan, mixmonitor_ds::destruction_condition, mixmonitor_ds::destruction_ok, and mixmonitor_ds::lock.
00168 { 00169 struct mixmonitor_ds *mixmonitor_ds = data; 00170 00171 ast_mutex_lock(&mixmonitor_ds->lock); 00172 mixmonitor_ds->chan = NULL; 00173 mixmonitor_ds->destruction_ok = 1; 00174 ast_cond_signal(&mixmonitor_ds->destruction_condition); 00175 ast_mutex_unlock(&mixmonitor_ds->lock); 00176 }
static int mixmonitor_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 417 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_module_user_add, ast_module_user_remove, 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 load_module(), and mixmonitor_cli().
00418 { 00419 int x, readvol = 0, writevol = 0; 00420 struct ast_module_user *u; 00421 struct ast_flags flags = {0}; 00422 char *parse; 00423 AST_DECLARE_APP_ARGS(args, 00424 AST_APP_ARG(filename); 00425 AST_APP_ARG(options); 00426 AST_APP_ARG(post_process); 00427 ); 00428 00429 if (ast_strlen_zero(data)) { 00430 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00431 return -1; 00432 } 00433 00434 u = ast_module_user_add(chan); 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 ast_module_user_remove(u); 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 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename); 00492 launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process); 00493 00494 ast_module_user_remove(u); 00495 00496 return 0; 00497 }
static void mixmonitor_free | ( | struct mixmonitor * | mixmonitor | ) | [static] |
Definition at line 211 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().
00212 { 00213 if (mixmonitor) { 00214 if (mixmonitor->mixmonitor_ds) { 00215 ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock); 00216 ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition); 00217 ast_free(mixmonitor->mixmonitor_ds); 00218 } 00219 ast_free(mixmonitor); 00220 } 00221 }
static void* mixmonitor_thread | ( | void * | obj | ) | [static] |
Definition at line 223 of file app_mixmonitor.c.
References ast_audiohook_destroy(), ast_audiohook_detach(), 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_verbose(), ast_writefile(), ast_writestream(), mixmonitor::audiohook, mixmonitor_ds::chan, 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, option_verbose, mixmonitor::post_process, SAMPLES_PER_FRAME, ast_audiohook::status, and VERBOSE_PREFIX_2.
Referenced by launch_monitor_thread().
00224 { 00225 struct mixmonitor *mixmonitor = obj; 00226 struct ast_filestream **fs = NULL; 00227 unsigned int oflags; 00228 char *ext; 00229 int errflag = 0; 00230 00231 if (option_verbose > 1) 00232 ast_verbose(VERBOSE_PREFIX_2 "Begin MixMonitor Recording %s\n", mixmonitor->name); 00233 00234 ast_audiohook_lock(&mixmonitor->audiohook); 00235 00236 fs = &mixmonitor->mixmonitor_ds->fs; 00237 00238 while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) { 00239 struct ast_frame *fr = NULL; 00240 00241 ast_audiohook_trigger_wait(&mixmonitor->audiohook); 00242 00243 if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) 00244 break; 00245 00246 if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) 00247 continue; 00248 00249 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00250 if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) { 00251 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00252 /* Initialize the file if not already done so */ 00253 if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) { 00254 oflags = O_CREAT | O_WRONLY; 00255 oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC; 00256 00257 if ((ext = strrchr(mixmonitor->filename, '.'))) 00258 *(ext++) = '\0'; 00259 else 00260 ext = "raw"; 00261 00262 if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0644))) { 00263 ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext); 00264 errflag = 1; 00265 } 00266 } 00267 00268 /* Write out the frame(s) */ 00269 if (*fs) { 00270 struct ast_frame *cur; 00271 00272 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) { 00273 ast_writestream(*fs, cur); 00274 } 00275 } 00276 } else { 00277 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00278 } 00279 00280 /* All done! free it. */ 00281 ast_frame_free(fr, 0); 00282 } 00283 00284 ast_audiohook_detach(&mixmonitor->audiohook); 00285 ast_audiohook_unlock(&mixmonitor->audiohook); 00286 ast_audiohook_destroy(&mixmonitor->audiohook); 00287 00288 mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds); 00289 00290 if (mixmonitor->post_process) { 00291 if (option_verbose > 2) 00292 ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", mixmonitor->post_process); 00293 ast_safe_system(mixmonitor->post_process); 00294 } 00295 00296 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00297 if (!mixmonitor->mixmonitor_ds->destruction_ok) { 00298 ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock); 00299 } 00300 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00301 00302 if (option_verbose > 1) 00303 ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name); 00304 00305 mixmonitor_free(mixmonitor); 00306 00307 return NULL; 00308 }
static int setup_mixmonitor_ds | ( | struct mixmonitor * | mixmonitor, | |
struct ast_channel * | chan | |||
) | [static] |
Definition at line 310 of file app_mixmonitor.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy(), ast_cond_init(), ast_free, ast_mutex_destroy(), ast_mutex_init(), mixmonitor_ds::chan, ast_datastore::data, mixmonitor::mixmonitor_ds, and mixmonitor_ds_info.
Referenced by launch_monitor_thread().
00311 { 00312 struct ast_datastore *datastore = NULL; 00313 struct mixmonitor_ds *mixmonitor_ds; 00314 00315 if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) { 00316 return -1; 00317 } 00318 00319 ast_mutex_init(&mixmonitor_ds->lock); 00320 ast_cond_init(&mixmonitor_ds->destruction_condition, NULL); 00321 00322 if (!(datastore = ast_channel_datastore_alloc(&mixmonitor_ds_info, NULL))) { 00323 ast_mutex_destroy(&mixmonitor_ds->lock); 00324 ast_cond_destroy(&mixmonitor_ds->destruction_condition); 00325 ast_free(mixmonitor_ds); 00326 return -1; 00327 } 00328 00329 /* No need to lock mixmonitor_ds since this is still operating in the channel's thread */ 00330 mixmonitor_ds->chan = chan; 00331 datastore->data = mixmonitor_ds; 00332 00333 ast_channel_lock(chan); 00334 ast_channel_datastore_add(chan, datastore); 00335 ast_channel_unlock(chan); 00336 00337 mixmonitor->mixmonitor_ds = mixmonitor_ds; 00338 return 0; 00339 }
static int startmon | ( | struct ast_channel * | chan, | |
struct ast_audiohook * | audiohook | |||
) | [static] |
Definition at line 193 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().
00194 { 00195 struct ast_channel *peer; 00196 int res; 00197 00198 if (!chan) 00199 return -1; 00200 00201 res = ast_audiohook_attach(chan, audiohook); 00202 00203 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) 00204 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00205 00206 return res; 00207 }
static int stop_mixmonitor_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 499 of file app_mixmonitor.c.
References ast_audiohook_detach_source(), ast_channel_datastore_find(), ast_module_user_add, ast_module_user_remove, ast_datastore::data, mixmonitor_ds_close_fs(), and mixmonitor_ds_info.
Referenced by load_module().
00500 { 00501 struct ast_module_user *u; 00502 struct ast_datastore *datastore = NULL; 00503 00504 /* closing the filestream here guarantees the file is avaliable to the dialplan 00505 * after calling StopMixMonitor */ 00506 if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) { 00507 mixmonitor_ds_close_fs(datastore->data); 00508 } 00509 00510 u = ast_module_user_add(chan); 00511 00512 ast_audiohook_detach_source(chan, mixmonitor_spy_type); 00513 00514 ast_module_user_remove(u); 00515 00516 return 0; 00517 }
static int unload_module | ( | void | ) | [static] |
Definition at line 555 of file app_mixmonitor.c.
References ast_cli_unregister_multiple(), ast_module_user_hangup_all, ast_unregister_application(), and cli_mixmonitor.
00556 { 00557 int res; 00558 00559 ast_cli_unregister_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry)); 00560 res = ast_unregister_application(stop_app); 00561 res |= ast_unregister_application(app); 00562 00563 ast_module_user_hangup_all(); 00564 00565 return res; 00566 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 579 of file app_mixmonitor.c.
const char* app = "MixMonitor" [static] |
Definition at line 60 of file app_mixmonitor.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 579 of file app_mixmonitor.c.
struct ast_cli_entry cli_mixmonitor[] [static] |
const char* desc [static] |
Definition at line 62 of file app_mixmonitor.c.
struct module_symbols* me |
Definition at line 95 of file app_mixmonitor.c.
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 187 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] |
Definition at line 97 of file app_mixmonitor.c.
const char* stop_app = "StopMixMonitor" [static] |
Definition at line 88 of file app_mixmonitor.c.
const char* stop_desc [static] |
Initial value:
"" " StopMixMonitor()\n\n" "Stop recording a call through MixMonitor, and free the recording's file handle.\n" ""
Definition at line 90 of file app_mixmonitor.c.
const char* stop_synopsis = "Stop recording a call through MixMonitor" [static] |
Definition at line 89 of file app_mixmonitor.c.
const char* synopsis = "Record a call and mix the audio during the recording" [static] |
Definition at line 61 of file app_mixmonitor.c.