diff --git a/CHANGES b/CHANGES
index b7d01aed45..eae5067cc4 100644
--- a/CHANGES
+++ b/CHANGES
@@ -17,6 +17,11 @@ Core
  * 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 @@ Parking
  * 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
@@ -91,6 +101,10 @@ AMI (Asterisk Manager Interface) changes
  * 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
 -----------
  * FAXOPT(faxdetect) will enable a generic fax detect framehook for dialplan
diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c
index 99dc7a4a89..4515805bcd 100644
--- a/apps/app_mixmonitor.c
+++ b/apps/app_mixmonitor.c
@@ -52,6 +52,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #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 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 						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 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 		<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 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 			<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 @@ enum mixmonitor_flags {
 	MUXFLAG_READ = (1 << 6),
 	MUXFLAG_WRITE = (1 << 7),
 	MUXFLAG_COMBINED = (1 << 8),
+        MUXFLAG_UID = (1 << 9),
 };
 
 enum mixmonitor_args {
@@ -253,6 +268,7 @@ enum mixmonitor_args {
 	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_OPTIONS(mixmonitor_opts, {
 	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 @@ static void *mixmonitor_thread(void *obj)
 	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 @@ static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel
 		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 int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel
 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,12 +626,21 @@ static void launch_monitor_thread(struct ast_channel *chan, const char *filename
 		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));
 
 	if (!ast_strlen_zero(postprocess2)) {
@@ -676,6 +707,7 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
 	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 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
 		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 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
 				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 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
 				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 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
 		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 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
 	}
 
 	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 mixmonitor_exec(struct ast_channel *chan, const char *data)
 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);
+	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);
 
-		/* Remove the datastore so the monitor thread can exit */
-		if (!ast_channel_datastore_remove(chan, datastore)) {
-			ast_datastore_free(datastore);
+	/* 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 int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
 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 @@ static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_
 		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 @@ static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_
 	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 @@ static int manager_mixmonitor(struct mansession *s, const struct message *m)
 	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 @@ static int manager_mixmonitor(struct mansession *s, const struct message *m)
 		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 @@ static int manager_mixmonitor(struct mansession *s, const struct message *m)
 		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 @@ static int manager_stop_mixmonitor(struct mansession *s, const struct message *m
 
 	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 @@ static int manager_stop_mixmonitor(struct mansession *s, const struct message *m
 		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");