[asterisk-commits] rmudgett: trunk r393612 - in /trunk: bridges/ include/asterisk/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jul 3 17:36:50 CDT 2013


Author: rmudgett
Date: Wed Jul  3 17:36:38 2013
New Revision: 393612

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=393612
Log:
OneTouchRecord: Make so Monitor/MixMonitor can be toggled/started/stopped.

The OneTouchRecord feature has historically been a toggle.  This patch
adds the ability to make the OneTouchRecord hook optionally start/stop
recording only.  If OneTouchRecord is already doing what is requested then
only the invoker hears the courtesy tone and/or start/stop recording
message.

The new feature is written so we could easily add explicit start/stop
recording DTMF hooks for Monitor and MixMonitor.

The majority of the changes in bridge_builtin_features.c is a refactoring
of the OneTouchRecord code (Monitor and MixMonitor versions) so it is easy
to direct the toggle/start/stop functionality.

Review: https://reviewboard.asterisk.org/r/2655/

Modified:
    trunk/bridges/bridge_builtin_features.c
    trunk/include/asterisk/bridging_features.h

Modified: trunk/bridges/bridge_builtin_features.c
URL: http://svnview.digium.com/svn/asterisk/trunk/bridges/bridge_builtin_features.c?view=diff&rev=393612&r1=393611&r2=393612
==============================================================================
--- trunk/bridges/bridge_builtin_features.c (original)
+++ trunk/bridges/bridge_builtin_features.c Wed Jul  3 17:36:38 2013
@@ -466,15 +466,57 @@
 	return 0;
 }
 
-static void stop_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg)
-{
-	const char *stop_message;
-
-	ast_channel_lock(bridge_channel->chan);
-	stop_message = pbx_builtin_getvar_helper(bridge_channel->chan, "TOUCH_MONITOR_MESSAGE_STOP");
-	stop_message = ast_strdupa(S_OR(stop_message, ""));
-	ast_channel_unlock(bridge_channel->chan);
-
+enum set_touch_variables_res {
+	SET_TOUCH_SUCCESS,
+	SET_TOUCH_UNSET,
+	SET_TOUCH_ALLOC_FAILURE,
+};
+
+static void set_touch_variable(enum set_touch_variables_res *res, struct ast_channel *chan, const char *var_name, char **touch)
+{
+	const char *c_touch;
+
+	if (*res == SET_TOUCH_ALLOC_FAILURE) {
+		return;
+	}
+	c_touch = pbx_builtin_getvar_helper(chan, var_name);
+	if (!ast_strlen_zero(c_touch)) {
+		*touch = ast_strdup(c_touch);
+		if (!*touch) {
+			*res = SET_TOUCH_ALLOC_FAILURE;
+		} else {
+			*res = SET_TOUCH_SUCCESS;
+		}
+	}
+}
+
+static enum set_touch_variables_res set_touch_variables(struct ast_channel *chan, int is_mixmonitor, char **touch_format, char **touch_monitor, char **touch_monitor_prefix)
+{
+	enum set_touch_variables_res res = SET_TOUCH_UNSET;
+	const char *var_format;
+	const char *var_monitor;
+	const char *var_prefix;
+
+	SCOPED_CHANNELLOCK(lock, chan);
+
+	if (is_mixmonitor) {
+		var_format = "TOUCH_MIXMONITOR_FORMAT";
+		var_monitor = "TOUCH_MIXMONITOR";
+		var_prefix = "TOUCH_MIXMONITOR_PREFIX";
+	} else {
+		var_format = "TOUCH_MONITOR_FORMAT";
+		var_monitor = "TOUCH_MONITOR";
+		var_prefix = "TOUCH_MONITOR_PREFIX";
+	}
+	set_touch_variable(&res, chan, var_format, touch_format);
+	set_touch_variable(&res, chan, var_monitor, touch_monitor);
+	set_touch_variable(&res, chan, var_prefix, touch_monitor_prefix);
+
+	return res;
+}
+
+static void stop_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *stop_message)
+{
 	ast_verb(3, "AutoMonitor used to stop recording call.\n");
 
 	ast_channel_lock(peer_chan);
@@ -506,54 +548,10 @@
 	}
 }
 
