sl@0: /*
sl@0: * Copyright (c) 1997-2002 Nokia Corporation and/or its subsidiary(-ies).
sl@0: * All rights reserved.
sl@0: * This component and the accompanying materials are made available
sl@0: * under the terms of "Eclipse Public License v1.0"
sl@0: * which accompanies this distribution, and is available
sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: *
sl@0: * Initial Contributors:
sl@0: * Nokia Corporation - initial contribution.
sl@0: *
sl@0: * Contributors:
sl@0: *
sl@0: * Description:
sl@0: *
sl@0: */
sl@0: 
sl@0: 
sl@0: 
sl@0: #include "MMFPcm16ToImaAdPcmCodec.h"
sl@0: 
sl@0: // __________________________________________________________________________
sl@0: // Implementation
sl@0: 
sl@0: CMMFCodec* CMMFPcm16ImaAdPcmCodec::NewL(TAny* aInitParams)
sl@0: 	{
sl@0: 	CMMFPcm16ImaAdPcmCodec* self=new(ELeave) CMMFPcm16ImaAdPcmCodec();
sl@0: 	CleanupStack::PushL(self);
sl@0: 	self->ConstructL(aInitParams);
sl@0: 	CleanupStack::Pop(self);
sl@0: 	return STATIC_CAST( CMMFCodec*, self );
sl@0: 	}
sl@0: 
sl@0: CMMFPcm16ImaAdPcmCodec::~CMMFPcm16ImaAdPcmCodec()
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: CMMFPcm16ImaAdPcmCodec::CMMFPcm16ImaAdPcmCodec() : i16PcmToImaAdpcm(1)
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: void CMMFPcm16ImaAdPcmCodec::ConstructL(TAny*  /*aInitParams*/)
sl@0: 	{
sl@0: 	iTempSrcBufferPtr = iTempSrcBuffer;
sl@0: 	iTempSrcBufferCount = 0;
sl@0: 	}
sl@0: 
sl@0: void CMMFPcm16ImaAdPcmCodec::ResetL()
sl@0: 	{
sl@0: 	//Reset the actual codec
sl@0: 	TMMFImaAdpcmCodecStateOld state;
sl@0: 	state.iIndex = 0;
sl@0: 	state.iPredicted = 0;
sl@0: 	i16PcmToImaAdpcm.SetState(state);
sl@0: 	iTempSrcBufferPtr = iTempSrcBuffer;
sl@0: 	iTempSrcBufferCount = 0;
sl@0: 	}
sl@0: 
sl@0: /*************************************************************
sl@0: CMMFPcm16ImaAdPcmCodec::ProcessL
sl@0: 
sl@0: This function converts PCM samples to IMA ADPCM samples in
sl@0: blocks of KImaAdpcmBlockAlign (256) bytes. 1010 source 
sl@0: bytes are required to fill a 256 byte block.
sl@0: **************************************************************/
sl@0: TCodecProcessResult CMMFPcm16ImaAdPcmCodec::ProcessL(const CMMFBuffer& aSrc, CMMFBuffer& aDst)
sl@0: 	{
sl@0: 	TCodecProcessResult result;
sl@0: 	result.iStatus = TCodecProcessResult::EProcessIncomplete;
sl@0: 
sl@0: 	//convert from generic CMMFBuffer to CMMFDataBuffer
sl@0: 	iSrc = STATIC_CAST(const CMMFDataBuffer*, &aSrc);
sl@0: 	iDst = STATIC_CAST(CMMFDataBuffer*, &aDst);
sl@0: 
sl@0: 	// If the Destination is set to zero, ensure the Codec is fully reset,
sl@0: 	// as this may be a reposition
sl@0: 	if ((iSrc->FrameNumber() == 0) && (iDst->Position() == 0))
sl@0: 		{
sl@0: 		ResetL();
sl@0: 		}
sl@0: 
sl@0: 
sl@0: 	const TUint srcLen = iSrc->Data().Length();
sl@0: 	const TUint dstMaxLen = iDst->Data().MaxLength();
sl@0: 	const TUint sourceRemain = srcLen - iSrc->Position();
sl@0: 
sl@0: 	if (dstMaxLen < KImaAdpcmBlockAlign)
sl@0: 		User::Leave(KErrArgument);
sl@0: 
sl@0: 	//reset data if not a consecutive frame number
sl@0: 	if ((iSrc->FrameNumber() != iLastFrameNumber) && (iSrc->FrameNumber() != (iLastFrameNumber+1)))
sl@0: 		{
sl@0: 		iTempSrcBufferPtr = iTempSrcBuffer;
sl@0: 		iTempSrcBufferCount = 0;
sl@0: 		}
sl@0: 	iLastFrameNumber = iSrc->FrameNumber();
sl@0: 
sl@0: 	TUint dstRemain = (dstMaxLen - iDst->Position());	
sl@0: 	TUint srcToFillTempBuffer = 0;
sl@0: 
sl@0: 	//take account of src to be added to temporary buffer
sl@0: 	if (iTempSrcBufferCount > 0)
sl@0: 		{
sl@0: 		srcToFillTempBuffer = KImaAdpcmTempBufferSize - iTempSrcBufferCount;
sl@0: 		if (srcToFillTempBuffer<sourceRemain) //enough source to fill temporary buffer
sl@0: 			dstRemain -= KImaAdpcmBlockAlign;
sl@0: 		else //not enough source to fill the temporary buffer
sl@0: 			srcToFillTempBuffer = sourceRemain;
sl@0: 		}
sl@0: 
sl@0: 	//calculate how much source is required to fill the destination buffer
sl@0: 	TUint blocksRemaining = dstRemain/KImaAdpcmBlockAlign;
sl@0: 	TUint maxUsableDst = blocksRemaining * KImaAdpcmBlockAlign;
sl@0: 	TUint srcToUse = blocksRemaining * KImaAdpcmSamplesPerBlock * 2;
sl@0: 
sl@0: 	srcToUse += srcToFillTempBuffer;
sl@0: 	srcToUse = (srcToUse<sourceRemain ? srcToUse : sourceRemain);
sl@0: 
sl@0: 	//we need to cast away CONST even on the source, as the TClass needs a TUint8*
sl@0: 	TUint8* pSrc = CONST_CAST(TUint8*,iSrc->Data().Ptr());
sl@0: 	pSrc += iSrc->Position();
sl@0: 	TUint8* pDst = CONST_CAST(TUint8*,iDst->Data().Ptr());
sl@0: 	pDst += iDst->Position();
sl@0: 	
sl@0: 	TUint dstBytesAdded = 0;
sl@0: 	TUint srcLeft = srcToUse;
sl@0: 
sl@0: 	//convert remaining source from previous call to ProcessL
sl@0: 	if (iTempSrcBufferCount > 0)
sl@0: 		{
sl@0: 		//Fill temp buffer from source buffer
sl@0: 		while((iTempSrcBufferCount < KImaAdpcmTempBufferSize) && (srcLeft))
sl@0: 			{
sl@0: 			*iTempSrcBufferPtr++ = *pSrc++;
sl@0: 			iTempSrcBufferCount++;
sl@0: 			srcLeft--;
sl@0: 			}
sl@0: 
sl@0: 		if (iTempSrcBufferCount == KImaAdpcmTempBufferSize)
sl@0: 			{
sl@0: 			//reset
sl@0: 			iTempSrcBufferCount = 0;
sl@0: 			iTempSrcBufferPtr = iTempSrcBuffer;
sl@0: 
sl@0: 			i16PcmToImaAdpcm.Convert(iTempSrcBufferPtr, pDst, KImaAdpcmSamplesPerBlock);
sl@0: 
sl@0: 			pDst += KImaAdpcmBlockAlign;
sl@0: 			dstBytesAdded += KImaAdpcmBlockAlign;
sl@0: 			}
sl@0: 		}
sl@0: 
sl@0: 	//convert full blocks
sl@0: 	while (srcLeft >= (KImaAdpcmSamplesPerBlock*2)) 
sl@0: 		{
sl@0: 		i16PcmToImaAdpcm.Convert(pSrc, pDst, KImaAdpcmSamplesPerBlock);
sl@0: 
sl@0: 		pSrc += KImaAdpcmSamplesPerBlock*2;
sl@0: 		pDst += KImaAdpcmBlockAlign;
sl@0: 
sl@0: 		dstBytesAdded += KImaAdpcmBlockAlign;	
sl@0: 		srcLeft -= KImaAdpcmSamplesPerBlock*2;	
sl@0: 		}
sl@0: 
sl@0: 	//save remaining source in iTempSrcBuffer
sl@0: 	while (srcLeft)
sl@0: 		{
sl@0: 		*iTempSrcBufferPtr++ = *pSrc++;
sl@0: 		iTempSrcBufferCount++;
sl@0: 		srcLeft--;
sl@0: 		}
sl@0: 
sl@0: 	//if the source buffer is consumed
sl@0: 	if ((srcLen == srcToUse + iSrc->Position()))
sl@0: 		{
sl@0: 		if (dstBytesAdded < maxUsableDst)
sl@0: 			result.iStatus = TCodecProcessResult::EDstNotFilled;
sl@0: 		else
sl@0: 			result.iStatus = TCodecProcessResult::EProcessComplete;
sl@0: 		}
sl@0: 
sl@0: 	result.iSrcBytesProcessed = srcToUse;
sl@0: 	result.iDstBytesAdded = dstBytesAdded;
sl@0: 
sl@0: 	iDst->Data().SetLength(iDst->Position() + result.iDstBytesAdded);
sl@0: 
sl@0: 	return result;	
sl@0: 	}