multimediacommscontroller/mmccamrpayloadformat/src/amrpayloadencoder.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccamrpayloadformat/src/amrpayloadencoder.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,713 @@
+/*
+* Copyright (c) 2002-2006 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:    PayloadFormat plugin capable to read RTP payload containing
+*                AMR audio.
+*
+*/
+
+
+
+
+// INCLUDE FILES
+#include "amrpayloadencoder.h"
+#include "amrcommonutil.h"
+
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::CAmrPayloadEncoder
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CAmrPayloadEncoder::CAmrPayloadEncoder( TBool aIsNb ) : CAmrPayloadFormatter( aIsNb )
+    {
+    DP_AMR_ENCODE( "CAmrPayloadEncoder::CAmrPayloadEncoder" );       
+        
+    CAmrPayloadEncoder::InitializeFrameEncoder( );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadEncoder::ConstructL( )
+    {
+    DP_AMR_ENCODE( "CAmrPayloadEncoder::ConstructL" );
+        
+    // Allocate memory for iHeaderEncoder and iTocEntryEncoder
+    iHeaderEncoder = CAmrPayloadHeader::NewL();
+    iTocEntryEncoder = CAmrTocEntry::NewL();
+    
+    #ifdef FTD_ENABLED    
+    User::LeaveIfError( iCodecStatsQueue.OpenGlobal( KMccCodecStats, EOwnerProcess ) ); 
+    #endif    
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CAmrPayloadEncoder* CAmrPayloadEncoder::NewL( TBool aIsNb )
+    {
+    DP_AMR_ENCODE( "CAmrPayloadEncoder::NewL" );
+    
+    CAmrPayloadEncoder* self = new( ELeave ) CAmrPayloadEncoder( aIsNb );
+    
+    CleanupStack::PushL( self );
+    self->ConstructL( );
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+
+// Destructor
+CAmrPayloadEncoder::~CAmrPayloadEncoder( )
+    {
+    DP_AMR_ENCODE( "CAmrPayloadEncoder::~CAmrPayloadEncoder" );
+        
+    delete iHeaderEncoder;
+    delete iTocEntryEncoder;
+    
+    #ifdef FTD_ENABLED
+    
+    iCodecStatsQueue.Close();
+    
+    #endif
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::DoInitialize
+// Initialize encoder. Encoder MUST BE initialized when starting playing.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadEncoder::DoInitialize()
+    {
+    DP_AMR_ENCODE( "CAmrPayloadEncoder::DoInitialize" );
+        
+    iRedIntervalCollected = EFalse;
+    iFrameIndex = iRedCount;
+    }
+    
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::SetModeRequest
+// Set ModeRequest.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadEncoder::SetModeRequest( TAmrModeRequest aRequest )
+    {
+    DP_AMR_ENCODE2( "CAmrPayloadEncoder::SetModeRequest - REQUEST: %d", aRequest );
+        
+    iModeRequest = aRequest;
+    
+    #ifdef FTD_ENABLED
+    
+    TMccCodecStats stats;
+    stats.iCMRUplink = iModeRequest;
+    stats.SetFieldUpdatedFlag( ECMRUplink );
+    iCodecStatsQueue.Send( stats );
+    
+    #endif
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::EncodeFrame
+// Encode a received AMR frame into the payload buffer to be sent.
+// If AMR FEC redundancy is used and we have collected needed count of redundant
+// frames, them are encoded first to the payload buffer. Last iRedCount frames
+// are saved to be used with next RTP packet. iRedCount first frames in the 
+// 'iFrames'-array are reserved for redundant frames info saving. Thus new 
+// frames starts from index iFrames[iRedCount].
+// -----------------------------------------------------------------------------
+//
+TBool CAmrPayloadEncoder::EncodeFrame( TInt aChannel,
+                                       TAmrFrameType aFrameType,
+                                       TUint8 aFrameQualityInd,
+                                       const TDes8& aFrameData )
+    {
+    DP_AMR_ENCODE( "CAmrPayloadEncoder::EncodeFrame" );
+        
+    TBool payloadComplete( EFalse );
+    
+    // Encode redundant frames if there is some
+    // Frame info relating to redundant frames is saved at the beginning of iFrames
+    TInt count( iFrameDatas.Count() );
+
+    if ( iRedCount == iFrameIndex && count && iRedIntervalCollected )
+        {
+        for ( TInt i = iRedCount - count; i < iRedCount; i++ )
+            {
+            const TUint8* redFrameData = iFrames[i].iFrameData;
+            TInt speechBits = SpeechBitCount( iFrames[i].iFrameType );
+            iFrameEncoder.Encode( redFrameData, 0, 0, speechBits );
+            iTotalSpeechBits += speechBits;
+            
+            #ifdef _DEBUG
+            if ( speechBits )
+                {
+                DP_AMR_ENCODE2( "ENCODING RED FRAME #%d: ", i );
+                DP_AMR_ENCODE6( "| %d | %d | %d | %d | %d |", redFrameData[KNumValue0],
+                    redFrameData[KNumValue1], redFrameData[KNumValue2],
+                    redFrameData[KNumValue3], redFrameData[KNumValue4] );    
+                }
+            else
+                {
+                DP_AMR_ENCODE2( "ENCODING RED FRAME #%d: - NO DATA FRAME", i );
+                }
+            #endif
+            }
+        }
+
+    // Update iFrames array
+    iFrames[iFrameIndex].iFrameType = aFrameType;
+    iFrames[iFrameIndex].iFrameQualityInd = aFrameQualityInd;
+    iFrames[iFrameIndex].iChannel = aChannel;
+    if ( EAmrFrameNoData == aFrameType  )
+        {
+        DP_AMR_ENCODE( "FRAME TO ENCODE - NO DATA FRAME" );
+
+        iFrames[iFrameIndex].iFrameData = NULL;
+        iFrames[iFrameIndex].iBitIndex = 0;
+        }
+    else
+        {
+        iFrames[iFrameIndex].iFrameData = iPayload + iFrameEncoder.ByteIndex( );
+        iFrames[iFrameIndex].iBitIndex = TUint( iFrameEncoder.BitIndex( ) );
+        const TUint8* frameData = aFrameData.Ptr( );
+
+        // Get the speech bit count of current frame
+        TInt speechBits = SpeechBitCount( aFrameType ); 
+        iFrameEncoder.Encode( frameData, 0, 0, speechBits );
+
+        // Update TotalSpeechBits 
+        iTotalSpeechBits += speechBits;
+        
+        #ifdef _DEBUG
+        DP_AMR_ENCODE2( "ENCODED FRAME #%d: ", iFrameIndex );
+        if ( aFrameData.Size() )
+            {
+            TStreamDecoder decoder;
+            TUint8* refBufPtr = iFrames[iFrameIndex].iFrameData;
+            decoder.Initialize( refBufPtr, 0, TInt( iFrames[iFrameIndex].iBitIndex ) );
+            TUint32 vals[KNumValue5];
+            for ( TInt v = 0; v < (TInt) KNumValue5; v++ )
+                {
+                vals[v] = decoder.Decode( KBitsIn1Byte );
+                }
+            DP_AMR_ENCODE6( "| %d | %d | %d | %d | %d |", vals[KNumValue0],
+            vals[KNumValue1], vals[KNumValue2], vals[KNumValue3], vals[KNumValue4] );
+            }
+        #endif            
+        }
+
+    iFrameIndex++;
+    if ( iFrameIndex == iFrameCount + iRedCount )
+        {
+        DP_AMR_ENCODE( "CAmrPayloadEncoder::EncodeFrame - NEEDED FRAMES COLLECTED" );
+
+        // Add header information to the RTP packet
+        TInt payloadLen = Encode( iPayload );
+        DP_AMR_ENCODE3( "CAmrPayloadEncoder::EncodeFrame - PAYLOAD SIZE: %d, TARGET MAX: %d",
+            payloadLen, iPayloadPtr.MaxLength() );
+        iPayloadPtr.SetLength( payloadLen );
+
+        // Finish a payload
+        iFrameIndex = iRedCount;
+        iTotalSpeechBits = 0;
+        SaveRedundantFrame( aFrameData );
+        if ( iRedCount <= iFrameDatas.Count() )
+            {
+            iRedIntervalCollected = ETrue;
+            }
+        
+        // Reset iFrameEncoder
+        InitializeFrameEncoder( );
+        payloadComplete = ETrue;
+        }
+    else if ( iRedCount && iFrameIndex > iFrameCount )
+        {
+        // Save iRedCount latest frames to be sent with next RTP packet as redundancy
+        SaveRedundantFrame( aFrameData );
+        }
+    else
+        {
+        // Make PC-LINT happy.
+        }        
+
+    return payloadComplete;
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::SaveRedundantFrame
+// Saves frame to the array reserved for redundancy saving.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadEncoder::SaveRedundantFrame( const TDes8& aFrameData )
+    {
+    DP_AMR_ENCODE( "CAmrPayloadEncoder::SaveRedundantFrame" );
+        
+    HBufC8* hFrame = aFrameData.Alloc();
+    if ( hFrame )
+        {
+        if ( iFrameDatas.Append( hFrame ) != KErrNone )
+            {
+            delete hFrame;
+            }
+        else if ( iRedCount < iFrameDatas.Count() )
+            {
+            delete iFrameDatas[0];
+            iFrameDatas.Remove( 0 );
+            }
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::ResetPayloadBuffer
+// Resets iFrames array. iRedCount newest frames from payload just sent are
+// copied to the beginning of the iFrames array, where is area reserved for
+// redundant frames keeping. That way frames can be encoded to the next payload
+// as redundat frames.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadEncoder::ResetPayloadBuffer( )
+    {
+    DP_AMR_ENCODE( "CAmrPayloadEncoder::ResetPayloadBuffer" );
+        
+    iFrameIndex = iRedCount;
+    iPayloadPtr.SetLength( 0 );
+    
+    // Save redCount newest frames to the beginning of iFrames array
+    TInt numOfRedFrames = iFrameDatas.Count();
+    if ( iRedCount - numOfRedFrames >= 0 )
+        {
+        for ( TInt i = iRedCount - numOfRedFrames; i < iRedCount; i++ )
+            {
+           	if ( i > KMaxFrameCountPerPacket )
+   				{
+       			DP_AMR_ENCODE3("CAmrPayloadEncoder::ResetPayloadBuffer,\
+       				 i: %d > KMaxFrameCountPerPacket: %d",  \
+       				 i , KMaxFrameCountPerPacket);	
+        		}
+        	if ( ( i + iFrameCount ) > KMaxFrameCountPerPacket )
+   				{
+       			DP_AMR_ENCODE3("CAmrPayloadEncoder::ResetPayloadBuffer, i + iFrameCount: %d > KMaxFrameCountPerPacket: %d",  \
+        		(i + iFrameCount) , KMaxFrameCountPerPacket);	
+        		}
+        	
+        	// Checking index limit to appease PC-lint
+        	if ( ( i + iFrameCount ) < KMaxFrameCountPerPacket )	
+        		{
+        		iFrames[ i ] = iFrames[ i + iFrameCount ];
+        		
+            	}
+            }
+
+        for ( TInt j = 0; j < numOfRedFrames; j++ )
+            {
+            
+            if ( ( j + ( iRedCount - numOfRedFrames )  ) > KMaxFrameCountPerPacket )
+   				{
+       			DP_AMR_ENCODE3("CAmrPayloadEncoder::ResetPayloadBuffer,\
+       				j + ( iRedCount - numOfRedFrames ): %d > KMaxFrameCountPerPacket: %d", \
+       				( j + ( iRedCount - numOfRedFrames ) ), KMaxFrameCountPerPacket);	
+        		}
+        		
+            // Checking index limit to appease PC-lint
+        	if ( ( j + ( iRedCount - numOfRedFrames )  ) < KMaxFrameCountPerPacket )
+        		{
+        		
+            	// Move frame data ptr to point redundant frames
+            	iFrames[ j + ( iRedCount - numOfRedFrames ) ].iFrameData
+	                = const_cast<TUint8*>( ( *iFrameDatas[ j ] ).Ptr() );
+                
+            	}
+            }
+        }
+    else
+        {
+        DP_AMR_ENCODE( "CAmrPayloadEncoder::ResetPayloadBuffer - TOO MANY RED FRAMES" );
+        }        
+        
+    // NULL rest of frame datas
+    TInt index( KMaxFrameCountPerPacket );
+    while ( --index >= iRedCount )
+        {
+        iFrames[index].iFrameData = NULL;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::SetChannelCount
+// Set number of audio channels.
+// -----------------------------------------------------------------------------
+//
+TInt CAmrPayloadEncoder::SetChannelCount( TInt aChannelCount )
+    {
+    DP_AMR_ENCODE2( "CAmrPayloadEncoder::SetChannelCount - COUNT: %d", aChannelCount );
+        
+    TInt ret = CAmrPayloadFormatter::SetChannelCount( aChannelCount );
+    InitializeFrameEncoder( );
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::SetFrameBlockCount
+// Set number of AMR frame blocks included in one RTP packet.
+// -----------------------------------------------------------------------------
+//
+TInt CAmrPayloadEncoder::SetFrameBlockCount( TInt aFrameblockCount )
+    {
+    DP_AMR_ENCODE2( "CAmrPayloadEncoder::SetFrameBlockCount - COUNT: %d", aFrameblockCount );
+        
+    TInt ret = CAmrPayloadFormatter::SetFrameBlockCount( aFrameblockCount );
+    InitializeFrameEncoder( );
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::SetRedFrameBlockCount
+// Set number of redundant AMR frame blocks to be included in one RTP packet.
+// -----------------------------------------------------------------------------
+//
+TInt CAmrPayloadEncoder::SetRedFrameBlockCount( TInt aRedBlockCount )
+    {
+    DP_AMR_ENCODE2( "CAmrPayloadEncoder::SetFrameBlockCount - COUNT: %d", aRedBlockCount );
+        
+    if ( KMaxAmrRedCount >= aRedBlockCount && 0 <= aRedBlockCount )
+        {
+        iRedCount = aRedBlockCount;
+        return KErrNone;
+        }
+    else
+        {
+        return KErrArgument;
+        }        
+    }
+    
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::Encode
+// Encode the AMR payload ( for one RTP packet ) into a given buffer.
+// If payload contains only NO_DATA frames, packet is not encoded at all.
+// NO_DATA frames at the end of payload are ripped off.
+// -----------------------------------------------------------------------------
+//
+TInt CAmrPayloadEncoder::Encode( TUint8* aBuffer )
+    {
+    DP_AMR_ENCODE( "CAmrPayloadEncoder::Encode" );
+    
+    TInt byteIndex( 0 );
+    TInt bitIndex( 0 );
+
+    // Rip off extra NO_DATA frames
+    TInt framesDiscarded = DiscardExtraNoDataFrames( );
+    if ( iRedIntervalCollected )
+        {
+        if ( framesDiscarded == iFrameCount + iRedCount )
+            {
+            DP_AMR_ENCODE( "PACKET WILL NOT BE SENT - ONLY NO DATA FRAMES" );
+            return 0;
+            }
+        }
+    else
+        {
+        if ( framesDiscarded == iFrameCount )
+            {
+            DP_AMR_ENCODE( "PACKET WILL NOT BE SENT - NEW FRAMES WERE NO DATA FRAMES" );
+            DP_AMR_ENCODE2( "CAmrPayloadEncoder::Encode framesDiscarded: %d", framesDiscarded );
+            return 0;
+            }
+        }        
+
+    // Encode payload header
+    iHeaderEncoder->iCmr = iModeRequest;
+    iHeaderEncoder->Encode( aBuffer, byteIndex, bitIndex );
+
+    // Encode TOC entries
+    EncodeTableOfContents( aBuffer, byteIndex, bitIndex );
+    
+    // Pad last several bits if needed
+    TInt totalBytes = iFrameEncoder.ByteIndex();
+    
+    if ( iFrameEncoder.BitIndex() != 0 )
+        {
+        // Padding Zeros
+        iFrameEncoder.Encode( 0, KBitsIn1Byte - iFrameEncoder.BitIndex() );
+        totalBytes++;
+        }
+    
+    return totalBytes;
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::DiscardExtraNoDataFrames
+// Unwanted NO_DATA frames are ripped off from payload according to RFC3267: 4.3.2.
+// TOC-fields indicating NO_DATA frame are deleted and speech bits following 
+// TOCs are moved to start earlier correspondingly.
+// -----------------------------------------------------------------------------
+//
+TInt CAmrPayloadEncoder::DiscardExtraNoDataFrames( )
+    {
+    DP_AMR_ENCODE( "CAmrPayloadEncoder::DiscardExtraNoDataFrames" );
+        
+    TInt endIndex( iFrameCount + iRedCount );
+    iFramesDiscarded = 0;
+    
+    // write debug info if the endIndex is greater than the iFrames[] range
+    if ( endIndex > KMaxFrameCountPerPacket )
+   		{
+       	DP_AMR_ENCODE3("CAmrPayloadEncoder::DiscardExtraNoDataFrames, endIndex: %d > KMaxFrameCountPerPacket: %d",  \
+        	endIndex, KMaxFrameCountPerPacket);	
+        }
+    // Count NO_DATA frames to reject
+    for ( TInt i = 0; i < endIndex; i++ )
+        {
+        if ( EAmrFrameNoData == iFrames[i].iFrameType )
+            {
+            iFramesDiscarded++;
+            }
+        else
+            {
+            iFramesDiscarded = 0;
+            }                
+        }
+    
+    // Move speech bits to start earlier if TOCs are removed
+    if ( iFramesDiscarded )
+        {
+        DP_AMR_ENCODE2( "CAmrPayloadEncoder::DiscardExtraNoDataFrames - REJECT %d FRAMES", iFramesDiscarded );
+        
+        TStreamDecoder decoder;
+        TStreamEncoder encoder;
+
+        TInt numOfRedFrames( 0 );
+        if ( iRedIntervalCollected )
+            {
+            numOfRedFrames = iFrameDatas.Count();
+            }
+        
+        TInt writeByteIndex = ( KHeaderBitsBE 
+            + KTOCFieldBitsBE * ( iFrameCount + numOfRedFrames - iFramesDiscarded ) )
+            / KBitsIn1Byte;
+
+        TInt writeBitIndex = ( KHeaderBitsBE
+            + KTOCFieldBitsBE * ( iFrameCount + numOfRedFrames - iFramesDiscarded ) )
+            % KBitsIn1Byte;
+
+        encoder.Initialize( iPayload, writeByteIndex, writeBitIndex );
+        
+        DP_AMR_ENCODE3( "AMR ENCODER - START BYTE IND: %d, BIT IND: %d",
+            encoder.ByteIndex(), encoder.BitIndex() );
+        
+        TInt readByteIndex = ( KHeaderBitsBE
+            + KTOCFieldBitsBE * ( iFrameCount + numOfRedFrames ) )
+            / KBitsIn1Byte;
+        TInt readBitIndex = ( KHeaderBitsBE 
+            + KTOCFieldBitsBE * ( iFrameCount + numOfRedFrames ) )
+            % KBitsIn1Byte;
+
+        decoder.Initialize( iPayload, readByteIndex, readBitIndex );
+        
+        // Move speech bits
+        encoder.Encode( iPayload, readByteIndex, readBitIndex, iTotalSpeechBits );
+        
+        DP_AMR_ENCODE3( "AMR ENCODER - END BYTE IND: %d, BIT IND: %d",
+            encoder.ByteIndex(), encoder.BitIndex() );
+            
+        // Update frame encoder position so that payload length is set correctly
+        iFrameEncoder.Initialize( iPayload, encoder.ByteIndex(), encoder.BitIndex() );
+        }
+    
+    return iFramesDiscarded;        
+    }
+    
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::ReEncodeFrame
+// Do bit shifting when AmrPayloadFormatPlugin is doing buffer flushing.
+// -----------------------------------------------------------------------------
+//
+TBool CAmrPayloadEncoder::ReEncodeFrameL( )
+    {
+    return ReEncodeFrameL( iPayload );
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::ReEncodeFrame
+// Do bit shifting when AmrPayloadFormatPlugin is doing buffer flushing.
+// -----------------------------------------------------------------------------
+//
+TBool CAmrPayloadEncoder::ReEncodeFrameL( TUint8* aBuffer )
+    {
+    DP_AMR_ENCODE( "CAmrPayloadEncoder::ReEncodeFrameL" );
+        
+    // No outstanding buffer at all
+    if ( iFrameIndex == iRedCount )
+        {
+        return EFalse;
+        }
+
+    // Only called when AmrPayloadFormatPlugin is flushing buffer out
+    TInt byteIndex( 0 );
+    TInt bitIndex( 0 );
+
+    // Encode payload header
+    iHeaderEncoder->iCmr = iModeRequest;
+    iHeaderEncoder->Encode( aBuffer, byteIndex, bitIndex );
+    
+    // Encode TOC entries
+    EncodeTableOfContents( aBuffer, byteIndex, bitIndex );
+    
+    // Do bit shifting for the speech bits
+    // orginal starting position
+    TInt frameByteIndex = ( KHeaderBitsBE
+        + KTOCFieldBitsBE * ( iFrameCount + iRedCount ) ) / KBitsIn1Byte;
+
+    TInt frameBitIndex = ( KHeaderBitsBE
+        + KTOCFieldBitsBE * ( iFrameCount + iRedCount ) ) % KBitsIn1Byte;
+    
+    // Current speech data length
+    TInt speechBytes
+        = ( iTotalSpeechBits % KBitsIn1Byte == 0 )
+        ? iTotalSpeechBits / KBitsIn1Byte : iTotalSpeechBits / KBitsIn1Byte + 1;
+    
+    // Read out speech data to temp buffer
+    TUint8* tempBuf = static_cast<TUint8*>
+        ( User::AllocL( sizeof( TUint8 ) * TUint8( speechBytes ) ) );
+
+    CleanupStack::PushL( tempBuf );
+    TStreamEncoder streamEnc;
+    TStreamDecoder streamDec;
+    streamEnc.Initialize( aBuffer, byteIndex, bitIndex );
+    streamDec.Initialize( aBuffer, frameByteIndex, frameBitIndex );
+    streamDec.Decode( tempBuf, 0, 0, iTotalSpeechBits );
+    streamEnc.Encode( tempBuf, 0, 0, iTotalSpeechBits );
+
+    if ( streamEnc.BitIndex( ) != 0 )
+        {
+        // Padding zeros
+        streamEnc.Encode( 0, KBitsIn1Byte - streamEnc.BitIndex( ) );
+        }
+    
+    TInt payloadLen = streamEnc.ByteIndex( );
+    iPayloadPtr.SetLength( payloadLen );
+
+    // Finish current payload
+    iFrameIndex = iRedCount;
+    // Reset iFrameEncoder
+    InitializeFrameEncoder( );
+    // Reset TotalSpeechBits counter
+    iTotalSpeechBits = 0; 
+
+    CleanupStack::PopAndDestroy( tempBuf );
+    return ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::IsStartOfPeriod
+// Returns ETrue if next frame to be encoded starts a new packetization period.
+// -----------------------------------------------------------------------------
+//
+TBool CAmrPayloadEncoder::IsStartOfPeriod()
+    {
+    return ( iFrameIndex == iRedCount );
+    }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::EncodeTableOfContents
+// Encode 'Table of Contents' into a given buffer at the given position.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadEncoder::EncodeTableOfContents( TUint8* aBuffer,
+                                                TInt& aByteIndex, 
+                                                TInt& aBitIndex )
+    {
+    DP_AMR_ENCODE( "CAmrPayloadEncoder::EncodeTableOfContents" );
+    
+    // Iterate iFrames array and encode each TOC entry
+    // Encode TOCs for redundant frames if exist
+    TInt ind( iRedCount );
+    if ( iRedIntervalCollected )
+        {
+        ind = iRedCount - iFrameDatas.Count();
+        }
+
+    TInt endIndex = iFramesDiscarded ? iFrameIndex - iFramesDiscarded : iFrameIndex;
+    // write debug info if the endIndex is greater than the iFrames[] range
+    if ( endIndex > KMaxFrameCountPerPacket )
+   		{
+       	DP_AMR_ENCODE3("CAmrPayloadEncoder::EncodeTableOfContents, endIndex: %d > KMaxFrameCountPerPacket: %d",  \
+        	endIndex, KMaxFrameCountPerPacket);	
+        }
+    for ( ; ind < endIndex; ind++ )
+        {
+        if ( ind == endIndex - 1 )
+            {
+            iTocEntryEncoder->iFrameFollowed = 0; // last frame in a payload
+            }
+        else
+            {
+            iTocEntryEncoder->iFrameFollowed = 1;
+            }
+
+        // Checking index limit to appease PC-lint
+        if ( (ind) < KMaxFrameCountPerPacket )
+        	{
+        iTocEntryEncoder->iFrameQualityInd = iFrames[ind].iFrameQualityInd;
+        iTocEntryEncoder->iFrameType = iFrames[ind].iFrameType;
+        	}
+        iTocEntryEncoder->Encode( aBuffer, aByteIndex, aBitIndex );
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::InitializeFrameEncoder
+// Initialize frame encoder ( Stream Encoder ). Starting position of first AMR
+// frame data is calculated. Refer to RFC3267 4.3.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadEncoder::InitializeFrameEncoder( )
+    {
+    DP_AMR_ENCODE( "CAmrPayloadEncoder::InitializeFrameEncoder" );
+        
+    // Payload header: 4 bits; TOC: 6 bits
+    // Total number of TOCs: iChannelCount * iFrameBlockCount
+    TInt numOfRedFrames( 0 );
+    if ( iRedIntervalCollected )
+        {
+        numOfRedFrames = iFrameDatas.Count();
+        }
+
+    // Save space for frame TOCs
+    TInt frameByteIndex = ( KHeaderBitsBE
+        + KTOCFieldBitsBE * ( iFrameCount + numOfRedFrames ) ) / KBitsIn1Byte;
+    
+    TInt frameBitIndex = ( KHeaderBitsBE 
+        + KTOCFieldBitsBE * ( iFrameCount + numOfRedFrames ) ) % KBitsIn1Byte;
+
+    iFrameEncoder.Initialize( iPayload, frameByteIndex, frameBitIndex );
+    }
+    
+
+// ========================== OTHER EXPORTED FUNCTIONS =========================
+
+//  End of File