Index: apps/app_mixmonitor.c
===================================================================
--- apps/app_mixmonitor.c	(revision 258189)
+++ apps/app_mixmonitor.c	(working copy)
@@ -46,6 +46,7 @@
 #include "asterisk/app.h"
 #include "asterisk/channel.h"
 #include "asterisk/autochan.h"
+#include "asterisk/manager.h"
 
 /*** DOCUMENTATION
 	<application name="MixMonitor" language="en_US">
@@ -124,7 +125,27 @@
 			<ref type="application">MixMonitor</ref>
 		</see-also>
 	</application>
-		
+	<manager name="MixMonitorMute" language="en_US">
+		<synopsis>
+			Mute / unMute a Mixmonitor recording.
+		</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+			<parameter name="Channel" required="true">
+				<para>Used to specify the channel to mute.</para>
+			</parameter>
+			<parameter name="Direction">
+				<para>Which part of the recording to mute:  read, write or both (from channel, to channel or both channels).</para>
+			</parameter>
+			<parameter name="State">
+				<para>Turn mute on or off : 1 to turn on, 0 to turn off.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>This action may be used to mute a MixMonitor recording.</para>
+		</description>
+	</manager>
+
  ***/
 
 #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
@@ -606,6 +627,73 @@
 	return CLI_SUCCESS;
 }
 
+/*! \brief  Mute / unmute  a MixMonitor channel */
+static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
+{
+	struct ast_channel *c = NULL;
+
+	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");
+
+	int clearmute = 1;
+
+	enum ast_audiohook_flags flag;
+
+	if (ast_strlen_zero(direction)) {
+		astman_send_error(s, m, "No direction specified. Must be read, write or both");
+		return AMI_SUCCESS;
+	}
+
+	if (!strcasecmp(direction, "read")) {
+		flag = AST_AUDIOHOOK_MUTE_READ;
+	} else  if (!strcasecmp(direction, "write")) {
+		flag = AST_AUDIOHOOK_MUTE_WRITE;
+	} 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");
+		return AMI_SUCCESS;
+	}
+
+	if (ast_strlen_zero(name)) {
+		astman_send_error(s, m, "No channel specified");
+		return AMI_SUCCESS;
+	}
+
+	if (ast_strlen_zero(state)) {
+		astman_send_error(s, m, "No state specified");
+		return AMI_SUCCESS;
+	}
+
+	clearmute = ast_false(state);
+	c = ast_channel_get_by_name(name);
+
+	if (!c) {
+		astman_send_error(s, m, "No such channel");
+		return AMI_SUCCESS;
+	}
+
+	if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
+		c = ast_channel_unref(c);
+		astman_send_error(s, m, "Cannot set mute flag");
+		return AMI_SUCCESS;
+	}
+
+	astman_append(s, "Response: Success\r\n");
+
+	if (!ast_strlen_zero(id)) {
+		astman_append(s, "ActionID: %s\r\n", id);
+	}
+
+	astman_append(s, "\r\n");
+
+	c = ast_channel_unref(c);
+
+	return AMI_SUCCESS;
+}
+
 static struct ast_cli_entry cli_mixmonitor[] = {
 	AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
 };
@@ -617,6 +705,7 @@
 	ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
 	res = ast_unregister_application(stop_app);
 	res |= ast_unregister_application(app);
+	res |= ast_manager_unregister("MixMonitorMute");
 	
 	return res;
 }
@@ -628,6 +717,7 @@
 	ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
 	res = ast_register_application_xml(app, mixmonitor_exec);
 	res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec);
+	res |= ast_manager_register_xml("MixMonitorMute", 0, manager_mute_mixmonitor);
 
 	return res;
 }
Index: include/asterisk/frame.h
===================================================================
--- include/asterisk/frame.h	(revision 258189)
+++ include/asterisk/frame.h	(working copy)
@@ -728,6 +728,11 @@
 	}
 }
 
+/*!
+ * \brief Clear all audio samples from an ast_frame. The frame must be AST_FRAME_VOICE and AST_FORMAT_SLINEAR 
+ */
+int ast_frame_clear(struct ast_frame *frame);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
Index: include/asterisk/audiohook.h
===================================================================
--- include/asterisk/audiohook.h	(revision 258189)
+++ include/asterisk/audiohook.h	(working copy)
@@ -62,6 +62,8 @@
 	 * slinfactories. We will flush the factories if they contain too many samples.
 	 */
 	AST_AUDIOHOOK_SMALL_QUEUE = (1 << 3),
