• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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