[asterisk-commits] oej: branch oej/teapot-1.8 r384887 - in /team/oej/teapot-1.8: channels/ chann...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Apr 8 09:00:30 CDT 2013


Author: oej
Date: Mon Apr  8 09:00:26 2013
New Revision: 384887

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=384887
Log:
Adding roibos

Modified:
    team/oej/teapot-1.8/channels/chan_sip.c
    team/oej/teapot-1.8/channels/sip/include/sip.h
    team/oej/teapot-1.8/configs/sip.conf.sample
    team/oej/teapot-1.8/funcs/func_frame_trace.c
    team/oej/teapot-1.8/include/asterisk/channel.h
    team/oej/teapot-1.8/include/asterisk/frame.h
    team/oej/teapot-1.8/main/channel.c
    team/oej/teapot-1.8/main/features.c
    team/oej/teapot-1.8/main/frame.c
    team/oej/teapot-1.8/main/rtp_engine.c
    team/oej/teapot-1.8/res/res_rtp_asterisk.c

Modified: team/oej/teapot-1.8/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/channels/chan_sip.c?view=diff&rev=384887&r1=384886&r2=384887
==============================================================================
--- team/oej/teapot-1.8/channels/chan_sip.c (original)
+++ team/oej/teapot-1.8/channels/chan_sip.c Mon Apr  8 09:00:26 2013
@@ -4762,6 +4762,10 @@
 		 * implied else case here
 		 */
 		break;
+	case AST_OPTION_CNG_SUPPORT:
+		/* Check if the current dialog has agreed on Comfort Noise support */
+		res = (p->noncodeccapability & AST_RTP_CN);
+		break;
 	default:
 		break;
 	}
@@ -5756,6 +5760,10 @@
 		dialog->noncodeccapability |= AST_RTP_DTMF;
 	else
 		dialog->noncodeccapability &= ~AST_RTP_DTMF;
+
+	if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_ALLOW_CN)) {
+		dialog->noncodeccapability |= AST_RTP_CN;
+	}
 	dialog->directmediaha = ast_duplicate_ha_list(peer->directmediaha);
 	if (peer->call_limit)
 		ast_set_flag(&dialog->flags[0], SIP_CALL_LIMIT);
@@ -9679,7 +9687,7 @@
 		   they are acceptable */
 		p->jointcapability = newjointcapability;                /* Our joint codec profile for this call */
 		p->peercapability = newpeercapability;                  /* The other side's capability in latest offer */
-		p->jointnoncodeccapability = newnoncodeccapability;     /* DTMF capabilities */
+		p->jointnoncodeccapability = newnoncodeccapability;     /* CN and DTMF capabilities */
 
 		/* respond with single most preferred joint codec, limiting the other side's choice */
 		if (ast_test_flag(&p->flags[1], SIP_PAGE2_PREFERRED_CODEC)) {
@@ -11466,6 +11474,7 @@
 		fmt = ast_codec_pref_getsize(pref, codec);
 	} else /* I don't see how you couldn't have p->rtp, but good to check for and error out if not there like earlier code */
 		return;
+
 	ast_str_append(m_buf, 0, " %d", rtp_code);
 	ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code,
 		       ast_rtp_lookup_mime_subtype2(1, codec,
@@ -11585,7 +11594,7 @@
 	}
 }
 
-/*! \brief Add RFC 2833 DTMF offer to SDP */
+/*! \brief Add CN and RFC 2833 DTMF offer to SDP */
 static void add_noncodec_to_sdp(const struct sip_pvt *p, int format,
 				struct ast_str **m_buf, struct ast_str **a_buf,
 				int debug)
@@ -11951,10 +11960,12 @@
 				add_tcodec_to_sdp(p, x, &m_text, &a_text, debug, &min_text_packet_size);
 		}
 
