diff --git a/apps/app_dial.c b/apps/app_dial.c
index a7f5fff6f6a78c4327d937cf196606a34413c836..265b49be7976c2984a03f0b43cc5dccb907bf8e1 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -203,8 +203,12 @@ static char *descrip =
 "    w    - Allow the called party to enable recording of the call by sending\n"
 "           the DTMF sequence defined for one-touch recording in features.conf.\n"
 "    W    - Allow the calling party to enable recording of the call by sending\n"
-"           the DTMF sequence defined for one-touch recording in features.conf.\n";
-
+"           the DTMF sequence defined for one-touch recording in features.conf.\n"
+"    x    - Allow the called party to enable recording of the call by sending\n"
+"           the DTMF sequence defined for one-touch automixmonitor in features.conf\n"
+"    X    - Allow the calling party to enable recording of the call by sending\n"
+"           the DTMF sequence defined for one-touch automixmonitor in features.conf\n";
+ 
 /* RetryDial App by Anthony Minessale II <anthmct@yahoo.com> Jan/2005 */
 static char *rapp = "RetryDial";
 static char *rsynopsis = "Place a call, retrying on failure allowing optional exit extension.";
@@ -250,12 +254,14 @@ enum {
 	OPT_CALLER_PARK =	(1 << 26),
 	OPT_IGNORE_FORWARDING = (1 << 27),
 	OPT_CALLEE_GOSUB =	(1 << 28),
-	OPT_CANCEL_ELSEWHERE =  (1 << 29),
-	OPT_PEER_H =            (1 << 30),
+	OPT_CALLEE_MIXMONITOR = (1 << 29),
+	OPT_CALLER_MIXMONITOR = (1 << 30),
 };
 
 #define DIAL_STILLGOING			(1 << 31)
 #define DIAL_NOFORWARDHTML		((uint64_t)1 << 32) /* flags are now 64 bits, so keep it up! */
+#define OPT_CANCEL_ELSEWHERE	((uint64_t)1 << 33)
+#define OPT_PEER_H   			((uint64_t)1 << 34)
 
 enum {
 	OPT_ARG_ANNOUNCE = 0,
@@ -305,6 +311,8 @@ AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
 	AST_APP_OPTION_ARG('U', OPT_CALLEE_GOSUB, OPT_ARG_CALLEE_GOSUB),
 	AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
 	AST_APP_OPTION('W', OPT_CALLER_MONITOR),
+	AST_APP_OPTION('x', OPT_CALLEE_MIXMONITOR),
+	AST_APP_OPTION('X', OPT_CALLER_MIXMONITOR),
 END_OPTIONS );
 
 #define CAN_EARLY_BRIDGE(flags) (!ast_test_flag64(flags, OPT_CALLEE_HANGUP | \
@@ -621,6 +629,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 						       OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
 						       OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
 						       OPT_CALLEE_PARK | OPT_CALLER_PARK |
+						       OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
 						       DIAL_NOFORWARDHTML);
 					ast_copy_string(c->dialcontext, "", sizeof(c->dialcontext));
 					ast_copy_string(c->exten, "", sizeof(c->exten));
@@ -655,6 +664,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
 							       OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
 							       OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
 							       OPT_CALLEE_PARK | OPT_CALLER_PARK |
+							       OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
 							       DIAL_NOFORWARDHTML);
 						ast_copy_string(c->dialcontext, "", sizeof(c->dialcontext));
 						ast_copy_string(c->exten, "", sizeof(c->exten));
@@ -1332,6 +1342,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
 				       OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
 				       OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
 				       OPT_CALLEE_PARK | OPT_CALLER_PARK |
+				       OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
 				       OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID);
 			ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML);	
 		}
@@ -1758,6 +1769,10 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
 				ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
 			if (ast_test_flag64(peerflags, OPT_CALLER_PARK))
 				ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
+			if (ast_test_flag64(peerflags, OPT_CALLEE_MIXMONITOR))
+				ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMIXMON);
+			if (ast_test_flag64(peerflags, OPT_CALLER_MIXMONITOR))
+				ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMIXMON);
 
 			if (moh) {
 				moh = 0;
diff --git a/apps/app_queue.c b/apps/app_queue.c
index d78420e12f5df0bf5bef98f209bb740edd5c8ec2..8be6a30458e4e780add25331837a14e0527187fe 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -152,6 +152,9 @@ static char *descrip =
 "             the DTMF sequence defined for call parking in features.conf.\n"
 "      'K' -- Allow the calling party to enable parking of the call by sending\n"
 "             the DTMF sequence defined for call parking in features.conf.\n"
+"      'x' -- allow the called user to write the conversation to disk via MixMonitor\n"
+"      'X' -- allow the calling user to write the conversation to disk via MixMonitor\n"
+ 
 "  In addition to transferring the call, a call may be parked and then picked\n"
 "up by another user.\n"
 "  The optional URL will be sent to the called party if the channel supports\n"
@@ -2775,6 +2778,13 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
 		case 'i':
 			forwardsallowed = 0;
 			break;
+		case 'x':
+			ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
+			break;
+		case 'X':
+			ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
+			break;
+
 		}
 
 	/* Hold the lock while we setup the outgoing calls */
