[asterisk-commits] oej: branch oej/roibos-cng-support-1.8 r374754 - in /team/oej/roibos-cng-supp...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Oct 9 04:54:23 CDT 2012


Author: oej
Date: Tue Oct  9 04:54:06 2012
New Revision: 374754

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=374754
Log:
Moving the noise generator into the core. Test with the whitenoise() application

Modified:
    team/oej/roibos-cng-support-1.8/include/asterisk/channel.h
    team/oej/roibos-cng-support-1.8/main/channel.c
    team/oej/roibos-cng-support-1.8/res/res_noise.c

Modified: team/oej/roibos-cng-support-1.8/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/roibos-cng-support-1.8/include/asterisk/channel.h?view=diff&rev=374754&r1=374753&r2=374754
==============================================================================
--- team/oej/roibos-cng-support-1.8/include/asterisk/channel.h (original)
+++ team/oej/roibos-cng-support-1.8/include/asterisk/channel.h Tue Oct  9 04:54:06 2012
@@ -2350,6 +2350,42 @@
 void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state);
 
 /*!
+ * \brief An opaque 'object' structure use by noise generators on channels.
+ */
+struct ast_noise_generator;
+
+/*!
+ * \brief Starts a noise generator on the given channel.
+ * \param chan The channel to generate silence on
+ * \param level The noise level in negative (dBOV)
+ * \return An ast_noise_generator pointer, or NULL if an error occurs
+ *
+ * \details
+ * This function will cause SLINEAR noise to be generated on the supplied
+ * channel until it is disabled; if the channel cannot be put into SLINEAR
+ * mode then the function will fail.
+ *
+ * \note
+ * The pointer returned by this function must be preserved and passed to
+ * ast_channel_stop_noise_generator when you wish to stop the noise
+ * generation.
+ */
+struct ast_noise_generator *ast_channel_start_noise_generator(struct ast_channel *chan, const float level);
+
+/*!
+ * \brief Stops a previously-started noise generator on the given channel.
+ * \param chan The channel to operate on
+ * \param state The ast_noise_generator pointer return by a previous call to
+ * ast_channel_start_noise_generator.
+ * \return nothing
+ *
+ * \details
+ * This function will stop the operating noise generator and return the channel
+ * to its previous write format.
+ */
+void ast_channel_stop_noise_generator(struct ast_channel *chan, struct ast_noise_generator *state);
+
+/*!
  * \brief Check if the channel can run in internal timing mode.
  * \param chan The channel to check
  * \return boolean

Modified: team/oej/roibos-cng-support-1.8/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/roibos-cng-support-1.8/main/channel.c?view=diff&rev=374754&r1=374753&r2=374754
==============================================================================
--- team/oej/roibos-cng-support-1.8/main/channel.c (original)
+++ team/oej/roibos-cng-support-1.8/main/channel.c Tue Oct  9 04:54:06 2012
@@ -8198,6 +8198,242 @@
 }
 
 
+#ifdef HAVE_EXP10L
+#define FUNC_EXP10       exp10l
+#elif (defined(HAVE_EXPL) && defined(HAVE_LOGL))
+#define FUNC_EXP10(x)   expl((x) * logl(10.0))
+#elif (defined(HAVE_EXP) && defined(HAVE_LOG))
+#define FUNC_EXP10(x)   (long double)exp((x) * log(10.0))
+#endif
+
+/*! \brief Noise generator default frame */
+static struct ast_frame noiseframedefaults = {
+	.frametype = AST_FRAME_VOICE,
+	.subclass.codec = AST_FORMAT_SLINEAR,
+	.offset = AST_FRIENDLY_OFFSET,
+	.mallocd = 0,
+	.data.ptr = NULL,
+	.datalen = 0,
+	.samples = 0,
+	.src = "noisegenerator",
+	.delivery.tv_sec = 0,
+	.delivery.tv_usec = 0
+};
+
+struct ast_noise_generator {
+	int old_write_format;
+	float level;
+};
+
+
+#ifndef LOW_MEMORY
+/*
+ * We pregenerate 64k of white noise samples that will be used instead of
+ * generating the samples continously and wasting CPU cycles. The buffer
+ * below stores these pregenerated samples.
+ */
+static float pregeneratedsamples[65536L];
+#endif
+
+/* 
+ * We need a nice, not too expensive, gaussian random number generator.
+ * It generates two random numbers at a time, which is great.
+ * From http://www.taygeta.com/random/gaussian.html
+ */
+static void box_muller_rng(float stddev, float *rn1, float *rn2) {
+	const float twicerandmaxinv = 2.0 / RAND_MAX;
+	float x1, x2, w;
+	 
+	do {
+		x1 = random() * twicerandmaxinv - 1.0;
+		x2 = random() * twicerandmaxinv - 1.0;
+		w = x1 * x1 + x2 * x2;
+	} while (w >= 1.0);
+	
+	w = stddev * sqrt((-2.0 * logf(w)) / w);
+	*rn1 = x1 * w;
+	*rn2 = x2 * w;
+}
+
+static void *noise_generator_alloc(struct ast_channel *chan, void *params) {
+	struct ast_noise_generator *state = params;
+	float level = state->level; 	/* level is noise level in dBov */
+	float *pnoisestddev; 		/* pointer to calculated noise standard dev */
+	const float maxsigma = 32767.0 / 3.0;
+
+	/*
+	 * When level is zero (full power, by definition) standard deviation
+	 * (sigma) is calculated so that 3 * sigma equals max sample value
+	 * before overload. For signed linear, which is what we use, this
+	 * value is 32767. The max value of sigma will therefore be
+	 * 32767.0 / 3.0. This guarantees that roughly 99.7% of the samples
+	 * generated will be between -32767 and +32767. The rest, 0.3%,
+	 * will be clipped to comform to the channel limits, i.e., +/-32767.
+	 * 
+	 */
+	pnoisestddev = malloc(sizeof (float));
+	if(pnoisestddev) {
+		*pnoisestddev = maxsigma * FUNC_EXP10(level / 20.0);
+	}
+
+	return (void *) pnoisestddev;
+}
+
+static void noise_generator_release(struct ast_channel *chan, void *data) {
+	free((float *)data);
+}
+
+/*! \brief Generator of White Noise at a certain level.
+
+Current level is defined in the generator data structure as noiselevel (float) in dBov's
+
+
+	Level is a non-positive number. For example, WhiteNoise(0.0) generates
+	white noise at full power, while WhiteNoise(-3.0) generates white noise at
+	half full power. Every -3dBov's reduces white noise power in half. Full
+	power in this case is defined as noise that overloads the channel roughly 0.3%
+	of the time. Note that values below -69 dBov's start to give out silence
+	frequently, resulting in intermittent noise, i.e, alternating periods of
+	silence and noise.
+
+This code orginally contributed to Asterisk by cmantunes in issue ASTERISK-5263
+as part of res_noise.c
+*/
+static int noise_generate(struct ast_channel *chan, void *data, int len, int samples) {
+#ifdef LOW_MEMORY
+	float randomnumber[2];
+	float sampleamplitude;
+	int j;
+#else
+	uint16_t start;
+#endif
+	float noisestddev = *(float *)data;
+	struct ast_frame f;
+	int16_t *buf, *pbuf;
+	int i;
+
+#ifdef LOW_MEMORY
+	/* We need samples to be an even number */
+	if (samples & 0x1) {
+		ast_log(LOG_WARNING, "Samples (%d) needs to be an even number\n", samples);
+		return -1;
+	}
+#endif
+
+	/* Allocate enough space for samples.
+	 * Remember that slin uses signed dword samples */
+	len = samples * sizeof (int16_t);
+	if(!(buf = ast_alloca(len))) {
+		ast_log(LOG_WARNING, "Unable to allocate buffer to generate %d samples\n", samples);
+		return -1;
+	}
+
+	/* Setup frame */
+	memcpy(&f, &noiseframedefaults, sizeof (f));
+	f.data.ptr = buf;
+	f.datalen = len;
+	f.samples = samples;
+
+	/* Let's put together our frame "data" */
+	pbuf = buf;
+
+#ifdef LOW_MEMORY
+	/* We need to generate samples every time we are called */
+	for (i = 0; i < samples; i += 2) {
+		box_muller_rng(noisestddev, &randomnumber[0], &randomnumber[1]);
+		for (j = 0; j < 2; j++) {
+			sampleamplitude = randomnumber[j];
+			if (sampleamplitude > 32767.0)
+				sampleamplitude = 32767.0;
+			else if (sampleamplitude < -32767.0)
+				sampleamplitude = -32767.0;
+			*(pbuf++) = (int16_t)sampleamplitude;
+		}
+	}
+#else
+	/*
+	 * We are going to use pregenerated samples. But we start at
+	 * different points on the pregenerated samples buffer every time
+	 * to create a little bit more randomness
+	 *
+	 */
+	start = (uint16_t) (65536.0 * random() / RAND_MAX);
+	for (i = 0; i < samples; i++) {
+		*(pbuf++) = (int16_t)(noisestddev * pregeneratedsamples[start++]);
+	}
+#endif
+
+	/* Send it out */
+	if (ast_write(chan, &f) < 0) {
+		ast_log(LOG_WARNING, "Failed to write frame to channel '%s'\n", chan->name);
+		return -1;
+	}
+	return 0;
+}
+
+static struct ast_generator noise_generator = 
+{
+	alloc: noise_generator_alloc,
+	release: noise_generator_release,
+	generate: noise_generate,
+} ;
+
+struct ast_noise_generator *ast_channel_start_noise_generator(struct ast_channel *chan, const float level)
+{
+	struct ast_noise_generator  *state;
+	int i;
+
+#ifndef LOW_MEMORY
+	/* This should only be done once per asterisk instance */
+	if (pregeneratedsamples[0] == 0.0) {
+		for (i = 0; i < sizeof (pregeneratedsamples) / sizeof (pregeneratedsamples[0]); i += 2) {
+			box_muller_rng(1.0, &pregeneratedsamples[i], &pregeneratedsamples[i + 1]);
+		}
+	}
+#endif
+
+	if (level > 0) {
+		ast_log(LOG_ERROR, "Noise generator: Invalid argument -  non-positive floating-point argument for noise level in dBov's required \n");
+		return NULL;
+	}
+
+	if (!(state = ast_calloc(1, sizeof(*state)))) {
+		return NULL;
+	}
+
+	state->old_write_format = chan->writeformat;
+	state->level = level;
+
+	if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
+		ast_log(LOG_ERROR, "Could not set write format to SLINEAR\n");
+		ast_free(state);
+		return NULL;
+	}
+
+	ast_activate_generator(chan, &noise_generator, state);
+
+	ast_debug(1, "Started noise generator on '%s'\n", chan->name);
+
+	return state;
+}
+
+void ast_channel_stop_noise_generator(struct ast_channel *chan, struct ast_noise_generator *state)
+{
+	if (!state)
+		return;
+
+	ast_deactivate_generator(chan);
+
+	ast_debug(1, "Stopped silence generator on '%s'\n", chan->name);
+
+	if (ast_set_write_format(chan, state->old_write_format) < 0)
+		ast_log(LOG_ERROR, "Could not return write format to its original state\n");
+
+	ast_free(state);
+}
+
+
+
 /*! \ brief Convert channel reloadreason (ENUM) to text string for manager event */
 const char *channelreloadreason2txt(enum channelreloadreason reason)
 {

Modified: team/oej/roibos-cng-support-1.8/res/res_noise.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/roibos-cng-support-1.8/res/res_noise.c?view=diff&rev=374754&r1=374753&r2=374754
==============================================================================
--- team/oej/roibos-cng-support-1.8/res/res_noise.c (original)
+++ team/oej/roibos-cng-support-1.8/res/res_noise.c Tue Oct  9 04:54:06 2012
@@ -26,7 +26,6 @@
 	<support_level>random</support_level>
  ***/
 
-#include <math.h>
 
 #include "asterisk.h"
 
@@ -40,13 +39,7 @@
 #include "asterisk/module.h"
 #include "asterisk/app.h"
 
-#ifdef HAVE_EXP10L
-#define FUNC_EXP10       exp10l
-#elif (defined(HAVE_EXPL) && defined(HAVE_LOGL))
-#define FUNC_EXP10(x)   expl((x) * logl(10.0))
-#elif (defined(HAVE_EXP) && defined(HAVE_LOG))
-#define FUNC_EXP10(x)   (long double)exp((x) * log(10.0))
-#endif
+#include <math.h>
 
 static char *app = "WhiteNoise";
 
@@ -77,154 +70,6 @@
 	</application>
 ***/
 
-static struct ast_frame framedefaults = {
-	.frametype = AST_FRAME_VOICE,
-	.subclass.codec = AST_FORMAT_SLINEAR,
-	.offset = AST_FRIENDLY_OFFSET,
-	.mallocd = 0,
-	.data.ptr = NULL,
-	.datalen = 0,
-	.samples = 0,
-	.src = "whitenoise",
-	.delivery.tv_sec = 0,
-	.delivery.tv_usec = 0
-};
-
-
-#ifndef LOW_MEMORY
-/*
- * We pregenerate 64k of white noise samples that will be used instead of
- * generating the samples continously and wasting CPU cycles. The buffer
- * below stores these pregenerated samples.
- */
-static float pregeneratedsamples[65536L];
-#endif
-
-/* 
- * We need a nice, not too expensive, gaussian random number generator.
- * It generates two random numbers at a time, which is great.
- * From http://www.taygeta.com/random/gaussian.html
- */
-static void box_muller_rng(float stddev, float *rn1, float *rn2) {
-	const float twicerandmaxinv = 2.0 / RAND_MAX;
-	float x1, x2, w;
-	 
-	do {
-		x1 = random() * twicerandmaxinv - 1.0;
-		x2 = random() * twicerandmaxinv - 1.0;
-		w = x1 * x1 + x2 * x2;
-	} while (w >= 1.0);
-	
-	w = stddev * sqrt((-2.0 * logf(w)) / w);
-	*rn1 = x1 * w;
-	*rn2 = x2 * w;
-}
-
-static void *noise_alloc(struct ast_channel *chan, void *data) {
-	float level = *(float *)data; /* level is noise level in dBov */
-	float *pnoisestddev; /* pointer to calculated noise standard dev */
-	const float maxsigma = 32767.0 / 3.0;
-
-	/*
-	 * When level is zero (full power, by definition) standard deviation
-	 * (sigma) is calculated so that 3 * sigma equals max sample value
-	 * before overload. For signed linear, which is what we use, this
-	 * value is 32767. The max value of sigma will therefore be
-	 * 32767.0 / 3.0. This guarantees that roughly 99.7% of the samples
-	 * generated will be between -32767 and +32767. The rest, 0.3%,
-	 * will be clipped to comform to the channel limits, i.e., +/-32767.
-	 * 
-	 */
-	pnoisestddev = malloc(sizeof (float));
-	if(pnoisestddev) {
-		*pnoisestddev = maxsigma * FUNC_EXP10(level / 20.0);
-	}
-	return pnoisestddev;
-}
-
-static void noise_release(struct ast_channel *chan, void *data) {
-	free((float *)data);
-}
-
-static int noise_generate(struct ast_channel *chan, void *data, int len, int samples) {
-#ifdef LOW_MEMORY
-	float randomnumber[2];
-	float sampleamplitude;
-	int j;
-#else
-	uint16_t start;
-#endif
-	float noisestddev = *(float *)data;
-	struct ast_frame f;
-	int16_t *buf, *pbuf;
-	int i;
-
-#ifdef LOW_MEMORY
-	/* We need samples to be an even number */
-	if (samples & 0x1) {
-		ast_log(LOG_WARNING, "Samples (%d) needs to be an even number\n", samples);
-		return -1;
-	}
-#endif
-
-	/* Allocate enough space for samples.
-	 * Remember that slin uses signed dword samples */
-	len = samples * sizeof (int16_t);
-	if(!(buf = alloca(len))) {
-		ast_log(LOG_WARNING, "Unable to allocate buffer to generate %d samples\n", samples);
-		return -1;
-	}
-
-	/* Setup frame */
-	memcpy(&f, &framedefaults, sizeof (f));
-	f.data.ptr = buf;
-	f.datalen = len;
-	f.samples = samples;
-
-	/* Let's put together our frame "data" */
-	pbuf = buf;
-
-#ifdef LOW_MEMORY
-	/* We need to generate samples every time we are called */
-	for (i = 0; i < samples; i += 2) {
-		box_muller_rng(noisestddev, &randomnumber[0], &randomnumber[1]);
-		for (j = 0; j < 2; j++) {
-			sampleamplitude = randomnumber[j];
-			if (sampleamplitude > 32767.0)
-				sampleamplitude = 32767.0;
-			else if (sampleamplitude < -32767.0)
-				sampleamplitude = -32767.0;
-			*(pbuf++) = (int16_t)sampleamplitude;
-		}
-	}
-#else
-	/*
-	 * We are going to use pregenerated samples. But we start at
-	 * different points on the pregenerated samples buffer every time
-	 * to create a little bit more randomness
-	 *
-	 */
-	start = (uint16_t) (65536.0 * random() / RAND_MAX);
-	for (i = 0; i < samples; i++) {
-		*(pbuf++) = (int16_t)(noisestddev * pregeneratedsamples[start++]);
-	}
-#endif
-
-	/* Send it out */
-	if (ast_write(chan, &f) < 0) {
-		ast_log(LOG_WARNING, "Failed to write frame to channel '%s'\n", chan->name);
-		return -1;
-	}
-	return 0;
-}
-
-static struct ast_generator noise_generator = 
-{
-	alloc: noise_alloc,
-	release: noise_release,
-	generate: noise_generate,
-} ;
-
 static int noise_exec(struct ast_channel *chan, const char *data) {
 
 	struct ast_module_user *u;
@@ -233,6 +78,7 @@
 	float timeout = 0;
 	char *s;
 	int res;
+	struct ast_noise_generator *gendata;
 
         AST_DECLARE_APP_ARGS(args,
                 AST_APP_ARG(timeout);
@@ -281,12 +127,11 @@
 	ast_debug(1, "Setting up white noise generator with level %.1fdBov's and %.0fms %stimeout\n", level, timeout, timeout == 0 ? "(no) " : "");
 
 	u = ast_module_user_add(chan);
-	ast_set_write_format(chan, AST_FORMAT_SLINEAR);
-	ast_set_read_format(chan, AST_FORMAT_SLINEAR);
 	if (chan->_state != AST_STATE_UP) {
 		ast_answer(chan);
 	}
-	if (ast_activate_generator(chan, &noise_generator, &level) < 0)	{
+	gendata = ast_channel_start_noise_generator(chan, level);
+	if (data == NULL)	{
 		ast_log(LOG_WARNING, "Failed to activate white noise generator on '%s'\n",chan->name);
 		res = -1;
 	} else {
@@ -297,7 +142,7 @@
 		} else  {
 			while(!ast_safe_sleep(chan, 10000));
 		}
-		ast_deactivate_generator(chan);
+		ast_channel_stop_noise_generator(chan, gendata);
 	}
 	ast_module_user_remove(u);
 	return res;
@@ -310,15 +155,6 @@
 }
 
 static int load_module(void) {
-#ifndef LOW_MEMORY
-	/* Let's pregenerate all samples with std dev = 1.0 */
-	int i;
-
-	for (i = 0; i < sizeof (pregeneratedsamples) / sizeof (pregeneratedsamples[0]); i += 2) {
-		box_muller_rng(1.0, &pregeneratedsamples[i], &pregeneratedsamples[i + 1]);
-
-	}
-#endif
 	return ast_register_application_xml(app, noise_exec);
 }
 




More information about the asterisk-commits mailing list