diff --git a/CHANGES b/CHANGES
index cc6181010f67effe92dbd8d85505d7736a0b2706..91cd210bb4b1d312bef2ec2457db53b02c0d7cbb 100644
--- a/CHANGES
+++ b/CHANGES
@@ -51,6 +51,11 @@ Say
    the background application and jump to the received extension once a match
    is established or after a short period of inactivity.
 
+MixMonitor
+-------------------------
+ * A new function, MIXMONITOR, has been added to allow access to individual
+   instances of MixMonitor on a channel.
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 11 to Asterisk 12 --------------------
 ------------------------------------------------------------------------------
diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c
index f4ea27fe85b30ef0b6f398000dd51eb2e624509a..e22c8b0eae97fc945dbc104f375a4799e6b7d6eb 100644
--- a/apps/app_mixmonitor.c
+++ b/apps/app_mixmonitor.c
@@ -237,6 +237,23 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 			action on the current channel.</para>
 		</description>
 	</manager>
+	<function name="MIXMONITOR" language="en_US">
+		<synopsis>
+			Retrieve data pertaining to specific instances of MixMonitor on a channel.
+		</synopsis>
+		<syntax>
+			<parameter name="id" required="true">
+				<para>The unique ID of the MixMonitor instance. The unique ID can be retrieved through the channel
+				variable used as an argument to the <replaceable>i</replaceable> option to MixMonitor.</para>
+			</parameter>
+			<parameter name="key" required="true">
+				<para>The piece of data to retrieve from the MixMonitor.</para>
+				<enumlist>
+					<enum name="filename" />
+				</enumlist>
+			</parameter>
+		</syntax>
+	</function>
 
  ***/
 
@@ -338,6 +355,7 @@ struct mixmonitor_ds {
 	struct ast_audiohook *audiohook;
 
 	unsigned int samp_rate;
+	char *filename;
 };
 
 /*!
@@ -381,6 +399,7 @@ static void mixmonitor_ds_destroy(void *data)
 	ast_mutex_lock(&mixmonitor_ds->lock);
 	mixmonitor_ds->audiohook = NULL;
 	mixmonitor_ds->destruction_ok = 1;
+	ast_free(mixmonitor_ds->filename);
 	ast_cond_signal(&mixmonitor_ds->destruction_condition);
 	ast_mutex_unlock(&mixmonitor_ds->lock);
 }
@@ -774,6 +793,7 @@ static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel
 
 	mixmonitor_ds->samp_rate = 8000;
 	mixmonitor_ds->audiohook = &mixmonitor->audiohook;
+	mixmonitor_ds->filename = ast_strdup(mixmonitor->filename);
 	datastore->data = mixmonitor_ds;
 
 	ast_channel_lock(chan);
@@ -835,6 +855,18 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
 		return -1;
 	}
 
+	if (!ast_strlen_zero(filename)) {
+		mixmonitor->filename = ast_strdup(filename);
+	}
+
+	if (!ast_strlen_zero(filename_write)) {
+		mixmonitor->filename_write = ast_strdup(filename_write);
+	}
+
+	if (!ast_strlen_zero(filename_read)) {
+		mixmonitor->filename_read = ast_strdup(filename_read);
+	}
+
 	if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id)) {
 		ast_autochan_destroy(mixmonitor->autochan);
 		mixmonitor_free(mixmonitor);
@@ -855,18 +887,6 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
 		mixmonitor->post_process = ast_strdup(postprocess2);
 	}
 
-	if (!ast_strlen_zero(filename)) {
-		mixmonitor->filename = ast_strdup(filename);
-	}
-
-	if (!ast_strlen_zero(filename_write)) {
-		mixmonitor->filename_write = ast_strdup(filename_write);
-	}
-
-	if (!ast_strlen_zero(filename_read)) {
-		mixmonitor->filename_read = ast_strdup(filename_read);
-	}
-
 	if (!ast_strlen_zero(recipients)) {
 		char callerid[256];
 		struct ast_party_connected_line *connected;
@@ -1368,6 +1388,49 @@ static int manager_stop_mixmonitor(struct mansession *s, const struct message *m
 	return AMI_SUCCESS;
 }
 
+static int func_mixmonitor_read(struct ast_channel *chan, const char *cmd, char *data,
+		char *buf, size_t len)
+{
+	struct ast_datastore *datastore;
+	struct mixmonitor_ds *ds_data;
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(id);
+		AST_APP_ARG(key);
+	);
+
+	AST_STANDARD_APP_ARGS(args, data);
+
+	if (ast_strlen_zero(args.id) || ast_strlen_zero(args.key)) {
+		ast_log(LOG_WARNING, "Not enough arguments provided to %s. "
+				"An ID and key must be provided\n", cmd);
+		return -1;
+	}
+
+	ast_channel_lock(chan);
+	datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.id);
+	ast_channel_unlock(chan);
+
+	if (!datastore) {
+		ast_log(LOG_WARNING, "Could not find MixMonitor with ID %s\n", args.id);
+		return -1;
+	}
+
+	ds_data = datastore->data;
+
+	if (!strcasecmp(args.key, "filename")) {
+		ast_copy_string(buf, ds_data->filename, len);
+	} else {
+		ast_log(LOG_WARNING, "Unrecognized %s option %s\n", cmd, args.key);
+		return -1;
+	}
+	return 0;
+}
+
+static struct ast_custom_function mixmonitor_function = {
+	.name = "MIXMONITOR",
+	.read = func_mixmonitor_read,
+};
+
 static struct ast_cli_entry cli_mixmonitor[] = {
 	AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
 };
@@ -1397,6 +1460,7 @@ static int unload_module(void)
 	res |= ast_manager_unregister("MixMonitorMute");
 	res |= ast_manager_unregister("MixMonitor");
 	res |= ast_manager_unregister("StopMixMonitor");
+	res |= ast_custom_function_unregister(&mixmonitor_function);
 	res |= clear_mixmonitor_methods();
 
 	return res;
@@ -1412,6 +1476,7 @@ static int load_module(void)
 	res |= ast_manager_register_xml("MixMonitorMute", 0, manager_mute_mixmonitor);
 	res |= ast_manager_register_xml("MixMonitor", 0, manager_mixmonitor);
 	res |= ast_manager_register_xml("StopMixMonitor", 0, manager_stop_mixmonitor);
+	res |= ast_custom_function_register(&mixmonitor_function);
 	res |= set_mixmonitor_methods();
 
 	return res;