MixMonitor() - Record a call and mix the audio during the recording. More...
#include "asterisk.h"#include "asterisk/paths.h"#include "asterisk/file.h"#include "asterisk/audiohook.h"#include "asterisk/pbx.h"#include "asterisk/module.h"#include "asterisk/cli.h"#include "asterisk/app.h"#include "asterisk/channel.h"#include "asterisk/autochan.h"#include "asterisk/manager.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 | mixmonitor_args { OPT_ARG_READVOLUME = 0, OPT_ARG_WRITEVOLUME, OPT_ARG_VOLUME, OPT_ARG_ARRAY_SIZE } |
| enum | mixmonitor_flags { MUXFLAG_APPEND = (1 << 1), MUXFLAG_BRIDGED = (1 << 2), MUXFLAG_VOLUME = (1 << 3), MUXFLAG_READVOLUME = (1 << 4), MUXFLAG_WRITEVOLUME = (1 << 5) } |
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 int | manager_mute_mixmonitor (struct mansession *s, const struct message *m) |
| Mute / unmute a MixMonitor channel. | |
| 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, const char *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, const char *data) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "7a1b8b48c852d7a7061c7e499b9bd0d2" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } |
| static const char *const | app = "MixMonitor" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_cli_entry | cli_mixmonitor [] |
| static struct ast_datastore_info | mixmonitor_ds_info |
| 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 *const | mixmonitor_spy_type = "MixMonitor" |
| static const char *const | stop_app = "StopMixMonitor" |
MixMonitor() - Record a call and mix the audio during the recording.
Definition in file app_mixmonitor.c.
| #define get_volfactor | ( | x | ) | x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0 |
Definition at line 155 of file app_mixmonitor.c.
Referenced by mixmonitor_exec().
| #define SAMPLES_PER_FRAME 160 |
Definition at line 268 of file app_mixmonitor.c.
Referenced by mixmonitor_thread().
| enum mixmonitor_args |
Definition at line 181 of file app_mixmonitor.c.
| enum mixmonitor_flags |
Definition at line 173 of file app_mixmonitor.c.
{
MUXFLAG_APPEND = (1 << 1),
MUXFLAG_BRIDGED = (1 << 2),
MUXFLAG_VOLUME = (1 << 3),
MUXFLAG_READVOLUME = (1 << 4),
MUXFLAG_WRITEVOLUME = (1 << 5),
};
| static void __reg_module | ( | void | ) | [static] |
Definition at line 731 of file app_mixmonitor.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 731 of file app_mixmonitor.c.
| static void destroy_monitor_audiohook | ( | struct mixmonitor * | mixmonitor | ) | [static] |
Definition at line 238 of file app_mixmonitor.c.
References mixmonitor::mixmonitor_ds, ast_mutex_lock, mixmonitor_ds::lock, mixmonitor_ds::audiohook, ast_mutex_unlock, ast_audiohook_lock, mixmonitor::audiohook, ast_audiohook_detach(), ast_audiohook_unlock, and ast_audiohook_destroy().
Referenced by mixmonitor_thread().
{
if (mixmonitor->mixmonitor_ds) {
ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
mixmonitor->mixmonitor_ds->audiohook = NULL;
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
}
/* kill the audiohook.*/
ast_audiohook_lock(&mixmonitor->audiohook);
ast_audiohook_detach(&mixmonitor->audiohook);
ast_audiohook_unlock(&mixmonitor->audiohook);
ast_audiohook_destroy(&mixmonitor->audiohook);
}
| static char* handle_cli_mixmonitor | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 596 of file app_mixmonitor.c.
References CLI_INIT, ast_cli_entry::command, ast_cli_entry::usage, CLI_GENERATE, ast_complete_channels(), ast_cli_args::line, ast_cli_args::word, ast_cli_args::pos, ast_cli_args::n, ast_cli_args::argc, CLI_SHOWUSAGE, ast_channel_get_by_name_prefix(), ast_cli_args::argv, ast_cli(), ast_cli_args::fd, CLI_SUCCESS, ast_channel_lock, mixmonitor_exec(), ast_channel_unlock, ast_audiohook_detach_source(), and ast_channel_unref.
{
struct ast_channel *chan;
switch (cmd) {
case CLI_INIT:
e->command = "mixmonitor {start|stop}";
e->usage =
"Usage: mixmonitor <start|stop> <chan_name> [args]\n"
" The optional arguments are passed to the MixMonitor\n"
" application when the 'start' command is used.\n";
return NULL;
case CLI_GENERATE:
return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
}
if (a->argc < 3)
return CLI_SHOWUSAGE;
if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
/* Technically this is a failure, but we don't want 2 errors printing out */
return CLI_SUCCESS;
}
ast_channel_lock(chan);
if (!strcasecmp(a->argv[1], "start")) {
mixmonitor_exec(chan, a->argv[3]);
ast_channel_unlock(chan);
} else {
ast_channel_unlock(chan);
ast_audiohook_detach_source(chan, mixmonitor_spy_type);
}
chan = ast_channel_unref(chan);
return CLI_SUCCESS;
}
| 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 401 of file app_mixmonitor.c.
References thread, len(), ast_channel::name, ast_strlen_zero(), ast_strdupa, pbx_substitute_variables_helper(), ast_calloc, ast_audiohook_init(), mixmonitor::audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_free(), mixmonitor::flags, mixmonitor::autochan, ast_autochan_setup(), setup_mixmonitor_ds(), ast_autochan_destroy(), mixmonitor::name, mixmonitor::post_process, mixmonitor::filename, ast_set_flag, AST_AUDIOHOOK_TRIGGER_SYNC, ast_audiohook::options, ast_audiohook_options::read_volume, ast_audiohook_options::write_volume, startmon(), ast_log(), LOG_WARNING, ast_audiohook_destroy(), ast_pthread_create_detached_background, and mixmonitor_thread().
Referenced by mixmonitor_exec().
{
pthread_t thread;
struct mixmonitor *mixmonitor;
char postprocess2[1024] = "";
size_t len;
len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2;
postprocess2[0] = 0;
/* If a post process system command is given attach it to the structure */
if (!ast_strlen_zero(post_process)) {
char *p1, *p2;
p1 = ast_strdupa(post_process);
for (p2 = p1; *p2 ; p2++) {
if (*p2 == '^' && *(p2+1) == '{') {
*p2 = '$';
}
}
pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
if (!ast_strlen_zero(postprocess2))
len += strlen(postprocess2) + 1;
}
/* Pre-allocate mixmonitor structure and spy */
if (!(mixmonitor = ast_calloc(1, len))) {
return;
}
/* Setup the actual spy before creating our thread */
if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) {
mixmonitor_free(mixmonitor);
return;
}
/* Copy over flags and channel name */
mixmonitor->flags = flags;
if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
mixmonitor_free(mixmonitor);
return;
}
if (setup_mixmonitor_ds(mixmonitor, chan)) {
ast_autochan_destroy(mixmonitor->autochan);
mixmonitor_free(mixmonitor);
return;
}
mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor);
strcpy(mixmonitor->name, chan->name);
if (!ast_strlen_zero(postprocess2)) {
mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2;
strcpy(mixmonitor->post_process, postprocess2);
}
mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1;
strcpy(mixmonitor->filename, filename);
ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
if (readvol)
mixmonitor->audiohook.options.read_volume = readvol;
if (writevol)
mixmonitor->audiohook.options.write_volume = writevol;
if (startmon(chan, &mixmonitor->audiohook)) {
ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
mixmonitor_spy_type, chan->name);
ast_audiohook_destroy(&mixmonitor->audiohook);
mixmonitor_free(mixmonitor);
return;
}
ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
}
| static int load_module | ( | void | ) | [static] |
Definition at line 719 of file app_mixmonitor.c.
References ast_cli_register_multiple(), ARRAY_LEN, ast_register_application_xml, mixmonitor_exec(), stop_mixmonitor_exec(), ast_manager_register_xml, and manager_mute_mixmonitor().
{
int res;
ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
res = ast_register_application_xml(app, mixmonitor_exec);
res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec);
res |= ast_manager_register_xml("MixMonitorMute", 0, manager_mute_mixmonitor);
return res;
}
| static int manager_mute_mixmonitor | ( | struct mansession * | s, |
| const struct message * | m | ||
| ) | [static] |
Mute / unmute a MixMonitor channel.
Definition at line 637 of file app_mixmonitor.c.
References name, astman_get_header(), ast_strlen_zero(), astman_send_error(), AMI_SUCCESS, AST_AUDIOHOOK_MUTE_READ, AST_AUDIOHOOK_MUTE_WRITE, ast_false(), ast_channel_get_by_name(), ast_audiohook_set_mute(), ast_channel_unref, and astman_append().
Referenced by load_module().
{
struct ast_channel *c = NULL;
const char *name = astman_get_header(m, "Channel");
const char *id = astman_get_header(m, "ActionID");
const char *state = astman_get_header(m, "State");
const char *direction = astman_get_header(m,"Direction");
int clearmute = 1;
enum ast_audiohook_flags flag;
if (ast_strlen_zero(direction)) {
astman_send_error(s, m, "No direction specified. Must be read, write or both");
return AMI_SUCCESS;
}
if (!strcasecmp(direction, "read")) {
flag = AST_AUDIOHOOK_MUTE_READ;
} else if (!strcasecmp(direction, "write")) {
flag = AST_AUDIOHOOK_MUTE_WRITE;
} else if (!strcasecmp(direction, "both")) {
flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE;
} else {
astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
return AMI_SUCCESS;
}
if (ast_strlen_zero(name)) {
astman_send_error(s, m, "No channel specified");
return AMI_SUCCESS;
}
if (ast_strlen_zero(state)) {
astman_send_error(s, m, "No state specified");
return AMI_SUCCESS;
}
clearmute = ast_false(state);
c = ast_channel_get_by_name(name);
if (!c) {
astman_send_error(s, m, "No such channel");
return AMI_SUCCESS;
}
if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
c = ast_channel_unref(c);
astman_send_error(s, m, "Cannot set mute flag");
return AMI_SUCCESS;
}
astman_append(s, "Response: Success\r\n");
if (!ast_strlen_zero(id)) {
astman_append(s, "ActionID: %s\r\n", id);
}
astman_append(s, "\r\n");
c = ast_channel_unref(c);
return AMI_SUCCESS;
}
| static void mixmonitor_ds_close_fs | ( | struct mixmonitor_ds * | mixmonitor_ds | ) | [static] |
Definition at line 212 of file app_mixmonitor.c.
References mixmonitor_ds::fs, ast_closestream(), mixmonitor_ds::fs_quit, and ast_verb.
Referenced by mixmonitor_thread(), and stop_mixmonitor_exec().
| static void mixmonitor_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 222 of file app_mixmonitor.c.
References ast_mutex_lock, mixmonitor_ds::lock, mixmonitor_ds::audiohook, mixmonitor_ds::destruction_ok, ast_cond_signal, mixmonitor_ds::destruction_condition, and ast_mutex_unlock.
{
struct mixmonitor_ds *mixmonitor_ds = data;
ast_mutex_lock(&mixmonitor_ds->lock);
mixmonitor_ds->audiohook = NULL;
mixmonitor_ds->destruction_ok = 1;
ast_cond_signal(&mixmonitor_ds->destruction_condition);
ast_mutex_unlock(&mixmonitor_ds->lock);
}
| static int mixmonitor_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Definition at line 478 of file app_mixmonitor.c.
References parse(), AST_DECLARE_APP_ARGS, args, AST_APP_ARG, ast_strlen_zero(), ast_log(), LOG_WARNING, ast_strdupa, AST_STANDARD_APP_ARGS, OPT_ARG_ARRAY_SIZE, ast_app_parse_options(), mixmonitor_opts, ast_test_flag, MUXFLAG_READVOLUME, OPT_ARG_READVOLUME, LOG_NOTICE, get_volfactor, MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME, MUXFLAG_VOLUME, OPT_ARG_VOLUME, ast_config_AST_MONITOR_DIR, ast_mkdir(), pbx_builtin_setvar_helper(), launch_monitor_thread(), and ast_flags::flags.
Referenced by handle_cli_mixmonitor(), and load_module().
{
int x, readvol = 0, writevol = 0;
struct ast_flags flags = {0};
char *parse, *tmp, *slash;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(filename);
AST_APP_ARG(options);
AST_APP_ARG(post_process);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
return -1;
}
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.filename)) {
ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
return -1;
}
if (args.options) {
char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
} else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
} else {
readvol = get_volfactor(x);
}
}
if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
} else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
} else {
writevol = get_volfactor(x);
}
}
if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
} else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
} else {
readvol = writevol = get_volfactor(x);
}
}
}
/* if not provided an absolute path, use the system-configured monitoring directory */
if (args.filename[0] != '/') {
char *build;
build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3);
sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename);
args.filename = build;
}
tmp = ast_strdupa(args.filename);
if ((slash = strrchr(tmp, '/')))
*slash = '\0';
ast_mkdir(tmp, 0777);
pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process);
return 0;
}
| static void mixmonitor_free | ( | struct mixmonitor * | mixmonitor | ) | [static] |
Definition at line 270 of file app_mixmonitor.c.
References mixmonitor::mixmonitor_ds, ast_mutex_destroy, mixmonitor_ds::lock, ast_cond_destroy, mixmonitor_ds::destruction_condition, and ast_free.
Referenced by mixmonitor_thread(), and launch_monitor_thread().
{
if (mixmonitor) {
if (mixmonitor->mixmonitor_ds) {
ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
ast_free(mixmonitor->mixmonitor_ds);
}
ast_free(mixmonitor);
}
}
| static void* mixmonitor_thread | ( | void * | obj | ) | [static] |
Definition at line 281 of file app_mixmonitor.c.
References ext, ast_verb, mixmonitor::name, mixmonitor::mixmonitor_ds, mixmonitor_ds::fs, ast_audiohook_lock, mixmonitor::audiohook, ast_audiohook::status, AST_AUDIOHOOK_STATUS_RUNNING, mixmonitor_ds::fs_quit, ast_audiohook_read_frame(), SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR, ast_audiohook_trigger_wait(), ast_audiohook_unlock, ast_test_flag, MUXFLAG_BRIDGED, mixmonitor::autochan, ast_autochan::chan, ast_bridged_channel(), ast_mutex_lock, mixmonitor_ds::lock, MUXFLAG_APPEND, mixmonitor::filename, ast_writefile(), ast_log(), LOG_ERROR, AST_LIST_NEXT, ast_writestream(), ast_mutex_unlock, ast_frame_free(), ast_autochan_destroy(), mixmonitor_ds_close_fs(), mixmonitor_ds::destruction_ok, ast_cond_wait, mixmonitor_ds::destruction_condition, destroy_monitor_audiohook(), mixmonitor::post_process, ast_safe_system(), and mixmonitor_free().
Referenced by launch_monitor_thread().
{
struct mixmonitor *mixmonitor = obj;
struct ast_filestream **fs = NULL;
unsigned int oflags;
char *ext;
char *last_slash;
int errflag = 0;
ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
fs = &mixmonitor->mixmonitor_ds->fs;
/* The audiohook must enter and exit the loop locked */
ast_audiohook_lock(&mixmonitor->audiohook);
while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
struct ast_frame *fr = NULL;
if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) {
ast_audiohook_trigger_wait(&mixmonitor->audiohook);
if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
break;
}
continue;
}
/* audiohook lock is not required for the next block.
* Unlock it, but remember to lock it before looping or exiting */
ast_audiohook_unlock(&mixmonitor->audiohook);
if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
/* Initialize the file if not already done so */
if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
oflags = O_CREAT | O_WRONLY;
oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
last_slash = strrchr(mixmonitor->filename, '/');
if ((ext = strrchr(mixmonitor->filename, '.')) && (ext > last_slash))
*(ext++) = '\0';
else
ext = "raw";
if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0666))) {
ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext);
errflag = 1;
}
}
/* Write out the frame(s) */
if (*fs) {
struct ast_frame *cur;
for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
ast_writestream(*fs, cur);
}
}
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
}
/* All done! free it. */
ast_frame_free(fr, 0);
ast_audiohook_lock(&mixmonitor->audiohook);
}
ast_audiohook_unlock(&mixmonitor->audiohook);
ast_autochan_destroy(mixmonitor->autochan);
/* Datastore cleanup. close the filestream and wait for ds destruction */
ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
if (!mixmonitor->mixmonitor_ds->destruction_ok) {
ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
}
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
/* kill the audiohook */
destroy_monitor_audiohook(mixmonitor);
if (mixmonitor->post_process) {
ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
ast_safe_system(mixmonitor->post_process);
}
ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
mixmonitor_free(mixmonitor);
return NULL;
}
| static int setup_mixmonitor_ds | ( | struct mixmonitor * | mixmonitor, |
| struct ast_channel * | chan | ||
| ) | [static] |
Definition at line 371 of file app_mixmonitor.c.
References ast_calloc, ast_mutex_init, mixmonitor_ds::lock, ast_cond_init, mixmonitor_ds::destruction_condition, ast_datastore_alloc(), ast_mutex_destroy, ast_cond_destroy, ast_free, mixmonitor_ds::audiohook, mixmonitor::audiohook, ast_datastore::data, ast_channel_lock, ast_channel_datastore_add(), ast_channel_unlock, and mixmonitor::mixmonitor_ds.
Referenced by launch_monitor_thread().
{
struct ast_datastore *datastore = NULL;
struct mixmonitor_ds *mixmonitor_ds;
if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
return -1;
}
ast_mutex_init(&mixmonitor_ds->lock);
ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) {
ast_mutex_destroy(&mixmonitor_ds->lock);
ast_cond_destroy(&mixmonitor_ds->destruction_condition);
ast_free(mixmonitor_ds);
return -1;
}
mixmonitor_ds->audiohook = &mixmonitor->audiohook;
datastore->data = mixmonitor_ds;
ast_channel_lock(chan);
ast_channel_datastore_add(chan, datastore);
ast_channel_unlock(chan);
mixmonitor->mixmonitor_ds = mixmonitor_ds;
return 0;
}
| static int startmon | ( | struct ast_channel * | chan, |
| struct ast_audiohook * | audiohook | ||
| ) | [static] |
Definition at line 252 of file app_mixmonitor.c.
References ast_audiohook_attach(), ast_test_flag, AST_FLAG_NBRIDGE, ast_bridged_channel(), ast_softhangup(), and AST_SOFTHANGUP_UNBRIDGE.
Referenced by launch_monitor_thread().
{
struct ast_channel *peer = NULL;
int res = 0;
if (!chan)
return -1;
ast_audiohook_attach(chan, audiohook);
if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
return res;
}
| static int stop_mixmonitor_exec | ( | struct ast_channel * | chan, |
| const char * | data | ||
| ) | [static] |
Definition at line 559 of file app_mixmonitor.c.
References ast_channel_lock, ast_audiohook_detach_source(), ast_channel_datastore_find(), ast_datastore::data, ast_mutex_lock, mixmonitor_ds::lock, mixmonitor_ds_close_fs(), mixmonitor_ds::audiohook, ast_audiohook_lock, ast_cond_signal, ast_audiohook::trigger, ast_audiohook_unlock, ast_mutex_unlock, ast_channel_datastore_remove(), ast_datastore_free(), and ast_channel_unlock.
Referenced by load_module().
{
struct ast_datastore *datastore = NULL;
ast_channel_lock(chan);
ast_audiohook_detach_source(chan, mixmonitor_spy_type);
if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) {
struct mixmonitor_ds *mixmonitor_ds = datastore->data;
ast_mutex_lock(&mixmonitor_ds->lock);
/* closing the filestream here guarantees the file is avaliable to the dialplan
* after calling StopMixMonitor */
mixmonitor_ds_close_fs(mixmonitor_ds);
/* The mixmonitor thread may be waiting on the audiohook trigger.
* In order to exit from the mixmonitor loop before waiting on channel
* destruction, poke the audiohook trigger. */
if (mixmonitor_ds->audiohook) {
ast_audiohook_lock(mixmonitor_ds->audiohook);
ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
ast_audiohook_unlock(mixmonitor_ds->audiohook);
mixmonitor_ds->audiohook = NULL;
}
ast_mutex_unlock(&mixmonitor_ds->lock);
/* Remove the datastore so the monitor thread can exit */
if (!ast_channel_datastore_remove(chan, datastore)) {
ast_datastore_free(datastore);
}
}
ast_channel_unlock(chan);
return 0;
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 707 of file app_mixmonitor.c.
References ast_cli_unregister_multiple(), ARRAY_LEN, ast_unregister_application(), and ast_manager_unregister().
{
int res;
ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
res = ast_unregister_application(stop_app);
res |= ast_unregister_application(app);
res |= ast_manager_unregister("MixMonitorMute");
return res;
}
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "7a1b8b48c852d7a7061c7e499b9bd0d2" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 731 of file app_mixmonitor.c.
const char* const app = "MixMonitor" [static] |
Definition at line 157 of file app_mixmonitor.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 731 of file app_mixmonitor.c.
struct ast_cli_entry cli_mixmonitor[] [static] |
{
AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
}
Definition at line 703 of file app_mixmonitor.c.
struct ast_datastore_info mixmonitor_ds_info [static] |
{
.type = "mixmonitor",
.destroy = mixmonitor_ds_destroy,
}
Definition at line 233 of file app_mixmonitor.c.
struct ast_app_option mixmonitor_opts[128] = { [ 'a' ] = { .flag = MUXFLAG_APPEND }, [ 'b' ] = { .flag = MUXFLAG_BRIDGED }, [ 'v' ] = { .flag = MUXFLAG_READVOLUME , .arg_index = OPT_ARG_READVOLUME + 1 }, [ 'V' ] = { .flag = MUXFLAG_WRITEVOLUME , .arg_index = OPT_ARG_WRITEVOLUME + 1 }, [ 'W' ] = { .flag = MUXFLAG_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 },} [static] |
Definition at line 194 of file app_mixmonitor.c.
Referenced by mixmonitor_exec().
const char* const mixmonitor_spy_type = "MixMonitor" [static] |
Definition at line 161 of file app_mixmonitor.c.
Referenced by builtin_automixmonitor().
const char* const stop_app = "StopMixMonitor" [static] |
Definition at line 159 of file app_mixmonitor.c.