-enum set_touch_variables_res {
-	SET_TOUCH_SUCCESS = 0,
-	SET_TOUCH_UNSET,
-	SET_TOUCH_ALLOC_FAILURE,
-};
-
-static int set_touch_variables(struct ast_channel *chan, int is_mixmonitor, char **touch_format, char **touch_monitor, char **touch_monitor_prefix)
-{
-	enum set_touch_variables_res res = SET_TOUCH_UNSET;
-	const char *c_touch_format, *c_touch_monitor, *c_touch_monitor_prefix;
-
-	SCOPED_CHANNELLOCK(lock, chan);
-
-	c_touch_format = pbx_builtin_getvar_helper(chan, is_mixmonitor ? "TOUCH_MIXMONITOR_FORMAT" : "TOUCH_MONITOR_FORMAT");
-
-	if (!ast_strlen_zero(c_touch_format)) {
-		if (!(*touch_format = ast_strdup(c_touch_format))) {
-			return SET_TOUCH_ALLOC_FAILURE;
-		}
-		res = SET_TOUCH_SUCCESS;
-	}
-
-	c_touch_monitor = pbx_builtin_getvar_helper(chan, is_mixmonitor ? "TOUCH_MIXMONITOR" : "TOUCH_MONITOR");
-
-	if (!ast_strlen_zero(c_touch_monitor)) {
-		if (!(*touch_monitor = ast_strdup(c_touch_monitor))) {
-			return SET_TOUCH_ALLOC_FAILURE;
-		}
-		res = SET_TOUCH_SUCCESS;
-	}
-
-	c_touch_monitor_prefix = pbx_builtin_getvar_helper(chan, is_mixmonitor ? "TOUCH_MIXMONITOR_PREFIX" : "TOUCH_MONITOR_PREFIX");
-
-	if (!ast_strlen_zero(c_touch_monitor_prefix)) {
-		if (!(*touch_monitor_prefix = ast_strdup(c_touch_monitor_prefix))) {
-			return SET_TOUCH_ALLOC_FAILURE;
-		}
-		res = SET_TOUCH_SUCCESS;
-	}
-
-	return res;
-}
-
-static int feature_automonitor(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	char *caller_chan_id = NULL, *peer_chan_id = NULL, *touch_filename = NULL;
+static void start_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
+{
+	char *touch_filename;
 	size_t len;
-	const char *automon_message;
 	int x;
 	enum set_touch_variables_res set_touch_res;
 
@@ -561,49 +559,47 @@
 	RAII_VAR(char *, touch_monitor, NULL, ast_free);
 	RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
 
-	RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
-	RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
-
-	features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
-	peer_chan = ast_bridge_peer(bridge, bridge_channel->chan);
-
-	if (!peer_chan) {
-		ast_verb(3, "Cannot start AutoMonitor for %s - can not determine peer in bridge.\n", ast_channel_name(bridge_channel->chan));
-		if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
-			ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
-		}
-		return 0;
-	}
-
-	if (ast_channel_monitor(peer_chan)) {
-		stop_automonitor(bridge_channel, peer_chan, features_cfg);
-		return 0;
-	}
-
-	if ((set_touch_res = set_touch_variables(bridge_channel->chan, 0, &touch_format, &touch_monitor, &touch_monitor_prefix))) {
+	set_touch_res = set_touch_variables(bridge_channel->chan, 0, &touch_format,
+		&touch_monitor, &touch_monitor_prefix);
+	switch (set_touch_res) {
+	case SET_TOUCH_SUCCESS:
+		break;
+	case SET_TOUCH_UNSET:
+		set_touch_res = set_touch_variables(peer_chan, 0, &touch_format, &touch_monitor,
+			&touch_monitor_prefix);
 		if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
-			return 0;
-		}
-		if (set_touch_variables(peer_chan, 0, &touch_format, &touch_monitor, &touch_monitor_prefix) == SET_TOUCH_ALLOC_FAILURE) {
-			return 0;
-		}
+			return;
+		}
+		break;
+	case SET_TOUCH_ALLOC_FAILURE:
+		return;
 	}
 
 	if (!ast_strlen_zero(touch_monitor)) {
 		len = strlen(touch_monitor) + 50;
 		touch_filename = ast_alloca(len);
-		snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
+		snprintf(touch_filename, len, "%s-%ld-%s",
+			S_OR(touch_monitor_prefix, "auto"),
+			(long) time(NULL),
+			touch_monitor);
 	} else {
+		char *caller_chan_id;
+		char *peer_chan_id;
+
 		caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
 			ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
 		peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
 			ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
 		len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
 		touch_filename = ast_alloca(len);
-		snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, peer_chan_id);
-	}
-
-	for ( x = 0; x < strlen(touch_filename); x++) {
+		snprintf(touch_filename, len, "%s-%ld-%s-%s",
+			S_OR(touch_monitor_prefix, "auto"),
+			(long) time(NULL),
+			caller_chan_id,
+			peer_chan_id);
+	}
+
+	for (x = 0; x < strlen(touch_filename); x++) {
 		if (touch_filename[x] == '/') {
 			touch_filename[x] = '-';
 		}
@@ -612,40 +608,102 @@
 	ast_verb(3, "AutoMonitor used to record call. Filename: %s\n", touch_filename);
 
 	if (ast_monitor_start(peer_chan, touch_format, touch_filename, 1, X_REC_IN | X_REC_OUT)) {
-		ast_verb(3, "automon feature was tried by '%s' but monitor failed to start.\n", ast_channel_name(bridge_channel->chan));
-		return 0;
-	}
-
-	ast_channel_lock(bridge_channel->chan);
-	if ((automon_message = pbx_builtin_getvar_helper(bridge_channel->chan, "TOUCH_MONITOR_MESSAGE_START"))) {
-		automon_message = ast_strdupa(automon_message);
-	}
-	ast_channel_unlock(bridge_channel->chan);
-
-	if ((features_cfg = ast_get_chan_features_general_config(bridge_channel->chan)) && !(ast_strlen_zero(features_cfg->courtesytone))) {
+		ast_verb(3, "automon feature was tried by '%s' but monitor failed to start.\n",
+			ast_channel_name(bridge_channel->chan));
+		return;
+	}
+
+	if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
 		ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
 		ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
 	}
 
