[svn-commits] bbryant: trunk r120635 - in /trunk: channels/ funcs/ include/asterisk/ main/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Jun 5 11:24:19 CDT 2008


Author: bbryant
Date: Thu Jun  5 11:24:19 2008
New Revision: 120635

URL: http://svn.digium.com/view/asterisk?view=rev&rev=120635
Log:
This patch adds more detailed statistics for RTP channels, and provides an API call to access it, including maximums, minimums, standard deviatinos, 
and normal deviations. Currently this is implemented for chan_sip, but could be added to the func_channel_read callbacks for the CHANNEL function 
for any channel that uses RTP.

(closes issue #10590)
Reported by: gasparz
Patches:
      chan_sip_c.diff uploaded by gasparz (license 219)
      rtp_c.diff uploaded by gasparz (license 219)
      rtp_h.diff uploaded by gasparz (license 219)
      audioqos-trunk.diff uploaded by snuffy (license 35)
      rtpqos-trunk-r119891.diff uploaded by sergee (license 138)
Tested by: jsmith, gasparz, snuffy, marsosa, chappell, sergee

Modified:
    trunk/channels/chan_sip.c
    trunk/funcs/func_channel.c
    trunk/include/asterisk/rtp.h
    trunk/main/rtp.c

Modified: trunk/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_sip.c?view=diff&rev=120635&r1=120634&r2=120635
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Thu Jun  5 11:24:19 2008
@@ -5063,15 +5063,25 @@
 			}
 		} else {	/* Call is in UP state, send BYE */
 			if (!p->pendinginvite) {
+				struct ast_channel *bridge = ast_bridged_channel(oldowner);
 				char *audioqos = "";
 				char *videoqos = "";
 				char *textqos = "";
+
 				if (p->rtp)
-					audioqos = ast_rtp_get_quality(p->rtp, NULL);
+					ast_rtp_set_vars(oldowner, p->rtp);
+
+				if (bridge) {
+					struct sip_pvt *q = bridge->tech_pvt;
+
+					if (IS_SIP_TECH(bridge->tech) && q->rtp)
+						ast_rtp_set_vars(bridge, q->rtp);
+				}
+
 				if (p->vrtp)
-					videoqos = ast_rtp_get_quality(p->vrtp, NULL);
+					videoqos = ast_rtp_get_quality(p->vrtp, NULL, RTPQOS_SUMMARY);
 				if (p->trtp)
-					textqos = ast_rtp_get_quality(p->trtp, NULL);
+					textqos = ast_rtp_get_quality(p->trtp, NULL, RTPQOS_SUMMARY);
 				/* Send a hangup */
 				transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
 
@@ -18429,10 +18439,13 @@
 			ast_rtp_get_peer(p->vrtp, &sin);
 		else if (!strcasecmp(args.type, "text"))
 			ast_rtp_get_peer(p->trtp, &sin);
+		else
+			return -1;
 
 		snprintf(buf, buflen, "%s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
 	} else if (!strcasecmp(args.param, "rtpqos")) {
 		struct ast_rtp_quality qos;
+		struct ast_rtp *rtp = p->rtp;
 		
 		memset(&qos, 0, sizeof(qos));
 
@@ -18442,11 +18455,13 @@
 			args.field = "all";
 		
 		if (strcasecmp(args.type, "AUDIO") == 0) {
-			all = ast_rtp_get_quality(p->rtp, &qos);
+			all = ast_rtp_get_quality(rtp = p->rtp, &qos, RTPQOS_SUMMARY);
 		} else if (strcasecmp(args.type, "VIDEO") == 0) {
-			all = ast_rtp_get_quality(p->vrtp, &qos);
+			all = ast_rtp_get_quality(rtp = p->vrtp, &qos, RTPQOS_SUMMARY);
 		} else if (strcasecmp(args.type, "TEXT") == 0) {
-			all = ast_rtp_get_quality(p->trtp, &qos);
+			all = ast_rtp_get_quality(rtp = p->trtp, &qos, RTPQOS_SUMMARY);
+		} else {
+			return -1;
 		}
 		
 		if (strcasecmp(args.field, "local_ssrc") == 0)
@@ -18469,6 +18484,8 @@
 			snprintf(buf, buflen, "%.0f", qos.rtt * 1000.0);
 		else if (strcasecmp(args.field, "all") == 0)
 			ast_copy_string(buf, all, buflen);
+		else if (!ast_rtp_get_qos(rtp, args.field, buf, buflen))
+			 ;
 		else {
 			ast_log(LOG_WARNING, "Unrecognized argument '%s' to %s\n", preparse, funcname);
 			return -1;
@@ -18501,23 +18518,47 @@
 
 	/* Get RTCP quality before end of call */
 	if (p->do_history || p->owner) {
-		char *audioqos, *videoqos, *textqos;
-		if (p->rtp) {
-			audioqos = ast_rtp_get_quality(p->rtp, NULL);
-			if (p->do_history)
+		struct ast_channel *bridge = ast_bridged_channel(p->owner);
+		char *videoqos, *textqos;
+
+		if (p->rtp) {	
+			if (p->do_history) {
+				char *audioqos,
+				     *audioqos_jitter,
+				     *audioqos_loss,
+				     *audioqos_rtt;
+
+				audioqos        = ast_rtp_get_quality(p->rtp, NULL, RTPQOS_SUMMARY);
+				audioqos_jitter = ast_rtp_get_quality(p->rtp, NULL, RTPQOS_JITTER);
+				audioqos_loss   = ast_rtp_get_quality(p->rtp, NULL, RTPQOS_LOSS);
+				audioqos_rtt    = ast_rtp_get_quality(p->rtp, NULL, RTPQOS_RTT);
+
 				append_history(p, "RTCPaudio", "Quality:%s", audioqos);
-			if (p->owner)
-				pbx_builtin_setvar_helper(p->owner, "RTPAUDIOQOS", audioqos);
-		}
+				append_history(p, "RTCPaudioJitter", "Quality:%s", audioqos_jitter);
+				append_history(p, "RTCPaudioLoss", "Quality:%s", audioqos_loss);
+				append_history(p, "RTCPaudioRTT", "Quality:%s", audioqos_rtt);
+			}
+			
+			ast_rtp_set_vars(p->owner, p->rtp);
+		}
+
+		if (bridge) {
+			struct sip_pvt *q = bridge->tech_pvt;
+
+			if (IS_SIP_TECH(bridge->tech) && q->rtp)
+				ast_rtp_set_vars(bridge, q->rtp);
+		}
+
 		if (p->vrtp) {
-			videoqos = ast_rtp_get_quality(p->vrtp, NULL);
+			videoqos = ast_rtp_get_quality(p->vrtp, NULL, RTPQOS_SUMMARY);
 			if (p->do_history)
 				append_history(p, "RTCPvideo", "Quality:%s", videoqos);
 			if (p->owner)
 				pbx_builtin_setvar_helper(p->owner, "RTPVIDEOQOS", videoqos);
 		}
+
 		if (p->trtp) {
-			textqos = ast_rtp_get_quality(p->trtp, NULL);
+			textqos = ast_rtp_get_quality(p->trtp, NULL, RTPQOS_SUMMARY);
 			if (p->do_history)
 				append_history(p, "RTCPtext", "Quality:%s", textqos);
 			if (p->owner)

Modified: trunk/funcs/func_channel.c
URL: http://svn.digium.com/view/asterisk/trunk/funcs/func_channel.c?view=diff&rev=120635&r1=120634&r2=120635
==============================================================================
--- trunk/funcs/func_channel.c (original)
+++ trunk/funcs/func_channel.c Thu Jun  5 11:24:19 2008
@@ -200,12 +200,24 @@
 		"    local_ssrc            Local SSRC (stream ID)\n"
 		"    local_lostpackets     Local lost packets\n"
 		"    local_jitter          Local calculated jitter\n"
+		"    local_maxjitter       Local calculated jitter (maximum)\n"
+		"    local_minjitter       Local calculated jitter (minimum)\n"
+		"    local_normdevjitter   Local calculated jitter (normal deviation)\n"
+		"    local_stdevjitter     Local calculated jitter (standard deviation)\n"
 		"    local_count           Number of received packets\n"
 		"    remote_ssrc           Remote SSRC (stream ID)\n"
 		"    remote_lostpackets    Remote lost packets\n"
 		"    remote_jitter         Remote reported jitter\n"
+		"    remote_maxjitter      Remote calculated jitter (maximum)\n"
+		"    remote_minjitter      Remote calculated jitter (minimum)\n"
+		"    remote_normdevjitter  Remote calculated jitter (normal deviation)\n"
+		"    remote_stdevjitter    Remote calculated jitter (standard deviation)\n"
 		"    remote_count          Number of transmitted packets\n"
 		"    rtt                   Round trip time\n"
+		"    maxrtt                Round trip time (maximum)\n"
+		"    minrtt                Round trip time (minimum)\n"
+		"    normdevrtt            Round trip time (normal deviation)\n"
+		"    stdevrtt              Round trip time (standard deviation)\n"
 		"    all                   All statistics (in a form suited to logging, but not for parsing)\n"
 		"R/O    rtpdest            Get remote RTP destination information\n"
 		"       This option takes one additional argument:\n"

Modified: trunk/include/asterisk/rtp.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/rtp.h?view=diff&rev=120635&r1=120634&r2=120635
==============================================================================
--- trunk/include/asterisk/rtp.h (original)
+++ trunk/include/asterisk/rtp.h Thu Jun  5 11:24:19 2008
@@ -89,6 +89,13 @@
 	AST_LIST_ENTRY(ast_rtp_protocol) list;
 };
 
+enum ast_rtp_quality_type {
+	RTPQOS_SUMMARY = 0,
+	RTPQOS_JITTER,
+	RTPQOS_LOSS,
+	RTPQOS_RTT
+};
+
 /*! \brief RTCP quality report storage */
 struct ast_rtp_quality {
 	unsigned int local_ssrc;          /*!< Our SSRC */
@@ -259,9 +266,32 @@
            having to send a re-invite later */
 int ast_rtp_early_bridge(struct ast_channel *c0, struct ast_channel *c1);
 
-/*! \brief Return RTCP quality string */
-char *ast_rtp_get_quality(struct ast_rtp *rtp, struct ast_rtp_quality *qual);
-
+/*! \brief Get QOS stats on a RTP channel */
+int ast_rtp_get_qos(struct ast_rtp *rtp, const char *qos, char *buf, unsigned int buflen);
+/*! \brief Set RTPAUDIOQOS(...) variables on a channel when it is being hung up */
+void ast_rtp_set_vars(struct ast_channel *chan, struct ast_rtp *rtp);
+
+/*! \brief Return RTCP quality string 
+ *
+ *  \param rtp An rtp structure to get qos information about.
+ *
+ *  \param qual An (optional) rtp quality structure that will be 
+ *              filled with the quality information described in 
+ *              the ast_rtp_quality structure. This structure is
+ *              not dependent on any qtype, so a call for any
+ *              type of information would yield the same results
+ *              because ast_rtp_quality is not a data type 
+ *              specific to any qos type.
+ *
+ *  \param qtype The quality type you'd like, default should be
+ *               RTPQOS_SUMMARY which returns basic information
+ *               about the call. The return from RTPQOS_SUMMARY
+ *               is basically ast_rtp_quality in a string. The
+ *               other types are RTPQOS_JITTER, RTPQOS_LOSS and
+ *               RTPQOS_RTT which will return more specific 
+ *               statistics.
+ */
+char *ast_rtp_get_quality(struct ast_rtp *rtp, struct ast_rtp_quality *qual, enum ast_rtp_quality_type qtype);
 /*! \brief Send an H.261 fast update request. Some devices need this rather than the XML message  in SIP */
 int ast_rtcp_send_h261fur(void *data);
 

Modified: trunk/main/rtp.c
URL: http://svn.digium.com/view/asterisk/trunk/main/rtp.c?view=diff&rev=120635&r1=120634&r2=120635
==============================================================================
--- trunk/main/rtp.c (original)
+++ trunk/main/rtp.c Thu Jun  5 11:24:19 2008
@@ -33,8 +33,10 @@
 #include <sys/time.h>
 #include <signal.h>
 #include <fcntl.h>
+#include <math.h> 
 
 #include "asterisk/rtp.h"
+#include "asterisk/pbx.h"
 #include "asterisk/frame.h"
 #include "asterisk/channel.h"
 #include "asterisk/acl.h"
@@ -229,6 +231,7 @@
  * 
  */
 struct ast_rtcp {
+	int rtcp_info;
 	int s;				/*!< Socket */
 	struct sockaddr_in us;		/*!< Socket representation of the local endpoint. */
 	struct sockaddr_in them;	/*!< Socket representation of the remote endpoint. */
@@ -248,10 +251,38 @@
 	unsigned int reported_jitter;	/*!< The contents of their last jitter entry in the RR */
 	unsigned int reported_lost;	/*!< Reported lost packets in their RR */
 	char quality[AST_MAX_USER_FIELD];
+	char quality_jitter[AST_MAX_USER_FIELD];
+	char quality_loss[AST_MAX_USER_FIELD];
+	char quality_rtt[AST_MAX_USER_FIELD];
+
+	double reported_maxjitter;
+	double reported_minjitter;
+	double reported_normdev_jitter;
+	double reported_stdev_jitter;
+	unsigned int reported_jitter_count;
+
+	double reported_maxlost;
+	double reported_minlost;
+	double reported_normdev_lost;
+	double reported_stdev_lost;
+
+	double rxlost;
+	double maxrxlost;
+	double minrxlost;
+	double normdev_rxlost;
+	double stdev_rxlost;
+	unsigned int rxlost_count;
+
 	double maxrxjitter;
 	double minrxjitter;
+	double normdev_rxjitter;
+	double stdev_rxjitter;
+	unsigned int rxjitter_count;
 	double maxrtt;
 	double minrtt;
+	double normdevrtt;
+	double stdevrtt;
+	unsigned int rtt_count;
 	int sendfur;
 };
 
@@ -805,6 +836,35 @@
 	return;
 }
 
+/*! \brief Calculate normal deviation */
+static double normdev_compute(double normdev, double sample, unsigned int sample_count)
+{
+	normdev = normdev * sample_count + sample;
+	sample_count++;
+
+	return normdev / sample_count;
+}
+
+static double stddev_compute(double stddev, double sample, double normdev, double normdev_curent, unsigned int sample_count)
+{
+/*
+		for the formula check http://www.cs.umd.edu/~austinjp/constSD.pdf
+		return sqrt( (sample_count*pow(stddev,2) + sample_count*pow((sample-normdev)/(sample_count+1),2) + pow(sample-normdev_curent,2)) / (sample_count+1));
+		we can compute the sigma^2 and that way we would have to do the sqrt only 1 time at the end and would save another pow 2 compute
+		optimized formula
+*/
+#define SQUARE(x) ((x) * (x))
+
+	stddev = sample_count * stddev;
+	sample_count++;
+
+	return stddev + 
+	       ( sample_count * SQUARE( (sample - normdev) / sample_count ) ) + 
+	       ( SQUARE(sample - normdev_curent) / sample_count );
+
+#undef SQUARE
+}
+
 static struct ast_frame *send_dtmf(struct ast_rtp *rtp, enum ast_frame_type type)
 {
 	if (((ast_test_flag(rtp, FLAG_DTMF_COMPENSATE) && type == AST_FRAME_DTMF_END) ||
@@ -1086,6 +1146,12 @@
 	unsigned int comp;
 	struct ast_frame *f = &ast_null_frame;
 	
+	double reported_jitter;
+	double reported_normdev_jitter_current;
+	double normdevrtt_current;
+	double reported_lost;
+	double reported_normdev_lost_current;
+
 	if (!rtp || !rtp->rtcp)
 		return &ast_null_frame;
 
@@ -1179,14 +1245,27 @@
 				}
 				rtt = rtt / 1000.;
 				rttsec = rtt / 1000.;
+				rtp->rtcp->rtt = rttsec;
 
 				if (comp - dlsr >= lsr) {
 					rtp->rtcp->accumulated_transit += rttsec;
-					rtp->rtcp->rtt = rttsec;
+
+					if (rtp->rtcp->rtt_count == 0) 
+						rtp->rtcp->minrtt = rttsec;
+
 					if (rtp->rtcp->maxrtt<rttsec)
 						rtp->rtcp->maxrtt = rttsec;
+
 					if (rtp->rtcp->minrtt>rttsec)
 						rtp->rtcp->minrtt = rttsec;
+
+					normdevrtt_current = normdev_compute(rtp->rtcp->normdevrtt, rttsec, rtp->rtcp->rtt_count);
+
+					rtp->rtcp->stdevrtt = stddev_compute(rtp->rtcp->stdevrtt, rttsec, rtp->rtcp->normdevrtt, normdevrtt_current, rtp->rtcp->rtt_count);
+
+					rtp->rtcp->normdevrtt = normdevrtt_current;
+
+					rtp->rtcp->rtt_count++;
 				} else if (rtcp_debug_test_addr(&sin)) {
 					ast_verbose("Internal RTCP NTP clock skew detected: "
 							   "lsr=%u, now=%u, dlsr=%u (%d:%03dms), "
@@ -1198,7 +1277,45 @@
 			}
 
 			rtp->rtcp->reported_jitter = ntohl(rtcpheader[i + 3]);
+			reported_jitter = (double) rtp->rtcp->reported_jitter;
+
+			if (rtp->rtcp->reported_jitter_count == 0) 
+				rtp->rtcp->reported_minjitter = reported_jitter;
+
+			if (reported_jitter < rtp->rtcp->reported_minjitter) 
+				rtp->rtcp->reported_minjitter = reported_jitter;
+
+			if (reported_jitter > rtp->rtcp->reported_maxjitter) 
+				rtp->rtcp->reported_maxjitter = reported_jitter;
+
+			reported_normdev_jitter_current = normdev_compute(rtp->rtcp->reported_normdev_jitter, reported_jitter, rtp->rtcp->reported_jitter_count);
+
+			rtp->rtcp->reported_stdev_jitter = stddev_compute(rtp->rtcp->reported_stdev_jitter, reported_jitter, rtp->rtcp->reported_normdev_jitter, reported_normdev_jitter_current, rtp->rtcp->reported_jitter_count);
+
+			rtp->rtcp->reported_normdev_jitter = reported_normdev_jitter_current;
+
 			rtp->rtcp->reported_lost = ntohl(rtcpheader[i + 1]) & 0xffffff;
+
+			reported_lost = (double) rtp->rtcp->reported_lost;
+
+			/* using same counter as for jitter */
+			if (rtp->rtcp->reported_jitter_count == 0)
+				rtp->rtcp->reported_minlost = reported_lost;
+
+			if (reported_lost < rtp->rtcp->reported_minlost)
+				rtp->rtcp->reported_minlost = reported_lost;
+
+			if (reported_lost > rtp->rtcp->reported_maxlost) 
+				rtp->rtcp->reported_maxlost = reported_lost;
+
+			reported_normdev_lost_current = normdev_compute(rtp->rtcp->reported_normdev_lost, reported_lost, rtp->rtcp->reported_jitter_count);
+
+			rtp->rtcp->reported_stdev_lost = stddev_compute(rtp->rtcp->reported_stdev_lost, reported_lost, rtp->rtcp->reported_normdev_lost, reported_normdev_lost_current, rtp->rtcp->reported_jitter_count);
+
+			rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current;
+
+			rtp->rtcp->reported_jitter_count++;
+
 			if (rtcp_debug_test_addr(&sin)) {
 				ast_verbose("  Fraction lost: %ld\n", (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24));
 				ast_verbose("  Packets lost so far: %d\n", rtp->rtcp->reported_lost);
@@ -1210,6 +1327,7 @@
 				if (rtt)
 					ast_verbose("  RTT: %lu(sec)\n", (unsigned long) rtt);
 			}
+
 			if (rtt) {
 				manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From %s:%d\r\n"
 								    "PT: %d(%s)\r\n"
@@ -1286,7 +1404,7 @@
 		}
 		position += (length + 1);
 	}
-			
+	rtp->rtcp->rtcp_info = 1;	
 	return f;
 }
 
@@ -1299,6 +1417,7 @@
 	double dtv;
 	double prog;
 	
+	double normdev_rxjitter_current;
 	if ((!rtp->rxcore.tv_sec && !rtp->rxcore.tv_usec) || mark) {
 		gettimeofday(&rtp->rxcore, NULL);
 		rtp->drxcore = (double) rtp->rxcore.tv_sec + (double) rtp->rxcore.tv_usec / 1000000;
@@ -1334,8 +1453,16 @@
 	rtp->rxjitter += (1./16.) * (d - rtp->rxjitter);
 	if (rtp->rtcp && rtp->rxjitter > rtp->rtcp->maxrxjitter)
 		rtp->rtcp->maxrxjitter = rtp->rxjitter;
+	if (rtp->rtcp->rxjitter_count == 1) 
+		rtp->rtcp->minrxjitter = rtp->rxjitter;
 	if (rtp->rtcp && rtp->rxjitter < rtp->rtcp->minrxjitter)
 		rtp->rtcp->minrxjitter = rtp->rxjitter;
+		
+	normdev_rxjitter_current = normdev_compute(rtp->rtcp->normdev_rxjitter,rtp->rxjitter,rtp->rtcp->rxjitter_count);
+	rtp->rtcp->stdev_rxjitter = stddev_compute(rtp->rtcp->stdev_rxjitter,rtp->rxjitter,rtp->rtcp->normdev_rxjitter,normdev_rxjitter_current,rtp->rtcp->rxjitter_count);
+
+	rtp->rtcp->normdev_rxjitter = normdev_rxjitter_current;
+	rtp->rtcp->rxjitter_count++;
 }
 
 /*! \brief Perform a Packet2Packet RTP write */
@@ -1557,7 +1684,7 @@
 		/* Schedule transmission of Receiver Report */
 		rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, rtp);
 	}
-	if ( (int)rtp->lastrxseqno - (int)seqno  > 100) /* if so it would indicate that the sender cycled; allow for misordering */
+	if ((int)rtp->lastrxseqno - (int)seqno  > 100) /* if so it would indicate that the sender cycled; allow for misordering */
 		rtp->cycles += RTP_SEQ_MOD;
 	
 	prev_seqno = rtp->lastrxseqno;
@@ -1688,7 +1815,7 @@
 		ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);
 		rtp->f.ts = timestamp / 8;
 		rtp->f.len = rtp->f.samples / ( (ast_format_rate(rtp->f.subclass) == 16000) ? 16 : 8 );
-	} else if(rtp->f.subclass & AST_FORMAT_VIDEO_MASK) {
+	} else if (rtp->f.subclass & AST_FORMAT_VIDEO_MASK) {
 		/* Video -- samples is # of samples vs. 90000 */
 		if (!rtp->lastividtimestamp)
 			rtp->lastividtimestamp = timestamp;
@@ -2497,7 +2624,89 @@
 	rtp->rxseqno = 0;
 }
 
-char *ast_rtp_get_quality(struct ast_rtp *rtp, struct ast_rtp_quality *qual)
+static double __ast_rtp_get_qos(struct ast_rtp *rtp, const char *qos, int *found)
+{
+	*found = 1;
+
+	if (!strcasecmp(qos, "remote_maxjitter"))
+		return rtp->rtcp->reported_maxjitter * 1000.0;
+	if (!strcasecmp(qos, "remote_minjitter"))
+		return rtp->rtcp->reported_minjitter * 1000.0;
+	if (!strcasecmp(qos, "remote_normdevjitter"))
+		return rtp->rtcp->reported_normdev_jitter * 1000.0;
+	if (!strcasecmp(qos, "remote_stdevjitter"))
+		return sqrt(rtp->rtcp->reported_stdev_jitter) * 1000.0;
+
+	if (!strcasecmp(qos, "local_maxjitter"))
+		return rtp->rtcp->maxrxjitter * 1000.0;
+	if (!strcasecmp(qos, "local_minjitter"))
+		return rtp->rtcp->minrxjitter * 1000.0;
+	if (!strcasecmp(qos, "local_normdevjitter"))
+		return rtp->rtcp->normdev_rxjitter * 1000.0;
+	if (!strcasecmp(qos, "local_stdevjitter"))
+		return sqrt(rtp->rtcp->stdev_rxjitter) * 1000.0;
+
+	if (!strcasecmp(qos, "maxrtt"))
+		return rtp->rtcp->maxrtt * 1000.0;
+	if (!strcasecmp(qos, "minrtt"))
+		return rtp->rtcp->minrtt * 1000.0;
+	if (!strcasecmp(qos, "normdevrtt"))
+		return rtp->rtcp->normdevrtt * 1000.0;
+	if (!strcasecmp(qos, "stdevrtt"))
+		return sqrt(rtp->rtcp->stdevrtt) * 1000.0;
+
+	*found = 0;
+
+	return 0.0;
+}
+
+int ast_rtp_get_qos(struct ast_rtp *rtp, const char *qos, char *buf, unsigned int buflen)
+{
+	double value;
+	int found;
+
+	value = __ast_rtp_get_qos(rtp, qos, &found);
+
+	if (!found)
+		return -1;
+
+	snprintf(buf, buflen, "%.0lf", value);
+
+	return 0;
+}
+
+void ast_rtp_set_vars(struct ast_channel *chan, struct ast_rtp *rtp) {
+	char *audioqos;
+	char *audioqos_jitter;
+	char *audioqos_loss;
+	char *audioqos_rtt;
+	struct ast_channel *bridge;
+
+	if (!rtp || !chan)
+		return;
+
+	bridge = ast_bridged_channel(chan);
+
+	audioqos        = ast_rtp_get_quality(rtp, NULL, RTPQOS_SUMMARY);
+	audioqos_jitter = ast_rtp_get_quality(rtp, NULL, RTPQOS_JITTER);
+	audioqos_loss   = ast_rtp_get_quality(rtp, NULL, RTPQOS_LOSS);
+	audioqos_rtt    = ast_rtp_get_quality(rtp, NULL, RTPQOS_RTT);
+
+	pbx_builtin_setvar_helper(chan, "RTPAUDIOQOS", audioqos);
+	pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSJITTER", audioqos_jitter);
+	pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSLOSS", audioqos_loss);
+	pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSRTT", audioqos_rtt);
+
+	if (!bridge)
+		return;
+
+	pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSBRIDGED", audioqos);
+	pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSJITTERBRIDGED", audioqos_jitter);
+	pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSLOSSBRIDGED", audioqos_loss);
+	pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSRTTBRIDGED", audioqos_rtt);
+}
+
+static char *__ast_rtp_get_quality_jitter(struct ast_rtp *rtp)
 {
 	/*
 	*ssrc          our ssrc
@@ -2510,21 +2719,129 @@
 	*rlp           remote lost packets
 	*rtt           round trip time
 	*/
-
-	if (qual && rtp) {
-		qual->local_ssrc = rtp->ssrc;
-		qual->local_jitter = rtp->rxjitter;
-		qual->local_count = rtp->rxcount;
-		qual->remote_ssrc = rtp->themssrc;
-		qual->remote_count = rtp->txcount;
-		if (rtp->rtcp) {
-			qual->local_lostpackets = rtp->rtcp->expected_prior - rtp->rtcp->received_prior;
-			qual->remote_lostpackets = rtp->rtcp->reported_lost;
-			qual->remote_jitter = rtp->rtcp->reported_jitter / 65536.0;
-			qual->rtt = rtp->rtcp->rtt;
-		}
-	}
-	if (rtp->rtcp) {
+#define RTCP_JITTER_FORMAT1 \
+	"minrxjitter=%f;" \
+	"maxrxjitter=%f;" \
+	"avgrxjitter=%f;" \
+	"stdevrxjitter=%f;" \
+	"reported_minjitter=%f;" \
+	"reported_maxjitter=%f;" \
+	"reported_avgjitter=%f;" \
+	"reported_stdevjitter=%f;"
+
+#define RTCP_JITTER_FORMAT2 \
+	"rxjitter=%f;"
+
+	if (rtp->rtcp && rtp->rtcp->rtcp_info) {
+		snprintf(rtp->rtcp->quality_jitter, sizeof(rtp->rtcp->quality_jitter), RTCP_JITTER_FORMAT1,
+			rtp->rtcp->minrxjitter,
+			rtp->rtcp->maxrxjitter,
+			rtp->rtcp->normdev_rxjitter,
+			sqrt(rtp->rtcp->stdev_rxjitter),
+			rtp->rtcp->reported_minjitter,
+			rtp->rtcp->reported_maxjitter,
+			rtp->rtcp->reported_normdev_jitter,
+			sqrt(rtp->rtcp->reported_stdev_jitter)
+		);
+	} else {
+		snprintf(rtp->rtcp->quality_jitter, sizeof(rtp->rtcp->quality_jitter), RTCP_JITTER_FORMAT2,
+			rtp->rxjitter
+		);
+	}
+
+	return rtp->rtcp->quality_jitter;
+
+#undef RTCP_JITTER_FORMAT1
+#undef RTCP_JITTER_FORMAT2
+}
+
+static char *__ast_rtp_get_quality_loss(struct ast_rtp *rtp)
+{
+	unsigned int lost;
+	unsigned int extended;
+	unsigned int expected;
+	int fraction;
+
+#define RTCP_LOSS_FORMAT1 \
+	"minrxlost=%f;" \
+	"maxrxlost=%f;" \
+	"avgrxlostr=%f;" \
+	"stdevrxlost=%f;" \
+	"reported_minlost=%f;" \
+	"reported_maxlost=%f;" \
+	"reported_avglost=%f;" \
+	"reported_stdevlost=%f;"
+
+#define RTCP_LOSS_FORMAT2 \
+	"lost=%d;" \
+	"expected=%d;"
+	
+	if (rtp->rtcp && rtp->rtcp->rtcp_info && rtp->rtcp->maxrxlost > 0) {
+		snprintf(rtp->rtcp->quality_loss, sizeof(rtp->rtcp->quality_loss), RTCP_LOSS_FORMAT1,
+			rtp->rtcp->minrxlost,
+			rtp->rtcp->maxrxlost,
+			rtp->rtcp->normdev_rxlost,
+			sqrt(rtp->rtcp->stdev_rxlost),
+			rtp->rtcp->reported_minlost,
+			rtp->rtcp->reported_maxlost,
+			rtp->rtcp->reported_normdev_lost,
+			sqrt(rtp->rtcp->reported_stdev_lost)
+		);
+	} else {
+		extended = rtp->cycles + rtp->lastrxseqno;
+		expected = extended - rtp->seedrxseqno + 1;
+		if (rtp->rxcount > expected) 
+			expected += rtp->rxcount - expected;
+		lost = expected - rtp->rxcount;
+
+		if (!expected || lost <= 0)
+			fraction = 0;
+		else
+			fraction = (lost << 8) / expected;
+
+		snprintf(rtp->rtcp->quality_loss, sizeof(rtp->rtcp->quality_loss), RTCP_LOSS_FORMAT2,
+			lost,
+			expected
+		);
+	}
+
+	return rtp->rtcp->quality_loss;
+
+#undef RTCP_LOSS_FORMAT1
+#undef RTCP_LOSS_FORMAT2
+}
+
+static char *__ast_rtp_get_quality_rtt(struct ast_rtp *rtp)
+{
+	if (rtp->rtcp && rtp->rtcp->rtcp_info) {
+		snprintf(rtp->rtcp->quality_rtt, sizeof(rtp->rtcp->quality_rtt), "minrtt=%f;maxrtt=%f;avgrtt=%f;stdevrtt=%f;",
+			rtp->rtcp->minrtt,
+			rtp->rtcp->maxrtt,
+			rtp->rtcp->normdevrtt,
+			sqrt(rtp->rtcp->stdevrtt)
+		);
+	} else {
+		snprintf(rtp->rtcp->quality_rtt, sizeof(rtp->rtcp->quality_rtt), "Not available");
+	}
+
+	return rtp->rtcp->quality_rtt;
+}
+
+static char *__ast_rtp_get_quality(struct ast_rtp *rtp)
+{
+	/*
+	*ssrc          our ssrc
+	*themssrc      their ssrc
+	*lp            lost packets
+	*rxjitter      our calculated jitter(rx)
+	*rxcount       no. received packets
+	*txjitter      reported jitter of the other end
+	*txcount       transmitted packets
+	*rlp           remote lost packets
+	*rtt           round trip time
+	*/	
+
+	if (rtp->rtcp && rtp->rtcp->rtcp_info) {
 		snprintf(rtp->rtcp->quality, sizeof(rtp->rtcp->quality),
 			"ssrc=%u;themssrc=%u;lp=%u;rxjitter=%f;rxcount=%u;txjitter=%f;txcount=%u;rlp=%u;rtt=%f",
 			rtp->ssrc,
@@ -2535,10 +2852,50 @@
 			(double)rtp->rtcp->reported_jitter / 65536.0,
 			rtp->txcount,
 			rtp->rtcp->reported_lost,
-			rtp->rtcp->rtt);
-		return rtp->rtcp->quality;
-	} else
-		return "<Unknown> - RTP/RTCP has already been destroyed";
+			rtp->rtcp->rtt
+		);
+	} else {
+		snprintf(rtp->rtcp->quality, sizeof(rtp->rtcp->quality), "ssrc=%u;themssrc=%u;rxjitter=%f;rxcount=%u;txcount=%u;",
+			rtp->ssrc,
+			rtp->themssrc,
+			rtp->rxjitter,
+			rtp->rxcount,
+			rtp->txcount
+		);
+	}
+
+	return rtp->rtcp->quality;
+}
+
+char *ast_rtp_get_quality(struct ast_rtp *rtp, struct ast_rtp_quality *qual, enum ast_rtp_quality_type qtype) 
+{
+	if (qual && rtp) {
+		qual->local_ssrc   = rtp->ssrc;
+		qual->local_jitter = rtp->rxjitter;
+		qual->local_count  = rtp->rxcount;
+		qual->remote_ssrc  = rtp->themssrc;
+		qual->remote_count = rtp->txcount;
+
+		if (rtp->rtcp) {
+			qual->local_lostpackets  = rtp->rtcp->expected_prior - rtp->rtcp->received_prior;
+			qual->remote_lostpackets = rtp->rtcp->reported_lost;
+			qual->remote_jitter      = rtp->rtcp->reported_jitter / 65536.0;
+			qual->rtt                = rtp->rtcp->rtt;
+		}
+	}
+
+	switch (qtype) {
+	case RTPQOS_SUMMARY:
+		return __ast_rtp_get_quality(rtp);
+	case RTPQOS_JITTER:
+		return __ast_rtp_get_quality_jitter(rtp);
+	case RTPQOS_LOSS:
+		return __ast_rtp_get_quality_loss(rtp);
+	case RTPQOS_RTT:
+		return __ast_rtp_get_quality_rtt(rtp);
+	}
+
+	return NULL;
 }
 
 void ast_rtp_destroy(struct ast_rtp *rtp)
@@ -2944,6 +3301,8 @@
 	struct timeval dlsr;
 	int fraction;
 
+	double rxlost_current;
+	
 	if (!rtp || !rtp->rtcp || (&rtp->rtcp->them.sin_addr == 0))
 		return 0;
 	  
@@ -2961,6 +3320,22 @@
 	received_interval = rtp->rxcount - rtp->rtcp->received_prior;
 	rtp->rtcp->received_prior = rtp->rxcount;
 	lost_interval = expected_interval - received_interval;
+
+	if (lost_interval <= 0)
+		rtp->rtcp->rxlost = 0;
+	else rtp->rtcp->rxlost = rtp->rtcp->rxlost;
+	if (rtp->rtcp->rxlost_count == 0)
+		rtp->rtcp->minrxlost = rtp->rtcp->rxlost;
+	if (lost_interval < rtp->rtcp->minrxlost) 
+		rtp->rtcp->minrxlost = rtp->rtcp->rxlost;
+	if (lost_interval > rtp->rtcp->maxrxlost) 
+		rtp->rtcp->maxrxlost = rtp->rtcp->rxlost;
+
+	rxlost_current = normdev_compute(rtp->rtcp->normdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->rxlost_count);
+	rtp->rtcp->stdev_rxlost = stddev_compute(rtp->rtcp->stdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->normdev_rxlost, rxlost_current, rtp->rtcp->rxlost_count);
+	rtp->rtcp->normdev_rxlost = rxlost_current;
+	rtp->rtcp->rxlost_count++;
+
 	if (expected_interval == 0 || lost_interval <= 0)
 		fraction = 0;
 	else
@@ -3223,7 +3598,7 @@
 		return 0;
 
 	/* If there is no data length, return immediately */
-	if(!_f->datalen && !rtp->red)
+	if (!_f->datalen && !rtp->red)
 		return 0;
 	
 	/* Make sure we have enough space for RTP header */
@@ -3903,8 +4278,8 @@
 	 * we can still do packet-to-packet bridging, because passing through the 
 	 * core will handle DTMF mode translation.
 	 */
-	if ( (ast_test_flag(p0, FLAG_HAS_DTMF) != ast_test_flag(p1, FLAG_HAS_DTMF)) ||
-		 (!c0->tech->send_digit_begin != !c1->tech->send_digit_begin)) {
+	if ((ast_test_flag(p0, FLAG_HAS_DTMF) != ast_test_flag(p1, FLAG_HAS_DTMF)) ||
+		(!c0->tech->send_digit_begin != !c1->tech->send_digit_begin)) {
 		if (!ast_test_flag(p0, FLAG_P2P_NEED_DTMF) || !ast_test_flag(p1, FLAG_P2P_NEED_DTMF)) {
 			ast_channel_unlock(c0);
 			ast_channel_unlock(c1);
@@ -4456,7 +4831,7 @@
  */
 void red_buffer_t140(struct ast_rtp *rtp, struct ast_frame *f)
 {
-	if( f->datalen > -1 ) {
+	if (f->datalen > -1) {
 		struct rtp_red *red = rtp->red;
 		memcpy(&red->buf_data[red->t140.datalen], f->data.ptr, f->datalen); 
 		red->t140.datalen += f->datalen;




More information about the svn-commits mailing list