--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmlibs/mmfw/src/ControllerFramework/mmfcontrollerserver.cpp Thu Oct 07 22:34:12 2010 +0100
@@ -0,0 +1,790 @@
+// 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:
+//
+
+#include <mmf/common/mmfcontroller.h>
+#include <mmf/server/mmffile.h>
+#include <mmf/common/mmfdrmcustomcommands.h>
+#include <mmf/common/mmfstandardcustomcommands.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <mmf/common/mmfcontrollerextendeddata.h>
+#include <mmf/common/mmfcustomcommandparsermanager.h>
+#endif
+
+inline void ExtendedDataTlsCleanup(TAny* /*aPtr*/)
+ {
+ delete static_cast<CMMFControllerExtendedData*>(Dll::Tls());
+ Dll::SetTls(NULL);
+ }
+
+CMMFController* CMMFController::NewL(TUid aControllerUid, MAsyncEventHandler& aEventHandler, TThreadId aClientTid)
+ {
+ Dll::SetTls(CMMFController::CreateExtendedDataL(aClientTid));
+ CleanupStack::PushL(TCleanupItem(&ExtendedDataTlsCleanup, NULL));
+ CMMFController* s = REINTERPRET_CAST(CMMFController*,REComSession::CreateImplementationL(aControllerUid,_FOFF(CMMFController,iDtor_ID_Key)));
+ CleanupStack::PushL(s);
+ s->ConstructL(aEventHandler, aClientTid);
+ CleanupStack::Pop(s);
+ CleanupStack::PopAndDestroy(); // TCleanupItem(ExtendedDataTlsCleanup)
+ return s;
+ }
+
+void CMMFController::ConstructL(MAsyncEventHandler& aEventHandler, TThreadId aClientTid)
+ {
+ iAsyncEventHandler = &aEventHandler;
+
+ // If extended data hasn't been initialized, GetExtendedDataL will initialize it and
+ // add it into iMMFObjectContainer
+#ifdef _DEBUG
+ CMMFControllerExtendedData* extendData =
+#endif
+ GetExtendedDataL();
+#ifdef _DEBUG
+ ASSERT(extendData->ClientThreadId() == aClientTid);
+#else
+ (void)aClientTid; // remove compilation error
+#endif
+ }
+
+EXPORT_C CMMFController::~CMMFController()
+ {
+ delete iCustomCommandParserManager;
+ delete iMMFObjectContainer;
+ delete iMetaDataBuffer;
+ REComSession::DestroyedImplementation(iDtor_ID_Key);
+ }
+
+EXPORT_C TInt CMMFController::DoSendEventToClient(const TMMFEvent& aEvent)
+ {
+ return iAsyncEventHandler->SendEventToClient(aEvent);
+ }
+
+EXPORT_C CMMFObjectContainer& CMMFController::MMFObjectContainerL()
+ {
+ // Construct iMMFObjectContainer if we haven't already.
+ if (!iMMFObjectContainer)
+ iMMFObjectContainer = new(ELeave) CMMFObjectContainer;
+ return *iMMFObjectContainer;
+ }
+
+EXPORT_C void CMMFController::AddCustomCommandParserL(CMMFCustomCommandParserBase& aParser)
+ {
+ // Construct iCustomCommandParserManager if we haven't already
+ if (!iCustomCommandParserManager)
+ iCustomCommandParserManager = CMMFCustomCommandParserManager::NewL();
+ iCustomCommandParserManager->AddCustomCommandParserL(aParser);
+ }
+
+
+EXPORT_C void CMMFController::HandleRequestL(TMMFMessage& aMessage)
+ {
+ // If the message has the constant controller destination handle, pass the message to
+ // the controller plugin to handle.
+ // Otherwise, the message must be for one of the MMFObjects.
+ if (aMessage.Destination().DestinationHandle() == KMMFObjectHandleController)
+ {
+ // If the message has an interface ID for this controller, handle it here.
+ // Otherwise, pass it to the controller plugin to handle as a custom command.
+ if (aMessage.Destination().InterfaceId() == KUidInterfaceMMFController)
+ {
+ TBool complete = ETrue;
+ switch (aMessage.Function())
+ {
+ case EMMFControllerAddDataSource:
+ complete = DoAddDataSourceL(aMessage);
+ break;
+ case EMMFControllerAddDataSink:
+ complete = DoAddDataSinkL(aMessage);
+ break;
+ case EMMFControllerRemoveDataSource:
+ complete = DoRemoveDataSourceL(aMessage);
+ break;
+ case EMMFControllerRemoveDataSink:
+ complete = DoRemoveDataSinkL(aMessage);
+ break;
+ case EMMFControllerReset:
+ complete = DoResetL(aMessage);
+ break;
+ case EMMFControllerPrime:
+ complete = DoPrimeL(aMessage);
+ break;
+ case EMMFControllerPlay:
+ complete = DoPlayL(aMessage);
+ break;
+ case EMMFControllerPause:
+ complete = DoPauseL(aMessage);
+ break;
+ case EMMFControllerStop:
+ complete = DoStopL(aMessage);
+ break;
+ case EMMFControllerGetPosition:
+ complete = DoGetPositionL(aMessage);
+ break;
+ case EMMFControllerSetPosition:
+ complete = DoSetPositionL(aMessage);
+ break;
+ case EMMFControllerGetDuration:
+ complete = DoGetDurationL(aMessage);
+ break;
+ case EMMFControllerGetNumberOfMetaDataEntries:
+ complete = DoGetNumberOfMetaDataEntriesL(aMessage);
+ break;
+ case EMMFControllerGetSizeOfMetaDataEntry:
+ complete = DoGetSizeOfMetaDataEntryL(aMessage);
+ break;
+ case EMMFControllerGetMetaDataEntry:
+ complete = DoGetMetaDataEntryL(aMessage);
+ break;
+ case EMMFControllerSetPrioritySettings:
+ complete = DoSetPrioritySettingsL(aMessage);
+ break;
+ case EMMFControllerCancelAddDataSource:
+ complete = ETrue;//Nothing to cancel since AddDataSource is synchronous server-side
+ break;
+ case EMMFControllerCancelAddDataSink:
+ complete = ETrue;//Nothing to cancel since AddDataSink is synchronous server-side
+ break;
+ case EMMFControllerAddFileHandleDataSource:
+ complete = DoAddFileHandleDataSourceL(aMessage);
+ break;
+ case EMMFControllerAddFileHandleDataSink:
+ complete = DoAddFileHandleDataSinkL(aMessage);
+ break;
+ case EMMFControllerSourceSinkInitDataPreload:
+ complete = DoPreloadSourceSinkInitDataL(aMessage);
+ break;
+ case EMMFControllerAddFileHandleDataSourceWithInitData:
+ complete = DoAddFileHandleDataSourceWithInitDataL(aMessage);
+ break;
+ case EMMFControllerAddFileHandleDataSinkWithInitData:
+ complete = DoAddFileHandleDataSinkWithInitDataL(aMessage);
+ break;
+ default:
+ User::Leave(KErrNotSupported);
+ break;
+ }
+ if (complete)
+ aMessage.Complete(KErrNone);
+ }
+ else
+ {
+ // Must be a custom command
+ DoCustomCommand(aMessage);
+ }
+ }
+ else
+ {
+ // Message for one of the MMF Objects
+ CMMFObject* object = NULL;
+ User::LeaveIfError(MMFObjectContainerL().FindMMFObject(aMessage.Destination(), object));
+ object->HandleRequest(aMessage);
+ }
+
+ }
+
+TBool CMMFController::DoAddDataSourceL(TMMFMessage& aMessage)
+ {
+ // Get the UID of the source from the client
+ TMMFUidPckg uidPckg;
+ aMessage.ReadData1FromClientL(uidPckg);
+
+ // Get the size of the init data and create a buffer to hold it
+ TInt desLength = aMessage.SizeOfData2FromClient();
+ // Leaving here in order to prevent a panic in the NewLC if the value is negative
+ User::LeaveIfError(desLength);
+ HBufC8* buf = HBufC8::NewLC(desLength);
+ TPtr8 ptr = buf->Des();
+ aMessage.ReadData2FromClientL(ptr);
+
+ // Create the source
+ MDataSource* source = MDataSource::NewSourceL(uidPckg(), *buf);
+ CleanupStack::PopAndDestroy(buf);//buf
+ AddMDataSourceAndRepondClientL(source, aMessage);
+
+ return ETrue;
+ }
+
+
+TBool CMMFController::DoAddDataSinkL(TMMFMessage& aMessage)
+ {
+ // Get the UID of the sink from the client
+ TMMFUidPckg uidPckg;
+ aMessage.ReadData1FromClientL(uidPckg);
+
+ // Get the size of the init data and create a buffer to hold it
+ TInt desLength = aMessage.SizeOfData2FromClient();
+ // Leaving here in order to prevent a panic in the NewLC if the value is negative
+ User::LeaveIfError(desLength);
+ HBufC8* buf = HBufC8::NewLC(desLength);
+ TPtr8 ptr = buf->Des();
+ aMessage.ReadData2FromClientL(ptr);
+
+ // Create the sink
+ MDataSink* sink = MDataSink::NewSinkL(uidPckg(), *buf);
+ CleanupStack::PopAndDestroy(buf);//buf
+ AddMDataSinkAndRepondClientL(sink, aMessage);
+
+ return ETrue;
+ }
+
+TBool CMMFController::DoRemoveDataSourceL(TMMFMessage& aMessage)
+ {
+ TMMFMessageDestinationPckg handleInfo;
+ aMessage.ReadData1FromClientL(handleInfo);
+
+ // Find the correct source
+ CMMFObject* object = NULL;
+ CMMFDataSourceHolder* holder = NULL;
+ User::LeaveIfError(MMFObjectContainerL().FindMMFObject(handleInfo(), object));
+ // Cast the object found if possible..
+ if (object->Handle().InterfaceId() == KUidInterfaceMMFDataSourceHolder)
+ holder = STATIC_CAST(CMMFDataSourceHolder*, object);
+ else
+ User::Leave(KErrBadHandle);
+
+ // Try to remove the data source from the plugin
+ RemoveDataSourceL(holder->DataSource());
+
+ // If we're here, the removal worked so remove the source from the object array and delete it
+ MMFObjectContainerL().RemoveAndDestroyMMFObject(*holder);
+ return ETrue;
+ }
+
+TBool CMMFController::DoRemoveDataSinkL(TMMFMessage& aMessage)
+ {
+ TMMFMessageDestinationPckg handleInfo;
+ aMessage.ReadData1FromClientL(handleInfo);
+
+ // Find the correct source
+ CMMFObject* object = NULL;
+ CMMFDataSinkHolder* holder = NULL;
+ User::LeaveIfError(MMFObjectContainerL().FindMMFObject(handleInfo(), object));
+ // Cast the object found if possible..
+ if (object->Handle().InterfaceId() == KUidInterfaceMMFDataSinkHolder)
+ holder = STATIC_CAST(CMMFDataSinkHolder*, object);
+ else
+ User::Leave(KErrBadHandle);
+
+ // Try to remove the data sink from the plugin
+ RemoveDataSinkL(holder->DataSink());
+
+ // If we're here, the removal worked so remove the source from the object array and delete it
+ MMFObjectContainerL().RemoveAndDestroyMMFObject(*holder);
+ return ETrue;
+ }
+
+TBool CMMFController::DoResetL(TMMFMessage& /*aMessage*/)
+ {
+ ResetL();
+ // Controller extended data must be kept until the death of controller
+ const RPointerArray<CMMFObject>& objects = iMMFObjectContainer->MMFObjects();
+ for (TInt i = objects.Count()-1; i >= 0; i--)
+ {
+ CMMFObject* object = objects[i];
+ if (object->Handle().InterfaceId() != KUidMMFControllerExtendedDataHolder)
+ {
+ iMMFObjectContainer->RemoveAndDestroyMMFObject(*object);
+ }
+ }
+ return ETrue;
+ }
+
+TBool CMMFController::DoPrimeL(TMMFMessage& aMessage)
+ {
+ PrimeL(aMessage);
+ return EFalse;
+ }
+
+
+EXPORT_C void CMMFController::PrimeL(TMMFMessage& aMessage)
+ {
+ PrimeL();
+ aMessage.Complete(KErrNone);
+ }
+
+
+TBool CMMFController::DoPlayL(TMMFMessage& aMessage)
+ {
+ PlayL(aMessage);
+ return EFalse;
+ }
+
+EXPORT_C void CMMFController::PlayL(TMMFMessage& aMessage)
+ {
+ PlayL();
+ aMessage.Complete(KErrNone);
+ }
+
+
+
+TBool CMMFController::DoPauseL(TMMFMessage& aMessage)
+ {
+ PauseL(aMessage);
+ return EFalse;
+ }
+
+EXPORT_C void CMMFController::PauseL(TMMFMessage& aMessage)
+ {
+ PauseL();
+ aMessage.Complete(KErrNone);
+ }
+
+
+TBool CMMFController::DoStopL(TMMFMessage& aMessage)
+ {
+ StopL(aMessage);
+ return EFalse;
+ }
+
+EXPORT_C void CMMFController::StopL(TMMFMessage& aMessage)
+ {
+ StopL();
+ aMessage.Complete(KErrNone);
+ }
+
+
+
+TBool CMMFController::DoGetPositionL(TMMFMessage& aMessage)
+ {
+ TMMFTimeIntervalMicroSecondsPckg pckg(PositionL());
+ aMessage.WriteDataToClientL(pckg);
+ return ETrue;
+ }
+
+TBool CMMFController::DoSetPositionL(TMMFMessage& aMessage)
+ {
+ TMMFTimeIntervalMicroSecondsPckg pckg;
+ aMessage.ReadData1FromClientL(pckg);
+ SetPositionL(pckg());
+ return ETrue;
+ }
+
+TBool CMMFController::DoGetDurationL(TMMFMessage& aMessage)
+ {
+ TMMFTimeIntervalMicroSecondsPckg pckg(DurationL());
+ aMessage.WriteDataToClientL(pckg);
+ return ETrue;
+ }
+
+TBool CMMFController::DoSetPrioritySettingsL(TMMFMessage& aMessage)
+ {
+ TMMFPrioritySettingsPckg pckg;
+ aMessage.ReadData1FromClientL(pckg);
+ SetPrioritySettings(pckg());
+ return ETrue;
+ }
+
+void CMMFController::DoCustomCommand(TMMFMessage& aMessage)
+ {
+ // First, try giving the message to the custom command parser manager...
+ TBool handled = EFalse;
+ if (iCustomCommandParserManager)
+ {
+ if (aMessage.Destination().InterfaceId() == KUidInterfaceMMFDRMControl ||
+ aMessage.Destination().InterfaceId() == KUidInterfaceMMFVideoDRMExt)
+ {
+ TBool secureDrmMode = EFalse;
+ TRAPD(err, secureDrmMode = GetExtendedDataL()->SecureDrmMode());
+ if (err)
+ {
+ aMessage.Complete(err);
+ handled = ETrue;
+ }
+ else if (secureDrmMode)
+ {
+ aMessage.Complete(KErrPermissionDenied);
+ handled = ETrue;
+ }
+ }
+
+ if (!handled)
+ {
+ handled = iCustomCommandParserManager->HandleRequest(aMessage);
+ }
+ }
+
+ // If the ccp manager couldn't handle the message, pass directly to the
+ // controller plugin as a custom command.
+ if (!handled)
+ CustomCommand(aMessage);
+ }
+
+TBool CMMFController::DoGetNumberOfMetaDataEntriesL(TMMFMessage& aMessage)
+ {
+ TInt numberOfEntries;
+ GetNumberOfMetaDataEntriesL(numberOfEntries);
+ TPckgBuf<TInt> pckg(numberOfEntries);
+ aMessage.WriteDataToClientL(pckg);
+ return ETrue;
+ }
+
+TBool CMMFController::DoGetSizeOfMetaDataEntryL(TMMFMessage& aMessage)
+ {
+ // Get the index of the required entry
+ TPckgBuf<TInt> pckg;
+ aMessage.ReadData1FromClientL(pckg);
+ // Get the entry
+ CMMFMetaDataEntry* entry = GetMetaDataEntryL(pckg());
+ CleanupStack::PushL(entry);
+ // Delete any existing buffer
+ delete iMetaDataBuffer;
+ iMetaDataBuffer = NULL;
+ // Create a buffer to hold the externalised entry
+ iMetaDataBuffer = CBufFlat::NewL(32);
+ RBufWriteStream s;
+ s.Open(*iMetaDataBuffer);
+ CleanupClosePushL(s);
+ entry->ExternalizeL(s);
+ CleanupStack::PopAndDestroy(2);//s, entry
+ // Write the size of the externalised data back to the client
+ pckg() = iMetaDataBuffer->Ptr(0).Length();
+ aMessage.WriteDataToClientL(pckg);
+ return ETrue;
+ }
+
+TBool CMMFController::DoGetMetaDataEntryL(TMMFMessage& aMessage)
+ {
+ // We should have already prepared the buffer
+ if (!iMetaDataBuffer)
+ User::Leave(KErrNotReady);
+ aMessage.WriteDataToClientL(iMetaDataBuffer->Ptr(0));
+ return ETrue;
+ }
+
+TBool CMMFController::DoPreloadSourceSinkInitDataL(TMMFMessage& aMessage)
+ {
+ GetExtendedDataL()->ResetSourceSinkInitData();
+
+ // Get the size of the init data and create a buffer to hold it
+ TInt desLength = aMessage.SizeOfData1FromClient();
+ HBufC8* sourceSinkInitData = HBufC8::NewLC(desLength);
+ TPtr8 ptr = sourceSinkInitData->Des();
+ aMessage.ReadData1FromClientL(ptr);
+
+ GetExtendedDataL()->SetSourceSinkInitData(sourceSinkInitData);
+ CleanupStack::Pop(sourceSinkInitData);
+ return ETrue;
+ }
+
+TBool CMMFController::DoAddFileHandleDataSourceWithInitDataL(TMMFMessage& aMessage)
+ {
+ if (GetExtendedDataL()->SourceSinkInitData() == NULL)
+ {
+ User::Leave(KErrNotReady);
+ }
+ HBufC8* initData = GetExtendedDataL()->SourceSinkInitData()->AllocLC();
+
+ // Get the client file handle and replace
+ RFile file;
+ aMessage.AdoptFileHandleFromClientL(1,2, file);
+ CleanupClosePushL(file);
+ TPtr8 initDataPtr(initData->Des());
+ ReplaceFileHandleInInitDataL(&file, initDataPtr);
+
+ // Create the source
+ MDataSource* source = MDataSource::NewSourceL(KUidMmfFileSource, *initData);
+ CleanupStack::PopAndDestroy(2, initData); //file, initData
+ AddMDataSourceAndRepondClientL(source, aMessage);
+
+ GetExtendedDataL()->ResetSourceSinkInitData();
+ return ETrue;
+ }
+
+TBool CMMFController::DoAddFileHandleDataSinkWithInitDataL(TMMFMessage& aMessage)
+ {
+ if (GetExtendedDataL()->SourceSinkInitData() == NULL)
+ {
+ User::Leave(KErrNotReady);
+ }
+ HBufC8* initData = GetExtendedDataL()->SourceSinkInitData()->AllocLC();
+
+ // Get the client file handle and replace
+ RFile file;
+ aMessage.AdoptFileHandleFromClientL(1,2, file);
+ CleanupClosePushL(file);
+ TPtr8 initDataPtr(initData->Des());
+ ReplaceFileHandleInInitDataL(&file, initDataPtr);
+
+ // Create the sink
+ MDataSink* sink = MDataSink::NewSinkL(KUidMmfFileSink, *initData);
+ CleanupStack::PopAndDestroy(2, initData); //file, initData
+ AddMDataSinkAndRepondClientL(sink, aMessage);
+
+ GetExtendedDataL()->ResetSourceSinkInitData();
+ return ETrue;
+ }
+
+void CMMFController::ReplaceFileHandleInInitDataL(RFile* aFile, TDes8& aInitData)
+ {
+ // aInitData should have the second 4bytes data (first 4bytes represent TUid) containing
+ // a client RFile pointer.
+ // This RFile pointer may be invalid due to the fact that client and server threads
+ // may reside in different processes, and therefore, different memory space.
+ // In this context, we would rather trust the file handle retrieve from the call
+ // AdoptFileHandleFromClientL, and replace the RFile pointer with a more reliable one
+ TPtr8 filePtrStart = aInitData.MidTPtr(sizeof(TUid));
+ RDesWriteStream writeStream;
+ writeStream.Open(filePtrStart);
+ CleanupClosePushL(writeStream);
+ TPckgBuf<RFile*> filePtr(aFile);
+ writeStream.WriteL(filePtr);
+ writeStream.CommitL();
+ CleanupStack::PopAndDestroy(&writeStream);
+ }
+
+void CMMFController::AddMDataSourceAndRepondClientL(MDataSource* aSource, TMMFMessage& aMessage)
+ {
+ CleanupDeletePushL(aSource);
+ CMMFDataSourceHolder* holder = new(ELeave) CMMFDataSourceHolder(*aSource);
+ CleanupStack::Pop(aSource); //aSource (since now owned by holder)
+
+ CleanupStack::PushL(holder);
+ // Append holder to array of MMFObjects
+ User::LeaveIfError(MMFObjectContainerL().AddMMFObject(*holder));
+ CleanupStack::Pop(holder);//holder
+
+ // Write source handle info back to client
+ TMMFMessageDestination handleInfo(holder->Handle());
+ TMMFMessageDestinationPckg handlePckg(handleInfo);
+ TInt error = aMessage.WriteDataToClient(handlePckg);
+
+ // Add source to plugin
+ if (!error)
+ TRAP(error, AddDataSourceL(*aSource));
+
+ if (error)
+ {
+ // Source not accepted by plugin or we couldn't write handle info back to client,
+ // so delete it and return error to client
+ MMFObjectContainerL().RemoveAndDestroyMMFObject(*holder);
+ User::Leave(error);
+ }
+ }
+
+void CMMFController::AddMDataSinkAndRepondClientL(MDataSink* aSink, TMMFMessage& aMessage)
+ {
+ CleanupDeletePushL(aSink);
+ CMMFDataSinkHolder* holder = new(ELeave) CMMFDataSinkHolder(*aSink);
+ CleanupStack::Pop(aSink); //aSink (since now owned by holder)
+
+ CleanupStack::PushL(holder);
+ // Append sink to array
+ User::LeaveIfError(MMFObjectContainerL().AddMMFObject(*holder));
+ CleanupStack::Pop(holder);//holder
+
+ // Write sink handle info back to client
+ TMMFMessageDestination handleInfo(holder->Handle());
+ TMMFMessageDestinationPckg handlePckg(handleInfo);
+ TInt error = aMessage.WriteDataToClient(handlePckg);
+
+ // Add sink to plugin
+ if (!error)
+ TRAP(error, AddDataSinkL(*aSink));
+
+ if (error)
+ {
+ // Sink not accepted by plugin or we couldn't write handle info back to client,
+ // so delete it and return error to client
+ MMFObjectContainerL().RemoveAndDestroyMMFObject(*holder);
+ User::Leave(error);
+ }
+ }
+
+CMMFControllerExtendedData* CMMFController::GetExtendedDataL()
+ {
+ CMMFControllerExtendedData* data = NULL;
+
+ // iMMFObjectContainer and CMMFControllerExtendedData must be constructed
+ // in CMMFController constructor. Only 1 CMMFControllerExtendedData object can
+ // be found in iMMFObjectContainer.
+ const RPointerArray<CMMFObject>& objects = MMFObjectContainerL().MMFObjects();
+ for (TInt i = 0; i < objects.Count(); i++)
+ {
+ if (objects[i]->Handle().InterfaceId() == KUidMMFControllerExtendedDataHolder)
+ {
+ data = static_cast<CMMFControllerExtendedData*>(objects[i]);
+ break;
+ }
+ }
+ if (data == NULL)
+ {
+ // In this case, extended data has not been constructed and added into iMMFObjectContainer.
+ // This is a situation where GetExtendedDataL is being indirectly called in the controller
+ // initialization process (i.e. CMMFController::NewL() or constructor of licensee's controller).
+ // Extended data should have a copy stored in Dll::Tls already at this point.
+ const CMMFControllerExtendedData* dataCopy = static_cast<CMMFControllerExtendedData*>(Dll::Tls());
+ data = CreateExtendedDataL(dataCopy->ClientThreadId());
+ CleanupStack::PushL(data);
+ User::LeaveIfError(MMFObjectContainerL().AddMMFObject(*data));
+ CleanupStack::Pop(data);
+ }
+ return data;
+ }
+
+CMMFControllerExtendedData* CMMFController::CreateExtendedDataL(TThreadId aClientTid)
+ {
+ // In secureDRMMode, SecureDRM server and user are running in
+ // different processes.
+ TProcessId clientProcessId;
+ RThread clientThread;
+ CleanupClosePushL(clientThread);
+ User::LeaveIfError(clientThread.Open(aClientTid));
+
+ RProcess clientProcess;
+ CleanupClosePushL(clientProcess);
+ User::LeaveIfError(clientThread.Process(clientProcess));
+ clientProcessId = clientProcess.Id();
+ CleanupStack::PopAndDestroy(2, &clientThread); // clientProcess, clientThread
+
+ RProcess thisProcess;
+ TBool secureDrmMode = clientProcessId != thisProcess.Id();
+ thisProcess.Close();
+
+ CMMFControllerExtendedData* dataSet = new(ELeave) CMMFControllerExtendedData();
+ CleanupStack::PushL(dataSet);
+ dataSet->SetClientThreadId(aClientTid);
+ dataSet->SetSecureDrmMode(secureDrmMode);
+ CleanupStack::Pop(dataSet);
+
+ return dataSet;
+ }
+
+
+EXPORT_C CMMFCustomCommandParserManager* CMMFCustomCommandParserManager::NewL()
+ {
+ return new(ELeave) CMMFCustomCommandParserManager;
+ }
+
+CMMFCustomCommandParserManager::CMMFCustomCommandParserManager()
+ {
+ }
+
+EXPORT_C CMMFCustomCommandParserManager::~CMMFCustomCommandParserManager()
+ {
+ iParsers.ResetAndDestroy();
+ iParsers.Close();
+ }
+
+EXPORT_C TBool CMMFCustomCommandParserManager::HandleRequest(TMMFMessage& aMessage)
+ {
+ TBool handledRequest = EFalse;
+ for (TInt i=0; i<iParsers.Count(); i++)
+ {
+ CMMFCustomCommandParserBase* c = iParsers[i];
+ if (c->InterfaceId() == aMessage.Destination().InterfaceId())
+ {
+ c->HandleRequest(aMessage);
+ handledRequest = ETrue;
+ break;
+ }
+ }
+ return handledRequest;
+ }
+
+EXPORT_C void CMMFCustomCommandParserManager::AddCustomCommandParserL(CMMFCustomCommandParserBase& aParser)
+ {
+ User::LeaveIfError(iParsers.Append(&aParser));
+ }
+
+
+TBool CMMFController::DoAddFileHandleDataSourceL(TMMFMessage& aMessage)
+ {
+ RFile file;
+ aMessage.AdoptFileHandleFromClientL(1,2, file);
+ CleanupClosePushL(file);
+ TMMFFileHandleConfig fileConfig;
+ fileConfig().iFile = &file;
+ // Create the source
+ MDataSource* source = MDataSource::NewSourceL(KUidMmfFileSource, fileConfig);
+ CleanupStack::PopAndDestroy(&file);
+ CleanupDeletePushL(source);
+ CMMFDataSourceHolder* holder = new(ELeave) CMMFDataSourceHolder(*source);
+ CleanupStack::Pop(source);//source (since now owned by holder)
+
+ CleanupStack::PushL(holder);
+ // Append holder to array of MMFObjects
+ User::LeaveIfError(MMFObjectContainerL().AddMMFObject(*holder));
+ CleanupStack::Pop(holder);//holder
+
+ // Write source handle info back to client
+ TMMFMessageDestination handleInfo(holder->Handle());
+ TMMFMessageDestinationPckg handlePckg(handleInfo);
+ TInt error = aMessage.WriteDataToClient(handlePckg);
+
+ // Add source to plugin
+ if (!error)
+ TRAP(error, AddDataSourceL(*source));
+
+ if (error)
+ {
+ // Source not accepted by plugin or we couldn't write handle info back to client,
+ // so delete it and return error to client
+ MMFObjectContainerL().RemoveAndDestroyMMFObject(*holder);
+ User::Leave(error);
+ }
+
+ return ETrue;
+ }
+
+
+TBool CMMFController::DoAddFileHandleDataSinkL(TMMFMessage& aMessage)
+ {
+ RFile file;
+ aMessage.AdoptFileHandleFromClientL(1,2, file);
+ CleanupClosePushL(file);
+ TMMFFileHandleConfig fileConfig;
+ fileConfig().iFile = &file;
+ // Create the sink
+ MDataSink* sink = MDataSink::NewSinkL(KUidMmfFileSink, fileConfig);
+ CleanupStack::PopAndDestroy(&file); // close our handle to the file
+ CleanupDeletePushL(sink);
+ CMMFDataSinkHolder* holder = new(ELeave) CMMFDataSinkHolder(*sink);
+ CleanupStack::Pop(sink);//sink (since now owned by holder)
+
+ CleanupStack::PushL(holder);
+ // Append sink to array
+ User::LeaveIfError(MMFObjectContainerL().AddMMFObject(*holder));
+ CleanupStack::Pop(holder);//holder
+
+
+ // Write sink handle info back to client
+ TMMFMessageDestination handleInfo(holder->Handle());
+ TMMFMessageDestinationPckg handlePckg(handleInfo);
+ TInt error = aMessage.WriteDataToClient(handlePckg);
+
+ // Add sink to plugin
+ if (!error)
+ TRAP(error, AddDataSinkL(*sink));
+
+ if (error)
+ {
+ // Sink not accepted by plugin or we couldn't write handle info back to client,
+ // so delete it and return error to client
+ MMFObjectContainerL().RemoveAndDestroyMMFObject(*holder);
+ User::Leave(error);
+ }
+
+ return ETrue;
+ }
+
+EXPORT_C TThreadId CMMFController::ClientThreadIdL()
+ {
+ return GetExtendedDataL()->ClientThreadId();
+ }
+
+EXPORT_C TBool CMMFController::IsSecureDrmModeL()
+ {
+ return GetExtendedDataL()->SecureDrmMode();
+ }
+