-	if (!ast_strlen_zero(automon_message)) {
-		ast_bridge_channel_queue_playfile(bridge_channel, NULL, automon_message, NULL);
-		ast_bridge_channel_write_playfile(bridge_channel, NULL, automon_message, NULL);
+	if (!ast_strlen_zero(start_message)) {
+		ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
+		ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
 	}
 
 	pbx_builtin_setvar_helper(peer_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
-
-	return 0;
-}
-
-static void stop_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg)
-{
+}
+
+static int feature_automonitor(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+	const char *start_message;
 	const char *stop_message;
+	struct ast_bridge_features_automonitor *options = hook_pvt;
+	enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
+	int is_monitoring;
+
+	RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
+	RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
+
+	features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
+	peer_chan = ast_bridge_peer(bridge, bridge_channel->chan);
+
+	if (!peer_chan) {
+		ast_verb(3, "Cannot start AutoMonitor for %s - can not determine peer in bridge.\n",
+			ast_channel_name(bridge_channel->chan));
+		if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
+			ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
+		}
+		return 0;
+	}
 
 	ast_channel_lock(bridge_channel->chan);
-	stop_message = pbx_builtin_getvar_helper(bridge_channel->chan, "TOUCH_MIXMONITOR_MESSAGE_STOP");
+	start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
+		"TOUCH_MONITOR_MESSAGE_START");
+	start_message = ast_strdupa(S_OR(start_message, ""));
+	stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
+		"TOUCH_MONITOR_MESSAGE_STOP");
 	stop_message = ast_strdupa(S_OR(stop_message, ""));
 	ast_channel_unlock(bridge_channel->chan);
 
+	is_monitoring = ast_channel_monitor(peer_chan) != NULL;
+	switch (start_stop) {
+	case AUTO_MONITOR_TOGGLE:
+		if (is_monitoring) {
+			stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
+		} else {
+			start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
+		}
+		return 0;
+	case AUTO_MONITOR_START:
+		if (!is_monitoring) {
+			start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
+			return 0;
+		}
+		ast_verb(3, "AutoMonitor already recording call.\n");
+		break;
+	case AUTO_MONITOR_STOP:
+		if (is_monitoring) {
+			stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
+			return 0;
+		}
+		ast_verb(3, "AutoMonitor already not recording call.\n");
+		break;
+	}
+
+	/*
+	 * Fake start/stop to invoker so will think it did something but
+	 * was already in that mode.
+	 */
+	if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
+		ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
+	}
+	if (is_monitoring) {
+		if (!ast_strlen_zero(start_message)) {
+			ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
+		}
+	} else {
+		if (!ast_strlen_zero(stop_message)) {
+			ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
+		}
+	}
+	return 0;
+}
+
+static void stop_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *stop_message)
+{
 	ast_verb(3, "AutoMixMonitor used to stop recording call.\n");
 
 	if (ast_stop_mixmonitor(peer_chan, NULL)) {
@@ -656,7 +714,7 @@
 		return;
 	}
 
-	if (features_cfg && !(ast_strlen_zero(features_cfg->courtesytone))) {
+	if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
 		ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
 		ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
 	}
@@ -665,67 +723,62 @@
 		ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
 		ast_bridge_channel_write_playfile(bridge_channel, NULL, stop_message, NULL);
 	}
