#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 | destroy_monitor_audiohook (struct mixmonitor *mixmonitor) |
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 624 of file app_mixmonitor.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 624 of file app_mixmonitor.c.
static char* complete_mixmonitor_cli | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 586 of file app_mixmonitor.c.
References ast_complete_channels().
00587 { 00588 return ast_complete_channels(line, word, pos, state, 2); 00589 }
static void destroy_monitor_audiohook | ( | struct mixmonitor * | mixmonitor | ) | [static] |
Definition at line 197 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().
00198 { 00199 if (mixmonitor->mixmonitor_ds) { 00200 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00201 mixmonitor->mixmonitor_ds->audiohook = NULL; 00202 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00203 } 00204 /* kill the audiohook.*/ 00205 ast_audiohook_lock(&mixmonitor->audiohook); 00206 ast_audiohook_detach(&mixmonitor->audiohook); 00207 ast_audiohook_unlock(&mixmonitor->audiohook); 00208 ast_audiohook_destroy(&mixmonitor->audiohook); 00209 }
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 369 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(), mixmonitor::audiohook, calloc, 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().
00371 { 00372 pthread_attr_t attr; 00373 pthread_t thread; 00374 struct mixmonitor *mixmonitor; 00375 char postprocess2[1024] = ""; 00376 size_t len; 00377 00378 len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2; 00379 00380 /* If a post process system command is given attach it to the structure */ 00381 if (!ast_strlen_zero(post_process)) { 00382 char *p1, *p2; 00383 00384 p1 = ast_strdupa(post_process); 00385 for (p2 = p1; *p2 ; p2++) { 00386 if (*p2 == '^' && *(p2+1) == '{') { 00387 *p2 = '$'; 00388 } 00389 } 00390 00391 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1); 00392 if (!ast_strlen_zero(postprocess2)) 00393 len += strlen(postprocess2) + 1; 00394 } 00395 00396 /* Pre-allocate mixmonitor structure and spy */ 00397 if (!(mixmonitor = calloc(1, len))) { 00398 return; 00399 } 00400 00401 /* Setup the actual spy before creating our thread */ 00402 if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) { 00403 mixmonitor_free(mixmonitor); 00404 return; 00405 } 00406 00407 /* Copy over flags and channel name */ 00408 mixmonitor->flags = flags; 00409 if (setup_mixmonitor_ds(mixmonitor, chan)) { 00410 mixmonitor_free(mixmonitor); 00411 return; 00412 } 00413 mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor); 00414 strcpy(mixmonitor->name, chan->name); 00415 if (!ast_strlen_zero(postprocess2)) { 00416 mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2; 00417 strcpy(mixmonitor->post_process, postprocess2); 00418 } 00419 00420 mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1; 00421 strcpy(mixmonitor->filename, filename); 00422 00423 ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC); 00424 00425 if (readvol) 00426 mixmonitor->audiohook.options.read_volume = readvol; 00427 if (writevol) 00428 mixmonitor->audiohook.options.write_volume = writevol; 00429 00430 if (startmon(chan, &mixmonitor->audiohook)) { 00431 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n", 00432 mixmonitor_spy_type, chan->name); 00433 /* Since we couldn't add ourselves - bail out! */ 00434 ast_audiohook_destroy(&mixmonitor->audiohook); 00435 mixmonitor_free(mixmonitor); 00436 return; 00437 } 00438 00439 pthread_attr_init(&attr); 00440 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00441 ast_pthread_create_background(&thread, &attr, mixmonitor_thread, mixmonitor); 00442 pthread_attr_destroy(&attr); 00443 }
static int load_module | ( | void | ) | [static] |
Definition at line 613 of file app_mixmonitor.c.
References ast_cli_register_multiple(), ast_register_application(), cli_mixmonitor, mixmonitor_exec(), and stop_mixmonitor_exec().
00614 { 00615 int res; 00616 00617 ast_cli_register_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry)); 00618 res = ast_register_application(app, mixmonitor_exec, synopsis, desc); 00619 res |= ast_register_application(stop_app, stop_mixmonitor_exec, stop_synopsis, stop_desc); 00620 00621 return res; 00622 }
static int mixmonitor_cli | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 564 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.
00565 { 00566 struct ast_channel *chan; 00567 00568 if (argc < 3) 00569 return RESULT_SHOWUSAGE; 00570 00571 if (!(chan = ast_get_channel_by_name_prefix_locked(argv[2], strlen(argv[2])))) { 00572 ast_cli(fd, "No channel matching '%s' found.\n", argv[2]); 00573 return RESULT_SUCCESS; 00574 } 00575 00576 if (!strcasecmp(argv[1], "start")) 00577 mixmonitor_exec(chan, argv[3]); 00578 else if (!strcasecmp(argv[1], "stop")) 00579 ast_audiohook_detach_source(chan, mixmonitor_spy_type); 00580 00581 ast_channel_unlock(chan); 00582 00583 return RESULT_SUCCESS; 00584 }
static void mixmonitor_ds_chan_fixup | ( | void * | data, | |
struct ast_channel * | old_chan, | |||
struct ast_channel * | new_chan | |||
) | [static] |
Definition at line 182 of file app_mixmonitor.c.
References ast_mutex_lock(), ast_mutex_unlock(), mixmonitor_ds::chan, and mixmonitor_ds::lock.
00183 { 00184 struct mixmonitor_ds *mixmonitor_ds = data; 00185 00186 ast_mutex_lock(&mixmonitor_ds->lock); 00187 mixmonitor_ds->chan = new_chan; 00188 ast_mutex_unlock(&mixmonitor_ds->lock); 00189 }
static void mixmonitor_ds_close_fs | ( | struct mixmonitor_ds * | mixmonitor_ds | ) | [static] |
Definition at line 159 of file app_mixmonitor.c.
References ast_closestream(), ast_verbose(), mixmonitor_ds::fs, mixmonitor_ds::fs_quit, option_verbose, and VERBOSE_PREFIX_2.
Referenced by mixmonitor_thread(), and stop_mixmonitor_exec().
00160 { 00161 if (mixmonitor_ds->fs) { 00162 ast_closestream(mixmonitor_ds->fs); 00163 mixmonitor_ds->fs = NULL; 00164 mixmonitor_ds->fs_quit = 1; 00165 if (option_verbose > 1) 00166 ast_verbose(VERBOSE_PREFIX_2 "MixMonitor close filestream\n"); 00167 } 00168 }
static void mixmonitor_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 170 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.
00171 { 00172 struct mixmonitor_ds *mixmonitor_ds = data; 00173 00174 ast_mutex_lock(&mixmonitor_ds->lock); 00175 mixmonitor_ds->audiohook = NULL; 00176 mixmonitor_ds->chan = NULL; 00177 mixmonitor_ds->destruction_ok = 1; 00178 ast_cond_signal(&mixmonitor_ds->destruction_condition); 00179 ast_mutex_unlock(&mixmonitor_ds->lock); 00180 }
static int mixmonitor_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 445 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().
00446 { 00447 int x, readvol = 0, writevol = 0; 00448 struct ast_module_user *u; 00449 struct ast_flags flags = {0}; 00450 char *parse; 00451 AST_DECLARE_APP_ARGS(args, 00452 AST_APP_ARG(filename); 00453 AST_APP_ARG(options); 00454 AST_APP_ARG(post_process); 00455 ); 00456 00457 if (ast_strlen_zero(data)) { 00458 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00459 return -1; 00460 } 00461 00462 u = ast_module_user_add(chan); 00463 00464 parse = ast_strdupa(data); 00465 00466 AST_STANDARD_APP_ARGS(args, parse); 00467 00468 if (ast_strlen_zero(args.filename)) { 00469 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00470 ast_module_user_remove(u); 00471 return -1; 00472 } 00473 00474 if (args.options) { 00475 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, }; 00476 00477 ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options); 00478 00479 if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) { 00480 if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) { 00481 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n"); 00482 } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00483 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]); 00484 } else { 00485 readvol = get_volfactor(x); 00486 } 00487 } 00488 00489 if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) { 00490 if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) { 00491 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n"); 00492 } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00493 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]); 00494 } else { 00495 writevol = get_volfactor(x); 00496 } 00497 } 00498 00499 if (ast_test_flag(&flags, MUXFLAG_VOLUME)) { 00500 if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) { 00501 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n"); 00502 } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) { 00503 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]); 00504 } else { 00505 readvol = writevol = get_volfactor(x); 00506 } 00507 } 00508 } 00509 00510 /* if not provided an absolute path, use the system-configured monitoring directory */ 00511 if (args.filename[0] != '/') { 00512 char *build; 00513 00514 build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3); 00515 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename); 00516 args.filename = build; 00517 } 00518 00519 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename); 00520 launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process); 00521 00522 ast_module_user_remove(u); 00523 00524 return 0; 00525 }
static void mixmonitor_free | ( | struct mixmonitor * | mixmonitor | ) | [static] |
Definition at line 229 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().
00230 { 00231 if (mixmonitor) { 00232 if (mixmonitor->mixmonitor_ds) { 00233 ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock); 00234 ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition); 00235 ast_free(mixmonitor->mixmonitor_ds); 00236 } 00237 ast_free(mixmonitor); 00238 } 00239 }
static void* mixmonitor_thread | ( | void * | obj | ) | [static] |
Definition at line 241 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_verbose(), 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, option_verbose, mixmonitor::post_process, SAMPLES_PER_FRAME, ast_audiohook::status, and VERBOSE_PREFIX_2.
Referenced by launch_monitor_thread().
00242 { 00243 struct mixmonitor *mixmonitor = obj; 00244 struct ast_filestream **fs = NULL; 00245 unsigned int oflags; 00246 char *ext; 00247 char *last_slash; 00248 int errflag = 0; 00249 00250 if (option_verbose > 1) 00251 ast_verbose(VERBOSE_PREFIX_2 "Begin MixMonitor Recording %s\n", mixmonitor->name); 00252 00253 fs = &mixmonitor->mixmonitor_ds->fs; 00254 00255 /* The audiohook must enter and exit the loop locked */ 00256 ast_audiohook_lock(&mixmonitor->audiohook); 00257 while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) { 00258 struct ast_frame *fr = NULL; 00259 00260 if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) { 00261 ast_audiohook_trigger_wait(&mixmonitor->audiohook); 00262 00263 if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { 00264 break; 00265 } 00266 continue; 00267 } 00268 00269 /* audiohook lock is not required for the next block. 00270 * Unlock it, but remember to lock it before looping or exiting */ 00271 ast_audiohook_unlock(&mixmonitor->audiohook); 00272 00273 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00274 if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) { 00275 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00276 /* Initialize the file if not already done so */ 00277 if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) { 00278 oflags = O_CREAT | O_WRONLY; 00279 oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC; 00280 00281 last_slash = strrchr(mixmonitor->filename, '/'); 00282 if ((ext = strrchr(mixmonitor->filename, '.')) && (ext > last_slash)) 00283 *(ext++) = '\0'; 00284 else 00285 ext = "raw"; 00286 00287 if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0644))) { 00288 ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext); 00289 errflag = 1; 00290 } 00291 } 00292 00293 /* Write out the frame(s) */ 00294 if (*fs) { 00295 struct ast_frame *cur; 00296 00297 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) { 00298 ast_writestream(*fs, cur); 00299 } 00300 } 00301 } else { 00302 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00303 } 00304 00305 /* All done! free it. */ 00306 ast_frame_free(fr, 0); 00307 00308 ast_audiohook_lock(&mixmonitor->audiohook); 00309 } 00310 ast_audiohook_unlock(&mixmonitor->audiohook); 00311 00312 /* Datastore cleanup. close the filestream and wait for ds destruction */ 00313 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); 00314 mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds); 00315 if (!mixmonitor->mixmonitor_ds->destruction_ok) { 00316 ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock); 00317 } 00318 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); 00319 00320 /* kill the audiohook */ 00321 destroy_monitor_audiohook(mixmonitor); 00322 00323 if (mixmonitor->post_process) { 00324 if (option_verbose > 2) 00325 ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", mixmonitor->post_process); 00326 ast_safe_system(mixmonitor->post_process); 00327 } 00328 00329 if (option_verbose > 1) 00330 ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name); 00331 00332 mixmonitor_free(mixmonitor); 00333 00334 return NULL; 00335 }
static int setup_mixmonitor_ds | ( | struct mixmonitor * | mixmonitor, | |
struct ast_channel * | chan | |||
) | [static] |
Definition at line 337 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::audiohook, mixmonitor_ds::chan, ast_datastore::data, mixmonitor::mixmonitor_ds, and mixmonitor_ds_info.
Referenced by launch_monitor_thread().
00338 { 00339 struct ast_datastore *datastore = NULL; 00340 struct mixmonitor_ds *mixmonitor_ds; 00341 00342 if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) { 00343 return -1; 00344 } 00345 00346 ast_mutex_init(&mixmonitor_ds->lock); 00347 ast_cond_init(&mixmonitor_ds->destruction_condition, NULL); 00348 00349 if (!(datastore = ast_channel_datastore_alloc(&mixmonitor_ds_info, NULL))) { 00350 ast_mutex_destroy(&mixmonitor_ds->lock); 00351 ast_cond_destroy(&mixmonitor_ds->destruction_condition); 00352 ast_free(mixmonitor_ds); 00353 return -1; 00354 } 00355 00356 /* No need to lock mixmonitor_ds since this is still operating in the channel's thread */ 00357 mixmonitor_ds->chan = chan; 00358 mixmonitor_ds->audiohook = &mixmonitor->audiohook; 00359 datastore->data = mixmonitor_ds; 00360 00361 ast_channel_lock(chan); 00362 ast_channel_datastore_add(chan, datastore); 00363 ast_channel_unlock(chan); 00364 00365 mixmonitor->mixmonitor_ds = mixmonitor_ds; 00366 return 0; 00367 }
static int startmon | ( | struct ast_channel * | chan, | |
struct ast_audiohook * | audiohook | |||
) | [static] |
Definition at line 211 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().
00212 { 00213 struct ast_channel *peer; 00214 int res; 00215 00216 if (!chan) 00217 return -1; 00218 00219 res = ast_audiohook_attach(chan, audiohook); 00220 00221 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) 00222 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00223 00224 return res; 00225 }
static int stop_mixmonitor_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 527 of file app_mixmonitor.c.
References ast_audiohook_detach_source(), ast_audiohook_lock, ast_audiohook_unlock, ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_cond_signal(), ast_mutex_lock(), ast_mutex_unlock(), mixmonitor_ds::audiohook, mixmonitor_ds::chan, ast_datastore::data, mixmonitor_ds::lock, mixmonitor_ds_close_fs(), mixmonitor_ds_info, and ast_audiohook::trigger.
Referenced by load_module().
00528 { 00529 struct ast_datastore *datastore = NULL; 00530 00531 ast_channel_lock(chan); 00532 ast_audiohook_detach_source(chan, mixmonitor_spy_type); 00533 if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) { 00534 struct mixmonitor_ds *mixmonitor_ds = datastore->data; 00535 00536 ast_mutex_lock(&mixmonitor_ds->lock); 00537 00538 /* closing the filestream here guarantees the file is avaliable to the dialplan 00539 * after calling StopMixMonitor */ 00540 mixmonitor_ds_close_fs(mixmonitor_ds); 00541 00542 /* The mixmonitor thread may be waiting on the audiohook trigger. 00543 * In order to exit from the mixmonitor loop before waiting on channel 00544 * destruction, poke the audiohook trigger. */ 00545 if (mixmonitor_ds->audiohook) { 00546 ast_audiohook_lock(mixmonitor_ds->audiohook); 00547 ast_cond_signal(&mixmonitor_ds->audiohook->trigger); 00548 ast_audiohook_unlock(mixmonitor_ds->audiohook); 00549 mixmonitor_ds->audiohook = NULL; 00550 } 00551 00552 ast_mutex_unlock(&mixmonitor_ds->lock); 00553 00554 /* Remove the datastore so the monitor thread can exit */ 00555 if (!ast_channel_datastore_remove(chan, datastore)) { 00556 ast_channel_datastore_free(datastore); 00557 } 00558 } 00559 ast_channel_unlock(chan); 00560 00561 return 0; 00562 }
static int unload_module | ( | void | ) | [static] |
Definition at line 600 of file app_mixmonitor.c.
References ast_cli_unregister_multiple(), ast_module_user_hangup_all, ast_unregister_application(), and cli_mixmonitor.
00601 { 00602 int res; 00603 00604 ast_cli_unregister_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry)); 00605 res = ast_unregister_application(stop_app); 00606 res |= ast_unregister_application(app); 00607 00608 ast_module_user_hangup_all(); 00609 00610 return res; 00611 }
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 624 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 624 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 191 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.