multimediacommscontroller/mmccrtpsourcesink/src/mccjittercalculator.cpp
changeset 43 bf4e57f9a0ce
parent 0 1bce908db942
child 59 b0e4b01681c5
--- a/multimediacommscontroller/mmccrtpsourcesink/src/mccjittercalculator.cpp	Tue Jul 06 14:42:02 2010 +0300
+++ b/multimediacommscontroller/mmccrtpsourcesink/src/mccjittercalculator.cpp	Wed Aug 18 10:09:50 2010 +0300
@@ -11,7 +11,7 @@
 *
 * Contributors:
 *
-* Description:    MccJitterCalculator calculates jitter level and compares given
+* Description:  MccJitterCalculator calculates jitter level and compares given
 *                triggers.
 *
 */
@@ -46,6 +46,13 @@
 const TInt KNum4( 4 );
 const TInt KNum8( 8 );
 const TInt KNumZero( 0 );
+const TInt KNumHundred( 100 );
+
+const TUint32 KRtpFractationAccuracy = 5000;
+// Specified period of the moving average
+const TUint32 KDivider = 250;
+// Specified the max calculate count of package loss
+const TUint32 KMaxCalCount = 200;
 
 // ============================ MEMBER FUNCTIONS ===============================
 
@@ -137,7 +144,7 @@
 // -----------------------------------------------------------------------------
 //
 void CMccJitterCalculator::RtpPacketReceived( const TUint32 aTimeStamp, 
-    TBool aMarker )
+    TBool aMarker, TUint16 aSeqNum )
     {
     #ifdef TRACE_JITCALC
         RDebug::Print( _L("CMccJitterCalculator::RtpPacketReceived IN") );
@@ -147,6 +154,33 @@
         VoipTrace("%x %x %d %d %d", MCC_TRACE, MCC_RECEIVED_RTP_PACKET_INFO,
         aHeaderInfo.iSeqNum, aHeaderInfo.iTimestamp, iPacketsReceived );
     #endif
+          
+    TBool calculatePkgLoss = ETrue;  
+    if ( EMccQualityPacketBased == iReportIntervalType || iFrameLossObsOn )
+        {
+        // Save current packet sequence number
+	    // The SeqNum come from RTP package. It maybe start from a random number between
+        // 0 to 65535. iStartingSeqNum should be reset 
+        // while iCurrentSeqNum was reset (by remote packages)
+    	iCurrentSeqNum = aSeqNum;
+		if( iStartingSeqNum == KNumZero ||
+			iStartingSeqNum > iCurrentSeqNum )
+			{
+			iStartingSeqNum = aSeqNum;
+			if ( iStartingSeqNum > 0 )
+				{
+			    iStartingSeqNum--;
+				}
+			else
+				{
+                #ifdef TRACE_JITCALC
+                RDebug::Print( _L("Received SeqNum is 0, don't calculate lost package") );
+                #endif
+			    calculatePkgLoss = EFalse;
+				}
+			}
+        iReceivedPacketCounter++; 
+		}
     
     // Jitter calculating based on RFC3550 Appendix A.8, see www.ietf.org
     if ( aMarker || !iPacketsReceived )
@@ -218,15 +252,20 @@
             RDebug::Print( _L("CMccJitterCalculator::RtpPacketReceived SENDING RCV: %d"), iPacketsReceived );
         #endif
         
-        TMccRtpEventData event( ( iCurJitter >> KNum4 ), 
+        TMccRtpEventDataExtended event( ( iCurJitter >> KNum4 ), 
                                 iPacketsReceived, 
                                 iPrevPacketTransit,
+                                KNumZero,
+                                KNumZero,
                                 KNumZero );
         
         iObserver->SendJitterEvent( event, KErrNone );
         }
     
-    JitterObserving();
+    if ( calculatePkgLoss )	
+    	{
+        JitterObserving();
+    	}    
     }
 
 // ---------------------------------------------------------------------------
@@ -302,6 +341,7 @@
     iJitterObsOn = EFalse;
     iFrameLossObsOn = EFalse;
     iMediaQualityObservingStarted = EFalse;
+    iStartingSeqNum = KNumZero;
     }
 
 // ---------------------------------------------------------------------------
