sl@0: // Copyright (c) 2003-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: // EPOC includes sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: // Test system includes sl@0: #include "tsu_mmf_CodecTests.h" sl@0: #include "TSU_MMF_DeviceSuite.h" sl@0: sl@0: //[codec includes ] sl@0: #include sl@0: #include "MmfPcm16toAlawhwDevice.h" sl@0: #include "MmfALawToPcm16HwDevice.h" sl@0: #include "mmfpcm16toMulawhwdevice.h" sl@0: #include "MmfMuLawToPcm16hwDevice.h" sl@0: #include "mmfpcmS8ToPcmS16HwDevice.h" sl@0: #include "mmfpcmS16PcmS8HwDevice.h" sl@0: #include "mmfpcm16topcmU16BEHwDevice.h" sl@0: #include "mmfpcm16SwapEndianhwdevice.h" sl@0: #include "mmfpcm16ToImaAdpcm.h" sl@0: #include "MmfImaAdpcmtopcm16hwdevice.h" sl@0: #include "MMFpcm16ToPcm16HwDevice.h" sl@0: #include "MMFpcm16ToPcmU8HwDevice.h" sl@0: #include "MMFpcmU8ToPcm16HwDevice.h" sl@0: #include "mmfpcmS16PcmS8HwDevice.h" sl@0: sl@0: const TInt KFmtChunkSize = 16; sl@0: const TInt KAuMagic = 0x2e736e64; sl@0: sl@0: //[ Codec Unit tests structure sl@0: // The unit tests shall use text files sl@0: // for small portions of test data sl@0: // which should be stored are stored in a simple format sl@0: // containing the relevant parameters for the test sl@0: //] sl@0: class TCodecUnitTestParams sl@0: { sl@0: public: sl@0: const TText* iTestName; // name of the test sl@0: const TText* iInputFilename; // input wav file sl@0: const TText* iComparisonFileName; // output wav file sl@0: TInt iExpectedResult; // expected result sl@0: }; sl@0: sl@0: // constant table of parameters for tests sl@0: const TCodecUnitTestParams KTestParameters[] = sl@0: { sl@0: { sl@0: _S("MM-MMF-SWCODECDEVICES-U-0010-HP"), sl@0: _S("Pcm16Mono8khz400hzTone.wav"), sl@0: _S("Pcm16BMono8Khz400hzTone.Au"), sl@0: KErrNone sl@0: }, sl@0: sl@0: { sl@0: _S("MM-MMF-SWCODECDEVICES-U-0011-HP"), sl@0: _S("Pcm16Mono8khz400hzTone.wav"), sl@0: _S("Imaad4BitMono8Khz400hzTone.wav"), sl@0: KErrNone sl@0: }, sl@0: sl@0: { sl@0: _S("MM-MMF-SWCODECDEVICES-U-0012-HP"), sl@0: _S("Imaad4BitMono8Khz400hzTone.wav"), sl@0: _S("Pcm16Mono8khz400hzTone.wav"), sl@0: KErrNone sl@0: }, sl@0: sl@0: { sl@0: _S("MM-MMF-SWCODECDEVICES-U-0014-HP"), sl@0: _S("Pcm16Mono8khz400hzTone.wav"), sl@0: _S("PcmU8Mono8khz400hzTone.wav"), sl@0: KErrNone sl@0: }, sl@0: sl@0: { sl@0: _S("MM-MMF-SWCODECDEVICES-U-0015-HP"), sl@0: _S("PcmU8Mono8khz400hzTone.wav"), sl@0: _S("Pcm16Mono8khz400hzTone.wav"), sl@0: KErrNone sl@0: }, sl@0: sl@0: { sl@0: _S("MM-MMF-SWCODECDEVICES-U-0016-HP"), sl@0: _S("Pcm16Stereo8khz400hzTone.wav"), sl@0: _S("PcmU8Stereo8khz400hzTone.wav"), sl@0: KErrNone sl@0: }, sl@0: }; sl@0: sl@0: /** sl@0: * sl@0: * Print8BitResults sl@0: * @param aRefCodedData sl@0: * @param aCodedData sl@0: * @param aDataLength sl@0: * sl@0: **/ sl@0: template sl@0: void CTestStepCodecUnitTest::Print8BitResults( TUint8* aRefCodedData, TUint8* aCodedData, TInt aDataLength ) sl@0: { sl@0: __ASSERT_DEBUG(aRefCodedData,Panic(EBadArgument)); sl@0: __ASSERT_DEBUG(aCodedData,Panic(EBadArgument)); sl@0: sl@0: for( TInt i = 0; i < aDataLength; i++ ) sl@0: { sl@0: INFO_PRINTF6( _L("delta %u p1 %u p2 %u p1 %x p2 %x"), (*aRefCodedData-*aCodedData),*aRefCodedData, *aCodedData, *aRefCodedData, *aCodedData ); sl@0: aRefCodedData++; sl@0: aCodedData++; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: * sl@0: * Print16BitResults sl@0: * @param aRefCodedData sl@0: * @param aCodedData sl@0: * @param aDataLength sl@0: * sl@0: **/ sl@0: template sl@0: void CTestStepCodecUnitTest::Print16BitResults( TUint8* aRefCodedData, TUint8* aCodedData, TInt aDataLength ) sl@0: { sl@0: //[precondition pointers are aok] sl@0: __ASSERT_DEBUG(aRefCodedData,Panic(EBadArgument)); sl@0: __ASSERT_DEBUG(aCodedData,Panic(EBadArgument)); sl@0: //[precondition data is of even length ] sl@0: __ASSERT_DEBUG( (aDataLength % 2 == 0),Panic(EBadArgument)); sl@0: sl@0: TInt length = aDataLength /2; sl@0: TInt16 refCodedValue = 0; sl@0: TInt16 codedValue = 0; sl@0: for( TInt i = 0; i < length; i++ ) sl@0: { sl@0: refCodedValue = static_cast( aRefCodedData[0] ); sl@0: refCodedValue |= static_cast((aRefCodedData[1] << 8 )); sl@0: codedValue = static_cast( aCodedData[0] &KAndMask8bit); sl@0: codedValue |= static_cast((aCodedData[1] << 8 )); sl@0: INFO_PRINTF6( _L("delta %d p1 %d p2 %d p1 %x p2 %x"), (refCodedValue-codedValue),refCodedValue, codedValue, refCodedValue, codedValue ); sl@0: aRefCodedData+=2; sl@0: aCodedData+=2; sl@0: } sl@0: } sl@0: /** sl@0: * sl@0: * CTestStepCodecUnitTest sl@0: * sl@0: **/ sl@0: template sl@0: CTestStepCodecUnitTest::CTestStepCodecUnitTest( TUint aTestIndex ) sl@0: { sl@0: //[precondition valid index ] sl@0: // __ASSERT_DEBUG( (aTestIndex >= 0),Panic(EBadArgument)); // EABI warning removal sl@0: __ASSERT_DEBUG( (aTestIndex < (sizeof(KTestParameters)/sizeof(TCodecUnitTestParams))),Panic(EBadArgument)); sl@0: // store a pointer to the test parameters sl@0: iTestParameters = &(KTestParameters[aTestIndex]); sl@0: // store the name of this test case sl@0: // this is the name that is used by the script file sl@0: iTestStepName = iTestParameters->iTestName; sl@0: } sl@0: sl@0: /** sl@0: * sl@0: * ~CTestStepCodecUnitTest sl@0: * sl@0: **/ sl@0: template sl@0: CTestStepCodecUnitTest::~CTestStepCodecUnitTest() sl@0: { sl@0: } sl@0: /** sl@0: * sl@0: * DoTestStepL sl@0: * sl@0: **/ sl@0: template sl@0: TVerdict CTestStepCodecUnitTest::DoTestStepL() sl@0: { sl@0: __MM_HEAP_MARK; sl@0: TVerdict result = EPass; sl@0: sl@0: // code and decode the input file sl@0: TInt numBuffersToProcess = ComputeBuffersToProcess(); sl@0: TInt codedBufferSize = numBuffersToProcess*iCodecUnderTest->SinkBufferSize(); sl@0: iCodedData = CMMFDescriptorBuffer::NewL( codedBufferSize); sl@0: // Compare the results and return test status sl@0: TUint8* ptrSrc = CONST_CAST(TUint8*,iSourceData->Data().Ptr()); sl@0: TUint8* ptrDest = CONST_CAST(TUint8*,iCodedData->Data().Ptr()); sl@0: CMMFDataBuffer* srcBuffer = CMMFDescriptorBuffer::NewL(iCodecUnderTest->SourceBufferSize()); sl@0: CleanupStack::PushL(srcBuffer); sl@0: CMMFDataBuffer* destBuffer = CMMFDescriptorBuffer::NewL(iCodecUnderTest->SinkBufferSize()); sl@0: TUint8* pInBuffer = CONST_CAST(TUint8*,srcBuffer->Data().Ptr()); sl@0: TUint8* pOutBuffer = CONST_CAST(TUint8*,destBuffer->Data().Ptr()); sl@0: CleanupStack::PushL(destBuffer); sl@0: sl@0: for( TInt i = 0; i < numBuffersToProcess; i++) sl@0: { sl@0: //[ copy data & increment input pointer] sl@0: Mem::Copy( pInBuffer, ptrSrc, iCodecUnderTest->SourceBufferSize() ); sl@0: srcBuffer->Data().SetLength( iCodecUnderTest->SourceBufferSize() ); sl@0: ptrSrc+= iCodecUnderTest->SourceBufferSize(); sl@0: sl@0: //[ code the data ] sl@0: iCodecUnderTest->ProcessL( *srcBuffer, *destBuffer); sl@0: sl@0: //[ copy out the data & increment pointer ] sl@0: Mem::Copy( ptrDest, pOutBuffer, iCodecUnderTest->SinkBufferSize() ); sl@0: iCodedData->Data().SetLength( (i+1)*iCodecUnderTest->SinkBufferSize() ); sl@0: destBuffer->Data().SetLength(0); // reset buffer length sl@0: ptrDest+=iCodecUnderTest->SinkBufferSize(); sl@0: } sl@0: sl@0: //[ compare the coded data against the reference data] sl@0: //[ compare the processed number of bytes in the sl@0: // coded buffer to the reference data] sl@0: __ASSERT_DEBUG( iRefCodedData->Data().Length() >= iCodedData->Data().Length(),Panic(EBadInvariant)); sl@0: sl@0: TUint8* ptr1 = CONST_CAST(TUint8*,iRefCodedData->Data().Ptr()); sl@0: TUint8* ptr2 = CONST_CAST(TUint8*,iCodedData->Data().Ptr()); sl@0: sl@0: if(!iComparator.CompareL( ptr1,ptr2, iCodedData->Data().Length())!=0) sl@0: { sl@0: INFO_PRINTF1( _L("Comparison has failed")); sl@0: //(this->*iPrintFormats[ C ])( ptr1, ptr2, iCodedData->Data().Length() ); sl@0: result = EFail ; sl@0: } sl@0: sl@0: //[ pop buffers ] sl@0: CleanupStack::PopAndDestroy(2,srcBuffer); //srcBuffer, destBuffer sl@0: delete iCodedData; sl@0: iCodedData = NULL; sl@0: sl@0: __MM_HEAP_MARKEND; sl@0: return result; sl@0: } sl@0: sl@0: /** sl@0: * sl@0: * DoTestStepPreambleL sl@0: * sl@0: **/ sl@0: template sl@0: TVerdict CTestStepCodecUnitTest::DoTestStepPreambleL() sl@0: { sl@0: //[ assert preconditions on a and b ] sl@0: __ASSERT_DEBUG( A >= 0, Panic(EBadInvariant)); //sanity check on data sl@0: __ASSERT_DEBUG( B >= 0, Panic(EBadInvariant)); //sanity check on data sl@0: __ASSERT_DEBUG( C >= 0, Panic(EBadInvariant)); //sanity check on data sl@0: __ASSERT_DEBUG( A < 2, Panic(EBadInvariant)); //sanity check on data sl@0: __ASSERT_DEBUG( B < 2, Panic(EBadInvariant)); //sanity check on data sl@0: __ASSERT_DEBUG( C < 2, Panic(EBadInvariant)); //sanity check on data sl@0: sl@0: //[ initialise file reader callbacks ] sl@0: iReaders[ 0 ] = &CTestStepCodecUnitTest::ReadWavFileL; sl@0: iReaders[ 1 ] = &CTestStepCodecUnitTest::ReadAuFileL; sl@0: sl@0: //[ initialise print format callbacks ] sl@0: iPrintFormats[ 0 ] = &CTestStepCodecUnitTest::Print8BitResults; sl@0: iPrintFormats[ 1 ] = &CTestStepCodecUnitTest::Print16BitResults; sl@0: sl@0: // make codec sl@0: iCodecUnderTest = new(ELeave) T; // a cmmfcodec sl@0: sl@0: // [ Parse files into buffers, input & comparison sl@0: // using the configured file readers ] sl@0: TBuf<40> testFileName = iTestParameters->iInputFilename; sl@0: (this->*iReaders[ A ])(iSourceData, testFileName ); sl@0: testFileName = iTestParameters->iComparisonFileName; sl@0: (this->*iReaders[ B ])(iRefCodedData,testFileName ); sl@0: return EPass; sl@0: } sl@0: /** sl@0: * sl@0: * DoTestStepPostambleL sl@0: * sl@0: **/ sl@0: template sl@0: TVerdict CTestStepCodecUnitTest::DoTestStepPostambleL(void) sl@0: { sl@0: //Destroy Codec sl@0: delete iCodecUnderTest; sl@0: delete iSourceData; sl@0: delete iCodedData; sl@0: delete iRefCodedData; sl@0: return EPass; sl@0: } sl@0: sl@0: /** sl@0: * Reads wav file data into the supplied buffer sl@0: * ReadFileL sl@0: * @param sl@0: * @param sl@0: * This function reads the data portion of a wav file sl@0: * into a data buffer sl@0: **/ sl@0: template sl@0: void CTestStepCodecUnitTest::ReadWavFileL( CMMFDataBuffer* &aBuffer, const TDesC& aFile ) sl@0: { sl@0: // connect to the file server sl@0: User::LeaveIfError(iFs.Connect()); sl@0: sl@0: // [open the file and read its data contents into the buffer ] sl@0: // [the assumption will be the data is stored in wav format only] sl@0: TFileName fileName = GetSuite()->DefaultPath(); sl@0: fileName.Append(aFile); sl@0: sl@0: RFile file1; sl@0: User::LeaveIfError(file1.Open(iFs, fileName, EFileShareAny | EFileStream | EFileRead)); sl@0: CleanupClosePushL(file1); sl@0: sl@0: //[ get the size and position of the data from the wav file ] sl@0: TInt pos = KFmtChunkSize; sl@0: User::LeaveIfError(file1.Seek( ESeekStart, pos )); sl@0: TInt fmtChunkSize = 0; sl@0: User::LeaveIfError(ReadInt(file1, fmtChunkSize)); sl@0: //[ seek to data chunk size ] sl@0: pos = KFmtChunkSize+fmtChunkSize+8; sl@0: User::LeaveIfError(file1.Seek(ESeekStart, pos )); sl@0: //read data chunk size sl@0: TInt dataChunkSize = 0; sl@0: User::LeaveIfError(ReadInt(file1, dataChunkSize)); sl@0: //create buffer large eneough to deal with data size sl@0: TInt fileSize = 0; sl@0: User::LeaveIfError(file1.Size(fileSize)); sl@0: __ASSERT_DEBUG( fileSize > dataChunkSize, Panic(EBadInvariant)); //sanity check on data sl@0: aBuffer = CMMFDescriptorBuffer::NewL(dataChunkSize); sl@0: User::LeaveIfError(file1.Read( aBuffer->Data(),dataChunkSize)); sl@0: aBuffer->Data().SetLength(dataChunkSize); sl@0: file1.Close(); sl@0: CleanupStack::PopAndDestroy(1); //file1 sl@0: } sl@0: sl@0: /** sl@0: * Reads Au file data into the supplied buffer sl@0: * ReadFileL sl@0: * @param sl@0: * @param sl@0: * This function reads the data portion of a wav file sl@0: * into a data buffer sl@0: **/ sl@0: template sl@0: void CTestStepCodecUnitTest::ReadAuFileL( CMMFDataBuffer* &aBuffer, const TDesC& aFile ) sl@0: { sl@0: // connect to the file server sl@0: User::LeaveIfError(iFs.Connect()); sl@0: sl@0: // [open the file and read its data contents into the buffer ] sl@0: TFileName fileName = GetSuite()->DefaultPath(); sl@0: fileName.Append(aFile); sl@0: sl@0: RFile file1; sl@0: User::LeaveIfError(file1.Open(iFs, fileName, EFileShareAny | EFileStream | EFileRead)); sl@0: CleanupClosePushL(file1); sl@0: sl@0: TInt magicNumber = 0; sl@0: User::LeaveIfError(ReadIntB(file1, magicNumber)); sl@0: if( magicNumber != KAuMagic ) sl@0: { sl@0: // have not detected the appropriate header sl@0: INFO_PRINTF1(_L("Have not detected Au Header ie magic number 0x2e736e64")); sl@0: User::Leave( KErrCorrupt ); sl@0: } sl@0: sl@0: //[ header size ] sl@0: TInt headerSize = 0; sl@0: User::LeaveIfError(ReadIntB(file1, headerSize)); sl@0: sl@0: TInt fileSize = 0; sl@0: User::LeaveIfError(file1.Size(fileSize)); sl@0: sl@0: //[ filesize - headersize = datasize ] sl@0: TInt dataSize = fileSize - headerSize; sl@0: sl@0: // [ assert that the datasize >= 0 ] sl@0: __ASSERT_DEBUG( dataSize >= 0, Panic(EBadInvariant)); //sanity check on data sl@0: sl@0: //[Seek to the correct position and read data into Buffer] sl@0: User::LeaveIfError(file1.Seek(ESeekStart, headerSize )); sl@0: __ASSERT_DEBUG( fileSize > dataSize, Panic(EBadInvariant)); //sanity check on data sl@0: sl@0: //[ read the data into a Buffer ] sl@0: aBuffer = CMMFDescriptorBuffer::NewL(dataSize); sl@0: User::LeaveIfError(file1.Read( aBuffer->Data(),dataSize)); sl@0: aBuffer->Data().SetLength(dataSize); sl@0: file1.Close(); sl@0: CleanupStack::PopAndDestroy(1); //file1 sl@0: } sl@0: sl@0: /** sl@0: * Reads file into buffer sl@0: * ReadFileL sl@0: * @param aFile the file from which to read the data sl@0: * @param aValue the returned value sl@0: * This function reads a 32bit value in a rather inefficient way sl@0: **/ sl@0: template sl@0: TInt CTestStepCodecUnitTest::ReadInt( RFile& aFile, TInt& aValue ) sl@0: { sl@0: TUint8 data[4]; sl@0: TPtr8 theDes( data, 4 ); sl@0: User::LeaveIfError(aFile.Read( theDes, 4)); sl@0: // now assemble the data from the buffer sl@0: aValue = data[0]; sl@0: aValue |= data[1] << 8; sl@0: aValue |= data[2] << 16; sl@0: aValue |= data[3] << 24; sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** sl@0: * Reads file into buffer sl@0: * ReadFileL sl@0: * @param aFile the file from which to read the data sl@0: * @param aValue the returned value sl@0: * This function reads a 32bit value in BigEndian forma sl@0: and coverts it to Little Endian in a rather inefficient way sl@0: **/ sl@0: template sl@0: TInt CTestStepCodecUnitTest::ReadIntB( RFile& aFile, TInt& aValue ) sl@0: { sl@0: TUint8 data[4]; sl@0: TPtr8 theDes( data, 4 ); sl@0: User::LeaveIfError(aFile.Read( theDes, 4)); sl@0: // now assemble the data from the buffer sl@0: aValue = data[3]; sl@0: aValue |= data[2] << 8; sl@0: aValue |= data[1] << 16; sl@0: aValue |= data[0] << 24; sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: * sl@0: * ComputeBuffersToProcess sl@0: * @precondition InputBuffer has been setup sl@0: * @precondition Codec has been instantiated sl@0: * sl@0: **/ sl@0: template sl@0: TInt CTestStepCodecUnitTest::ComputeBuffersToProcess() sl@0: { sl@0: TInt numWholeBuffers = (iSourceData->Data().MaxLength()/iCodecUnderTest->SourceBufferSize() ); sl@0: return numWholeBuffers; sl@0: } sl@0: sl@0: sl@0: /** sl@0: * sl@0: * This is used for template instantiation. sl@0: * sl@0: **/ sl@0: sl@0: template class CTestStepCodecUnitTest; sl@0: template class CTestStepCodecUnitTest; sl@0: template class CTestStepCodecUnitTest,0,0,1>; sl@0: template class CTestStepCodecUnitTest; sl@0: template class CTestStepCodecUnitTest,0,0,1>; sl@0: sl@0: sl@0: /** sl@0: * sl@0: * Compare sl@0: * @param aData sl@0: * @param aData2 sl@0: * @param aNoSamples sl@0: * @return TBool sl@0: * sl@0: **/ sl@0: TBool TComparator::CompareL( TUint8* aData, TUint8* aData2, TInt aLength ) sl@0: { sl@0: TBool result = ETrue; sl@0: if( !aData ) sl@0: User::Leave(KErrArgument); sl@0: if( !aData2 ) sl@0: User::Leave(KErrArgument); sl@0: sl@0: if( Mem::Compare( aData,aLength, aData2, aLength )!=0) sl@0: { sl@0: result = EFalse; sl@0: } sl@0: sl@0: return result; sl@0: } sl@0: sl@0: /** sl@0: * sl@0: * Compare sl@0: * @param aData sl@0: * @param aData2 sl@0: * @param aNoSamples sl@0: * @result TBool sl@0: * sl@0: **/ sl@0: template sl@0: TBool TDbComparator::CompareL( TUint8* aData, TUint8* aData2, TInt aLength ) sl@0: { sl@0: TBool result = ETrue; sl@0: if( !aData ) sl@0: User::Leave(KErrArgument); sl@0: if( !aData2 ) sl@0: User::Leave(KErrArgument); sl@0: sl@0: //[ lets compute the signal to noise ratio ] sl@0: TReal sumSigSquared = 0.0; sl@0: TReal sumErrorSquared = 0.0; sl@0: TUint8* pData = aData; sl@0: TUint8* pData2 = aData2; sl@0: TInt numSamples = aLength/2; sl@0: // compute the sum of sig and error squared sl@0: for( TInt count = 0; count < numSamples; count++ ) sl@0: { sl@0: TInt16 sample1 = static_cast( pData[0] &KAndMask8bit); sl@0: sample1 |= static_cast((pData[1] << 8 )); sl@0: TInt16 sample2 = static_cast( pData2[0] &KAndMask8bit); sl@0: sample2 |= static_cast((pData2[1] << 8 )); sl@0: pData +=1; sl@0: pData2+=2; sl@0: sumSigSquared += sample1*sample1; sl@0: sumErrorSquared += (sample1-sample2)*(sample1-sample2); sl@0: } sl@0: sl@0: TReal sn = 0.0; sl@0: const TReal tolerance = 0.001; sl@0: //[precondition error is >= tolerance ] sl@0: if( sumErrorSquared < tolerance ) sl@0: User::Leave( KErrArgument ); sl@0: //[claculate ratio safely ] sl@0: Math::Log( sn, (sumSigSquared/sumErrorSquared)); sl@0: sn*= 10; sl@0: TReal threshold = T; // integer used as real with 100ths db accuracy sl@0: threshold /= 100.0; sl@0: if( sn < threshold ) sl@0: result = EFalse; sl@0: sl@0: return result; sl@0: } sl@0: