multimediacommscontroller/mmccjitterbuffer/src/mccjitterbufferimpl.cpp
changeset 0 1bce908db942
child 32 f2ed1fc4c163
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccjitterbuffer/src/mccjitterbufferimpl.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,1034 @@
+/*
+* Copyright (c) 2004-2007 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:    Implementation of Mcc Jitterbuffer
+*
+*/
+
+
+
+
+// INCLUDE FILES
+#include "mmcccodecinformation.h"
+#include "mccjitterbufferimpl.h"
+#include "mcccngenerator.h"
+#include "mccinternalevents.h"
+#include "mccinternaldef.h"
+#include "mccjitterbufferlogs.h"
+#include "mccjitterbufferobserver.h"
+
+// LOCAL CONSTANTS
+const TInt KDefaultSampleRateInkHz = 8;
+const TInt KWbSampleRateInkHz = 16;
+const TInt KLowBufferLimit = 2;
+const TInt KOverflowAlarmLimit = 20;
+const TInt KSequentialLateFramesLimit = 20;
+
+// Codec frame sizes
+const TInt KAMRNBFrameSize = 32;
+const TInt KAMRWBFrameSize = 64;
+const TInt KILBCFrameSize = 52;
+const TInt KG729FrameSize = 24; // 10 octets + 2 for header
+
+// Maximum possible sequence number of RTP packet with standard RTP header.
+const TInt KMaxSeqNumber = 65535;        // 16-bit value
+
+// Codec frame times
+const TInt KAMRNBFrameTime = 20;
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// TJitterBufferElement::CompareSeqNum
+// Compare SequenceNumber
+// -----------------------------------------------------------------------------    
+//
+TInt TJitterBufferElement::CompareSeqNum( const TJitterBufferElement& aElem1, 
+        const TJitterBufferElement& aElem2 )
+    {
+    if ( aElem1.iSequenceNumber > aElem2.iSequenceNumber )
+        {
+        return (-1);
+        }
+    else if ( aElem1.iSequenceNumber < aElem2.iSequenceNumber )
+        {
+        return (1);
+        }
+    else
+        {
+        return (0);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// TJitterBufferElement::CompareStamp
+// Compare Stamp
+// -----------------------------------------------------------------------------        
+//
+TInt TJitterBufferElement::CompareStamp( const TJitterBufferElement& aElem1, 
+        const TJitterBufferElement& aElem2 )
+    {
+    if ( aElem1.iStamp > aElem2.iStamp )
+        {
+        return (-1);
+        }
+    else if ( aElem1.iStamp < aElem2.iStamp )
+        {
+        return (1);
+        }
+    else
+        {
+        return (0);
+        }
+    }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::CMccJitterBufferImpl
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CMccJitterBufferImpl::CMccJitterBufferImpl( MJitterBufferObserver* aObserver): 
+		iPacketsInBuffer( 0 ), 
+        iLastGetSeqNum( -1 ), 
+        iBufStampSorter( 
+            TLinearOrder<TJitterBufferElement>( TJitterBufferElement::CompareStamp ) 
+            ),
+        iBufSequenceSorter( 
+            TLinearOrder<TJitterBufferElement>( TJitterBufferElement::CompareSeqNum ) 
+            ),
+        iSeqNumIncrement( 0 ),
+        iPlay( EFalse ),
+        iObserver( aObserver ),
+        iOverflowCounter( 0 ),
+        iPlayToneInterval( 0 ),
+        iNotifyUser( ETrue ),
+        iLatestNotifiedEvent( KMccEventNone ),
+        iSampleRate( KDefaultSampleRateInkHz )
+    {
+    iTonePlayTime.UniversalTime();
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::NewL
+// Static constructor.
+// -----------------------------------------------------------------------------
+//
+CMccJitterBufferImpl* CMccJitterBufferImpl::NewL( MJitterBufferObserver* aObserver )
+    {
+    __JITTER_BUFFER( "CMccJitterBufferImpl::NewL 64bit version" )
+
+    CMccJitterBufferImpl* self = new( ELeave ) CMccJitterBufferImpl( aObserver );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBufferImpl::ConstructL()
+    {
+    SetBufferState( EIdle );
+    SendStreamEventToClient( KMccStreamIdle, ETrue );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::~CMccJitterBufferImpl
+// Destructor deallocate memory.
+// -----------------------------------------------------------------------------
+//
+CMccJitterBufferImpl::~CMccJitterBufferImpl()
+    {
+    __JITTER_BUFFER( "CMccJitterBufferImpl::~CMccJitterBufferImpl entry" )
+
+    delete iCnGenerator;    
+        
+    // Deallocate payload memory of jitter buffer elements.
+    const TInt count = iBuffer.Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        delete iBuffer[i].iDataFrame;
+        } 
+
+    iBuffer.Close();
+    iObserver = NULL;
+    
+    __JITTER_BUFFER( "CMccJitterBufferImpl::~CMccJitterBufferImpl exit" )
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::SetupL
+// Setup Jitterbuffer
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBufferImpl::SetupL( 
+    TInt aPlayoutThreshold, 
+    const TMccCodecInfo& aCInfo, 
+    CMMFDevSound& aDevSound, 
+    MAsyncEventHandler* aEventHandler,
+    TUint32 aEndpointId )
+    {
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::SetupL aCInfo.iJitterBufBufferLength:",
+                          aCInfo.iJitterBufBufferLength )
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::SetupL aPlayoutThreshold:",
+                          aPlayoutThreshold )
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::SetupL aCInfo.iJitterBufInactivityTimeOut:",
+                          aCInfo.iJitterBufInactivityTimeOut )
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::SetupL aCInfo.iJitterBufPlayToneTimeout:",
+                          aCInfo.iJitterBufPlayToneTimeout )
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::SetupL aCInfo.iJitterBufPlayToneFrequency:",
+                          aCInfo.iJitterBufPlayToneFrequency )
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::SetupL aCInfo.iJitterBufPlayToneDuration:",
+                          aCInfo.iJitterBufPlayToneDuration )
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::SetupL aCInfo.iHwFrameTime:",
+                          aCInfo.iHwFrameTime )
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::SetupL aCInfo.iPtime:",
+                          aCInfo.iPtime )
+    
+    // Changed if-statement to asserts. Added also check agains 0 hwframetime
+    __ASSERT_ALWAYS( aCInfo.iPtime, User::Leave( KErrArgument ) );
+    __ASSERT_ALWAYS( aCInfo.iJitterBufBufferLength, User::Leave( KErrArgument ) );
+    __ASSERT_ALWAYS( aCInfo.iHwFrameTime, User::Leave( KErrArgument ) );
+    
+    // Save the original HW frame time because we may need it in case of
+    // dynamic G.711 adjustment.
+    const TUint8 origHwtime = iCInfo.iHwFrameTime;
+    iCInfo = aCInfo;
+    iEventHandler = aEventHandler;
+    iEndpointId = aEndpointId;
+    
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::SetupL origHwtime:", origHwtime )
+    
+    if( iCInfo.iJitterBufInactivityTimeOut )
+        {
+        if( ( iCInfo.iJitterBufPlayToneFrequency > 0 ) && 
+            ( iCInfo.iJitterBufPlayToneDuration > 0 ) )
+            {
+            iPlayToneInterval = iCInfo.iJitterBufPlayToneTimeout;            
+            iPlay = ETrue;
+            }
+        }
+        
+    TInt bufLenMultiplier = 1;
+    if ( iCInfo.iFourCC == KMMFFourCCCodeAMR )
+        {
+        iFrameSize = KAMRNBFrameSize;
+        iFrameTime = KAMRNBFrameTime;
+        }
+    else if ( iCInfo.iFourCC == KMMFFourCCCodeAWB )
+        {   
+        iFrameSize = KAMRWBFrameSize;
+        iFrameTime = KAMRNBFrameTime;
+        iSampleRate = KWbSampleRateInkHz;
+        }
+    else if( iCInfo.iFourCC == KMccFourCCIdG711 )
+        {
+        // G.711 is configured dynamically. Take voip headerlength also in to
+        // account. G.711 hwframetime is in milliseconds, so need to multiply.
+        iFrameSize = ( iCInfo.iHwFrameTime * KDefaultSampleRateInkHz )
+            + KVoIPHeaderLength;
+        iFrameTime = 0;
+        
+        // In case of G.711 codec dynamic configuration, we may need to double
+        // the jitterbuffer length if HW frame time is changed from 20ms to
+        // 10ms. 
+        if ( origHwtime )
+            {
+            bufLenMultiplier = origHwtime / iCInfo.iHwFrameTime;
+            if ( !bufLenMultiplier )
+                {
+                bufLenMultiplier = 1;
+                }
+            }
+        }
+    else if( iCInfo.iFourCC == KMccFourCCIdILBC )
+        {
+        iFrameSize = KILBCFrameSize;
+        iFrameTime = 0;
+        }
+    else if( iCInfo.iFourCC == KMccFourCCIdG729 )
+        {
+        iFrameSize = KG729FrameSize;
+        iFrameTime = 0;
+        // Multiply G.729 also by two...
+        bufLenMultiplier = 2;
+        }
+    else
+        {
+        __JITTER_BUFFER( "CMccJitterBufferImpl::SetupL KErrNotSupported" )
+        
+        User::Leave( KErrNotSupported );
+        }
+            
+    // Delete old buffer & reset it
+    const TInt elems = iBuffer.Count();
+    for( TInt i = 0; i < elems; i++ )
+        {
+        delete iBuffer[i].iDataFrame;
+        iBuffer[i].iDataFrame = NULL;
+        }
+    
+    iBuffer.Reset();
+    
+    // Calculate needed elements
+    TInt bufLen = iCInfo.iJitterBufBufferLength * bufLenMultiplier;
+    
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::SetupL G.711 bufLenMultiplier ",
+        bufLenMultiplier )
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::SetupL iBufferLength: ",
+        bufLen )
+    
+    __ASSERT_ALWAYS( aPlayoutThreshold < bufLen, User::Leave( KErrTooBig ) );
+    
+    // if differences between bufferlength and treshold set by client
+    // is less than 10, increase bufferlength so the differences is 10
+    // this is to help buffer goes to overflow easily.
+    // Also possible G.711/729 multiplier needs to be taken care of.
+    CheckThresholdBufferLength( bufLen, aPlayoutThreshold );
+    iCurrentPlayThreshold = aPlayoutThreshold * bufLenMultiplier;
+    iOriginalPlayThreshold = aPlayoutThreshold * bufLenMultiplier;
+    
+    if( iCnGenerator )
+        {
+        delete iCnGenerator;
+        iCnGenerator = NULL;
+        }
+
+    iCnGenerator = CMccCnGenerator::NewL( iCInfo.iFourCC, aDevSound );
+    
+    // Create the elements in the Buffer
+    for( TInt k = 0; k < bufLen; k++ )
+        {
+        CMMFDataBuffer* buf = CMMFDataBuffer::NewL( iFrameSize );
+        CleanupStack::PushL( buf );
+        TJitterBufferElement newElement;
+        newElement.iDataFrame = buf;
+        newElement.iSequenceNumber = -1;
+        newElement.iStamp = -1;
+        iBuffer.AppendL( newElement );
+        CleanupStack::Pop( buf );
+        }
+    
+    // Zero the statistic members
+    iFramesLost = 0;
+    iFramesReceived = 0;
+    iNumOfLateFrames = 0;
+    iFramesRemoved = 0;
+    iFramesPlayed = 0;
+    iPacketsInBuffer = 0;
+    
+    // Calculate the sequence number increment
+    iSeqNumIncrement = iSampleRate * iCInfo.iHwFrameTime;
+    } 
+        
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::ResetBufferL
+// Reset Jitterbuffer
+// -----------------------------------------------------------------------------
+//
+
+void CMccJitterBufferImpl::ResetBuffer( TBool aPlayTone, TBool aNotifyUser )
+    {
+    const TInt bufLen = BufferLength();
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::ResetBuffer bufLen: ", bufLen )
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::ResetBuffer pktsIn: ", iPacketsInBuffer )
+    
+    for( TInt i = 0; i < bufLen; i++ )
+        {
+        iBuffer[i].iSequenceNumber = -1;
+        iBuffer[i].iStamp = -1;
+        }
+    
+    iLastGetSeqNum = -1;
+    iCurrentPlayThreshold = iOriginalPlayThreshold;
+    iPacketsInBuffer = 0; 
+    iPlay = aPlayTone; 
+    
+    if ( BufferState() != EIdle && 
+         aNotifyUser && 
+         iLatestNotifiedEvent != KMccStreamIdle )
+        {
+        SendStreamEventToClient( KMccStreamIdle, ETrue );
+        }
+    
+    SetBufferState( EIdle );
+    iDropNextFrame = EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::CurrentCodec
+// Return current codec.
+// -----------------------------------------------------------------------------
+//
+TFourCC CMccJitterBufferImpl::CurrentCodec() const
+    {
+    return iCInfo.iFourCC;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::DelayUpL
+// Adds a buffer element into the jitter buffer
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBufferImpl::DelayUpL()
+    {
+    CMMFDataBuffer* buf = CMMFDataBuffer::NewL( iFrameSize );
+    CleanupStack::PushL( buf );
+    TJitterBufferElement newElement;
+    newElement.iDataFrame = buf;
+    newElement.iSequenceNumber = -1;
+    newElement.iStamp = -1;
+    iBuffer.AppendL( newElement );
+    CleanupStack::Pop( buf );
+    
+    // Insert one NO_DATA frame into the audio stream, so the jitterbuffer has
+    // the possibility to grow at least one frame from the current status. 
+    // If the current playout threshold is zero, then there is playout ongoing or
+    // a DTX period. This means that we should buffer at least one frame before
+    // starting playout.
+    if( 0 == iCurrentPlayThreshold )
+        {
+        __JITTER_BUFFER( "CMccJitterBufferImpl::DelayUpL Adjusting Playout Threshold" )
+        
+        iCurrentPlayThreshold = iPacketsInBuffer + 1;
+        }
+    
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::DelayUpL BUF_LEN:", BufferLength() )
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::DelayUpL CUR_FRAMES:", iPacketsInBuffer )
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::DelayUpL PLAY_TH:", iCurrentPlayThreshold )
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::DelayDownL
+// Removes an buffer element from the jitter buffer
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBufferImpl::DelayDownL()
+    {
+    // We need to remove one frame from the jitterbuffer. If currently we are
+    // in a DTX period, we're in luck as we do not affect voice quality at all.
+    
+    // DURING DTX:
+    // During DTX periods the jitterbuffer can be empty, so we cannot remove
+    // anything from nothing. Then we basically can remove one element from the
+    // buffer so it is shorter.
+    
+    // DURING SPEECH:
+    // We'll need to remove one audio frame and mark the one preceding the 
+    // removed frame as bad. Then we'll continue as usual.
+    const TInt bufLen = BufferLength();
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::DelayDownL BUF_LEN:", bufLen )
+    __JITTER_BUFFER_INT1("CMccJitterBufferImpl::DelayDownL CUR_FRAMES:", iPacketsInBuffer )
+    
+    if( this->IsEmpty() )
+        {
+        // Cannot do anything for empty buffer
+        if( KLowBufferLimit < bufLen )
+            {
+            __JITTER_BUFFER( "CMccJitterBufferImpl::DelayDownL Empty buffer" )
+            
+            delete iBuffer[bufLen - 1].iDataFrame;
+            iBuffer.Remove( bufLen - 1 );
+            }
+        else if( 0 < iCurrentPlayThreshold )
+            {
+            __JITTER_BUFFER( "CMccJitterBufferImpl::DelayDownL Playthreshold modification" )
+                        
+            iCurrentPlayThreshold--;
+            }
+        else
+            {
+            __JITTER_BUFFER( "CMccJitterBufferImpl::DelayDownL Buffer empty, cant do anything" )
+            // Cannot do anything currently
+            return;
+            }
+        }
+    else if( this->IsFull() )
+        {
+        // If there is sufficiently data in the buffer, then remove one
+        // frame and mark the one preceding it bad
+        if( KLowBufferLimit < iPacketsInBuffer )
+            {
+            __JITTER_BUFFER( "CMccJitterBufferImpl::DelayDownL Buffer full, doing removal" )
+            
+            // Remove the 2nd oldest frame and mark the oldest as bad
+            delete iBuffer[1].iDataFrame;
+            iBuffer.Remove( 1 );
+            
+            // MARK THE FIRST AS BAD FRAME!!!
+            iPacketsInBuffer--;
+            iFramesRemoved++;
+            }
+        else
+            {
+            // Cant do removing, see if playthreshold can be adjusted
+            if( 0 < iCurrentPlayThreshold )
+                {
+                __JITTER_BUFFER( "CMccJitterBufferImpl::DelayDownL Buffer full, cant do anything" )
+                
+                iCurrentPlayThreshold--;
+                }
+            }
+        }
+    else
+        {
+        if( KLowBufferLimit < bufLen )
+            {
+            __JITTER_BUFFER( "CMccJitterBufferImpl::DelayDownL Some frames, adjusting length" )
+            
+            // Adjust the length of the buffer
+            delete iBuffer[bufLen - 1].iDataFrame;
+            iBuffer.Remove( bufLen - 1 );
+            }
+        else
+            {
+            __JITTER_BUFFER( "CMccJitterBufferImpl::DelayDownL Some frames, too small buffer" )
+            }
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::CalculateDelay
+// Calculates the current delay that jitterbuffer has in the playback
+// -----------------------------------------------------------------------------
+//
+TTimeIntervalMicroSeconds32 CMccJitterBufferImpl::CalculateDelay() const
+    {
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::CalculateDelay:", iCInfo.iPtime * iPacketsInBuffer )
+
+    return iCInfo.iPtime * iPacketsInBuffer;
+    }        
+        
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::AddDataFrameL
+// Adds a audio frame into the jitterbuffer passed in the aDataBuffer
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBufferImpl::AddDataFrameL( CMMFBuffer* aDataBuffer )
+    {
+    User::LeaveIfNull( aDataBuffer );
+    const TInt64 seqNum = aDataBuffer->FrameNumber();
+    iFramesReceived++;
+    
+    const TInt num( FindLargestSeqNum() );
+    
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::AddDataFrameL FRAM_SEQNUM:", seqNum )
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::AddDataFrameL LAST_SEQNUM:", iLastGetSeqNum )
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::AddDataFrameL PACKETS:", iPacketsInBuffer )
+    
+    const CMMFDataBuffer* dataBuffer( static_cast<CMMFDataBuffer*>( aDataBuffer ) );
+    
+    if( seqNum > iLastGetSeqNum )
+        {
+        iNumOfSequentialLateFrames = 0;
+        if( IsFull() )
+            {
+            __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::AddDataFrameL OFLOW dropnext: ",
+                iDropNextFrame );
+            
+            iFramesRemoved++;
+			iOverflowCounter++;
+			if ( iObserver && iOverflowCounter > KOverflowAlarmLimit )
+                {
+	            __JITTER_BUFFER( "CMccJitterBufferImpl::AddDataFrameL OFLOW reported" )
+	            
+                iOverflowCounter = 0;
+                iObserver->JitterBufferError( MJitterBufferObserver::EBufferOverflow );
+                ResetBuffer( ETrue, EFalse );
+                
+                // Do not inform resource unavailability several times. Once playback
+                // is ok again, resource unavailability can be informed if it occurs.
+                SendStreamEventToClient( KMccResourceNotAvailable, ETrue );
+                iNotifyUser = EFalse;
+                }
+            
+            // Check that we actually have packets to remove from the buffer.
+            if ( !iDropNextFrame && iPacketsInBuffer )
+                {
+                // Remove the newest frame in the buffer
+                (void) iBuffer[ iPacketsInBuffer - 1 ].iSequenceNumber;
+                iBuffer[ iPacketsInBuffer - 1 ].iSequenceNumber = -1;
+                iBuffer[ iPacketsInBuffer - 1 ].iStamp = -1;
+                iPacketsInBuffer--;
+                
+                iDropNextFrame = ETrue;
+                }
+            else
+                {
+                iDropNextFrame = EFalse;
+                }
+            
+            // If we dropped this frame, then return from here.
+            if ( !iDropNextFrame )
+                {
+                return;
+                }
+            }
+        else if( IsEmpty() )
+            {
+            // Buffering
+            HandleNotifications( ETrue );
+            
+    		TTimeIntervalSeconds interval;
+    		TTime currentTime;
+    		currentTime.UniversalTime();
+            currentTime.SecondsFrom( iTonePlayTime, interval );
+            
+            if( iPlay && interval.Int() >= iPlayToneInterval )
+                {    
+                __JITTER_BUFFER( "CMccJitterBufferImpl::AddDataFrameL tone to be played" )                
+    			iTonePlayTime.UniversalTime();
+                iPlay = EFalse;
+                }
+            
+            const TInt64 nextGetSeqNum( iLastGetSeqNum + iSeqNumIncrement );
+            if( seqNum > nextGetSeqNum )
+                {
+                // We are empty and there is frames missing between last get frame
+                // and frame sequence number. This might be because of DTX period
+                // so we need to adjust to the situation
+                iLastGetSeqNum = seqNum - iSeqNumIncrement;
+                
+                __JITTER_BUFFER( "CMccJitterBufferImpl::AddDataFrameL MISSING & EMPTY" )
+                __JITTER_BUFFER_INT2( "CMccJitterBufferImpl::AddDataFrameL ADJ_LAST:", iLastGetSeqNum,
+                                      " FRM_SEQ:", seqNum )
+                }
+            }
+        else
+            {
+            __JITTER_BUFFER( "CMccJitterBufferImpl::AddDataFrameL NORMAL" )
+            
+			iOverflowCounter = 0;
+            }
+        
+        // Reset inactivity timing. NB. all branches need to reset inactivity
+        // and insert the new element.
+        iInactivityTime = 0;
+        InsertBufferElement( dataBuffer->Data(), num, seqNum );
+        }
+    else
+        {
+        iNumOfLateFrames++;
+        if(++iNumOfSequentialLateFrames > KSequentialLateFramesLimit )
+             iLastGetSeqNum = -1;
+        
+        __JITTER_BUFFER( "CMccJitterBufferImpl::AddDataFrameL TOO LATE" )
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::GetDataFrameL
+// Get DataFrame
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBufferImpl::GetDataFrameL( CMMFBuffer* aBuffer )
+    {
+    User::LeaveIfNull( aBuffer );
+    CMMFDataBuffer& dataBuffer = static_cast<CMMFDataBuffer&>( *aBuffer );
+    TDes8& playBuffer( dataBuffer.Data() );
+    iFramesPlayed++;
+    
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::GetDataFrameL PACKETS:", iPacketsInBuffer )
+    
+    if( IsEmpty() )
+        {
+        // Buffer is empty, so we need to generate CN frames. During DTX period
+        // this is where we'll end up. If we are empty because of DTX period,
+        // the CN generator will do the error concealment.
+        iCnGenerator->GenerateSidPacket( playBuffer, dataBuffer.RequestSize() );
+        iCurrentPlayThreshold = iOriginalPlayThreshold;
+        
+        // Used for talkburst, if talkburst over, reset buffer and sequence numbers
+        if( iCInfo.iJitterBufInactivityTimeOut > 0 && iInactivityTime >= 0 )
+            {
+            iInactivityTime = iInactivityTime + iFrameTime;
+            if( iInactivityTime >= (TInt) iCInfo.iJitterBufInactivityTimeOut )
+                {
+                __JITTER_BUFFER_INT2("CMccJitterBufferImpl::Inactivity timeout:",
+                                     iCInfo.iJitterBufInactivityTimeOut,
+                                     " time:", iInactivityTime )
+                
+                iInactivityTime = -1;
+                ResetBuffer();
+                }
+            }
+        }
+    else 
+        {
+        // This is where we buffer some data before starting the playout so we can
+        // take some jitter by nature without adaptation.
+        if( iPacketsInBuffer < iCurrentPlayThreshold )
+            {
+            // Give comfort noise when we are buffering for playback start
+            __JITTER_BUFFER( "CMccJitterBufferImpl::GetDataFrameL THRESHOLD NOT REACHED" )
+            __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::GetDataFrameL iCurrentPlayThreshold",
+                iCurrentPlayThreshold )
+            
+            iCnGenerator->GenerateSidPacket(
+                playBuffer, dataBuffer.RequestSize() );
+            }
+        else
+            {
+            // Not buffering
+            HandleNotifications( EFalse );
+            
+            // Set the playout threshold to zero so we play the current talkspurt to the
+            // end and do not affect the speech quality. This means that we will play the
+            // buffer until it is empty. After that it is either DTX period or it is packet
+            // loss.
+            iCurrentPlayThreshold = 0;
+            
+            // Next sequence number that should be in the buffer
+            TInt64 nextSeqNum = iLastGetSeqNum + iSeqNumIncrement;
+            if( -1 == iLastGetSeqNum )
+                {
+                // Last get sequence number was -1, so add one
+                __JITTER_BUFFER( "CMccJitterBufferImpl::GetDataFrameL LAST WAS -1 ADJUSTING" )
+
+                nextSeqNum += 1;
+                }
+                
+            // The actual sequence number which is in the buffer
+            const TInt64 nextFrameSeqNum(
+                iBuffer[ iPacketsInBuffer - 1 ].iSequenceNumber );
+            
+            __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::GetDataFrameL NEXT_GET_SEQ_NUM:", nextSeqNum )
+            __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::GetDataFrameL FRAME_SEQ_NUM:", nextFrameSeqNum )
+            __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::GetDataFrameL PACKETS:", iPacketsInBuffer )
+            __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::GetDataFrameL LAST_GET_SEQ_NUM:", iLastGetSeqNum )
+            
+            // Check if the next sequence number is smaller than the frame number of the next
+            // frame to be played out. This will mean that a frame was lost and we need to do
+            // error concealment. 
+            // Also we need to take account the start of the playout when iLastGetSeqNum == -1 
+            // so we play the first frame in the buffer regardless of it's sequence number.
+            // This should also take the sequence number wrap around situation.
+            
+            // As if(0) is intentional, PC-lint warning disabled:
+            /*lint -e506 */
+            //if ( nextSeqNum < nextFrameSeqNum )
+            if ( 0 )
+                {
+                __JITTER_BUFFER( "CMccJitterBufferImpl::GetDataFrameL LOST FRAME" )
+
+                iFramesLost++;
+                iLastGetSeqNum = iLastGetSeqNum + iSeqNumIncrement;
+                
+                __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::GetDataFrameL 1. LAST_GET_SEQ_NUM IS NOW:", iLastGetSeqNum )
+                
+                iCnGenerator->GenerateSidPacket( playBuffer,
+                    dataBuffer.RequestSize() );
+                }
+            else
+                {
+                __JITTER_BUFFER( "CMccJitterBufferImpl::GetDataFrameL NORMAL" )
+                
+                TJitterBufferElement& bufferElement = iBuffer[ iPacketsInBuffer - 1 ];
+                if ( playBuffer.MaxLength() >= bufferElement.iDataFrame->Data().Length() )
+                    {
+                    playBuffer.Copy( bufferElement.iDataFrame->Data() );
+                    }
+                else
+                    {
+                    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::GetDataFrameL ERROR - output buffer too small, maxlen:", 
+                                          playBuffer.MaxLength() )
+
+                    iCnGenerator->GenerateSidPacket( playBuffer, dataBuffer.RequestSize() );
+                    }
+                
+                iLastGetSeqNum = bufferElement.iSequenceNumber;
+                bufferElement.iSequenceNumber = -1;
+                bufferElement.iStamp = -1;
+                iPacketsInBuffer--;
+                iInactivityTime = -1;
+                
+                // Lets see if the new buffer will lead into a DTX period
+                iCnGenerator->DoDtxDecision( playBuffer );
+                }
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::FindLargestSeqNum
+// Find Largest SequenceNumber
+// -----------------------------------------------------------------------------
+//
+TInt CMccJitterBufferImpl::FindLargestSeqNum() const
+    {
+    TInt64 num = 0;
+    TInt pos = 0;
+    const TInt len( BufferLength() );
+    
+    for( TInt i = 0; i < len; i++ )
+        {
+        if( iBuffer[i].iSequenceNumber > num ) 
+            {
+            num = iBuffer[i].iSequenceNumber;
+            pos = i;
+            }
+        }
+
+    return pos;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::InsertBufferElement
+// Insert Buffer Element
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBufferImpl::InsertBufferElement( const TDesC8& aBuffer, 
+    TInt64 aLargestSeqNum, TInt64 aFrameNumber )
+    {
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::InsertBufferElement aFrameNumber:",
+        aFrameNumber )
+    
+    if ( !aBuffer.Length() || aBuffer.Length() > iFrameSize )
+        {
+        __JITTER_BUFFER( "CMccJitterBufferImpl::InsertBufferElement INVALID DATA, IGNORING" )
+        return;
+        }
+    
+    const TInt len( this->BufferLength() );
+    iBuffer[len-1].iDataFrame->Data().Copy( aBuffer );
+    iBuffer[len-1].iSequenceNumber = aFrameNumber;
+    
+    if ( IsSeqNumWrappedAround( iBuffer[aLargestSeqNum].iSequenceNumber, aFrameNumber ) )
+        {
+        for ( TInt i = 0; i < len; i++ )
+            {
+            if( iBuffer[i].iStamp > aLargestSeqNum ) 
+                {
+                aLargestSeqNum = iBuffer[i].iStamp;
+                }
+            }
+        
+        iBuffer[len-1].iStamp = aLargestSeqNum + 1;
+        iBuffer.Sort( iBufStampSorter );
+        iLastGetSeqNum = -1;
+        }
+    else 
+        {
+        iBuffer[len-1].iStamp = aFrameNumber - BufferLength();
+        iBuffer.Sort( iBufSequenceSorter );
+        }
+    
+    iPacketsInBuffer++;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::BufferLength()
+// Return bufferlength.
+// -----------------------------------------------------------------------------
+//
+TInt CMccJitterBufferImpl::BufferLength() const
+    {
+    return iBuffer.Count();
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::IsFull()
+// Return:    True if full
+//            False if not full
+// -----------------------------------------------------------------------------
+//
+TBool CMccJitterBufferImpl::IsFull() const
+    {
+    return ( iPacketsInBuffer == BufferLength() );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::IsEmpty()
+// Return:    True if empty
+//            False if not empty
+// -----------------------------------------------------------------------------
+//
+TBool CMccJitterBufferImpl::IsEmpty() const
+    {
+    return ( iPacketsInBuffer == 0 );    
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::IsSeqNumWrappedAround
+// Checks if sequence number wrapped around from aSeqNum1 to aSeqNum2
+// The sequence number wrap-around condition cannot be reliably detected by 
+// checking for exact numbers, i.e., aSeqNum1==KMaxSeqNumber and aSeqNum2==0, 
+// because, due to packet losses in network, sequence numbers may have gaps 
+// between them.
+// -----------------------------------------------------------------------------
+//
+TBool CMccJitterBufferImpl::IsSeqNumWrappedAround( TInt64 aSeqNum1, 
+    TInt64 aSeqNum2 ) const
+    {
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::IsSeqNumWrappedAround aSeqNum1:", aSeqNum1 )
+    __JITTER_BUFFER_INT1( "CMccJitterBufferImpl::IsSeqNumWrappedAround aSeqNum2:", aSeqNum2 )
+    
+    if ( aSeqNum1 > ( KMaxSeqNumber - BufferLength() ) && 
+         aSeqNum2 < BufferLength() )
+        {
+        __JITTER_BUFFER( "CMccJitterBufferImpl::IsSeqNumWrappedAround ETrue" )
+        return ETrue;
+        }
+    else
+        {
+        __JITTER_BUFFER( "CMccJitterBufferImpl::IsSeqNumWrappedAround EFalse" )
+        return EFalse;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::GenerateStatistics
+// Generates the statistics from the jitterbuffer
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBufferImpl::GenerateStatistics( TMccJitterBufferEventData& aEvent ) const
+    {
+    aEvent.iFramesReceived = iFramesReceived;
+    aEvent.iBufferLength = BufferLength();
+    aEvent.iFramesInBuffer = iPacketsInBuffer;
+    aEvent.iFrameLoss = iFramesLost;
+    aEvent.iLateFrames = iNumOfLateFrames;
+    aEvent.iFramesRemoved = iFramesRemoved;
+    aEvent.iFramesPlayed = iFramesPlayed;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::HandleNotifications
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBufferImpl::HandleNotifications( TBool aBuffering )
+    {
+    if ( aBuffering )
+        {
+        if ( BufferState() < EPlaying )
+            {
+            __JITTER_BUFFER( "CMccJitterBufferImpl::HandleNotifications, to buffering state" )
+            
+            SetBufferState( EBuffering );
+            SendStreamEventToClient( KMccStreamBuffering, ETrue );
+            }
+        }
+    else
+        {
+        if ( BufferState() >= EBuffering )
+            {
+            // Do not notify about streaming until we know that speaker
+            // is really playing provided data. This cannot be known when
+            // first buffer is sent to speaker.
+            if ( BufferState() == EDetermining )
+                {
+                __JITTER_BUFFER( "CMccJitterBufferImpl::HandleNotifications, to playing state" )
+
+                SetBufferState( EPlaying );
+                iNotifyUser = ETrue;
+                
+                // As we are hiding buffer state changes when doing several
+                // speaker starting attempts in row:
+                // idle->buffering->streaming->idle->noresources->(buffering)->
+                // (streaming)->(idle)->(noresources)->(buffering)-> etc.
+                // We have to "fake" the buffering event when we are
+                // sure that playback is fine.
+                if ( KMccStreamBuffering != iLatestNotifiedEvent )
+                    {
+                    SendStreamEventToClient( KMccStreamBuffering, ETrue );
+                    }
+                
+                SendStreamEventToClient( KMccStreamPlaying, ETrue );
+                }
+            else
+                {
+                SetBufferState( EDetermining );
+                }
+            }
+        }
+    }
+  
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::CheckThresholdBufferLength
+// -----------------------------------------------------------------------------
+//  
+void CMccJitterBufferImpl::CheckThresholdBufferLength(
+    TInt& aBufferLength, TInt aTreshhold ) const
+    {
+    const TInt numTen = 10;
+    if ( ( aBufferLength - aTreshhold ) < numTen )  
+        {
+        aBufferLength = aTreshhold + numTen;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::SendStreamEventToClient
+// -----------------------------------------------------------------------------
+//	
+void CMccJitterBufferImpl::SendStreamEventToClient( 
+    TMccEventType aEventType,
+    TBool aAllEndpoints )
+    {
+    __JITTER_BUFFER( "CMccJitterBufferImpl::SendStreamEventToClient" )
+    
+    if ( iEventHandler && iNotifyUser )
+	    {
+	    const TUint32 endpointId = aAllEndpoints ? 0 : iEndpointId;
+	    // Clear old event
+	    { 
+	    iMccEvent = TMccEvent();
+	    }
+	    
+	    iMccEvent.iEndpointId = endpointId;
+	    iMccEvent.iEventCategory = KMccEventCategoryStream;
+	    iMccEvent.iEventType = aEventType;
+
+		TMccInternalEvent internalEvent( KMccJitterBufferUid, 
+		                                 EMccInternalEventNone,
+		                                 iMccEvent );
+		                         
+		iEventHandler->SendEventToClient( internalEvent );
+		iLatestNotifiedEvent = aEventType;
+	    }
+	else
+		{
+		__JITTER_BUFFER( "CMccJitterBufferImpl::SendStreamEventToClient, sending ignored" )
+		}
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::SetBufferState
+// -----------------------------------------------------------------------------
+//		
+void CMccJitterBufferImpl::SetBufferState( TMccJitterBufferImplState aState )
+    {
+    iBufferState = aState;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBufferImpl::BufferState
+// -----------------------------------------------------------------------------
+//   
+CMccJitterBufferImpl::TMccJitterBufferImplState 
+    CMccJitterBufferImpl::BufferState() const
+    {
+    return iBufferState;
+    }
+        
+// ========================== OTHER EXPORTED FUNCTIONS =========================
+
+//  End of File 
+