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