diff -r 000000000000 -r 71ca22bcf22a mmfenh/enhancedmediaclient/Plugins/FileSource/src/FileSource.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmfenh/enhancedmediaclient/Plugins/FileSource/src/FileSource.cpp Tue Feb 02 01:08:46 2010 +0200 @@ -0,0 +1,1381 @@ +/* +* Copyright (c) 2006 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: Implementation of FileSource. +* Version : %version: bh1mmcf#5.1.7 % +* +*/ + + +#include +#include +#include +#include +#include +#include +#include "FileMultimediaSource.h" +#include "FileDataSource.h" +#include "MmffilePriv.h" +#include "FileAccess.h" +#include "SinkQueueItem.h" +#include "FileDataSourceCommon.h" +#include +#include "FileSourceUid.h" + + +#ifdef _DEBUG +#define DEBPRN1(str) RDebug::Print(str); +#define DEBPRN2(str, val1) RDebug::Print(str, val1); +#define DEBPRN3(str, val1, val2) RDebug::Print(str, val1, val2); +#define DEBPRN4(str, val1, val2, val3) RDebug::Print(str, val1, val2, val3); +#define DEBPRN5(str, val1, val2, val3, val4) RDebug::Print(str, val1, val2, val3, val4); +#else +#define DEBPRN1(str) +#define DEBPRN2(str, val1) +#define DEBPRN3(str, val1, val2) +#define DEBPRN4(str, val1, val2, val3) +#define DEBPRN5(str, val1, val2, val3, val4) +#endif // _DEBUG + +void Panic(TMMFFilePanicCode aPanicCode) + { + _LIT(KMMFFilePanicCategory, "MMFFile"); + User::Panic(KMMFFilePanicCategory, aPanicCode); + } + +/** +* Constructs a CTransferBufferCopy +* +* @return CTransferBufferCopy* +*/ +CTransferBufferCopy* CTransferBufferCopy::NewL(TInt aMaxLength) + { + CTransferBufferCopy* self = new (ELeave) CTransferBufferCopy(aMaxLength); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +/** +* Second phase constructor for CTransferBufferCopy +* +* @return void +*/ +void CTransferBufferCopy::ConstructL() + { + iBuffer = static_cast(User::AllocL(iMaxLength)); + iBufferDes.Set(iBuffer,0,iMaxLength); + } + + + +CFileSource* CFileSource::NewL(TUid aType ) + { + DEBPRN1(_L("CFileSource::NewL")); + CFileSource* self = new (ELeave) CFileSource(aType); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CFileSource::CFileSource(TUid aType) +: MDataSource(aType) + { + iInitData = NULL; + } + +CFileSource::~CFileSource(void) + { + delete iInitData; + iInitData = NULL; + } + +void CFileSource::ConstructL (void) + { + } + +// From MDataSource begins +TUid CFileSource::DataSourceType() const + { + return KMmfFileSource; + } + + +TFourCC CFileSource::SourceDataTypeCode(TMediaId /*aMediaId*/ ) + { + TFourCC fourCC; + return iMultiMediaSource->GetDataTypeCode(fourCC); + } + +TInt CFileSource::SetSourceDataTypeCode(TFourCC aSourceFourCC, + TMediaId /*aMediaId*/ ) + { + iMultiMediaSource->SetDataTypeCode(aSourceFourCC); + return KErrNone; + } + +void CFileSource::FillBufferL(CMMFBuffer* aBuffer, + MDataSink* aConsumer, + TMediaId /*aMediaId*/ ) + { + // Requires that iFile is open for read. + // Reads data from iFile into aBuffer + //TInt status(KErrNone); + if ((!aConsumer) || (!aBuffer)) + User::Leave(KErrArgument); + + iMultiMediaSource->AppendBufferToSinkQueue(aBuffer,NULL,aConsumer,EFalse); + iMultiMediaSource->ServiceFillBuffer(); + } + +void CFileSource::BufferEmptiedL(CMMFBuffer* /*aBuffer*/ ) + { + User::Leave(KErrUnknown); + } + +TBool CFileSource::CanCreateSourceBuffer() + { + return EFalse; + } + +CMMFBuffer* CFileSource::CreateSourceBufferL(TMediaId /*aMediaId*/, + TBool &/*aReference*/ ) + { + return NULL; + } + +TInt CFileSource::SourceThreadLogon( MAsyncEventHandler& /*aEventHandler*/ ) + { + return iMultiMediaSource->Open(); + } + +void CFileSource::SourceThreadLogoff() + { + iMultiMediaSource->Close(); + } + +void CFileSource::SourcePrimeL() + { + DEBPRN1(_L("CFileSource::SourcePrimeL")); + User::LeaveIfError(iMultiMediaSource->Prime()); + } + +void CFileSource::SourcePlayL() + { + DEBPRN1(_L("CFileSource::SourcePlayL")); + User::LeaveIfError(iMultiMediaSource->Play()); + } + +void CFileSource::SourceStopL() + { + DEBPRN1(_L("CFileSource::SourceStopL")); + User::LeaveIfError(iMultiMediaSource->Stop()); + } + + +void CFileSource::ConstructSourceL(const TDesC8& aInitData ) + { + if(iInitData) + { + delete iInitData; + iInitData = NULL; + } + iInitData = aInitData.AllocL(); + } + +void CFileSource::SourceCustomCommand(TMMFMessage& aMessage) + { + iMultiMediaSource->SourceCustomCommand(aMessage); + } + +void CFileSource::SetMultimediaSource(CFileMultimediaSource& aMultimediaSource) + { + iMultiMediaSource = &aMultimediaSource; + } + +TDesC8& CFileSource::GetInitData() + { + return *iInitData; + } + + + + +EXPORT_C CFileMultimediaSource* CFileMultimediaSource::NewL(MDataSource& aDataSource) + { + DEBPRN1(_L("CFileMultimediaSource::NewL")); + CFileMultimediaSource* self = new (ELeave) CFileMultimediaSource(aDataSource); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + + + +/** +Destructor. +*/ +CFileMultimediaSource::~CFileMultimediaSource() + { + DEBPRN1(_L("CFileMultimediaSource::~CFileMultimediaSource() ")); + + delete iInitData; + + delete iFile; + EmptySinkQueue(); + iHandle.Close(); + iFsSession.Close(); + delete iFileName; + delete iFileExt; + delete iFilePath; + delete iFileDrive; + + + delete iCAFParameters; + delete iSinkQueue; + + if(iMessage) + { + if(!iMessage->IsCompleted()) + { + iMessage->Complete(KErrDied); + delete iMessage; + iMessage = NULL; + } + } + // Get rid of everything in RArray's & close them. + iRequests.ResetAndDestroy(); + iTransferBufferCopies.ResetAndDestroy(); + DEBPRN1(_L("CFileMultimediaSource::~CFileMultimediaSource() exit")); + } + +/** +Protected constructor. + +The default implementation is empty. +*/ +CFileMultimediaSource::CFileMultimediaSource( + MDataSource& aDataSource ) + : iSnkItemsCount(0), + iSnkBytes(0), + iDownloadSize(0), + iTransferRate(0), + //iConsumer(NULL), + iBufferedDataSize(0), + iDLFileSize(0), + isDownloadComplete(EFalse), + iFileSize(0), + iParentDataSource(&aDataSource) + { + iMessage = NULL; + iFile = NULL; + iState = ECLOSED; + iObserver = NULL; + iInitData = NULL; + } + +/** +Constructs an CFileMultimediaSource MDataSource. + +@return A pointer to the new CFileMultimediaSource data source. +*/ +/*MDataSource* CFileMultimediaSource::NewSourceL() + { + CFileMultimediaSource* self = new (ELeave) CFileMultimediaSource( KMmfFileSource ) ; + return STATIC_CAST( MDataSource*, self ) ; + }*/ + + +/** +Perform source construction dependant on the source construction +initialisation data aInitData. + +@param aInitData +The TPckg descriptor package containing the file name and full path. +*/ +void CFileMultimediaSource::ConstructL() + { + CFileSource* fileSource = static_cast(iParentDataSource); + iInitData = (fileSource->GetInitData()).AllocL(); + fileSource->SetMultimediaSource(*this); + ConstructL(*iInitData, ESourceMode); + iSinkQueue = new(ELeave) TSglQue(_FOFF(CSinkQueueItem, iLink)); + } + + +/** +Protected constructor. + +Extracts the initialisation data provided by the calling functions: ConstructSourceL() and +ConstructSinkL(). Creates a file server session and sets up file name. If there is a file name and +it cannot be found this function leaves. If there is no file name the function leaves. Does not +attempt to open the file or check whether the file exists. + +If aInitData contains a TMMFFileHandleParams instead of TMMFFileParams, the source/sink is constructed from +the file handle provided by the caller + +@param aInitData +Initialisation data packaged in a TMMFFileParams or in a TMMFFileHandleParams (File Handle) +*/ +void CFileMultimediaSource::ConstructL(const TDesC8& aInitData,TMMFileMode aFileMode) + { + User::LeaveIfError(iFsSession.Connect()); + // on IPCv2 we auto attach + User::LeaveIfError(iFsSession.ShareAuto()); + + User::LeaveIfError(iFsSession.ShareProtected()); + + TBool fileInit = EFalse; + HBufC* filename = NULL; + TBool filenamePushed = EFalse; + + iCAFParameters = new (ELeave) CCAFParameters; + TBool drmContent = EFalse; + RDesReadStream stream(aInitData); + CleanupClosePushL(stream); + + TUid initUid; + + initUid = TUid::Uid(stream.ReadInt32L()); + + if (initUid == KMMFileHandleSourceUid) + { + TPckgBuf fileptr; + stream.ReadL(fileptr); + + iHandle.Duplicate(*fileptr()); + + TInt length; + length = stream.ReadInt32L(); + if (length>0) + { + iCAFParameters->iUniqueId = HBufC::NewL(length); + TPtr16 ptr = iCAFParameters->iUniqueId->Des(); + stream.ReadL(ptr, length); + } + iFileHandle = ETrue; + filename = HBufC::NewMaxL(KMaxFileName); + TPtr ptr = filename->Des(); + iHandle.Name(ptr); + fileInit = ETrue; + drmContent = ETrue; + + iCAFParameters->iEnableUI = stream.ReadInt32L(); + } + + else if (initUid == KMMFileSourceUid) + { + TInt length; + length = stream.ReadInt32L(); + filename = HBufC::NewMaxLC(length); + TPtr ptr = filename->Des(); + stream.ReadL(ptr, length); + + length = stream.ReadInt32L(); + if (length>0) + { + iCAFParameters->iUniqueId = HBufC::NewMaxL(length); + ptr.Set(iCAFParameters->iUniqueId->Des()); + stream.ReadL(ptr, length); + } + CleanupStack::Pop(filename); + + fileInit = ETrue; + drmContent = ETrue; + iFileHandle = EFalse; + iCAFParameters->iEnableUI = stream.ReadInt32L(); + } + else + { + // TODO If the UID is unknown we should reject, but currently + // code also used for older calls that just supply filename. + // User::Leave(KErrNotSupported); + } + + CleanupStack::PopAndDestroy(&stream); + + if (!fileInit && aInitData.Length() == sizeof(TMMFFileHandleParams)) + { + TMMFFileHandleParams params; + TPckgC config(params); + config.Set(aInitData); + params = config(); + + + if (params.iUid == KFileHandleUid) + { + fileInit = ETrue; + User::LeaveIfError(iHandle.Duplicate(*params.iFile)); + TInt pos = 0; + // make sure the duplicate handle is at the start of the file - the usage of the file handle really requires this + User::LeaveIfError(iHandle.Seek(ESeekStart, pos)); + iFileHandle = ETrue; + filename = HBufC::NewMaxLC(KMaxFileName); + filenamePushed = ETrue; + TPtr ptr = filename->Des(); + User::LeaveIfError(iHandle.Name(ptr)); + } + } + + if (!fileInit) // do old case as last resort + { + TMMFFileParams params; + TPckgC config(params); + config.Set(aInitData); + params = config(); + + filename = params.iPath.AllocL(); + fileInit = ETrue; + } + + if (!filenamePushed) + { + // from now on it is assumed pushed. + CleanupStack::PushL(filename); + } + + TParse parser ; + User::LeaveIfError(parser.Set(*filename, NULL, NULL)); + CleanupStack::PopAndDestroy(filename); + if ( !( parser.NamePresent() ) && !( parser.ExtPresent() ) ) + User::Leave( KErrBadName ) ; + + iFullFileName.Copy( parser.FullName() ) ; + iFileName = parser.Name().AllocL() ; + iFileExt = parser.Ext().AllocL() ; + iFilePath = parser.Path().AllocL() ; + iFileDrive = parser.Drive().AllocL() ; + + // in order to simulate old behaviour we are not passing error out + // but will try to create Content again during PrimeL() + if (fileInit && drmContent && aFileMode==ESourceMode) + { + TInt contentError; + if (iFileHandle) + { + TRAP(contentError, + iFile = CContentFile::NewL(iHandle, UniqueId(), iCAFParameters->iEnableUI); + ); + } + else + { + // Open for read-only access + TRAP(contentError, + iFile = CContentFile::NewL(iFsSession, iFullFileName, UniqueId(), EFileShareAny, iCAFParameters->iEnableUI); + ); + } + } + } + + +/** +@deprecated + +Returns an RFile handle to the current file. + +If there is no current file, one is created. If the file exists then it is opened with read access +if it is read only, write access otherwise. If the file does not exist then it is opened with +write access. + +@leave KErrNotReady +The file is not open. + +@return A handle to the current file. +*/ +RFile& CFileMultimediaSource::FileL() + { + if (!iFile) + User::Leave(KErrNotReady); + if (iFileHandle) + return iHandle; + else + return iFile->FileL(); + } + +/** +Returns the file name of the current file. + +Note: This will give the wrong answer if the file is renamed! + +@return The FileName (without extension). +*/ +const TDesC& CFileMultimediaSource::FileName() const + { + return *iFileName ; + } + +/** +Returns the extension of the current file. + +Note: This will give the wrong answer if the file is renamed! + +@return The File Extension. +*/ +const TDesC& CFileMultimediaSource::Extension() const + { + return *iFileExt ; + } + +/** +Returns the path of the current file. + +Note: This will give the wrong answer if the file is renamed! + +@return The FilePath (without filename and extension) +*/ +const TDesC& CFileMultimediaSource::FilePath() const + { + return *iFilePath ; + } + +/** +Returns the drive on which the current file is located. + +Note: This will give the wrong answer if the file is renamed! + +@return The FileDrive (drive letter only, without path, filename and extension). +*/ +const TDesC& CFileMultimediaSource::FileDrive() const + { + return *iFileDrive ; + } + +/** +Returns the full name of the current file. + +Note: This will give the wrong answer if the file is renamed! + +@return The file name (full filename including drive letter, without path, filename and extension). +*/ +const TFileName CFileMultimediaSource::FullName() const + { + return iFullFileName; + } + +/** +Returns the uniqueID associated with this content. If no uniqueID has been provided, a null +descriptor will be provided + +@return The UniqueID +*/ +const TDesC& CFileMultimediaSource::UniqueId() const + { + if (iCAFParameters->iUniqueId) + return *(iCAFParameters->iUniqueId); + else + return KNullDesC; + } + +/** +Obtains a CTransferBufferCopy from iTransferBufferCopies that is +at least as big as that required. + +There is no need to put the pointer returned by this method onto the CleanupStack +as it will have already been placed into iTransferBufferCopies. + +@param aMaxLength +The size required. + +@return A pointer to a valid CTransferBufferCopy. +*/ +CTransferBufferCopy* CFileMultimediaSource::ObtainCopyOfTransferBufferL(TInt aMaxLength) + { + //find a free transfer buffer copy of the right size + TInt firstFree = -1; + CTransferBufferCopy* transBufCopyToUse = NULL; + + for(TInt cnt=0; cnt < iTransferBufferCopies.Count(); cnt++) + { + if(!iTransferBufferCopies[cnt]->InUse()) + { + //record the first free entry, we may remove this + //if entries in iTransferBufferCopies > KAcceptableTransferBufferCopiesSize + if(firstFree == -1) + firstFree = cnt; + + if(iTransferBufferCopies[cnt]->MaxLength() >= aMaxLength) + { + transBufCopyToUse = iTransferBufferCopies[cnt]; + + //Set the MaxLength. This will ensure that the copy acts the same as + //the original Transfer buffer, eg. file server will throw KErrOverflow + transBufCopyToUse->ReUse(aMaxLength); + break; + } + } + } + + //If we failed to find a suitable entry, we need to create a new one + if(!transBufCopyToUse) + { + //Firstly, should we re-cycle an existing entry? + //There must be entries in the array, a free entry must have been found, + //the size of the array must be beyond the water mark where we want to start + //cycling free entries. + if((iTransferBufferCopies.Count() > 0) && + (firstFree != -1) && + (iTransferBufferCopies.Count() > KAcceptableTransferBufferCopiesSize)) + { + delete iTransferBufferCopies[firstFree]; + iTransferBufferCopies.Remove(firstFree); + + transBufCopyToUse = CTransferBufferCopy::NewL(aMaxLength); + CleanupStack::PushL(transBufCopyToUse); + User::LeaveIfError(iTransferBufferCopies.Insert(transBufCopyToUse,firstFree)); + + CleanupStack::Pop(); + } + else + { + #ifdef _DEBUG + if(iTransferBufferCopies.Count() > KMaximumTransferBufferCopiesSize) + { + User::Panic(_L("iTransferBufferCopies grew too large in CFileMultimediaSource"),KErrTooBig); + } + #endif + + transBufCopyToUse = CTransferBufferCopy::NewL(aMaxLength); + CleanupStack::PushL(transBufCopyToUse); + User::LeaveIfError(iTransferBufferCopies.Append(transBufCopyToUse)); + + CleanupStack::Pop(); + } + } + + return transBufCopyToUse; + } + + +/** +Stores a request in an array. + +CReadWriteRequests are stored in the array iRequests. +This function takes ownership and places the request in the array. +It also checks the array for completed requests and removes them. + +@param aRequest +The request to store. +*/ +void CFileMultimediaSource::StoreRequestL( CReadWriteRequest* aRequest ) + { + // add aRequest to iRequests + User::LeaveIfError( iRequests.Append( aRequest ) ) ; + + // Clear out any completed requests + for ( TInt ii = 0 ; ii < iRequests.Count() ; ii++ ) + { + if (iRequests[ii]->Completed()) + { + CReadWriteRequest* request = iRequests[ii]; + delete request; + + iRequests.Remove(ii); + ii--; + } + } + } + + +/** +Cancels outstanding requests. + +CReadWriteRequests are stored in the array iRequests. +This function cancels any outstanding requests and removes them +from iRequests. +*/ +void CFileMultimediaSource::CancelRequests() + { + // Clear out any completed requests + for ( TInt ii = 0 ; ii < iRequests.Count() ; ii++ ) + { + CReadWriteRequest* request = iRequests[ii]; + delete request; + iRequests.Remove(ii); + ii--; + } + } + +/** +Evaluates a given intent against the rights associated with the file. + +The rights are not updated by this function call. + +@param aIntent +The intent to evaluate. + +@return An error code indicating if the function call was successful. KErrNone on success, otherwise +another of the system-wide error codes. +*/ +TInt CFileMultimediaSource::EvaluateIntent(ContentAccess::TIntent aIntent) + { + if (!iFile) + { + return KErrNotReady; + } + + return iFile->EvaluateIntent(aIntent); + } + +/** +Evaluates and executes a given intent against the rights associated with the file. + +The rights object is updated after calling this function. + +@param aIntent +The intent to evaluate. + +@return An error code indicating if the function call was successful. KErrNone on success, otherwise +another of the system-wide error codes. +*/ +TInt CFileMultimediaSource::ExecuteIntent(ContentAccess::TIntent aIntent) + { + if (!iFile) + { + return KErrNotReady; + } + + return iFile->ExecuteIntent(aIntent); + } + +/** +Returns whether the file is protected. + +@return A boolean indicating if the file is protected. ETrue if the file is protected. +*/ +TInt CFileMultimediaSource::GetDRMProtection(TBool& aIsProtected) + { + TInt err(KErrNone); + if (!iFile) + { + return KErrNotReady; + } + + TRAP(err,aIsProtected = iFile->IsProtected()); + return err; + } + +TInt CFileMultimediaSource::SetAgentProperty(ContentAccess::TAgentProperty aProperty, TInt aValue) + { + if (!iFile) + { + return KErrNotReady; + } + + return iFile->SetAgentProperty(aProperty, aValue); + } + + +TInt CFileMultimediaSource::GetSeekingSupport( TBool& aSeekSupport ) + { + aSeekSupport = ETrue; + return KErrNone; + }; + +TInt CFileMultimediaSource::GetRandomSeekingSupport(TBool& aSeekSupport ) + { + aSeekSupport = ETrue; + return KErrNone; + }; + +TInt CFileMultimediaSource::Seek(TUint aPosInBytes) + { + if (!iFile) + { + return KErrNotReady; + } + + return iFile->Seek(ESeekStart, aPosInBytes); + }; + +/* +* Returns ETrue if the request can safely be deleted. +*/ + +TBool CReadWriteRequest::Completed() + { + return iCompleted ; + } + +TInt CReadWriteRequest::SetStatus(TBool aStatus) + { + iCompleted = aStatus; + return KErrNone; + } + +TBool CReadWriteRequest::SourceType() + { + return iSourceType ; + } + + +/* +* Returns the data member of CMMFDataBuffer or CMMFTransferBuffer (as TPtr8) +* +*/ +TDes8& CReadWriteRequest::BufferDes() + { + if(iTransferBufferCopy) + return iTransferBufferCopy->Des(); + else + { + //reset iBufferDes in case iBuffer has changed... + iBufferDes = &(STATIC_CAST(CMMFDataBuffer*, iBuffer)->Data()); + return *iBufferDes; + } + } + +const TDesC8& CReadWriteRequest::BufferDesC() + { + if(iTransferBufferCopy) + return iTransferBufferCopy->Des(); + else + return BufferDes(); + } + +CMMFBuffer* CReadWriteRequest::Buffer() + { + return iBuffer; + } + +TAny* CReadWriteRequest::GetSinkOrSource() + { + return iSinkOrSource; + } + +/* +* Destructor. +*/ +CReadWriteRequest::~CReadWriteRequest() + { + Cancel(); + if(iTransferBufferCopy) + iTransferBufferCopy->SetInUse(EFalse); + } + +/* +* Allows owning class access to SetActive() +*/ +void CReadWriteRequest::SetActive() + { + CActive::SetActive() ; + } + +/* +* For the moment at least... Canceled requests may be deleted +*/ +void CReadWriteRequest::DoCancel() + { + iCompleted = ETrue ; + } + +/* +* Called when errors in RunL force Leave. For the moment just mark the request deletable +*/ +TInt CReadWriteRequest::RunError( TInt aError ) + { + //RunL can leave. + iCompleted = ETrue ; + iError = aError; //keep this error internally for now + return KErrNone ; + } + +/* +* On completion of read request call back to the MDataSink +*/ +void CReadRequest::RunL() + { + //Copy the data from the normal buffer into the Transfer buffer + if(iTransferBufferCopy) + { + //must specify the size here as the dest may be smaller than the source. + TDes8& destDesc = STATIC_CAST(CMMFDataBuffer*, iBuffer)->Data(); + destDesc.Copy(iTransferBufferCopy->Des().Left(destDesc.MaxLength())); + + iTransferBufferCopy->SetInUse(EFalse); + } + + STATIC_CAST(CFileMultimediaSource*,iParent)->ReadRequestStatus(STATIC_CAST(CReadWriteRequest*,this),iStatus); + } + + // From CMultimediaDataSource begins +TInt CFileMultimediaSource::SetObserver( MMultimediaDataSourceObserver& aObserver ) + { + TInt status(KErrNone); + iObserver = &aObserver; + return status; + } + +TInt CFileMultimediaSource::GetObserver( MMultimediaDataSourceObserver*& aObserver ) + { + TInt status(KErrNone); + aObserver = iObserver; + return status; + } + +void CFileMultimediaSource::Event( TUid aEvent ) + { + if( aEvent == KMultimediaDataSourceEventBitRateChanged ) + { + if(iObserver) + { + iObserver->GetBitRate( iObserverBitRate ); + } + TPckgBuf bitRatePckg; + bitRatePckg().iBitRate = iObserverBitRate; + bitRatePckg().iType = EFileBitRateChanged; + + if(iMessage) + { + iMessage->WriteDataToClient(bitRatePckg); + iMessage->Complete(KErrNone); + } + } + } + +TInt CFileMultimediaSource::SetDataTypeCode(TFourCC aSourceFourCC ) + { + TInt status(KErrNone); + iSourceFourCC = aSourceFourCC; + return status; + } + +TInt CFileMultimediaSource::GetDataTypeCode(TFourCC& aSourceFourCC ) + { + TInt status(KErrNone); + aSourceFourCC = iSourceFourCC; + return status; + } + +TInt CFileMultimediaSource::GetSize( TUint& aSize ) + { + TInt err = KErrNone; + aSize = iFileSize; + return err; + } + +TInt CFileMultimediaSource::Open() + { + TInt status(KErrNotReady); + DEBPRN1(_L("CFileMultimediaSource::Open")); + switch ( iState ) + { + case ECLOSED: + StateChanged(ESTOPPED); + status = KErrNone; + break; + case ESTOPPED: + case EPRIMED: + case EEXECUTING: + case EBUFFERING: + default: + DEBPRN2(_L("CFileMultimediaSource::Open[Illegal cmd on state[%d]]"), iState ); + break; + }; + return status; + } + +TInt CFileMultimediaSource::Close() + { + TInt status(KErrNone); + iHandle.Close(); + iFsSession.Close(); + + StateChanged(ECLOSED); + // Clear app buffers + EmptySinkQueue(); + iSnkBytes = 0; + // Clear observer buffers + return status; + } + +TInt CFileMultimediaSource::Prime() + { + TInt status(KErrNotReady); + DEBPRN1(_L("CFileMultimediaSource::Prime")); + switch ( iState ) + { + case ESTOPPED: + + // don't reopen file if already open + if (!iFile) + { + if (iFileHandle) + { + TRAPD(err,iFile = CContentFile::NewL(iHandle, UniqueId(), iCAFParameters->iEnableUI)); + if(err) + return err; + } + else + { + // Open for read-only access + TRAPD(err,iFile = CContentFile::NewL(iFsSession, iFullFileName, UniqueId(), EFileShareAny, iCAFParameters->iEnableUI)); + if(err) + return err; + } + } + + if(iFile) + { + iFile->Size(iFileSize); + } + + StateChanged(EPRIMED); + status = KErrNone; + break; + case EPRIMED: + status = KErrNone; + break; + case ECLOSED: + case EEXECUTING: + case EBUFFERING: + default: + DEBPRN2(_L("CFileMultimediaSource::Prime[Illegal cmd on state[%d]]"), iState ); + break; + } + return status; + } + +TInt CFileMultimediaSource::Play() + { + TInt status(KErrNotReady); + DEBPRN1(_L("CFileMultimediaSource::Play")); + switch ( iState ) + { + case EPRIMED: + StateChanged(EEXECUTING); + + while ( !iSinkQueue->IsEmpty() ) + { + status = ServiceFillBuffer(); + } + + status = KErrNone; + break; + case EEXECUTING: + case EBUFFERING: + status = KErrNone; + // No op + break; + case ECLOSED: + case ESTOPPED: + default: + DEBPRN2(_L("CFileMultimediaSource::Play[Illegal cmd on state[%d]]"), iState ); + break; + }; + return status; + } + +TInt CFileMultimediaSource::Stop() + { + TInt status(KErrNotReady); + DEBPRN1(_L("CFileMultimediaSource::Stop")); + switch ( iState ) + { + case EPRIMED: + case EEXECUTING: + case EBUFFERING: + { + TInt pos = 0; + CancelRequests(); + delete iFile; + iFile = NULL; + iSnkBytes=pos; + EmptySinkQueue(); + StateChanged(ESTOPPED); + status = KErrNone; + } + break; + case ESTOPPED: + case ECLOSED: + default: + DEBPRN2(_L("CFileMultimediaSource::Stop[Illegal cmd on state[%d]]"), iState ); + status = KErrNone; + break; + }; + return status; + } + +TInt CFileMultimediaSource::FillBuffer( CMMFBuffer* aBuffer ) + { + // Requires that iFile is open for read. + // Reads data from iFile into aBuffer + TInt status(KErrNone); + if (!aBuffer) + return KErrArgument; + + if (!iFile) + return KErrNotReady; + + AppendBufferToSinkQueue(aBuffer,iObserver,NULL,EFalse); + + status = ServiceFillBuffer(); + + return status; + } + + +TAny* CFileMultimediaSource::CustomInterface( TUid /*aInterfaceUid*/ ) + { + return NULL; + } + +TInt CFileMultimediaSource::AppendBufferToSinkQueue( CMMFBuffer* aBuffer, + MMultimediaDataSourceObserver* aObserver, + MDataSink* aConsumer,TBool aTop ) + { + TInt status(KErrNone); + + DEBPRN2(_L("CFileMultimediaSource::AppendBufferToSinkQueue() Buffer[%x]"), aBuffer ); + // Add observer buffer to queue + CMMFDataBuffer* dest = static_cast( aBuffer ); + TDes8& destBufferDes = dest->Data(); + + CSinkQueueItem* request(NULL); + + TRAP( status, request = CSinkQueueItem::NewL( aBuffer, aObserver,aConsumer) ); + if ( status == KErrNone ) + { + if(aTop) + iSinkQueue->AddFirst(*request); + else + iSinkQueue->AddLast(*request); + + iSnkItemsCount++; + + DEBPRN3(_L("CFileMultimediaSource::AppendBufferToQueue[ReqSize[%d]SnkItems[%d]]"), \ + aBuffer->RequestSize(), iSnkItemsCount ); + } + return status; + } + +void CFileMultimediaSource::SourceCustomCommand(TMMFMessage& aMessage) + { + //TInt err(KErrNone); + switch ( aMessage.Function() ) + { + case EGetFileSourceEvent: + { + TPckgBuf statePckg; + aMessage.ReadData1FromClient(statePckg); + DEBPRN3(_L("CFileMultimediaSource::SourceCustomCommand() Client State[%d] SourceState[%d]"), statePckg().iState, iState); + + if(statePckg().iType == EFileBitRateChanged) + { + if(iObserver) + { + iObserver->GetBitRate( iObserverBitRate ); + } + statePckg().iBitRate = iObserverBitRate; + aMessage.WriteDataToClient(statePckg); + aMessage.Complete(KErrNone); + } + else if(statePckg().iType == EFileSize) + { + TUint size = 0; + GetSize(size); + statePckg().iFileSize = size; + aMessage.WriteDataToClient(statePckg); + aMessage.Complete(KErrNone); + } + else if(statePckg().iType == EFileSourceStateChanged) + { + if(iState != statePckg().iState) + { + statePckg().iState = iState; + aMessage.WriteDataToClient(statePckg); + aMessage.Complete(KErrNone); + } + else + iMessage = new(ELeave) TMMFMessage(aMessage); + } + } + break; + + default: + //err = KErrArgument; + break; + } + } + +TInt CFileMultimediaSource::ServiceFillBuffer() + { + + DEBPRN3(_L("CFileMultimediaSource::ServiceFillBuffer() state[%d] Download Size[%d]"), iState ,iDownloadSize ); + + TInt status(KErrNone); + if ( iSinkQueue->IsEmpty() ) + return KErrNone; + + CSinkQueueItem* snkItem = iSinkQueue->First(); + iSinkQueue->Remove(*snkItem); + iSnkItemsCount--; + CMMFBuffer* buffer = snkItem->Buffer(); + DEBPRN2(_L("CFileMultimediaSource::ServiceFillBuffer() Buffer[%x]"), buffer ); + MMultimediaDataSourceObserver* observer = snkItem->Observer(); + MDataSink* consumer = snkItem->Consumer(); + delete snkItem; + + if (CMMFBuffer::IsSupportedDataBuffer(buffer->Type())) + { + CTransferBufferCopy* transBufCopy = NULL; + CReadRequest* request = NULL; + + TDes8& bufferDes = STATIC_CAST( CMMFDataBuffer*, buffer )->Data(); + + TInt requestSize; + if(buffer->RequestSize()) + requestSize = buffer->RequestSize(); + else + requestSize = bufferDes.MaxLength(); + + //check whether buffer is safe to send to file server + //if not, eg for a transfer buffer, then it needs to be copied + if (!CMMFBuffer::IsFileServerSafe(buffer->Type())) + { + //NB: failure in this method will NOT cause transBufCopy to leak as it will be + //inserted into iTransferBufferCopies by ObtainCopyOfTransferBufferL. + TRAP(status,transBufCopy = ObtainCopyOfTransferBufferL(bufferDes.MaxLength())); + + if(consumer && !observer) + request = new(ELeave) CReadRequest(this,STATIC_CAST(TAny*, consumer), buffer, transBufCopy, iSnkBytes, iDownloadSize, ETrue); + else + request = new(ELeave) CReadRequest(this,STATIC_CAST(TAny*, observer), buffer, transBufCopy, iSnkBytes, iDownloadSize, EFalse); + + } + else + { + if(consumer && !observer) + request = new(ELeave) CReadRequest(this,STATIC_CAST(TAny*, consumer), buffer, iSnkBytes, iDownloadSize, ETrue); + else + request = new(ELeave) CReadRequest(this,STATIC_CAST(TAny*, observer), buffer, iSnkBytes, iDownloadSize, EFalse); + } + + CleanupStack::PushL( request ); + + TRAP_IGNORE(StoreRequestL(request)); // transfers ownership + CleanupStack::Pop() ; // request + + request->SetActive(); + + if ((iSnkBytes + request->Buffer()->RequestSize()) > iFileSize) + { + request->Buffer()->SetLastBuffer(ETrue); + DEBPRN1(_L("CFileMultimediaSource::ServiceFillBuffer() LastBuffer$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$")); + } + + iFile->Read(request->BufferDes(), requestSize, request->iStatus); + + } + else // if (CMMFBuffer::IsSupportedDataBuffer(buffer->Type())) + return KErrNotSupported; + + + return status; + } + +TInt CFileMultimediaSource::EmptySinkQueue() + { + TInt status(KErrNone); + // Empty sink queue + CSinkQueueItem* snkItem; + while ( !iSinkQueue->IsEmpty() ) + { + snkItem = iSinkQueue->First(); + iSinkQueue->Remove(*snkItem); + delete snkItem; + } + + iSnkItemsCount = 0; + return status; + } + +void CFileMultimediaSource::StateChanged(TState newState) + { + DEBPRN3(_L("CFileMultimediaSource::StateChanged OLD[%d] NEW[%d]"),iState, newState); + if(iState != newState) + { + if(iMessage) + { + if(!iMessage->IsCompleted()) + { + TPckgBuf statePckg; + statePckg().iState = newState; + statePckg().iType = EFileSourceStateChanged; + iMessage->WriteDataToClient(statePckg); + iMessage->Complete(KErrNone); + delete iMessage; + iMessage = NULL; + } + } + iState = newState; + } + } + +TInt CFileMultimediaSource::ReadRequestStatus(CReadWriteRequest* aRequest, TRequestStatus& aStatus) + { + + if(aStatus != KErrNone) + { + TMMFEvent event(KMMFErrorCategoryControllerGeneralError, aStatus.Int()); + iEventHandler->SendEventToClient(event); + return KErrNone; + } + else + { + + DEBPRN4(_L("CFileMultimediaSource::ReadRequestStatus Buffer[%x] BufferSize[%d] RequestSize[%d]"),aRequest->Buffer(),aRequest->Buffer()->BufferSize(),aRequest->Buffer()->RequestSize()); + DEBPRN3(_L("CFileMultimediaSource::ReadRequestStatus Buffer[%x] LastBuffer[%d]"),aRequest->Buffer(),aRequest->Buffer()->LastBuffer()); + + TBool lastBuffer = aRequest->Buffer()->LastBuffer(); + + if((aRequest->Buffer()->BufferSize() != aRequest->Buffer()->RequestSize()) && !lastBuffer) + { + if(aRequest->SourceType()) + { + MDataSink* sinkOrSource = REINTERPRET_CAST(MDataSink*,aRequest->GetSinkOrSource()); + AppendBufferToSinkQueue(aRequest->Buffer(),(MMultimediaDataSourceObserver*)NULL,sinkOrSource,ETrue); + iSnkBytes -= aRequest->Buffer()->BufferSize(); + iFile->Seek(ESeekStart,iSnkBytes); + StateChanged(EBUFFERING); + } + else + { + MMultimediaDataSourceObserver* sinkOrSource = REINTERPRET_CAST(MMultimediaDataSourceObserver*,aRequest->GetSinkOrSource()); + AppendBufferToSinkQueue(aRequest->Buffer(),sinkOrSource,(MDataSink*)NULL,ETrue); + iSnkBytes -= aRequest->Buffer()->BufferSize(); + iFile->Seek(ESeekStart,iSnkBytes); + StateChanged(EBUFFERING); + } + } + else + { + iSnkBytes += aRequest->Buffer()->BufferSize(); + + + if(aRequest->SourceType()) + REINTERPRET_CAST(MDataSink*, aRequest->GetSinkOrSource())->BufferFilledL(aRequest->Buffer()) ; // callback to MDataSource/Sink + else + REINTERPRET_CAST(MMultimediaDataSourceObserver*, aRequest->GetSinkOrSource())->BufferFilled(aRequest->Buffer()) ; // callback to MDataSource/Sink + + } + + aRequest->SetStatus(ETrue); + return KErrNone; + } + } + +//End of File +