multimediacommscontroller/mmccamrpayloadformat/src/amrpayloadformatwrite.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccamrpayloadformat/src/amrpayloadformatwrite.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,1094 @@
+/*
+* 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:    Payload format component capable to write RTP payload
+*                containing AMR audio.
+*
+*/
+
+
+
+
+// INCLUDE FILES
+#include <e32base.h>
+#include <mmf/common/mmffourcc.h>
+#include "amrpayloadformatwrite.h"
+#include "amrpayloadencoder.h"
+#include "amrpayloadencoderoa.h"
+#include "amrpayloaddecoder.h"
+#include "amrcommonutil.h"
+#include "mccrtpdatasink.h"
+#include "mccuids.hrh"
+#include "mccdef.h"
+#include "mccinternaldef.h"
+#include "amrpayloadformatter.h"
+#include "mccrtpmediaclock.h" 
+#include "mccredpayloadwrite.h"
+
+const TUint KSampleRate8kHz = 8;
+const TUint KSampleRate16kHz = 16;
+const TReal KTimeMultiplier = 0.001;
+
+// MACROS
+
+#define MCC_AUDIO_TIMESTAMP( a ) \
+TUint32( iFramesPerPacket * a * iChannels * \
+         (iIsNb?KSampleRate8kHz:KSampleRate16kHz) * KTimeMultiplier )
+
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::CAmrPayloadFormatWrite
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CAmrPayloadFormatWrite::CAmrPayloadFormatWrite( )
+    : iIsNb( ETrue ), iSamplingRate( KAmrNbSampleRate ), iChannels( 1 )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadFormatWrite::ConstructL ( MDataSink* aSink )
+    {
+    // Set default values
+    iFramesPerPacket = 1;
+    iFourCC.Set( TFourCC( ' ','A','M','R' ) );
+    
+    // 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
+        {
+        AMR_PAYLOAD_FORMAT_WRITE( "CAmrPayloadFormatWrite::ConstructL, not RTP sink" )
+        }
+    
+    iClip = aSink;
+    
+    // Set default set of modes
+    for ( TInt i = 0; i < KNumberOfNbModes; i++ )
+        {
+        iModes.Append( KAmrNbModes[i] );
+        }
+    
+    // Initialize state machine
+    iStateMachine = CFormatEncodeStateMachine::NewL( this );
+    iStateMachine->ChangeState( EEncodeIdle );
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CAmrPayloadFormatWrite* CAmrPayloadFormatWrite::NewL( MDataSink* aSink )
+    {
+    #ifdef TRACE_AMR_PAYLOAD_FORMAT_WRITE
+        RDebug::Print( _L("CAmrPayloadFormatWrite::NewL") );
+    #endif
+    
+    __ASSERT_ALWAYS( aSink, User::Leave( KErrArgument ) );
+
+    CAmrPayloadFormatWrite* self = new ( ELeave ) CAmrPayloadFormatWrite;
+    CleanupStack::PushL( self );
+    self->ConstructL( aSink );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::~CAmrPayloadFormatWrite
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+CAmrPayloadFormatWrite::~CAmrPayloadFormatWrite ( )
+    {
+    delete iSourceBuffer;
+    delete iSinkBuffer;
+    delete iStateMachine;
+    delete iPayloadEncoder;
+    iModes.Close();
+    
+    // Media clock is not owned
+    if ( iRtpMediaClock )
+        {
+        iRtpMediaClock->UnregisterMediaFormat( iKey );
+        }
+    }
+
+ 
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::FrameTimeInterval
+// Return the frame time interval for the given media
+// -----------------------------------------------------------------------------
+//
+TTimeIntervalMicroSeconds CAmrPayloadFormatWrite::FrameTimeInterval( 
+        TMediaId aMediaId ) const
+    {
+    if ( KUidMediaTypeAudio == aMediaId.iMediaType )
+        {
+        TInt hwFrametime = static_cast<TInt>( iCInfo.iHwFrameTime );
+        return TTimeIntervalMicroSeconds( TInt64( hwFrametime ) );
+        }
+    else
+        {
+        return TTimeIntervalMicroSeconds( TInt64( 0 ) );
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::CreateSinkBufferL
+//
+// Create a source buffer for the given media and indicate in aReference if buffer
+// is created.
+// -----------------------------------------------------------------------------
+//
+CMMFBuffer* CAmrPayloadFormatWrite::CreateSinkBufferL( TMediaId aMediaId, 
+                                                       TBool &aReference )
+    {
+    #ifdef TRACE_AMR_PAYLOAD_FORMAT_WRITE
+        AMR_PAYLOAD_FORMAT_WRITE ( "CAmrPayloadFormatWrite::CreateSinkBufferL( )" );
+    #endif
+
+    if ( KUidMediaTypeAudio != aMediaId.iMediaType )
+        {
+        User::Leave( KErrNotSupported );
+        }
+    // the ownership of iSourceBuffer is in CAmrPayloadFormatWrite
+    aReference = ETrue;
+    return CreateSinkBufferOfSizeL( iCInfo.iFrameSize );
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::SinkDataTypeCode
+// Return the sink data type ( four CC code ) for the given media
+// -----------------------------------------------------------------------------
+//
+TFourCC CAmrPayloadFormatWrite::SinkDataTypeCode( TMediaId aMediaId )
+    {
+    if ( KUidMediaTypeAudio == aMediaId.iMediaType ) 
+        {
+         #ifdef TRACE_AMR_PAYLOAD_FORMAT_WRITE
+        	AMR_PAYLOAD_FORMAT_WRITE2( 
+        		"CAmrPayloadFormatWrite::SinkDataTypeCode: 0x%x", iFourCC.FourCC() );
+        #endif
+        return iFourCC;
+        }
+    else 
+        {
+        return TFourCC( ); //defaults to 'NULL' fourCC
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::SetSinkDataTypeCode
+// Set the sink data type to the given four CC code for the given media
+// -----------------------------------------------------------------------------
+//
+TInt CAmrPayloadFormatWrite::SetSinkDataTypeCode( TFourCC aSinkFourCC, 
+                                                  TMediaId aMediaId )
+    {
+    #ifdef TRACE_AMR_PAYLOAD_FORMAT_WRITE
+        	AMR_PAYLOAD_FORMAT_WRITE2( 
+        		"CAmrPayloadFormatWrite::SetSinkDataTypeCode: 0x%x", 
+        		aSinkFourCC.FourCC() );
+    #endif
+    if ( KUidMediaTypeAudio != aMediaId.iMediaType )
+        {
+        return KErrNotSupported;
+        }
+    else if ( aSinkFourCC == KMccFourCCIdAMRNB )
+        {
+        iFourCC = aSinkFourCC;
+        }
+    else if ( aSinkFourCC == KMccFourCCIdAMRWB )
+        {
+        iFourCC = aSinkFourCC;
+        // Nb modes were set in the construtor. We need to replace them with wb modes.
+        iIsNb = EFalse; 
+        iModes.Reset();
+	    for ( TInt i = 0; i < KNumberOfWbModes; i++ )
+	        {
+	        iModes.Append( KAmrWbModes[i] );
+	        }
+	    SetSampleRate( KAmrWbSampleRate );
+        }
+    else
+        {
+        return KErrNotSupported;
+        }
+
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::SinkThreadLogon
+// Passes the logon command to the sink clip
+// -----------------------------------------------------------------------------
+//
+TInt CAmrPayloadFormatWrite::SinkThreadLogon( MAsyncEventHandler& aEventHandler )
+    {
+    iClip->SinkThreadLogon( aEventHandler );
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::SinkThreadLogoff
+// Log out of the sink thread.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadFormatWrite::SinkThreadLogoff( )
+    {
+    #ifdef TRACE_AMR_PAYLOAD_FORMAT_WRITE
+        AMR_PAYLOAD_FORMAT_WRITE( "CAmrPayloadFormatWrite::SinkThreadLogoff " );
+    #endif   
+    
+    iClip->SinkThreadLogoff( );
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::ProcessFramesL
+// Packetize the AMR frames received from AMR codec and deliver the packets.
+// The AMR frames are stored in "iSourceBuffer".
+// return value - Current talk spurt finished, ETrue. Otherwise, EFalse.
+// -----------------------------------------------------------------------------
+//
+TBool CAmrPayloadFormatWrite::ProcessFramesL()
+    {
+    #ifdef TRACE_AMR_PAYLOAD_FORMAT_WRITE
+        AMR_PAYLOAD_FORMAT_WRITE ( "CAmrPayloadFormatWrite::ProcessFramesL( ) Begin" );
+    #endif
+
+    TBool payloadReady( EFalse );
+    TBool isDone( EFalse );
+    TAmrFrameInfo frameInfo;
+
+    CMMFBuffer* buffer = iSourceBuffer;
+    TDes8& srcDes = ( static_cast<CMMFDataBuffer*>( buffer )->Data() );
+    TInt readLen = srcDes.Length();
+    TInt byteIndex = 0;
+    TInt seekLen = readLen - byteIndex;
+
+    const TUint8* seekPtr = srcDes.Ptr() + byteIndex;
+
+    while ( seekLen >= CAmrCommonUtility::FrameHeaderSize() )
+        {
+        // Scan frame by frame until free format frame or EOB detected.
+        TInt length = CAmrCommonUtility::FrameInfo( seekPtr, seekLen, frameInfo, iIsNb );
+        if ( length > 0 && frameInfo.iBitrate > 0 ) // got a frame
+            {
+            TStreamDecoder decoder;
+            decoder.Initialize( seekPtr, 0, 0 );
+            decoder.Decode( 1 );                              // Skip first Padding bit
+            TInt frameType( decoder.Decode( KNumValue4 ) ); // FT value
+            TUint8 qualityInd = TUint8( decoder.Decode( 1 ) );// QualityInd value
+
+            // Encode a frame, speech data starts from the second byte in a frame
+            TPtr8 dataPtr( const_cast<TUint8*>( seekPtr+1 ), seekLen - 1, seekLen - 1 );
+            
+            #ifdef TRACE_AMR_PAYLOAD_FORMAT_WRITE
+                RDebug::Print( _L("CAmrPayloadFormatWrite::ProcessFramesL frameType: %d"), frameType );
+            #endif
+            
+            // frameType 8 (SID) or 15 (NO_DATA) tells us that we can set the 
+            // CMR to NO_REQUEST, otherwise we can keep the CMR in which ever
+            // the frameType is as they map directly to each other.
+            // NOTE: There is no clear information on how to set the CMR field
+            // regarding SID or NO_DATA frames. So there might be a possibility
+            // that we should keep the original CMR also for SID and NO_DATA 
+            // frames.
+            
+            // In the old implementation, the iPayloadEncoder used always the
+            // same (moderequest for 12.2kbps) but this should be the correct
+            // way of things.
+            TAmrModeRequest modeReq;
+            if ( ( iIsNb && ( frameType == EAmrFrameNoData || frameType == EAmrFrameSid ) ) ||
+                 ( !iIsNb && ( frameType == EAmrWbFrameNoData || frameType == EAmrWbFrameSid  ) ) )
+                {
+                #ifdef TRACE_AMR_PAYLOAD_FORMAT_WRITE
+                    RDebug::Print( _L("CAmrPayloadFormatWrite::ProcessFramesL CMR NO_REQ") );
+                #endif
+            
+                modeReq = EAmrModeReqNone;
+                }
+            else
+                {
+                #ifdef TRACE_AMR_PAYLOAD_FORMAT_WRITE
+                    RDebug::Print( _L("CAmrPayloadFormatWrite::ProcessFramesL CMR: %d"), frameType );
+                #endif
+
+                modeReq = static_cast<TAmrModeRequest>( frameType );
+                }
+                
+            iPayloadEncoder->SetModeRequest( modeReq );
+            payloadReady = iPayloadEncoder->EncodeFrame( TInt( iCurrentChannel ),
+                    TAmrFrameType( frameType ), qualityInd, dataPtr );
+                    
+     		#ifdef TRACE_AMR_PAYLOAD_FORMAT_WRITE
+        		AMR_PAYLOAD_FORMAT_WRITE2 ( "CAmrPayloadFormatWrite::ProcessFramesL( ): payloadReady1 = %d ", payloadReady );
+    		#endif
+
+            // Increase current channel
+            iCurrentChannel++;
+            if ( iCurrentChannel == iChannels )
+                {
+                // All channel frames for a frame block are received
+                iCurrentChannel = 0;
+                }
+
+            seekPtr += length; // update byte positions
+            seekLen -= length; // update seek length
+            byteIndex += length;
+            
+            iFramesEncoded++;
+            }
+        else
+            {
+            if ( frameInfo.iBitrate < 0 )
+                {
+                #ifdef TRACE_AMR_PAYLOAD_FORMAT_WRITE
+        		AMR_PAYLOAD_FORMAT_WRITE ( "CAmrPayloadFormatWrite::ProcessFramesL( ): frameInfo.iBitrate < 0 ");
+    			#endif
+                break;
+                }
+            else
+                {
+                //  No data frame
+                TStreamDecoder decoder;
+                decoder.Initialize( seekPtr, 0, 0 );
+                decoder.Decode( 1 );                        // Skip first Padding bit
+                TInt frameType = decoder.Decode( KNumValue4 );       // FT value
+
+                if ( frameType != TInt( EAmrFrameNoData ) ) // bad frame
+                    {
+                    #ifdef TRACE_AMR_PAYLOAD_FORMAT_WRITE
+        				AMR_PAYLOAD_FORMAT_WRITE ( "CAmrPayloadFormatWrite::ProcessFramesL( ): bad frame ");
+    				#endif
+                    break;
+                    }
+
+                // QualityIndicator value
+                TUint8 qualityInd = TUint8( decoder.Decode( 1 ) );
+                TPtr8 dummy( 0,0,0 );
+                payloadReady = iPayloadEncoder->EncodeFrame( TInt( iCurrentChannel ),
+                            TAmrFrameType( frameType ), qualityInd, dummy );
+                            
+                #ifdef TRACE_AMR_PAYLOAD_FORMAT_WRITE
+        				AMR_PAYLOAD_FORMAT_WRITE2 ( "CAmrPayloadFormatWrite::ProcessFramesL( ): payloadReady2 = %d ", payloadReady);
+    			#endif   
+                // Increase current channel
+                iCurrentChannel++;
+                if ( iCurrentChannel == iChannels )
+                    {
+                    // All channel frames for a frame block are received
+                    iCurrentChannel = 0;
+                    }
+
+                seekPtr++;
+                seekLen--;
+                byteIndex++;
+
+                iFramesEncoded++;
+                }
+            }
+
+        if ( payloadReady )
+            {
+            AMR_PAYLOAD_FORMAT_WRITE2( "CAmrPayloadFormatWrite::ProcessFramesL: iSinkBuffer1 = %X ", iSinkBuffer );
+            AMR_PAYLOAD_FORMAT_WRITE2( "CAmrPayloadFormatWrite::ProcessFramesL: iSourceBuffer = %X ", iSourceBuffer );
+    	    
+    	    if ( !iSinkBuffer )
+                {
+                return EFalse;
+                }
+                
+            // Payload has been constructed; deliver it to RTP datasink
+            // Update length info of payload buffer.
+            if ( seekLen < CAmrCommonUtility::FrameHeaderSize( ) 
+                &&  ( iSourceBuffer->LastBuffer( ) || iNeedToFlush ) )
+                {
+                // No more AMR frames
+                iSinkBuffer->SetLastBuffer( ETrue );    
+                isDone = ETrue;
+                }
+
+            TDes8& dataDes = static_cast<CMMFDataBuffer*>( iSinkBuffer )->Data( );
+            TDesC8& payloadDes = iPayloadEncoder->PayloadBuffer( );
+            dataDes.SetLength( payloadDes.Length( ) );
+            DeliverPacketL( *iSinkBuffer );
+            }            
+        }
+
+    // If this is the last buffer, 
+    // Set from datapath or by AmrPayloadFormatWrite itself
+    if ( iSourceBuffer->LastBuffer( ) || iNeedToFlush ) 
+        {
+        AMR_PAYLOAD_FORMAT_WRITE2( "CAmrPayloadFormatWrite::ProcessFramesL: iSinkBuffer2 = %X ", iSinkBuffer );
+        
+        isDone = ETrue;
+        if ( iPayloadEncoder->ReEncodeFrameL( ) )
+            {
+            // added for last buffer  
+            // length can not be zero.
+            if ( !iSinkBuffer )
+                {
+                return EFalse;
+                }
+
+            TDes8& dataDes = static_cast<CMMFDataBuffer*>( iSinkBuffer )->Data( );
+            TDesC8& payloadDes = iPayloadEncoder->PayloadBuffer( );
+            dataDes.SetLength( payloadDes.Length( ) );
+            iSinkBuffer->SetLastBuffer( ETrue );   
+            DeliverPacketL( *iSinkBuffer );
+            }
+        }
+
+    return isDone;
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::DeliverPacketL
+//
+// Prepare packet header and deliver the packet to the datasink.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadFormatWrite::DeliverPacketL( CMMFDataBuffer& aPayload )
+    {
+    AMR_PAYLOAD_FORMAT_WRITE2( "CAmrPayloadFormatWrite::DeliverPacketL - TSTAMP: %u",
+        static_cast<TUint32>( aPayload.TimeToPlay().Int64() ) );
+    
+    // Construct RTP header.
+    if ( !iFirstPacketFinished )
+        {
+        iRtpSendHeader.iMarker = 1;
+        iFirstPacketFinished = ETrue;
+        }
+    else
+        {
+        iRtpSendHeader.iMarker = 0;
+        }
+    
+    iRtpSendHeader.iPayloadType = iCInfo.iPayloadType;
+    iRtpSendHeader.iTimestamp 
+        = static_cast<TUint32>( aPayload.TimeToPlay().Int64() );
+    
+    if ( aPayload.BufferSize() )
+        {  
+        if ( iIsRtpSink )
+            {
+            iRtpDataSink->EmptyBufferL( &aPayload, this, iMediaId, iRtpSendHeader );
+            }
+        else
+            {
+		    aPayload.SetLastBuffer( iRtpSendHeader.iMarker );
+            iClip->EmptyBufferL( &aPayload, this, iMediaId );
+            }
+        }
+    
+    // Reset the payload buffer as previous EmptyBufferL() is a synchronous call.
+    aPayload.Data().Zero();
+    iPayloadEncoder->ResetPayloadBuffer();
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::EmptyBufferL
+// Empty the given source buffer by formatting the AMR frames into RTP payload.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadFormatWrite::EmptyBufferL( CMMFBuffer* aBuffer, 
+                                           MDataSource* aSupplier, 
+                                           TMediaId aMediaId )
+    {
+    AMR_PAYLOAD_FORMAT_WRITE2( "CAmrPayloadFormatWrite::EmptyBufferL aBuffer = 0x%x", aBuffer );
+    
+    __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 );
+    
+    TUint32 ts = 0;
+    if ( iCInfo.iSourceDefinedTimeStamps )
+        {
+        AMR_PAYLOAD_FORMAT_WRITE( "CAmrPayloadFormatWrite::EmptyBufferL source has defined timestamp" );
+        
+        ts = MCC_AUDIO_TIMESTAMP( iSourceBuffer->TimeToPlay().Int64() );
+        iSinkBuffer->SetTimeToPlay( TInt64( ts ) );
+        iSinkBuffer->SetFrameNumber( aBuffer->FrameNumber() );
+        }
+    else if ( iPayloadEncoder->IsStartOfPeriod() )
+        {
+        AMR_PAYLOAD_FORMAT_WRITE( "CAmrPayloadFormatWrite::EmptyBufferL SetTimeToPlay" );
+        
+        User::LeaveIfError( iRtpMediaClock->GetTimeStamp( iKey, ts ) );
+
+        if ( iRtpMediaClock->TimeBasedIncrement() )
+	    	{
+    		iFirstPacketFinished = EFalse;
+    		}
+        
+        iSinkBuffer->SetTimeToPlay( TInt64( ts ) );
+        iSinkBuffer->SetFrameNumber( aBuffer->FrameNumber() );
+        }
+    else if( !iCInfo.iSourceDefinedTimeStamps &&
+             !iPayloadEncoder->IsStartOfPeriod() )
+        {
+        User::LeaveIfError( iRtpMediaClock->GetTimeStamp( iKey, ts ) );
+        
+        if ( iRtpMediaClock->TimeBasedIncrement() )
+	    	{
+    		iFirstPacketFinished = EFalse;
+    		}
+        
+        }
+    else
+        {
+        // nop
+        }
+    
+    iStateMachine->ChangeState( EEmptySourceBuffer );
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::EmptySourceBufferL
+// Empty the given source buffer by formatting the AMR frames into RTP payload.
+// Source buffer is given in "iSourceBuffer".
+// Called by the state machine.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadFormatWrite::EmptySourceBufferL( )
+    {
+    AMR_PAYLOAD_FORMAT_WRITE2( "CAmrPayloadFormatWrite::EmptySourceBufferL SRCBUFLEN:%d", iSourceBuffer->Data().Length() );
+
+    if ( ProcessFramesL() )
+        {
+        // Current talk spurt is finished. Either last buffer or iNeedToFlush
+        iStateMachine->ChangeState( EEncodeIdle );
+        iClip->SinkStopL();
+        }
+    else
+        {
+        // Just one step in a talk spurt
+        iStateMachine->ChangeState( ESourceBufferEmptied );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::SourceBufferEmptiedL
+//
+// Hanlde the event that source buffer has been emptied.
+// Source buffer is given in "iSourceBuffer".
+// Called by the state machine.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadFormatWrite::SourceBufferEmptiedL()
+    {
+    AMR_PAYLOAD_FORMAT_WRITE ( "CAmrPayloadFormatWrite::SourceBufferEmptiedL" );
+
+    iDataPath->BufferEmptiedL( iSourceBuffer );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::BufferEmptiedL
+// Called after payload buffer is completely emptied by RtpDataSink.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadFormatWrite::BufferEmptiedL( CMMFBuffer* /*aBuffer*/ )
+    {
+    /* 
+    * We're using synchronous EmptyBufferL( aBuffer ) function call to RTP Sink.
+    * The aBuffer is ready to be used again when the EmptyBufferL returns back.
+    * So BufferEmptiedL( aBuffer ) is not really used.
+    */
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::NumChannels
+// Get the number of channels
+// -----------------------------------------------------------------------------
+//
+TUint CAmrPayloadFormatWrite::NumChannels( )
+    {
+    return KMono;
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::SampleRate
+// Returns the samplerate
+// -----------------------------------------------------------------------------
+//
+TUint CAmrPayloadFormatWrite::SampleRate( )
+    {
+    return iSamplingRate;
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::SetSampleRate
+// Sets the sample rate, AMR-NB is always 8000Hz
+// -----------------------------------------------------------------------------
+//
+TInt CAmrPayloadFormatWrite::SetSampleRate ( TUint aSampleRate )
+    {
+    if( (iIsNb && KAmrNbSampleRate != aSampleRate) ||
+        (!iIsNb && KAmrWbSampleRate != aSampleRate) )
+        {
+        return KErrNotSupported;
+        }
+    else
+        {
+        iSamplingRate = aSampleRate;
+        return KErrNone;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::Duration
+// Return the clip duration for the given media.
+// -----------------------------------------------------------------------------
+//
+TTimeIntervalMicroSeconds CAmrPayloadFormatWrite::Duration( 
+        TMediaId /*aMediaType*/ ) const
+    {
+    return TTimeIntervalMicroSeconds( TInt64( 0 ) );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::CreateSinkBufferOfSizeL
+// Create a sink buffer of the given size.
+// -----------------------------------------------------------------------------
+//
+CMMFDataBuffer* CAmrPayloadFormatWrite::CreateSinkBufferOfSizeL( TUint aSize )
+    {
+    AMR_PAYLOAD_FORMAT_WRITE ( "CAmrPayloadFormatWrite::CreateSinkBufferOfSizeL" );
+
+    if ( !iSourceBuffer )
+	    {  
+	    iSourceBuffer = CMMFDataBuffer::NewL( aSize );
+    	iSourceBuffer->Data().FillZ( aSize );
+    	iSourceBuffer->SetRequestSizeL( aSize );
+	    }
+    return iSourceBuffer;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::IsBitrateChangeValid
+// Checks if codec mode change request is valid.
+// -----------------------------------------------------------------------------
+//
+TBool CAmrPayloadFormatWrite::IsBitrateChangeValid( TInt aBitRate ) 
+    {
+    AMR_PAYLOAD_FORMAT_WRITE( "CAmrPayloadFormatWrite::IsBitrateChangeValid" );
+    
+    TInt currentModeIndex = iModes.Find( iCInfo.iBitrate ); 
+    TInt desiredModeIndex = iModes.Find( aBitRate );  
+    
+    TBool modechangeperiodvalid( EFalse );
+    
+    if ( iFirstCmrHandled )
+        {
+        modechangeperiodvalid = !TBool( iFramesEncoded % iCInfo.iModeChangePeriod );
+        }
+    else
+        {
+        // Initialize counter
+        iFramesEncoded = 0;
+        }
+     
+    if ( KErrNotFound == currentModeIndex )            
+        {                        
+        if ( ( modechangeperiodvalid || !iFirstCmrHandled ) &&
+            ( KErrNotFound != desiredModeIndex ) )        
+            {                                         
+            iCInfo.iBitrate = aBitRate;
+            iFirstCmrHandled = ETrue;
+            return ETrue;
+            }
+        else                                          
+            {
+            return EFalse;        
+            }            
+        }
+         
+    if ( ( modechangeperiodvalid || !iFirstCmrHandled ) && ( ( ( iCInfo.iNeighbor ) &&
+        ( desiredModeIndex == currentModeIndex + 1 ) ||
+        ( desiredModeIndex == currentModeIndex - 1 && currentModeIndex != 0 ) ) ||
+        ( !iCInfo.iNeighbor && KErrNotFound != desiredModeIndex  ) ) )
+        {
+        iCInfo.iBitrate = aBitRate;
+        iFirstCmrHandled = ETrue;
+        return ETrue;
+        }
+    else
+        {
+        return EFalse;
+        }               
+    }
+    
+    
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::CancelUlRequest
+// Cancel UL Request
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadFormatWrite::CancelUlRequest( )
+    {
+    AMR_PAYLOAD_FORMAT_WRITE( "CAmrPayloadFormatWrite::CancelUlRequest" );
+
+    iStateMachine->Cancel();
+    iStateMachine->ChangeState( EEncodeIdle );
+
+    // Reset the payload buffer
+    if ( iSinkBuffer )
+        {
+        TDes8& dataDes = static_cast<CMMFDataBuffer*>( iSinkBuffer )->Data();
+        dataDes.SetLength( 0 );
+        // Reset iFrameEncoder
+        iPayloadEncoder->InitializeFrameEncoder();
+        iPayloadEncoder->ResetPayloadBuffer();
+        }
+    };
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::SinkPrimeL()
+// Primes sink
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadFormatWrite::SinkPrimeL()
+    {
+    iClip->SinkPrimeL();
+    };
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::SinkPlayL()
+// Plays sink
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadFormatWrite::SinkPlayL()
+    {
+    AMR_PAYLOAD_FORMAT_WRITE2( "CAmrPayloadFormatWrite::SinkPlayL RedCount: %d", iCInfo.iRedundancyCount );
+
+    // Allocate buffer for data transfer between
+    // FormatWrite - MDataSink AND FormatWrite - redundancy payload encoder
+    delete iSinkBuffer;
+    iSinkBuffer = NULL;
+    iSinkBuffer = CMMFDataBuffer::NewL( iCInfo.iFrameSize * iFramesPerPacket
+        * ( 1 + iCInfo.iRedundancyCount ) + KNumValue2 );
+
+    // Initialize payload encoder
+    iPayloadEncoder->Initialize();
+    TDes8& dataDes = static_cast<CMMFDataBuffer*>( iSinkBuffer )->Data( );
+    dataDes.SetLength( 0 );   // for first packet length
+    iPayloadEncoder->SetPayloadBuffer( dataDes );
+	iPayloadEncoder->SetChannelCount( iChannels );
+
+    // Reset flag
+    iNeedToFlush = EFalse;
+
+    // Start state machine
+    iStateMachine->ChangeState( EEncodeIdle );
+    iFirstPacketFinished = EFalse;
+
+    if ( iSinkBuffer )
+        {
+        iSinkBuffer->SetLastBuffer( EFalse );
+        }
+
+    iClip->SinkPlayL();
+    };
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::SinkPauseL()
+// Pauses sink
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadFormatWrite::SinkPauseL()
+    {
+    this->CancelUlRequest();
+    iClip->SinkPauseL();
+    };
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::SinkStopL()
+// Stops sink
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadFormatWrite::SinkStopL()
+    {
+    if ( EEmptySourceBuffer == iStateMachine->CurrentState() )
+        {
+        iNeedToFlush = ETrue; 
+        return;
+        }
+
+    if ( ESourceBufferEmptied == iStateMachine->CurrentState() )
+        {
+        // Finished emptying current buffer to RTP
+        // check whether there is internal buffer left
+        if ( iPayloadEncoder->ReEncodeFrameL() )
+            {
+            // length can not be zero.
+            if ( !iSinkBuffer )
+                {
+                return;
+                }
+                
+            TDes8& dataDes = static_cast<CMMFDataBuffer*>( iSinkBuffer )->Data();
+            TDesC8& payloadDes = iPayloadEncoder->PayloadBuffer();
+            dataDes.SetLength( payloadDes.Length() );
+            iSinkBuffer->SetLastBuffer( ETrue );
+
+            this->DeliverPacketL( *iSinkBuffer );
+
+            AMR_PAYLOAD_FORMAT_WRITE( "CAmrPayloadFormatWrite::StopUlStream ReEncodeFrame done" );
+            }
+        }
+
+    // Stop state machine
+    this->CancelUlRequest();
+    iClip->SinkStopL();
+    };
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::ConfigurePayloadFormatL
+// Configure payload encoding parameters.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadFormatWrite::ConfigurePayloadFormatL( 
+        const TDesC8& aConfigParams, 
+        CMccRtpMediaClock& aClock  )
+    {
+    AMR_PAYLOAD_FORMAT_WRITE( "CAmrPayloadFormatWrite::ConfigurePayloadFormatL (NB/WB)" )
+    __ASSERT_ALWAYS( aConfigParams.Size() == sizeof( TMccCodecInfo ),
+        User::Leave( KErrArgument ) );
+    
+    TMccCodecInfoBuffer infoBuffer;
+    infoBuffer.Copy( aConfigParams );  
+        
+    if ( !infoBuffer().iIsUpdate )
+        {
+        __ASSERT_ALWAYS( infoBuffer().iHwFrameTime, User::Leave( KErrArgument ) );
+        __ASSERT_ALWAYS( infoBuffer().iModeChangePeriod, User::Leave( KErrArgument ) );
+        
+        iCInfo = infoBuffer();
+        iRtpMediaClock = &aClock;
+
+        TUint tempMask(0x0001);
+        // Reset old iModes array if new modes exist
+        if ( iCInfo.iBitrateMask != 0x0000 )
+            {
+            iModes.Reset();
+            }
+        
+        if ( iIsNb )
+        	{
+        	iKey = iRtpMediaClock->RegisterMediaFormat( KAmrNbSampleRate,
+        	                                            iCInfo.iHwFrameTime );
+
+	        for ( TInt ii = KNumValue0; ii < KNumberOfNbModes; ii++ )
+	            {
+	            if( iCInfo.iBitrateMask & tempMask )
+	                {
+	                iModes.AppendL( KAmrNbModes[ii] );
+	                }
+	            tempMask*=2;
+	            }           
+        	}
+        else // Wb
+        	{
+        	iKey = iRtpMediaClock->RegisterMediaFormat( KAmrWbSampleRate, 
+        	                                            iCInfo.iHwFrameTime );
+
+	        for ( TInt ii = 0; ii < KNumberOfWbModes; ii++ )
+	            {
+	            if( iCInfo.iBitrateMask & tempMask )
+	                {
+	                iModes.AppendL( KAmrWbModes[ii] );
+	                }
+	            tempMask*=2;
+	            }           
+        	}
+                                    
+        if ( !iPayloadEncoder )
+            {
+            if( KAmrCodecModeBandwidthEfficient == iCInfo.iCodecMode )
+                {
+                iPayloadEncoder = CAmrPayloadEncoder::NewL( iIsNb );
+                }
+            else if( KAmrCodecModeOctetAlign == iCInfo.iCodecMode )
+                {
+                iPayloadEncoder = CAmrPayloadEncoderOA::NewL( iIsNb );
+                }
+            else
+                {
+                User::Leave( KErrArgument );
+                }    
+            }
+        
+        iFramesPerPacket = iCInfo.iPtime / iCInfo.iHwFrameTime;
+        iPayloadEncoder->SetFrameBlockCount( iFramesPerPacket );
+  
+        if ( EAmrFecUsed == iCInfo.iAlgoUsed && iCInfo.iRedundancyCount > 0 )
+            {
+            AMR_PAYLOAD_FORMAT_WRITE( "CAmrPayloadFormatWrite::ConfigurePayloadFormatL - Using AMR FEC" );
+            iPayloadEncoder->Initialize();
+            User::LeaveIfError( iPayloadEncoder
+                ->SetRedFrameBlockCount( iCInfo.iRedundancyCount ) );
+            }
+        else if ( EGenRedUsed == iCInfo.iAlgoUsed )
+            {
+            AMR_PAYLOAD_FORMAT_WRITE2( "CAmrPayloadFormatWrite::ConfigurePayloadFormatL, RED LEVEL: %d",
+                iCInfo.iRedundancyCount );
+            
+            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 );
+            }
+        else
+            {
+            // NOP
+            }
+        }
+    else
+        {
+        UpdateConfigurationL( infoBuffer() );            
+        } 
+               
+    AMR_PAYLOAD_FORMAT_WRITE( "CAmrPayloadFormatWrite::ConfigurePayloadFormatL OUT" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadFormatWrite::UpdateConfigurationL
+// Update payload encoding parameters
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadFormatWrite::UpdateConfigurationL( const TMccCodecInfo& aCodecInfo )
+    {
+    AMR_PAYLOAD_FORMAT_WRITE( "CAmrPayloadFormatWrite::UpdateConfigurationL" )
+    
+    __ASSERT_ALWAYS( aCodecInfo.iModeChangePeriod, User::Leave( KErrArgument ) );
+    
+    iCInfo.iNeighbor = aCodecInfo.iNeighbor;                            
+    iCInfo.iModeChangePeriod = aCodecInfo.iModeChangePeriod;          
+    iCInfo.iRedundancyCount = aCodecInfo.iRedundancyCount;
+    iCInfo.iPtime = aCodecInfo.iPtime;
+    iCInfo.iSourceDefinedTimeStamps = aCodecInfo.iSourceDefinedTimeStamps;
+    iCInfo.iPayloadType = aCodecInfo.iPayloadType;
+    
+    TUint tempMask(0x0001);
+    
+    // Reset old iModes array if new modes exist
+    if ( iCInfo.iBitrateMask != 0x0000 )
+        {
+        iModes.Reset();
+        }
+    
+    if ( iIsNb )
+    	{
+	    for ( TInt ii = 0; ii < KNumberOfNbModes; ii++ )
+	        {
+	        if( iCInfo.iBitrateMask & tempMask )
+	            {
+	            iModes.AppendL( KAmrNbModes[ii] );
+	            }
+	        tempMask*=2;
+	        } 
+    	}
+	else // Wb
+		{
+	    for ( TInt ii = 0; ii < KNumberOfWbModes; ii++ )
+	        {
+	        if( iCInfo.iBitrateMask & tempMask )
+	            {
+	            iModes.AppendL( KAmrWbModes[ii] );
+	            }
+	        tempMask*=2;
+	        } 
+		}	        
+    
+    iFramesPerPacket = iCInfo.iPtime / iCInfo.iHwFrameTime;
+    iPayloadEncoder->SetFrameBlockCount( iFramesPerPacket );
+    
+    if ( EAmrFecUsed == iCInfo.iAlgoUsed )
+        {                           
+        iPayloadEncoder->Initialize();
+        User::LeaveIfError( iPayloadEncoder
+            ->SetRedFrameBlockCount( iCInfo.iRedundancyCount ) );
+        }
+    else
+        {
+        AMR_PAYLOAD_FORMAT_WRITE( "CAmrPayloadFormatWrite::ConfigurePayloadFormatL - Not using AMR FEC" );
+        }
+    
+    // Allocate buffer for data transfer between
+    // FormatWrite - MDataSink AND FormatWrite - redundancy payload encoder
+    delete iSinkBuffer;
+    iSinkBuffer = NULL;
+    iSinkBuffer = CMMFDataBuffer::NewL( iCInfo.iFrameSize * iFramesPerPacket
+        * ( 1 + iCInfo.iRedundancyCount ) + KNumValue2 );
+    
+    iPayloadEncoder->Initialize();
+    TDes8& dataDes = static_cast<CMMFDataBuffer*>( iSinkBuffer )->Data( );
+    dataDes.SetLength( 0 );   // for first packet length
+    iPayloadEncoder->SetPayloadBuffer( dataDes );
+    iPayloadEncoder->SetChannelCount( iChannels );
+    
+    // Reset flag
+    iNeedToFlush = EFalse;
+    
+    AMR_PAYLOAD_FORMAT_WRITE( "CAmrPayloadFormatWrite::UpdateConfigurationL OUT" )
+    }
+
+// ========================== OTHER EXPORTED FUNCTIONS =========================
+
+//  End of File