as reported in mantis #6066, fix a bunch of cli bugs and
[asterisk/asterisk.git] / dsp.c
diff --git a/dsp.c b/dsp.c
old mode 100755 (executable)
new mode 100644 (file)
index d349a7d..a11f272
--- a/dsp.c
+++ b/dsp.c
@@ -1,18 +1,30 @@
 /*
- * Asterisk -- A telephony toolkit for Linux.
+ * Asterisk -- An open source telephony toolkit.
  *
- * Convenience Signal Processing routines
- * 
- * Copyright (C) 2002, Digium
+ * Copyright (C) 1999 - 2005, Digium, Inc.
  *
- * Mark Spencer <markster@linux-support.net>
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License.
+ * Mark Spencer <markster@digium.com>
  *
  * Goertzel routines are borrowed from Steve Underwood's tremendous work on the
  * DTMF detector.
  *
+ * 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.
+ */
+
+/*! \file
+ *
+ * \brief Convenience Signal Processing routines
+ *
+ * \author Mark Spencer <markster@digium.com>
+ * \author Steve Underwood <steveu@coppice.org>
  */
 
 /* Some routines from tone_detect.c by Steven Underwood as published under the zapata library */
         detriment.
 */
 
-#include <asterisk/frame.h>
-#include <asterisk/channel.h>
-#include <asterisk/channel_pvt.h>
-#include <asterisk/logger.h>
-#include <asterisk/dsp.h>
-#include <asterisk/ulaw.h>
-#include <asterisk/alaw.h>
+#include <sys/types.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
 #include <stdio.h>
 
-#define DEFAULT_THRESHOLD 1024
+#include "asterisk.h"
 
-#define BUSY_THRESHOLD 100             /* Max number of ms difference between max and min times in busy */
-#define BUSY_MIN               80              /* Busy must be at least 80 ms in half-cadence */
-#define BUSY_MAX               1100    /* Busy can't be longer than 1100 ms in half-cadence */
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
-/* Remember last 3 units */
-#define DSP_HISTORY 5
+#include "asterisk/frame.h"
+#include "asterisk/channel.h"
+#include "asterisk/logger.h"
+#include "asterisk/dsp.h"
+#include "asterisk/ulaw.h"
+#include "asterisk/alaw.h"
+#include "asterisk/utils.h"
 
-/* Number of goertzels for progress detect */
-#define GSAMP_SIZE 183
+/*! 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 */
+};
 
-#define HZ_350  0
-#define HZ_440  1
-#define HZ_480  2
-#define HZ_620  3
-#define HZ_950  4
-#define HZ_1400 5
-#define HZ_1800 6
+enum prog_mode {
+       PROG_MODE_NA = 0,
+       PROG_MODE_CR,
+       PROG_MODE_UK
+};
+
+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 */
+       HZ_400 = 0
+};
+
+static struct progalias {
+       char *name;
+       enum prog_mode mode;
+} aliases[] = {
+       { "us", PROG_MODE_NA },
+       { "ca", PROG_MODE_NA },
+       { "cr", PROG_MODE_CR },
+       { "br", PROG_MODE_CR },
+       { "uk", PROG_MODE_UK },
+};
+
+static struct progress {
+       enum gsamp_size size;
+       int freqs[7];
+} modes[] = {
+       { GSAMP_SIZE_NA, { 350, 440, 480, 620, 950, 1400, 1800 } },     /*!< North America */
+       { GSAMP_SIZE_CR, { 425 } },                                     /*!< Costa Rica, Brazil */
+       { GSAMP_SIZE_UK, { 400 } },                                     /*!< UK */
+};
 
-#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 */
-#define COUNT_THRESH  3                /* Need at least 50ms of stuff to count it */
+#define DEFAULT_THRESHOLD      512
 
-#define TONE_STATE_SILENCE  0
-#define TONE_STATE_RINGING  1 
-#define TONE_STATE_DIALTONE 2
-#define TONE_STATE_TALKING  3
-#define TONE_STATE_BUSY     4
-#define TONE_STATE_SPECIAL1    5
-#define TONE_STATE_SPECIAL2 6
-#define TONE_STATE_SPECIAL3 7
+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 */
+};
 
-#define        MAX_DTMF_DIGITS 128
+/*! Remember last 15 units */
+#define DSP_HISTORY            15
+
+/*! Define if you want the fax detector -- NOT RECOMMENDED IN -STABLE */
+#define FAX_DETECT
+
+#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) */
+};
+
+#define        MAX_DTMF_DIGITS         128
 
 /* Basic DTMF specs:
  *
  * Frequency tolerance +- 1.5% will detect, +-3.5% will reject
  */
 
-#define DTMF_THRESHOLD              8.0e7
-#define FAX_THRESHOLD              8.0e7
-#define FAX_2ND_HARMONIC                       2.0     /* 4dB */
-#define DTMF_NORMAL_TWIST           6.3     /* 8dB */
+#define DTMF_THRESHOLD         8.0e7
+#define FAX_THRESHOLD          8.0e7
+#define FAX_2ND_HARMONIC       2.0     /* 4dB */
+#define DTMF_NORMAL_TWIST      6.3     /* 8dB */
+#ifdef RADIO_RELAX
+#define DTMF_REVERSE_TWIST          ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 6.5 : 2.5)     /* 4dB normal */
+#else
 #define DTMF_REVERSE_TWIST          ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 4.0 : 2.5)     /* 4dB normal */
-#define DTMF_RELATIVE_PEAK_ROW      6.3     /* 8dB */
-#define DTMF_RELATIVE_PEAK_COL      6.3     /* 8dB */
+#endif
+#define DTMF_RELATIVE_PEAK_ROW 6.3     /* 8dB */
+#define DTMF_RELATIVE_PEAK_COL 6.3     /* 8dB */
 #define DTMF_2ND_HARMONIC_ROW       ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 1.7 : 2.5)     /* 4dB normal */
-#define DTMF_2ND_HARMONIC_COL       63.1    /* 18dB */
+#define DTMF_2ND_HARMONIC_COL  63.1    /* 18dB */
+#define DTMF_TO_TOTAL_ENERGY   42.0
+
+#ifdef OLD_DSP_ROUTINES
+#define MF_THRESHOLD           8.0e7
+#define MF_NORMAL_TWIST                5.3     /* 8dB */
+#define MF_REVERSE_TWIST       4.0     /* was 2.5 */
+#define MF_RELATIVE_PEAK       5.3     /* 8dB */
+#define MF_2ND_HARMONIC                1.7     /* was 2.5  */
+#else
+#define BELL_MF_THRESHOLD      1.6e9
+#define BELL_MF_TWIST          4.0     /* 6dB */
+#define BELL_MF_RELATIVE_PEAK  12.6    /* 11dB */
+#endif
 
-#define MF_THRESHOLD              8.0e7
-#define MF_NORMAL_TWIST           5.3     /* 8dB */
-#define MF_REVERSE_TWIST          4.0     /* was 2.5 */
-#define MF_RELATIVE_PEAK      5.3     /* 8dB */
-#define MF_2ND_HARMONIC       1.7 /* was 2.5  */
+#if !defined(BUSYDETECT_MARTIN) && !defined(BUSYDETECT) && !defined(BUSYDETECT_TONEONLY) && !defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
+#define BUSYDETECT_MARTIN
+#endif
 
 typedef struct {
        float v2;
        float v3;
        float fac;
+#ifndef OLD_DSP_ROUTINES
+       int samples;
+#endif 
 } goertzel_state_t;
 
 typedef struct
 {
-    int hit1;
-    int hit2;
-    int hit3;
-    int hit4;
-    int mhit;
-
-    goertzel_state_t row_out[4];
-    goertzel_state_t col_out[4];
-    goertzel_state_t row_out2nd[4];
-    goertzel_state_t col_out2nd[4];
+       goertzel_state_t row_out[4];
+       goertzel_state_t col_out[4];
+#ifdef FAX_DETECT
        goertzel_state_t fax_tone;
-       goertzel_state_t fax_tone2nd;
-    float energy;
-    
-    int current_sample;
-    char digits[MAX_DTMF_DIGITS + 1];
-    int current_digits;
-    int detected_digits;
-    int lost_digits;
-    int digit_hits[16];
+#endif
+#ifdef OLD_DSP_ROUTINES
+       goertzel_state_t row_out2nd[4];
+       goertzel_state_t col_out2nd[4];
+#ifdef FAX_DETECT
+       goertzel_state_t fax_tone2nd;    
+#endif
+       int hit1;
+       int hit2;
+       int hit3;
+       int hit4;
+#else
+       int hits[3];
+#endif 
+       int mhit;
+       float energy;
+       int current_sample;
+
+       char digits[MAX_DTMF_DIGITS + 1];
+       
+       int current_digits;
+       int detected_digits;
+       int lost_digits;
+       int digit_hits[16];
+#ifdef FAX_DETECT
        int fax_hits;
+#endif
 } dtmf_detect_state_t;
 
 typedef struct
 {
-    int hit1;
-    int hit2;
-    int hit3;
-    int hit4;
-    int mhit;
-
-    goertzel_state_t tone_out[6];
-    goertzel_state_t tone_out2nd[6];
-    float energy;
-    
-    int current_sample;
-    char digits[MAX_DTMF_DIGITS + 1];
-    int current_digits;
-    int detected_digits;
-    int lost_digits;
+       goertzel_state_t tone_out[6];
+       int mhit;
+#ifdef OLD_DSP_ROUTINES
+       int hit1;
+       int hit2;
+       int hit3;
+       int hit4;
+       goertzel_state_t tone_out2nd[6];
+       float energy;
+#else
+       int hits[5];
+#endif
+       int current_sample;
+       
+       char digits[MAX_DTMF_DIGITS + 1];
+
+       int current_digits;
+       int detected_digits;
+       int lost_digits;
+#ifdef FAX_DETECT
        int fax_hits;
+#endif
 } mf_detect_state_t;
 
 static float dtmf_row[] =
 {
-     697.0,  770.0,  852.0,  941.0
+       697.0,  770.0,  852.0,  941.0
 };
 static float dtmf_col[] =
 {
-    1209.0, 1336.0, 1477.0, 1633.0
+       1209.0, 1336.0, 1477.0, 1633.0
 };
 
 static float mf_tones[] =
@@ -170,10 +268,13 @@ static float mf_tones[] =
        700.0, 900.0, 1100.0, 1300.0, 1500.0, 1700.0
 };
 
+#ifdef FAX_DETECT
 static float fax_freq = 1100.0;
+#endif
 
 static char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
 
