--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccamrpayloadformat/src/amrpayloaddecoder.cpp Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,464 @@
+/*
+* 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 "amrpayloaddecoder.h"
+#include "amrcommonutil.h"
+#include "amrpayloadheader.h"
+#include "amrtocentry.h"
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadDecoder::CAmrPayloadDecoder
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CAmrPayloadDecoder::CAmrPayloadDecoder( TBool aIsNb ) : CAmrPayloadFormatter( aIsNb )
+ {
+ DP_AMR_DECODE ("CAmrPayloadDecoder::CAmrPayloadDecoder");
+ }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadEncoder::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadDecoder::ConstructL( )
+ {
+ DP_AMR_DECODE( "CAmrPayloadDecoder::ConstructL" );
+
+ // Allocate memory for iHeaderDecoder and iTocEntryDecoder
+ iHeaderDecoder = CAmrPayloadHeader::NewL();
+ iTocEntryDecoder = CAmrTocEntry::NewL();
+
+ #ifdef FTD_ENABLED
+
+ User::LeaveIfError( iCodecStatsQueue.OpenGlobal( KMccCodecStats,
+ EOwnerProcess ) );
+ User::LeaveIfError( iJBufStatsQueue.OpenGlobal( KMccJBufferStats,
+ EOwnerProcess ) );
+
+ #endif
+ }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadDecoder::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CAmrPayloadDecoder* CAmrPayloadDecoder::NewL( TBool aIsNb )
+ {
+ DP_AMR_DECODE( "CAmrPayloadDecoder::NewL" );
+
+ CAmrPayloadDecoder* self = new( ELeave ) CAmrPayloadDecoder( aIsNb );
+
+ CleanupStack::PushL( self );
+ self->ConstructL( );
+ CleanupStack::Pop( self );
+
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadDecoder::~CAmrPayloadDecoder
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CAmrPayloadDecoder::~CAmrPayloadDecoder( )
+ {
+ DP_AMR_DECODE( "CAmrPayloadDecoder::~CAmrPayloadDecoder" );
+
+ delete iHeaderDecoder;
+ delete iTocEntryDecoder;
+
+ #ifdef FTD_ENABLED
+
+ iCodecStatsQueue.Close();
+ iJBufStatsQueue.Close();
+
+ #endif
+ }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadDecoder::DoInitialize
+// Initialize decoder. Decoder should be initialized when starting playing.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadDecoder::DoInitialize()
+ {
+ DP_AMR_DECODE( "CAmrPayloadDecoder::DoInitialize" );
+
+ }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadDecoder::DecodePayload
+// Decode payload data received in the payload buffer.
+// If AMR FEC is used and redundant frames are discarded, time stamp is
+// increased to correspond start of remaining frames.
+// -----------------------------------------------------------------------------
+//
+TInt CAmrPayloadDecoder::DecodePayload( TUint32& aTimeStamp, TUint32 aTimeStampInc )
+ {
+ DP_AMR_DECODE( "CAmrPayloadDecoder::DecodePayload" );
+
+ iTimeStamp = aTimeStamp;
+ iTimeStampInc = aTimeStampInc;
+ Decode( iPayload, iPayloadSize );
+ aTimeStamp = iTimeStamp;
+ iFrameIndex = 0;
+ return iDecodedFrames;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadDecoder::ModeRequest
+// Get AMR codec mode request ( CMR ) received in the payload.
+// -----------------------------------------------------------------------------
+//
+TAmrModeRequest CAmrPayloadDecoder::ModeRequest() const
+ {
+ DP_AMR_DECODE( "CAmrPayloadDecoder::ModeRequest" );
+
+ return iModeRequest;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadDecoder::Frames
+// Get AMR frames decoded from the payload.
+// -----------------------------------------------------------------------------
+//
+TAmrFrame* CAmrPayloadDecoder::Frames( )
+ {
+ DP_AMR_DECODE( "CAmrPayloadDecoder::Frames" );
+
+ return iFrames;
+ }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadDecoder::CompareBuffers
+// Compares contents of two buffers.
+// -----------------------------------------------------------------------------
+//
+TBool CAmrPayloadDecoder::CompareBuffers( const TDesC8& aBuffer,
+ const TAmrFrame& aFrameToCmp,
+ TInt aOctetsToCmp ) const
+ {
+ DP_AMR_DECODE( "CAmrPayloadDecoder::CompareBuffers" );
+
+ TBool isSame( ETrue );
+ if ( EAmrFrameNoData == aFrameToCmp.iFrameType )
+ {
+ if ( aBuffer.Size() )
+ {
+ return EFalse;
+ }
+ else
+ {
+ return ETrue;
+ }
+ }
+ else
+ {
+ if ( 0 == aBuffer.Size() )
+ {
+ return EFalse;
+ }
+ }
+
+ TStreamDecoder decoder;
+ decoder.Initialize( aFrameToCmp.iFrameData, 0, aFrameToCmp.iBitIndex );
+
+ TInt octetsToCmp = aOctetsToCmp < aBuffer.Size() ? aOctetsToCmp : aBuffer.Size();
+ for ( TInt i = 0; i < octetsToCmp && isSame; i++ )
+ {
+ TUint8 val = TUint8( decoder.Decode( KBitsIn1Byte ) );
+ if ( aBuffer[i] != val )
+ {
+ isSame = EFalse;
+ }
+ }
+
+ return isSame;
+ }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadDecoder::Decode
+// Decode the AMR payload ( for one RTP packet ) from a given buffer.
+// If more frames is received than expected based on SDPs PTIme negotiation,
+// we may have AMR FEC frames in a payload. Frames from previous payload are
+// compared to first frame in a new payload. If match is found we have received
+// that frame before and have redundant frames, which MUST be discarded.
+// After processing frames them are saved for redundancy check at next round.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadDecoder::Decode( const TUint8* aBuffer,
+ TInt aBufferSize )
+ {
+ DP_AMR_DECODE( "CAmrPayloadDecoder::Decode" );
+
+ TInt byteIndex( 0 );
+ TInt bitIndex( 0 );
+
+ // Decode Payload Header first
+ iHeaderDecoder->Decode( aBuffer, byteIndex, bitIndex );
+ iModeRequest = iHeaderDecoder->iCmr;
+
+ // Decode TOC entries
+ iDecodedFrames = DecodeTableOfContents( aBuffer, aBufferSize, byteIndex, bitIndex );
+
+ // Update frame positions in the `iFrames' array.
+ CalculateFramePosition( aBuffer, iDecodedFrames );
+
+ // Discard redundand frames already received
+ TUint framesToDel( 0 );
+ TInt numOfFramesSaved( iFrameDatas.Count() );
+ DP_AMR_DECODE2( "CAmrPayloadDecoder::Decode - NUM OF SAVED FRAMES %d", numOfFramesSaved );
+
+ DP_AMR_DECODE2( "CAmrPayloadDecoder::Decode - DECODED FRAMES %d", iDecodedFrames );
+
+ TInt i = 0;
+ TInt ind = 0;
+
+ #ifdef _DEBUG
+ if ( iDecodedFrames > KMaxFrameCountPerPacket )
+ {
+ DP_AMR_DECODE3("CAmrPayloadDecoder::Decode, iDecodedFrames: %d > KMaxFrameCountPerPacket: %d", \
+ iDecodedFrames , KMaxFrameCountPerPacket);
+ }
+ for ( i = 0; i < iDecodedFrames; i++ )
+ {
+ DP_AMR_DECODE2( "DECODED FRAME #%d: ", i );
+ if ( EAmrFrameNoData != iFrames[i].iFrameType )
+ {
+ TStreamDecoder decoder;
+ TUint8* refBufPtr = iFrames[i].iFrameData;
+ decoder.Initialize( refBufPtr, 0, iFrames[i].iBitIndex );
+ TUint32 vals[KNumValue5];
+ for ( ind = 0; ind < (TInt) KNumValue5; ind ++ )
+ {
+ vals[ind] = decoder.Decode( KBitsIn1Byte );
+ }
+ DP_AMR_DECODE6( "| %d | %d | %d | %d | %d |", vals[KNumValue0], vals[KNumValue1],
+ vals[KNumValue2], vals[KNumValue3], vals[KNumValue4] );
+ }
+ else
+ {
+ DP_AMR_DECODE( "DECODED FRAME - NO DATA FRAME" );
+ }
+ }
+
+ for ( i = 0; i < numOfFramesSaved; i++ )
+ {
+ if ( (*iFrameDatas[i] ).Size() )
+ {
+ DP_AMR_DECODE3( "SAVED FRAME #%d, l: %d", i, (*iFrameDatas[i] ).Size() );
+ }
+ else
+ {
+ DP_AMR_DECODE2( "SAVED FRAME #%d - NO DATA FRAME: ", i );
+ }
+ }
+ #endif
+
+ // Last frame in previous payload is always other than NO_DATA frame,
+ // so newly received frames can be compared to it.
+ TInt lastFrameInd = numOfFramesSaved - 1 >= 0 ? numOfFramesSaved - 1 : 0;
+ for ( i = 0; i < iDecodedFrames && numOfFramesSaved; i++ )
+ {
+ DP_AMR_DECODE2( "CMP LAST FRAME FROM PREV PAYLOAD TO NEW FRAME #%d", i );
+ if ( CompareBuffers( *iFrameDatas[lastFrameInd],
+ iFrames[i],
+ KMaxCompareOctets ) )
+ {
+ // Last frame from previous payload matched with some frame in a
+ // new payload. Frames from this point onwards can be accepted.
+ framesToDel = i + 1;
+ for ( ind = 0; ind < iDecodedFrames; ind++ )
+ {
+ iFrames[ ind ] = iFrames[ ind + framesToDel ];
+ }
+
+ i = iDecodedFrames; // Stop loop
+ iDecodedFrames -= framesToDel;
+ if ( iDecodedFrames <= 0 )
+ {
+ DP_AMR_DECODE( "Amr::Decode - NO FRAMES REMAINING AFTER RED CHECK" );
+ iDecodedFrames = 0;
+ }
+ iTimeStamp += iTimeStampInc * framesToDel;
+ }
+ }
+
+ DP_AMR_DECODE2( "NUMBER OF RED FRAMES SKIPPED %d: ", framesToDel );
+
+ // Save received frames for redundancy check purposes
+ if ( iDecodedFrames )
+ {
+ iFrameDatas.ResetAndDestroy();
+ }
+
+ if ( iDecodedFrames > KMaxFrameCountPerPacket )
+ {
+ DP_AMR_DECODE3("CAmrPayloadDecoder::Decode, iDecodedFrames: %d > KMaxFrameCountPerPacket: %d", \
+ iDecodedFrames , KMaxFrameCountPerPacket);
+ }
+ for ( i = 0; i < iDecodedFrames; i++ )
+ {
+ if ( EAmrFrameNoData != iFrames[i].iFrameType )
+ {
+ TInt dataLen = SpeechBitCount( iFrames[i].iFrameType );
+ HBufC8* frame = HBufC8::New( dataLen / KBitsIn1Byte + 1 );
+ if (frame)
+ {
+ TUint8* toBuf = const_cast<TUint8*>( ( *frame ).Ptr() );
+ TStreamEncoder encoder;
+ encoder.Initialize( toBuf, 0, 0 );
+ encoder.Encode( iFrames[i].iFrameData, 0, iFrames[i].iBitIndex, dataLen );
+ TPtr8 dataPtr = frame->Des();
+ dataPtr.SetLength( dataLen / KBitsIn1Byte + 1 );
+ if (iFrameDatas.Append( frame ) != KErrNone)
+ {
+ delete frame;
+ }
+ }
+ }
+ else
+ {
+ HBufC8* frame = HBufC8::New( 0 );
+ if (frame && iFrameDatas.Append( frame ) != KErrNone)
+ {
+ delete frame;
+ }
+ }
+ }
+
+ #ifdef FTD_ENABLED
+
+ TMccCodecStats stats;
+ stats.iCMRDownlink = iModeRequest;
+ stats.SetFieldUpdatedFlag( ECMRDownlink );
+ iCodecStatsQueue.Send( stats );
+
+ TMccJBufferStats jStats;
+ jStats.iRedLevel = framesToDel;
+ jStats.iSampleSizeMultiplier = iDecodedFrames;
+ jStats.SetFieldUpdatedFlag( ERedLevel );
+ jStats.SetFieldUpdatedFlag( ESampleSizeMultiplier );
+
+ iJBufStatsQueue.Send( jStats );
+
+ #endif
+ }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadDecoder::DecodeTableOfContents
+// Decode TOC ( Table of contents ) entries from the payload buffer.
+// Decoded values are put in `iFrames[]' array.
+// Return number of TOC entries decoded.
+// -----------------------------------------------------------------------------
+//
+TInt CAmrPayloadDecoder::DecodeTableOfContents( const TUint8* aBuffer,
+ TInt aBufferSize,
+ TInt& aByteIndex,
+ TInt& aBitIndex )
+ {
+ DP_AMR_DECODE( "CAmrPayloadDecoder::DecodeTableOfContents" );
+
+ TInt curChannel( 0 );
+ TInt i( 0 );
+
+ for ( i = 0; ( i < KMaxFrameCountPerPacket ) && ( aByteIndex < aBufferSize ); i++ )
+ {
+ iTocEntryDecoder->Decode( aBuffer, aByteIndex, aBitIndex );
+ iFrames[i].iFrameType = iTocEntryDecoder->iFrameType;
+ iFrames[i].iFrameQualityInd = iTocEntryDecoder->iFrameQualityInd;
+ iFrames[i].iChannel = curChannel;
+
+ if ( !( iTocEntryDecoder->iFrameFollowed ) )
+ {
+ break;
+ }
+
+ // Update currentChannel
+ curChannel++;
+ if ( curChannel == iChannelCount )
+ {
+ curChannel = 0;
+ }
+ }
+
+ return i + 1;
+ }
+
+// -----------------------------------------------------------------------------
+// CAmrPayloadDecoder::CalculateFramePosition
+// Calculate frames' starting Byte and Bit positions.
+// -----------------------------------------------------------------------------
+//
+void CAmrPayloadDecoder::CalculateFramePosition( const TUint8* aBuffer,
+ TInt aFrameCount )
+ {
+ DP_AMR_DECODE( "CAmrPayloadDecoder::CalculateFramePosition" );
+
+ TUint frameByteIndex;
+ TUint frameBitIndex;
+
+ // Number of bits for CMR and TOC entries
+ TUint bitCount = KHeaderBitsBE + KTOCFieldBitsBE * TUint( aFrameCount );
+
+ if ( aFrameCount > KMaxFrameCountPerPacket )
+ {
+ DP_AMR_DECODE3("CAmrPayloadDecoder::CalculateFramePosition, aFrameCount: %d > KMaxFrameCountPerPacket: %d", \
+ aFrameCount, KMaxFrameCountPerPacket);
+ }
+ for ( TInt i = 0; i < aFrameCount; i++ )
+ {
+ frameByteIndex = bitCount >> KNumValue3;
+ frameBitIndex = bitCount & KBitIndex7;
+ if ( EAmrFrameNoData == iFrames[i].iFrameType )
+ {
+ iFrames[i].iBitIndex = 0;
+ iFrames[i].iFrameData = NULL;
+ }
+ else
+ {
+ // Set frame byte and bit positions
+ iFrames[i].iBitIndex = frameBitIndex;
+ iFrames[i].iFrameData = const_cast<TUint8*>( aBuffer ) + frameByteIndex;
+ }
+
+ // Update bit-count for next frame entry.
+ bitCount = bitCount + TUint( SpeechBitCount( iFrames[i].iFrameType ) );
+ }
+ }
+
+
+// ========================== OTHER EXPORTED FUNCTIONS =========================
+
+// End of File
+