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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Sep 18 11:02:15 CDT 2012


Author: oej
Date: Tue Sep 18 11:02:11 2012
New Revision: 373121

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=373121
Log:
Adding cmantunes res_noise.c with permission from the developer. Disclaimer is in jira/mantis.

Added:
    team/oej/roibos-cng-support-1.8/README.roibos-cng.txt   (with props)
    team/oej/roibos-cng-support-1.8/res/res_noise.c   (with props)

Added: team/oej/roibos-cng-support-1.8/README.roibos-cng.txt
URL: http://svnview.digium.com/svn/asterisk/team/oej/roibos-cng-support-1.8/README.roibos-cng.txt?view=auto&rev=373121
==============================================================================
--- team/oej/roibos-cng-support-1.8/README.roibos-cng.txt (added)
+++ team/oej/roibos-cng-support-1.8/README.roibos-cng.txt Tue Sep 18 11:02:11 2012
@@ -1,0 +1,95 @@
+Edvina AB
+Olle E. Johansson
+
+
+Started: 2012-09-18
+
+
+
+
+
+Comfort Noise support in Asterisk 1.8
+=====================================
+
+Current state:
+
+* RTP Channel
+-------------
+
+- Asterisk RTP (res_rtp_asterisk.c) will read CNG packets and produce a warning. 
+  These will be forwarded to the core.
+- CNG packets will be sent only as RTP keepalives
+
+* SIP Channel
+-------------
+- The SIP channel will *NOT* negotiate any CNG support if offered, nor 
+  offer CNG
+
+* Core
+------
+
+- If a generator is active and CNG is received, Asterisk moves to timer based
+  generation of outbound packets
+- No comfort noise generator exists in core
+
+To add comfort noise support
+----------------------------
+
+- Add SIP negotiation in SDP
+- For inbound streams, generate noise in calls
+- For outbound we can as step 1 just never send any CNG packets
+  - As step 2, add silence detection to calls
+  - Measure noise level
+  - Start sending CNG
+  - Listen for talk detection
+  - Stop sending CNG, send media
+
+References
+----------
+
+- RFC 3389 http://tools.ietf.org/html/rfc3389
+- Appendix II to Recommendation G.711 (02/2000) - A comfort noise
+        payload definition for ITU-T G.711 use in packet-based
+        multimedia communication systems.
+
+
+Terms
+-----
+- DTX Discontinues Transmission capability
+- VAD Voice Activity Detection
+- CN Comfort Noise 
+- CNG Comfort Noise Generator
+
+RTP Framing (RFC 3389 section 4)
+--------------------------------
+The RTP header for the comfort noise packet SHOULD be constructed as
+   if the comfort noise were an independent codec.  Thus, the RTP
+   timestamp designates the beginning of the comfort noise period.
+
+At the beginning of
+   an inactive voice segment (silence period), a CN packet is
+   transmitted in the same RTP stream and indicated by the CN payload
+   type.  The CN packet update rate is left implementation specific. For
+   example, the CN packet may be sent periodically or only when there is
+   a significant change in the background noise characteristics.  The
+   CNG algorithm at the receiver uses the information in the CN payload
+   to update its noise generation model and then produce an appropriate
+   amount of comfort noise.
+
+Noise Level (RFC 3389 Section 3.1)
+----------------------------------
+The magnitude of the noise level is packed into the least significant
+   bits of the noise-level byte with the most significant bit unused and
+   always set to 0 as shown below in Figure 1.  The least significant
+   bit of the noise level magnitude is packed into the least significant
+   bit of the byte.
+
+   The noise level is expressed in -dBov, with values from 0 to 127
+   representing 0 to -127 dBov.  dBov is the level relative to the
+   overload of the system.  (Note: Representation relative to the
+   overload point of a system is particularly useful for digital
+   implementations, since one does not need to know the relative
+   calibration of the analog circuitry.)  For example, in the case of a
+   u-law system, the reference would be a square wave with values +/-
+   8031, and this square wave represents 0dBov.  This translates into
+   6.18dBm0.