-		/* Now add DTMF RFC2833 telephony-event as a codec */
+		/* Now add Comfort Noise and DTMF RFC2833 telephony-event as a codec */
 		for (x = 1LL; x <= AST_RTP_MAX; x <<= 1) {
-			if (!(p->jointnoncodeccapability & x))
+			if (!(p->jointnoncodeccapability & x)) {
+				ast_debug(1, "NOT Adding non-codec 0x%lx (%s) to SDP\n", (int64_t)x, ast_rtp_lookup_mime_subtype2(0, x, 0));
 				continue;
+			}
 
 			add_noncodec_to_sdp(p, x, &m_audio, &a_audio, debug);
 		}
@@ -16695,6 +16706,9 @@
 			p->noncodeccapability |= AST_RTP_DTMF;
 		else
 			p->noncodeccapability &= ~AST_RTP_DTMF;
+		if (ast_test_flag(&p->flags[1], SIP_PAGE2_ALLOW_CN)) {
+			p->noncodeccapability |= AST_RTP_CN;
+		}
 		p->jointnoncodeccapability = p->noncodeccapability;
 		p->rtptimeout = peer->rtptimeout;
 		p->rtpholdtimeout = peer->rtpholdtimeout;
@@ -18141,6 +18155,7 @@
 		ast_cli(fd, "  User=Phone   : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_USEREQPHONE)));
 		ast_cli(fd, "  Video Support: %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_VIDEOSUPPORT) || ast_test_flag(&peer->flags[1], SIP_PAGE2_VIDEOSUPPORT_ALWAYS)));
 		ast_cli(fd, "  Text Support : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_TEXTSUPPORT)));
+		ast_cli(fd, "  Comfort Noise: %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOW_CN)));
 		ast_cli(fd, "  Ign SDP ver  : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_IGNORESDPVERSION)));
 		ast_cli(fd, "  Trust RPID   : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_TRUSTRPID)));
 		ast_cli(fd, "  Send RPID    : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_SENDRPID)));
@@ -18253,6 +18268,7 @@
 		astman_append(s, "SIP-T.38Support: %s\r\n", (ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT)?"Y":"N"));
 		astman_append(s, "SIP-T.38EC: %s\r\n", faxec2str(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT)));
 		astman_append(s, "SIP-T.38MaxDtgrm: %d\r\n", peer->t38_maxdatagram);
+		astman_append(s, "SIP-ComfortNoise: %s\r\n", (ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOW_CN)?"Y":"N"));
 		astman_append(s, "SIP-Sess-Timers: %s\r\n", stmode2str(peer->stimer.st_mode_oper));
 		astman_append(s, "SIP-Sess-Refresh: %s\r\n", strefresherparam2str(peer->stimer.st_ref));
 		astman_append(s, "SIP-Sess-Expires: %d\r\n", peer->stimer.st_max_se);
@@ -18706,6 +18722,7 @@
 				"Disabled");
 	ast_cli(a->fd, "  Videosupport:           %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_VIDEOSUPPORT)));
 	ast_cli(a->fd, "  Textsupport:            %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_TEXTSUPPORT)));
+	ast_cli(a->fd, "  Comfort Noise:          %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOW_CN)));
 	ast_cli(a->fd, "  Ignore SDP sess. ver.:  %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_IGNORESDPVERSION)));
 	ast_cli(a->fd, "  AutoCreate Peer:        %s\n", AST_CLI_YESNO(sip_cfg.autocreatepeer));
 	ast_cli(a->fd, "  Match Auth Username:    %s\n", AST_CLI_YESNO(global_match_auth_username));
@@ -19228,6 +19245,7 @@
 			ast_cli(a->fd, "  Format:                 %s\n", ast_getformatname_multiple(formatbuf, sizeof(formatbuf), cur->owner ? cur->owner->nativeformats : 0) );
 			ast_cli(a->fd, "  T.38 support            %s\n", AST_CLI_YESNO(cur->udptl != NULL));
 			ast_cli(a->fd, "  Video support           %s\n", AST_CLI_YESNO(cur->vrtp != NULL));
+			ast_cli(a->fd, "  Comfort Noise support   %s\n", AST_CLI_YESNO(ast_test_flag(&cur->flags[1],SIP_PAGE2_ALLOW_CN)));
 			ast_cli(a->fd, "  MaxCallBR:              %d kbps\n", cur->maxcallbitrate);
 			ast_cli(a->fd, "  Theoretical Address:    %s\n", ast_sockaddr_stringify(&cur->sa));
 			ast_cli(a->fd, "  Received Address:       %s\n", ast_sockaddr_stringify(&cur->recv));
@@ -27603,6 +27621,8 @@
 	} else if (!strcasecmp(v->name, "buggymwi")) {
 		ast_set_flag(&mask[1], SIP_PAGE2_BUGGY_MWI);
 		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_BUGGY_MWI);
+	} else if (!strcasecmp(v->name, "comfort-noise")) {
+		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_ALLOW_CN);
 	} else
 		res = 0;
 

Modified: team/oej/teapot-1.8/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/channels/sip/include/sip.h?view=diff&rev=384887&r1=384886&r2=384887
==============================================================================
--- team/oej/teapot-1.8/channels/sip/include/sip.h (original)
+++ team/oej/teapot-1.8/channels/sip/include/sip.h Mon Apr  8 09:00:26 2013
@@ -347,6 +347,7 @@
 #define SIP_PAGE2_VIDEOSUPPORT_ALWAYS       (1 << 27)   /*!< DP: Always set up video, even if endpoints don't support it */
 #define SIP_PAGE2_HAVEPEERCONTEXT           (1 << 28)   /*< Are we associated with a configured peer context? */
 #define SIP_PAGE2_USE_SRTP                  (1 << 29)   /*!< DP: Whether we should offer (only)  SRTP */
+#define SIP_PAGE2_ALLOW_CN                  (1 << 30)   /*!< DP: If we allow Comfort Noise generation */
 
 #define SIP_PAGE2_FLAGS_TO_COPY \
 	(SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_IGNORESDPVERSION | \
@@ -354,7 +355,8 @@
 	SIP_PAGE2_BUGGY_MWI | SIP_PAGE2_TEXTSUPPORT | SIP_PAGE2_FAX_DETECT | \
 	SIP_PAGE2_UDPTL_DESTINATION | SIP_PAGE2_VIDEOSUPPORT_ALWAYS | SIP_PAGE2_PREFERRED_CODEC | \
 	SIP_PAGE2_RPID_IMMEDIATE | SIP_PAGE2_RPID_UPDATE | SIP_PAGE2_SYMMETRICRTP |\
-	SIP_PAGE2_Q850_REASON | SIP_PAGE2_HAVEPEERCONTEXT | SIP_PAGE2_USE_SRTP)
+	SIP_PAGE2_Q850_REASON | SIP_PAGE2_HAVEPEERCONTEXT | SIP_PAGE2_USE_SRTP |\
+	SIP_PAGE2_ALLOW_CN )
 
 
 #define SIP_PAGE3_SNOM_AOC               (1 << 0)  /*!< DPG: Allow snom aoc messages */

Modified: team/oej/teapot-1.8/configs/sip.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/configs/sip.conf.sample?view=diff&rev=384887&r1=384886&r2=384887
==============================================================================
--- team/oej/teapot-1.8/configs/sip.conf.sample (original)
+++ team/oej/teapot-1.8/configs/sip.conf.sample Mon Apr  8 09:00:26 2013
@@ -300,6 +300,13 @@
 ;allow=ulaw                     ; Allow codecs in order of preference
 ;allow=ilbc                     ; see https://wiki.asterisk.org/wiki/display/AST/RTP+Packetization
 				; for framing options
+
+;comfort-noise=yes		; Enable Comfort Noise generation on RTP streams
+;				; Available per device too
+;				; Generating comfort noise is a burden to your CPU
+;				; This should not be enabled on low-end devices.
+;				; You should not enable this unless you have internal
+;				; timing support enabled in asterisk.conf
 ;
 ; This option specifies a preference for which music on hold class this channel
 ; should listen to when put on hold if the music class has not been set on the

Modified: team/oej/teapot-1.8/funcs/func_frame_trace.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/funcs/func_frame_trace.c?view=diff&rev=384887&r1=384886&r2=384887
==============================================================================
--- team/oej/teapot-1.8/funcs/func_frame_trace.c (original)
+++ team/oej/teapot-1.8/funcs/func_frame_trace.c Mon Apr  8 09:00:26 2013
@@ -321,6 +321,9 @@
 		case AST_CONTROL_UPDATE_RTP_PEER:
 			ast_verbose("SubClass: UPDATE_RTP_PEER\n");
 			break;
+		case AST_CONTROL_CNG_END:
+			ast_verbose("SubClass: CNG_END");
+			break;
 		}
 		
 		if (frame->subclass.integer == -1) {

Modified: team/oej/teapot-1.8/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/include/asterisk/channel.h?view=diff&rev=384887&r1=384886&r2=384887
==============================================================================
--- team/oej/teapot-1.8/include/asterisk/channel.h (original)
+++ team/oej/teapot-1.8/include/asterisk/channel.h Mon Apr  8 09:00:26 2013
@@ -2365,6 +2365,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/teapot-1.8/include/asterisk/frame.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/include/asterisk/frame.h?view=diff&rev=384887&r1=384886&r2=384887
==============================================================================
--- team/oej/teapot-1.8/include/asterisk/frame.h (original)
+++ team/oej/teapot-1.8/include/asterisk/frame.h Mon Apr  8 09:00:26 2013
@@ -301,6 +301,8 @@
 #define AST_FORMAT_SPEEX16    (1ULL << 33)
 /*! Raw mu-law data (G.711) */
 #define AST_FORMAT_TESTLAW    (1ULL << 47)
+/*! Comfort noise. Not a frame type per se, but needs to be added as a codec */
+#define AST_FORMAT_CN    (1ULL << 48)
 /*! Reserved bit - do not use */
 #define AST_FORMAT_RESERVED   (1ULL << 63)
 
@@ -336,6 +338,7 @@
 	AST_CONTROL_END_OF_Q = 29,		/*!< Indicate that this position was the end of the channel queue for a softhangup. */
 	AST_CONTROL_INCOMPLETE = 30,	/*!< Indication that the extension dialed is incomplete */
 	AST_CONTROL_UPDATE_RTP_PEER = 31, /*!< Interrupt the bridge and have it update the peer */
+	AST_CONTROL_CNG_END = 32,	/*!< Disable CNG playout in bridge */
 };
 
 enum ast_frame_read_action {
@@ -493,6 +496,10 @@
  * Option data is an integer value of 0 or 1 */
 #define AST_OPTION_SECURE_SIGNALING        18
 #define AST_OPTION_SECURE_MEDIA            19
+
+/*! Support of CNG transmission,
+    if not enabled a noise generator will kick in  */
+#define AST_OPTION_CNG_SUPPORT            20
 
 struct oprmode {
 	struct ast_channel *peer;

Modified: team/oej/teapot-1.8/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/main/channel.c?view=diff&rev=384887&r1=384886&r2=384887
==============================================================================
--- team/oej/teapot-1.8/main/channel.c (original)
+++ team/oej/teapot-1.8/main/channel.c Mon Apr  8 09:00:26 2013
@@ -4382,6 +4382,7 @@
 	case AST_CONTROL_AOC:
 	case AST_CONTROL_END_OF_Q:
 	case AST_CONTROL_UPDATE_RTP_PEER:
+	case AST_CONTROL_CNG_END:
 		break;
 
 	case AST_CONTROL_INCOMPLETE:
@@ -4551,6 +4552,7 @@
 	case AST_CONTROL_SRCUPDATE:
 	case AST_CONTROL_SRCCHANGE:
 	case AST_CONTROL_RADIO_KEY:
+	case AST_CONTROL_CNG_END:
 	case AST_CONTROL_RADIO_UNKEY:
 	case AST_CONTROL_OPTION:
 	case AST_CONTROL_WINK:
@@ -7258,6 +7260,12 @@
 					ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
 				}
 				break;
+			case AST_CONTROL_CNG_END:
+				/* If we are playing out CNG noise on the bridged channel, stop it now. 
+				   otherwise, ignore this frame. */
+				ast_debug(1, "*** Bridge got CNG END frame \n");
+				ast_channel_stop_noise_generator(other, NULL);
+				break;
 			case AST_CONTROL_HOLD:
 			case AST_CONTROL_UNHOLD:
 			case AST_CONTROL_VIDUPDATE:
@@ -7278,6 +7286,21 @@
 			}
 			if (bridge_exit)
 				break;
+		}
+		if (f->frametype == AST_FRAME_CNG) {
+			/* We got a CNG frame 
+			  Check if the bridged channel has active CNG 
+			*/
+			int cngsupport = 0;
+			int len = sizeof(cngsupport);
+			ast_channel_queryoption(other, AST_OPTION_CNG_SUPPORT, &cngsupport, &len, 0);
+			if (cngsupport) {
+				ast_debug(1, "*** Bridge got CNG frame. Forwarding it \n");
+				ast_write(other, f);
+			} else {
+				ast_debug(1, "*** Bridge got CNG frame. Playing out noise. (CNG not supported by other channel) Level: - %d\n", f->subclass.integer );
+				ast_channel_start_noise_generator(other, (float)  -f->subclass.integer);
+			}
 		}
 		if ((f->frametype == AST_FRAME_VOICE) ||
 		    (f->frametype == AST_FRAME_DTMF_BEGIN) ||
@@ -8277,6 +8300,305 @@
 	}
 	ast_free(state);
 }
