[asterisk-commits] oej: branch oej/teapot-1.8 r402886 - in /team/oej/teapot-1.8: ./ channels/sip...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Nov 19 02:33:17 CST 2013


Author: oej
Date: Tue Nov 19 02:33:14 2013
New Revision: 402886

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=402886
Log:
And some missing files... It's still morning, so just live with it.

Added:
    team/oej/teapot-1.8/README.pinefrog-rtcp   (with props)
    team/oej/teapot-1.8/channels/sip/include/rtcp.h   (with props)
    team/oej/teapot-1.8/channels/sip/rtcp.c   (with props)

Added: team/oej/teapot-1.8/README.pinefrog-rtcp
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/README.pinefrog-rtcp?view=auto&rev=402886
==============================================================================
--- team/oej/teapot-1.8/README.pinefrog-rtcp (added)
+++ team/oej/teapot-1.8/README.pinefrog-rtcp Tue Nov 19 02:33:14 2013
@@ -1,0 +1,204 @@
+Olle E. Johansson
+oej at edvina.net
+
+2013-03-05
+
+
+
+
+
+
+Pinefrog - RTCP cleanup and additions
+-------------------------------------
+
+This branch is aimed at porting the code in pinefrog-1.4, which is now a few years old,
+to Asterisk 1.8 and hopefully (with some help) to Asterisk trunk to be integrated.
+The 1.4 code has been running in production for years in universities, call centers
+and service providers.
+
+The 1.8 port of Pinefrog is supported by Nordicom, Norway (http://www.nordicom.no). 
+The 1.4 work was sponsored by several companies, including ClearIT AB, Sweden.
+
+Status of 1.8 port
+------------------
+2013-03-05	Started
+2013-03-12	Updated README to document current status
+
+Todo for 1.8
+------------
+Done. - Add support of outbound and inbound SDES. The SDES includes a stream identifier, CNAME. 
+Done. - Add support of outbound SDES end and goodbye
+Done. - Add manager events at end-of call
+Done. - Add realtime storage of RTCP reports
+Done. - Add time manager events (configured in sip.conf)
+Done. - Add more information to RTCP debug
+Done. - Add more data aggregation to ast_rtcp structure (from svn trunk really)
+- Add RTCP for p2p RTP bridges. Needs to be tested and validated.
+
+Background
+==========
+RTCP, as defined in RFC 3550, is a protocol that co-exists with RTP, the protocol used
+for realtime multimedia in VoIP. RTCP gives the endpoints a tool to exchange data about
+the media streams exchanged. As a result, both ends can get informaiton about the
+latency for data sent in both directions, packet loss and jitter for each media stream.
+
+A VoIP call is at least two media streams and they can have different properties in
+regards of quality. A router or switch in the middle could have a lot of outbound traffic,
+causing delays and possible packet loss. This might not affect inbound traffic.
+
+In Asterisk, the RTCP handler is part of the RTP module. The RTP module produces RTCP
+report that can be added to channel variables, cdr logs or sent through AMI.
+
+In 1.4, the data used is mostly based on the latest report, it's not aggregated. This
+is fixed in trunk.
+
+In both implementations (and the 1.6 releases in between) the RTCP support is not
+very complete.
+
+- It doesn't handle RTCP SDES packets
+- It doesn't send RTCP END packets at end of session
+- It doesn't handle receiving END packets
+- It doesn't handle re-invites in a good way.
+- It seems to mix sender and receiver reports, thus mixing data from two streams 
+    - when does this happen, if at all?
+
+NOTES
+-----
+RTCP is a mutual protocol. Asterisk sends data to a phone and tells the phone in a
+"Sender report" how much we've sent. The phone responds with a "Receiver report"
+to give data about packets lost between the sender and receiver, variations in
+time (jitter) and timestamps to calculate latency. The phone does the same
+with the RTP stream towards Asterisk - sends a "Sender Report" and receives
+a "Receiver report". 
+
+This means that in order to get relevant data, it's a tango for two. The phone
+needs to have a working RTCP implementation. This is sadly not the case for 
+all SIP phones. Some phones have timers, so for short calls you will not get
+any reports, because it's set to send RTCP after five minutes or something
+longer than your phone call. 
+
+The conclusion is that the CQRs doesn't work for all phones. You will always
+get data from Asterisk's point of view, but you may not get data from the other
+end. Put pressure on your vendors to participate in the RTCP interaction
+so you can get control of your calls.
+
+RTCP and NAT
+------------
+I suspect that RTCP doesn't traverse NAT very well in our implementation. For RTP,
+we start with sending media to probe NAT. I've added emtpy RTCP RR+SDES CNAME packets
+to start probing a NAT (if Asterisk is behind a NAT). I am afraid that very few devices
+do that early on.
+The idea is (like RTP)
+ - Send a few RTCP packets in the start of the session.
+ - The receiver can then apply symmetric RTCP and start sending to the NAT outside port
+   that we're sending from and we'll get their packets.
+
+Logging
+-------
+This module logs Call Quality Records either to Realtime databases (see structure
+below) or to a new log channel named CQR. Here's an example log entry, broken
+to multiple lines for clarity:
+
+[Mar 12 14:10:13] CQR[27938] sip/rtcp.c: CQR Channel: SIP/demo2-0000000b Uid example.com-1363086575.11
+     Bch SIP/demo3-0000000a Buid example.com-1363086575.10 Pvt 12474f1963f3312d0cfc930472a164d7 at 62.80.214.22:5060 
+     Media audio Lssrc 653259305 Rssrc 1997455415 Rip 87.96.134.129 Rtt 0:0:0 Ljitter 0.000000 Rjitter 0.026454 
+     Rtcpstatus Active Dur 6 Pout 169 Plossout 0 Pin 157 Plossin 0
+
+Todo
+----
+- When CNAME changes, we have a different stream and need to restart the stats.
+  Should we add ability to produce multiple RTCP reports for one "call" and aggregate them?
+  The different parts might have different properties.
+
+Done in 1.4
+-----------
+- Added support of outbound and inbound SDES. The SDES includes a stream identifier, CNAME. 
+- Added support of outbound SDES end and goodbye
+- Added manager events at end-of call
+- Added realtime storage of RTCP reports
+- Added time manager events (configured in sip.conf)
+- Added more information to RTCP debug
+- Added more data aggregation to ast_rtcp structure (from svn trunk really)
+- Added RTCP for p2p RTP bridges. Needs to be tested and validated.
+
+Open Issues
+-----------
+The final manager report lacks (in the case of the second channel) the bridged channel. 
+We could save that data.  This will affect realtime as well, so we need to copy the 
+channel name to a stored variable while it exists.
+
+Do we have a counter of consecutive lost packets? How do we measure lost packets on inbound
+stream? Gaps in seq numbers or just the sender reports from the other end compared with received 
+no of packets?
+
+
+Ideas and thoughts for the future
+---------------------------------
+- Asterisk propagates jitter and packet loss over a bridge (especially the p2p RTP bridge).
+  If the call is transfered on the OTHER side of the bridge, we have a new call with new
+  properties. Maybe events like this should generate a new SDES and reset RTCP?
+  Part A of the call can have very different properties than part B. If I have a call with
+  someone internally, that then transfers me to a call with someone on the Internet, the
+  call quality (jitter etc) will change dramatically. This will require some sort of CONTROL
+  packet over the bridge, informing about changes on the other side of the bridge (masq).
+- Can we have some sort of ring buffer for the latest RTCP reports for a device (peer) 
+  and use that to determine the status of the connection to the peer?
+- Can we use the RTCP APP packet for relaying events in joined bridges, like meetme?
+- What should we use as CNAME? Currently SIP call ID.
+- Separate on the IPs of different media servers. IE we can have one SIP peer with
+  multiple media IPs with different properties
+
+Scenarios to test
+------------------
+- normal bridged call
+- RTP p2p bridged call
+- Nat traversal - Asterisk outside of NAT and inside (as client to external service)
+- Call hold
+- Call with music-on-hold
+- Call transfer
+
+Send feedback from your reports to oej at edvina.net
+
+Database structure
+-------------------
+Example database schema for MySQL:
+
+CREATE TABLE `astcqr` (
+  `channel` varchar(50) NOT NULL,
+  `uniqueid` varchar(35) NOT NULL,
+  `bridgedchannel` varchar(50) NOT NULL,
+  `bridgeduniqueid` varchar(35) NOT NULL,
+  `pvtcallid` varchar(80) NOT NULL,
+  `rtpmedia` varchar(50) NOT NULL,
+  `localssrc` varchar(50) NOT NULL,
+  `remotessrc` varchar(50) NOT NULL,
+  `rtt` varchar(10) NOT NULL,
+  `localjitter` varchar(10) NOT NULL,
+  `remotejitter` varchar(10) NOT NULL,
+  `sendformat` varchar(10) NOT NULL,
+  `receiveformat` varchar(10) NOT NULL,
+  `rtcpstatus` varchar(10) NOT NULL,
+  `duration` varchar(10) NOT NULL,
+  `packetsent` varchar(30) NOT NULL,
+  `packetreceived` varchar(30) NOT NULL,
+  `packetlossin` varchar(30) NOT NULL,
+  `packetlossout` varchar(30) NOT NULL,
+  `rttmax` varchar(12) NOT NULL,
+  `rttmin` varchar(12) NOT NULL,
+  `writetranslator` varchar(15) NOT NULL,
+  `readtranslator` varchar(15) NOT NULL,
+  `writecost` varchar(10) NOT NULL,
+  `readcost` varchar(10) NOT NULL,
+  `remoteip` varchar(25) NOT NULL,
+  KEY `ChannelUnique` (`channel`,`uniqueid`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='FOr pinefrog stats'
+
+Realtime configuration
+========================
+In extconfig.conf add
+
+rtpcqr => mysql,asterisk,astqos
+
+When you run "sip show settings" you should see this:
+
+  QoS realtime reports:   Enabled

Propchange: team/oej/teapot-1.8/README.pinefrog-rtcp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/oej/teapot-1.8/README.pinefrog-rtcp
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/oej/teapot-1.8/README.pinefrog-rtcp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/oej/teapot-1.8/channels/sip/include/rtcp.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/channels/sip/include/rtcp.h?view=auto&rev=402886
==============================================================================
--- team/oej/teapot-1.8/channels/sip/include/rtcp.h (added)
+++ team/oej/teapot-1.8/channels/sip/include/rtcp.h Tue Nov 19 02:33:14 2013
@@ -1,0 +1,50 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013 Olle E. Johansson, Edvina AB
+ *
+ * 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 rtcp.h
+ *
+ * \brief RTCP additional functions
+ *
+ * \author Olle E. Johansson <oej at edvina.net>
+ */
+
+#include "asterisk.h"
+
+#include "asterisk/utils.h"
+#include "asterisk/rtp_engine.h"
+#include "sip.h"
+
+#ifndef _SIP_RTCP_H
+#define _SIP_RTCP_H
+
+/*! \brief Set various data items in the RTP structure, like channel identifier.
+ */
+void sip_rtcp_set_data(struct sip_pvt *dialog, struct ast_rtp_instance *instance, enum media_type type);
+
+int send_rtcp_events(const void *data);
+void start_rtcp_events(struct sip_pvt *dialog, struct sched_context *sched);
+/*
+# For 1.4:
+# static void sip_rtcp_report(struct sip_pvt *p, struct ast_rtp *rtp, enum media_type type, int reporttype);
+*/
+
+void sip_rtcp_report(struct sip_pvt *dialog, struct ast_rtp_instance *instance, enum media_type type, int reporttype);
+//void qos_write_realtime(struct sip_pvt *dialog, struct ast_rtp_quality *qual);
+void qos_write_realtime(struct sip_pvt *dialog, struct ast_rtp_instance_stats *qual);
+
+
+
+#endif /* _SIP_RTCP_H */

Propchange: team/oej/teapot-1.8/channels/sip/include/rtcp.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/oej/teapot-1.8/channels/sip/include/rtcp.h
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/oej/teapot-1.8/channels/sip/include/rtcp.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/oej/teapot-1.8/channels/sip/rtcp.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/teapot-1.8/channels/sip/rtcp.c?view=auto&rev=402886
==============================================================================
--- team/oej/teapot-1.8/channels/sip/rtcp.c (added)
+++ team/oej/teapot-1.8/channels/sip/rtcp.c Tue Nov 19 02:33:14 2013
@@ -1,0 +1,384 @@
+/*
+* Asterisk -- An open source telephony toolkit.
+*
+* Copyright (C) 2013 Olle E. Johansson, Edvina AB
+*
+* 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 rtcp.c
+*
+* \brief RTCP additional functions
+*
+* \author Olle E. Johansson <oej at edvina.net>
+*/
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/utils.h"
+#include "asterisk/manager.h"
+#include "asterisk/logger.h"
+#include "asterisk/translate.h"
+#include "asterisk/rtp_engine.h"
+#include "include/sip.h"
+#include "include/rtcp.h"
+
+/*! \brief Set various data items in the RTP structure, like channel identifier.
+ */
+void sip_rtcp_set_data(struct sip_pvt *dialog, struct ast_rtp_instance *instance, enum media_type type)
+{
+
+	if (dialog && dialog->owner) {
+ 		int readtrans = FALSE, writetrans = FALSE;
+		struct ast_channel *bridgepeer = ast_bridged_channel(dialog->owner);
+
+		if (bridgepeer) {
+			/* Store the bridged peer data while we have it */
+			ast_rtp_instance_set_bridged_chan(instance, dialog->owner->name, dialog->owner->uniqueid, S_OR(bridgepeer->name,""), S_OR(bridgepeer->uniqueid,""));
+			ast_debug(1, "---- Setting bridged peer name to %s\n", bridgepeer->name);
+		} else {
+			ast_rtp_instance_set_bridged_chan(instance, dialog->owner->name, dialog->owner->uniqueid, NULL, NULL);
+		}
+		ast_debug(1, "---- Setting channel name to %s\n", dialog->owner->name);
+
+ 		/* Try to find out if there's active transcoding */
+		/* Currently, the only media stream that has translation is the audio stream. At some point
+		   we might have transcoding for other types of media. */
+		if (type == SDP_AUDIO) {
+			struct ast_channel *chan = dialog->owner;
+			const char *rtname = NULL, *wtname = NULL;
+			/* if we have a translator, the bridge delay is increased, which affects the QoS of the call.  */
+ 			readtrans = (chan->readtrans != NULL);
+ 			writetrans = (chan->writetrans != NULL);
+			if (readtrans) {
+				rtname = chan->readtrans->t->name;
+			}
+			if (writetrans) {
+				wtname = chan->writetrans->t->name;
+			}
+			if (readtrans || writetrans) {
+				ast_rtp_instance_set_translator(instance, rtname, readtrans ? chan->readtrans->t->cost : (const int) 0,
+					wtname, writetrans ? chan->writetrans->t->cost : (const int) 0);
+			}
+		
+			if (option_debug > 1) {
+ 				if (readtrans && dialog->owner->readtrans->t) {
+ 					ast_debug(1, "--- Audio Read translator: %s Cost %d\n", dialog->owner->readtrans->t->name, dialog->owner->readtrans->t->cost);
+ 				}
+ 				if (writetrans && dialog->owner->writetrans->t) {
+ 					ast_debug(1, "--- Audio Write translator: %s Cost %d\n", dialog->owner->writetrans->t->name, dialog->owner->writetrans->t->cost);
+ 				}
+			}
+		}
+
+	} else {
+ 		ast_debug(1, "######## Not setting rtcp media data. Dialog %s Dialog owner %s \n", dialog ? "set" : "unset",  dialog->owner ? "set" : "unset");
+	}
+}
+
+/*! \brief send manager report of RTCP 
+	reporttype = 0  means report during call (if configured)
+	reporttype = 1  means endof-call (hangup) report
+	reporttype = 10  means report at end of call leg (like transfer)
+*/
+void sip_rtcp_report(struct sip_pvt *dialog, struct ast_rtp_instance *instance, enum media_type media, int reporttype)
+{
+	struct ast_rtp_instance_stats qual;
+	//char *rtpqstring = NULL;
+	//int qosrealtime = ast_check_realtime("rtpcqr");
+	unsigned int duration;	/* Duration in secs */
+	memset(&qual, 0, sizeof(qual));
+	
+	sip_rtcp_set_data(dialog, instance, media);
+
+	if (ast_rtp_instance_get_stats(instance, &qual, AST_RTP_INSTANCE_STAT_ALL)) {
+ 		ast_debug(1, "######## Did not get any statistics... bad, bad, RTP instance\n");
+		/* Houston, we got a problem */
+		return;
+	}
+	
+	if (dialog->sip_cfg->rtcpevents) {
+		/* 
+		   If numberofreports == 0 we have no incoming RTCP active, thus we can't
+		   get any reliable data to handle packet loss or any RTT timing.
+		*/
+
+		duration = (unsigned int)(ast_tvdiff_ms(ast_tvnow(), qual.start) / 1000);
+		manager_event(EVENT_FLAG_CALL, "RTPQuality", 
+			"Channel: %s\r\n"			/* AST_CHANNEL for this call */
+			"Uniqueid: %s\r\n"			/* AST_CHANNEL for this call */
+			"BridgedChannel: %s\r\n"
+			"BridgedUniqueid: %s\r\n"
+			"RTPreporttype: %s\r\n"
+			"RTPrtcpstatus: %s\r\n"
+			"Duration: %u\r\n"		/* used in cdr_manager */
+			"PvtCallid: %s\r\n"		/* ??? Generic PVT identifier */
+			"RTPipaddress: %s\r\n"
+			"RTPmedia: %s\r\n"		/* Audio, video, text */
+			"RTPsendformat: %s\r\n"
+			"RTPrecvformat: %s\r\n"
+			"RTPlocalssrc: %u\r\n"
+			"RTPremotessrc: %u\r\n"
+			"RTPrtt: %f\r\n"
+			"RTPrttMax: %f\r\n"
+			"RTPrttMin: %f\r\n"
+			"RTPLocalJitter: %f\r\n"
+			"RTPRemoteJitter: %f\r\n" 
+			"RTPInPacketLoss: %d\r\n" 
+			"RTPInLocalPlPercent: %5.2f\r\n"
+			"RTPOutPacketLoss: %d\r\n"
+			"RTPOutPlPercent: %5.2f\r\n"
+			"TranslateRead: %s\r\n"
+			"TranslateReadCost: %d\r\n"
+			"TranslateWrite: %s\r\n"
+			"TranslateWriteCost: %d\r\n"
+			"\r\n", 
+			dialog->owner ? dialog->owner->name : "",
+			dialog->owner ? dialog->owner->uniqueid : "",
+			qual.bridgedchannel[0] ? qual.bridgedchannel : "" ,
+			qual.bridgeduniqueid[0] ? qual.bridgeduniqueid : "",
+			reporttype == 1 ? "Final" : "Update",
+			qual.numberofreports == 0 ? "Inactive" : "Active",
+			duration,
+			dialog->callid, 
+			ast_inet_ntoa(qual.them.sin_addr), 	
+			media == SDP_AUDIO ? "audio" : (media == SDP_VIDEO ? "video" : "fax") ,
+			ast_getformatname(qual.lasttxformat),
+			ast_getformatname(qual.lastrxformat),
+			qual.local_ssrc, 
+			qual.remote_ssrc,
+			qual.rtt,
+			qual.maxrtt,
+			qual.minrtt,
+			qual.rxjitter,
+			qual.txjitter,
+			qual.rxploss,
+			/* The local counter of lost packets in inbound stream divided with received packets plus lost packets */
+			(qual.remote_txcount + qual.rxploss) > 0 ? (double) qual.rxploss / (qual.remote_txcount + qual.rxploss) * 100 : 0,
+			qual.txploss,
+			/* The remote counter of lost packets (if we got the reports)
+			   divided with our counter of sent packets
+			 */
+			(qual.rxcount + qual.txploss) > 0 ? (double) qual.txploss / qual.rxcount  * 100 : 0,
+			qual.readtranslator, qual.readcost,
+			qual.writetranslator, qual.writecost
+		);
+	}
+
+	/* CDR records are not reliable when it comes to near-death-of-channel events, so we need to store the RTCP
+	   report in realtime when we have it.
+	   Tests have proven that storing to realtime from the call thread is NOT a good thing. Therefore, we just save
+	   the quality report structure in the PVT and let the function that kills the pvt store the stuff in the
+	   monitor thread instead.
+	 */
+	if (reporttype == 1) {
+		ast_log(LOG_DEBUG, "---- Activation qual structure in dialog \n");
+		qual.end = ast_tvnow();
+ 		qual.mediatype = media;
+		if (media == SDP_AUDIO) {  /* Audio */
+			dialog->audioqual = ast_calloc(1, sizeof(struct ast_rtp_instance_stats));
+			(* dialog->audioqual) = qual;
+		} else if (media == SDP_VIDEO) {  /* Video */
+			dialog->videoqual = ast_calloc(1,sizeof(struct ast_rtp_instance_stats));
+			(* dialog->videoqual) = qual;
+		}
+	}
+}
+
+/*! \brief Write quality report to realtime storage */
+void qos_write_realtime(struct sip_pvt *dialog, struct ast_rtp_instance_stats *qual)
+{
+	unsigned int duration;	/* Duration in secs */
+	char buf_duration[10], buf_lssrc[30], buf_rssrc[30];
+	char buf_rtt[10], buf_rttmin[10], buf_rttmax[10];
+	char localjitter[10], remotejitter[10];
+	char buf_readcost[5], buf_writecost[5];
+	char buf_mediatype[10];
+	char buf_remoteip[25];
+	char buf_inpacketloss[25], buf_outpacketloss[25];
+	char buf_outpackets[25], buf_inpackets[25];
+	int qosrealtime = ast_check_realtime("rtpcqr");
+
+	ast_log(LOG_DEBUG, "************* QOS END REPORTS: The final countdown!!!!! Yeah. \n");
+
+	if (!qual) {
+		ast_log(LOG_ERROR, "No CQR data provided \n");
+		return;
+	}
+
+	/* Since the CDR is already gone, we need to calculate our own duration.
+	   The CDR duration is the definitive resource for billing, this is
+	   the RTP stream duration which may include early media (ringing and
+	   provider messages). Only useful for measurements.
+	 */
+	if (!ast_tvzero(qual->end) && !ast_tvzero(qual->start)) {
+		duration = (unsigned int)(ast_tvdiff_ms(qual->end, qual->start) / 1000);
+	} else {
+		ast_log(LOG_DEBUG, "**** WTF? No duration? What type of call is THAT? \n");
+		duration = 0;
+	}
+
+	/* Realtime is based on strings, so let's make strings */
+	sprintf(localjitter, "%f", qual->rxjitter);
+	sprintf(remotejitter, "%f", qual->txjitter);
+	sprintf(buf_lssrc, "%u", qual->local_ssrc);
+	sprintf(buf_rssrc, "%u", qual->remote_ssrc);
+	sprintf(buf_rtt, "%.0f", qual->rtt);
+	sprintf(buf_rttmax, "%.0f", qual->maxrtt);
+	sprintf(buf_rttmin, "%.0f", qual->minrtt);
+	sprintf(buf_duration, "%u", duration);
+	sprintf(buf_readcost, "%d", qual->readcost);
+	sprintf(buf_writecost, "%d", qual->writecost);
+	sprintf(buf_mediatype,"%s", qual->mediatype == SDP_AUDIO ? "audio" : (qual->mediatype == SDP_VIDEO ? "video" : "fax") );
+	sprintf(buf_remoteip,"%s", ast_inet_ntoa(qual->them.sin_addr));
+	sprintf(buf_inpacketloss, "%d", qual->rxploss);
+	sprintf(buf_outpacketloss, "%d", qual->txploss);
+	sprintf(buf_inpackets, "%d", qual->rxcount);		/* Silly value. Need to check this */
+	sprintf(buf_outpackets, "%d", qual->txcount);
+	//sprintf(buf_inpackets, "%d", qual->remote_count);	/* Do check again */
+	//sprintf(buf_outpackets, "%d", qual->local_count);
+
+	ast_log(LOG_DEBUG, "************* QOS END REPORTS: Probing new logging channel LOG_CQR!!!!! Yeah. \n");
+	ast_log(LOG_CQR, "CQR Channel: %s Uid %s Bch %s Buid %s Pvt %s Media %s Lssrc %s Rssrc %s Rip %s Rtt %s:%s:%s Ljitter %s Rjitter %s Rtcpstatus %s Dur %s Pout %s Plossout %s Pin %s Plossin %s\n",
+		qual->channel[0] ? qual->channel : "",
+		qual->uniqueid[0] ? qual->uniqueid : "",
+		qual->bridgedchannel[0] ? qual->bridgedchannel : "" ,
+		qual->bridgeduniqueid[0] ? qual->bridgeduniqueid : "",
+		dialog->callid,
+		buf_mediatype,
+		buf_lssrc,
+		buf_rssrc,
+		buf_remoteip,
+		buf_rtt, buf_rttmax, buf_rttmin,
+		localjitter,
+		remotejitter,
+		qual->numberofreports == 0 ? "Inactive" : "Active",
+		buf_duration,
+		buf_outpackets,
+		buf_outpacketloss,
+		buf_inpackets,
+		buf_inpacketloss);
+
+	if (!qosrealtime) {
+		return;
+	}
+/* Example database schema for MySQL:
+CREATE TABLE `astcqr` (
+  `channel` varchar(50) NOT NULL,
+  `uniqueid` varchar(35) NOT NULL,
+  `bridgedchannel` varchar(50) NOT NULL,
+  `bridgeduniqueid` varchar(35) NOT NULL,
+  `pvtcallid` varchar(80) NOT NULL,
+  `rtpmedia` varchar(50) NOT NULL,
+  `localssrc` varchar(50) NOT NULL,
+  `remotessrc` varchar(50) NOT NULL,
+  `rtt` varchar(10) NOT NULL,
+  `localjitter` varchar(10) NOT NULL,
+  `remotejitter` varchar(10) NOT NULL,
+  `sendformat` varchar(10) NOT NULL,
+  `receiveformat` varchar(10) NOT NULL,
+  `rtcpstatus` varchar(10) NOT NULL,
+  `duration` varchar(10) NOT NULL,
+  `packetsent` varchar(30) NOT NULL,
+  `packetreceived` varchar(30) NOT NULL,
+  `packetlossin` varchar(30) NOT NULL,
+  `packetlossout` varchar(30) NOT NULL,
+  `rttmax` varchar(12) NOT NULL,
+  `rttmin` varchar(12) NOT NULL,
+  `writetranslator` varchar(15) NOT NULL,
+  `readtranslator` varchar(15) NOT NULL,
+  `writecost` varchar(10) NOT NULL,
+  `readcost` varchar(10) NOT NULL,
+  `remoteip` varchar(25) NOT NULL,
+  KEY `ChannelUnique` (`channel`,`uniqueid`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='FOr pinefrog stats'
+*/
+
+	ast_store_realtime("rtpcqr", 
+		"channel", qual->channel[0] ? qual->channel : "--no channel--",
+		"uniqueid", qual->uniqueid[0] ? qual->uniqueid : "--no uniqueid --",
+		"bridgedchannel", qual->bridgedchannel[0] ? qual->bridgedchannel : "" ,
+		"bridgeduniqueid", qual->bridgeduniqueid[0] ? qual->bridgeduniqueid : "",
+		"pvtcallid", dialog->callid, 
+		"rtpmedia", buf_mediatype, 
+		"localssrc", buf_lssrc, 
+		"remotessrc", buf_rssrc,
+		"remoteip", buf_remoteip,
+		"rtt", buf_rtt, 
+		"rttmax", buf_rttmax, 
+		"rttmin", buf_rttmin, 
+		"localjitter", localjitter, 
+		"remotejitter", remotejitter, 
+		"sendformat", ast_getformatname(qual->lasttxformat),
+		"receiveformat", ast_getformatname(qual->lastrxformat),
+		"rtcpstatus", qual->numberofreports == 0 ? "Inactive" : "Active",
+		"duration", buf_duration,
+		"writetranslator", qual->writetranslator[0] ? qual->writetranslator : "",
+		"writecost", buf_writecost,
+		"readtranslator", qual->readtranslator[0] ? qual->readtranslator : "",
+		"readcost", buf_readcost,
+		"packetlossin", buf_inpacketloss,
+		"packetlossout", buf_outpacketloss,
+		"packetsent", buf_outpackets,
+		"packetreceived", buf_inpackets,
+		NULL);
+}
+
+/*! \brief Send RTCP manager events */
+int send_rtcp_events(const void *data)
+{
+	struct sip_pvt *dialog = (struct sip_pvt *) data;
+	ast_log(LOG_DEBUG, "***** SENDING RTCP EVENT \n");
+
+	if (dialog->rtp && !ast_rtp_instance_isactive(dialog->rtp)) {
+		ast_debug(1, "          ***** Activating RTCP report \n");
+		sip_rtcp_report(dialog, dialog->rtp, SDP_AUDIO, FALSE);
+	} else {
+		ast_debug(1, "          ***** NOT Activating RTCP report \n");
+	}
+	if (dialog->vrtp && !ast_rtp_instance_isactive(dialog->vrtp)) {
+		sip_rtcp_report(dialog, dialog->vrtp, SDP_VIDEO, FALSE);
+	}
+	return (dialog->sip_cfg ? dialog->sip_cfg->rtcptimer : 0);
+}
+
+/*! \brief Activate RTCP events at start of call */
+void start_rtcp_events(struct sip_pvt *dialog, struct sched_context *sched)
+{
+	ast_debug(2, "***** STARTING SENDING RTCP EVENT \n");
+	/* Check if it's already active */
+
+	if (dialog->rtp && !ast_rtp_instance_isactive(dialog->rtp)) {
+		sip_rtcp_set_data(dialog, dialog->rtp, SDP_AUDIO);
+	}
+	if (dialog->vrtp && !ast_rtp_instance_isactive(dialog->vrtp)) {
+		sip_rtcp_set_data(dialog, dialog->vrtp, SDP_VIDEO);
+	}
+
+	if (!dialog->sip_cfg->rtcpevents || !dialog->sip_cfg->rtcptimer) {
+		ast_debug(2, "***** NOT SENDING RTCP EVENTS \n");
+		return;
+	}
+
+	if (dialog->rtcpeventid != -1) {
+		return;
+	}
+
+
+	/*! \brief Schedule events */
+	dialog->rtcpeventid = ast_sched_add(sched, dialog->sip_cfg->rtcptimer * 1000, send_rtcp_events, dialog);
+}

Propchange: team/oej/teapot-1.8/channels/sip/rtcp.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/oej/teapot-1.8/channels/sip/rtcp.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/oej/teapot-1.8/channels/sip/rtcp.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the asterisk-commits mailing list