[asterisk-commits] bbryant: branch bbryant/noise_reduction_and_agc r114910 - /team/bbryant/noise...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Apr 30 15:29:56 CDT 2008


Author: bbryant
Date: Wed Apr 30 15:29:55 2008
New Revision: 114910

URL: http://svn.digium.com/view/asterisk?view=rev&rev=114910
Log:
Update code in the func_speex.c file

Modified:
    team/bbryant/noise_reduction_and_agc/funcs/func_speex.c

Modified: team/bbryant/noise_reduction_and_agc/funcs/func_speex.c
URL: http://svn.digium.com/view/asterisk/team/bbryant/noise_reduction_and_agc/funcs/func_speex.c?view=diff&rev=114910&r1=114909&r2=114910
==============================================================================
--- team/bbryant/noise_reduction_and_agc/funcs/func_speex.c (original)
+++ team/bbryant/noise_reduction_and_agc/funcs/func_speex.c Wed Apr 30 15:29:55 2008
@@ -4,7 +4,7 @@
  * Copyright (C) 2008, Digium, Inc.
  *
  * Brian Degenhardt <bmd at digium.com>
- * Russell Bryant <russell at digium.com> 
+ * Brett Bryant <bbryant at digium.com> 
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
@@ -22,7 +22,7 @@
  * \brief Noise reduction and automatic gain control (AGC)
  *
  * \author Brian Degenhardt <bmd at digium.com> 
- * \author Russell Bryant <russell at digium.com> 
+ * \author Brett Bryant <bbryant at digium.com> 
  *
  * \ingroup functions
  *
@@ -47,14 +47,16 @@
 #define DEFAULT_AGC_LEVEL 8000.0
 
 struct speex_direction_info {
-	int denoise;
-	float agclevel;
-	SpeexPreprocessState *preprocess_state;
+	SpeexPreprocessState *state;	/*! speex preprocess state object */
+	int agc;						/*! audio gain control is enabled or not */
+	int denoise;					/*! denoise is enabled or not */
+	int samples;					/*! n of 8Khz samples in last frame */
+	float agclevel;					/*! audio gain control level [1.0 - 32768.0] */
 };
 
 struct speex_info {
 	struct ast_audiohook audiohook;
-	struct speex_direction_info tx, rx;
+	struct speex_direction_info *tx, *rx;
 };
 
 static void destroy_callback(void *data) 
@@ -62,6 +64,22 @@
 	struct speex_info *si = data;
 
 	ast_audiohook_destroy(&si->audiohook);
+
+	if (si->rx && si->rx->state) {
+		speex_preprocess_state_destroy(si->rx->state);
+	}
+
+	if (si->tx && si->tx->state) {
+		speex_preprocess_state_destroy(si->tx->state);
+	}
+
+	if (si->rx) {
+		ast_free(si->rx);
+	}
+
+	if (si->tx) {
+		ast_free(si->tx);
+	}
 
 	ast_free(data);
 };
@@ -74,33 +92,48 @@
 static int speex_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
 {
 	struct ast_datastore *datastore = NULL;
+	struct speex_direction_info *sdi = NULL;
 	struct speex_info *si = NULL;
-	struct speex_direction_info *sdi = NULL;
-	int agcenabled;
 
 	/* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
-	if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
+	if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE || frame->frametype != AST_FRAME_VOICE) {
 		return 0;
-
-	if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL)))
+	}
+	
+	ast_channel_lock(chan);
+	if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
+		ast_channel_unlock(chan);
 		return 0;
+	}
+	ast_channel_unlock(chan);
 
 	si = datastore->data;
 
-	/* If we don't have a voice frame, or there's no agc level for the direction of this frame... exit */
-	if (frame->frametype != AST_FRAME_VOICE)
+	sdi = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? si->rx : si->tx;
+
+	if (!sdi) {
 		return 0;
-
-	sdi = (direction = AST_AUDIOHOOK_DIRECTION_READ) ? &si->rx : &si->tx;
-
-	agcenabled = !!sdi->agclevel;
-
-	speex_preprocess_ctl(sdi->preprocess_state, SPEEX_PREPROCESS_SET_DENOISE, &sdi->denoise);
-	speex_preprocess_ctl(sdi->preprocess_state, SPEEX_PREPROCESS_SET_AGC, &agcenabled);
-	if (agcenabled)
-		speex_preprocess_ctl(sdi->preprocess_state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &sdi->agclevel);
-
-	speex_preprocess(sdi->preprocess_state, frame->data, NULL);
+	}
+
+	if (sdi->samples != frame->samples) {
+		if (sdi->state) {
+			speex_preprocess_state_destroy(sdi->state);
+		}
+
+		if (!(sdi->state = speex_preprocess_state_init((sdi->samples = frame->samples), 8000))) {
+			return -1;
+		}
+		
+		speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC, &sdi->agc);
+
+		if (sdi->agc) {
+			speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &sdi->agclevel);
+		}
+
+		speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_DENOISE, &sdi->denoise);
+	}
+
+	speex_preprocess(sdi->state, frame->data, NULL);
 
 	return 0;
 }
