sl@0: // Copyright (c) 1997-2009 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: #include "MMFImaAdPcmToPcm16Codec.h" sl@0: #include "MMFImaAudioCodecState.h" sl@0: sl@0: #include // TMMFAudioConfig sl@0: #include // KUidMmfCodecAudioSettings sl@0: sl@0: const TUid KUidCodecAudioConfig = {KUidMmfCodecAudioSettings}; sl@0: sl@0: // __________________________________________________________________________ sl@0: // Implementation sl@0: sl@0: CMMFCodec* CMMFImaAdPcmPcm16Codec::NewL(TAny* aInitParams) sl@0: { sl@0: CMMFImaAdPcmPcm16Codec* self=new(ELeave) CMMFImaAdPcmPcm16Codec(); 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: CMMFImaAdPcmPcm16Codec::~CMMFImaAdPcmPcm16Codec() sl@0: { sl@0: } sl@0: sl@0: CMMFImaAdPcmPcm16Codec::CMMFImaAdPcmPcm16Codec() : iImaAdpcmTo16Pcm(1) sl@0: { sl@0: } sl@0: sl@0: void CMMFImaAdPcmPcm16Codec::ConstructL(TAny* /*aInitParams*/) sl@0: { sl@0: iTempSrcBufferPtr = iTempSrcBuffer; sl@0: iTempSrcBufferCount = 0; sl@0: sl@0: iChannels = 1; sl@0: iSamplesRate = 0; sl@0: iSamplesPerBlock = KImaAdpcmSamplesPerBlock; sl@0: iBlockAlign = KImaAdpcmBlockAlign; sl@0: } sl@0: sl@0: void CMMFImaAdPcmPcm16Codec::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: iImaAdpcmTo16Pcm.SetState(state); sl@0: iTempSrcBufferPtr = iTempSrcBuffer; sl@0: iTempSrcBufferCount = 0; sl@0: } sl@0: sl@0: /** sl@0: CMMFImaAdPcmPcm16Codec::ProcessL sl@0: sl@0: This function converts IMA ADPCM samples to PCM 16 samples, sl@0: it is for mono ADPCM only at the moment. sl@0: */ sl@0: TCodecProcessResult CMMFImaAdPcmPcm16Codec::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: 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 < (iSamplesPerBlock * 2)) sl@0: User::Leave(KErrArgument); sl@0: sl@0: if ((iSrc->FrameNumber() == 0) && (iDst->Position() == 0)) sl@0: { sl@0: ResetL(); sl@0: } 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 = iBlockAlign - iTempSrcBufferCount; sl@0: sl@0: if (srcToFillTempBuffer < sourceRemain) //enough source to fill temporary buffer sl@0: dstRemain -= (iSamplesPerBlock * 2); 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 / (iSamplesPerBlock * 2); sl@0: TUint maxUsableDst = blocksRemaining * iSamplesPerBlock * 2; sl@0: TUint srcToUse = blocksRemaining * iBlockAlign; 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 < iBlockAlign) && (srcLeft)) sl@0: { sl@0: *iTempSrcBufferPtr++ = *pSrc++; sl@0: iTempSrcBufferCount++; sl@0: srcLeft --; sl@0: } sl@0: sl@0: if (iTempSrcBufferCount == iBlockAlign) //temp buffer full sl@0: { sl@0: //reset sl@0: iTempSrcBufferCount = 0; sl@0: iTempSrcBufferPtr = iTempSrcBuffer; sl@0: sl@0: iImaAdpcmTo16Pcm.Convert(iTempSrcBufferPtr, pDst, iSamplesPerBlock); sl@0: sl@0: pDst += (iSamplesPerBlock * 2); sl@0: dstBytesAdded += (iSamplesPerBlock * 2); sl@0: } sl@0: } sl@0: sl@0: //convert full blocks sl@0: while (srcLeft >= iBlockAlign) sl@0: { sl@0: iImaAdpcmTo16Pcm.Convert(pSrc, pDst, iSamplesPerBlock); sl@0: sl@0: pSrc += iBlockAlign; sl@0: pDst += (iSamplesPerBlock * 2); sl@0: sl@0: dstBytesAdded += (iSamplesPerBlock * 2); sl@0: srcLeft -= iBlockAlign; sl@0: } sl@0: 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: } sl@0: sl@0: /** sl@0: Sets codec configuration. sl@0: sl@0: @param aConfigType sl@0: The UID of the codec to configure. sl@0: @param aConfigData sl@0: The configuration information. sl@0: */ sl@0: void CMMFImaAdPcmPcm16Codec::ConfigureL(TUid aConfigType, const TDesC8& aConfigData) sl@0: { sl@0: if (aConfigType != KUidCodecAudioConfig) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: const TMMFAudioConfig& audioConfig = static_cast&>(aConfigData)(); sl@0: sl@0: iChannels = audioConfig.iChannels; sl@0: iSamplesRate = audioConfig.iSampleRate; sl@0: sl@0: switch (iSamplesRate * iChannels) sl@0: { sl@0: case 8000: // fall through, same as 11025 sl@0: case 11025: sl@0: case 16000: sl@0: iBlockAlign = 256; sl@0: break; sl@0: case 22050: sl@0: iBlockAlign = 512; sl@0: break; sl@0: sl@0: case 44100: sl@0: iBlockAlign = 1024; sl@0: break; sl@0: sl@0: case 88200: sl@0: iBlockAlign = 2048; sl@0: break; sl@0: sl@0: default: sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: sl@0: // SamplesPerBlock = [(BlockAlign - 4 * Channels) * 8] / (BitsPerSample * Channels) + 1 sl@0: iSamplesPerBlock = (iBlockAlign - 4 * iChannels) * 8 / (KImaAdpcmBitsPerSample * iChannels) + 1; sl@0: } sl@0: sl@0: TInt CMMFImaAdPcmPcm16Codec::Extension_(TUint aExtensionId, TAny*& aExtPtr, TAny*) sl@0: { sl@0: if (aExtensionId == KUidCustomInterfaceDevSoundFileBlockLength.iUid) sl@0: { sl@0: aExtPtr = static_cast(this); sl@0: return KErrNone; sl@0: } sl@0: else sl@0: { sl@0: return CMMFCodec::Extension_(aExtensionId, aExtPtr, NULL); sl@0: } sl@0: } sl@0: sl@0: void CMMFImaAdPcmPcm16Codec::SetFileBlockLength(TUint aBlockAlign) sl@0: { sl@0: iBlockAlign = aBlockAlign; sl@0: iSamplesPerBlock = (iBlockAlign - 4 * iChannels) * 8 / (KImaAdpcmBitsPerSample * iChannels) + 1; sl@0: sl@0: } sl@0: