[asterisk-commits] jrose: trunk r352093 - in /trunk: CHANGES apps/app_mixmonitor.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Jan 23 12:16:28 CST 2012


Author: jrose
Date: Mon Jan 23 12:16:20 2012
New Revision: 352093

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=352093
Log:
Adds the ability to stop specific mixmonitors by using unique IDs set at monitor launch.

MixMonitor receives a new option i(channel_variable) which stores the unique id at said
variable. StopMixMonitor now accepts ID as an optional argument, which if included will
make StopMixMonitor specifically target the mixmonitor on that particular channel. CLI
commands and AMI actions have been ammended to work with the IDs as well. In addition,
monitors across a channel can now be listed be listed via CLI command "mixmonitor list
<channel>" which will display all of the mixmonitors active on that channel along with
the files they each have open.

(closes issue ASTERISK-19096)
Reported by: Sergio González Martín
Review: https://reviewboard.asterisk.org/r/1643/
Review: https://reviewboard.asterisk.org/r/1682/

Modified:
    trunk/CHANGES
    trunk/apps/app_mixmonitor.c

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=352093&r1=352092&r2=352093
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Mon Jan 23 12:16:20 2012
@@ -17,6 +17,11 @@
  * The expression parser now recognizes the ABS() absolute value function,
    which will convert negative floating point values to positive values.
 
+CLI Changes
+-------------------
+ * mixmonitor list <channel> command will now show MixMonitor ID, and the filenames
+   of all running mixmonitors on a channel.
+
 ConfBridge
 -------------------
  * Added menu action admin_toggle_mute_participants.  This will mute / unmute
@@ -82,6 +87,11 @@
  * Channel variable PARKER is now set when comebacktoorigin is disabled in
    a parking lot.
 
+ * MixMonitor hooks now have IDs associated with them which can be used to assign
+   a target to StopMixMonitor. Use of MixMonitor's i(variable) option will allow
+   storage of the MixMontior ID in a channel variable.  StopMixmonitor now accepts
+   that ID as an argument.
+
 CDR postgresql driver changes
 -----------------------------
  * Added command "cdr show pgsql status" to check connection status
@@ -90,6 +100,10 @@
 ----------------------------------------
  * Originate now generates an error response if the extension given
    is not found in the dialplan
+
+ * MixMonitor will now show IDs associated with the mixmonitor upon creating them
+   if the i(variable) option is used. StopMixMonitor will accept MixMonitorID as
+   on option to close specific MixMonitors.
 
 FAX changes
 -----------

Modified: trunk/apps/app_mixmonitor.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_mixmonitor.c?view=diff&rev=352093&r1=352092&r2=352093
==============================================================================
--- trunk/apps/app_mixmonitor.c (original)
+++ trunk/apps/app_mixmonitor.c Mon Jan 23 12:16:20 2012
@@ -52,6 +52,7 @@
 #include "asterisk/autochan.h"
 #include "asterisk/manager.h"
 #include "asterisk/mod_format.h"
+#include "asterisk/linkedlists.h"
 
 /*** DOCUMENTATION
 	<application name="MixMonitor" language="en_US">
@@ -107,6 +108,10 @@
 						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="i">
+						<argument name="chanvar" required="true" />
+						<para>Stores the MixMonitor's ID on this channel variable.</para>
+					</option>
 				</optionlist>
 			</parameter>
 			<parameter name="command">
@@ -136,7 +141,12 @@
 		<synopsis>
 			Stop recording a call through MixMonitor, and free the recording's file handle.
 		</synopsis>
-		<syntax />
+		<syntax>
+			<parameter name="MixMonitorID" required="false">
+				<para>If a valid ID is provided, then this command will stop only that specific
+				MixMonitor.</para>
+			</parameter>
+		</syntax>
 		<description>
 			<para>Stops the audio recording that was started with a call to <literal>MixMonitor()</literal>
 			on the current channel.</para>
@@ -207,6 +217,10 @@
 			<parameter name="Channel" required="true">
 				<para>The name of the channel monitored.</para>
 			</parameter>
+			<parameter name="MixMonitorID" required="false">
+				<para>If a valid ID is provided, then this command will stop only that specific
+				MixMonitor.</para>
+			</parameter>
 		</syntax>
 		<description>
 			<para>This action stops the audio recording that was started with the <literal>MixMonitor</literal>
@@ -245,6 +259,7 @@
 	MUXFLAG_READ = (1 << 6),
 	MUXFLAG_WRITE = (1 << 7),
 	MUXFLAG_COMBINED = (1 << 8),
+        MUXFLAG_UID = (1 << 9),
 };
 
 enum mixmonitor_args {
@@ -253,6 +268,7 @@
 	OPT_ARG_VOLUME,
 	OPT_ARG_WRITENAME,
 	OPT_ARG_READNAME,
+        OPT_ARG_UID,
 	OPT_ARG_ARRAY_SIZE,	/* Always last element of the enum */
 };
 