diff --git a/configs/features.conf.sample b/configs/features.conf.sample
index 30a61b5d2f03c96a622861f36dbaf0e0a3492a7e..c3026adda978a58c1afc16a6c84b30ab34ab2343 100644
--- a/configs/features.conf.sample
+++ b/configs/features.conf.sample
@@ -52,6 +52,7 @@ context => parkedcalls		; Which context parked calls are in
 ;automon => *1			; One Touch Record a.k.a. Touch Monitor
 ;atxfer => *2			; Attended transfer
 ;parkcall => #72                ; Park call (one step parking)
+;automixmon => *3		; One Touch Record a.k.a. Touch MixMonitor
 
 [applicationmap]
 ; Note that the DYNAMIC_FEATURES channel variable must be set to use the features
diff --git a/include/asterisk/app.h b/include/asterisk/app.h
index 656e8390fcb6c9b403f38dcce2697c03ef708265..f76b0d96f759a3b9c46dda197e09cbafdf553f5b 100644
--- a/include/asterisk/app.h
+++ b/include/asterisk/app.h
@@ -344,7 +344,7 @@ unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arra
  */
 struct ast_app_option {
 	/*! \brief The flag bit that represents this option. */
-	unsigned int flag;
+	uint64_t flag;
 	/*! \brief The index of the entry in the arguments array
 	  that should be used for this option's argument. */
 	unsigned int arg_index;
diff --git a/include/asterisk/audiohook.h b/include/asterisk/audiohook.h
index 3fd2eb1bf0b6f7360cbe8ece8154a903b696db3a..5ef0ac29432a4ea03fd339f4f4d9bd15ae10cb38 100644
--- a/include/asterisk/audiohook.h
+++ b/include/asterisk/audiohook.h
@@ -171,6 +171,28 @@ struct ast_frame *ast_audiohook_write_list(struct ast_channel *chan, struct ast_
  */
 void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook);
 
+/*!
+  \brief Find out how many audiohooks from  a certain source exist on a given channel, regardless of status.
+  \param chan The channel on which to find the spies 
+  \param source The audiohook's source
+  \param type The type of audiohook 
+  \return Return the number of audiohooks which are from the source specified
+
+  Note: Function performs nlocking.
+*/
+int ast_channel_audiohook_count_by_source(struct ast_channel *chan, const char *source, enum ast_audiohook_type type);
+
+/*!
+  \brief Find out how many spies of a certain type exist on a given channel, and are in state running.
+  \param chan The channel on which to find the spies
+  \param source The source of the audiohook
+  \param type The type of spy to look for
+  \return Return the number of running audiohooks which are from the source specified
+
+  Note: Function performs no locking.
+*/
+int ast_channel_audiohook_count_by_source_running(struct ast_channel *chan, const char *source, enum ast_audiohook_type type);
+
 /*! \brief Lock an audiohook
  * \param ah Audiohook structure
  */
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 4bf33d7bd1f8e0c8b428ffb4559ecb1c8a234fc2..aea8f4d8c164aa182e10da5df9a8639cc012d55c 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -565,6 +565,7 @@ enum {
 	AST_FEATURE_ATXFER =       (1 << 3),
 	AST_FEATURE_AUTOMON =      (1 << 4),
 	AST_FEATURE_PARKCALL =     (1 << 5),
+	AST_FEATURE_AUTOMIXMON =   (1 << 6),
 };
 
 /*! \brief bridge configuration */
diff --git a/main/audiohook.c b/main/audiohook.c
index f1e5f5809c078245595ca71cee8655753d3d3aae..9b979306185b456dc33c2bc7b3138b6bb380bc0a 100644
--- a/main/audiohook.c
+++ b/main/audiohook.c
@@ -612,3 +612,83 @@ void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
 	
 	return;
 }
