aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--channels/chan_usbradio.c2
-rw-r--r--channels/chan_vpb.cc8
-rw-r--r--channels/chan_zap.c31
-rw-r--r--include/asterisk/dsp.h4
-rw-r--r--main/dsp.c500
5 files changed, 293 insertions, 252 deletions
diff --git a/channels/chan_usbradio.c b/channels/chan_usbradio.c
index 11c06e957..84a2ce2bb 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 be1ed535b..bd67ab0ec 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 effd5cccf..beb3c33fc 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 b8e21b4f6..81735d625 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 3d639a3b6..084a37cfb 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;