+
+
+#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,
+} ;
+
+static void *cng_channel_params_copy(void *data)
+{
+	const struct ast_noise_generator *src = data;
+	struct ast_noise_generator *dest = ast_calloc(1, sizeof(struct ast_noise_generator));
+	if (!dest) {
+		return NULL;
+	}
+	dest->level = src->level;
+	dest->old_write_format = src->old_write_format;
+	return dest;
+}
+
+static void cng_channel_params_destroy(void *data)
+{
+	struct ast_noise_generator *ng = data;
+	ast_free(ng);
+}
+
+static const struct ast_datastore_info cng_channel_datastore_info = {
+	.type = "Comfort Noise Generator",
+	.duplicate = cng_channel_params_copy,
+	.destroy = cng_channel_params_destroy,
+};
+
+static int ast_channel_cng_params_init(struct ast_channel *chan, int level, int old_write_format)
+{
+	struct ast_noise_generator *new_cng;
+	struct ast_datastore *cng_datastore;
+
+	/* If we already have a datastore, reuse it */
+	if ((cng_datastore = ast_channel_datastore_find(chan, &cng_channel_datastore_info, NULL))) {
+		new_cng = cng_datastore->data;
+	} else {
+		/* Create new datastore */
+		new_cng = ast_calloc(1, sizeof(struct ast_noise_generator));
+		if (!new_cng) {
+			return -1;
+		}
+
+		if (!(cng_datastore = ast_datastore_alloc(&cng_channel_datastore_info, NULL))) {
+			cng_channel_params_destroy(new_cng);
+			return -1;
+		}
+		cng_datastore->data = new_cng;
+		ast_channel_datastore_add(chan, cng_datastore);
+	}
+	new_cng->level = level;
+	new_cng->old_write_format = old_write_format;
+
+	return 0;
+}
+
+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;
+	}
+
+	/* Store noise generation data in a channel datastore */
+	ast_channel_cng_params_init(chan, level, chan->writeformat);
+
+	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)
+{
+	struct ast_datastore *cng_datastore;
+	struct ast_noise_generator *cngstate = state;
+
+	if (!cngstate) {
+		if (!(cng_datastore = ast_channel_datastore_find(chan, &cng_channel_datastore_info, NULL))) {
+			return;
+		}
+		cngstate = cng_datastore->data;
+	}
+
+	/* We will leave the allocated channel datastore in memory for reuse */
+	ast_deactivate_generator(chan);
+
+	ast_debug(1, "Stopped silence generator on '%s'\n", chan->name);
+
+	if (ast_set_write_format(chan, cngstate->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 */

Modified: team/oej/teapot-1.8/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/main/features.c?view=diff&rev=384887&r1=384886&r2=384887
==============================================================================
--- team/oej/teapot-1.8/main/features.c (original)
+++ team/oej/teapot-1.8/main/features.c Mon Apr  8 09:00:26 2013
@@ -4243,6 +4243,12 @@
 				}
 				ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
 				break;
+			case AST_CONTROL_CNG_END:
+				/* If we are playing out CNG noise on the bridged channel, stop it now. 
+				   otherwise, ignore this frame. */
+				ast_debug(2, "*** Bridge got CNG END frame \n");
+				ast_channel_stop_noise_generator(other, NULL);
+				break;
 			case AST_CONTROL_AOC:
 			case AST_CONTROL_HOLD:
 			case AST_CONTROL_UNHOLD:
@@ -4362,6 +4368,21 @@
 					ast_debug(1, "Set feature timer to %ld ms\n", config->feature_timer);
 				}
 			}