+#ifdef OLD_DSP_ROUTINES
 static char mf_hit[6][6] = {
        /*  700 + */ {   0, '1', '2', '4', '7', 'C' },
        /*  900 + */ { '1',   0, '3', '5', '8', 'A' },
@@ -182,11 +283,15 @@ static char mf_hit[6][6] = {
        /* 1500 + */ { '7', '8', '9', '0',  0, '#' },
        /* 1700 + */ { 'C', 'A', '*', 'B', '#',  0  },
 };
+#else
+static char bell_mf_positions[] = "1247C-358A--69*---0B----#";
+#endif
 
 static inline void goertzel_sample(goertzel_state_t *s, short sample)
 {
        float v1;
        float fsamp  = sample;
+       
        v1 = s->v2;
        s->v2 = s->v3;
        s->v3 = s->fac * s->v2 - v1 + fsamp;
@@ -195,6 +300,7 @@ static inline void goertzel_sample(goertzel_state_t *s, short sample)
 static inline void goertzel_update(goertzel_state_t *s, short *samps, int count)
 {
        int i;
+       
        for (i=0;i<count;i++) 
                goertzel_sample(s, samps[i]);
 }
@@ -205,10 +311,13 @@ static inline float goertzel_result(goertzel_state_t *s)
        return s->v3 * s->v3 + s->v2 * s->v2 - s->v2 * s->v3 * s->fac;
 }
 
-static inline void goertzel_init(goertzel_state_t *s, float freq)
+static inline void goertzel_init(goertzel_state_t *s, float freq, int samples)
 {
        s->v2 = s->v3 = 0.0;
        s->fac = 2.0 * cos(2.0 * M_PI * (freq / 8000.0));
+#ifndef OLD_DSP_ROUTINES
+       s->samples = samples;
+#endif
 }
 
 static inline void goertzel_reset(goertzel_state_t *s)
@@ -222,12 +331,18 @@ struct ast_dsp {
        int totalsilence;
        int totalnoise;
        int features;
+       int ringtimeout;
        int busymaybe;
        int busycount;
+       int busy_tonelength;
+       int busy_quietlength;
        int historicnoise[DSP_HISTORY];
        int historicsilence[DSP_HISTORY];
        goertzel_state_t freqs[7];
+       int freqcount;
        int gsamps;
+       enum gsamp_size gsamp_size;
+       enum prog_mode progmode;
        int tstate;
        int tcount;
        int digitmode;
@@ -241,184 +356,179 @@ struct ast_dsp {
 
 static void ast_dtmf_detect_init (dtmf_detect_state_t *s)
 {
-    int i;
-
-    s->hit1 = 
-    s->hit2 = 0;
-
-    for (i = 0;  i < 4;  i++)
-    {
-    
-               goertzel_init (&s->row_out[i], dtmf_row[i]);
-       goertzel_init (&s->col_out[i], dtmf_col[i]);
-       goertzel_init (&s->row_out2nd[i], dtmf_row[i] * 2.0);
-       goertzel_init (&s->col_out2nd[i], dtmf_col[i] * 2.0);
-       
-               s->energy = 0.0;
-    }
+       int i;
 
+#ifdef OLD_DSP_ROUTINES
+       s->hit1 = 
+       s->mhit = 
+       s->hit3 =
+       s->hit4 = 
+       s->hit2 = 0;
+#else
+       s->hits[0] = s->hits[1] = s->hits[2] = 0;
+#endif
+       for (i = 0;  i < 4;  i++) {
+               goertzel_init (&s->row_out[i], dtmf_row[i], 102);
+               goertzel_init (&s->col_out[i], dtmf_col[i], 102);
+#ifdef OLD_DSP_ROUTINES
+               goertzel_init (&s->row_out2nd[i], dtmf_row[i] * 2.0, 102);
+               goertzel_init (&s->col_out2nd[i], dtmf_col[i] * 2.0, 102);
+#endif 
+               s->energy = 0.0;
+       }
+#ifdef FAX_DETECT
        /* Same for the fax dector */
-    goertzel_init (&s->fax_tone, fax_freq);
+       goertzel_init (&s->fax_tone, fax_freq, 102);
 
+#ifdef OLD_DSP_ROUTINES
        /* Same for the fax dector 2nd harmonic */
-    goertzel_init (&s->fax_tone2nd, fax_freq * 2.0);
-       
-    s->current_sample = 0;
-    s->detected_digits = 0;
+       goertzel_init (&s->fax_tone2nd, fax_freq * 2.0, 102);
+#endif 
+#endif /* FAX_DETECT */
+       s->current_sample = 0;
+       s->detected_digits = 0;
        s->current_digits = 0;
        memset(&s->digits, 0, sizeof(s->digits));
-    s->lost_digits = 0;
-    s->digits[0] = '\0';
-    s->mhit = 0;
+       s->lost_digits = 0;
+       s->digits[0] = '\0';
 }
 
 static void ast_mf_detect_init (mf_detect_state_t *s)
 {
-    int i;
-
-    s->hit1 = 
-    s->hit2 = 0;
-
-    for (i = 0;  i < 6;  i++)
-    {
-    
-               goertzel_init (&s->tone_out[i], mf_tones[i]);
-       goertzel_init (&s->tone_out2nd[i], mf_tones[i] * 2.0);
-       
+       int i;
+#ifdef OLD_DSP_ROUTINES
+       s->hit1 = 
+       s->hit2 = 0;
+#else  
+       s->hits[0] = s->hits[1] = s->hits[2] = s->hits[3] = s->hits[4] = 0;
+#endif
+       for (i = 0;  i < 6;  i++) {
+               goertzel_init (&s->tone_out[i], mf_tones[i], 160);
+#ifdef OLD_DSP_ROUTINES
+               goertzel_init (&s->tone_out2nd[i], mf_tones[i] * 2.0, 160);
                s->energy = 0.0;
-    }
-
+#endif
+       }
        s->current_digits = 0;
        memset(&s->digits, 0, sizeof(s->digits));
-    s->current_sample = 0;
-    s->detected_digits = 0;
-    s->lost_digits = 0;
-    s->digits[0] = '\0';
-    s->mhit = 0;
+       s->current_sample = 0;
+       s->detected_digits = 0;
+       s->lost_digits = 0;
+       s->digits[0] = '\0';
+       s->mhit = 0;
 }
 
-static int dtmf_detect (dtmf_detect_state_t *s,
-                 int16_t amp[],
-                 int samples, 
-                int digitmode, int *writeback)
+static int dtmf_detect (dtmf_detect_state_t *s, int16_t amp[], int samples, 
+                int digitmode, int *writeback, int faxdetect)
 {
-
-    float row_energy[4];
-    float col_energy[4];
-    float fax_energy;
-    float fax_energy_2nd;
-    float famp;
-    float v1;
-    int i;
-    int j;
-    int sample;
-    int best_row;
-    int best_col;
-    int hit;
-    int limit;
-
-    hit = 0;
-    for (sample = 0;  sample < samples;  sample = limit)
-    {
-        /* 102 is optimised to meet the DTMF specs. */
-        if ((samples - sample) >= (102 - s->current_sample))
-            limit = sample + (102 - s->current_sample);
-        else
-            limit = samples;
+       float row_energy[4];
+       float col_energy[4];
+#ifdef FAX_DETECT
+       float fax_energy;
+#ifdef OLD_DSP_ROUTINES
+       float fax_energy_2nd;
+#endif 
+#endif /* FAX_DETECT */
+       float famp;
+       float v1;
+       int i;
+       int j;
+       int sample;
+       int best_row;
+       int best_col;
+       int hit;
+       int limit;
+
+       hit = 0;
+       for (sample = 0;  sample < samples;  sample = limit) {
+               /* 102 is optimised to meet the DTMF specs. */
+               if ((samples - sample) >= (102 - s->current_sample))
+                       limit = sample + (102 - s->current_sample);
+               else
+                       limit = samples;
 #if defined(USE_3DNOW)
-        _dtmf_goertzel_update (s->row_out, amp + sample, limit - sample);
-        _dtmf_goertzel_update (s->col_out, amp + sample, limit - sample);
-        _dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample);
-        _dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample);
+               _dtmf_goertzel_update (s->row_out, amp + sample, limit - sample);
+               _dtmf_goertzel_update (s->col_out, amp + sample, limit - sample);
+#ifdef OLD_DSP_ROUTINES
+               _dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample);
+               _dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample);
+#endif         
                /* XXX Need to fax detect for 3dnow too XXX */
                #warning "Fax Support Broken"
 #else
-        /* 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++)
-        {
-            famp = amp[j];
-           
-           s->energy += famp*famp;
-           
-            /* With GCC 2.95, the following unrolled code seems to take about 35%
-               (rough estimate) as long as a neat little 0-3 loop */
-            v1 = s->row_out[0].v2;
-            s->row_out[0].v2 = s->row_out[0].v3;
-            s->row_out[0].v3 = s->row_out[0].fac*s->row_out[0].v2 - v1 + famp;
-    
-            v1 = s->col_out[0].v2;
-            s->col_out[0].v2 = s->col_out[0].v3;
-            s->col_out[0].v3 = s->col_out[0].fac*s->col_out[0].v2 - v1 + famp;
-    
-            v1 = s->row_out[1].v2;
-            s->row_out[1].v2 = s->row_out[1].v3;
-            s->row_out[1].v3 = s->row_out[1].fac*s->row_out[1].v2 - v1 + famp;
-    
-            v1 = s->col_out[1].v2;
-            s->col_out[1].v2 = s->col_out[1].v3;
-            s->col_out[1].v3 = s->col_out[1].fac*s->col_out[1].v2 - v1 + famp;
-    
-            v1 = s->row_out[2].v2;
-            s->row_out[2].v2 = s->row_out[2].v3;
-            s->row_out[2].v3 = s->row_out[2].fac*s->row_out[2].v2 - v1 + famp;
-    
-            v1 = s->col_out[2].v2;
-            s->col_out[2].v2 = s->col_out[2].v3;
-            s->col_out[2].v3 = s->col_out[2].fac*s->col_out[2].v2 - v1 + famp;
-    
-            v1 = s->row_out[3].v2;
-            s->row_out[3].v2 = s->row_out[3].v3;
-            s->row_out[3].v3 = s->row_out[3].fac*s->row_out[3].v2 - v1 + famp;
-
-            v1 = s->col_out[3].v2;
-            s->col_out[3].v2 = s->col_out[3].v3;
-            s->col_out[3].v3 = s->col_out[3].fac*s->col_out[3].v2 - v1 + famp;
-
-            v1 = s->col_out2nd[0].v2;
-            s->col_out2nd[0].v2 = s->col_out2nd[0].v3;
-            s->col_out2nd[0].v3 = s->col_out2nd[0].fac*s->col_out2nd[0].v2 - v1 + famp;
-        
-            v1 = s->row_out2nd[0].v2;
-            s->row_out2nd[0].v2 = s->row_out2nd[0].v3;
-            s->row_out2nd[0].v3 = s->row_out2nd[0].fac*s->row_out2nd[0].v2 - v1 + famp;
-        
-            v1 = s->col_out2nd[1].v2;
-            s->col_out2nd[1].v2 = s->col_out2nd[1].v3;
-            s->col_out2nd[1].v3 = s->col_out2nd[1].fac*s->col_out2nd[1].v2 - v1 + famp;
-    
-            v1 = s->row_out2nd[1].v2;
-            s->row_out2nd[1].v2 = s->row_out2nd[1].v3;
-            s->row_out2nd[1].v3 = s->row_out2nd[1].fac*s->row_out2nd[1].v2 - v1 + famp;
-        
-            v1 = s->col_out2nd[2].v2;
-            s->col_out2nd[2].v2 = s->col_out2nd[2].v3;
-            s->col_out2nd[2].v3 = s->col_out2nd[2].fac*s->col_out2nd[2].v2 - v1 + famp;
-        
-            v1 = s->row_out2nd[2].v2;
-            s->row_out2nd[2].v2 = s->row_out2nd[2].v3;
-            s->row_out2nd[2].v3 = s->row_out2nd[2].fac*s->row_out2nd[2].v2 - v1 + famp;
-        
-            v1 = s->col_out2nd[3].v2;
-            s->col_out2nd[3].v2 = s->col_out2nd[3].v3;
-            s->col_out2nd[3].v3 = s->col_out2nd[3].fac*s->col_out2nd[3].v2 - v1 + famp;
-        
-            v1 = s->row_out2nd[3].v2;
-            s->row_out2nd[3].v2 = s->row_out2nd[3].v3;
-            s->row_out2nd[3].v3 = s->row_out2nd[3].fac*s->row_out2nd[3].v2 - v1 + famp;
-
+               /* 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++) {
+                       famp = amp[j];
+                       s->energy += famp*famp;
+                       /* With GCC 2.95, the following unrolled code seems to take about 35%
+                          (rough estimate) as long as a neat little 0-3 loop */
+                       v1 = s->row_out[0].v2;
+                       s->row_out[0].v2 = s->row_out[0].v3;
+                       s->row_out[0].v3 = s->row_out[0].fac*s->row_out[0].v2 - v1 + famp;
+                       v1 = s->col_out[0].v2;
+                       s->col_out[0].v2 = s->col_out[0].v3;
+                       s->col_out[0].v3 = s->col_out[0].fac*s->col_out[0].v2 - v1 + famp;
+                       v1 = s->row_out[1].v2;
+                       s->row_out[1].v2 = s->row_out[1].v3;
+                       s->row_out[1].v3 = s->row_out[1].fac*s->row_out[1].v2 - v1 + famp;
+                       v1 = s->col_out[1].v2;
+                       s->col_out[1].v2 = s->col_out[1].v3;
+                       s->col_out[1].v3 = s->col_out[1].fac*s->col_out[1].v2 - v1 + famp;
+                       v1 = s->row_out[2].v2;
+                       s->row_out[2].v2 = s->row_out[2].v3;
+                       s->row_out[2].v3 = s->row_out[2].fac*s->row_out[2].v2 - v1 + famp;
+                       v1 = s->col_out[2].v2;
+                       s->col_out[2].v2 = s->col_out[2].v3;
+                       s->col_out[2].v3 = s->col_out[2].fac*s->col_out[2].v2 - v1 + famp;
+                       v1 = s->row_out[3].v2;
+                       s->row_out[3].v2 = s->row_out[3].v3;
+                       s->row_out[3].v3 = s->row_out[3].fac*s->row_out[3].v2 - v1 + famp;
+                       v1 = s->col_out[3].v2;
+                       s->col_out[3].v2 = s->col_out[3].v3;
+                       s->col_out[3].v3 = s->col_out[3].fac*s->col_out[3].v2 - v1 + famp;
+#ifdef FAX_DETECT
                        /* Update fax tone */
-            v1 = s->fax_tone.v2;
-            s->fax_tone.v2 = s->fax_tone.v3;
-            s->fax_tone.v3 = s->fax_tone.fac*s->fax_tone.v2 - v1 + famp;
-
-            v1 = s->fax_tone.v2;
-            s->fax_tone2nd.v2 = s->fax_tone2nd.v3;
-            s->fax_tone2nd.v3 = s->fax_tone2nd.fac*s->fax_tone2nd.v2 - v1 + famp;
-        }
+                       v1 = s->fax_tone.v2;
+                       s->fax_tone.v2 = s->fax_tone.v3;
+                       s->fax_tone.v3 = s->fax_tone.fac*s->fax_tone.v2 - v1 + famp;
+#endif /* FAX_DETECT */
+#ifdef OLD_DSP_ROUTINES
+                       v1 = s->col_out2nd[0].v2;
+                       s->col_out2nd[0].v2 = s->col_out2nd[0].v3;
+                       s->col_out2nd[0].v3 = s->col_out2nd[0].fac*s->col_out2nd[0].v2 - v1 + famp;
+                       v1 = s->row_out2nd[0].v2;
+                       s->row_out2nd[0].v2 = s->row_out2nd[0].v3;
+                       s->row_out2nd[0].v3 = s->row_out2nd[0].fac*s->row_out2nd[0].v2 - v1 + famp;
+                       v1 = s->col_out2nd[1].v2;
+                       s->col_out2nd[1].v2 = s->col_out2nd[1].v3;
+                       s->col_out2nd[1].v3 = s->col_out2nd[1].fac*s->col_out2nd[1].v2 - v1 + famp;
+                       v1 = s->row_out2nd[1].v2;
+                       s->row_out2nd[1].v2 = s->row_out2nd[1].v3;
+                       s->row_out2nd[1].v3 = s->row_out2nd[1].fac*s->row_out2nd[1].v2 - v1 + famp;
+                       v1 = s->col_out2nd[2].v2;
+                       s->col_out2nd[2].v2 = s->col_out2nd[2].v3;
+                       s->col_out2nd[2].v3 = s->col_out2nd[2].fac*s->col_out2nd[2].v2 - v1 + famp;
+                       v1 = s->row_out2nd[2].v2;
+                       s->row_out2nd[2].v2 = s->row_out2nd[2].v3;
+                       s->row_out2nd[2].v3 = s->row_out2nd[2].fac*s->row_out2nd[2].v2 - v1 + famp;
+                       v1 = s->col_out2nd[3].v2;
+                       s->col_out2nd[3].v2 = s->col_out2nd[3].v3;
+                       s->col_out2nd[3].v3 = s->col_out2nd[3].fac*s->col_out2nd[3].v2 - v1 + famp;
+                       v1 = s->row_out2nd[3].v2;
+                       s->row_out2nd[3].v2 = s->row_out2nd[3].v3;
+                       s->row_out2nd[3].v3 = s->row_out2nd[3].fac*s->row_out2nd[3].v2 - v1 + famp;
+#ifdef FAX_DETECT
+                       /* Update fax tone */            
+                       v1 = s->fax_tone.v2;
+                       s->fax_tone2nd.v2 = s->fax_tone2nd.v3;
+                       s->fax_tone2nd.v3 = s->fax_tone2nd.fac*s->fax_tone2nd.v2 - v1 + famp;
+#endif /* FAX_DETECT */
+#endif
+               }
 #endif
