[asterisk-commits] jrose: branch jrose/mix-monitor-branch r309078 - in /team/jrose/mix-monitor-b...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Feb 28 10:53:44 CST 2011
Author: jrose
Date: Mon Feb 28 10:53:39 2011
New Revision: 309078
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=309078
Log:
first attempt at commit
Modified:
team/jrose/mix-monitor-branch/ (props changed)
team/jrose/mix-monitor-branch/apps/app_mixmonitor.c
team/jrose/mix-monitor-branch/include/asterisk/audiohook.h
team/jrose/mix-monitor-branch/main/audiohook.c
Propchange: team/jrose/mix-monitor-branch/
------------------------------------------------------------------------------
automerge = *
Modified: team/jrose/mix-monitor-branch/apps/app_mixmonitor.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/mix-monitor-branch/apps/app_mixmonitor.c?view=diff&rev=309078&r1=309077&r2=309078
==============================================================================
--- team/jrose/mix-monitor-branch/apps/app_mixmonitor.c (original)
+++ team/jrose/mix-monitor-branch/apps/app_mixmonitor.c Mon Feb 28 10:53:39 2011
@@ -36,8 +36,7 @@
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */
+#include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */
#include "asterisk/file.h"
#include "asterisk/audiohook.h"
#include "asterisk/pbx.h"
@@ -47,7 +46,6 @@
#include "asterisk/channel.h"
#include "asterisk/autochan.h"
#include "asterisk/manager.h"
-
/*** DOCUMENTATION
<application name="MixMonitor" language="en_US">
<synopsis>
@@ -103,7 +101,7 @@
<variable name="MIXMONITOR_FILENAME">
<para>Will contain the filename used to record.</para>
</variable>
- </variablelist>
+ </variablelist>
</description>
<see-also>
<ref type="application">Monitor</ref>
@@ -147,47 +145,58 @@
</manager>
***/
-
#define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
-
-static const char * const app = "MixMonitor";
-
-static const char * const stop_app = "StopMixMonitor";
-
-static const char * const mixmonitor_spy_type = "MixMonitor";
-
-struct mixmonitor {
- struct ast_audiohook audiohook;
- char *filename;
- char *post_process;
- char *name;
- unsigned int flags;
- struct ast_autochan *autochan;
- struct mixmonitor_ds *mixmonitor_ds;
-};
-
-enum mixmonitor_flags {
- MUXFLAG_APPEND = (1 << 1),
- MUXFLAG_BRIDGED = (1 << 2),
- MUXFLAG_VOLUME = (1 << 3),
- MUXFLAG_READVOLUME = (1 << 4),
- MUXFLAG_WRITEVOLUME = (1 << 5),
-};
-
-enum mixmonitor_args {
- OPT_ARG_READVOLUME = 0,
- OPT_ARG_WRITEVOLUME,
- OPT_ARG_VOLUME,
- OPT_ARG_ARRAY_SIZE,
-};
-
-AST_APP_OPTIONS(mixmonitor_opts, {
- AST_APP_OPTION('a', MUXFLAG_APPEND),
- AST_APP_OPTION('b', MUXFLAG_BRIDGED),
- AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
- AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME),
- AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
-});
+ static const char *const app = "MixMonitor";
+
+ static const char *const stop_app = "StopMixMonitor";
+
+ static const char *const mixmonitor_spy_type = "MixMonitor";
+
+ struct mixmonitor {
+ struct ast_audiohook audiohook;
+ char *filename;
+ char *filename_read;
+ char *filename_write;
+
+
+
+ char *post_process;
+ char *name;
+ unsigned int flags;
+ struct ast_autochan *autochan;
+ struct mixmonitor_ds *mixmonitor_ds;
+ };
+
+ enum mixmonitor_flags {
+ MUXFLAG_APPEND = (1 << 1),
+ MUXFLAG_BRIDGED = (1 << 2),
+ MUXFLAG_VOLUME = (1 << 3),
+ MUXFLAG_READVOLUME = (1 << 4),
+ MUXFLAG_WRITEVOLUME = (1 << 5),
+ MUXFLAG_READ = (1 << 6),
+ MUXFLAG_WRITE = (1 << 7),
+ MUXFLAG_COMBINED = (1 << 8),
+
+ };
+
+ enum mixmonitor_args {
+ OPT_ARG_READVOLUME = 0,
+ OPT_ARG_WRITEVOLUME,
+ OPT_ARG_VOLUME,
+ OPT_ARG_WRITENAME,
+ OPT_ARG_READNAME,
+ OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
+ };
+
+AST_APP_OPTIONS(mixmonitor_opts,
+ {
+ AST_APP_OPTION('a', MUXFLAG_APPEND),
+ AST_APP_OPTION('b', MUXFLAG_BRIDGED),
+ AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
+ AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME),
+ AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
+ AST_APP_OPTION_ARG('r', MUXFLAG_READ, OPT_ARG_READNAME),
+ AST_APP_OPTION_ARG('t', MUXFLAG_WRITE, OPT_ARG_WRITENAME),});
struct mixmonitor_ds {
unsigned int destruction_ok;
@@ -197,7 +206,12 @@
/* The filestream is held in the datastore so it can be stopped
* immediately during stop_mixmonitor or channel destruction. */
int fs_quit;
+
+
struct ast_filestream *fs;
+ struct ast_filestream *fs_read;
+ struct ast_filestream *fs_write;
+
struct ast_audiohook *audiohook;
};
@@ -208,9 +222,19 @@
static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
{
if (mixmonitor_ds->fs) {
- ast_closestream(mixmonitor_ds->fs);
+ if (mixmonitor_ds->fs_read)
+ ast_closestream(mixmonitor_ds->fs_read);
+ if (mixmonitor_ds->fs_write)
+ ast_closestream(mixmonitor_ds->fs_write);
+ if (mixmonitor_ds->fs)
+ ast_closestream(mixmonitor_ds->fs);
+
mixmonitor_ds->fs = NULL;
+ mixmonitor_ds->fs_read = NULL;
+ mixmonitor_ds->fs_write = NULL;
+
mixmonitor_ds->fs_quit = 1;
+
ast_verb(2, "MixMonitor close filestream\n");
}
}
@@ -238,14 +262,14 @@
mixmonitor->mixmonitor_ds->audiohook = NULL;
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
}
- /* kill the audiohook.*/
+ /* kill the audiohook. */
ast_audiohook_lock(&mixmonitor->audiohook);
ast_audiohook_detach(&mixmonitor->audiohook);
ast_audiohook_unlock(&mixmonitor->audiohook);
ast_audiohook_destroy(&mixmonitor->audiohook);
}
-static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
+static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
{
struct ast_channel *peer = NULL;
int res = 0;
@@ -255,8 +279,9 @@
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);
+ if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) &&
+ (peer = ast_bridged_channel(chan)))
+ ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
return res;
}
@@ -269,17 +294,25 @@
if (mixmonitor->mixmonitor_ds) {
ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
+ ast_free(mixmonitor->filename_write);
+ ast_free(mixmonitor->filename_read);
ast_free(mixmonitor->mixmonitor_ds);
}
ast_free(mixmonitor);
}
}
-static void *mixmonitor_thread(void *obj)
+
+static void *mixmonitor_thread(void *obj)
{
struct mixmonitor *mixmonitor = obj;
+
struct ast_filestream **fs = NULL;
+ struct ast_filestream **fs_read = NULL;
+ struct ast_filestream **fs_write = NULL;
+
unsigned int oflags;
- char *ext;
+ char *ext = NULL;
+
int errflag = 0;
struct ast_format format_slin;
@@ -287,13 +320,23 @@
ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
fs = &mixmonitor->mixmonitor_ds->fs;
+ fs_read = &mixmonitor->mixmonitor_ds->fs_read;
+ fs_write = &mixmonitor->mixmonitor_ds->fs_write;
/* 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) {
+
+ 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, &format_slin))) {
+ struct ast_frame *fr_read = NULL;
+ struct ast_frame *fr_write = NULL;
+
+
+ /* here we need to use a modified version of the ast_audiohook_read_frame function designed to take our read and write frames as arguments. */
+ if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME,
+ AST_AUDIOHOOK_DIRECTION_BOTH, &format_slin,
+ &fr_read, &fr_write))) {
ast_audiohook_trigger_wait(&mixmonitor->audiohook);
if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
@@ -306,39 +349,125 @@
* 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))) {
+ 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;
-
- if ((ext = strrchr(mixmonitor->filename, '.')))
- *(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;
+ if (mixmonitor->filename[0] != '\0') {
+
+ if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
+ oflags = O_CREAT | O_WRONLY;
+ oflags |=
+ ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
+
+ if ((ext = strrchr(mixmonitor->filename, '.')))
+ *(ext++) = '\0';
+ else
+ ext = "wav";
+
+ 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;
+ }
}
}
+ /* repeat for the reading file if necessary */
+
+ if (ast_test_flag(mixmonitor, MUXFLAG_READ)) {
+ if (!*fs_read && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
+ oflags = O_CREAT | O_WRONLY;
+ oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
+
+ if ((ext = strrchr(mixmonitor->filename_read, '.')))
+ *(ext++) = '\0';
+ else
+ ext = "wav";
+
+ if (!
+ (*fs_read =
+ ast_writefile(mixmonitor->filename_read, ext, NULL, oflags, 0, 0666))) {
+ ast_log(LOG_ERROR, "Cannot open %s.%s\n",
+ mixmonitor->filename_read, ext);
+ errflag = 1;
+ }
+ }
+ }
+
+ /* repeat for write */
+
+ if (ast_test_flag(mixmonitor, MUXFLAG_WRITE)) {
+ if (!*fs_write && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
+ oflags = O_CREAT | O_WRONLY;
+ oflags |=
+ ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
+
+ if ((ext = strrchr(mixmonitor->filename_write, '.')))
+ *(ext++) = '\0';
+ else
+ ext = "wav";
+
+ if (!
+ (*fs_write =
+ ast_writefile(mixmonitor->filename_write, ext, NULL, oflags, 0,
+ 0666))) {
+ ast_log(LOG_ERROR, "Cannot open %s.%s\n",
+ mixmonitor->filename_write, ext);
+ errflag = 1;
+ }
+ }
+ }
+
/* Write out the frame(s) */
- if (*fs) {
+ if ((*fs_read) && (fr_read)) {
+ struct ast_frame *cur;
+
+ for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
+ ast_writestream(*fs_read, cur);
+ }
+ }
+
+ if ((*fs_write) && (fr_write)) {
+ struct ast_frame *cur;
+
+ for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
+ ast_writestream(*fs_write, cur);
+ }
+ }
+
+ if ((fs) && (fr)) {
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);
+ if (fr) {
+ ast_frame_free(fr, 0);
+ }
+ if (fr_read) {
+ ast_frame_free(fr_read, 0);
+ }
+ if (fr_write) {
+ ast_frame_free(fr_write, 0);
+ }
+
+ fr = NULL;
+ fr_write = NULL;
+ fr_read = NULL;
ast_audiohook_lock(&mixmonitor->audiohook);
}
+
ast_audiohook_unlock(&mixmonitor->audiohook);
ast_autochan_destroy(mixmonitor->autochan);
@@ -347,7 +476,8 @@
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_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition,
+ &mixmonitor->mixmonitor_ds->lock);
}
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
@@ -394,8 +524,10 @@
return 0;
}
-static void launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags,
- int readvol, int writevol, const char *post_process)
+static void launch_monitor_thread(struct ast_channel *chan, const char *filename,
+ unsigned int flags, int readvol, int writevol,
+ const char *post_process, const char *filename_write,
+ const char *filename_read)
{
pthread_t thread;
struct mixmonitor *mixmonitor;
@@ -410,8 +542,8 @@
char *p1, *p2;
p1 = ast_strdupa(post_process);
- for (p2 = p1; *p2 ; p2++) {
- if (*p2 == '^' && *(p2+1) == '{') {
+ for (p2 = p1; *p2; p2++) {
+ if (*p2 == '^' && *(p2 + 1) == '{') {
*p2 = '$';
}
}
@@ -446,12 +578,18 @@
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;
+ 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;
+ mixmonitor->filename =
+ (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1;
strcpy(mixmonitor->filename, filename);
+
+ mixmonitor->filename_write = ast_strdup(filename_write);
+ mixmonitor->filename_read = ast_strdup(filename_read);
+
ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
@@ -462,7 +600,7 @@
if (startmon(chan, &mixmonitor->audiohook)) {
ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
- mixmonitor_spy_type, chan->name);
+ mixmonitor_spy_type, chan->name);
ast_audiohook_destroy(&mixmonitor->audiohook);
mixmonitor_free(mixmonitor);
return;
@@ -474,27 +612,25 @@
static int mixmonitor_exec(struct ast_channel *chan, const char *data)
{
int x, readvol = 0, writevol = 0;
- struct ast_flags flags = {0};
+ char *filename_read = NULL;
+ char *filename_write = NULL;
+
+
+ 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);
- );
-
+ 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");
+ ast_log(LOG_WARNING,
+ "MixMonitor requires an argument (filename or ,t(filename) and/or r(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, };
@@ -503,32 +639,101 @@
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]);
+ 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]);
+ 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]);
+ 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 (ast_test_flag(&flags, MUXFLAG_WRITE)) {
+ if (ast_strlen_zero(opts[OPT_ARG_WRITENAME])) {
+ ast_log(LOG_WARNING,
+ "No file name was provided for the transmission ('t') option.\n");
+ }
+ /* if not provided an absolute path, use the system-configured monitoring directory for the write file */
+ else if (opts[OPT_ARG_WRITENAME][0] != '/') {
+ char *build;
+ build =
+ alloca(strlen(ast_config_AST_MONITOR_DIR) +
+ strlen(opts[OPT_ARG_WRITENAME]) + 3);
+ sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR,
+ opts[OPT_ARG_WRITENAME]);
+
+ opts[OPT_ARG_WRITENAME] = build;
+ }
+
+
+ filename_write = opts[OPT_ARG_WRITENAME];
+
+ tmp = ast_strdupa(opts[OPT_ARG_WRITENAME]);
+ if ((slash = strrchr(tmp, '/')))
+ *slash = '\0';
+ ast_mkdir(tmp, 0777);
+ }
+
+
+
+ if (ast_test_flag(&flags, MUXFLAG_READ)) {
+ if (ast_strlen_zero(opts[OPT_ARG_READNAME])) {
+ ast_log(LOG_WARNING,
+ "No file name was provided for the receiving ('r') option.\n");
+ }
+ /* if not provided an absolute path, use the system-configured monitoring directory for the read file */
+ else if (opts[OPT_ARG_READNAME][0] != '/') {
+
+ char *build;
+ build =
+ alloca(strlen(ast_config_AST_MONITOR_DIR) +
+ strlen(opts[OPT_ARG_READNAME]) + 3);
+
+ sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR,
+ opts[OPT_ARG_READNAME]);
+
+ opts[OPT_ARG_READNAME] = build;
+ }
+
+ filename_read = opts[OPT_ARG_READNAME];
+
+ tmp = ast_strdupa(opts[OPT_ARG_READNAME]);
+ if ((slash = strrchr(tmp, '/')))
+ *slash = '\0';
+ ast_mkdir(tmp, 0777);
}
}
@@ -547,7 +752,8 @@
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);
+ launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol,
+ args.post_process, filename_write, filename_read);
return 0;
}
@@ -564,7 +770,7 @@
ast_mutex_lock(&mixmonitor_ds->lock);
/* closing the filestream here guarantees the file is avaliable to the dialplan
- * after calling StopMixMonitor */
+ * after calling StopMixMonitor */
mixmonitor_ds_close_fs(mixmonitor_ds);
/* The mixmonitor thread may be waiting on the audiohook trigger.
@@ -589,7 +795,8 @@
return 0;
}
-static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd,
+ struct ast_cli_args *a)
{
struct ast_channel *chan;
@@ -637,7 +844,7 @@
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");
+ const char *direction = astman_get_header(m, "Direction");
int clearmute = 1;
@@ -650,12 +857,13 @@
if (!strcasecmp(direction, "read")) {
flag = AST_AUDIOHOOK_MUTE_READ;
- } else if (!strcasecmp(direction, "write")) {
+ } else if (!strcasecmp(direction, "write")) {
flag = AST_AUDIOHOOK_MUTE_WRITE;
- } else if (!strcasecmp(direction, "both")) {
+ } 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");
+ astman_send_error(s, m,
+ "Invalid direction specified. Must be read, write or both");
return AMI_SUCCESS;
}
@@ -708,7 +916,7 @@
res = ast_unregister_application(stop_app);
res |= ast_unregister_application(app);
res |= ast_manager_unregister("MixMonitorMute");
-
+
return res;
}
Modified: team/jrose/mix-monitor-branch/include/asterisk/audiohook.h
URL: http://svnview.digium.com/svn/asterisk/team/jrose/mix-monitor-branch/include/asterisk/audiohook.h?view=diff&rev=309078&r1=309077&r2=309078
==============================================================================
--- team/jrose/mix-monitor-branch/include/asterisk/audiohook.h (original)
+++ team/jrose/mix-monitor-branch/include/asterisk/audiohook.h Mon Feb 28 10:53:39 2011
@@ -28,6 +28,7 @@
#endif
/* these two are used in struct ast_audiohook */
+
#include "asterisk/lock.h"
#include "asterisk/linkedlists.h"
#include "asterisk/slinfactory.h"
@@ -151,6 +152,17 @@
*/
struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format);
+/*! \brief Reads a frame in from the audiohook structure, automatically tweaks provided frames
+ * \param audiohook Audiohook structure
+ * \param samples Number of samples wanted
+ * \param direction Direction the audio frame came from
+ * \param format Format of frame remote side wants back
+ * \param ast_frame readFrame - if available, we'll copy the read buffer to this.
+ * \param ast_frame writeFrame - if available, we'll copy the write buffer to this.
+ * \return Returns frame on success, NULL on failure
+ */
+struct ast_frame *ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format, struct ast_frame **readFrame, struct ast_frame **writeFrame);
+
/*! \brief Attach audiohook to channel
* \param chan Channel
* \param audiohook Audiohook structure
Modified: team/jrose/mix-monitor-branch/main/audiohook.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/mix-monitor-branch/main/audiohook.c?view=diff&rev=309078&r1=309077&r2=309078
==============================================================================
--- team/jrose/mix-monitor-branch/main/audiohook.c (original)
+++ team/jrose/mix-monitor-branch/main/audiohook.c Mon Feb 28 10:53:39 2011
@@ -226,7 +226,7 @@
/* Ensure the factory is able to give us the samples we want */
if (samples > ast_slinfactory_available(factory))
return NULL;
-
+
/* Read data in from factory */
if (!ast_slinfactory_read(factory, buf, samples))
return NULL;
@@ -238,7 +238,7 @@
return ast_frdup(&frame);
}
-static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audiohook, size_t samples)
+static struct ast_frame *audiohook_read_frame_both_all(struct ast_audiohook *audiohook, size_t samples, struct ast_frame **readFrame, struct ast_frame **writeFrame)
{
int i = 0, usable_read, usable_write;
short buf1[samples], buf2[samples], *read_buf = NULL, *write_buf = NULL, *final_buf = NULL, *data1 = NULL, *data2 = NULL;
@@ -248,7 +248,8 @@
.datalen = sizeof(buf1),
.samples = samples,
};
- ast_format_set(&frame.subclass.format, ast_format_slin_by_rate(audiohook->hook_internal_samp_rate), 0);
+
+ ast_format_set(&frame.subclass.format, AST_FORMAT_SLINEAR, 0);
/* Make sure both factories have the required samples */
usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
@@ -310,6 +311,115 @@
}
ast_debug(1, "Failed to get %d samples from write factory %p\n", (int)samples, &audiohook->write_factory);
+
+
+ /* Basically we figure out which buffer to use... and if mixing can be done here */
+
+
+ if (!read_buf && !write_buf)
+ return NULL;
+
+ if (read_buf) {
+ final_buf = buf1;
+ frame.data.ptr = final_buf;
+ *readFrame = ast_frdup(&frame);
+ }
+
+
+ if (write_buf) {
+ final_buf = buf2;
+ frame.data.ptr = final_buf;
+ *writeFrame = ast_frdup(&frame);
+ }
+
+
+ if (read_buf && write_buf) {
+ for (i = 0, data1 = read_buf, data2 = write_buf; i < samples; i++, data1++, data2++)
+ ast_slinear_saturated_add(data1, data2);
+ final_buf = buf1;
+ }
+
+
+ /* Make the final buffer part of the frame, so it gets duplicated fine */
+ frame.data.ptr = final_buf;
+
+ /* Yahoo, a combined copy of the audio! */
+ return ast_frdup(&frame);
+
+}
+
+static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audiohook, size_t samples)
+{
+ int i = 0, usable_read, usable_write;
+ short buf1[samples], buf2[samples], *read_buf = NULL, *write_buf = NULL, *final_buf = NULL, *data1 = NULL, *data2 = NULL;
+ struct ast_frame frame = {
+ .frametype = AST_FRAME_VOICE,
+ .data.ptr = NULL,
+ .datalen = sizeof(buf1),
+ .samples = samples,
+ };
+ ast_format_set(&frame.subclass.format, ast_format_slin_by_rate(audiohook->hook_internal_samp_rate), 0);
+
+ /* Make sure both factories have the required samples */
+ usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
+ usable_write = (ast_slinfactory_available(&audiohook->write_factory) >= samples ? 1 : 0);
+
+ if (!usable_read && !usable_write) {
+ /* If both factories are unusable bail out */
+ ast_debug(1, "Read factory %p and write factory %p both fail to provide %zd samples\n", &audiohook->read_factory, &audiohook->write_factory, samples);
+ return NULL;
+ }
+
+ /* If we want to provide only a read factory make sure we aren't waiting for other audio */
+ if (usable_read && !usable_write && (ast_tvdiff_ms(ast_tvnow(), audiohook->write_time) < (samples/8)*2)) {
+ ast_debug(3, "Write factory %p was pretty quick last time, waiting for them.\n", &audiohook->write_factory);
+ return NULL;
+ }
+
+ /* If we want to provide only a write factory make sure we aren't waiting for other audio */
+ if (usable_write && !usable_read && (ast_tvdiff_ms(ast_tvnow(), audiohook->read_time) < (samples/8)*2)) {
+ ast_debug(3, "Read factory %p was pretty quick last time, waiting for them.\n", &audiohook->read_factory);
+ return NULL;
+ }
+
+ /* Start with the read factory... if there are enough samples, read them in */
+ if (usable_read) {
+ if (ast_slinfactory_read(&audiohook->read_factory, buf1, samples)) {
+ read_buf = buf1;
+ /* Adjust read volume if need be */
+ if (audiohook->options.read_volume) {
+ int count = 0;
+ short adjust_value = abs(audiohook->options.read_volume);
+ for (count = 0; count < samples; count++) {
+ if (audiohook->options.read_volume > 0)
+ ast_slinear_saturated_multiply(&buf1[count], &adjust_value);
+ else if (audiohook->options.read_volume < 0)
+ ast_slinear_saturated_divide(&buf1[count], &adjust_value);
+ }
+ }
+ }
+ }
+ ast_debug(1, "Failed to get %d samples from read factory %p\n", (int)samples, &audiohook->read_factory);
+
+ /* Move on to the write factory... if there are enough samples, read them in */
+ if (usable_write) {
+ if (ast_slinfactory_read(&audiohook->write_factory, buf2, samples)) {
+ write_buf = buf2;
+ /* Adjust write volume if need be */
+ if (audiohook->options.write_volume) {
+ int count = 0;
+ short adjust_value = abs(audiohook->options.write_volume);
+ for (count = 0; count < samples; count++) {
+ if (audiohook->options.write_volume > 0)
+ ast_slinear_saturated_multiply(&buf2[count], &adjust_value);
+ else if (audiohook->options.write_volume < 0)
+ ast_slinear_saturated_divide(&buf2[count], &adjust_value);
+ }
+ }
+ }
+ }
+ ast_debug(1, "Failed to get %d samples from write factory %p\n", (int)samples, &audiohook->write_factory);
+
/* Basically we figure out which buffer to use... and if mixing can be done here */
if (!read_buf && !write_buf)
return NULL;
@@ -383,6 +493,49 @@
return final_frame;
}
+
+/*! \brief Reads a frame in from the audiohook structure
+ * \param audiohook Audiohook structure
+ * \param samples Number of samples wanted
+ * \param direction Direction the audio frame came from
+ * \param format Format of frame remote side wants back
+ * \return Returns frame on success, NULL on failure
+ */
+struct ast_frame *ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format, struct ast_frame **readFrame, struct ast_frame **writeFrame)
+{
+ struct ast_frame *read_frame = NULL, *final_frame = NULL;
+ struct ast_format tmp_fmt;
+
+ if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ? audiohook_read_frame_both_all(audiohook, samples, readFrame, writeFrame) : audiohook_read_frame_single(audiohook, samples, direction))))
+ return NULL;
+
+ /* If they don't want signed linear back out, we'll have to send it through the translation path */
+ if (format->id != AST_FORMAT_SLINEAR) {
+ /* Rebuild translation path if different format then previously */
+ if (ast_format_cmp(format, &audiohook->format) == AST_FORMAT_CMP_NOT_EQUAL) {
+ if (audiohook->trans_pvt) {
+ ast_translator_free_path(audiohook->trans_pvt);
+ audiohook->trans_pvt = NULL;
+ }
+ /* Setup new translation path for this format... if we fail we can't very well return signed linear so free the frame and return nothing */
+ if (!(audiohook->trans_pvt = ast_translator_build_path(format, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0)))) {
+ ast_frfree(read_frame);
+ return NULL;
+ }
+ }
+ /* Convert to requested format, and allow the read in frame to be freed */
+ final_frame = ast_translate(audiohook->trans_pvt, read_frame, 1);
+ } else {
+ final_frame = read_frame;
+ }
+
+ return final_frame;
+}
+
+
+
+
+
static void audiohook_list_set_samplerate_compatibility(struct ast_audiohook_list *audiohook_list)
{
struct ast_audiohook *ah = NULL;
@@ -394,6 +547,7 @@
}
}
}
+
/*! \brief Attach audiohook to channel
* \param chan Channel
@@ -504,7 +658,7 @@
if (audiohook_list->out_translate[i].trans_pvt)
ast_translator_free_path(audiohook_list->out_translate[i].trans_pvt);
}
-
+
/* Free ourselves */
ast_free(audiohook_list);
@@ -738,7 +892,7 @@
* because no translation to SLINEAR audio was required.
* Part_3: Translate end_frame's audio back into the format of start frame if necessary. This
* is only necessary if manipulation of middle_frame occurred.
- *
+ *
* \param chan Channel that the list is coming off of
* \param audiohook_list List of audiohooks
* \param direction Direction frame is coming in from
@@ -897,9 +1051,9 @@
wait = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
ts.tv_sec = wait.tv_sec;
ts.tv_nsec = wait.tv_usec * 1000;
-
+
ast_cond_timedwait(&audiohook->trigger, &audiohook->lock, &ts);
-
+
return;
}
More information about the asterisk-commits
mailing list