-
-}
-
-static int feature_automixmonitor(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
-{
-	char *caller_chan_id = NULL, *peer_chan_id = NULL, *touch_filename = NULL;
+}
+
+static void start_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
+{
+	char *touch_filename;
 	size_t len;
-	const char *automon_message;
-	static char *mixmonitor_spy_type = "MixMonitor";
-	int count, x;
+	int x;
 	enum set_touch_variables_res set_touch_res;
 
 	RAII_VAR(char *, touch_format, NULL, ast_free);
 	RAII_VAR(char *, touch_monitor, NULL, ast_free);
 	RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
 
-	RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
-	RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
-
-	features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
-
-	peer_chan = ast_bridge_peer(bridge, bridge_channel->chan);
-
-	if (!peer_chan) {
-		ast_verb(3, "Cannot start AutoMixMonitor for %s - can not determine peer in bridge.\n", ast_channel_name(bridge_channel->chan));
-		if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
-			ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
-		}
-		return 0;
-	}
-
-	count = ast_channel_audiohook_count_by_source(peer_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
-	if (count > 0) {
-		stop_automixmonitor(bridge_channel, peer_chan, features_cfg);
-		return 0;
-	}
-
-	if ((set_touch_res = set_touch_variables(bridge_channel->chan, 1, &touch_format, &touch_monitor, &touch_monitor_prefix))) {
+	set_touch_res = set_touch_variables(bridge_channel->chan, 1, &touch_format,
+		&touch_monitor, &touch_monitor_prefix);
+	switch (set_touch_res) {
+	case SET_TOUCH_SUCCESS:
+		break;
+	case SET_TOUCH_UNSET:
+		set_touch_res = set_touch_variables(peer_chan, 1, &touch_format, &touch_monitor,
+			&touch_monitor_prefix);
 		if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
-			return 0;
-		}
-		if (set_touch_variables(peer_chan, 1, &touch_format, &touch_monitor, &touch_monitor_prefix) == SET_TOUCH_ALLOC_FAILURE) {
-			return 0;
-		}
+			return;
+		}
+		break;
+	case SET_TOUCH_ALLOC_FAILURE:
+		return;
 	}
 
 	if (!ast_strlen_zero(touch_monitor)) {
 		len = strlen(touch_monitor) + 50;
 		touch_filename = ast_alloca(len);
-		snprintf(touch_filename, len, "%s-%ld-%s.%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor, S_OR(touch_format, "wav"));
+		snprintf(touch_filename, len, "%s-%ld-%s.%s",
+			S_OR(touch_monitor_prefix, "auto"),
+			(long) time(NULL),
+			touch_monitor,
+			S_OR(touch_format, "wav"));
 	} else {
+		char *caller_chan_id;
+		char *peer_chan_id;
+
 		caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
 			ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
 		peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
 			ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
 		len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
 		touch_filename = ast_alloca(len);
-		snprintf(touch_filename, len, "%s-%ld-%s-%s.%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, peer_chan_id, S_OR(touch_format, "wav"));
-	}
-
-	for ( x = 0; x < strlen(touch_filename); x++) {
+		snprintf(touch_filename, len, "%s-%ld-%s-%s.%s",
+			S_OR(touch_monitor_prefix, "auto"),
+			(long) time(NULL),
+			caller_chan_id,
+			peer_chan_id,
+			S_OR(touch_format, "wav"));
+	}
+
+	for (x = 0; x < strlen(touch_filename); x++) {
 		if (touch_filename[x] == '/') {
 			touch_filename[x] = '-';
 		}
@@ -734,33 +787,103 @@
 	ast_verb(3, "AutoMixMonitor used to record call. Filename: %s\n", touch_filename);
 
 	if (ast_start_mixmonitor(peer_chan, touch_filename, "b")) {
-		ast_verb(3, "automixmon feature was tried by '%s' but mixmonitor failed to start.\n", ast_channel_name(bridge_channel->chan));
+		ast_verb(3, "automixmon feature was tried by '%s' but mixmonitor failed to start.\n",
+			ast_channel_name(bridge_channel->chan));
 
 		if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
 			ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
 		}
-
-		return 0;
-	}
-
-	ast_channel_lock(bridge_channel->chan);
-	if ((automon_message = pbx_builtin_getvar_helper(bridge_channel->chan, "TOUCH_MIXMONITOR_MESSAGE_START"))) {
-		automon_message = ast_strdupa(automon_message);
-	}
-	ast_channel_unlock(bridge_channel->chan);
-
-	if ((features_cfg = ast_get_chan_features_general_config(bridge_channel->chan)) && !(ast_strlen_zero(features_cfg->courtesytone))) {
+		return;
+	}
+
+	if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
 		ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
 		ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
 	}
 
-	if (!ast_strlen_zero(automon_message)) {
-		ast_bridge_channel_queue_playfile(bridge_channel, NULL, automon_message, NULL);
-		ast_bridge_channel_write_playfile(bridge_channel, NULL, automon_message, NULL);
+	if (!ast_strlen_zero(start_message)) {
+		ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
+		ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
 	}
 
 	pbx_builtin_setvar_helper(peer_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
-
+}
+
+static int feature_automixmonitor(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+	static const char *mixmonitor_spy_type = "MixMonitor";
+	const char *stop_message;
+	const char *start_message;
+	struct ast_bridge_features_automixmonitor *options = hook_pvt;
+	enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
+	int is_monitoring;
+
+	RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
+	RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
+
+	features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
+	peer_chan = ast_bridge_peer(bridge, bridge_channel->chan);
+
+	if (!peer_chan) {
+		ast_verb(3, "Cannot do AutoMixMonitor for %s - cannot determine peer in bridge.\n",
+			ast_channel_name(bridge_channel->chan));
+		if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
+			ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
+		}
+		return 0;
+	}
+
+	ast_channel_lock(bridge_channel->chan);
+	start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
+		"TOUCH_MIXMONITOR_MESSAGE_START");
+	start_message = ast_strdupa(S_OR(start_message, ""));
+	stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
+		"TOUCH_MIXMONITOR_MESSAGE_STOP");
+	stop_message = ast_strdupa(S_OR(stop_message, ""));
+	ast_channel_unlock(bridge_channel->chan);
+
+	is_monitoring =
+		0 < ast_channel_audiohook_count_by_source(peer_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
+	switch (start_stop) {
+	case AUTO_MONITOR_TOGGLE:
+		if (is_monitoring) {
+			stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
+		} else {
+			start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
+		}
+		return 0;
+	case AUTO_MONITOR_START:
+		if (!is_monitoring) {
+			start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
+			return 0;
+		}
+		ast_verb(3, "AutoMixMonitor already recording call.\n");
+		break;
+	case AUTO_MONITOR_STOP:
+		if (is_monitoring) {
+			stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
+			return 0;
+		}
+		ast_verb(3, "AutoMixMonitor already not recording call.\n");
+		break;
+	}
+
+	/*
+	 * Fake start/stop to invoker so will think it did something but
+	 * was already in that mode.
+	 */
+	if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
+		ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
+	}
+	if (is_monitoring) {
+		if (!ast_strlen_zero(start_message)) {
+			ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
+		}
+	} else {
+		if (!ast_strlen_zero(stop_message)) {
+			ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
+		}
+	}
 	return 0;
 }
 