+		} else if (f->frametype == AST_FRAME_CNG) {
+			/* We got a CNG frame 
+			  Check if the bridged channel has active CNG 
+			*/
+			int cngsupport = 0;
+			int len = sizeof(cngsupport);
+			ast_channel_queryoption(other, AST_OPTION_CNG_SUPPORT, &cngsupport, &len, 0);
+			if (cngsupport) {
+				ast_debug(1, "*** Bridge got CNG frame. Forwarding it \n");
+				ast_write(other, f);
+			} else {
+				ast_debug(1, "*** Bridge got CNG frame. Playing out noise. (CNG not supported by other channel) \n");
+				ast_moh_start(other, NULL, NULL);
+			}
+			
 		}
 		if (f)
 			ast_frfree(f);

Modified: team/oej/teapot-1.8/main/frame.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/main/frame.c?view=diff&rev=384887&r1=384886&r2=384887
==============================================================================
--- team/oej/teapot-1.8/main/frame.c (original)
+++ team/oej/teapot-1.8/main/frame.c Mon Apr  8 09:00:26 2013
@@ -126,6 +126,7 @@
 	{ AST_FORMAT_SIREN14, "siren14", 32000, "ITU G.722.1 Annex C, (Siren14, licensed from Polycom)", 120, 20, 80, 20, 20 },	/*!< Binary commercial distribution */
 	{ AST_FORMAT_TESTLAW, "testlaw", 8000, "G.711 test-law", 80, 10, 150, 10, 20 },                        /*!< codec_ulaw.c */
 	{ AST_FORMAT_G719, "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20 },
+	{ AST_FORMAT_CN, "cn", 8000, "Comfort Noise"},
 };
 
 struct ast_frame ast_null_frame = { AST_FRAME_NULL, };