-        s->current_sample += (limit - sample);
-        if (s->current_sample < 102) {
+               s->current_sample += (limit - sample);
+               if (s->current_sample < 102) {
                        if (hit && !((digitmode & DSP_DIGITMODE_NOQUELCH))) {
                                /* If we had a hit last time, go ahead and clear this out since likely it
                                   will be another hit */
@@ -426,238 +536,249 @@ static int dtmf_detect (dtmf_detect_state_t *s,
                                        amp[i] = 0;
                                *writeback = 1;
                        }
-            continue;
+                       continue;
                }
-
+#ifdef FAX_DETECT
                /* Detect the fax energy, too */
                fax_energy = goertzel_result(&s->fax_tone);
-               
-        /* We are at the end of a DTMF detection block */
-        /* Find the peak row and the peak column */
-        row_energy[0] = goertzel_result (&s->row_out[0]);
-        col_energy[0] = goertzel_result (&s->col_out[0]);
-
-       for (best_row = best_col = 0, i = 1;  i < 4;  i++)
-       {
-           row_energy[i] = goertzel_result (&s->row_out[i]);
-            if (row_energy[i] > row_energy[best_row])
-                best_row = i;
-           col_energy[i] = goertzel_result (&s->col_out[i]);
-            if (col_energy[i] > col_energy[best_col])
-                best_col = i;
-       }
-        hit = 0;
-        /* Basic signal level test and the twist test */
-        if (row_energy[best_row] >= DTMF_THRESHOLD
-           &&
-           col_energy[best_col] >= DTMF_THRESHOLD
-            &&
-            col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST
-            &&
-            col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row])
-        {
-            /* Relative peak test */
-            for (i = 0;  i < 4;  i++)
-            {
-                if ((i != best_col  &&  col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col])
-                    ||
-                    (i != best_row  &&  row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row]))
-                {
-                    break;
-                }
-            }
-            /* ... and second harmonic test */
-            if (i >= 4
-               &&
-               (row_energy[best_row] + col_energy[best_col]) > 42.0*s->energy
-                &&
-                goertzel_result (&s->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col]
-                &&
-                goertzel_result (&s->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row])
-            {
+#endif
+               /* We are at the end of a DTMF detection block */
+               /* Find the peak row and the peak column */
+               row_energy[0] = goertzel_result (&s->row_out[0]);
+               col_energy[0] = goertzel_result (&s->col_out[0]);
+
+               for (best_row = best_col = 0, i = 1;  i < 4;  i++) {
+                       row_energy[i] = goertzel_result (&s->row_out[i]);
+                       if (row_energy[i] > row_energy[best_row])
+                               best_row = i;
+                       col_energy[i] = goertzel_result (&s->col_out[i]);
+                       if (col_energy[i] > col_energy[best_col])
+                               best_col = i;
+               }
+               hit = 0;
+               /* Basic signal level test and the twist test */
+               if (row_energy[best_row] >= DTMF_THRESHOLD && 
+                   col_energy[best_col] >= DTMF_THRESHOLD &&
+                   col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST &&
+                   col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) {
+                       /* Relative peak test */
+                       for (i = 0;  i < 4;  i++) {
+                               if ((i != best_col &&
+                                   col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) ||
+                                   (i != best_row 
+                                    && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) {
+                                       break;
+                               }
+                       }
+#ifdef OLD_DSP_ROUTINES
+                       /* ... and second harmonic test */
+                       if (i >= 4 && 
+                           (row_energy[best_row] + col_energy[best_col]) > 42.0*s->energy &&
+                           goertzel_result(&s->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col]
+                           && goertzel_result(&s->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) {
+#else
+                       /* ... and fraction of total energy test */
+                       if (i >= 4 &&
+                           (row_energy[best_row] + col_energy[best_col]) > DTMF_TO_TOTAL_ENERGY*s->energy) {
+#endif
                                /* Got a hit */
-                hit = dtmf_positions[(best_row << 2) + best_col];
+                               hit = dtmf_positions[(best_row << 2) + best_col];
                                if (!(digitmode & DSP_DIGITMODE_NOQUELCH)) {
                                        /* Zero out frame data if this is part DTMF */
                                        for (i=sample;i<limit;i++) 
                                                amp[i] = 0;
                                        *writeback = 1;
                                }
-                /* Look for two successive similar results */
-                /* The logic in the next test is:
-                   We need two successive identical clean detects, with
-                  something different preceeding it. This can work with
-                  back to back differing digits. More importantly, it
-                  can work with nasty phones that give a very wobbly start
-                  to a digit. */
-                if (hit == s->hit3  &&  s->hit3 != s->hit2)
-                {
-                   s->mhit = hit;
-                    s->digit_hits[(best_row << 2) + best_col]++;
-                    s->detected_digits++;
-                    if (s->current_digits < MAX_DTMF_DIGITS)
-                    {
-                        s->digits[s->current_digits++] = hit;
-                        s->digits[s->current_digits] = '\0';
-                    }
-                    else
-                    {
-                        s->lost_digits++;
-                    }
-                }
-            }
-        } 
-               if (!hit && (fax_energy >= FAX_THRESHOLD) && (fax_energy > s->energy * 21.0)) {
-                               fax_energy_2nd = goertzel_result(&s->fax_tone2nd);
-                               if (fax_energy_2nd * FAX_2ND_HARMONIC < fax_energy) {
+                               /* Look for two successive similar results */
+                               /* The logic in the next test is:
+                                  We need two successive identical clean detects, with
+                                  something different preceeding it. This can work with
+                                  back to back differing digits. More importantly, it
+                                  can work with nasty phones that give a very wobbly start
+                                  to a digit */
+#ifdef OLD_DSP_ROUTINES
+                               if (hit == s->hit3  &&  s->hit3 != s->hit2) {
+                                       s->mhit = hit;
+                                       s->digit_hits[(best_row << 2) + best_col]++;
+                                       s->detected_digits++;
+                                       if (s->current_digits < MAX_DTMF_DIGITS) {
+                                               s->digits[s->current_digits++] = hit;
+                                               s->digits[s->current_digits] = '\0';
+                                       } else {
+                                               s->lost_digits++;
+                                       }
+                               }
+#else                          
+                               if (hit == s->hits[2]  &&  hit != s->hits[1]  &&  hit != s->hits[0]) {
+                                       s->mhit = hit;
+                                       s->digit_hits[(best_row << 2) + best_col]++;
+                                       s->detected_digits++;
+                                       if (s->current_digits < MAX_DTMF_DIGITS) {
+                                               s->digits[s->current_digits++] = hit;
+                                               s->digits[s->current_digits] = '\0';
+                                       } else {
+                                               s->lost_digits++;
+                                       }
+                               }
+#endif
+                       }
+               } 
+#ifdef FAX_DETECT
+               if (!hit && (fax_energy >= FAX_THRESHOLD) && 
+                       (fax_energy >= DTMF_TO_TOTAL_ENERGY*s->energy) &&
+                       (faxdetect)) {
 #if 0
-                                       printf("Fax energy/Second Harmonic: %f/%f\n", fax_energy, fax_energy_2nd);
+                       printf("Fax energy/Second Harmonic: %f\n", fax_energy);
 #endif                                 
-                                       /* XXX Probably need better checking than just this the energy XXX */
-                                       hit = 'f';
-                                       s->fax_hits++;
-                               } /* Don't reset fax hits counter */
+                       /* XXX Probably need better checking than just this the energy XXX */
+                       hit = 'f';
+                       s->fax_hits++;
                } else {
                        if (s->fax_hits > 5) {
-                                hit = 'f';
-                                s->mhit = 'f';
-                    s->detected_digits++;
-                    if (s->current_digits < MAX_DTMF_DIGITS)
-                    {
-                         s->digits[s->current_digits++] = hit;
-                         s->digits[s->current_digits] = '\0';
-                    }
-                    else
-                    {
-                          s->lost_digits++;
-                    }
+                               hit = 'f';
+                               s->mhit = 'f';
+                               s->detected_digits++;
+                               if (s->current_digits < MAX_DTMF_DIGITS) {
+                                       s->digits[s->current_digits++] = hit;
+                                       s->digits[s->current_digits] = '\0';
+                               } else {
+                                       s->lost_digits++;
+                               }
                        }
                        s->fax_hits = 0;
                }
-        s->hit1 = s->hit2;
-        s->hit2 = s->hit3;
-        s->hit3 = hit;
-        /* Reinitialise the detector for the next block */
-        for (i = 0;  i < 4;  i++)
-        {
-                   goertzel_reset(&s->row_out[i]);
-            goertzel_reset(&s->col_out[i]);
-           goertzel_reset(&s->row_out2nd[i]);
-           goertzel_reset(&s->col_out2nd[i]);
-        }
-       goertzel_reset (&s->fax_tone);
-       goertzel_reset (&s->fax_tone2nd);
+#endif /* FAX_DETECT */
+#ifdef OLD_DSP_ROUTINES
+               s->hit1 = s->hit2;
+               s->hit2 = s->hit3;
+               s->hit3 = hit;
+#else
+               s->hits[0] = s->hits[1];
+               s->hits[1] = s->hits[2];
+               s->hits[2] = hit;
+#endif         
+               /* Reinitialise the detector for the next block */
+               for (i = 0;  i < 4;  i++) {
+                       goertzel_reset(&s->row_out[i]);
+                       goertzel_reset(&s->col_out[i]);
+#ifdef OLD_DSP_ROUTINES
+                       goertzel_reset(&s->row_out2nd[i]);
+                       goertzel_reset(&s->col_out2nd[i]);
+#endif                 
+               }
+#ifdef FAX_DETECT
+               goertzel_reset (&s->fax_tone);
+#ifdef OLD_DSP_ROUTINES
+               goertzel_reset (&s->fax_tone2nd);
+#endif                 
+#endif
                s->energy = 0.0;
-        s->current_sample = 0;
-    }
-    if ((!s->mhit) || (s->mhit != hit))
-    {
-       s->mhit = 0;
-       return(0);
-    }
-    return (hit);
+               s->current_sample = 0;
+       }
+       if ((!s->mhit) || (s->mhit != hit)) {
+               s->mhit = 0;
+               return(0);
+       }
+       return (hit);
 }
 
 /* MF goertzel size */
