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
*/
2012-10-18 14:17:40 +00:00
/*! \li \ref dsp.c uses the configuration file \ref dsp.conf
* \ addtogroup configuration_file Configuration Files
*/
/*!
* \ page dsp . conf dsp . conf
* \ verbinclude dsp . conf . sample
*/
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
*/
2012-06-15 16:20:16 +00:00
/*** MODULEINFO
< support_level > core < / support_level >
* * */
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 */
2011-09-13 18:11:33 +00:00
GSAMP_SIZE_UK = 160 /*!< UK disconnect goertzel feed - should trigger 400hz */
2006-02-09 02:08:04 +00:00
} ;
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
2011-09-13 18:11:33 +00:00
enum freq_index {
2006-02-09 02:08:04 +00:00
/*! 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 */
2011-09-13 18:11:33 +00:00
{ GSAMP_SIZE_CR , { 425 } } , /*!< Costa Rica, Brazil */
{ 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 {
2011-09-13 18:11:33 +00:00
BUSY_PERCENT = 10 , /*!< The percentage difference between the two last silence periods */
2006-02-09 02:08:04 +00:00
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 */
2011-09-13 18:11:33 +00:00
BUSY_MIN = 75 , /*!< Busy must be at least 80 ms in half-cadence */
2012-09-21 09:11:39 +00:00
BUSY_MAX = 3100 /*!< Busy can't be longer than 3100 ms in half-cadence */
2006-02-09 02:08:04 +00:00
} ;
2003-02-04 15:48:42 +00:00
2006-02-09 02:08:04 +00:00
/*! Remember last 15 units */
2011-09-13 18:11:33 +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 */
2011-09-13 18:11:33 +00:00
# define TONE_MIN_THRESH 1e8 /*!< How much tone there should be at least to attempt */
2006-02-09 02:08:04 +00:00
/*! All THRESH_XXX values are in GSAMP_SIZE chunks (us = 22ms) */
enum gsamp_thresh {
2011-09-13 18:11:33 +00:00
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 */
2006-02-09 02:08:04 +00:00
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
2012-10-04 04:50:16 +00:00
/* Basic DTMF (AT&T) specs:
2003-02-04 15:48:42 +00:00
*
* Minimum tone on = 40 ms
* Minimum tone off = 50 ms
* Maximum digit rate = 10 per second
* Normal twist < = 8 dB accepted
* Reverse twist < = 4 dB accepted
* S / N > = 15 dB will detect OK
* Attenuation < = 26 dB 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 */
2012-10-04 04:50:16 +00:00
# define DEF_DTMF_NORMAL_TWIST 6.31 /* 8.0dB */
# define DEF_RELAX_DTMF_NORMAL_TWIST 6.31 /* 8.0dB */
2004-05-31 16:04:10 +00:00
# ifdef RADIO_RELAX
2012-10-04 04:50:16 +00:00
# define DEF_DTMF_REVERSE_TWIST 2.51 /* 4.01dB */
# define DEF_RELAX_DTMF_REVERSE_TWIST 6.61 /* 8.2dB */
2004-05-31 16:04:10 +00:00
# else
2012-10-04 04:50:16 +00:00
# define DEF_DTMF_REVERSE_TWIST 2.51 /* 4.01dB */
# define DEF_RELAX_DTMF_REVERSE_TWIST 3.98 /* 6.0dB */
2004-05-31 16:04:10 +00:00
# endif
2012-10-04 04:50:16 +00:00
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
2011-04-21 18:11:40 +00:00
# define DEFAULT_SAMPLE_RATE 8000
2008-02-20 21:36:46 +00:00
2008-03-26 19:05:51 +00:00
/* MF goertzel size */
# define MF_GSIZE 120
/* DTMF goertzel size */
# define DTMF_GSIZE 102
2012-10-04 20:21:36 +00:00
/* How many successive hits needed to consider begin of a digit
* IE . Override with dtmf_hits_to_begin = 4 in dsp . conf
*/
# define DEF_DTMF_HITS_TO_BEGIN 2
/* How many successive misses needed to consider end of a digit
* IE . Override with dtmf_misses_to_end = 4 in dsp . conf
*/
# define DEF_DTMF_MISSES_TO_END 3
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-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 ; /* 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 ] ;
2012-10-04 04:50:16 +00:00
static float dtmf_normal_twist ; /* AT&T = 8dB */
static float dtmf_reverse_twist ; /* AT&T = 4dB */
static float relax_dtmf_normal_twist ; /* AT&T = 8dB */
static float relax_dtmf_reverse_twist ; /* AT&T = 6dB */
2012-10-04 20:21:36 +00:00
static int dtmf_hits_to_begin ; /* How many successive hits needed to consider begin of a digit */
static int dtmf_misses_to_end ; /* How many successive misses needed to consider end of a digit */
2008-03-05 16:23:44 +00:00
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 ;
2011-09-13 18:11:33 +00:00
2003-02-04 15:48:42 +00:00
v1 = s - > v2 ;
s - > v2 = s - > v3 ;
2011-09-13 18:11:33 +00:00
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 ;
}
2003-02-04 15:48:42 +00:00
}
static inline void goertzel_update ( goertzel_state_t * s , short * samps , int count )
{
int i ;
2011-09-13 18:11:33 +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
}
2012-09-05 18:56:39 +00:00
static inline void goertzel_init ( goertzel_state_t * s , float freq , unsigned int sample_rate )
2003-02-04 15:48:42 +00:00
{
2007-05-29 19:00:40 +00:00
s - > v2 = s - > v3 = s - > chunky = 0.0 ;
2011-04-21 18:11:40 +00:00
s - > fac = ( int ) ( 32768.0 * 2.0 * cos ( 2.0 * M_PI * freq / sample_rate ) ) ;
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)
2012-09-05 07:43:32 +00:00
* report fragments of the frame in which detected tone resides and which needs
2008-03-26 19:05:51 +00:00
* 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 ;
2011-04-01 17:01:01 +00:00
struct ast_dsp_busy_pattern busy_cadence ;
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 ;
2011-04-21 18:11:40 +00:00
unsigned int sample_rate ;
2008-03-26 19:05:51 +00:00
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 ;
}
2011-04-21 18:11:40 +00:00
static void ast_tone_detect_init ( tone_detect_state_t * s , int freq , int duration , int amp , unsigned int sample_rate )
2008-02-20 21:36:46 +00:00
{
int duration_samples ;
float x ;
int periods_in_block ;
s - > freq = freq ;
/* Desired tone duration in samples */
2011-04-21 18:11:40 +00:00
duration_samples = duration * sample_rate / 1000 ;
2008-02-20 21:36:46 +00:00
/* 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
2011-09-13 18:11:33 +00:00
to squelch it from previous frames . Block size is 20 ms at the given sample rate . */
2011-04-21 18:11:40 +00:00
s - > block_size = ( 20 * sample_rate ) / 1000 ;
2008-02-20 21:36:46 +00:00
2011-04-21 18:11:40 +00:00
periods_in_block = s - > block_size * freq / sample_rate ;
2008-02-20 21:36:46 +00:00
/* 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 */
2011-09-13 18:11:33 +00:00
if ( periods_in_block < 5 ) {
2008-02-20 21:36:46 +00:00
periods_in_block = 5 ;
2011-09-13 18:11:33 +00:00
}
2008-02-20 21:36:46 +00:00
/* Now calculate final block size. It will contain integer number of periods */
2011-04-21 18:11:40 +00:00
s - > block_size = periods_in_block * sample_rate / freq ;
2008-02-20 21:36:46 +00:00
/* tone_detect is currently only used to detect fax tones and we
2012-09-05 07:43:32 +00:00
do not need squelching the fax tones */
2008-02-20 21:36:46 +00:00
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 ;
2012-09-05 18:56:39 +00:00
goertzel_init ( & s - > tone , freq , sample_rate ) ;
2008-02-20 21:36:46 +00:00
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 )
{
2011-04-21 18:11:40 +00:00
ast_tone_detect_init ( & s - > cng_tone_state , FAX_TONE_CNG_FREQ , FAX_TONE_CNG_DURATION , FAX_TONE_CNG_DB , s - > sample_rate ) ;
ast_tone_detect_init ( & s - > ced_tone_state , FAX_TONE_CED_FREQ , FAX_TONE_CED_DURATION , FAX_TONE_CED_DB , s - > sample_rate ) ;
2011-07-25 14:07:01 +00:00
if ( s - > faxmode & DSP_FAXMODE_DETECT_SQUELCH ) {
s - > cng_tone_state . squelch = 1 ;
s - > ced_tone_state . squelch = 1 ;
}
2008-02-20 21:36:46 +00:00
}
2012-09-20 10:41:30 +00:00
static void ast_dtmf_detect_init ( dtmf_detect_state_t * s , unsigned int sample_rate )
2003-02-04 15:48:42 +00:00
{
2005-01-03 01:21:15 +00:00
int i ;
2003-02-04 15:48:42 +00:00
2012-09-20 10:41:30 +00:00
for ( i = 0 ; i < 4 ; i + + ) {
2012-09-05 18:56:39 +00:00
goertzel_init ( & s - > row_out [ i ] , dtmf_row [ i ] , sample_rate ) ;
goertzel_init ( & s - > col_out [ i ] , dtmf_col [ i ] , sample_rate ) ;
2005-01-03 01:21:15 +00:00
}
2012-09-21 06:51:25 +00:00
s - > lasthit = 0 ;
s - > current_hit = 0 ;
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 ;
2003-02-04 15:48:42 +00:00
}
2012-09-05 18:56:39 +00:00
static void ast_mf_detect_init ( mf_detect_state_t * s , unsigned int sample_rate )
2003-02-04 15:48:42 +00:00
{
2005-01-03 01:21:15 +00:00
int i ;
2012-09-21 06:51:25 +00:00
2012-09-05 18:56:39 +00:00
for ( i = 0 ; i < 6 ; i + + ) {
goertzel_init ( & s - > tone_out [ i ] , mf_tones [ i ] , sample_rate ) ;
2005-01-03 01:21:15 +00:00
}
2012-09-21 06:51:25 +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
s - > current_sample = 0 ;
2008-02-20 21:36:46 +00:00
s - > current_hit = 0 ;
}
2011-04-21 18:11:40 +00:00
static void ast_digit_detect_init ( digit_detect_state_t * s , int mf , unsigned int sample_rate )
2008-02-20 21:36:46 +00:00
{
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 ) {
2011-04-21 18:11:40 +00:00
ast_mf_detect_init ( & s - > td . mf , sample_rate ) ;
2008-11-25 22:45:59 +00:00
} else {
2011-04-21 18:11:40 +00:00
ast_dtmf_detect_init ( & s - > td . dtmf , sample_rate ) ;
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 ;
2012-09-05 06:52:30 +00:00
short samp ;
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 ;
}
2012-09-20 10:41:30 +00:00
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 + + ) {
2012-09-05 06:52:30 +00:00
samp = * ptr ;
2012-09-05 07:43:32 +00:00
/* signed 32 bit int should be enough to square any possible signed 16 bit value */
2012-09-05 06:52:30 +00:00
s - > energy + = ( int32_t ) samp * ( int32_t ) samp ;
2008-02-20 21:36:46 +00:00
2012-09-05 06:52:30 +00:00
goertzel_sample ( & s - > tone , samp ) ;
2008-02-20 21:36:46 +00:00
}
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 ] ;
int i ;
int j ;
int sample ;
2012-09-05 06:52:30 +00:00
short samp ;
2005-01-03 01:21:15 +00:00
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
}
2012-03-22 19:51:16 +00:00
/* The following unrolled loop takes only 35% (rough estimate) of the
2005-01-03 01:21:15 +00:00
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 + + ) {
2012-09-05 06:52:30 +00:00
samp = amp [ j ] ;
s - > td . dtmf . energy + = ( int32_t ) samp * ( int32_t ) samp ;
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 */
2012-09-05 06:52:30 +00:00
goertzel_sample ( s - > td . dtmf . row_out , samp ) ;
goertzel_sample ( s - > td . dtmf . col_out , samp ) ;
goertzel_sample ( s - > td . dtmf . row_out + 1 , samp ) ;
goertzel_sample ( s - > td . dtmf . col_out + 1 , samp ) ;
goertzel_sample ( s - > td . dtmf . row_out + 2 , samp ) ;
goertzel_sample ( s - > td . dtmf . col_out + 2 , samp ) ;
goertzel_sample ( s - > td . dtmf . row_out + 3 , samp ) ;
goertzel_sample ( s - > td . dtmf . col_out + 3 , samp ) ;
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 */
2012-09-21 09:11:39 +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
2012-09-20 10:41:30 +00:00
for ( best_row = best_col = 0 , i = 1 ; i < 4 ; i + + ) {
2012-09-21 09:11:39 +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
}
2012-09-21 09:11:39 +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 */
2011-09-13 18:11:33 +00:00
if ( row_energy [ best_row ] > = DTMF_THRESHOLD & &
2005-01-03 01:21:15 +00:00
col_energy [ best_col ] > = DTMF_THRESHOLD & &
2012-10-04 04:50:16 +00:00
col_energy [ best_col ] < row_energy [ best_row ] * ( relax ? relax_dtmf_reverse_twist : dtmf_reverse_twist ) & &
row_energy [ best_row ] < col_energy [ best_col ] * ( relax ? relax_dtmf_normal_twist : dtmf_normal_twist ) ) {
2005-01-03 01:21:15 +00:00
/* Relative peak test */
2012-09-20 10:41:30 +00:00
for ( i = 0 ; i < 4 ; i + + ) {
2005-01-03 01:21:15 +00:00
if ( ( i ! = best_col & &
2008-11-25 22:45:59 +00:00
col_energy [ i ] * DTMF_RELATIVE_PEAK_COL > col_energy [ best_col ] ) | |
2011-09-13 18:11:33 +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 ] ;
}
2011-09-13 18:11:33 +00:00
}
2007-08-24 20:25:39 +00:00
2012-09-05 07:43:32 +00:00
/*
* Adapted from ETSI ES 201 235 - 3 V1 .3 .1 ( 2006 - 03 )
* ( 40 ms reference is tunable with hits_to_begin and misses_to_end )
* each hit / miss is 12.75 ms with DTMF_GSIZE at 102
*
* Character recognition : When not DRC * ( 1 ) and then
* Shall exist VSC > 40 ms ( hits_to_begin )
* May exist 20 ms < = VSC < = 40 ms
* Shall not exist VSC < 20 ms
*
* Character recognition : When DRC and then
* Shall cease Not VSC > 40 ms ( misses_to_end )
* May cease 20 ms > = Not VSC > = 40 ms
* Shall not cease Not VSC < 20 ms
*
* * ( 1 ) or optionally a different digit recognition condition
*
* Legend : VSC The continuous existence of a valid signal condition .
* Not VSC The continuous non - existence of valid signal condition .
* DRC The existence of digit recognition condition .
* Not DRC The non - existence of digit recognition condition .
*/
/*
* Example : hits_to_begin = 2 misses_to_end = 3
* - - - - - - - A last_hit = A hits = 0 & 1
* - - - - - - AA hits = 2 current_hit = A misses = 0 BEGIN A
* - - - - - AA - misses = 1 last_hit = ' ' hits = 0
* - - - - AA - - misses = 2
* - - - AA - - - misses = 3 current_hit = ' ' END A
* - - AA - - - B last_hit = B hits = 0 & 1
* - AA - - - BC last_hit = C hits = 0 & 1
* AA - - - BCC hits = 2 current_hit = C misses = 0 BEGIN C
* A - - - BCC - misses = 1 last_hit = ' ' hits = 0
* - - - BCC - C misses = 0 last_hit = C hits = 0 & 1
* - - BCC - CC misses = 0
*
* Example : hits_to_begin = 3 misses_to_end = 2
* - - - - - - - A last_hit = A hits = 0 & 1
* - - - - - - AA hits = 2
* - - - - - AAA hits = 3 current_hit = A misses = 0 BEGIN A
* - - - - AAAB misses = 1 last_hit = B hits = 0 & 1
* - - - AAABB misses = 2 current_hit = ' ' hits = 2 END A
* - - AAABBB hits = 3 current_hit = B misses = 0 BEGIN B
* - AAABBBB misses = 0
*
* Example : hits_to_begin = 2 misses_to_end = 2
* - - - - - - - A last_hit = A hits = 0 & 1
* - - - - - - AA hits = 2 current_hit = A misses = 0 BEGIN A
* - - - - - AAB misses = 1 hits = 0 & 1
* - - - - AABB misses = 2 current_hit = ' ' hits = 2 current_hit = B misses = 0 BEGIN B
* - - - AABBB misses = 0
*/
if ( s - > td . dtmf . current_hit ) {
/* We are in the middle of a digit already */
if ( hit ! = s - > td . dtmf . current_hit ) {
s - > td . dtmf . misses + + ;
2012-10-04 20:21:36 +00:00
if ( s - > td . dtmf . misses = = dtmf_misses_to_end ) {
2012-09-05 07:43:32 +00:00
/* There were enough misses to consider digit ended */
s - > td . dtmf . current_hit = 0 ;
2012-01-05 22:02:33 +00:00
}
2012-09-05 07:43:32 +00:00
} else {
s - > td . dtmf . misses = 0 ;
/* Current hit was same as last, so increment digit duration (of last digit) */
s - > digitlen [ s - > current_digits - 1 ] + = DTMF_GSIZE ;
2007-08-24 20:25:39 +00:00
}
2012-09-05 07:43:32 +00:00
}
/* Look for a start of a new digit no matter if we are already in the middle of some
digit or not . This is because hits_to_begin may be smaller than misses_to_end
and we may find begin of new digit before we consider last one ended . */
if ( hit ! = s - > td . dtmf . lasthit ) {
2012-01-05 22:02:33 +00:00
s - > td . dtmf . lasthit = hit ;
2012-09-05 07:43:32 +00:00
s - > td . dtmf . hits = 0 ;
}
if ( hit & & hit ! = s - > td . dtmf . current_hit ) {
s - > td . dtmf . hits + + ;
2012-10-04 20:21:36 +00:00
if ( s - > td . dtmf . hits = = dtmf_hits_to_begin ) {
2012-09-05 07:43:32 +00:00
store_digit ( s , hit ) ;
2012-10-04 20:21:36 +00:00
s - > digitlen [ s - > current_digits - 1 ] = dtmf_hits_to_begin * DTMF_GSIZE ;
2012-09-05 07:43:32 +00:00
s - > td . dtmf . current_hit = hit ;
s - > td . dtmf . misses = 0 ;
}
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 [ ] ,
2012-03-22 19:51:16 +00:00
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 ;
2012-09-05 06:52:30 +00:00
short samp ;
2005-01-03 01:21:15 +00:00
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 ;
2012-09-20 10:41:30 +00:00
for ( sample = 0 ; sample < samples ; sample = limit ) {
2005-01-03 01:21:15 +00:00
/* 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
}
2012-03-22 19:51:16 +00:00
/* The following unrolled loop takes only 35% (rough estimate) of the
2005-01-03 01:21:15 +00:00
time of a rolled loop on the machine on which it was developed */
2012-09-20 10:41:30 +00:00
for ( j = sample ; j < limit ; j + + ) {
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 */
2012-09-05 06:52:30 +00:00
samp = amp [ j ] ;
goertzel_sample ( s - > td . mf . tone_out , samp ) ;
goertzel_sample ( s - > td . mf . tone_out + 1 , samp ) ;
goertzel_sample ( s - > td . mf . tone_out + 2 , samp ) ;
goertzel_sample ( s - > td . mf . tone_out + 3 , samp ) ;
goertzel_sample ( s - > td . mf . tone_out + 4 , samp ) ;
goertzel_sample ( s - > td . mf . tone_out + 5 , samp ) ;
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
2011-09-13 18:11:33 +00:00
& & energy [ best ] < energy [ second_best ] * BELL_MF_TWIST
& & 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 ] ) | |
2011-09-13 18:11:33 +00:00
( hit = = ' * ' & & hit = = s - > td . mf . hits [ 2 ] & & hit ! = s - > td . mf . hits [ 1 ] & &
2008-02-20 21:36:46 +00:00
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 ;
}
2012-08-26 23:10:30 +00:00
mute . end = limit + MF_GSIZE ;
2008-03-26 19:05:51 +00:00
}
2005-01-03 01:21:15 +00:00
/* Reinitialise the detector for the next block */
2012-09-20 10:41:30 +00:00
for ( i = 0 ; i < 6 ; i + + ) {
2008-02-20 21:36:46 +00:00
goertzel_reset ( & s - > td . mf . tone_out [ i ] ) ;
2011-09-13 18:11:33 +00:00
}
2008-02-20 21:36:46 +00:00
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 )
{
2012-09-21 06:51:25 +00:00
short samp ;
2003-02-04 15:48:42 +00:00
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 + + ) {
2012-09-21 06:51:25 +00:00
samp = s [ x ] ;
dsp - > genergy + = ( int32_t ) samp * ( int32_t ) samp ;
2008-11-25 22:45:59 +00:00
for ( y = 0 ; y < dsp - > freqcount ; y + + ) {
2012-09-21 06:51:25 +00:00
goertzel_sample ( & dsp - > freqs [ y ] , samp ) ;
2008-11-25 22:45:59 +00:00
}
2003-02-04 15:48:42 +00:00
}
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 ;
}
2011-04-21 18:11:40 +00:00
if ( ! ast_format_is_slinear ( & inf - > subclass . format ) ) {
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
}
2011-06-30 20:33:15 +00:00
static int __ast_dsp_silence_noise ( struct ast_dsp * dsp , short * s , int len , int * totalsilence , int * totalnoise , int * frames_energy )
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 */
2011-04-21 18:11:40 +00:00
dsp - > totalsilence + = len / ( dsp - > sample_rate / 1000 ) ;
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 */
2011-04-21 18:11:40 +00:00
dsp - > totalnoise + = len / ( dsp - > sample_rate / 1000 ) ;
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
}
2011-06-30 20:33:15 +00:00
if ( frames_energy ) {
* frames_energy = accum ;
}
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 ;
2011-04-01 17:01:01 +00:00
/* if we have a 4 length pattern, the way busymaybe is set doesn't help us. */
if ( dsp - > busy_cadence . length ! = 4 ) {
if ( ! dsp - > busymaybe ) {
return res ;
}
2008-11-25 22:45:59 +00:00
}
2011-04-01 17:01:01 +00:00
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
2011-09-13 18:11:33 +00:00
if ( ( hittone > = dsp - > busycount - 1 ) & & ( hitsilence > = dsp - > busycount - 1 ) & &
( avgtone > = BUSY_MIN & & avgtone < = BUSY_MAX ) & &
2005-01-03 01:21:15 +00:00
( 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
}
2011-04-01 17:01:01 +00:00
/* If we have a 4-length pattern, we can go ahead and just check it in a different way. */
if ( dsp - > busy_cadence . length = = 4 ) {
int x ;
int errors = 0 ;
int errors_max = ( ( 4 * dsp - > busycount ) / 100.0 ) * BUSY_PAT_PERCENT ;
for ( x = DSP_HISTORY - ( dsp - > busycount ) ; x < DSP_HISTORY ; x + = 2 ) {
int temp_error ;
temp_error = abs ( dsp - > historicnoise [ x ] - dsp - > busy_cadence . pattern [ 0 ] ) ;
if ( ( temp_error * 100 ) / dsp - > busy_cadence . pattern [ 0 ] > BUSY_PERCENT ) {
errors + + ;
}
temp_error = abs ( dsp - > historicnoise [ x + 1 ] - dsp - > busy_cadence . pattern [ 2 ] ) ;
if ( ( temp_error * 100 ) / dsp - > busy_cadence . pattern [ 2 ] > BUSY_PERCENT ) {
errors + + ;
}
temp_error = abs ( dsp - > historicsilence [ x ] - dsp - > busy_cadence . pattern [ 1 ] ) ;
if ( ( temp_error * 100 ) / dsp - > busy_cadence . pattern [ 1 ] > BUSY_PERCENT ) {
errors + + ;
}
temp_error = abs ( dsp - > historicsilence [ x + 1 ] - dsp - > busy_cadence . pattern [ 3 ] ) ;
if ( ( temp_error * 100 ) / dsp - > busy_cadence . pattern [ 3 ] > BUSY_PERCENT ) {
errors + + ;
}
}
ast_debug ( 5 , " errors = %d max = %d \n " , errors , errors_max ) ;
if ( errors < = errors_max ) {
return 1 ;
}
}
2005-08-08 00:08:48 +00:00
/* If we know the expected busy tone length, check we are in the range */
2011-04-01 17:01:01 +00:00
if ( res & & ( dsp - > busy_cadence . pattern [ 0 ] > 0 ) ) {
2011-05-16 21:08:50 +00:00
if ( abs ( avgtone - dsp - > busy_cadence . pattern [ 0 ] ) > MAX ( dsp - > busy_cadence . pattern [ 0 ] * 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 " ,
2011-04-01 17:01:01 +00:00
avgtone , dsp - > busy_cadence . pattern [ 0 ] ) ;
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 */
2011-04-01 17:01:01 +00:00
if ( res & & ( dsp - > busy_cadence . pattern [ 1 ] > 0 ) ) {
2011-05-16 21:08:50 +00:00
if ( abs ( avgsilence - dsp - > busy_cadence . pattern [ 1 ] ) > MAX ( dsp - > busy_cadence . pattern [ 1 ] * 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 " ,
2011-04-01 17:01:01 +00:00
avgsilence , dsp - > busy_cadence . pattern [ 1 ] ) ;
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
2011-07-25 14:07:01 +00:00
static int ast_dsp_silence_noise_with_energy ( struct ast_dsp * dsp , struct ast_frame * f , int * total , int * frames_energy , int noise )
2003-02-04 15:48:42 +00:00
{
short * s ;
int len ;
2011-07-25 14:07:01 +00:00
int x ;
unsigned char * odata ;
if ( ! f ) {
return 0 ;
}
2003-02-04 15:48:42 +00:00
if ( f - > frametype ! = AST_FRAME_VOICE ) {
ast_log ( LOG_WARNING , " Can't calculate silence on a non-voice frame \n " ) ;
return 0 ;
}
2011-04-21 18:11:40 +00:00
if ( ! ast_format_is_slinear ( & f - > subclass . format ) ) {
2011-07-25 14:07:01 +00:00
odata = f - > data . ptr ;
len = f - > datalen ;
switch ( f - > subclass . format . id ) {
case AST_FORMAT_ULAW :
2012-07-31 20:21:43 +00:00
s = ast_alloca ( len * 2 ) ;
2012-09-21 09:11:39 +00:00
for ( x = 0 ; x < len ; x + + ) {
2011-07-25 14:07:01 +00:00
s [ x ] = AST_MULAW ( odata [ x ] ) ;
}
break ;
case AST_FORMAT_ALAW :
2012-07-31 20:21:43 +00:00
s = ast_alloca ( len * 2 ) ;
2012-09-21 09:11:39 +00:00
for ( x = 0 ; x < len ; x + + ) {
2011-07-25 14:07:01 +00:00
s [ x ] = AST_ALAW ( odata [ x ] ) ;
}
break ;
default :
ast_log ( LOG_WARNING , " Can only calculate silence on signed-linear, alaw or ulaw frames :( \n " ) ;
return 0 ;
}
} else {
s = f - > data . ptr ;
len = f - > datalen / 2 ;
}
if ( noise ) {
return __ast_dsp_silence_noise ( dsp , s , len , NULL , total , frames_energy ) ;
} else {
return __ast_dsp_silence_noise ( dsp , s , len , total , NULL , frames_energy ) ;
2003-02-04 15:48:42 +00:00
}
2011-06-30 20:33:15 +00:00
}
int ast_dsp_silence_with_energy ( struct ast_dsp * dsp , struct ast_frame * f , int * totalsilence , int * frames_energy )
{
2011-07-25 14:07:01 +00:00
return ast_dsp_silence_noise_with_energy ( dsp , f , totalsilence , frames_energy , 0 ) ;
}
2011-06-30 20:33:15 +00:00
2011-07-25 14:07:01 +00:00
int ast_dsp_silence ( struct ast_dsp * dsp , struct ast_frame * f , int * totalsilence )
{
return ast_dsp_silence_noise_with_energy ( dsp , f , totalsilence , NULL , 0 ) ;
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 )
{
2011-07-25 14:07:01 +00:00
return ast_dsp_silence_noise_with_energy ( dsp , f , totalnoise , NULL , 1 ) ;
2008-03-05 16:23:44 +00:00
}
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 */
2011-04-21 18:11:40 +00:00
if ( ast_format_is_slinear ( & af - > subclass . format ) ) {
2008-05-22 16:29:54 +00:00
shortdata = af - > data . ptr ;
2003-02-04 15:48:42 +00:00
len = af - > datalen / 2 ;
2011-04-21 18:11:40 +00:00
} else {
switch ( af - > subclass . format . id ) {
case AST_FORMAT_ULAW :
case AST_FORMAT_TESTLAW :
2012-07-31 20:21:43 +00:00
shortdata = ast_alloca ( af - > datalen * 2 ) ;
2012-09-21 09:11:39 +00:00
for ( x = 0 ; x < len ; x + + ) {
2011-04-21 18:11:40 +00:00
shortdata [ x ] = AST_MULAW ( odata [ x ] ) ;
}
break ;
case AST_FORMAT_ALAW :
2012-07-31 20:21:43 +00:00
shortdata = ast_alloca ( af - > datalen * 2 ) ;
2011-04-21 18:11:40 +00:00
for ( x = 0 ; x < len ; x + + ) {
shortdata [ x ] = AST_ALAW ( odata [ x ] ) ;
}
break ;
default :
/*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 . format ) ) ;
dsp - > display_inband_dtmf_warning = 0 ;
return af ;
2008-11-25 22:45:59 +00:00
}
2003-02-04 15:48:42 +00:00
}
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 ) ) {
2011-06-30 20:33:15 +00:00
res = __ast_dsp_silence_noise ( dsp , shortdata , len , & silence , NULL , NULL ) ;
2008-03-26 19:16:31 +00:00
}
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 ) ) {
2012-03-01 22:09:18 +00:00
ast_channel_softhangup_internal_flag_add ( chan , 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 ) ;
2012-01-09 22:15:50 +00:00
ast_debug ( 1 , " Requesting Hangup because the busy tone was detected on channel %s \n " , ast_channel_name ( chan ) ) ;
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 ) ) {
2011-09-13 18:11:33 +00:00
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 ) ) ;
2011-09-13 18:11:33 +00:00
} else {
2008-03-26 19:05:51 +00:00
digit = dtmf_detect ( dsp , & dsp - > digit_state , shortdata , len , ( dsp - > digitmode & DSP_DIGITMODE_NOQUELCH ) = = 0 , ( dsp - > digitmode & DSP_DIGITMODE_RELAXDTMF ) ) ;
2011-09-13 18:11:33 +00:00
}
2008-03-26 19:05:51 +00:00
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 ] ;
2011-04-21 18:11:40 +00:00
event_len = dsp - > digit_state . digitlen [ 0 ] * 1000 / dsp - > 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 ) {
2011-09-13 18:11:33 +00:00
/* 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 " ;
2011-09-13 18:11:33 +00:00
if ( chan ) {
2004-04-06 22:17:32 +00:00
ast_queue_frame ( chan , & dsp - > f ) ;
2011-09-13 18:11:33 +00:00
}
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 ) ) ;
}
2011-02-03 16:22:10 +00:00
switch ( af - > subclass . format . id ) {
2008-03-26 19:05:51 +00:00
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
}
2011-02-03 16:22:10 +00:00
/* fall through */
default :
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 ;
2011-09-13 18:11:33 +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 ] ) {
2012-09-05 18:56:39 +00:00
goertzel_init ( & dsp - > freqs [ x ] , ( float ) modes [ dsp - > progmode ] . freqs [ x ] , dsp - > sample_rate ) ;
2004-11-10 20:20:18 +00:00
max = x + 1 ;
2004-03-28 02:53:04 +00:00
}
}
dsp - > freqcount = max ;
2012-09-21 09:11:39 +00:00
dsp - > ringtimeout = 0 ;
2004-03-28 02:53:04 +00:00
}
2011-04-21 18:11:40 +00:00
unsigned int ast_dsp_get_sample_rate ( const struct ast_dsp * dsp )
{
return dsp - > sample_rate ;
}
static struct ast_dsp * __ast_dsp_new ( unsigned int sample_rate )
2003-02-04 15:48:42 +00:00
{
struct ast_dsp * dsp ;
2011-09-13 18:11:33 +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 ;
2011-04-21 18:11:40 +00:00
dsp - > sample_rate = sample_rate ;
2008-02-20 21:36:46 +00:00
/* Initialize digit detector */
2011-04-21 18:11:40 +00:00
ast_digit_detect_init ( & dsp - > digit_state , dsp - > digitmode & DSP_DIGITMODE_MF , dsp - > sample_rate ) ;
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 ;
}
2011-04-21 18:11:40 +00:00
struct ast_dsp * ast_dsp_new ( void )
{
return __ast_dsp_new ( DEFAULT_SAMPLE_RATE ) ;
}
struct ast_dsp * ast_dsp_new_with_rate ( unsigned int sample_rate )
{
return __ast_dsp_new ( sample_rate ) ;
}
2003-02-04 15:48:42 +00:00
void ast_dsp_set_features ( struct ast_dsp * dsp , int features )
{
dsp - > features = features ;
2011-05-05 22:12:10 +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 ;
}
2011-04-01 17:01:01 +00:00
void ast_dsp_set_busy_pattern ( struct ast_dsp * dsp , const struct ast_dsp_busy_pattern * cadence )
2005-08-08 00:08:48 +00:00
{
2011-04-01 17:01:01 +00:00
dsp - > busy_cadence = * cadence ;
ast_debug ( 1 , " dsp busy pattern set to %d,%d,%d,%d \n " , cadence - > pattern [ 0 ] , cadence - > pattern [ 1 ] , ( cadence - > length = = 4 ) ? cadence - > pattern [ 2 ] : 0 , ( cadence - > length = = 4 ) ? cadence - > pattern [ 3 ] : 0 ) ;
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 ;
2011-09-13 18:11:33 +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 */
2012-09-20 10:41:30 +00:00
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
}
2012-09-21 06:51:25 +00:00
s - > hits [ 4 ] = s - > hits [ 3 ] = s - > hits [ 2 ] = s - > hits [ 1 ] = s - > hits [ 0 ] = 0 ;
s - > current_hit = 0 ;
2008-02-20 21:36:46 +00:00
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 */
2012-09-20 10:41:30 +00:00
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
}
2012-09-21 06:51:25 +00:00
s - > lasthit = 0 ;
s - > current_hit = 0 ;
2008-02-20 21:36:46 +00:00
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 ;
2011-09-13 18:11:33 +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 ) ) ;
2011-09-13 18:11:33 +00:00
memset ( dsp - > historicnoise , 0 , sizeof ( dsp - > historicnoise ) ) ;
2012-09-21 09:11:39 +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 ;
2011-09-13 18:11:33 +00:00
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 */
2011-04-21 18:11:40 +00:00
ast_digit_detect_init ( & dsp - > digit_state , new & DSP_DIGITMODE_MF , dsp - > sample_rate ) ;
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 ) {
2011-07-25 14:07:01 +00:00
dsp - > faxmode = faxmode ;
2008-02-20 21:36:46 +00:00
ast_fax_detect_init ( dsp ) ;
}
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 ;
2011-09-13 18:11:33 +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 ) ;
}
2011-09-13 18:11:33 +00:00
int ast_dsp_get_tstate ( struct ast_dsp * dsp )
2004-11-17 05:55:26 +00:00
{
return dsp - > tstate ;
}
2011-09-13 18:11:33 +00:00
int ast_dsp_get_tcount ( struct ast_dsp * dsp )
2004-11-17 05:55:26 +00:00
{
return dsp - > tcount ;
}
2008-03-05 16:23:44 +00:00
static int _dsp_init ( int reload )
{
struct ast_config * cfg ;
2011-09-13 18:11:33 +00:00
struct ast_variable * v ;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 } ;
int cfg_threshold ;
2012-10-04 04:50:16 +00:00
float cfg_twist ;
2008-03-05 16:23:44 +00:00
2011-09-13 18:11:33 +00:00
if ( ( cfg = ast_config_load2 ( CONFIG_FILE_NAME , " dsp " , config_flags ) ) = = CONFIG_STATUS_FILEUNCHANGED ) {
2010-06-07 17:34:45 +00:00
return 0 ;
}
2011-09-13 18:11:33 +00:00
thresholds [ THRESHOLD_SILENCE ] = DEFAULT_SILENCE_THRESHOLD ;
2012-10-04 04:50:16 +00:00
dtmf_normal_twist = DEF_DTMF_NORMAL_TWIST ;
dtmf_reverse_twist = DEF_DTMF_REVERSE_TWIST ;
relax_dtmf_normal_twist = DEF_RELAX_DTMF_NORMAL_TWIST ;
relax_dtmf_reverse_twist = DEF_RELAX_DTMF_REVERSE_TWIST ;
2012-10-04 20:21:36 +00:00
dtmf_hits_to_begin = DEF_DTMF_HITS_TO_BEGIN ;
dtmf_misses_to_end = DEF_DTMF_MISSES_TO_END ;
2011-09-13 18:11:33 +00:00
if ( cfg = = CONFIG_STATUS_FILEMISSING | | cfg = = CONFIG_STATUS_FILEINVALID ) {
2008-09-12 23:30:03 +00:00
return 0 ;
}
2008-03-05 16:23:44 +00:00
2011-09-13 18:11:33 +00:00
for ( v = ast_variable_browse ( cfg , " default " ) ; v ; v = v - > next ) {
if ( ! strcasecmp ( v - > name , " silencethreshold " ) ) {
if ( sscanf ( v - > value , " %30d " , & cfg_threshold ) < 1 ) {
2012-03-22 19:51:16 +00:00
ast_log ( LOG_WARNING , " Unable to convert '%s' to a numeric value. \n " , v - > value ) ;
2011-09-13 18:11:33 +00:00
} else if ( cfg_threshold < 0 ) {
ast_log ( LOG_WARNING , " Invalid silence threshold '%d' specified, using default \n " , cfg_threshold ) ;
} else {
thresholds [ THRESHOLD_SILENCE ] = cfg_threshold ;
}
2012-10-04 04:50:16 +00:00
} else if ( ! strcasecmp ( v - > name , " dtmf_normal_twist " ) ) {
if ( sscanf ( v - > value , " %30f " , & cfg_twist ) < 1 ) {
ast_log ( LOG_WARNING , " Unable to convert '%s' to a numeric value. \n " , v - > value ) ;
} else if ( ( cfg_twist < 2.0 ) | | ( cfg_twist > 100.0 ) ) { /* < 3.0dB or > 20dB */
ast_log ( LOG_WARNING , " Invalid dtmf_normal_twist value '%.2f' specified, using default of %.2f \n " , cfg_twist , dtmf_normal_twist ) ;
} else {
dtmf_normal_twist = cfg_twist ;
}
} else if ( ! strcasecmp ( v - > name , " dtmf_reverse_twist " ) ) {
if ( sscanf ( v - > value , " %30f " , & cfg_twist ) < 1 ) {
ast_log ( LOG_WARNING , " Unable to convert '%s' to a numeric value. \n " , v - > value ) ;
} else if ( ( cfg_twist < 2.0 ) | | ( cfg_twist > 100.0 ) ) { /* < 3.0dB or > 20dB */
ast_log ( LOG_WARNING , " Invalid dtmf_reverse_twist value '%.2f' specified, using default of %.2f \n " , cfg_twist , dtmf_reverse_twist ) ;
} else {
dtmf_reverse_twist = cfg_twist ;
}
} else if ( ! strcasecmp ( v - > name , " relax_dtmf_normal_twist " ) ) {
if ( sscanf ( v - > value , " %30f " , & cfg_twist ) < 1 ) {
ast_log ( LOG_WARNING , " Unable to convert '%s' to a numeric value. \n " , v - > value ) ;
} else if ( ( cfg_twist < 2.0 ) | | ( cfg_twist > 100.0 ) ) { /* < 3.0dB or > 20dB */
ast_log ( LOG_WARNING , " Invalid relax_dtmf_normal_twist value '%.2f' specified, using default of %.2f \n " , cfg_twist , relax_dtmf_normal_twist ) ;
} else {
relax_dtmf_normal_twist = cfg_twist ;
}
} else if ( ! strcasecmp ( v - > name , " relax_dtmf_reverse_twist " ) ) {
if ( sscanf ( v - > value , " %30f " , & cfg_twist ) < 1 ) {
ast_log ( LOG_WARNING , " Unable to convert '%s' to a numeric value. \n " , v - > value ) ;
} else if ( ( cfg_twist < 2.0 ) | | ( cfg_twist > 100.0 ) ) { /* < 3.0dB or > 20dB */
ast_log ( LOG_WARNING , " Invalid relax_dtmf_reverse_twist value '%.2f' specified, using default of %.2f \n " , cfg_twist , relax_dtmf_reverse_twist ) ;
} else {
relax_dtmf_reverse_twist = cfg_twist ;
}
2012-10-04 20:21:36 +00:00
} else if ( ! strcasecmp ( v - > name , " dtmf_hits_to_begin " ) ) {
if ( sscanf ( v - > value , " %30d " , & cfg_threshold ) < 1 ) {
ast_log ( LOG_WARNING , " Unable to convert '%s' to a numeric value. \n " , v - > value ) ;
} else if ( cfg_threshold < 1 ) { /* must be 1 or greater */
ast_log ( LOG_WARNING , " Invalid dtmf_hits_to_begin value '%d' specified, using default of %d \n " , cfg_threshold , dtmf_hits_to_begin ) ;
} else {
dtmf_hits_to_begin = cfg_threshold ;
}
} else if ( ! strcasecmp ( v - > name , " dtmf_misses_to_end " ) ) {
if ( sscanf ( v - > value , " %30d " , & cfg_threshold ) < 1 ) {
ast_log ( LOG_WARNING , " Unable to convert '%s' to a numeric value. \n " , v - > value ) ;
} else if ( cfg_threshold < 1 ) { /* must be 1 or greater */
ast_log ( LOG_WARNING , " Invalid dtmf_misses_to_end value '%d' specified, using default of %d \n " , cfg_threshold , dtmf_misses_to_end ) ;
} else {
dtmf_misses_to_end = cfg_threshold ;
}
2008-11-25 22:45:59 +00:00
}
2008-03-05 16:23:44 +00:00
}
2011-09-13 18:11:33 +00:00
ast_config_destroy ( cfg ) ;
2008-03-05 16:23:44 +00:00
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 ) ;
}