sl@0: // Copyright (c) 2005-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: #include "MmfBtAudioCodec.h" sl@0: #include sl@0: #include "MmfBtImaAdpcmToPcm16HwDevice.h" sl@0: #include "../../MmfBtFileDependencyUtil.h" sl@0: sl@0: /** sl@0: * sl@0: * NewL sl@0: * sl@0: */ sl@0: CMMFImaAdpcmToPcm16CodecHwDevice* CMMFImaAdpcmToPcm16CodecHwDevice::NewL() sl@0: { sl@0: CMMFImaAdpcmToPcm16CodecHwDevice* self=new(ELeave)CMMFImaAdpcmToPcm16CodecHwDevice(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: * sl@0: * ConstructL sl@0: * sl@0: */ sl@0: void CMMFImaAdpcmToPcm16CodecHwDevice::ConstructL() sl@0: { sl@0: iCodec = new (ELeave) CMMFImaAdpcmToPcm16Codec(); sl@0: } sl@0: sl@0: /** sl@0: * sl@0: * ~CMMFMulawPcm16HwDevice sl@0: * sl@0: */ sl@0: CMMFImaAdpcmToPcm16CodecHwDevice::~CMMFImaAdpcmToPcm16CodecHwDevice() sl@0: { sl@0: } sl@0: sl@0: /** sl@0: * sl@0: * Codec sl@0: * sl@0: */ sl@0: CMMFSwCodec &CMMFImaAdpcmToPcm16CodecHwDevice::Codec() sl@0: { sl@0: return *iCodec; sl@0: } sl@0: sl@0: /** sl@0: @see CMMFSwCodecWrapper::Start sl@0: sl@0: this function sets SampleRate and Channels for CMMFImaAdpcmToPcm16Codec sl@0: */ sl@0: TInt CMMFImaAdpcmToPcm16CodecHwDevice::Start(TDeviceFunc aFuncCmd, TDeviceFlow aFlowCmd) sl@0: { sl@0: TInt err = CMMFSwCodecWrapper::Start(aFuncCmd, aFlowCmd); sl@0: if (err != 0) sl@0: return err; sl@0: return ((CMMFImaAdpcmToPcm16Codec*)iCodec)->Configure(iChannels, iSampleRate); sl@0: } sl@0: sl@0: CMMFImaAdpcmToPcm16Codec::CMMFImaAdpcmToPcm16Codec() sl@0: { sl@0: iChannels = 1; sl@0: iSampleRate = 0; sl@0: iBlockAlign = KImaAdpcmBlockAlign; sl@0: iSamplesPerBlock = KImaAdpcmSamplesPerBlock; sl@0: } sl@0: /** sl@0: * sl@0: * ProcessL sl@0: * @param aSrc sl@0: * @param aDst sl@0: * @pre position of buffer aSrc is 0 sl@0: * @pre position of buffer aDst is 0 sl@0: * @pre sufficient bytes in output to consume input sl@0: * @return TCodecProcessResult sl@0: * This function converts IMA ADPCM samples to PCM samples. sl@0: * sl@0: */ sl@0: CMMFSwCodec::TCodecProcessResult CMMFImaAdpcmToPcm16Codec::ProcessL(const CMMFBuffer& aSrc, CMMFBuffer& aDst) sl@0: { sl@0: CMMFSwCodec::TCodecProcessResult result; sl@0: result.iCodecProcessStatus = result.iCodecProcessStatus = TCodecProcessResult::EProcessComplete; sl@0: sl@0: //convert from generic CMMFBuffer to CMMFDataBuffer sl@0: const CMMFDataBuffer* src = STATIC_CAST(const CMMFDataBuffer*, &aSrc); sl@0: CMMFDataBuffer* dst = STATIC_CAST(CMMFDataBuffer*, &aDst); sl@0: sl@0: if( !CheckPreconditions( src, dst ) ) sl@0: { sl@0: //[ precondition(s) violation ] sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: //calculate how much source is required to fill the destination buffer sl@0: TUint blocksRemaining = src->Data().Length() / iBlockAlign; 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*,src->Data().Ptr()); sl@0: TUint8* pDst = CONST_CAST(TUint8*,dst->Data().Ptr()); sl@0: sl@0: //[ [process full blocks ] sl@0: TUint dstBytesAdded = 0; sl@0: for( TUint count = 0; count < blocksRemaining; count++ ) sl@0: { sl@0: iImaAdpcmTo16Pcm.Convert(pSrc, pDst, iSamplesPerBlock); sl@0: pSrc += iBlockAlign; sl@0: pDst += (iSamplesPerBlock * sizeof(TInt16)); sl@0: dstBytesAdded += (iSamplesPerBlock * sizeof(TInt16)); sl@0: } sl@0: sl@0: result.iCodecProcessStatus = TCodecProcessResult::EProcessComplete; sl@0: result.iSrcBytesProcessed = blocksRemaining * iBlockAlign; sl@0: result.iDstBytesAdded = dstBytesAdded; sl@0: dst->Data().SetLength(result.iDstBytesAdded); sl@0: sl@0: //[ check post conditions sl@0: __ASSERT_DEBUG( (src->Position() == 0), TMmfAudioCodecPanicsNameSpace::Panic( TMmfAudioCodecPanicsNameSpace::EPostConditionViolation )); sl@0: __ASSERT_DEBUG( (dst->Position() == 0), TMmfAudioCodecPanicsNameSpace::Panic( TMmfAudioCodecPanicsNameSpace::EPostConditionViolation )); sl@0: TInt r1 = src->Data().Length(); sl@0: r1 /= iBlockAlign; sl@0: TInt r2 = dst->Data().Length(); sl@0: r2 /=(iSamplesPerBlock * sizeof(TInt16)); sl@0: __ASSERT_DEBUG( r1== r2, TMmfAudioCodecPanicsNameSpace::Panic(TMmfAudioCodecPanicsNameSpace::EPostConditionViolation )); sl@0: __ASSERT_DEBUG( dst->Data().Length() % 2 == 0, TMmfAudioCodecPanicsNameSpace::Panic( TMmfAudioCodecPanicsNameSpace::EPostConditionViolation )); // pcm output sl@0: sl@0: return result; sl@0: } sl@0: sl@0: /** sl@0: * sl@0: * Preconditions sl@0: * This methos tests the preconditions of the ProcessL method sl@0: * @return TBool ETrue for sucess and EFalse for failure of the preconditions sl@0: * sl@0: **/ sl@0: TBool CMMFImaAdpcmToPcm16Codec::CheckPreconditions( const CMMFDataBuffer* aSrcBuffer, CMMFDataBuffer* aDestBuffer ) sl@0: { sl@0: TBool result = EFalse; sl@0: sl@0: if(! aSrcBuffer ) sl@0: { sl@0: return result; sl@0: } sl@0: sl@0: if( ! aDestBuffer ) sl@0: { sl@0: return result; sl@0: } sl@0: sl@0: // Check position of src and dest are 0 sl@0: if( aSrcBuffer->Position() ) sl@0: { sl@0: return result; sl@0: } sl@0: sl@0: // Check position of src and dest are 0 sl@0: if( aDestBuffer->Position() ) sl@0: { sl@0: return result; sl@0: } sl@0: sl@0: // check there are sufficient bytes in the output to consume the input sl@0: const TUint KTempBufferSize = iSamplesPerBlock * 2; sl@0: TInt numInputSubFrames = aSrcBuffer->Data().Length() / iBlockAlign; sl@0: TInt numOutputSubFrames = aDestBuffer->Data().MaxLength() / KTempBufferSize; sl@0: sl@0: //[ we need modulo 1010 bytes on all src frames that are not the last sl@0: // frame sl@0: // For the last frame we will code only whole frames and effectively sl@0: // drop any remaining samples] sl@0: TBool validInputDataLength = (aSrcBuffer->Data().Length() % iBlockAlign == 0) ; sl@0: sl@0: if( (numInputSubFrames > numOutputSubFrames) || // sufficient space in the output for the input sl@0: (aSrcBuffer->Position() > 0 ) || // position must be zero since we can eat all the data sl@0: (aDestBuffer->Position() > 0 ) || sl@0: (!validInputDataLength)) //position must be zero sl@0: { sl@0: return result; sl@0: } sl@0: sl@0: result = ETrue; // preconditions have been satisfied sl@0: sl@0: return result; sl@0: } sl@0: sl@0: TInt CMMFImaAdpcmToPcm16Codec::Configure(TUint aChannels, TUint aSampleRate) sl@0: { sl@0: iChannels = aChannels; sl@0: iSampleRate = aSampleRate; sl@0: sl@0: switch (iSampleRate * 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: return KErrArgument; sl@0: } sl@0: sl@0: const TUint KImaAdpcmBitsPerSample = 4; sl@0: // SamplesPerBlock = [(BlockAlign - 4 * Channels) * 8] / (BitsPerSample * Channels) + 1 sl@0: iSamplesPerBlock = (iBlockAlign - 4 * iChannels) * 8 / (KImaAdpcmBitsPerSample * iChannels) + 1; sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: