rtp/rtpstack/src/rtptranstream.cpp
changeset 0 307788aac0a8
child 29 5f12516512fa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rtp/rtpstack/src/rtptranstream.cpp	Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,693 @@
+/*
+* Copyright (c) 2002-2003 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:    
+*
+*/
+
+
+
+
+#include "rtptranstream.h"
+
+// ---------------------------------------------------------------------------
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// ---------------------------------------------------------------------------
+//
+CRtpTranStream::CRtpTranStream( const TRtpPayloadType aPayloadType,
+                                const TRtpId aSessionId,
+                                const TRtpId aStreamId,
+                                const TRtpSSRC aSSRC,
+                                MRtcpObserver* aRtcpObserver,
+                                const TUint32* aProfileRTPTimeRates )
+    :
+    CRtpStream( aStreamId,
+                aSessionId,
+                aProfileRTPTimeRates,
+                aRtcpObserver,
+                aPayloadType ),
+    iFlagSentRTPPackets( EFalse ),
+    iPreviousTime( 0 ),
+    iPreviousRemoteSN( 0 ),
+    iPrevRemoteTime( 0 ),
+    iCumNumOctetsSent( 0 ),
+    iCumNumOctetsReceived( 0 ),
+    iCumNumOctetsSent_last( 0 ),
+    iFSentRtcpReport( EFalse )
+    {
+    iLocalSSRC = aSSRC;
+    iTimeStamp = 0;
+    iSeqNumCycles = 0;
+
+    for ( TUint i = 0; i < KSNMaxArray; i++ )
+        {
+        iSN_size[i] = 0;
+        }
+    // If the client application does not specify sequence numbers, we
+    // randomize the first one.
+    TTime tmp_time;
+    tmp_time.HomeTime();
+    TInt64 seed = tmp_time.Int64();
+    iBaseSeqNum = static_cast<TRtpSequence>( TRtpUtil::Random( seed )
+                                             & 0xFFFF ); // Use 16-LSB only
+    iSeqNum = iBaseSeqNum;
+    }
+
+// ---------------------------------------------------------------------------
+// Symbian 2nd phase constructor can leave.
+// ---------------------------------------------------------------------------
+//
+void CRtpTranStream::ConstructL()
+    {
+    }
+
+
+// ---------------------------------------------------------------------------
+// Two-phased constructor.
+// ---------------------------------------------------------------------------
+//
+CRtpTranStream* CRtpTranStream::NewL( const TRtpPayloadType aPayloadType,
+                                      const TRtpId aSessionId,
+                                      const TRtpId aTranStreamId,
+                                      const TRtpSSRC aSSRC,
+                                      MRtcpObserver* aRtcpObserver,
+                                      const TUint32* aProfileRTPTimeRates )
+    {
+    CRtpTranStream* self =
+        new ( ELeave ) CRtpTranStream( aPayloadType,
+                                       aSessionId,
+                                       aTranStreamId,
+                                       aSSRC,
+                                       aRtcpObserver,
+                                       aProfileRTPTimeRates );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop(); // self 
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CRtpTranStream::~CRtpTranStream()
+    {
+    }
+
+
+// ---------------------------------------------------------------------------
+// TInt CRtpTranStream::ResetStreamStat()
+// 
+// ---------------------------------------------------------------------------
+//
+TInt CRtpTranStream::ResetStreamStat()
+    {
+    TRtcpStats rtcpStat;
+
+    RtcpStats( rtcpStat );
+    
+    rtcpStat.iRtcpSenderStats.iNumPacketsSent = 0;
+    rtcpStat.iRtcpSenderStats.iCumNumOctetsSent = 0;
+    rtcpStat.iRtcpSenderStats.iNTPTimeStampSec = 0;    // NTP seconds
+    rtcpStat.iRtcpSenderStats.iNTPTimeStampFrac = 0;   // NTPfraction
+    rtcpStat.iRtcpSenderStats.iTimeStamp = 0; 
+
+    // The receiver stats are updated when receiving RR packets, so reset
+    rtcpStat.iRtcpReceiverStats.iChannelBufferSize = 0;
+    rtcpStat.iRtcpReceiverStats.iRoundTripDelay = 0;
+    rtcpStat.iRtcpReceiverStats.iFractionLost = 0; 
+    rtcpStat.iRtcpReceiverStats.iCumNumPacketsLost = 0;
+    rtcpStat.iRtcpReceiverStats.iSeqNumReceived = 0;
+    rtcpStat.iRtcpReceiverStats.iSSRC = 0;
+
+    iRtcpStats = rtcpStat;
+    
+    iFlagSentRTPPackets = EFalse;
+    iFSentRtcpReport = EFalse;
+
+    iCumNumOctetsSent = 0;
+    iCumNumOctetsSent_last = 0;
+    iPreviousTime = 0;
+    iPreviousRemoteSN = 0;
+    iSeqNumCycles = 0;
+
+    for ( TUint i = 0; i < KSNMaxArray; i++ )
+        {
+        iSN_size[i] = 0;
+        }
+        
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// TInt CRtpTranStream::GetStreamStat()
+// 
+// ---------------------------------------------------------------------------
+//
+TInt CRtpTranStream::GetStreamStat( TRtpPeerStat& aStat )
+    {
+    TRtcpStats rtcpStat;
+
+    RtcpStats( rtcpStat );
+
+    aStat.iCumNumOctetsSent = rtcpStat.iRtcpSenderStats.iCumNumOctetsSent;
+    aStat.iNumPacketsSent = rtcpStat.iRtcpSenderStats.iNumPacketsSent;
+
+    aStat.iTxBandwidth = rtcpStat.iRtcpReceiverStats.iTxBandwidth;
+    aStat.iArrivalJitter = rtcpStat.iRtcpReceiverStats.iArrivalJitter;
+    aStat.iCumNumPacketsLost = rtcpStat.iRtcpReceiverStats.iCumNumPacketsLost;
+    aStat.iFractionLost = rtcpStat.iRtcpReceiverStats.iFractionLost;
+    aStat.iRoundTripDelay = rtcpStat.iRtcpReceiverStats.iRoundTripDelay;
+    aStat.iRxBandwidth = rtcpStat.iRtcpReceiverStats.iBandwidth;
+    aStat.iChannelBufferSize = rtcpStat.iRtcpReceiverStats.iChannelBufferSize;
+    aStat.iNTPTimeStampSec = rtcpStat.iRtcpSenderStats.iNTPTimeStampSec;
+    aStat.iNTPTimeStampFrac = rtcpStat.iRtcpSenderStats.iNTPTimeStampFrac;
+    aStat.iTimeStamp = rtcpStat.iRtcpSenderStats.iTimeStamp;
+
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// TInt CRtpTranStream::BuildRtpPacket()
+// 
+// ---------------------------------------------------------------------------
+//
+TInt CRtpTranStream::BuildRtpPacket( const TRtpSendHeader& aHeaderInfo,
+                                     const TDesC8& aPayloadData,
+                                     TRtpSequence aSeqNum,
+                                     TBool aSetSeqNum,
+                                     CRtpPacket* aPktSnd )
+    {
+    TRtpPacketStreamParam streamParam;
+    TRtpPacketIOParam inParam;
+
+    if ( FirstPkg() )
+        {
+        RtpStreamSyncInit( aHeaderInfo.iTimestamp );
+        SetFirstPkg( EFalse );
+        }
+
+    //
+    // The interpretation of the marker is defined by a profile.
+    // It is used for marking significant events such as frame boundaries or
+    // talkspurts in the packet stream.
+
+    // Timestamp
+    // -- random initial value
+    // -- monotonically increasing 
+    // -- increases by one sampling period for fixed-rate audio
+    // -- increases for every sample independent of whether the block is
+    //    transmitted or dropped as silent.
+    // -- used for playout and inter-media synchronization.
+    //
+
+    //
+    // construct RTP packet
+    //
+
+    inParam.TRTP.padding = aHeaderInfo.iPadding;
+
+    if ( aHeaderInfo.iHeaderExtension )
+        {
+        inParam.TRTP.fHeaderExtension = 1;
+        inParam.TRTP.extension.type = aHeaderInfo.iHeaderExtension->iType;
+        inParam.TRTP.extension.length = aHeaderInfo.iHeaderExtension->iLength;
+        inParam.TRTP.extension.data = aHeaderInfo.iHeaderExtension->iData;
+        }
+    else
+        {
+        inParam.TRTP.extension.data = NULL;
+        }
+
+    inParam.TRTP.marker = aHeaderInfo.iMarker; 
+
+    inParam.TRTP.payloadData = const_cast<TUint8*>( aPayloadData.Ptr() );
+    inParam.TRTP.payloadDataLen = aPayloadData.Length();
+
+    streamParam.TRTP.payload = aHeaderInfo.iPayloadType;
+
+    if ( aSetSeqNum )
+        {
+        iSeqNum = aSeqNum;
+        }
+    streamParam.TRTP.seqNum = iSeqNum;
+
+    streamParam.TRTP.SSRC = iLocalSSRC;
+    streamParam.TRTP.timeStamp = aHeaderInfo.iTimestamp;
+    
+    //
+    // build and send the packet
+    //
+    aPktSnd->RtpPacketBuild( &streamParam, &inParam ); 
+
+    
+    RTP_DEBUG_DETAIL_DVALUE( "CRtpTranStream::BuildRtpPacket, Stream ID = ",
+                  iStreamId );
+    RTP_DEBUG_DETAIL_DVALUE( "CRtpTranStream::BuildRtpPacket, SSRC = ",
+                  streamParam.TRTP.SSRC );
+    RTP_DEBUG_DETAIL_DVALUE( "CRtpTranStream::BuildRtpPacket, Seq Num = ",
+                  static_cast<TInt>( streamParam.TRTP.seqNum ) );
+    RTP_DEBUG_DETAIL_DVALUE( "CRtpTranStream::BuildRtpPacket, Time Stamp = ",
+                  aHeaderInfo.iTimestamp );
+    
+    
+    // update sent octets and remote bandwidth parameters 
+    IncCumNumOctetsSent( aPayloadData.Length() );
+
+    // update stream parameters
+    iTimeStamp = aHeaderInfo.iTimestamp;
+    iSeqNum++;
+    if ( iSeqNum == 0 )
+        {
+        iSeqNumCycles++;
+        }
+
+    SetSentRTPPackets( ETrue );
+
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// TInt CRtpTranStream::BuildRtcpBYEPacket()
+// 
+// ---------------------------------------------------------------------------
+//
+TInt CRtpTranStream::BuildRtcpBYEPacket( const TDesC8& aReason,
+                                         CRtpPacket* aPktRtcpSnd )
+    {
+    TInt paddingSize = 0;
+    TRtpPacketStreamParam streamParam;
+    TRtpPacketIOParam initParam;
+    TInt ret = KErrNone;
+
+    TInt byeSize = aReason.Size();
+
+    // build RTCP BYE packet header
+    TInt sourceCount = 1; 
+    TInt length = 0;
+
+    initParam.TRTCP_HEADER.pt = ERTCP_BYE;
+
+    if ( ( 1 + byeSize ) % 4 == 0 )
+        {
+        // multiples of 4 bytes, no padding is needed
+        // calculate total number of 32 bit words in SDES packet
+        length = ( 1 + byeSize ) / 4 + 1;   
+        }
+    else
+        {
+        // not multiples of 4 bytes, padding is needed
+        paddingSize = 4 - ( 1 + byeSize ) % 4;
+        length = ( 1 + byeSize ) / 4 + 2;
+        }
+
+    initParam.TRTCP_HEADER.sourceCount = sourceCount;
+    initParam.TRTCP_HEADER.length = length;
+    aPktRtcpSnd->SetType( ERTCP_HEADER );
+
+    aPktRtcpSnd->RtpPacketBuild( &streamParam, &initParam );
+
+    streamParam.TRTCP_BYE.SSRC = iLocalSSRC;
+
+    initParam.TRTCP_BYE.reason = ( TUint8 * ) aReason.Ptr();
+    initParam.TRTCP_BYE.reasonSize = byeSize;
+    initParam.TRTCP_BYE.paddingSize = paddingSize;
+
+    aPktRtcpSnd->SetType( ERTCP_BYE );
+    aPktRtcpSnd->RtpPacketBuild( &streamParam, &initParam ); 
+    
+
+    RTCP_DEBUG_DETAIL_DVALUE( "SEND: Send BYE Packet TX Stream ID = ",
+              iStreamId );
+    RTCP_DEBUG_DETAIL_DVALUE( "SEND: Send BYE Packet SSRC = ",
+              iLocalSSRC );
+    RTCP_DEBUG_DETAIL( "SEND: Sending RTCP BYE message as" );
+    RTCP_DEBUG_DETAIL( initParam.TRTCP_BYE.reason );
+
+    return ret;
+    }
+
+// ---------------------------------------------------------------------------
+// TInt CRtpTranStream::BuildRtcpAPPPacket()
+// 
+// ---------------------------------------------------------------------------
+//
+TInt CRtpTranStream::BuildRtcpAPPPacket( const TRtcpApp& aApp,
+                                         CRtpPacket* aPktRtcpSnd )
+    {
+    TRtpPacketStreamParam streamParam;
+    TRtpPacketIOParam initParam;
+
+    initParam.TRTCP_HEADER.pt = ERTCP_APP;
+
+    initParam.TRTCP_HEADER.sourceCount = aApp.iSubType;
+
+    initParam.TRTCP_HEADER.length = aApp.iAppDataLen / 4 + 3 - 1;
+
+    aPktRtcpSnd->SetType( ERTCP_HEADER );
+
+    aPktRtcpSnd->RtpPacketBuild( &streamParam, &initParam );
+
+    streamParam.TRTCP_APP.SSRC = iLocalSSRC;
+
+    Mem::Copy( initParam.TRTCP_APP.name, aApp.iName, 4 );
+    initParam.TRTCP_APP.appData = const_cast<TUint8*>( aApp.iAppData );
+    initParam.TRTCP_APP.appDataLen = aApp.iAppDataLen;
+
+    aPktRtcpSnd->SetType( ERTCP_APP );
+
+    aPktRtcpSnd->RtpPacketBuild( &streamParam, &initParam ) ; 
+
+    RTP_DEBUG_DETAIL_DVALUE( "SEND: Send APP Packet TX Stream ID = ", iStreamId );
+    RTP_DEBUG_DETAIL_DVALUE( "SEND: Send APP Packet SSRC = " , iLocalSSRC );
+    RTCP_DEBUG_DETAIL( "SEND: Sending RTCP APP packet as " );
+    RTCP_DEBUG_DETAIL( "InitParam.TRTCP_APP.appData " );
+
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// CRtpTranStream::RtpStreamSyncInit()
+// For transmission stream, iSyncInfo is initialized by the
+// first packet sent.
+// ---------------------------------------------------------------------------
+//
+void CRtpTranStream::RtpStreamSyncInit( TRtpTimeStamp aInitTimeStamp )
+    {
+    TUint32 gtTime = TRtpUtil::GtGetTime();
+
+    TTime time1;
+    TTime time2;
+    TTimeIntervalSeconds interval;
+    time1.HomeTime();
+    _LIT( KTime, "19700101:000000.000000" );
+    time2.Set( KTime ); // microsecond from Jan. 1 1970
+    time1.SecondsFrom( time2, interval );
+
+    iSyncInfo.iNTPTimeStampSec = interval.Int() + KGetTimeOfDayToNTPOffset;
+
+
+    iSyncInfo.iNTPTimeStampFrac = static_cast<TUint32>(
+        ( ( ( ( TUint32 ) ( gtTime % KTenthOfmsPerSecond ) ) << 16 )
+        / KTenthOfmsPerSecond ) << 16 );
+
+    iSyncInfo.iTimeStamp = aInitTimeStamp;
+    iSyncInfo.iLastUpdateLocalTime = gtTime;
+    }
+
+// ---------------------------------------------------------------------------
+// CRtpTranStream::RtpStreamSyncCurrent()
+// iSyncInfo : NTP timestamp of initialization as a reference
+//             to update the current NTP timestamp
+// aSyncInfoCurrent : Bring back current NTP Time stamp
+// ---------------------------------------------------------------------------
+//
+void CRtpTranStream::RtpStreamSyncCurrent( TRtpTimeSync* aSyncInfoCurrent )
+    {
+    if ( !aSyncInfoCurrent )
+        {
+        return;
+        }
+    TUint32 gtTime = TRtpUtil::GtGetTime();
+    TUint32 diffFraction = ( gtTime - iSyncInfo.iLastUpdateLocalTime )
+                           % KTenthOfmsPerSecond;
+
+    aSyncInfoCurrent->iNTPTimeStampSec = iSyncInfo.iNTPTimeStampSec +
+          static_cast<TUint32>( gtTime - iSyncInfo.iLastUpdateLocalTime )
+          / KTenthOfmsPerSecond;
+    aSyncInfoCurrent->iNTPTimeStampFrac = ( static_cast<TUint32>(
+        ( diffFraction << 16 ) / KTenthOfmsPerSecond ) << 16 );
+    }
+
+// ---------------------------------------------------------------------------
+// CRtpTranStream::RtpStreamCreateRtcpReportSection()
+// For transmission stream, it only generates SR packet.
+// ---------------------------------------------------------------------------
+//
+void CRtpTranStream::RtpStreamCreateRtcpReportSection( CRtpPacket* aPkt )
+    {
+    TRtpPacketStreamParam streamParam;
+    TRtpPacketIOParam inParam;
+
+    TRtpTimeSync syncInfoCurrent;
+
+    streamParam.TRTCP_SR.SSRC = iLocalSSRC;
+
+    streamParam.TRTCP_SR.numPacketsSent = iSeqNum + ( iSeqNumCycles << 16 )
+                                          - iBaseSeqNum;
+    streamParam.TRTCP_SR.cumNumOctetsSent = iCumNumOctetsSent;
+
+    iRtcpStats.iRtcpSenderStats.iNumPacketsSent =
+        streamParam.TRTCP_SR.numPacketsSent;
+    iRtcpStats.iRtcpSenderStats.iCumNumOctetsSent =
+        streamParam.TRTCP_SR.cumNumOctetsSent;
+    iRtcpStats.iRtcpSenderStats.iSSRC = streamParam.TRTCP_SR.SSRC;
+
+    RtpStreamSyncCurrent( &syncInfoCurrent );
+
+    inParam.TRTCP_SR.NTPTimeStampSec = syncInfoCurrent.iNTPTimeStampSec;
+    inParam.TRTCP_SR.NTPTimeStampFrac = syncInfoCurrent.iNTPTimeStampFrac;
+    inParam.TRTCP_SR.timeStamp = iTimeStamp;
+
+    iRtcpStats.iRtcpSenderStats.iNTPTimeStampSec =
+        inParam.TRTCP_SR.NTPTimeStampSec;
+    iRtcpStats.iRtcpSenderStats.iNTPTimeStampFrac =
+        inParam.TRTCP_SR.NTPTimeStampFrac;
+    iRtcpStats.iRtcpSenderStats.iTimeStamp = inParam.TRTCP_SR.timeStamp;
+    
+
+    RTP_DEBUG_STAT( "----- TX: Create RTCP Report Statistics -----" );
+    RTP_DEBUG_STAT_DVALUE( "TX: numPacketsSent = ",
+              iRtcpStats.iRtcpSenderStats.iNumPacketsSent );
+    RTP_DEBUG_STAT_DVALUE( "TX: cumNumOctetsSent = ",
+              iRtcpStats.iRtcpSenderStats.iCumNumOctetsSent );
+    RTP_DEBUG_STAT_DVALUE( "TX: SSRC (Tx) = ",
+              iRtcpStats.iRtcpSenderStats.iSSRC );
+    RTP_DEBUG_STAT_DVALUE( "TX: NTPTimeStampSec = ",
+              iRtcpStats.iRtcpSenderStats.iNTPTimeStampSec );
+    RTP_DEBUG_STAT_DVALUE( "TX: NTPTimeStampFrac = ",
+              iRtcpStats.iRtcpSenderStats.iNTPTimeStampFrac );
+    RTP_DEBUG_STAT_DVALUE( "TX: timeStamp = ",
+              iRtcpStats.iRtcpSenderStats.iTimeStamp );
+
+
+    // For transmission stream, it only generates SR packet.
+    aPkt->SetType( ERTCP_SR );
+    aPkt->RtpPacketBuild( &streamParam, &inParam );
+    }
+
+
+// ---------------------------------------------------------------------------
+// TRtpRtcpEnum CRtpTranStream::RtpStreamProcessRtcpReportSectionL()
+// For transmission stream, it only processes RR packet.
+// ---------------------------------------------------------------------------
+//
+TRtpRtcpEnum CRtpTranStream::RtpStreamProcessRtcpReportSectionL(
+                                 CRtpPacket* aPkt )
+    {
+    TRtpPacketStreamParam streamParam;
+    TRtpPacketIOParam extractParam;
+    TRtpRtcpEnum parseResult = ERTCP_NO_ERROR;
+    TUint32 gtTime = TRtpUtil::GtGetTime();
+
+    parseResult = aPkt->RtpPacketProcessL( &streamParam, &extractParam );
+    if ( parseResult == ERTCP_PACKET_ERROR )
+        {
+        return ERTCP_PACKET_ERROR;
+        }
+
+    // For transmission stream, it only processes RR packet.
+    if ( aPkt->Type() == ERTCP_RR )
+        {
+        TInt roundTripDelay;
+
+        roundTripDelay = RtpStreamSyncGetRoundTripDelay(
+                             extractParam.TRTCP_RR.lastSRTimeStamp,
+                             extractParam.TRTCP_RR.delaySinceLSR );
+
+        iCumNumOctetsReceived += iSN_size[streamParam.TRTCP_RR.seqNumReceived
+                                     % KSNMaxArray] -
+                                 iSN_size[iPreviousRemoteSN % KSNMaxArray];
+
+        if ( iCumNumOctetsSent > iCumNumOctetsReceived )
+            {
+            iRtcpStats.iRtcpReceiverStats.iChannelBufferSize =
+                8 * ( iCumNumOctetsSent - iCumNumOctetsReceived );
+            }
+        else
+            {
+            iRtcpStats.iRtcpReceiverStats.iChannelBufferSize = 0;
+            }
+
+        iRtcpStats.iRtcpReceiverStats.iRoundTripDelay = roundTripDelay;
+        iRtcpStats.iRtcpReceiverStats.iFractionLost =
+            streamParam.TRTCP_RR.fractionLost;
+        iRtcpStats.iRtcpReceiverStats.iCumNumPacketsLost =
+            streamParam.TRTCP_RR.cumNumPacketsLost;
+        iRtcpStats.iRtcpReceiverStats.iSeqNumReceived =
+            streamParam.TRTCP_RR.seqNumReceived;
+
+        // SSRC coming from the source 
+        iRtcpStats.iRtcpReceiverStats.iSSRC = streamParam.TRTCP_RR.SSRC;
+
+        EstimateBandWidths( gtTime );
+
+        // Remember some things for next time we receive an RR
+        iPreviousRemoteSN = streamParam.TRTCP_RR.seqNumReceived;
+        iPrevRemoteTime = gtTime;
+        iPreviousTime = gtTime;
+        iCumNumOctetsSent_last = iCumNumOctetsSent;
+        
+        
+        RTP_DEBUG_STAT( "----- TX: Process RTCP Report Statistics -----" );
+        RTP_DEBUG_STAT_DVALUE( "TX: bandwidth (Tx) = ",
+                  iRtcpStats.iRtcpReceiverStats.iTxBandwidth );
+        RTP_DEBUG_STAT_DVALUE( "TX: roundTripDelay = ",
+                  iRtcpStats.iRtcpReceiverStats.iRoundTripDelay );
+        RTP_DEBUG_STAT_DVALUE( "TX: fractionLost = ",
+                  static_cast<TInt>(
+                      iRtcpStats.iRtcpReceiverStats.iFractionLost ) );
+        RTP_DEBUG_STAT_DVALUE( "TX: cumNumPacketsLost = ",
+                  iRtcpStats.iRtcpReceiverStats.iCumNumPacketsLost );
+        RTP_DEBUG_STAT_DVALUE( "TX: seqNumReceived = ",
+                  iRtcpStats.iRtcpReceiverStats.iSeqNumReceived );
+        RTP_DEBUG_STAT_DVALUE( "TX: SSRC (Rx) = ",
+                  iRtcpStats.iRtcpReceiverStats.iSSRC );
+        
+        
+        if ( iRtcpObserver )
+            {
+            iRtcpObserver->RrReceived( iStreamId,
+                                       iRtcpStats.iRtcpReceiverStats.iSSRC );
+            }
+        }
+
+    return parseResult;
+    }
+
+// ---------------------------------------------------------------------------
+// TUint32 CRtpTranStream::EstimateBandWidths()
+// Make an estimate of the Tx and Rx bandwidths.
+// ---------------------------------------------------------------------------
+// 
+void CRtpTranStream::EstimateBandWidths( TUint32 aCurrentTime )
+    {
+    /* NOTE: This is just a simple estimate, which assumes the following:
+     * - this is an end-to-end session
+     * - the sessions and streams are set up before traffic starts
+     * - the payload bitrate is constant
+     * The result of this estimation should not be used in any other contexts.
+     */
+
+    // Tx bandwidth
+    TReal B_A( 0 );
+
+    // Rx bandwidth
+    TReal B_B( 0 );
+
+    // number of received packets between the current and previous RR's
+    TInt N_B( 0 );
+
+    TReal avgPacketSize( 0 );
+    TUint8 fracLost_i( iRtcpStats.iRtcpReceiverStats.iFractionLost );
+    TUint32 lastRecvd_i( iRtcpStats.iRtcpReceiverStats.iSeqNumReceived ); 
+    TUint32 lastRecvd_k( iPreviousRemoteSN );
+    TUint packetsSent( iRtcpStats.iRtcpSenderStats.iNumPacketsSent ); 
+
+    TReal timeBetweenRRs = static_cast<TReal>( aCurrentTime - iPreviousTime )
+                           / KTenthOfmsPerSecond;
+
+    // Continue only if two RR's have been received and numbers are valid
+    if ( iCumNumOctetsSent_last == 0 ||
+         iPreviousRemoteSN == 0 ||
+         iPrevRemoteTime == 0 ||
+         iPreviousTime == 0 ||
+         timeBetweenRRs <= 0 ||
+         packetsSent == 0 ||
+         fracLost_i == 255 /* Would result in divide by zero and B_B = 0 */ )
+        {
+        // If this is the first RR to be received, this returns 0,
+        // otherwise this returns the result of the previous calculation
+        iRtcpStats.iRtcpReceiverStats.iBandwidth = 0;
+        iRtcpStats.iRtcpReceiverStats.iTxBandwidth = 0;
+        return;
+        }
+
+    B_A = 8 * static_cast<TReal>( ( iCumNumOctetsSent -
+              iCumNumOctetsSent_last ) ) / timeBetweenRRs;
+    iRtcpStats.iRtcpReceiverStats.iTxBandwidth = static_cast<TUint32>( B_A );
+
+    avgPacketSize = static_cast<TReal>( iCumNumOctetsSent )/ packetsSent;
+
+    /* The fraction lost is the fractional part of a decimal value between 0 
+     * and 1 (the fixed point is at the left edge of this value. The decimal
+     * equivalent can be computed by dividing by 255. */
+    N_B = static_cast<TInt>( 
+              ( lastRecvd_i - lastRecvd_k ) * ( 1 - ( fracLost_i / 255.0 ) ) );
+
+    B_B = 8 * ( avgPacketSize * N_B ) / timeBetweenRRs;
+    
+    iRtcpStats.iRtcpReceiverStats.iBandwidth = static_cast<TUint32>( B_B );
+    }
+
+// ---------------------------------------------------------------------------
+// TUint32 CRtpTranStream::RtpStreamSyncGetRoundTripDelay()
+// It is transmission stream's duty to calculate round trip delay.
+// ---------------------------------------------------------------------------
+// 
+TUint32 CRtpTranStream::RtpStreamSyncGetRoundTripDelay(
+                            TUint32 aLastSRTimeStamp, TUint32 aDelaySinceLSR )
+    {
+    TInt roundTripDelay = 0;
+    TRtpTimeStamp currentNTP;
+    TUint32 gtTime = TRtpUtil::GtGetTime();
+    TUint32 diffFraction = ( gtTime - iSyncInfo.iLastUpdateLocalTime )
+                           % KTenthOfmsPerSecond;
+
+    if ( aLastSRTimeStamp != 0 )
+        {
+        // calculate current NTP in a 16+16 bit precision
+        // (same format as lastSRTimeStamp)
+        currentNTP = ( ( iSyncInfo.iNTPTimeStampSec +
+                       ( gtTime - iSyncInfo.iLastUpdateLocalTime )
+                       / KTenthOfmsPerSecond ) << 16 );    
+        currentNTP += static_cast<TUint32>( ( diffFraction << 16 )
+                      / KTenthOfmsPerSecond );
+
+        roundTripDelay = currentNTP - aLastSRTimeStamp - aDelaySinceLSR;
+        if ( roundTripDelay > 0 )
+            {
+            // 16-MSB of roundTripDelay are seconds, 16-LSB of roundTripDelay
+            // is the fraction part. Transform this to a decimal value
+            // representing the round trip delay in tenths of millisecons
+            // ( 10^4 ). See RFC 3550 page 34 for details.
+            roundTripDelay = ( static_cast<TUint32>( roundTripDelay ) >> 16 ) *
+                             KTenthOfmsPerSecond +
+                             ( ( ( roundTripDelay & 0xFFFF ) *
+                                 KTenthOfmsPerSecond ) >> 16 );
+            }
+        else
+            {
+            // here we assume the delay is so small that we cannot get
+            // an accurate reading
+            roundTripDelay = 0;     
+            }
+        }
+
+    return static_cast<TUint32>( roundTripDelay );
+    }
+
+//end of file
+
+