+	AST_AUDIOHOOK_MUTE_READ = (1 << 4),     /*!< audiohook should be mute frames read */
+	AST_AUDIOHOOK_MUTE_WRITE = (1 << 5),    /*!< audiohook should be mute frames written */
 };
 
 #define AST_AUDIOHOOK_SYNC_TOLERANCE 100 /*< Tolerance in milliseconds for audiohooks synchronization */
@@ -277,6 +279,16 @@
  */
 int ast_audiohook_volume_adjust(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume);
 
+/*! \brief Mute frames read from or written to a channel
+ * \param chan Channel to muck with
+ * \param source Type of audiohook
+ * \param flag which direction to set / clear
+ * \param clear set or clear muted frames on direction based on flag parameter
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int ast_audiohook_set_mute(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
Index: main/frame.c
===================================================================
--- main/frame.c	(revision 258189)
+++ main/frame.c	(working copy)
@@ -1587,3 +1587,15 @@
 
 	return 0;
 }
+
+int ast_frame_clear(struct ast_frame *frame)
+{
+	struct ast_frame *next;
+
+	for (next = AST_LIST_NEXT(frame, frame_list);
+		 frame;
+		 frame = next, next = frame ? AST_LIST_NEXT(frame, frame_list) : NULL) {
+		memset(frame->data.ptr, 0, frame->datalen);
+	}
+	return 0;
+}
Index: main/audiohook.c
===================================================================
--- main/audiohook.c	(revision 258189)
+++ main/audiohook.c	(working copy)
@@ -127,6 +127,7 @@
 	int our_factory_ms;
 	int other_factory_samples;
 	int other_factory_ms;
+	int muteme = 0;
 
 	/* Update last feeding time to be current */
 	*rwtime = ast_tvnow();
@@ -151,6 +152,17 @@
 		ast_slinfactory_flush(other_factory);
 	}
 
+	/* swap frame data for zeros if mute is required */
+	if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) ||
+		(ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) ||
+		(ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE) == (AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE))) {
+			muteme = 1;
+	}
+
+	if (muteme && frame->datalen > 0) {
+		ast_frame_clear(frame);
+	}
+
 	/* Write frame out to respective factory */
 	ast_slinfactory_feed(factory, frame);
 
@@ -1001,3 +1013,37 @@
 
 	return 0;
 }
+
+/*! \brief Mute frames read from or written to a channel
+ * \param chan Channel to muck with
+ * \param source Type of audiohook
+ * \param flag which flag to set / clear
+ * \param clear set or clear
+ * \return Returns 0 on success, -1 on failure
+ */
+int ast_audiohook_set_mute(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear)
+{
+	struct ast_audiohook *audiohook = NULL;
+
+	ast_channel_lock(chan);
+
+	/* Ensure the channel has audiohooks on it */
+	if (!chan->audiohooks) {
+		ast_channel_unlock(chan);
+		return -1;
+	}
+
+	audiohook = find_audiohook_by_source(chan->audiohooks, source);
+
+	if (audiohook) {
+		if (clear) {
+			ast_clear_flag(audiohook, flag);
+		} else {
+			ast_set_flag(audiohook, flag);
+		}
+	}
+
+	ast_channel_unlock(chan);
+
+	return (audiohook ? 0 : -1);
+}
Index: res/res_mutestream.c
===================================================================
--- res/res_mutestream.c	(revision 258189)
+++ res/res_mutestream.c	(working copy)
@@ -116,19 +116,6 @@
 	.destroy = destroy_callback
 };
 
-/*! \brief Wipe out all audio samples from an ast_frame. Clean it. */
-static void ast_frame_clear(struct ast_frame *frame)
-{
-	struct ast_frame *next;
-
-	for (next = AST_LIST_NEXT(frame, frame_list);
-		frame;
-		frame = next, next = frame ? AST_LIST_NEXT(frame, frame_list) : NULL) {
-		memset(frame->data.ptr, 0, frame->datalen);
-        }
-}
-
-
 /*! \brief The callback from the audiohook subsystem. We basically get a frame to have fun with */
 static int mute_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
 {