Propchange: team/oej/roibos-cng-support-1.8/README.roibos-cng.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/oej/roibos-cng-support-1.8/README.roibos-cng.txt
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/oej/roibos-cng-support-1.8/README.roibos-cng.txt
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 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=auto&rev=373121
==============================================================================
--- team/oej/roibos-cng-support-1.8/res/res_noise.c (added)
+++ team/oej/roibos-cng-support-1.8/res/res_noise.c Tue Sep 18 11:02:11 2012
@@ -1,0 +1,328 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Contributed by Carlos Antunes <cmantunes at gmail.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file 
+ *
+ * \brief Just generate white noise 
+ * 
+ */
+
+/*** MODULEINFO
+	<support_level>random</support_level>
+ ***/
+
+#include <math.h>
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/lock.h"
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#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
+
+static char *app = "WhiteNoise";
+
+
+/*** DOCUMENTATION
+	<application name="WhiteNoise" language="en_US">
+		<synopsis>
+			Generates white noise
+		</synopsis>
+		<syntax>
+		<parameter name="args">
+			<argument name="timeout" required="true" />
+			<argument name="level" required="false" />
+		</parameter>
+		</syntax>
+		<description>
+			<para>Generates white noise at 'level' dBov's for 'timeout' seconds or indefinitely if timeout
+			is absent or is zero.</para>
+			<para>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.</para>
+
+		</description>
+	</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;
+	char *excessdata;
+	float level = 0;
+	float timeout = 0;
+	char *s;
+	int res;
+
+        AST_DECLARE_APP_ARGS(args,
+                AST_APP_ARG(timeout);
+                AST_APP_ARG(level);
+        );
+
+	/* Verify we potentially have arguments and get local copy */
+        if (!data) {
+                ast_log(LOG_WARNING, "WhiteNoise usage following: WhiteNoise([timeout[, level]])\n");
+                return -1;
+        }
+	
+	/* Separate arguments */	
+        s = ast_strdupa(data);
+        AST_STANDARD_APP_ARGS(args, s);
+
+	if (args.timeout) {	
+		/* Extract second argument, if available, and validate
+		 * timeout is non-negative. Zero timeout means no timeout */
+		args.timeout = ast_trim_blanks(args.timeout);
+		timeout = strtof(args.timeout, &excessdata);
+		if ((excessdata && *excessdata) || timeout < 0) {
+			ast_log(LOG_WARNING, "Invalid argument 'timeout': WhiteNoise requires non-negative floating-point argument for timeout in seconds\n");				
+			return -1;
+		}
+
+		/* Convert timeout to milliseconds
+		 * and ensure minimum of 20ms      */
+		timeout = roundf(timeout * 1000.0);
+		if (timeout > 0 && timeout < 20) {
+			timeout = 20;
+		}
+	} 
+
+	if (args.level) {
+		/* Extract first argument and ensure we have
+		 * a valid noise level argument value        */
+		args.level = ast_trim_blanks(args.level);
+		level = strtof(args.level, &excessdata);
+		if ((excessdata && *excessdata) || level > 0) {
+			ast_log(LOG_ERROR, "Invalid argument 'level': WhiteNoise requires non-positive floating-point argument for noise level in dBov's\n");
+			return -1;
+		}
+	} 
+
+	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)	{
+		ast_log(LOG_WARNING, "Failed to activate white noise generator on '%s'\n",chan->name);
+		res = -1;
+	} else {
+		/* Just do the noise... */
+		res = -1;
+		if (timeout > 0) {
+			res = ast_safe_sleep(chan, timeout);
+		} else  {
+			while(!ast_safe_sleep(chan, 10000));
+		}
+		ast_deactivate_generator(chan);
+	}
+	ast_module_user_remove(u);
+	return res;
+}
+
+static int unload_module(void) {
+	ast_module_user_hangup_all();
+	
+	return ast_unregister_application(app);
+}
+
+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);
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "White Noise Generator Application",
+                .load = load_module,
+                .unload = unload_module,
+               );

Propchange: team/oej/roibos-cng-support-1.8/res/res_noise.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/oej/roibos-cng-support-1.8/res/res_noise.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/oej/roibos-cng-support-1.8/res/res_noise.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the asterisk-commits mailing list