[asterisk-commits] jrose: branch jrose/mix-monitor-branch r309258 - in /team/jrose/mix-monitor-b...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Mar 2 13:59:53 CST 2011


Author: jrose
Date: Wed Mar  2 13:59:49 2011
New Revision: 309258

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=309258
Log:
Significant changes to improve code reuse and better conform to the written standards for development in Asterisk.

Modified:
    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

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=309258&r1=309257&r2=309258
==============================================================================
--- team/jrose/mix-monitor-branch/apps/app_mixmonitor.c (original)
+++ team/jrose/mix-monitor-branch/apps/app_mixmonitor.c Wed Mar  2 13:59:49 2011
@@ -37,7 +37,7 @@
 
 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"
@@ -89,6 +89,19 @@
 						of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para>
 						<argument name="x" required="true" />
 					</option>
+					<option name="r">
+						<argument name="file" required="true" />
+						<para>Use the specified file to record the <emphasis>receive</emphasis> audio feed.
+						Like with the basic filename argument, if an absolute path isn't given, it will create
+						the file in the configured monitoring directory.</para>
+						
+					</option>
+					<option name="t">
+						<argument name="file" required="true" />
+						<para>Use the specified file to record the <emphasis>transmit</emphasis> audio feed.
+						Like with the basic filename argument, if an absolute path isn't given, it will create
+						the file in the configured monitoring directory.</para>
+					</option>
 				</optionlist>
 			</parameter>
 			<parameter name="command">
@@ -103,7 +116,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>
@@ -150,59 +163,59 @@
 
 #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 *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 */
-	 };
+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),
+    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;
 	ast_cond_t destruction_condition;
 	ast_mutex_t lock;
+
 	/* The filestream is held in the datastore so it can be stopped
 	 * immediately during stop_mixmonitor or channel destruction. */
 	int fs_quit;
@@ -220,22 +233,30 @@
  */
 static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
 {
+	unsigned char quitting = 0;
+
 	if (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);
-
+		quitting = 1;
+		ast_closestream(mixmonitor_ds->fs);
 		mixmonitor_ds->fs = NULL;
+		ast_verb(2, "MixMonitor close filestream (mixed)\n");
+	}
+
+	if (mixmonitor_ds->fs_read) {
+		quitting = 1;
+		ast_closestream(mixmonitor_ds->fs_read);
 		mixmonitor_ds->fs_read = NULL;
+		ast_verb(2, "MixMonitor close filestream (read)\n");
+	}
+
+	if (mixmonitor_ds->fs_write) {
+		quitting = 1;
+		ast_closestream(mixmonitor_ds->fs_write);
 		mixmonitor_ds->fs_write = NULL;
-
-		mixmonitor_ds->fs_quit = 1;
-
-		ast_verb(2, "MixMonitor close filestream(s)\n");
-	}
+		ast_verb(2, "MixMonitor close filestream (write)\n");
+	}
+
+	if (quitting) { mixmonitor_ds->fs_quit = 1; }
 }
 
 static void mixmonitor_ds_destroy(void *data)
@@ -261,14 +282,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;
@@ -279,7 +300,7 @@
 	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);
+		ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
 
 	return res;
 }
@@ -300,6 +321,33 @@
 	}
 }
 
+static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag)
+{
+    /* Initialize the file if not already done so */
+    char *ext = NULL;
+    if (!ast_strlen_zero(filename)) {
+
+
+		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(filename, '.')))
+				*(ext++) = '\0';
+			else
+				ext = "raw";
+
+			if (!
+				(*fs =
+					ast_writefile(filename, ext, NULL, *oflags, 0, 0666))) {
+					ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, ext);
+					*errflag = 1;
+            }
+        }
+    }
+}
+
 static void *mixmonitor_thread(void *obj)
 {
 	struct mixmonitor *mixmonitor = obj;
@@ -309,8 +357,6 @@
 	struct ast_filestream **fs_write = NULL;
 
 	unsigned int oflags;
-	char *ext = NULL;
-
 	int errflag = 0;
 	struct ast_format format_slin;
 
@@ -324,17 +370,14 @@
 	/* 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;
 		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,
+		if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, &format_slin,
                                                 &fr_read, &fr_write))) {
 			ast_audiohook_trigger_wait(&mixmonitor->audiohook);
 
@@ -348,78 +391,12 @@
 		 * 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 (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 = "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;
-					}
-				}
-			}
-
-			/* 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 = "raw";
-
-					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 = "raw";
-
-					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;
-					}
-				}
-			}
+			mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag);
+			mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag);
+			mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag);
 
 			/* Write out the frame(s) */
 			if ((*fs_read) && (fr_read)) {
@@ -438,17 +415,17 @@
 				}
 			}
 