Modified: team/oej/teapot-1.8/main/rtp_engine.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/main/rtp_engine.c?view=diff&rev=384887&r1=384886&r2=384887
==============================================================================
--- team/oej/teapot-1.8/main/rtp_engine.c (original)
+++ team/oej/teapot-1.8/main/rtp_engine.c Mon Apr  8 09:00:26 2013
@@ -162,7 +162,7 @@
 	[16] = {1, AST_FORMAT_ADPCM}, /* 11.025 kHz */
 	[17] = {1, AST_FORMAT_ADPCM}, /* 22.050 kHz */
 	[18] = {1, AST_FORMAT_G729A},
-	[19] = {0, AST_RTP_CN},         /* Also used for CN */
+	[19] = {1, AST_FORMAT_CN},         /* Also used for CN */
 	[26] = {1, AST_FORMAT_JPEG},
 	[31] = {1, AST_FORMAT_H261},
 	[34] = {1, AST_FORMAT_H263},

Modified: team/oej/teapot-1.8/res/res_rtp_asterisk.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/res/res_rtp_asterisk.c?view=diff&rev=384887&r1=384886&r2=384887
==============================================================================
--- team/oej/teapot-1.8/res/res_rtp_asterisk.c (original)
+++ team/oej/teapot-1.8/res/res_rtp_asterisk.c Mon Apr  8 09:00:26 2013
@@ -113,6 +113,7 @@
 #define FLAG_NAT_INACTIVE_NOWARN        (1 << 1)
 #define FLAG_NEED_MARKER_BIT            (1 << 3)
 #define FLAG_DTMF_COMPENSATE            (1 << 4)