+#ifdef OLD_DSP_ROUTINES
 #define        MF_GSIZE 160
+#else
+#define MF_GSIZE 120
+#endif
 
-static int mf_detect (mf_detect_state_t *s,
-                 int16_t amp[],
-                 int samples, 
-                int digitmode, int *writeback)
+static int mf_detect (mf_detect_state_t *s, int16_t amp[],
+                 int samples, int digitmode, int *writeback)
 {
-
-    float tone_energy[6];
-    float famp;
-    float v1;
-    int i;
-    int j;
-    int sample;
-    int best1;
-    int best2;
+#ifdef OLD_DSP_ROUTINES
+       float tone_energy[6];
+       int best1;
+       int best2;
        float max;
-    int hit;
-    int limit;
        int sofarsogood;
-
-    hit = 0;
-    for (sample = 0;  sample < samples;  sample = limit)
-    {
-        /* 80 is optimised to meet the MF specs. */
-        if ((samples - sample) >= (MF_GSIZE - s->current_sample))
-            limit = sample + (MF_GSIZE - s->current_sample);
-        else
-            limit = samples;
+#else
+       float energy[6];
+       int best;
+       int second_best;
+#endif
+       float famp;
+       float v1;
+       int i;
+       int j;
+       int sample;
+       int hit;
+       int limit;
+
+       hit = 0;
+       for (sample = 0;  sample < samples;  sample = limit) {
+               /* 80 is optimised to meet the MF specs. */
+               if ((samples - sample) >= (MF_GSIZE - s->current_sample))
+                       limit = sample + (MF_GSIZE - s->current_sample);
+               else
+                       limit = samples;
 #if defined(USE_3DNOW)
-        _dtmf_goertzel_update (s->row_out, amp + sample, limit - sample);
-        _dtmf_goertzel_update (s->col_out, amp + sample, limit - sample);
-        _dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample);
-        _dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample);
+               _dtmf_goertzel_update (s->row_out, amp + sample, limit - sample);
+               _dtmf_goertzel_update (s->col_out, amp + sample, limit - sample);
+#ifdef OLD_DSP_ROUTINES
+               _dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample);
+               _dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample);
+#endif
                /* XXX Need to fax detect for 3dnow too XXX */
                #warning "Fax Support Broken"
 #else
