Index: apps/app_queue.c
===================================================================
--- apps/app_queue.c	(revision 75155)
+++ apps/app_queue.c	(working copy)
@@ -146,6 +146,8 @@
 "      'T' -- to allow the calling user to transfer the call.\n"
 "      'w' -- allow the called user to write the conversation to disk via Monitor\n"
 "      'W' -- allow the calling user to write the conversation to disk via Monitor\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"
@@ -2361,6 +2363,13 @@
 		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 */
Index: doc/channelvariables.txt
===================================================================
--- doc/channelvariables.txt	(revision 75155)
+++ doc/channelvariables.txt	(working copy)
@@ -641,23 +641,26 @@
 
 Various application variables
 -----------------------------
-${CURL}			* Resulting page content for curl()
-${ENUM}			* Result of application EnumLookup
-${EXITCONTEXT}		Context to exit to in IVR menu (app background())
-			or in the RetryDial() application
-${MONITOR}		* Set to "TRUE" if the channel is/has been monitored (app monitor())
-${MONITOR_EXEC}		Application to execute after monitoring a call
-${MONITOR_EXEC_ARGS}	Arguments to application
-${MONITOR_FILENAME} 	File for monitoring (recording) calls in queue
-${QUEUE_PRIO}		Queue priority
-${QUEUE_MAX_PENALTY}	Maximum member penalty allowed to answer caller
-${QUEUESTATUS} 		Status of the call, one of:
-			(TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL)
-${RECORDED_FILE} 	* Recorded file in record()
-${TALK_DETECTED} 	* Result from talkdetect()
-${TOUCH_MONITOR} 	The filename base to use with Touch Monitor (auto record)
-${TOUCH_MONITOR_FORMAT} The audio format to use with Touch Monitor (auto record)
-${TOUCH_MONITOR_OUTPUT} * Recorded file from Touch Monitor (auto record)
+${CURL}				* Resulting page content for curl()
+${ENUM}				* Result of application EnumLookup
+${EXITCONTEXT}			Context to exit to in IVR menu (app background())
+				or in the RetryDial() application
+${MONITOR}			* Set to "TRUE" if the channel is/has been monitored (app monitor())
+${MONITOR_EXEC}			Application to execute after monitoring a call
+${MONITOR_EXEC_ARGS}		Arguments to application
+${MONITOR_FILENAME} 		File for monitoring (recording) calls in queue
+${QUEUE_PRIO}			Queue priority
+${QUEUE_MAX_PENALTY}		Maximum member penalty allowed to answer caller
+${QUEUESTATUS} 			Status of the call, one of:
+				(TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL)
+${RECORDED_FILE} 		* Recorded file in record()
+${TALK_DETECTED} 		* Result from talkdetect()
+${TOUCH_MONITOR} 		The filename base to use with Touch Monitor (auto record)
+${TOUCH_MONITOR_FORMAT} 	The audio format to use with Touch Monitor (auto record)
+${TOUCH_MONITOR_OUTPUT} 	* Recorded file from Touch Monitor (auto record)
+${TOUCH_MIXMONITOR}     	The filename base to use with Touch MixMonitor (auto record)
+${TOUCH_MIXMONITOR_FORMAT}	The audio format to use with Touch MixMonitor (auto record)
+${TOUCH_MIXMONITOR_OUTPUT}	* Recorded file from Touch MixMonitor (auto record)
 ${TXTCIDNAME}		* Result of application TXTCIDName
 ${VPB_GETDTMF}		chan_vpb
 
Index: include/asterisk/channel.h
===================================================================
--- include/asterisk/channel.h	(revision 75155)
+++ include/asterisk/channel.h	(working copy)
@@ -488,6 +488,7 @@
 	AST_FEATURE_ATXFER =       (1 << 3),
 	AST_FEATURE_AUTOMON =      (1 << 4),
 	AST_FEATURE_PARKCALL =     (1 << 5),
+	AST_FEATURE_AUTOMIXMON =   (1 << 6),
 };
 
 struct ast_bridge_config {
Index: configs/features.conf.sample
===================================================================
--- configs/features.conf.sample	(revision 75155)
+++ configs/features.conf.sample	(working copy)
@@ -37,6 +37,7 @@
 ;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
Index: res/res_features.c
===================================================================
--- res/res_features.c	(revision 75155)
+++ res/res_features.c	(working copy)
@@ -131,6 +131,12 @@
 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 */
@@ -612,6 +618,102 @@
 	return -1;
 }
 
+static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
+{
+	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;
+
+	if (!mixmonitor_ok) {
+		ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
+		return -1;
+	}
+
+	if (!mixmonitor_app && !(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, caller_chan->language, "")) {
+			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;
+	}
+
+	if (ast_test_flag(config, AST_FEATURE_AUTOMIXMON)) {
+		if (option_verbose > 3)
+			ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
+		if (!stopmixmonitor_ok) {
+			ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
+			return -1;
+		}
+		if (!stopmixmonitor_app && !(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
+			mixmonitor_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;
+		}
+        }
+
+	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, args);
+
+		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)
 {
 	if (option_verbose > 3)
@@ -890,6 +992,7 @@
 	{ 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, "" },
 };
 
 
