devsound/devsoundrefplugin/src/sounddevice/DevSoundUtility.cpp
changeset 0 40261b775718
child 38 4269ca484c7b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/devsound/devsoundrefplugin/src/sounddevice/DevSoundUtility.cpp	Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,532 @@
+// Copyright (c) 2001-2009 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:
+// MMF\SoundDev\src\SoundDevice\DevSoundUtility.cpp
+// File:		DevSoundUtility.cpp
+// Author:		Vasudevan Ramachandraiah
+// Date:		July 16, 2002
+// Class that provides API to list ECOM plugin implementation IDs
+// (c) Nokia Inc.
+// Revisions:
+// Date:			Author			Description
+// 
+//
+
+#include <e32std.h>
+#include <barsc.h>
+#include <barsread.h>
+#include <mmfbase.h>
+#include <mmfplugininterfaceuids.hrh>
+#include <fixedsequence.rsg>
+#include "DevSoundUtility.h"
+#include <mmf/common/mmfcontroller.h> //needed for CleanupResetAndDestroyPushL()
+#include <mm/mmpluginutils.h>
+#ifdef SYMBIAN_MULTIMEDIA_CODEC_API
+#include <mdf/codecapiresolverutils.h>
+#include <mdf/codecapiresolverdata.h>
+#include <mdf/codecapiuids.hrh>
+#include <mdf/codecapiresolver.hrh>
+#endif // SYMBIAN_MULTIMEDIA_CODEC_API
+
+_LIT(KFixedSequenceResourceFile, "Z:\\Resource\\DevSound\\FixedSequence.rsc"); 
+const TInt KFourCCStringLength = 9;
+
+inline TMMFRawPackage::TMMFRawPackage(TInt aDerivedSize)
+#pragma warning( disable : 4355 )	// 'this' : used in base member initializer list
+: iThis((TUint8*)this,aDerivedSize,aDerivedSize) 
+#pragma warning( default : 4355 )
+	{ 
+	}
+
+inline TPtr8& TMMFRawPackage::Package()
+	{ 
+	((TMMFRawPackage*)this)->iThis.Set((TUint8*)this,iThis.Length(),iThis.MaxLength()); 
+	return iThis; 
+	}
+
+inline const TPtr8& TMMFRawPackage::Package() const
+	{ 
+	((TMMFRawPackage*)this)->iThis.Set((TUint8*)this,iThis.Length(),iThis.MaxLength()); 
+	return iThis; 
+	}
+
+inline void TMMFRawPackage::SetSize(TInt aDerivedSize)
+	{ 
+	iThis.Set((TUint8*)this,aDerivedSize,aDerivedSize);
+	}
+
+inline TMMFToneFixedSequenceNames::TMMFToneFixedSequenceNames() :
+TMMFRawPackage(sizeof(TMMFToneFixedSequenceNames)) {}
+
+#ifdef _UNICODE
+class TNameBuf : public TBufCBase16
+#else
+class TNameBuf : public TBufCBase8
+#endif
+	{
+	friend class HMMFToneFixedSequenceNames;
+	};
+
+HMMFToneFixedSequenceNames::HMMFToneFixedSequenceNames()
+	{
+	iCount = 0;
+	}
+
+HMMFToneFixedSequenceNames* HMMFToneFixedSequenceNames::AddNameL(const TDesC& aName)
+// Append a copy of the supplied descriptor to the end of the 
+// current heap cell. This will involve a realloc that will normally
+// result in the object moving
+	{
+	TInt size = Package().Length();
+	TInt desSize = aName.Size() + sizeof(TInt);
+	if (desSize&3) 
+		desSize = ((desSize+4)&(~3)); // Must round up to word boundary to keep aligned
+	HMMFToneFixedSequenceNames* self = REINTERPRET_CAST(HMMFToneFixedSequenceNames*,User::ReAllocL(STATIC_CAST(TAny*,this),size + desSize));
+	TUint8* newDesPtr = REINTERPRET_CAST(TUint8*,self) + size;
+	Mem::FillZ(newDesPtr,desSize);
+	TNameBuf* newDes = REINTERPRET_CAST(TNameBuf*,newDesPtr);
+	newDes->Copy(aName,aName.Length());
+	self->SetSize(size+desSize);
+	self->iCount++;
+	return self;
+	}
+
+
+/******************************************************************
+ *				CMMFDevSoundUtility
+ ******************************************************************/
+CMMFDevSoundUtility::CMMFDevSoundUtility()
+	{
+	// No default implementation
+	}
+
+
+CMMFDevSoundUtility::~CMMFDevSoundUtility()
+	{
+	delete iInfo;
+	delete iFixedSequenceNames;
+	}
+
+CMMFDevSoundUtility* CMMFDevSoundUtility::NewL()
+	{
+	CMMFDevSoundUtility* self = NewLC();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CMMFDevSoundUtility* CMMFDevSoundUtility::NewLC()
+	{
+	CMMFDevSoundUtility* self = new(ELeave) CMMFDevSoundUtility();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	// Leave it on Cleanupstack
+	return self;
+	}
+
+void CMMFDevSoundUtility::ConstructL()
+	{
+	iFixedSequenceNames = new (ELeave) HMMFToneFixedSequenceNames;
+	}
+
+void CMMFDevSoundUtility::SeekUsingFourCCL(TUid aInterfaceUid, RImplInfoPtrArray& aPlugInArray, const TFourCC& aSrcDataType, const TFourCC& aDstDataType, const TDesC& aPreferredSupplier)
+	{
+
+	// Create a match string using the two FourCC codes.
+	_LIT8(KEmptyFourCCString, "    ,    ");
+	TBufC8<KFourCCStringLength> fourCCString(KEmptyFourCCString);
+	TPtr8 fourCCPtr = fourCCString.Des();
+	TPtr8 fourCCPtr1(&fourCCPtr[0], 4);
+	TPtr8 fourCCPtr2(&fourCCPtr[5], 4 );
+	aSrcDataType.FourCC(&fourCCPtr1);
+	aDstDataType.FourCC(&fourCCPtr2);
+
+	MmPluginUtils::FindImplementationsL(aInterfaceUid, aPlugInArray, fourCCPtr);
+
+	// If more than one match.  Narrow the search by preferred supplier
+	if((aPlugInArray.Count() > 1) && aPreferredSupplier.Length())
+		{
+		SelectByPreference( aPlugInArray, aPreferredSupplier );
+		}		
+
+	// If there are no plugins, return failure
+	if(aPlugInArray.Count() == 0)
+		{
+		User::Leave( KErrNotFound );
+		}	
+	}
+	
+	
+#ifdef SYMBIAN_MULTIMEDIA_CODEC_API
+void CMMFDevSoundUtility::FindHwDeviceAdapterL(TUid aInterfaceUid, RImplInfoPtrArray& aPlugInArray)
+	{
+	// Create a match string using the two FourCC codes.
+	_LIT8(KAdapterMatch, "*");
+
+	MmPluginUtils::FindImplementationsL(aInterfaceUid, aPlugInArray, KAdapterMatch);
+
+	// If there are no plugins, return failure
+
+	if(aPlugInArray.Count() == 0)
+		{
+		User::Leave( KErrNotFound );
+		}		
+	}
+	
+void CMMFDevSoundUtility::SeekCodecPluginsL(RArray<TFourCC>& aSupportedDataTypes, TMMFState aState, TBool aAppend)	
+	{
+	_LIT8(KPCM16FourCCString, " P16");
+	//check argument precondition for aState
+	if ((aState != EMMFStatePlaying) && (aState != EMMFStateRecording))
+		{
+		User::Leave(KErrArgument);		
+		}		
+
+	if (!aAppend)
+		{
+		aSupportedDataTypes.Reset(); //clear any existing data in aSupportedDataTypes array if not appending
+		}
+	
+	CCodecApiResolverData* customMatchData = CCodecApiResolverData::NewLC();
+	if (aState == EMMFStatePlaying)
+		{
+		customMatchData->SetMatchType(EMatchOutputDataFormat);
+		customMatchData->SetOutputDataL(KPCM16FourCCString);
+		}
+	else
+		{
+		customMatchData->SetMatchType(EMatchInputDataFormat);
+		customMatchData->SetInputDataL(KPCM16FourCCString);
+		}
+
+	customMatchData->SetImplementationType(TUid::Uid(KUidAudioCodec));
+	
+	HBufC8* package = customMatchData->NewPackLC();	
+	
+	RImplInfoPtrArray ecomArray;
+	CleanupResetAndDestroyPushL(ecomArray);
+
+	TInt err = KErrNone;
+	MmPluginUtils::FindImplementationsL(TUid::Uid(KUidMdfProcessingUnit), ecomArray, *package, TUid::Uid(KUidCodecApiResolverImplementation));
+
+	for (TInt i=0 ; i < ecomArray.Count() ; i++)
+		{
+		CCodecApiOpaqueData* data = NULL;
+		TRAP(err, data =  CCodecApiOpaqueData::NewL(ecomArray[i]->OpaqueData()));
+		// simply ignore plugins that we can't parse the opaque data. They should not cause other plugins
+		// to fall over
+		if (err == KErrNone)
+			{
+			const TDesC8* dataType;
+			if (aState == EMMFStatePlaying)
+				{
+				dataType = &data->InputDataType();	
+				}
+			else
+				{
+				dataType = &data->OutputDataType();	
+				}
+			TFourCC fourCC(*dataType);
+			delete data;
+			aSupportedDataTypes.AppendL(fourCC);
+			}		
+		}
+	CleanupStack::PopAndDestroy(3, customMatchData);
+	}
+#endif // SYMBIAN_MULTIMEDIA_CODEC_API
+
+/*
+ * local function to disable items which do not match the preferred supplier.
+ * Note that at least one enabled item is returned (if there was an enabled item to begin with) which
+ * may not match the preferred supplier.
+ * 
+ */
+void CMMFDevSoundUtility::SelectByPreference( RImplInfoPtrArray& aPlugInArray, const TDesC& aPreferredSupplier ) 
+	{
+
+	// Use the Disabled flag to eliminated all currently enabled matches that
+	// do not match the preferred supplier.
+	TInt firstEnabled = -1 ; // to ensure that we return something valid
+	TInt matchCount = 0 ;
+	for ( TInt ii = 0 ; ii < aPlugInArray.Count() ; ii++ )
+		{
+		if ( !( aPlugInArray[ii]->Disabled() ) )
+			{
+			if ( firstEnabled == -1 )
+				firstEnabled = ii ;
+			if ( aPlugInArray[ii]->DisplayName().FindF( aPreferredSupplier ) == KErrNotFound )
+				aPlugInArray[ii]->SetDisabled( ETrue ) ;
+			else
+				matchCount++ ;
+			}
+		}
+
+	// If there are no matches then re-enable the first enabled
+	if ( matchCount == 0 )
+		aPlugInArray[firstEnabled]->SetDisabled( EFalse ) ;
+	else if ( matchCount > 1 )
+		{
+		// find the latest version from more than one match
+		TInt highestVersionIndex = -1 ;
+		for ( TInt ii = 0 ; ii < aPlugInArray.Count() ; ii++ )
+			{
+			if ( !( aPlugInArray[ii]->Disabled() ) )  // only interested in enabled elements
+				{
+				if ( highestVersionIndex == -1 )
+					{ // first match.  Store this.  Keep it enabled
+					highestVersionIndex = ii ;
+					}
+				else if ( aPlugInArray[ii]->Version() > aPlugInArray[highestVersionIndex]->Version() )
+					{ // a new leader.  Disable the previous leader.  Keep this one.
+					aPlugInArray[highestVersionIndex]->SetDisabled( ETrue ) ;
+					highestVersionIndex = ii ;
+					}
+				else  // we already have a higher version.
+					aPlugInArray[ii]->SetDisabled( ETrue ) ;
+				}
+			}
+		}
+	}
+
+
+/*
+ *  SeekHwDevicePluginsL
+ *  This method looks for hwDevicePlugins that support the state given in aState which
+ *  must be either EMMFStatePlaying or EMMFStateRecording
+ *  For each HwDevice plugin found the datatype as indicated by its fourCC code
+ *  from the default_data field in the resource file is added to the array of aSupportedDataTypes
+ *
+ *  @internalComponent
+ *
+ *	@param	"RArray<TFourCC>& aSupportedDataTypes"
+ *  an array of fourCC codes that has a fourCC code added to for each hardware device found
+ *
+ *	@param  "TMMFState aState"
+ *  must be set to EMMFStatePlaying if seeking HwDevice plugins that support play and
+ *  EMMFStateRecording if seeking HwDevice plugins that support record
+ *	
+ *  @leave KErrArgument if aState is not EMMFStatePlaying or EMMFStateRecording else leaves
+ *  with standard symbian OS error code
+ */
+void CMMFDevSoundUtility::SeekHwDevicePluginsL(RArray<TFourCC>& aSupportedDataTypes, TMMFState aState)
+	{	
+	//check argument precondition for aState
+	if ((aState != EMMFStatePlaying) && (aState != EMMFStateRecording))
+		{
+		User::Leave(KErrArgument);
+		}
+
+	aSupportedDataTypes.Reset(); //clear any existing data in aSupportedDataTypes array
+
+	RImplInfoPtrArray plugInArray ; // Array to return hw device plugin resource info
+	CleanupResetAndDestroyPushL(plugInArray);
+
+	TUid KUidMmfHWPluginInterfaceCodec = {KMmfUidPluginInterfaceHwDevice};
+
+	MmPluginUtils::FindImplementationsL(KUidMmfHWPluginInterfaceCodec, plugInArray);
+
+	TUint numberOfHwDevicePlugins = plugInArray.Count();
+
+	//if have hwdevice plugin resource entries then scan entries
+	//matching on a datatype of pcm16 as the destination datatype for play and the 
+	//source datatype for record
+	//if a match is found and isn't already in list of supported data types
+	//then add it to the list
+	if (numberOfHwDevicePlugins)
+		{					
+		CImplementationInformation* hwDeviceResourceEntry = NULL;
+		_LIT8(KPCM16FourCCString, " P16");
+		TBufC8<KFourCCLength> fourCCStringPCM16(KPCM16FourCCString);
+		TPtr8 fourCCPtrPCM16 = fourCCStringPCM16.Des();
+		TUint entryNumber = 0;
+
+		//check each resource entry for dst 4CC = P16 for play and src 4CC = P16 for record
+		for (TUint hwDeviceEntry = 0; hwDeviceEntry < numberOfHwDevicePlugins; hwDeviceEntry++)
+			{
+			hwDeviceResourceEntry = plugInArray[hwDeviceEntry];
+			if (IsDataTypeMatch(hwDeviceResourceEntry, fourCCPtrPCM16, aState))
+				{//resource entry data field has dest/src datatype ' P16' ie pcm16 for play/record
+				TPtrC8 fourCCPtr(0,0);
+				if (aState == EMMFStatePlaying)//then datatype supported 4CC is left 4 chars
+					{
+					fourCCPtr.Set(hwDeviceResourceEntry->DataType().Left(KFourCCLength));
+					}
+				else if (aState == EMMFStateRecording) //then datatype supported 4CC is right 4 chars
+					{
+					fourCCPtr.Set(hwDeviceResourceEntry->DataType().Right(KFourCCLength));
+					}
+				TFourCC fourCCEntry(fourCCPtr);
+				//need to check if entry already exists to prevent duplicate entries
+				entryNumber = aSupportedDataTypes.Count();
+				TBool alreadyExists = EFalse;
+				for (TUint fourCCEntryNumber = 0; fourCCEntryNumber < entryNumber; fourCCEntryNumber++)
+					{
+					if (aSupportedDataTypes[fourCCEntryNumber]==fourCCEntry)
+						{
+						alreadyExists = ETrue;//we already have this 4CC in the supported data types
+						break;
+						}
+					}
+				if (!alreadyExists)
+					{
+					TInt err = aSupportedDataTypes.Append(fourCCEntry);
+					if (err)
+						{//note we don't destroy array because we don't own it
+						//but we do reset it as it is incomplete
+						aSupportedDataTypes.Reset();
+						User::Leave(err);
+						}
+					}
+				}//if (IsDataTypeMatch(hwDeviceResourceEntry, fourCCPtrPCM16, aState))
+			}//for (TUint hwDeviceEntry = 0; hwDeviceEntry < numberOfHwDevicePlugins; hwDeviceEntry++)
+		}//if (numberOfHwDevicePlugins)
+
+	CleanupStack::PopAndDestroy(&plugInArray);
+	}
+
+
+/*
+ *	IsDataTypeMatch
+ *  This method takes a given resource entry from a hardware device and determines 
+ *  whether the hwdevice plugin is a data type match for playing or recording
+ *  depending on the setting of aState
+ *  The method matchs the default_data field from the hw device resource entry matching
+ *  it with the aHwMatchFourCC code.
+ *
+ *  @internalComponent
+ *
+ *	@param	"CImplementationInformation aHwDeviceResourceEntry"
+ *  the hw device resource entry that is to be checked 
+ *  whether it can be used to play or record
+ *
+ *	@param  "TDesC8& aHwMatchFourCC
+ *	the data type fourCC code to match to that the hardware device that must convert to for
+ *	playing and convert from for recording - for the reference DevSound this is always ' P16' ie pcm16
+ *
+ *  @param "TMMFState aState"
+ *  this determines whether the match is for playing or recording and should take 
+ *  either the values EMMFStatePlaying or EMMFStateRecording
+ *
+ *  @return ETrue if a match for play or record else EFalse
+ */
+TBool CMMFDevSoundUtility::IsDataTypeMatch(CImplementationInformation* aHwDeviceResourceEntry,const TDesC8& aHwMatchFourCC, TMMFState aState)
+	{
+	TBool match = EFalse;
+	// extra length safety check to remove adapter plugins and incorrect ones
+	if (aHwDeviceResourceEntry->DataType().Length()>=KFourCCStringLength)
+		{
+		if (aState == EMMFStatePlaying)
+			{//play need to match with the right four characters
+			match =  (!(aHwMatchFourCC.Match(aHwDeviceResourceEntry->DataType().Right(KFourCCLength))==KErrNotFound));
+			}
+		else if (aState == EMMFStateRecording)
+			{//record need to match with the left four characters
+			match = (!(aHwMatchFourCC.Match(aHwDeviceResourceEntry->DataType().Left(KFourCCLength))==KErrNotFound));
+			}
+		}
+	return match;
+	}
+
+
+/**
+ *	Populate fixed sequences
+ *
+ */
+void CMMFDevSoundUtility::InitializeFixedSequenceL(CPtrC8Array** aFixedSequences)
+	{
+
+	RFs fsSession;
+	User::LeaveIfError(fsSession.Connect());
+	CleanupClosePushL(fsSession);
+
+	// Open the resource file
+	RResourceFile resourceFile;
+	resourceFile.OpenL(fsSession, KFixedSequenceResourceFile);
+	CleanupClosePushL(resourceFile);
+
+	// Allocate buffer to hold resource data in binary format
+	iInfo = resourceFile.AllocReadL(FIXED_TONE_SEQUENCE);
+
+	TResourceReader reader;
+	reader.SetBuffer(iInfo);
+
+	// Create array to hold fixed sequences data
+	CPtrC8Array* tempSequences = new(ELeave) CPtrC8Array(8); //  granularity
+	CleanupStack::PushL(tempSequences);
+
+	// First word gives number of entries
+	TInt numberOfEntries = reader.ReadUint16(); 
+	ASSERT(!(numberOfEntries&1)); // Should have atleast one entry
+
+	// There must be an even number entries as each sequence structure
+	// is made of a name string and a data string (SEQUENCE_NAME and SEQUENCE_DATA)
+
+	HMMFToneFixedSequenceNames* names = new (ELeave) HMMFToneFixedSequenceNames;
+	CleanupStack::PushL(names);
+	for (TInt i=0;i<numberOfEntries;i+=2)
+		{
+		// Copy name from resource array to returnable array
+		HMMFToneFixedSequenceNames* newNames = names->AddNameL(reader.ReadTPtrC());
+		if (names != newNames)
+			{ // May have moved so fixup cleanupstack reference
+			CleanupStack::Pop();
+			names = newNames;
+			CleanupStack::PushL(names);
+			}
+		TInt len = reader.ReadUint16();
+		TPtrC8 tempTPtrC8(REINTERPRET_CAST(const TUint8*,reader.Ptr()),len<<1);
+		tempSequences->AppendL(tempTPtrC8);
+		reader.Advance(len<<1);
+		}
+	CleanupStack::Pop(); // names
+
+	// Delete the old fixed sequence names
+	delete iFixedSequenceNames;
+	iFixedSequenceNames = NULL;
+	iFixedSequenceNames = names;
+
+	*aFixedSequences = tempSequences;
+	CleanupStack::Pop(tempSequences);
+	CleanupStack::PopAndDestroy(2);	// resourceFile, fsSession
+	}
+
+TBool CMMFDevSoundUtility::RecognizeSequence(const TDesC8& aData)
+	{
+	// Reference plug-in only supports its own sequence format
+	_LIT8(KSequenceSignature,"SQNC");
+	if (aData.Length() > 4)
+		{
+		if (aData.Left(4) == KSequenceSignature)
+			return ETrue;
+		}
+	// Didn't recognise
+	return EFalse;
+	}
+
+const TDesC& CMMFDevSoundUtility::FixedSequenceName(TInt aSequenceNumber)
+	{
+	ASSERT(iFixedSequenceNames); // Defect if this not true when previous was true
+	ASSERT((aSequenceNumber>=0)&&(aSequenceNumber<iFixedSequenceNames->iCount));
+
+	// Ptr to first descriptor
+	TUint8* ptr = REINTERPRET_CAST(TUint8*,&(iFixedSequenceNames->iCount))+sizeof(TInt);
+	TDesC* desPtr = REINTERPRET_CAST(TDesC*,ptr); // First des
+	while (aSequenceNumber--)
+		{
+		TInt size = desPtr->Size();
+		if (size&3)
+			size = ((size+4)&(~3));
+		ptr += sizeof(TInt) + size;
+		desPtr = REINTERPRET_CAST(TDesC*,ptr); // Next des
+		}
+	return *desPtr;
+	}