| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2003 - 2006, Aheeva Technology. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Claude Klimos (claude.klimos@aheeva.com) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software, distributed under the terms of | 
					
						
							|  |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							| 
									
										
										
										
											2006-06-14 14:12:56 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * A license has been granted to Digium (via disclaimer) for the use of | 
					
						
							|  |  |  |  * this code. | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-24 20:29:41 +00:00
										 |  |  | /*! \file
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \brief Answering machine detection | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \author Claude Klimos (claude.klimos@aheeva.com) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-14 20:13:06 +00:00
										 |  |  | /*** MODULEINFO
 | 
					
						
							|  |  |  | 	<support_level>extended</support_level> | 
					
						
							|  |  |  |  ***/ | 
					
						
							| 
									
										
										
										
											2007-02-24 20:29:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-24 15:01:22 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-24 15:01:22 +00:00
										 |  |  | ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | #include "asterisk/module.h"
 | 
					
						
							|  |  |  | #include "asterisk/lock.h"
 | 
					
						
							|  |  |  | #include "asterisk/channel.h"
 | 
					
						
							|  |  |  | #include "asterisk/dsp.h"
 | 
					
						
							|  |  |  | #include "asterisk/pbx.h"
 | 
					
						
							|  |  |  | #include "asterisk/config.h"
 | 
					
						
							|  |  |  | #include "asterisk/app.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  | /*** DOCUMENTATION
 | 
					
						
							|  |  |  | 	<application name="AMD" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Attempt to detect answering machines. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="initialSilence" required="false"> | 
					
						
							|  |  |  | 				<para>Is maximum initial silence duration before greeting.</para> | 
					
						
							|  |  |  | 				<para>If this is exceeded set as MACHINE</para> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 			<parameter name="greeting" required="false"> | 
					
						
							|  |  |  | 				<para>is the maximum length of a greeting.</para> | 
					
						
							|  |  |  | 				<para>If this is exceeded set as MACHINE</para> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 			<parameter name="afterGreetingSilence" required="false"> | 
					
						
							|  |  |  | 				<para>Is the silence after detecting a greeting.</para> | 
					
						
							|  |  |  | 				<para>If this is exceeded set as HUMAN</para> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 			<parameter name="totalAnalysis Time" required="false"> | 
					
						
							|  |  |  | 				<para>Is the maximum time allowed for the algorithm</para> | 
					
						
							|  |  |  | 				<para>to decide HUMAN or MACHINE</para> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 			<parameter name="miniumWordLength" required="false"> | 
					
						
							|  |  |  | 				<para>Is the minimum duration of Voice considered to be a word</para> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 			<parameter name="betweenWordSilence" required="false"> | 
					
						
							|  |  |  | 				<para>Is the minimum duration of silence after a word to | 
					
						
							|  |  |  | 				consider the audio that follows to be a new word</para> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 			<parameter name="maximumNumberOfWords" required="false"> | 
					
						
							|  |  |  | 				<para>Is the maximum number of words in a greeting</para> | 
					
						
							|  |  |  | 				<para>If this is exceeded set as MACHINE</para> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 			<parameter name="silenceThreshold" required="false"> | 
					
						
							|  |  |  | 				<para>How long do we consider silence</para> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 			<parameter name="maximumWordLength" required="false"> | 
					
						
							|  |  |  | 				<para>Is the maximum duration of a word to accept.</para> | 
					
						
							|  |  |  | 				<para>If exceeded set as MACHINE</para> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>This application attempts to detect answering machines at the beginning | 
					
						
							|  |  |  | 			of outbound calls. Simply call this application after the call | 
					
						
							|  |  |  | 			has been answered (outbound only, of course).</para> | 
					
						
							|  |  |  | 			<para>When loaded, AMD reads amd.conf and uses the parameters specified as | 
					
						
							|  |  |  | 			default values. Those default values get overwritten when the calling AMD | 
					
						
							|  |  |  | 			with parameters.</para> | 
					
						
							|  |  |  | 			<para>This application sets the following channel variables:</para> | 
					
						
							|  |  |  | 			<variablelist> | 
					
						
							|  |  |  | 				<variable name="AMDSTATUS"> | 
					
						
							|  |  |  | 					<para>This is the status of the answering machine detection</para> | 
					
						
							|  |  |  | 					<value name="MACHINE" /> | 
					
						
							|  |  |  | 					<value name="HUMAN" /> | 
					
						
							|  |  |  | 					<value name="NOTSURE" /> | 
					
						
							|  |  |  | 					<value name="HANGUP" /> | 
					
						
							|  |  |  | 				</variable> | 
					
						
							|  |  |  | 				<variable name="AMDCAUSE"> | 
					
						
							|  |  |  | 					<para>Indicates the cause that led to the conclusion</para> | 
					
						
							|  |  |  | 					<value name="TOOLONG"> | 
					
						
							|  |  |  | 						Total Time. | 
					
						
							|  |  |  | 					</value> | 
					
						
							|  |  |  | 					<value name="INITIALSILENCE"> | 
					
						
							|  |  |  | 						Silence Duration - Initial Silence. | 
					
						
							|  |  |  | 					</value> | 
					
						
							|  |  |  | 					<value name="HUMAN"> | 
					
						
							|  |  |  | 						Silence Duration - afterGreetingSilence. | 
					
						
							|  |  |  | 					</value> | 
					
						
							|  |  |  | 					<value name="LONGGREETING"> | 
					
						
							|  |  |  | 						Voice Duration - Greeting. | 
					
						
							|  |  |  | 					</value> | 
					
						
							|  |  |  | 					<value name="MAXWORDLENGTH"> | 
					
						
							|  |  |  | 						Word Count - maximum number of words. | 
					
						
							|  |  |  | 					</value>	 | 
					
						
							|  |  |  | 				</variable> | 
					
						
							|  |  |  | 			</variablelist> | 
					
						
							|  |  |  | 		</description> | 
					
						
							| 
									
										
										
										
											2008-11-05 14:37:07 +00:00
										 |  |  | 		<see-also> | 
					
						
							|  |  |  | 			<ref type="application">WaitForSilence</ref> | 
					
						
							|  |  |  | 			<ref type="application">WaitForNoise</ref> | 
					
						
							|  |  |  | 		</see-also> | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  | 	</application> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  ***/ | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-07 14:55:51 +00:00
										 |  |  | static const char app[] = "AMD"; | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define STATE_IN_WORD       1
 | 
					
						
							|  |  |  | #define STATE_IN_SILENCE    2
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Some default values for the algorithm parameters. These defaults will be overwritten from amd.conf */ | 
					
						
							|  |  |  | static int dfltInitialSilence       = 2500; | 
					
						
							|  |  |  | static int dfltGreeting             = 1500; | 
					
						
							|  |  |  | static int dfltAfterGreetingSilence = 800; | 
					
						
							|  |  |  | static int dfltTotalAnalysisTime    = 5000; | 
					
						
							|  |  |  | static int dfltMinimumWordLength    = 100; | 
					
						
							|  |  |  | static int dfltBetweenWordsSilence  = 50; | 
					
						
							|  |  |  | static int dfltMaximumNumberOfWords = 3; | 
					
						
							|  |  |  | static int dfltSilenceThreshold     = 256; | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | static int dfltMaximumWordLength    = 5000; /* Setting this to a large default so it is not used unless specify it in the configs or command line */ | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-01 00:08:17 +00:00
										 |  |  | /* Set to the lowest ms value provided in amd.conf or application parameters */ | 
					
						
							|  |  |  | static int dfltMaxWaitTimeForFrame  = 50; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static void isAnsweringMachine(struct ast_channel *chan, const char *data) | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 	int res = 0; | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 	struct ast_frame *f = NULL; | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 	struct ast_dsp *silenceDetector = NULL; | 
					
						
							| 
									
										
										
										
											2008-02-01 00:08:17 +00:00
										 |  |  | 	int dspsilence = 0, readFormat, framelength = 0; | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 	int inInitialSilence = 1; | 
					
						
							|  |  |  | 	int inGreeting = 0; | 
					
						
							|  |  |  | 	int voiceDuration = 0; | 
					
						
							|  |  |  | 	int silenceDuration = 0; | 
					
						
							|  |  |  | 	int iTotalTime = 0; | 
					
						
							|  |  |  | 	int iWordsCount = 0; | 
					
						
							| 
									
										
										
										
											2008-02-01 00:08:17 +00:00
										 |  |  | 	int currentState = STATE_IN_WORD; | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 	int consecutiveVoiceDuration = 0; | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 	char amdCause[256] = "", amdStatus[256] = ""; | 
					
						
							|  |  |  | 	char *parse = ast_strdupa(data); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Lets set the initial values of the variables that will control the algorithm.
 | 
					
						
							|  |  |  | 	   The initial values are the default ones. If they are passed as arguments | 
					
						
							|  |  |  | 	   when invoking the application, then the default values will be overwritten | 
					
						
							|  |  |  | 	   by the ones passed as parameters. */ | 
					
						
							|  |  |  | 	int initialSilence       = dfltInitialSilence; | 
					
						
							|  |  |  | 	int greeting             = dfltGreeting; | 
					
						
							|  |  |  | 	int afterGreetingSilence = dfltAfterGreetingSilence; | 
					
						
							|  |  |  | 	int totalAnalysisTime    = dfltTotalAnalysisTime; | 
					
						
							|  |  |  | 	int minimumWordLength    = dfltMinimumWordLength; | 
					
						
							|  |  |  | 	int betweenWordsSilence  = dfltBetweenWordsSilence; | 
					
						
							|  |  |  | 	int maximumNumberOfWords = dfltMaximumNumberOfWords; | 
					
						
							|  |  |  | 	int silenceThreshold     = dfltSilenceThreshold; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 	int maximumWordLength    = dfltMaximumWordLength; | 
					
						
							| 
									
										
										
										
											2008-02-01 00:08:17 +00:00
										 |  |  | 	int maxWaitTimeForFrame  = dfltMaxWaitTimeForFrame; | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 		AST_APP_ARG(argInitialSilence); | 
					
						
							|  |  |  | 		AST_APP_ARG(argGreeting); | 
					
						
							|  |  |  | 		AST_APP_ARG(argAfterGreetingSilence); | 
					
						
							|  |  |  | 		AST_APP_ARG(argTotalAnalysisTime); | 
					
						
							|  |  |  | 		AST_APP_ARG(argMinimumWordLength); | 
					
						
							|  |  |  | 		AST_APP_ARG(argBetweenWordsSilence); | 
					
						
							|  |  |  | 		AST_APP_ARG(argMaximumNumberOfWords); | 
					
						
							|  |  |  | 		AST_APP_ARG(argSilenceThreshold); | 
					
						
							|  |  |  | 		AST_APP_ARG(argMaximumWordLength); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 	); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 	ast_verb(3, "AMD: %s %s %s (Fmt: %s)\n", chan->name, | 
					
						
							| 
									
										
										
										
											2010-07-14 16:58:03 +00:00
										 |  |  | 		S_COR(chan->caller.ani.number.valid, chan->caller.ani.number.str, "(N/A)"), | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 		S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, "(N/A)"), | 
					
						
							|  |  |  | 		ast_getformatname(chan->readformat)); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Lets parse the arguments. */ | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 	if (!ast_strlen_zero(parse)) { | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 		/* Some arguments have been passed. Lets parse them and overwrite the defaults. */ | 
					
						
							|  |  |  | 		AST_STANDARD_APP_ARGS(args, parse); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 		if (!ast_strlen_zero(args.argInitialSilence)) | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 			initialSilence = atoi(args.argInitialSilence); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 		if (!ast_strlen_zero(args.argGreeting)) | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 			greeting = atoi(args.argGreeting); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 		if (!ast_strlen_zero(args.argAfterGreetingSilence)) | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 			afterGreetingSilence = atoi(args.argAfterGreetingSilence); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 		if (!ast_strlen_zero(args.argTotalAnalysisTime)) | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 			totalAnalysisTime = atoi(args.argTotalAnalysisTime); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 		if (!ast_strlen_zero(args.argMinimumWordLength)) | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 			minimumWordLength = atoi(args.argMinimumWordLength); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 		if (!ast_strlen_zero(args.argBetweenWordsSilence)) | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 			betweenWordsSilence = atoi(args.argBetweenWordsSilence); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 		if (!ast_strlen_zero(args.argMaximumNumberOfWords)) | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 			maximumNumberOfWords = atoi(args.argMaximumNumberOfWords); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 		if (!ast_strlen_zero(args.argSilenceThreshold)) | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 			silenceThreshold = atoi(args.argSilenceThreshold); | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 		if (!ast_strlen_zero(args.argMaximumWordLength)) | 
					
						
							|  |  |  | 			maximumWordLength = atoi(args.argMaximumWordLength); | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		ast_debug(1, "AMD using the default parameters.\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-01 00:08:17 +00:00
										 |  |  | 	/* Find lowest ms value, that will be max wait time for a frame */ | 
					
						
							|  |  |  | 	if (maxWaitTimeForFrame > initialSilence) | 
					
						
							|  |  |  | 		maxWaitTimeForFrame = initialSilence; | 
					
						
							|  |  |  | 	if (maxWaitTimeForFrame > greeting) | 
					
						
							|  |  |  | 		maxWaitTimeForFrame = greeting; | 
					
						
							|  |  |  | 	if (maxWaitTimeForFrame > afterGreetingSilence) | 
					
						
							|  |  |  | 		maxWaitTimeForFrame = afterGreetingSilence; | 
					
						
							|  |  |  | 	if (maxWaitTimeForFrame > totalAnalysisTime) | 
					
						
							|  |  |  | 		maxWaitTimeForFrame = totalAnalysisTime; | 
					
						
							|  |  |  | 	if (maxWaitTimeForFrame > minimumWordLength) | 
					
						
							|  |  |  | 		maxWaitTimeForFrame = minimumWordLength; | 
					
						
							|  |  |  | 	if (maxWaitTimeForFrame > betweenWordsSilence) | 
					
						
							|  |  |  | 		maxWaitTimeForFrame = betweenWordsSilence; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 	/* Now we're ready to roll! */ | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 	ast_verb(3, "AMD: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] " | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 		"totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d] \n", | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 				initialSilence, greeting, afterGreetingSilence, totalAnalysisTime, | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 				minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold, maximumWordLength); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 	/* Set read format to signed linear so we get signed linear frames in */ | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 	readFormat = chan->readformat; | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 	if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0 ) { | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to set to linear mode, giving up\n", chan->name ); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 		pbx_builtin_setvar_helper(chan , "AMDSTATUS", ""); | 
					
						
							|  |  |  | 		pbx_builtin_setvar_helper(chan , "AMDCAUSE", ""); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 	/* Create a new DSP that will detect the silence */ | 
					
						
							|  |  |  | 	if (!(silenceDetector = ast_dsp_new())) { | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to create silence detector :(\n", chan->name ); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 		pbx_builtin_setvar_helper(chan , "AMDSTATUS", ""); | 
					
						
							|  |  |  | 		pbx_builtin_setvar_helper(chan , "AMDCAUSE", ""); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 	/* Set silence threshold to specified value */ | 
					
						
							|  |  |  | 	ast_dsp_set_threshold(silenceDetector, silenceThreshold); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Now we go into a loop waiting for frames from the channel */ | 
					
						
							| 
									
										
										
										
											2008-02-01 00:08:17 +00:00
										 |  |  | 	while ((res = ast_waitfor(chan, 2 * maxWaitTimeForFrame)) > -1) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 		/* If we fail to read in a frame, that means they hung up */ | 
					
						
							|  |  |  | 		if (!(f = ast_read(chan))) { | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 			ast_verb(3, "AMD: Channel [%s]. HANGUP\n", chan->name); | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 			ast_debug(1, "Got hangup\n"); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 			strcpy(amdStatus, "HANGUP"); | 
					
						
							| 
									
										
										
										
											2009-12-02 17:06:54 +00:00
										 |  |  | 			res = 1; | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-01 00:08:17 +00:00
										 |  |  | 		if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_NULL || f->frametype == AST_FRAME_CNG) { | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 			/* If the total time exceeds the analysis time then give up as we are not too sure */ | 
					
						
							| 
									
										
										
										
											2010-07-16 17:13:46 +00:00
										 |  |  | 			if (f->frametype == AST_FRAME_VOICE) { | 
					
						
							| 
									
										
										
										
											2008-02-01 00:08:17 +00:00
										 |  |  | 				framelength = (ast_codec_get_samples(f) / DEFAULT_SAMPLES_PER_MS); | 
					
						
							| 
									
										
										
										
											2010-07-16 17:13:46 +00:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				framelength = 2 * maxWaitTimeForFrame; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-02-01 00:08:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-06 20:23:18 +00:00
										 |  |  | 			iTotalTime += framelength; | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 			if (iTotalTime >= totalAnalysisTime) { | 
					
						
							| 
									
										
										
										
											2007-12-14 14:48:38 +00:00
										 |  |  | 				ast_verb(3, "AMD: Channel [%s]. Too long...\n", chan->name ); | 
					
						
							| 
									
										
										
										
											2006-04-06 20:23:18 +00:00
										 |  |  | 				ast_frfree(f); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 				strcpy(amdStatus , "NOTSURE"); | 
					
						
							|  |  |  | 				sprintf(amdCause , "TOOLONG-%d", iTotalTime); | 
					
						
							| 
									
										
										
										
											2006-04-06 20:23:18 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			/* Feed the frame of audio into the silence detector and see if we get a result */ | 
					
						
							| 
									
										
										
										
											2008-02-01 00:08:17 +00:00
										 |  |  | 			if (f->frametype != AST_FRAME_VOICE) | 
					
						
							|  |  |  | 				dspsilence += 2 * maxWaitTimeForFrame; | 
					
						
							|  |  |  | 			else { | 
					
						
							|  |  |  | 				dspsilence = 0; | 
					
						
							|  |  |  | 				ast_dsp_silence(silenceDetector, f, &dspsilence); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (dspsilence > 0) { | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 				silenceDuration = dspsilence; | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 				 | 
					
						
							|  |  |  | 				if (silenceDuration >= betweenWordsSilence) { | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 					if (currentState != STATE_IN_SILENCE ) { | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 						ast_verb(3, "AMD: Channel [%s]. Changed state to STATE_IN_SILENCE\n", chan->name); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 					/* Find words less than word duration */ | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 					if (consecutiveVoiceDuration < minimumWordLength && consecutiveVoiceDuration > 0){ | 
					
						
							|  |  |  | 						ast_verb(3, "AMD: Channel [%s]. Short Word Duration: %d\n", chan->name, consecutiveVoiceDuration); | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 					currentState  = STATE_IN_SILENCE; | 
					
						
							|  |  |  | 					consecutiveVoiceDuration = 0; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 				if (inInitialSilence == 1  && silenceDuration >= initialSilence) { | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 					ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n", | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 						chan->name, silenceDuration, initialSilence); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 					ast_frfree(f); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 					strcpy(amdStatus , "MACHINE"); | 
					
						
							|  |  |  | 					sprintf(amdCause , "INITIALSILENCE-%d-%d", silenceDuration, initialSilence); | 
					
						
							| 
									
										
										
										
											2008-02-01 00:08:17 +00:00
										 |  |  | 					res = 1; | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 				 | 
					
						
							|  |  |  | 				if (silenceDuration >= afterGreetingSilence  &&  inGreeting == 1) { | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 					ast_verb(3, "AMD: Channel [%s]. HUMAN: silenceDuration:%d afterGreetingSilence:%d\n", | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 						chan->name, silenceDuration, afterGreetingSilence); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 					ast_frfree(f); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 					strcpy(amdStatus , "HUMAN"); | 
					
						
							|  |  |  | 					sprintf(amdCause , "HUMAN-%d-%d", silenceDuration, afterGreetingSilence); | 
					
						
							| 
									
										
										
										
											2008-02-01 00:08:17 +00:00
										 |  |  | 					res = 1; | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 				 | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2006-02-14 23:30:18 +00:00
										 |  |  | 				consecutiveVoiceDuration += framelength; | 
					
						
							|  |  |  | 				voiceDuration += framelength; | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 				/* If I have enough consecutive voice to say that I am in a Word, I can only increment the
 | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 				   number of words if my previous state was Silence, which means that I moved into a word. */ | 
					
						
							|  |  |  | 				if (consecutiveVoiceDuration >= minimumWordLength && currentState == STATE_IN_SILENCE) { | 
					
						
							|  |  |  | 					iWordsCount++; | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 					ast_verb(3, "AMD: Channel [%s]. Word detected. iWordsCount:%d\n", chan->name, iWordsCount); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 					currentState = STATE_IN_WORD; | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 				if (consecutiveVoiceDuration >= maximumWordLength){ | 
					
						
							|  |  |  | 					ast_verb(3, "AMD: Channel [%s]. Maximum Word Length detected. [%d]\n", chan->name, consecutiveVoiceDuration); | 
					
						
							|  |  |  | 					ast_frfree(f); | 
					
						
							|  |  |  | 					strcpy(amdStatus , "MACHINE"); | 
					
						
							|  |  |  | 					sprintf(amdCause , "MAXWORDLENGTH-%d", consecutiveVoiceDuration); | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 				if (iWordsCount >= maximumNumberOfWords) { | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 					ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: iWordsCount:%d\n", chan->name, iWordsCount); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 					ast_frfree(f); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 					strcpy(amdStatus , "MACHINE"); | 
					
						
							|  |  |  | 					sprintf(amdCause , "MAXWORDS-%d-%d", iWordsCount, maximumNumberOfWords); | 
					
						
							| 
									
										
										
										
											2008-02-01 00:08:17 +00:00
										 |  |  | 					res = 1; | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 				if (inGreeting == 1 && voiceDuration >= greeting) { | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 					ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: voiceDuration:%d greeting:%d\n", chan->name, voiceDuration, greeting); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 					ast_frfree(f); | 
					
						
							|  |  |  | 					strcpy(amdStatus , "MACHINE"); | 
					
						
							|  |  |  | 					sprintf(amdCause , "LONGGREETING-%d-%d", voiceDuration, greeting); | 
					
						
							| 
									
										
										
										
											2008-02-01 00:08:17 +00:00
										 |  |  | 					res = 1; | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 				if (voiceDuration >= minimumWordLength ) { | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 					if (silenceDuration > 0) | 
					
						
							|  |  |  | 						ast_verb(3, "AMD: Channel [%s]. Detected Talk, previous silence duration: %d\n", chan->name, silenceDuration); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 					silenceDuration = 0; | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 				if (consecutiveVoiceDuration >= minimumWordLength && inGreeting == 0) { | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 					/* Only go in here once to change the greeting flag when we detect the 1st word */ | 
					
						
							|  |  |  | 					if (silenceDuration > 0) | 
					
						
							|  |  |  | 						ast_verb(3, "AMD: Channel [%s]. Before Greeting Time:  silenceDuration: %d voiceDuration: %d\n", chan->name, silenceDuration, voiceDuration); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 					inInitialSilence = 0; | 
					
						
							|  |  |  | 					inGreeting = 1; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 				 | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ast_frfree(f); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	if (!res) { | 
					
						
							| 
									
										
										
										
											2006-04-06 20:23:18 +00:00
										 |  |  | 		/* It took too long to get a frame back. Giving up. */ | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 		ast_verb(3, "AMD: Channel [%s]. Too long...\n", chan->name); | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 		strcpy(amdStatus , "NOTSURE"); | 
					
						
							|  |  |  | 		sprintf(amdCause , "TOOLONG-%d", iTotalTime); | 
					
						
							| 
									
										
										
										
											2006-04-06 20:23:18 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 	/* Set the status and cause on the channel */ | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(chan , "AMDSTATUS" , amdStatus); | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(chan , "AMDCAUSE" , amdCause); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 	/* Restore channel read format */ | 
					
						
							|  |  |  | 	if (readFormat && ast_set_read_format(chan, readFormat)) | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "AMD: Unable to restore read format on '%s'\n", chan->name); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 	/* Free the DSP used to detect silence */ | 
					
						
							|  |  |  | 	ast_dsp_free(silenceDetector); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static int amd_exec(struct ast_channel *chan, const char *data) | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	isAnsweringMachine(chan, data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-26 20:02:27 +00:00
										 |  |  | static int load_config(int reload) | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 	struct ast_config *cfg = NULL; | 
					
						
							|  |  |  | 	char *cat = NULL; | 
					
						
							|  |  |  | 	struct ast_variable *var = NULL; | 
					
						
							| 
									
										
										
										
											2007-08-16 21:09:46 +00:00
										 |  |  | 	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 	dfltSilenceThreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-16 21:09:46 +00:00
										 |  |  | 	if (!(cfg = ast_config_load("amd.conf", config_flags))) { | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 		ast_log(LOG_ERROR, "Configuration file amd.conf missing.\n"); | 
					
						
							| 
									
										
										
										
											2007-12-26 20:02:27 +00:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2008-09-12 23:30:03 +00:00
										 |  |  | 	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { | 
					
						
							| 
									
										
										
										
											2007-12-26 20:02:27 +00:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2008-09-12 23:30:03 +00:00
										 |  |  | 	} else if (cfg == CONFIG_STATUS_FILEINVALID) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Config file amd.conf is in an invalid format.  Aborting.\n"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	cat = ast_category_browse(cfg, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (cat) { | 
					
						
							| 
									
										
										
										
											2006-06-20 22:26:16 +00:00
										 |  |  | 		if (!strcasecmp(cat, "general") ) { | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 			var = ast_variable_browse(cfg, cat); | 
					
						
							|  |  |  | 			while (var) { | 
					
						
							|  |  |  | 				if (!strcasecmp(var->name, "initial_silence")) { | 
					
						
							|  |  |  | 					dfltInitialSilence = atoi(var->value); | 
					
						
							|  |  |  | 				} else if (!strcasecmp(var->name, "greeting")) { | 
					
						
							|  |  |  | 					dfltGreeting = atoi(var->value); | 
					
						
							|  |  |  | 				} else if (!strcasecmp(var->name, "after_greeting_silence")) { | 
					
						
							|  |  |  | 					dfltAfterGreetingSilence = atoi(var->value); | 
					
						
							|  |  |  | 				} else if (!strcasecmp(var->name, "silence_threshold")) { | 
					
						
							|  |  |  | 					dfltSilenceThreshold = atoi(var->value); | 
					
						
							|  |  |  | 				} else if (!strcasecmp(var->name, "total_analysis_time")) { | 
					
						
							|  |  |  | 					dfltTotalAnalysisTime = atoi(var->value); | 
					
						
							|  |  |  | 				} else if (!strcasecmp(var->name, "min_word_length")) { | 
					
						
							|  |  |  | 					dfltMinimumWordLength = atoi(var->value); | 
					
						
							|  |  |  | 				} else if (!strcasecmp(var->name, "between_words_silence")) { | 
					
						
							|  |  |  | 					dfltBetweenWordsSilence = atoi(var->value); | 
					
						
							|  |  |  | 				} else if (!strcasecmp(var->name, "maximum_number_of_words")) { | 
					
						
							|  |  |  | 					dfltMaximumNumberOfWords = atoi(var->value); | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 				} else if (!strcasecmp(var->name, "maximum_word_length")) { | 
					
						
							|  |  |  | 					dfltMaximumWordLength = atoi(var->value); | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 				} else { | 
					
						
							|  |  |  | 					ast_log(LOG_WARNING, "%s: Cat:%s. Unknown keyword %s at line %d of amd.conf\n", | 
					
						
							|  |  |  | 						app, cat, var->name, var->lineno); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				var = var->next; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		cat = ast_category_browse(cfg, cat); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-09-06 17:05:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 	ast_config_destroy(cfg); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 	ast_verb(3, "AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] " | 
					
						
							| 
									
										
										
										
											2007-12-28 16:12:06 +00:00
										 |  |  | 		"totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d]\n", | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | 		dfltInitialSilence, dfltGreeting, dfltAfterGreetingSilence, dfltTotalAnalysisTime, | 
					
						
							|  |  |  | 		dfltMinimumWordLength, dfltBetweenWordsSilence, dfltMaximumNumberOfWords, dfltSilenceThreshold, dfltMaximumWordLength); | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-26 20:02:27 +00:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int unload_module(void) | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	return ast_unregister_application(app); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int load_module(void) | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-26 20:02:27 +00:00
										 |  |  | 	if (load_config(0)) | 
					
						
							|  |  |  | 		return AST_MODULE_LOAD_DECLINE; | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  | 	if (ast_register_application_xml(app, amd_exec)) | 
					
						
							| 
									
										
										
										
											2007-12-26 20:02:27 +00:00
										 |  |  | 		return AST_MODULE_LOAD_FAILURE; | 
					
						
							|  |  |  | 	return AST_MODULE_LOAD_SUCCESS; | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int reload(void) | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-26 20:02:27 +00:00
										 |  |  | 	if (load_config(1)) | 
					
						
							|  |  |  | 		return AST_MODULE_LOAD_DECLINE; | 
					
						
							|  |  |  | 	return AST_MODULE_LOAD_SUCCESS; | 
					
						
							| 
									
										
										
										
											2006-02-14 18:44:18 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Answering Machine Detection Application", | 
					
						
							|  |  |  | 		.load = load_module, | 
					
						
							|  |  |  | 		.unload = unload_module, | 
					
						
							|  |  |  | 		.reload = reload, | 
					
						
							| 
									
										
										
										
											2008-02-09 11:27:10 +00:00
										 |  |  | ); |