[svn-commits] mmichelson: trunk r90388 - in /trunk: apps/ configs/ include/asterisk/ main/ ...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Nov 30 15:19:57 CST 2007


Author: mmichelson
Date: Fri Nov 30 15:19:57 2007
New Revision: 90388

URL: http://svn.digium.com/view/asterisk?view=rev&rev=90388
Log:
Adding support for the "automixmonitor" dial and queue options.

This works in much the same way as the automonitor, except that instead of using the monitor
app, it uses the mixmonitor app. By providing an 'x' or 'X' as a dial or queue option, a DTMF
sequence may be entered (as defined in features.conf) to start the one-touch mixmonitor.

This patch also introduces some new API calls to the audiohooks code for searching for an audiohook
by type and for searching for a running audiohook by type.

Big thanks to joetester for writing the initial patch, testing it and patiently waiting for it to 
be committed.

(closes issue #10185, reported and patched by xmarksthespot)


Modified:
    trunk/apps/app_dial.c
    trunk/apps/app_queue.c
    trunk/configs/features.conf.sample
    trunk/include/asterisk/app.h
    trunk/include/asterisk/audiohook.h
    trunk/include/asterisk/channel.h
    trunk/main/audiohook.c
    trunk/res/res_features.c

Modified: trunk/apps/app_dial.c
URL: http://svn.digium.com/view/asterisk/trunk/apps/app_dial.c?view=diff&rev=90388&r1=90387&r2=90388
==============================================================================
--- trunk/apps/app_dial.c (original)
+++ trunk/apps/app_dial.c Fri Nov 30 15:19:57 2007
@@ -203,8 +203,12 @@
 "    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 at 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 @@
 	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_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 @@
 						       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 @@
 							       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 @@
 				       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 @@
 				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;

Modified: trunk/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/trunk/apps/app_queue.c?view=diff&rev=90388&r1=90387&r2=90388
==============================================================================
--- trunk/apps/app_queue.c (original)
+++ trunk/apps/app_queue.c Fri Nov 30 15:19:57 2007
@@ -152,6 +152,9 @@
 "             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 @@
 		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 */

Modified: trunk/configs/features.conf.sample
URL: http://svn.digium.com/view/asterisk/trunk/configs/features.conf.sample?view=diff&rev=90388&r1=90387&r2=90388
==============================================================================
--- trunk/configs/features.conf.sample (original)
+++ trunk/configs/features.conf.sample Fri Nov 30 15:19:57 2007
@@ -52,6 +52,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

Modified: trunk/include/asterisk/app.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/app.h?view=diff&rev=90388&r1=90387&r2=90388
==============================================================================
--- trunk/include/asterisk/app.h (original)
+++ trunk/include/asterisk/app.h Fri Nov 30 15:19:57 2007
@@ -344,7 +344,7 @@
  */
 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;

Modified: trunk/include/asterisk/audiohook.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/audiohook.h?view=diff&rev=90388&r1=90387&r2=90388
==============================================================================
--- trunk/include/asterisk/audiohook.h (original)
+++ trunk/include/asterisk/audiohook.h Fri Nov 30 15:19:57 2007
@@ -171,6 +171,28 @@
  */
 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
  */

Modified: trunk/include/asterisk/channel.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/channel.h?view=diff&rev=90388&r1=90387&r2=90388
==============================================================================
--- trunk/include/asterisk/channel.h (original)
+++ trunk/include/asterisk/channel.h Fri Nov 30 15:19:57 2007
@@ -565,6 +565,7 @@
 	AST_FEATURE_ATXFER =       (1 << 3),
 	AST_FEATURE_AUTOMON =      (1 << 4),
 	AST_FEATURE_PARKCALL =     (1 << 5),
+	AST_FEATURE_AUTOMIXMON =   (1 << 6),
 };
 
 /*! \brief bridge configuration */

Modified: trunk/main/audiohook.c
URL: http://svn.digium.com/view/asterisk/trunk/main/audiohook.c?view=diff&rev=90388&r1=90387&r2=90388
==============================================================================
--- trunk/main/audiohook.c (original)
+++ trunk/main/audiohook.c Fri Nov 30 15:19:57 2007
@@ -612,3 +612,83 @@
 	
 	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;
+}
+

Modified: trunk/res/res_features.c
URL: http://svn.digium.com/view/asterisk/trunk/res/res_features.c?view=diff&rev=90388&r1=90387&r2=90388
==============================================================================
--- trunk/res/res_features.c (original)
+++ trunk/res/res_features.c Fri Nov 30 15:19:57 2007
@@ -50,6 +50,7 @@
 #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
@@ -150,6 +151,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 */
@@ -717,6 +724,118 @@
 	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 @@
 	{ 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, "" },
 };
 
 




More information about the svn-commits mailing list