@@ -264,6 +280,7 @@
 	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_ARG('i', MUXFLAG_UID, OPT_ARG_UID),
 });
 
 struct mixmonitor_ds {
@@ -531,7 +548,7 @@
 	return NULL;
 }
 
-static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan)
+static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id)
 {
 	struct ast_datastore *datastore = NULL;
 	struct mixmonitor_ds *mixmonitor_ds;
@@ -540,10 +557,14 @@
 		return -1;
 	}
 
+	if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
+		ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
+	}
+
 	ast_mutex_init(&mixmonitor_ds->lock);
 	ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
 
-	if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) {
+	if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
 		ast_mutex_destroy(&mixmonitor_ds->lock);
 		ast_cond_destroy(&mixmonitor_ds->destruction_condition);
 		ast_free(mixmonitor_ds);
@@ -566,11 +587,12 @@
 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) 
+				  char *filename_read, const char *uid_channel_var)
 {
 	pthread_t thread;
 	struct mixmonitor *mixmonitor;
 	char postprocess2[1024] = "";
+	char *datastore_id = NULL;
 
 	postprocess2[0] = 0;
 	/* If a post process system command is given attach it to the structure */
@@ -604,11 +626,20 @@
 		return;
 	}
 
-	if (setup_mixmonitor_ds(mixmonitor, chan)) {
+	if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id)) {
 		ast_autochan_destroy(mixmonitor->autochan);
 		mixmonitor_free(mixmonitor);
+		ast_free(datastore_id);
 		return;
 	}
+
+	if (!ast_strlen_zero(uid_channel_var)) {
+		if (datastore_id) {
+			pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
+		}
+	}
+	ast_free(datastore_id);
+
 
 	mixmonitor->name = ast_strdup(ast_channel_name(chan));
 
@@ -676,6 +707,7 @@
 	char *filename_read = NULL;
 	char *filename_write = NULL;
 	char filename_buffer[1024] = "";
+        char *uid_channel_var = NULL;
 
 	struct ast_flags flags = { 0 };
 	char *parse;
@@ -684,7 +716,7 @@
 		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;
@@ -708,7 +740,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");
@@ -718,7 +750,7 @@
 				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");
@@ -736,8 +768,11 @@
 		if (ast_test_flag(&flags, MUXFLAG_READ)) {
 			filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
 		}