@@ -109,12 +142,17 @@
 {
 	struct ast_datastore *datastore = NULL;
 	struct speex_info *si = NULL;
+	struct speex_direction_info **sdi = NULL;
 	int is_new = 0;
-	float *agcval = NULL;
-
+
+	ast_channel_lock(chan);
 	if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
-		if (!(datastore = ast_channel_datastore_alloc(&speex_datastore, NULL)))
+		ast_channel_unlock(chan);
+
+		if (!(datastore = ast_channel_datastore_alloc(&speex_datastore, NULL))) {
 			return 0;
+		}
+
 		if (!(si = ast_calloc(1, sizeof(*si)))) {
 			ast_channel_datastore_free(datastore);
 			return 0;
@@ -125,29 +163,86 @@
 
 		is_new = 1;
 	} else {
+		ast_channel_unlock(chan);
 		si = datastore->data;
 	}
+
+	if (!strcasecmp(data, "rx")) {
+		sdi = &si->rx;
+	} else if (!strcasecmp(data, "tx")) {
+		sdi = &si->tx;
+	} else {
+		ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);
+
+		if (is_new) {
+			ast_channel_datastore_free(datastore);
+			return -1;
+		}
+	}
+
+	if (!*sdi) {
+		if (!(*sdi = ast_calloc(1, sizeof(*sdi)))) {
+			return 0;
+		}
+		/* Right now, the audiohooks API will _only_ provide us 8 kHz slinear
+		 * audio.  When it supports 16 kHz (or any other sample rates, we will
+		 * have to take that into account here. */
+		(*sdi)->samples = -1;
+	}
+
+	if (!strcasecmp(cmd, "agc")) {
+		if (!sscanf(value, "%f", &(*sdi)->agclevel))
+			(*sdi)->agclevel = ast_true(value) ? DEFAULT_AGC_LEVEL : 0.0;
 	
-	if (!strcasecmp(cmd, "agc")) {
-		if (!strcasecmp(data, "tx") && !sscanf(value, "%f", agcval))
-			agcval = &si->tx.agclevel;
-		else if (!strcasecmp(data, "rx"))
-			agcval = &si->rx.agclevel;
-
-		if (agcval && !sscanf(value, "%f", agcval))
-			*agcval = (ast_true(value)) ? DEFAULT_AGC_LEVEL : 0;
+		if ((*sdi)->agclevel > 32768.0) {
+			ast_log(LOG_WARNING, "AGC(%s)=%.01f is greater than 32768... setting to 32768 instead\n", 
+					((*sdi == si->rx) ? "rx" : "tx"), (*sdi)->agclevel);
+			(*sdi)->agclevel = 32768.0;
+		}
+	
+		(*sdi)->agc = !!((*sdi)->agclevel);
+
+		if ((*sdi)->state) {
+			speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC, &(*sdi)->agc);
+			if ((*sdi)->agc) {
+				speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &(*sdi)->agclevel);
+			}
+		}
 	} else if (!strcasecmp(cmd, "denoise")) {
-		if (!strcasecmp(data, "tx"))
-			si->tx.denoise = ast_true(value);
-		else if (!strcasecmp(data, "rx"))	
-			si->rx.denoise = ast_true(value);
+		(*sdi)->denoise = ast_true(value);
+
+		if ((*sdi)->state) {
+			speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_DENOISE, &(*sdi)->denoise);
+		}
+	}
+
+	if (!(*sdi)->agc && !(*sdi)->denoise) {
+		if ((*sdi)->state)
+			speex_preprocess_state_destroy((*sdi)->state);
+
+		ast_free(*sdi);
+		*sdi = NULL;
+	}
+
+	if (!si->rx && !si->tx) {
+		if (is_new) {
+			is_new = 0;
+		} else {
+			ast_channel_lock(chan);
+			ast_channel_datastore_remove(chan, datastore);
+			ast_channel_unlock(chan);
+		}
+
+		ast_audiohook_detach(&si->audiohook);
+
+		ast_channel_datastore_free(datastore);
 	}
 
 	if (is_new) { 
-		si->rx.preprocess_state = speex_preprocess_state_init(160, 8000);
-		si->tx.preprocess_state = speex_preprocess_state_init(160, 8000);
 		datastore->data = si;
+		ast_channel_lock(chan);
 		ast_channel_datastore_add(chan, datastore);
+		ast_channel_unlock(chan);
 		ast_audiohook_attach(chan, &si->audiohook);
 	}
 




More information about the asterisk-commits mailing list