mmfenh/enhancedmediaclient/Plugins/CacheSource/src/CacheSource.cpp
changeset 0 71ca22bcf22a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmfenh/enhancedmediaclient/Plugins/CacheSource/src/CacheSource.cpp	Tue Feb 02 01:08:46 2010 +0200
@@ -0,0 +1,615 @@
+/*
+* 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:  S60 Cache Data Source Plugin implementation
+*
+*/
+
+#include "CacheSource.h"
+#include "SinkQueueItem.h"
+#include "CacheSourceUid.h"
+#include <MultimediaDataSourceEvents.h>
+#include "ReadWriteRequestAO.h"
+#include <mmfdatabuffer.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
+
+
+const TUint KTransferBufferSize = 8192;
+
+EXPORT_C CCacheSource* CCacheSource::NewL(CMultimediaDataSource* aDataSource, CDataSourceConfigIntfc* aDataSourceConfig )
+    {
+    DEBPRN1(_L("CCacheSource::NewL"));
+    CCacheSource* self = new (ELeave) CCacheSource(aDataSource,aDataSourceConfig);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+CCacheSource::CCacheSource(CMultimediaDataSource* aDataSource,CDataSourceConfigIntfc* aDataSourceConfig )
+: iDataSource(aDataSource),iDataSourceConfig(aDataSourceConfig)
+    {
+    // iState from Base
+    iState = ECLOSED;
+    iFileSize = 0;
+    iLastBufferWritten = false;
+    iAbsBufferStart = 0;
+    iAbsBufferEnd = 0;
+    iBufferReadPos = 0;
+    iSeekStart = 0;
+    iSeekEnd = 0;
+    iSnkBytes = 0;
+    iDataBuffer = NULL;
+    iCacheLocation = NULL;
+    }
+
+CCacheSource::~CCacheSource()
+    {
+    DEBPRN1(_L("CCacheSource::~CCacheSource"));
+    iState = ECLOSED;
+    EmptySinkQueue();
+    // Empty sink queue
+    delete iSinkQueue;
+    delete iDataSourceObserver;
+    delete iTransferBuffer;
+    delete iReadRequest;
+    delete iWriteRequest;
+    delete iDataSource;
+    
+    if(iCacheType == CDataSourceConfigIntfc::EFILE)
+        {
+        if(iCacheLocation)
+            {
+            delete iCacheLocation;    
+            }
+        iFile.Close();
+        iFs.Delete(iFileName);
+        iFs.Close();
+        }
+    else
+        {
+        delete iDataBuffer;
+        }        
+    }
+
+void CCacheSource::ConstructL (void)
+    {
+    DEBPRN1(_L("CCacheSource::ConstructL ENTER"));
+    iSinkQueue = new(ELeave) TSglQue<CSinkQueueItem>(_FOFF(CSinkQueueItem, iLink));
+    iDataSourceObserver = CMDataSourceObserver::NewL(iDataSource,this);
+    iTransferBuffer = CMMFDataBuffer::NewL(KTransferBufferSize);
+    iTransferBuffer->SetRequestSizeL(KTransferBufferSize);
+    iWriteRequest = CReadWriteRequestAO::NewL(*this,CReadWriteRequestAO::EWriteRequest);
+    iWriteRequest->SetBuffer(iTransferBuffer);
+    iReadRequest = CReadWriteRequestAO::NewL(*this,CReadWriteRequestAO::EReadRequest);
+    iReadRequest->SetBuffer(iTransferBuffer);
+    iDataSourceConfig->GetCacheType(iCacheType);
+    DEBPRN1(_L("CCacheSource::ConstructL EXIT"));        
+    }
+
+
+
+// From CMultimediaDataSource begins
+TInt CCacheSource::SetObserver( MMultimediaDataSourceObserver& aObserver )
+    {
+    TInt status(KErrNone);    
+    iObserver = &aObserver;
+    return status;
+    }
+
+TInt CCacheSource::GetObserver( MMultimediaDataSourceObserver*& aObserver )
+    {
+    aObserver = iObserver;
+    return KErrNone;
+    }
+
+void CCacheSource::Event( TUid aEvent )
+    {
+    // CAll the Parent DataSource
+    iDataSource->Event(aEvent);
+    }
+
+TInt CCacheSource::SetDataTypeCode(TFourCC aSourceFourCC )
+    {
+    TInt status(KErrNone);
+    status = iDataSource->SetDataTypeCode(aSourceFourCC);
+    return status;
+    }
+
+TInt CCacheSource::GetDataTypeCode(TFourCC& aSourceFourCC )
+    {
+    TInt status(KErrNone);
+    status = iDataSource->GetDataTypeCode(aSourceFourCC);
+    return status;
+    }
+
+TInt CCacheSource::GetSize( TUint& aSize )
+    {
+    TInt status(KErrNone);
+    status = iDataSource->GetSize(aSize);
+    return status;
+    }
+
+TInt CCacheSource::Open()
+    {
+    TInt status(KErrNone);
+    DEBPRN1(_L("CCacheSource::Open"));                 
+    status = iDataSource->Open();
+    return status;
+    }
+
+TInt CCacheSource::Close()
+    {
+    TInt status(KErrNone);
+    DEBPRN1(_L("CCacheSource::Close"));                 
+    status = iDataSource->Close();
+    return status;
+    }
+
+TInt CCacheSource::Prime()
+    {
+    TInt status(KErrNone);
+    DEBPRN1(_L("CCacheSource::Prime"));             
+    status = iDataSource->Prime();
+
+    iDataSourceConfig->GetCacheType(iCacheType);
+    if(iCacheType == CDataSourceConfigIntfc::EFILE)
+        {
+	    status = iFs.Connect();
+	    if(status == KErrNone)
+	        {
+	        	if(iCacheLocation)
+	            {
+	            delete iCacheLocation;
+	            iCacheLocation = NULL;                
+	            }
+	        iCacheLocation = HBufC16::NewL(KMaxFileName);
+	        TPtr des = iCacheLocation->Des();
+	        iDataSourceConfig->GetCacheLocation(des);
+	
+	        TInt err = iFile.Temp(iFs,des,iFileName,EFileWrite);
+			status = err;
+			}
+        }
+    else
+        {
+        TUint cacheSize = 0;
+        iDataSourceConfig->GetCacheSize(cacheSize);            
+        
+        if(iDataBuffer)
+            {
+            delete iDataBuffer;
+            iDataBuffer = NULL;            
+            }
+        TRAP(status,iDataBuffer = CMMFDataBuffer::NewL( cacheSize ));
+        if(status == KErrNone)
+        	{
+        	iDataBuffer->Data().SetLength(cacheSize);
+        	}
+        }        
+
+    //status = iDataSource->FillBuffer(iTransferBuffer);
+    return status;
+    }
+
+TInt CCacheSource::Play()
+    {
+     TInt status(KErrNone);
+    DEBPRN1(_L("CCacheSource::Play"));         
+    status = iDataSource->Play();
+    return status;
+    }
+
+TInt CCacheSource::Stop()
+    {
+    TInt status(KErrNone);
+    DEBPRN1(_L("CCacheSource::Stop"));    
+    status = iDataSource->Stop();
+    iFileSize = 0;
+    iLastBufferWritten = false;
+    iAbsBufferStart = 0;
+    iAbsBufferEnd = 0;
+    iBufferReadPos = 0;
+    iSeekStart = 0;
+    iSeekEnd = 0;
+    iSnkBytes = 0;
+    iTransferBuffer->SetLastBuffer(EFalse);
+    if(iCacheType == CDataSourceConfigIntfc::EFILE)
+        {
+        iFile.Close();
+        iFs.Delete(iFileName);
+        }
+    return status;
+    }
+
+TInt CCacheSource::FillBuffer( CMMFBuffer* aBuffer )
+    {
+    TInt status(KErrNone);
+    ASSERT(aBuffer);
+    CMMFDataBuffer* dest = static_cast<CMMFDataBuffer*>( aBuffer );
+    TDes8& destBufferDes = dest->Data();
+    
+    DEBPRN4(_L("CCacheSource::FillBuffer RequestSize[%d] AbsBufEnd[%d] SnkBytes[%d]"),aBuffer->RequestSize(),iAbsBufferEnd,iSnkBytes); 
+    
+    AppendBufferToSinkQueue(dest);
+    
+    if(iCacheType == CDataSourceConfigIntfc::EFILE)
+        {
+        if(((iSnkBytes + aBuffer->RequestSize())  < iFileSize) || iLastBufferWritten)
+            {
+            status = ServiceFillBuffer();
+            }
+        else
+            {
+            if(!iLastBufferWritten)
+                {
+				iTransferBuffer->Data().FillZ();
+				iTransferBuffer->Data().SetLength(0);
+				iDataSource->FillBuffer(iTransferBuffer);                
+				}
+                
+            status = KErrUnderflow;                                
+            }        
+        }
+    else
+        {
+        if((aBuffer->RequestSize() < (iAbsBufferEnd - iAbsBufferReadPos)) || iLastBufferWritten)
+            {
+            status = ServiceFillBuffer();                
+            }
+        else
+            {
+            if(!iLastBufferWritten)                
+                {
+				iTransferBuffer->Data().FillZ();
+				iTransferBuffer->Data().SetLength(0);
+				iDataSource->FillBuffer(iTransferBuffer);                
+				}
+            
+            status = KErrUnderflow;                
+            }                                
+        }        
+    return status;
+    }
+
+TInt CCacheSource::ServiceFillBuffer()
+    {
+    TInt status(KErrNone);
+    if ( iSinkQueue->IsEmpty() )
+        return status;
+    
+    CSinkQueueItem* snkItem = iSinkQueue->First();
+    iSinkQueue->Remove(*snkItem);
+    iSnkItemsCount--;
+    CMMFBuffer* buffer = snkItem->Buffer();
+    delete snkItem;
+    
+    if(iCacheType == CDataSourceConfigIntfc::EFILE)
+        {
+        iReadRequest->SetBuffer(buffer);
+        iReadRequest->SetActive();
+        if((iSnkBytes + iReadRequest->Buffer()->RequestSize()) > iFileSize)
+            {
+            iReadRequest->Buffer()->SetLastBuffer(ETrue);    
+            }
+
+        iFile.Read(iSnkBytes,iReadRequest->Buffer()->Data(),iReadRequest->iStatus);
+        iSnkBytes += iReadRequest->Buffer()->RequestSize();
+        }
+    else
+        {
+        iReadRequest->SetBuffer(buffer);
+        
+        DEBPRN4(_L("CCacheSource::ServiceFillBuffer DataSize[%d] iBufferReadPos[%d] SnkBytes[%d]"),iDataBuffer->Data().Size(),iBufferReadPos,iSnkBytes); 
+        if((iBufferReadPos + iReadRequest->Buffer()->RequestSize()) > iAbsBufferEnd)
+            {
+            iReadRequest->Buffer()->SetLastBuffer(ETrue);    
+            }
+        
+        iDataBuffer->SetPosition(iBufferReadPos);
+        
+        if((iBufferReadPos + iReadRequest->Buffer()->RequestSize()) <= iDataBuffer->Data().Size())
+            {
+            iReadRequest->Buffer()->Data().Copy(iDataBuffer->Data().MidTPtr(iBufferReadPos,iReadRequest->Buffer()->RequestSize()));
+            iBufferReadPos += iReadRequest->Buffer()->RequestSize();
+            }
+        else
+            {
+            TInt dataToCopy = iDataBuffer->Data().Size() - iBufferReadPos;
+            iReadRequest->Buffer()->Data().Append(iDataBuffer->Data().MidTPtr(iBufferReadPos,dataToCopy));
+            iBufferReadPos = 0;
+            TInt dataLeftToCopy = iReadRequest->Buffer()->RequestSize() - dataToCopy;
+            iReadRequest->Buffer()->Data().Append(iDataBuffer->Data().MidTPtr(iBufferReadPos,dataLeftToCopy));            
+            iBufferReadPos +=  dataLeftToCopy;                   
+            DEBPRN4(_L("CCacheSource::ServiceFillBuffer dataToCopy[%d] dataLeftToCopy[%d] SnkBytes[%d]"),dataToCopy,dataLeftToCopy,iBufferReadPos);         
+            }            
+
+        iSnkBytes += iReadRequest->Buffer()->Data().Length();     
+        DEBPRN4(_L("CCacheSource::ServiceFillBuffer RequestSize[%d] iBufferReadPos[%d] SnkBytes[%d]"),iReadRequest->Buffer()->RequestSize(),iBufferReadPos,iSnkBytes);                 
+        iReadRequest->SetActive();
+        TRequestStatus* status = &(iReadRequest->iStatus);
+        User::RequestComplete(status,KErrNone);
+        }        
+    return status;        
+    }
+
+TAny* CCacheSource::CustomInterface( TUid /*aInterfaceUid*/ )
+    {
+    return NULL;    
+    }
+
+TInt CCacheSource::GetSeekingSupport( TBool& aSeekSupport )
+    {
+    aSeekSupport = ETrue;
+    return KErrNone;
+    };
+
+TInt CCacheSource::GetRandomSeekingSupport( TBool& aSeekSupport )
+    {
+    aSeekSupport = EFalse;
+    return KErrNone;
+    };
+
+// Seek Implementation
+
+TInt CCacheSource::Seek(TUint aPosInBytes)
+    {
+    TInt status(KErrNone);
+    DEBPRN2(_L("CCacheSource::Seek[%d]"),aPosInBytes);    
+    
+    if(iCacheType == CDataSourceConfigIntfc::EFILE)
+        {
+		// This is File Seek so the SeekPosition has to be less
+		// then the File Size otherwise we leave        	
+        if(aPosInBytes <= iFileSize)
+            {
+            iSnkBytes = aPosInBytes;
+            }
+        else
+            {
+            status = KErrNotReady;        
+            }
+        }
+    else
+        {
+        DEBPRN3(_L("CCacheSource::Seek AbsBufStart[%d] AbsBufEnd[%d]"),iAbsBufferStart,iAbsBufferEnd);            
+        // Here we seek in the Buffer, so we can only seek from the begining of the
+        // buffer window. which is iAbsBufferStart
+        if(aPosInBytes >= iAbsBufferStart)
+            {
+            iAbsBufferReadPos = aPosInBytes;
+            TInt seekDelta = aPosInBytes - iAbsBufferStart;
+            if(seekDelta <= (iDataBuffer->Data().MaxLength() - iSeekStart))
+                {
+                iBufferReadPos = iSeekStart + seekDelta;    
+                }
+            else
+                {
+                iBufferReadPos = seekDelta - (iDataBuffer->Data().MaxLength() - iSeekStart);    
+                }                    
+            }
+        else
+            {
+            status = KErrNotReady;    
+            }                
+        }        
+    return status;        
+    }
+
+// From CMultimediaDataSource ends
+
+TInt CCacheSource::ServiceBufferFilled( CMMFBuffer* aBuffer )
+    {
+    TInt status(KErrNone);
+    CMMFDataBuffer* dest = static_cast<CMMFDataBuffer*>( aBuffer );
+    TDes8& destBufferDes = dest->Data();
+    
+    if(iCacheType == CDataSourceConfigIntfc::EFILE)
+        {
+        iWriteRequest->SetActive();
+        iFile.Write(iFileSize,destBufferDes,iWriteRequest->iStatus);
+        iFileSize = iFileSize + dest->BufferSize();    
+        DEBPRN3(_L("CCacheSource::ServiceBufferFilled FileSize[%d] LastBuffer[%d]"),iFileSize,dest->LastBuffer());
+        if(dest->LastBuffer())
+            {
+            iLastBufferWritten = ETrue;
+            dest->SetLastBuffer(EFalse);
+            }
+        }
+    else
+        {
+        iWriteRequest->SetActive();
+
+        iDataBuffer->SetPosition(iSeekEnd);
+        
+        if((iSeekEnd + dest->BufferSize()) <= iDataBuffer->Data().MaxLength())
+            {
+            iDataBuffer->Data().Replace(iSeekEnd,dest->Data().Size(),dest->Data());
+            iSeekEnd += dest->Data().Size();
+            }
+        else
+            {
+            TInt copyEndData = iDataBuffer->Data().MaxLength() - iSeekEnd;    
+            iDataBuffer->Data().Replace(iSeekEnd,copyEndData,dest->Data().MidTPtr(0,copyEndData));
+            TInt dataLeftToCopy = dest->Data().Size() - copyEndData;
+            iSeekEnd = 0;
+            iDataBuffer->Data().Replace(iSeekEnd,dataLeftToCopy,dest->Data().MidTPtr(copyEndData,dataLeftToCopy));
+            iSeekEnd = dataLeftToCopy;
+            }            
+        
+        iAbsBufferEnd += dest->BufferSize();    
+        if(iAbsBufferEnd < iDataBuffer->Data().MaxLength())
+            {
+            iAbsBufferStart = 0;    
+            }
+        else
+            {
+            iAbsBufferStart =  iAbsBufferEnd - iDataBuffer->Data().MaxLength();   
+            }            
+        
+        if(iAbsBufferEnd < iDataBuffer->Data().MaxLength())
+            {
+            iSeekStart = 0;    
+            }
+        else
+            {
+            iSeekStart = iSeekEnd;    
+            }            
+        
+        DEBPRN4(_L("CCacheSource::ServiceBufferFilled DataSize[%d] AbsBufferEnd[%d] LastBuffer[%d]"),iDataBuffer->Data().Size(),iAbsBufferEnd,dest->LastBuffer());
+        if(dest->LastBuffer())
+            iLastBufferWritten = ETrue;            
+            
+        TRequestStatus* status = &(iWriteRequest->iStatus);
+        User::RequestComplete(status,KErrNone);
+        }        
+    return status;
+    }
+
+void CCacheSource::ReadRequestComplete(CReadWriteRequestAO* aRequest,TRequestStatus& aStatus)
+    {
+    if(aStatus != KErrNone)
+        {
+        }
+    else
+        {
+        if(aRequest->RequestType() == CReadWriteRequestAO::EReadRequest)
+            {
+            DEBPRN3(_L("CCacheSource::ReadRequestComplete [%d] [%d]"),aRequest->Buffer()->Data().Size(),aRequest->Buffer()->RequestSize());
+            iObserver->BufferFilled(aRequest->Buffer());
+            }
+        else
+            {
+			CSinkQueueItem* snkItem = iSinkQueue->First();
+			iSinkQueue->Remove(*snkItem);
+			iSnkItemsCount--;
+			CMMFBuffer* buffer = snkItem->Buffer();
+			delete snkItem;
+			FillBuffer(buffer);
+            }
+        }        
+    }
+
+
+TInt CCacheSource::AppendBufferToSinkQueue( CMMFBuffer* aBuffer )
+    {
+    TInt status(KErrNone);
+    // Add observer buffer to queue
+    CMMFDataBuffer* dest = static_cast<CMMFDataBuffer*>( aBuffer );
+    TDes8& destBufferDes = dest->Data();
+    
+    CSinkQueueItem* request(NULL);
+    
+    TRAP( status, request = CSinkQueueItem::NewL( aBuffer ) );
+    if ( status == KErrNone )
+        {
+        iSinkQueue->AddLast(*request);
+        iSnkItemsCount++;
+        }
+    return status;
+    }
+
+TInt CCacheSource::EmptySinkQueue()
+    {
+    TInt status(KErrNone);
+    // Empty sink queue
+    CSinkQueueItem* snkItem;
+    while ( !iSinkQueue->IsEmpty() )
+        {
+        snkItem = iSinkQueue->First();
+        iSinkQueue->Remove(*snkItem);
+        delete snkItem;
+        }
+    
+    iSnkItemsCount = 0;
+    return status;
+    }
+
+//From MMultimediaDataSourceObserver
+
+
+CMDataSourceObserver::CMDataSourceObserver(CMultimediaDataSource* aDataSource ,CMultimediaDataSource* aParent)
+                               :iDataSource(aDataSource)
+                               ,iParent(aParent)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CSinkQueueItem::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CMDataSourceObserver::ConstructL()
+    {
+    iDataSource->SetObserver(*this);    
+    }
+
+// -----------------------------------------------------------------------------
+// CSinkQueueItem::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CMDataSourceObserver* CMDataSourceObserver::NewL(CMultimediaDataSource* aDataSource ,CMultimediaDataSource* aParent)
+    {
+    CMDataSourceObserver* self = new(ELeave) CMDataSourceObserver( aDataSource, aParent );
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CSinkQueueItem::~CSinkQueueItem
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CMDataSourceObserver::~CMDataSourceObserver()
+    {
+    }
+
+void CMDataSourceObserver::BufferFilled( CMMFBuffer* aBuffer )
+    {
+    (static_cast<CCacheSource*>(iParent))->ServiceBufferFilled(aBuffer);        
+    }
+
+void CMDataSourceObserver::Event( TUid aEvent )
+    {
+    MMultimediaDataSourceObserver* obsvr(NULL);    
+    iParent->GetObserver(obsvr);
+    obsvr->Event(aEvent);    
+    }
+
+TInt CMDataSourceObserver::GetBitRate( TUint& aBitRate )
+    {
+    TInt status(KErrNone);
+    MMultimediaDataSourceObserver* obsvr(NULL);    
+    iParent->GetObserver(obsvr);
+    status = obsvr->GetBitRate(aBitRate);    
+    return status;
+    }
+
+// End of file