|
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 |