rtp/rtpstack/src/rtprecvstream.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:27:36 +0100
branchRCL_3
changeset 44 0dcb073356a5
parent 43 b5e99d8877c7
child 33 b8a7e07b2677
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* 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 "rtprecvstream.h"
 


// ---------------------------------------------------------------------------
// C++ default constructor can NOT contain any code, that
// might leave.
// ---------------------------------------------------------------------------
//
CRtpRecvStream::CRtpRecvStream( MSsrcCheckCallback* aCallback,
                                const TRtpPayloadType aPayloadType,
                                const TRtpId aSessionId,
                                const TRtpId aReceiveStreamId,
                                MRtpObserver** aRtpObserver,
                                MRtcpObserver* aRtcpObserver,
                                const TUint32* aProfileRTPTimeRates )
    :
    CRtpStream( aReceiveStreamId,
             aSessionId,
             aProfileRTPTimeRates,
             aRtcpObserver,
             aPayloadType ),
    iNumWrapAround( 0 ),
    iRtpObserver( aRtpObserver ),
    iCallback( aCallback )
    {
    // set syncInfo values to zero 
    RtpStreamJitterInit();
    RtpStreamSyncInfoInit();
    }

// ---------------------------------------------------------------------------
// Symbian 2nd phase constructor can leave.
// ---------------------------------------------------------------------------
//
void CRtpRecvStream::ConstructL()
    {
    iRemoteSDES = CRtpSDES::NewL();
    }

// ---------------------------------------------------------------------------
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
CRtpRecvStream* CRtpRecvStream::NewL( const TRtpPayloadType aPayloadType,
                                      const TRtpId aSessionId,
                                      const TRtpId aReceiveStreamId,
                                      MRtpObserver** aRtpObserver,
                                      MRtcpObserver* aRtcpObserver,
                                      const TUint32* aProfileRTPTimeRates,
                                      MSsrcCheckCallback* aCallback )
    {
    CRtpRecvStream* self =
        new ( ELeave ) CRtpRecvStream( aCallback,
                                       aPayloadType,
                                       aSessionId,
                                       aReceiveStreamId,
                                       aRtpObserver,
                                       aRtcpObserver,
                                       aProfileRTPTimeRates );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop(); // self 
    return self;
    }

// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CRtpRecvStream::~CRtpRecvStream()
    {
	delete iRemoteSDES;
    }


// ---------------------------------------------------------------------------
// RegisterRtpObserver
// ---------------------------------------------------------------------------
//
void CRtpRecvStream::RegisterRtpObserver(MRtpObserver* aRtpObserver)
    {
    *iRtpObserver = aRtpObserver; 
    }


// ---------------------------------------------------------------------------
// UnRegisterRtpObserver
// ---------------------------------------------------------------------------
//
void CRtpRecvStream::UnRegisterRtpObserver()
    {
    *iRtpObserver = NULL;
    }

