diff -r 052d4b8fc4fd -r a2070821d450 breakdeps/mmfclientutility.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/breakdeps/mmfclientutility.cpp Fri Nov 12 11:56:07 2010 +0000 @@ -0,0 +1,2531 @@ +// Copyright (c) 2002-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: +// Audio, MIDI and Video client utility functions. +// +// + +#include +#include +#include +#include +#include +#include +using namespace ContentAccess; + +#include "mmfclientutility.h" +#include + +const TInt KMaxMimeLength = 256; +const TInt KMaxHeaderSize = 256; +const TInt KExpandSize = 100; + +#ifdef SYMBIAN_ENABLE_MMF_MULTISCREEN_SUPPORT + const TInt KDefaultScreenNo = 0; +#endif + +void CUPanic(TInt aCUPanicCode) + { + _LIT(KMMFMediaClientUtilityPaanicCategory, "MMFClientUtility"); + User::Panic(KMMFMediaClientUtilityPaanicCategory, aCUPanicCode); + } + +/** + * @internalComponent + */ +EXPORT_C TUid CMMFClientUtility::ConvertMdaFormatUidToECOMWrite(TUid aMdaFormatUid) + { + TUid ECOMUid = KNullUid; + if (aMdaFormatUid == KUidMdaClipFormatWav) + ECOMUid = TUid::Uid(KMmfUidFormatWAVWrite); + else if (aMdaFormatUid == KUidMdaClipFormatAu) + ECOMUid = TUid::Uid(KMmfUidFormatAUWrite); + else if (aMdaFormatUid == KUidMdaClipFormatRawAudio) + ECOMUid = TUid::Uid(KMmfUidFormatRAWWrite); + else if (aMdaFormatUid == KUidMdaClipFormatRawAmr) + ECOMUid = TUid::Uid(KAdvancedUidFormatAMRWrite); + + return ECOMUid; + } + +/** + * @internalComponent + */ +EXPORT_C TUid CMMFClientUtility::ConvertMdaFormatUidToECOMRead(TUid aMdaFormatUid) + { + TUid ECOMUid = KNullUid; + if (aMdaFormatUid == KUidMdaClipFormatWav) + ECOMUid = TUid::Uid(KMmfUidFormatWAVRead); + else if (aMdaFormatUid == KUidMdaClipFormatAu) + ECOMUid = TUid::Uid(KMmfUidFormatAURead); + else if (aMdaFormatUid == KUidMdaClipFormatRawAudio) + ECOMUid = TUid::Uid(KMmfUidFormatRAWRead); + else if (aMdaFormatUid == KUidMdaClipFormatRawAmr) + ECOMUid = TUid::Uid(KAdvancedUidFormatAMRRead); + + return ECOMUid; + } + +/** + * @internalComponent + */ +EXPORT_C TInt CMMFClientUtility::GetFileHeaderData(const TDesC& aFileName, TDes8& aHeaderData, TInt aMaxLength) + { + RFs fsSession; + RFile file; + TInt error = KErrNone; + + if ((error = fsSession.Connect()) == KErrNone) + { + if ((error = file.Open(fsSession, aFileName, EFileShareReadersOrWriters)) == KErrNone) + { + TInt size = 0; + + if ((error = file.Size(size)) == KErrNone) + { + if (size > 0) + { + if (size > aMaxLength) + size = aMaxLength; + + error = file.Read(aHeaderData, size); + } + } + file.Close(); + } + fsSession.Close(); + } + + return error; + } + +/** + * @internalComponent + */ +EXPORT_C TFourCC CMMFClientUtility::ConvertMdaCodecToFourCC(TMdaPackage& aCodec) + { + TFourCC dataType = KMMFFourCCCodeNULL; + switch (aCodec.Uid().iUid) + { + case KUidMdaWavPcmCodecDefine: + { + TMdaPcmWavCodec* pcmWavCodec = (TMdaPcmWavCodec*)&aCodec; + if (pcmWavCodec->iBits == TMdaPcmWavCodec::E8BitPcm) + dataType = KMMFFourCCCodePCMU8; //8 bit PCM + else + dataType = KMMFFourCCCodePCM16; //16 bit PCM + break; + } + case KUidMdaAu8PcmCodecDefine: + dataType = KMMFFourCCCodePCM8; + break; + case KUidMdaAuCodecDefine: + case KUidMdaAu16PcmCodecDefine: + dataType = KMMFFourCCCodePCM16B; + break; + + case KUidMdaAuMulawCodecDefine: + case KUidMdaWavMulawCodecDefine: + case KUidMdaRawAudioMulawCodecDefine: //uLAW + dataType = KMMFFourCCCodeMuLAW; + break; + case KUidMdaAuAlawCodecDefine: + case KUidMdaWavAlawCodecDefine: + case KUidMdaRawAudioAlawCodecDefine: //ALAW + dataType = KMMFFourCCCodeALAW; + break; + case KUidMdaRawAudioS8PcmCodecDefine: // P8 + dataType = KMMFFourCCCodePCM8; + break; + case KUidMdaRawAudioU8PcmCodecDefine: // PU8 + dataType = KMMFFourCCCodePCMU8; + break; + case KUidMdaRawAudioSL16PcmCodecDefine: // P16 + dataType = KMMFFourCCCodePCM16; + break; + case KUidMdaRawAudioSB16PcmCodecDefine: //P16B + dataType = KMMFFourCCCodePCM16B; + break; + case KUidMdaRawAudioUL16PcmCodecDefine: //PU16 + dataType = KMMFFourCCCodePCMU16; + break; + case KUidMdaRawAudioUB16PcmCodecDefine: //PU6B + dataType = KMMFFourCCCodePCMU16B; + break; + case KUidMdaGsmWavCodecDefine: //GSM6 + dataType = KMMFFourCCCodeGSM610; + break; + case KUidMdaWavImaAdpcmCodecDefine: + dataType = KMMFFourCCCodeIMAD; + break; + case KUidMdaRawAmrCodecDefine: + dataType = KMMFFourCCCodeAMR; + break; + default: // Not a Uid we recognise + dataType = KMMFFourCCCodeNULL; + break; + } + return dataType; + } + + +CMMFUtilityFileInfo* CMMFUtilityFileInfo::NewL(TMMSource& aSource, TBool aSecureDRMMode) + { + CMMFUtilityFileInfo* self = CMMFUtilityFileInfo::NewLC(aSource, aSecureDRMMode); + CleanupStack::Pop(self); + return self; + } + + +CMMFUtilityFileInfo* CMMFUtilityFileInfo::NewLC(TMMSource& aSource, TBool aSecureDRMMode) + { + CMMFUtilityFileInfo* self = new (ELeave) CMMFUtilityFileInfo; + CleanupStack::PushL(self); + self->ConstructL(aSource, aSecureDRMMode); + return self; + } + + +void CMMFUtilityFileInfo::ConstructL(const TMMSource& aSource, TBool aSecureDRMMode) + { + if (!aSecureDRMMode) + { + if (aSource.SourceType()==KUidMMFileSource) + { + const TMMFileSource& fileSource = static_cast(aSource); + iData = CData::NewL(TVirtualPathPtr(fileSource.Name(), fileSource.UniqueId()), + EContentShareReadWrite); + } + + if (aSource.SourceType()==KUidMMFileHandleSource) + { + const TMMFileHandleSource& fileHandleSource = static_cast(aSource); + iData = CData::NewL(fileHandleSource.Handle(), fileHandleSource.UniqueId()); + } + + TInt err = iData->SetProperty(EAgentPropertyAgentUI, aSource.IsUIEnabled()); + if (err != KErrNone && err != KErrCANotSupported) + { + // KErrCANotSupported isn't a problem for us so eat the error code. + User::Leave(err); + } + + err = iData->EvaluateIntent(aSource.Intent()); + User::LeaveIfError(err); + } + else + { + // Use RMMFDRMPluginServerProxy as medium + iDrmPluginServer = new (ELeave) RMMFDRMPluginServerProxy; + User::LeaveIfError(iDrmPluginServer->Open()); + + CBufFlat* dataBuffer = CBufFlat::NewL(KExpandSize); + CleanupStack::PushL(dataBuffer); + RBufWriteStream stream; + stream.Open(*dataBuffer); + CleanupClosePushL(stream); + + stream.WriteInt32L(aSource.UniqueId().Length()); + stream.WriteL(aSource.UniqueId()); + stream.WriteInt32L(aSource.IsUIEnabled()); + TPckgBuf intentPckg(aSource.Intent()); + stream.WriteL(intentPckg); + stream.CommitL(); + + CleanupStack::PopAndDestroy(&stream); + if (aSource.SourceType()==KUidMMFileSource) + { + const TMMFileSource& fileSource = static_cast(aSource); + iDrmPluginServer->OpenDataContentL(fileSource.Name(), dataBuffer->Ptr(0)); + } + if (aSource.SourceType()==KUidMMFileHandleSource) + { + const TMMFileHandleSource& fileHandleSource = static_cast(aSource); + iDrmPluginServer->OpenDataContentL(fileHandleSource.Handle(), dataBuffer->Ptr(0)); + } + CleanupStack::PopAndDestroy(dataBuffer); + } + } + +TInt CMMFUtilityFileInfo::EvaluateIntent(TIntent aIntent) + { + if (iData) + { + return iData->EvaluateIntent(aIntent); + } + else + { + ASSERT(iDrmPluginServer); + return iDrmPluginServer->EvaluateDataContentIntent(aIntent); + } + } +/** + * @internalComponent + */ +TBool CMMFUtilityFileInfo::GetFileMimeTypeL(TDes8& aMimeType) + { + if (iData) + { + return iData->GetMimeTypeL(aMimeType); + } + else + { + ASSERT(iDrmPluginServer); + return iDrmPluginServer->GetDataContentMimeTypeL(aMimeType); + } + } + +/** + * @internalComponent + */ +void CMMFUtilityFileInfo::GetFileHeaderDataL(TDes8& aHeaderData, TInt aMaxLength) + { + if (iData) + { + TInt size = 0; + iData->DataSizeL(size); + if (size > 0) + { + if (size > aMaxLength) + size = aMaxLength; + TInt pos = 0; + User::LeaveIfError(iData->Seek(ESeekStart, pos)); + User::LeaveIfError(iData->Read(aHeaderData, size)); + } + } + else + { + ASSERT(iDrmPluginServer); + iDrmPluginServer->GetDataContentFileHeaderL(aHeaderData, aMaxLength); + } + } + +/** + * @internalComponent + */ +EXPORT_C HBufC8* CMMFClientUtility::GetFileExtensionL(const TDesC& aFileName) + { + TParse fileName; + fileName.Set(aFileName,NULL,NULL); + HBufC8* fileSuffix = NULL; + if(fileName.ExtPresent()) + { + TPtrC fileSuffixPtr(fileName.Ext()); + fileSuffix = HBufC8::NewL(fileSuffixPtr.Length()); + fileSuffix->Des().Copy(fileSuffixPtr); + } + else + { + fileSuffix = KNullDesC8().AllocL(); + } + return fileSuffix; + } + + +/** + * @internalComponent + */ +CMMFUtilityFileInfo::~CMMFUtilityFileInfo() + { + if (iData) + { + delete iData; + } + if (iDrmPluginServer) + { + iDrmPluginServer->Close(); + delete iDrmPluginServer; + } + } + +/* + * @internalComponent + * + * Returns an integer rating indicating how well the supplied format matches + * the header data and file extension supplied. + * 3 brownie points awarded for data & suffix match. + * 2 brownie points awarded for data match alone. + * 1 brownie point awarded for suffix match alone. + */ +TInt CMMFClientUtility::GetBestMatchL(const CMMFFormatImplementationInformation* format, const TDesC8& aHeaderData, const TDesC8& aFileExtension) + { + TInt browniePoints = 0; + + if (aHeaderData.Length() > 0) // Non empty file + { + if (aFileExtension.Length() > 0) // With a file extension + { + if (format->SupportsHeaderDataL(aHeaderData) && + format->SupportsFileExtension(aFileExtension)) + { + browniePoints = 3; + } + else if (format->SupportsHeaderDataL(aHeaderData)) + { + browniePoints = 2; + } + else + { + // See if this format has any 'empty' match data or no match data, indicating + // that this format will match extension alone even if data present. + // (A format may have more than one match data string.) + const CDesC8Array& supportedHeaderData = format->SupportedHeaderData(); + + if (supportedHeaderData.Count() == 0) + { + // No header data indicated. + if (format->SupportsFileExtension(aFileExtension)) + { + browniePoints = 1; + } + } + else + { + for (register TInt i = 0; i < supportedHeaderData.Count(); i++) + { + if ((supportedHeaderData[i].Length() == 0) && + format->SupportsFileExtension(aFileExtension)) + { + browniePoints = 1; + } + } + } + } + } + else + { + // No file suffix, so must match header data alone. + if (format->SupportsHeaderDataL(aHeaderData)) + { + browniePoints = 2; + } + } + } + else // Empty File + { + // We have no choice but to match extension, if there is one. + if ((aFileExtension.Length() > 0) && format->SupportsFileExtension(aFileExtension)) + { + browniePoints = 1; + } + } + + return browniePoints; +} + +/** + * @internalComponent + * + * This function parses all the play & record formats in the given list of controllers, + * looking for controllers & formats that best match the requirements. + * Play controllers will be returned before record controllers, and + * in cases of equal priority between formats, ECom order will be maintained. + * + * @param "aControllers" + * A reference to a user supplied list of controllers retrieved from ECom. + * This list may be have been filtered for audio/video/play/record. + * @param "aHeaderDataPlayback" + * A descriptor reference containing the file's header data. + * for matching against a controller's play formats. May be KNullDesC8 + * @param "aFileExtensionPlayback" + * A descriptor reference containing the filename's extension. + * for matching against a controller's play formats. May be KNullDesC8 + * @param "aHeaderDataRecord" + * A descriptor reference containing the file's header data. + * for matching against a controller's record formats. May be KNullDesC8 + * @param "aFileExtensionRecord" + * A descriptor reference containing the filename's extension. + * for matching against a controller's record formats. May be KNullDesC8 + * @param "aPrioritisedControllers" + * A reference to a user supplied list through which the list of + * prioritised controllers will be returned. + * @since 7.0s + */ +void CMMFClientUtility::PrioritiseControllersL( + const RMMFControllerImplInfoArray& aControllers, + const TDesC8& aHeaderDataPlayback, + const TDesC8& aFileExtensionPlayback, + const TDesC8& aHeaderDataRecord, + const TDesC8& aFileExtensionRecord, + RMMFControllerImplInfoArray& prioritisedControllers) + { + RMMFControllerImplInfoArray fullMatchControllers; // data AND suffix + CleanupClosePushL(fullMatchControllers); + RMMFControllerImplInfoArray partMatchControllers; // data OR suffix + CleanupClosePushL(partMatchControllers); + + TBool checkingPlaybackFormats = EFalse; + TBool checkingRecordFormats = EFalse; + + if (aHeaderDataPlayback != KNullDesC8 || aFileExtensionPlayback != KNullDesC8) + checkingPlaybackFormats = ETrue; + if (aHeaderDataRecord != KNullDesC8 || aFileExtensionRecord != KNullDesC8) + checkingRecordFormats = ETrue; + + // Examine each format for each controller. We only want to know at this stage + // if the controller has suitable formats, so as soon as we know it has, we can + // add it to out list, ranked by how well it matched. + for (register TInt i = 0; i < aControllers.Count(); i++) + { + const CMMFControllerImplementationInformation* controller = aControllers[i]; + TInt savedBrowniePointsPlayback = 0; + TInt savedBrowniePointsRecord = 0; + + if (checkingPlaybackFormats) + { + for (register TInt p = 0; p < controller->PlayFormats().Count(); p++) + { + const CMMFFormatImplementationInformation* format = controller->PlayFormats()[p]; + + TInt browniePoints = GetBestMatchL(format, aHeaderDataPlayback, aFileExtensionPlayback); + + if (browniePoints >= savedBrowniePointsPlayback) + savedBrowniePointsPlayback = browniePoints; + } + } + + if (checkingRecordFormats) + { + for (register TInt r = 0; r < controller->RecordFormats().Count(); r++) + { + const CMMFFormatImplementationInformation* format = controller->RecordFormats()[r]; + + TInt browniePoints = GetBestMatchL(format, aHeaderDataRecord, aFileExtensionRecord); + + if (browniePoints >= savedBrowniePointsRecord) + savedBrowniePointsRecord = browniePoints; + } + } + + TInt savedBrowniePoints = 0; + // if we're checking both playback & record formats + // make sure we've found both + if (checkingPlaybackFormats && checkingRecordFormats) + { + savedBrowniePoints = Min(savedBrowniePointsPlayback, savedBrowniePointsRecord); + } + else if (checkingPlaybackFormats) + { + savedBrowniePoints = savedBrowniePointsPlayback; + } + else if (checkingRecordFormats) + { + savedBrowniePoints = savedBrowniePointsRecord; + } + + // Checked all formats for this controller, now count our brownie points. + switch (savedBrowniePoints) + { + case 3: + User::LeaveIfError(fullMatchControllers.Append(controller)); + break; + case 2: + User::LeaveIfError(partMatchControllers.Insert(controller, 0)); + break; + case 1: + User::LeaveIfError(partMatchControllers.Append(controller)); + break; + default: + break; + } + } + + // The better the controller matches, the earlier it will be in the final list. + for (register TInt x = 0; x < fullMatchControllers.Count(); x++) + { + if (prioritisedControllers.Find(fullMatchControllers[x]) == KErrNotFound) + { + User::LeaveIfError(prioritisedControllers.Append(fullMatchControllers[x])); + } + } + + for (register TInt y = 0; y < partMatchControllers.Count(); y++) + { + if (prioritisedControllers.Find(partMatchControllers[y]) == KErrNotFound) + { + User::LeaveIfError(prioritisedControllers.Append(partMatchControllers[y])); + } + } + + CleanupStack::PopAndDestroy(2, &fullMatchControllers); // fullMatchControllers, partMatchControllers + } + +/** + * @internalComponent + */ +EXPORT_C CMMFMdaObjectStateChangeObserverCallback* CMMFMdaObjectStateChangeObserverCallback::NewL(MMdaObjectStateChangeObserver& aCallback) + { + return new(ELeave) CMMFMdaObjectStateChangeObserverCallback(aCallback); + } + +/** + * @internalComponent + */ +CMMFMdaObjectStateChangeObserverCallback::~CMMFMdaObjectStateChangeObserverCallback() + { + Cancel(); + } + +/** + * @internalComponent + */ +EXPORT_C void CMMFMdaObjectStateChangeObserverCallback::CallBack(CBase* aObject, TInt aPreviousState, TInt aCurrentState, TInt aErrorCode) + { + iObject = aObject; + iPreviousState = aPreviousState; + iCurrentState = aCurrentState; + iErrorCode = aErrorCode; + if (!IsActive()) + { + TRequestStatus* s = &iStatus; + SetActive(); + User::RequestComplete(s, KErrNone); + } + } + +CMMFMdaObjectStateChangeObserverCallback::CMMFMdaObjectStateChangeObserverCallback(MMdaObjectStateChangeObserver& aCallback) : + CActive(CActive::EPriorityHigh), + iCallback(aCallback) + { + CActiveScheduler::Add(this); + } + +void CMMFMdaObjectStateChangeObserverCallback::RunL() + { + iCallback.MoscoStateChangeEvent(iObject, iPreviousState, iCurrentState, iErrorCode); + } + +void CMMFMdaObjectStateChangeObserverCallback::DoCancel() + { + //nothing to cancel + } + + +//**************************************** +// CMMFFindAndOpenController +//**************************************** + +/** + * Factory function to create a CMMFFindAndOpenController class + * + * @internalComponent + */ +EXPORT_C CMMFFindAndOpenController* CMMFFindAndOpenController::NewL(MMMFFindAndOpenControllerObserver& aObserver) + { + CMMFFindAndOpenController* self = new(ELeave) CMMFFindAndOpenController(aObserver); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CMMFFindAndOpenController::~CMMFFindAndOpenController() + { + Cancel(); + + // delete temporary variables + Close(); + + // this should cancel the AO + delete iAddDataSourceSinkAsync; + + delete iPrimaryConfig; + delete iSecondaryConfig; + } + +/** + * Function to free up memory after a successful open has completed + * Useful to allow a alloc testing to work. + * Must not be called if ReOpen() is to be called + * + * @internalComponent + */ +EXPORT_C void CMMFFindAndOpenController::Close() + { + + Cancel(); + + if(iAddDataSourceSinkAsync) + { + iAddDataSourceSinkAsync->Cancel(); + } + + if (iPrimaryConfig) + iPrimaryConfig->Close(); + if (iSecondaryConfig) + iSecondaryConfig->Close(); + + iPrioritisedControllers.Close(); + iControllers.ResetAndDestroy(); + iControllers.Close(); + + iFileName.SetLength(0); + iFileNameSecondary.SetLength(0); + + delete iUrl; + iUrl = NULL; + + delete iMimeType; + iMimeType = NULL; + + delete iUniqueId; + iUniqueId = NULL; + + if (iOwnFileHandle) + { + iFileHandle.Close(); + iOwnFileHandle = EFalse; + } + } +/** + * Function to free up memory of which is not required in ReOpen() + * after a successful open has completed + * Useful to allow a alloc testing to work. + * + * @internalComponent + */ + +EXPORT_C void CMMFFindAndOpenController::CloseConfig() + { + Cancel(); + if(iAddDataSourceSinkAsync) + { + iAddDataSourceSinkAsync->Cancel(); + } + + if (iSecondaryConfig) + { + iSecondaryConfig->Close(); + } + + iPrioritisedControllers.Close(); + iControllers.ResetAndDestroy(); + iControllers.Close(); + + iFileName.SetLength(0); + iFileNameSecondary.SetLength(0); + + delete iUrl; + iUrl = NULL; + + delete iMimeType; + iMimeType = NULL; + + delete iUniqueId; + iUniqueId = NULL; + + if (iOwnFileHandle) + { + iFileHandle.Close(); + iOwnFileHandle = EFalse; + } + } + +CMMFFindAndOpenController::CMMFFindAndOpenController(MMMFFindAndOpenControllerObserver& aObserver) : + CActive(EPriorityStandard), + iObserver(aObserver), + iDescriptor(NULL, 0) + { + CActiveScheduler::Add(this); + } + +void CMMFFindAndOpenController::ConstructL() + { + iAddDataSourceSinkAsync = CMMFAddDataSourceSinkAsync::NewL(*this); + iPrimaryConfig = new (ELeave) CConfig(); + iSecondaryConfig = new (ELeave) CConfig; + iCurrentConfig = iPrimaryConfig; + + RProcess thisProcess; + iHasDrmCapability = thisProcess.HasCapability(ECapabilityDRM, KSuppressPlatSecDiagnostic); + thisProcess.Close(); + } + +void CMMFFindAndOpenController::RunL() + { + Process(); + } + +void CMMFFindAndOpenController::DoCancel() + { + iAddDataSourceSinkAsync->Cancel(); + } + +/** + * Defines the media ID & priority to be used when opening a controller + * Normally called once only after class has been constructed + * + * @param aMediaId + * the media ID to use when searching for a controller + * e.g. KUidMediaTypeAudio + * @param aPrioritySettings + * the priority settings to use when opening a controller + * @param aMediaIdMatchType + * Defines the type of media id match to be performed on the plugins + * returned from the ECOM registry. + * @leave can leave with KErrNoMemory + + * @internalComponent + */ +EXPORT_C void CMMFFindAndOpenController::Configure( + TUid aMediaId, + TMMFPrioritySettings aPrioritySettings, + CMMFPluginSelectionParameters::TMediaIdMatchType aMediaIdMatchType) + { + iPrioritySettings = aPrioritySettings; + + iMediaIdMatchType = aMediaIdMatchType; + + iMediaId = aMediaId; + } + +void CMMFFindAndOpenController::ConfigureController( + CConfig& config, + RMMFController& aController, + CMMFControllerEventMonitor& aEventMonitor, + TControllerMode aControllerMode) + { + config.iController = &aController; + config.iEventMonitor = &aEventMonitor; + config.iControllerMode = aControllerMode; + } + +/** + * Configures the primary controller + * + * @param aController + * a reference to the client controller object to use + * @param aEventMonitor + * a reference to an event monitor object for receiving + * events from the controller + * @param aControllerMode + * indicates whether this controller is to be used for recording + * or playback + * + * @internalComponent + */ +EXPORT_C void CMMFFindAndOpenController::ConfigureController( + RMMFController& aController, + CMMFControllerEventMonitor& aEventMonitor, + TControllerMode aControllerMode) + { + ConfigureController( + *iPrimaryConfig, + aController, + aEventMonitor, + aControllerMode); + } + +/** + * Configures the secondary controller + * + * This is only needed for the audio recorder utility which opens + * one controller for playback and another for recording + * + * @param aController + * a reference to the client controller object to use + * @param aEventMonitor + * a reference to an event monitor object for receiving + * events from the controller + * @param aControllerMode + * indicates whether this controller is to be used for recording + * or playback or converting + * + * @internalComponent + */ +EXPORT_C void CMMFFindAndOpenController::ConfigureSecondaryController( + RMMFController& aController, + CMMFControllerEventMonitor& aEventMonitor, + TControllerMode aControllerMode) + { + ConfigureController( + *iSecondaryConfig, + aController, + aEventMonitor, + aControllerMode); + } + +/** + * Makes any controllers that are opened subsequently share a single heap. + * + * The default behaviour is that each controller is created with its own heap. + * Each heap uses a chunk, so using this function avoids situations where the number + * of chunks per process is limited. + * The default behaviour is generally to be preferred, and should give lower overall + * memory usage. However, if many controllers are to be created for a particular thread, + * then this function should be used to prevent running out of heaps or chunks. + * + * @internalComponent + */ +EXPORT_C void CMMFFindAndOpenController::UseSharedHeap() + { + iUseSharedHeap = ETrue; + } + +void CMMFFindAndOpenController::Init() + { + // This should be called prior to opening, so reset the error + iError = KErrNone; + iSourceSinkConfigured = EFalse; + iControllerCount = 0; + } + +void CMMFFindAndOpenController::ConfigureSourceSink( + CConfig& config, + TSourceSink aSource, + TSourceSink aSink) + { + TInt err; + TRAP(err, config.iSource = CreateSourceSinkL(aSource)); + if (err != KErrNone) + { + iError = err; + return; + } + + TRAP(err, config.iSink = CreateSourceSinkL(aSink)); + if (err != KErrNone) + { + iError = err; + return; + } + } + + +void CMMFFindAndOpenController::ConfigureSourceSink( + CConfig& config, + const TMMSource& aSource, + TSourceSink aSink) + { + TInt err; + TRAP(err, config.iSource = CreateSourceSinkL(aSource)); + if (err != KErrNone) + { + iError = err; + return; + } + + TRAP(err, config.iSink = CreateSourceSinkL(aSink)); + if (err != KErrNone) + { + iError = err; + return; + } + } + + + +/** + * Configure the primary controller's source and sink + * The descriptors passed to this function are copied so they do not need to be persistent. + * To simplify the API, any errors that occur are reported back asynchronously following + * a subsequent call to OpenByXXX() + * + * @param aSourceUid + * the UID of the data source + * @param aSourceData + * a reference to a descriptor used to configure the source + * @param aSinkUid + * the UID of the data sink + * @param aSinkData + * a reference to a descriptor used to configure the sink + * + * @internalComponent + */ +EXPORT_C void CMMFFindAndOpenController::ConfigureSourceSink( + TSourceSink aSource, + TSourceSink aSink) + { + + CConfig* config = NULL; + + Init(); + config = iPrimaryConfig; + + + // must have already called ConfigureController() + __ASSERT_ALWAYS(config->iController != NULL, CUPanic(EMMFMediaClientUtilityBadState)); + + ConfigureSourceSink( + *config, + aSource, + aSink); + iCurrentConfig = config; + + iSourceSinkConfigured = ETrue; + } + + +/** + * Configure the primary controller's source and sink + * The descriptors passed to this function are copied so they do not need to be persistent. + * To simplify the API, any errors that occur are reported back asynchronously following + * a subsequent call to OpenByXXX() + * + * @param aSourceUid + * the UID of the data source + * @param aSourceData + * a reference to a descriptor used to configure the source + * @param aSinkUid + * the UID of the data sink + * @param aSinkData + * a reference to a descriptor used to configure the sink + * + * @internalComponent + */ +EXPORT_C void CMMFFindAndOpenController::ConfigureSecondarySourceSink( + TSourceSink aSource, + TSourceSink aSink) + { + if (iError != KErrNone) + { + // if there was an error configuring the primary source/sink, do not try the secondary one + // Don't return the error, since the stored error will be returned by the OpenBy... method + return; + } + + CConfig* config = NULL; + + config = iSecondaryConfig; + + // must have already configured the primary controller + __ASSERT_ALWAYS(iSourceSinkConfigured, CUPanic(EMMFMediaClientUtilityBadState)); + config = iSecondaryConfig; + + // must have already called ConfigureController() + __ASSERT_ALWAYS(config->iController != NULL, CUPanic(EMMFMediaClientUtilityBadState)); + + ConfigureSourceSink( + *config, + aSource, + aSink); + iCurrentConfig = config; + + iSourceSinkConfigured = ETrue; + } + + + +EXPORT_C void CMMFFindAndOpenController::ConfigureSourceSink( + const TMMSource& aSource, + TSourceSink aSink) + { + Init(); + CConfig* config = iPrimaryConfig; + + // must have already called ConfigureController() + __ASSERT_ALWAYS(config->iController != NULL, CUPanic(EMMFMediaClientUtilityBadState)); + + ConfigureSourceSink( + *config, + aSource, + aSink); + iCurrentConfig = config; + + iSourceSinkConfigured = ETrue; + } + + + +/** + * Opens a controller using the supplied controller UID + * and adds the source & sink + * Completion is indicated asynchonously by a call to MfaocComplete() + * + * @param aControllerUid + * the UID of the primary controller + * @param aControllerUid + * the UID of the secondary controller + * + * @internalComponent + */ +EXPORT_C void CMMFFindAndOpenController::OpenByControllerUid( + TUid aControllerUid, + TUid aSecondaryControllerUid) + { + // must have already called ConfigureSourceSink() + __ASSERT_ALWAYS(iSourceSinkConfigured, CUPanic(EMMFMediaClientUtilityBadState)); + + // Have there been any errors so far ? + if (iError != KErrNone) + { + SchedSendError(); + return; + } + + if (iCurrentConfig == iPrimaryConfig) + { + // only do this for the playback controller + TRAP(iError, iCurrentConfig->iSource->EvaluateIntentL()) + + if (iError != KErrNone && + !(iCurrentConfig->iControllerMode == EPlayback && iError == KErrPermissionDenied && !iHasDrmCapability)) + { + // KErrPermissionDenied error and no DRM capability are not problems in Playback mode + // proper action will be performed when controller is loaded + SchedSendError(); + return; + } + } + + iPrimaryConfig->iControllerUid = aControllerUid; + if (iCurrentConfig == iSecondaryConfig) + { + if (aSecondaryControllerUid == KNullUid) + iSecondaryConfig->iControllerUid = aControllerUid; + else + iSecondaryConfig->iControllerUid = aSecondaryControllerUid; + } + + iMode = EOpenByControllerUid; + iControllerImplInfo = NULL; + iState = EOpenController; + KickState(); + } + +/** + * Opens a controller using the supplied file name + * and adds the source & sink + * A copy is made of the filename or file handle so that it need not be persistent + * Completion is indicated asynchonously by a call to MfaocComplete() + * + * @param aSource + * a reference to a TFileSource object to be used when searching + * for a controller + * @param aFileNameSecondary + * a reference to the seconday filename to be used when searching + * for a controller. This need only be supplied when converting + * between two files. + * + * @internalComponent + */ +EXPORT_C void CMMFFindAndOpenController::OpenByFileSource(const TMMSource& aSource, const TDesC& aFileNameSecondary) + { + // must have already called ConfigureSourceSink() + __ASSERT_ALWAYS(iSourceSinkConfigured, CUPanic(EMMFMediaClientUtilityBadState)); + + TInt err; + // Have there been any errors so far ? + if (iError != KErrNone) + { + SchedSendError(); + return; + } + + if (iOwnFileHandle) + { + // in case of error + iFileHandle.Close(); + iOwnFileHandle = EFalse; + } + + iEnableUi = aSource.IsUIEnabled(); + if (aSource.SourceType()==KUidMMFileSource) + { + const TMMFileSource& fileSource = static_cast(aSource); + iFileName = fileSource.Name(); + iUseFileHandle = EFalse; + } + + if (aSource.SourceType()==KUidMMFileHandleSource) + { + const TMMFileHandleSource& fileHandleSource = static_cast(aSource); + ASSERT(iFileHandle.SubSessionHandle()==0); // closed just above + err = iFileHandle.Duplicate(fileHandleSource.Handle()); + if (err != KErrNone) + { + SchedSendError(err); + return; + } + iFileHandle.Name(iFileName); //ignore error return since we'll just do without the filename if not available + iUseFileHandle = ETrue; + iOwnFileHandle = ETrue; // because we dup'd it + } + + TRAP(err, iUniqueId = aSource.UniqueId().AllocL()); + iIntent = aSource.Intent(); + if (err != KErrNone) + { + SchedSendError(err); + return; + } + + + // take a copy of the secondary file name + iFileNameSecondary = aFileNameSecondary; + + iMode = EOpenByFileName; + iState = EBuildControllerList; + KickState(); + } + +/** + * Opens a controller using the supplied format UID + * and adds the source & sink + * Completion is indicated asynchonously by a call to MfaocComplete() + * + * @param aFormatUid + * the UID of a format that must be supported by the controller + * @param aFormatUidSecondary + * the UID of a secondary format that must be supported by the controller + * This need only be supplied when converting between two differnet formats. + * + * @internalComponent + */ +EXPORT_C void CMMFFindAndOpenController::OpenByFormatUid(TUid aFormatUid, TUid aFormatUidSecondary) + { + // must have already called ConfigureSourceSink() + __ASSERT_ALWAYS(iSourceSinkConfigured, CUPanic(EMMFMediaClientUtilityBadState)); + + // Have there been any errors so far ? + if (iError != KErrNone) + { + SchedSendError(); + return; + } + + iFormatUid = aFormatUid; + iFormatUidSecondary = aFormatUidSecondary; + + iMode = EOpenByFormatUid; + iState = EBuildControllerList; + KickState(); + } + +/** + * Opens a controller using the supplied descriptor + * and adds the source & sink + * Completion is indicated asynchonously by a call to MfaocComplete() + * + * @param aDescriptor + * a reference to the descriptor to be used when searching + * for a controller + * + * @internalComponent + */ +EXPORT_C void CMMFFindAndOpenController::OpenByDescriptor(const TDesC8& aDescriptor) + { + // must have already called ConfigureSourceSink() + __ASSERT_ALWAYS(iSourceSinkConfigured, CUPanic(EMMFMediaClientUtilityBadState)); + + // Have there been any errors so far ? + if (iError != KErrNone) + { + SchedSendError(); + return; + } + + // take a copy of the descriptor + TUint8* desBufferPtr = const_cast (aDescriptor.Ptr()); + iDescriptor.Set( desBufferPtr,aDescriptor.Length(),aDescriptor.Length()); + + iMode = EOpenByDescriptor; + iState = EBuildControllerList; + KickState(); + } + +/** + * Opens a controller using the supplied URL + * and adds the source & sink + * Completion is indicated asynchonously by a call to MfaocComplete() + * + * @param aUrl + * a reference to the URL to be used when searching for a controller + * @param aIapId + * the IAP ID to be used when searching for a controller + * @param aMimeType + * the MIME type of the data to be used when searching for a controller + * + * @internalComponent + */ +EXPORT_C void CMMFFindAndOpenController::OpenByUrl(const TDesC& aUrl, TInt aIapId, const TDesC8& aMimeType) + { + // must have already called ConfigureSourceSink() + __ASSERT_ALWAYS(iSourceSinkConfigured, CUPanic(EMMFMediaClientUtilityBadState)); + + // Have there been any errors so far ? + if (iError != KErrNone) + { + SchedSendError(); + return; + } + + // take a copy of the Url + delete iUrl; + iUrl = NULL; + iUrl = aUrl.Alloc(); + if (iUrl == NULL) + { + SchedSendError(KErrNoMemory); + return; + } + + // take a copy of the IapId + iIapId = aIapId; + + // take a copy of the mime type + delete iMimeType; + iMimeType = NULL; + iMimeType = aMimeType.Alloc(); + if (iMimeType == NULL) + { + SchedSendError(KErrNoMemory); + return; + } + + iMode = EOpenByUrl; + iState = EBuildControllerList; + KickState(); + } + +/** + * Static function to return a TMMFFileConfig object + * suitable for passing to ConfigureSourceSink() + * + * @param aFileName + * the filename to use + * + * @internalComponent + */ +EXPORT_C TMMFFileConfig CMMFFindAndOpenController::GetConfigFile(const TDesC& aFileName) + { + TMMFFileConfig sourceSinkData; + sourceSinkData().iPath = aFileName; + return sourceSinkData; + } + +/** + * Static function to return a TMMFDescriptorConfig object + * suitable for passing to ConfigureSourceSink() + * + * @param aFileName + * the filename to use + * + * @internalComponent + */ +EXPORT_C TMMFDescriptorConfig CMMFFindAndOpenController::GetConfigDescriptor(const TDesC8& aDescriptor) + { + TMMFDescriptorConfig sourceSinkData; + sourceSinkData().iDes = (TAny*)&aDescriptor; + sourceSinkData().iDesThreadId = RThread().Id(); + return sourceSinkData; + } + +/** + * Static function to create a CBufFlat object + * suitable for passing to ConfigureSourceSink() + * + * @param aUrlCfgBuffer + * the reference to a caller-supplied pointer used to create + * a CBufFlat object. The caller is responsible for deletion. + * @param aUrl + * a reference to the URL to be used + * @param aIapId + * the IAP ID to be used + * @return can return KErrNone or KErrNoMemory + * + * @internalComponent + */ + +EXPORT_C void CMMFFindAndOpenController::GetConfigUrlL(CBufFlat*& aUrlCfgBuffer, const TDesC& aUrl, TInt aIapId) + { + delete aUrlCfgBuffer; + aUrlCfgBuffer = NULL; + + CMMFUrlParams* urlCfg = CMMFUrlParams::NewL(aUrl,aIapId); + CleanupStack::PushL(urlCfg); + aUrlCfgBuffer = urlCfg->ExternalizeToCBufFlatLC(); + CleanupStack::Pop(aUrlCfgBuffer); + CleanupStack::PopAndDestroy(urlCfg); + } +/** + * ReOpens the previously opened primary controller + * + * @internalComponent + */ +EXPORT_C void CMMFFindAndOpenController::ReOpen() + { + // should already have a valid controller uid so just open it + iControllerImplInfo = NULL; + iState = EOpenController; + KickState(); + } + +void CMMFFindAndOpenController::OpenPrimaryController(void) + { + iCurrentConfig = iPrimaryConfig; + switch(iMode) + { + case EOpenByFileName: + case EOpenByFormatUid: + case EOpenByDescriptor: + case EOpenByUrl: + iState = EBuildControllerList; + break; + case EOpenByControllerUid: + iControllerImplInfo = NULL; + iState = EOpenController; + break; + } + KickState(); + } + +void CMMFFindAndOpenController::KickState() + { + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + SetActive(); + } + +void CMMFFindAndOpenController::CloseController() + { + if (iCurrentConfig->iEventMonitor) + iCurrentConfig->iEventMonitor->Cancel(); + iCurrentConfig->iController->Close(); + } + +void CMMFFindAndOpenController::Process() + { + switch(iState) + { + case EBuildControllerList: + switch(iMode) + { + case EOpenByFileName: + TRAP(iError, BuildControllerListFileNameL()); + break; + case EOpenByDescriptor: + TRAP(iError, BuildControllerListDescriptorL()); + break; + case EOpenByUrl: + TRAP(iError, BuildControllerListUrlL()); + break; + case EOpenByFormatUid: + TRAP(iError, BuildControllerListFormatL()); + break; + default: + CUPanic(EMMFMediaClientUtilityBadState); + } + + if (iError != KErrNone) + { + iState = EIdle; + SendError(); + break; + } + + // try the first controller + iControllerIndex = -1; + TryNextController(); + break; + + case EOpenController: + { + // Make sure any existing controller is closed. + CloseController(); + + TBool isSecureDrmProcess = EFalse;// need to keep it false as UseSecureDRMProcess may return error + // Loading controller in new threading model is enabled only in playback mode + TUid sourceUid = iCurrentConfig->iSource->SourceSinkUid(); + TBool localPlaybackMode = iCurrentConfig->iControllerMode == EPlayback && + (sourceUid == KUidMmfFileSource || sourceUid == KUidMmfDescriptorSource); + if(localPlaybackMode) + { + TRAPD(err,UseSecureDRMProcessL(isSecureDrmProcess)); + if(err == KErrPermissionDenied) + { + isSecureDrmProcess = ETrue; + } + else if(err != KErrNone) + { + iError = err; + SendError(err); + return; + } + } + // Open the controller + if (iControllerImplInfo) + { + if(isSecureDrmProcess && localPlaybackMode) + { + iError = iCurrentConfig->iController->OpenInSecureDRMProcess(*iControllerImplInfo, iPrioritySettings, iUseSharedHeap); + iUsingSecureDrmProcess = ETrue; + } + else + { + iError = iCurrentConfig->iController->Open(*iControllerImplInfo, iPrioritySettings, iUseSharedHeap); + iUsingSecureDrmProcess = EFalse;; + } + } + else + { + if(isSecureDrmProcess && localPlaybackMode) + { + iError = iCurrentConfig->iController->OpenInSecureDRMProcess(iCurrentConfig->iControllerUid, iPrioritySettings, iUseSharedHeap); + iUsingSecureDrmProcess = ETrue; + + } + else + { + iError = iCurrentConfig->iController->Open(iCurrentConfig->iControllerUid, iPrioritySettings, iUseSharedHeap); + iUsingSecureDrmProcess = EFalse; + } + } + //in case of error, including KErrNomemory try next controller + if (iError) + { + TryNextController(); + } + else + { + #ifdef SYMBIAN_ENABLE_MMF_MULTISCREEN_SUPPORT + #ifndef SYMBIAN_BUILD_GCE + if(iCurrentConfig->iControllerMode == EPlayback && iMediaId == KUidMediaTypeVideo) + { + iError = iVideoSetInitScreenCustomCommands->SetInitScreenNumber(iScreenNumber); + if(iError) + { + if (iError == KErrNotSupported && iScreenNumber == KDefaultScreenNo) + { + iError = KErrNone; + } + else + { + iState = EIdle; + SendError(); + break; + } + } + } + #endif // SYMBIAN_BUILD_GCE + #endif // SYMBIAN_ENABLE_MMF_MULTISCREEN_SUPPORT + iCurrentConfig->iEventMonitor->Start(); + + if (iCurrentConfig == iSecondaryConfig) + { + iState = EAddSource; + KickState(); + } + else + { + iState = EAddSink; + KickState(); + } + } + } + break; + + case EAddSource: + { + iState = EWaitingForSource; + const CMMSourceSink* source = iCurrentConfig->iSource; + // CMMSourceSink has the ability to transform the data it stored into a data stream + // which can be passed to CMMFAddDataSourceSinkAsync for further processing. + // CMMFileSourceSink, which is a specialized CMMSourceSink, stores info about a file + // source/sink. The info about the file can be a file path or a file handle. + // When it holds a file handle and turns info into data stream, the file handle is + // stored as a pointer in the stream. However, at this point, it cannot guarantee that + // the streamed info is always extracted within the same process. If the pointer is + // dereferenced in other process, a panic will raise in the system. Therefore, a file + // handle, rather than pointer, is used when necessary. + if (iUsingSecureDrmProcess && source->CarryingFileHandle()) + { + iAddDataSourceSinkAsync->AddFileHandleDataSource(*iCurrentConfig->iController, + static_cast(source)->FileHandle(), + source->SourceSinkData()); + } + else + { + iAddDataSourceSinkAsync->AddDataSource(*iCurrentConfig->iController, + source->SourceSinkUid(), + source->SourceSinkData()); + } + } + break; + + case EAddSink: + { + iState = EWaitingForSink; + const CMMSourceSink* sink = iCurrentConfig->iSink; + // CMMSourceSink has the ability to transform the data it stored into a data stream + // which can be passed to CMMFAddDataSourceSinkAsync for further processing. + // CMMFileSourceSink, which is a specialized CMMSourceSink, stores info about a file + // source/sink. The info about the file can be a file path or a file handle. + // When it holds a file handle and turns info into data stream, the file handle is + // stored as a pointer in the stream. However, at this point, it cannot guarantee that + // the streamed info is always extracted within the same process. If the pointer is + // dereferenced in other process, a panic will raise in the system. Therefore, a file + // handle, rather than pointer, is used when necessary. + const TDesC8& sinkData = sink->SourceSinkData(); + if (iUsingSecureDrmProcess && sink->CarryingFileHandle()) + { + iAddDataSourceSinkAsync->AddFileHandleDataSink(*iCurrentConfig->iController, + static_cast(sink)->FileHandle(), + sinkData); + } + else + { + iAddDataSourceSinkAsync->AddDataSink(*iCurrentConfig->iController, + sink->SourceSinkUid(), + sinkData); + } + } + break; + + case EWaitingForSource: + break; + + case EWaitingForSink: + break; + + case ESendError: + SendError(); + iState = EIdle; + break; + + case EIdle: + default: + break; + } + } + +void CMMFFindAndOpenController::TryNextController() + { + // If an error occurred close the controller. + if (iError != KErrNone) + { + CloseController(); + } + + iStopTryLoadController = EFalse; + + if (iMode == EOpenByControllerUid || ++iControllerIndex >= iControllerCount) + { + //Raise a flag to stop trying to load the controllers + iStopTryLoadController = ETrue; + + // KErrNotSupported is the default error, but will only be used if no other error + // has been discovered (the first error found is used by default) + // However, KErrBadHandle seems to mean that we tried to use the DRM server without + // RFs::ShareProtected() having been called, so force usage of KErrNotSupported so + // client does not see changed + TBool forceErrorUse = EFalse; + if (iError==KErrBadHandle) + { + forceErrorUse = ETrue; + } + SendError(KErrNotSupported, forceErrorUse); + + return; + } + + if (iMode == EOpenByFileName || iMode == EOpenByFormatUid) + { + iControllerImplInfo = iPrioritisedControllers[iControllerIndex]; + } + else //if (iMode == EOpenByDescriptor || iMode == EOpenByUrl) + { + iControllerImplInfo = iControllers[iControllerIndex]; + } + + iCurrentConfig->iControllerUid = iControllerImplInfo->Uid(); + iState = EOpenController; + KickState(); + } + +void CMMFFindAndOpenController::MadssaoAddDataSourceSinkAsyncComplete(TInt aError, const TMMFMessageDestination& aHandle) + { + iError = aError; + + // take the first available exit if we're out of memory + // or we've been cancelled + if (iError == KErrNoMemory || iError == KErrCancel) + { + SendError(); + return; + } + + // failed to add source or sink - try the next controller + if (aError != KErrNone) + { + TryNextController(); + return; + } + + if (iState == EWaitingForSource) + { + #ifdef SYMBIAN_ENABLE_MMF_MULTISCREEN_SUPPORT + #ifdef SYMBIAN_BUILD_GCE + // If surfaces are required try to use them. If this fails then fall back to using + // direct screen access. + if(iCurrentConfig->iControllerMode == EPlayback && iMediaId == KUidMediaTypeVideo) + { + // UseSurfaces call has to be done after adding data sink and adding data source. + iSurfaceSupported = iVideoPlaySurfaceSupportCustomCommands->UseSurfaces(); + + if (iSurfaceSupported == KErrNotSupported) + { + if (iUseVPU2) + { + if (ControllerIndex() < ControllerCount() - 1) + { + // Until end of the list of controllers, + // try the next one for surface support + TryNextController(); // this will also kick-state + return; + } + else + { + iError = iSurfaceSupported; + } + } + else + { + // No surface enabled controller found + // not required to do only surface, + // use the last one that matched. + iError = iVideoSetInitScreenCustomCommands->SetInitScreenNumber(iScreenNumber); + if (iError == KErrNotSupported && iScreenNumber == KDefaultScreenNo) + { + iError = KErrNone; + } + } + } + else + { + iError = iSurfaceSupported; + } + } + #endif // SYMBIAN_BUILD_GCE + #endif // SYMBIAN_ENABLE_MMF_MULTISCREEN_SUPPORT + + iSourceHandle = aHandle; + if (iCurrentConfig == iSecondaryConfig) + { + iState = EAddSink; + } + else // completed ok ! + { + iState = EIdle; + SendError(KErrNone, ETrue); + return; + } + } + else if (iState == EWaitingForSink) + { + iSinkHandle = aHandle; + if (iCurrentConfig == iSecondaryConfig) // completed ok ! + { + iState = EIdle; + iError = KErrNone; + SendError(); + return; + } + else + { + iState = EAddSource; + } + } + + KickState(); + } + +void CMMFFindAndOpenController::SendError(TInt aError, TBool aOverrideError) + { + if (iError == KErrNone || aOverrideError) + { + iError = aError; + } + + iObserver.MfaocComplete(iError, iCurrentConfig->iController, iCurrentConfig->iControllerUid, &iSourceHandle, &iSinkHandle); + + // if we've just attempted to open the Secondary controller, + // try to open the Primary controller + if (iCurrentConfig == iSecondaryConfig) + { + if (iError == KErrNone) + OpenPrimaryController(); + } + + // if we failed to open, may as well free up some memory + // if open succeeded we need to preserve state in case of a re-open + if (iError != KErrNone) + { + if(iControllerIndex >= iControllerCount-1) + { + Close(); + } + else //if there are other controllers selected in the controller list, try them + { + Cancel(); + if(iAddDataSourceSinkAsync) + { + iAddDataSourceSinkAsync->Cancel(); + } + + TryNextController(); + } + } + } + +void CMMFFindAndOpenController::SchedSendError(TInt aError) + { + if (aError != KErrNone) + iError = aError; + iState = ESendError; + KickState(); + } + +void CMMFFindAndOpenController::BuildControllerListFileNameL() + { + // Retrieve a list of possible controllers from ECOM + // If we don't have a match, leave with unsupported + + iControllers.ResetAndDestroy(); + iPrioritisedControllers.Reset(); + + TControllerMode mode = iCurrentConfig->iControllerMode; + + // if we're playing, try to get the MIME type from the Content Access + // Framework (CAF) & use that to select a controller - if that fails, + // try to select a controller based on the header data/file extension + + CMMFUtilityFileInfo* fileInfo = NULL; + + TInt error; + + //If the current CMMSourceSink is a CMMFileSourceSink + // Using the previous version we'd get KErrCANoPermission when calling EvaluateIntent in the + // CMMFUtilityFileInfo ConstructL as the intent == EUnknown, so now pass the intent as a parameter + // to TMMFileHandleSource and.... + TBool isSecureDrmProcess = EFalse; + //need to do this only in local playback mode + //UseSecureDRMProcess() function in called only in case of local play / record + // so we'll just chk for playback mode + if(mode == EPlayback) + { + TRAP(error, UseSecureDRMProcessL(isSecureDrmProcess)); + if(error == KErrPermissionDenied) + { + isSecureDrmProcess = ETrue; + } + else + { + User::LeaveIfError(error); + } + } + TRAP(error, fileInfo = CreateFileInfoL(isSecureDrmProcess)); + + if (fileInfo != NULL) + { + CleanupDeletePushL(fileInfo); + } + + if (error != KErrNone) + { + // if playback mode, leave for any error + // if record mode, allow KErrNotFound + if (mode == EPlayback || (mode != EPlayback && error != KErrNotFound)) + { + User::Leave(error); + } + } + + CMMFControllerPluginSelectionParameters* cSelect = NULL; + if (isSecureDrmProcess) + { + cSelect = CMMFControllerSecureDrmPluginSelectionParameters::NewLC(); + } + else + { + cSelect = CMMFControllerPluginSelectionParameters::NewLC(); + } + RArray mediaIds; + CleanupClosePushL(mediaIds); + User::LeaveIfError(mediaIds.Append(iMediaId)); + + cSelect->SetMediaIdsL(mediaIds, iMediaIdMatchType); + + if (mode == EPlayback) + { + ASSERT(fileInfo!=NULL); + TBuf8 mimeType; + TBool mimeTypeKnown = fileInfo->GetFileMimeTypeL(mimeType); + if (mimeTypeKnown) + { + CMMFFormatSelectionParameters* fSelect = CMMFFormatSelectionParameters::NewLC(); + fSelect->SetMatchToMimeTypeL(mimeType); + cSelect->SetRequiredPlayFormatSupportL(*fSelect); + cSelect->ListImplementationsL(iControllers); + CleanupStack::PopAndDestroy(fSelect); + } + + + // copy to the iPrioritisedControllers array - this is a NOOP if the + // MIME type is not known since iControllers will be empty + ASSERT(mimeTypeKnown || iControllers.Count() == 0); + for (TInt controllerIndex=0; controllerIndex < iControllers.Count(); controllerIndex++) + User::LeaveIfError(iPrioritisedControllers.Append(iControllers[controllerIndex])); + + iControllerCount = iPrioritisedControllers.Count(); + if (iControllerCount > 0) + { + // Clean up + // cSelect, mediaIds, + CleanupStack::PopAndDestroy(2, cSelect); + if (fileInfo != NULL) + { + CleanupStack::PopAndDestroy(fileInfo); + } + return; + } + } + + // Retrieve header data first. If file doesn't exist, its ok. + HBufC8* headerData = HBufC8::NewLC(KMaxHeaderSize); + TPtr8 headerDataPtr = headerData->Des(); + if (fileInfo) + { + fileInfo->GetFileHeaderDataL(headerDataPtr, KMaxHeaderSize); + } + + // Get the filename's suffix + HBufC8* fileSuffix = CMMFClientUtility::GetFileExtensionL(iFileName); + + CleanupStack::PushL(fileSuffix); + TPtr8 fileSuffixPtr = fileSuffix->Des(); + + // Get the secondary filename's header data (for convert) + HBufC8* headerDataSecondary = HBufC8::NewLC(KMaxHeaderSize); + TPtr8 headerDataPtrSecondary = headerDataSecondary->Des(); + if (iFileNameSecondary.Length() > 0 && fileInfo) + { + fileInfo->GetFileHeaderDataL(headerDataPtrSecondary, KMaxHeaderSize); + } + + // Get the secondary filename's suffix + HBufC8* fileSuffixSecondary = CMMFClientUtility::GetFileExtensionL(iFileNameSecondary); + CleanupStack::PushL(fileSuffixSecondary); + TPtr8 fileSuffixPtrSecondary = fileSuffixSecondary->Des(); + + + CMMFFormatSelectionParameters* fSelect = CMMFFormatSelectionParameters::NewLC(); + + if (mode == EPlayback || mode == EConvert) + cSelect->SetRequiredPlayFormatSupportL(*fSelect); + if (mode == ERecord || mode == EConvert) + cSelect->SetRequiredRecordFormatSupportL(*fSelect); + + cSelect->ListImplementationsL(iControllers); + + if (iControllers.Count()==0) + User::Leave(KErrNotSupported); + + if (mode == ERecord) + { + CMMFClientUtility::PrioritiseControllersL( + iControllers, + headerDataPtrSecondary, + fileSuffixPtrSecondary, + headerDataPtr, + fileSuffixPtr, + iPrioritisedControllers); + } + else + { + CMMFClientUtility::PrioritiseControllersL( + iControllers, + headerDataPtr, + fileSuffixPtr, + headerDataPtrSecondary, + fileSuffixPtrSecondary, + iPrioritisedControllers); + } + + iControllerCount = iPrioritisedControllers.Count(); + if (iControllerCount == 0) + User::Leave(KErrNotSupported); + + // Clean up + // cSelect, mediaIds, + // headerData, fileSuffix, headerDataSecondary, fileSuffixSecondary, + // fSelect + CleanupStack::PopAndDestroy(7, cSelect); + if (fileInfo != NULL) + { + CleanupStack::PopAndDestroy(fileInfo); + } + } + +void CMMFFindAndOpenController::BuildControllerListDescriptorL() + { + // Retrieve a list of possible controllers from ECOM + // If we don't have a match, leave with unsupported + + iControllers.ResetAndDestroy(); + + CMMFControllerPluginSelectionParameters* cSelect = CMMFControllerPluginSelectionParameters::NewLC(); + CMMFFormatSelectionParameters* fSelect = CMMFFormatSelectionParameters::NewLC(); + + + RArray mediaIds; + CleanupClosePushL(mediaIds); + User::LeaveIfError(mediaIds.Append(iMediaId)); + + cSelect->SetMediaIdsL(mediaIds, iMediaIdMatchType); + + TPtrC8 header = iDescriptor.Left(KMaxHeaderSize); + fSelect->SetMatchToHeaderDataL(header); + + + TControllerMode mode = iCurrentConfig->iControllerMode; + if (mode == EPlayback || mode == EConvert) + cSelect->SetRequiredPlayFormatSupportL(*fSelect); + if (mode == ERecord || mode == EConvert) + cSelect->SetRequiredRecordFormatSupportL(*fSelect); + + cSelect->ListImplementationsL(iControllers); + + iControllerCount = iControllers.Count(); + if (iControllerCount == 0) + User::Leave(KErrNotSupported); + + // Clean up + // cSelect, fSelect, mediaIds + CleanupStack::PopAndDestroy(3, cSelect); + } + +void CMMFFindAndOpenController::BuildControllerListUrlL() + { + // Retrieve a list of possible controllers from ECOM + // If we don't have a match, leave with unsupported + + iControllers.ResetAndDestroy(); + + CMMFControllerPluginSelectionParameters* cSelect = CMMFControllerPluginSelectionParameters::NewLC(); + CMMFFormatSelectionParameters* fSelect = CMMFFormatSelectionParameters::NewLC(); + + RArray mediaIds; + CleanupClosePushL(mediaIds); + User::LeaveIfError(mediaIds.Append(iMediaId)); + + cSelect->SetMediaIdsL(mediaIds, iMediaIdMatchType); + + + if (*iMimeType != KNullDesC8) + { + fSelect->SetMatchToMimeTypeL(*iMimeType);//We match to mime type + } + else + { + fSelect->SetMatchToUriSupportL(*iUrl); + } + + TControllerMode mode = iCurrentConfig->iControllerMode; + if (mode == EPlayback || mode == EConvert) + cSelect->SetRequiredPlayFormatSupportL(*fSelect); + if (mode == ERecord || mode == EConvert) + cSelect->SetRequiredRecordFormatSupportL(*fSelect); + + cSelect->ListImplementationsL(iControllers); + + iControllerCount = iControllers.Count(); + if (iControllerCount == 0) + User::Leave(KErrNotSupported); + + // Clean up + // cSelect, fSelect, mediaIds + CleanupStack::PopAndDestroy(3, cSelect); + } + +void CMMFFindAndOpenController::BuildControllerListFormatL() + { + // Retrieve a list of possible controllers from ECOM + // If we don't have a match, leave with unsupported + + iControllers.ResetAndDestroy(); + iPrioritisedControllers.Reset(); + + CMMFControllerPluginSelectionParameters* cSelect = CMMFControllerPluginSelectionParameters::NewLC(); + + // Select the media IDs to allow + RArray mediaIds; + CleanupClosePushL(mediaIds); + User::LeaveIfError(mediaIds.Append(iMediaId)); + + cSelect->SetMediaIdsL(mediaIds, iMediaIdMatchType); + + CMMFFormatSelectionParameters* fSelect = CMMFFormatSelectionParameters::NewLC(); + + TControllerMode mode = iCurrentConfig->iControllerMode; + if (mode == EPlayback || mode == EConvert) + cSelect->SetRequiredPlayFormatSupportL(*fSelect); + if (mode == ERecord || mode == EConvert) + cSelect->SetRequiredRecordFormatSupportL(*fSelect); + + //Obtain a list of the controllers + cSelect->ListImplementationsL(iControllers); + + CleanupStack::PopAndDestroy(3, cSelect); // cSelect, mediaIds, fSelect + + iControllerCount = iControllers.Count(); + if (iControllerCount == 0) + User::Leave(KErrNotSupported); + + TUid formatUidPrimary; + TUid formatUidSecondary; + if (mode == ERecord) + { + formatUidSecondary = iFormatUid; + formatUidPrimary = iFormatUidSecondary; + } + else + { + formatUidPrimary = iFormatUid; + formatUidSecondary = iFormatUidSecondary; + } + + for (TInt controllerIndex=0; controllerIndex < iControllers.Count(); controllerIndex++) + { + const RMMFFormatImplInfoArray& recFormatInfo = iControllers[controllerIndex]->RecordFormats(); + const RMMFFormatImplInfoArray& playFormatInfo = iControllers[controllerIndex]->PlayFormats(); + + TBool playFormatMatched = EFalse; + TBool recordFormatMatched = EFalse; + + if (formatUidPrimary == KNullUid) + { + playFormatMatched = ETrue; + } + else + { + for(TInt playFormatIndex =0; playFormatIndex < playFormatInfo.Count(); playFormatIndex++) + { + if(playFormatInfo[playFormatIndex]->Uid() == formatUidPrimary) + { + playFormatMatched = ETrue; + break; + } + } + } + + if (formatUidSecondary == KNullUid) + { + recordFormatMatched = ETrue; + } + else + { + for (TInt recFormatIndex =0; recFormatIndex < recFormatInfo.Count(); recFormatIndex++) + { + if (recFormatInfo[recFormatIndex]->Uid() == formatUidSecondary) + { + recordFormatMatched = ETrue; + break; + } + } + } + + if (playFormatMatched && recordFormatMatched) + User::LeaveIfError(iPrioritisedControllers.Append(iControllers[controllerIndex])); + } + + iControllerCount = iPrioritisedControllers.Count(); + if (iControllerCount == 0) + User::Leave(KErrNotSupported); + } + +CMMSourceSink* CMMFFindAndOpenController::CreateSourceSinkL(const TSourceSink& aParams) + { + if (aParams.iUseFileHandle) + { + return CMMFileSourceSink::NewL(aParams.iUid, aParams.iFileHandle); + } + return CMMSourceSink::NewL(aParams.iUid, aParams.iConfigData); + } + + +CMMSourceSink* CMMFFindAndOpenController::CreateSourceSinkL(const TMMSource& aSource) + { + if (!(aSource.SourceType()==KUidMMFileSource || + aSource.SourceType()==KUidMMFileHandleSource)) + User::Leave(KErrNotSupported); + + return CMMFileSourceSink::NewL(KUidMmfFileSource, aSource); + } + +CMMFUtilityFileInfo* CMMFFindAndOpenController::CreateFileInfoL(TBool aSecureDRMMode) + { + CMMFUtilityFileInfo* fileInfo = NULL; + if (iUseFileHandle) + { + if (iUniqueId != NULL) + { + TMMFileHandleSource fileHandleSource(iFileHandle, (*iUniqueId), iIntent,iEnableUi); + fileInfo = CMMFUtilityFileInfo::NewL(fileHandleSource, aSecureDRMMode); + } + else + { + TMMFileHandleSource fileHandleSource(iFileHandle); + fileInfo = CMMFUtilityFileInfo::NewL(fileHandleSource, aSecureDRMMode); + } + } + else + { + if (iUniqueId != NULL) + { + TMMFileSource fileSource(iFileName, (*iUniqueId), iIntent,iEnableUi); + fileInfo = CMMFUtilityFileInfo::NewL(fileSource, aSecureDRMMode); + } + else + { + TMMFileSource fileSource(iFileName); + fileInfo = CMMFUtilityFileInfo::NewL(fileSource, aSecureDRMMode); + } + } + return fileInfo; + } + +EXPORT_C CMMFFindAndOpenController::TSourceSink::TSourceSink(TUid aUid, const TDesC8& aConfigData) + : iConfigData(aConfigData) + { + iUid = aUid; + + iUseFileHandle = EFalse; + } + +EXPORT_C CMMFFindAndOpenController::TSourceSink::TSourceSink(TUid aUid, const RFile& aFile) + : iConfigData(KNullDesC8) + { + iUid = aUid; + + iFileHandle = aFile; + iUseFileHandle = ETrue; + } + +EXPORT_C void CMMFFindAndOpenController::SetInitScreenNumber(TInt aScreenNumber, RMMFVideoSetInitScreenCustomCommands* aVideoSetInitScreenCustomCommands) + { + iScreenNumber = aScreenNumber; + iVideoSetInitScreenCustomCommands = aVideoSetInitScreenCustomCommands; + } + +CMMFFindAndOpenController::CConfig::CConfig() + { + } + +void CMMFFindAndOpenController::CConfig::Close() + { + delete iSource; + iSource = NULL; + delete iSink; + iSink = NULL; + } +CMMFFindAndOpenController::CConfig::~CConfig() + { + Close(); + } + +void CMMFFindAndOpenController::UseSecureDRMProcessL(TBool& aIsSecureDrmProcess) + { + if(iHasDrmCapability)//if client has DRM capability, we never use Secure DRM Process + { + aIsSecureDrmProcess = EFalse; + return; + } + TBool isDataProtected = EFalse; + ContentAccess::CContent* content = NULL; + TControllerMode mode = iCurrentConfig->iControllerMode; + + //setting aUseSecureDrmProcess to false(default value) + aIsSecureDrmProcess = EFalse; + + //need to proceed only in case of local playback mode + TUid sourceUid = iCurrentConfig->iSource->SourceSinkUid(); + TBool localPlaybackMode = ( mode == EPlayback && + (sourceUid == KUidMmfFileSource || sourceUid == KUidMmfDescriptorSource) ); + if(!localPlaybackMode) + { + return; + } + + if (iUseFileHandle && iOwnFileHandle) + { + content = ContentAccess::CContent::NewLC(iFileHandle); + } + else if(iFileName.Length()) //need to check if file name exist + { + content = ContentAccess::CContent::NewLC(iFileName); + } + else + {//in case of descriptor source content object will not be created + return; + } + TInt value = 0; + TInt error = KErrNone; + if(iUniqueId != NULL) + { + error = content->GetAttribute(EIsProtected, value, *iUniqueId ); + } + else + { + error = content->GetAttribute(EIsProtected, value); + } + if( (error == KErrNone && value) || error == KErrPermissionDenied ) + {//2nd condition can be true if GetAttribute checks for DRM cap and return error if not found + isDataProtected = ETrue; + } + else if( error != KErrNone && error != KErrPermissionDenied) + {//leaving as GetAttribute of CAF caused an error. + User::Leave(error); + } + + CleanupStack::PopAndDestroy(content); + if(isDataProtected && !iHasDrmCapability && mode == EPlayback) + {//only when the Data is protected and client does not have the DRM capability, we need secure DRM process + aIsSecureDrmProcess = ETrue; + } + } + +EXPORT_C CMMSourceSink* CMMSourceSink::NewLC(TUid aUid, const TDesC8& aDescriptor) + { + CMMSourceSink* self = new (ELeave) CMMSourceSink(aUid); + CleanupStack::PushL(self); + self->ConstructL(aDescriptor); + return self; + } + +EXPORT_C CMMSourceSink* CMMSourceSink::NewL(TUid aUid, const TDesC8& aDescriptor) + { + CMMSourceSink* sourcesink = CMMSourceSink::NewLC(aUid, aDescriptor); + CleanupStack::Pop(sourcesink); + return sourcesink; + } + +CMMSourceSink::CMMSourceSink(TUid aUid) + : iUid(aUid) + { + } + +CMMSourceSink::~CMMSourceSink() + { + delete iBuf; + } + +void CMMSourceSink::ConstructL(const TDesC8& aDescriptor) + { + iBuf = aDescriptor.AllocL(); + } + +TUid CMMSourceSink::SourceSinkUid() const + { + return iUid; + } + +const TDesC8& CMMSourceSink::SourceSinkData() const + { + return *iBuf; + } + +TBool CMMSourceSink::CarryingFileHandle() const + { + return EFalse; + } + +EXPORT_C CMMFileSourceSink* CMMFileSourceSink::NewLC(TUid aUid, const RFile& aFile) + { + CMMFileSourceSink* self = new (ELeave) CMMFileSourceSink(aUid); + CleanupStack::PushL(self); + self->ConstructL(aFile); + return self; + } + +EXPORT_C CMMFileSourceSink* CMMFileSourceSink::NewL(TUid aUid, const RFile& aFile) + { + CMMFileSourceSink* sourcesink = CMMFileSourceSink::NewLC(aUid, aFile); + CleanupStack::Pop(sourcesink); + return sourcesink; + } + +CMMFileSourceSink::CMMFileSourceSink(TUid aUid) + : CMMSourceSink(aUid) + { + } + +void CMMFileSourceSink::ConstructL(const RFile& aFile) + { + User::LeaveIfError(iHandle.Duplicate(aFile)); + iUsingFileHandle = ETrue; + iFileName = HBufC::NewMaxL(KMaxFileName); + TPtr fileNamePtr = iFileName->Des(); + iHandle.Name(fileNamePtr); + DoCreateFileHandleSourceConfigDataL(); + } + +void CMMFileSourceSink::DoCreateFileHandleSourceConfigDataL() + { + CBufFlat* buf = CBufFlat::NewL(KExpandSize); + CleanupStack::PushL(buf); + RBufWriteStream stream; + stream.Open(*buf); + CleanupClosePushL(stream); + + TPckgBuf fileptr(&iHandle); + stream.WriteInt32L(KMMFileHandleSourceUid.iUid); + stream.WriteL(fileptr); + + TInt length = 0; + if (iUniqueId != NULL) + length = iUniqueId->Length(); + stream.WriteInt32L(length); + if (length>0) + stream.WriteL(*iUniqueId); + + stream.WriteInt32L(iEnableUI); + + stream.CommitL(); + CleanupStack::PopAndDestroy(&stream); + iSourceSinkData = buf->Ptr(0).AllocL(); + + CleanupStack::PopAndDestroy(buf); + } + +const TDesC8& CMMFileSourceSink::SourceSinkData() const + { + ASSERT(iSourceSinkData); + return *iSourceSinkData; + } + +CMMFileSourceSink::~CMMFileSourceSink() + { + iHandle.Close(); // delete whatever + delete iFileName; + delete iSourceSinkData; + delete iUniqueId; + } + +EXPORT_C CMMFileSourceSink* CMMFileSourceSink::NewLC(TUid aUid, const TMMSource& aSource) + { + CMMFileSourceSink* self = new (ELeave) CMMFileSourceSink(aUid); + CleanupStack::PushL(self); + self->ConstructL(aSource); + return self; + } + +EXPORT_C CMMFileSourceSink* CMMFileSourceSink::NewL(TUid aUid, const TMMSource& aSource) + { + CMMFileSourceSink* sourcesink = CMMFileSourceSink::NewLC(aUid, aSource); + CleanupStack::Pop(sourcesink); + return sourcesink; + } + +void CMMFileSourceSink::ConstructL(const TMMSource& aSource) + { + iUniqueId = aSource.UniqueId().AllocL(); + iIntent = aSource.Intent(); + iEnableUI = aSource.IsUIEnabled(); + + if (aSource.SourceType() == KUidMMFileSource) + { + const TMMFileSource& fileSource = static_cast(aSource); + iFileName = fileSource.Name().AllocL(); + + DoCreateFileSourceConfigDataL(); + } + else if (aSource.SourceType() == KUidMMFileHandleSource) + { + const TMMFileHandleSource& fileHandleSource = static_cast(aSource); + iHandle.Close(); // in case already open + User::LeaveIfError(iHandle.Duplicate(fileHandleSource.Handle())); + iUsingFileHandle = ETrue; + iFileName = HBufC::NewMaxL(KMaxFileName); + TPtr fileNamePtr = iFileName->Des(); + iHandle.Name(fileNamePtr); + + DoCreateFileHandleSourceConfigDataL(); + } + else + { + User::Leave(KErrNotSupported); + } + } + +void CMMSourceSink::EvaluateIntentL() + { + } + +void CMMFileSourceSink::EvaluateIntentL() + { + if (iUsingFileHandle) + { + ContentAccess::CContent* Content = ContentAccess::CContent::NewLC(iHandle); + Content->OpenContentLC(iIntent, *iUniqueId); + CleanupStack::PopAndDestroy(2, Content); + } + else + { + ContentAccess::CContent* Content = ContentAccess::CContent::NewLC(*iFileName); + Content->OpenContentLC(iIntent, *iUniqueId); + CleanupStack::PopAndDestroy(2, Content); + } + } + + + +EXPORT_C void CMMFileSourceSink::EvaluateIntentL(ContentAccess::TIntent aIntent) + { + if (iUsingFileHandle) + { + ContentAccess::CContent* Content = ContentAccess::CContent::NewLC(iHandle); + Content->OpenContentLC(aIntent, *iUniqueId); + CleanupStack::PopAndDestroy(2, Content); + } + else + { + ContentAccess::CContent* Content = ContentAccess::CContent::NewLC(*iFileName); + Content->OpenContentLC(aIntent, *iUniqueId); + CleanupStack::PopAndDestroy(2, Content); + } + } + +void CMMFileSourceSink::DoCreateFileSourceConfigDataL() + { + CBufFlat* buf = CBufFlat::NewL(KExpandSize); + CleanupStack::PushL(buf); + RBufWriteStream stream; + stream.Open(*buf); + CleanupClosePushL(stream); + + stream.WriteInt32L(KMMFileSourceUid.iUid); + stream.WriteInt32L(iFileName->Length()); + stream.WriteL(*iFileName); + TInt length = 0; + if (iUniqueId != NULL) + length = iUniqueId->Length(); + stream.WriteInt32L(length); + if (length>0) + stream.WriteL(*iUniqueId); + + stream.WriteInt32L(iEnableUI); + + stream.CommitL(); + CleanupStack::PopAndDestroy(&stream); + iSourceSinkData = buf->Ptr(0).AllocL(); + + CleanupStack::PopAndDestroy(buf); + } + +TBool CMMFileSourceSink::CarryingFileHandle() const + { + return iUsingFileHandle; + } + +