diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccamrpayloadformat/src/amrpayloadencoder.cpp --- /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( ( *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 + ( 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