+
+/* Count number of channel audiohooks by type, regardless of type */
+int ast_channel_audiohook_count_by_source(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
+{
+	int count = 0;
+	struct ast_audiohook *ah = NULL;
+
+	if (!chan->audiohooks)
+		return -1;
+
+	switch (type) {
+		case AST_AUDIOHOOK_TYPE_SPY:
+			AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->spy_list, ah, list) {
+				if (!strcmp(ah->source, source)) {
+					count++;
+				}
+			}
+			AST_LIST_TRAVERSE_SAFE_END;
+			break;
+		case AST_AUDIOHOOK_TYPE_WHISPER:
+			AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->whisper_list, ah, list) {
+				if (!strcmp(ah->source, source)) {
+					count++;
+				}
+			}
+			AST_LIST_TRAVERSE_SAFE_END;
+			break;
+		case AST_AUDIOHOOK_TYPE_MANIPULATE:
+			AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->manipulate_list, ah, list) {
+				if (!strcmp(ah->source, source)) {
+					count++;
+				}
+			}
+			AST_LIST_TRAVERSE_SAFE_END;
+			break;
+		default:
+			ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
+			return -1;
+	}
+
+	return count;
+}
+
+/* Count number of channel audiohooks by type that are running */
+int ast_channel_audiohook_count_by_source_running(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
+{
+	int count = 0;
+	struct ast_audiohook *ah = NULL;
+	if (!chan->audiohooks)
+		return -1;
+
+	switch (type) {
+		case AST_AUDIOHOOK_TYPE_SPY:
+			AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->spy_list, ah, list) {
+				if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
+					count++;
+			}
+			AST_LIST_TRAVERSE_SAFE_END;
+			break;
+		case AST_AUDIOHOOK_TYPE_WHISPER:
+			AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->whisper_list, ah, list) {
+				if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
+					count++;
+			}
+			AST_LIST_TRAVERSE_SAFE_END;
+			break;
+		case AST_AUDIOHOOK_TYPE_MANIPULATE:
+			AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->manipulate_list, ah, list) {
+				if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
+					count++;
+			}
+			AST_LIST_TRAVERSE_SAFE_END;
+			break;
+		default:
+			ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%d)\n", type);
+			return -1;
+	}
+	return count;
+}
+
diff --git a/res/res_features.c b/res/res_features.c
index b483dbb005cb9596362e2cdd7262a6b4fb3eed21..3deb1bc6a22d10e1d0b3716bcb1d113b5d0e87f2 100644
--- a/res/res_features.c
+++ b/res/res_features.c
@@ -50,6 +50,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/adsi.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/monitor.h"
+#include "asterisk/audiohook.h"
 
 #define DEFAULT_PARK_TIME 45000
 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
@@ -151,6 +152,12 @@ static char *descrip2 = "Park(): "
 static struct ast_app *monitor_app = NULL;
 static int monitor_ok = 1;
 
+static struct ast_app *mixmonitor_app = NULL;
+static int mixmonitor_ok = 1;
+
+static struct ast_app *stopmixmonitor_app = NULL;
+static int stopmixmonitor_ok = 1;
+
 struct parkeduser {
 	struct ast_channel *chan;                   /*!< Parking channel */
 	struct timeval start;                       /*!< Time the parking started */
@@ -717,6 +724,118 @@ static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *pee
 	return -1;
 }
 
+static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
+{
+	char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
+	int x = 0;
+	size_t len;
+	struct ast_channel *caller_chan, *callee_chan;
+	const char *mixmonitor_spy_type = "MixMonitor";
+	int count = 0;
+
+	if (!mixmonitor_ok) {
+		ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
+		return -1;
+	}
+
+	if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
+		mixmonitor_ok = 0;
+		ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
+		return -1;
+	}
+
+	set_peers(&caller_chan, &callee_chan, peer, chan, sense);
+
+	if (!ast_strlen_zero(courtesytone)) {
+		if (ast_autoservice_start(callee_chan))
+			return -1;
+		if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
+			ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
+			ast_autoservice_stop(callee_chan);
+			return -1;
+		}
+		if (ast_autoservice_stop(callee_chan))
+			return -1;
+	}
+
+	ast_channel_lock(callee_chan);
+	count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
+	ast_channel_unlock(callee_chan);
+
+	// This means a mixmonitor is attached to the channel, running or not is unknown.
+	if (count > 0) {
+		
+		if (option_verbose > 3)
+			ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
+
+		//Make sure they are running
+		ast_channel_lock(callee_chan);
+		count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
+		ast_channel_unlock(callee_chan);
+		if (count > 0) {
+			if (!stopmixmonitor_ok) {
+				ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
+				return -1;
+			}
+			if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
+				stopmixmonitor_ok = 0;
+				ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
+				return -1;
+			} else {
+				pbx_exec(callee_chan, stopmixmonitor_app, "");
+				return FEATURE_RETURN_SUCCESS;
+			}
+		}
+		
+		ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n");	
+	}			
+
+	if (caller_chan && callee_chan) {
+		const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
+		const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
+
+		if (!touch_format)
+			touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
+
+		if (!touch_monitor)
+			touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
+
+		if (touch_monitor) {
+			len = strlen(touch_monitor) + 50;
+			args = alloca(len);
+			touch_filename = alloca(len);
+			snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
+			snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
+		} else {
+			caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
+			callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
+			len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
+			args = alloca(len);
+			touch_filename = alloca(len);
+			snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
+			snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
+		}
+
+		for( x = 0; x < strlen(args); x++) {
+			if (args[x] == '/')
+				args[x] = '-';
+		}
+
+		if (option_verbose > 3)
+			ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, touch_filename);
+
+		pbx_exec(callee_chan, mixmonitor_app, args);
+		pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
+		pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
+		return FEATURE_RETURN_SUCCESS;
+	
+	}
+
+	ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
+	return -1;
+
+}
+
 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
 {
 	ast_verb(4, "User hit '%s' to disconnect call.\n", code);
@@ -1136,6 +1255,7 @@ static struct ast_call_feature builtin_features[] =
 	{ AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
 	{ AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
 	{ AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
+	{ AST_FEATURE_AUTOMIXMON, "One Touch MixMonitor", "automixmon", "", "", builtin_automixmonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
 };