-	}
-
+
+		if (ast_test_flag(&flags, MUXFLAG_UID)) {
+			uid_channel_var = opts[OPT_ARG_UID];
+		}
+	}
 	/* 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)) {
@@ -751,7 +786,7 @@
 	}
 
 	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, uid_channel_var);
 
 	return 0;
 }
@@ -759,34 +794,51 @@
 static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
 {
 	struct ast_datastore *datastore = NULL;
+	char *parse = "";
+	struct mixmonitor_ds *mixmonitor_ds;
+
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(mixmonid);
+	);
+
+	if (!ast_strlen_zero(data)) {
+		parse = ast_strdupa(data);
+	}
+
+	AST_STANDARD_APP_ARGS(args, parse);
 
 	ast_channel_lock(chan);
-	ast_audiohook_detach_source(chan, mixmonitor_spy_type);
-	if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) {
-		struct mixmonitor_ds *mixmonitor_ds = datastore->data;
-
-		ast_mutex_lock(&mixmonitor_ds->lock);
-
-		/* closing the filestream here guarantees the file is avaliable to the dialplan
-	 	 * after calling StopMixMonitor */
-		mixmonitor_ds_close_fs(mixmonitor_ds);
-
-		/* The mixmonitor thread may be waiting on the audiohook trigger.
-		 * In order to exit from the mixmonitor loop before waiting on channel
-		 * destruction, poke the audiohook trigger. */
-		if (mixmonitor_ds->audiohook) {
-			ast_audiohook_lock(mixmonitor_ds->audiohook);
-			ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
-			ast_audiohook_unlock(mixmonitor_ds->audiohook);
-			mixmonitor_ds->audiohook = NULL;
-		}
-
-		ast_mutex_unlock(&mixmonitor_ds->lock);
-
-		/* Remove the datastore so the monitor thread can exit */
-		if (!ast_channel_datastore_remove(chan, datastore)) {
-			ast_datastore_free(datastore);
-		}
+
+	if (!(datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.mixmonid))) {
+		ast_channel_unlock(chan);
+                return -1;
+	}
+	mixmonitor_ds = datastore->data;
+
+	ast_mutex_lock(&mixmonitor_ds->lock);
+
+	/* closing the filestream here guarantees the file is avaliable to the dialplan
+	 * after calling StopMixMonitor */
+	mixmonitor_ds_close_fs(mixmonitor_ds);
+
+	/* The mixmonitor thread may be waiting on the audiohook trigger.
+	 * In order to exit from the mixmonitor loop before waiting on channel
+	 * destruction, poke the audiohook trigger. */
+	if (mixmonitor_ds->audiohook) {
+		if (mixmonitor_ds->audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
+			ast_audiohook_update_status(mixmonitor_ds->audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
+		}
+		ast_audiohook_lock(mixmonitor_ds->audiohook);
+		ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
+		ast_audiohook_unlock(mixmonitor_ds->audiohook);
+		mixmonitor_ds->audiohook = NULL;
+	}
+
+	ast_mutex_unlock(&mixmonitor_ds->lock);
+
+	/* Remove the datastore so the monitor thread can exit */
+	if (!ast_channel_datastore_remove(chan, datastore)) {
+		ast_datastore_free(datastore);
 	}
 	ast_channel_unlock(chan);
 
@@ -796,12 +848,14 @@
 static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct ast_channel *chan;
+	struct ast_datastore *datastore = NULL;
+	struct mixmonitor_ds *mixmonitor_ds = NULL;
 
 	switch (cmd) {
 	case CLI_INIT:
-		e->command = "mixmonitor {start|stop}";
+		e->command = "mixmonitor {start|stop|list}";
 		e->usage =
-			"Usage: mixmonitor <start|stop> <chan_name> [args]\n"
+			"Usage: mixmonitor <start|stop|list> <chan_name> [args]\n"
 			"       The optional arguments are passed to the MixMonitor\n"
 			"       application when the 'start' command is used.\n";
 		return NULL;
@@ -809,8 +863,9 @@
 		return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
 	}
 
-	if (a->argc < 3)
+	if (a->argc < 3) {
 		return CLI_SHOWUSAGE;
+	}
 
 	if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
 		ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
@@ -821,11 +876,34 @@
 	ast_channel_lock(chan);
 
 	if (!strcasecmp(a->argv[1], "start")) {
-		mixmonitor_exec(chan, a->argv[3]);
+		mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
+		ast_channel_unlock(chan);
+	} else if (!strcasecmp(a->argv[1], "stop")){
+		ast_channel_unlock(chan);
+		stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
+	} else if (!strcasecmp(a->argv[1], "list")) {
+		ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
+		ast_cli(a->fd, "=========================================================================\n");
+		AST_LIST_TRAVERSE(&chan->datastores, datastore, entry) {
+			if (datastore->info == &mixmonitor_ds_info) {
+				char *filename = "";
+				char *filename_read = "";
+				char *filename_write = "";
+				mixmonitor_ds = datastore->data;
+				if (mixmonitor_ds->fs)
+					filename = ast_strdupa(mixmonitor_ds->fs->filename);
+				if (mixmonitor_ds->fs_read)
+					filename_read = ast_strdupa(mixmonitor_ds->fs_read->filename);
+				if (mixmonitor_ds->fs_write)
+					filename_write = ast_strdupa(mixmonitor_ds->fs_write->filename);
+				ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
+			}
+		}
 		ast_channel_unlock(chan);
 	} else {
 		ast_channel_unlock(chan);
-		ast_audiohook_detach_source(chan, mixmonitor_spy_type);
+		chan = ast_channel_unref(chan);
+		return CLI_SHOWUSAGE;
 	}
 
 	chan = ast_channel_unref(chan);
@@ -908,6 +986,10 @@
 	const char *id = astman_get_header(m, "ActionID");
 	const char *file = astman_get_header(m, "File");
 	const char *options = astman_get_header(m, "Options");
+	char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
+	struct ast_flags flags = { 0 };
+	char *uid_channel_var = NULL;
+	const char *mixmonitor_id = NULL;
 
 	int res;
 	char args[PATH_MAX] = "";
@@ -923,10 +1005,19 @@
 		return AMI_SUCCESS;
 	}
 
+	if (!ast_strlen_zero(options)) {
+		ast_app_parse_options(mixmonitor_opts, &flags, opts, ast_strdupa(options));
+	}
+
 	snprintf(args, sizeof(args), "%s,%s", file, options);
 
 	ast_channel_lock(c);
 	res = mixmonitor_exec(c, args);
+
+	if (ast_test_flag(&flags, MUXFLAG_UID)) {
+		uid_channel_var = opts[OPT_ARG_UID];
+		mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
+	}
 	ast_channel_unlock(c);
 
 	if (res) {
@@ -940,6 +1031,10 @@
 		astman_append(s, "ActionID: %s\r\n", id);
 	}
 
+	if (!ast_strlen_zero(mixmonitor_id)) {
+		astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
+	}
+
 	astman_append(s, "\r\n");
 
 	c = ast_channel_unref(c);
@@ -953,6 +1048,7 @@
 
 	const char *name = astman_get_header(m, "Channel");
 	const char *id = astman_get_header(m, "ActionID");
+	const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
 
 	int res;
 	if (ast_strlen_zero(name)) {
@@ -967,7 +1063,7 @@
 		return AMI_SUCCESS;
 	}
 
-	res = stop_mixmonitor_exec(c, NULL);
+	res = stop_mixmonitor_exec(c, mixmonitor_id);
 
 	if (res) {
 		astman_send_error(s, m, "Could not stop monitoring channel");




More information about the asterisk-commits mailing list