multimediacommscontroller/mmccrtpsourcesink/src/mccjittercalculator.cpp
changeset 0 1bce908db942
child 32 f2ed1fc4c163
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccrtpsourcesink/src/mccjittercalculator.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,479 @@
+/*
+* Copyright (c) 2005-2006 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:    MccJitterCalculator calculates jitter level and compares given
+*                triggers.
+*
+*/
+
+
+
+
+// INCLUDE FILES
+#include "mccinternaldef.h"
+#include "mccrtpdatasource.h"
+#include "mccjittercalculator.h"
+#include "mccinternalevents.h"
+
+#ifdef VOIP_TRACE_ENABLED
+#include <voip_trace.h>
+#endif
+
+#ifdef _DEBUG
+#define TRACE_JITCALC
+#include <e32svr.h>
+#endif
+
+// CONSTANTS
+
+// Packet interval for jitter/jitterbuffer stat reports
+const TUint KJitterReportInterval = 16;
+// Conversion factor from uSecs to mSecs
+const TInt KConversionFactor = 1000;
+// Samplerate in kHz, currently only 8kHz supported
+const TUint KSampleRate = 8;
+
+const TInt KNum4( 4 );
+const TInt KNum8( 8 );
+const TInt KNumZero( 0 );
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMccJitterCalculator::CMccJitterCalculator
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CMccJitterCalculator::CMccJitterCalculator( MRtpJitterObserver& aObserver ) : 
+    iObserver( &aObserver )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterCalculator::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+#ifdef FTD_ENABLED
+void CMccJitterCalculator::ConstructL()
+    {
+    TInt err = iStreamStatsQueue.OpenGlobal( KMccStreamStats, EOwnerProcess );
+    if ( KErrNone != err )
+        {
+        User::Leave( err );
+        }
+    
+    err = iJBufStatsQueue.OpenGlobal( KMccJBufferStats, EOwnerProcess );
+    if ( KErrNone != err )
+        {
+        iStreamStatsQueue.Close();
+        User::Leave( err );
+        }
+    }
+#endif
+
+// -----------------------------------------------------------------------------
+// CMccJitterCalculator::NewL
+// Static constructor.
+// -----------------------------------------------------------------------------
+//
+CMccJitterCalculator* CMccJitterCalculator::NewL( MRtpJitterObserver& aObserver )
+    {
+    CMccJitterCalculator* self = 
+            new ( ELeave ) CMccJitterCalculator( aObserver );
+    
+    #ifdef FTD_ENABLED
+    CleanupStack::PushL ( self );
+    self->ConstructL ();
+    CleanupStack::Pop( self );
+    #endif
+    
+    return self;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMccJitterCalculator::~CMccJitterCalculator
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+CMccJitterCalculator::~CMccJitterCalculator()
+    {
+    #ifdef TRACE_JITCALC
+        RDebug::Print( _L("CMccJitterCalculator::~CMccJitterCalculator IN") );
+    #endif
+    
+    if ( IsObserving() )
+    	{
+        CancelObserving();               
+        }
+
+    iObserver = NULL;
+    
+    #ifdef FTD_ENABLED
+    iStreamStatsQueue.Close();
+    iJBufStatsQueue.Close();
+    #endif
+    
+    #ifdef TRACE_JITCALC
+        RDebug::Print( _L("CMccJitterCalculator::~CMccJitterCalculator OUT") );
+    #endif
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterCalculator::RtpPacketReceived
+// Calculates jitter values
+// -----------------------------------------------------------------------------
+//
+void CMccJitterCalculator::RtpPacketReceived( const TUint32 aTimeStamp, 
+    TBool aMarker )
+    {
+    #ifdef TRACE_JITCALC
+        RDebug::Print( _L("CMccJitterCalculator::RtpPacketReceived IN") );
+    #endif
+    
+    #ifdef VOIP_RECEIVED_RTP_PACKET_INFO_ENABLED
+        VoipTrace("%x %x %d %d %d", MCC_TRACE, MCC_RECEIVED_RTP_PACKET_INFO,
+        aHeaderInfo.iSeqNum, aHeaderInfo.iTimestamp, iPacketsReceived );
+    #endif
+    
+    // Jitter calculating based on RFC3550 Appendix A.8, see www.ietf.org
+    if ( aMarker || !iPacketsReceived )
+        {
+        // A new talkspurt, redo calculations Marker bit is set after silent
+        // period and indicates that new speech data is received
+        iPrevPacketArrival.HomeTime();
+        TInt64 pcktTrans = iPrevPacketArrival.Int64() / TInt64( KConversionFactor );
+        
+        // Convert timestamp to milliseconds and calculate transit time   
+        iPrevPacketTransit = 
+                pcktTrans - static_cast<TInt64>( ( aTimeStamp / KSampleRate ) );
+        
+        // Reset jitter and packet counter for new talkspurt
+        iCurJitter = KNumZero;
+        iPacketsReceived = KNumZero;
+        }
+    else
+        {
+        // Just another packet in the talkspurt
+        TTime newPacket;
+        newPacket.HomeTime();
+        
+        // Time of Arrival in milliseconds
+        TInt64 curPacketTOA = ( newPacket.Int64() / TInt64( KConversionFactor ) );
+        
+        // Convert timestamp to milliseconds and calculate transit time
+        TInt64 curPacketTransit 
+            = curPacketTOA - static_cast<TInt64>( ( aTimeStamp / KSampleRate ) );
+        
+        TInt64 diff = curPacketTransit - iPrevPacketTransit;
+        iPrevPacketTransit = curPacketTransit;
+        diff = Abs( diff );
+
+        // Jitter is floating mean value over 16 packets last received
+        iCurJitter +=  diff - ( ( iCurJitter + KNum8 ) >> KNum4 );
+        
+        #ifdef TRACE_JITCALC
+            RDebug::Print( _L("CMccJitterCalculator::RtpPacketReceived CUR_TOA: %Ld"), curPacketTOA );
+            RDebug::Print( _L("CMccJitterCalculator::RtpPacketReceived CUR_TRANS: %Ld"), curPacketTransit );
+            RDebug::Print( _L("CMccJitterCalculator::RtpPacketReceived CUR_DIFF: %Ld"), diff );
+            RDebug::Print( _L("CMccJitterCalculator::RtpPacketReceived CUR_JITT: %Lu"), iCurJitter );
+            RDebug::Print( _L("CMccJitterCalculator::RtpPacketReceived SC_CUR_JITT: %Lu"), ( iCurJitter >> KNum4 ) );
+        #endif
+        }
+    
+    iPacketsReceived++;
+    iCurTime.HomeTime();
+    
+    #ifdef TRACE_JITCALC
+        RDebug::Print ( _L("CMccJitterCalculator::RtpPacketReceived newPacket = %Ld"), iCurTime.Int64() );
+    #endif
+    
+    #ifdef FTD_ENABLED
+    TMccStreamStats stats;
+    stats.iPacketsReceived = iPacketsReceived;
+    stats.SetFieldUpdatedFlag( EPacketsReceived );
+    iStreamStatsQueue.Send( stats );
+    
+    TMccJBufferStats jStats;
+    jStats.iJitterEstimate = iCurJitter;
+    iJBufStatsQueue.Send( jStats );
+    #endif 
+    
+    // Report jitter if we have enough received packets and jitter
+    if ( !( iPacketsReceived % KJitterReportInterval ) && iCurJitter )
+        {
+        #ifdef TRACE_JITCALC
+            RDebug::Print( _L("CMccJitterCalculator::RtpPacketReceived SENDING RCV: %d"), iPacketsReceived );
+        #endif
+        
+        TMccRtpEventData event( ( iCurJitter >> KNum4 ), 
+                                iPacketsReceived, 
+                                iPrevPacketTransit,
+                                KNumZero );
+        
+        iObserver->SendJitterEvent( event, KErrNone );
+        }
+    
+    JitterObserving();
+    }
+
+// ---------------------------------------------------------------------------
+// CMccJitterCalculator::StartObserving
+// Switch to deside report type
+// ---------------------------------------------------------------------------
+//  
+TInt CMccJitterCalculator::StartObserving()
+    {
+    #ifdef TRACE_JITCALC
+        RDebug::Print( _L("CMccJitterCalculator::StartObserving IN") );
+    #endif
+    
+    TInt err( KErrNone );
+    iHomeTime.HomeTime();
+    
+    #ifdef TRACE_JITCALC
+        RDebug::Print ( _L("CMccJitterCalculator::StartObserving HomeTime = %Ld"), iHomeTime.Int64()  );
+        RDebug::Print( _L("CMccJitterCalculator::StartObserving iReportType: %d"), iReportType );
+    #endif
+
+    switch( iReportType )
+        {
+        case EMccJitterReport:
+            #ifdef TRACE_JITCALC
+                RDebug::Print( _L("CMccJitterCalculator::StartObserving  iReportType selected EMccJitterReport"));
+            #endif
+            iJitterObsOn = ETrue;                
+            iMediaQualityObservingStarted = ETrue;                
+            break;
+            
+        case EMccPacketLossReport:
+            #ifdef TRACE_JITCALC
+                RDebug::Print( _L("CMccJitterCalculator::StartObserving  iReportType selected EMccPacketLossReport"));
+            #endif
+            iFrameLossObsOn = ETrue;
+            iMediaQualityObservingStarted = ETrue;
+            break;
+            
+        case EMccQualityReportAll:
+            #ifdef TRACE_JITCALC
+                RDebug::Print( _L("CMccJitterCalculator::StartObserving  iReportType selected EMccQualityReportAll"));
+            #endif
+            iJitterObsOn = ETrue;
+            iFrameLossObsOn = ETrue;
+            iMediaQualityObservingStarted = ETrue;
+            break;
+
+        default:
+            // if report type is not set
+            #ifdef TRACE_JITCALC
+                RDebug::Print( _L("CMccJitterCalculator::StartObserving  iReportType selected default"));
+            #endif
+            
+            err = KErrArgument;
+            break;
+        }
+    
+    return err;
+    }
+
+// ---------------------------------------------------------------------------
+// CMccJitterCalculator::CancelObserving
+// Cancel is called by client
+// ---------------------------------------------------------------------------
+//  
+void CMccJitterCalculator::CancelObserving()
+    {
+    #ifdef TRACE_JITCALC
+        RDebug::Print( _L("CMccJitterCalculator::CancelObserving IN") );
+    #endif
+    
+    iJitterObsOn = EFalse;
+    iFrameLossObsOn = EFalse;
+    iMediaQualityObservingStarted = EFalse;
+    }
+
+// ---------------------------------------------------------------------------
+// CMccJitterCalculator::SetMediaConfigsL
+// Open aMessage and read media configs
+// ---------------------------------------------------------------------------
+//     
+void CMccJitterCalculator::SetMediaConfigsL( const TMMFMessage& aMessage )
+    {
+    #ifdef TRACE_JITCALC
+        RDebug::Print( _L("CMccJitterCalculator::SetMediaConfigs IN") );
+    #endif
+    
+    TMMFMessage* tmp = new ( ELeave ) TMMFMessage( aMessage );
+    CleanupStack::PushL( tmp );
+    
+    TMccMediaQualConfBuf configPckg;
+    tmp->ReadData1FromClientL( configPckg );
+
+    iMediaConf = configPckg();
+        
+    // Read data from client
+    iJitterLevelFromClient = iMediaConf.iJitterLevel;
+    iPacketLossFromClient = iMediaConf.iPacketLoss;
+    iReportType = iMediaConf.iReportType;
+    iReportIntervalType = iMediaConf.iReportIntervalType;
+    iReportInterval = iMediaConf.iReportInterval;
+        
+    #ifdef TRACE_JITCALC
+        RDebug::Print( _L("CMccJitterCalculator::SetMediaConfigsL SESSION %d"), iMediaConf.iSessionId );
+        RDebug::Print( _L("CMccJitterCalculator::SetMediaConfigsL JITTER LEVEL %d"), iMediaConf.iJitterLevel );
+        RDebug::Print( _L("CMccJitterCalculator::SetMediaConfigsL PACKET LOSS %d"), iMediaConf.iPacketLoss ); 
+        RDebug::Print( _L("CMccJitterCalculator::SetMediaConfigsL REPORT TYPE %d"), iMediaConf.iReportType );
+        RDebug::Print( _L("CMccJitterCalculator::SetMediaConfigsL REPORT INTERVAL TYPE %d"), iMediaConf.iReportIntervalType );
+        RDebug::Print( _L("CMccJitterCalculator::SetMediaConfigsL REPORT INTERVAL %d"), iMediaConf.iReportInterval );
+    #endif
+        
+    CleanupStack::PopAndDestroy( tmp );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterCalculator::ResetCounters
+// Set counters ready to receive packets
+// -----------------------------------------------------------------------------
+//
+void CMccJitterCalculator::ResetCounters()
+    {
+    #ifdef TRACE_JITCALC
+        RDebug::Print( _L("CMccJitterCalculator::ResetCounters()") );
+    #endif
+        
+    iPacketsReceived = KNumZero;
+    iCurJitter = KNumZero;
+    iPrevPacketTransit = KNumZero;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterCalculator::JitterObserving
+// Trigger controller. Compares calculated and defined values.
+// private method
+// -----------------------------------------------------------------------------
+//  
+void CMccJitterCalculator::JitterObserving()
+    {
+    if ( iJitterObsOn )
+        {
+        #ifdef TRACE_JITCALC
+            RDebug::Print( _L("CMccJitterCalculator::JitterObserving Jitter level observing ON") );
+            RDebug::Print( _L("CMccJitterCalculator::JitterObserving jitterlevel %u ms compared to jitter estimate %Lu ms"), 
+                iJitterLevelFromClient, ( iCurJitter / KConversionFactor ) );
+        #endif
+        
+        // Normalize iCurJitter
+        TUint64 modJitter = iCurJitter >> KNum4;
+            
+        if ( EMccQualityTimeBased == iReportIntervalType )
+            {
+            // change microsecs to millisecs
+            TTimeIntervalMicroSeconds getTime = 
+                iCurTime.MicroSecondsFrom( iHomeTime );
+            
+            #ifdef TRACE_JITCALC
+                RDebug::Print( _L("CMccJitterCalculator::JitterObserving getTime = %Ld"), getTime.Int64() );
+            #endif
+            
+            if ( static_cast<TInt64>( iReportInterval ) <= 
+               ( getTime.Int64() / KConversionFactor ) )
+                {
+                // compare clients jitter level to current level
+                if ( static_cast<TUint64>( iJitterLevelFromClient ) < 
+                    modJitter )
+                    {
+                    #ifdef TRACE_JITCALC
+                        RDebug::Print ( _L("CMccJitterCalculator::JitterObserving jitterlevel %u ms compared to jitter estimate %Lu ms"), 
+                            iJitterLevelFromClient, modJitter );
+                    #endif
+                    
+                    TMccRtpEventData event( ( iCurJitter >> KNum4 ), 
+                                            iPacketsReceived, 
+                                            iPrevPacketTransit,
+                                            modJitter );
+                    
+                    // Informs client via event and cancels jitter observing
+                    iObserver->SendJitterEvent( event, KErrNone );
+                    CancelObserving();
+                    }
+                
+                // Initialize hometime again
+                iHomeTime.HomeTime();
+                
+                #ifdef TRACE_JITCALC       
+                    RDebug::Print ( _L("CMccJitterCalculator::JitterObserving Initialize iHomeTime = %Ld"), iHomeTime.Int64() );
+                #endif
+            
+                }           
+            }
+        else if ( EMccQualityPacketBased == iReportIntervalType )
+            {
+            iReceivedPacketCounter++;
+            
+            #ifdef TRACE_JITCALC
+                RDebug::Print( _L("CMccJitterCalculator::JitterObserving iReceivedPacketCounter: %u"), iReceivedPacketCounter );
+            #endif
+            
+            if ( iReportInterval == iReceivedPacketCounter )
+                {
+                // compare clients jitter level to current level
+                if ( iJitterLevelFromClient < modJitter )
+                    {
+                    #ifdef TRACE_JITCALC
+                        RDebug::Print( _L("CMccJitterCalculator::JitterObserving jitterlevel %u ms compared to jitter estimate %Lu ms"), 
+                            iJitterLevelFromClient, modJitter );
+                    #endif
+                    
+                    TMccRtpEventData event( ( iCurJitter >> KNum4 ), 
+                                            iPacketsReceived, 
+                                            iPrevPacketTransit,
+                                            modJitter );
+                    
+                    // Informs client via event and cancels jitter observing
+                    iObserver->SendJitterEvent( event, KErrNone );
+                    CancelObserving();
+                    }
+                  
+                iReceivedPacketCounter = KNumZero;
+                }
+            }
+         else
+            {
+            #ifdef TRACE_JITCALC
+                RDebug::Print( _L("CMccJitterCalculator::JitterObserving Report type is not valid!") );
+            #endif
+            
+            TMccRtpEventData event( ( iCurJitter >> KNum4 ), 
+                                      iPacketsReceived, 
+                                      iPrevPacketTransit,
+                                      KNumZero );
+            
+            iObserver->SendJitterEvent( event, KErrArgument );
+            CancelObserving();
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CMccJitterCalculator::IsObserving
+// To check if observing is ON
+// ---------------------------------------------------------------------------
+//      
+TBool CMccJitterCalculator::IsObserving() const
+    {
+    return iMediaQualityObservingStarted;
+    }
+    
+//  End of File