multimediacommscontroller/mmccamrpayloadformat/src/amrpayloaddecoder.cpp
changeset 0 1bce908db942
--- /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  
+