diff options
author | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-08-21 02:11:39 +0000 |
---|---|---|
committer | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-08-21 02:11:39 +0000 |
commit | 8b0c007ad990aa27d9868da49215fd1076ac77cc (patch) | |
tree | 270b9c46c1e644483d6d2a35b509f43218ba3252 /dsp.c | |
parent | a42edc84034f91932a3e12d503e07f76a6eb498a (diff) |
merge new_loader_completion branch, including (at least):
- restructured build tree and makefiles to eliminate recursion problems
- support for embedded modules
- support for static builds
- simpler cross-compilation support
- simpler module/loader interface (no exported symbols)
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@40722 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'dsp.c')
-rw-r--r-- | dsp.c | 1761 |
1 files changed, 0 insertions, 1761 deletions
diff --git a/dsp.c b/dsp.c deleted file mode 100644 index 7e62c8bf7..000000000 --- a/dsp.c +++ /dev/null @@ -1,1761 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * 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 */ -/* - tone_detect.c - General telephony tone detection, and specific - detection of DTMF. - - Copyright (C) 2001 Steve Underwood <steveu@coppice.org> - - Despite my general liking of the GPL, I place this code in the - public domain for the benefit of all mankind - even the slimy - ones who might try to proprietize my work and use it to my - detriment. -*/ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include <sys/types.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <math.h> -#include <errno.h> -#include <stdio.h> - -#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 */ -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 */ -}; - -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 DEFAULT_THRESHOLD 512 - -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 */ -}; - -/*! 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: - * - * Minimum tone on = 40ms - * Minimum tone off = 50ms - * Maximum digit rate = 10 per second - * Normal twist <= 8dB accepted - * Reverse twist <= 4dB accepted - * S/N >= 15dB will detect OK - * Attenuation <= 26dB will detect OK - * Frequency tolerance +- 1.5% will detect, +-3.5% will reject - */ - -#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 */ -#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_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 - -#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 -{ - goertzel_state_t row_out[4]; - goertzel_state_t col_out[4]; -#ifdef FAX_DETECT - goertzel_state_t fax_tone; -#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 -{ - 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 -}; -static float dtmf_col[] = -{ - 1209.0, 1336.0, 1477.0, 1633.0 -}; - -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' }, - /* 1100 + */ { '2', '3', 0, '6', '9', '*' }, - /* 1300 + */ { '4', '5', '6', 0, '0', 'B' }, - /* 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; -} - -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]); -} - - -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, 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) -{ - s->v2 = s->v3 = 0.0; -} - -struct ast_dsp { - struct ast_frame f; - int threshold; - 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; - int thinkdigit; - float genergy; - union { - dtmf_detect_state_t dtmf; - mf_detect_state_t mf; - } td; -}; - -static void ast_dtmf_detect_init (dtmf_detect_state_t *s) -{ - 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, 102); - -#ifdef OLD_DSP_ROUTINES - /* Same for the fax dector 2nd harmonic */ - 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'; -} - -static void ast_mf_detect_init (mf_detect_state_t *s) -{ - 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; -} - -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]; -#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); -#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; -#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; -#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) { - 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 */ - for (i=sample;i<limit;i++) - amp[i] = 0; - *writeback = 1; - } - continue; - } -#ifdef FAX_DETECT - /* Detect the fax energy, too */ - fax_energy = goertzel_result(&s->fax_tone); -#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]; - 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 */ -#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\n", fax_energy); -#endif - /* 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++; - } - } - s->fax_hits = 0; - } -#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); -} - -/* 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) -{ -#ifdef OLD_DSP_ROUTINES - float tone_energy[6]; - int best1; - int best2; - float max; - int sofarsogood; -#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); -#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]; -#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) { - 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 */ - for (i=sample;i<limit;i++) - amp[i] = 0; - *writeback = 1; - } - 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]; - for (i=1;i<6;i++) { - if (tone_energy[i] > max) { - max = tone_energy[i]; - best1 = i; - } - } - - /* Find 2nd highest */ - if (best1) { - max = tone_energy[0]; - best2 = 0; - } else { - max = tone_energy[1]; - best2 = 1; - } - - for (i=0;i<6;i++) { - if (i == best1) continue; - if (tone_energy[i] > max) { - max = tone_energy[i]; - best2 = i; - } - } - 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 (tone_energy[best1] < tone_energy[i] * MF_RELATIVE_PEAK) { - sofarsogood = 0; - break; - } - if (tone_energy[best2] < tone_energy[i] * MF_RELATIVE_PEAK) { - sofarsogood = 0; - break; - } - } - - if (sofarsogood) { - /* Check for 2nd harmonic */ - if (goertzel_result(&s->tone_out2nd[best1]) * MF_2ND_HARMONIC > tone_energy[best1]) - sofarsogood = 0; - else if (goertzel_result(&s->tone_out2nd[best2]) * MF_2ND_HARMONIC > tone_energy[best2]) - sofarsogood = 0; - } - if (sofarsogood) { - hit = mf_hit[best1][best2]; - 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 consecutive clean hits */ - if ((hit == s->hit3) && (s->hit3 != s->hit2)) { - s->mhit = hit; - s->detected_digits++; - if (s->current_digits < MAX_DTMF_DIGITS - 2) { - s->digits[s->current_digits++] = hit; - s->digits[s->current_digits] = '\0'; - } else { - s->lost_digits++; - } - } - } - - 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; - } -#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); -} - -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, dsp->features & DSP_FEATURE_FAX_DETECT); - return res; -} - -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; - } - if (inf->subclass != AST_FORMAT_SLINEAR) { - ast_log(LOG_WARNING, "Can only check call progress in signed-linear frames\n"); - return 0; - } - s = inf->data; - len = inf->datalen / 2; - return __ast_dsp_digitdetect(dsp, s, len, &ign); -} - -static inline int pair_there(float p1, float p2, float i1, float i2, float e) -{ - /* See if p1 and p2 are there, relative to i1 and i2 and total energy */ - /* Make sure absolute levels are high enough */ - if ((p1 < TONE_MIN_THRESH) || (p2 < TONE_MIN_THRESH)) - return 0; - /* Amplify ignored stuff */ - i2 *= TONE_THRESH; - i1 *= TONE_THRESH; - e *= TONE_THRESH; - /* Check first tone */ - if ((p1 < i1) || (p1 < i2) || (p1 < e)) - return 0; - /* And second */ - if ((p2 < i1) || (p2 < i2) || (p2 < e)) - return 0; - /* Guess it's there... */ - return 1; -} - -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; - } 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; - } -} - -static int __ast_dsp_call_progress(struct ast_dsp *dsp, short *s, int len) -{ - int x; - int y; - int pass; - 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 > dsp->gsamp_size - dsp->gsamps) - pass = dsp->gsamp_size - dsp->gsamps; - for (x=0;x<pass;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 == dsp->gsamp_size) { - float hz[7]; - for (y=0;y<7;y++) - hz[y] = goertzel_result(&dsp->freqs[y]); -#if 0 - 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 - 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->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 - 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; - } - - /* Reset goertzel */ - for (x=0;x<7;x++) - dsp->freqs[x].v2 = dsp->freqs[x].v3 = 0.0; - dsp->gsamps = 0; - dsp->genergy = 0.0; - } - } -#if 0 - if (res) - printf("Returning %d\n", res); -#endif - return res; -} - -int ast_dsp_call_progress(struct ast_dsp *dsp, struct ast_frame *inf) -{ - if (inf->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Can't check call progress of non-voice frames\n"); - return 0; - } - if (inf->subclass != AST_FORMAT_SLINEAR) { - ast_log(LOG_WARNING, "Can only check call progress in signed-linear frames\n"); - return 0; - } - return __ast_dsp_call_progress(dsp, inf->data, inf->datalen / 2); -} - -static int __ast_dsp_silence(struct ast_dsp *dsp, short *s, int len, int *totalsilence) -{ - int accum; - int x; - int res = 0; - - if (!len) - return 0; - accum = 0; - for (x=0;x<len; x++) - accum += abs(s[x]); - accum /= len; - if (accum < dsp->threshold) { - /* Silent */ - dsp->totalsilence += len/8; - if (dsp->totalnoise) { - /* Move and save history */ - 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_HISTORY - dsp->busycount, dsp->historicsilence + DSP_HISTORY - dsp->busycount + 1, dsp->busycount*sizeof(dsp->historicsilence[0])); - dsp->historicsilence[DSP_HISTORY - 1] = dsp->totalsilence; - /* 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; - } - if (totalsilence) - *totalsilence = dsp->totalsilence; - 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; - } - } -#ifndef BUSYDETECT_TONEONLY - /* 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; - } - } -#endif -#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"); -#endif - dsp->busymaybe = 0; - min = 9999; - max = 0; - for (x=DSP_HISTORY - dsp->busycount;x<DSP_HISTORY;x++) { -#if 0 - printf("Silence: %d, Noise: %d\n", dsp->historicsilence[x], dsp->historicnoise[x]); -#endif - if (dsp->historicsilence[x] < min) - min = dsp->historicsilence[x]; - if (dsp->historicnoise[x] < min) - min = dsp->historicnoise[x]; - if (dsp->historicsilence[x] > max) - max = dsp->historicsilence[x]; - if (dsp->historicnoise[x] > max) - max = dsp->historicnoise[x]; - } - if ((max - min < BUSY_THRESHOLD) && (max < BUSY_MAX) && (min > BUSY_MIN)) { -#if 0 - printf("Busy!\n"); -#endif - res = 1; - } -#if 0 - printf("Min: %d, max: %d\n", min, max); -#endif - } - return res; -} -#endif - -int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence) -{ - short *s; - int len; - - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Can't calculate silence on a non-voice frame\n"); - return 0; - } - if (f->subclass != AST_FORMAT_SLINEAR) { - ast_log(LOG_WARNING, "Can only calculate silence on signed-linear frames :(\n"); - return 0; - } - s = f->data; - len = f->datalen/2; - 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 silence; - int res; - int digit; - int x; - short *shortdata; - unsigned char *odata; - int len; - int writeback = 0; - -#define FIX_INF(inf) do { \ - if (writeback) { \ - switch(inf->subclass) { \ - case AST_FORMAT_SLINEAR: \ - break; \ - case AST_FORMAT_ULAW: \ - for (x=0;x<len;x++) \ - odata[x] = AST_LIN2MU((unsigned short)shortdata[x]); \ - break; \ - case AST_FORMAT_ALAW: \ - for (x=0;x<len;x++) \ - odata[x] = AST_LIN2A((unsigned short)shortdata[x]); \ - break; \ - } \ - } \ - } while(0) - - if (!af) - return NULL; - if (af->frametype != AST_FRAME_VOICE) - return af; - odata = af->data; - len = af->datalen; - /* Make sure we have short data */ - switch(af->subclass) { - case AST_FORMAT_SLINEAR: - shortdata = af->data; - len = af->datalen / 2; - break; - case AST_FORMAT_ULAW: - shortdata = alloca(af->datalen * 2); - for (x = 0;x < len; x++) - shortdata[x] = AST_MULAW(odata[x]); - break; - case AST_FORMAT_ALAW: - shortdata = alloca(af->datalen * 2); - for (x = 0; x < len; x++) - shortdata[x] = AST_ALAW(odata[x]); - break; - default: - 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); - if ((dsp->features & DSP_FEATURE_SILENCE_SUPPRESS) && silence) { - memset(&dsp->f, 0, sizeof(dsp->f)); - dsp->f.frametype = AST_FRAME_NULL; - 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)) { - digit = __ast_dsp_digitdetect(dsp, shortdata, len, &writeback); -#if 0 - if (digit) - printf("Performing digit detection returned %d, digitmode is %d\n", digit, dsp->digitmode); -#endif - 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 */ - 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); - ast_frfree(af); - return &dsp->f; - } - } else { - if (digit) { - /* Thought we saw one last time. Pretty sure we really have now */ - if (dsp->thinkdigit) { - 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... */ - memset(&dsp->f, 0, sizeof(dsp->f)); - dsp->f.frametype = AST_FRAME_DTMF; - dsp->f.subclass = dsp->thinkdigit; - FIX_INF(af); - if (chan) - 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)); - if (dsp->thinkdigit != 'x') { - /* If we found a digit, send it now */ - dsp->f.frametype = AST_FRAME_DTMF; - dsp->f.subclass = dsp->thinkdigit; - dsp->thinkdigit = 0; - } else { - dsp->f.frametype = AST_FRAME_DTMF; - dsp->f.subclass = 'u'; - dsp->thinkdigit = 0; - } - FIX_INF(af); - if (chan) - ast_queue_frame(chan, af); - ast_frfree(af); - return &dsp->f; - } - } - } - } else if (!digit) { - /* Only check when there is *not* a hit... */ - if (dsp->digitmode & DSP_DIGITMODE_MF) { - if (dsp->td.mf.current_digits) { - memset(&dsp->f, 0, sizeof(dsp->f)); - dsp->f.frametype = AST_FRAME_DTMF; - dsp->f.subclass = dsp->td.mf.digits[0]; - memmove(dsp->td.mf.digits, dsp->td.mf.digits + 1, dsp->td.mf.current_digits); - dsp->td.mf.current_digits--; - FIX_INF(af); - if (chan) - ast_queue_frame(chan, af); - ast_frfree(af); - return &dsp->f; - } - } else { - if (dsp->td.dtmf.current_digits) { - memset(&dsp->f, 0, sizeof(dsp->f)); - dsp->f.frametype = AST_FRAME_DTMF; - dsp->f.subclass = dsp->td.dtmf.digits[0]; - memmove(dsp->td.dtmf.digits, dsp->td.dtmf.digits + 1, dsp->td.dtmf.current_digits); - dsp->td.dtmf.current_digits--; - FIX_INF(af); - if (chan) - ast_queue_frame(chan, af); - ast_frfree(af); - return &dsp->f; - } - } - } - } - if ((dsp->features & DSP_FEATURE_CALL_PROGRESS)) { - res = __ast_dsp_call_progress(dsp, shortdata, len); - 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); - break; - default: - ast_log(LOG_WARNING, "Don't know how to represent call progress message %d\n", res); - } - } - } - FIX_INF(af); - 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; - - if ((dsp = ast_calloc(1, sizeof(*dsp)))) { - dsp->threshold = DEFAULT_THRESHOLD; - dsp->features = DSP_FEATURE_SILENCE_SUPPRESS; - 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; -} - -void ast_dsp_set_features(struct ast_dsp *dsp, int features) -{ - dsp->features = features; -} - -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 < 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]); -#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; - } 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]); -#ifdef OLD_DSP_ROUTINES - goertzel_reset(&dsp->td.dtmf.row_out2nd[i]); - goertzel_reset(&dsp->td.dtmf.col_out2nd[i]); -#endif - } -#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; - } -} - -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)); - dsp->ringtimeout= 0; -} - -int ast_dsp_digitmode(struct ast_dsp *dsp, int digitmode) -{ - 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) { - /* Must initialize structures if switching from MF to DTMF or vice-versa */ - if (new & DSP_DIGITMODE_MF) - ast_mf_detect_init(&dsp->td.mf); - else - ast_dtmf_detect_init(&dsp->td.dtmf); - } - 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; -} |