// ---------------------------------------------------------------------------
// TInt CRtpRecvStream::ResetStreamStat()
// ---------------------------------------------------------------------------
//
TInt CRtpRecvStream::ResetStreamStat()
    {
    TRtcpStats rtcpStat;

    RtcpStats( rtcpStat );
    
    rtcpStat.iRtcpReceiverStats.iFractionLost = 0;
    rtcpStat.iRtcpReceiverStats.iCumNumPacketsLost = 0;
    rtcpStat.iRtcpReceiverStats.iSeqNumReceived = 0; 
    rtcpStat.iRtcpReceiverStats.iArrivalJitter = 0;
    rtcpStat.iRtcpReceiverStats.iRoundTripDelay = 0;
    rtcpStat.iRtcpReceiverStats.iChannelBufferSize = 0;
   
    // The sender stats are updated when receiving SR packets, so reset 
    rtcpStat.iRtcpSenderStats.iSSRC = 0;
    rtcpStat.iRtcpSenderStats.iCumNumOctetsSent = 0;
    rtcpStat.iRtcpSenderStats.iNumPacketsSent = 0;
    rtcpStat.iRtcpSenderStats.iNTPTimeStampSec = 0;
    rtcpStat.iRtcpSenderStats.iNTPTimeStampFrac = 0;
    rtcpStat.iRtcpSenderStats.iTimeStamp = 0;

    iRtcpStats = rtcpStat;
    
    iNumReceivedPackets = 0;
    iNumWrapAround = 0;   
    
    // set syncInfo values to zero 
    RtpStreamJitterInit();
    RtpStreamSyncInfoInit();
    
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// TInt CRtpTranStream::GetStreamStat()
// 
// ---------------------------------------------------------------------------
//
TInt CRtpRecvStream::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 = 0;
    aStat.iNTPTimeStampFrac = 0;
    aStat.iTimeStamp = 0;

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// TInt CRtpRecvStream::RtpStreamProcessRtpPacketL()
// 
// ---------------------------------------------------------------------------
//
TInt CRtpRecvStream::RtpStreamProcessRtpPacketL( CRtpPacket* aPktRcv, TBool aAssignStream )
    {
    RTP_DEBUG_DETAIL( "CRtpRecvStream::RtpStreamProcessRtpPacketL Entry" );
    aPktRcv->RtpPacketResetPtr();

    // Check if this packet belongs to this stream by looking at the source SSRC
    if ( !aAssignStream )
        {
        TRtpSSRC aRemoteSSRC( NULL );
        aPktRcv->SetType( ERTP );
        aRemoteSSRC = aPktRcv->RtpPacketGetSSRC();
        if ( iRemoteSSRC != aRemoteSSRC )
            {
            RTP_DEBUG_DETAIL( "RtpRecvStream: Wrong SSRC" );
            return KErrNotFound;
            }
        }
    else
        {
        //assigned RTP packet SSRC if this stream's remote SSRC is NULL
        // if it is not null then return KErrNotFound
        if ( iRemoteSSRC )
            {
            RTP_DEBUG_DETAIL( "RtpRecvStream: Did not expect own SSRC" );
            return KErrNotFound;
            }
        }

    TRtpPacketStreamParam streamParam;
    TRtpPacketIOParam extractParam;

    // process RTP packet
    aPktRcv->SetType( ERTP );

    extractParam.TRTP.extension.data = NULL;

    if ( aPktRcv->RtpPacketProcessL( &streamParam, &extractParam ) < 0 )
        {
        RTP_DEBUG_DETAIL( "Invalid Rtp packet is received" );
        return KErrCorrupt;
        }
	if (!iCallback->CheckRemoteAddr())
		{
		RTP_DEBUG_DETAIL( "Packet comes from wrong remote address" );
		return KErrNotFound;
		}
    // update and check stream parameters
    if ( RtpStreamUpdateParamL( aPktRcv->Type(), &streamParam ) < 0 )
        {
        
        RTP_DEBUG_PACKET("RtpRecvStream: Could not update params" );
        
        return KErrNotFound;
        }

    iHdr.iPadding = extractParam.TRTP.padding;
    iHdr.iExtension = extractParam.TRTP.fHeaderExtension;
    iHdr.iCsrcCount = extractParam.TRTP.numCSRC;

    iHdr.iMarker = extractParam.TRTP.marker;
    iHdr.iTimestamp = streamParam.TRTP.timeStamp;
    iHdr.iPayloadType = streamParam.TRTP.payload; // iPayload; pass payload type to app,even if it changed

    if ( iHdr.iExtension )
        {
		iHdr.iHeaderExtension = &iHeaderExtension;
        iHdr.iHeaderExtension->iType = extractParam.TRTP.extension.type;
        iHdr.iHeaderExtension->iLength = extractParam.TRTP.extension.length;
        iHdr.iHeaderExtension->iData = extractParam.TRTP.extension.data;
        }

    iFlagReceivedRTPPackets = ETrue;

    // calculate jitter, maybe it eats a big portion of CPU time?
    RtpStreamUpdateJitter( iHdr.iTimestamp );

    iHdr.iSeqNum = streamParam.TRTP.seqNum;
    
    RTP_DEBUG_DETAIL_DVALUE( "The received RTP packet size = ", extractParam.TRTP.payloadDataLen );
    RTP_DEBUG_DETAIL_DVALUE( "The received RTP packet Seq Num = ", streamParam.TRTP.seqNum );
    
    TPtrC8 payloadData( extractParam.TRTP.payloadData, extractParam.TRTP.payloadDataLen );

    if ( *iRtpObserver )
        {
        RTP_DEBUG_PACKET("RTP packet received and pass to upper application" );
        
        (*iRtpObserver)->RtpPacketReceived( iStreamId, iHdr, payloadData );
        }
    else
        {
        RTP_DEBUG_PACKET( "RtpRecvStream: No observer registered" );
        }
   	if(aPktRcv->iExdataAlloc )
      	{
       	User::Free( extractParam.TRTP.extension.data );
       	}
   	if (aPktRcv->iCsrcAlloc)
   		{
   		User::Free( extractParam.TRTP.CSRCarray);
   		}    
   	RTP_DEBUG_DETAIL( "CRtpRecvStream::RtpStreamProcessRtpPacketL Exit" );
    	
    return KErrNone;
    }



// ---------------------------------------------------------------------------
// CRtpRecvStream::RtpStreamSyncInfoInit()
// For receiving stream, iSyncInfo is initialized to zero
// and will be updated by SR received for the future RR creating
// iSyncInfo.timeStamp & iSyncInfo.lastUpdateLocalTime are
// not useful actually.
// ---------------------------------------------------------------------------
// 
void CRtpRecvStream::RtpStreamSyncInfoInit()
    {
    iSyncInfo.iNTPTimeStampFrac = 0;
    iSyncInfo.iNTPTimeStampSec = 0;
    iSyncInfo.iTimeStamp = 0;
    iSyncInfo.iLastUpdateLocalTime = 0;
    }

// ---------------------------------------------------------------------------
// CRtpRecvStream::RtpStreamJitterInit()
// 
// ---------------------------------------------------------------------------
//
void CRtpRecvStream::RtpStreamJitterInit()
    {
    iSyncJitter.iLastPacketS = 0;
    iSyncJitter.iLastPacketR = 0;
    iSyncJitter.iJitterTime = 0;

    iSyncJitter.iWaitTime = 0;
    }

// ---------------------------------------------------------------------------
// CRtpRecvStream::RtpStreamUpdateJitter()
// 
// ---------------------------------------------------------------------------
//
void CRtpRecvStream::RtpStreamUpdateJitter( TRtpTimeStamp aCurrentTimeStamp )
    {
    TUint32 gtTime = TRtpUtil::GtGetTime();
    TRtpTimeStamp packetRTP( aCurrentTimeStamp );
    TInt jitterTime = 0;

    if ( packetRTP == iSyncJitter.iLastPacketS )
        {
        return;
        }

    jitterTime = ( ( ( gtTime - iSyncJitter.iLastPacketR ) * iSyncJitter.iTimeStampResolution ) 
                 / KTenthOfmsPerSecond ) - ( packetRTP - iSyncJitter.iLastPacketS );

    iSyncJitter.iJitterTime = iSyncJitter.iJitterTime + 
        ( ( ( TReal64 ) Abs( jitterTime ) - iSyncJitter.iJitterTime ) / 16.0 );

    // if jitter > 100 seconds, reset it. 
    if ( iSyncJitter.iJitterTime > 1000000 ) // 100 * KTenthOfmsPerSecond 
        {
        iSyncJitter.iJitterTime = 0;
        }
    iSyncJitter.iLastPacketR = gtTime;
    iSyncJitter.iLastPacketS = packetRTP;
    }

// ---------------------------------------------------------------------------
// TInt CRtpRecvStream::RtpStreamUpdateParamL()
// 
// ---------------------------------------------------------------------------
//
TInt CRtpRecvStream::RtpStreamUpdateParamL( TRtpPacketType aPType, 
                                           TRtpPacketStreamParam* aStreamParam )
    {
    TUint32 timerate;
    TInt error( KErrNone );

    if ( aPType == ERTP )
        {
        // Check if there is an SSRC collision
        if ( iCallback )
            {
            error = iCallback->CheckRemoteSsrcL( aStreamParam->TRTP.SSRC );
            }
        if ( error < KErrNone )
            {
            return KErrCorrupt;
            }
        if ( error > KErrNone )
            {
            // There was an SSRC collision, and TRTP.SSRC now contains the
            // updated SSRC value.
            iRemoteSSRC = aStreamParam->TRTP.SSRC;
            }

        if ( iFlagFirstPkg )
            {
            iRemoteSSRC = aStreamParam->TRTP.SSRC;
            iPayload = aStreamParam->TRTP.payload;
            iBaseSeqNum = aStreamParam->TRTP.seqNum;

            timerate = *( iProfileRTPTimeRates + iPayload );
            if ( timerate != 0 )
                {
                iSyncJitter.iTimeStampResolution = KMicrosecondPerSecond / timerate;
                }
            else
                {
                iSyncJitter.iTimeStampResolution = 0;
                }
            }
        else if ( iRemoteSSRC != aStreamParam->TRTP.SSRC )
            {
            // SSRC and seqNum change. start monitoring if this change is intentional, 
            // if several packets received sequentionally, and then re-initialize the stream 
            
            RTP_DEBUG_DETAIL( "SSRC changed" );
            
            
            return KErrNotFound;
            }
        else
            {
            if ( iPayload != aStreamParam->TRTP.payload )
                {
                // payload type changed, inform application somehow 
                RTP_DEBUG_DETAIL( "payload type changed" );
                
                }
            }

        if ( aStreamParam->TRTP.seqNum == TRtpUtil::Min16( aStreamParam->TRTP.seqNum, iSeqNum ) && !iFlagFirstPkg )
            {
            // if there is no buffering, out of order and duplicate packets
            // have to be discarded
            return KErrNone; // give this packet to the application as there is no buffer in RTP
            }
        else
            {
            //update the highest received SN and TS
            if ( TRtpUtil::Wrap16( iSeqNum, aStreamParam->TRTP.seqNum ) && !iFlagFirstPkg )
                {
                iSeqNumCycles++;
                }
            iSeqNum = aStreamParam->TRTP.seqNum;
            iTimeStamp = aStreamParam->TRTP.timeStamp;
            iFlagFirstPkg = 0;
            iNumReceivedPackets++;
            }
        }
    else
        {
        return KErrNotFound;
        }

    return KErrNone;
    } 


// ---------------------------------------------------------------------------
// CRtpRecvStream::RtpStreamCreateRtcpReportSection()
// For receiving stream, it only creates RR packet
// ---------------------------------------------------------------------------
// 
void CRtpRecvStream::RtpStreamCreateRtcpReportSection( CRtpPacket* aPkt )
    {
    TRtpPacketStreamParam streamParam;
    TRtpPacketIOParam inParam;

    TUint32 numPacketsExpected;
    TUint32 numPacketsIntervalLost;
    TUint32 numPacketsIntervalExpected;

    streamParam.TRTCP_RR.SSRC = iRemoteSSRC;

    // iSeqNum is 16 bit, but streamParam.TRTCP_RR.seqNumReceived is 32 bits. 
    // Check RFC1889 for RTCP part 

    streamParam.TRTCP_RR.seqNumReceived = iSeqNum + ( iSeqNumCycles << 16 );
    numPacketsExpected = streamParam.TRTCP_RR.seqNumReceived - iBaseSeqNum + 1;

    if ( numPacketsExpected < iNumReceivedPackets )
        {
        streamParam.TRTCP_RR.cumNumPacketsLost = 0;
        }
    else
        {
        if ( ( numPacketsExpected + ( 1 << 16 ) * iNumWrapAround ) < iLastRR_numExpectedPackets )
            {
            iNumWrapAround++;
            numPacketsExpected += ( 1 << 16 ) * iNumWrapAround;
            }
        else
            {
            numPacketsExpected += ( 1 << 16 ) * iNumWrapAround;
            }
        streamParam.TRTCP_RR.cumNumPacketsLost = numPacketsExpected - iNumReceivedPackets;
        }

    numPacketsIntervalExpected = numPacketsExpected - iLastRR_numExpectedPackets;
    numPacketsIntervalLost = numPacketsIntervalExpected - ( iNumReceivedPackets - iLastRR_numReceivedPackets );

    //
    // From RFC 1889
    // fraction lost: 8 bits
    // The fraction of RTP data packets from source SSRC_n lost since the previous SR or RR packet was sent, 
    // expressed as a fixed point number with the binary point at the left edge of the field. (That is 
    // equivalent to taking the integer part after multiplying the loss fraction by 256.) This fraction is
    // defined to be the number of packets lost divided by the number of packets expected.
    //

    if ( ( numPacketsIntervalExpected == 0 ) || ( numPacketsIntervalLost == 0 ) )
        {
        streamParam.TRTCP_RR.fractionLost = 0;
        }
    else
        {
        streamParam.TRTCP_RR.fractionLost = static_cast<TUint8>(
            ( numPacketsIntervalLost << 8 ) / numPacketsIntervalExpected );
        }

    iLastRR_numReceivedPackets = iNumReceivedPackets;
    iLastRR_numExpectedPackets = numPacketsExpected;

    streamParam.TRTCP_RR.arrivalJitter = static_cast<TUint32>( iSyncJitter.iJitterTime );

    // add receiver statistics to sender of SR packet 
    iRtcpStats.iRtcpReceiverStats.iRoundTripDelay = 0;
    iRtcpStats.iRtcpReceiverStats.iFractionLost = streamParam.TRTCP_RR.fractionLost;
    iRtcpStats.iRtcpReceiverStats.iCumNumPacketsLost = streamParam.TRTCP_RR.cumNumPacketsLost;
    iRtcpStats.iRtcpReceiverStats.iSeqNumReceived = streamParam.TRTCP_RR.seqNumReceived;
    iRtcpStats.iRtcpReceiverStats.iBandwidth = 0;
    iRtcpStats.iRtcpReceiverStats.iChannelBufferSize = 0;

    if ( iSyncJitter.iTimeStampResolution > 0 )
        {
        iRtcpStats.iRtcpReceiverStats.iArrivalJitter = ( streamParam.TRTCP_RR.arrivalJitter * KTenthOfmsPerSecond ) /
                                                      iSyncJitter.iTimeStampResolution;
        }
    else
        {
        iRtcpStats.iRtcpReceiverStats.iArrivalJitter = 0;
        }

    iRtcpStats.iRtcpReceiverStats.iSSRC = streamParam.TRTCP_RR.SSRC; // SSRC sender (coming source)
    
    
    RTP_DEBUG_STAT( "----- RX: Create RTCP Report Statistics -----" );
    RTP_DEBUG_STAT_DVALUE( "RX: roundTripDelay = ", iRtcpStats.iRtcpReceiverStats.iRoundTripDelay );
    RTP_DEBUG_STAT_DVALUE( "RX: fractionLost = ", (TInt)iRtcpStats.iRtcpReceiverStats.iFractionLost );
    RTP_DEBUG_STAT_DVALUE( "RX: cumNumPacketsLost = ", iRtcpStats.iRtcpReceiverStats.iCumNumPacketsLost );
    RTP_DEBUG_STAT_DVALUE( "RX: seqNumReceived = ", iRtcpStats.iRtcpReceiverStats.iSeqNumReceived );
    RTP_DEBUG_STAT_DVALUE( "RX: bandwidth = ", iRtcpStats.iRtcpReceiverStats.iBandwidth );
    RTP_DEBUG_STAT_DVALUE( "RX: channelBufferSize = ", iRtcpStats.iRtcpReceiverStats.iChannelBufferSize );
    RTP_DEBUG_STAT_DVALUE( "RX: arrivalJitter = ", iRtcpStats.iRtcpReceiverStats.iArrivalJitter );
    RTP_DEBUG_STAT_DVALUE( "RX: SSRC (Tx) = ", iRtcpStats.iRtcpReceiverStats.iSSRC );

    TUint32 gtTime = TRtpUtil::GtGetTime();
    // lastSRTimeStamp: use the middle 32 bits of the 64-bit NTP timestamp
    // This results in value where the 16-MSB is the amount of seconds, and
    // the 16-LSB is the fraction of seconds (in tenths of milliseconds).
    // See RFC3550 page 34 for details.
    inParam.TRTCP_RR.lastSRTimeStamp = ( iSyncInfo.iNTPTimeStampSec << 16 ) + ( iSyncInfo.iNTPTimeStampFrac >> 16 );
    inParam.TRTCP_RR.delaySinceLSR = 
        ( static_cast<TUint32>( ( gtTime - iSyncInfo.iLastUpdateLocalTime ) / KTenthOfmsPerSecond ) << 16 );
    inParam.TRTCP_RR.delaySinceLSR += 
    ( ( ( ( TUint32 ) ( ( gtTime - iSyncInfo.iLastUpdateLocalTime ) % KTenthOfmsPerSecond ) ) << 16 ) / KTenthOfmsPerSecond );

    // For receiving stream, it only generates RR packet. 
    aPkt->SetType( ERTCP_RR );
    aPkt->RtpPacketBuild( &streamParam, &inParam );
    }


// ---------------------------------------------------------------------------
// TRtpRtcpEnum CRtpRecvStream::RtpStreamProcessRtcpReportSectionL()
// For receiving stream, it only process SR packet
// ---------------------------------------------------------------------------
//
TRtpRtcpEnum CRtpRecvStream::RtpStreamProcessRtcpReportSectionL( CRtpPacket* aPkt )
    {
    TRtpPacketStreamParam streamParam;
    TRtpPacketIOParam extractParam;
    TRtpRtcpEnum parseResult = ERTCP_NO_ERROR;
    TUint32 gtTime = TRtpUtil::GtGetTime();

    parseResult = aPkt->RtpPacketProcessL( &streamParam, &extractParam );
    if ( parseResult < 0 )
        {
        return ERTCP_PACKET_ERROR; 
        }

    // For receiving stream, it only processes SR packet.
    if ( aPkt->Type() == ERTCP_SR )
        {
        // give this information to receiver on RTCP callback
        iSyncInfo.iLastUpdateLocalTime = gtTime;
        iSyncInfo.iNTPTimeStampSec = extractParam.TRTCP_SR.NTPTimeStampSec;
        iSyncInfo.iNTPTimeStampFrac = extractParam.TRTCP_SR.NTPTimeStampFrac;
        iSyncInfo.iTimeStamp = extractParam.TRTCP_SR.timeStamp;
        
        // do something with numPacketsSent and cumNumOctetsSent 
        iRtcpStats.iRtcpSenderStats.iSSRC = streamParam.TRTCP_SR.SSRC;
        iRtcpStats.iRtcpSenderStats.iCumNumOctetsSent = streamParam.TRTCP_SR.cumNumOctetsSent;
        iRtcpStats.iRtcpSenderStats.iNumPacketsSent = streamParam.TRTCP_SR.numPacketsSent;
        iRtcpStats.iRtcpSenderStats.iNTPTimeStampSec = iSyncInfo.iNTPTimeStampSec;
        iRtcpStats.iRtcpSenderStats.iNTPTimeStampFrac = iSyncInfo.iNTPTimeStampFrac;
        iRtcpStats.iRtcpSenderStats.iTimeStamp = iSyncInfo.iTimeStamp;
        
        
        RTP_DEBUG_STAT( "----- RX: Process RTCP Report Statistics -----" );
        RTP_DEBUG_STAT_DVALUE( "RX: cumNumOctetsSent = ", iRtcpStats.iRtcpSenderStats.iCumNumOctetsSent );
        RTP_DEBUG_STAT_DVALUE( "RX: numPacketsSent = ", iRtcpStats.iRtcpSenderStats.iNumPacketsSent );
        RTP_DEBUG_STAT_DVALUE( "RX: SSRC (Tx) = ", iRtcpStats.iRtcpSenderStats.iSSRC );
        RTP_DEBUG_STAT_DVALUE( "RX: NTPTimeStampSec = ", iRtcpStats.iRtcpSenderStats.iNTPTimeStampSec );
        RTP_DEBUG_STAT_DVALUE( "RX: NTPTimeStampFrac = ", iRtcpStats.iRtcpSenderStats.iNTPTimeStampFrac );
        RTP_DEBUG_STAT_DVALUE( "RX: timeStamp = ", iRtcpStats.iRtcpSenderStats.iTimeStamp );
   
        
        TTimeStamps timeStamps;
        timeStamps.iNTPTimeStampFrac = iRtcpStats.iRtcpSenderStats.iNTPTimeStampFrac;
        timeStamps.iNTPTimeStampSec = iRtcpStats.iRtcpSenderStats.iNTPTimeStampSec;
        timeStamps.iTimeStamp = iRtcpStats.iRtcpSenderStats.iTimeStamp;

        if ( iRtcpObserver )
            {
            iRtcpObserver->SrReceived( iStreamId, iRtcpStats.iRtcpSenderStats.iSSRC, timeStamps );
            }
        }
    else
        {
        // the received report can not be associated with the stream 
        return ERTCP_PACKET_ERROR;
        }

    return parseResult;
    }

// ---------------------------------------------------------------------------
// TInt CRtpRecvStream::GetRemoteStreamInfo()
// 
// ---------------------------------------------------------------------------
//
TInt CRtpRecvStream::GetRemoteStreamInfo( TRtpSdesParams& aSdes )
    {
    iRemoteSDES->GetSDES( aSdes );
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// TInt CRtpRecvStream::SetReceivedRTPPackets()
// 
// ---------------------------------------------------------------------------
//
void CRtpRecvStream::SetReceivedRTPPackets( TBool aFlag )
    {
    iFlagReceivedRTPPackets = aFlag;
    };


// ---------------------------------------------------------------------------
// TInt CRtpRecvStream::ReceivedRTPPackets()
// 
// ---------------------------------------------------------------------------
//
TBool CRtpRecvStream::ReceivedRTPPackets() const
    {
    return iFlagReceivedRTPPackets;
    };

// ---------------------------------------------------------------------------
// TInt CRtpRecvStream::GetRemoteSSRC()
// 
// ---------------------------------------------------------------------------
//
TRtpSSRC CRtpRecvStream::GetRemoteSSRC()
    {
    return iRemoteSSRC;
    }