1 /* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18 /**
19 * Memory Buffer Data Stream (MBDS) class will act as the data pipe between the
20 * protocol engine node and the file format parsing node.
21 * This will write the data from the protocol engine in a memoery for later reading by the
22 * file format parsing node.
23 */
24
25 #ifndef OSCL_EXCEPTION_H_INCLUDED
26 #include "oscl_exception.h"
27 #endif
28 #ifndef PVMF_MEMORYBUFFERDATASTREAM_FACTORY_H_INCLUDED
29 #include "pvmf_memorybufferdatastream_factory.h"
30 #endif
31 #ifndef OSCL_TICKCOUNT_H_INCLUDED
32 #include "oscl_tickcount.h"
33 #endif
34
35 // Logging #define
36 #define LOGDEBUG(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_VERBOSE, m);
37 #define LOGERROR(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, m);
38 #define LOGTRACE(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, m);
39
40 //////////////////////////////////////////////////////////////////////
41 // PVMFMemoryBufferReadDataStreamFactoryImpl
42 //////////////////////////////////////////////////////////////////////
43 OSCL_EXPORT_REF
PVMFMemoryBufferReadDataStreamFactoryImpl(PVMFMemoryBufferDataStreamTempCache * aTempCache,PVMFMemoryBufferDataStreamPermCache * aPermCache)44 PVMFMemoryBufferReadDataStreamFactoryImpl::PVMFMemoryBufferReadDataStreamFactoryImpl(PVMFMemoryBufferDataStreamTempCache* aTempCache,
45 PVMFMemoryBufferDataStreamPermCache* aPermCache)
46 {
47 // store the cache pointer
48 iTempCache = aTempCache;
49 iPermCache = aPermCache;
50 iDownloadComplete = false;
51 }
52
53 OSCL_EXPORT_REF void
SetWriteDataStreamPtr(PVInterface * aWriteDataStream)54 PVMFMemoryBufferReadDataStreamFactoryImpl::SetWriteDataStreamPtr(PVInterface* aWriteDataStream)
55 {
56 // Called by PVMFMemoryBufferDataStream constructor
57 if (aWriteDataStream)
58 {
59 iWriteDataStream = OSCL_STATIC_CAST(PVMFMemoryBufferWriteDataStreamImpl*, aWriteDataStream);
60 }
61 }
62
63 OSCL_EXPORT_REF PVMFStatus
QueryAccessInterfaceUUIDs(Oscl_Vector<PVUuid,OsclMemAllocator> & aUuids)64 PVMFMemoryBufferReadDataStreamFactoryImpl::QueryAccessInterfaceUUIDs(Oscl_Vector<PVUuid, OsclMemAllocator>& aUuids)
65 {
66 aUuids.push_back(PVMIDataStreamSyncInterfaceUuid);
67 return PVMFSuccess;
68 }
69
70 OSCL_EXPORT_REF PVInterface*
CreatePVMFCPMPluginAccessInterface(PVUuid & aUuid)71 PVMFMemoryBufferReadDataStreamFactoryImpl::CreatePVMFCPMPluginAccessInterface(PVUuid& aUuid)
72 {
73 // Create a new PVMFMemoryBufferReadDataStreamFactoryImpl for each request
74 // Can have up to PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS connections
75 if (aUuid == PVMIDataStreamSyncInterfaceUuid)
76 {
77 PVMFMemoryBufferReadDataStreamImpl* ReadStream = NULL;
78 ReadStream = OSCL_NEW(PVMFMemoryBufferReadDataStreamImpl, (iWriteDataStream, iTempCache, iPermCache));
79 if (ReadStream == NULL)
80 {
81 OSCL_LEAVE(OsclErrNoMemory);
82 }
83 ReadStream->iDownloadComplete = iDownloadComplete;
84 // save this connection in list
85 iReadStreamVec.push_back(ReadStream);
86 return OSCL_STATIC_CAST(PVInterface*, ReadStream);
87 }
88 return NULL;
89 }
90
91 OSCL_EXPORT_REF void
DestroyPVMFCPMPluginAccessInterface(PVUuid & aUuid,PVInterface * aPtr)92 PVMFMemoryBufferReadDataStreamFactoryImpl::DestroyPVMFCPMPluginAccessInterface(PVUuid& aUuid,
93 PVInterface* aPtr)
94 {
95 // Destroy the incoming object only if it uses the right UUID and has a vaild pointer
96 if ((aUuid == PVMIDataStreamSyncInterfaceUuid) && (aPtr))
97 {
98 // Cast the incoming ptr to the correct type, then delete
99 PVMFMemoryBufferReadDataStreamImpl* iReadStream = NULL;
100 iReadStream = OSCL_STATIC_CAST(PVMFMemoryBufferReadDataStreamImpl*, aPtr);
101 // Remove from list
102 Oscl_Vector<PVMFMemoryBufferReadDataStreamImpl*, OsclMemAllocator>::iterator it;
103 it = iReadStreamVec.begin();
104 while (it != iReadStreamVec.end())
105 {
106 if (*it == aPtr)
107 {
108 iReadStreamVec.erase(it);
109 break;
110 }
111 else
112 {
113 it++;
114 }
115 }
116 OSCL_DELETE(iReadStream);
117 }
118 }
119
120 OSCL_EXPORT_REF void
NotifyDownloadComplete()121 PVMFMemoryBufferReadDataStreamFactoryImpl::NotifyDownloadComplete()
122 {
123 iDownloadComplete = true;
124
125 Oscl_Vector<PVMFMemoryBufferReadDataStreamImpl*, OsclMemAllocator>::iterator it;
126 // Notify all read connections
127 for (it = iReadStreamVec.begin(); it != iReadStreamVec.end(); it++)
128 {
129 (*it)->NotifyDownloadComplete();
130 }
131 }
132
133
134 //////////////////////////////////////////////////////////////////////
135 // PVMFMemoryBufferWriteDataStreamFactoryImpl
136 //////////////////////////////////////////////////////////////////////
137 OSCL_EXPORT_REF
PVMFMemoryBufferWriteDataStreamFactoryImpl(PVMFMemoryBufferDataStreamTempCache * aTempCache,PVMFMemoryBufferDataStreamPermCache * aPermCache,MBDSStreamFormat aStreamFormat,uint32 aTempCacheCapacity)138 PVMFMemoryBufferWriteDataStreamFactoryImpl::PVMFMemoryBufferWriteDataStreamFactoryImpl(PVMFMemoryBufferDataStreamTempCache* aTempCache,
139 PVMFMemoryBufferDataStreamPermCache* aPermCache, MBDSStreamFormat aStreamFormat, uint32 aTempCacheCapacity)
140 {
141 // Init to NULL for later creation in CreatePVMFCPMPluginAccessInterface()
142 iWriteDataStream = NULL;
143 // store the cache pointer
144 iTempCache = aTempCache;
145 iPermCache = aPermCache;
146 iDownloadComplete = false;
147 iStreamFormat = aStreamFormat;
148 iTempCacheCapacity = aTempCacheCapacity;
149 }
150
151 OSCL_EXPORT_REF
~PVMFMemoryBufferWriteDataStreamFactoryImpl()152 PVMFMemoryBufferWriteDataStreamFactoryImpl::~PVMFMemoryBufferWriteDataStreamFactoryImpl()
153 {
154 if (iWriteDataStream)
155 {
156 OSCL_DELETE(iWriteDataStream);
157 }
158 }
159
160 OSCL_EXPORT_REF PVMFStatus
QueryAccessInterfaceUUIDs(Oscl_Vector<PVUuid,OsclMemAllocator> & aUuids)161 PVMFMemoryBufferWriteDataStreamFactoryImpl::QueryAccessInterfaceUUIDs(Oscl_Vector<PVUuid, OsclMemAllocator>& aUuids)
162 {
163 aUuids.push_back(PVMIDataStreamSyncInterfaceUuid);
164 return PVMFSuccess;
165 }
166
167 OSCL_EXPORT_REF PVInterface*
CreatePVMFCPMPluginAccessInterface(PVUuid & aUuid)168 PVMFMemoryBufferWriteDataStreamFactoryImpl::CreatePVMFCPMPluginAccessInterface(PVUuid& aUuid)
169 {
170 if (aUuid == PVMIDataStreamSyncInterfaceUuid)
171 {
172 // iWriteDataStream should have only one instance.
173 if (!iWriteDataStream)
174 {
175 // It does not exist so allocate
176 iWriteDataStream = OSCL_NEW(PVMFMemoryBufferWriteDataStreamImpl, (iTempCache, iPermCache, iStreamFormat, iTempCacheCapacity));
177 if (iWriteDataStream == NULL)
178 {
179 OSCL_LEAVE(OsclErrNoMemory);
180 }
181 }
182 // Return the ptr to the iWriteDataStream
183 return OSCL_STATIC_CAST(PVInterface*, iWriteDataStream);
184 }
185 return NULL;
186 }
187
188 OSCL_EXPORT_REF void
DestroyPVMFCPMPluginAccessInterface(PVUuid & aUuid,PVInterface * aPtr)189 PVMFMemoryBufferWriteDataStreamFactoryImpl::DestroyPVMFCPMPluginAccessInterface(PVUuid& aUuid,
190 PVInterface* aPtr)
191 {
192 // Do nothing
193 OSCL_UNUSED_ARG(aUuid);
194 OSCL_UNUSED_ARG(aPtr);
195 }
196
197 OSCL_EXPORT_REF void
NotifyDownloadComplete()198 PVMFMemoryBufferWriteDataStreamFactoryImpl::NotifyDownloadComplete()
199 {
200 iDownloadComplete = true;
201 iWriteDataStream->NotifyDownloadComplete();
202 }
203
204 //////////////////////////////////////////////////////////////////////
205 // PVMFMemoryBufferReadDataStreamImpl
206 //////////////////////////////////////////////////////////////////////
207 OSCL_EXPORT_REF
PVMFMemoryBufferReadDataStreamImpl(PVMFMemoryBufferWriteDataStreamImpl * aWriteDataStream,PVMFMemoryBufferDataStreamTempCache * aTempCache,PVMFMemoryBufferDataStreamPermCache * aPermCache)208 PVMFMemoryBufferReadDataStreamImpl::PVMFMemoryBufferReadDataStreamImpl(PVMFMemoryBufferWriteDataStreamImpl* aWriteDataStream,
209 PVMFMemoryBufferDataStreamTempCache* aTempCache,
210 PVMFMemoryBufferDataStreamPermCache* aPermCache)
211 {
212 iDownloadComplete = false;
213 iWriteDataStream = aWriteDataStream;
214 iSessionID = 0;
215 iFilePtrPos = 0;
216 iReadSessionOpened = false;
217
218 // save the pointer to the cache
219 iTempCache = aTempCache;
220 iPermCache = aPermCache;
221
222 iLogger = PVLogger::GetLoggerObject("PVMFMemoryBufferDataStream");
223
224 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::PVMFMemoryBufferReadDataStreamImpl"));
225 }
226
227
228 OSCL_EXPORT_REF
~PVMFMemoryBufferReadDataStreamImpl()229 PVMFMemoryBufferReadDataStreamImpl::~PVMFMemoryBufferReadDataStreamImpl()
230 {
231 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::~PVMFMemoryBufferReadDataStreamImpl"));
232
233 if (iReadSessionOpened)
234 {
235 // need to close the session
236 iWriteDataStream->CloseSession(iSessionID);
237 }
238 iLogger = NULL;
239 }
240
241
242 OSCL_EXPORT_REF bool
queryInterface(const PVUuid & uuid,PVInterface * & iface)243 PVMFMemoryBufferReadDataStreamImpl::queryInterface(const PVUuid& uuid, PVInterface*& iface)
244 {
245 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::queryInterface"));
246
247 iface = NULL;
248 if (uuid == PVMIDataStreamSyncInterfaceUuid)
249 {
250 PVMIDataStreamSyncInterface* myInterface = OSCL_STATIC_CAST(PVMIDataStreamSyncInterface*, this);
251 iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
252 return true;
253 }
254 return false;
255 }
256
257
258 OSCL_EXPORT_REF PvmiDataStreamStatus
OpenSession(PvmiDataStreamSession & aSessionID,PvmiDataStreamMode aMode,bool nonblocking)259 PVMFMemoryBufferReadDataStreamImpl::OpenSession(PvmiDataStreamSession& aSessionID, PvmiDataStreamMode aMode,
260 bool nonblocking)
261 {
262 OSCL_UNUSED_ARG(nonblocking);
263 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::OpenSession"));
264
265 PvmiDataStreamStatus status = PVDS_SUCCESS;
266 // Can only open session once
267 if (iReadSessionOpened)
268 {
269 status = PVDS_INVALID_REQUEST;
270 }
271 else
272 {
273 // Only support read-only mode
274 if (aMode != PVDS_READ_ONLY)
275 {
276 status = PVDS_UNSUPPORTED_MODE;
277 }
278 else
279 {
280 aSessionID = 0;
281 iReadSessionOpened = true;
282 // Set current file position pointer to the beginning of the file
283 iFilePtrPos = 0;
284 // Register with the write data stream
285 if (iSessionID == 0)
286 {
287 // open one now
288 status = iWriteDataStream->OpenReadSession(iSessionID, PVDS_READ_ONLY, false, this);
289 }
290 }
291 }
292
293 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::OpenSession - returning %d session %d", status, iSessionID));
294 return status;
295 }
296
297 OSCL_EXPORT_REF PvmiDataStreamStatus
CloseSession(PvmiDataStreamSession aSessionID)298 PVMFMemoryBufferReadDataStreamImpl::CloseSession(PvmiDataStreamSession aSessionID)
299 {
300 OSCL_UNUSED_ARG(aSessionID);
301 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::CloseSession session %d", iSessionID));
302
303 PvmiDataStreamStatus status = PVDS_SUCCESS;
304 if (!iReadSessionOpened)
305 {
306 status = PVDS_INVALID_REQUEST;
307 }
308 else
309 {
310 iReadSessionOpened = false;
311
312 iWriteDataStream->CloseSession(iSessionID);
313 }
314
315 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::CloseSession - returning %d", status));
316 return status;
317 }
318
319
320 OSCL_EXPORT_REF PvmiDataStreamRandomAccessType
QueryRandomAccessCapability()321 PVMFMemoryBufferReadDataStreamImpl::QueryRandomAccessCapability()
322 {
323 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::QueryRandomAccessCapability"));
324 return PVDS_FULL_RANDOM_ACCESS;
325 }
326
327
328 OSCL_EXPORT_REF PvmiDataStreamStatus
QueryReadCapacity(PvmiDataStreamSession aSessionID,uint32 & aCapacity)329 PVMFMemoryBufferReadDataStreamImpl::QueryReadCapacity(PvmiDataStreamSession aSessionID,
330 uint32& aCapacity)
331 {
332 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::QueryReadCapacity"));
333
334 PvmiDataStreamStatus status = PVDS_SUCCESS;
335 // OpenSession needs to be called first
336 if (!iReadSessionOpened)
337 {
338 status = PVDS_INVALID_REQUEST;
339 }
340 else
341 {
342 // Return the number of bytes that is available for reading
343 // i.e. from the current file pointer position to the last byte that has been written to the file so far
344
345 // Get the current file position
346 uint32 currFilePosition = GetCurrentPointerPosition(aSessionID);
347 uint32 lastFilePosition = 0;
348
349 // Determine the file size from write datastream.
350 status = iWriteDataStream->QueryReadCapacity(iSessionID, lastFilePosition);
351 if (PVDS_SUCCESS == status)
352 {
353 // Calculate the capacity from these two positions.
354 aCapacity = (lastFilePosition - currFilePosition) + 1;
355 }
356 if (iDownloadComplete == true)
357 {
358 status = PVDS_END_OF_STREAM;
359 }
360 }
361
362 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::QueryReadCapacity returning %d", status));
363 return status;
364 }
365
366
367 OSCL_EXPORT_REF PvmiDataStreamCommandId
RequestReadCapacityNotification(PvmiDataStreamSession aSessionID,PvmiDataStreamObserver & aObserver,uint32 aCapacity,OsclAny * aContextData)368 PVMFMemoryBufferReadDataStreamImpl::RequestReadCapacityNotification(PvmiDataStreamSession aSessionID,
369 PvmiDataStreamObserver& aObserver, uint32 aCapacity,
370 OsclAny* aContextData)
371 {
372 OSCL_UNUSED_ARG(aSessionID);
373 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::RequestReadCapacityNotification"));
374
375 // Check for an open session to write data stream
376 // iSession contains the session id returned from opening a read session with the wrtie data stream
377 if (iSessionID == 0)
378 {
379 // open one now
380 PvmiDataStreamStatus result = iWriteDataStream->OpenSession(iSessionID, PVDS_READ_ONLY, false);
381 if (result != PVDS_SUCCESS)
382 {
383 // No READ sessions left
384 OSCL_LEAVE(OsclErrNoResources);
385 }
386 }
387 // Trap the error from the RequestReadCapacityNotification
388 PvmiDataStreamCommandId commandID = 0;
389 int32 error = 0;
390 OSCL_TRY(error, commandID = iWriteDataStream->RequestReadCapacityNotification(iSessionID, aObserver,
391 aCapacity, aContextData));
392 if (error)
393 {
394 OSCL_LEAVE(error);
395 }
396
397 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::RequestReadCapacityNotification returning %d", commandID));
398 return commandID;
399 }
400
401
402 OSCL_EXPORT_REF PvmiDataStreamStatus
QueryWriteCapacity(PvmiDataStreamSession aSessionID,uint32 & aCapacity)403 PVMFMemoryBufferReadDataStreamImpl::QueryWriteCapacity(PvmiDataStreamSession aSessionID, uint32& aCapacity)
404 {
405 OSCL_UNUSED_ARG(aSessionID);
406 OSCL_UNUSED_ARG(aCapacity);
407 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::QueryWriteCapacity"));
408
409 // no writing in a read stream
410 return PVDS_NOT_SUPPORTED;
411 }
412
413
414 OSCL_EXPORT_REF PvmiDataStreamCommandId
RequestWriteCapacityNotification(PvmiDataStreamSession aSessionID,PvmiDataStreamObserver & aObserver,uint32 aCapacity,OsclAny * aContextData)415 PVMFMemoryBufferReadDataStreamImpl::RequestWriteCapacityNotification(PvmiDataStreamSession aSessionID,
416 PvmiDataStreamObserver& aObserver,
417 uint32 aCapacity, OsclAny* aContextData)
418 {
419 OSCL_UNUSED_ARG(aSessionID);
420 OSCL_UNUSED_ARG(aObserver);
421 OSCL_UNUSED_ARG(aCapacity);
422 OSCL_UNUSED_ARG(aContextData);
423 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::RequestWriteCapacityNotification"));
424
425 // no writing in a read stream
426 OSCL_LEAVE(OsclErrNotSupported);
427 // to satisfy the compiler
428 return 0;
429 }
430
431
432 OSCL_EXPORT_REF PvmiDataStreamCommandId
CancelNotification(PvmiDataStreamSession aSessionID,PvmiDataStreamObserver & aObserver,PvmiDataStreamCommandId aID,OsclAny * aContextData)433 PVMFMemoryBufferReadDataStreamImpl::CancelNotification(PvmiDataStreamSession aSessionID,
434 PvmiDataStreamObserver& aObserver,
435 PvmiDataStreamCommandId aID,
436 OsclAny* aContextData)
437 {
438 OSCL_UNUSED_ARG(aSessionID);
439 OSCL_UNUSED_ARG(aObserver);
440 OSCL_UNUSED_ARG(aID);
441 OSCL_UNUSED_ARG(aContextData);
442 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::CancelNotification"));
443
444 // asynch version is not supported
445 OSCL_LEAVE(OsclErrNotSupported);
446 // satisfy compiler
447 return 0;
448 }
449
450
451 OSCL_EXPORT_REF PvmiDataStreamStatus
CancelNotificationSync(PvmiDataStreamSession aSessionID)452 PVMFMemoryBufferReadDataStreamImpl::CancelNotificationSync(PvmiDataStreamSession aSessionID)
453 {
454 OSCL_UNUSED_ARG(aSessionID);
455 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::CancelNotificationSync"));
456
457 return iWriteDataStream->CancelNotificationSync(iSessionID);
458 }
459
460 // The perm cache and the temp cache are treated as separate entities
461 // Always look in the perm cache first, if not in perm cache, then look in the temp cache
462 // However, if only a part of the data is in one cache, we do not expect to look into the other cache for the rest
463 OSCL_EXPORT_REF PvmiDataStreamStatus
Read(PvmiDataStreamSession aSessionID,uint8 * aBuffer,uint32 aSize,uint32 & aNumElements)464 PVMFMemoryBufferReadDataStreamImpl::Read(PvmiDataStreamSession aSessionID, uint8* aBuffer,
465 uint32 aSize, uint32& aNumElements)
466 {
467 OSCL_UNUSED_ARG(aSessionID);
468 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::Read session %d offset %d size %d", iSessionID, iFilePtrPos, aSize * aNumElements));
469
470 // OpenSession needs to be called first
471 if (!iReadSessionOpened)
472 {
473 return PVDS_INVALID_REQUEST;
474 }
475
476 // Reading from the current file pointer position
477 uint32 bytesToRead = aSize * aNumElements;
478
479 // Check the content range in cache
480 uint32 firstByteToRead = iFilePtrPos;
481 uint32 lastByteToRead = iFilePtrPos + bytesToRead - 1;
482
483 uint32 numPermEntries = iPermCache->GetNumEntries();
484 uint32 firstPermByteOffset = 0;
485 uint32 lastPermByteOffset = 0;
486 iPermCache->GetFileOffsets(firstPermByteOffset, lastPermByteOffset);
487
488 uint32 numTempEntries = iTempCache->GetNumEntries();
489 uint32 firstTempByteOffset = 0;
490 uint32 lastTempByteOffset = 0;
491 iTempCache->GetFileOffsets(firstTempByteOffset, lastTempByteOffset);
492
493 // for debugging only
494 //LOGERROR((0, "PVMFMemoryBufferReadDataStreamImpl::Read session %d offset %d size %d firstTempByteOffset %d lastTempByteOffset %d",
495 // iSessionID, iFilePtrPos, aSize * aNumElements, firstTempByteOffset, lastTempByteOffset));
496
497 uint32 bytesRead = 0;
498 uint32 firstEntry = 0;
499
500 bool inTempCache = true;
501
502 // Look at the perm cache first
503 if ((0 == numPermEntries) || ((firstByteToRead < firstPermByteOffset) || (firstByteToRead >= lastPermByteOffset)))
504 {
505 // not in perm cache, look in temp cache
506 if ((0 == numTempEntries) || ((firstByteToRead < firstTempByteOffset) || (firstByteToRead > lastTempByteOffset)))
507 {
508 // First byte not in the temp cache
509 // Find out if it is on route to the cache, if so, no need to send reposition request
510 // But if the cache is full, we need to send reposition request
511 if ((firstByteToRead < firstTempByteOffset) || ((firstByteToRead - lastTempByteOffset) > PV_MBDS_BYTES_TO_WAIT) ||
512 (((firstByteToRead - lastTempByteOffset) <= PV_MBDS_BYTES_TO_WAIT) && ((lastTempByteOffset - firstTempByteOffset + 1) >= iWriteDataStream->GetTempCacheCapacity())))
513 {
514 LOGDEBUG((0, "PVMFMemoryBufferReadDataStreamImpl::Read Reposition first %d last %d session %d offset %d",
515 firstTempByteOffset, lastTempByteOffset, iSessionID, firstByteToRead));
516
517 // Send a reposition request to the writer
518 // Cache should be trimmed to some degree to free buffers for new connection, etc
519 // Return a read failure to reader
520 PvmiDataStreamStatus status = iWriteDataStream->Reposition(iSessionID, firstByteToRead, MBDS_REPOSITION_WITH_MARGIN);
521 if (PVDS_SUCCESS == status)
522 {
523 iWriteDataStream->TrimTempCache(MBDS_CACHE_TRIM_HEAD_AND_TAIL);
524 }
525 }
526 // Fail this read
527 aNumElements = 0;
528 return PVDS_FAILURE;
529 }
530 // First byte is in temp cache
531 if (lastTempByteOffset < lastByteToRead)
532 {
533 // Not all the bytes are in the temp cache, copy what is there
534 bytesRead = iTempCache->ReadBytes(aBuffer, firstByteToRead, lastTempByteOffset, firstEntry);
535 }
536 else
537 {
538 // All the bytes are in the cache
539 bytesRead = iTempCache->ReadBytes(aBuffer, firstByteToRead, lastByteToRead, firstEntry);
540 }
541 }
542 else
543 {
544 inTempCache = false;
545 // At least part of the data is in the perm cache
546 if (lastPermByteOffset < lastByteToRead)
547 {
548 // Not all the bytes are in the perm cache, copy what is there
549 bytesRead = iPermCache->ReadBytes(aBuffer, firstByteToRead, lastPermByteOffset);
550 }
551 else
552 {
553 // All the bytes are in the perm cache
554 bytesRead = iPermCache->ReadBytes(aBuffer, firstByteToRead, lastByteToRead);
555 }
556 }
557
558 iFilePtrPos += bytesRead;
559 aNumElements = bytesRead / aSize;
560
561 iWriteDataStream->SetReadPointerCacheLocation(iSessionID, inTempCache);
562 iWriteDataStream->SetReadPointerPosition(iSessionID, iFilePtrPos);
563
564 if (0 != bytesRead && 0 != firstEntry)
565 {
566 // there may be some entries in the cache that can be released
567 iWriteDataStream->ManageCache();
568 }
569 if (bytesToRead != bytesRead)
570 {
571 LOGDEBUG((0, "***** bytesToRead %d != bytesRead %d", bytesToRead, bytesRead));
572 }
573
574 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::Read session %d returning %d", iSessionID, aNumElements));
575 return PVDS_SUCCESS;
576 }
577
578
579 OSCL_EXPORT_REF PvmiDataStreamStatus
Write(PvmiDataStreamSession aSessionID,uint8 * aBuffer,uint32 aSize,uint32 & aNumElements)580 PVMFMemoryBufferReadDataStreamImpl::Write(PvmiDataStreamSession aSessionID, uint8* aBuffer,
581 uint32 aSize, uint32& aNumElements)
582 {
583 OSCL_UNUSED_ARG(aSessionID);
584 OSCL_UNUSED_ARG(aBuffer);
585 OSCL_UNUSED_ARG(aSize);
586 OSCL_UNUSED_ARG(aNumElements);
587 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::Write"));
588
589 // Write not supported in the PVMFMemoryBufferReadDataStreamImpl object
590 return PVDS_NOT_SUPPORTED;
591 }
592
593 OSCL_EXPORT_REF PvmiDataStreamStatus
Write(PvmiDataStreamSession aSessionID,OsclRefCounterMemFrag * aFrag,uint32 & aNumElements)594 PVMFMemoryBufferReadDataStreamImpl::Write(PvmiDataStreamSession aSessionID, OsclRefCounterMemFrag* aFrag, uint32& aNumElements)
595 {
596 OSCL_UNUSED_ARG(aSessionID);
597 OSCL_UNUSED_ARG(aFrag);
598 OSCL_UNUSED_ARG(aNumElements);
599 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::Write"));
600
601 // Write not supported in the PVMFMemoryBufferReadDataStreamImpl object
602 return PVDS_NOT_SUPPORTED;
603 }
604
605 OSCL_EXPORT_REF PvmiDataStreamStatus
Seek(PvmiDataStreamSession aSessionID,int32 aOffset,PvmiDataStreamSeekType aOrigin)606 PVMFMemoryBufferReadDataStreamImpl::Seek(PvmiDataStreamSession aSessionID, int32 aOffset, PvmiDataStreamSeekType aOrigin)
607 {
608 OSCL_UNUSED_ARG(aSessionID);
609
610 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::Seek session %d offset %d origin %d", iSessionID, aOffset, aOrigin));
611
612 PvmiDataStreamStatus status = PVDS_SUCCESS;
613
614 // OpenSession needs to be called first
615 if (!iReadSessionOpened)
616 {
617 status = PVDS_INVALID_REQUEST;
618 }
619 else
620 {
621 // For now, seek changes the read position pointer,
622 // but not the content of the cache, i.e. if the read position pointer is outside of the cache
623 // repostion request is not issued until a read is done.
624 // The downside is that there will be a delay in reading if the pointer is far out.
625 // The upside is that if the pointer is slighttly ahead, no reposition request may be needed
626 // as more data is coming from the server.
627 // If the requested offset is far from the current offset, should trigger a reposition request now.
628 // Make sure not seeking beyond end of clip if content length is known
629
630 uint32 contentLength = iWriteDataStream->GetContentLength();
631 bool skip = false;
632 uint32 skipTo = 0;
633
634 switch (aOrigin)
635 {
636 case PVDS_SEEK_SET:
637 if ((0 != contentLength) && ((uint32)aOffset >= contentLength))
638 {
639 status = PVDS_FAILURE;
640 }
641 else
642 {
643 iFilePtrPos = aOffset;
644 }
645 break;
646
647 case PVDS_SEEK_CUR:
648 if ((0 != contentLength) && ((iFilePtrPos + aOffset) >= contentLength))
649 {
650 status = PVDS_FAILURE;
651 }
652 else
653 {
654 iFilePtrPos += aOffset;
655 }
656 break;
657
658 case PVDS_SEEK_END:
659 if ((0 == contentLength) || (contentLength <= (uint32)aOffset))
660 {
661 // contentLength is not known, fail the seek
662 // if known, do not seek beyond beginning of clip
663 status = PVDS_FAILURE;
664 }
665 else
666 {
667 iFilePtrPos = contentLength - aOffset - 1;
668 }
669 break;
670
671 case PVDS_SKIP_SET:
672 if ((0 != contentLength) && ((uint32)aOffset >= contentLength))
673 {
674 status = PVDS_FAILURE;
675 }
676 else
677 {
678 skipTo = aOffset;
679 skip = true;
680 }
681 break;
682
683 case PVDS_SKIP_CUR:
684 if ((0 != contentLength) && ((iFilePtrPos + aOffset) >= contentLength))
685 {
686 status = PVDS_FAILURE;
687 }
688 else
689 {
690 skipTo = iFilePtrPos + aOffset;
691 skip = true;
692 }
693 break;
694
695 case PVDS_SKIP_END:
696 if ((0 == contentLength) || (contentLength <= (uint32)aOffset))
697 {
698 // contentLength is not known, fail the skip
699 // if known, do not skip beyond beginning of clip
700 status = PVDS_FAILURE;
701 }
702 else
703 {
704 skipTo = contentLength - aOffset - 1;
705 skip = true;
706 }
707 break;
708
709 default:
710 status = PVDS_FAILURE;
711 break;
712 }
713
714 if (PVDS_SUCCESS == status)
715 {
716 if (false == skip)
717 {
718 // seek should not change the cache location
719 iWriteDataStream->SetReadPointerPosition(iSessionID, iFilePtrPos);
720 }
721 else
722 {
723 // If seeking backwards, data will never come with a reposition request
724 uint32 firstTempByteOffset = 0;
725 uint32 lastTempByteOffset = 0;
726 iTempCache->GetFileOffsets(firstTempByteOffset, lastTempByteOffset);
727
728 if ((skipTo >= firstTempByteOffset) &&
729 (lastTempByteOffset + PV_MBDS_FWD_SEEKING_NO_GET_REQUEST_THRESHOLD >= skipTo))
730 {
731 // Seeking forward,, eed to see if the data may be coming shortly before sending request
732 // If the temp cache is full, send the request right away
733 uint32 capacity = 0;
734 iWriteDataStream->QueryWriteCapacity(0, capacity);
735 if (capacity > 64000)
736 {
737 // Check if the data for new offset will eventually come and that there is room
738 // in the cache for it. If there is no room and no more reads are issued by the parser,
739 // no buffers will be released and there will be a deadlock
740 if ((lastTempByteOffset + capacity) > (skipTo + PV_MBDS_BYTES_TO_WAIT))
741 {
742 // data is coming, no need to send request
743 LOGDEBUG((0, "PVMFMemoryBufferReadDataStreamImpl::Seek/Skip data is expected shortly session %d offset %d", iSessionID, skipTo));
744 skip = false;
745 }
746 }
747 }
748 if (skip)
749 {
750 LOGDEBUG((0, "PVMFMemoryBufferReadDataStreamImpl::Seek/Skip Reposition session %d offset %d",
751 iSessionID, skipTo));
752
753 // Send a reposition request to the writer
754 status = iWriteDataStream->Reposition(iSessionID, skipTo, MBDS_REPOSITION_WITH_MARGIN);
755 }
756 }
757 }
758 }
759
760 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::Seek returning %d", status));
761 return status;
762 }
763
764 OSCL_EXPORT_REF uint32
GetCurrentPointerPosition(PvmiDataStreamSession aSessionID)765 PVMFMemoryBufferReadDataStreamImpl::GetCurrentPointerPosition(PvmiDataStreamSession aSessionID)
766 {
767 OSCL_UNUSED_ARG(aSessionID);
768
769 uint32 pos = 0;
770
771 // OpenSession needs to be called first
772 if (iReadSessionOpened)
773 {
774 pos = iFilePtrPos;
775 }
776
777 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::GetCurrentPointerPosition returning %d", pos));
778 return pos;
779 }
780
781
782 OSCL_EXPORT_REF PvmiDataStreamStatus
Flush(PvmiDataStreamSession aSessionID)783 PVMFMemoryBufferReadDataStreamImpl::Flush(PvmiDataStreamSession aSessionID)
784 {
785 OSCL_UNUSED_ARG(aSessionID);
786
787 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::Flush"));
788
789 // Nothing to do
790 return PVDS_SUCCESS;
791 }
792
793
794 OSCL_EXPORT_REF void
NotifyDownloadComplete()795 PVMFMemoryBufferReadDataStreamImpl::NotifyDownloadComplete()
796 {
797 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::NotifyDownloadComplete"));
798
799 iDownloadComplete = true;
800 }
801
802
803 OSCL_EXPORT_REF uint32
GetContentLength()804 PVMFMemoryBufferReadDataStreamImpl::GetContentLength()
805 {
806 // returning length of media, if known
807 uint32 length = 0;
808 if (NULL != iWriteDataStream)
809 {
810 length = iWriteDataStream->GetContentLength();
811 }
812
813 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::GetContentLength returning %d", length));
814 return length;
815 }
816
817
818 OSCL_EXPORT_REF PvmiDataStreamStatus
SetSourceRequestObserver(PvmiDataStreamRequestObserver & aObserver)819 PVMFMemoryBufferReadDataStreamImpl::SetSourceRequestObserver(PvmiDataStreamRequestObserver& aObserver)
820 {
821 OSCL_UNUSED_ARG(aObserver);
822
823 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::SetRequestObserver"));
824
825 // not supoprted for read streams
826 return PVDS_NOT_SUPPORTED;
827 }
828
829
SetBufferingCapacityAndTrimMargin(uint32 aMinCapacity,uint32 aTrimMargin)830 OSCL_EXPORT_REF PvmiDataStreamStatus PVMFMemoryBufferReadDataStreamImpl::SetBufferingCapacityAndTrimMargin(uint32 aMinCapacity, uint32 aTrimMargin)
831 {
832 if (NULL == iWriteDataStream)
833 {
834 LOGERROR((0,"PVMFMemoryBufferReadDataStreamImpl::SetBufferingCapacityAndTrimMargin failed - no write data stream.\n"));
835 return PVDS_FAILURE;
836 }
837
838 return iWriteDataStream->SetBufferingCapacityAndTrimMargin(aMinCapacity, aTrimMargin);
839 }
840
841
842 OSCL_EXPORT_REF uint32
QueryBufferingCapacity()843 PVMFMemoryBufferReadDataStreamImpl::QueryBufferingCapacity()
844 {
845 // return size of sliding window
846 uint32 capacity = 0;
847 if (NULL != iWriteDataStream)
848 {
849 capacity = iWriteDataStream->QueryBufferingCapacity();
850 }
851
852 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::QueryBufferingCapacity returning %d", capacity));
853 return capacity;
854 }
855
856
QueryBufferingTrimMargin()857 OSCL_EXPORT_REF uint32 PVMFMemoryBufferReadDataStreamImpl::QueryBufferingTrimMargin()
858 {
859 uint32 margin = 0;
860
861 if (NULL != iWriteDataStream)
862 {
863 margin = iWriteDataStream->QueryBufferingTrimMargin();
864 }
865
866 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::QueryBufferingTrimMargin returning %d", margin));
867 return margin;
868 }
869
870
871 // The data to be made persistent may be already in the temp cache.
872 // If so, copy the data from temp cache into perm cache.
873 // If not, when the data arrives, it is be written directly in the perm cache
874 //
875 // All parsers need to call MakePersistent to get the cache trimming,
876 // with (offset = 0, size = 0) if nothing is to be copied.
877 //
878 // there are possible scenarios:
879 // all the data to be made persistent is in the perm cache,
880 // do nothing, return success
881 // part of the data be made persistent is in the perm cache,
882 // only first part of data can be in perm cache,
883 // we can only add to cache in contiguous manner now,
884 // malloc a buffer and add to cache,
885 // return success
886 // if second part of data is already in cache
887 // we don't allow filling the gap now
888 // return failure
889 // none of the data be made persistent is in the perm cache,
890 // most common usage,
891 // malloc a buffer and add to cache,
892 // return success
893 //
894 // all the data to be made persistent is in the temp cache
895 // copy data from temp cache into perm cache, release mem frags
896 // none of the data to be made persistent is in the temp cache
897 // just alloc the buffer but copy nothing
898 // some of the data to be made persistent is in the temp cache
899 // make sure there will not a gap in the perm cache
900 // if only second part of data is on temp cache,
901 // return failure
902 //
903 OSCL_EXPORT_REF PvmiDataStreamStatus
MakePersistent(int32 aOffset,uint32 aSize)904 PVMFMemoryBufferReadDataStreamImpl::MakePersistent(int32 aOffset, uint32 aSize)
905 {
906 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::MakePersistent offset %d size %d", aOffset, aSize));
907
908 // MakePersistent should not be called multiple times with different offsets
909 uint32 firstPersistentOffset = 0;
910 uint32 lastPeristentOffset = 0;
911 bool bMadePersistent = iWriteDataStream->GetPermCachePersistence(firstPersistentOffset, lastPeristentOffset);
912
913 if (bMadePersistent)
914 {
915 // has already been called, check the offset + size
916 // last byte in perm cache is one byte beyond moov atom
917 if ((0 == aSize && 0 == firstPersistentOffset && 0 == lastPeristentOffset) ||
918 (aOffset == (int32)firstPersistentOffset && (aOffset + aSize) == lastPeristentOffset))
919 {
920 // same paramerters, it is ok
921 LOGDEBUG((0, "PVMFMemoryBufferReadDataStreamImpl::MakePersistent has already been called with same offset and size"));
922 return PVDS_SUCCESS;
923 }
924
925 // does not support calling this function again with different parameters
926 LOGERROR((0, "PVMFMemoryBufferReadDataStreamImpl::MakePersistent has already been called with first offset %d last offset %d",
927 firstPersistentOffset, lastPeristentOffset));
928 return PVDS_NOT_SUPPORTED;
929 }
930
931 if (0 == aSize)
932 {
933 // Just info write stream that cache can now be managed
934 iWriteDataStream->MakePersistent(aOffset, aSize);
935 return PVDS_SUCCESS;
936 }
937 // check for upper bound, if any
938 if (PV_MBDS_PERM_CACHE_SIZE != NO_LIMIT)
939 {
940 // find out current perm cache size
941 // want to know what has been allocated, not what has been filled
942 uint32 cacheSize = iPermCache->GetCacheSize();
943 if ((cacheSize + aSize) > PV_MBDS_PERM_CACHE_SIZE)
944 {
945 LOGERROR((0, "PVMFMemoryBufferReadDataStreamImpl::MakePersistent exceed cache size limit cacheSize %d limit %d", cacheSize, PV_MBDS_PERM_CACHE_SIZE));
946 return PVDS_FAILURE;
947 }
948 }
949
950 // find out what is in the temp cache and perm cache
951 // currently, the data in the temp cache and the perm cache are sequential, there are no gaps in the caches
952 // however, the caches can easily modified to be permit gaps
953
954 uint32 firstPermByteOffset = 0;
955 uint32 lastPermByteOffset = 0;
956 iPermCache->GetPermOffsets(firstPermByteOffset, lastPermByteOffset);
957
958 uint32 firstTempByteOffset = 0;
959 uint32 lastTempByteOffset = 0;
960 iTempCache->GetFileOffsets(firstTempByteOffset, lastTempByteOffset);
961
962 LOGDEBUG((0, "PVMFMemoryBufferReadDataStreamImpl::MakePersistent perm %d %d temp %d %d",
963 firstPermByteOffset, lastPermByteOffset, firstTempByteOffset, lastTempByteOffset));
964
965 // last byte in perm cache is one byte beyond moov atom
966 uint32 copyFirstByteOffset = aOffset;
967 uint32 copyLastByteOffset = aOffset + aSize;
968
969 // check if some or all data is already in the perm cache, if the perm cache is not empty
970 uint32 count = iPermCache->GetNumEntries();
971 if (count)
972 {
973 if (copyFirstByteOffset >= firstPermByteOffset)
974 {
975 if (copyFirstByteOffset <= lastPermByteOffset)
976 {
977 // the first byte of data is in perm cache, some or all is in perm cache
978 if (copyLastByteOffset <= lastPermByteOffset)
979 {
980 // all of it is in the perm cache already, do nothing
981 return PVDS_SUCCESS;
982 }
983 else
984 {
985 // first part is in perm cache
986 // find out how much is left
987 copyFirstByteOffset = lastPermByteOffset + 1;
988 }
989 }
990 else
991 {
992 // first byte is not the perm cache, check if it is immediately after the last byte of the perm cache
993 // if not, there will be a gap, return failure
994 if (copyFirstByteOffset != lastPermByteOffset + 1)
995 {
996 LOGERROR((0, "PVMFMemoryBufferReadDataStreamImpl::MakePersistent FAILED leaving a gap lastPermOffset %d", lastPermByteOffset));
997 return PVDS_FAILURE;
998 }
999 }
1000 }
1001 else
1002 {
1003 // first byte of data is before the perm cache, see if the part of the data is in the perm cache
1004 if (copyLastByteOffset <= lastPermByteOffset)
1005 {
1006 // the second part of the data is already in perm cache
1007 // add the new buffer in the front of the cache
1008 copyLastByteOffset = firstPermByteOffset - 1;
1009 }
1010 else
1011 {
1012 // the middle part of the data is in cache!
1013 // this done be done, but let's fail that for now
1014 LOGERROR((0, "PVMFMemoryBufferReadDataStreamImpl::MakePersistent FAILED middle part of data in cache already firstPermByteOffset %d lastPermByteOffset %d", firstPermByteOffset, lastPermByteOffset));
1015 return PVDS_FAILURE;
1016 }
1017 }
1018 }
1019
1020 // allocate a memory buffer
1021 uint32 bufSize = copyLastByteOffset - copyFirstByteOffset + 1;
1022 uint8* memBuf = (uint8*)oscl_malloc(bufSize);
1023 if (NULL == memBuf)
1024 {
1025 LOGERROR((0, "PVMFMemoryBufferReadDataStreamImpl::MakePersistent out of memory"));
1026 return PVDS_FAILURE;
1027 }
1028
1029 PvmiDataStreamStatus status = PVDS_SUCCESS;
1030 bool releaseMemFrags = false;
1031 uint32 bytesRead = 0;
1032 uint32 firstEntry = 0;
1033
1034 // the data to be made permanent may not be in the temp cache yet
1035 if ((copyFirstByteOffset > lastTempByteOffset) || (copyLastByteOffset < firstTempByteOffset))
1036 {
1037 // data is not in temp cache, just add the cache entry and when the data arrives,
1038 // the data will be written to cache
1039 LOGDEBUG((0, "PVMFMemoryBufferReadDataStreamImpl::MakePersistent data not in temp cache yet"));
1040
1041 status = iPermCache->AddEntry(memBuf, bufSize, memBuf, copyFirstByteOffset, copyLastByteOffset, copyFirstByteOffset, 0);
1042 }
1043 else if ((copyFirstByteOffset >= firstTempByteOffset) && (copyLastByteOffset <= lastTempByteOffset))
1044 {
1045 // all the data is in the temp cache, copy the data
1046 bytesRead = iTempCache->ReadBytes(memBuf, copyFirstByteOffset, copyLastByteOffset, firstEntry);
1047 if (bytesRead != bufSize)
1048 {
1049 // something went wrong
1050 LOGERROR((0, "PVMFMemoryBufferReadDataStreamImpl::MakePersistent read from temp cache failed %d/%d",
1051 bytesRead, bufSize));
1052 status = PVDS_FAILURE;
1053 }
1054 else
1055 {
1056 // write out to cache
1057 status = iPermCache->AddEntry(memBuf, bufSize, memBuf + bufSize, copyFirstByteOffset, copyLastByteOffset, copyLastByteOffset + 1, bufSize);
1058 if (PVDS_SUCCESS == status)
1059 {
1060 releaseMemFrags = true;
1061 }
1062 }
1063 }
1064 else if ((copyFirstByteOffset >= firstTempByteOffset) && (copyFirstByteOffset <= lastTempByteOffset))
1065 {
1066 // first part of data is in the temp cache, copy whatever is there
1067 uint32 copySize = lastTempByteOffset - copyFirstByteOffset + 1;
1068
1069 bytesRead = iTempCache->ReadBytes(memBuf, copyFirstByteOffset, lastTempByteOffset, firstEntry);
1070 if (bytesRead != copySize)
1071 {
1072 // something went wrong
1073 LOGERROR((0, "PVMFMemoryBufferReadDataStreamImpl::MakePersistent read from temp cache failed %d/%d",
1074 bytesRead, copySize));
1075 status = PVDS_FAILURE;
1076 }
1077 else
1078 {
1079 // write out to cache
1080 status = iPermCache->AddEntry(memBuf, bufSize, memBuf + copySize, copyFirstByteOffset, copyLastByteOffset, copyFirstByteOffset + copySize, copySize);
1081 if (PVDS_SUCCESS == status)
1082 {
1083 releaseMemFrags = true;
1084 }
1085 }
1086 }
1087 else
1088 {
1089 // first part of data is not in temp cache
1090 // fail this operation and free the mem buf
1091 status = PVDS_FAILURE;
1092 }
1093
1094 if ((PVDS_FAILURE == status) && (memBuf))
1095 {
1096 oscl_free(memBuf);
1097 }
1098 else if (PVDS_SUCCESS == status)
1099 {
1100 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::MakePersistent succeeded"));
1101
1102 if ((releaseMemFrags) && (NULL != iWriteDataStream))
1103 {
1104 iWriteDataStream->UpdateReadPointersAfterMakePersistent();
1105
1106 iWriteDataStream->MakePersistent(aOffset, aSize);
1107 // give a cache a chance to release mem frags
1108 iWriteDataStream->ManageCache();
1109 }
1110 }
1111
1112 return status;
1113 }
1114
1115
1116 OSCL_EXPORT_REF void
GetCurrentByteRange(uint32 & aCurrentFirstByteOffset,uint32 & aCurrentLastByteOffset)1117 PVMFMemoryBufferReadDataStreamImpl::GetCurrentByteRange(uint32& aCurrentFirstByteOffset, uint32& aCurrentLastByteOffset)
1118 {
1119 // if the perm cache and the temp cache was contiguous,
1120 // report the entire range
1121 // if not, report only the temp cache range
1122 uint32 firstTempByteOffset = 0;
1123 uint32 lastTempByteOffset = 0;
1124 iTempCache->GetFileOffsets(firstTempByteOffset, lastTempByteOffset);
1125
1126 uint32 firstPermByteOffset = 0;
1127 uint32 lastPermByteOffset = 0;
1128 iPermCache->GetFileOffsets(firstPermByteOffset, lastPermByteOffset);
1129
1130 if (firstTempByteOffset == (lastPermByteOffset + 1))
1131 {
1132 aCurrentFirstByteOffset = firstPermByteOffset;
1133 aCurrentLastByteOffset = lastTempByteOffset;
1134 }
1135 else
1136 {
1137 aCurrentFirstByteOffset = firstTempByteOffset;
1138 aCurrentLastByteOffset = lastTempByteOffset;
1139 }
1140
1141 LOGTRACE((0, "PVMFMemoryBufferReadDataStreamImpl::GetCurrentByteRange aCurrentFirstByteOffset %d aCurrentLastByteOffset %d", aCurrentFirstByteOffset, aCurrentLastByteOffset));
1142 }
1143
1144
1145 //////////////////////////////////////////////////////////////////////
1146 // PVMFMemoryBufferWriteDataStreamImpl
1147 //////////////////////////////////////////////////////////////////////
1148 OSCL_EXPORT_REF
PVMFMemoryBufferWriteDataStreamImpl(PVMFMemoryBufferDataStreamTempCache * aTempCache,PVMFMemoryBufferDataStreamPermCache * aPermCache,MBDSStreamFormat aStreamFormat,uint32 aTempCacheCapacity)1149 PVMFMemoryBufferWriteDataStreamImpl::PVMFMemoryBufferWriteDataStreamImpl(PVMFMemoryBufferDataStreamTempCache* aTempCache,
1150 PVMFMemoryBufferDataStreamPermCache* aPermCache, MBDSStreamFormat aStreamFormat, uint32 aTempCacheCapacity)
1151 {
1152 iDownloadComplete = false;
1153 iFileNumBytes = 0;
1154 iSessionID = 0;
1155 iContentLength = 0;
1156 iRequestObserver = NULL;
1157 iNumReadSessions = 0;
1158 iWriteSessionOpened = false;
1159 iThrowAwayData = false;
1160 iFilePtrPos = 0;
1161 iAVTSessionID[0] = 0;
1162 iAVTSessionID[1] = 0;
1163 iAVTSessionID[2] = 0;
1164 iAVTOffsetDelta = 0;
1165 iMadePersistent = false;
1166
1167 // save pointer to cache
1168 iTempCache = aTempCache;
1169 iPermCache = aPermCache;
1170 iStreamFormat = aStreamFormat;
1171 iTempCacheCapacity = aTempCacheCapacity;
1172
1173 for (uint32 i = 0; i < PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS; i++)
1174 {
1175 iReadNotifications[i].iReadStructValid = false;
1176
1177 iReadFilePositions[i].iReadPositionStructValid = false;
1178 }
1179
1180 iRepositionRequest.iOutstanding = false;
1181 iWriteNotification.iOutstanding = false;
1182 iLogger = PVLogger::GetLoggerObject("PVMFMemoryBufferDataStream");
1183
1184 // put this in the header
1185 if (MBDS_STREAM_FORMAT_SHOUTCAST == iStreamFormat)
1186 {
1187 iTempCacheTrimThreshold = PV_MBDS_TEMP_CACHE_TRIM_THRESHOLD_SC(iTempCacheCapacity);
1188 iTempCacheTrimMargin = PV_MBDS_TEMP_CACHE_TRIM_MARGIN_SC;
1189 }
1190 else
1191 {
1192 iTempCacheTrimThreshold = PV_MBDS_TEMP_CACHE_TRIM_THRESHOLD_PS(iTempCacheCapacity);
1193 iTempCacheTrimMargin = PV_MBDS_TEMP_CACHE_TRIM_MARGIN_PS;
1194 }
1195
1196 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::PVMFMemoryBufferWriteDataStreamImpl stream format %d temp cache size %d trim threshold %d trim margin %d",
1197 iStreamFormat, iTempCacheCapacity, iTempCacheTrimThreshold, iTempCacheTrimMargin));
1198 }
1199
1200 OSCL_EXPORT_REF
~PVMFMemoryBufferWriteDataStreamImpl()1201 PVMFMemoryBufferWriteDataStreamImpl::~PVMFMemoryBufferWriteDataStreamImpl()
1202 {
1203 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::~PVMFMemoryBufferWriteDataStreamImpl"));
1204
1205 // If there are read notifications outstanding, send them
1206 // If there are reposition request, signal the semaphores
1207 for (uint32 i = 0; i < PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS; i++)
1208 {
1209 if ((iReadNotifications[i].iReadStructValid == true) &&
1210 (iReadNotifications[i].iOutstanding == true) &&
1211 (iReadNotifications[i].iReadObserver != NULL))
1212 {
1213 PvmiDataStreamObserver* observer = iReadNotifications[i].iReadObserver;
1214 OsclAny* contextData = iReadNotifications[i].iContextData;
1215 PvmiDataStreamCommandId cmdID = iReadNotifications[i].iCommandID;
1216
1217 // Form a command response
1218 PVMFCmdResp resp(cmdID, contextData, PVMFFailure, NULL, NULL);
1219 // Make the Command Complete notification
1220 observer->DataStreamCommandCompleted(resp);
1221 }
1222 }
1223 if (iRepositionRequest.iOutstanding == true)
1224 {
1225 iRepositionRequest.iOutstanding = false;
1226 iRepositionRequest.iSuccess = PVDS_FAILURE;
1227 }
1228 // If there is an outstanding write notification, send it
1229 if (iWriteNotification.iOutstanding && (NULL != iWriteNotification.iWriteObserver))
1230 {
1231 PvmiDataStreamObserver* observer2 = iWriteNotification.iWriteObserver;
1232 OsclAny* contextData = iWriteNotification.iContextData;
1233 PvmiDataStreamCommandId cmdID = iWriteNotification.iCommandID;
1234
1235 // Form a command response
1236 PVMFCmdResp resp2(cmdID, contextData, PVMFFailure, NULL, NULL);
1237 // Make the Command Complete notification
1238 observer2->DataStreamCommandCompleted(resp2);
1239 }
1240 // Clean up the caches
1241 while (1)
1242 {
1243 OsclRefCounterMemFrag* frag;
1244 uint8* fragPtr;
1245 bool found = iTempCache->RemoveFirstEntry(frag, fragPtr);
1246 if (!found)
1247 {
1248 // cache should be empty now
1249 break;
1250 }
1251 // return mem frag to stream writer (e.g. protocol engine)
1252 iRequestObserver->DataStreamRequestSync(0, PVDS_REQUEST_MEM_FRAG_RELEASED, (OsclAny*)frag);
1253 }
1254 while (1)
1255 {
1256 uint8* memBuf;
1257 bool found = iPermCache->RemoveFirstEntry(memBuf);
1258 if (!found)
1259 {
1260 // cache should be empty now
1261 break;
1262 }
1263 // free memory buffer
1264 if (memBuf)
1265 {
1266 oscl_free(memBuf);
1267 }
1268 }
1269
1270 iLogger = NULL;
1271 }
1272
1273
1274 OSCL_EXPORT_REF bool
queryInterface(const PVUuid & uuid,PVInterface * & iface)1275 PVMFMemoryBufferWriteDataStreamImpl::queryInterface(const PVUuid& uuid, PVInterface*& iface)
1276 {
1277 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::queryInterface"));
1278
1279 iface = NULL;
1280 if (uuid == PVMIDataStreamSyncInterfaceUuid)
1281 {
1282 PVMIDataStreamSyncInterface* myInterface = OSCL_STATIC_CAST(PVMIDataStreamSyncInterface*, this);
1283
1284 iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
1285 return true;
1286 }
1287 return false;
1288 }
1289
1290
1291 OSCL_EXPORT_REF PvmiDataStreamStatus
OpenSession(PvmiDataStreamSession & aSessionID,PvmiDataStreamMode aMode,bool nonblocking)1292 PVMFMemoryBufferWriteDataStreamImpl::OpenSession(PvmiDataStreamSession& aSessionID,
1293 PvmiDataStreamMode aMode, bool nonblocking)
1294 {
1295 OSCL_UNUSED_ARG(nonblocking);
1296
1297 // There are 2 kinds of sessions:
1298 // write session (there can only be 1)
1299 // read only sessions (at most 4, to support read capacity notifications)
1300 // read only sessions are opened by hte read data stream
1301
1302 // This function assumes that the WRITE mode will be requested first!
1303
1304 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::OpenSession"));
1305
1306 PvmiDataStreamStatus status = PVDS_SUCCESS;
1307 switch (aMode)
1308 {
1309 case PVDS_READ_ONLY:
1310 // Check to see if we have free READ connections before setting one.
1311 if (iNumReadSessions < PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS)
1312 {
1313 // at least one of them is free
1314 bool found = false;
1315 for (int i = 0; i < PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS; i++)
1316 {
1317 if (false == iReadFilePositions[i].iReadPositionStructValid)
1318 {
1319 found = true;
1320
1321 iReadNotifications[i].iReadStructValid = true;
1322 iReadNotifications[i].iReadSessionID = i + PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS;
1323 iReadNotifications[i].iReadObserver = NULL;
1324 iReadNotifications[i].iFilePosition = 0;
1325 iReadNotifications[i].iReadCapacity = 0;
1326 iReadNotifications[i].iContextData = NULL;
1327 iReadNotifications[i].iCommandID = 0;
1328 iReadNotifications[i].iCurrentCommandID = 0;
1329
1330 aSessionID = iReadNotifications[i].iReadSessionID;
1331
1332 iReadFilePositions[i].iReadPositionStructValid = true;
1333 iReadFilePositions[i].iReadFilePtr = 0;
1334 iReadFilePositions[i].iInTempCache = true;
1335 iReadFilePositions[i].iReadDataStream = NULL;
1336
1337 iNumReadSessions++;
1338
1339 break;
1340 }
1341 }
1342 if (!found)
1343 {
1344 // something went wrong
1345 LOGERROR((0, "PVMFMemoryBufferWriteDataStreamImpl::OpenSession SHOULD NOT GET HERE"));
1346 status = PVDS_INVALID_REQUEST;
1347 }
1348 }
1349 else
1350 {
1351 status = PVDS_INVALID_REQUEST;
1352 }
1353 break;
1354
1355 case PVDS_WRITE_ONLY:
1356 case PVDS_APPEND:
1357 // Can only open a write session once
1358 if (iWriteSessionOpened)
1359 {
1360 status = PVDS_INVALID_REQUEST;
1361 }
1362 else
1363 {
1364 // write-only starts from beginning of cache, at file offset 0
1365 // append adds to the last byte in cache
1366
1367 // id 0 is the write session
1368 aSessionID = 0;
1369
1370 iWriteSessionOpened = true;
1371
1372 iFilePtrPos = 0;
1373
1374 // reset notification
1375 iWriteNotification.iOutstanding = false;
1376 iWriteNotification.iWriteObserver = NULL;
1377 iWriteNotification.iFilePosition = 0;
1378 iWriteNotification.iWriteCapacity = 0;
1379 iWriteNotification.iContextData = NULL;
1380 iWriteNotification.iCommandID = 0;
1381 iWriteNotification.iCurrentCommandID = 0;
1382 // TBD, update file offset and byte count if needed
1383
1384 }
1385 break;
1386
1387 default:
1388 status = PVDS_UNSUPPORTED_MODE;
1389 break;
1390
1391 }
1392
1393 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::OpenSession returning %d", status));
1394 return status;
1395 }
1396
1397 OSCL_EXPORT_REF PvmiDataStreamStatus
OpenReadSession(PvmiDataStreamSession & aSessionID,PvmiDataStreamMode aMode,bool nonblocking,PVMFMemoryBufferReadDataStreamImpl * aReadDataStream)1398 PVMFMemoryBufferWriteDataStreamImpl::OpenReadSession(PvmiDataStreamSession& aSessionID,
1399 PvmiDataStreamMode aMode, bool nonblocking,
1400 PVMFMemoryBufferReadDataStreamImpl* aReadDataStream)
1401 {
1402 PvmiDataStreamStatus status = OpenSession(aSessionID, aMode, nonblocking);
1403 if ((PVDS_SUCCESS == status) && (PVDS_READ_ONLY == aMode))
1404 {
1405 iReadFilePositions[aSessionID - 1].iReadDataStream = aReadDataStream;
1406 }
1407
1408 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::OpenReadSession returning %d", status));
1409 return status;
1410 }
1411
1412 OSCL_EXPORT_REF PvmiDataStreamStatus
CloseSession(PvmiDataStreamSession aSessionID)1413 PVMFMemoryBufferWriteDataStreamImpl::CloseSession(PvmiDataStreamSession aSessionID)
1414 {
1415 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::CloseSession"));
1416
1417 PvmiDataStreamStatus status = PVDS_SUCCESS;
1418 // Check for the WRITE session
1419 if (aSessionID == 0)
1420 {
1421 // Check to make sure we don't close the write session twice
1422 if (!iWriteSessionOpened)
1423 {
1424 // Either OpenSession was never called or we already called CloseSession
1425 status = PVDS_FAILURE;
1426 }
1427 else
1428 {
1429 iWriteSessionOpened = false;
1430 iWriteNotification.iOutstanding = false;
1431 // empty the cache now
1432 // release memory buffers back to the writer
1433 TrimTempCache(MBDS_CACHE_TRIM_EMPTY);
1434 }
1435 }
1436 else
1437 {
1438 // Close the READ sessions
1439 if ((aSessionID > (PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS + PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS)) ||
1440 (iReadFilePositions[aSessionID - PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS].iReadPositionStructValid != true))
1441 {
1442 status = PVDS_INVALID_SESSION;
1443 }
1444 else
1445 {
1446 // Have a valid READ session so close it by setting the flag to invalid
1447 PvmiDataStreamSession sessionId = aSessionID - PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS;
1448
1449 if (sessionId == iRepositionRequest.iRepositionSessionID)
1450 {
1451 iRepositionRequest.iOutstanding = false;
1452 }
1453
1454 iReadNotifications[sessionId].iReadStructValid = false;
1455 iReadNotifications[sessionId].iOutstanding = false;
1456
1457 iReadFilePositions[sessionId].iReadPositionStructValid = false;
1458
1459 iNumReadSessions--;
1460
1461 if (sessionId == iAVTSessionID[0])
1462 {
1463 iAVTSessionID[0] = iAVTSessionID[1];
1464 iAVTSessionID[1] = iAVTSessionID[2];
1465 iAVTSessionID[2] = 0;
1466 }
1467 else if (sessionId == iAVTSessionID[1])
1468 {
1469 iAVTSessionID[1] = iAVTSessionID[2];
1470 iAVTSessionID[2] = 0;
1471 }
1472 else if (sessionId == iAVTSessionID[2])
1473 {
1474 iAVTSessionID[2] = 0;
1475 }
1476 }
1477 }
1478
1479 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::CloseSession returning %d", status));
1480 return status;
1481 }
1482
1483
1484 OSCL_EXPORT_REF PvmiDataStreamRandomAccessType
QueryRandomAccessCapability()1485 PVMFMemoryBufferWriteDataStreamImpl::QueryRandomAccessCapability()
1486 {
1487 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::QueryRandomAccessCapability"));
1488
1489 return PVDS_FULL_RANDOM_ACCESS;
1490 }
1491
1492 OSCL_EXPORT_REF PvmiDataStreamStatus
QueryReadCapacity(PvmiDataStreamSession aSessionID,uint32 & aCapacity)1493 PVMFMemoryBufferWriteDataStreamImpl::QueryReadCapacity(PvmiDataStreamSession aSessionID, uint32& aCapacity)
1494 {
1495 OSCL_UNUSED_ARG(aSessionID);
1496
1497 // return the offset of the last byte in the cache
1498 uint32 firstTempByteOffset = 0;
1499 uint32 lastTempByteOffset = 0;
1500 iTempCache->GetFileOffsets(firstTempByteOffset, lastTempByteOffset);
1501
1502 uint32 firstPermByteOffset = 0;
1503 uint32 lastPermByteOffset = 0;
1504 iPermCache->GetFileOffsets(firstPermByteOffset, lastPermByteOffset);
1505
1506 // Return the larger of the two offsets, as the temp cache may be trimmed
1507 iTempCache->GetFileOffsets(firstTempByteOffset, lastTempByteOffset);
1508
1509 aCapacity = (lastTempByteOffset > lastPermByteOffset) ? lastTempByteOffset : lastPermByteOffset;
1510
1511 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::QueryReadCapacity returning %d", aCapacity));
1512 return PVDS_SUCCESS;
1513 }
1514
1515 OSCL_EXPORT_REF PvmiDataStreamCommandId
RequestReadCapacityNotification(PvmiDataStreamSession aSessionID,PvmiDataStreamObserver & aObserver,uint32 aCapacity,OsclAny * aContextData)1516 PVMFMemoryBufferWriteDataStreamImpl::RequestReadCapacityNotification(PvmiDataStreamSession aSessionID,
1517 PvmiDataStreamObserver& aObserver,
1518 uint32 aCapacity, OsclAny* aContextData)
1519 {
1520 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::RequestReadCapacityNotification"));
1521
1522 // Check that aSessionID is valid and is not the WRITE session
1523 if ((aSessionID == 0) ||
1524 (aSessionID > (PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS + PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS)) ||
1525 (iReadNotifications[aSessionID - PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS].iReadStructValid != true))
1526 {
1527 OSCL_LEAVE(OsclErrArgument);
1528 }
1529 // Read SessionID index is PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS less than the aSessionID passed in
1530 PvmiDataStreamSession temp_session = aSessionID - PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS;
1531
1532 // Save the read notification
1533 iReadNotifications[temp_session].iOutstanding = true;
1534 iReadNotifications[temp_session].iReadObserver = &aObserver;
1535 iReadNotifications[temp_session].iFilePosition = iReadFilePositions[temp_session].iReadFilePtr;
1536 iReadNotifications[temp_session].iReadCapacity = aCapacity;
1537 iReadNotifications[temp_session].iContextData = aContextData;
1538 iReadNotifications[temp_session].iCommandID = iReadNotifications[temp_session].iCurrentCommandID++;
1539
1540 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::RequestReadCapacityNotification returning %d", iReadNotifications[temp_session].iCommandID));
1541 return iReadNotifications[temp_session].iCommandID;
1542 }
1543
1544
1545 OSCL_EXPORT_REF PvmiDataStreamStatus
QueryWriteCapacity(PvmiDataStreamSession aSessionID,uint32 & aCapacity)1546 PVMFMemoryBufferWriteDataStreamImpl::QueryWriteCapacity(PvmiDataStreamSession aSessionID, uint32& aCapacity)
1547 {
1548 OSCL_UNUSED_ARG(aSessionID);
1549
1550 // return the number of bytes left in the sliding window that can be filled
1551 // only support writing to the temp cache right now
1552 // the perm cache is filled by copyig from the temp cache
1553 aCapacity = (iTempCache->GetTotalBytes() >= iTempCacheCapacity) ? 0 : iTempCacheCapacity - (iTempCache->GetTotalBytes());
1554
1555 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::QueryWriteCapacity returning %d", aCapacity));
1556
1557 return PVDS_SUCCESS;
1558 }
1559
1560
1561 OSCL_EXPORT_REF PvmiDataStreamCommandId
RequestWriteCapacityNotification(PvmiDataStreamSession aSessionID,PvmiDataStreamObserver & aObserver,uint32 aCapacity,OsclAny * aContextData)1562 PVMFMemoryBufferWriteDataStreamImpl::RequestWriteCapacityNotification(PvmiDataStreamSession aSessionID,
1563 PvmiDataStreamObserver& aObserver,
1564 uint32 aCapacity, OsclAny* aContextData)
1565 {
1566 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::RequestWriteCapacityNotification"));
1567
1568 // Check that aSessionID is the WRITE session
1569 if (aSessionID != 0)
1570 {
1571 OSCL_LEAVE(OsclErrArgument);
1572 }
1573 // Only one notification request can be made
1574 if (iWriteNotification.iOutstanding)
1575 {
1576 OSCL_LEAVE(OsclErrAlreadyExists);
1577 }
1578 // Save the write notification
1579 iWriteNotification.iOutstanding = true;
1580 iWriteNotification.iWriteObserver = &aObserver;
1581 iWriteNotification.iFilePosition = GetCurrentPointerPosition(0);
1582 iWriteNotification.iWriteCapacity = aCapacity;
1583 iWriteNotification.iContextData = aContextData;
1584 iWriteNotification.iCommandID = iWriteNotification.iCurrentCommandID++;
1585
1586 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::RequestWriteCapacityNotification returning %d", iWriteNotification.iCommandID));
1587 return iWriteNotification.iCommandID;
1588 }
1589
1590
1591 OSCL_EXPORT_REF PvmiDataStreamCommandId
CancelNotification(PvmiDataStreamSession aSessionID,PvmiDataStreamObserver & aObserver,PvmiDataStreamCommandId aID,OsclAny * aContextData)1592 PVMFMemoryBufferWriteDataStreamImpl::CancelNotification(PvmiDataStreamSession aSessionID,
1593 PvmiDataStreamObserver& aObserver,
1594 PvmiDataStreamCommandId aID,
1595 OsclAny* aContextData)
1596 {
1597 OSCL_UNUSED_ARG(aSessionID);
1598 OSCL_UNUSED_ARG(aObserver);
1599 OSCL_UNUSED_ARG(aID);
1600 OSCL_UNUSED_ARG(aContextData);
1601
1602 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::CancelNotification"));
1603
1604 // asynch version not supported
1605 OSCL_LEAVE(OsclErrNotSupported);
1606 // satisfy compiler
1607 return 0;
1608 }
1609
1610
1611 OSCL_EXPORT_REF PvmiDataStreamStatus
CancelNotificationSync(PvmiDataStreamSession aSessionID)1612 PVMFMemoryBufferWriteDataStreamImpl::CancelNotificationSync(PvmiDataStreamSession aSessionID)
1613 {
1614 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::CancelNotificationSync"));
1615
1616 PvmiDataStreamStatus status = PVDS_SUCCESS;
1617 if (aSessionID == 0)
1618 {
1619 // Cancel write notification
1620 if (!iWriteNotification.iOutstanding)
1621 {
1622 status = PVDS_INVALID_REQUEST;
1623 }
1624 else
1625 {
1626 // Clean out notification info
1627 iWriteNotification.iOutstanding = false;
1628 iWriteNotification.iWriteObserver = NULL;
1629 iWriteNotification.iFilePosition = 0;
1630 iWriteNotification.iWriteCapacity = 0;
1631 iWriteNotification.iContextData = NULL;
1632 iWriteNotification.iCommandID = 0;
1633 }
1634 }
1635 else if ((aSessionID > (PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS + PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS)) ||
1636 (iReadNotifications[aSessionID - PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS].iReadStructValid != true))
1637 {
1638 // Cancel read notification
1639 // Check that aSessionID is valid
1640 status = PVDS_INVALID_REQUEST;
1641 }
1642 else
1643 {
1644 // Zero out notification info
1645 PvmiDataStreamSession temp_sessionID = aSessionID - PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS;
1646 iReadNotifications[temp_sessionID].iOutstanding = false;
1647 iReadNotifications[temp_sessionID].iReadObserver = NULL;
1648 iReadNotifications[temp_sessionID].iFilePosition = 0;
1649 iReadNotifications[temp_sessionID].iReadCapacity = 0;
1650 iReadNotifications[temp_sessionID].iContextData = NULL;
1651 iReadNotifications[temp_sessionID].iCommandID = 0;
1652 }
1653
1654 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::CancelNotificationSync returning %d", status));
1655 return status;
1656 }
1657
1658
1659 OSCL_EXPORT_REF PvmiDataStreamStatus
Read(PvmiDataStreamSession aSessionID,uint8 * buffer,uint32 size,uint32 & numelements)1660 PVMFMemoryBufferWriteDataStreamImpl::Read(PvmiDataStreamSession aSessionID, uint8* buffer,
1661 uint32 size, uint32& numelements)
1662 {
1663 OSCL_UNUSED_ARG(aSessionID);
1664 OSCL_UNUSED_ARG(buffer);
1665 OSCL_UNUSED_ARG(size);
1666 OSCL_UNUSED_ARG(numelements);
1667
1668 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::Read"));
1669
1670 // Can't read from a write session
1671 return PVDS_NOT_SUPPORTED;
1672 }
1673
1674 OSCL_EXPORT_REF PvmiDataStreamStatus
Write(PvmiDataStreamSession aSessionID,uint8 * buffer,uint32 size,uint32 & numelements)1675 PVMFMemoryBufferWriteDataStreamImpl::Write(PvmiDataStreamSession aSessionID, uint8* buffer,
1676 uint32 size, uint32& numelements)
1677 {
1678 OSCL_UNUSED_ARG(aSessionID);
1679 OSCL_UNUSED_ARG(buffer);
1680 OSCL_UNUSED_ARG(size);
1681 OSCL_UNUSED_ARG(numelements);
1682
1683 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::Write"));
1684
1685 // Only support mem frags
1686 return PVDS_NOT_SUPPORTED;
1687 }
1688
1689
1690 OSCL_EXPORT_REF PvmiDataStreamStatus
Write(PvmiDataStreamSession aSessionID,OsclRefCounterMemFrag * aFrag,uint32 & aNumElements)1691 PVMFMemoryBufferWriteDataStreamImpl::Write(PvmiDataStreamSession aSessionID, OsclRefCounterMemFrag* aFrag, uint32& aNumElements)
1692 {
1693 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::Write iFilePtrPos %d", iFilePtrPos));
1694
1695 PvmiDataStreamStatus status = PVDS_FAILURE;
1696
1697 // Make sure this is the write session and that the session is open
1698 if ((aSessionID == 0) && (iWriteSessionOpened))
1699 {
1700 if (iThrowAwayData)
1701 {
1702 // Reposition in progress, throw away the data
1703 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::Write reposition, throw away frag %x", aFrag));
1704 return PVDS_SUCCESS;
1705 }
1706 // check if this is the start of the new data from a repositioning,
1707 // if so, repositioning is finally done
1708 if ((true == iRepositionRequest.iOutstanding) && (true == iRepositionRequest.iRequestCompleted))
1709 {
1710 iRepositionRequest.iOutstanding = false;
1711 }
1712 bool written = false;
1713
1714 // check if this data is supposed to written to the perm cache if perm cache is not empty
1715 uint32 firstPermOffset = 0;
1716 uint32 lastPermOffset = 0;
1717 iPermCache->GetPermOffsets(firstPermOffset, lastPermOffset);
1718
1719 uint32 firstPermReadOffset = 0;
1720 uint32 lastPermReadOffset = 0;
1721 iPermCache->GetFileOffsets(firstPermReadOffset, lastPermReadOffset);
1722
1723 uint32 permEntries = iPermCache->GetNumEntries();
1724
1725 uint32 fragSize = aFrag->getMemFragSize();
1726 uint8* fragPtr = (uint8*)aFrag->getMemFragPtr();
1727
1728 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::Write fragSize %d", fragSize));
1729
1730 if (permEntries && ((iFilePtrPos >= firstPermOffset) && (iFilePtrPos <= lastPermOffset)))
1731 {
1732 // part or all of this mem frag should be copied to the perm cache
1733 // the cache entry and the mem buffer have already been allocated during MakePersistent()
1734 // however, there may be data in this frag that has not been made persistent
1735 // if there is data left in this frag that does not belong in the perm cache,
1736 // add the entire fragment to the temp cache
1737 if ((iFilePtrPos + fragSize - 1) > lastPermOffset)
1738 {
1739 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::Write partially to perm cache"));
1740
1741 // part of frag has been made persistent
1742 uint32 firstEntrySize = lastPermOffset - iFilePtrPos + 1;
1743 // copy the first part
1744 status = iPermCache->WriteBytes(fragPtr, firstEntrySize, iFilePtrPos);
1745 if (PVDS_SUCCESS != status)
1746 {
1747 LOGERROR((0, "PVMFMemoryBufferWriteDataStreamImpl::Write WriteBytes FAILED"));
1748 }
1749 else
1750 {
1751 // this fragment should be the first entry in the temp cache
1752 // if not, something went wrong
1753 uint32 count = iTempCache->GetNumEntries();
1754 if (count)
1755 {
1756 LOGERROR((0, "PVMFMemoryBufferWriteDataStreamImpl::Write FAILED Temp Cache not empty"));
1757 status = PVDS_FAILURE;
1758 }
1759 else
1760 {
1761 status = iTempCache->AddEntry(aFrag, fragPtr, fragSize, iFilePtrPos);
1762 if (PVDS_SUCCESS == status)
1763 {
1764 // notify the writer that the buffer should not be freed
1765 // as it has become a part of the cache
1766 status = PVDS_PENDING;
1767 }
1768 }
1769 }
1770 }
1771 else
1772 {
1773 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::Write entirely to perm cache"));
1774
1775 // all of the frag has been made persistent
1776 status = iPermCache->WriteBytes(fragPtr, fragSize, iFilePtrPos);
1777 }
1778 if ((PVDS_SUCCESS == status) || (PVDS_PENDING == status))
1779 {
1780 // see if any read notifications can be satisified
1781 written = true;
1782 }
1783 }
1784 else
1785 {
1786 // this mem frag should be added to temp cache
1787 // If this mem frag does not fit sequentially in the cache, i.e. a reposition has happened
1788 // The cache needs to be flushed and all the existing entries returned
1789 uint32 firstByteOffset = 0;
1790 uint32 lastByteOffset = 0;
1791 iTempCache->GetFileOffsets(firstByteOffset, lastByteOffset);
1792 if (iFilePtrPos != (lastByteOffset + 1))
1793 {
1794 while (1)
1795 {
1796 OsclRefCounterMemFrag* frag;
1797 uint8* ptr;
1798 bool found = iTempCache->RemoveFirstEntry(frag, ptr);
1799 if (!found)
1800 {
1801 // cache should be empty now
1802 break;
1803 }
1804 // return mem frag to stream writer (e.g. protocol engine)
1805 iRequestObserver->DataStreamRequestSync(0, PVDS_REQUEST_MEM_FRAG_RELEASED, (OsclAny*)frag);
1806 }
1807 }
1808 status = iTempCache->AddEntry(aFrag, fragPtr, fragSize, iFilePtrPos);
1809 if (PVDS_SUCCESS == status)
1810 {
1811 written = true;
1812 // notify the writer that the buffer should not be freed
1813 // as it has become a part of the cache
1814 status = PVDS_PENDING;
1815 }
1816 // Check if there are frags that are not being read from
1817 // at the beginning of the cache that can be returned to the writer (protocol engine)
1818 ManageCache();
1819 }
1820 if (written)
1821 {
1822 // advance the write pointer
1823 iFilePtrPos += fragSize;
1824 aNumElements = fragSize;
1825
1826 // Send notification if requested read capacity is available
1827 ManageReadCapacityNotifications();
1828 }
1829 }
1830
1831 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::Write returning %d", status));
1832 return status;
1833 }
1834
1835
1836 OSCL_EXPORT_REF PvmiDataStreamStatus
Seek(PvmiDataStreamSession aSessionID,int32 aOffset,PvmiDataStreamSeekType aOrigin)1837 PVMFMemoryBufferWriteDataStreamImpl::Seek(PvmiDataStreamSession aSessionID, int32 aOffset, PvmiDataStreamSeekType aOrigin)
1838 {
1839 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::Seek offset %d origin %d", aOffset, aOrigin));
1840
1841 PvmiDataStreamStatus status = PVDS_SUCCESS;
1842 // Make sure this is the write session and that the session is open
1843 if ((aSessionID == 0) && (iWriteSessionOpened))
1844 {
1845 // Seek just advances the write pointer
1846 // The content in the cache does not change until the next Write
1847 // Seek is used to discard the data in the stream
1848 switch (aOrigin)
1849 {
1850 case PVDS_SEEK_SET:
1851 iFilePtrPos = aOffset;
1852 break;
1853
1854 case PVDS_SEEK_CUR:
1855 iFilePtrPos += aOffset;
1856 break;
1857
1858 case PVDS_SEEK_END:
1859 if (0 == iContentLength)
1860 {
1861 // content length not known, fail the seek
1862 status = PVDS_FAILURE;
1863 }
1864 else
1865 {
1866 iFilePtrPos = iContentLength - aOffset - 1;
1867 }
1868 break;
1869
1870 default:
1871 status = PVDS_FAILURE;
1872 break;
1873 }
1874 }
1875
1876 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::Seek returning %d", status));
1877 return status;
1878 }
1879
1880
1881 OSCL_EXPORT_REF PvmiDataStreamStatus
Reposition(PvmiDataStreamSession aSessionID,uint32 aOffset,MBDSRepositionMode aMode)1882 PVMFMemoryBufferWriteDataStreamImpl::Reposition(PvmiDataStreamSession aSessionID, uint32 aOffset,
1883 MBDSRepositionMode aMode)
1884 {
1885 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::Reposition"));
1886
1887 uint32 writeCap = 0;
1888 QueryWriteCapacity(0, writeCap);
1889 PvmiDataStreamStatus status = PVDS_SUCCESS;
1890
1891 // Check that aSessionID is valid and is not the WRITE session
1892 if ((aSessionID == 0) ||
1893 (aSessionID > (PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS + PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS)))
1894 {
1895 status = PVDS_FAILURE;
1896 return status;
1897 }
1898 else if (NULL == iRequestObserver)
1899 {
1900 // Protocol engine is not listening
1901 status = PVDS_FAILURE;
1902 return status;
1903 }
1904 else if ((aOffset >= iFilePtrPos)
1905 && ((writeCap != 0) && ((writeCap + iFilePtrPos) > aOffset)))
1906 {
1907 // data is on route. Now check whether we should send new GET and flush the old data or just wait
1908 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::Reposition data is en route, GET request not sent"));
1909 // Check for read position pointers in temp cache
1910 bool found = false;
1911 uint32 smallest = 0xFFFFFFFF;
1912 {
1913 uint32 firstPersistentOffset = 0;
1914 uint32 lastPersistentOffset = 0;
1915 iPermCache->GetPermOffsets(firstPersistentOffset, lastPersistentOffset);
1916 for (int32 i = 0; i < PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS; i++)
1917 {
1918 if ((iReadFilePositions[i].iReadPositionStructValid == true) && (iReadFilePositions[i].iInTempCache == true))
1919 {
1920 if ((0 == i) && (0 == firstPersistentOffset) && (0 == lastPersistentOffset) && (0 == iReadFilePositions[i].iReadFilePtr))
1921 {
1922 // nothing made persistent, ignore session 0 ptr at offset 0
1923 continue;
1924 }
1925 found = true;
1926 //LOGE("Ln %d smalltest %d iReadFilePositions[%d].iReadFilePtr %d ", __LINE__, smallest , i, iReadFilePositions[i].iReadFilePtr );
1927 if (iReadFilePositions[i].iReadFilePtr < smallest)
1928 {
1929 smallest = iReadFilePositions[i].iReadFilePtr;
1930 }
1931 }
1932 }
1933 }
1934 //LOGE("Ln %d found %d smalltest %d iFilePtrPos %d aOffset %d", __LINE__, found, smallest , iFilePtrPos, aOffset );
1935 //LOGE("Ln %d tmpCache [%d %d] iFilePtrPos %d", __LINE__, firstTempByteOffset, lastTempByteOffset , iFilePtrPos);
1936 if (found)
1937 {
1938 if (smallest < iFilePtrPos)
1939 {
1940 uint32 firstTempOffset = 0;
1941 uint32 lastTempOffset = 0;
1942 iTempCache->GetFileOffsets(firstTempOffset, lastTempOffset);
1943 uint32 bytesToWait = aOffset - lastTempOffset;
1944
1945 if (bytesToWait <= PV_MBDS_FWD_SEEKING_NO_GET_REQUEST_THRESHOLD)
1946 {
1947 LOGDEBUG((0, "Ln %d Do nothing. found %d smalltest %d bytesToWait", __LINE__, found, smallest, bytesToWait));
1948 return status;
1949 }
1950 }
1951
1952 if ((smallest >= iFilePtrPos) &&
1953 (iFilePtrPos + PV_MBDS_FWD_SEEKING_NO_GET_REQUEST_THRESHOLD > smallest) &&
1954 ((writeCap != 0) && ((smallest - iFilePtrPos) < writeCap)) &&
1955 (iAVTOffsetDelta < iTempCacheCapacity))
1956 {
1957 //LOGE("Ln %d Do nothing. found %d smalltest %d", __LINE__, found, smallest );
1958 return status;
1959 }
1960 }
1961 }
1962
1963 {
1964 // Only support one outstanding reposition request, do not send another
1965 // If this is requesting the same offset as the outstanding request, return success, otherwise failure
1966 if (true == iRepositionRequest.iOutstanding)
1967 {
1968 if (aOffset < iRepositionRequest.iNewFilePosition)
1969 {
1970 // Definitely not getting the data
1971 status = PVDS_FAILURE;
1972 }
1973 else
1974 {
1975 // TBD
1976 // may have to wait for a long time
1977 }
1978 }
1979 else
1980 {
1981 // This is a non-blocking call, store the request info
1982 // If mode is MBDS_REPOSITION_EXACT, request the exact offset (e.g. connection to data source
1983 // was disrupted, want to continue exactly where the last write left off)
1984 // If mode is MBDS_REPOSITION_WITH_MARGIN, subtract a 64000 bytes from the offset,
1985 // this creates a comfortable margin (e.g. video seeks to 100000, if reposition exactly to 100000
1986 // and then audio then seeks to 90000, another reposition will be needed, not good)
1987 // However, if MakePersistent has been called and the perm cache is not empty,
1988 // do not try to re-fill the perm cache.
1989
1990 if (MBDS_REPOSITION_EXACT == aMode)
1991 {
1992 // Save the requested offset
1993 iRepositionRequest.iNewFilePosition = aOffset;
1994
1995 // When new data comes, only trim from the top
1996 iRepositionRequest.iFlushCache = false;
1997 }
1998 else if (MBDS_REPOSITION_WITH_MARGIN == aMode)
1999 {
2000 // check perm cache status
2001 bool hasPerm = false;
2002 if (iMadePersistent)
2003 {
2004 if (0 != iPermCache->GetNumEntries())
2005 {
2006 hasPerm = true;
2007 uint32 firstPermByteOffset = 0;
2008 uint32 lastPermByteOffset = 0;
2009 iPermCache->GetFileOffsets(firstPermByteOffset, lastPermByteOffset);
2010
2011 // should never reposition outside of the temp cache
2012 if (aOffset >= lastPermByteOffset + PV_MBDS_TEMP_CACHE_TRIM_MARGIN_PS)
2013 {
2014 iRepositionRequest.iNewFilePosition = aOffset - PV_MBDS_TEMP_CACHE_TRIM_MARGIN_PS;
2015 }
2016 else
2017 {
2018 iRepositionRequest.iNewFilePosition = lastPermByteOffset;
2019 }
2020 }
2021 }
2022
2023 if (!hasPerm)
2024 {
2025 // add the margin
2026 if (aOffset > PV_MBDS_TEMP_CACHE_TRIM_MARGIN_PS)
2027 {
2028 iRepositionRequest.iNewFilePosition = aOffset - PV_MBDS_TEMP_CACHE_TRIM_MARGIN_PS;
2029 }
2030 else
2031 {
2032 iRepositionRequest.iNewFilePosition = 0;
2033 }
2034 }
2035
2036 // Set the read pointer to the request offset,
2037 // so that the new data will be kept in the cache
2038 // and not get thrown out because there is no pointer to it
2039 // Reposition should never change the cache location
2040 SetReadPointerPosition(aSessionID, iRepositionRequest.iNewFilePosition);
2041
2042 // When new data comes, the cache can be flushed
2043 iRepositionRequest.iFlushCache = true;
2044 }
2045 else
2046 {
2047 status = PVDS_UNSUPPORTED_MODE;
2048
2049 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::Reposition failed returning %d", status));
2050 return status;
2051 }
2052
2053 // Send reposition request to the Protocol Engine, which should just queue the request
2054 // Write session id is 0
2055 iRepositionRequest.iOutstanding = true;
2056 iRepositionRequest.iRequestCompleted = false;
2057 iRepositionRequest.iSuccess = PVDS_PENDING;
2058
2059 // Read SessionID index is PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS less than the aSessionID passed in
2060 iRepositionRequest.iRepositionSessionID = aSessionID - PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS;
2061
2062 PvmiDataStreamCommandId cmdId = 0;
2063 int32 error = 0;
2064 OSCL_TRY(error, cmdId = iRequestObserver->DataStreamRequest(0, PVDS_REQUEST_REPOSITION, (OsclAny*)iRepositionRequest.iNewFilePosition, (OsclAny*) & iRepositionRequest));
2065 if (error)
2066 {
2067 status = PVDS_FAILURE;
2068 }
2069 if (PVDS_SUCCESS == status)
2070 {
2071 // set a flag to throw away any write data
2072 // and trim the cache, to release buffers back to the writer
2073 iThrowAwayData = true;
2074
2075 // new download session is commencing
2076 iDownloadComplete = false;
2077 }
2078 }
2079 }
2080
2081 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::Reposition returning %d", status));
2082 return status;
2083 }
2084
2085
2086 OSCL_EXPORT_REF uint32
GetCurrentPointerPosition(PvmiDataStreamSession aSessionID)2087 PVMFMemoryBufferWriteDataStreamImpl::GetCurrentPointerPosition(PvmiDataStreamSession aSessionID)
2088 {
2089 uint32 pos = 0;
2090 // Return the write position pointer
2091 // Make sure this is the write session and that the session is open
2092 if ((aSessionID == 0) && (iWriteSessionOpened))
2093 {
2094 pos = iFilePtrPos;
2095 }
2096
2097 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::GetCurrentPointerPosition returning %d", pos));
2098 return pos;
2099 }
2100
2101 OSCL_EXPORT_REF PvmiDataStreamStatus
Flush(PvmiDataStreamSession aSessionID)2102 PVMFMemoryBufferWriteDataStreamImpl::Flush(PvmiDataStreamSession aSessionID)
2103 {
2104 PvmiDataStreamStatus status = PVDS_SUCCESS;
2105 // Make sure this is the write session and that the session is open
2106 if ((aSessionID != 0) || (!iWriteSessionOpened))
2107 {
2108 status = PVDS_FAILURE;
2109 }
2110 else
2111 {
2112 // Empty cache and return mem buffers to writer
2113 // It doesn't matter if there are read sessions still open
2114 // subsequent reads will fail
2115 for (int32 i = 0; i < PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS; i++)
2116 {
2117 if (true == iReadFilePositions[i].iReadPositionStructValid)
2118 {
2119 // write session id is 0 and read session id's are 1 and up
2120 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::Flush read session %d still open!!", i + 1));
2121 }
2122 }
2123 TrimTempCache(MBDS_CACHE_TRIM_EMPTY);
2124 }
2125
2126 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::Flush returning %d", status));
2127 return status;
2128 }
2129
2130 OSCL_EXPORT_REF void
NotifyDownloadComplete()2131 PVMFMemoryBufferWriteDataStreamImpl::NotifyDownloadComplete()
2132 {
2133 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::NotifyDownloadComplete"));
2134
2135 iDownloadComplete = true;
2136
2137 ManageReadCapacityNotifications();
2138 }
2139
2140
2141 OSCL_EXPORT_REF void
SetContentLength(uint32 aContentLength)2142 PVMFMemoryBufferWriteDataStreamImpl::SetContentLength(uint32 aContentLength)
2143 {
2144 iContentLength = aContentLength;
2145
2146 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::SetContentLength %d", iContentLength));
2147 }
2148
2149
2150 OSCL_EXPORT_REF uint32
GetContentLength()2151 PVMFMemoryBufferWriteDataStreamImpl::GetContentLength()
2152 {
2153 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::GetContentLength returning %d", iContentLength));
2154
2155 return iContentLength;
2156 }
2157
2158
2159 OSCL_EXPORT_REF PvmiDataStreamStatus
SetSourceRequestObserver(PvmiDataStreamRequestObserver & aObserver)2160 PVMFMemoryBufferWriteDataStreamImpl::SetSourceRequestObserver(PvmiDataStreamRequestObserver& aObserver)
2161 {
2162 PvmiDataStreamStatus status = PVDS_SUCCESS;
2163 // only one observer per write stream
2164 if (NULL != iRequestObserver)
2165 {
2166 status = PVDS_FAILURE;
2167 }
2168 else
2169 {
2170 iRequestObserver = &aObserver;
2171 }
2172 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::SetSourceRequestObserver returning %d", status));
2173
2174 return status;
2175 }
2176
2177
2178 OSCL_EXPORT_REF void
SourceRequestCompleted(const PVMFCmdResp & aResponse)2179 PVMFMemoryBufferWriteDataStreamImpl::SourceRequestCompleted(const PVMFCmdResp& aResponse)
2180 {
2181 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::SourceRequestCompleted"));
2182
2183 // Currently, we only have reposition requests, if we have other kinds later on, CmdId will become important
2184
2185 // request completely, but still needs to wait for the data to show up
2186 RepositionRequestStruct* reqStruct = (RepositionRequestStruct*)aResponse.GetContext();
2187 reqStruct->iRequestCompleted = true;
2188 if (aResponse.GetCmdStatus() != PVMFSuccess)
2189 {
2190 // do nothing now, log error
2191 reqStruct->iSuccess = PVDS_FAILURE;
2192 LOGERROR((0, "PVMFMemoryBufferWriteDataStreamImpl::SourceRequestCompleted Reposition failed"));
2193 }
2194 else
2195 {
2196 // Success does not mean that all the data is in the cache,
2197 // it only means that the networks has responded with the data
2198 reqStruct->iSuccess = PVDS_SUCCESS;
2199 iThrowAwayData = false;
2200 iFilePtrPos = reqStruct->iNewFilePosition;
2201
2202 if (reqStruct->iFlushCache)
2203 {
2204 TrimTempCache(MBDS_CACHE_TRIM_EMPTY);
2205 }
2206 }
2207
2208 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::SourceRequestCompleted cmdId %d status %d", aResponse.GetCmdId(), aResponse.GetCmdStatus()));
2209 }
2210
2211
SetBufferingCapacityAndTrimMargin(uint32 aMinCapacity,uint32 aTrimMargin)2212 OSCL_EXPORT_REF PvmiDataStreamStatus PVMFMemoryBufferWriteDataStreamImpl::SetBufferingCapacityAndTrimMargin(uint32 aMinCapacity, uint32 aTrimMargin)
2213 {
2214 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_INFO, (2,"PVMFMemoryBufferWriteDataStreamImpl::SetBufferingCapacityAndTrimMargin capacity=%d trim margin=%d", aMinCapacity, aTrimMargin));
2215
2216 /*TODO: pvmi/pvmf/include/pvmi_data_stream_interface.h
2217 if( ( aMinCapacity > SOCKET_NODE_MEMPOOL_SIZE) || ( aTrimMargin > SOCKET_NODE_MEMPOOL_SIZE) ){
2218 LOGERROR((0, "PVMFMemoryBufferWriteDataStreamImpl::SetBufferingCapacityAndTrimMargin failed"));
2219 return PVDS_FAILURE;
2220 }
2221 */
2222 iTempCacheCapacity = aMinCapacity;
2223 iTempCacheTrimThreshold = PV_MBDS_TEMP_CACHE_TRIM_THRESHOLD_PS(iTempCacheCapacity);
2224 iTempCacheTrimMargin = (MBDS_STREAM_FORMAT_SHOUTCAST == iStreamFormat) ? PV_MBDS_TEMP_CACHE_TRIM_MARGIN_SC : aTrimMargin;
2225
2226 return PVDS_SUCCESS;
2227 }
2228
2229
2230 OSCL_EXPORT_REF uint32
QueryBufferingCapacity()2231 PVMFMemoryBufferWriteDataStreamImpl::QueryBufferingCapacity()
2232 {
2233 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::QueryBufferingCapacity returning %d", iTempCacheCapacity));
2234
2235 // return the minimum size of the cache/sliding window
2236 return iTempCacheCapacity;
2237 }
2238
QueryBufferingTrimMargin()2239 OSCL_EXPORT_REF uint32 PVMFMemoryBufferWriteDataStreamImpl::QueryBufferingTrimMargin()
2240 {
2241 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::QueryBufferingTrimMargin returning %d", iTempCacheTrimMargin));
2242 return iTempCacheTrimMargin;
2243 }
2244
2245 OSCL_EXPORT_REF PvmiDataStreamStatus
MakePersistent(int32 aOffset,uint32 aSize)2246 PVMFMemoryBufferWriteDataStreamImpl::MakePersistent(int32 aOffset, uint32 aSize)
2247 {
2248 OSCL_UNUSED_ARG(aOffset);
2249 OSCL_UNUSED_ARG(aSize);
2250
2251 iMadePersistent = true;
2252 return PVDS_SUCCESS;
2253 }
2254
2255
2256 OSCL_EXPORT_REF PvmiDataStreamStatus
SetReadPointerPosition(PvmiDataStreamSession aSessionID,uint32 aFilePosition)2257 PVMFMemoryBufferWriteDataStreamImpl::SetReadPointerPosition(PvmiDataStreamSession aSessionID, uint32 aFilePosition)
2258 {
2259 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::SetReadPointerPosition session %d pos %d", aSessionID, aFilePosition));
2260
2261 if (iMadePersistent && ((0 == iAVTSessionID[0]) || (0 == iAVTSessionID[1]) || (0 == iAVTSessionID[2])))
2262 {
2263 // go through the temp cache looking for the id's of the audio/video/text sessions
2264 PvmiDataStreamSession avtFirst = 0, avtSecond = 0, avtThird = 0;
2265 for (int32 i = 0; i < PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS; i++)
2266 {
2267 if ((iReadFilePositions[i].iReadPositionStructValid == true) && (iReadFilePositions[i].iInTempCache == true))
2268 {
2269 if (0 == avtFirst)
2270 {
2271 avtFirst = i;
2272 }
2273 else if (0 == avtSecond)
2274 {
2275 avtSecond = i;
2276 }
2277 else if (0 == avtThird)
2278 {
2279 avtThird = i;
2280 }
2281 }
2282 }
2283 if ((0 != avtFirst) && (0 != avtSecond))
2284 {
2285 iAVTSessionID[0] = avtFirst;
2286 iAVTSessionID[1] = avtSecond;
2287 if (0 != avtThird)
2288 {
2289 iAVTSessionID[2] = avtThird;
2290 }
2291 }
2292 }
2293
2294 PvmiDataStreamStatus status = PVDS_SUCCESS;
2295 if ((aSessionID == 0) ||
2296 (aSessionID > (PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS + PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS)) ||
2297 (iReadFilePositions[aSessionID - PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS].iReadPositionStructValid != true))
2298 {
2299 LOGERROR((0, "PVMFMemoryBufferWriteDataStreamImpl::SetReadPointerPosition invalid session %d", aSessionID));
2300 status = PVDS_FAILURE;
2301 }
2302 else
2303 {
2304 PvmiDataStreamSession index = aSessionID - PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS;
2305 iReadFilePositions[index].iReadFilePtr = aFilePosition;
2306
2307 // Once MakePersistent has been called
2308 // need to keep track of the av sample offsets in the temp cache, only worry if we have more than 1 avt sessions
2309 if ((true == iReadFilePositions[index].iInTempCache) && (0 != iAVTSessionID[0] && (0 != iAVTSessionID[1])))
2310 {
2311 if ((index == iAVTSessionID[0]) || (index == iAVTSessionID[1]) || (index == iAVTSessionID[2]))
2312 {
2313 // one of the avt file pointers have changed, need to find the largest delta
2314 if (iReadFilePositions[iAVTSessionID[0]].iReadFilePtr > iReadFilePositions[iAVTSessionID[1]].iReadFilePtr)
2315 {
2316 iAVTOffsetDelta = iReadFilePositions[iAVTSessionID[0]].iReadFilePtr - iReadFilePositions[iAVTSessionID[1]].iReadFilePtr;
2317 }
2318 else
2319 {
2320 iAVTOffsetDelta = iReadFilePositions[iAVTSessionID[1]].iReadFilePtr - iReadFilePositions[iAVTSessionID[0]].iReadFilePtr;
2321 }
2322 if (0 != iAVTSessionID[2])
2323 {
2324 uint32 tempDelta = 0;
2325 if (iReadFilePositions[iAVTSessionID[1]].iReadFilePtr > iReadFilePositions[iAVTSessionID[2]].iReadFilePtr)
2326 {
2327 tempDelta = iReadFilePositions[iAVTSessionID[1]].iReadFilePtr > iReadFilePositions[iAVTSessionID[2]].iReadFilePtr;
2328 }
2329 else
2330 {
2331 tempDelta = iReadFilePositions[iAVTSessionID[2]].iReadFilePtr > iReadFilePositions[iAVTSessionID[1]].iReadFilePtr;
2332 }
2333 if (tempDelta > iAVTOffsetDelta)
2334 {
2335 iAVTOffsetDelta = tempDelta;
2336 }
2337 if (iReadFilePositions[iAVTSessionID[0]].iReadFilePtr > iReadFilePositions[iAVTSessionID[2]].iReadFilePtr)
2338 {
2339 tempDelta = iReadFilePositions[iAVTSessionID[0]].iReadFilePtr > iReadFilePositions[iAVTSessionID[2]].iReadFilePtr;
2340 }
2341 else
2342 {
2343 tempDelta = iReadFilePositions[iAVTSessionID[2]].iReadFilePtr > iReadFilePositions[iAVTSessionID[0]].iReadFilePtr;
2344 }
2345 if (tempDelta > iAVTOffsetDelta)
2346 {
2347 iAVTOffsetDelta = tempDelta;
2348 }
2349 }
2350 }
2351 }
2352 }
2353
2354 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::SetReadPointerPosition returning %d", status));
2355 return status;
2356 }
2357
2358
2359 OSCL_EXPORT_REF PvmiDataStreamStatus
SetReadPointerCacheLocation(PvmiDataStreamSession aSessionID,bool aInTempCache)2360 PVMFMemoryBufferWriteDataStreamImpl::SetReadPointerCacheLocation(PvmiDataStreamSession aSessionID, bool aInTempCache)
2361 {
2362 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::SetReadPointerCacheLocation session %d temp cache %d", aSessionID, aInTempCache));
2363
2364 PvmiDataStreamStatus status = PVDS_SUCCESS;
2365 if ((aSessionID == 0) ||
2366 (aSessionID > (PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS + PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS)) ||
2367 (iReadFilePositions[aSessionID - PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS].iReadPositionStructValid != true))
2368 {
2369 LOGERROR((0, "PVMFMemoryBufferWriteDataStreamImpl::SetReadPointerCacheLocation invalid session %d", aSessionID));
2370 status = PVDS_FAILURE;
2371 }
2372 else
2373 {
2374 PvmiDataStreamSession index = aSessionID - PV_MBDS_MAX_NUMBER_OF_WRITE_CONNECTIONS;
2375 iReadFilePositions[index].iInTempCache = aInTempCache;
2376 }
2377 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::SetReadPointerCacheLocation returning %d", status));
2378 return status;
2379
2380 }
2381
2382
2383 OSCL_EXPORT_REF void
ManageReadCapacityNotifications()2384 PVMFMemoryBufferWriteDataStreamImpl::ManageReadCapacityNotifications()
2385 {
2386 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::ManageReadCapacityNotifications"));
2387
2388 // Loop through iReadNotifications for a Read Notification
2389 // Send notification if write pointer has advanced beyond requested read capacity, or
2390 // download has completed
2391
2392 uint32 currFilePosition = iFilePtrPos;
2393 for (uint32 i = 0; i < PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS; i++)
2394 {
2395 // Make sure it a valid iReadNotifications element
2396 // AND the iReadObserver != NULL
2397 if ((iReadNotifications[i].iReadStructValid == true) &&
2398 (iReadNotifications[i].iOutstanding == true) &&
2399 (iReadNotifications[i].iReadObserver != NULL))
2400 {
2401 bool bSend = false;
2402 PVMFStatus status = PVMFFailure;
2403
2404 if ((currFilePosition - iReadNotifications[i].iFilePosition) >
2405 iReadNotifications[i].iReadCapacity)
2406 {
2407 bSend = true;
2408 status = PVMFSuccess;
2409
2410 }
2411 else if (iDownloadComplete)
2412 {
2413 // no more data is coming
2414 // return failure
2415 bSend = true;
2416 }
2417 if (bSend)
2418 {
2419 // Retrieve notification info
2420 PvmiDataStreamObserver* observer = iReadNotifications[i].iReadObserver;
2421 OsclAny* contextData = iReadNotifications[i].iContextData;
2422 PvmiDataStreamCommandId cmdID = iReadNotifications[i].iCommandID;
2423 // Reset the iReadNotifications for the next notification
2424 iReadNotifications[i].iOutstanding = false;
2425 iReadNotifications[i].iReadObserver = NULL;
2426 iReadNotifications[i].iReadCapacity = 0;
2427 iReadNotifications[i].iFilePosition = 0;
2428 iReadNotifications[i].iCommandID = 0;
2429 iReadNotifications[i].iContextData = NULL;
2430 // Form a command response.
2431 PVMFCmdResp resp(cmdID, contextData, status, NULL, NULL);
2432 // Make the Command Complete notification.
2433 observer->DataStreamCommandCompleted(resp);
2434 }
2435 }
2436 }
2437 }
2438
2439
2440 OSCL_EXPORT_REF void
ManageCache()2441 PVMFMemoryBufferWriteDataStreamImpl::ManageCache()
2442 {
2443 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::ManageCache entry"));
2444
2445 // Only need to manage temporary cache,
2446 // leave a 64000 buffer zone at the beginning of cache
2447 // only release the buffers when the cache has reached a certain capacity,
2448 // except in the case of when MakePersistent has just been called,
2449 // where the data may be duplicated in both caches
2450 // The mem frags should be released in the order they sent to MBDS
2451 if (0 == iTempCache->GetNumEntries())
2452 {
2453 // temp cache is empty, nothing to do
2454 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::ManageCache temp cache is empty, do nothing"));
2455 return;
2456 }
2457
2458 // for debug only
2459 for (int32 j = 0; j < PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS; j++)
2460 {
2461 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::ManageCache session %d valid %d cache %d ptr %d",
2462 j + 1, iReadFilePositions[j].iReadPositionStructValid, iReadFilePositions[j].iInTempCache, iReadFilePositions[j].iReadFilePtr));
2463 }
2464
2465 // All parsers have to call MakePersistent to get the cache moving
2466 if (!iMadePersistent)
2467 {
2468 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::ManageCache MakePersistent not yet called"));
2469 return;
2470 }
2471
2472 // If there are no read position pointers in the temp cache, leave the cache alone,
2473 // except in the case where MakePersistent has just been called,
2474 // the data in the perm cache will also be in the temp cache,
2475 // Currently MakePersistent is called with (offset = 0, num of bytes)
2476
2477 // If there are read position pointers in the temp cache,
2478 // find the smallest pointer position,
2479 // subtract 64000 from that and release old mem frags up to that point
2480
2481 uint32 firstPermByteOffset = 0;
2482 uint32 lastPermByteOffset = 0;
2483 iPermCache->GetFileOffsets(firstPermByteOffset, lastPermByteOffset);
2484
2485 uint32 firstPersistentOffset = 0;
2486 uint32 lastPersistentOffset = 0;
2487 iPermCache->GetPermOffsets(firstPersistentOffset, lastPersistentOffset);
2488
2489 uint32 firstTempByteOffset = 0;
2490 uint32 lastTempByteOffset = 0;
2491 iTempCache->GetFileOffsets(firstTempByteOffset, lastTempByteOffset);
2492
2493 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::ManageCache firstPermByteOffset %d lastPermByteOffset %d firstTempByteOffset %d lastTempByteOffset %d",
2494 firstPermByteOffset, lastPermByteOffset, firstTempByteOffset, lastTempByteOffset));
2495
2496 // Check for read position pointers in temp cache
2497 bool found = false;
2498 bool trim = false;
2499 uint32 smallest = 0xFFFFFFFF;
2500 for (int32 i = 0; i < PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS; i++)
2501 {
2502 if ((iReadFilePositions[i].iReadPositionStructValid == true) && (iReadFilePositions[i].iInTempCache == true))
2503 {
2504 if ((0 == i) && (0 == firstPersistentOffset) && (0 == lastPersistentOffset) && (0 == iReadFilePositions[i].iReadFilePtr))
2505 {
2506 // nothing made persistent, ignore session 0 ptr at offset 0
2507 continue;
2508 }
2509 found = true;
2510 if (iReadFilePositions[i].iReadFilePtr < smallest)
2511 {
2512 smallest = iReadFilePositions[i].iReadFilePtr;
2513 }
2514 }
2515 }
2516
2517 if (!found && (0 != iPermCache->GetNumEntries()))
2518 {
2519 // No read position pointers in temp cache and perm cache is not empty
2520 // Check if data in perm cache is also in temp cache (right after MakePersistent)
2521 // If not, don't touch the temp cache
2522 // TBD - what if the bytes are not at the beginning of the clip?
2523 if (!((firstPermByteOffset == firstTempByteOffset) && (lastPermByteOffset <= lastTempByteOffset)))
2524 {
2525 // nothing to do
2526 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::ManageCache no read ptrs in temp cache, do nothing"));
2527 return;
2528 }
2529 else
2530 {
2531 // This is the case right after MakePersistent
2532 // Need to release the mem frags containing duplicated data in the temp cache
2533 trim = true;
2534 smallest = lastPermByteOffset + 1;
2535 }
2536 }
2537
2538 if ((0xFFFFFFFF != smallest) && !trim)
2539 {
2540 // Put in a buffer zone at the beginning of cache (64000 for PS and 4096 for Shoutcast)
2541 // If there is less than 64000 at the beginning, don't touch the cache
2542 // This is important in case there are other read sessions (audio, video, text) that have not yet been opened,
2543 // don't want to throw away any media data that may be needed later
2544 if ((smallest - firstTempByteOffset) <= iTempCacheTrimMargin)
2545 {
2546 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::ManageCache leaving a %d zone, do nothing", iTempCacheTrimMargin));
2547 return;
2548 }
2549 else
2550 {
2551 smallest -= iTempCacheTrimMargin;
2552 }
2553 }
2554
2555 while ((0 != iTempCache->GetNumEntries()) && (trim || (iTempCache->GetTotalBytes() > (iTempCacheTrimThreshold))))
2556 {
2557 // Check if any read pointers are pointing to this frag
2558 uint32 size = 0;
2559 uint32 offset = 0;
2560 iTempCache->GetFirstEntryInfo(offset, size);
2561
2562 if ((offset + size) <= smallest)
2563 {
2564 // this entire fragment is below the zone and can be released if no read pointers are in it
2565 found = true;
2566 for (int32 i = 0; i < PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS; i++)
2567 {
2568 if ((iReadFilePositions[i].iReadPositionStructValid == true) && (iReadFilePositions[i].iInTempCache == true))
2569 {
2570 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::ManageCache ptr %d session %d", iReadFilePositions[i].iReadFilePtr, i + 1));
2571
2572 if ((0 == i) && (0 == firstPersistentOffset) && (0 == lastPersistentOffset) && (0 == iReadFilePositions[i].iReadFilePtr))
2573 {
2574 // nothing made persistent, ignore session 0 ptr at offset 0
2575 continue;
2576 }
2577 if (iReadFilePositions[i].iReadFilePtr < (offset + size))
2578 {
2579 // this pointer is in cache entry, don't release
2580 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::ManageCache found ptr %d session %d in temp cache, done", iReadFilePositions[i].iReadFilePtr, i + 1));
2581 found = false;
2582 break;
2583 }
2584 }
2585 }
2586
2587 if (found)
2588 {
2589 OsclRefCounterMemFrag* frag = NULL;
2590 uint8* fragPtr = NULL;
2591 if (iTempCache->RemoveFirstEntry(frag, fragPtr))
2592 {
2593 // return mem frag to stream writer (e.g. protocol engine)
2594 iRequestObserver->DataStreamRequestSync(0, PVDS_REQUEST_MEM_FRAG_RELEASED, (OsclAny*)frag);
2595 }
2596 }
2597 else
2598 {
2599 // done
2600 break;
2601 }
2602 }
2603 else
2604 {
2605 // done
2606 break;
2607 }
2608 }
2609 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::ManageCache exit"));
2610 }
2611
2612
2613 OSCL_EXPORT_REF void
TrimTempCache(MBDSCacheTrimMode aTrimMode)2614 PVMFMemoryBufferWriteDataStreamImpl::TrimTempCache(MBDSCacheTrimMode aTrimMode)
2615 {
2616 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::TrimTempCache mode %d", aTrimMode));
2617
2618 if (MBDS_CACHE_TRIM_EMPTY == aTrimMode)
2619 {
2620 // empty the cache
2621 while (iTempCache->GetNumEntries() > 0)
2622 {
2623 bool found = false;
2624 OsclRefCounterMemFrag* frag = NULL;
2625 uint8* fragPtr = NULL;
2626 found = iTempCache->RemoveFirstEntry(frag, fragPtr);
2627 if (found)
2628 {
2629 // return mem frag to stream writer (e.g. protocol engine)
2630 iRequestObserver->DataStreamRequestSync(0, PVDS_REQUEST_MEM_FRAG_RELEASED, (OsclAny*)frag);
2631 }
2632 else
2633 {
2634 // should never get here
2635 LOGDEBUG((0, "PVMFMemoryBufferWriteDataStreamImpl::TrimTempCache cache corruption"));
2636 break;
2637 }
2638 }
2639 }
2640 // This is called after a reposition request has been issued to the server
2641 // Need to release as many buffers as possible to faciliate cache refill with new data
2642 // For seek (max), trim from both ends and keep the middle intact
2643 // For source reconnect (half), trim from bottom end until 1/2 of the buffers are returned.
2644
2645 if ((MBDS_CACHE_TRIM_HEAD_AND_TAIL == aTrimMode) || (MBDS_CACHE_TRIM_HEAD_ONLY == aTrimMode))
2646 {
2647 // Trim from the beginning
2648 while (iTempCache->GetNumEntries() > 0)
2649 {
2650 bool releaseBuf = true;
2651 uint32 size = 0;
2652 uint32 offset = 0;
2653 iTempCache->GetFirstEntryInfo(offset, size);
2654
2655 for (int i = 0; i < PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS; i++)
2656 {
2657 if ((true == iReadFilePositions[i].iReadPositionStructValid) &&
2658 (iReadFilePositions[i].iInTempCache == true) &&
2659 (iReadFilePositions[i].iReadFilePtr >= offset) &&
2660 (iReadFilePositions[i].iReadFilePtr < (offset + size)))
2661 {
2662 // don't release this buffer
2663 releaseBuf = false;
2664 break;
2665 }
2666 }
2667 if (releaseBuf)
2668 {
2669 OsclRefCounterMemFrag* frag;
2670 uint8* fragPtr;
2671 bool found = iTempCache->RemoveFirstEntry(frag, fragPtr);
2672 if (found)
2673 {
2674 // return mem frag to stream writer (e.g. protocol engine)
2675 iRequestObserver->DataStreamRequestSync(0, PVDS_REQUEST_MEM_FRAG_RELEASED, (OsclAny*)frag);
2676 }
2677 }
2678 else
2679 {
2680 // done trimming from the beginning
2681 break;
2682 }
2683 }
2684 }
2685
2686 if ((MBDS_CACHE_TRIM_HEAD_AND_TAIL == aTrimMode) || (MBDS_CACHE_TRIM_TAIL_ONLY == aTrimMode))
2687 {
2688 // Trim from the end, up to 1/2 of max cache size
2689 while (((MBDS_CACHE_TRIM_HEAD_AND_TAIL == aTrimMode) && (iTempCache->GetNumEntries() > 0)) ||
2690 ((MBDS_CACHE_TRIM_TAIL_ONLY == aTrimMode) && (iTempCache->GetTotalBytes() > (iTempCacheCapacity >> 1))))
2691 {
2692 bool releaseBuf = true;
2693 uint32 size = 0;
2694 uint32 offset = 0;
2695 iTempCache->GetLastEntryInfo(offset, size);
2696
2697 for (int i = 0; i < PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS; i++)
2698 {
2699 if ((true == iReadFilePositions[i].iReadPositionStructValid) &&
2700 (iReadFilePositions[i].iInTempCache == true) &&
2701 (iReadFilePositions[i].iReadFilePtr >= offset) &&
2702 (iReadFilePositions[i].iReadFilePtr < (offset + size)))
2703 {
2704 // don't release this buffer
2705 releaseBuf = false;
2706 break;
2707 }
2708 }
2709 if (releaseBuf)
2710 {
2711 OsclRefCounterMemFrag* frag;
2712 uint8* fragPtr;
2713 bool found = iTempCache->RemoveLastEntry(frag, fragPtr);
2714 if (found)
2715 {
2716 // return mem frag to stream writer (e.g. protocol engine)
2717 iRequestObserver->DataStreamRequestSync(0, PVDS_REQUEST_MEM_FRAG_RELEASED, (OsclAny*)frag);
2718 }
2719 }
2720 else
2721 {
2722 // done trimming from the end
2723 break;
2724 }
2725 }
2726 }
2727
2728 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::TrimTempCache exit"));
2729 }
2730
2731
2732 OSCL_EXPORT_REF void
UpdateReadPointersAfterMakePersistent()2733 PVMFMemoryBufferWriteDataStreamImpl::UpdateReadPointersAfterMakePersistent()
2734 {
2735 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::UpdateReadPointersAfterMakePersistent"));
2736
2737 uint32 firstOffset = 0;
2738 uint32 lastOffset = 0;
2739 iPermCache->GetFileOffsets(firstOffset, lastOffset);
2740
2741 for (int32 i = 0; i < PV_MBDS_MAX_NUMBER_OF_READ_CONNECTIONS; i++)
2742 {
2743 if ((true == iReadFilePositions[i].iReadPositionStructValid) && (true == iReadFilePositions[i].iInTempCache))
2744 {
2745 if ((iReadFilePositions[i].iReadFilePtr >= firstOffset) &&
2746 (iReadFilePositions[i].iReadFilePtr <= lastOffset))
2747 {
2748 // data is in perm cache after MakePersistent
2749 iReadFilePositions[i].iInTempCache = false;
2750 }
2751 }
2752 }
2753 }
2754
2755
2756 OSCL_EXPORT_REF bool
GetPermCachePersistence(uint32 & aFirstOffset,uint32 & aLastOffset)2757 PVMFMemoryBufferWriteDataStreamImpl::GetPermCachePersistence(uint32& aFirstOffset, uint32& aLastOffset)
2758 {
2759 uint32 firstPersistentOffset = 0;
2760 uint32 lastPersistentOffset = 0;
2761 iPermCache->GetPermOffsets(firstPersistentOffset, lastPersistentOffset);
2762
2763 LOGTRACE((0, "PVMFMemoryBufferWriteDataStreamImpl::GetPermCachePersistence MakePersistent called %d first offset %d last offset %d",
2764 iMadePersistent, firstPersistentOffset, lastPersistentOffset));
2765
2766 if (iMadePersistent)
2767 {
2768 aFirstOffset = firstPersistentOffset;
2769 aLastOffset = lastPersistentOffset;
2770 }
2771 return iMadePersistent;
2772 }
2773
2774 OSCL_EXPORT_REF void
SetStreamFormat(MBDSStreamFormat aStreamFormat)2775 PVMFMemoryBufferWriteDataStreamImpl::SetStreamFormat(MBDSStreamFormat aStreamFormat)
2776 {
2777 iStreamFormat = aStreamFormat;
2778 }
2779
2780 OSCL_EXPORT_REF void
SetTempCacheCapacity(uint32 aCapacity)2781 PVMFMemoryBufferWriteDataStreamImpl::SetTempCacheCapacity(uint32 aCapacity)
2782 {
2783 iTempCacheCapacity = aCapacity;
2784 }
2785
2786 OSCL_EXPORT_REF MBDSStreamFormat
GetStreamFormat()2787 PVMFMemoryBufferWriteDataStreamImpl::GetStreamFormat()
2788 {
2789 return iStreamFormat;
2790 }
2791
2792 OSCL_EXPORT_REF uint32
GetTempCacheCapacity()2793 PVMFMemoryBufferWriteDataStreamImpl::GetTempCacheCapacity()
2794 {
2795 return iTempCacheCapacity;
2796 }
2797
2798 //////////////////////////////////////////////////////////////////////
2799 // PVMFMemoryBufferDataStream
2800 //////////////////////////////////////////////////////////////////////
2801 OSCL_EXPORT_REF
PVMFMemoryBufferDataStream(PVMFFormatType & aStreamFormat,uint32 aTempCacheCapacity)2802 PVMFMemoryBufferDataStream::PVMFMemoryBufferDataStream(PVMFFormatType& aStreamFormat, uint32 aTempCacheCapacity)
2803 {
2804 // Create a temporary cache and a permanent cache
2805 iTemporaryCache = OSCL_NEW(PVMFMemoryBufferDataStreamTempCache, ());
2806 iPermanentCache = OSCL_NEW(PVMFMemoryBufferDataStreamPermCache, ());
2807
2808 // set the stream format and the temp cache size
2809 MBDSStreamFormat streamFormat = MBDS_STREAM_FORMAT_PROGRESSIVE_PLAYBACK;
2810 if (aStreamFormat == PVMF_MIME_DATA_SOURCE_SHOUTCAST_URL)
2811 {
2812 streamFormat = MBDS_STREAM_FORMAT_SHOUTCAST;
2813 }
2814
2815 // Create the two factories
2816 iWriteDataStreamFactory = OSCL_NEW(PVMFMemoryBufferWriteDataStreamFactoryImpl, (iTemporaryCache, iPermanentCache, streamFormat, aTempCacheCapacity));
2817 iReadDataStreamFactory = OSCL_NEW(PVMFMemoryBufferReadDataStreamFactoryImpl, (iTemporaryCache, iPermanentCache));
2818
2819 // Now create a iWriteDataStream
2820 PVUuid uuid = PVMIDataStreamSyncInterfaceUuid;
2821 iWriteDataStream = iWriteDataStreamFactory->CreatePVMFCPMPluginAccessInterface(uuid);
2822
2823 // Set the pointer in the iReadDataStreamFactory
2824 iReadDataStreamFactory->SetWriteDataStreamPtr(iWriteDataStream);
2825
2826 iLogger = PVLogger::GetLoggerObject("PVMFMemoryBufferDataStream");
2827 LOGTRACE((0, "PVMFMemoryBufferDataStream::PVMFMemoryBufferDataStream"));
2828 }
2829
2830 OSCL_EXPORT_REF
~PVMFMemoryBufferDataStream()2831 PVMFMemoryBufferDataStream::~PVMFMemoryBufferDataStream()
2832 {
2833 LOGTRACE((0, "PVMFMemoryBufferDataStream::~PVMFMemoryBufferDataStream"));
2834
2835 // Delete the two DataStreamFactories
2836 OSCL_DELETE(iWriteDataStreamFactory);
2837 OSCL_DELETE(iReadDataStreamFactory);
2838
2839 // Delete the caches
2840 OSCL_DELETE(iTemporaryCache);
2841 OSCL_DELETE(iPermanentCache);
2842
2843 iLogger = NULL;
2844 }
2845
2846 OSCL_EXPORT_REF PVMFDataStreamFactory*
GetReadDataStreamFactoryPtr()2847 PVMFMemoryBufferDataStream::GetReadDataStreamFactoryPtr()
2848 {
2849 LOGTRACE((0, "PVMFMemoryBufferDataStream::GetReadDataStreamFactoryPtr"));
2850
2851 return OSCL_STATIC_CAST(PVMFDataStreamFactory*, iReadDataStreamFactory);
2852 }
2853
2854 OSCL_EXPORT_REF PVMFDataStreamFactory*
GetWriteDataStreamFactoryPtr()2855 PVMFMemoryBufferDataStream::GetWriteDataStreamFactoryPtr()
2856 {
2857 LOGTRACE((0, "PVMFMemoryBufferDataStream::GetWriteDataStreamFactoryPtr"));
2858
2859 return OSCL_STATIC_CAST(PVMFDataStreamFactory*, iWriteDataStreamFactory);
2860 }
2861
2862
2863 // Called by download manager when buffering is complete
2864 OSCL_EXPORT_REF void
NotifyDownloadComplete()2865 PVMFMemoryBufferDataStream::NotifyDownloadComplete()
2866 {
2867 LOGTRACE((0, "PVMFMemoryBufferDataStream::NotifyDownloadComplete"));
2868
2869 if (iReadDataStreamFactory != NULL)
2870 {
2871 iReadDataStreamFactory->NotifyDownloadComplete();
2872 }
2873 if (iWriteDataStreamFactory != NULL)
2874 {
2875 iWriteDataStreamFactory->NotifyDownloadComplete();
2876 }
2877 }
2878
2879
2880 //////////////////////////////////////////////////////////////////////
2881 // PVMFMemoryBufferDataStreamTempCache
2882 //////////////////////////////////////////////////////////////////////
PVMFMemoryBufferDataStreamTempCache()2883 PVMFMemoryBufferDataStreamTempCache::PVMFMemoryBufferDataStreamTempCache()
2884 {
2885 iTotalBytes = 0;
2886 iFirstByteFileOffset = 0;
2887 iLastByteFileOffset = 0;
2888
2889 iLogger = PVLogger::GetLoggerObject("PVMFMemoryBufferDataStream");
2890 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::PVMFMemoryBufferDataStreamTempCache %x", this));
2891 }
2892
2893
~PVMFMemoryBufferDataStreamTempCache()2894 PVMFMemoryBufferDataStreamTempCache::~PVMFMemoryBufferDataStreamTempCache()
2895 {
2896 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::~PVMFMemoryBufferDataStreamTempCache %x", this));
2897
2898 // clean out the cache, remove reference to mem frags is good enough
2899 if (!iEntries.empty())
2900 {
2901 iEntries.clear();
2902 }
2903
2904 iLogger = NULL;
2905 }
2906
2907
2908 uint32
GetTotalBytes()2909 PVMFMemoryBufferDataStreamTempCache::GetTotalBytes()
2910 {
2911 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::GetTotalBytes returning %d", iTotalBytes));
2912 return iTotalBytes;
2913 }
2914
2915
2916 void
GetFileOffsets(uint32 & aFirstByte,uint32 & aLastByte)2917 PVMFMemoryBufferDataStreamTempCache::GetFileOffsets(uint32& aFirstByte, uint32& aLastByte)
2918 {
2919
2920 aFirstByte = iFirstByteFileOffset;
2921 aLastByte = iLastByteFileOffset;
2922
2923 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::GetFileOffsets returning first %d last %d", iFirstByteFileOffset, iLastByteFileOffset));
2924 }
2925
2926
2927 PvmiDataStreamStatus
AddEntry(OsclRefCounterMemFrag * aFrag,uint8 * aFragPtr,uint32 aFragSize,uint32 aFileOffset)2928 PVMFMemoryBufferDataStreamTempCache::AddEntry(OsclRefCounterMemFrag* aFrag, uint8* aFragPtr, uint32 aFragSize, uint32 aFileOffset)
2929 {
2930 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::AddEntry ptr %x size %d offset %d", aFragPtr, aFragSize, aFileOffset));
2931
2932 PvmiDataStreamStatus status = PVDS_SUCCESS;
2933 // Create an entry for the cache
2934 // Caller is write data stream,
2935 // it has checked for contiguous write
2936 // May want to double check, just in case
2937 if (!iEntries.empty() && (aFileOffset != (iLastByteFileOffset + 1)))
2938 {
2939 status = PVDS_INVALID_REQUEST;
2940 }
2941 else
2942 {
2943 MBDSTempCacheEntry* entry = (MBDSTempCacheEntry*)OSCL_MALLOC(sizeof(struct MBDSTempCacheEntry));
2944 if (entry)
2945 {
2946 entry->frag = aFrag;
2947 entry->fragPtr = aFragPtr;
2948 entry->fragSize = aFragSize;
2949 entry->fileOffset = aFileOffset;
2950
2951 iEntries.push_back(entry);
2952
2953 if (1 == iEntries.size())
2954 {
2955 // If there is only one entry,
2956 // set the first byte offset
2957 iFirstByteFileOffset = aFileOffset;
2958 iLastByteFileOffset = iFirstByteFileOffset + aFragSize - 1;
2959 }
2960 else
2961 {
2962 iLastByteFileOffset += aFragSize;
2963 }
2964 iTotalBytes += aFragSize;
2965
2966 LOGDEBUG((0, "PVMFMemoryBufferDataStreamTempCache::AddEntry %x size %d first %d last %d total %d",
2967 entry, aFragSize, iFirstByteFileOffset, iLastByteFileOffset, iTotalBytes));
2968 // for debugging
2969 uint8 data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2970 int32 count = 16;
2971 if (aFragSize < 16)
2972 count = aFragSize;
2973 for (int32 i = 0; i < count; i++)
2974 {
2975 data[i] = *(aFragPtr + i);
2976 }
2977 LOGDEBUG((0, "%2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
2978 data[0], data[1], data[2], data[3], data[4], data[5], data[6],
2979 data[7], data[8], data[9], data[10], data[11], data[12], data[13],
2980 data[14], data[15]));
2981 }
2982 else
2983 {
2984 status = PVDS_FAILURE;
2985 }
2986 }
2987
2988 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::AddEntry returning %d", status));
2989 return status;
2990 }
2991
2992
2993
2994 bool
RemoveFirstEntry(OsclRefCounterMemFrag * & aFrag,uint8 * & aFragPtr)2995 PVMFMemoryBufferDataStreamTempCache::RemoveFirstEntry(OsclRefCounterMemFrag*& aFrag, uint8*& aFragPtr)
2996 {
2997 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::RemoveFirstEntry first %d last %d total %d", iFirstByteFileOffset, iLastByteFileOffset, iTotalBytes));
2998
2999 bool found = false;
3000
3001 if (!iEntries.empty())
3002 {
3003 // Remove and return the first/oldest entry in the cache and free the memory
3004 MBDSTempCacheEntry* entry = iEntries.front();
3005
3006 found = true;
3007
3008 #if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
3009 uint32 offset = entry->fileOffset;
3010 #endif
3011 uint32 size = entry->fragSize;
3012
3013 aFrag = entry->frag;
3014 aFragPtr = entry->fragPtr;
3015
3016 iEntries.erase(iEntries.begin());
3017
3018 OSCL_FREE(entry);
3019
3020 if (!iEntries.empty())
3021 {
3022 iTotalBytes -= size;
3023
3024 // Next entry becomes first entry
3025 entry = iEntries.front();
3026 iFirstByteFileOffset = entry->fileOffset;
3027 }
3028 else
3029 {
3030 // no more entries
3031 iFirstByteFileOffset = 0;
3032 iLastByteFileOffset = 0;
3033 iTotalBytes = 0;
3034 }
3035
3036 #if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
3037 LOGDEBUG((0, "PVMFMemoryBufferDataStreamTempCache::RemoveFirstEntry %x offset %d size %d first %d last %d total %d",
3038 entry, offset, size, iFirstByteFileOffset, iLastByteFileOffset, iTotalBytes));
3039 #endif
3040
3041 }
3042
3043 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::RemoveFirstEntry returning %d", (int)found));
3044 return found;
3045 }
3046
3047
3048 bool
RemoveLastEntry(OsclRefCounterMemFrag * & aFrag,uint8 * & aFragPtr)3049 PVMFMemoryBufferDataStreamTempCache::RemoveLastEntry(OsclRefCounterMemFrag*& aFrag, uint8*& aFragPtr)
3050 {
3051 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::RemoveLastEntry first %d last %d total %d", iFirstByteFileOffset, iLastByteFileOffset, iTotalBytes));
3052
3053 bool found = false;
3054
3055 if (!iEntries.empty())
3056 {
3057 // Remove and return the last/newest entry in the cache
3058 // Free the memory
3059 MBDSTempCacheEntry* entry = iEntries.back();
3060
3061 found = true;
3062
3063 uint32 offset = entry->fileOffset;
3064 uint32 size = entry->fragSize;
3065
3066 aFrag = entry->frag;
3067 aFragPtr = entry->fragPtr;
3068
3069 iEntries.pop_back();
3070
3071 OSCL_FREE(entry);
3072
3073 if (!iEntries.empty())
3074 {
3075 // Second last entry becomes last entry
3076 iTotalBytes -= size;
3077 iLastByteFileOffset = offset - 1;
3078 }
3079 else
3080 {
3081 // no more entries
3082 iFirstByteFileOffset = 0;
3083 iLastByteFileOffset = 0;
3084 iTotalBytes = 0;
3085 }
3086
3087 LOGDEBUG((0, "PVMFMemoryBufferDataStreamTempCache::RemoveLastEntry %x offset %d size %d first %d last %d total %d",
3088 entry, offset, size, iFirstByteFileOffset, iLastByteFileOffset, iTotalBytes));
3089 }
3090
3091 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::RemoveLastEntry returning %d", (int)found));
3092 return found;
3093 }
3094
3095
3096 uint32
ReadBytes(uint8 * aBuffer,uint32 aFirstByte,uint32 aLastByte,uint32 & firstEntry)3097 PVMFMemoryBufferDataStreamTempCache::ReadBytes(uint8* aBuffer, uint32 aFirstByte, uint32 aLastByte, uint32& firstEntry)
3098 {
3099 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::ReadBytes buf %x first %d last %d", aBuffer, aFirstByte, aLastByte));
3100
3101 // Caller is the read data stream, it limits the read to what is in the cache
3102 // the first byte should be in the cache, need to go through the cache entries for the file offset
3103 bool found = false;
3104 uint32 count = iEntries.size();
3105 uint32 bytesRead = 0;
3106 uint32 bytesToRead = 0;
3107 uint8* dataPtr = NULL;
3108 uint8* bufferPtr = aBuffer;
3109
3110 firstEntry = 0;
3111
3112 for (uint32 i = 0; i < count; i++)
3113 {
3114 if (!found)
3115 {
3116 // haven't found the first offset yet
3117 if ((aFirstByte >= iEntries[i]->fileOffset) && (aFirstByte < (iEntries[i]->fileOffset + iEntries[i]->fragSize)))
3118 {
3119 // the first byte to be read is in this frag
3120 found = true;
3121 if (aLastByte < (iEntries[i]->fileOffset + iEntries[i]->fragSize))
3122 {
3123 //LOGDEBUG((0, "TC1 entry %d offset %d size %d", i, iEntries[i]->fileOffset, iEntries[i]->fragSize));
3124 // every byte to be read is in this one frag
3125 dataPtr = iEntries[i]->fragPtr + (aFirstByte - iEntries[i]->fileOffset);
3126 bytesToRead = aLastByte - aFirstByte + 1;
3127 // copy the data to the buffer
3128 oscl_memcpy(bufferPtr, dataPtr, bytesToRead);
3129 bytesRead += bytesToRead;
3130 firstEntry = i;
3131 // done
3132 break;
3133 }
3134 else
3135 {
3136 //LOGDEBUG((0, "TC2 entry %d offset %d size %d", i, iEntries[i]->fileOffset, iEntries[i]->fragSize));
3137 // only a portion is in this frag
3138 dataPtr = iEntries[i]->fragPtr + (aFirstByte - iEntries[i]->fileOffset);
3139 bytesToRead = iEntries[i]->fragSize - (aFirstByte - iEntries[i]->fileOffset);
3140 // copy the data, the rest of the data should be in the next frag or frags
3141 oscl_memcpy(bufferPtr, dataPtr, bytesToRead);
3142 bytesRead += bytesToRead;
3143 bufferPtr += bytesToRead;
3144 firstEntry = i;
3145 }
3146 }
3147 }
3148 else
3149 {
3150 // the first byte was in the previous frag, more data to copy from this frag
3151 if (aLastByte < (iEntries[i]->fileOffset + iEntries[i]->fragSize))
3152 {
3153 //LOGDEBUG((0, "TC3 entry %d offset %d size %d", i, iEntries[i]->fileOffset, iEntries[i]->fragSize));
3154 // what is left to be read is in this one frag
3155 dataPtr = iEntries[i]->fragPtr;
3156 bytesToRead = aLastByte - iEntries[i]->fileOffset + 1;
3157 // copy the data to the buffer
3158 oscl_memcpy(bufferPtr, dataPtr, bytesToRead);
3159 bytesRead += bytesToRead;
3160 // done
3161 break;
3162 }
3163 else
3164 {
3165 //LOGDEBUG((0, "TC4 entry %d offset %d size %d", i, iEntries[i]->fileOffset, iEntries[i]->fragSize));
3166 // all of this frag is needed
3167 dataPtr = iEntries[i]->fragPtr;
3168 bytesToRead = iEntries[i]->fragSize;
3169 // copy the data, the rest of the data should be in the next frag or frags
3170 oscl_memcpy(bufferPtr, dataPtr, bytesToRead);
3171 bytesRead += bytesToRead;
3172 bufferPtr += bytesToRead;
3173 }
3174 }
3175 }
3176
3177 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::ReadBytes returning %d firstEntry %d", bytesRead, firstEntry));
3178 return bytesRead;
3179 }
3180
3181
3182 void
GetFirstEntryInfo(uint32 & entryOffset,uint32 & entrySize)3183 PVMFMemoryBufferDataStreamTempCache::GetFirstEntryInfo(uint32& entryOffset, uint32& entrySize)
3184 {
3185 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::GetFirstEntryInfo"));
3186
3187 // Return the frag size of the first/oldest entry in cache
3188 if (!iEntries.empty())
3189 {
3190 MBDSTempCacheEntry* entry = iEntries.front();
3191
3192 entrySize = entry->fragSize;
3193 entryOffset = entry->fileOffset;
3194 }
3195
3196 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::GetFirstEntryInfo returning offset %d size %d", entryOffset, entrySize));
3197 }
3198
3199
3200 void
GetLastEntryInfo(uint32 & entryOffset,uint32 & entrySize)3201 PVMFMemoryBufferDataStreamTempCache::GetLastEntryInfo(uint32& entryOffset, uint32& entrySize)
3202 {
3203 LOGTRACE((0, "PVMFMemoryBufferDataStreamCache::GetLastEntryInfo"));
3204
3205 // Return the frag size of the last/newest entry in cache
3206 if (!iEntries.empty())
3207 {
3208 MBDSTempCacheEntry* entry = iEntries.back();
3209
3210 entrySize = entry->fragSize;
3211 entryOffset = entry->fileOffset;
3212 }
3213
3214 LOGTRACE((0, "PVMFMemoryBufferDataStreamCache::GetFirstEntryInfo returning offset %d size %d", entryOffset, entrySize));
3215 }
3216
3217
3218 uint32
GetNumEntries()3219 PVMFMemoryBufferDataStreamTempCache::GetNumEntries()
3220 {
3221 LOGTRACE((0, "PVMFMemoryBufferDataStreamTempCache::GetNumEntries returning %d", iEntries.size()));
3222 // return number of entries in cache
3223 return iEntries.size();
3224 }
3225
3226
3227 //////////////////////////////////////////////////////////////////////
3228 // PVMFMemoryBufferDataStreamPermCache
3229 //////////////////////////////////////////////////////////////////////
PVMFMemoryBufferDataStreamPermCache()3230 PVMFMemoryBufferDataStreamPermCache::PVMFMemoryBufferDataStreamPermCache()
3231 {
3232 iTotalBytes = 0;
3233 iTotalBufferAlloc = 0;
3234 iFirstByteFileOffset = 0;
3235 iLastByteFileOffset = 0;
3236 iFirstPermByteOffset = 0;
3237 iLastPermByteOffset = 0;
3238
3239 iLogger = PVLogger::GetLoggerObject("PVMFMemoryBufferDataStream");
3240 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::PVMFMemoryBufferDataStreamPermCache %x", this));
3241 }
3242
3243
3244
~PVMFMemoryBufferDataStreamPermCache()3245 PVMFMemoryBufferDataStreamPermCache::~PVMFMemoryBufferDataStreamPermCache()
3246 {
3247 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::~PVMFMemoryBufferDataStreamPermCache %x", this));
3248
3249 // clean out the cache, need to free the memory
3250 if (!iEntries.empty())
3251 {
3252 while (!iEntries.empty())
3253 {
3254 uint8* memPtr = iEntries[0]->bufPtr;
3255 if (memPtr)
3256 {
3257 oscl_free(memPtr);
3258 }
3259 iEntries.erase(iEntries.begin());
3260 }
3261 }
3262
3263 iLogger = NULL;
3264 }
3265
3266
3267 uint32
GetTotalBytes()3268 PVMFMemoryBufferDataStreamPermCache::GetTotalBytes()
3269 {
3270 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::GetTotalBytes returning %d", iTotalBytes));
3271 return iTotalBytes;
3272 }
3273
3274
3275 void
GetFileOffsets(uint32 & aFirstByte,uint32 & aLastByte)3276 PVMFMemoryBufferDataStreamPermCache::GetFileOffsets(uint32& aFirstByte, uint32& aLastByte)
3277 {
3278 aFirstByte = iFirstByteFileOffset;
3279 aLastByte = iLastByteFileOffset;
3280
3281 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::GetFileOffsets returning first %d last %d", aFirstByte, aLastByte));
3282 }
3283
3284
3285 void
GetPermOffsets(uint32 & aFirstByte,uint32 & aLastByte)3286 PVMFMemoryBufferDataStreamPermCache::GetPermOffsets(uint32& aFirstByte, uint32& aLastByte)
3287 {
3288 aFirstByte = iFirstPermByteOffset;
3289 aLastByte = iLastPermByteOffset;
3290
3291 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::GetPermOffsets returning first %d last %d", aFirstByte, aLastByte));
3292 }
3293
3294 PvmiDataStreamStatus
AddEntry(uint8 * aBufPtr,uint32 aBufSize,uint8 * aFillPtr,uint32 aFirstOffset,uint32 aLastOffset,uint32 aFillOffset,uint32 aFillSize)3295 PVMFMemoryBufferDataStreamPermCache::AddEntry(uint8* aBufPtr, uint32 aBufSize, uint8* aFillPtr, uint32 aFirstOffset,
3296 uint32 aLastOffset, uint32 aFillOffset, uint32 aFillSize)
3297 {
3298 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::AddEntry bufPtr %x bufSize %d fillPtr %x firstOffset %d lastOffset %d fillOffset %d fillSize %d",
3299 aBufPtr, aBufSize, aFillPtr, aFirstOffset, aLastOffset, aFillOffset, aFillSize));
3300
3301 PvmiDataStreamStatus status = PVDS_SUCCESS;
3302 // caller should have checked for contiguous write
3303 // may want to double check, just in case
3304 if (!iEntries.empty() && ((aFirstOffset != (iLastByteFileOffset + 1)) && (aLastOffset != iFirstByteFileOffset - 1)))
3305 {
3306 status = PVDS_INVALID_REQUEST;
3307 LOGERROR((0, "PVMFMemoryBufferDataStreamPermCache::AddEntry FAILED not contiguous entry"));
3308 }
3309 else
3310 {
3311 MBDSPermCacheEntry* entry = (MBDSPermCacheEntry*)OSCL_MALLOC(sizeof(struct MBDSPermCacheEntry));
3312 if (entry)
3313 {
3314 entry->bufPtr = aBufPtr;
3315 entry->bufSize = aBufSize;
3316 entry->fillBufPtr = aFillPtr;
3317 entry->firstFileOffset = aFirstOffset;
3318 entry->lastFileOffset = aLastOffset;
3319 entry->fillFileOffset = aFillOffset;
3320 entry->fillSize = aFillSize;
3321
3322 // the entry can be added to the beginning or the end of the cache
3323 if (!iEntries.empty() && (aLastOffset == iFirstByteFileOffset - 1))
3324 {
3325 // adding to the beginning
3326 iEntries.push_front(entry);
3327 // first byte made persistent
3328 iFirstPermByteOffset = aFirstOffset;
3329 // data may not be here yet
3330 if (0 != aFillSize)
3331 {
3332 iFirstByteFileOffset = aFirstOffset;
3333 }
3334 }
3335 else
3336 {
3337 // adding to the end
3338 iEntries.push_back(entry);
3339 // last byte to be made persistent
3340 iLastPermByteOffset = aLastOffset;
3341 // data may not be here yet
3342 if (0 != aFillSize)
3343 {
3344 if (aFillSize == aBufSize)
3345 {
3346 iLastByteFileOffset = aLastOffset;
3347 }
3348 else
3349 {
3350 iLastByteFileOffset = aFillOffset - 1;
3351 }
3352 }
3353 }
3354 iTotalBytes += aFillSize;
3355 iTotalBufferAlloc += aBufSize;
3356 // for debugging use
3357 LOGDEBUG((0, "PVMFMemoryBufferDataStreamPermCache::AddEntry %x bufsize %d fillsize %d first %d last %d total %d",
3358 entry, aBufSize, aFillSize, iFirstByteFileOffset, iLastByteFileOffset, iTotalBytes));
3359 uint8 data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
3360 int32 count = 16;
3361 if (aBufSize < 16)
3362 count = aBufSize;
3363 for (int32 i = 0; i < count; i++)
3364 {
3365 data[i] = *(aBufPtr + i);
3366 }
3367 LOGDEBUG((0, "%2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
3368 data[0], data[1], data[2], data[3], data[4], data[5], data[6],
3369 data[7], data[8], data[9], data[10], data[11], data[12], data[13],
3370 data[14], data[15]));
3371 }
3372 else
3373 {
3374 status = PVDS_FAILURE;
3375 }
3376 }
3377
3378 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::AddEntry returning %d", status));
3379 return status;
3380 }
3381
3382
3383 PvmiDataStreamStatus
WriteBytes(uint8 * aFragPtr,uint32 aFragSize,uint32 aFileOffset)3384 PVMFMemoryBufferDataStreamPermCache::WriteBytes(uint8* aFragPtr, uint32 aFragSize, uint32 aFileOffset)
3385 {
3386 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::WriteBytes aFragPtr %x aFragSize %d aFileOffset %d", aFragPtr, aFragSize, aFileOffset));
3387
3388 // make sure cache is not empty
3389 if (iEntries.empty())
3390 {
3391 LOGDEBUG((0, "PVMFMemoryBufferDataStreamPermCache::WriteBytes Failed invalid request"));
3392 return PVDS_INVALID_REQUEST;
3393 }
3394 // the cache entry/entries has already been allocated and added to the cache
3395 // find the cache entry that matches the file offset
3396 // copy the data into the cache and update the data structure
3397 // caller is responsible to make sure that the cache entries are in the cache
3398 bool found = false;
3399 uint32 entry = 0;
3400 for (uint32 i = 0; i < iEntries.size(); i++)
3401 {
3402 // find the first cache entry in which the file offset resides
3403 if ((aFileOffset >= iEntries[i]->firstFileOffset) && (aFileOffset <= iEntries[i]->lastFileOffset))
3404 {
3405 // allow writing over existing data,
3406 // but do not allow a gap in the cache entry
3407 if (aFileOffset > iEntries[i]->fillFileOffset)
3408 {
3409 // gap
3410 LOGERROR((0, "PVMFMemoryBufferDataStreamPermCache::WriteBytes Failed gap found fillFileOffset %d aFileOffset %d", iEntries[i]->fillFileOffset, aFileOffset));
3411 return PVDS_INVALID_REQUEST;
3412 }
3413
3414 found = true;
3415 entry = i;
3416 break;
3417 }
3418 }
3419 if (!found)
3420 {
3421 LOGERROR((0, "PVMFMemoryBufferDataStreamPermCache::WriteBytes Failed cache entry not found"));
3422 return PVDS_INVALID_REQUEST;
3423 }
3424 // copy data into cache
3425 uint8* dstPtr = iEntries[entry]->bufPtr + (aFileOffset - iEntries[entry]->firstFileOffset);
3426 uint8* srcPtr = aFragPtr;
3427 uint32 bytesToCopy = aFragSize;
3428 uint32 bufAvail = iEntries[entry]->bufSize - (aFileOffset - iEntries[entry]->firstFileOffset);
3429 uint32 copySize = bytesToCopy;
3430 while (bytesToCopy)
3431 {
3432 copySize = bytesToCopy;
3433 if (bytesToCopy > bufAvail)
3434 {
3435 copySize = bufAvail;
3436 }
3437 oscl_memcpy(dstPtr, srcPtr, copySize);
3438
3439 iEntries[entry]->fillFileOffset += copySize;
3440 iEntries[entry]->fillSize += copySize;
3441
3442 bytesToCopy -= copySize;
3443 if (++entry >= iEntries.size())
3444 {
3445 break;
3446 }
3447 dstPtr = iEntries[entry]->bufPtr;
3448 srcPtr += copySize;
3449 bufAvail = iEntries[entry]->bufSize;
3450 }
3451
3452 if ((aFileOffset + aFragSize - 1) > iLastByteFileOffset)
3453 {
3454 iLastByteFileOffset = aFileOffset + aFragSize - 1;
3455 }
3456 iTotalBytes += aFragSize;
3457
3458 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::WriteBytes success iLastByteFileOffset % d", iLastByteFileOffset));
3459 return PVDS_SUCCESS;
3460 }
3461
3462
3463 uint32
ReadBytes(uint8 * aBuffer,uint32 aFirstByte,uint32 aLastByte)3464 PVMFMemoryBufferDataStreamPermCache::ReadBytes(uint8* aBuffer, uint32 aFirstByte, uint32 aLastByte)
3465 {
3466 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::ReadBytes buf %x first %d last %d", aBuffer, aFirstByte, aLastByte));
3467
3468 // Caller is the read data stream, it limits the read to what is in the cache
3469 // the first byte should be in the cache, go through the cache entires looking for the file offset
3470 bool found = false;
3471 uint32 count = iEntries.size();
3472 uint32 bytesRead = 0;
3473 uint32 bytesToRead = 0;
3474 uint8* dataPtr = NULL;
3475 uint8* bufferPtr = aBuffer;
3476
3477 for (uint32 i = 0; i < count; i++)
3478 {
3479 // there should not be holes in the cache right now
3480 // once an empty cache entry is found, break out
3481 if (0 == iEntries[i]->fillSize)
3482 {
3483 break;
3484 }
3485 if (!found)
3486 {
3487 // haven't found the first offset yet
3488 if ((aFirstByte >= iEntries[i]->firstFileOffset) && (aFirstByte < iEntries[i]->fillFileOffset))
3489 {
3490 // the first byte to be read is in this entry
3491 found = true;
3492 if (aLastByte < iEntries[i]->fillFileOffset)
3493 {
3494 //LOGDEBUG((0, "PC1 entry %d offset %d size %d", i, iEntries[i]->firstFileOffset, iEntries[i]->fillSize));
3495 // every byte to be read is in this entry
3496 dataPtr = iEntries[i]->bufPtr + (aFirstByte - iEntries[i]->firstFileOffset);
3497 bytesToRead = aLastByte - aFirstByte + 1;
3498 // copy the data to the buffer
3499 oscl_memcpy(bufferPtr, dataPtr, bytesToRead);
3500 bytesRead += bytesToRead;
3501 // done
3502 break;
3503 }
3504 else
3505 {
3506 //LOGDEBUG((0, "PC2 entry %d offset %d size %d", i, iEntries[i]->firstFileOffset, iEntries[i]->fillSize));
3507 // only a portion is in this entry
3508 dataPtr = iEntries[i]->bufPtr + (aFirstByte - iEntries[i]->firstFileOffset);
3509 bytesToRead = iEntries[i]->fillSize - (aFirstByte - iEntries[i]->firstFileOffset);
3510 // copy the data, the rest of the data should be in the next entry/entries
3511 oscl_memcpy(bufferPtr, dataPtr, bytesToRead);
3512 bytesRead += bytesToRead;
3513 bufferPtr += bytesToRead;
3514 }
3515 }
3516 }
3517 else
3518 {
3519 // the first byte was in the previous entry, more data to copy from this entry
3520 if (aLastByte < (iEntries[i]->firstFileOffset + iEntries[i]->fillSize))
3521 {
3522 //LOGDEBUG((0, "PC3 entry %d offset %d size %d", i, iEntries[i]->firstFileOffset, iEntries[i]->fillSize));
3523 // what is left to be read is in this entry
3524 dataPtr = iEntries[i]->bufPtr;
3525 bytesToRead = aLastByte - iEntries[i]->firstFileOffset + 1;
3526 // copy the data to the buffer
3527 oscl_memcpy(bufferPtr, dataPtr, bytesToRead);
3528 bytesRead += bytesToRead;
3529 // done
3530 break;
3531 }
3532 else
3533 {
3534 //LOGDEBUG((0, "PC4 entry %d offset %d size %d", i, iEntries[i]->firstFileOffset, iEntries[i]->fillSize));
3535 // all of this entry is needed
3536 dataPtr = iEntries[i]->bufPtr;
3537 bytesToRead = iEntries[i]->fillSize;
3538 // copy the data, the rest of the data should be in the next entry/entries
3539 oscl_memcpy(bufferPtr, dataPtr, bytesToRead);
3540 bytesRead += bytesToRead;
3541 bufferPtr += bytesToRead;
3542 }
3543 }
3544 }
3545 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::ReadBytes returning %d", bytesRead));
3546 return bytesRead;
3547 }
3548
3549
3550 bool
RemoveFirstEntry(uint8 * & aFragPtr)3551 PVMFMemoryBufferDataStreamPermCache::RemoveFirstEntry(uint8*& aFragPtr)
3552 {
3553 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::RemoveFirstEntry first %d last %d total %d", iFirstByteFileOffset, iLastByteFileOffset, iTotalBytes));
3554
3555 bool found = false;
3556
3557 if (!iEntries.empty())
3558 {
3559 // Remove and return the first/oldest entry in the cache and free the memory
3560 MBDSPermCacheEntry* entry = iEntries.front();
3561
3562 found = true;
3563 #if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
3564 uint32 offset = entry->firstFileOffset;
3565 #endif
3566 uint32 size = entry->fillSize;
3567
3568 aFragPtr = entry->bufPtr;
3569
3570 iEntries.erase(iEntries.begin());
3571
3572 OSCL_FREE(entry);
3573
3574 // House keeping
3575 if (!iEntries.empty())
3576 {
3577 iTotalBytes -= size;
3578
3579 // Next entry becomes first entry
3580 entry = iEntries.front();
3581 iFirstByteFileOffset = entry->firstFileOffset;
3582 }
3583 else
3584 {
3585 // no more entries
3586 iFirstByteFileOffset = 0;
3587 iLastByteFileOffset = 0;
3588 iTotalBytes = 0;
3589 }
3590 #if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
3591 LOGDEBUG((0, "PVMFMemoryBufferDataStreamTempCache::RemoveFirstEntry %x offset %d size %d first %d last %d total %d",
3592 entry, offset, size, iFirstByteFileOffset, iLastByteFileOffset, iTotalBytes));
3593 #endif
3594
3595 }
3596
3597 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::RemoveFirstEntry returning %d", (int)found));
3598 return found;
3599 }
3600
3601
3602 uint32
GetNumEntries()3603 PVMFMemoryBufferDataStreamPermCache::GetNumEntries()
3604 {
3605 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::GetNumEntries returning %d", iEntries.size()));
3606 // return number of entries in cache
3607 return iEntries.size();
3608 }
3609
3610
3611 uint32
GetCacheSize()3612 PVMFMemoryBufferDataStreamPermCache::GetCacheSize()
3613 {
3614 LOGTRACE((0, "PVMFMemoryBufferDataStreamPermCache::GetCacheSize %d", iTotalBufferAlloc));
3615 // return the size of all buffers allocated
3616 return iTotalBufferAlloc;
3617 }
3618
3619