-			if ((fs) && (fr)) {
-				struct ast_frame *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. */
 		if (fr) {
 			ast_frame_free(fr, 0);
@@ -523,9 +500,9 @@
 }
 
 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)
+				  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;
@@ -541,7 +518,7 @@
 
 		p1 = ast_strdupa(post_process);
 		for (p2 = p1; *p2; p2++) {
-			if (*p2 == '^' && *(p2 + 1) == '{') {
+			if (*p2 == '^' && *(p2+1) == '{') {
 				*p2 = '$';
 			}
 		}
@@ -576,17 +553,15 @@
 	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;
-	strcpy(mixmonitor->filename, filename);
-
+
+	mixmonitor->filename = ast_strdup(filename);
 	mixmonitor->filename_write = ast_strdup(filename_write);
 	mixmonitor->filename_read = ast_strdup(filename_read);
-
 
 	ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
 
@@ -606,21 +581,40 @@
 	ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
 }
 
+static char *filename_parse(char *filename)
+{
+	char *tmp, *slash;
+	if (ast_strlen_zero(filename)) {
+		ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
+	} else if (filename[0] != '/') {
+		char *build;
+		build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
+		sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
+		filename = build;
+	}
+
+	tmp = ast_strdupa(filename);
+	if ((slash = strrchr(tmp, '/')))
+		*slash = '\0';
+	ast_mkdir(tmp, 0777);
+
+	return filename;
+}
+
 static int mixmonitor_exec(struct ast_channel *chan, const char *data)
 {
 	int x, readvol = 0, writevol = 0;
 	char *filename_read = NULL;
 	char *filename_write = NULL;
 
-
 	struct ast_flags flags = { 0 };
-	char *parse, *tmp, *slash;
+	char *parse;
 	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 or ,t(filename) and/or r(filename)\n");
 		return -1;
@@ -644,7 +638,7 @@
 				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");
@@ -654,81 +648,41 @@
 				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_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);
-		}
-
-
+			filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME]));
+		}
 
 		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);
-		}
-	}
-
-	/* 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);
-
+			filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME]));
+		}
+	}
+	
+	/* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
+	
+	if (!ast_test_flag(&flags, MUXFLAG_WRITE) && !ast_test_flag(&flags, MUXFLAG_READ) && ast_strlen_zero(args.filename)) {
+		ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
+		return -1;
+	}
+	
+	/* If filename exists, try to create directories for it */
+	if (!(ast_strlen_zero(args.filename))) {
+		args.filename = ast_strdupa(filename_parse(args.filename));
+	}
+	
 	pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
-	launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol,
-						  args.post_process, filename_write, filename_read);
-
+	launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process, filename_write, filename_read);
+	
 	return 0;
 }
 
@@ -769,8 +723,7 @@
 	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;
 
@@ -836,8 +789,7 @@
 	} 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;
 	}
 
@@ -890,7 +842,7 @@
 	res = ast_unregister_application(stop_app);
 	res |= ast_unregister_application(app);
 	res |= ast_manager_unregister("MixMonitorMute");
-
+	
 	return res;
 }
 
@@ -906,4 +858,4 @@
 	return res;
 }
 
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");

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=309258&r1=309257&r2=309258
==============================================================================
--- team/jrose/mix-monitor-branch/include/asterisk/audiohook.h (original)
+++ team/jrose/mix-monitor-branch/include/asterisk/audiohook.h Wed Mar  2 13:59:49 2011
@@ -28,7 +28,6 @@
 #endif
 
 /* these two are used in struct ast_audiohook */
-
 #include "asterisk/lock.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/slinfactory.h"
@@ -152,16 +151,16 @@
  */
 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
