imaging/imagingfws/src/asyncfilewriter.cpp
changeset 0 5752a19fdefe
equal deleted inserted replaced
-1:000000000000 0:5752a19fdefe
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #if defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES)
       
    17 
       
    18 #include <f32file.h>
       
    19 
       
    20 #include "ImageClientMain.h"
       
    21 
       
    22 #include "asyncfilewriter.h"
       
    23 
       
    24 /**
       
    25    @file
       
    26    @internalComponent
       
    27 */
       
    28 
       
    29 /**
       
    30 	Simple buffer manager can be used for checking in/out memory buffers
       
    31 */
       
    32 class CBufferPool; // declared here
       
    33 NONSHARABLE_CLASS( CBufferPool ): public CBase
       
    34     {
       
    35 private:    
       
    36     enum
       
    37         {
       
    38         // defines maximum number of managed buffers, each would be aBufSize size
       
    39         EMaxNumOfBuffers = 3
       
    40         };
       
    41 public: 
       
    42     static CBufferPool* NewL(TInt aBufSize);
       
    43     ~CBufferPool();
       
    44     
       
    45     TPtr8 TakeBuffer();
       
    46     void ReleaseBuffer(const TPtrC8& aPtr);
       
    47     inline TBool HasSpareBuffers() const;
       
    48     
       
    49 private:
       
    50     explicit CBufferPool(TInt aSubBufSize);
       
    51     void ConstructL();
       
    52 
       
    53     TText8* iBufPtr[EMaxNumOfBuffers];	// array of buffer pointers 
       
    54     TBool iIsBufTaken[EMaxNumOfBuffers];// array of ETrue if the buffers is taken
       
    55     TInt iNumOfTaken;					// number of checked out buffers
       
    56     TInt iSubBufSize;					// size of a single buffer
       
    57     TText8* iBuffer;					// single contiguous buffer
       
    58     };
       
    59 
       
    60 /*static*/
       
    61 CBufferPool* CBufferPool::NewL(TInt aBufSize)
       
    62     {
       
    63     CBufferPool* self = new (ELeave) CBufferPool(aBufSize);
       
    64     CleanupStack::PushL(self);
       
    65     self->ConstructL();
       
    66 	CleanupStack::Pop(self);
       
    67     return self;
       
    68     }
       
    69 
       
    70 CBufferPool::CBufferPool(TInt aSubBufSize):
       
    71 							iSubBufSize( Align4(aSubBufSize) )
       
    72     {
       
    73     }
       
    74     
       
    75 void CBufferPool::ConstructL()
       
    76 	{
       
    77 	// allocate a buffer which is guaranteed to be aligned per TUint size boundary,
       
    78 	// so add sizeof(TUint) as precaution
       
    79 	//
       
    80     iBuffer = reinterpret_cast<TText8*>( 
       
    81                                     Align4( User::AllocL( iSubBufSize * EMaxNumOfBuffers + sizeof(TUint) ) ) 
       
    82                                );
       
    83     TText8* bufPtr = iBuffer;
       
    84     for (TInt i=0; i < EMaxNumOfBuffers; i++)
       
    85         {
       
    86         iBufPtr[ i ] = bufPtr;
       
    87         bufPtr += iSubBufSize;
       
    88         }
       
    89 	}
       
    90 
       
    91 CBufferPool::~CBufferPool()
       
    92     {
       
    93     User::Free( iBuffer );
       
    94     }
       
    95     
       
    96 inline 
       
    97 TBool CBufferPool::HasSpareBuffers() const
       
    98 	{
       
    99 	return (iNumOfTaken < EMaxNumOfBuffers);
       
   100 	}
       
   101     
       
   102 TPtr8 CBufferPool::TakeBuffer()
       
   103     {
       
   104     for (TInt i=0; i < EMaxNumOfBuffers; i++)
       
   105         {
       
   106         if ( !iIsBufTaken[i])
       
   107             {
       
   108             iIsBufTaken[i] = ETrue;
       
   109             ++iNumOfTaken;
       
   110             return TPtr8(iBufPtr[i], iSubBufSize, iSubBufSize);
       
   111             }
       
   112         }
       
   113     Panic(EBufPoolNoMoreBuffers);
       
   114     return TPtr8(NULL, 0, 0);
       
   115     }
       
   116     
       
   117 void CBufferPool::ReleaseBuffer(const TPtrC8& aPtr)
       
   118     {
       
   119     for (TInt i=0; i < EMaxNumOfBuffers; i++)
       
   120         {
       
   121         if ( iBufPtr[i] == aPtr.Ptr() )
       
   122             {
       
   123             ASSERT(iIsBufTaken[i]);
       
   124             --iNumOfTaken;
       
   125             iIsBufTaken[i] = EFalse;
       
   126             return;
       
   127             }
       
   128         }
       
   129     Panic(EBufPoolInvalidBuffer);
       
   130     }
       
   131     
       
   132     
       
   133 #ifdef WRITER_EMULATE_SLOW_MEDIA
       
   134 /*static*/
       
   135 TInt CAsyncFileWriter::TimerGate(TAny* aPtr)
       
   136 	{
       
   137 	CAsyncFileWriter* self=reinterpret_cast<CAsyncFileWriter*>(aPtr);
       
   138 	self->iFile->Write(self->iFilePos[self->iCurrentBuf], self->iBufPtr[self->iCurrentBuf], self->iStatus);	
       
   139 	self->SetActive();
       
   140 	return KErrNone;
       
   141 	}
       
   142 	
       
   143 class CCallbackTimer; //declared here
       
   144 NONSHARABLE_CLASS( CCallbackTimer ): public CTimer
       
   145 	{
       
   146 public:
       
   147 	static CCallbackTimer* NewL();
       
   148 	
       
   149 	~CCallbackTimer();
       
   150 	void After(TTimeIntervalMicroSeconds32 aCancelDelay, TCallBack aCallback);
       
   151 
       
   152 private:
       
   153 	void DoCancel();
       
   154 	CCallbackTimer();
       
   155 	// from CActive
       
   156 	void RunL();
       
   157 
       
   158 private:
       
   159 	TCallBack iCallback; 
       
   160 	};
       
   161 
       
   162 CCallbackTimer::~CCallbackTimer()
       
   163     {
       
   164     Cancel();
       
   165     }
       
   166     
       
   167 void CCallbackTimer::DoCancel()
       
   168 	{
       
   169 	CTimer::DoCancel();
       
   170 	iCallback.CallBack();
       
   171 	}
       
   172 	
       
   173 void CCallbackTimer::After(TTimeIntervalMicroSeconds32 aCancelDelay, TCallBack aCallback)
       
   174     {
       
   175     ASSERT( !IsActive() );
       
   176    	iCallback = aCallback;   
       
   177    	CTimer::After(aCancelDelay);
       
   178 	}
       
   179 
       
   180 void CCallbackTimer::RunL()
       
   181     {
       
   182     iCallback.CallBack();
       
   183     }
       
   184 
       
   185 CCallbackTimer* CCallbackTimer::NewL()
       
   186     {
       
   187    	CCallbackTimer* self=new (ELeave) CCallbackTimer();
       
   188    	CleanupStack::PushL(self);
       
   189    	self->ConstructL();
       
   190    	CleanupStack::Pop();
       
   191     return self;
       
   192     }
       
   193 
       
   194 CCallbackTimer::CCallbackTimer()
       
   195    					:CTimer(CActive::EPriorityUserInput)
       
   196 	{
       
   197    	CActiveScheduler::Add(this);
       
   198 	}
       
   199   
       
   200 #endif // WRITER_EMULATE_SLOW_MEDIA    
       
   201 
       
   202 CAsyncFileWriter* CAsyncFileWriter::NewL(MBufferWrittenObserver& aObserver, RFile& aFile, TInt aBufferSize)
       
   203     {
       
   204     CAsyncFileWriter* self=new (ELeave) CAsyncFileWriter(aObserver, aFile);
       
   205     CleanupStack::PushL( self );
       
   206     self->ConstructL( aBufferSize );
       
   207     CleanupStack::Pop( self );
       
   208     return self;
       
   209     }
       
   210 
       
   211 CAsyncFileWriter::CAsyncFileWriter(MBufferWrittenObserver& aObserver, RFile& aFile):
       
   212                                                     CActive(EPriorityNormal),
       
   213                                                     iObserver(aObserver),
       
   214                                                     iFile(&aFile)
       
   215                                     
       
   216     {
       
   217     CActiveScheduler::Add(this);
       
   218     }
       
   219     
       
   220 void CAsyncFileWriter::ConstructL(TInt aBufferSize)    
       
   221     {
       
   222     iBufferPool = CBufferPool::NewL( aBufferSize );
       
   223     
       
   224 #ifdef WRITER_EMULATE_SLOW_MEDIA    
       
   225 	iCallbackTimer = CCallbackTimer::NewL();    
       
   226 #endif	
       
   227     }
       
   228 
       
   229 CAsyncFileWriter::~CAsyncFileWriter()
       
   230     {
       
   231     Cancel();
       
   232     delete iBufferPool;
       
   233     
       
   234 #ifdef WRITER_EMULATE_SLOW_MEDIA
       
   235 	delete iCallbackTimer;
       
   236 #endif    
       
   237     }
       
   238     
       
   239 void CAsyncFileWriter::WriteBufferL(const TDesC8& aBuf,TInt aPos)
       
   240     {
       
   241     if (iNumOfPendingBuffs == KMaxNumOfBuffers)
       
   242         {
       
   243 		Panic( EAsyncWrtrQOverflow );
       
   244         }
       
   245     // place the buffer into Q
       
   246     iBufPtr[ (iCurrentBuf + iNumOfPendingBuffs ) & (KMaxNumOfBuffers - 1)  ].Set(aBuf);
       
   247     iFilePos[ (iCurrentBuf + iNumOfPendingBuffs ) & (KMaxNumOfBuffers - 1)  ] = aPos;
       
   248     if (++iNumOfPendingBuffs == 1)
       
   249         {
       
   250         ASSERT( !IsActive() );
       
   251         User::LeaveIfError( WriteNextBuffer() );
       
   252         }
       
   253     if (!iBufferPool->HasSpareBuffers())
       
   254     	{
       
   255     	TInt result = WaitForCurrentBuffer();
       
   256     	User::LeaveIfError( result );
       
   257     	HandleBufferCompletion( KErrNone );
       
   258     	}
       
   259     }
       
   260     
       
   261 TInt CAsyncFileWriter::WaitForCurrentBuffer()
       
   262     {
       
   263 #ifdef WRITER_EMULATE_SLOW_MEDIA
       
   264 // cancel delay emulation timer and kick off real writing immediately
       
   265     iCallbackTimer->Cancel();
       
   266     if (!IsActive())
       
   267         {
       
   268         TimerGate(this);
       
   269         }
       
   270 #endif
       
   271 
       
   272     Cancel();   // that would mean waiting for buffer to be written by the FServer
       
   273                 // as we have to clear RequestStatus which can be done only 
       
   274                 // by CActive
       
   275     return iStatus.Int();
       
   276     }
       
   277     
       
   278 TInt CAsyncFileWriter::WriteNextBuffer()
       
   279     {
       
   280     TInt destSize = 0;
       
   281     TInt error = iFile->Size(destSize);
       
   282     if (error != KErrNone)
       
   283         {
       
   284         return error;
       
   285         }
       
   286       //If we start writing past EOF
       
   287     if (iFilePos[iCurrentBuf] > destSize)
       
   288         {
       
   289         error = iFile->SetSize( iFilePos[iCurrentBuf] );
       
   290         }
       
   291     if (error != KErrNone)
       
   292         {
       
   293         return error;
       
   294         }
       
   295 #ifdef WRITER_EMULATE_SLOW_MEDIA
       
   296 	if (!iEmulateSlowMedia || iDelayOff)
       
   297 	{
       
   298 #endif
       
   299 
       
   300     iFile->Write(iFilePos[iCurrentBuf], iBufPtr[iCurrentBuf], iStatus);
       
   301 	SetActive();
       
   302 	
       
   303 #ifdef WRITER_EMULATE_SLOW_MEDIA
       
   304 	}
       
   305 	if (iEmulateSlowMedia && !iDelayOff)
       
   306 		{
       
   307 		iCallbackTimer->After(10000, TCallBack(TimerGate, this));	
       
   308 		}
       
   309 #endif
       
   310 
       
   311     return KErrNone;
       
   312     }
       
   313 
       
   314 void CAsyncFileWriter::CheckBufferOut(TPtr8& aBuffer)
       
   315     {
       
   316     aBuffer.Set( iBufferPool->TakeBuffer() );
       
   317     }
       
   318     
       
   319 void CAsyncFileWriter::CheckBufferIn(const TPtrC8& aBuffer)
       
   320     {
       
   321     iBufferPool->ReleaseBuffer( aBuffer );
       
   322     }
       
   323     
       
   324 TInt CAsyncFileWriter::FlushBuffers()
       
   325     {
       
   326 #ifdef WRITER_EMULATE_SLOW_MEDIA    
       
   327 	iDelayOff = ETrue;
       
   328 	iCallbackTimer->Cancel();
       
   329 #endif
       
   330 
       
   331     TInt result = KErrNone;
       
   332     while ( iNumOfPendingBuffs > 0 && result == KErrNone)
       
   333         {
       
   334         result = WaitForCurrentBuffer();
       
   335         
       
   336         CheckBufferIn(iBufPtr[iCurrentBuf]);
       
   337         
       
   338         if ( result != KErrNone)
       
   339             {
       
   340             break;
       
   341             }
       
   342         if (--iNumOfPendingBuffs != 0)
       
   343             {
       
   344             iCurrentBuf = (iCurrentBuf + 1) & (KMaxNumOfBuffers - 1);
       
   345             result = WriteNextBuffer();
       
   346             }        
       
   347         }
       
   348     return result;
       
   349     }
       
   350 
       
   351 void CAsyncFileWriter::HandleBufferCompletion(TInt aError)
       
   352     {
       
   353     if ( aError != KErrNone)
       
   354         {
       
   355         iObserver.BufferWritten(KNullDesC8(), aError );
       
   356         return;
       
   357         }
       
   358 
       
   359     TPtrC8 written( iBufPtr[iCurrentBuf] );
       
   360     iBufPtr[iCurrentBuf].Set( KNullDesC8 );
       
   361     
       
   362     TInt result = KErrNone;
       
   363     if (--iNumOfPendingBuffs != 0)
       
   364         {
       
   365         iCurrentBuf = (iCurrentBuf + 1) & (KMaxNumOfBuffers - 1);
       
   366         result = WriteNextBuffer();
       
   367         }
       
   368 
       
   369     iObserver.BufferWritten( (result == KErrNone ? written : iBufPtr[iCurrentBuf]) , result);
       
   370     }
       
   371 
       
   372 void CAsyncFileWriter::RunL()
       
   373     {
       
   374     HandleBufferCompletion(iStatus.Int());
       
   375     }
       
   376     
       
   377 void CAsyncFileWriter::DoCancel()
       
   378     {
       
   379     // we do nothing here since the File Server will complete our request
       
   380     // i.e. asynchronous File Server operations can't be cancelled
       
   381     }
       
   382 
       
   383 
       
   384 #endif // defined(SYMBIAN_ENABLE_ENCODER_ASYNC_WRITES)
       
   385