| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2005, Anthony Minessale II | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  |  * Copyright (C) 2005, Digium, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Mark Spencer <markster@digium.com> | 
					
						
							|  |  |  |  * Kevin P. Fleming <kpfleming@digium.com> | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  |  * Based on app_muxmon.c provided by | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  |  * Anthony Minessale II <anthmct@yahoo.com> | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  |  * This program is free software, distributed under the terms of | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  | /*! \file
 | 
					
						
							| 
									
										
										
										
											2005-10-31 15:33:27 +00:00
										 |  |  |  * \brief MixMonitor() - Record a call and mix the audio during the recording | 
					
						
							| 
									
										
										
										
											2005-11-06 15:09:47 +00:00
										 |  |  |  * \ingroup applications | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | #include <stdlib.h>
 | 
					
						
							| 
									
										
										
										
											2005-11-08 04:48:00 +00:00
										 |  |  | #include <stdio.h>
 | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											2005-11-08 04:48:00 +00:00
										 |  |  | #include <unistd.h>
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk/file.h"
 | 
					
						
							|  |  |  | #include "asterisk/logger.h"
 | 
					
						
							|  |  |  | #include "asterisk/channel.h"
 | 
					
						
							| 
									
										
										
										
											2005-11-11 03:48:28 +00:00
										 |  |  | #include "asterisk/chanspy.h"
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | #include "asterisk/pbx.h"
 | 
					
						
							|  |  |  | #include "asterisk/module.h"
 | 
					
						
							|  |  |  | #include "asterisk/lock.h"
 | 
					
						
							|  |  |  | #include "asterisk/cli.h"
 | 
					
						
							|  |  |  | #include "asterisk/options.h"
 | 
					
						
							|  |  |  | #include "asterisk/app.h"
 | 
					
						
							|  |  |  | #include "asterisk/linkedlists.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static const char *tdesc = "Mixed Audio Monitoring Application"; | 
					
						
							|  |  |  | static const char *app = "MixMonitor"; | 
					
						
							|  |  |  | static const char *synopsis = "Record a call and mix the audio during the recording"; | 
					
						
							|  |  |  | static const char *desc = "" | 
					
						
							|  |  |  | "  MixMonitor(<file>.<ext>[|<options>[|<command>]])\n\n" | 
					
						
							|  |  |  | "Records the audio on the current channel to the specified file.\n" | 
					
						
							|  |  |  | "If the filename is an absolute path, uses that path, otherwise\n" | 
					
						
							|  |  |  | "creates the file in the configured monitoring directory from\n" | 
					
						
							|  |  |  | "asterisk.conf.\n\n" | 
					
						
							|  |  |  | "Valid options:\n" | 
					
						
							|  |  |  | " a      - Append to the file instead of overwriting it.\n" | 
					
						
							|  |  |  | " b      - Only save audio to the file while the channel is bridged.\n" | 
					
						
							| 
									
										
										
										
											2007-01-25 01:48:52 +00:00
										 |  |  | "          Note: Does not include conferences or sounds played to each bridged\n" | 
					
						
							|  |  |  | "                party.\n" | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | " v(<x>) - Adjust the heard volume by a factor of <x> (range -4 to 4)\n"	 | 
					
						
							|  |  |  | " V(<x>) - Adjust the spoken volume by a factor of <x> (range -4 to 4)\n"	 | 
					
						
							|  |  |  | " W(<x>) - Adjust the both heard and spoken volumes by a factor of <x>\n" | 
					
						
							|  |  |  | "         (range -4 to 4)\n\n"	 | 
					
						
							|  |  |  | "<command> will be executed when the recording is over\n" | 
					
						
							| 
									
										
										
										
											2007-06-27 23:24:01 +00:00
										 |  |  | "Any strings matching ^{X} will be unescaped to ${X}.\n" | 
					
						
							|  |  |  | "All variables will be evaluated at the time MixMonitor is called.\n" | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | "The variable MIXMONITOR_FILENAME will contain the filename used to record.\n" | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | ""; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STANDARD_LOCAL_USER; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | LOCAL_USER_DECL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | static const char *mixmonitor_spy_type = "MixMonitor"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct mixmonitor { | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 	struct ast_channel_spy spy; | 
					
						
							| 
									
										
										
										
											2007-01-22 19:08:52 +00:00
										 |  |  | 	char *filename; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	char *post_process; | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 	char *name; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	unsigned int flags; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | enum { | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | 	MUXFLAG_APPEND = (1 << 1), | 
					
						
							|  |  |  | 	MUXFLAG_BRIDGED = (1 << 2), | 
					
						
							|  |  |  | 	MUXFLAG_VOLUME = (1 << 3), | 
					
						
							|  |  |  | 	MUXFLAG_READVOLUME = (1 << 4), | 
					
						
							|  |  |  | 	MUXFLAG_WRITEVOLUME = (1 << 5), | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | } mixmonitor_flags; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | enum { | 
					
						
							|  |  |  | 	OPT_ARG_READVOLUME = 0, | 
					
						
							|  |  |  | 	OPT_ARG_WRITEVOLUME, | 
					
						
							|  |  |  | 	OPT_ARG_VOLUME, | 
					
						
							|  |  |  | 	OPT_ARG_ARRAY_SIZE, | 
					
						
							|  |  |  | } mixmonitor_args; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AST_APP_OPTIONS(mixmonitor_opts, { | 
					
						
							|  |  |  | 	AST_APP_OPTION('a', MUXFLAG_APPEND), | 
					
						
							|  |  |  | 	AST_APP_OPTION('b', MUXFLAG_BRIDGED), | 
					
						
							|  |  |  | 	AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME), | 
					
						
							|  |  |  | 	AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME), | 
					
						
							|  |  |  | 	AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME), | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | static int startmon(struct ast_channel *chan, struct ast_channel_spy *spy)  | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ast_channel *peer; | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	int res; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	if (!chan) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_lock(&chan->lock); | 
					
						
							|  |  |  | 	res = ast_channel_spy_add(chan, spy); | 
					
						
							|  |  |  | 	ast_mutex_unlock(&chan->lock); | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) | 
					
						
							|  |  |  | 		ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);	 | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | #define SAMPLES_PER_FRAME 160
 | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | static void *mixmonitor_thread(void *obj)  | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct mixmonitor *mixmonitor = obj; | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 	struct ast_frame *f = NULL; | 
					
						
							| 
									
										
										
										
											2007-01-22 19:08:52 +00:00
										 |  |  | 	struct ast_filestream *fs = NULL; | 
					
						
							|  |  |  | 	unsigned int oflags; | 
					
						
							|  |  |  | 	char *ext; | 
					
						
							|  |  |  | 	int errflag = 0; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	STANDARD_INCREMENT_USECOUNT; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if (option_verbose > 1) | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 		ast_verbose(VERBOSE_PREFIX_2 "Begin MixMonitor Recording %s\n", mixmonitor->name); | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 	ast_mutex_lock(&mixmonitor->spy.lock); | 
					
						
							| 
									
										
										
										
											2006-03-04 11:45:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 	while (mixmonitor->spy.chan) { | 
					
						
							|  |  |  | 		struct ast_frame *next; | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 		int write; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 		ast_channel_spy_trigger_wait(&mixmonitor->spy); | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 		 | 
					
						
							| 
									
										
										
										
											2006-09-05 20:02:48 +00:00
										 |  |  | 		if (!mixmonitor->spy.chan || mixmonitor->spy.status != CHANSPY_RUNNING) | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		while (1) { | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 			if (!(f = ast_channel_spy_read_frame(&mixmonitor->spy, SAMPLES_PER_FRAME))) | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			write = (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 				 ast_bridged_channel(mixmonitor->spy.chan)); | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			/* it is possible for ast_channel_spy_read_frame() to return a chain
 | 
					
						
							|  |  |  | 			   of frames if a queue flush was necessary, so process them | 
					
						
							|  |  |  | 			*/ | 
					
						
							|  |  |  | 			for (; f; f = next) { | 
					
						
							|  |  |  | 				next = f->next; | 
					
						
							| 
									
										
										
										
											2007-01-22 19:08:52 +00:00
										 |  |  | 				if (write && errflag == 0) { | 
					
						
							|  |  |  | 					if (!fs) { | 
					
						
							|  |  |  | 						/* Determine creation flags and filename plus extension for filestream */ | 
					
						
							|  |  |  | 						oflags = O_CREAT | O_WRONLY; | 
					
						
							|  |  |  | 						oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						if ((ext = strrchr(mixmonitor->filename, '.'))) | 
					
						
							|  |  |  | 							*(ext++) = '\0'; | 
					
						
							|  |  |  | 						else | 
					
						
							|  |  |  | 							ext = "raw"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						/* Move onto actually creating the filestream */ | 
					
						
							|  |  |  | 						if (!(fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0644))) { | 
					
						
							|  |  |  | 							ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext); | 
					
						
							|  |  |  | 							errflag = 1; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					if (fs) | 
					
						
							|  |  |  | 						ast_writestream(fs, f); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 				ast_frfree(f); | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 	ast_mutex_unlock(&mixmonitor->spy.lock); | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2006-09-05 20:02:48 +00:00
										 |  |  | 	ast_channel_spy_free(&mixmonitor->spy); | 
					
						
							| 
									
										
										
										
											2006-01-03 17:24:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	if (option_verbose > 1) | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 		ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name); | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 	if (mixmonitor->post_process) { | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 		if (option_verbose > 2) | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 			ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", mixmonitor->post_process); | 
					
						
							|  |  |  | 		ast_safe_system(mixmonitor->post_process); | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 		 | 
					
						
							| 
									
										
										
										
											2007-01-22 19:08:52 +00:00
										 |  |  | 	if (fs) | 
					
						
							|  |  |  | 		ast_closestream(fs); | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	free(mixmonitor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	STANDARD_DECREMENT_USECOUNT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | static void launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags, | 
					
						
							|  |  |  | 				  int readvol, int writevol, const char *post_process)  | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	pthread_attr_t attr; | 
					
						
							|  |  |  | 	pthread_t thread; | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	struct mixmonitor *mixmonitor; | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 	char postprocess2[1024] = ""; | 
					
						
							|  |  |  | 	size_t len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-22 19:08:52 +00:00
										 |  |  | 	len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2; | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* If a post process system command is given attach it to the structure */ | 
					
						
							|  |  |  | 	if (!ast_strlen_zero(post_process)) { | 
					
						
							|  |  |  | 		char *p1, *p2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		p1 = ast_strdupa(post_process); | 
					
						
							|  |  |  | 		for (p2 = p1; *p2 ; p2++) { | 
					
						
							|  |  |  | 			if (*p2 == '^' && *(p2+1) == '{') { | 
					
						
							|  |  |  | 				*p2 = '$'; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1); | 
					
						
							|  |  |  | 		if (!ast_strlen_zero(postprocess2)) | 
					
						
							|  |  |  | 			len += strlen(postprocess2) + 1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 	/* Pre-allocate mixmonitor structure and spy */ | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 	if (!(mixmonitor = calloc(1, len))) { | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 		ast_log(LOG_ERROR, "Memory Error!\n"); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 	/* Copy over flags and channel name */ | 
					
						
							|  |  |  | 	mixmonitor->flags = flags; | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 	mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor); | 
					
						
							|  |  |  | 	strcpy(mixmonitor->name, chan->name); | 
					
						
							|  |  |  | 	if (!ast_strlen_zero(postprocess2)) { | 
					
						
							| 
									
										
										
										
											2007-01-29 23:39:39 +00:00
										 |  |  | 		mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2; | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 		strcpy(mixmonitor->post_process, postprocess2); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-22 19:08:52 +00:00
										 |  |  | 	mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1; | 
					
						
							|  |  |  | 	strcpy(mixmonitor->filename, filename); | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Setup the actual spy before creating our thread */ | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 	ast_set_flag(&mixmonitor->spy, CHANSPY_FORMAT_AUDIO); | 
					
						
							|  |  |  | 	ast_set_flag(&mixmonitor->spy, CHANSPY_MIXAUDIO); | 
					
						
							|  |  |  | 	mixmonitor->spy.type = mixmonitor_spy_type; | 
					
						
							|  |  |  | 	mixmonitor->spy.status = CHANSPY_RUNNING; | 
					
						
							|  |  |  | 	mixmonitor->spy.read_queue.format = AST_FORMAT_SLINEAR; | 
					
						
							|  |  |  | 	mixmonitor->spy.write_queue.format = AST_FORMAT_SLINEAR; | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 	if (readvol) { | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 		ast_set_flag(&mixmonitor->spy, CHANSPY_READ_VOLADJUST); | 
					
						
							|  |  |  | 		mixmonitor->spy.read_vol_adjustment = readvol; | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (writevol) { | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 		ast_set_flag(&mixmonitor->spy, CHANSPY_WRITE_VOLADJUST); | 
					
						
							|  |  |  | 		mixmonitor->spy.write_vol_adjustment = writevol; | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 	ast_mutex_init(&mixmonitor->spy.lock); | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 	if (startmon(chan, &mixmonitor->spy)) { | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n", | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 			mixmonitor->spy.type, chan->name); | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 		/* Since we couldn't add ourselves - bail out! */ | 
					
						
							| 
									
										
										
										
											2006-06-13 13:30:06 +00:00
										 |  |  | 		ast_mutex_destroy(&mixmonitor->spy.lock); | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 		free(mixmonitor); | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	pthread_attr_init(&attr); | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	ast_pthread_create(&thread, &attr, mixmonitor_thread, mixmonitor); | 
					
						
							|  |  |  | 	pthread_attr_destroy(&attr); | 
					
						
							| 
									
										
										
										
											2006-06-12 21:34:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | static int mixmonitor_exec(struct ast_channel *chan, void *data) | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	int x, readvol = 0, writevol = 0; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	struct localuser *u; | 
					
						
							|  |  |  | 	struct ast_flags flags = {0}; | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	char *parse; | 
					
						
							|  |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							|  |  |  | 		AST_APP_ARG(filename); | 
					
						
							|  |  |  | 		AST_APP_ARG(options); | 
					
						
							|  |  |  | 		AST_APP_ARG(post_process); | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2005-10-26 19:48:14 +00:00
										 |  |  | 	if (ast_strlen_zero(data)) { | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-19 18:19:02 +00:00
										 |  |  | 	LOCAL_USER_ADD(u); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	if (!(parse = ast_strdupa(data))) { | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Memory Error!\n"); | 
					
						
							| 
									
										
										
										
											2005-10-19 18:19:02 +00:00
										 |  |  | 		LOCAL_USER_REMOVE(u); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	AST_STANDARD_APP_ARGS(args, parse); | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	if (ast_strlen_zero(args.filename)) { | 
					
						
							| 
									
										
										
										
											2005-11-04 22:11:51 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); | 
					
						
							| 
									
										
										
										
											2005-10-19 18:19:02 +00:00
										 |  |  | 		LOCAL_USER_REMOVE(u); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	if (args.options) { | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | 		char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, }; | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | 		ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options); | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) { | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | 			if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) { | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 				ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n"); | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | 			} else if ((sscanf(opts[OPT_ARG_READVOLUME], "%d", &x) != 1) || (x < -4) || (x > 4)) { | 
					
						
							|  |  |  | 				ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]); | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				readvol = get_volfactor(x); | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 		if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) { | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | 			if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) { | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 				ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n"); | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | 			} else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%d", &x) != 1) || (x < -4) || (x > 4)) { | 
					
						
							|  |  |  | 				ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]); | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				writevol = get_volfactor(x); | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		if (ast_test_flag(&flags, MUXFLAG_VOLUME)) { | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | 			if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) { | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 				ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n"); | 
					
						
							| 
									
										
										
										
											2005-11-03 21:19:11 +00:00
										 |  |  | 			} else if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &x) != 1) || (x < -4) || (x > 4)) { | 
					
						
							|  |  |  | 				ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]); | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				readvol = writevol = get_volfactor(x); | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* if not provided an absolute path, use the system-configured monitoring directory */ | 
					
						
							|  |  |  | 	if (args.filename[0] != '/') { | 
					
						
							|  |  |  | 		char *build; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3); | 
					
						
							|  |  |  | 		sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename); | 
					
						
							|  |  |  | 		args.filename = build; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename); | 
					
						
							|  |  |  | 	launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process); | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	LOCAL_USER_REMOVE(u); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | static int mixmonitor_cli(int fd, int argc, char **argv)  | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ast_channel *chan; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	if (argc < 3) | 
					
						
							|  |  |  | 		return RESULT_SHOWUSAGE; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	if (!(chan = ast_get_channel_by_name_prefix_locked(argv[2], strlen(argv[2])))) { | 
					
						
							|  |  |  | 		ast_cli(fd, "No channel matching '%s' found.\n", argv[2]); | 
					
						
							|  |  |  | 		return RESULT_SUCCESS; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	if (!strcasecmp(argv[1], "start")) | 
					
						
							|  |  |  | 		mixmonitor_exec(chan, argv[3]); | 
					
						
							| 
									
										
										
										
											2006-01-03 17:24:56 +00:00
										 |  |  | 	else if (!strcasecmp(argv[1], "stop")) | 
					
						
							|  |  |  | 		ast_channel_spy_stop_by_type(chan, mixmonitor_spy_type); | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_unlock(&chan->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return RESULT_SUCCESS; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | static struct ast_cli_entry cli_mixmonitor = { | 
					
						
							|  |  |  | 	{ "mixmonitor", NULL, NULL }, | 
					
						
							|  |  |  | 	mixmonitor_cli,  | 
					
						
							|  |  |  | 	"Execute a MixMonitor command", | 
					
						
							| 
									
										
										
										
											2005-11-06 04:51:00 +00:00
										 |  |  | 	"mixmonitor <start|stop> <chan_name> [<args>]\n" | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int unload_module(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-18 22:52:21 +00:00
										 |  |  | 	int res; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	res = ast_cli_unregister(&cli_mixmonitor); | 
					
						
							| 
									
										
										
										
											2005-10-18 22:52:21 +00:00
										 |  |  | 	res |= ast_unregister_application(app); | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	STANDARD_HANGUP_LOCALUSERS; | 
					
						
							| 
									
										
										
										
											2005-10-18 22:52:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int load_module(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-18 22:52:21 +00:00
										 |  |  | 	int res; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	res = ast_cli_register(&cli_mixmonitor); | 
					
						
							|  |  |  | 	res |= ast_register_application(app, mixmonitor_exec, synopsis, desc); | 
					
						
							| 
									
										
										
										
											2005-10-18 22:52:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | char *description(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 	return (char *) tdesc; | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int usecount(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int res; | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	STANDARD_USECOUNT(res); | 
					
						
							| 
									
										
										
										
											2005-10-28 23:01:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-16 02:59:13 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | char *key() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return ASTERISK_GPL_KEY; | 
					
						
							|  |  |  | } |