-        /* 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++)
-        {
-            famp = amp[j];
-           
-           s->energy += famp*famp;
-           
-            /* With GCC 2.95, the following unrolled code seems to take about 35%
-               (rough estimate) as long as a neat little 0-3 loop */
-            v1 = s->tone_out[0].v2;
-            s->tone_out[0].v2 = s->tone_out[0].v3;
-            s->tone_out[0].v3 = s->tone_out[0].fac*s->tone_out[0].v2 - v1 + famp;
-
-            v1 = s->tone_out[1].v2;
-            s->tone_out[1].v2 = s->tone_out[1].v3;
-            s->tone_out[1].v3 = s->tone_out[1].fac*s->tone_out[1].v2 - v1 + famp;
-    
-            v1 = s->tone_out[2].v2;
-            s->tone_out[2].v2 = s->tone_out[2].v3;
-            s->tone_out[2].v3 = s->tone_out[2].fac*s->tone_out[2].v2 - v1 + famp;
-    
-            v1 = s->tone_out[3].v2;
-            s->tone_out[3].v2 = s->tone_out[3].v3;
-            s->tone_out[3].v3 = s->tone_out[3].fac*s->tone_out[3].v2 - v1 + famp;
-
-            v1 = s->tone_out[4].v2;
-            s->tone_out[4].v2 = s->tone_out[4].v3;
-            s->tone_out[4].v3 = s->tone_out[4].fac*s->tone_out[4].v2 - v1 + famp;
-
-            v1 = s->tone_out[5].v2;
-            s->tone_out[5].v2 = s->tone_out[5].v3;
-            s->tone_out[5].v3 = s->tone_out[5].fac*s->tone_out[5].v2 - v1 + famp;
-
-            v1 = s->tone_out2nd[0].v2;
-            s->tone_out2nd[0].v2 = s->tone_out2nd[0].v3;
-            s->tone_out2nd[0].v3 = s->tone_out2nd[0].fac*s->tone_out2nd[0].v2 - v1 + famp;
-        
-            v1 = s->tone_out2nd[1].v2;
-            s->tone_out2nd[1].v2 = s->tone_out2nd[1].v3;
-            s->tone_out2nd[1].v3 = s->tone_out2nd[1].fac*s->tone_out2nd[1].v2 - v1 + famp;
-        
-            v1 = s->tone_out2nd[2].v2;
-            s->tone_out2nd[2].v2 = s->tone_out2nd[2].v3;
-            s->tone_out2nd[2].v3 = s->tone_out2nd[2].fac*s->tone_out2nd[2].v2 - v1 + famp;
-        
-            v1 = s->tone_out2nd[3].v2;
-            s->tone_out2nd[3].v2 = s->tone_out2nd[3].v3;
-            s->tone_out2nd[3].v3 = s->tone_out2nd[3].fac*s->tone_out2nd[3].v2 - v1 + famp;
-
-            v1 = s->tone_out2nd[4].v2;
-            s->tone_out2nd[4].v2 = s->tone_out2nd[4].v3;
-            s->tone_out2nd[4].v3 = s->tone_out2nd[4].fac*s->tone_out2nd[2].v2 - v1 + famp;
-        
-            v1 = s->tone_out2nd[3].v2;
-            s->tone_out2nd[5].v2 = s->tone_out2nd[6].v3;
-            s->tone_out2nd[5].v3 = s->tone_out2nd[6].fac*s->tone_out2nd[3].v2 - v1 + famp;
-
-        }
+               /* 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++) {
+                       famp = amp[j];
+#ifdef OLD_DSP_ROUTINES
+                       s->energy += famp*famp;
+#endif
+                       /* With GCC 2.95, the following unrolled code seems to take about 35%
+                          (rough estimate) as long as a neat little 0-3 loop */
+                       v1 = s->tone_out[0].v2;
+                       s->tone_out[0].v2 = s->tone_out[0].v3;
+                       s->tone_out[0].v3 = s->tone_out[0].fac*s->tone_out[0].v2 - v1 + famp;
+                       v1 = s->tone_out[1].v2;
+                       s->tone_out[1].v2 = s->tone_out[1].v3;
+                       s->tone_out[1].v3 = s->tone_out[1].fac*s->tone_out[1].v2 - v1 + famp;
+                       v1 = s->tone_out[2].v2;
+                       s->tone_out[2].v2 = s->tone_out[2].v3;
+                       s->tone_out[2].v3 = s->tone_out[2].fac*s->tone_out[2].v2 - v1 + famp;
+                       v1 = s->tone_out[3].v2;
+                       s->tone_out[3].v2 = s->tone_out[3].v3;
+                       s->tone_out[3].v3 = s->tone_out[3].fac*s->tone_out[3].v2 - v1 + famp;
+                       v1 = s->tone_out[4].v2;
+                       s->tone_out[4].v2 = s->tone_out[4].v3;
+                       s->tone_out[4].v3 = s->tone_out[4].fac*s->tone_out[4].v2 - v1 + famp;
+                       v1 = s->tone_out[5].v2;
+                       s->tone_out[5].v2 = s->tone_out[5].v3;
+                       s->tone_out[5].v3 = s->tone_out[5].fac*s->tone_out[5].v2 - v1 + famp;
+#ifdef OLD_DSP_ROUTINES
+                       v1 = s->tone_out2nd[0].v2;
+                       s->tone_out2nd[0].v2 = s->tone_out2nd[0].v3;
+                       s->tone_out2nd[0].v3 = s->tone_out2nd[0].fac*s->tone_out2nd[0].v2 - v1 + famp;
+                       v1 = s->tone_out2nd[1].v2;
+                       s->tone_out2nd[1].v2 = s->tone_out2nd[1].v3;
+                       s->tone_out2nd[1].v3 = s->tone_out2nd[1].fac*s->tone_out2nd[1].v2 - v1 + famp;
+                       v1 = s->tone_out2nd[2].v2;
+                       s->tone_out2nd[2].v2 = s->tone_out2nd[2].v3;
+                       s->tone_out2nd[2].v3 = s->tone_out2nd[2].fac*s->tone_out2nd[2].v2 - v1 + famp;
+                       v1 = s->tone_out2nd[3].v2;
+                       s->tone_out2nd[3].v2 = s->tone_out2nd[3].v3;
+                       s->tone_out2nd[3].v3 = s->tone_out2nd[3].fac*s->tone_out2nd[3].v2 - v1 + famp;
+                       v1 = s->tone_out2nd[4].v2;
+                       s->tone_out2nd[4].v2 = s->tone_out2nd[4].v3;
+                       s->tone_out2nd[4].v3 = s->tone_out2nd[4].fac*s->tone_out2nd[2].v2 - v1 + famp;
+                       v1 = s->tone_out2nd[3].v2;
+                       s->tone_out2nd[5].v2 = s->tone_out2nd[6].v3;
+                       s->tone_out2nd[5].v3 = s->tone_out2nd[6].fac*s->tone_out2nd[3].v2 - v1 + famp;
+#endif
+               }
 #endif
-        s->current_sample += (limit - sample);
-        if (s->current_sample < MF_GSIZE) {
+               s->current_sample += (limit - sample);
+               if (s->current_sample < MF_GSIZE) {
                        if (hit && !((digitmode & DSP_DIGITMODE_NOQUELCH))) {
                                /* If we had a hit last time, go ahead and clear this out since likely it
                                   will be another hit */
@@ -665,15 +786,14 @@ static int mf_detect (mf_detect_state_t *s,
                                        amp[i] = 0;
                                *writeback = 1;
                        }
-            continue;
+                       continue;
                }
-
+#ifdef OLD_DSP_ROUTINES                
                /* We're at the end of an MF detection block.  Go ahead and calculate
                   all the energies. */
                for (i=0;i<6;i++) {
                        tone_energy[i] = goertzel_result(&s->tone_out[i]);
                }
-               
                /* Find highest */
                best1 = 0;
                max = tone_energy[0];
@@ -685,11 +805,14 @@ static int mf_detect (mf_detect_state_t *s,
                }
 
                /* Find 2nd highest */
-               if (best1)
+               if (best1) {
                        max = tone_energy[0];
-               else
+                       best2 = 0;
+               } else {
                        max = tone_energy[1];
-               best2 = 0;
+                       best2 = 1;
+               }
+
                for (i=0;i<6;i++) {
                        if (i == best1) continue;
                        if (tone_energy[i] > max) {
@@ -697,13 +820,17 @@ static int mf_detect (mf_detect_state_t *s,
                                best2 = i;
                        }
                }
-               
-        hit = 0;
-               sofarsogood=1;
+               hit = 0;
+               if (best1 != best2) 
+                       sofarsogood=1;
+               else 
+                       sofarsogood=0;
                /* Check for relative energies */
                for (i=0;i<6;i++) {
-                       if (i == best1) continue;
-                       if (i == best2) continue;
+                       if (i == best1) 
+                               continue;
+                       if (i == best2) 
+                               continue;
                        if (tone_energy[best1] < tone_energy[i] * MF_RELATIVE_PEAK) {
                                sofarsogood = 0;
                                break;
@@ -742,33 +869,117 @@ static int mf_detect (mf_detect_state_t *s,
                        }
                }
                
-        s->hit1 = s->hit2;
-        s->hit2 = s->hit3;
-        s->hit3 = hit;
-        /* Reinitialise the detector for the next block */
-        for (i = 0;  i < 6;  i++)
-        {
-                   goertzel_reset(&s->tone_out[i]);
-            goertzel_reset(&s->tone_out2nd[i]);
-        }
+               s->hit1 = s->hit2;
+               s->hit2 = s->hit3;
+               s->hit3 = hit;
+               /* Reinitialise the detector for the next block */
+               for (i = 0;  i < 6;  i++) {
+                       goertzel_reset(&s->tone_out[i]);
+                       goertzel_reset(&s->tone_out2nd[i]);
+               }
                s->energy = 0.0;
-        s->current_sample = 0;
-    }
-    if ((!s->mhit) || (s->mhit != hit))
-    {
+               s->current_sample = 0;
+       }
+#else
+               /* We're at the end of an MF detection block.  */
+               /* 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. */
+               energy[0] = goertzel_result(&s->tone_out[0]);
+               energy[1] = goertzel_result(&s->tone_out[1]);
+               if (energy[0] > energy[1]) {
+                       best = 0;
+                       second_best = 1;
+               } else {
+                       best = 1;
+                       second_best = 0;
+               }
+               /*endif*/
+               for (i=2;i<6;i++) {
+                       energy[i] = goertzel_result(&s->tone_out[i]);
+                       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
+                   && energy[best]*BELL_MF_TWIST > energy[second_best]) {
+                       /* Relative peak test */
+                       hit = -1;
+                       for (i=0;i<6;i++) {
+                               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;
+                       }
+                       best = best*5 + second_best - 1;
+                       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. */
+                       if (hit == s->hits[4] && hit == s->hits[3] &&
+                          ((hit != '*' && hit != s->hits[2] && hit != s->hits[1])||
+                           (hit == '*' && hit == s->hits[2] && hit != s->hits[1] && 
+                           hit != s->hits[0]))) {
+                               s->detected_digits++;
+                               if (s->current_digits < MAX_DTMF_DIGITS) {
+                                       s->digits[s->current_digits++] = hit;
+                                       s->digits[s->current_digits] = '\0';
+                               } else {
+                                       s->lost_digits++;
+                               }
+                       }
+               } else {
+                       hit = 0;
+               }
+               s->hits[0] = s->hits[1];
+               s->hits[1] = s->hits[2];
+               s->hits[2] = s->hits[3];
+               s->hits[3] = s->hits[4];
+               s->hits[4] = hit;
+               /* Reinitialise the detector for the next block */
+               for (i = 0;  i < 6;  i++)
+                       goertzel_reset(&s->tone_out[i]);
+               s->current_sample = 0;
+       }
+#endif 
+       if ((!s->mhit) || (s->mhit != hit)) {
                s->mhit = 0;
                return(0);
-    }
-    return (hit);
+       }
+       return (hit);
 }
 
 static int __ast_dsp_digitdetect(struct ast_dsp *dsp, short *s, int len, int *writeback)
 {
        int res;
+       
        if (dsp->digitmode & DSP_DIGITMODE_MF)
                res = mf_detect(&dsp->td.mf, s, len, dsp->digitmode & DSP_DIGITMODE_RELAXDTMF, writeback);
        else
-               res = dtmf_detect(&dsp->td.dtmf, s, len, dsp->digitmode & DSP_DIGITMODE_RELAXDTMF, writeback);
+               res = dtmf_detect(&dsp->td.dtmf, s, len, dsp->digitmode & DSP_DIGITMODE_RELAXDTMF, writeback, dsp->features & DSP_FEATURE_FAX_DETECT);
        return res;
 }
 
@@ -777,6 +988,7 @@ int ast_dsp_digitdetect(struct ast_dsp *dsp, struct ast_frame *inf)
        short *s;
        int len;
        int ign=0;
+
        if (inf->frametype != AST_FRAME_VOICE) {
                ast_log(LOG_WARNING, "Can't check call progress of non-voice frames\n");
                return 0;
@@ -810,117 +1022,149 @@ static inline int pair_there(float p1, float p2, float i1, float i2, float e)
        return 1;
 }
 