Modified: trunk/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/bridging_features.h?view=diff&rev=393612&r1=393611&r2=393612
==============================================================================
--- trunk/include/asterisk/bridging_features.h (original)
+++ trunk/include/asterisk/bridging_features.h Wed Jul  3 17:36:38 2013
@@ -267,6 +267,25 @@
 	char complete[MAXIMUM_DTMF_FEATURE_STRING];
 };
 
+enum ast_bridge_features_monitor {
+	/*! Toggle start/stop of Monitor/MixMonitor. */
+	AUTO_MONITOR_TOGGLE,
+	/*! Start Monitor/MixMonitor if not already started. */
+	AUTO_MONITOR_START,
+	/*! Stop Monitor/MixMonitor if not already stopped. */
+	AUTO_MONITOR_STOP,
+};
+
+struct ast_bridge_features_automonitor {
+	/*! Start/Stop behavior. */
+	enum ast_bridge_features_monitor start_stop;
+};
+
+struct ast_bridge_features_automixmonitor {
+	/*! Start/Stop behavior. */
+	enum ast_bridge_features_monitor start_stop;
+};
+
 /*!
  * \brief Structure that contains configuration information for the limits feature
  */
@@ -330,6 +349,26 @@
 int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature);
 
 /*!
+ * \brief Invoke a built in feature hook now.
+ *
+ * \param feature The feature to invoke
+ *
+ * \note This API call is only meant to be used by bridge
+ * subclasses and hook callbacks to request a builtin feature
+ * hook to be executed.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_bridge_features_do(AST_BRIDGE_BUILTIN_ATTENDED_TRANSFER, bridge, bridge_channel, hook_pvt);
+ * \endcode
+ */
+int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt);
+
+/*!
  * \brief Attach interval hooks to a bridge features structure
  *
  * \param features Bridge features structure




More information about the asterisk-commits mailing list