+#define FLAG_CN_ACTIVE			(1 << 5)
 
 /*! \brief RTP session description */
 struct ast_rtp {
@@ -1738,17 +1739,8 @@
 	/* Convert comfort noise into audio with various codecs.  Unfortunately this doesn't
 	   totally help us out becuase we don't have an engine to keep it going and we are not
 	   guaranteed to have it every 20ms or anything */
-	if (rtpdebug)
+	if (rtpdebug) {
 		ast_debug(0, "- RTP 3389 Comfort noise event: Level %" PRId64 " (len = %d)\n", rtp->lastrxformat, len);
-
-	if (ast_test_flag(rtp, FLAG_3389_WARNING)) {
-		struct ast_sockaddr remote_address = { {0,} };
-
-		ast_rtp_instance_get_remote_address(instance, &remote_address);
-
-		ast_log(LOG_NOTICE, "Comfort noise support incomplete in Asterisk (RFC 3389). Please turn off on client if possible. Client address: %s\n",
-			ast_sockaddr_stringify(&remote_address));
-		ast_set_flag(rtp, FLAG_3389_WARNING);
 	}
 
 	/* Must have at least one byte */
@@ -1765,9 +1757,21 @@
 		rtp->f.datalen = 0;
 	}
 	rtp->f.frametype = AST_FRAME_CNG;
+		/* The noise level is expressed in -dBov with values 0 to 127, representing 0 to -127 dBov
+		   It's in bits 1-7 in the payload. Bit 0 is always 0.
+		*/
 	rtp->f.subclass.integer = data[0] & 0x7f;
 	rtp->f.samples = 0;
 	rtp->f.delivery.tv_usec = rtp->f.delivery.tv_sec = 0;
+
+	if(!ast_test_flag(rtp, FLAG_CN_ACTIVE)) {
+		ast_set_flag(rtp, FLAG_CN_ACTIVE);
+		ast_debug(0, "###### ACTIVATING Comfort Noise on channel Level - %d\n", rtp->f.subclass.integer);
+		/* Start the generator on the other end. */
+	
+	} else {
+		/* Check if the level is the same. If not, reactivate. */
+	}
 
 	return &rtp->f;
 }
