[asterisk-commits] [svn-commits] qwell: trunk r111022 - in /trunk: channels/ include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Mar 26 14:05:52 CDT 2008


Author: qwell
Date: Wed Mar 26 14:05:51 2008
New Revision: 111022

URL: http://svn.digium.com/view/asterisk?view=rev&rev=111022
Log:
Large cleanup of DSP code

Per comments from dimas:
1. The code now generates DTMF_BEGIN frames in addition to DTMF_END ones.

2. "quelching" rewritten - now each detector (MF/DTMF/generic tone) may mark fragment of a frame for suppression (squelching, muting) with a call to mute_fragment. Actual muting happens only once at the very end of ast_dsp_process where all marked fragments are zeroed. This way every detector sees original data in the frame without any piece of a frame being zeroed by a detector which was run before.

3. DTMF detector tries to "mute" one block before and one block after the block where actual tone was detected. Muting of previois block is something new for this patch. Obviously this operation is not always possible - if current frame does not contain data for previous block - it is too late. But at least we make our best.
Muting of next block was already done by the old code but it only affects part of the next block which is in the frame being processed. New code keeps this information in state structures so it will mute proper number of samples in the next frame(s) too.

4. Removed ast_dsp_digitdetect and ast_dsp_getdigits APIs because these are not used.

5. DSP API extended a bit - ast_dsp_was_muted() function added which returns true if DSP code was muting any fragment in the last frame. chan_zap uses this function to decide it needs to turn on confmute on the channel.
This is to replace AST_FRAME_DTMF 'm'/'u' (mute/unmute) functionality.


(closes issue #11968)
Reported by: dimas
Patches:
      v2-11968-dsp.patch uploaded by dimas (license 88)
      v4-11968-zap.patch uploaded by dimas (license 88)
Tested by: dimas, qwell

Modified:
    trunk/channels/chan_usbradio.c
    trunk/channels/chan_vpb.cc
    trunk/channels/chan_zap.c
    trunk/include/asterisk/dsp.h
    trunk/main/dsp.c

Modified: trunk/channels/chan_usbradio.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_usbradio.c?view=diff&rev=111022&r1=111021&r2=111022
==============================================================================
--- trunk/channels/chan_usbradio.c (original)
+++ trunk/channels/chan_usbradio.c Wed Mar 26 14:05:51 2008
@@ -1210,8 +1210,6 @@
 	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;

Modified: trunk/channels/chan_vpb.cc
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_vpb.cc?view=diff&rev=111022&r1=111021&r2=111022
==============================================================================
--- trunk/channels/chan_vpb.cc (original)
+++ trunk/channels/chan_vpb.cc Wed Mar 26 14:05:51 2008
@@ -2400,14 +2400,6 @@
 				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') {
 				}
 			}

Modified: trunk/channels/chan_zap.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_zap.c?view=diff&rev=111022&r1=111021&r2=111022
==============================================================================
--- trunk/channels/chan_zap.c (original)
+++ trunk/channels/chan_zap.c Wed Mar 26 14:05:51 2008
@@ -706,6 +706,7 @@
 	unsigned int loopedback:1;
 #endif
 	char begindigit;
+	int muting;
 } *iflist = NULL, *ifend = NULL;
 
 /*! \brief Channel configuration from zapata.conf .
@@ -2988,6 +2989,7 @@
 
 	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 @@
 				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 @@
 		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 @@
 	}
 	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 @@
 	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);
 

Modified: trunk/include/asterisk/dsp.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/dsp.h?view=diff&rev=111022&r1=111021&r2=111022
==============================================================================
--- trunk/include/asterisk/dsp.h (original)
+++ trunk/include/asterisk/dsp.h Wed Mar 26 14:05:51 2008
@@ -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);
 

Modified: trunk/main/dsp.c
URL: http://svn.digium.com/view/asterisk/trunk/main/dsp.c?view=diff&rev=111022&r1=111021&r2=111022
==============================================================================
--- trunk/main/dsp.c (original)
+++ trunk/main/dsp.c Wed Mar 26 14:05:51 2008
@@ -150,13 +150,13 @@
 #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 @@
  */
 #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 @@
 	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 @@
 {
 	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 @@
 	int current_hit;
 	int hits[5];
 	int current_sample;
+	int mute_samples;
 } mf_detect_state_t;
 
 typedef struct
@@ -323,6 +340,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;
@@ -346,12 +381,24 @@
 	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)
 {
@@ -426,11 +473,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 +509,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 +517,20 @@
 	int limit;
 	int res = 0;
 	int16_t *ptr;
-
-	while (1) {
+	int start, end;
+	fragment_t mute = {0, 0};
+
+	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,16 +543,8 @@
 
 		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);
 
@@ -499,19 +552,12 @@
 		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 @@
 
 		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 @@
 		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 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 @@
 	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 @@
 			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,30 +703,52 @@
 			    (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;
+			}
+		} 
+
+		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;
 				}
-			}
-		} 
-
-		/* 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) {
+			} 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++) {
@@ -674,14 +758,20 @@
 		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 @@
 	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 @@
 		}
 		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 @@
 		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;
 	}
 
+	if (squelch && mute.end) {
+		if (mute.end > samples) {
+			s->td.mf.mute_samples = mute.end - samples;
+			mute.end = samples;
+		}
+		mute_fragment(dsp, &mute);
+	}
+
 	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 ((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);
 }
 
 static inline int pair_there(float p1, float p2, float i1, float i2, float e)
@@ -873,19 +937,6 @@
 		return 0;
 	/* Guess it's there... */
 	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)
@@ -1212,34 +1263,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;
-
-#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 @@
 		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 @@
 		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;
-				}
-			}
-		} 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 ((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;
+			}
+		}
+	}
+
+	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 @@
 			}
 		}
 	}
-	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 @@
 {
 	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 @@
 		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 @@
 	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;


_______________________________________________
--Bandwidth and Colocation Provided by http://www.api-digital.com--

svn-commits mailing list
To UNSUBSCRIBE or update options visit:
   http://lists.digium.com/mailman/listinfo/svn-commits

-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.




More information about the asterisk-commits mailing list