-int ast_dsp_getdigits (struct ast_dsp *dsp,
-              char *buf,
-              int max)
+int ast_dsp_getdigits (struct ast_dsp *dsp, char *buf, int max)
 {
        if (dsp->digitmode & DSP_DIGITMODE_MF) {
-           if (max > dsp->td.mf.current_digits)
-               max = dsp->td.mf.current_digits;
-           if (max > 0)
-           {
-               memcpy (buf, dsp->td.mf.digits, max);
-               memmove (dsp->td.mf.digits, dsp->td.mf.digits + max, dsp->td.mf.current_digits - max);
-               dsp->td.mf.current_digits -= max;
-           }
-           buf[max] = '\0';
-           return  max;
+               if (max > dsp->td.mf.current_digits)
+                       max = dsp->td.mf.current_digits;
+               if (max > 0) {
+                       memcpy(buf, dsp->td.mf.digits, max);
+                       memmove(dsp->td.mf.digits, dsp->td.mf.digits + max, dsp->td.mf.current_digits - max);
+                       dsp->td.mf.current_digits -= max;
+               }
+               buf[max] = '\0';
+               return  max;
        } else {
-           if (max > dsp->td.dtmf.current_digits)
-               max = dsp->td.dtmf.current_digits;
-           if (max > 0)
-           {
-               memcpy (buf, dsp->td.dtmf.digits, max);
-               memmove (dsp->td.dtmf.digits, dsp->td.dtmf.digits + max, dsp->td.dtmf.current_digits - max);
-               dsp->td.dtmf.current_digits -= max;
-           }
-           buf[max] = '\0';
-           return  max;
+               if (max > dsp->td.dtmf.current_digits)
+                       max = dsp->td.dtmf.current_digits;
+               if (max > 0) {
+                       memcpy (buf, dsp->td.dtmf.digits, max);
+                       memmove (dsp->td.dtmf.digits, dsp->td.dtmf.digits + max, dsp->td.dtmf.current_digits - max);
+                       dsp->td.dtmf.current_digits -= max;
+               }
+               buf[max] = '\0';
+               return  max;
        }
 }
 
 static int __ast_dsp_call_progress(struct ast_dsp *dsp, short *s, int len)
 {
        int x;
+       int y;
        int pass;
-       int newstate = TONE_STATE_SILENCE;
+       int newstate = DSP_TONE_STATE_SILENCE;
        int res = 0;
        while(len) {
                /* Take the lesser of the number of samples we need and what we have */
                pass = len;
-               if (pass > GSAMP_SIZE - dsp->gsamps) 
-                       pass = GSAMP_SIZE - dsp->gsamps;
+               if (pass > dsp->gsamp_size - dsp->gsamps) 
+                       pass = dsp->gsamp_size - dsp->gsamps;
                for (x=0;x<pass;x++) {
-                       goertzel_sample(&dsp->freqs[HZ_350], s[x]);
-                       goertzel_sample(&dsp->freqs[HZ_440], s[x]);
-                       goertzel_sample(&dsp->freqs[HZ_480], s[x]);
-                       goertzel_sample(&dsp->freqs[HZ_620], s[x]);
-                       goertzel_sample(&dsp->freqs[HZ_950], s[x]);
-                       goertzel_sample(&dsp->freqs[HZ_1400], s[x]);
-                       goertzel_sample(&dsp->freqs[HZ_1800], s[x]);
+                       for (y=0;y<dsp->freqcount;y++) 
+                               goertzel_sample(&dsp->freqs[y], s[x]);
                        dsp->genergy += s[x] * s[x];
                }
                s += pass;
                dsp->gsamps += pass;
                len -= pass;
-               if (dsp->gsamps == GSAMP_SIZE) {
-                       float hz_350;
-                       float hz_440;
-                       float hz_480;
-                       float hz_620;
-                       float hz_950;
-                       float hz_1400;
-                       float hz_1800;
-                       hz_350 = goertzel_result(&dsp->freqs[HZ_350]);
-                       hz_440 = goertzel_result(&dsp->freqs[HZ_440]);
-                       hz_480 = goertzel_result(&dsp->freqs[HZ_480]);
-                       hz_620 = goertzel_result(&dsp->freqs[HZ_620]);
-                       hz_950 = goertzel_result(&dsp->freqs[HZ_950]);
-                       hz_1400 = goertzel_result(&dsp->freqs[HZ_1400]);
-                       hz_1800 = goertzel_result(&dsp->freqs[HZ_1800]);
+               if (dsp->gsamps == dsp->gsamp_size) {
+                       float hz[7];
+                       for (y=0;y<7;y++)
+                               hz[y] = goertzel_result(&dsp->freqs[y]);
 #if 0
-                       printf("Got whole dsp state: 350: %e, 440: %e, 480: %e, 620: %e, 950: %e, 1400: %e, 1800: %e, Energy: %e\n", 
-                               hz_350, hz_440, hz_480, hz_620, hz_950, hz_1400, hz_1800, dsp->genergy);
+                       printf("\n350:     425:     440:     480:     620:     950:     1400:    1800:    Energy:   \n");
+                       printf("%.2e %.2e %.2e %.2e %.2e %.2e %.2e %.2e %.2e\n", 
+                               hz[HZ_350], hz[HZ_425], hz[HZ_440], hz[HZ_480], hz[HZ_620], hz[HZ_950], hz[HZ_1400], hz[HZ_1800], dsp->genergy);
 #endif
-                       if (pair_there(hz_480, hz_620, hz_350, hz_440, dsp->genergy)) {
-                               newstate = TONE_STATE_BUSY;
-                       } else if (pair_there(hz_440, hz_480, hz_350, hz_620, dsp->genergy)) {
-                               newstate = TONE_STATE_RINGING;
-                       } else if (pair_there(hz_350, hz_440, hz_480, hz_620, dsp->genergy)) {
-                               newstate = TONE_STATE_DIALTONE;
-                       } else if (hz_950 > TONE_MIN_THRESH * TONE_THRESH) {
-                               newstate = TONE_STATE_SPECIAL1;
-                       } else if (hz_1400 > TONE_MIN_THRESH * TONE_THRESH) {
-                               if (dsp->tstate == TONE_STATE_SPECIAL1)
-                                       newstate = TONE_STATE_SPECIAL2;
-                       } else if (hz_1800 > TONE_MIN_THRESH * TONE_THRESH) {
-                               if (dsp->tstate == TONE_STATE_SPECIAL2)
-                                       newstate = TONE_STATE_SPECIAL3;
-                       } else if (dsp->genergy > TONE_MIN_THRESH * TONE_THRESH) {
-                               newstate = TONE_STATE_TALKING;
-                       } else
-                               newstate = TONE_STATE_SILENCE;
-                       
+                       switch(dsp->progmode) {
+                       case PROG_MODE_NA:
+                               if (pair_there(hz[HZ_480], hz[HZ_620], hz[HZ_350], hz[HZ_440], dsp->genergy)) {
+                                       newstate = DSP_TONE_STATE_BUSY;
+                               } else if (pair_there(hz[HZ_440], hz[HZ_480], hz[HZ_350], hz[HZ_620], dsp->genergy)) {
+                                       newstate = DSP_TONE_STATE_RINGING;
+                               } else if (pair_there(hz[HZ_350], hz[HZ_440], hz[HZ_480], hz[HZ_620], dsp->genergy)) {
+                                       newstate = DSP_TONE_STATE_DIALTONE;
+                               } else if (hz[HZ_950] > TONE_MIN_THRESH * TONE_THRESH) {
+                                       newstate = DSP_TONE_STATE_SPECIAL1;
+                               } else if (hz[HZ_1400] > TONE_MIN_THRESH * TONE_THRESH) {
+                                       if (dsp->tstate == DSP_TONE_STATE_SPECIAL1)
+                                               newstate = DSP_TONE_STATE_SPECIAL2;
+                               } else if (hz[HZ_1800] > TONE_MIN_THRESH * TONE_THRESH) {
+                                       if (dsp->tstate == DSP_TONE_STATE_SPECIAL2)
+                                               newstate = DSP_TONE_STATE_SPECIAL3;
+                               } else if (dsp->genergy > TONE_MIN_THRESH * TONE_THRESH) {
+                                       newstate = DSP_TONE_STATE_TALKING;
+                               } else
+                                       newstate = DSP_TONE_STATE_SILENCE;
+                               break;
+                       case PROG_MODE_CR:
+                               if (hz[HZ_425] > TONE_MIN_THRESH * TONE_THRESH) {
+                                       newstate = DSP_TONE_STATE_RINGING;
+                               } else if (dsp->genergy > TONE_MIN_THRESH * TONE_THRESH) {
+                                       newstate = DSP_TONE_STATE_TALKING;
+                               } else
+                                       newstate = DSP_TONE_STATE_SILENCE;
+                               break;
+                       case PROG_MODE_UK:
+                               if (hz[HZ_400] > TONE_MIN_THRESH * TONE_THRESH) {
+                                       newstate = DSP_TONE_STATE_HUNGUP;
+                               }
+                               break;
+                       default:
+                               ast_log(LOG_WARNING, "Can't process in unknown prog mode '%d'\n", dsp->progmode);
+                       }
                        if (newstate == dsp->tstate) {
                                dsp->tcount++;
-                               if (dsp->tcount == COUNT_THRESH) {
-                                       if (dsp->tstate == TONE_STATE_BUSY) {
-                                               res = AST_CONTROL_BUSY;
-                                               dsp->features &= ~DSP_FEATURE_CALL_PROGRESS;
-                                       } else if (dsp->tstate == TONE_STATE_TALKING) {
-                                               res = AST_CONTROL_ANSWER;
-                                               dsp->features &= ~DSP_FEATURE_CALL_PROGRESS;
-                                       } else if (dsp->tstate == TONE_STATE_RINGING)
-                                               res = AST_CONTROL_RINGING;
-                                       else if (dsp->tstate == TONE_STATE_SPECIAL3) {
-                                               res = AST_CONTROL_CONGESTION;
-                                               dsp->features &= ~DSP_FEATURE_CALL_PROGRESS;
-                                       }
-                                       
+                               if (dsp->ringtimeout)
+                                       dsp->ringtimeout++;
+                               switch (dsp->tstate) {
+                                       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;
+                               }
+                               if (dsp->ringtimeout==THRESH_RING2ANSWER) {
+#if 0
+                                       ast_log(LOG_NOTICE, "Consider call as answered because of timeout after last ring\n");
+#endif
+                                       res = AST_CONTROL_ANSWER;
+                                       dsp->features &= ~DSP_FEATURE_CALL_PROGRESS;
                                }
                        } else {
 #if 0
-                               printf("Newstate: %d\n", newstate);
+                               ast_log(LOG_NOTICE, "Stop state %d with duration %d\n", dsp->tstate, dsp->tcount);
+                               ast_log(LOG_NOTICE, "Start state %d\n", newstate);
 #endif
                                dsp->tstate = newstate;
                                dsp->tcount = 1;
@@ -958,28 +1202,48 @@ static int __ast_dsp_silence(struct ast_dsp *dsp, short *s, int len, int *totals
        int accum;
        int x;
        int res = 0;
-       
+
+       if (!len)
+               return 0;
        accum = 0;
        for (x=0;x<len; x++) 
                accum += abs(s[x]);
-       accum /= x;
+       accum /= len;
        if (accum < dsp->threshold) {
+               /* Silent */
                dsp->totalsilence += len/8;
                if (dsp->totalnoise) {
                        /* Move and save history */
-                       memmove(dsp->historicnoise, dsp->historicnoise + 1, sizeof(dsp->historicnoise) - sizeof(dsp->historicnoise[0]));
+                       memmove(dsp->historicnoise + DSP_HISTORY - dsp->busycount, dsp->historicnoise + DSP_HISTORY - dsp->busycount +1, dsp->busycount*sizeof(dsp->historicnoise[0]));
                        dsp->historicnoise[DSP_HISTORY - 1] = dsp->totalnoise;
+/* we don't want to check for busydetect that frequently */
+#if 0
                        dsp->busymaybe = 1;
+#endif
                }
                dsp->totalnoise = 0;
                res = 1;
        } else {
+               /* Not silent */
                dsp->totalnoise += len/8;
                if (dsp->totalsilence) {
+                       int silence1 = dsp->historicsilence[DSP_HISTORY - 1];
+                       int silence2 = dsp->historicsilence[DSP_HISTORY - 2];
                        /* Move and save history */
-                       memmove(dsp->historicsilence, dsp->historicsilence + 1, sizeof(dsp->historicsilence) - sizeof(dsp->historicsilence[0]));
+                       memmove(dsp->historicsilence + DSP_HISTORY - dsp->busycount, dsp->historicsilence + DSP_HISTORY - dsp->busycount + 1, dsp->busycount*sizeof(dsp->historicsilence[0]));
                        dsp->historicsilence[DSP_HISTORY - 1] = dsp->totalsilence;
-                       dsp->busymaybe = 1;
+                       /* check if the previous sample differs only by BUSY_PERCENT from the one before it */
+                       if (silence1 < silence2) {
+                               if (silence1 + silence1*BUSY_PERCENT/100 >= silence2)
+                                       dsp->busymaybe = 1;
+                               else 
+                                       dsp->busymaybe = 0;
+                       } else {
+                               if (silence1 - silence1*BUSY_PERCENT/100 <= silence2)
+                                       dsp->busymaybe = 1;
+                               else 
+                                       dsp->busymaybe = 0;
+                       }
                }
                dsp->totalsilence = 0;
        }
@@ -988,11 +1252,105 @@ static int __ast_dsp_silence(struct ast_dsp *dsp, short *s, int len, int *totals
        return res;
 }
 
+#ifdef BUSYDETECT_MARTIN
+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;
+       if (!dsp->busymaybe)
+               return res;
+       for (x=DSP_HISTORY - dsp->busycount;x<DSP_HISTORY;x++) {
+#ifndef BUSYDETECT_TONEONLY
+               avgsilence += dsp->historicsilence[x];
+#endif
+               avgtone += dsp->historicnoise[x];
+       }
+#ifndef BUSYDETECT_TONEONLY
+       avgsilence /= dsp->busycount;
+#endif
+       avgtone /= dsp->busycount;
+       for (x=DSP_HISTORY - dsp->busycount;x<DSP_HISTORY;x++) {
+#ifndef BUSYDETECT_TONEONLY
+               if (avgsilence > dsp->historicsilence[x]) {
+                       if (avgsilence - (avgsilence*BUSY_PERCENT/100) <= dsp->historicsilence[x])
+                               hitsilence++;
+               } else {
+                       if (avgsilence + (avgsilence*BUSY_PERCENT/100) >= dsp->historicsilence[x])
+                               hitsilence++;
+               }
+#endif
+               if (avgtone > dsp->historicnoise[x]) {
+                       if (avgtone - (avgtone*BUSY_PERCENT/100) <= dsp->historicnoise[x])
+                               hittone++;
+               } else {
+                       if (avgtone + (avgtone*BUSY_PERCENT/100) >= dsp->historicnoise[x])
+                               hittone++;
+               }
+       }
+#ifndef BUSYDETECT_TONEONLY
+       if ((hittone >= dsp->busycount - 1) && (hitsilence >= dsp->busycount - 1) && 
+           (avgtone >= BUSY_MIN && avgtone <= BUSY_MAX) && 
+           (avgsilence >= BUSY_MIN && avgsilence <= BUSY_MAX)) {
+#else
+       if ((hittone >= dsp->busycount - 1) && (avgtone >= BUSY_MIN && avgtone <= BUSY_MAX)) {
+#endif
+#ifdef BUSYDETECT_COMPARE_TONE_AND_SILENCE
+#ifdef BUSYDETECT_TONEONLY
+#error You cant use BUSYDETECT_TONEONLY together with BUSYDETECT_COMPARE_TONE_AND_SILENCE
+#endif
+               if (avgtone > avgsilence) {
+                       if (avgtone - avgtone*BUSY_PERCENT/100 <= avgsilence)
+                               res = 1;
+               } else {
+                       if (avgtone + avgtone*BUSY_PERCENT/100 >= avgsilence)
+                               res = 1;
+               }
+#else
+               res = 1;
+#endif
+       }
+       /* If we know the expected busy tone length, check we are in the range */
+       if (res && (dsp->busy_tonelength > 0)) {
+               if (abs(avgtone - dsp->busy_tonelength) > (dsp->busy_tonelength*BUSY_PAT_PERCENT/100)) {
+#if 0
+                       ast_log(LOG_NOTICE, "busy detector: avgtone of %d not close enough to desired %d\n",
+                                               avgtone, dsp->busy_tonelength);
+#endif
+                       res = 0;
+               }
+       }
+       /* If we know the expected busy tone silent-period length, check we are in the range */
+       if (res && (dsp->busy_quietlength > 0)) {
+               if (abs(avgsilence - dsp->busy_quietlength) > (dsp->busy_quietlength*BUSY_PAT_PERCENT/100)) {
+#if 0
+                       ast_log(LOG_NOTICE, "busy detector: avgsilence of %d not close enough to desired %d\n",
+                                               avgsilence, dsp->busy_quietlength);
+#endif
+                       res = 0;
+               }
+       }
+#if 1
+       if (res)
+               ast_log(LOG_DEBUG, "ast_dsp_busydetect detected busy, avgtone: %d, avgsilence %d\n", avgtone, avgsilence);
+#endif
+       return res;
+}
+#endif
+
+#ifdef BUSYDETECT
 int ast_dsp_busydetect(struct ast_dsp *dsp)
 {
        int x;
        int res = 0;
        int max, min;
+
+#if 0
+       if (dsp->busy_hits > 5);
+       return 0;
+#endif
        if (dsp->busymaybe) {
 #if 0
                printf("Maybe busy!\n");
@@ -1025,6 +1383,7 @@ int ast_dsp_busydetect(struct ast_dsp *dsp)
        }
        return res;
 }
+#endif
 
 int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
 {
@@ -1044,13 +1403,13 @@ int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
        return __ast_dsp_silence(dsp, s, len, totalsilence);
 }
 
-struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, struct ast_frame *af, int needlock)
+struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, struct ast_frame *af)
 {
        int silence;
        int res;
        int digit;
        int x;
-       unsigned short *shortdata;
+       short *shortdata;
        unsigned char *odata;
        int len;
        int writeback = 0;
@@ -1062,11 +1421,11 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
                                break; \
                        case AST_FORMAT_ULAW: \
                                for (x=0;x<len;x++) \
-                                       odata[x] = AST_LIN2MU(shortdata[x]); \
+                                       odata[x] = AST_LIN2MU((unsigned short)shortdata[x]); \
                                break; \
                        case AST_FORMAT_ALAW: \
                                for (x=0;x<len;x++) \
-                                       odata[x] = AST_LIN2A(shortdata[x]); \
+                                       odata[x] = AST_LIN2A((unsigned short)shortdata[x]); \
                                break; \
                        } \
                } \
@@ -1085,8 +1444,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
                len = af->datalen / 2;
                break;
        case AST_FORMAT_ULAW:
-               shortdata = alloca(af->datalen * 2);
-               if (!shortdata) {
+               if (!(shortdata = alloca(af->datalen * 2))) {
                        ast_log(LOG_WARNING, "Unable to allocate stack space for data: %s\n", strerror(errno));
                        return af;
                }
@@ -1094,8 +1452,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
                        shortdata[x] = AST_MULAW(odata[x]);
                break;
        case AST_FORMAT_ALAW:
-               shortdata = alloca(af->datalen * 2);
-               if (!shortdata) {
+               if (!(shortdata = alloca(af->datalen * 2))) {
                        ast_log(LOG_WARNING, "Unable to allocate stack space for data: %s\n", strerror(errno));
                        return af;
                }
@@ -1103,7 +1460,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
                        shortdata[x] = AST_ALAW(odata[x]);
                break;
        default:
-               ast_log(LOG_WARNING, "Unable to detect process %d frames\n", af->subclass);
+               ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(af->subclass));
                return af;
        }
        silence = __ast_dsp_silence(dsp, shortdata, len, NULL);
@@ -1113,9 +1470,11 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
                return &dsp->f;
        }
        if ((dsp->features & DSP_FEATURE_BUSY_DETECT) && ast_dsp_busydetect(dsp)) {
+               chan->_softhangup |= AST_SOFTHANGUP_DEV;
                memset(&dsp->f, 0, sizeof(dsp->f));
                dsp->f.frametype = AST_FRAME_CONTROL;
                dsp->f.subclass = AST_CONTROL_BUSY;
+               ast_log(LOG_DEBUG, "Requesting Hangup because the busy tone was detected on channel %s\n", chan->name);
                return &dsp->f;
        }
        if ((dsp->features & DSP_FEATURE_DTMF_DETECT)) {
@@ -1127,14 +1486,15 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
                if (dsp->digitmode & (DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX)) {
                        if (!dsp->thinkdigit) {
                                if (digit) {
-                                       /* Looks like we might have something.  Request a conference mute for the moment */
+                                       /* Looks like we might have something.  
+                                        * Request a conference mute for the moment */
                                        memset(&dsp->f, 0, sizeof(dsp->f));
                                        dsp->f.frametype = AST_FRAME_DTMF;
                                        dsp->f.subclass = 'm';
                                        dsp->thinkdigit = 'x';
                                        FIX_INF(af);
                                        if (chan)
-                                               ast_queue_frame(chan, af, needlock);
+                                               ast_queue_frame(chan, af);
                                        ast_frfree(af);
                                        return &dsp->f;
                                }
@@ -1142,7 +1502,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
                                if (digit) {
                                        /* Thought we saw one last time.  Pretty sure we really have now */
                                        if (dsp->thinkdigit) {
-                                               if (dsp->thinkdigit != 'x') {
+                                               if ((dsp->thinkdigit != 'x') && (dsp->thinkdigit != digit)) {
                                                        /* If we found a digit, and we're changing digits, go
                                                           ahead and send this one, but DON'T stop confmute because
                                                           we're detecting something else, too... */
@@ -1151,12 +1511,13 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
                                                        dsp->f.subclass = dsp->thinkdigit;
                                                        FIX_INF(af);
                                                        if (chan)
-                                                               ast_queue_frame(chan, af, needlock);
+                                                               ast_queue_frame(chan, af);
                                                        ast_frfree(af);
                                                }
                                                dsp->thinkdigit = digit;
                                                return &dsp->f;
                                        }
+                                       dsp->thinkdigit = digit;
                                } else {
                                        if (dsp->thinkdigit) {
                                                memset(&dsp->f, 0, sizeof(dsp->f));
@@ -1164,15 +1525,15 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
                                                        /* If we found a digit, send it now */
                                                        dsp->f.frametype = AST_FRAME_DTMF;
                                                        dsp->f.subclass = dsp->thinkdigit;
-                                                       if (chan)
-                                                               ast_queue_frame(chan, &dsp->f, needlock);
+                                                       dsp->thinkdigit = 0;
+                                               } else {
+                                                       dsp->f.frametype = AST_FRAME_DTMF;
+                                                       dsp->f.subclass = 'u';
+                                                       dsp->thinkdigit = 0;
                                                }
-                                               dsp->f.frametype = AST_FRAME_DTMF;
-                                               dsp->f.subclass = 'u';
-                                               dsp->thinkdigit = 0;
                                                FIX_INF(af);
                                                if (chan)
-                                                       ast_queue_frame(chan, af, needlock);
+                                                       ast_queue_frame(chan, af);
                                                ast_frfree(af);
                                                return &dsp->f;
                                        }
@@ -1189,7 +1550,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
                                        dsp->td.mf.current_digits--;
                                        FIX_INF(af);
                                        if (chan)
-                                               ast_queue_frame(chan, af, needlock);
+                                               ast_queue_frame(chan, af);
                                        ast_frfree(af);
                                        return &dsp->f;
                                }
@@ -1202,7 +1563,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
                                        dsp->td.dtmf.current_digits--;
                                        FIX_INF(af);
                                        if (chan)
-                                               ast_queue_frame(chan, af, needlock);
+                                               ast_queue_frame(chan, af);
                                        ast_frfree(af);
                                        return &dsp->f;
                                }
@@ -1211,17 +1572,19 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
        }
        if ((dsp->features & DSP_FEATURE_CALL_PROGRESS)) {
                res = __ast_dsp_call_progress(dsp, shortdata, len);
-               memset(&dsp->f, 0, sizeof(dsp->f));
-               dsp->f.frametype = AST_FRAME_CONTROL;
                if (res) {
                        switch(res) {
                        case AST_CONTROL_ANSWER:
                        case AST_CONTROL_BUSY:
                        case AST_CONTROL_RINGING:
                        case AST_CONTROL_CONGESTION:
+                       case AST_CONTROL_HANGUP:
+                               memset(&dsp->f, 0, sizeof(dsp->f));
+                               dsp->f.frametype = AST_FRAME_CONTROL;
                                dsp->f.subclass = res;
+                               dsp->f.src = "dsp_progress";
                                if (chan) 
-                                       ast_queue_frame(chan, &dsp->f, needlock);
+                                       ast_queue_frame(chan, &dsp->f);
                                break;
                        default:
                                ast_log(LOG_WARNING, "Don't know how to represent call progress message %d\n", res);
@@ -1232,25 +1595,35 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
        return af;
 }
 
+static void ast_dsp_prog_reset(struct ast_dsp *dsp)
+{
+       int max = 0;
+       int x;
+       
+       dsp->gsamp_size = modes[dsp->progmode].size;
+       dsp->gsamps = 0;
+       for (x=0;x<sizeof(modes[dsp->progmode].freqs) / sizeof(modes[dsp->progmode].freqs[0]);x++) {
+               if (modes[dsp->progmode].freqs[x]) {
+                       goertzel_init(&dsp->freqs[x], (float)modes[dsp->progmode].freqs[x], dsp->gsamp_size);
+                       max = x + 1;
+               }
+       }
+       dsp->freqcount = max;
+       dsp->ringtimeout= 0;
+}
+
 struct ast_dsp *ast_dsp_new(void)
 {
        struct ast_dsp *dsp;
-       dsp = malloc(sizeof(struct ast_dsp));
-       if (dsp) {
-               memset(dsp, 0, sizeof(struct ast_dsp));
+       
+       if ((dsp = ast_calloc(1, sizeof(*dsp)))) {              
                dsp->threshold = DEFAULT_THRESHOLD;
                dsp->features = DSP_FEATURE_SILENCE_SUPPRESS;
-               dsp->busycount = 3;
-               /* Initialize goertzels */
-               goertzel_init(&dsp->freqs[HZ_350], 350.0);
-               goertzel_init(&dsp->freqs[HZ_440], 440.0);
-               goertzel_init(&dsp->freqs[HZ_480], 480.0);
-               goertzel_init(&dsp->freqs[HZ_620], 620.0);
-               goertzel_init(&dsp->freqs[HZ_950], 950.0);
-               goertzel_init(&dsp->freqs[HZ_1400], 1400.0);
-               goertzel_init(&dsp->freqs[HZ_1800], 1800.0);
+               dsp->busycount = DSP_HISTORY;
                /* Initialize DTMF detector */
                ast_dtmf_detect_init(&dsp->td.dtmf);
+               /* Initialize initial DSP progress detect parameters */
+               ast_dsp_prog_reset(dsp);
        }
        return dsp;
 }
@@ -1265,63 +1638,95 @@ void ast_dsp_free(struct ast_dsp *dsp)
        free(dsp);
 }
 
+void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
+{
+       dsp->threshold = threshold;
+}
+
 void ast_dsp_set_busy_count(struct ast_dsp *dsp, int cadences)
 {
-       if (cadences < 1)
-               cadences = 1;
+       if (cadences < 4)
+               cadences = 4;
        if (cadences > DSP_HISTORY)
                cadences = DSP_HISTORY;
        dsp->busycount = cadences;
 }
 
+void ast_dsp_set_busy_pattern(struct ast_dsp *dsp, int tonelength, int quietlength)
+{
+       dsp->busy_tonelength = tonelength;
+       dsp->busy_quietlength = quietlength;
+       ast_log(LOG_DEBUG, "dsp busy pattern set to %d,%d\n", tonelength, quietlength);
+}
+
 void ast_dsp_digitreset(struct ast_dsp *dsp)
 {
        int i;
+       
        dsp->thinkdigit = 0;
        if (dsp->digitmode & DSP_DIGITMODE_MF) {
                memset(dsp->td.mf.digits, 0, sizeof(dsp->td.mf.digits));
                dsp->td.mf.current_digits = 0;
                /* Reinitialise the detector for the next block */
                for (i = 0;  i < 6;  i++) {
-               goertzel_reset(&dsp->td.mf.tone_out[i]);
-                   goertzel_reset(&dsp->td.mf.tone_out2nd[i]);
+                       goertzel_reset(&dsp->td.mf.tone_out[i]);
+#ifdef OLD_DSP_ROUTINES
+                       goertzel_reset(&dsp->td.mf.tone_out2nd[i]);
+#endif                 
                }
+#ifdef OLD_DSP_ROUTINES
                dsp->td.mf.energy = 0.0;
+               dsp->td.mf.hit1 = dsp->td.mf.hit2 = dsp->td.mf.hit3 = dsp->td.mf.hit4 = dsp->td.mf.mhit = 0;
+#else
+               dsp->td.mf.hits[4] = dsp->td.mf.hits[3] = dsp->td.mf.hits[2] = dsp->td.mf.hits[1] = dsp->td.mf.hits[0] = dsp->td.mf.mhit = 0;
+#endif         
                dsp->td.mf.current_sample = 0;
-           dsp->td.mf.hit1 = dsp->td.mf.hit2 = dsp->td.mf.hit3 = dsp->td.mf.hit4 = dsp->td.mf.mhit = 0;
        } else {
                memset(dsp->td.dtmf.digits, 0, sizeof(dsp->td.dtmf.digits));
                dsp->td.dtmf.current_digits = 0;
                /* Reinitialise the detector for the next block */
                for (i = 0;  i < 4;  i++) {
-               goertzel_reset(&dsp->td.dtmf.row_out[i]);
-                   goertzel_reset(&dsp->td.dtmf.col_out[i]);
-               goertzel_reset(&dsp->td.dtmf.row_out2nd[i]);
-               goertzel_reset(&dsp->td.dtmf.col_out2nd[i]);
+                       goertzel_reset(&dsp->td.dtmf.row_out[i]);
+                       goertzel_reset(&dsp->td.dtmf.col_out[i]);
+#ifdef OLD_DSP_ROUTINES
+                       goertzel_reset(&dsp->td.dtmf.row_out2nd[i]);
+                       goertzel_reset(&dsp->td.dtmf.col_out2nd[i]);
+#endif                 
                }
-           goertzel_reset (&dsp->td.dtmf.fax_tone);
-           goertzel_reset (&dsp->td.dtmf.fax_tone2nd);
+#ifdef FAX_DETECT
+               goertzel_reset (&dsp->td.dtmf.fax_tone);
+#endif
+#ifdef OLD_DSP_ROUTINES
+#ifdef FAX_DETECT
+               goertzel_reset (&dsp->td.dtmf.fax_tone2nd);
+#endif
+               dsp->td.dtmf.hit1 = dsp->td.dtmf.hit2 = dsp->td.dtmf.hit3 = dsp->td.dtmf.hit4 = dsp->td.dtmf.mhit = 0;
+#else
+               dsp->td.dtmf.hits[2] = dsp->td.dtmf.hits[1] = dsp->td.dtmf.hits[0] =  dsp->td.dtmf.mhit = 0;
+#endif         
                dsp->td.dtmf.energy = 0.0;
                dsp->td.dtmf.current_sample = 0;
-           dsp->td.dtmf.hit1 = dsp->td.dtmf.hit2 = dsp->td.dtmf.hit3 = dsp->td.dtmf.hit4 = dsp->td.dtmf.mhit = 0;
        }
 }
 
 void ast_dsp_reset(struct ast_dsp *dsp)
 {
        int x;
+       
        dsp->totalsilence = 0;
        dsp->gsamps = 0;
        for (x=0;x<4;x++)
                dsp->freqs[x].v2 = dsp->freqs[x].v3 = 0.0;
        memset(dsp->historicsilence, 0, sizeof(dsp->historicsilence));
-       memset(dsp->historicnoise, 0, sizeof(dsp->historicnoise));
-       
+       memset(dsp->historicnoise, 0, sizeof(dsp->historicnoise));      
+       dsp->ringtimeout= 0;
 }
 
 int ast_dsp_digitmode(struct ast_dsp *dsp, int digitmode)
 {
-       int new, old;
+       int new;
+       int old;
+       
        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) {
@@ -1334,3 +1739,27 @@ int ast_dsp_digitmode(struct ast_dsp *dsp, int digitmode)
        dsp->digitmode = digitmode;
        return 0;
 }
+
+int ast_dsp_set_call_progress_zone(struct ast_dsp *dsp, char *zone)
+{
+       int x;
+       
+       for (x=0;x<sizeof(aliases) / sizeof(aliases[0]);x++) {
+               if (!strcasecmp(aliases[x].name, zone)) {
+                       dsp->progmode = aliases[x].mode;
+                       ast_dsp_prog_reset(dsp);
+                       return 0;
+               }
+       }
+       return -1;
+}
+
+int ast_dsp_get_tstate(struct ast_dsp *dsp) 
+{
+       return dsp->tstate;
+}
+
+int ast_dsp_get_tcount(struct ast_dsp *dsp) 
+{
+       return dsp->tcount;
+}