[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