+/*! \brief Reads a frame in from the audiohook structure in mixed audio mode and copies read and write frame data to provided arguments.
  * \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.
+ * \param ast_frame read_frame - if available, we'll copy the read buffer to this.
+ * \param ast_frame write_frame - 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);
+struct ast_frame *ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, struct ast_format *format, struct ast_frame **read_frame, struct ast_frame **write_frame);
 
 /*! \brief Attach audiohook to channel
  * \param chan Channel

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=309258&r1=309257&r2=309258
==============================================================================
--- team/jrose/mix-monitor-branch/main/audiohook.c (original)
+++ team/jrose/mix-monitor-branch/main/audiohook.c Wed Mar  2 13:59:49 2011
@@ -238,7 +238,7 @@
 	return ast_frdup(&frame);
 }
 
-static struct ast_frame *audiohook_read_frame_both_all(struct ast_audiohook *audiohook, size_t samples, struct ast_frame **readFrame, struct ast_frame **writeFrame)
+static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audiohook, size_t samples, struct ast_frame **read_reference, struct ast_frame **write_reference)
 {
 	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,6 @@
 		.datalen = sizeof(buf1),
 		.samples = samples,
 	};
-
 	ast_format_set(&frame.subclass.format, AST_FORMAT_SLINEAR, 0);
 
 	/* Make sure both factories have the required samples */
@@ -311,27 +310,22 @@
 	}
 	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) {
+		final_buf = buf1;
+		frame.data.ptr = final_buf;
+		*read_reference = ast_frdup(&frame);
+	}
+
+	if (write_buf) {
+		final_buf = buf2;
+		frame.data.ptr = final_buf;
+		*write_reference = ast_frdup(&frame);
+	}
 
 	if (read_buf && write_buf) {
 		for (i = 0, data1 = read_buf, data2 = write_buf; i < samples; i++, data1++, data2++)
@@ -339,176 +333,20 @@
 		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;
-	else 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;
-	} else if (read_buf)
-		final_buf = buf1;
-	else if (write_buf)
-		final_buf = buf2;
-
-	/* 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);
-}
-
-/*! \brief Reads a frame in from the audiohook structure
- * \param audiohook Audiohook structure
- * \param samples Number of samples wanted in requested output format
- * \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(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format)
+}
+
+static struct ast_frame *ast_audiohook_read_frame_helper(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format, struct ast_frame **read_reference, struct ast_frame **write_reference)
 {
 	struct ast_frame *read_frame = NULL, *final_frame = NULL;
 	struct ast_format tmp_fmt;
-	int samples_converted;
-
-	/* the number of samples requested is based on the format they are requesting.  Inorder
-	 * to process this correctly samples must be converted to our internal sample rate */
-	if (audiohook->hook_internal_samp_rate == ast_format_rate(format)) {
-		samples_converted = samples;
-	} else if (audiohook->hook_internal_samp_rate > ast_format_rate(format)) {
-		samples_converted = samples * (audiohook->hook_internal_samp_rate / (float) ast_format_rate(format));
-	} else {
-		samples_converted = samples * (ast_format_rate(format) / (float) audiohook->hook_internal_samp_rate);
-	}
-
-	if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ?
-		audiohook_read_frame_both(audiohook, samples_converted) :
-		audiohook_read_frame_single(audiohook, samples_converted, 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_slin_by_rate(audiohook->hook_internal_samp_rate)) {
-		/* 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_slin_by_rate(audiohook->hook_internal_samp_rate), 0)))) {
-				ast_frfree(read_frame);
-				return NULL;
-			}
-			ast_format_copy(&audiohook->format, format);
-		}
-		/* 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;
-}
-
-
-/*! \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 (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ? audiohook_read_frame_both(audiohook, samples, read_reference, write_reference) : 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 */
@@ -532,9 +370,30 @@
 	return final_frame;
 }
 
-
-
-
+/*! \brief Reads a frame in from the audiohook structure
+ * \param audiohook Audiohook structure
+ * \param samples Number of samples wanted in requested output format
+ * \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(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format)
+{
+	return ast_audiohook_read_frame_helper(audiohook, samples, direction, format, NULL, NULL);
+}
+
+/*! \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
+ * \param read_frame
+ * \return Returns frame on success, NULL on failure
+ */
+struct ast_frame *ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, struct ast_format *format, struct ast_frame **read_frame, struct ast_frame **write_frame)
+{
+	return ast_audiohook_read_frame_helper(audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, format, read_frame, write_frame);
+}
 
 static void audiohook_list_set_samplerate_compatibility(struct ast_audiohook_list *audiohook_list)
 {
@@ -547,7 +406,6 @@
 		}
 	}
 }
-
 
 /*! \brief Attach audiohook to channel
  * \param chan Channel
@@ -1051,9 +909,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