123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746 |
- /*
- * Asterisk -- A telephony toolkit for Linux.
- *
- * Convenience Signal Processing routines
- *
- * Copyright (C) 2002, Digium
- *
- * Mark Spencer <markster@linux-support.net>
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License.
- *
- * Goertzel routines are borrowed from Steve Underwood's tremendous work on the
- * DTMF detector.
- *
- */
- /* 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 <sys/types.h>
- #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 <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <math.h>
- #include <errno.h>
- #include <stdio.h>
- /* Number of goertzels for progress detect */
- #define GSAMP_SIZE_NA 183 /* North America - 350, 440, 480, 620, 950, 1400, 1800 Hz */
- #define GSAMP_SIZE_CR 188 /* Costa Rica - Only care about 425 Hz */
- #define PROG_MODE_NA 0
- #define PROG_MODE_CR 1
- /* For US modes */
- #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
- /* For CR modes */
- #define HZ_425 0
- static struct progalias {
- char *name;
- int mode;
- } aliases[] = {
- { "us", PROG_MODE_NA },
- { "ca", PROG_MODE_NA },
- { "cr", PROG_MODE_CR },
- };
- static struct progress {
- int size;
- int freqs[7];
- } modes[] = {
- { GSAMP_SIZE_NA, { 350, 440, 480, 620, 950, 1400, 1800 } }, /* North America */
- { GSAMP_SIZE_CR, { 425 } },
- };
- #define DEFAULT_THRESHOLD 512
- #define BUSY_PERCENT 10 /* The percentage diffrence between the two last silence periods */
- #define BUSY_THRESHOLD 100 /* Max number of ms difference between max and min times in busy */
- #define BUSY_MIN 75 /* 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 */
- /* 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 */
- #define COUNT_THRESH 3 /* Need at least 50ms of stuff to count it */
- #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
- #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
- 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 busymaybe;
- int busycount;
- int historicnoise[DSP_HISTORY];
- int historicsilence[DSP_HISTORY];
- goertzel_state_t freqs[7];
- int freqcount;
- int gsamps;
- int gsamp_size;
- int 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 = 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 = TONE_STATE_BUSY;
- } else if (pair_there(hz[HZ_440], hz[HZ_480], hz[HZ_350], hz[HZ_620], dsp->genergy)) {
- newstate = TONE_STATE_RINGING;
- } else if (pair_there(hz[HZ_350], hz[HZ_440], hz[HZ_480], hz[HZ_620], dsp->genergy)) {
- newstate = TONE_STATE_DIALTONE;
- } else if (hz[HZ_950] > TONE_MIN_THRESH * TONE_THRESH) {
- newstate = TONE_STATE_SPECIAL1;
- } else if (hz[HZ_1400] > TONE_MIN_THRESH * TONE_THRESH) {
- if (dsp->tstate == TONE_STATE_SPECIAL1)
- newstate = TONE_STATE_SPECIAL2;
- } else if (hz[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;
- break;
- case PROG_MODE_CR:
- if (hz[HZ_425] > TONE_MIN_THRESH * TONE_THRESH) {
- newstate = TONE_STATE_RINGING;
- } else if (dsp->genergy > TONE_MIN_THRESH * TONE_THRESH) {
- newstate = TONE_STATE_TALKING;
- } else
- newstate = TONE_STATE_SILENCE;
- 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;
- }
-
- }
- } else {
- #if 0
- printf("Newstate: %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) {
- 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 {
- 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 >= silence2)
- dsp->busymaybe = 1;
- else
- dsp->busymaybe = 0;
- } else {
- if (silence1 - silence1/BUSY_PERCENT <= 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) <= dsp->historicsilence[x])
- hitsilence++;
- } else {
- if (avgsilence + (avgsilence / BUSY_PERCENT) >= dsp->historicsilence[x])
- hitsilence++;
- }
- #endif
- if (avgtone > dsp->historicnoise[x]) {
- if (avgtone - (avgtone / BUSY_PERCENT) <= dsp->historicnoise[x])
- hittone++;
- } else {
- if (avgtone + (avgtone / BUSY_PERCENT) >= 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*2) <= avgsilence)
- res = 1;
- } else {
- if (avgtone + avgtone/(BUSY_PERCENT*2) >= avgsilence)
- res = 1;
- }
- #else
- res = 1;
- #endif
- }
- #if 0
- if (res)
- ast_log(LOG_NOTICE, "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;
- unsigned 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(shortdata[x]); \
- break; \
- case AST_FORMAT_ALAW: \
- for (x=0;x<len;x++) \
- odata[x] = AST_LIN2A(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);
- if (!shortdata) {
- ast_log(LOG_WARNING, "Unable to allocate stack space for data: %s\n", strerror(errno));
- return af;
- }
- for (x=0;x<len;x++)
- shortdata[x] = AST_MULAW(odata[x]);
- break;
- case AST_FORMAT_ALAW:
- shortdata = alloca(af->datalen * 2);
- if (!shortdata) {
- ast_log(LOG_WARNING, "Unable to allocate stack space for data: %s\n", strerror(errno));
- return af;
- }
- 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);
- 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:
- dsp->f.subclass = res;
- 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;
- }
- }
- dsp->freqcount = max;
- }
- 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));
- 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_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));
-
- }
- int ast_dsp_digitmode(struct ast_dsp *dsp, int digitmode)
- {
- int new, 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;
- }
|