@@ -356,6 +396,9 @@
     iPacketsReceived = KNumZero;
     iCurJitter = KNumZero;
     iPrevPacketTransit = KNumZero;
+    iCurrentSeqNum = KNumZero;
+	iStartingSeqNum = KNumZero;
+	iReceivedPacketCounter = KNumZero;
     }
 
 // -----------------------------------------------------------------------------
@@ -366,6 +409,13 @@
 //  
 void CMccJitterCalculator::JitterObserving()
     {
+    #ifdef TRACE_JITCALC
+        RDebug::Print( _L("CMccJitterCalculator::JitterObserving IN") );
+    #endif
+    
+    TBool resetValuesForNextReport = EFalse;
+    TBool cancelObs = EFalse;
+    
     if ( iJitterObsOn )
         {
         #ifdef TRACE_JITCALC
@@ -374,98 +424,32 @@
                 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();
-            }
+        CheckJitter( resetValuesForNextReport, cancelObs );
+        }
+        	
+	if ( iFrameLossObsOn )
+        {
+        #ifdef TRACE_JITCALC
+            RDebug::Print( _L("CMccJitterCalculator::JitterObserving Frame Loss observing ON") );
+        #endif
+        
+        CheckPacketLoss( resetValuesForNextReport, cancelObs );
         }
+ 
+    if( resetValuesForNextReport ) 
+		{
+        // Initialize hometime again
+        iHomeTime.HomeTime();
+        #ifdef TRACE_JITCALC       
+            RDebug::Print ( _L("CMccJitterCalculator::JitterObserving Initialize iHomeTime = %Ld"), iHomeTime.Int64() );
+        #endif
+		}
+	if( cancelObs )
+		{
+		CancelObserving();	
+		}
     }
-
+    
 // ---------------------------------------------------------------------------
 // CMccJitterCalculator::IsObserving
 // To check if observing is ON
@@ -476,4 +460,288 @@
     return iMediaQualityObservingStarted;
     }
     
