Index: main/dsp.c =================================================================== --- main/dsp.c (revision 110864) +++ main/dsp.c (working copy) @@ -150,9 +150,9 @@ #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 */ +#define DTMF_REVERSE_TWIST (relax ? 6.5 : 2.5) /* 4dB normal */ #else -#define DTMF_REVERSE_TWIST ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 4.0 : 2.5) /* 4dB normal */ +#define DTMF_REVERSE_TWIST (relax ? 4.0 : 2.5) /* 4dB normal */ #endif #define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */ #define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */ @@ -193,7 +193,14 @@ */ #define SAMPLES_IN_FRAME 160 +/* DTMF goertzel size */ +#define DTMF_GSIZE 102 +/* How many successive hits needed to consider begin of a digit */ +#define DTMF_HITS_TO_BEGIN 2 +/* How many successive misses needed to consider end of a digit */ +#define DTMF_MISSES_TO_END 3 + #define CONFIG_FILE_NAME "dsp.conf" typedef struct { @@ -217,6 +224,7 @@ goertzel_state_t tone; float energy; /* Accumulated energy of the current block */ int samples_pending; /* Samples remain to complete the current block */ + int mute_samples; /* How many additional samples needs to be muted to suppress already detected tone */ int hits_required; /* How many successive blocks with tone we are looking for */ float threshold; /* Energy of the tone relative to energy from all other signals to consider a hit */ @@ -230,10 +238,15 @@ { goertzel_state_t row_out[4]; goertzel_state_t col_out[4]; + int hits_to_begin; /* How many successive hits needed to consider begin of a digit */ + int misses_to_end; /* How many successive misses needed to consider end of a digit */ + int hits; /* How many successive hits we have seen already */ + int misses; /* How many successive misses we have seen already */ int lasthit; int current_hit; float energy; int current_sample; + int mute_samples; } dtmf_detect_state_t; typedef struct @@ -242,6 +255,7 @@ int current_hit; int hits[5]; int current_sample; + int mute_samples; } mf_detect_state_t; typedef struct @@ -324,6 +338,24 @@ s->v2 = s->v3 = s->chunky = 0.0; } +typedef struct { + int start; + int end; +} fragment_t; + +/* Note on tone suppression (squelching). Individual detectors (DTMF/MF/generic tone) + * report fragmens of the frame in which detected tone resides and which needs + * to be "muted" in order to suppress the tone. To mark fragment for muting, + * detectors call mute_fragment passing fragment_t there. Multiple fragments + * can be marked and ast_dsp_process later will mute all of them. + * + * Note: When tone starts in the middle of a Goertzel block, it won't be properly + * detected in that block, only in the next. If we only mute the next block + * where tone is actually detected, the user will still hear beginning + * of the tone in preceeding block. This is why we usually want to mute some amount + * of samples preceeding and following the block where tone was detected. +*/ + struct ast_dsp { struct ast_frame f; int threshold; @@ -346,13 +378,25 @@ int tcount; int digitmode; int faxmode; - int thinkdigit; + int dtmf_began; float genergy; + int mute_fragments; + fragment_t mute_data[5]; digit_detect_state_t digit_state; tone_detect_state_t cng_tone_state; tone_detect_state_t ced_tone_state; }; +static void mute_fragment(struct ast_dsp *dsp, fragment_t *fragment) +{ + if (dsp->mute_fragments >= sizeof(dsp->mute_data) / sizeof(dsp->mute_data[0])) { + ast_log(LOG_ERROR, "Too many fragments to mute. Ignoring\n"); + return; + } + + dsp->mute_data[dsp->mute_fragments++] = *fragment; +} + static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration, int amp) { int duration_samples; @@ -426,11 +470,16 @@ s->lasthit = 0; s->current_hit = 0; 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); + goertzel_init (&s->row_out[i], dtmf_row[i], DTMF_GSIZE); + goertzel_init (&s->col_out[i], dtmf_col[i], DTMF_GSIZE); s->energy = 0.0; } s->current_sample = 0; + s->hits = 0; + s->misses = 0; + + s->hits_to_begin = DTMF_HITS_TO_BEGIN; + s->misses_to_end = DTMF_MISSES_TO_END; } static void ast_mf_detect_init (mf_detect_state_t *s) @@ -457,8 +506,7 @@ ast_dtmf_detect_init(&s->td.dtmf); } -static int tone_detect(tone_detect_state_t *s, int16_t *amp, int samples, - int *writeback) +static int tone_detect(struct ast_dsp *dsp, tone_detect_state_t *s, int16_t *amp, int samples) { float tone_energy; int i; @@ -466,10 +514,20 @@ int limit; int res = 0; int16_t *ptr; + int start, end; + fragment_t mute = {0, 0}; - while (1) { + if (s->squelch && s->mute_samples > 0) { + mute.end = (s->mute_samples < samples) ? s->mute_samples : samples; + s->mute_samples -= mute.end; + } + + for (start = 0; start < samples; start = end) { /* Process in blocks. */ - limit = (samples < s->samples_pending) ? samples : s->samples_pending; + limit = samples - start; + if (limit > s->samples_pending) + limit = s->samples_pending; + end = start + limit; for (i = limit, ptr = amp ; i > 0; i--, ptr++) { /* signed 32 bit int should be enough to suqare any possible signed 16 bit value */ @@ -482,36 +540,21 @@ if (s->samples_pending) { /* Finished incomplete (last) block */ - if (s->last_hit && s->squelch) { - /* If we had a hit last time, go ahead and clear this out since likely it - will be another hit */ - memset(amp, 0, sizeof(*amp) * limit); - if (writeback) - *writeback = 1; - } break; } - tone_energy = goertzel_result(&s->tone); /* Scale to make comparable */ tone_energy *= 2.0; s->energy *= s->block_size; - ast_debug(10, "tone %d, Ew=%f, Et=%f, s/n=%10.2f\n", s->freq, tone_energy, s->energy, tone_energy / (s->energy - tone_energy)); + ast_debug(10, "tone %d, Ew=%.2E, Et=%.2E, s/n=%10.2f\n", s->freq, tone_energy, s->energy, tone_energy / (s->energy - tone_energy)); hit = 0; if (tone_energy > s->energy * s->threshold) { ast_debug(10, "Hit! count=%d\n", s->hit_count); hit = 1; - - if (s->squelch) { - /* Zero out frame data */ - memset(amp, 0, sizeof(*amp) * limit); - if (writeback) - *writeback = 1; - } } if (s->hit_count) @@ -534,6 +577,17 @@ s->last_hit = hit; + /* If we had a hit in this block, include it into mute fragment */ + if (s->squelch && hit) { + if (mute.end < start - s->block_size) { + /* There is a gap between fragments */ + mute_fragment(dsp, &mute); + mute.start = (start > s->block_size) ? (start - s->block_size) : 0; + } + mute.end = end + s->block_size; + } + + /* Reinitialise the detector for the next block */ /* Reset for the next block */ goertzel_reset(&s->tone); @@ -542,9 +596,16 @@ s->samples_pending = s->block_size; amp += limit; - samples -= limit; } + if (s->squelch && mute.end) { + if (mute.end > samples) { + s->mute_samples = mute.end - samples; + mute.end = samples; + } + mute_fragment(dsp, &mute); + } + return res; } @@ -560,8 +621,7 @@ } } -static int dtmf_detect(digit_detect_state_t *s, int16_t amp[], int samples, - int digitmode, int *writeback) +static int dtmf_detect(struct ast_dsp *dsp, digit_detect_state_t *s, int16_t amp[], int samples, int squelch, int relax) { float row_energy[4]; float col_energy[4]; @@ -573,12 +633,18 @@ int best_col; int hit; int limit; + fragment_t mute = {0, 0}; + if (squelch && s->td.dtmf.mute_samples > 0) { + mute.end = (s->td.dtmf.mute_samples < samples) ? s->td.dtmf.mute_samples : samples; + s->td.dtmf.mute_samples -= mute.end; + } + hit = 0; for (sample = 0; sample < samples; sample = limit) { - /* 102 is optimised to meet the DTMF specs. */ - if ((samples - sample) >= (102 - s->td.dtmf.current_sample)) - limit = sample + (102 - s->td.dtmf.current_sample); + /* DTMF_GSIZE is optimised to meet the DTMF specs. */ + if ((samples - sample) >= (DTMF_GSIZE - s->td.dtmf.current_sample)) + limit = sample + (DTMF_GSIZE - s->td.dtmf.current_sample); else limit = samples; /* The following unrolled loop takes only 35% (rough estimate) of the @@ -598,14 +664,7 @@ goertzel_sample(s->td.dtmf.col_out + 3, amp[j]); } s->td.dtmf.current_sample += (limit - sample); - if (s->td.dtmf.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;itd.dtmf.current_sample < DTMF_GSIZE) { continue; } /* We are at the end of a DTMF detection block */ @@ -641,31 +700,53 @@ (row_energy[best_row] + col_energy[best_col]) > DTMF_TO_TOTAL_ENERGY*s->td.dtmf.energy) { /* 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;itd.dtmf.current_hit) { - if (hit && s->td.dtmf.lasthit == hit) { + if (s->td.dtmf.current_hit) { + /* We are in the middle of a digit already */ + if (hit != s->td.dtmf.current_hit) { + s->td.dtmf.misses++; + if (s->td.dtmf.misses == s->td.dtmf.misses_to_end) { + /* There were enough misses to consider digit ended */ + s->td.dtmf.current_hit = 0; + } + } else { + s->td.dtmf.misses = 0; + } + } + + /* Look for a start of a new digit no matter if we are already in the middle of some + digit or not. This is because hits_to_begin may be smaller than misses_to_end + and we may find begin of new digit before we consider last one ended. */ + if (hit) { + if (hit == s->td.dtmf.lasthit) { + s->td.dtmf.hits++; + } else { + s->td.dtmf.hits = 1; + } + + if (s->td.dtmf.hits == s->td.dtmf.hits_to_begin && hit != s->td.dtmf.current_hit) { + store_digit(s, hit); s->td.dtmf.current_hit = hit; - store_digit(s, hit); - } else if (s->td.dtmf.lasthit != s->td.dtmf.current_hit) { - s->td.dtmf.current_hit = 0; + s->td.dtmf.misses = 0; } + } else { + s->td.dtmf.hits = 0; } + s->td.dtmf.lasthit = hit; + /* If we had a hit in this block, include it into mute fragment */ + if (squelch && hit) { + if (mute.end < sample - DTMF_GSIZE) { + /* There is a gap between fragments */ + mute_fragment(dsp, &mute); + mute.start = (sample > DTMF_GSIZE) ? (sample - DTMF_GSIZE) : 0; + } + mute.end = limit + DTMF_GSIZE; + } + /* Reinitialise the detector for the next block */ for (i = 0; i < 4; i++) { goertzel_reset(&s->td.dtmf.row_out[i]); @@ -674,14 +755,23 @@ s->td.dtmf.energy = 0.0; s->td.dtmf.current_sample = 0; } + + if (squelch && mute.end) { + if (mute.end > samples) { + s->td.dtmf.mute_samples = mute.end - samples; + mute.end = samples; + } + mute_fragment(dsp, &mute); + } + return (s->td.dtmf.current_hit); /* return the debounced hit */ } /* MF goertzel size */ #define MF_GSIZE 120 -static int mf_detect(digit_detect_state_t *s, int16_t amp[], - int samples, int digitmode, int *writeback) +static int mf_detect(struct ast_dsp *dsp, digit_detect_state_t *s, int16_t amp[], + int samples, int squelch, int relax) { float energy[6]; int best; @@ -692,7 +782,13 @@ int sample; int hit; int limit; + fragment_t mute = {0, 0}; + if (squelch && s->td.mf.mute_samples > 0) { + mute.end = (s->td.mf.mute_samples < samples) ? s->td.mf.mute_samples : samples; + s->td.mf.mute_samples -= mute.end; + } + hit = 0; for (sample = 0; sample < samples; sample = limit) { /* 80 is optimised to meet the MF specs. */ @@ -715,13 +811,6 @@ } s->td.mf.current_sample += (limit - sample); if (s->td.mf.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;itd.mf.hits[2] = s->td.mf.hits[3]; s->td.mf.hits[3] = s->td.mf.hits[4]; s->td.mf.hits[4] = hit; + + /* If we had a hit in this block, include it into mute fragment */ + if (squelch && hit) { + if (mute.end < sample - MF_GSIZE) { + /* There is a gap between fragments */ + mute_fragment(dsp, &mute); + mute.start = (sample > MF_GSIZE) ? (sample - MF_GSIZE) : 0; + } + mute.end = limit + DTMF_GSIZE; + } + /* Reinitialise the detector for the next block */ for (i = 0; i < 6; i++) goertzel_reset(&s->td.mf.tone_out[i]); s->td.mf.current_sample = 0; } - return (s->td.mf.current_hit); /* return the debounced hit */ -} - -static int __ast_dsp_digitdetect(struct ast_dsp *dsp, short *s, int len, int *writeback) -{ - int res = 0; - - if ((dsp->features & DSP_FEATURE_DIGIT_DETECT) && (dsp->digitmode & DSP_DIGITMODE_MF)) - res = mf_detect(&dsp->digit_state, s, len, dsp->digitmode & DSP_DIGITMODE_RELAXDTMF, writeback); - else if (dsp->features & DSP_FEATURE_DIGIT_DETECT) - res = dtmf_detect(&dsp->digit_state, s, len, dsp->digitmode & DSP_DIGITMODE_RELAXDTMF, writeback); - - if ((dsp->features & DSP_FEATURE_FAX_DETECT) && (dsp->faxmode & DSP_FAXMODE_DETECT_CNG)) { - if (tone_detect(&dsp->cng_tone_state, s, len, NULL)) { - store_digit(&dsp->digit_state, 'f'); - res = 'f'; + if (squelch && mute.end) { + if (mute.end > samples) { + s->td.mf.mute_samples = mute.end - samples; + mute.end = samples; } + mute_fragment(dsp, &mute); } - if ((dsp->features & DSP_FEATURE_FAX_DETECT) && (dsp->faxmode & DSP_FAXMODE_DETECT_CED)) { - if (tone_detect(&dsp->ced_tone_state, s, len, NULL)) { - store_digit(&dsp->digit_state, 'e'); - res = 'e'; - } - } - - return res; + return (s->td.mf.current_hit); /* return the debounced hit */ } -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 */ @@ -875,19 +938,6 @@ return 1; } -int ast_dsp_getdigits(struct ast_dsp *dsp, char *buf, int max) -{ - if (max > dsp->digit_state.current_digits) - max = dsp->digit_state.current_digits; - if (max > 0) { - memcpy(buf, dsp->digit_state.digits, max); - memmove(dsp->digit_state.digits, dsp->digit_state.digits + max, dsp->digit_state.current_digits - max); - dsp->digit_state.current_digits -= max; - } - buf[max] = '\0'; - return max; -} - static int __ast_dsp_call_progress(struct ast_dsp *dsp, short *s, int len) { int x; @@ -1212,34 +1262,18 @@ { int silence; int res; - int digit; + int digit = 0, fax_digit = 0; int x; short *shortdata; unsigned char *odata; int len; - int writeback = 0; + struct ast_frame *outf = NULL; -#define FIX_INF(inf) do { \ - if (writeback) { \ - switch (inf->subclass) { \ - case AST_FORMAT_SLINEAR: \ - break; \ - case AST_FORMAT_ULAW: \ - for (x=0;xframetype != AST_FRAME_VOICE) return af; + odata = af->data; len = af->datalen; /* Make sure we have short data */ @@ -1262,6 +1296,10 @@ ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(af->subclass)); return af; } + + /* Initially we do not want to mute anything */ + dsp->mute_fragments = 0; + res = __ast_dsp_silence_noise(dsp, shortdata, len, &silence, NULL); if ((dsp->features & DSP_FEATURE_SILENCE_SUPPRESS) && silence) { memset(&dsp->f, 0, sizeof(dsp->f)); @@ -1278,88 +1316,66 @@ ast_debug(1, "Requesting Hangup because the busy tone was detected on channel %s\n", chan->name); return &dsp->f; } - if (((dsp->features & DSP_FEATURE_DIGIT_DETECT) || (dsp->features & DSP_FEATURE_FAX_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 != '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_END; - dsp->f.subclass = dsp->thinkdigit; - FIX_INF(af); - if (chan) - ast_queue_frame(chan, af); - ast_frfree(af); - } else { - dsp->thinkdigit = digit; - memset(&dsp->f, 0, sizeof(dsp->f)); - dsp->f.frametype = AST_FRAME_DTMF_BEGIN; - dsp->f.subclass = dsp->thinkdigit; - FIX_INF(af); - if (chan) - ast_queue_frame(chan, af); - ast_frfree(af); - } - return &dsp->f; - } else { - 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_END; - 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; - } + + if ((dsp->features & DSP_FEATURE_FAX_DETECT)) { + + if ((dsp->faxmode & DSP_FAXMODE_DETECT_CNG) && tone_detect(dsp, &dsp->cng_tone_state, shortdata, len)) { + fax_digit = 'f'; + } + + if ((dsp->faxmode & DSP_FAXMODE_DETECT_CED) && tone_detect(dsp, &dsp->ced_tone_state, shortdata, len)) { + fax_digit = 'e'; + } + } + + if ((dsp->features & DSP_FEATURE_DIGIT_DETECT)) { + + if ((dsp->digitmode & DSP_DIGITMODE_MF)) + digit = mf_detect(dsp, &dsp->digit_state, shortdata, len, (dsp->digitmode & DSP_DIGITMODE_NOQUELCH) == 0, dsp->digitmode & DSP_DIGITMODE_RELAXDTMF); + else + digit = dtmf_detect(dsp, &dsp->digit_state, shortdata, len, (dsp->digitmode & DSP_DIGITMODE_NOQUELCH) == 0, dsp->digitmode & DSP_DIGITMODE_RELAXDTMF); + + if (dsp->digit_state.current_digits) { + int event = 0; + char event_digit = 0; + + if (!dsp->dtmf_began) { + /* We have not reported DTMF_BEGIN for anything yet */ + + event = AST_FRAME_DTMF_BEGIN; + event_digit = dsp->digit_state.digits[0]; + dsp->dtmf_began = 1; + + } else if (dsp->digit_state.current_digits > 1 || digit != dsp->digit_state.digits[0]) { + /* Digit changed. This means digit we have reported with DTMF_BEGIN ended */ + + event = AST_FRAME_DTMF_END; + event_digit = dsp->digit_state.digits[0]; + memmove(dsp->digit_state.digits, dsp->digit_state.digits + 1, dsp->digit_state.current_digits); + dsp->digit_state.current_digits--; + dsp->dtmf_began = 0; } - } else if (dsp->digit_state.current_digits > 1 || - (dsp->digit_state.current_digits == 1 && digit != dsp->digit_state.digits[0])) { - /* Since we basically generate DTMF_END frames we do it only when a digit - has finished. */ - memset(&dsp->f, 0, sizeof(dsp->f)); - dsp->f.frametype = AST_FRAME_DTMF; - dsp->f.subclass = dsp->digit_state.digits[0]; - memmove(dsp->digit_state.digits, dsp->digit_state.digits + 1, dsp->digit_state.current_digits); - dsp->digit_state.current_digits--; - FIX_INF(af); - if (chan) - ast_queue_frame(chan, af); - ast_frfree(af); - return &dsp->f; + if (event) { + memset(&dsp->f, 0, sizeof(dsp->f)); + dsp->f.frametype = event; + dsp->f.subclass = event_digit; + outf = &dsp->f; + goto done; + } } } + + if (fax_digit) { + /* Fax was detected - digit is either 'f' or 'e' */ + + memset(&dsp->f, 0, sizeof(dsp->f)); + dsp->f.frametype = AST_FRAME_DTMF; + dsp->f.subclass = fax_digit; + outf = &dsp->f; + goto done; + } + if ((dsp->features & DSP_FEATURE_CALL_PROGRESS)) { res = __ast_dsp_call_progress(dsp, shortdata, len); if (res) { @@ -1381,8 +1397,34 @@ } } } - FIX_INF(af); - return af; + +done: + /* Mute fragment of the frame */ + for (x = 0; x < dsp->mute_fragments; x++) { + memset(shortdata + dsp->mute_data[x].start, 0, sizeof(int16_t) * (dsp->mute_data[x].end - dsp->mute_data[x].start)); + } + + switch (af->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; + } + + if (outf) { + if (chan) + ast_queue_frame(chan, af); + ast_frfree(af); + return outf; + } else { + return af; + } } static void ast_dsp_prog_reset(struct ast_dsp *dsp) @@ -1457,7 +1499,7 @@ { int i; - dsp->thinkdigit = 0; + dsp->dtmf_began = 0; if (dsp->digitmode & DSP_DIGITMODE_MF) { mf_detect_state_t *s = &dsp->digit_state.td.mf; /* Reinitialise the detector for the next block */ @@ -1476,6 +1518,8 @@ s->lasthit = s->current_hit = 0; s->energy = 0.0; s->current_sample = 0; + s->hits = 0; + s->misses = 0; } dsp->digit_state.digits[0] = '\0'; @@ -1533,6 +1577,11 @@ return -1; } +int ast_dsp_was_muted(struct ast_dsp *dsp) +{ + return (dsp->mute_fragments > 0); +} + int ast_dsp_get_tstate(struct ast_dsp *dsp) { return dsp->tstate; Index: include/asterisk/dsp.h =================================================================== --- include/asterisk/dsp.h (revision 110864) +++ include/asterisk/dsp.h (working copy) @@ -120,6 +120,10 @@ /*! \brief Set fax mode */ int ast_dsp_set_faxmode(struct ast_dsp *dsp, int faxmode); +/*! \brief Returns true if DSP code was muting any fragment of the last processed frame. + Muting (squelching) happens when DSP code removes DTMF/MF/generic tones from the audio */ +int ast_dsp_was_muted(struct ast_dsp *dsp); + /*! \brief Get tstate (Tone State) */ int ast_dsp_get_tstate(struct ast_dsp *dsp);