@@ -2345,6 +2349,15 @@
 	/* If the payload is not actually an Asterisk one but a special one pass it off to the respective handler */
 	if (!payload.asterisk_format) {
 		struct ast_frame *f = NULL;
+		if (payload.code != AST_RTP_CN && ast_test_flag(rtp, FLAG_CN_ACTIVE)) {
+			/* Insert a control frame to indicate that we need to shut down Comfort Noise generators, if active */
+			struct ast_frame cngoff = { AST_FRAME_CONTROL, { AST_CONTROL_CNG_END, } };
+			ast_debug(0, "####### DEACTIVATING Comfort Noise \n");
+			ast_clear_flag(rtp, FLAG_CN_ACTIVE);
+			f = ast_frdup(&cngoff);
+			AST_LIST_INSERT_TAIL(&frames, f, frame_list);
+			f = NULL;
+		}
 		if (payload.code == AST_RTP_DTMF) {
 			/* process_dtmf_rfc2833 may need to return multiple frames. We do this
 			 * by passing the pointer to the frame list to it so that the method
@@ -2371,6 +2384,15 @@
 			return AST_LIST_FIRST(&frames);
 		}
 		return &ast_null_frame;
+	}
+	if (ast_test_flag(rtp, FLAG_CN_ACTIVE)) {
+		struct ast_frame *f = NULL;
+		struct ast_frame cngoff = { AST_FRAME_CONTROL, { AST_CONTROL_CNG_END, } };
+		ast_debug(0, "####### DEACTIVATING Comfort Noise \n");
+		ast_clear_flag(rtp, FLAG_CN_ACTIVE);
+		f = ast_frdup(&cngoff);
+		AST_LIST_INSERT_TAIL(&frames, f, frame_list);
+		f = NULL;
 	}
 
 	rtp->lastrxformat = rtp->f.subclass.codec = payload.code;




More information about the asterisk-commits mailing list