diff --git a/channels/chan_usbradio.c b/channels/chan_usbradio.c index 11c06e957ddef1da20b54fd1fd23092885e328c6..84a2ce2bb395fc62ba527e3f9450ed9d9b733fc1 100644 --- a/channels/chan_usbradio.c +++ b/channels/chan_usbradio.c @@ -1210,8 +1210,6 @@ static struct ast_frame *usbradio_read(struct ast_channel *c) if (o->dsp) { f1 = ast_dsp_process(c, o->dsp, f); if ((f1->frametype == AST_FRAME_DTMF_END) || (f1->frametype == AST_FRAME_DTMF_BEGIN)) { - if ((f1->subclass == 'm') || (f1->subclass == 'u')) - f1->frametype = AST_FRAME_DTMF_BEGIN; if (f1->frametype == AST_FRAME_DTMF_END) ast_log(LOG_NOTICE,"Got DTMF char %c\n",f1->subclass); return f1; diff --git a/channels/chan_vpb.cc b/channels/chan_vpb.cc index be1ed535b4f664e8e7db4060c15b02747c7152fa..bd67ab0ec2d2bdc26606e3445e3d0b271a44f3c4 100644 --- a/channels/chan_vpb.cc +++ b/channels/chan_vpb.cc @@ -2400,14 +2400,6 @@ static void *do_chanreads(void *pvt) fr = ast_dsp_process(p->owner,p->vad,fr); if (fr && (fr->frametype == AST_FRAME_DTMF)) ast_debug(1, "%s: chanreads: Detected DTMF '%c'\n", p->dev, fr->subclass); - if (fr->subclass == 'm') { - /* conf mute request */ - fr->frametype = AST_FRAME_NULL; - fr->subclass = 0; - } else if (fr->subclass == 'u') { - /* Unmute */ - fr->frametype = AST_FRAME_NULL; - fr->subclass = 0; } else if (fr->subclass == 'f') { } } diff --git a/channels/chan_zap.c b/channels/chan_zap.c index effd5cccf1ac8d7a7810b047ae508e739bdf5e47..beb3c33fc9f70674a1085a0972baf0faad91da01 100644 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -706,6 +706,7 @@ static struct zt_pvt { unsigned int loopedback:1; #endif char begindigit; + int muting; } *iflist = NULL, *ifend = NULL; /*! \brief Channel configuration from zapata.conf . @@ -2988,6 +2989,7 @@ static int zt_hangup(struct ast_channel *ast) x = 0; zt_confmute(p, 0); + p->muting = 0; restore_gains(p); if (p->origcid_num) { ast_copy_string(p->cid_num, p->origcid_num, sizeof(p->cid_num)); @@ -4232,8 +4234,7 @@ static void zt_handle_dtmfup(struct ast_channel *ast, int index, struct ast_fram ast_free(p->cidspill); send_cwcidspill(p); } - if ((f->subclass != 'm') && (f->subclass != 'u')) - p->callwaitcas = 0; + p->callwaitcas = 0; p->subs[index].f.frametype = AST_FRAME_NULL; p->subs[index].f.subclass = 0; *dest = &p->subs[index].f; @@ -4260,20 +4261,7 @@ static void zt_handle_dtmfup(struct ast_channel *ast, int index, struct ast_fram p->subs[index].f.frametype = AST_FRAME_NULL; p->subs[index].f.subclass = 0; *dest = &p->subs[index].f; - } else if (f->subclass == 'm') { - /* Confmute request */ - zt_confmute(p, 1); - p->subs[index].f.frametype = AST_FRAME_NULL; - p->subs[index].f.subclass = 0; - *dest = &p->subs[index].f; - } else if (f->subclass == 'u') { - /* Unmute */ - zt_confmute(p, 0); - p->subs[index].f.frametype = AST_FRAME_NULL; - p->subs[index].f.subclass = 0; - *dest = &p->subs[index].f; - } else - zt_confmute(p, 0); + } } static struct ast_frame *zt_handle_event(struct ast_channel *ast) @@ -5463,7 +5451,17 @@ static struct ast_frame *zt_read(struct ast_channel *ast) } if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect || p->callprogress) && !index) { /* Perform busy detection. etc on the zap line */ + int mute; + f = ast_dsp_process(ast, p->dsp, &p->subs[index].f); + + /* Check if DSP code thinks we should be muting this frame and mute the conference if so */ + mute = ast_dsp_was_muted(p->dsp); + if (p->muting != mute) { + p->muting = mute; + zt_confmute(p, mute); + } + if (f) { if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_BUSY)) { if ((ast->_state == AST_STATE_UP) && !p->outgoing) { @@ -5996,6 +5994,7 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int i->fake_event = 0; /* Assure there is no confmute on this channel */ zt_confmute(i, 0); + i->muting = 0; /* Configure the new channel jb */ ast_jb_configure(tmp, &global_jbconf); diff --git a/include/asterisk/dsp.h b/include/asterisk/dsp.h index b8e21b4f6a15aa3516fc97731586786c5665aa89..81735d625023022369012e5a733d4e4f2d7d6f19 100644 --- a/include/asterisk/dsp.h +++ b/include/asterisk/dsp.h @@ -120,6 +120,10 @@ int ast_dsp_set_digitmode(struct ast_dsp *dsp, int digitmode); /*! \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); diff --git a/main/dsp.c b/main/dsp.c index 3d639a3b6a510eedab7cc42590946256136bfded..084a37cfbac95debfa92ea1fdf9d9e9761597e83 100644 --- a/main/dsp.c +++ b/main/dsp.c @@ -150,13 +150,13 @@ enum gsamp_thresh { #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 */ -#define DTMF_2ND_HARMONIC_ROW ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 1.7 : 2.5) /* 4dB normal */ +#define DTMF_2ND_HARMONIC_ROW (relax ? 1.7 : 2.5) /* 4dB normal */ #define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */ #define DTMF_TO_TOTAL_ENERGY 42.0 @@ -193,6 +193,16 @@ enum gsamp_thresh { */ #define SAMPLES_IN_FRAME 160 +/* MF goertzel size */ +#define MF_GSIZE 120 + +/* 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" @@ -217,6 +227,7 @@ typedef struct 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 +241,15 @@ typedef struct { 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 +258,7 @@ typedef struct int current_hit; int hits[5]; int current_sample; + int mute_samples; } mf_detect_state_t; typedef struct @@ -324,6 +341,24 @@ static inline void goertzel_reset(goertzel_state_t *s) 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 +381,25 @@ struct ast_dsp { 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 +473,16 @@ static void ast_dtmf_detect_init (dtmf_detect_state_t *s) 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 +509,7 @@ static void ast_digit_detect_init(digit_detect_state_t *s, int mf) 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 +517,20 @@ static int tone_detect(tone_detect_state_t *s, int16_t *amp, int samples, 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 +543,21 @@ static int tone_detect(tone_detect_state_t *s, int16_t *amp, int samples, 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 +580,17 @@ static int tone_detect(tone_detect_state_t *s, int16_t *amp, int samples, 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,7 +599,14 @@ static int tone_detect(tone_detect_state_t *s, int16_t *amp, int samples, 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 +624,7 @@ static void store_digit(digit_detect_state_t *s, char digit) } } -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 +636,18 @@ static int dtmf_detect(digit_detect_state_t *s, int16_t amp[], int samples, 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 +667,7 @@ static int dtmf_detect(digit_detect_state_t *s, int16_t amp[], int samples, 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;i<limit;i++) - amp[i] = 0; - *writeback = 1; - } + if (s->td.dtmf.current_sample < DTMF_GSIZE) { continue; } /* We are at the end of a DTMF detection block */ @@ -641,31 +703,53 @@ static int dtmf_detect(digit_detect_state_t *s, int16_t amp[], int samples, (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;i<limit;i++) - amp[i] = 0; - *writeback = 1; - } } } - /* The logic in the next test is: - For digits we need two successive identical clean detects, with - something different preceeding it. This can work with - back to back differing digits. More importantly, it - can work with nasty phones that give a very wobbly start - to a digit */ - if (hit != s->td.dtmf.current_hit) { - if (hit && s->td.dtmf.lasthit == hit) { - s->td.dtmf.current_hit = 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); - } else if (s->td.dtmf.lasthit != s->td.dtmf.current_hit) { - s->td.dtmf.current_hit = 0; + s->td.dtmf.current_hit = hit; + 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 +758,20 @@ static int dtmf_detect(digit_detect_state_t *s, int16_t amp[], int samples, 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,10 +782,17 @@ static int mf_detect(digit_detect_state_t *s, int16_t amp[], 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. */ + /* XXX So then why is MF_GSIZE defined as 120? */ if ((samples - sample) >= (MF_GSIZE - s->td.mf.current_sample)) limit = sample + (MF_GSIZE - s->td.mf.current_sample); else @@ -715,13 +812,6 @@ static int mf_detect(digit_detect_state_t *s, int16_t amp[], } 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;i<limit;i++) - amp[i] = 0; - *writeback = 1; - } continue; } /* We're at the end of an MF detection block. */ @@ -801,58 +891,32 @@ static int mf_detect(digit_detect_state_t *s, int16_t amp[], s->td.mf.hits[2] = s->td.mf.hits[3]; s->td.mf.hits[3] = s->td.mf.hits[4]; s->td.mf.hits[4] = hit; + + /* 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; -} - -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); + return (s->td.mf.current_hit); /* return the debounced hit */ } static inline int pair_there(float p1, float p2, float i1, float i2, float e) @@ -875,19 +939,6 @@ static inline int pair_there(float p1, float p2, float i1, float i2, float e) return 1; } -int ast_dsp_getdigits(struct ast_dsp *dsp, char *buf, int max) -{ - 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 +1263,18 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, { int silence; int res; - int digit; + int digit = 0, fax_digit = 0; 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) + struct ast_frame *outf = NULL; if (!af) return NULL; if (af->frametype != AST_FRAME_VOICE) return af; + odata = af->data; len = af->datalen; /* Make sure we have short data */ @@ -1262,6 +1297,10 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, 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 +1317,64 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, 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; + } + + if (event) { + memset(&dsp->f, 0, sizeof(dsp->f)); + dsp->f.frametype = event; + dsp->f.subclass = event_digit; + outf = &dsp->f; + goto done; } - } 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 (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 +1396,34 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, } } } - 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 +1498,7 @@ void ast_dsp_digitreset(struct ast_dsp *dsp) { 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 +1517,8 @@ void ast_dsp_digitreset(struct ast_dsp *dsp) 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 +1576,11 @@ int ast_dsp_set_call_progress_zone(struct ast_dsp *dsp, char *zone) 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;