First public contribution.
1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // Class that provides API to list ECOM plugin implementation IDs
22 #include <mmfplugininterfaceuids.hrh>
23 #include <fixedsequence.rsg>
24 #include "DevSoundUtility.h"
25 #include <mmf/common/mmfcontroller.h> //needed for CleanupResetAndDestroyPushL()
26 #include <mm/mmpluginutils.h>
27 #ifdef SYMBIAN_MULTIMEDIA_CODEC_API
28 #include <mdf/codecapiresolverutils.h>
29 #include <mdf/codecapiresolverdata.h>
30 #include <mdf/codecapiuids.hrh>
31 #include <mdf/codecapiresolver.hrh>
32 #endif // SYMBIAN_MULTIMEDIA_CODEC_API
34 _LIT(KFixedSequenceResourceFile, "Z:\\Resource\\DevSound\\FixedSequence.rsc");
35 const TInt KFourCCStringLength = 9;
37 inline TMMFRawPackage::TMMFRawPackage(TInt aDerivedSize)
38 #pragma warning( disable : 4355 ) // 'this' : used in base member initializer list
39 : iThis((TUint8*)this,aDerivedSize,aDerivedSize)
40 #pragma warning( default : 4355 )
44 inline TPtr8& TMMFRawPackage::Package()
46 ((TMMFRawPackage*)this)->iThis.Set((TUint8*)this,iThis.Length(),iThis.MaxLength());
50 inline const TPtr8& TMMFRawPackage::Package() const
52 ((TMMFRawPackage*)this)->iThis.Set((TUint8*)this,iThis.Length(),iThis.MaxLength());
56 inline void TMMFRawPackage::SetSize(TInt aDerivedSize)
58 iThis.Set((TUint8*)this,aDerivedSize,aDerivedSize);
61 inline TMMFToneFixedSequenceNames::TMMFToneFixedSequenceNames() :
62 TMMFRawPackage(sizeof(TMMFToneFixedSequenceNames)) {}
65 class TNameBuf : public TBufCBase16
67 class TNameBuf : public TBufCBase8
70 friend class HMMFToneFixedSequenceNames;
73 HMMFToneFixedSequenceNames::HMMFToneFixedSequenceNames()
78 HMMFToneFixedSequenceNames* HMMFToneFixedSequenceNames::AddNameL(const TDesC& aName)
79 // Append a copy of the supplied descriptor to the end of the
80 // current heap cell. This will involve a realloc that will normally
81 // result in the object moving
83 TInt size = Package().Length();
84 TInt desSize = aName.Size() + sizeof(TInt);
86 desSize = ((desSize+4)&(~3)); // Must round up to word boundary to keep aligned
87 HMMFToneFixedSequenceNames* self = REINTERPRET_CAST(HMMFToneFixedSequenceNames*,User::ReAllocL(STATIC_CAST(TAny*,this),size + desSize));
88 TUint8* newDesPtr = REINTERPRET_CAST(TUint8*,self) + size;
89 Mem::FillZ(newDesPtr,desSize);
90 TNameBuf* newDes = REINTERPRET_CAST(TNameBuf*,newDesPtr);
91 newDes->Copy(aName,aName.Length());
92 self->SetSize(size+desSize);
98 /******************************************************************
100 ******************************************************************/
101 CMMFDevSoundUtility::CMMFDevSoundUtility()
103 // No default implementation
107 CMMFDevSoundUtility::~CMMFDevSoundUtility()
110 delete iFixedSequenceNames;
113 CMMFDevSoundUtility* CMMFDevSoundUtility::NewL()
115 CMMFDevSoundUtility* self = NewLC();
120 CMMFDevSoundUtility* CMMFDevSoundUtility::NewLC()
122 CMMFDevSoundUtility* self = new(ELeave) CMMFDevSoundUtility();
123 CleanupStack::PushL(self);
125 // Leave it on Cleanupstack
129 void CMMFDevSoundUtility::ConstructL()
131 iFixedSequenceNames = new (ELeave) HMMFToneFixedSequenceNames;
134 void CMMFDevSoundUtility::SeekUsingFourCCL(TUid aInterfaceUid, RImplInfoPtrArray& aPlugInArray, const TFourCC& aSrcDataType, const TFourCC& aDstDataType, const TDesC& aPreferredSupplier)
137 // Create a match string using the two FourCC codes.
138 _LIT8(KEmptyFourCCString, " , ");
139 TBufC8<KFourCCStringLength> fourCCString(KEmptyFourCCString);
140 TPtr8 fourCCPtr = fourCCString.Des();
141 TPtr8 fourCCPtr1(&fourCCPtr[0], 4);
142 TPtr8 fourCCPtr2(&fourCCPtr[5], 4 );
143 aSrcDataType.FourCC(&fourCCPtr1);
144 aDstDataType.FourCC(&fourCCPtr2);
146 MmPluginUtils::FindImplementationsL(aInterfaceUid, aPlugInArray, fourCCPtr);
148 // If more than one match. Narrow the search by preferred supplier
149 if((aPlugInArray.Count() > 1) && aPreferredSupplier.Length())
151 SelectByPreference( aPlugInArray, aPreferredSupplier );
154 // If there are no plugins, return failure
155 if(aPlugInArray.Count() == 0)
157 User::Leave( KErrNotFound );
162 #ifdef SYMBIAN_MULTIMEDIA_CODEC_API
163 void CMMFDevSoundUtility::FindHwDeviceAdapterL(TUid aInterfaceUid, RImplInfoPtrArray& aPlugInArray)
165 // Create a match string using the two FourCC codes.
166 _LIT8(KAdapterMatch, "*");
168 MmPluginUtils::FindImplementationsL(aInterfaceUid, aPlugInArray, KAdapterMatch);
170 // If there are no plugins, return failure
172 if(aPlugInArray.Count() == 0)
174 User::Leave( KErrNotFound );
178 void CMMFDevSoundUtility::SeekCodecPluginsL(RArray<TFourCC>& aSupportedDataTypes, TMMFState aState, TBool aAppend)
180 _LIT8(KPCM16FourCCString, " P16");
181 //check argument precondition for aState
182 if ((aState != EMMFStatePlaying) && (aState != EMMFStateRecording))
184 User::Leave(KErrArgument);
189 aSupportedDataTypes.Reset(); //clear any existing data in aSupportedDataTypes array if not appending
192 CCodecApiResolverData* customMatchData = CCodecApiResolverData::NewLC();
193 if (aState == EMMFStatePlaying)
195 customMatchData->SetMatchType(EMatchOutputDataFormat);
196 customMatchData->SetOutputDataL(KPCM16FourCCString);
200 customMatchData->SetMatchType(EMatchInputDataFormat);
201 customMatchData->SetInputDataL(KPCM16FourCCString);
204 customMatchData->SetImplementationType(TUid::Uid(KUidAudioCodec));
206 HBufC8* package = customMatchData->NewPackLC();
208 RImplInfoPtrArray ecomArray;
209 CleanupResetAndDestroyPushL(ecomArray);
212 MmPluginUtils::FindImplementationsL(TUid::Uid(KUidMdfProcessingUnit), ecomArray, *package, TUid::Uid(KUidCodecApiResolverImplementation));
214 for (TInt i=0 ; i < ecomArray.Count() ; i++)
216 CCodecApiOpaqueData* data = NULL;
217 TRAP(err, data = CCodecApiOpaqueData::NewL(ecomArray[i]->OpaqueData()));
218 // simply ignore plugins that we can't parse the opaque data. They should not cause other plugins
222 const TDesC8* dataType;
223 if (aState == EMMFStatePlaying)
225 dataType = &data->InputDataType();
229 dataType = &data->OutputDataType();
231 TFourCC fourCC(*dataType);
233 aSupportedDataTypes.AppendL(fourCC);
236 CleanupStack::PopAndDestroy(3, customMatchData);
238 #endif // SYMBIAN_MULTIMEDIA_CODEC_API
241 * local function to disable items which do not match the preferred supplier.
242 * Note that at least one enabled item is returned (if there was an enabled item to begin with) which
243 * may not match the preferred supplier.
246 void CMMFDevSoundUtility::SelectByPreference( RImplInfoPtrArray& aPlugInArray, const TDesC& aPreferredSupplier )
249 // Use the Disabled flag to eliminated all currently enabled matches that
250 // do not match the preferred supplier.
251 TInt firstEnabled = -1 ; // to ensure that we return something valid
252 TInt matchCount = 0 ;
253 for ( TInt ii = 0 ; ii < aPlugInArray.Count() ; ii++ )
255 if ( !( aPlugInArray[ii]->Disabled() ) )
257 if ( firstEnabled == -1 )
259 if ( aPlugInArray[ii]->DisplayName().FindF( aPreferredSupplier ) == KErrNotFound )
260 aPlugInArray[ii]->SetDisabled( ETrue ) ;
266 // If there are no matches then re-enable the first enabled
267 if ( matchCount == 0 )
268 aPlugInArray[firstEnabled]->SetDisabled( EFalse ) ;
269 else if ( matchCount > 1 )
271 // find the latest version from more than one match
272 TInt highestVersionIndex = -1 ;
273 for ( TInt ii = 0 ; ii < aPlugInArray.Count() ; ii++ )
275 if ( !( aPlugInArray[ii]->Disabled() ) ) // only interested in enabled elements
277 if ( highestVersionIndex == -1 )
278 { // first match. Store this. Keep it enabled
279 highestVersionIndex = ii ;
281 else if ( aPlugInArray[ii]->Version() > aPlugInArray[highestVersionIndex]->Version() )
282 { // a new leader. Disable the previous leader. Keep this one.
283 aPlugInArray[highestVersionIndex]->SetDisabled( ETrue ) ;
284 highestVersionIndex = ii ;
286 else // we already have a higher version.
287 aPlugInArray[ii]->SetDisabled( ETrue ) ;
295 * SeekHwDevicePluginsL
296 * This method looks for hwDevicePlugins that support the state given in aState which
297 * must be either EMMFStatePlaying or EMMFStateRecording
298 * For each HwDevice plugin found the datatype as indicated by its fourCC code
299 * from the default_data field in the resource file is added to the array of aSupportedDataTypes
303 * @param "RArray<TFourCC>& aSupportedDataTypes"
304 * an array of fourCC codes that has a fourCC code added to for each hardware device found
306 * @param "TMMFState aState"
307 * must be set to EMMFStatePlaying if seeking HwDevice plugins that support play and
308 * EMMFStateRecording if seeking HwDevice plugins that support record
310 * @leave KErrArgument if aState is not EMMFStatePlaying or EMMFStateRecording else leaves
311 * with standard symbian OS error code
313 void CMMFDevSoundUtility::SeekHwDevicePluginsL(RArray<TFourCC>& aSupportedDataTypes, TMMFState aState)
315 //check argument precondition for aState
316 if ((aState != EMMFStatePlaying) && (aState != EMMFStateRecording))
318 User::Leave(KErrArgument);
321 aSupportedDataTypes.Reset(); //clear any existing data in aSupportedDataTypes array
323 RImplInfoPtrArray plugInArray ; // Array to return hw device plugin resource info
324 CleanupResetAndDestroyPushL(plugInArray);
326 TUid KUidMmfHWPluginInterfaceCodec = {KMmfUidPluginInterfaceHwDevice};
328 MmPluginUtils::FindImplementationsL(KUidMmfHWPluginInterfaceCodec, plugInArray);
330 TUint numberOfHwDevicePlugins = plugInArray.Count();
332 //if have hwdevice plugin resource entries then scan entries
333 //matching on a datatype of pcm16 as the destination datatype for play and the
334 //source datatype for record
335 //if a match is found and isn't already in list of supported data types
336 //then add it to the list
337 if (numberOfHwDevicePlugins)
339 CImplementationInformation* hwDeviceResourceEntry = NULL;
340 _LIT8(KPCM16FourCCString, " P16");
341 TBufC8<KFourCCLength> fourCCStringPCM16(KPCM16FourCCString);
342 TPtr8 fourCCPtrPCM16 = fourCCStringPCM16.Des();
343 TUint entryNumber = 0;
345 //check each resource entry for dst 4CC = P16 for play and src 4CC = P16 for record
346 for (TUint hwDeviceEntry = 0; hwDeviceEntry < numberOfHwDevicePlugins; hwDeviceEntry++)
348 hwDeviceResourceEntry = plugInArray[hwDeviceEntry];
349 if (IsDataTypeMatch(hwDeviceResourceEntry, fourCCPtrPCM16, aState))
350 {//resource entry data field has dest/src datatype ' P16' ie pcm16 for play/record
351 TPtrC8 fourCCPtr(0,0);
352 if (aState == EMMFStatePlaying)//then datatype supported 4CC is left 4 chars
354 fourCCPtr.Set(hwDeviceResourceEntry->DataType().Left(KFourCCLength));
356 else if (aState == EMMFStateRecording) //then datatype supported 4CC is right 4 chars
358 fourCCPtr.Set(hwDeviceResourceEntry->DataType().Right(KFourCCLength));
360 TFourCC fourCCEntry(fourCCPtr);
361 //need to check if entry already exists to prevent duplicate entries
362 entryNumber = aSupportedDataTypes.Count();
363 TBool alreadyExists = EFalse;
364 for (TUint fourCCEntryNumber = 0; fourCCEntryNumber < entryNumber; fourCCEntryNumber++)
366 if (aSupportedDataTypes[fourCCEntryNumber]==fourCCEntry)
368 alreadyExists = ETrue;//we already have this 4CC in the supported data types
374 TInt err = aSupportedDataTypes.Append(fourCCEntry);
376 {//note we don't destroy array because we don't own it
377 //but we do reset it as it is incomplete
378 aSupportedDataTypes.Reset();
382 }//if (IsDataTypeMatch(hwDeviceResourceEntry, fourCCPtrPCM16, aState))
383 }//for (TUint hwDeviceEntry = 0; hwDeviceEntry < numberOfHwDevicePlugins; hwDeviceEntry++)
384 }//if (numberOfHwDevicePlugins)
386 CleanupStack::PopAndDestroy(&plugInArray);
392 * This method takes a given resource entry from a hardware device and determines
393 * whether the hwdevice plugin is a data type match for playing or recording
394 * depending on the setting of aState
395 * The method matchs the default_data field from the hw device resource entry matching
396 * it with the aHwMatchFourCC code.
400 * @param "CImplementationInformation aHwDeviceResourceEntry"
401 * the hw device resource entry that is to be checked
402 * whether it can be used to play or record
404 * @param "TDesC8& aHwMatchFourCC
405 * the data type fourCC code to match to that the hardware device that must convert to for
406 * playing and convert from for recording - for the reference DevSound this is always ' P16' ie pcm16
408 * @param "TMMFState aState"
409 * this determines whether the match is for playing or recording and should take
410 * either the values EMMFStatePlaying or EMMFStateRecording
412 * @return ETrue if a match for play or record else EFalse
414 TBool CMMFDevSoundUtility::IsDataTypeMatch(CImplementationInformation* aHwDeviceResourceEntry,const TDesC8& aHwMatchFourCC, TMMFState aState)
416 TBool match = EFalse;
417 // extra length safety check to remove adapter plugins and incorrect ones
418 if (aHwDeviceResourceEntry->DataType().Length()>=KFourCCStringLength)
420 if (aState == EMMFStatePlaying)
421 {//play need to match with the right four characters
422 match = (!(aHwMatchFourCC.Match(aHwDeviceResourceEntry->DataType().Right(KFourCCLength))==KErrNotFound));
424 else if (aState == EMMFStateRecording)
425 {//record need to match with the left four characters
426 match = (!(aHwMatchFourCC.Match(aHwDeviceResourceEntry->DataType().Left(KFourCCLength))==KErrNotFound));
434 * Populate fixed sequences
437 void CMMFDevSoundUtility::InitializeFixedSequenceL(CPtrC8Array** aFixedSequences)
441 User::LeaveIfError(fsSession.Connect());
442 CleanupClosePushL(fsSession);
444 // Open the resource file
445 RResourceFile resourceFile;
446 resourceFile.OpenL(fsSession, KFixedSequenceResourceFile);
447 CleanupClosePushL(resourceFile);
449 // Allocate buffer to hold resource data in binary format
450 iInfo = resourceFile.AllocReadL(FIXED_TONE_SEQUENCE);
452 TResourceReader reader;
453 reader.SetBuffer(iInfo);
455 // Create array to hold fixed sequences data
456 CPtrC8Array* tempSequences = new(ELeave) CPtrC8Array(8); // granularity
457 CleanupStack::PushL(tempSequences);
459 // First word gives number of entries
460 TInt numberOfEntries = reader.ReadUint16();
461 ASSERT(!(numberOfEntries&1)); // Should have atleast one entry
463 // There must be an even number entries as each sequence structure
464 // is made of a name string and a data string (SEQUENCE_NAME and SEQUENCE_DATA)
466 HMMFToneFixedSequenceNames* names = new (ELeave) HMMFToneFixedSequenceNames;
467 CleanupStack::PushL(names);
468 for (TInt i=0;i<numberOfEntries;i+=2)
470 // Copy name from resource array to returnable array
471 HMMFToneFixedSequenceNames* newNames = names->AddNameL(reader.ReadTPtrC());
472 if (names != newNames)
473 { // May have moved so fixup cleanupstack reference
476 CleanupStack::PushL(names);
478 TInt len = reader.ReadUint16();
479 TPtrC8 tempTPtrC8(REINTERPRET_CAST(const TUint8*,reader.Ptr()),len<<1);
480 tempSequences->AppendL(tempTPtrC8);
481 reader.Advance(len<<1);
483 CleanupStack::Pop(); // names
485 // Delete the old fixed sequence names
486 delete iFixedSequenceNames;
487 iFixedSequenceNames = NULL;
488 iFixedSequenceNames = names;
490 *aFixedSequences = tempSequences;
491 CleanupStack::Pop(tempSequences);
492 CleanupStack::PopAndDestroy(2); // resourceFile, fsSession
495 TBool CMMFDevSoundUtility::RecognizeSequence(const TDesC8& aData)
497 // Reference plug-in only supports its own sequence format
498 _LIT8(KSequenceSignature,"SQNC");
499 if (aData.Length() > 4)
501 if (aData.Left(4) == KSequenceSignature)
508 const TDesC& CMMFDevSoundUtility::FixedSequenceName(TInt aSequenceNumber)
510 ASSERT(iFixedSequenceNames); // Defect if this not true when previous was true
511 ASSERT((aSequenceNumber>=0)&&(aSequenceNumber<iFixedSequenceNames->iCount));
513 // Ptr to first descriptor
514 TUint8* ptr = REINTERPRET_CAST(TUint8*,&(iFixedSequenceNames->iCount))+sizeof(TInt);
515 TDesC* desPtr = REINTERPRET_CAST(TDesC*,ptr); // First des
516 while (aSequenceNumber--)
518 TInt size = desPtr->Size();
520 size = ((size+4)&(~3));
521 ptr += sizeof(TInt) + size;
522 desPtr = REINTERPRET_CAST(TDesC*,ptr); // Next des