+// -----------------------------------------------------------------------------
+// CMccJitterCalculator::CountPacketLossPercentage
+// Counts packet loss percentage from iStartingSeqNum, iCurrentSeqNum
+// 		and iReceivedPacketCounter
+// private method
+// -----------------------------------------------------------------------------
+//  
+TInt CMccJitterCalculator::CountPacketLossPercentage()
+	{
+    TUint32 numberOfPacketsExpected( 0 );
+    numberOfPacketsExpected = iCurrentSeqNum - iStartingSeqNum;
+        
+    if ( ( iPrevExpectedPackets - iPrevPacketsReceived ) ==
+            ( numberOfPacketsExpected - iReceivedPacketCounter ) )
+        {
+        // no packet  lost - inorder
+        iPrevFerValue = CalculateFer( iPrevFerValue, EFalse, ETrue );
+        }
+    else if ( ( iPrevPacketsReceived < iReceivedPacketCounter ) &&
+                ( iPrevExpectedPackets == numberOfPacketsExpected ) )
+        {
+        // no packet  lost - late packet - remove FER
+        iPrevFerValue = CalculateFer( iPrevFerValue, ETrue, EFalse );                               
+        }
+    else if ( numberOfPacketsExpected > iPrevExpectedPackets )
+        {
+
+        // packet  lost - add FER by number of packets lost.
+        // expected = 5, prev_expected 3 => diff 2 but loss is ONE thats why - 1
+        TUint32 maxCalcount = 
+				 numberOfPacketsExpected - iPrevExpectedPackets - 1  < KMaxCalCount ?
+				 numberOfPacketsExpected - iPrevExpectedPackets - 1 : KMaxCalCount;
+        for ( TUint32 i = 0; i < maxCalcount; i++ )
+           {
+           iPrevFerValue = CalculateFer( iPrevFerValue, ETrue, ETrue );
+           }
+        }
+    
+    iPrevExpectedPackets = numberOfPacketsExpected; 
+    iPrevPacketsReceived = iReceivedPacketCounter;
+    
+    TInt percentage( iPrevFerValue / KRtpFractationAccuracy ); 
+    return percentage;
+	}    
+    
+// -----------------------------------------------------------------------------
+// CMccJitterCalculator::CheckJitter
+// Checks if current jitter level exceeds the jitter level given by the client,
+// 		and if exceeded, sends the report to client 
+// private method
+// -----------------------------------------------------------------------------
+//      
+void CMccJitterCalculator::CheckJitter( TBool& aReportIntervalReached, 
+										TBool& aReportSent )
+	{
+	#ifdef TRACE_JITCALC
+        RDebug::Print( _L("CMccJitterCalculator::CheckJitter IN") );
+    #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::CheckJitter 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::CheckJitter jitterlevel %u ms compared to jitter estimate %Lu ms"), 
+                        iJitterLevelFromClient, modJitter );
+                #endif
+                
+                TMccRtpEventDataExtended event( ( iCurJitter >> KNum4 ), 
+                                        	iPacketsReceived, 
+                                        	iPrevPacketTransit,
+                                        	modJitter,
+                                        	KNumZero,
+                                        	KNumZero );
+                
+                // Informs client via event and cancels jitter observing
+                iObserver->SendJitterEvent( event, KErrNone );
+                aReportSent = ETrue; 
+                }
+            aReportIntervalReached = ETrue;
+            }           
+        }
+    else if ( EMccQualityPacketBased == iReportIntervalType )
+        {
+        #ifdef TRACE_JITCALC
+            RDebug::Print( _L("CMccJitterCalculator::CheckJitter iReceivedPacketCounter: %u"), iReceivedPacketCounter );
+        #endif
+        
+        if ( iReportInterval == iReceivedPacketCounter )
+            {
+            // compare clients jitter level to current level
+            if ( iJitterLevelFromClient < modJitter )
+                {
+                #ifdef TRACE_JITCALC
+                    RDebug::Print( _L("CMccJitterCalculator::CheckJitter jitterlevel %u ms compared to jitter estimate %Lu ms"), 
+                        iJitterLevelFromClient, modJitter );
+                #endif
+                
+                TMccRtpEventDataExtended event( ( iCurJitter >> KNum4 ), 
+                                        	iPacketsReceived, 
+                                        	iPrevPacketTransit,
+                                        	modJitter,
+                                        	KNumZero,
+                                        	KNumZero );
+                
+                // Informs client via event and cancels jitter observing
+                iObserver->SendJitterEvent( event, KErrNone );
+                aReportSent = ETrue; 
+                }  
+            aReportIntervalReached = ETrue;
+            }
+        }
+     else
+        {
+        #ifdef TRACE_JITCALC
+            RDebug::Print( _L("CMccJitterCalculator::CheckJitter Report type is not valid!") );
+        #endif
+        
+        TMccRtpEventDataExtended event( ( iCurJitter >> KNum4 ), 
+                                  	iPacketsReceived, 
+                                  	iPrevPacketTransit,
+                                  	KNumZero,
+                                  	KNumZero,
+                                  	KNumZero );
+        
+        iObserver->SendJitterEvent( event, KErrArgument );
+        aReportSent = ETrue; 
+        }
+	
+	}
+    
+// -----------------------------------------------------------------------------
+// CMccJitterCalculator::CheckPacketLoss
+// Checks if current packet loss level exceeds the packet loss level 
+// 		given by the client, and if exceeded, sends the report to client 
+// private method
+// -----------------------------------------------------------------------------
+//      
+void CMccJitterCalculator::CheckPacketLoss( TBool& aReportIntervalReached, 
+											TBool& aReportSent )
+	{
+	#ifdef TRACE_JITCALC
+        RDebug::Print( _L("CMccJitterCalculator::CheckPacketLoss IN") );
+    #endif
+
+    TInt packetLossPercentage = CountPacketLossPercentage();
+  
+    if ( EMccQualityTimeBased == iReportIntervalType )
+	    {
+	    // change microsecs to millisecs
+	    TTimeIntervalMicroSeconds getTime = 
+	        iCurTime.MicroSecondsFrom( iHomeTime );
+	    
+	    #ifdef TRACE_JITCALC
+	        RDebug::Print( _L("CMccJitterCalculator::CheckPacketLoss getTime = %Ld"), getTime.Int64() );
+	    #endif
+	    
+	    if ( static_cast<TInt64>( iReportInterval ) <= 
+	       ( getTime.Int64() / KConversionFactor ) )
+	        {
+			// If the packet loss percentage was exceeded
+			if( iPacketLossFromClient < packetLossPercentage ) 
+	            {
+	            #ifdef TRACE_JITCALC
+	                RDebug::Print( _L("CMccJitterCalculator::CheckPacketLoss Packet Loss From Client %u compared to Current Packet Loss %u "), 
+	                    iPacketLossFromClient, packetLossPercentage );
+	            #endif
+	            
+	            TMccRtpEventDataExtended event( ( iCurJitter >> KNum4 ), 
+	                                    iPacketsReceived, 
+	                                    iPrevPacketTransit,
+	                                    KNumZero,
+										packetLossPercentage,
+										packetLossPercentage );
+	            
+	            // Informs client via event and cancels jitter observing
+	            iObserver->SendJitterEvent( event, KErrNone );
+	            aReportSent = ETrue; 
+	   			}
+	        aReportIntervalReached = ETrue; 
+	        }
+	    }      
+	else if ( EMccQualityPacketBased == iReportIntervalType )
+	    {
+	    
+	    #ifdef TRACE_JITCALC
+		RDebug::Print( _L("CMccJitterCalculator::CheckPacketLoss EMccQualityPacketBased == iReportIntervalType") );
+	    RDebug::Print( _L("CMccJitterCalculator::CheckPacketLoss iReceivedPacketCounter: %u"), iReceivedPacketCounter );
+	    #endif
+	    
+	    if ( iReportInterval == iReceivedPacketCounter )  
+	        {
+			// If the packet loss percentage was exceeded
+			if( iPacketLossFromClient < packetLossPercentage ) 
+	            {
+	            #ifdef TRACE_JITCALC
+	                RDebug::Print( _L("CMccJitterCalculator::CheckPacketLoss Packet Loss From Client %u compared to Current Packet Loss %u "), 
+	                    iPacketLossFromClient, packetLossPercentage );
+	            #endif
+	            
+	            TMccRtpEventDataExtended event( ( iCurJitter >> KNum4 ), 
+	                                    iPacketsReceived, 
+	                                    iPrevPacketTransit,
+	                                    KNumZero,
+										packetLossPercentage,
+										packetLossPercentage );
+	            
+	            // Informs client via event and cancels jitter observing
+	            iObserver->SendJitterEvent( event, KErrNone );
+	            aReportSent = ETrue; 
+	   			}   
+	        aReportIntervalReached = ETrue; 
+	        }
+	    }
+	 else
+	    {
+	    #ifdef TRACE_JITCALC
+	        RDebug::Print( _L("CMccJitterCalculator::CheckPacketLoss Report type is not valid!") );
+	    #endif
+	    
+	    TMccRtpEventDataExtended event( ( iCurJitter >> KNum4 ), 
+	                              iPacketsReceived, 
+	                              iPrevPacketTransit,
+	                              KNumZero,
+	                              KNumZero,
+								  KNumZero );
+	    
+	    iObserver->SendJitterEvent( event, KErrArgument );
+	    aReportSent = ETrue; 
+	    }
+	}   
+
+// -----------------------------------------------------------------------------
+// CMccJitterCalculator::CalculateFer
+// Calculates a new FER value
+// -----------------------------------------------------------------------------
+//      
+TUint32 CMccJitterCalculator::CalculateFer( TUint32 aPrevValue,
+    TBool aAdd, TBool aFlag )
+    {
+    TUint32 ret = 0;
+    TInt64 temp_add = 0;
+
+    temp_add = aAdd * KNumHundred * KRtpFractationAccuracy;
+
+    TInt64 diff = temp_add - (TInt64)aPrevValue;
+    TInt32 tempValue = static_cast<TInt32>( diff / KDivider );
+    
+    if ( aFlag )
+        {
+        ret =  TUint32( aPrevValue + tempValue );
+        }
+    else
+        {
+        if ( aPrevValue > tempValue )
+            {
+            ret = TUint32( aPrevValue - tempValue );
+            }
+        else
+            {
+            // removed FER would have gone over thus zero
+            ret = 0;
+            }
+        }
+    
+    return ret;
+    }
+
 //  End of File