diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccredpayloadformat/src/mccreddecoder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multimediacommscontroller/mmccredpayloadformat/src/mccreddecoder.cpp Tue Feb 02 01:04:58 2010 +0200 @@ -0,0 +1,287 @@ +/* +* Copyright (c) 2005-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: Decoder capable to handle redundancy RTP payload. +* +*/ + + + + +// INCLUDE FILES +#include "mccreddecoder.h" +#include "streamformatter.h" +#include "mccredpayloadformatdefs.h" +#include "mccdef.h" + +const TInt KNumValue3 = 3; +const TInt KNumValue4 = 4; + +// ============================= LOCAL FUNCTIONS =============================== + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CMccRedDecoder::CMccRedDecoder +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CMccRedDecoder::CMccRedDecoder() + { + DP_RED_DECODE( "CMccRedDecoder::CMccRedDecoder" ) + } + +// ----------------------------------------------------------------------------- +// CMccRedDecoder::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CMccRedDecoder* CMccRedDecoder::NewL() + { + DP_RED_DECODE( "CMccRedDecoder::NewL" ) + + CMccRedDecoder* self = new( ELeave ) CMccRedDecoder; + return self; + } + +// Destructor +CMccRedDecoder::~CMccRedDecoder() + { + DP_RED_DECODE( "CMccRedDecoder::~CMccRedDecoder" ) + + iRedHeaderInfo.Close(); + } + +// ----------------------------------------------------------------------------- +// CMCCRedDecoder::DoInitializeL +// Initialize decoder after encoding parameters are changed or decoding is +// started again after a pause. +// ----------------------------------------------------------------------------- +// +void CMccRedDecoder::DoInitializeL( TInt aRedBlockCount, + TInt /*aMaxPayloadSize*/, + TInt /*aNumOfEncodings*/ ) + { + DP_RED_DECODE( "CMccRedDecoder::DoInitializeL" ) + + if ( KMaxRedCount >= aRedBlockCount ) + { + iRedBlockCount = aRedBlockCount; + iCurTimeStamp = 0; + iLatestTimeStamp = -1; + } + else + { + User::Leave( KErrArgument ); + } + } + +// ----------------------------------------------------------------------------- +// CMccRedDecoder::DecodePayload +// Decode encoding(s) from RTP payload given. +// ----------------------------------------------------------------------------- +// +TInt CMccRedDecoder::DecodePayload( TUint aCurTimeStamp ) + { + DP_RED_DECODE( "CMccRedDecoder::DecodePayload" ) + + iCurTimeStamp = aCurTimeStamp; + iRedHeaderInfo.Reset(); + iEncodings[EMccPrimaryEncoding]->Data().Zero(); + + TInt error = GetBlockInfos( iRedHeaderInfo, iRTPPayload->Data() ); + if ( KErrNone == error ) + { + // Ignore already received blocks + while ( iRedHeaderInfo.Count() + && static_cast( iRedHeaderInfo[0].iTimeStamp ) <= iLatestTimeStamp ) + { + DP_RED_ENCODE2( "BLOCK with TIMESTAMP %d REMOVED", + iRedHeaderInfo[0].iTimeStamp ) + iRedHeaderInfo.Remove( 0 ); + } + + // Separate encodings + for ( TInt i = 0; i < iRedHeaderInfo.Count(); i++ ) + { + if ( iRedHeaderInfo[i].iBlockPT + == iPayloadTypes[EMccPrimaryEncoding] ) + { + TDes8& primaryEnc = iEncodings[EMccPrimaryEncoding]->Data(); + primaryEnc.Append( iRedHeaderInfo[i].iBlockIndex, + iRedHeaderInfo[i].iBlockLength ); + } + else if ( iRedHeaderInfo[i].iBlockPT + == iPayloadTypes[EMccSecondaryEncoding] ) + { + TDes8& secondaryEnc = iEncodings[EMccSecondaryEncoding]->Data(); + secondaryEnc.Append( iRedHeaderInfo[i].iBlockIndex, + iRedHeaderInfo[i].iBlockLength ); + } + else if ( iRedHeaderInfo[i].iBlockPT == KComfortNoisePT ) + { + DP_RED_DECODE( "CMccRedDecoder::DecodePayload() - CN" ) + TDes8& primaryEnc = iEncodings[EMccPrimaryEncoding]->Data(); + primaryEnc.Append( iRedHeaderInfo[i].iBlockIndex, + iRedHeaderInfo[i].iBlockLength ); + } + else + { + DP_RED_ENCODE( "NOT SUPPORTED ENCODING, SKIPPED" ) + } + } + + iLatestTimeStamp = aCurTimeStamp; + return iRedHeaderInfo.Count(); + } + else + { + DP_RED_DECODE( "CMccRedDecoder::DecodePayload() - \ + ERROR with GetBlockInfos" ) + + iEncodings[EMccPrimaryEncoding]->Data().Zero(); + return error; + } + } + + +// ----------------------------------------------------------------------------- +// CMccRedDecoder::GetBlockInfos +// Get block indexes. Redundant blocks are ignored based on timestamp. +// Timestamp of the primary data block is saved. Data validity is verified by +// checking that decoded block indexes are inside bounds and overall length of +// decoded data blocks is not greater than RPT payload length. Time stamps +// are also checked that they are in increasing order. +// ----------------------------------------------------------------------------- +// +TInt CMccRedDecoder::GetBlockInfos( RArray& aBlockInfos, + const TDesC8& aRTPPayload ) + { + DP_RED_DECODE( "CMccRedDecoder::GetBlockInfos" ) + + if ( 0 == aRTPPayload.Size() ) + { + return KErrArgument; + } + + const TUint8* seekPtr = aRTPPayload.Ptr(); + + TStreamDecoder streamDecoder; + streamDecoder.Initialize( const_cast( seekPtr ), 0, 0 ); + + TBool FBitSet( ETrue ); + TInt allBlockLength(0); // For data validity check + + // Go through redundancy headers and count audio frame blocks + // Determine number of redundant frame blocks to ignore based on timestamp + TUint frameBlockCount(0); + + while ( FBitSet ) + { + frameBlockCount++; + TRedHeaderInfo curInfo; + + FBitSet = static_cast( streamDecoder.Decode( KFBitLength ) ); + curInfo.iBlockPT = static_cast( streamDecoder.Decode( KPTFieldBits ) ); + + if ( FBitSet ) + { + TUint offset = streamDecoder.Decode( KTSOffsetBits ); + curInfo.iTimeStamp = iCurTimeStamp - offset; + curInfo.iBlockLength = streamDecoder.Decode( KBlockLengthBits ); + + allBlockLength += curInfo.iBlockLength; + + DP_RED_DECODE6( "DEC RED_HEADER NUM %d: F:%d PT:%d \ + TIMESTAMP:%d, BL:%d", frameBlockCount, ETrue, curInfo.iBlockPT, + curInfo.iTimeStamp, curInfo.iBlockLength ) + + // Jump to the beginning of next redundancy header + streamDecoder.Initialize( const_cast( seekPtr ), + frameBlockCount * KNumValue4, 0 ); + } + else + { + // Primary data block's time stamp + curInfo.iTimeStamp = iCurTimeStamp; + DP_RED_DECODE5( "DEC FINAL RED_HEADER %d: F:%d PT:%d \ + #TIMESTAMP#:%d", frameBlockCount, 0, curInfo.iBlockPT, + curInfo.iTimeStamp ) + } + + TInt err = aBlockInfos.Append( curInfo ); + if ( err ) + { + return err; + } + } + + // Calculate frame block indexes + frameBlockCount = aBlockInfos.Count(); + TUint8* firstBlockIndex = ( const_cast( seekPtr ) + + frameBlockCount * KRedHeaderSize - KNumValue3 ); + aBlockInfos[0].iBlockIndex = firstBlockIndex; + + for( TUint i = 1; i < frameBlockCount; i++ ) + { + aBlockInfos[i].iBlockIndex + = firstBlockIndex + aBlockInfos[i - 1].iBlockLength; + } + + // Length of the last block + const TUint8* endPtr = aRTPPayload.Ptr() + aRTPPayload.Length(); + TInt lastIndex( aBlockInfos.Count() - 1 ); + aBlockInfos[lastIndex].iBlockLength = + endPtr - aBlockInfos[lastIndex].iBlockIndex; + + allBlockLength += aBlockInfos[lastIndex].iBlockLength; + + // Check data validity + for ( TUint i = 0; i < frameBlockCount - 1; i++ ) + { + // Check time stamps contiguousness + if ( aBlockInfos[i].iTimeStamp > aBlockInfos[i+1].iTimeStamp ) + { + return KErrCorrupt; + } + + // Check index bounds + if ( aBlockInfos[i].iBlockIndex < firstBlockIndex + || aBlockInfos[i].iBlockIndex > endPtr ) + { + return KErrCorrupt; + } + + TUint plLen = static_cast( aRTPPayload.Length() ); + if ( aBlockInfos[i].iBlockLength < 1 || aBlockInfos[i+1].iBlockLength < 1 + || plLen < aBlockInfos[i].iBlockLength ) + { + return KErrCorrupt; + } + } + + // Check overall block lengths + if ( aRTPPayload.Length() < allBlockLength || 0 > allBlockLength ) + { + return KErrCorrupt; + } + else + { + return KErrNone; + } + } + +// ========================== OTHER EXPORTED FUNCTIONS ========================= + +// End of File