| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-09-15 15:44:26 +00:00
										 |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-09-15 15:44:26 +00:00
										 |  |  |  * Copyright (C) 1999 - 2005, Digium, Inc. | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-05-15 17:22:41 +00:00
										 |  |  |  * Mark Spencer <markster@digium.com> | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Goertzel routines are borrowed from Steve Underwood's tremendous work on the | 
					
						
							|  |  |  |  * DTMF detector. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-09-15 15:44:26 +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. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  | /*! \file
 | 
					
						
							| 
									
										
										
										
											2005-09-15 15:44:26 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  |  * \brief Convenience Signal Processing routines | 
					
						
							| 
									
										
										
										
											2005-12-30 21:18:06 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \author Mark Spencer <markster@digium.com> | 
					
						
							|  |  |  |  * \author Steve Underwood <steveu@coppice.org> | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Some routines from tone_detect.c by Steven Underwood as published under the zapata library */ | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | 	tone_detect.c - General telephony tone detection, and specific | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  | 					detection of DTMF. | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  | 	Copyright (C) 2001  Steve Underwood <steveu@coppice.org> | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  | 	Despite my general liking of the GPL, I place this code in the | 
					
						
							|  |  |  | 	public domain for the benefit of all mankind - even the slimy | 
					
						
							|  |  |  | 	ones who might try to proprietize my work and use it to my | 
					
						
							|  |  |  | 	detriment. | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-07 18:54:56 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | #include <math.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-22 13:11:34 +00:00
										 |  |  | #include "asterisk/frame.h"
 | 
					
						
							|  |  |  | #include "asterisk/channel.h"
 | 
					
						
							|  |  |  | #include "asterisk/dsp.h"
 | 
					
						
							|  |  |  | #include "asterisk/ulaw.h"
 | 
					
						
							|  |  |  | #include "asterisk/alaw.h"
 | 
					
						
							| 
									
										
										
										
											2006-02-09 02:08:04 +00:00
										 |  |  | #include "asterisk/utils.h"
 | 
					
						
							| 
									
										
										
										
											2008-01-17 20:51:26 +00:00
										 |  |  | #include "asterisk/options.h"
 | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | #include "asterisk/config.h"
 | 
					
						
							| 
									
										
										
										
											2005-04-22 13:11:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-09 02:08:04 +00:00
										 |  |  | /*! Number of goertzels for progress detect */ | 
					
						
							|  |  |  | enum gsamp_size { | 
					
						
							|  |  |  | 	GSAMP_SIZE_NA = 183,			/*!< North America - 350, 440, 480, 620, 950, 1400, 1800 Hz */ | 
					
						
							|  |  |  | 	GSAMP_SIZE_CR = 188,			/*!< Costa Rica, Brazil - Only care about 425 Hz */ | 
					
						
							|  |  |  | 	GSAMP_SIZE_UK = 160 			/*!< UK disconnect goertzel feed - should trigger 400hz */ | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-09 02:08:04 +00:00
										 |  |  | enum prog_mode { | 
					
						
							|  |  |  | 	PROG_MODE_NA = 0, | 
					
						
							|  |  |  | 	PROG_MODE_CR, | 
					
						
							|  |  |  | 	PROG_MODE_UK | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-09 02:08:04 +00:00
										 |  |  | enum freq_index {  | 
					
						
							|  |  |  | 	/*! For US modes { */ | 
					
						
							|  |  |  | 	HZ_350 = 0, | 
					
						
							|  |  |  | 	HZ_440, | 
					
						
							|  |  |  | 	HZ_480, | 
					
						
							|  |  |  | 	HZ_620, | 
					
						
							|  |  |  | 	HZ_950, | 
					
						
							|  |  |  | 	HZ_1400, | 
					
						
							|  |  |  | 	HZ_1800, /*!< } */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*! For CR/BR modes */ | 
					
						
							|  |  |  | 	HZ_425 = 0, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*! For UK mode */ | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	HZ_350UK = 0, | 
					
						
							|  |  |  | 	HZ_400UK, | 
					
						
							|  |  |  | 	HZ_440UK | 
					
						
							| 
									
										
										
										
											2006-02-09 02:08:04 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2005-06-28 14:36:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | static struct progalias { | 
					
						
							|  |  |  | 	char *name; | 
					
						
							| 
									
										
										
										
											2006-02-09 02:08:04 +00:00
										 |  |  | 	enum prog_mode mode; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | } aliases[] = { | 
					
						
							|  |  |  | 	{ "us", PROG_MODE_NA }, | 
					
						
							|  |  |  | 	{ "ca", PROG_MODE_NA }, | 
					
						
							|  |  |  | 	{ "cr", PROG_MODE_CR }, | 
					
						
							| 
									
										
										
										
											2004-11-30 14:27:36 +00:00
										 |  |  | 	{ "br", PROG_MODE_CR }, | 
					
						
							| 
									
										
										
										
											2005-06-28 14:36:56 +00:00
										 |  |  | 	{ "uk", PROG_MODE_UK }, | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct progress { | 
					
						
							| 
									
										
										
										
											2006-02-09 02:08:04 +00:00
										 |  |  | 	enum gsamp_size size; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 	int freqs[7]; | 
					
						
							|  |  |  | } modes[] = { | 
					
						
							| 
									
										
										
										
											2006-02-09 02:08:04 +00:00
										 |  |  | 	{ GSAMP_SIZE_NA, { 350, 440, 480, 620, 950, 1400, 1800 } },	/*!< North America */ | 
					
						
							|  |  |  | 	{ GSAMP_SIZE_CR, { 425 } },                                	/*!< Costa Rica, Brazil */ | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	{ GSAMP_SIZE_UK, { 350, 400, 440 } },                                	/*!< UK */ | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-24 21:52:34 +00:00
										 |  |  | /*!\brief This value is the minimum threshold, calculated by averaging all
 | 
					
						
							|  |  |  |  * of the samples within a frame, for which a frame is determined to either | 
					
						
							|  |  |  |  * be silence (below the threshold) or noise (above the threshold).  Please | 
					
						
							|  |  |  |  * note that while the default threshold is an even exponent of 2, there is | 
					
						
							|  |  |  |  * no requirement that it be so.  The threshold will accept any value between | 
					
						
							|  |  |  |  * 0 and 32767. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | #define DEFAULT_THRESHOLD	512
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-09 02:08:04 +00:00
										 |  |  | enum busy_detect { | 
					
						
							|  |  |  | 	BUSY_PERCENT = 10,   	/*!< The percentage difference between the two last silence periods */ | 
					
						
							|  |  |  | 	BUSY_PAT_PERCENT = 7,	/*!< The percentage difference between measured and actual pattern */ | 
					
						
							|  |  |  | 	BUSY_THRESHOLD = 100,	/*!< Max number of ms difference between max and min times in busy */ | 
					
						
							|  |  |  | 	BUSY_MIN = 75,       	/*!< Busy must be at least 80 ms in half-cadence */ | 
					
						
							|  |  |  | 	BUSY_MAX =3100       	/*!< Busy can't be longer than 3100 ms in half-cadence */ | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-09 02:08:04 +00:00
										 |  |  | /*! Remember last 15 units */ | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | #define DSP_HISTORY 		15
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-09 02:08:04 +00:00
										 |  |  | #define TONE_THRESH		10.0	/*!< How much louder the tone should be than channel energy */
 | 
					
						
							|  |  |  | #define TONE_MIN_THRESH 	1e8	/*!< How much tone there should be at least to attempt */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! All THRESH_XXX values are in GSAMP_SIZE chunks (us = 22ms) */ | 
					
						
							|  |  |  | enum gsamp_thresh { | 
					
						
							|  |  |  | 	THRESH_RING = 8,        	/*!< Need at least 150ms ring to accept */ | 
					
						
							|  |  |  | 	THRESH_TALK = 2,        	/*!< Talk detection does not work continuously */ | 
					
						
							|  |  |  | 	THRESH_BUSY = 4,        	/*!< Need at least 80ms to accept */ | 
					
						
							|  |  |  | 	THRESH_CONGESTION = 4,  	/*!< Need at least 80ms to accept */ | 
					
						
							|  |  |  | 	THRESH_HANGUP = 60,     	/*!< Need at least 1300ms to accept hangup */ | 
					
						
							|  |  |  | 	THRESH_RING2ANSWER = 300	/*!< Timeout from start of ring to answer (about 6600 ms) */ | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | #define	MAX_DTMF_DIGITS		128
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Basic DTMF specs:
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Minimum tone on = 40ms | 
					
						
							|  |  |  |  * Minimum tone off = 50ms | 
					
						
							|  |  |  |  * Maximum digit rate = 10 per second | 
					
						
							|  |  |  |  * Normal twist <= 8dB accepted | 
					
						
							|  |  |  |  * Reverse twist <= 4dB accepted | 
					
						
							|  |  |  |  * S/N >= 15dB will detect OK | 
					
						
							|  |  |  |  * Attenuation <= 26dB will detect OK | 
					
						
							|  |  |  |  * Frequency tolerance +- 1.5% will detect, +-3.5% will reject | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | #define DTMF_THRESHOLD		8.0e7
 | 
					
						
							|  |  |  | #define FAX_THRESHOLD		8.0e7
 | 
					
						
							|  |  |  | #define FAX_2ND_HARMONIC	2.0     /* 4dB */
 | 
					
						
							|  |  |  | #define DTMF_NORMAL_TWIST	6.3     /* 8dB */
 | 
					
						
							| 
									
										
										
										
											2004-05-31 16:04:10 +00:00
										 |  |  | #ifdef	RADIO_RELAX
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | #define DTMF_REVERSE_TWIST          (relax ? 6.5 : 2.5)     /* 4dB normal */
 | 
					
						
							| 
									
										
										
										
											2004-05-31 16:04:10 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | #define DTMF_REVERSE_TWIST          (relax ? 4.0 : 2.5)     /* 4dB normal */
 | 
					
						
							| 
									
										
										
										
											2004-05-31 16:04:10 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | #define DTMF_RELATIVE_PEAK_ROW	6.3     /* 8dB */
 | 
					
						
							|  |  |  | #define DTMF_RELATIVE_PEAK_COL	6.3     /* 8dB */
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | #define DTMF_2ND_HARMONIC_ROW       (relax ? 1.7 : 2.5)     /* 4dB normal */
 | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | #define DTMF_2ND_HARMONIC_COL	63.1    /* 18dB */
 | 
					
						
							|  |  |  | #define DTMF_TO_TOTAL_ENERGY	42.0
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | #define BELL_MF_THRESHOLD	1.6e9
 | 
					
						
							|  |  |  | #define BELL_MF_TWIST		4.0     /* 6dB */
 | 
					
						
							|  |  |  | #define BELL_MF_RELATIVE_PEAK	12.6    /* 11dB */
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-17 20:51:26 +00:00
										 |  |  | #if defined(BUSYDETECT_TONEONLY) && defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
 | 
					
						
							|  |  |  | #error You cant use BUSYDETECT_TONEONLY together with BUSYDETECT_COMPARE_TONE_AND_SILENCE
 | 
					
						
							| 
									
										
										
										
											2005-07-25 21:57:14 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | /* The CNG signal consists of the transmission of 1100 Hz for 1/2 second,
 | 
					
						
							|  |  |  |  * followed by a 3 second silent (2100 Hz OFF) period. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define FAX_TONE_CNG_FREQ	1100
 | 
					
						
							|  |  |  | #define FAX_TONE_CNG_DURATION	500
 | 
					
						
							|  |  |  | #define FAX_TONE_CNG_DB		16
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* This signal may be sent by the Terminating FAX machine anywhere between
 | 
					
						
							|  |  |  |  * 1.8 to 2.5 seconds AFTER answering the call.  The CED signal consists | 
					
						
							|  |  |  |  * of a 2100 Hz tone that is from 2.6 to 4 seconds in duration. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | #define FAX_TONE_CED_FREQ	2100
 | 
					
						
							|  |  |  | #define FAX_TONE_CED_DURATION	2600
 | 
					
						
							|  |  |  | #define FAX_TONE_CED_DB		16
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define SAMPLE_RATE		8000
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* How many samples a frame has.  This constant is used when calculating
 | 
					
						
							|  |  |  |  * Goertzel block size for tone_detect.  It is only important if we want to | 
					
						
							|  |  |  |  * remove (squelch) the tone. In this case it is important to have block | 
					
						
							|  |  |  |  * size not to exceed size of voice frame.  Otherwise by the moment the tone | 
					
						
							|  |  |  |  * is detected it is too late to squelch it from previous frames. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define SAMPLES_IN_FRAME	160
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | /* MF goertzel size */ | 
					
						
							|  |  |  | #define MF_GSIZE		120
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* DTMF goertzel size */ | 
					
						
							|  |  |  | #define DTMF_GSIZE		102
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* How many successive hits needed to consider begin of a digit */ | 
					
						
							| 
									
										
										
										
											2012-01-05 21:46:55 +00:00
										 |  |  | #define DTMF_HITS_TO_BEGIN	4
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | /* How many successive misses needed to consider end of a digit */ | 
					
						
							| 
									
										
										
										
											2012-01-05 21:46:55 +00:00
										 |  |  | #define DTMF_MISSES_TO_END	4
 | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-07 17:34:45 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief The default silence threshold we will use if an alternate | 
					
						
							|  |  |  |  * configured value is not present or is invalid. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static const int DEFAULT_SILENCE_THRESHOLD = 256; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | #define CONFIG_FILE_NAME "dsp.conf"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | typedef struct { | 
					
						
							| 
									
										
										
										
											2007-05-29 19:00:40 +00:00
										 |  |  | 	int v2; | 
					
						
							|  |  |  | 	int v3; | 
					
						
							|  |  |  | 	int chunky; | 
					
						
							|  |  |  | 	int fac; | 
					
						
							| 
									
										
										
										
											2003-12-15 15:12:28 +00:00
										 |  |  | 	int samples; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } goertzel_state_t; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-29 19:00:40 +00:00
										 |  |  | typedef struct { | 
					
						
							|  |  |  | 	int value; | 
					
						
							|  |  |  | 	int power; | 
					
						
							|  |  |  | } goertzel_result_t; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int freq; | 
					
						
							|  |  |  | 	int block_size; | 
					
						
							|  |  |  | 	int squelch;		/* Remove (squelch) tone */ | 
					
						
							|  |  |  | 	goertzel_state_t tone; | 
					
						
							|  |  |  | 	float energy;		/* Accumulated energy of the current block */ | 
					
						
							|  |  |  | 	int samples_pending;	/* Samples remain to complete the current block */ | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	int mute_samples;	/* How many additional samples needs to be muted to suppress already detected tone */ | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	int hits_required;	/* How many successive blocks with tone we are looking for */ | 
					
						
							|  |  |  | 	float threshold;	/* Energy of the tone relative to energy from all other signals to consider a hit */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int hit_count;		/* How many successive blocks we consider tone present */ | 
					
						
							|  |  |  | 	int last_hit;		/* Indicates if the last processed block was a hit */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } tone_detect_state_t; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	goertzel_state_t row_out[4]; | 
					
						
							|  |  |  | 	goertzel_state_t col_out[4]; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	int hits_to_begin;		/* How many successive hits needed to consider begin of a digit */ | 
					
						
							|  |  |  | 	int misses_to_end;		/* How many successive misses needed to consider end of a digit */ | 
					
						
							|  |  |  | 	int hits;			/* How many successive hits we have seen already */ | 
					
						
							|  |  |  | 	int misses;			/* How many successive misses we have seen already */ | 
					
						
							| 
									
										
										
										
											2007-08-24 20:25:39 +00:00
										 |  |  | 	int lasthit; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 	int current_hit; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	float energy; | 
					
						
							|  |  |  | 	int current_sample; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	int mute_samples; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } dtmf_detect_state_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	goertzel_state_t tone_out[6]; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 	int current_hit; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	int hits[5]; | 
					
						
							|  |  |  | 	int current_sample; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	int mute_samples; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | } mf_detect_state_t; | 
					
						
							| 
									
										
										
										
											2003-12-15 15:12:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char digits[MAX_DTMF_DIGITS + 1]; | 
					
						
							| 
									
										
										
										
											2010-05-19 16:42:20 +00:00
										 |  |  | 	int digitlen[MAX_DTMF_DIGITS + 1]; | 
					
						
							| 
									
										
										
										
											2010-06-05 17:55:28 +00:00
										 |  |  | 	int current_digits; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	int detected_digits; | 
					
						
							|  |  |  | 	int lost_digits; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	union { | 
					
						
							|  |  |  | 		dtmf_detect_state_t dtmf; | 
					
						
							|  |  |  | 		mf_detect_state_t mf; | 
					
						
							|  |  |  | 	} td; | 
					
						
							|  |  |  | } digit_detect_state_t; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static const float dtmf_row[] = { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	697.0,  770.0,  852.0,  941.0 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static const float dtmf_col[] = { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	1209.0, 1336.0, 1477.0, 1633.0 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static const float mf_tones[] = { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	700.0, 900.0, 1100.0, 1300.0, 1500.0, 1700.0 | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static const char dtmf_positions[] = "123A" "456B" "789C" "*0#D"; | 
					
						
							|  |  |  | static const char bell_mf_positions[] = "1247C-358A--69*---0B----#"; | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | static int thresholds[THRESHOLD_MAX]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | static inline void goertzel_sample(goertzel_state_t *s, short sample) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-05-29 19:00:40 +00:00
										 |  |  | 	int v1; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	v1 = s->v2; | 
					
						
							|  |  |  | 	s->v2 = s->v3; | 
					
						
							| 
									
										
										
										
											2007-05-29 19:00:40 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	s->v3 = (s->fac * s->v2) >> 15; | 
					
						
							|  |  |  | 	s->v3 = s->v3 - v1 + (sample >> s->chunky); | 
					
						
							|  |  |  | 	if (abs(s->v3) > 32768) { | 
					
						
							|  |  |  | 		s->chunky++; | 
					
						
							|  |  |  | 		s->v3 = s->v3 >> 1; | 
					
						
							|  |  |  | 		s->v2 = s->v2 >> 1; | 
					
						
							|  |  |  | 		v1 = v1 >> 1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void goertzel_update(goertzel_state_t *s, short *samps, int count) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	for (i = 0; i < count; i++) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		goertzel_sample(s, samps[i]); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline float goertzel_result(goertzel_state_t *s) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-05-29 19:00:40 +00:00
										 |  |  | 	goertzel_result_t r; | 
					
						
							|  |  |  | 	r.value = (s->v3 * s->v3) + (s->v2 * s->v2); | 
					
						
							|  |  |  | 	r.value -= ((s->v2 * s->v3) >> 15) * s->fac; | 
					
						
							|  |  |  | 	r.power = s->chunky * 2; | 
					
						
							|  |  |  | 	return (float)r.value * (float)(1 << r.power); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-12-15 15:12:28 +00:00
										 |  |  | static inline void goertzel_init(goertzel_state_t *s, float freq, int samples) | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-05-29 19:00:40 +00:00
										 |  |  | 	s->v2 = s->v3 = s->chunky = 0.0; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 	s->fac = (int)(32768.0 * 2.0 * cos(2.0 * M_PI * freq / SAMPLE_RATE)); | 
					
						
							| 
									
										
										
										
											2003-12-15 15:12:28 +00:00
										 |  |  | 	s->samples = samples; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void goertzel_reset(goertzel_state_t *s) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-05-29 19:00:40 +00:00
										 |  |  | 	s->v2 = s->v3 = s->chunky = 0.0; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | typedef struct { | 
					
						
							|  |  |  | 	int start; | 
					
						
							|  |  |  | 	int end; | 
					
						
							|  |  |  | } fragment_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Note on tone suppression (squelching). Individual detectors (DTMF/MF/generic tone)
 | 
					
						
							|  |  |  |  * report fragmens of the frame in which detected tone resides and which needs | 
					
						
							|  |  |  |  * to be "muted" in order to suppress the tone. To mark fragment for muting, | 
					
						
							|  |  |  |  * detectors call mute_fragment passing fragment_t there. Multiple fragments | 
					
						
							|  |  |  |  * can be marked and ast_dsp_process later will mute all of them. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Note: When tone starts in the middle of a Goertzel block, it won't be properly | 
					
						
							|  |  |  |  * detected in that block, only in the next. If we only mute the next block | 
					
						
							|  |  |  |  * where tone is actually detected, the user will still hear beginning | 
					
						
							|  |  |  |  * of the tone in preceeding block. This is why we usually want to mute some amount | 
					
						
							|  |  |  |  * of samples preceeding and following the block where tone was detected. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | struct ast_dsp { | 
					
						
							|  |  |  | 	struct ast_frame f; | 
					
						
							|  |  |  | 	int threshold; | 
					
						
							|  |  |  | 	int totalsilence; | 
					
						
							|  |  |  | 	int totalnoise; | 
					
						
							|  |  |  | 	int features; | 
					
						
							| 
									
										
										
										
											2006-01-17 23:37:22 +00:00
										 |  |  | 	int ringtimeout; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	int busymaybe; | 
					
						
							|  |  |  | 	int busycount; | 
					
						
							| 
									
										
										
										
											2005-08-08 00:08:48 +00:00
										 |  |  | 	int busy_tonelength; | 
					
						
							|  |  |  | 	int busy_quietlength; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	int historicnoise[DSP_HISTORY]; | 
					
						
							|  |  |  | 	int historicsilence[DSP_HISTORY]; | 
					
						
							|  |  |  | 	goertzel_state_t freqs[7]; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 	int freqcount; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	int gsamps; | 
					
						
							| 
									
										
										
										
											2006-02-09 02:08:04 +00:00
										 |  |  | 	enum gsamp_size gsamp_size; | 
					
						
							|  |  |  | 	enum prog_mode progmode; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	int tstate; | 
					
						
							|  |  |  | 	int tcount; | 
					
						
							|  |  |  | 	int digitmode; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 	int faxmode; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	int dtmf_began; | 
					
						
							| 
									
										
										
										
											2009-12-04 15:38:33 +00:00
										 |  |  | 	int display_inband_dtmf_warning; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	float genergy; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	int mute_fragments; | 
					
						
							|  |  |  | 	fragment_t mute_data[5]; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 	digit_detect_state_t digit_state; | 
					
						
							|  |  |  | 	tone_detect_state_t cng_tone_state; | 
					
						
							|  |  |  | 	tone_detect_state_t ced_tone_state; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | static void mute_fragment(struct ast_dsp *dsp, fragment_t *fragment) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-11 18:09:35 +00:00
										 |  |  | 	if (dsp->mute_fragments >= ARRAY_LEN(dsp->mute_data)) { | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		ast_log(LOG_ERROR, "Too many fragments to mute. Ignoring\n"); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dsp->mute_data[dsp->mute_fragments++] = *fragment; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration, int amp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int duration_samples; | 
					
						
							|  |  |  | 	float x; | 
					
						
							|  |  |  | 	int periods_in_block; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s->freq = freq; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Desired tone duration in samples */ | 
					
						
							|  |  |  | 	duration_samples = duration * SAMPLE_RATE / 1000; | 
					
						
							|  |  |  | 	/* We want to allow 10% deviation of tone duration */ | 
					
						
							|  |  |  | 	duration_samples = duration_samples * 9 / 10; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* If we want to remove tone, it is important to have block size not
 | 
					
						
							|  |  |  | 	   to exceed frame size. Otherwise by the moment tone is detected it is too late | 
					
						
							|  |  |  |  	   to squelch it from previous frames */ | 
					
						
							|  |  |  | 	s->block_size = SAMPLES_IN_FRAME; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	periods_in_block = s->block_size * freq / SAMPLE_RATE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Make sure we will have at least 5 periods at target frequency for analisys.
 | 
					
						
							|  |  |  | 	   This may make block larger than expected packet and will make squelching impossible | 
					
						
							|  |  |  | 	   but at least we will be detecting the tone */ | 
					
						
							|  |  |  | 	if (periods_in_block < 5) | 
					
						
							|  |  |  | 		periods_in_block = 5; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Now calculate final block size. It will contain integer number of periods */ | 
					
						
							|  |  |  | 	s->block_size = periods_in_block * SAMPLE_RATE / freq; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* tone_detect is currently only used to detect fax tones and we
 | 
					
						
							|  |  |  | 	   do not need suqlching the fax tones */ | 
					
						
							|  |  |  | 	s->squelch = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Account for the first and the last block to be incomplete
 | 
					
						
							|  |  |  | 	   and thus no tone will be detected in them */ | 
					
						
							|  |  |  | 	s->hits_required = (duration_samples - (s->block_size - 1)) / s->block_size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	goertzel_init(&s->tone, freq, s->block_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s->samples_pending = s->block_size; | 
					
						
							|  |  |  | 	s->hit_count = 0; | 
					
						
							|  |  |  | 	s->last_hit = 0; | 
					
						
							|  |  |  | 	s->energy = 0.0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* We want tone energy to be amp decibels above the rest of the signal (the noise).
 | 
					
						
							|  |  |  | 	   According to Parseval's theorem the energy computed in time domain equals to energy | 
					
						
							|  |  |  | 	   computed in frequency domain. So subtracting energy in the frequency domain (Goertzel result) | 
					
						
							|  |  |  | 	   from the energy in the time domain we will get energy of the remaining signal (without the tone | 
					
						
							|  |  |  | 	   we are detecting). We will be checking that | 
					
						
							|  |  |  | 		10*log(Ew / (Et - Ew)) > amp | 
					
						
							|  |  |  | 	   Calculate threshold so that we will be actually checking | 
					
						
							|  |  |  | 		Ew > Et * threshold | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	x = pow(10.0, amp / 10.0); | 
					
						
							|  |  |  | 	s->threshold = x / (x + 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_debug(1, "Setup tone %d Hz, %d ms, block_size=%d, hits_required=%d\n", freq, duration, s->block_size, s->hits_required); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void ast_fax_detect_init(struct ast_dsp *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ast_tone_detect_init(&s->cng_tone_state, FAX_TONE_CNG_FREQ, FAX_TONE_CNG_DURATION, FAX_TONE_CNG_DB); | 
					
						
							|  |  |  | 	ast_tone_detect_init(&s->ced_tone_state, FAX_TONE_CED_FREQ, FAX_TONE_CED_DURATION, FAX_TONE_CED_DB); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | static void ast_dtmf_detect_init (dtmf_detect_state_t *s) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	int i; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-24 20:25:39 +00:00
										 |  |  | 	s->lasthit = 0; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 	s->current_hit = 0; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	for (i = 0;  i < 4;  i++) { | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		goertzel_init(&s->row_out[i], dtmf_row[i], DTMF_GSIZE); | 
					
						
							|  |  |  | 		goertzel_init(&s->col_out[i], dtmf_col[i], DTMF_GSIZE); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		s->energy = 0.0; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	s->current_sample = 0; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	s->hits = 0; | 
					
						
							|  |  |  | 	s->misses = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s->hits_to_begin = DTMF_HITS_TO_BEGIN; | 
					
						
							|  |  |  | 	s->misses_to_end = DTMF_MISSES_TO_END; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void ast_mf_detect_init (mf_detect_state_t *s) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	int i; | 
					
						
							| 
									
										
										
										
											2003-12-15 15:12:28 +00:00
										 |  |  | 	s->hits[0] = s->hits[1] = s->hits[2] = s->hits[3] = s->hits[4] = 0; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	for (i = 0;  i < 6;  i++) { | 
					
						
							|  |  |  | 		goertzel_init (&s->tone_out[i], mf_tones[i], 160); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	s->current_sample = 0; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 	s->current_hit = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void ast_digit_detect_init(digit_detect_state_t *s, int mf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	s->current_digits = 0; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	s->detected_digits = 0; | 
					
						
							|  |  |  | 	s->lost_digits = 0; | 
					
						
							|  |  |  | 	s->digits[0] = '\0'; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	if (mf) { | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		ast_mf_detect_init(&s->td.mf); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		ast_dtmf_detect_init(&s->td.dtmf); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | static int tone_detect(struct ast_dsp *dsp, tone_detect_state_t *s, int16_t *amp, int samples) | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	float tone_energy; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	int hit = 0; | 
					
						
							|  |  |  | 	int limit; | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							|  |  |  | 	int16_t *ptr; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	int start, end; | 
					
						
							|  |  |  | 	fragment_t mute = {0, 0}; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	if (s->squelch && s->mute_samples > 0) { | 
					
						
							|  |  |  | 		mute.end = (s->mute_samples < samples) ? s->mute_samples : samples; | 
					
						
							|  |  |  | 		s->mute_samples -= mute.end; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (start = 0;  start < samples;  start = end) { | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		/* Process in blocks. */ | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		limit = samples - start; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		if (limit > s->samples_pending) { | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 			limit = s->samples_pending; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		end = start + limit; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		for (i = limit, ptr = amp ; i > 0; i--, ptr++) { | 
					
						
							|  |  |  | 			/* signed 32 bit int should be enough to suqare any possible signed 16 bit value */ | 
					
						
							|  |  |  | 			s->energy += (int32_t) *ptr * (int32_t) *ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			goertzel_sample(&s->tone, *ptr); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		s->samples_pending -= limit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (s->samples_pending) { | 
					
						
							|  |  |  | 			/* Finished incomplete (last) block */ | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		tone_energy = goertzel_result(&s->tone); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Scale to make comparable */ | 
					
						
							|  |  |  | 		tone_energy *= 2.0; | 
					
						
							|  |  |  | 		s->energy *= s->block_size; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		ast_debug(10, "tone %d, Ew=%.2E, Et=%.2E, s/n=%10.2f\n", s->freq, tone_energy, s->energy, tone_energy / (s->energy - tone_energy)); | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		hit = 0; | 
					
						
							|  |  |  | 		if (tone_energy > s->energy * s->threshold) { | 
					
						
							|  |  |  | 			ast_debug(10, "Hit! count=%d\n", s->hit_count); | 
					
						
							|  |  |  | 			hit = 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		if (s->hit_count) { | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 			s->hit_count++; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (hit == s->last_hit) { | 
					
						
							|  |  |  | 			if (!hit) { | 
					
						
							|  |  |  | 				/* Two successive misses. Tone ended */ | 
					
						
							|  |  |  | 				s->hit_count = 0; | 
					
						
							|  |  |  | 			} else if (!s->hit_count) { | 
					
						
							|  |  |  | 				s->hit_count++; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (s->hit_count == s->hits_required) { | 
					
						
							|  |  |  | 			ast_debug(1, "%d Hz done detected\n", s->freq); | 
					
						
							|  |  |  | 			res = 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		s->last_hit = hit; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		/* If we had a hit in this block, include it into mute fragment */ | 
					
						
							|  |  |  | 		if (s->squelch && hit) { | 
					
						
							|  |  |  | 			if (mute.end < start - s->block_size) { | 
					
						
							|  |  |  | 				/* There is a gap between fragments */ | 
					
						
							|  |  |  | 				mute_fragment(dsp, &mute); | 
					
						
							|  |  |  | 				mute.start = (start > s->block_size) ? (start - s->block_size) : 0; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			mute.end = end + s->block_size; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Reinitialise the detector for the next block */ | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		/* Reset for the next block */ | 
					
						
							|  |  |  | 		goertzel_reset(&s->tone); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Advance to the next block */ | 
					
						
							|  |  |  | 		s->energy = 0.0; | 
					
						
							|  |  |  | 		s->samples_pending = s->block_size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		amp += limit; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (s->squelch && mute.end) { | 
					
						
							|  |  |  | 		if (mute.end > samples) { | 
					
						
							|  |  |  | 			s->mute_samples = mute.end - samples; | 
					
						
							|  |  |  | 			mute.end = samples; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		mute_fragment(dsp, &mute); | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void store_digit(digit_detect_state_t *s, char digit) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	s->detected_digits++; | 
					
						
							|  |  |  | 	if (s->current_digits < MAX_DTMF_DIGITS) { | 
					
						
							| 
									
										
										
										
											2010-05-19 16:42:20 +00:00
										 |  |  | 		s->digitlen[s->current_digits] = 0; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		s->digits[s->current_digits++] = digit; | 
					
						
							|  |  |  | 		s->digits[s->current_digits] = '\0'; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Digit lost due to full buffer\n"); | 
					
						
							|  |  |  | 		s->lost_digits++; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | static int dtmf_detect(struct ast_dsp *dsp, digit_detect_state_t *s, int16_t amp[], int samples, int squelch, int relax) | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	float row_energy[4]; | 
					
						
							|  |  |  | 	float col_energy[4]; | 
					
						
							|  |  |  | 	float famp; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	int j; | 
					
						
							|  |  |  | 	int sample; | 
					
						
							|  |  |  | 	int best_row; | 
					
						
							|  |  |  | 	int best_col; | 
					
						
							|  |  |  | 	int hit; | 
					
						
							|  |  |  | 	int limit; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	fragment_t mute = {0, 0}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (squelch && s->td.dtmf.mute_samples > 0) { | 
					
						
							|  |  |  | 		mute.end = (s->td.dtmf.mute_samples < samples) ? s->td.dtmf.mute_samples : samples; | 
					
						
							|  |  |  | 		s->td.dtmf.mute_samples -= mute.end; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	hit = 0; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	for (sample = 0; sample < samples; sample = limit) { | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		/* DTMF_GSIZE is optimised to meet the DTMF specs. */ | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		if ((samples - sample) >= (DTMF_GSIZE - s->td.dtmf.current_sample)) { | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 			limit = sample + (DTMF_GSIZE - s->td.dtmf.current_sample); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 			limit = samples; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 		/* The following unrolled loop takes only 35% (rough estimate) of the 
 | 
					
						
							|  |  |  | 		   time of a rolled loop on the machine on which it was developed */ | 
					
						
							| 
									
										
										
										
											2007-06-06 19:10:03 +00:00
										 |  |  | 		for (j = sample; j < limit; j++) { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 			famp = amp[j]; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 			s->td.dtmf.energy += famp*famp; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 			/* With GCC 2.95, the following unrolled code seems to take about 35%
 | 
					
						
							|  |  |  | 			   (rough estimate) as long as a neat little 0-3 loop */ | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 			goertzel_sample(s->td.dtmf.row_out, amp[j]); | 
					
						
							|  |  |  | 			goertzel_sample(s->td.dtmf.col_out, amp[j]); | 
					
						
							|  |  |  | 			goertzel_sample(s->td.dtmf.row_out + 1, amp[j]); | 
					
						
							|  |  |  | 			goertzel_sample(s->td.dtmf.col_out + 1, amp[j]); | 
					
						
							|  |  |  | 			goertzel_sample(s->td.dtmf.row_out + 2, amp[j]); | 
					
						
							|  |  |  | 			goertzel_sample(s->td.dtmf.col_out + 2, amp[j]); | 
					
						
							|  |  |  | 			goertzel_sample(s->td.dtmf.row_out + 3, amp[j]); | 
					
						
							|  |  |  | 			goertzel_sample(s->td.dtmf.col_out + 3, amp[j]); | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		s->td.dtmf.current_sample += (limit - sample); | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		if (s->td.dtmf.current_sample < DTMF_GSIZE) { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 		/* We are at the end of a DTMF detection block */ | 
					
						
							|  |  |  | 		/* Find the peak row and the peak column */ | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		row_energy[0] = goertzel_result (&s->td.dtmf.row_out[0]); | 
					
						
							|  |  |  | 		col_energy[0] = goertzel_result (&s->td.dtmf.col_out[0]); | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		for (best_row = best_col = 0, i = 1;  i < 4;  i++) { | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 			row_energy[i] = goertzel_result (&s->td.dtmf.row_out[i]); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			if (row_energy[i] > row_energy[best_row]) { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 				best_row = i; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 			col_energy[i] = goertzel_result (&s->td.dtmf.col_out[i]); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			if (col_energy[i] > col_energy[best_col]) { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 				best_col = i; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		hit = 0; | 
					
						
							|  |  |  | 		/* Basic signal level test and the twist test */ | 
					
						
							|  |  |  | 		if (row_energy[best_row] >= DTMF_THRESHOLD &&  | 
					
						
							|  |  |  | 		    col_energy[best_col] >= DTMF_THRESHOLD && | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		    col_energy[best_col] < row_energy[best_row] * DTMF_REVERSE_TWIST && | 
					
						
							|  |  |  | 		    col_energy[best_col] * DTMF_NORMAL_TWIST > row_energy[best_row]) { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 			/* Relative peak test */ | 
					
						
							|  |  |  | 			for (i = 0;  i < 4;  i++) { | 
					
						
							|  |  |  | 				if ((i != best_col && | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				    col_energy[i] * DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) || | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 				    (i != best_row  | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				     && row_energy[i] * DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			/* ... and fraction of total energy test */ | 
					
						
							|  |  |  | 			if (i >= 4 && | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			    (row_energy[best_row] + col_energy[best_col]) > DTMF_TO_TOTAL_ENERGY * s->td.dtmf.energy) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 				/* Got a hit */ | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 				hit = dtmf_positions[(best_row << 2) + best_col]; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}  | 
					
						
							| 
									
										
										
										
											2007-08-24 20:25:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-05 21:46:55 +00:00
										 |  |  | 		if (hit == s->td.dtmf.lasthit) { | 
					
						
							|  |  |  | 			if (s->td.dtmf.current_hit) { | 
					
						
							|  |  |  | 				/* We are in the middle of a digit already */ | 
					
						
							|  |  |  | 				if (hit) { | 
					
						
							|  |  |  | 					if (hit != s->td.dtmf.current_hit) { | 
					
						
							|  |  |  | 						/* Look for a start of a new digit.
 | 
					
						
							|  |  |  | 						   This is because hits_to_begin may be smaller than misses_to_end | 
					
						
							|  |  |  | 						   and we may find the beginning of new digit before we consider last one ended. */ | 
					
						
							|  |  |  | 						s->td.dtmf.current_hit = 0; | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						/* Current hit was same as last, so increment digit duration (of last digit) */ | 
					
						
							|  |  |  | 						s->digitlen[s->current_digits - 1] += DTMF_GSIZE; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					/* No Digit */ | 
					
						
							|  |  |  | 					s->td.dtmf.misses++; | 
					
						
							|  |  |  | 					if (s->td.dtmf.misses == s->td.dtmf.misses_to_end) { | 
					
						
							|  |  |  | 						/* There were enough misses to consider digit ended */ | 
					
						
							|  |  |  | 						s->td.dtmf.current_hit = 0; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2012-01-05 21:46:55 +00:00
										 |  |  | 			} else if (hit) { | 
					
						
							|  |  |  | 				/* Detecting new digit */ | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 				s->td.dtmf.hits++; | 
					
						
							| 
									
										
										
										
											2012-01-05 21:46:55 +00:00
										 |  |  | 				if (s->td.dtmf.hits == s->td.dtmf.hits_to_begin) { | 
					
						
							|  |  |  | 					store_digit(s, hit); | 
					
						
							|  |  |  | 					s->td.dtmf.current_hit = hit; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2007-08-24 20:25:39 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2012-01-05 21:46:55 +00:00
										 |  |  | 			s->td.dtmf.hits = 1; | 
					
						
							|  |  |  | 			s->td.dtmf.misses = 1; | 
					
						
							|  |  |  | 			s->td.dtmf.lasthit = hit; | 
					
						
							| 
									
										
										
										
											2007-08-24 20:25:39 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* If we had a hit in this block, include it into mute fragment */ | 
					
						
							|  |  |  | 		if (squelch && hit) { | 
					
						
							|  |  |  | 			if (mute.end < sample - DTMF_GSIZE) { | 
					
						
							|  |  |  | 				/* There is a gap between fragments */ | 
					
						
							|  |  |  | 				mute_fragment(dsp, &mute); | 
					
						
							|  |  |  | 				mute.start = (sample > DTMF_GSIZE) ? (sample - DTMF_GSIZE) : 0; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			mute.end = limit + DTMF_GSIZE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 		/* Reinitialise the detector for the next block */ | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		for (i = 0; i < 4; i++) { | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 			goertzel_reset(&s->td.dtmf.row_out[i]); | 
					
						
							|  |  |  | 			goertzel_reset(&s->td.dtmf.col_out[i]); | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		s->td.dtmf.energy = 0.0; | 
					
						
							|  |  |  | 		s->td.dtmf.current_sample = 0; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (squelch && mute.end) { | 
					
						
							|  |  |  | 		if (mute.end > samples) { | 
					
						
							|  |  |  | 			s->td.dtmf.mute_samples = mute.end - samples; | 
					
						
							|  |  |  | 			mute.end = samples; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		mute_fragment(dsp, &mute); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 	return (s->td.dtmf.current_hit);	/* return the debounced hit */ | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | static int mf_detect(struct ast_dsp *dsp, digit_detect_state_t *s, int16_t amp[], | 
					
						
							|  |  |  |                  int samples, int squelch, int relax) | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	float energy[6]; | 
					
						
							|  |  |  | 	int best; | 
					
						
							|  |  |  | 	int second_best; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	int j; | 
					
						
							|  |  |  | 	int sample; | 
					
						
							|  |  |  | 	int hit; | 
					
						
							|  |  |  | 	int limit; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	fragment_t mute = {0, 0}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (squelch && s->td.mf.mute_samples > 0) { | 
					
						
							|  |  |  | 		mute.end = (s->td.mf.mute_samples < samples) ? s->td.mf.mute_samples : samples; | 
					
						
							|  |  |  | 		s->td.mf.mute_samples -= mute.end; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	hit = 0; | 
					
						
							|  |  |  | 	for (sample = 0;  sample < samples;  sample = limit) { | 
					
						
							|  |  |  | 		/* 80 is optimised to meet the MF specs. */ | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		/* XXX So then why is MF_GSIZE defined as 120? */ | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		if ((samples - sample) >= (MF_GSIZE - s->td.mf.current_sample)) { | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 			limit = sample + (MF_GSIZE - s->td.mf.current_sample); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 			limit = samples; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 		/* The following unrolled loop takes only 35% (rough estimate) of the 
 | 
					
						
							|  |  |  | 		   time of a rolled loop on the machine on which it was developed */ | 
					
						
							|  |  |  | 		for (j = sample;  j < limit;  j++) { | 
					
						
							|  |  |  | 			/* With GCC 2.95, the following unrolled code seems to take about 35%
 | 
					
						
							|  |  |  | 			   (rough estimate) as long as a neat little 0-3 loop */ | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 			goertzel_sample(s->td.mf.tone_out, amp[j]); | 
					
						
							|  |  |  | 			goertzel_sample(s->td.mf.tone_out + 1, amp[j]); | 
					
						
							|  |  |  | 			goertzel_sample(s->td.mf.tone_out + 2, amp[j]); | 
					
						
							|  |  |  | 			goertzel_sample(s->td.mf.tone_out + 3, amp[j]); | 
					
						
							|  |  |  | 			goertzel_sample(s->td.mf.tone_out + 4, amp[j]); | 
					
						
							|  |  |  | 			goertzel_sample(s->td.mf.tone_out + 5, amp[j]); | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		s->td.mf.current_sample += (limit - sample); | 
					
						
							|  |  |  | 		if (s->td.mf.current_sample < MF_GSIZE) { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-12-15 15:12:28 +00:00
										 |  |  | 		/* We're at the end of an MF detection block.  */ | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 		/* Find the two highest energies. The spec says to look for
 | 
					
						
							|  |  |  | 		   two tones and two tones only. Taking this literally -ie | 
					
						
							|  |  |  | 		   only two tones pass the minimum threshold - doesn't work | 
					
						
							|  |  |  | 		   well. The sinc function mess, due to rectangular windowing | 
					
						
							|  |  |  | 		   ensure that! Find the two highest energies and ensure they | 
					
						
							|  |  |  | 		   are considerably stronger than any of the others. */ | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		energy[0] = goertzel_result(&s->td.mf.tone_out[0]); | 
					
						
							|  |  |  | 		energy[1] = goertzel_result(&s->td.mf.tone_out[1]); | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 		if (energy[0] > energy[1]) { | 
					
						
							|  |  |  | 			best = 0; | 
					
						
							|  |  |  | 			second_best = 1; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			best = 1; | 
					
						
							|  |  |  | 			second_best = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		/*endif*/ | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		for (i = 2; i < 6; i++) { | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 			energy[i] = goertzel_result(&s->td.mf.tone_out[i]); | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 			if (energy[i] >= energy[best]) { | 
					
						
							|  |  |  | 				second_best = best; | 
					
						
							|  |  |  | 				best = i; | 
					
						
							|  |  |  | 			} else if (energy[i] >= energy[second_best]) { | 
					
						
							|  |  |  | 				second_best = i; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		/* Basic signal level and twist tests */ | 
					
						
							|  |  |  | 		hit = 0; | 
					
						
							|  |  |  | 		if (energy[best] >= BELL_MF_THRESHOLD && energy[second_best] >= BELL_MF_THRESHOLD | 
					
						
							|  |  |  | 	            && energy[best] < energy[second_best]*BELL_MF_TWIST | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	            && energy[best] * BELL_MF_TWIST > energy[second_best]) { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 			/* Relative peak test */ | 
					
						
							|  |  |  | 			hit = -1; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			for (i = 0; i < 6; i++) { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 				if (i != best && i != second_best) { | 
					
						
							|  |  |  | 					if (energy[i]*BELL_MF_RELATIVE_PEAK >= energy[second_best]) { | 
					
						
							|  |  |  | 						/* The best two are not clearly the best */ | 
					
						
							|  |  |  | 						hit = 0; | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (hit) { | 
					
						
							|  |  |  | 			/* Get the values into ascending order */ | 
					
						
							|  |  |  | 			if (second_best < best) { | 
					
						
							|  |  |  | 				i = best; | 
					
						
							|  |  |  | 				best = second_best; | 
					
						
							|  |  |  | 				second_best = i; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			best = best * 5 + second_best - 1; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 			hit = bell_mf_positions[best]; | 
					
						
							|  |  |  | 			/* Look for two successive similar results */ | 
					
						
							|  |  |  | 			/* The logic in the next test is:
 | 
					
						
							|  |  |  | 			   For KP we need 4 successive identical clean detects, with | 
					
						
							|  |  |  | 			   two blocks of something different preceeding it. For anything | 
					
						
							|  |  |  | 			   else we need two successive identical clean detects, with | 
					
						
							|  |  |  | 			   two blocks of something different preceeding it. */ | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 			if (hit == s->td.mf.hits[4] && hit == s->td.mf.hits[3] && | 
					
						
							|  |  |  | 			   ((hit != '*' && hit != s->td.mf.hits[2] && hit != s->td.mf.hits[1])|| | 
					
						
							|  |  |  | 			    (hit == '*' && hit == s->td.mf.hits[2] && hit != s->td.mf.hits[1] &&  | 
					
						
							|  |  |  | 			    hit != s->td.mf.hits[0]))) { | 
					
						
							|  |  |  | 				store_digit(s, hit); | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (hit != s->td.mf.hits[4] && hit != s->td.mf.hits[3]) { | 
					
						
							|  |  |  | 			/* Two successive block without a hit terminate current digit */ | 
					
						
							|  |  |  | 			s->td.mf.current_hit = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		s->td.mf.hits[0] = s->td.mf.hits[1]; | 
					
						
							|  |  |  | 		s->td.mf.hits[1] = s->td.mf.hits[2]; | 
					
						
							|  |  |  | 		s->td.mf.hits[2] = s->td.mf.hits[3]; | 
					
						
							|  |  |  | 		s->td.mf.hits[3] = s->td.mf.hits[4]; | 
					
						
							|  |  |  | 		s->td.mf.hits[4] = hit; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* If we had a hit in this block, include it into mute fragment */ | 
					
						
							|  |  |  | 		if (squelch && hit) { | 
					
						
							|  |  |  | 			if (mute.end < sample - MF_GSIZE) { | 
					
						
							|  |  |  | 				/* There is a gap between fragments */ | 
					
						
							|  |  |  | 				mute_fragment(dsp, &mute); | 
					
						
							|  |  |  | 				mute.start = (sample > MF_GSIZE) ? (sample - MF_GSIZE) : 0; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			mute.end = limit + DTMF_GSIZE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 		/* Reinitialise the detector for the next block */ | 
					
						
							|  |  |  | 		for (i = 0;  i < 6;  i++) | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 			goertzel_reset(&s->td.mf.tone_out[i]); | 
					
						
							|  |  |  | 		s->td.mf.current_sample = 0; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	if (squelch && mute.end) { | 
					
						
							|  |  |  | 		if (mute.end > samples) { | 
					
						
							|  |  |  | 			s->td.mf.mute_samples = mute.end - samples; | 
					
						
							|  |  |  | 			mute.end = samples; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		mute_fragment(dsp, &mute); | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	return (s->td.mf.current_hit); /* return the debounced hit */ | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int pair_there(float p1, float p2, float i1, float i2, float e) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* See if p1 and p2 are there, relative to i1 and i2 and total energy */ | 
					
						
							|  |  |  | 	/* Make sure absolute levels are high enough */ | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	if ((p1 < TONE_MIN_THRESH) || (p2 < TONE_MIN_THRESH)) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	/* Amplify ignored stuff */ | 
					
						
							|  |  |  | 	i2 *= TONE_THRESH; | 
					
						
							|  |  |  | 	i1 *= TONE_THRESH; | 
					
						
							|  |  |  | 	e *= TONE_THRESH; | 
					
						
							|  |  |  | 	/* Check first tone */ | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	if ((p1 < i1) || (p1 < i2) || (p1 < e)) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	/* And second */ | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	if ((p2 < i1) || (p2 < i2) || (p2 < e)) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	/* Guess it's there... */ | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __ast_dsp_call_progress(struct ast_dsp *dsp, short *s, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int x; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 	int y; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	int pass; | 
					
						
							| 
									
										
										
										
											2004-11-17 05:55:26 +00:00
										 |  |  | 	int newstate = DSP_TONE_STATE_SILENCE; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	int res = 0; | 
					
						
							| 
									
										
										
										
											2007-01-23 00:11:32 +00:00
										 |  |  | 	while (len) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		/* Take the lesser of the number of samples we need and what we have */ | 
					
						
							|  |  |  | 		pass = len; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		if (pass > dsp->gsamp_size - dsp->gsamps) { | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 			pass = dsp->gsamp_size - dsp->gsamps; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		for (x = 0; x < pass; x++) { | 
					
						
							|  |  |  | 			for (y = 0; y < dsp->freqcount; y++) { | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 				goertzel_sample(&dsp->freqs[y], s[x]); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 			dsp->genergy += s[x] * s[x]; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		s += pass; | 
					
						
							|  |  |  | 		dsp->gsamps += pass; | 
					
						
							|  |  |  | 		len -= pass; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 		if (dsp->gsamps == dsp->gsamp_size) { | 
					
						
							|  |  |  | 			float hz[7]; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			for (y = 0; y < 7; y++) { | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 				hz[y] = goertzel_result(&dsp->freqs[y]); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2007-01-23 00:11:32 +00:00
										 |  |  | 			switch (dsp->progmode) { | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 			case PROG_MODE_NA: | 
					
						
							|  |  |  | 				if (pair_there(hz[HZ_480], hz[HZ_620], hz[HZ_350], hz[HZ_440], dsp->genergy)) { | 
					
						
							| 
									
										
										
										
											2004-11-17 05:55:26 +00:00
										 |  |  | 					newstate = DSP_TONE_STATE_BUSY; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 				} else if (pair_there(hz[HZ_440], hz[HZ_480], hz[HZ_350], hz[HZ_620], dsp->genergy)) { | 
					
						
							| 
									
										
										
										
											2004-11-17 05:55:26 +00:00
										 |  |  | 					newstate = DSP_TONE_STATE_RINGING; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 				} else if (pair_there(hz[HZ_350], hz[HZ_440], hz[HZ_480], hz[HZ_620], dsp->genergy)) { | 
					
						
							| 
									
										
										
										
											2004-11-17 05:55:26 +00:00
										 |  |  | 					newstate = DSP_TONE_STATE_DIALTONE; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 				} else if (hz[HZ_950] > TONE_MIN_THRESH * TONE_THRESH) { | 
					
						
							| 
									
										
										
										
											2004-11-17 05:55:26 +00:00
										 |  |  | 					newstate = DSP_TONE_STATE_SPECIAL1; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 				} else if (hz[HZ_1400] > TONE_MIN_THRESH * TONE_THRESH) { | 
					
						
							| 
									
										
										
										
											2010-05-19 06:41:04 +00:00
										 |  |  | 					/* End of SPECIAL1 or middle of SPECIAL2 */ | 
					
						
							|  |  |  | 					if (dsp->tstate == DSP_TONE_STATE_SPECIAL1 || dsp->tstate == DSP_TONE_STATE_SPECIAL2) { | 
					
						
							| 
									
										
										
										
											2004-11-17 05:55:26 +00:00
										 |  |  | 						newstate = DSP_TONE_STATE_SPECIAL2; | 
					
						
							| 
									
										
										
										
											2010-05-19 06:41:04 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 				} else if (hz[HZ_1800] > TONE_MIN_THRESH * TONE_THRESH) { | 
					
						
							| 
									
										
										
										
											2010-05-19 06:41:04 +00:00
										 |  |  | 					/* End of SPECIAL2 or middle of SPECIAL3 */ | 
					
						
							|  |  |  | 					if (dsp->tstate == DSP_TONE_STATE_SPECIAL2 || dsp->tstate == DSP_TONE_STATE_SPECIAL3) { | 
					
						
							| 
									
										
										
										
											2004-11-17 05:55:26 +00:00
										 |  |  | 						newstate = DSP_TONE_STATE_SPECIAL3; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 				} else if (dsp->genergy > TONE_MIN_THRESH * TONE_THRESH) { | 
					
						
							| 
									
										
										
										
											2004-11-17 05:55:26 +00:00
										 |  |  | 					newstate = DSP_TONE_STATE_TALKING; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2004-11-17 05:55:26 +00:00
										 |  |  | 					newstate = DSP_TONE_STATE_SILENCE; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			case PROG_MODE_CR: | 
					
						
							|  |  |  | 				if (hz[HZ_425] > TONE_MIN_THRESH * TONE_THRESH) { | 
					
						
							| 
									
										
										
										
											2004-11-17 05:55:26 +00:00
										 |  |  | 					newstate = DSP_TONE_STATE_RINGING; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 				} else if (dsp->genergy > TONE_MIN_THRESH * TONE_THRESH) { | 
					
						
							| 
									
										
										
										
											2004-11-17 05:55:26 +00:00
										 |  |  | 					newstate = DSP_TONE_STATE_TALKING; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2004-11-17 05:55:26 +00:00
										 |  |  | 					newstate = DSP_TONE_STATE_SILENCE; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2005-06-28 14:36:56 +00:00
										 |  |  | 			case PROG_MODE_UK: | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				if (hz[HZ_400UK] > TONE_MIN_THRESH * TONE_THRESH) { | 
					
						
							| 
									
										
										
										
											2005-06-28 14:36:56 +00:00
										 |  |  | 					newstate = DSP_TONE_STATE_HUNGUP; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				} else if (pair_there(hz[HZ_350UK], hz[HZ_440UK], hz[HZ_400UK], hz[HZ_400UK], dsp->genergy)) { | 
					
						
							|  |  |  | 					newstate = DSP_TONE_STATE_DIALTONE; | 
					
						
							| 
									
										
										
										
											2005-06-28 14:36:56 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 			default: | 
					
						
							|  |  |  | 				ast_log(LOG_WARNING, "Can't process in unknown prog mode '%d'\n", dsp->progmode); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 			if (newstate == dsp->tstate) { | 
					
						
							|  |  |  | 				dsp->tcount++; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				if (dsp->ringtimeout) { | 
					
						
							| 
									
										
										
										
											2006-01-17 23:37:22 +00:00
										 |  |  | 					dsp->ringtimeout++; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2006-01-17 23:37:22 +00:00
										 |  |  | 				switch (dsp->tstate) { | 
					
						
							| 
									
										
										
										
											2010-05-19 06:41:04 +00:00
										 |  |  | 				case DSP_TONE_STATE_RINGING: | 
					
						
							|  |  |  | 					if ((dsp->features & DSP_PROGRESS_RINGING) && | 
					
						
							|  |  |  | 					    (dsp->tcount == THRESH_RING)) { | 
					
						
							|  |  |  | 						res = AST_CONTROL_RINGING; | 
					
						
							|  |  |  | 						dsp->ringtimeout = 1; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				case DSP_TONE_STATE_BUSY: | 
					
						
							|  |  |  | 					if ((dsp->features & DSP_PROGRESS_BUSY) && | 
					
						
							|  |  |  | 					    (dsp->tcount == THRESH_BUSY)) { | 
					
						
							|  |  |  | 						res = AST_CONTROL_BUSY; | 
					
						
							|  |  |  | 						dsp->features &= ~DSP_FEATURE_CALL_PROGRESS; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				case DSP_TONE_STATE_TALKING: | 
					
						
							|  |  |  | 					if ((dsp->features & DSP_PROGRESS_TALK) && | 
					
						
							|  |  |  | 					    (dsp->tcount == THRESH_TALK)) { | 
					
						
							|  |  |  | 						res = AST_CONTROL_ANSWER; | 
					
						
							|  |  |  | 						dsp->features &= ~DSP_FEATURE_CALL_PROGRESS; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				case DSP_TONE_STATE_SPECIAL3: | 
					
						
							|  |  |  | 					if ((dsp->features & DSP_PROGRESS_CONGESTION) && | 
					
						
							|  |  |  | 					    (dsp->tcount == THRESH_CONGESTION)) { | 
					
						
							|  |  |  | 						res = AST_CONTROL_CONGESTION; | 
					
						
							|  |  |  | 						dsp->features &= ~DSP_FEATURE_CALL_PROGRESS; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				case DSP_TONE_STATE_HUNGUP: | 
					
						
							|  |  |  | 					if ((dsp->features & DSP_FEATURE_CALL_PROGRESS) && | 
					
						
							|  |  |  | 					    (dsp->tcount == THRESH_HANGUP)) { | 
					
						
							|  |  |  | 						res = AST_CONTROL_HANGUP; | 
					
						
							|  |  |  | 						dsp->features &= ~DSP_FEATURE_CALL_PROGRESS; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2006-01-17 23:37:22 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2010-05-19 06:41:04 +00:00
										 |  |  | 				if (dsp->ringtimeout == THRESH_RING2ANSWER) { | 
					
						
							| 
									
										
										
										
											2007-11-21 18:52:19 +00:00
										 |  |  | 					ast_debug(1, "Consider call as answered because of timeout after last ring\n"); | 
					
						
							| 
									
										
										
										
											2006-01-17 23:37:22 +00:00
										 |  |  | 					res = AST_CONTROL_ANSWER; | 
					
						
							|  |  |  | 					dsp->features &= ~DSP_FEATURE_CALL_PROGRESS; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2007-11-21 18:52:19 +00:00
										 |  |  | 				ast_debug(5, "Stop state %d with duration %d\n", dsp->tstate, dsp->tcount); | 
					
						
							|  |  |  | 				ast_debug(5, "Start state %d\n", newstate); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 				dsp->tstate = newstate; | 
					
						
							|  |  |  | 				dsp->tcount = 1; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2010-05-19 06:41:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			/* Reset goertzel */ | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			for (x = 0; x < 7; x++) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 				dsp->freqs[x].v2 = dsp->freqs[x].v3 = 0.0; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 			dsp->gsamps = 0; | 
					
						
							|  |  |  | 			dsp->genergy = 0.0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-11-21 18:52:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_dsp_call_progress(struct ast_dsp *dsp, struct ast_frame *inf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (inf->frametype != AST_FRAME_VOICE) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Can't check call progress of non-voice frames\n"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 	if (inf->subclass.codec != AST_FORMAT_SLINEAR) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Can only check call progress in signed-linear frames\n"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-05-22 16:29:54 +00:00
										 |  |  | 	return __ast_dsp_call_progress(dsp, inf->data.ptr, inf->datalen / 2); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | static int __ast_dsp_silence_noise(struct ast_dsp *dsp, short *s, int len, int *totalsilence, int *totalnoise) | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	int accum; | 
					
						
							|  |  |  | 	int x; | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							| 
									
										
										
										
											2004-08-19 18:52:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	if (!len) { | 
					
						
							| 
									
										
										
										
											2004-08-19 18:52:56 +00:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	accum = 0; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	for (x = 0; x < len; x++) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		accum += abs(s[x]); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 	accum /= len; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	if (accum < dsp->threshold) { | 
					
						
							| 
									
										
										
										
											2005-08-08 00:08:48 +00:00
										 |  |  | 		/* Silent */ | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		dsp->totalsilence += len / 8; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		if (dsp->totalnoise) { | 
					
						
							|  |  |  | 			/* Move and save history */ | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			memmove(dsp->historicnoise + DSP_HISTORY - dsp->busycount, dsp->historicnoise + DSP_HISTORY - dsp->busycount + 1, dsp->busycount * sizeof(dsp->historicnoise[0])); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 			dsp->historicnoise[DSP_HISTORY - 1] = dsp->totalnoise; | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | /* we don't want to check for busydetect that frequently */ | 
					
						
							|  |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 			dsp->busymaybe = 1; | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		dsp->totalnoise = 0; | 
					
						
							|  |  |  | 		res = 1; | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2005-08-08 00:08:48 +00:00
										 |  |  | 		/* Not silent */ | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		dsp->totalnoise += len / 8; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		if (dsp->totalsilence) { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 			int silence1 = dsp->historicsilence[DSP_HISTORY - 1]; | 
					
						
							|  |  |  | 			int silence2 = dsp->historicsilence[DSP_HISTORY - 2]; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 			/* Move and save history */ | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			memmove(dsp->historicsilence + DSP_HISTORY - dsp->busycount, dsp->historicsilence + DSP_HISTORY - dsp->busycount + 1, dsp->busycount * sizeof(dsp->historicsilence[0])); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 			dsp->historicsilence[DSP_HISTORY - 1] = dsp->totalsilence; | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 			/* check if the previous sample differs only by BUSY_PERCENT from the one before it */ | 
					
						
							|  |  |  | 			if (silence1 < silence2) { | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				if (silence1 + silence1 * BUSY_PERCENT / 100 >= silence2) { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 					dsp->busymaybe = 1; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 					dsp->busymaybe = 0; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				if (silence1 - silence1 * BUSY_PERCENT / 100 <= silence2) { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 					dsp->busymaybe = 1; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 					dsp->busymaybe = 0; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		dsp->totalsilence = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	if (totalsilence) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		*totalsilence = dsp->totalsilence; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (totalnoise) { | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 		*totalnoise = dsp->totalnoise; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2005-08-08 00:08:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | int ast_dsp_busydetect(struct ast_dsp *dsp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int res = 0, x; | 
					
						
							|  |  |  | #ifndef BUSYDETECT_TONEONLY
 | 
					
						
							|  |  |  | 	int avgsilence = 0, hitsilence = 0; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	int avgtone = 0, hittone = 0; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	if (!dsp->busymaybe) { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 		return res; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for (x = DSP_HISTORY - dsp->busycount; x < DSP_HISTORY; x++) { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | #ifndef BUSYDETECT_TONEONLY
 | 
					
						
							|  |  |  | 		avgsilence += dsp->historicsilence[x]; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 		avgtone += dsp->historicnoise[x]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #ifndef BUSYDETECT_TONEONLY
 | 
					
						
							|  |  |  | 	avgsilence /= dsp->busycount; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	avgtone /= dsp->busycount; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	for (x = DSP_HISTORY - dsp->busycount; x < DSP_HISTORY; x++) { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | #ifndef BUSYDETECT_TONEONLY
 | 
					
						
							|  |  |  | 		if (avgsilence > dsp->historicsilence[x]) { | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			if (avgsilence - (avgsilence * BUSY_PERCENT / 100) <= dsp->historicsilence[x]) { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 				hitsilence++; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			if (avgsilence + (avgsilence * BUSY_PERCENT / 100) >= dsp->historicsilence[x]) { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 				hitsilence++; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 		if (avgtone > dsp->historicnoise[x]) { | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			if (avgtone - (avgtone * BUSY_PERCENT / 100) <= dsp->historicnoise[x]) { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 				hittone++; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			if (avgtone + (avgtone * BUSY_PERCENT / 100) >= dsp->historicnoise[x]) { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 				hittone++; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #ifndef BUSYDETECT_TONEONLY
 | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	if ((hittone >= dsp->busycount - 1) && (hitsilence >= dsp->busycount - 1) &&  | 
					
						
							|  |  |  | 	    (avgtone >= BUSY_MIN && avgtone <= BUSY_MAX) &&  | 
					
						
							|  |  |  | 	    (avgsilence >= BUSY_MIN && avgsilence <= BUSY_MAX)) { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | 	if ((hittone >= dsp->busycount - 1) && (avgtone >= BUSY_MIN && avgtone <= BUSY_MAX)) { | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #ifdef BUSYDETECT_COMPARE_TONE_AND_SILENCE
 | 
					
						
							|  |  |  | 		if (avgtone > avgsilence) { | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			if (avgtone - avgtone*BUSY_PERCENT/100 <= avgsilence) { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 				res = 1; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			if (avgtone + avgtone*BUSY_PERCENT/100 >= avgsilence) { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 				res = 1; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 		res = 1; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-08-08 00:08:48 +00:00
										 |  |  | 	/* If we know the expected busy tone length, check we are in the range */ | 
					
						
							|  |  |  | 	if (res && (dsp->busy_tonelength > 0)) { | 
					
						
							| 
									
										
										
										
											2011-05-16 21:00:55 +00:00
										 |  |  | 		if (abs(avgtone - dsp->busy_tonelength) > MAX(dsp->busy_tonelength*BUSY_PAT_PERCENT/100, 20)) { | 
					
						
							| 
									
										
										
										
											2008-01-17 20:51:26 +00:00
										 |  |  | #ifdef BUSYDETECT_DEBUG
 | 
					
						
							|  |  |  | 			ast_debug(5, "busy detector: avgtone of %d not close enough to desired %d\n", | 
					
						
							|  |  |  | 				avgtone, dsp->busy_tonelength); | 
					
						
							| 
									
										
										
										
											2005-08-08 00:08:48 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 			res = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-07-03 03:24:58 +00:00
										 |  |  | #ifndef BUSYDETECT_TONEONLY
 | 
					
						
							| 
									
										
										
										
											2005-08-08 00:08:48 +00:00
										 |  |  | 	/* If we know the expected busy tone silent-period length, check we are in the range */ | 
					
						
							|  |  |  | 	if (res && (dsp->busy_quietlength > 0)) { | 
					
						
							| 
									
										
										
										
											2011-05-16 21:00:55 +00:00
										 |  |  | 		if (abs(avgsilence - dsp->busy_quietlength) > MAX(dsp->busy_quietlength*BUSY_PAT_PERCENT/100, 20)) { | 
					
						
							| 
									
										
										
										
											2008-01-17 20:51:26 +00:00
										 |  |  | #ifdef BUSYDETECT_DEBUG
 | 
					
						
							|  |  |  | 		ast_debug(5, "busy detector: avgsilence of %d not close enough to desired %d\n", | 
					
						
							|  |  |  | 			avgsilence, dsp->busy_quietlength); | 
					
						
							| 
									
										
										
										
											2005-08-08 00:08:48 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 			res = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-07-03 03:24:58 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-01-17 20:51:26 +00:00
										 |  |  | #if !defined(BUSYDETECT_TONEONLY) && defined(BUSYDETECT_DEBUG)
 | 
					
						
							| 
									
										
										
										
											2006-10-03 15:53:07 +00:00
										 |  |  | 	if (res) { | 
					
						
							| 
									
										
										
										
											2008-01-17 20:51:26 +00:00
										 |  |  | 		ast_debug(5, "ast_dsp_busydetect detected busy, avgtone: %d, avgsilence %d\n", avgtone, avgsilence); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ast_debug(5, "busy detector: FAILED with avgtone: %d, avgsilence %d\n", avgtone, avgsilence); | 
					
						
							| 
									
										
										
										
											2006-10-03 15:53:07 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	short *s; | 
					
						
							|  |  |  | 	int len; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if (f->frametype != AST_FRAME_VOICE) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Can't calculate silence on a non-voice frame\n"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 	if (f->subclass.codec != AST_FORMAT_SLINEAR) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Can only calculate silence on signed-linear frames :(\n"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-05-22 16:29:54 +00:00
										 |  |  | 	s = f->data.ptr; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	len = f->datalen/2; | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 	return __ast_dsp_silence_noise(dsp, s, len, totalsilence, NULL); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | int ast_dsp_noise(struct ast_dsp *dsp, struct ast_frame *f, int *totalnoise) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |        short *s; | 
					
						
							|  |  |  |        int len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        if (f->frametype != AST_FRAME_VOICE) { | 
					
						
							|  |  |  |                ast_log(LOG_WARNING, "Can't calculate noise on a non-voice frame\n"); | 
					
						
							|  |  |  |                return 0; | 
					
						
							|  |  |  |        } | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  |        if (f->subclass.codec != AST_FORMAT_SLINEAR) { | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  |                ast_log(LOG_WARNING, "Can only calculate noise on signed-linear frames :(\n"); | 
					
						
							|  |  |  |                return 0; | 
					
						
							|  |  |  |        } | 
					
						
							| 
									
										
										
										
											2008-05-22 16:29:54 +00:00
										 |  |  |        s = f->data.ptr; | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  |        len = f->datalen/2; | 
					
						
							|  |  |  |        return __ast_dsp_silence_noise(dsp, s, len, NULL, totalnoise); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-04-06 22:17:32 +00:00
										 |  |  | struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, struct ast_frame *af) | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	int silence; | 
					
						
							|  |  |  | 	int res; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	int digit = 0, fax_digit = 0; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	int x; | 
					
						
							| 
									
										
										
										
											2005-05-15 03:21:51 +00:00
										 |  |  | 	short *shortdata; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	unsigned char *odata; | 
					
						
							|  |  |  | 	int len; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	struct ast_frame *outf = NULL; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	if (!af) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (af->frametype != AST_FRAME_VOICE) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		return af; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-22 16:29:54 +00:00
										 |  |  | 	odata = af->data.ptr; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	len = af->datalen; | 
					
						
							|  |  |  | 	/* Make sure we have short data */ | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 	switch (af->subclass.codec) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	case AST_FORMAT_SLINEAR: | 
					
						
							| 
									
										
										
										
											2008-05-22 16:29:54 +00:00
										 |  |  | 		shortdata = af->data.ptr; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		len = af->datalen / 2; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case AST_FORMAT_ULAW: | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 	case AST_FORMAT_TESTLAW: | 
					
						
							| 
									
										
										
										
											2006-05-10 13:22:15 +00:00
										 |  |  | 		shortdata = alloca(af->datalen * 2); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		for (x = 0;x < len; x++) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 			shortdata[x] = AST_MULAW(odata[x]); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case AST_FORMAT_ALAW: | 
					
						
							| 
									
										
										
										
											2006-05-10 13:22:15 +00:00
										 |  |  | 		shortdata = alloca(af->datalen * 2); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		for (x = 0; x < len; x++) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 			shortdata[x] = AST_ALAW(odata[x]); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2009-12-04 15:38:33 +00:00
										 |  |  | 		/*Display warning only once. Otherwise you would get hundreds of warnings every second */ | 
					
						
							|  |  |  | 		if (dsp->display_inband_dtmf_warning) | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(af->subclass.codec)); | 
					
						
							|  |  |  | 		dsp->display_inband_dtmf_warning = 0; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		return af; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Initially we do not want to mute anything */ | 
					
						
							|  |  |  | 	dsp->mute_fragments = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:16:31 +00:00
										 |  |  | 	/* Need to run the silence detection stuff for silence suppression and busy detection */ | 
					
						
							|  |  |  | 	if ((dsp->features & DSP_FEATURE_SILENCE_SUPPRESS) || (dsp->features & DSP_FEATURE_BUSY_DETECT)) { | 
					
						
							|  |  |  | 		res = __ast_dsp_silence_noise(dsp, shortdata, len, &silence, NULL); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	if ((dsp->features & DSP_FEATURE_SILENCE_SUPPRESS) && silence) { | 
					
						
							|  |  |  | 		memset(&dsp->f, 0, sizeof(dsp->f)); | 
					
						
							|  |  |  | 		dsp->f.frametype = AST_FRAME_NULL; | 
					
						
							| 
									
										
										
										
											2007-12-07 23:32:09 +00:00
										 |  |  | 		ast_frfree(af); | 
					
						
							| 
									
										
										
										
											2009-10-21 03:09:04 +00:00
										 |  |  | 		return ast_frisolate(&dsp->f); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if ((dsp->features & DSP_FEATURE_BUSY_DETECT) && ast_dsp_busydetect(dsp)) { | 
					
						
							| 
									
										
										
										
											2003-07-08 21:14:59 +00:00
										 |  |  | 		chan->_softhangup |= AST_SOFTHANGUP_DEV; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		memset(&dsp->f, 0, sizeof(dsp->f)); | 
					
						
							|  |  |  | 		dsp->f.frametype = AST_FRAME_CONTROL; | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 		dsp->f.subclass.integer = AST_CONTROL_BUSY; | 
					
						
							| 
									
										
										
										
											2007-12-07 23:32:09 +00:00
										 |  |  | 		ast_frfree(af); | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 		ast_debug(1, "Requesting Hangup because the busy tone was detected on channel %s\n", chan->name); | 
					
						
							| 
									
										
										
										
											2009-10-21 03:09:04 +00:00
										 |  |  | 		return ast_frisolate(&dsp->f); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if ((dsp->features & DSP_FEATURE_FAX_DETECT)) { | 
					
						
							|  |  |  | 		if ((dsp->faxmode & DSP_FAXMODE_DETECT_CNG) && tone_detect(dsp, &dsp->cng_tone_state, shortdata, len)) { | 
					
						
							|  |  |  | 			fax_digit = 'f'; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ((dsp->faxmode & DSP_FAXMODE_DETECT_CED) && tone_detect(dsp, &dsp->ced_tone_state, shortdata, len)) { | 
					
						
							|  |  |  | 			fax_digit = 'e'; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-20 08:22:35 +00:00
										 |  |  | 	if (dsp->features & (DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_BUSY_DETECT)) { | 
					
						
							|  |  |  | 		if (dsp->digitmode & DSP_DIGITMODE_MF) | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 			digit = mf_detect(dsp, &dsp->digit_state, shortdata, len, (dsp->digitmode & DSP_DIGITMODE_NOQUELCH) == 0, (dsp->digitmode & DSP_DIGITMODE_RELAXDTMF)); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			digit = dtmf_detect(dsp, &dsp->digit_state, shortdata, len, (dsp->digitmode & DSP_DIGITMODE_NOQUELCH) == 0, (dsp->digitmode & DSP_DIGITMODE_RELAXDTMF)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (dsp->digit_state.current_digits) { | 
					
						
							| 
									
										
										
										
											2010-05-19 16:42:20 +00:00
										 |  |  | 			int event = 0, event_len = 0; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 			char event_digit = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (!dsp->dtmf_began) { | 
					
						
							|  |  |  | 				/* We have not reported DTMF_BEGIN for anything yet */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-20 08:22:35 +00:00
										 |  |  | 				if (dsp->features & DSP_FEATURE_DIGIT_DETECT) { | 
					
						
							|  |  |  | 					event = AST_FRAME_DTMF_BEGIN; | 
					
						
							|  |  |  | 					event_digit = dsp->digit_state.digits[0]; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 				dsp->dtmf_began = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} else if (dsp->digit_state.current_digits > 1 || digit != dsp->digit_state.digits[0]) { | 
					
						
							|  |  |  | 				/* Digit changed. This means digit we have reported with DTMF_BEGIN ended */ | 
					
						
							| 
									
										
										
										
											2009-12-20 08:22:35 +00:00
										 |  |  | 				if (dsp->features & DSP_FEATURE_DIGIT_DETECT) { | 
					
						
							|  |  |  | 					event = AST_FRAME_DTMF_END; | 
					
						
							|  |  |  | 					event_digit = dsp->digit_state.digits[0]; | 
					
						
							| 
									
										
										
										
											2010-05-19 16:42:20 +00:00
										 |  |  | 					event_len = dsp->digit_state.digitlen[0] * 1000 / SAMPLE_RATE; | 
					
						
							| 
									
										
										
										
											2009-12-20 08:22:35 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2010-05-19 16:42:20 +00:00
										 |  |  | 				memmove(&dsp->digit_state.digits[0], &dsp->digit_state.digits[1], dsp->digit_state.current_digits); | 
					
						
							| 
									
										
										
										
											2010-06-05 17:55:28 +00:00
										 |  |  | 				memmove(&dsp->digit_state.digitlen[0], &dsp->digit_state.digitlen[1], dsp->digit_state.current_digits * sizeof(dsp->digit_state.digitlen[0])); | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 				dsp->digit_state.current_digits--; | 
					
						
							|  |  |  | 				dsp->dtmf_began = 0; | 
					
						
							| 
									
										
										
										
											2009-12-15 03:04:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if (dsp->features & DSP_FEATURE_BUSY_DETECT) { | 
					
						
							|  |  |  | 					/* Reset Busy Detector as we have some confirmed activity */  | 
					
						
							| 
									
										
										
										
											2009-12-15 03:26:49 +00:00
										 |  |  | 					memset(dsp->historicsilence, 0, sizeof(dsp->historicsilence)); | 
					
						
							| 
									
										
										
										
											2009-12-15 03:04:59 +00:00
										 |  |  | 					memset(dsp->historicnoise, 0, sizeof(dsp->historicnoise)); | 
					
						
							| 
									
										
										
										
											2009-12-20 08:22:35 +00:00
										 |  |  | 					ast_debug(1, "DTMF Detected - Reset busydetector\n"); | 
					
						
							| 
									
										
										
										
											2009-12-15 03:04:59 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (event) { | 
					
						
							|  |  |  | 				memset(&dsp->f, 0, sizeof(dsp->f)); | 
					
						
							|  |  |  | 				dsp->f.frametype = event; | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 				dsp->f.subclass.integer = event_digit; | 
					
						
							| 
									
										
										
										
											2010-05-19 16:42:20 +00:00
										 |  |  | 				dsp->f.len = event_len; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 				outf = &dsp->f; | 
					
						
							|  |  |  | 				goto done; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (fax_digit) { | 
					
						
							|  |  |  | 		/* Fax was detected - digit is either 'f' or 'e' */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		memset(&dsp->f, 0, sizeof(dsp->f)); | 
					
						
							|  |  |  | 		dsp->f.frametype = AST_FRAME_DTMF; | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 		dsp->f.subclass.integer = fax_digit; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		outf = &dsp->f; | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	if ((dsp->features & DSP_FEATURE_CALL_PROGRESS)) { | 
					
						
							|  |  |  | 		res = __ast_dsp_call_progress(dsp, shortdata, len); | 
					
						
							|  |  |  | 		if (res) { | 
					
						
							| 
									
										
										
										
											2007-01-23 00:11:32 +00:00
										 |  |  | 			switch (res) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 			case AST_CONTROL_ANSWER: | 
					
						
							|  |  |  | 			case AST_CONTROL_BUSY: | 
					
						
							|  |  |  | 			case AST_CONTROL_RINGING: | 
					
						
							|  |  |  | 			case AST_CONTROL_CONGESTION: | 
					
						
							| 
									
										
										
										
											2005-06-28 14:36:56 +00:00
										 |  |  | 			case AST_CONTROL_HANGUP: | 
					
						
							| 
									
										
										
										
											2004-11-15 00:48:36 +00:00
										 |  |  | 				memset(&dsp->f, 0, sizeof(dsp->f)); | 
					
						
							|  |  |  | 				dsp->f.frametype = AST_FRAME_CONTROL; | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 				dsp->f.subclass.integer = res; | 
					
						
							| 
									
										
										
										
											2004-11-15 00:48:36 +00:00
										 |  |  | 				dsp->f.src = "dsp_progress"; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 				if (chan)  | 
					
						
							| 
									
										
										
										
											2004-04-06 22:17:32 +00:00
										 |  |  | 					ast_queue_frame(chan, &dsp->f); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				ast_log(LOG_WARNING, "Don't know how to represent call progress message %d\n", res); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} else if ((dsp->features & DSP_FEATURE_WAITDIALTONE)) { | 
					
						
							|  |  |  | 		res = __ast_dsp_call_progress(dsp, shortdata, len); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | done: | 
					
						
							|  |  |  | 	/* Mute fragment of the frame */ | 
					
						
							|  |  |  | 	for (x = 0; x < dsp->mute_fragments; x++) { | 
					
						
							|  |  |  | 		memset(shortdata + dsp->mute_data[x].start, 0, sizeof(int16_t) * (dsp->mute_data[x].end - dsp->mute_data[x].start)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-04 14:05:12 +00:00
										 |  |  | 	switch (af->subclass.codec) { | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	case AST_FORMAT_SLINEAR: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case AST_FORMAT_ULAW: | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		for (x = 0; x < len; x++) { | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 			odata[x] = AST_LIN2MU((unsigned short) shortdata[x]); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case AST_FORMAT_ALAW: | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		for (x = 0; x < len; x++) { | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 			odata[x] = AST_LIN2A((unsigned short) shortdata[x]); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (outf) { | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		if (chan) { | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 			ast_queue_frame(chan, af); | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		ast_frfree(af); | 
					
						
							| 
									
										
										
										
											2009-10-21 03:09:04 +00:00
										 |  |  | 		return ast_frisolate(outf); | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		return af; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | static void ast_dsp_prog_reset(struct ast_dsp *dsp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int max = 0; | 
					
						
							|  |  |  | 	int x; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 	dsp->gsamp_size = modes[dsp->progmode].size; | 
					
						
							|  |  |  | 	dsp->gsamps = 0; | 
					
						
							| 
									
										
										
										
											2008-07-11 18:09:35 +00:00
										 |  |  | 	for (x = 0; x < ARRAY_LEN(modes[dsp->progmode].freqs); x++) { | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 		if (modes[dsp->progmode].freqs[x]) { | 
					
						
							|  |  |  | 			goertzel_init(&dsp->freqs[x], (float)modes[dsp->progmode].freqs[x], dsp->gsamp_size); | 
					
						
							| 
									
										
										
										
											2004-11-10 20:20:18 +00:00
										 |  |  | 			max = x + 1; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dsp->freqcount = max; | 
					
						
							| 
									
										
										
										
											2006-01-17 23:37:22 +00:00
										 |  |  | 	dsp->ringtimeout= 0; | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | struct ast_dsp *ast_dsp_new(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_dsp *dsp; | 
					
						
							| 
									
										
										
										
											2006-02-09 02:08:04 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	if ((dsp = ast_calloc(1, sizeof(*dsp)))) {		 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		dsp->threshold = DEFAULT_THRESHOLD; | 
					
						
							|  |  |  | 		dsp->features = DSP_FEATURE_SILENCE_SUPPRESS; | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 		dsp->busycount = DSP_HISTORY; | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		dsp->digitmode = DSP_DIGITMODE_DTMF; | 
					
						
							|  |  |  | 		dsp->faxmode = DSP_FAXMODE_DETECT_CNG; | 
					
						
							|  |  |  | 		/* Initialize digit detector */ | 
					
						
							|  |  |  | 		ast_digit_detect_init(&dsp->digit_state, dsp->digitmode & DSP_DIGITMODE_MF); | 
					
						
							| 
									
										
										
										
											2009-12-04 15:38:33 +00:00
										 |  |  | 		dsp->display_inband_dtmf_warning = 1; | 
					
						
							| 
									
										
										
										
											2004-04-28 14:55:38 +00:00
										 |  |  | 		/* Initialize initial DSP progress detect parameters */ | 
					
						
							|  |  |  | 		ast_dsp_prog_reset(dsp); | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		/* Initialize fax detector */ | 
					
						
							|  |  |  | 		ast_fax_detect_init(dsp); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return dsp; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_dsp_set_features(struct ast_dsp *dsp, int features) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	dsp->features = features; | 
					
						
							| 
									
										
										
										
											2011-05-05 22:11:19 +00:00
										 |  |  | 	if (!(features & DSP_FEATURE_DIGIT_DETECT)) { | 
					
						
							|  |  |  | 		dsp->display_inband_dtmf_warning = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_dsp_free(struct ast_dsp *dsp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 	ast_free(dsp); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-28 05:07:52 +00:00
										 |  |  | void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	dsp->threshold = threshold; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | void ast_dsp_set_busy_count(struct ast_dsp *dsp, int cadences) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	if (cadences < 4) { | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 		cadences = 4; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (cadences > DSP_HISTORY) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		cadences = DSP_HISTORY; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	dsp->busycount = cadences; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-08 00:08:48 +00:00
										 |  |  | void ast_dsp_set_busy_pattern(struct ast_dsp *dsp, int tonelength, int quietlength) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	dsp->busy_tonelength = tonelength; | 
					
						
							|  |  |  | 	dsp->busy_quietlength = quietlength; | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 	ast_debug(1, "dsp busy pattern set to %d,%d\n", tonelength, quietlength); | 
					
						
							| 
									
										
										
										
											2005-08-08 00:08:48 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | void ast_dsp_digitreset(struct ast_dsp *dsp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 	dsp->dtmf_began = 0; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	if (dsp->digitmode & DSP_DIGITMODE_MF) { | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		mf_detect_state_t *s = &dsp->digit_state.td.mf; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		/* Reinitialise the detector for the next block */ | 
					
						
							|  |  |  | 		for (i = 0;  i < 6;  i++) { | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 			goertzel_reset(&s->tone_out[i]); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		s->hits[4] = s->hits[3] = s->hits[2] = s->hits[1] = s->hits[0] = s->current_hit = 0; | 
					
						
							|  |  |  | 		s->current_sample = 0; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		dtmf_detect_state_t *s = &dsp->digit_state.td.dtmf; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		/* Reinitialise the detector for the next block */ | 
					
						
							|  |  |  | 		for (i = 0;  i < 4;  i++) { | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 			goertzel_reset(&s->row_out[i]); | 
					
						
							|  |  |  | 			goertzel_reset(&s->col_out[i]); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		s->lasthit = s->current_hit = 0; | 
					
						
							|  |  |  | 		s->energy = 0.0; | 
					
						
							|  |  |  | 		s->current_sample = 0; | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | 		s->hits = 0; | 
					
						
							|  |  |  | 		s->misses = 0; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dsp->digit_state.digits[0] = '\0'; | 
					
						
							|  |  |  | 	dsp->digit_state.current_digits = 0; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_dsp_reset(struct ast_dsp *dsp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int x; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	dsp->totalsilence = 0; | 
					
						
							|  |  |  | 	dsp->gsamps = 0; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	for (x = 0; x < 4; x++) { | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 		dsp->freqs[x].v2 = dsp->freqs[x].v3 = 0.0; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	memset(dsp->historicsilence, 0, sizeof(dsp->historicsilence)); | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	memset(dsp->historicnoise, 0, sizeof(dsp->historicnoise));	 | 
					
						
							| 
									
										
										
										
											2006-01-17 23:37:22 +00:00
										 |  |  | 	dsp->ringtimeout= 0; | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-19 21:56:15 +00:00
										 |  |  | int ast_dsp_set_digitmode(struct ast_dsp *dsp, int digitmode) | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	int new; | 
					
						
							|  |  |  | 	int old; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	old = dsp->digitmode & (DSP_DIGITMODE_DTMF | DSP_DIGITMODE_MF | DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX); | 
					
						
							|  |  |  | 	new = digitmode & (DSP_DIGITMODE_DTMF | DSP_DIGITMODE_MF | DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX); | 
					
						
							|  |  |  | 	if (old != new) { | 
					
						
							|  |  |  | 		/* Must initialize structures if switching from MF to DTMF or vice-versa */ | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | 		ast_digit_detect_init(&dsp->digit_state, new & DSP_DIGITMODE_MF); | 
					
						
							| 
									
										
										
										
											2003-02-04 15:48:42 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	dsp->digitmode = digitmode; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2003-06-17 21:53:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-20 21:36:46 +00:00
										 |  |  | int ast_dsp_set_faxmode(struct ast_dsp *dsp, int faxmode) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (dsp->faxmode != faxmode) { | 
					
						
							|  |  |  | 		ast_fax_detect_init(dsp); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dsp->faxmode = faxmode; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | int ast_dsp_set_call_progress_zone(struct ast_dsp *dsp, char *zone) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int x; | 
					
						
							| 
									
										
										
										
											2005-01-03 01:21:15 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2007-06-06 19:35:49 +00:00
										 |  |  | 	for (x = 0; x < ARRAY_LEN(aliases); x++) { | 
					
						
							| 
									
										
										
										
											2004-03-28 02:53:04 +00:00
										 |  |  | 		if (!strcasecmp(aliases[x].name, zone)) { | 
					
						
							|  |  |  | 			dsp->progmode = aliases[x].mode; | 
					
						
							|  |  |  | 			ast_dsp_prog_reset(dsp); | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2004-11-17 05:55:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 19:05:51 +00:00
										 |  |  | int ast_dsp_was_muted(struct ast_dsp *dsp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (dsp->mute_fragments > 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-11-17 05:55:26 +00:00
										 |  |  | int ast_dsp_get_tstate(struct ast_dsp *dsp)  | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return dsp->tstate; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_dsp_get_tcount(struct ast_dsp *dsp)  | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return dsp->tcount; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static int _dsp_init(int reload) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; | 
					
						
							|  |  |  | 	struct ast_config *cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 18:39:06 +00:00
										 |  |  | 	cfg = ast_config_load2(CONFIG_FILE_NAME, "dsp", config_flags); | 
					
						
							| 
									
										
										
										
											2010-06-07 17:34:45 +00:00
										 |  |  | 	if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) { | 
					
						
							|  |  |  | 		ast_verb(5, "Can't find dsp config file %s. Assuming default silencethreshold of %d.\n", CONFIG_FILE_NAME, DEFAULT_SILENCE_THRESHOLD); | 
					
						
							|  |  |  | 		thresholds[THRESHOLD_SILENCE] = DEFAULT_SILENCE_THRESHOLD; | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cfg == CONFIG_STATUS_FILEUNCHANGED) { | 
					
						
							| 
									
										
										
										
											2008-09-12 23:30:03 +00:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-07 17:34:45 +00:00
										 |  |  | 	if (cfg) { | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 		const char *value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		value = ast_variable_retrieve(cfg, "default", "silencethreshold"); | 
					
						
							| 
									
										
										
										
											2009-08-10 19:20:57 +00:00
										 |  |  | 		if (value && sscanf(value, "%30d", &thresholds[THRESHOLD_SILENCE]) != 1) { | 
					
						
							| 
									
										
										
										
											2010-06-07 17:34:45 +00:00
										 |  |  | 			ast_verb(5, "%s: '%s' is not a valid silencethreshold value\n", CONFIG_FILE_NAME, value); | 
					
						
							|  |  |  | 			thresholds[THRESHOLD_SILENCE] = DEFAULT_SILENCE_THRESHOLD; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		} else if (!value) { | 
					
						
							| 
									
										
										
										
											2010-06-07 17:34:45 +00:00
										 |  |  | 			thresholds[THRESHOLD_SILENCE] = DEFAULT_SILENCE_THRESHOLD; | 
					
						
							| 
									
										
										
										
											2008-11-25 22:45:59 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		ast_config_destroy(cfg); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_dsp_get_threshold_from_settings(enum threshold which) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return thresholds[which]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_dsp_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return _dsp_init(0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_dsp_reload(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return _dsp_init(1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |