1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/mm/devsound/sounddevbt/src/SoundDevice/BtDevSoundUtility.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,445 @@
1.4 +// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// MMF\SoundDev\src\SoundDevice\BtDevSoundUtility.cpp
1.18 +// File: BtDevSoundUtility.cpp
1.19 +// Author: Vasudevan Ramachandraiah
1.20 +// Date: July 16, 2002
1.21 +// Class that provides API to list ECOM plugin implementation IDs
1.22 +// (c) Nokia Inc.
1.23 +// Revisions:
1.24 +// Date: Author Description
1.25 +//
1.26 +//
1.27 +
1.28 +#include <e32std.h>
1.29 +#include <barsc.h>
1.30 +#include <barsread.h>
1.31 +#include <mmfbase.h>
1.32 +#include <mmfplugininterfaceuids.hrh>
1.33 +#include <mmf/plugin/mmfbthwdeviceimplementationuids.hrh>
1.34 +#include <fixedsequence.rsg>
1.35 +#include "BtDevSoundUtility.h"
1.36 +#include <mmf/common/mmfcontroller.h> //needed for CleanupResetAndDestroyPushL()
1.37 +
1.38 +_LIT(KFixedSequenceResourceFile, "Z:\\Resource\\DevSound\\FixedSequence.rsc");
1.39 +
1.40 +inline TMMFRawPackage::TMMFRawPackage(TInt aDerivedSize)
1.41 +#pragma warning( disable : 4355 ) // 'this' : used in base member initializer list
1.42 +: iThis((TUint8*)this,aDerivedSize,aDerivedSize)
1.43 +#pragma warning( default : 4355 )
1.44 + {
1.45 + }
1.46 +
1.47 +inline TPtr8& TMMFRawPackage::Package()
1.48 + {
1.49 + ((TMMFRawPackage*)this)->iThis.Set((TUint8*)this,iThis.Length(),iThis.MaxLength());
1.50 + return iThis;
1.51 + }
1.52 +
1.53 +inline const TPtr8& TMMFRawPackage::Package() const
1.54 + {
1.55 + ((TMMFRawPackage*)this)->iThis.Set((TUint8*)this,iThis.Length(),iThis.MaxLength());
1.56 + return iThis;
1.57 + }
1.58 +
1.59 +inline void TMMFRawPackage::SetSize(TInt aDerivedSize)
1.60 + {
1.61 + iThis.Set((TUint8*)this,aDerivedSize,aDerivedSize);
1.62 + }
1.63 +
1.64 +inline TMMFToneFixedSequenceNames::TMMFToneFixedSequenceNames() :
1.65 +TMMFRawPackage(sizeof(TMMFToneFixedSequenceNames)) {}
1.66 +
1.67 +#ifdef _UNICODE
1.68 +class TNameBuf : public TBufCBase16
1.69 +#else
1.70 +class TNameBuf : public TBufCBase8
1.71 +#endif
1.72 + {
1.73 + friend class HMMFToneFixedSequenceNames;
1.74 + };
1.75 +
1.76 +HMMFToneFixedSequenceNames::HMMFToneFixedSequenceNames()
1.77 + {
1.78 + iCount = 0;
1.79 + }
1.80 +
1.81 +HMMFToneFixedSequenceNames* HMMFToneFixedSequenceNames::AddNameL(const TDesC& aName)
1.82 +// Append a copy of the supplied descriptor to the end of the
1.83 +// current heap cell. This will involve a realloc that will normally
1.84 +// result in the object moving
1.85 + {
1.86 + TInt size = Package().Length();
1.87 + TInt desSize = aName.Size() + sizeof(TInt);
1.88 + if (desSize&3)
1.89 + desSize = ((desSize+4)&(~3)); // Must round up to word boundary to keep aligned
1.90 + HMMFToneFixedSequenceNames* self = REINTERPRET_CAST(HMMFToneFixedSequenceNames*,User::ReAllocL(STATIC_CAST(TAny*,this),size + desSize));
1.91 + TUint8* newDesPtr = REINTERPRET_CAST(TUint8*,self) + size;
1.92 + Mem::FillZ(newDesPtr,desSize);
1.93 + TNameBuf* newDes = REINTERPRET_CAST(TNameBuf*,newDesPtr);
1.94 + newDes->Copy(aName,aName.Length());
1.95 + self->SetSize(size+desSize);
1.96 + self->iCount++;
1.97 + return self;
1.98 + }
1.99 +
1.100 +
1.101 +/******************************************************************
1.102 + * CMMFDevSoundUtility
1.103 + ******************************************************************/
1.104 +CMMFDevSoundUtility::CMMFDevSoundUtility()
1.105 + {
1.106 + // No default implementation
1.107 + }
1.108 +
1.109 +
1.110 +CMMFDevSoundUtility::~CMMFDevSoundUtility()
1.111 + {
1.112 + delete iInfo;
1.113 + delete iFixedSequenceNames;
1.114 + }
1.115 +
1.116 +CMMFDevSoundUtility* CMMFDevSoundUtility::NewL()
1.117 + {
1.118 + CMMFDevSoundUtility* self = NewLC();
1.119 + CleanupStack::Pop();
1.120 + return self;
1.121 + }
1.122 +
1.123 +CMMFDevSoundUtility* CMMFDevSoundUtility::NewLC()
1.124 + {
1.125 + CMMFDevSoundUtility* self = new(ELeave) CMMFDevSoundUtility();
1.126 + CleanupStack::PushL(self);
1.127 + self->ConstructL();
1.128 + // Leave it on Cleanupstack
1.129 + return self;
1.130 + }
1.131 +
1.132 +void CMMFDevSoundUtility::ConstructL()
1.133 + {
1.134 + iFixedSequenceNames = new (ELeave) HMMFToneFixedSequenceNames;
1.135 + }
1.136 +
1.137 +void CMMFDevSoundUtility::SeekUsingFourCCL(TUid aInterfaceUid, RImplInfoPtrArray& aPlugInArray, const TFourCC& aSrcDataType, const TFourCC& aDstDataType, const TDesC& aPreferredSupplier)
1.138 + {
1.139 +
1.140 + // Create a match string using the two FourCC codes.
1.141 + _LIT8(KEmptyFourCCString, " , ");
1.142 + TBufC8<9> fourCCString(KEmptyFourCCString);
1.143 + TPtr8 fourCCPtr = fourCCString.Des();
1.144 + TPtr8 fourCCPtr1(&fourCCPtr[0], 4);
1.145 + TPtr8 fourCCPtr2(&fourCCPtr[5], 4 );
1.146 + aSrcDataType.FourCC(&fourCCPtr1);
1.147 + aDstDataType.FourCC(&fourCCPtr2);
1.148 +
1.149 + // Create a TEcomResolverParams structure.
1.150 + TEComResolverParams resolverParams;
1.151 + resolverParams.SetDataType(fourCCPtr);
1.152 + resolverParams.SetWildcardMatch(EFalse);
1.153 +
1.154 + // ListImplementationsL leaves if it cannot find anything so trap the error and ignore it.
1.155 + TRAPD(err, REComSession::ListImplementationsL(aInterfaceUid, resolverParams, aPlugInArray));
1.156 +
1.157 + User::LeaveIfError(err); //The error above may not be KErrNotFound eg could be KErrNoMemory in which case leave
1.158 +
1.159 + // IF there are no plugins, return failure
1.160 + if(aPlugInArray.Count() == 0)
1.161 + User::Leave( KErrNotFound ) ;
1.162 +
1.163 + // If more than one match. Narrow the search by preferred supplier
1.164 + if((aPlugInArray.Count() > 1) && aPreferredSupplier.Length())
1.165 + SelectByPreference( aPlugInArray, aPreferredSupplier ) ;
1.166 +
1.167 + }
1.168 +
1.169 +
1.170 +/*
1.171 + * local function to disable items which do not match the preferred supplier.
1.172 + * Note that at least one enabled item is returned (if there was an enabled item to begin with) which
1.173 + * may not match the preferred supplier.
1.174 + *
1.175 + */
1.176 +void CMMFDevSoundUtility::SelectByPreference( RImplInfoPtrArray& aPlugInArray, const TDesC& aPreferredSupplier )
1.177 + {
1.178 +
1.179 + // Use the Disabled flag to eliminated all currently enabled matches that
1.180 + // do not match the preferred supplier.
1.181 + TInt firstEnabled = -1 ; // to ensure that we return something valid
1.182 + TInt matchCount = 0 ;
1.183 + for ( TInt ii = 0 ; ii < aPlugInArray.Count() ; ii++ )
1.184 + {
1.185 + if ( !( aPlugInArray[ii]->Disabled() ) )
1.186 + {
1.187 + if ( firstEnabled == -1 )
1.188 + firstEnabled = ii ;
1.189 + if ( aPlugInArray[ii]->DisplayName().FindF( aPreferredSupplier ) == KErrNotFound )
1.190 + aPlugInArray[ii]->SetDisabled( ETrue ) ;
1.191 + else
1.192 + matchCount++ ;
1.193 + }
1.194 + }
1.195 +
1.196 + // If there are no matches then re-enable the first enabled
1.197 + if ( matchCount == 0 )
1.198 + aPlugInArray[firstEnabled]->SetDisabled( EFalse ) ;
1.199 + else if ( matchCount > 1 )
1.200 + {
1.201 + // find the latest version from more than one match
1.202 + TInt highestVersionIndex = -1 ;
1.203 + for ( TInt ii = 0 ; ii < aPlugInArray.Count() ; ii++ )
1.204 + {
1.205 + if ( !( aPlugInArray[ii]->Disabled() ) ) // only interested in enabled elements
1.206 + {
1.207 + if ( highestVersionIndex == -1 )
1.208 + { // first match. Store this. Keep it enabled
1.209 + highestVersionIndex = ii ;
1.210 + }
1.211 + else if ( aPlugInArray[ii]->Version() > aPlugInArray[highestVersionIndex]->Version() )
1.212 + { // a new leader. Disable the previous leader. Keep this one.
1.213 + aPlugInArray[highestVersionIndex]->SetDisabled( ETrue ) ;
1.214 + highestVersionIndex = ii ;
1.215 + }
1.216 + else // we already have a higher version.
1.217 + aPlugInArray[ii]->SetDisabled( ETrue ) ;
1.218 + }
1.219 + }
1.220 + }
1.221 + }
1.222 +
1.223 +
1.224 +/*
1.225 + * SeekHwDevicePluginsL
1.226 + * This method looks for hwDevicePlugins that support the state given in aState which
1.227 + * must be either EMMFStatePlaying or EMMFStateRecording
1.228 + * For each HwDevice plugin found the datatype as indicated by its fourCC code
1.229 + * from the default_data field in the resource file is added to the array of aSupportedDataTypes
1.230 + *
1.231 + * @internalComponent
1.232 + *
1.233 + * @param "RArray<TFourCC>& aSupportedDataTypes"
1.234 + * an array of fourCC codes that has a fourCC code added to for each hardware device found
1.235 + *
1.236 + * @param "TMMFState aState"
1.237 + * must be set to EMMFStatePlaying if seeking HwDevice plugins that support play and
1.238 + * EMMFStateRecording if seeking HwDevice plugins that support record
1.239 + *
1.240 + * @leave KErrArgument if aState is not EMMFStatePlaying or EMMFStateRecording else leaves
1.241 + * with standard symbian OS error code
1.242 + */
1.243 +void CMMFDevSoundUtility::SeekHwDevicePluginsL(RArray<TFourCC>& aSupportedDataTypes, TMMFState aState)
1.244 + {
1.245 + //check argument precondition for aState
1.246 + if ((aState != EMMFStatePlaying) && (aState != EMMFStateRecording))
1.247 + User::Leave(KErrArgument);
1.248 +
1.249 + aSupportedDataTypes.Reset(); //clear any existing data in aSupportedDataTypes array
1.250 +
1.251 + RImplInfoPtrArray plugInArray ; // Array to return hw device plugin resource info(place on cleanupstack _after_ ListImplementationsL() )
1.252 + TUid KUidMmfHWPluginInterfaceCodec = {KMmfUidBtPluginInterfaceHwDevice};
1.253 +
1.254 + // ListImplementationsL leaves if it cannot find anything so trap the error
1.255 + TRAPD( err, REComSession::ListImplementationsL(KUidMmfHWPluginInterfaceCodec, plugInArray ) ) ;
1.256 + CleanupResetAndDestroyPushL(plugInArray);
1.257 +
1.258 + TUint numberOfHwDevicePlugins = plugInArray.Count();
1.259 +
1.260 + //if no errors and have hwdevice plugin resource entries then scan entries
1.261 + //matching on a datatype of pcm16 as the destination datatype for play and the
1.262 + //source datatype for record
1.263 + //if a match is found and isn't already in list of supported data types
1.264 + //then add it to the list
1.265 + if ((err == KErrNone)&&(numberOfHwDevicePlugins))
1.266 + {
1.267 + CImplementationInformation* hwDeviceResourceEntry = NULL;
1.268 + _LIT8(KPCM16FourCCString, " P16");
1.269 + TBufC8<KFourCCLength> fourCCStringPCM16(KPCM16FourCCString);
1.270 + TPtr8 fourCCPtrPCM16 = fourCCStringPCM16.Des();
1.271 + TUint entryNumber = 0;
1.272 +
1.273 + //check each resource entry for dst 4CC = P16 for play and src 4CC = P16 for record
1.274 + for (TUint hwDeviceEntry = 0; hwDeviceEntry < numberOfHwDevicePlugins; hwDeviceEntry++)
1.275 + {
1.276 + hwDeviceResourceEntry = plugInArray[hwDeviceEntry];
1.277 + if (IsDataTypeMatch(hwDeviceResourceEntry, fourCCPtrPCM16, aState))
1.278 + {//resource entry data field has dest/src datatype ' P16' ie pcm16 for play/record
1.279 + TPtrC8 fourCCPtr(0,0);
1.280 + if (aState == EMMFStatePlaying)//then datatype supported 4CC is left 4 chars
1.281 + fourCCPtr.Set(hwDeviceResourceEntry->DataType().Left(KFourCCLength));
1.282 + else if (aState == EMMFStateRecording) //then datatype supported 4CC is right 4 chars
1.283 + fourCCPtr.Set(hwDeviceResourceEntry->DataType().Right(KFourCCLength));
1.284 + TFourCC fourCCEntry(fourCCPtr);
1.285 + //need to check if entry already exists to prevent duplicate entries
1.286 + TBool alreadyExists = EFalse;
1.287 + for (TUint fourCCEntryNumber = 0; fourCCEntryNumber < entryNumber; fourCCEntryNumber++)
1.288 + {
1.289 + if (aSupportedDataTypes[fourCCEntryNumber]==fourCCEntry)
1.290 + {
1.291 + alreadyExists = ETrue;//we already have this 4CC in the supported data types
1.292 + break;
1.293 + }
1.294 + }
1.295 + if (!alreadyExists)
1.296 + {
1.297 + err = aSupportedDataTypes.Append(fourCCEntry);
1.298 + if (err)
1.299 + {//note we don't destroy array because we don't own it
1.300 + //but we do reset it as it is incomplete
1.301 + aSupportedDataTypes.Reset();
1.302 + User::Leave(err);
1.303 + }
1.304 + }
1.305 + }//if (IsDataTypeMatch(hwDeviceResourceEntry, fourCCPtrPCM16, aState))
1.306 + }//for (TUint hwDeviceEntry = 0; hwDeviceEntry < numberOfHwDevicePlugins; hwDeviceEntry++)
1.307 + }//if ((err == KErrNone)&&(numberOfHwDevicePlugins))
1.308 + else
1.309 + {//if an error occured and not KErrNotFound then must be a 'real' error eg KErrNoMemory
1.310 + if ((err != KErrNotFound)&&(err != KErrNone))
1.311 + User::Leave(err);
1.312 + }
1.313 + CleanupStack::PopAndDestroy(&plugInArray);
1.314 + }
1.315 +
1.316 +
1.317 +/*
1.318 + * IsDataTypeMatch
1.319 + * This method takes a given resource entry from a hardware device and determines
1.320 + * whether the hwdevice plugin is a data type match for playing or recording
1.321 + * depending on the setting of aState
1.322 + * The method matchs the default_data field from the hw device resource entry matching
1.323 + * it with the aHwMatchFourCC code.
1.324 + *
1.325 + * @internalComponent
1.326 + *
1.327 + * @param "CImplementationInformation aHwDeviceResourceEntry"
1.328 + * the hw device resource entry that is to be checked
1.329 + * whether it can be used to play or record
1.330 + *
1.331 + * @param "TDesC8& aHwMatchFourCC
1.332 + * the data type fourCC code to match to that the hardware device that must convert to for
1.333 + * playing and convert from for recording - for the reference DevSound this is always ' P16' ie pcm16
1.334 + *
1.335 + * @param "TMMFState aState"
1.336 + * this determines whether the match is for playing or recording and should take
1.337 + * either the values EMMFStatePlaying or EMMFStateRecording
1.338 + *
1.339 + * @return ETrue if a match for play or record else EFalse
1.340 + */
1.341 +TBool CMMFDevSoundUtility::IsDataTypeMatch(CImplementationInformation* aHwDeviceResourceEntry,const TDesC8& aHwMatchFourCC, TMMFState aState)
1.342 + {
1.343 + TBool match = EFalse;
1.344 + if (aState == EMMFStatePlaying)
1.345 + {//play need to match with the right four characters
1.346 + match = (!(aHwMatchFourCC.Match(aHwDeviceResourceEntry->DataType().Right(KFourCCLength))==KErrNotFound));
1.347 + }
1.348 + else if (aState == EMMFStateRecording)
1.349 + {//record need to match with the left four characters
1.350 + match = (!(aHwMatchFourCC.Match(aHwDeviceResourceEntry->DataType().Left(KFourCCLength))==KErrNotFound));
1.351 + }
1.352 + return match;
1.353 + }
1.354 +
1.355 +
1.356 +/**
1.357 + * Populate fixed sequences
1.358 + *
1.359 + */
1.360 +void CMMFDevSoundUtility::InitializeFixedSequenceL(CPtrC8Array** aFixedSequences)
1.361 + {
1.362 +
1.363 + RFs fsSession;
1.364 + User::LeaveIfError(fsSession.Connect());
1.365 + CleanupClosePushL(fsSession);
1.366 +
1.367 + // Open the resource file
1.368 + RResourceFile resourceFile;
1.369 + resourceFile.OpenL(fsSession, KFixedSequenceResourceFile);
1.370 + CleanupClosePushL(resourceFile);
1.371 +
1.372 + // Allocate buffer to hold resource data in binary format
1.373 + iInfo = resourceFile.AllocReadL(FIXED_TONE_SEQUENCE);
1.374 +
1.375 + TResourceReader reader;
1.376 + reader.SetBuffer(iInfo);
1.377 +
1.378 + // Create array to hold fixed sequences data
1.379 + CPtrC8Array* tempSequences = new(ELeave) CPtrC8Array(8); // granularity
1.380 + CleanupStack::PushL(tempSequences);
1.381 +
1.382 + // First word gives number of entries
1.383 + TInt numberOfEntries = reader.ReadUint16();
1.384 + ASSERT(!(numberOfEntries&1)); // Should have atleast one entry
1.385 +
1.386 + // There must be an even number entries as each sequence structure
1.387 + // is made of a name string and a data string (SEQUENCE_NAME and SEQUENCE_DATA)
1.388 +
1.389 + HMMFToneFixedSequenceNames* names = new (ELeave) HMMFToneFixedSequenceNames;
1.390 + CleanupStack::PushL(names);
1.391 + for (TInt i=0;i<numberOfEntries;i+=2)
1.392 + {
1.393 + // Copy name from resource array to returnable array
1.394 + HMMFToneFixedSequenceNames* newNames = names->AddNameL(reader.ReadTPtrC());
1.395 + if (names != newNames)
1.396 + { // May have moved so fixup cleanupstack reference
1.397 + CleanupStack::Pop();
1.398 + names = newNames;
1.399 + CleanupStack::PushL(names);
1.400 + }
1.401 + TInt len = reader.ReadUint16();
1.402 + TPtrC8 tempTPtrC8(REINTERPRET_CAST(const TUint8*,reader.Ptr()),len<<1);
1.403 + tempSequences->AppendL(tempTPtrC8);
1.404 + reader.Advance(len<<1);
1.405 + }
1.406 + CleanupStack::Pop(); // names
1.407 +
1.408 + // Delete the old fixed sequence names
1.409 + delete iFixedSequenceNames;
1.410 + iFixedSequenceNames = NULL;
1.411 + iFixedSequenceNames = names;
1.412 +
1.413 + *aFixedSequences = tempSequences;
1.414 + CleanupStack::Pop(tempSequences);
1.415 + CleanupStack::PopAndDestroy(2); // resourceFile, fsSession
1.416 + }
1.417 +
1.418 +TBool CMMFDevSoundUtility::RecognizeSequence(const TDesC8& aData)
1.419 + {
1.420 + // Reference plug-in only supports its own sequence format
1.421 + _LIT8(KSequenceSignature,"SQNC");
1.422 + if (aData.Length() > 4)
1.423 + {
1.424 + if (aData.Left(4) == KSequenceSignature)
1.425 + return ETrue;
1.426 + }
1.427 + // Didn't recognise
1.428 + return EFalse;
1.429 + }
1.430 +
1.431 +const TDesC& CMMFDevSoundUtility::FixedSequenceName(TInt aSequenceNumber)
1.432 + {
1.433 + ASSERT(iFixedSequenceNames); // Defect if this not true when previous was true
1.434 + ASSERT((aSequenceNumber>=0)&&(aSequenceNumber<iFixedSequenceNames->iCount));
1.435 +
1.436 + // Ptr to first descriptor
1.437 + TUint8* ptr = REINTERPRET_CAST(TUint8*,&(iFixedSequenceNames->iCount))+sizeof(TInt);
1.438 + TDesC* desPtr = REINTERPRET_CAST(TDesC*,ptr); // First des
1.439 + while (aSequenceNumber--)
1.440 + {
1.441 + TInt size = desPtr->Size();
1.442 + if (size&3)
1.443 + size = ((size+4)&(~3));
1.444 + ptr += sizeof(TInt) + size;
1.445 + desPtr = REINTERPRET_CAST(TDesC*,ptr); // Next des
1.446 + }
1.447 + return *desPtr;
1.448 + }