multimediacommscontroller/mmccilbcpayloadformat/src/ilbcpayloadformatwrite.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccilbcpayloadformat/src/ilbcpayloadformatwrite.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,785 @@
+/*
+* 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:    Payload format component capable to write RTP payload
+*                containing ILBC audio.
+*
+*/
+
+
+
+
+// INCLUDE FILES
+#include    "ilbcpayloadformatwrite.h"
+#include    "mccrtpdatasink.h"
+#include    "ilbcpayloadformatutil.h"
+#include    "mccuids.hrh"
+#include    "mccdef.h"
+#include    "mccinternaldef.h"
+#include    "mccrtpmediaclock.h" 
+#include    "mccredpayloadwrite.h"
+
+// MACROS
+#ifdef _DEBUG
+#define TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+#endif
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::CIlbcPayloadFormatWrite
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CIlbcPayloadFormatWrite::CIlbcPayloadFormatWrite()
+    {
+    
+    };
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CIlbcPayloadFormatWrite::ConstructL( MDataSink* aSink )
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print( _L("CIlbcPayloadFormatWrite::ConstructL") );
+    #endif
+    
+    __ASSERT_ALWAYS( aSink, User::Leave( KErrArgument ) );
+    
+    // Set default values
+    iFramesPerPacket = 1;
+    iFourCC.Set( KMccFourCCIdILBC );
+
+    // Set data sink
+    iIsRtpSink = ( KMccRtpSinkUid  == aSink->DataSinkType() );
+    TBool isRedEncoder 
+        = ( TUid::Uid( KImplUidRedPayloadFormatEncode ) == aSink->DataSinkType() );
+    
+    if ( iIsRtpSink )
+        {
+        CMccRtpDataSink* tmp = static_cast<CMccRtpDataSink*>( aSink );
+        iRtpDataSink = static_cast<MMccRtpDataSink*>( tmp );
+        }
+    else if ( isRedEncoder )
+        {
+        CMccRedPayloadWrite* tmp = static_cast<CMccRedPayloadWrite*>( aSink );
+        iRtpDataSink = static_cast<MMccRtpDataSink*>( tmp );
+        iIsRtpSink = ETrue;
+        }
+    else
+        {
+        #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+            RDebug::Print( _L("CG711PayloadFormatWrite::ConstructL, sink not RTP one") );
+        #endif
+        }
+    
+    iClip = aSink;
+
+    // Initialize state machine
+    iStateMachine = CFormatEncodeStateMachine::NewL( this );
+    iStateMachine->ChangeState( EEncodeIdle );
+    };
+        
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CIlbcPayloadFormatWrite* CIlbcPayloadFormatWrite::NewL( MDataSink* aSink )
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print( _L("CIlbcPayloadFormatWrite::NewL") );
+    #endif
+
+    __ASSERT_ALWAYS( aSink, User::Leave( KErrArgument ) );
+    
+    CIlbcPayloadFormatWrite* self = new ( ELeave ) CIlbcPayloadFormatWrite();
+    CleanupStack::PushL( self );
+    self->ConstructL ( aSink );
+    CleanupStack::Pop( self );
+    return self;
+    };
+
+// Destructor
+CIlbcPayloadFormatWrite::~CIlbcPayloadFormatWrite()
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print( _L("CIlbcPayloadFormatWrite::~CIlbcPayloadFormatWrite") );
+    #endif
+
+    if ( iStateMachine )
+        {
+        iStateMachine->Cancel();
+        }
+
+    // Media clock is not owned
+    if ( iRtpMediaClock )
+        {
+        iRtpMediaClock->UnregisterMediaFormat( iKey );
+        }
+    
+    delete iSourceBuffer;
+    delete iSinkBuffer;
+    delete iStateMachine;
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::SinkThreadLogon
+// Passes the logon command to the sink clip
+// -----------------------------------------------------------------------------
+//
+TInt CIlbcPayloadFormatWrite::SinkThreadLogon( 
+    MAsyncEventHandler& aEventHandler )
+    {
+    iClip->SinkThreadLogon( aEventHandler );
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::SinkThreadLogoff
+// Passes the logoff command to the sink clip
+// -----------------------------------------------------------------------------
+//
+void CIlbcPayloadFormatWrite::SinkThreadLogoff()
+    {
+    iClip->SinkThreadLogoff();
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::CreateSinkBufferL
+// Create a sink buffer
+// -----------------------------------------------------------------------------
+//
+CMMFBuffer* CIlbcPayloadFormatWrite::CreateSinkBufferL( TMediaId aMediaId, 
+        TBool &aReference )
+    {
+    if ( KUidMediaTypeAudio != aMediaId.iMediaType )
+        {
+        #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+            RDebug::Print (_L ("CIlbcPayloadFormatWrite::CreateSinkBufferL KErrNotSupported"));
+        #endif
+        
+        User::Leave( KErrNotSupported );
+        return NULL;
+        }
+    else
+        {
+        aReference = ETrue;
+        
+        // Create buffer for data transfer between UL datapth and FormatWrite.
+        // 30ms mode buffers can be used also for 20ms mode.
+        if ( KiLBCBitrateWith30ms == iCInfo.iBitrate ||
+             KiLBCBitrateWith20ms == iCInfo.iBitrate )
+            {
+            return CreateSinkBufferOfSizeL( 
+                    KiLBCNumOfHeaderBytes + KiLBCFrameSize30ms );
+            }
+        else
+            {
+            #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+                RDebug::Print (_L ("CIlbcPayloadFormatWrite::CreateSinkBufferL KErrNotReady"));
+            #endif
+        
+            User::Leave( KErrNotReady );
+            return NULL;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::CreateSinkBufferOfSizeL
+// Create a sink buffer of the given size.
+// -----------------------------------------------------------------------------
+//
+CMMFDataBuffer* CIlbcPayloadFormatWrite::CreateSinkBufferOfSizeL( TUint aSize )
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print( _L("CIlbcPayloadFormatWrite::CreateSinkBufferOfSizeL") );
+    #endif
+    
+    // Needs to create source buffer
+    if ( !iSourceBuffer )
+	    {  
+	    iSourceBuffer = CMMFDataBuffer::NewL( aSize );
+    	iSourceBuffer->Data().FillZ( aSize );
+    	iSourceBuffer->SetRequestSizeL( aSize );
+	    }
+	    
+    return iSourceBuffer;
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::EmptyBufferL
+// Empty the given source buffer
+// -----------------------------------------------------------------------------
+//
+void CIlbcPayloadFormatWrite::EmptyBufferL( CMMFBuffer* aBuffer, 
+        MDataSource* aSupplier, TMediaId aMediaId )
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print( _L("CIlbcPayloadFormatWrite::EmptyBufferL aBuffer = 0x%x"),
+            aBuffer );
+    #endif
+    
+    __ASSERT_ALWAYS( aBuffer, User::Leave( KErrArgument ) );
+    __ASSERT_ALWAYS ( aBuffer == iSourceBuffer, User::Leave( KErrArgument ) );
+    __ASSERT_ALWAYS( aSupplier, User::Leave( KErrArgument ) );
+    __ASSERT_ALWAYS( KUidMediaTypeAudio == aMediaId.iMediaType,
+        User::Leave( KErrNotSupported ) );
+    
+    // Save source buffer parameters and change the state.
+    iDataPath = aSupplier;
+    iMediaId = aMediaId;
+    iSourceBuffer = static_cast<CMMFDataBuffer*>( aBuffer );
+    
+    if ( !iSinkBuffer )
+        {
+        #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+            RDebug::Print( _L("CIlbcPayloadFormatWrite::EmptyBufferL, sink not ready!") );
+        #endif
+        iStateMachine->ChangeState( ESourceBufferEmptied );
+        return;
+        }
+    
+    TUint32 ts = 0;
+    User::LeaveIfError( iRtpMediaClock->GetTimeStamp( iKey, ts ) );
+
+    if ( iRtpMediaClock->TimeBasedIncrement() )
+    	{
+    	iFirstPacketFinished = EFalse;
+    	}
+    
+    if ( 0 == iFrameIndex )
+        {
+        #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+            RDebug::Print( _L("CIlbcPayloadFormatWrite::EmptyBufferL, SetTimeToPlay") );
+        #endif
+        
+        iSinkBuffer->SetTimeToPlay( TInt64( ts ) );
+        iSinkBuffer->SetFrameNumber( aBuffer->FrameNumber() );
+        }
+    else
+        {
+        iSourceBuffer->SetTimeToPlay( TInt64( ts ) );
+        }
+    
+    iStateMachine->ChangeState( EEmptySourceBuffer );
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::SetSinkDataTypeCode
+// Set the sink data type to the given four CC code for the given media
+// -----------------------------------------------------------------------------
+//
+TInt CIlbcPayloadFormatWrite::SetSinkDataTypeCode( TFourCC aSinkFourCC, 
+    TMediaId aMediaId )
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print (_L ("CIlbcPayloadFormatWrite::SetSinkDataTypeCode()"));
+    #endif
+
+    if ( KUidMediaTypeAudio != aMediaId.iMediaType ) 
+        {
+        return KErrNotSupported;
+        }
+    
+    iFourCC = aSinkFourCC;
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::SinkDataTypeCode
+// Return the sink data type (four CC code) for the given media
+// -----------------------------------------------------------------------------
+//
+TFourCC CIlbcPayloadFormatWrite::SinkDataTypeCode( TMediaId aMediaId )
+    {
+    if ( KUidMediaTypeAudio == aMediaId.iMediaType )
+        {
+        return iFourCC;
+        }
+    else
+        {
+        return TFourCC(); //defaults to 'NULL' fourCC
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::BufferEmptiedL
+// Called after payload buffer is completely emptied by RtpDataSink.
+// -----------------------------------------------------------------------------
+//
+void CIlbcPayloadFormatWrite::BufferEmptiedL( CMMFBuffer* /*aBuffer*/ )
+    {
+    
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::NumChannels
+// Returns number of channels
+// -----------------------------------------------------------------------------
+//
+TUint CIlbcPayloadFormatWrite::NumChannels()
+    {
+    return KMono;
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::SampleRate
+// Returns SampleRate
+// -----------------------------------------------------------------------------
+//
+TUint CIlbcPayloadFormatWrite::SampleRate()
+    {
+    return KiLBCSampleRate;
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::SetSampleRate
+// Set SampleRate
+// -----------------------------------------------------------------------------
+//
+TInt CIlbcPayloadFormatWrite::SetSampleRate( TUint aSampleRate )
+    {
+    return ( KiLBCSampleRate == aSampleRate ) ? KErrNone : KErrNotSupported;
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::FrameTimeInterval
+// Return the frame time interval for the given media
+// -----------------------------------------------------------------------------
+//
+TTimeIntervalMicroSeconds CIlbcPayloadFormatWrite::FrameTimeInterval(
+    TMediaId aMediaId ) const
+    {
+    if ( KUidMediaTypeAudio == aMediaId.iMediaType )
+        {
+        return iFrameTimeInterval;
+        }
+    else
+        {
+        return TTimeIntervalMicroSeconds( TInt64( 0 ) );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::Duration
+// Return the frame time interval for the given media
+// -----------------------------------------------------------------------------
+//
+TTimeIntervalMicroSeconds CIlbcPayloadFormatWrite::Duration(
+    TMediaId /*aMediaType*/) const
+    {
+    return TTimeIntervalMicroSeconds( TInt64( 0 ) );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::EmptySourceBufferL
+// Empty the given sourcebuffer
+// Sourcebuffer is given in iSourceBuffer
+// Called by statemachine
+// -----------------------------------------------------------------------------
+//
+void CIlbcPayloadFormatWrite::EmptySourceBufferL()
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print( _L("CIlbcPayloadFormatWrite::EmptySourceBufferL - SIZE OF SRC BUF: %d"), 
+            iSourceBuffer->Data().Size() );
+    #endif
+
+    TPtrC8 audioFrame( iSourceBuffer->Data().Mid( KiLBCNumOfHeaderBytes ) );
+    TPtrC8 frameHeader = iSourceBuffer->Data().Left( KiLBCNumOfHeaderBytes );
+    TDes8& destDes = iSinkBuffer->Data();
+    
+    if ( audioFrame.Size() > destDes.MaxSize() - destDes.Size() || !frameHeader.Length() )
+        {
+        #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print( _L("CIlbcPayloadFormatWrite::EmptySourceBufferL \
+            AUDIOFRAME DOES NOT FIT TO SINK BUF") );
+        RDebug::Print( _L("%d > %d || !%d"), audioFrame.Size(), destDes.MaxSize()-destDes.Size(),
+            !frameHeader.Length() );
+        #endif
+        }
+    else
+        {
+        if ( KAudioFrameHeaderByte == frameHeader[0] )
+            {
+            #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+                RDebug::Print( _L("CIlbcPayloadFormatWrite::EmptySourceBufferL AUDIO FRAME") );
+            #endif
+            if ( iCNModeON )
+                {
+                iCNModeON = EFalse;
+                iFirstPacketFinished = EFalse;
+                }
+
+            destDes.Append( audioFrame );
+            iFrameIndex++;
+            }
+        else if ( KCNoiseFrameHeaderByte == frameHeader[0] )
+            {
+            #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+                RDebug::Print( _L("CIlbcPayloadFormatWrite::EmptySourceBufferL CNOISE FRAME") );
+            #endif
+            if ( destDes.Size() )
+                {
+                // Send audio frames first
+                DeliverPacketL( *iSinkBuffer );
+                iSinkBuffer->SetTimeToPlay( iSourceBuffer->TimeToPlay() );
+                }
+            
+            iCNModeON = ETrue;
+            destDes.Append( audioFrame );
+
+            // Only one comfort noise frame per RTP packet
+            iFrameIndex = iFramesPerPacket;
+            }
+        else
+            {
+            #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+                RDebug::Print( _L("CIlbcPayloadFormatWrite::EmptySourceBufferL NULL BIT RATE FRAME") );
+            #endif
+            }        
+        }
+    
+    if ( iFrameIndex == iFramesPerPacket )
+        {
+        // Reset variables
+        iFrameIndex = 0;
+        this->DeliverPacketL( *iSinkBuffer );
+        destDes.Zero();
+        }
+
+    iStateMachine->ChangeState( ESourceBufferEmptied );
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::DeliverPacketL
+// Prepare the packet header and deliver the packet to the datasink.
+// -----------------------------------------------------------------------------
+//
+void CIlbcPayloadFormatWrite::DeliverPacketL( CMMFDataBuffer& aPayload )
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print( _L("CIlbcPayloadFormatWrite::DeliverPacketL - TSTAMP: %u"),
+            static_cast<TUint32>( aPayload.TimeToPlay().Int64() ) );
+    #endif
+    
+    if ( !iClip )
+        {
+        #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+            RDebug::Print( _L("CIlbcPayloadFormatWrite::DeliverPacketL - NO DATASINK") );
+        #endif
+        User::Leave( KErrNotReady );
+        }
+    
+    // Construct RTP header.
+    if ( !iFirstPacketFinished && !iCNModeON )
+        {
+        iRtpSendHeader.iMarker = 1;
+        iFirstPacketFinished = ETrue;
+        }
+    else
+        {
+        iRtpSendHeader.iMarker = 0;
+        }
+    
+    if ( !iRtpDataSink )
+        {
+        #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+            RDebug::Print( _L("CIlbcPayloadFormatWrite::DeliverPacketL - NO DATASINK") );
+        #endif
+        User::Leave( KErrNotReady );
+        }
+    
+    iRtpSendHeader.iTimestamp 
+        = static_cast<TUint32>( aPayload.TimeToPlay().Int64() );
+    
+    if ( iCNModeON )
+        {
+        if ( iCInfo.iComfortNoiseGenerationPt != KPayloadTypeUndefined )
+            {
+            iRtpSendHeader.iPayloadType = iCInfo.iComfortNoiseGenerationPt;
+            
+            if ( aPayload.Data().Size() )
+                {
+                if ( iIsRtpSink )
+                    {
+                    iRtpDataSink->EmptyBufferL( &aPayload, this, iMediaId, iRtpSendHeader );
+                    }
+                else
+                    {
+            	    aPayload.SetLastBuffer( iRtpSendHeader.iMarker );
+                    iClip->EmptyBufferL( &aPayload, this, iMediaId );
+                    }
+                }
+            }
+        }
+    else
+        {
+        iRtpSendHeader.iPayloadType = iCInfo.iPayloadType;
+        
+        if ( aPayload.Data().Size() )
+            {
+            if ( iIsRtpSink )
+                {
+                iRtpDataSink->EmptyBufferL( &aPayload, this, iMediaId, iRtpSendHeader );
+                }
+            else
+                {
+        	    aPayload.SetLastBuffer( iRtpSendHeader.iMarker );
+                iClip->EmptyBufferL( &aPayload, this, iMediaId );
+                }
+            }
+
+        }          
+
+    // Reset the payload buffer -- only if previous EmptyBufferL() is a 
+    // synchronous call
+    aPayload.Data().Zero();
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::SourceBufferEmptiedL
+// Handle the event that sourcebuffer has been emptied.
+// Sourcebuffer is given in "iSourceBuffer".
+// Called by the statemachine.
+// -----------------------------------------------------------------------------
+//
+void CIlbcPayloadFormatWrite::SourceBufferEmptiedL()
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print( _L("CIlbcPayloadFormatWrite::SourceBufferEmptiedL") );
+    #endif
+
+    iDataPath->BufferEmptiedL( iSourceBuffer );
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::SinkPrimeL
+// Prime sink
+// -----------------------------------------------------------------------------
+//
+void CIlbcPayloadFormatWrite::SinkPrimeL()
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print (_L ("CIlbcPayloadFormatWrite::SinkPrimeL()"));
+    #endif
+    
+    iClip->SinkPrimeL();
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::SinkPlayL
+// Start playing
+// -----------------------------------------------------------------------------
+//
+void CIlbcPayloadFormatWrite::SinkPlayL()
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print (_L ("CIlbcPayloadFormatWrite::SinkPlayL()"));
+    #endif
+    
+    // Allocate buffer for data transfer between 
+    // FormatWrite - MDataSink AND FormatWrite - redundancy payload encoder
+    delete iSinkBuffer;
+    iSinkBuffer = NULL;
+    iSinkBuffer = CMMFDataBuffer::NewL( iCInfo.iFrameSize * iFramesPerPacket );
+    
+    // Start state machine
+    iStateMachine->ChangeState( EEncodeIdle );
+    // RTP Header marker-bit must be set to 1 when starting stream
+    iFirstPacketFinished = EFalse;
+    
+    // Start a new cycle of frame collecting
+    iFrameIndex = 0;
+    
+    if ( iSinkBuffer )
+        {
+        iSinkBuffer->SetLastBuffer( EFalse );
+        }
+
+    iClip->SinkPlayL();
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::SinkPauseL
+// Pause sink
+// -----------------------------------------------------------------------------
+//
+void CIlbcPayloadFormatWrite::SinkPauseL()
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print( _L("CIlbcPayloadFormatWrite::SinkPauseL") );
+    #endif
+    
+    iStateMachine->Cancel();
+    iStateMachine->ChangeState( EEncodeIdle );
+    
+    iClip->SinkPauseL();
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::SinkStopL
+// Stop sink
+// -----------------------------------------------------------------------------
+//
+void CIlbcPayloadFormatWrite::SinkStopL()
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print( _L("CIlbcPayloadFormatWrite::SinkStopL") );
+    #endif
+    
+    // Stop state machine
+    iStateMachine->Cancel();
+    iStateMachine->ChangeState( EEncodeIdle );
+    iClip->SinkStopL();
+    }
+ 
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::ConfigurePayloadFormatL
+// Configure payload encoding parameters.
+// -----------------------------------------------------------------------------
+//
+void CIlbcPayloadFormatWrite::ConfigurePayloadFormatL( const TDesC8& aConfigParams, 
+    CMccRtpMediaClock& aClock )
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print( _L("CIlbcPayloadFormatWrite::ConfigurePayloadFormatL IN") );
+    #endif    
+    __ASSERT_ALWAYS( aConfigParams.Size() == sizeof( TMccCodecInfo ),
+        User::Leave( KErrArgument ) );
+        
+    iRtpMediaClock = &aClock; 
+    
+    TMccCodecInfoBuffer infoBuffer;
+    infoBuffer.Copy( aConfigParams );
+    
+    if ( !infoBuffer().iIsUpdate )
+        {
+        DoConfigurePayloadFormatL( infoBuffer() );
+        }
+    else
+        {
+        UpdateConfigurationL( infoBuffer() );
+        }  
+    
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+    RDebug::Print( _L("CIlbcPayloadFormatWrite::ConfigurePayloadFormatL OUT") );
+    #endif 
+    }
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::UpdateConfigurationL
+// Update payload encoding parameters
+// -----------------------------------------------------------------------------
+//
+void CIlbcPayloadFormatWrite::UpdateConfigurationL( const TMccCodecInfo& aCodecInfo )
+    {
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+        RDebug::Print( _L("CIlbcPayloadFormatWrite::UpdateConfigurationL") );
+    #endif
+    
+    iCInfo.iPayloadType = aCodecInfo.iPayloadType;
+    
+    if ( iCInfo.iMaxPtime != aCodecInfo.iMaxPtime ||
+         iCInfo.iPtime != aCodecInfo.iPtime ||
+         iCInfo.iHwFrameTime != aCodecInfo.iHwFrameTime ||
+         iCInfo.iBitrate != aCodecInfo.iBitrate ||
+         iCInfo.iComfortNoiseGenerationPt != aCodecInfo.iComfortNoiseGenerationPt )
+        {
+        DoConfigurePayloadFormatL( aCodecInfo );
+        
+        // Allocate buffer for data transfer between 
+        // FormatWrite - MDataSink AND FormatWrite - redundancy payload encoder
+        delete iSinkBuffer;
+        iSinkBuffer = NULL;
+        iSinkBuffer = CMMFDataBuffer::NewL( iCInfo.iFrameSize * iFramesPerPacket );
+        
+        // Start a new cycle of frame collecting
+        iFrameIndex = 0; 
+        }
+
+    #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+    RDebug::Print( _L("CIlbcPayloadFormatWrite::UpdateConfigurationL OUT") );
+    #endif
+    } 
+
+// -----------------------------------------------------------------------------
+// CIlbcPayloadFormatWrite::DoConfigurePayloadFormatL
+// -----------------------------------------------------------------------------
+//   
+void CIlbcPayloadFormatWrite::DoConfigurePayloadFormatL( const TMccCodecInfo& aCodecInfo )
+    {
+    __ASSERT_ALWAYS( aCodecInfo.iHwFrameTime != 0, User::Leave( KErrArgument ) );
+    
+    iCInfo = aCodecInfo;   
+    iKey = iRtpMediaClock->RegisterMediaFormat( KiLBCSampleRate, iCInfo.iHwFrameTime ); 
+
+    if ( KiLBCBitrateWith20ms == iCInfo.iBitrate )
+        {
+        iCInfo.iHwFrameTime = KiLBCFrameTime20ms;
+        // Maximum number of frames in RTP payload
+        iFramesPerPacket = iCInfo.iPtime / iCInfo.iHwFrameTime;
+        iCInfo.iFrameSize = KiLBCFrameSize20ms;
+        iFrameTimeInterval = TInt64( KiLBCFrameTime20ms * TUint8( iFramesPerPacket ) );
+        }
+    else if ( KiLBCBitrateWith30ms == iCInfo.iBitrate )
+        {
+        iCInfo.iHwFrameTime = KiLBCFrameTime30ms;
+        // Maximum number of frames in RTP payload
+        iFramesPerPacket = iCInfo.iPtime / iCInfo.iHwFrameTime;
+        iCInfo.iFrameSize = KiLBCFrameSize30ms;
+        iFrameTimeInterval = TInt64( KiLBCFrameTime30ms * TUint8( iFramesPerPacket ) );
+        }
+    else
+        {
+        #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+            RDebug::Print( _L("CIlbcPayloadFormatWrite::ConfigurePayloadFormatL - BITRATE INVALID: %d"), iCInfo.iBitrate );
+        #endif 
+        User::Leave( KErrArgument );
+        }
+
+    if ( EGenRedUsed == iCInfo.iAlgoUsed )
+        {
+        #ifdef TRACE_ILBC_PAYLOAD_FORMAT_WRITE
+            RDebug::Print( _L("CIlbcPayloadFormatWrite::ConfigurePayloadFormatL, RED LEVEL: %d"), 
+                iCInfo.iRedundancyCount );
+        #endif 
+        
+        CPayloadFormatWrite* redEncoder
+            = static_cast<CMccRedPayloadWrite*>( iClip );
+        
+        TMccRedPayloadWriteConfig config;
+        config.iRedBlockCount = iCInfo.iRedundancyCount;
+        config.iMaxPayloadSize = iCInfo.iFrameSize * iFramesPerPacket;
+        config.iNumOfEncodings = 1;
+        config.iRedPayloadType = iCInfo.iRedundantPayload;
+        config.InitPayloadTypes();
+        config.iEncPayloadTypes[0] = iCInfo.iPayloadType;
+        TMccRedPayloadWritePckg pckg( config );
+        redEncoder->ConfigurePayloadFormatL( pckg, *iRtpMediaClock );
+        }
+    }
+    
+// ========================== OTHER EXPORTED FUNCTIONS =========================
+
+//  End of File