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