multimediacommscontroller/mmccjitterbuffer/src/mccjitterbuffer.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccjitterbuffer/src/mccjitterbuffer.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,710 @@
+/*
+* Copyright (c) 2004-2008 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:    JitterBuffer component capable to audioframe buffering.
+*
+*/
+
+
+
+
+// INCLUDE FILES
+#include <mmf/server/mmfaudiooutput.h>
+#include "mccjitterbuffer.h"
+#include "mccjitterbufferimpl.h"
+#include "mccinternaldef.h"
+#include "mccinternalevents.h"
+#include "mccjitterbufferlogs.h"
+#include "mccjitterbufferobserver.h"
+
+// LOCAL CONSTANTS
+const TUint KAdaptUpdateIval = 250;
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::CMccJitterBuffer
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CMccJitterBuffer::CMccJitterBuffer( MJitterBufferObserver* aObserver ) :
+    MDataSink( KMccJitterBufferUid ), MDataSource( KMccJitterBufferUid ),
+    iState( EJBufStopped ),
+    iObserver ( aObserver )
+    {
+    
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::NewL
+// Static constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CMccJitterBuffer* CMccJitterBuffer::NewL( MJitterBufferObserver* aObserver )
+    {
+    CMccJitterBuffer* self = new ( ELeave ) CMccJitterBuffer( aObserver );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::~CMccJitterBuffer
+// Destructor deallocate memory.
+// -----------------------------------------------------------------------------
+//
+CMccJitterBuffer::~CMccJitterBuffer()
+    {
+    __JITTER_BUFFER_INT1( "CMccJitterBuffer::~CMccJitterBuffer:", 
+                          reinterpret_cast<TInt>( this ) )
+    __JITTER_BUFFER_INT1( "CMccJitterBuffer::~CMccJitterBuffer iDataSink:", 
+                          reinterpret_cast<TInt>( iDataSink ) )
+    __JITTER_BUFFER_INT1( "CMccJitterBuffer::~CMccJitterBuffer iDataSource:", 
+                          reinterpret_cast<TInt>( iDataSource ) )
+    __JITTER_BUFFER_INT1( "CMccJitterBuffer::~CMccJitterBuffer iSinkBuffer:", 
+                          reinterpret_cast<TInt>( iSinkBuffer ) )
+    __JITTER_BUFFER_INT1( "CMccJitterBuffer::~CMccJitterBuffer iBufferImpl:",
+                          reinterpret_cast<TInt>( iBufferImpl ) )
+    
+    if ( iDataSink )
+        {
+        iDataSink->SinkThreadLogoff();
+        }
+    
+    if ( !iSnkBufRef )
+        {
+        delete iSinkBuffer;
+        }
+    
+    delete iBufferImpl;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::SetupL
+// Setup Jitterbuffer
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMccJitterBuffer::SetupL( TInt /*aBufferSize*/, TInt aPlayThreshold, 
+        const TMccCodecInfo& aCInfo )
+    {
+    __JITTER_BUFFER( "CMccJitterBuffer::SetupL" )
+    
+    __ASSERT_ALWAYS( iDataSink, User::Leave( KErrNotReady ) );
+    
+    if( !iBufferImpl )
+        {
+        iBufferImpl = CMccJitterBufferImpl::NewL( iObserver );
+        }
+        
+    MMMFAudioOutput* output = static_cast<MMMFAudioOutput*>( iDataSink );
+    iBufferImpl->SetupL( aPlayThreshold,
+                         aCInfo,
+                         output->SoundDevice(),
+                         iEventHandler,
+                         MCC_ENDPOINT_ID( iDataSink ) );
+    } 
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::ResetBuffer
+// Reset Jitterbuffer
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMccJitterBuffer::ResetBuffer( TBool aPlayTone )
+    {
+    if ( iBufferImpl )
+        {
+        iBufferImpl->ResetBuffer( aPlayTone );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::DelayDownL
+// Delay Down
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMccJitterBuffer::DelayDownL()
+    {
+    User::LeaveIfNull( iBufferImpl );
+    iBufferImpl->DelayDownL();
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::DelayUpL
+// Delay Up
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMccJitterBuffer::DelayUpL()
+    {
+    User::LeaveIfNull( iBufferImpl );
+    iBufferImpl->DelayUpL();
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::SetSinkDataTypeCode
+// From MDataSink
+// -----------------------------------------------------------------------------
+//
+TInt CMccJitterBuffer::SetSinkDataTypeCode( TFourCC aSinkFourCC, TMediaId aMediaId )
+    {
+    if( KUidMediaTypeAudio == aMediaId.iMediaType )
+        {
+        __JITTER_BUFFER( "CMccJitterBuffer::SetSinkDataTypeCode To iDataSink" )
+        
+        return iDataSink->SetSinkDataTypeCode( aSinkFourCC, aMediaId );
+        }
+    else
+        {
+        __JITTER_BUFFER( "CMccJitterBuffer::SetSinkDataTypeCode NOT SUPPORTED" )
+
+        return KErrNotSupported;
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::SetSourceDataTypeCode
+// 
+// -----------------------------------------------------------------------------
+//
+TInt CMccJitterBuffer::SetSourceDataTypeCode( TFourCC aSourceFourCC, TMediaId aMediaId )
+    {
+    if( KUidMediaTypeAudio == aMediaId.iMediaType )
+        {
+        __JITTER_BUFFER( "CMccJitterBuffer::SetSourceDataTypeCode To iDataSource" )
+        
+        return iDataSource->SetSourceDataTypeCode( aSourceFourCC, aMediaId );
+        }
+    else
+        {
+        __JITTER_BUFFER( "CMccJitterBuffer::SetSourceDataTypeCode NOT SUPPORTED" )
+        
+        return KErrNotSupported;
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::SinkDataTypeCode
+// From MDataSink
+// -----------------------------------------------------------------------------
+//
+TFourCC CMccJitterBuffer::SinkDataTypeCode( TMediaId aMediaId )
+    {
+    if( KUidMediaTypeAudio == aMediaId.iMediaType )
+        {
+        __JITTER_BUFFER( "CMccJitterBuffer::SinkDataTypeCode From iDataSink" )
+
+        return iDataSink->SinkDataTypeCode( aMediaId );
+        }
+    else
+        {    
+        // Default to NULL FourCC
+        __JITTER_BUFFER( "CMccJitterBuffer::SinkDataTypeCode DEFAULT" )
+
+        return TFourCC();
+        }
+    }    
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::SourceDataTypeCode
+// From MDataSource
+// -----------------------------------------------------------------------------
+//
+TFourCC CMccJitterBuffer::SourceDataTypeCode( TMediaId aMediaId )
+    {
+    if( KUidMediaTypeAudio == aMediaId.iMediaType )
+        {
+        __JITTER_BUFFER( "CMccJitterBuffer::SourceDataTypeCode From iDataSource" )
+
+        return iDataSource->SourceDataTypeCode( aMediaId );
+        }
+    else
+        {    
+        // Default to NULL FourCC
+        __JITTER_BUFFER( "CMccJitterBuffer::SourceDataTypeCode DEFAULT" )
+
+        return TFourCC();
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::ConstructSinkL
+// From MDataSink
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBuffer::ConstructSinkL( const TDesC8& /*aInitData*/ )
+    {
+    User::Leave( KErrNotSupported );
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::ConstructSourceL
+// From MDataSource
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBuffer::ConstructSourceL( const TDesC8& /*aInitData*/ )
+    {    
+    User::Leave( KErrNotSupported );
+    }        
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::SinkThreadLogon
+// From MDataSink
+// -----------------------------------------------------------------------------
+//
+TInt CMccJitterBuffer::SinkThreadLogon( MAsyncEventHandler& aEventHandler )
+    {
+    if( !iEventHandler )
+        {
+        if( iDataSink )
+            {
+            __JITTER_BUFFER( "CMccJitterBuffer::SinkThreadLogon NORMAL" )
+            
+            iEventHandler = &aEventHandler;
+            return iDataSink->SinkThreadLogon( aEventHandler );
+            }
+        else
+            {
+            __JITTER_BUFFER( "CMccJitterBuffer::SinkThreadLogon KErrNotReady" )
+
+            return KErrNotReady;
+            }
+        }
+    else
+        {
+        __JITTER_BUFFER( "CMccJitterBuffer::SinkThreadLogon KErrAlreadyExists" )
+
+        return KErrAlreadyExists;
+        }
+    }    
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::SourceThreadLogon
+// From MDataSource
+// -----------------------------------------------------------------------------
+//
+TInt CMccJitterBuffer::SourceThreadLogon( MAsyncEventHandler& /*aEventHandler*/ )
+    {
+    __JITTER_BUFFER( "CMccJitterBuffer::SourceThreadLogon" )
+
+    // Jitter buffer is used always as a datasink, so we do not support any
+    // source threads logging on.
+    return KErrNotSupported;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::SinkThreadLogoff
+// From MDataSink
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBuffer::SinkThreadLogoff()
+    {
+    __JITTER_BUFFER( "CMccJitterBuffer::SinkThreadLogoff in" )
+
+    iEventHandler = NULL;
+        
+    if( iBufferImpl )
+        {
+        delete iBufferImpl;
+        iBufferImpl = NULL;
+        }
+    
+    if( iDataSink )
+        {
+        iDataSink->SinkThreadLogoff();
+        iDataSink = NULL;
+        }
+    
+    if ( !iSnkBufRef )
+        {
+        delete iSinkBuffer;
+        }
+    
+    iSinkBuffer = NULL;
+    
+    __JITTER_BUFFER( "CMccJitterBuffer::SinkThreadLogoff out" )
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::SinkPrimeL
+// 
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBuffer::SinkPrimeL()
+    {
+    __JITTER_BUFFER( "CMccJitterBuffer::SinkPrimeL" )
+
+    iState = EJBufPrimed;
+    this->ResetBuffer();
+    iDataSink->SinkPrimeL();
+    }    
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::SinkPlayL
+// 
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBuffer::SinkPlayL()
+    {
+    __JITTER_BUFFER("CMccJitterBuffer::SinkPlayL iDataSink->SinkPlayL" )
+    
+    iState = EJBufPlaying;
+    iDataSink->SinkPlayL();
+    iSnkBufRef = ETrue; // Sinkbuffer owned by MMF
+    iRequestSize = 0;
+    
+    __JITTER_BUFFER( "CMccJitterBuffer::SinkPlayL CreateSinkBufferL" )
+
+    iSinkBuffer = iDataSink->CreateSinkBufferL( KUidMediaTypeAudio, iSnkBufRef );
+    
+    // If buffer has not been supplied via CreateSinkBufferL, must use 
+    // asynchronous buffer creation
+    if ( !iSinkBuffer )
+        {
+        __JITTER_BUFFER( "CMccJitterBuffer::SinkPlayL EmptyBufferL ASYNC CREATION" )
+
+        iDataSink->EmptyBufferL( iSinkBuffer, this, KUidMediaTypeAudio );
+        }
+    else
+        {
+        //we have a sink buffer from CreateSinkBufferL
+        __JITTER_BUFFER( "CMccJitterBuffer::SinkPlayL EmptyBufferL SYNC CREATION" )
+
+        iSinkBuffer->SetStatus( EAvailable );
+        }
+    
+    iPlayedFrames = 0;        
+    }
+        
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::SinkPauseL
+// 
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBuffer::SinkPauseL()
+    {
+    __JITTER_BUFFER( "CMccJitterBuffer::SinkPauseL" )
+
+    iState = EJBufPaused;
+    ResetBuffer();
+    iDataSink->SinkPauseL();
+    iPlayedFrames = 0;
+    
+    // If sinkbuffer is not a reference then we need to delete it here so that
+    // play - pause - play works. Also devsound creates new buffers when
+    // resuming from Pause through Play.
+    if ( !iSnkBufRef )
+        {
+        delete iSinkBuffer;
+        }
+    
+    iSinkBuffer = NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::SinkStopL
+// 
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBuffer::SinkStopL()
+    {
+    __JITTER_BUFFER( "CMccJitterBuffer::SinkStopL" )
+    
+    iState = EJBufStopped;
+    ResetBuffer();
+    iDataSink->SinkStopL();
+    iPlayedFrames = 0;
+    if ( !iSnkBufRef )
+        {
+        delete iSinkBuffer;
+        }
+    
+    iSinkBuffer = NULL;
+    }
+    
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::CanCreateSinkBuffer
+// From MDataSink
+// -----------------------------------------------------------------------------
+//
+TBool CMccJitterBuffer::CanCreateSinkBuffer()
+    {
+    // CMccJitterBuffer can't create buffers
+    return EFalse;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::CanCreateSourceBuffer
+// From MDataSource
+// -----------------------------------------------------------------------------
+//
+TBool CMccJitterBuffer::CanCreateSourceBuffer()
+    {
+    // CMccJitterBuffer can't create buffers
+    return EFalse;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::CreateSinkBufferL
+// From MDataSink
+// -----------------------------------------------------------------------------
+//
+CMMFBuffer* CMccJitterBuffer::CreateSinkBufferL( TMediaId /*aMediaId*/, 
+        TBool& /*aReference*/ )
+    {
+    // CMccJitterBuffer can't create buffers
+    User::Leave( KErrNotSupported );
+    return NULL;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::CreateSourceBufferL
+// From MDataSource
+// -----------------------------------------------------------------------------
+//
+CMMFBuffer* CMccJitterBuffer::CreateSourceBufferL( TMediaId /*aMediaId*/, 
+        TBool& /*aReference*/ )
+    {
+    // CMccJitterBuffer can't create buffers
+    User::Leave( KErrNotSupported );
+    return NULL;
+    }              
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::FillBufferL
+// From MDataSource
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBuffer::FillBufferL( CMMFBuffer* /*aBuffer*/,
+    MDataSink* /*aConsumer*/, 
+    TMediaId /*aMediaId*/ )
+    {
+    __JITTER_BUFFER( "CMccJitterBuffer::FillBufferL KErrNotSupported" )
+    
+    User::Leave( KErrNotSupported );
+    }
+        
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::EmptyBufferL
+// From MDataSink
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBuffer::EmptyBufferL( CMMFBuffer* aBuffer,
+    MDataSource* aSupplier,
+    TMediaId /*aMediaId*/ )
+    {
+    if( iBufferImpl && ( iState == EJBufPlaying ) )
+        {
+        __ASSERT_ALWAYS( iBufferImpl->BufferLength(), User::Leave( KErrNotReady ) );
+        
+        __JITTER_BUFFER_INT1( "CMccJitterBuffer::EmptyBufferL BUF_SZ:", aBuffer->BufferSize() )
+        __JITTER_BUFFER_INT1( "CMccJitterBuffer::EmptyBufferL REQ_SZ:", aBuffer->RequestSize() )
+        
+        // Adaptation control will be done based on played frames
+        iBufferImpl->AddDataFrameL( aBuffer );
+        aBuffer->SetStatus( EAvailable );
+        }
+        
+    // Inform the source immediately so that packets keep on flowing in
+    if ( aSupplier )
+        {
+        aSupplier->BufferEmptiedL( aBuffer );
+        }
+    }    
+    
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::BufferFilledL
+// 
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBuffer::BufferFilledL( CMMFBuffer* /*aBuffer*/ )
+    {
+    __JITTER_BUFFER( "CMccJitterBuffer::BufferFilledL KErrNotSupported" )
+
+    User::Leave( KErrNotSupported );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::BufferEmptiedL
+// 
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBuffer::BufferEmptiedL( CMMFBuffer* aBuffer )
+    {
+    __JITTER_BUFFER( "CMccJitterBuffer::BufferEmptiedL" )
+    
+    User::LeaveIfNull( aBuffer );
+    iSinkBuffer = aBuffer;
+    iSinkBuffer->SetStatus( EAvailable );
+    
+    if( iBufferImpl && iBufferImpl->BufferLength() )
+        {
+        __JITTER_BUFFER( "CMccJitterBuffer::BufferEmptiedL NORMAL" )
+        
+        // Check for request size changes if current codec happens to support
+        // dynamic codec frame length changes. Currently only needed for
+        // supporting 10/20ms variants of G.711 codec. Also one frame has two
+        // bytes extra for the frameheader, so we remove it here.
+        const TInt reqSize( iSinkBuffer->RequestSize() - KVoIPHeaderLength );
+        if ( reqSize != iRequestSize &&
+             iBufferImpl->CurrentCodec() == KMccFourCCIdG711 )
+            {
+            __JITTER_BUFFER_INT1( "CMccJitterBuffer::BufferEmptiedL reqSize: ", reqSize )
+            __JITTER_BUFFER_INT1( "CMccJitterBuffer::BufferEmptiedL iRequestSize: ", iRequestSize )
+            iRequestSize = reqSize;
+            
+            if ( iObserver )
+                {
+                // We don't do this on emulator as it will kick us in the teeth
+                // later when re-calculating jitterbuffer size.
+                #ifndef __WINSCW__
+                iObserver->DynamicBufferChangeRequest( iRequestSize );
+                #endif
+                }
+            }
+        
+        iBufferImpl->GetDataFrameL( iSinkBuffer );
+        iPlayedFrames++;
+        
+        if( KAdaptUpdateIval == iPlayedFrames )
+            {
+            // Don't care about the error if frames haven't been received yet
+            // because it's sensible to do the adaptation only when there is 
+            // actual data in the buffer
+            iPlayedFrames = 0;
+            SendJitterBufferEventToClient();
+            }
+        
+        iSinkBuffer->SetStatus( EFull );
+        iDataSink->EmptyBufferL( iSinkBuffer, this, KUidMediaTypeAudio );
+        }
+    else
+        {
+        __JITTER_BUFFER( "CMccJitterBuffer::BufferEmptiedL KErrNotReady" )
+        
+        User::Leave( KErrNotReady );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::AddDataSinkL
+// From MDataSource 
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMccJitterBuffer::AddDataSinkL( MDataSink* aSink )
+    {
+    if( iDataSink )
+        {
+        __JITTER_BUFFER( "CMccJitterBuffer::AddDataSinkL KErrAlreadyExists" )
+
+        User::Leave( KErrAlreadyExists );
+        }
+    else
+        {
+        User::LeaveIfNull( aSink );
+        if( KUidMmfAudioOutput == aSink->DataSinkType() )
+            {
+            __JITTER_BUFFER( "CMccJitterBuffer::AddDataSinkL AUDIO SINK" )
+
+            iDataSink = aSink;
+            }
+        else
+            {
+            __JITTER_BUFFER( "CMccJitterBuffer::AddDataSinkL KErrArgument" )
+
+            User::Leave( KErrArgument );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::AddDataSourceL
+// From MDataSource 
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMccJitterBuffer::AddDataSourceL( MDataSource* aSource )
+    {
+    __JITTER_BUFFER( "CMccJitterBuffer::AddDataSourceL" )
+
+    User::LeaveIfNull( aSource );
+    iDataSource = aSource;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::SendJitterBufferEventToClient
+// 
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBuffer::SendJitterBufferEventToClient()
+    {  
+    TMccJitterBufferEventData eventData;
+    iBufferImpl->GenerateStatistics( eventData );
+    
+    if( iEventHandler )
+	    {
+	    TMccEvent event( 0, 
+	                     0, 
+	                     0, 
+	                     MCC_ENDPOINT_ID( iDataSink ), 
+	                     KMccEventCategoryStream, 
+	                     KMccEventNone, 
+	                     KErrNone, 
+	                     KNullDesC8 );
+	                     
+	    event.iEventData.Copy( TMccJitterBufferEventDataPackage( eventData ) );
+	    
+	    TMccInternalEvent internalEvent( KMccJitterBufferUid, 
+	                                     EMccInternalJitterEventStatusReport,
+	                                     event );
+	                                     
+	    iEventHandler->SendEventToClient( internalEvent );	
+	    }
+	else
+		{
+		__JITTER_BUFFER( "CMccJitterBuffer::RunError, iEventHandler=NULL" )	
+		}
+    }
+            
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::GetDataSink
+// Get DataSink
+// -----------------------------------------------------------------------------
+//
+EXPORT_C MDataSink* CMccJitterBuffer::GetDataSink()
+    {
+    return iDataSink;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccJitterBuffer::NegotiateL
+// From MDataSink
+// -----------------------------------------------------------------------------
+//
+void CMccJitterBuffer::NegotiateL( MDataSource& aDataSource )
+    {
+    if( iDataSink )
+        {
+        __JITTER_BUFFER( "CMccJitterBuffer::NegotiateL" )
+
+        iDataSink->NegotiateL( aDataSource );
+        }
+    else
+        {
+        __JITTER_BUFFER( "CMccJitterBuffer::NegotiateL KErrNotReady" )
+
+        User::Leave( KErrNotReady );
+        }
+    }
+
+//  End of File 
+