[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