diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccrtpsourcesink/src/mccjittercalculator.cpp --- /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 +#endif + +#ifdef _DEBUG +#define TRACE_JITCALC +#include +#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( ( 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( ( 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( iReportInterval ) <= + ( getTime.Int64() / KConversionFactor ) ) + { + // compare clients jitter level to current level + if ( static_cast( 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