• 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 #include "pvmf_protocol_engine_node_download_common.h"
19 #include "pvmf_protocolengine_node_tunables.h"
20 #include "pvmf_protocol_engine_command_format_ids.h"
21 
22 
23 ////////////////////////////////////////////////////////////////////////////////////
24 //////  DownloadContainer implementation
25 ////////////////////////////////////////////////////////////////////////////////////
26 
27 // constructor
DownloadContainer(PVMFProtocolEngineNode * aNode)28 OSCL_EXPORT_REF DownloadContainer::DownloadContainer(PVMFProtocolEngineNode *aNode) :
29         ProtocolContainer(aNode),
30         iForceSocketReconnect(false),
31         iNeedCheckResumeNotificationManually(false)
32 {
33     ;
34 }
35 
deleteProtocolObjects()36 OSCL_EXPORT_REF void DownloadContainer::deleteProtocolObjects()
37 {
38     if (iCfgFileContainer)
39     {
40         iCfgFileContainer->saveConfig();
41         OSCL_DELETE(iCfgFileContainer);
42         iCfgFileContainer = NULL;
43     }
44 
45     if (iDownloadSource) OSCL_DELETE(iDownloadSource);
46     iDownloadSource = NULL;
47     ProtocolContainer::deleteProtocolObjects();
48 }
49 
doPreStart()50 OSCL_EXPORT_REF int32 DownloadContainer::doPreStart()
51 {
52     // First make sure event reporter get the supporting objects
53     setEventReporterSupportObjects();
54 
55     // check the case: resume download after download is complete
56     OsclSharedPtr<PVDlCfgFile> aCfgFile = iCfgFileContainer->getCfgFile();
57     LOGINFODATAPATH((0, "DownloadContainer::doPreStart(), currFileSizeFromCfgFile=%d, totalFileSizeFromCfgFile=%d, aResumeDownload=%d, rangeStartTime=%d",
58                      aCfgFile->GetCurrentFileSize(), aCfgFile->GetOverallFileSize(), (uint32)(!aCfgFile->IsNewSession()), aCfgFile->GetRangeStartTime()));
59 
60     if (!aCfgFile->IsNewSession() && aCfgFile->GetCurrentFileSize() >= aCfgFile->GetOverallFileSize())
61     {
62         iInterfacingObjectContainer->setFileSize(aCfgFile->GetOverallFileSize());
63         iObserver->SetObserverState((uint32)EPVMFNodeStarted);
64         iNodeTimer->clear();
65         iEventReport->startRealDataflow();
66         iEventReport->checkReportEvent(PROCESS_SUCCESS_END_OF_MESSAGE);
67         iDownloadControl->checkResumeNotification();
68         iInterfacingObjectContainer->setInputDataUnwanted();
69         return PROCESS_SUCCESS_END_OF_MESSAGE;
70     }
71 
72     return PROCESS_SUCCESS;
73 }
74 
doPause()75 OSCL_EXPORT_REF bool DownloadContainer::doPause()
76 {
77     if (iCfgFileContainer) iCfgFileContainer->saveConfig();
78     return true;
79 }
80 
doStop()81 OSCL_EXPORT_REF PVMFStatus DownloadContainer::doStop()
82 {
83     ProtocolContainer::doStop();
84 
85     // set resume download mode for stop and play
86     OsclSharedPtr<PVDlCfgFile> aCfgFile = iCfgFileContainer->getCfgFile();
87     aCfgFile->SetNewSession(false); // set resume download session for the next time
88 
89     iForceSocketReconnect = true;
90     return PVMFSuccess;
91 }
92 
doClear(const bool aNeedDelete)93 OSCL_EXPORT_REF void DownloadContainer::doClear(const bool aNeedDelete)
94 {
95     // save config
96     if (iCfgFileContainer) iCfgFileContainer->saveConfig();
97     ProtocolContainer::doClear(aNeedDelete);
98 }
99 
doCancelClear()100 OSCL_EXPORT_REF void DownloadContainer::doCancelClear()
101 {
102     // save config
103     if (iCfgFileContainer) iCfgFileContainer->saveConfig();
104     ProtocolContainer::doCancelClear();
105 }
106 
addSourceData(OsclAny * aSourceData)107 OSCL_EXPORT_REF bool DownloadContainer::addSourceData(OsclAny* aSourceData)
108 {
109     if (!aSourceData) return false;
110     if (!iDownloadSource->addSource(aSourceData)) return false;
111     iCfgFileContainer->setDataSource(iDownloadSource);
112     return true;
113 }
114 
createCfgFile(OSCL_String & aUri)115 OSCL_EXPORT_REF bool DownloadContainer::createCfgFile(OSCL_String& aUri)
116 {
117     // create and set iCfgFile
118     if (!iCfgFileContainer) return false;
119     return (iCfgFileContainer->createCfgFile(aUri) == PVMFSuccess);
120 }
121 
getProxy(OSCL_String & aProxyName,uint32 & aProxyPort)122 OSCL_EXPORT_REF bool DownloadContainer::getProxy(OSCL_String& aProxyName, uint32 &aProxyPort)
123 {
124     // download proxy
125     // try proxy name/port from the context data at first, and then config file
126     // normally proxy name/port in the context data is stored in iCfgFileContainer,
127     // for resume download, the proxy name/port in iCfgFileContainer will be updated
128     // by the information from the actual config file (i.e., LoadConfig())
129     if (iDownloadSource->iProxyName.get_size() > 0 && iDownloadSource->iProxyPort > 0)
130     {
131         aProxyName = iDownloadSource->iProxyName;
132         aProxyPort = iDownloadSource->iProxyPort;
133     }
134     else
135     {
136         OsclSharedPtr<PVDlCfgFile> aCfgFile = iCfgFileContainer->getCfgFile();
137         if (aCfgFile->GetProxyName().get_size() == 0 || aCfgFile->GetProxyPort() == 0) return false;
138         aProxyName = aCfgFile->GetProxyName();
139         aProxyPort = aCfgFile->GetProxyPort();
140     }
141     return true;
142 }
143 
setHttpVersion(const uint32 aHttpVersion)144 OSCL_EXPORT_REF void DownloadContainer::setHttpVersion(const uint32 aHttpVersion)
145 {
146     if (!iCfgFileContainer->isEmpty())
147     {
148         iCfgFileContainer->getCfgFile()->setHttpVersion(aHttpVersion);
149     }
150 }
151 
setHttpExtensionHeaderField(OSCL_String & aFieldKey,OSCL_String & aFieldValue,const HttpMethod aMethod,const bool aPurgeOnRedirect)152 OSCL_EXPORT_REF void DownloadContainer::setHttpExtensionHeaderField(OSCL_String &aFieldKey,
153         OSCL_String &aFieldValue,
154         const HttpMethod aMethod,
155         const bool aPurgeOnRedirect)
156 {
157     iCfgFileContainer->getCfgFile()->SetExtensionHeaderKey(aFieldKey);
158     iCfgFileContainer->getCfgFile()->SetExtensionHeaderValue(aFieldValue);
159     iCfgFileContainer->getCfgFile()->SetHTTPMethodMaskForExtensionHeader(getBitMaskForHTTPMethod(aMethod));
160     iCfgFileContainer->getCfgFile()->SetExtensionHeaderPurgeOnRediect(aPurgeOnRedirect);
161 }
162 
handleContentRangeUnmatch()163 OSCL_EXPORT_REF bool DownloadContainer::handleContentRangeUnmatch()
164 {
165     // re-issue GET request with range from zero -- meaning starting download from beginning
166     OsclSharedPtr<PVDlCfgFile> aCfgFile = iCfgFileContainer->getCfgFile();
167     aCfgFile->SetCurrentFileSize(0);
168     aCfgFile->SetOverallFileSize(aCfgFile->GetMaxAllowedFileSize());
169     aCfgFile->SetNewSession();
170     iProtocol->stop();
171 
172     DownloadOutputConfig config;
173     config.isNeedOpenDataStream = true;
174     config.isRangeSupport       = false;
175     config.isResumeDownload     = true;
176     if (iNodeOutput->initialize((OsclAny*)(&config)) != PVMFSuccess) return false;
177     iNodeOutput->discardData(true); // true means closing and reopening the data stream object
178     iEventReport->startRealDataflow();
179     startDataFlowByCommand();
180     return true;
181 }
182 
downloadUpdateForHttpHeaderAvailable()183 OSCL_EXPORT_REF bool DownloadContainer::downloadUpdateForHttpHeaderAvailable()
184 {
185     if (!iCfgFileContainer->getCfgFile()->IsNewSession())
186     {
187         // for resume download session, open data stream with append mode
188         DownloadOutputConfig config;
189         config.isNeedOpenDataStream = true;
190         config.isRangeSupport       = true;
191         config.isResumeDownload     = true;
192         iNodeOutput->setCurrentOutputSize(iProtocol->getDownloadSize());
193         iDownloadControl->setPrevDownloadSize(iProtocol->getDownloadSize());
194         if (iNodeOutput->initialize((OsclAny*)(&config)) != PVMFSuccess) return false;
195     }
196     return true;
197 }
198 
isStreamingPlayback()199 OSCL_EXPORT_REF bool DownloadContainer::isStreamingPlayback()
200 {
201     return (iDownloadSource->iPlaybackControl ==
202             (uint32)PVMFSourceContextDataDownloadHTTP::ENoSaveToFile);
203 }
204 
initNodeOutput()205 OSCL_EXPORT_REF int32 DownloadContainer::initNodeOutput()
206 {
207     // pass objects to node output object
208     iNodeOutput->setOutputObject((OsclAny*)iPortInForData);
209     iNodeOutput->setOutputObject((OsclAny*)iInterfacingObjectContainer->getDataStreamFactory(), NodeOutputType_DataStreamFactory);
210     iInterfacingObjectContainer->setOutputPortConnect();  // for sending disconnect after download complete
211 
212     OsclSharedPtr<PVDlCfgFile> aCfgFile = iCfgFileContainer->getCfgFile();
213     DownloadOutputConfig config;
214     config.isResumeDownload     = !aCfgFile->IsNewSession();
215     // for resume download, initially no need to open data stream, because we don't know open mode determined by one of several factors: range support (not available)
216     // at this point, will call initialize again once we know if range is supported or not
217     config.isNeedOpenDataStream = !config.isResumeDownload;
218     if (config.isResumeDownload && (aCfgFile->GetCurrentFileSize() >= aCfgFile->GetOverallFileSize()))
219     {
220         config.isNeedOpenDataStream = true;
221     }
222 
223     return iNodeOutput->initialize((OsclAny*)(&config));
224 }
225 
initProtocol_SetConfigInfo()226 OSCL_EXPORT_REF bool DownloadContainer::initProtocol_SetConfigInfo()
227 {
228     OsclSharedPtr<PVDlCfgFile> aCfgFile = iCfgFileContainer->getCfgFile();
229     if (iUserAgentField)
230     {
231         OSCL_FastString aUserAgent;
232         if (!iUserAgentField->getUserAgent(aUserAgent)) return false;
233         aCfgFile->SetUserAgent(aUserAgent);
234     }
235     iProtocol->setConfigInfo((OsclAny*)(&aCfgFile));
236     return true;
237 }
238 
initDownloadControl()239 OSCL_EXPORT_REF void DownloadContainer::initDownloadControl()
240 {
241     iDownloadControl->setSupportObject((OsclAny*)iProtocol, DownloadControlSupportObjectType_ProtocolEngine);
242     iDownloadControl->setSupportObject((OsclAny*)iDownloadProgess, DownloadControlSupportObjectType_DownloadProgress);
243     iDownloadControl->setSupportObject((OsclAny*)iNodeOutput, DownloadControlSupportObjectType_OutputObject);
244     iDownloadControl->setSupportObject((OsclAny*)iCfgFileContainer, DownloadControlSupportObjectType_ConfigFileContainer);
245 
246     iDownloadProgess->setSupportObject((OsclAny*)iProtocol, DownloadControlSupportObjectType_ProtocolEngine);
247     iDownloadProgess->setSupportObject((OsclAny*)iCfgFileContainer, DownloadControlSupportObjectType_ConfigFileContainer);
248     iDownloadProgess->setSupportObject((OsclAny*)iNodeOutput, DownloadControlSupportObjectType_OutputObject);
249 }
250 
doInfoUpdate(uint32 downloadStatus)251 OSCL_EXPORT_REF bool DownloadContainer::doInfoUpdate(uint32 downloadStatus)
252 {
253     if (downloadStatus == PROCESS_SUCCESS_GOT_EOS ||
254             downloadStatus == PROCESS_WAIT_FOR_INCOMING_DATA) return true;
255 
256     if (iObserver->GetObserverState() == EPVMFNodeStarted)
257     {
258         updateDownloadControl(isDownloadComplete(downloadStatus));
259     }
260 
261     // centralize sending info events for download
262     return iEventReport->checkReportEvent(downloadStatus);
263 }
264 
updateDownloadControl(const bool isDownloadComplete)265 OSCL_EXPORT_REF void DownloadContainer::updateDownloadControl(const bool isDownloadComplete)
266 {
267     // check resume notification
268     if (iDownloadControl->checkResumeNotification(isDownloadComplete) == 1)
269     {
270         // report data ready event
271         iEventReport->sendDataReadyEvent();
272     }
273 
274     // update download progress
275     iDownloadProgess->update(isDownloadComplete);
276 }
277 
handleProtocolStateComplete(PVProtocolEngineNodeInternalEvent & aEvent,PVProtocolEngineNodeInternalEventHandler * aEventHandler)278 OSCL_EXPORT_REF bool DownloadContainer::handleProtocolStateComplete(PVProtocolEngineNodeInternalEvent &aEvent, PVProtocolEngineNodeInternalEventHandler *aEventHandler)
279 {
280     iNodeTimer->clear();
281     return ProtocolContainer::handleProtocolStateComplete(aEvent, aEventHandler);
282 }
283 
checkSendResumeNotification()284 OSCL_EXPORT_REF void DownloadContainer::checkSendResumeNotification()
285 {
286     iNodeTimer->start(WALL_CLOCK_TIMER_ID);
287 
288     if (needToCheckResumeNotificationMaually())
289     {
290         iNeedCheckResumeNotificationManually = false;
291         iObserver->SendManualResumeNotificationEvent();
292     }
293 }
294 
ignoreThisTimeout(const int32 timerID)295 OSCL_EXPORT_REF bool DownloadContainer::ignoreThisTimeout(const int32 timerID)
296 {
297     if (timerID != (int32)WALL_CLOCK_TIMER_ID && timerID != BUFFER_STATUS_TIMER_ID)
298     {
299         return ProtocolContainer::ignoreThisTimeout(timerID);
300     }
301 
302     // in case of WALL_CLOCK_TIMER_ID
303     if (timerID == (int32)WALL_CLOCK_TIMER_ID)
304     {
305         iNeedCheckResumeNotificationManually = true;
306         checkSendResumeNotification();
307     }
308     else if (timerID == BUFFER_STATUS_TIMER_ID)
309     {
310         iEventReport->sendBufferStatusEvent();
311     }
312     return true;
313 }
314 
setEventReporterSupportObjects()315 OSCL_EXPORT_REF void DownloadContainer::setEventReporterSupportObjects()
316 {
317     // assume all object pointers are valid (this method should be called after objects are checked as valid ones) to avoid duplicate checks
318     iEventReport->setSupportObject(iDownloadProgess, EventReporterSupportObjectType_DownloadProgress);
319     iEventReport->setSupportObject(iProtocol, EventReporterSupportObjectType_ProtocolEngine);
320     iEventReport->setSupportObject(iCfgFileContainer, EventReporterSupportObjectType_ConfigFileContainer);
321     iEventReport->setSupportObject(iInterfacingObjectContainer, EventReporterSupportObjectType_NodeInterfacingObject);
322     iEventReport->setSupportObject(iNodeTimer, EventReporterSupportObjectType_TimerObject);
323     iEventReport->setSupportObject(iNodeOutput, EventReporterSupportObjectType_OutputObject);
324 }
325 
326 ////////////////////////////////////////////////////////////////////////////////////
327 //////  pvHttpDownloadOutput implementation
328 ////////////////////////////////////////////////////////////////////////////////////
329 
330 // constructor
pvHttpDownloadOutput(PVMFProtocolEngineNodeOutputObserver * aObserver)331 OSCL_EXPORT_REF pvHttpDownloadOutput::pvHttpDownloadOutput(PVMFProtocolEngineNodeOutputObserver *aObserver) :
332         PVMFProtocolEngineNodeOutput(aObserver),
333         iDataStreamFactory(NULL),
334         iDataStream(NULL),
335         iSessionID(0),
336         isOpenDataStream(false),
337         iCounter(0)
338 {
339     ;
340 }
341 
342 // destructor
~pvHttpDownloadOutput()343 OSCL_EXPORT_REF pvHttpDownloadOutput::~pvHttpDownloadOutput()
344 {
345     reset();
346 }
347 
reset()348 OSCL_EXPORT_REF void pvHttpDownloadOutput::reset()
349 {
350     PVMFProtocolEngineNodeOutput::reset();
351 
352     // delete data stream object
353     if (iDataStreamFactory && iDataStream)
354     {
355         iDataStream->CloseSession(iSessionID);
356         PVUuid uuid = PVMIDataStreamSyncInterfaceUuid;
357         iDataStreamFactory->DestroyPVMFCPMPluginAccessInterface(uuid, iDataStream);
358         iDataStream = NULL;
359         iDataStreamFactory = NULL;
360     }
361 }
362 
setOutputObject(OsclAny * aOutputObject,const uint32 aObjectType)363 OSCL_EXPORT_REF void pvHttpDownloadOutput::setOutputObject(OsclAny* aOutputObject, const uint32 aObjectType)
364 {
365     if (aObjectType == NodeOutputType_DataStreamFactory && aOutputObject) iDataStreamFactory = (PVMFDataStreamFactory *)aOutputObject;
366     PVMFProtocolEngineNodeOutput::setOutputObject(aOutputObject, aObjectType);
367 }
368 
writeToDataStream(OUTPUT_DATA_QUEUE & aOutputQueue)369 OSCL_EXPORT_REF uint32 pvHttpDownloadOutput::writeToDataStream(OUTPUT_DATA_QUEUE &aOutputQueue)
370 {
371     uint32 totalFragSize = 0, i;
372     for (i = 0; i < aOutputQueue.size(); i++)
373     {
374         uint32 fragSize = aOutputQueue[i].getMemFragSize();
375         if (!writeToDataStream((uint8*)(aOutputQueue[i].getMemFragPtr()), fragSize)) return ~0;
376         totalFragSize += fragSize;
377     }
378 
379     LOGINFODATAPATH((0, "pvHttpDownloadOutput::writeToDataStream() SIZE= %d , SEQNUM=%d", totalFragSize, iCounter++));
380     iCurrTotalOutputSize += totalFragSize;
381     return totalFragSize;
382 }
383 
writeToDataStream(uint8 * aBuffer,uint32 aBufferLen)384 OSCL_EXPORT_REF bool pvHttpDownloadOutput::writeToDataStream(uint8 *aBuffer, uint32 aBufferLen)
385 {
386     if (iDataStream->Write(iSessionID, aBuffer, sizeof(uint8), aBufferLen) != PVDS_SUCCESS) return false;
387     return true;
388 }
389 
flushData(const uint32 aOutputType)390 OSCL_EXPORT_REF int32 pvHttpDownloadOutput::flushData(const uint32 aOutputType)
391 {
392     int32 status = PVMFProtocolEngineNodeOutput::flushData(aOutputType);
393     if (status != PROCESS_SUCCESS) return status;
394 
395     while (!iOutputFramesQueue.empty())
396     {
397         if (writeToDataStream(iOutputFramesQueue[0]) == 0xffffffff) return PROCESS_OUTPUT_TO_DATA_STREAM_FAILURE;
398         iOutputFramesQueue.erase(iOutputFramesQueue.begin());
399     }
400     return PROCESS_SUCCESS;
401 }
402 
initialize(OsclAny * aInitInfo)403 OSCL_EXPORT_REF int32 pvHttpDownloadOutput::initialize(OsclAny* aInitInfo)
404 {
405     // open data stream object
406     if (!iDataStreamFactory || !iPortIn) return PVMFFailure;
407     if (!iDataStream)
408     {
409         PVUuid uuid = PVMIDataStreamSyncInterfaceUuid;
410         iDataStream = (PVMIDataStreamSyncInterface*)iDataStreamFactory->CreatePVMFCPMPluginAccessInterface(uuid);
411         if (!iDataStream) return PVMFFailure;
412 
413         // create memory pool
414         int32 status = createMemPool();
415         if (status != PVMFSuccess) return status;
416     }
417 
418     // open data stream object if needed
419     return openDataStream(aInitInfo);
420 }
421 
openDataStream(OsclAny * aInitInfo)422 OSCL_EXPORT_REF int32 pvHttpDownloadOutput::openDataStream(OsclAny* aInitInfo)
423 {
424     DownloadOutputConfig* config = (DownloadOutputConfig*)aInitInfo;
425     if (config->isNeedOpenDataStream && !isOpenDataStream)
426     {
427         PvmiDataStreamMode aMode = PVDS_WRITE_ONLY;
428         if (config->isResumeDownload && config->isRangeSupport) aMode = PVDS_APPEND;
429 
430         if (iDataStream->OpenSession(iSessionID, aMode) != PVDS_SUCCESS) return PROCESS_DATA_STREAM_OPEN_FAILURE;
431         isOpenDataStream = true;
432     }
433     return PVMFSuccess;
434 }
435 
discardData(const bool aNeedReopen)436 OSCL_EXPORT_REF void pvHttpDownloadOutput::discardData(const bool aNeedReopen)
437 {
438     // discard the existing data inside the data stream object
439     if (iDataStream && isOpenDataStream)
440     {
441         if (aNeedReopen)
442         {
443             iDataStream->CloseSession(iSessionID);
444             iDataStream->OpenSession(iSessionID, PVDS_REWRITE);
445         }
446     }
447     PVMFProtocolEngineNodeOutput::discardData();
448 }
449 
getAvailableOutputSize()450 OSCL_EXPORT_REF uint32 pvHttpDownloadOutput::getAvailableOutputSize()
451 {
452     uint32 writeCapacity = 0xFFFFFFFF;
453     if (iDataStream)
454     {
455         iDataStream->QueryWriteCapacity(iSessionID, writeCapacity);
456     }
457     return writeCapacity;
458 }
459 
getMaxAvailableOutputSize()460 OSCL_EXPORT_REF uint32 pvHttpDownloadOutput::getMaxAvailableOutputSize()
461 {
462     return (iDataStream == NULL ? 0 : iDataStream->QueryBufferingCapacity());
463 }
464 
465 ////////////////////////////////////////////////////////////////////////////////////
466 //////  pvDownloadControl implementation
467 ////////////////////////////////////////////////////////////////////////////////////
468 
pvDownloadControl()469 OSCL_EXPORT_REF pvDownloadControl::pvDownloadControl() :
470         iCurrentPlaybackClock(NULL),
471         iProgDownloadSI(NULL),
472         iProtocol(NULL),
473         iDownloadProgress(NULL),
474         iNodeOutput(NULL),
475         iCfgFileContainer(NULL),
476         iFirstResumeNotificationSent(false),
477         iClipDurationMsec(0),
478         iFileSize(0)
479 {
480     clearBody();
481     createDownloadClock(); // may leave
482     iDataPathLogger = PVLogger::GetLoggerObject(NODEDATAPATHLOGGER_TAG);
483 }
484 
clear()485 OSCL_EXPORT_REF void pvDownloadControl::clear()
486 {
487     // check whether there is still pending resume request
488     if (iProgDownloadSI) sendResumeNotification(true);
489     clearBody();
490 }
491 
clearBody()492 OSCL_EXPORT_REF void pvDownloadControl::clearBody()
493 {
494     iPlaybackUnderflow           = true;
495     iDownloadComplete            = false;
496     iRequestResumeNotification   = false;
497     iCurrentNPTReadPosition      = 0;
498     iPlaybackByteRate            = 0;
499     iClipByterate                = 0;
500     iPrevDownloadSize            = 0;
501     iDlAlgoPreConditionMet       = false;
502     iSetFileSize                 = false;
503     iSendDownloadCompleteNotification = false;
504 }
505 
506 
507 // requst resume notification, implementation of PVMFDownloadProgressInterface API
requestResumeNotification(const uint32 currentNPTReadPosition,bool & aDownloadComplete,bool & aNeedSendUnderflowEvent)508 OSCL_EXPORT_REF void pvDownloadControl::requestResumeNotification(const uint32 currentNPTReadPosition, bool& aDownloadComplete, bool& aNeedSendUnderflowEvent)
509 {
510     LOGINFODATAPATH((0, "pvDownloadControl::requestResumeNotification() IN, iPlaybackUnderflow=%d, iRequestResumeNotification=%d, iDownloadComplete=%d",
511                      (uint32)iPlaybackUnderflow, (uint32)iRequestResumeNotification, (uint32)iDownloadComplete));
512 
513     if (iFirstResumeNotificationSent) aNeedSendUnderflowEvent = !iRequestResumeNotification;
514     else aNeedSendUnderflowEvent = false;
515 
516     if (!(aDownloadComplete = iDownloadComplete))
517     {
518         iPlaybackUnderflow = true;
519         iCurrentNPTReadPosition = currentNPTReadPosition;
520         iDownloadComplete = false;
521     }
522 
523     iRequestResumeNotification = true;
524 
525     // save the download size at the underflow point
526     iPrevDownloadSize = iNodeOutput->getCurrentOutputSize();
527 
528     // estimate playback rate and save the download size at the underflow point
529     if (currentNPTReadPosition > 0 && currentNPTReadPosition < 0xFFFFFFFF)
530     {
531         // estimate playback rate
532         iPlaybackByteRate = divisionInMilliSec(iProtocol->getDownloadSize(), currentNPTReadPosition);
533 
534         uint32 iPrevDownloadSizeOrig = 0;
535         iPrevDownloadSizeOrig = iPrevDownloadSize;
536         if (iClipByterate == 0 && iClipDurationMsec > 0) iClipByterate = divisionInMilliSec(iFileSize, iClipDurationMsec);
537         iPrevDownloadSize = OSCL_MAX(iPrevDownloadSize, currentNPTReadPosition / 1000 * iClipByterate);
538 
539         LOGINFODATAPATH((0, "pvDownloadControl::requestResumeNotification(), currentNPTReadPosition=%d, playbackRate=%dbps, prevDownloadSize=%d, iPrevDownloadSizeOrig=%d, iClipByterate=%dbps",
540                          currentNPTReadPosition, (iPlaybackByteRate << 3), iPrevDownloadSize, iPrevDownloadSizeOrig, (iClipByterate << 3)));
541     }
542 }
543 
setSupportObject(OsclAny * aDLSupportObject,DownloadControlSupportObjectType aType)544 OSCL_EXPORT_REF void pvDownloadControl::setSupportObject(OsclAny *aDLSupportObject, DownloadControlSupportObjectType aType)
545 {
546     switch (aType)
547     {
548         case DownloadControlSupportObjectType_SupportInterface:
549             iProgDownloadSI = (PVMFFormatProgDownloadSupportInterface*)aDLSupportObject;
550             // in high bandwidth conditions, iProgDownloadSI gets set AFTER download is complete, then
551             // need to check resume notification again if something is pending
552             if (iDownloadComplete) checkResumeNotification(iDownloadComplete);
553             else checkSendingNotification();
554             break;
555 
556         case DownloadControlSupportObjectType_ProgressInterface:
557         {
558             PVMFDownloadProgressInterface *aProgDownload = (PVMFDownloadProgressInterface *)aDLSupportObject;
559             if (iProgDownloadSI) iProgDownloadSI->setDownloadProgressInterface(aProgDownload);
560             break;
561         }
562         case DownloadControlSupportObjectType_EnginePlaybackClock:
563             iCurrentPlaybackClock = (PVMFMediaClock *)aDLSupportObject;
564             break;
565 
566         case DownloadControlSupportObjectType_ProtocolEngine:
567             iProtocol = (HttpBasedProtocol *)aDLSupportObject;
568             break;
569 
570         case DownloadControlSupportObjectType_DownloadProgress:
571             iDownloadProgress = (DownloadProgressInterface *)aDLSupportObject;
572             break;
573 
574         case DownloadControlSupportObjectType_OutputObject:
575             iNodeOutput = (PVMFProtocolEngineNodeOutput *)aDLSupportObject;
576             break;
577 
578         case DownloadControlSupportObjectType_ConfigFileContainer:
579             iCfgFileContainer = (PVDlCfgFileContainer *)aDLSupportObject;
580             if (!iCfgFileContainer->getCfgFile()->IsNewSession())
581             {
582                 if (iCfgFileContainer->getCfgFile()->HasContentLength())
583                 {
584                     iFileSize = iCfgFileContainer->getCfgFile()->GetOverallFileSize();
585                 }
586             }
587             break;
588 
589         default:
590             break;
591     }
592 }
593 
594 // check whether to make resume notification; if needed, then make resume notification
595 // Return value: 1 means making resume notification normally (underflow->auto resume),
596 //               2 means making resume notification for download complete
597 //               0 means anything else
checkResumeNotification(const bool aDownloadComplete)598 OSCL_EXPORT_REF int32 pvDownloadControl::checkResumeNotification(const bool aDownloadComplete)
599 {
600     //LOGINFODATAPATH((0, "pvDownloadControl::checkResumeNotification() IN, iPlaybackUnderflow=%d, iRequestResumeNotification=%d, aDownloadComplete=%d",
601     //  (uint32)iPlaybackUnderflow, (uint32)iRequestResumeNotification, (uint32)aDownloadComplete));
602 
603     // short-cut: download complete
604     // check sending file size, protocol info or download complete notification
605     if (!checkSendingNotification(aDownloadComplete))
606     {
607         LOGINFODATAPATH((0, "pvDownloadControl::checkResumeNotification()->checkDownloadCompleteForResumeNotification() return false, iProgDownloadSI=0x%x", iProgDownloadSI));
608         return 0;
609     }
610 
611     // real work that causes some PDL and PS differences
612     if (!iPlaybackUnderflow && iRequestResumeNotification)
613     {
614         sendResumeNotification(iDownloadComplete);
615         return 2;
616     }
617 
618     // check if need to resume playback
619     if (iPlaybackUnderflow &&
620             isResumePlayback(iProtocol->getDownloadRate(),
621                              iNodeOutput->getCurrentOutputSize(),
622                              iFileSize))
623     {
624         iPlaybackUnderflow = false;
625         sendResumeNotification(iDownloadComplete);
626         iFirstResumeNotificationSent = true;
627         return 1;
628     }
629 
630     return 0;
631 }
632 
checkSendingNotification(const bool aDownloadComplete)633 OSCL_EXPORT_REF bool pvDownloadControl::checkSendingNotification(const bool aDownloadComplete)
634 {
635     if (aDownloadComplete)
636     {
637         LOGINFODATAPATH((0, "pvDownloadControl::checkDownloadCompleteForResumeNotification()  Download is complete, final download rate = %dbps", (iProtocol->getDownloadRate() << 3)));
638     }
639     iDownloadComplete = aDownloadComplete;
640     // update iFileSize to minimize dependency on protocol object and improve the efficiency
641     updateFileSize();
642 
643     if (!isInfoReady()) return false;
644 
645     // set file size to parser node
646     setFileSize(iFileSize);
647 
648     // set protocol info to parser node if needed
649     setProtocolInfo();
650 
651     // send download complete notification to parser node
652     if (aDownloadComplete) sendDownloadCompleteNotification();
653 
654     // update download clock
655     if (!iDownloadComplete) updateDownloadClock();
656     return true;
657 }
658 
updateFileSize()659 void pvDownloadControl::updateFileSize()
660 {
661     if (iProtocol)
662     {
663         if (iProtocol->getContentLength() > 0 && iFileSize == 0) iFileSize = iProtocol->getContentLength();
664     }
665 }
666 
setFileSize(const uint32 aFileSize)667 OSCL_EXPORT_REF void pvDownloadControl::setFileSize(const uint32 aFileSize)
668 {
669     if (iSetFileSize) return;
670     if (aFileSize == 0 || !iProgDownloadSI) return;
671 
672     iProgDownloadSI->setFileSize(aFileSize);
673     iSetFileSize = true;
674 }
675 
sendResumeNotification(bool aDownloadComplete)676 OSCL_EXPORT_REF void pvDownloadControl::sendResumeNotification(bool aDownloadComplete)
677 {
678     if (iRequestResumeNotification && iProgDownloadSI)
679     {
680         iProgDownloadSI->playResumeNotification(aDownloadComplete);
681         iRequestResumeNotification = false;
682         iFirstResumeNotificationSent = true;
683         if (aDownloadComplete) iPlaybackUnderflow = false;
684 
685         // sync up with actual download complete
686         if (aDownloadComplete && !iDownloadComplete) iDownloadComplete = aDownloadComplete;
687     }
688 }
689 
sendDownloadCompleteNotification()690 OSCL_EXPORT_REF void pvDownloadControl::sendDownloadCompleteNotification()
691 {
692     if (!iProgDownloadSI || iSendDownloadCompleteNotification) return;
693 
694     // send download complete notification
695     LOGINFODATAPATH((0, "pvDownloadControl::sendDownloadCompleteNotification() - Notify download complete"));
696     iProgDownloadSI->notifyDownloadComplete();
697     iSendDownloadCompleteNotification = true;
698 }
699 
700 // create iDlProgressClock, will leave when memory allocation fails
createDownloadClock()701 OSCL_EXPORT_REF void pvDownloadControl::createDownloadClock()
702 {
703     // create shared PVMFMediaClock
704     PVDlSharedPtrAlloc<PVMFMediaClock> alloc;
705     PVMFMediaClock* myClock = alloc.allocate();
706     OsclRefCounterSA< PVDlSharedPtrAlloc<PVMFMediaClock> > *refcnt = new OsclRefCounterSA< PVDlSharedPtrAlloc<PVMFMediaClock> >(myClock);
707     OsclSharedPtr<PVMFMediaClock> myHandle(myClock, refcnt);
708     iDlProgressClock = myHandle;
709 
710     // set the clock base
711     iDlProgressClock->SetClockTimebase(iEstimatedServerClockTimeBase);
712     uint32 startTime = 0; // for type conversion
713     bool bOverflowFlag = false;
714     iDlProgressClock->SetStartTime32(startTime, PVMF_MEDIA_CLOCK_SEC, bOverflowFlag);
715 }
716 
717 
718 // auto-resume playback decision
isResumePlayback(const uint32 aDownloadRate,const uint32 aCurrDownloadSize,const uint32 aFileSize)719 OSCL_EXPORT_REF bool pvDownloadControl::isResumePlayback(const uint32 aDownloadRate,
720         const uint32 aCurrDownloadSize,
721         const uint32 aFileSize)
722 {
723     // check download complete, for download complete, no need to run the following algorithm
724     if (iDownloadComplete || isOutputBufferOverflow())
725     {
726         if (!iDownloadComplete)
727         {
728             LOGINFODATAPATH((0, "pvDownloadControl::isResumePlayback(), output buffer (MBDS is full) overflows!! Then auto-resume kicks off!!"));
729         }
730         return true;
731     }
732 
733     // check playback clock, if not available, then switch to the old algorithm
734     if (!iCurrentPlaybackClock) return isResumePlaybackWithOldAlg(aDownloadRate, aFileSize - aCurrDownloadSize);
735 
736 
737     // check the pre-conditins including initial download time/size for download rate estimation purpose
738     if (!isDlAlgoPreConditionMet(aDownloadRate, iClipDurationMsec, aCurrDownloadSize, aFileSize)) return false;
739 
740     // get the playback clock time
741     if (iClipDurationMsec > 0 && aFileSize > 0)
742     {
743         return checkAutoResumeAlgoWithConstraint(aDownloadRate, aFileSize - aCurrDownloadSize, iClipDurationMsec, aFileSize);
744     }
745 
746     return checkAutoResumeAlgoNoConstraint(aCurrDownloadSize, aFileSize, iClipDurationMsec);
747 }
748 
749 
isDlAlgoPreConditionMet(const uint32 aDownloadRate,const uint32 aDurationMsec,const uint32 aCurrDownloadSize,const uint32 aFileSize)750 OSCL_EXPORT_REF bool pvDownloadControl::isDlAlgoPreConditionMet(const uint32 aDownloadRate,
751         const uint32 aDurationMsec,
752         const uint32 aCurrDownloadSize,
753         const uint32 aFileSize)
754 {
755     if (iDlAlgoPreConditionMet) return iDlAlgoPreConditionMet;
756 
757     LOGINFODATAPATH((0, "pvDownloadControl::isResumePlayback()->isDlAlgoPreConditionMet(), download rate = %d , clip duration = %dms, download size = %d",
758                      aDownloadRate, aDurationMsec, aCurrDownloadSize));
759     OSCL_UNUSED_ARG(aDurationMsec);
760     if (aDownloadRate == 0) return false;
761 
762     // check initial download time for download rate estimation
763     uint32 downloadTimeMsec = iProtocol->getDownloadTimeForEstimation();
764     LOGINFODATAPATH((0, "pvDownloadControl::isResumePlayback()->isDlAlgoPreConditionMet(), check dl_time(%dms) > 1sec, OR download size(%d) >= 10 percent of file size(%d)=%d",
765                      downloadTimeMsec, aCurrDownloadSize, aFileSize, aFileSize / PVPROTOCOLENGINE_INIT_DOWNLOAD_SIZE_PERCENTAGE_THRESHOLD));
766     iDlAlgoPreConditionMet = (downloadTimeMsec >= PVPROTOCOLENGINE_INIT_DOWNLOAD_TIME_THRESHOLD);
767     if (iDlAlgoPreConditionMet) return true;
768 
769     // check initial download size for download rate estimation
770     uint32 initDownloadThreshold = (aFileSize > 0 ? aFileSize / PVPROTOCOLENGINE_INIT_DOWNLOAD_SIZE_PERCENTAGE_THRESHOLD : PVPROTOCOLENGINE_INIT_DOWNLOAD_SIZE_THRESHOLD);
771     iDlAlgoPreConditionMet = (aCurrDownloadSize >= initDownloadThreshold);
772     return iDlAlgoPreConditionMet;
773 }
774 
775 // with contraint: file size and clip duration are both available
checkAutoResumeAlgoWithConstraint(const uint32 aDownloadRate,const uint32 aRemainingDownloadSize,const uint32 aDurationMsec,const uint32 aFileSize)776 OSCL_EXPORT_REF bool pvDownloadControl::checkAutoResumeAlgoWithConstraint(const uint32 aDownloadRate,
777         const uint32 aRemainingDownloadSize,
778         const uint32 aDurationMsec,
779         const uint32 aFileSize)
780 {
781     // get the playback clock time
782     uint32 playbackTimeMec32 = 0;
783     if (!getPlaybackTimeFromEngineClock(playbackTimeMec32)) return false;
784 
785     LOGINFODATAPATH((0, "pvDownloadControl::isResumePlayback()->checkAutoResumeAlgowithConstraint(), algorithm: RemainingDownloadSize < 0.0009 * dl_rate * remaining_playback_time: remaining_dl_size= %d, dl_rate=%dByte/s,  playback_remaining_time=%dms",
786                      aRemainingDownloadSize, aDownloadRate, aDurationMsec - playbackTimeMec32));
787     // the basic algorithm is, remaining download time (remaining download size/download rate) <
788     //                         remaining playback time (duration - current playback time) * 0.9
789 
790     uint32 newDurationMsec = aDurationMsec;
791     if (!checkNewDuration(aDurationMsec, newDurationMsec)) return false;
792     uint32 playbackRemainingTimeMsec = newDurationMsec - playbackTimeMec32;
793     // 4sec buffering time
794     if (approveAutoResumeDecisionShortCut(aFileSize - aRemainingDownloadSize, newDurationMsec, playbackTimeMec32, playbackRemainingTimeMsec))
795     {
796         LOGINFODATAPATH((0, "pvDownloadControl::isResumePlayback()->checkAutoResumeAlgowithConstraint(), 4sec extra buffering time"));
797         return true;
798     }
799 
800     if (approveAutoResumeDecision(aRemainingDownloadSize, aDownloadRate, playbackRemainingTimeMsec))
801     {
802         LOGINFODATAPATH((0, "pvDownloadControl::isResumePlayback()->checkAutoResumeAlgowithConstraint(), BytesLeft = %d, dl_rate = %dbps, duration = %d(orig_duration=%d), playback_time=%d",
803                          aRemainingDownloadSize, (aDownloadRate << 3), newDurationMsec, aDurationMsec, playbackTimeMec32));
804         return true;
805     }
806 
807     return false;
808 }
809 
810 
getPlaybackTimeFromEngineClock(uint32 & aPlaybackTime)811 OSCL_EXPORT_REF bool pvDownloadControl::getPlaybackTimeFromEngineClock(uint32 &aPlaybackTime)
812 {
813     aPlaybackTime = 0;
814     bool isPbOverflow = false;
815     iCurrentPlaybackClock->GetCurrentTime32(aPlaybackTime, isPbOverflow, PVMF_MEDIA_CLOCK_MSEC);
816     if (isPbOverflow)
817     {
818         LOGERRORDATAPATH((0, "pvDownloadControl::getPlaybackTimeFromEngineClock(), Playback clock overflow %d", isPbOverflow));
819         return false;
820     }
821 
822     LOGINFODATAPATH((0, "pvDownloadControl::getPlaybackTimeFromEngineClock(), aPlaybackTime=%d, iCurrentNPTReadPosition=%d",
823                      aPlaybackTime, iCurrentNPTReadPosition));
824     aPlaybackTime = OSCL_MAX(aPlaybackTime, iCurrentNPTReadPosition);
825     return true;
826 }
827 
828 // use fixed-point calculation to replace the float-point calculation: aRemainingDLSize<0.0009*aDownloadRate*aRemainingPlaybackTime
approveAutoResumeDecision(const uint32 aRemainingDLSize,const uint32 aDownloadRate,const uint32 aRemainingPlaybackTime)829 OSCL_EXPORT_REF bool pvDownloadControl::approveAutoResumeDecision(const uint32 aRemainingDLSize,
830         const uint32 aDownloadRate,
831         const uint32 aRemainingPlaybackTime)
832 {
833 
834     // fixed-point calculation
835     // 0.0009 = 1/1111 ~= 1/1024 = 1/2^10 = right shift 10 bits
836     // aRemainingDLSize<(aDownloadRate*aRemainingPlaybackTime>>10)
837 
838     uint32 max = OSCL_MAX(aDownloadRate, aRemainingPlaybackTime);
839     if ((max >> PVPROTOCOLENGINE_AUTO_RESUME_FIXED_CALCULATION_MAX_LIMIT_RIGHT_SHIFT_FACTOR) == 0)   // right shift 16 bits, 2^16= 65536
840     {
841         return (aRemainingDLSize < (aDownloadRate*aRemainingPlaybackTime >>
842                                     PVPROTOCOLENGINE_AUTO_RESUME_FIXED_CALCULATION_RIGHT_SHIFT)); // right shift 10 bits
843     }
844     else
845     {
846         uint32 min = OSCL_MIN(aDownloadRate, aRemainingPlaybackTime);
847         uint32 maxRightShift10 = max >> PVPROTOCOLENGINE_AUTO_RESUME_FIXED_CALCULATION_RIGHT_SHIFT; // right shift 10 bits
848         return (aRemainingDLSize / maxRightShift10 < min);
849     }
850 }
851 
852 // result = x*1000/y
divisionInMilliSec(const uint32 x,const uint32 y)853 OSCL_EXPORT_REF uint32 pvDownloadControl::divisionInMilliSec(const uint32 x, const uint32 y)
854 {
855     // result = x*1000/y
856     // handle overflow issue
857     if (x >> PVPROTOCOLENGINE_DOWNLOAD_DURATION_CALCULATION_LIMIT_RIGHT_SHIFT_FACTOR == 0) return x*1000 / y; // no overflow
858 
859     // x*1000 overflows
860     uint32 result = (x >> PVPROTOCOLENGINE_DOWNLOAD_DURATION_CALCULATION_RIGHTSHIFT_FACTOR) * 1000;
861     if (result < y) result /= (y >> PVPROTOCOLENGINE_DOWNLOAD_DURATION_CALCULATION_RIGHTSHIFT_FACTOR);
862     else
863     {
864         uint32 resultTmp = result / y;
865         if (resultTmp >> PVPROTOCOLENGINE_DOWNLOAD_DURATION_CALCULATION_LIMIT_RIGHT_SHIFT_FACTOR) /* overflow */  result = 0xffffffff;
866         else
867         {
868             // check the accuracy of result/y
869             uint32 halfRightShift = PVPROTOCOLENGINE_DOWNLOAD_DURATION_CALCULATION_RIGHTSHIFT_FACTOR >> 1;
870             if (resultTmp >> halfRightShift)
871                 result = resultTmp << PVPROTOCOLENGINE_DOWNLOAD_DURATION_CALCULATION_RIGHTSHIFT_FACTOR;
872             else
873             {
874                 result /= (y >> halfRightShift);
875                 result <<= (PVPROTOCOLENGINE_DOWNLOAD_DURATION_CALCULATION_RIGHTSHIFT_FACTOR - halfRightShift);
876             }
877         }
878     }
879     return result;
880 }
881 
isResumePlaybackWithOldAlg(const uint32 aDownloadRate,const uint32 aRemainingDownloadSize)882 OSCL_EXPORT_REF bool pvDownloadControl::isResumePlaybackWithOldAlg(const uint32 aDownloadRate, const uint32 aRemainingDownloadSize)
883 {
884     // get the download progress clock time
885     uint32 download_time;
886     bool overflowFlag = false;
887     iDlProgressClock->GetCurrentTime32(download_time, overflowFlag, PVMF_MEDIA_CLOCK_MSEC);
888     uint32 currentNPTDownloadPosition = Oscl_Int64_Utils::get_uint64_lower32(download_time);
889 
890     LOGINFODATAPATH((0, "pvDownloadControl::isResumePlaybackWithOldAlg(), download_time=%dms, download_complete=%d\n", download_time, iDownloadComplete));
891 
892     if (iCurrentNPTReadPosition < currentNPTDownloadPosition)
893     {
894         // bytes_remaining < (0.9 * (received data rate * file duration ))
895 
896         uint32 BytesTobeDownloadedForAutoResume = (uint32)((currentNPTDownloadPosition - iCurrentNPTReadPosition) *
897                 aDownloadRate * 0.0009);
898 
899         LOGINFODATAPATH((0, "pvDownloadControl::isResumePlaybackWithOldAlg(), currentDLPosition=%dms, iCurrentReadPosition=%dms, downloadRate=%d, remainingSize %d\n", \
900                          currentNPTDownloadPosition, iCurrentNPTReadPosition, aDownloadRate, aRemainingDownloadSize));
901 
902         if (BytesTobeDownloadedForAutoResume > aRemainingDownloadSize)
903         {
904             return true;
905         }
906     }
907 
908     return false;
909 }
910 
cancelResumeNotification()911 OSCL_EXPORT_REF void pvDownloadControl::cancelResumeNotification()
912 {
913     // Just reset the boolean iRequestResumeNotification, so that download control sends no resume notification.
914     iRequestResumeNotification = false;
915 }
916 
917 
918 ////////////////////////////////////////////////////////////////////////////////////
919 //////  DownloadProgress implementation
920 ////////////////////////////////////////////////////////////////////////////////////
921 // constructor
DownloadProgress()922 OSCL_EXPORT_REF DownloadProgress::DownloadProgress() :
923         iProtocol(NULL),
924         iProgDownloadSI(NULL),
925         iNodeOutput(NULL)
926 {
927     reset();
928 }
929 
reset()930 OSCL_EXPORT_REF void DownloadProgress::reset()
931 {
932     //for progress reports
933     iCurrProgressPercent  = 0;
934     iPrevProgressPercent  = 0;
935     iDownloadNPTTime      = 0;
936     iDurationMsec         = 0;
937 }
938 
setSupportObject(OsclAny * aDLSupportObject,DownloadControlSupportObjectType aType)939 OSCL_EXPORT_REF void DownloadProgress::setSupportObject(OsclAny *aDLSupportObject, DownloadControlSupportObjectType aType)
940 {
941     switch (aType)
942     {
943         case DownloadControlSupportObjectType_SupportInterface:
944             iProgDownloadSI = (PVMFFormatProgDownloadSupportInterface*)aDLSupportObject;
945             break;
946 
947         case DownloadControlSupportObjectType_ProtocolEngine:
948             iProtocol = (HttpBasedProtocol *)aDLSupportObject;
949             break;
950 
951         case DownloadControlSupportObjectType_OutputObject:
952             iNodeOutput = (PVMFProtocolEngineNodeOutput *)aDLSupportObject;
953             break;
954 
955         default:
956             break;
957     }
958 }
959 
update(const bool aDownloadComplete)960 OSCL_EXPORT_REF bool DownloadProgress::update(const bool aDownloadComplete)
961 {
962     updateDownloadClock(aDownloadComplete);
963 
964     // update download progress
965     uint32 newProgressPercent = 0;
966     if (!calculateDownloadPercent(newProgressPercent)) return false;
967 
968     //Report 0... 100 percent complete.
969     // In progressive streaming, repositioning is allowed during download
970     // so the download percentage does not always increase
971     if (newProgressPercent != iCurrProgressPercent)
972     {
973         //avoid sending the same percentage update
974         iCurrProgressPercent = newProgressPercent;
975         return true;
976     }
977     return false;
978 }
979 
getNewProgressPercent(uint32 & aProgressPercent)980 OSCL_EXPORT_REF bool DownloadProgress::getNewProgressPercent(uint32 &aProgressPercent)
981 {
982     aProgressPercent = iCurrProgressPercent;
983     // in progressive streaming, after repositioning esp rewind, the current download percentage
984     // may be smaller than the previous percentage and current percentage may not be 0 unless rewind back to
985     // // beginning of clip
986     if (((iCurrProgressPercent < iPrevProgressPercent) && iPrevProgressPercent > 0) ||
987             iCurrProgressPercent > iPrevProgressPercent)
988     {
989         iPrevProgressPercent = iCurrProgressPercent;
990         return true;
991     }
992     return false;
993 }
994 
calculateDownloadPercent(uint32 & aDownloadProgressPercent)995 OSCL_EXPORT_REF bool DownloadProgress::calculateDownloadPercent(uint32 &aDownloadProgressPercent)
996 {
997     // clip duration
998     uint32 clipDuration = getClipDuration();
999     if (clipDuration == 0) return false;
1000 
1001     // download progress, convert to percent complete.
1002     aDownloadProgressPercent = iDownloadNPTTime * 100 / clipDuration;
1003     if (aDownloadProgressPercent > 100) aDownloadProgressPercent = 100;
1004     return true;
1005 }
1006 
getClipDuration()1007 OSCL_EXPORT_REF uint32 DownloadProgress::getClipDuration()
1008 {
1009     return iDurationMsec;
1010 }
1011 
1012 ////////////////////////////////////////////////////////////////////////////////////
1013 //////  PVMFDownloadDataSourceContainer implementation
1014 ////////////////////////////////////////////////////////////////////////////////////
PVMFDownloadDataSourceContainer(OsclAny * aSourceData)1015 PVMFDownloadDataSourceContainer::PVMFDownloadDataSourceContainer(OsclAny* aSourceData)
1016 {
1017     addSource(aSourceData);
1018 }
1019 
addSource(OsclAny * aSourceData)1020 bool PVMFDownloadDataSourceContainer::addSource(OsclAny* aSourceData)
1021 {
1022     PVInterface* pvInterface = OSCL_STATIC_CAST(PVInterface*, aSourceData);
1023 
1024     PVInterface* aDownloadSourceInterface = NULL;
1025     PVUuid downloadHTTPDataUuid(PVMF_DOWNLOAD_DATASOURCE_HTTP_UUID);
1026     if (pvInterface->queryInterface(downloadHTTPDataUuid, aDownloadSourceInterface))
1027     {
1028         PVMFDownloadDataSourceHTTP* aInterface = OSCL_STATIC_CAST(PVMFDownloadDataSourceHTTP*, aDownloadSourceInterface);
1029         copy(*aInterface);
1030         return true;
1031     }
1032 
1033     PVUuid downloadPVXDataUuid(PVMF_DOWNLOAD_DATASOURCE_PVX_UUID);
1034     if (pvInterface->queryInterface(downloadPVXDataUuid, aDownloadSourceInterface))
1035     {
1036         PVMFDownloadDataSourcePVX* aInterface = OSCL_STATIC_CAST(PVMFDownloadDataSourcePVX*, aDownloadSourceInterface);
1037         copy(*aInterface);
1038         return true;
1039     }
1040 
1041     PVInterface* sourceDataContext = NULL;
1042     PVUuid sourceContextUuid(PVMF_SOURCE_CONTEXT_DATA_UUID);
1043     if (pvInterface->queryInterface(sourceContextUuid, sourceDataContext))
1044     {
1045 
1046         PVUuid dlHTTPContextUuid(PVMF_SOURCE_CONTEXT_DATA_DOWNLOAD_HTTP_UUID);
1047         if (sourceDataContext->queryInterface(dlHTTPContextUuid, aDownloadSourceInterface))
1048         {
1049             PVMFSourceContextDataDownloadHTTP* aInterface = OSCL_STATIC_CAST(PVMFSourceContextDataDownloadHTTP*, aDownloadSourceInterface);
1050             copy(*aInterface);
1051             return true;
1052         }
1053 
1054         PVUuid dlPVXContextUuid(PVMF_SOURCE_CONTEXT_DATA_DOWNLOAD_PVX_UUID);
1055         if (sourceDataContext->queryInterface(dlPVXContextUuid, aDownloadSourceInterface))
1056         {
1057             PVMFSourceContextDataDownloadPVX* aInterface = OSCL_STATIC_CAST(PVMFSourceContextDataDownloadPVX*, aDownloadSourceInterface);
1058             copy(*aInterface);
1059             return true;
1060         }
1061     }
1062     return false;
1063 }
1064 
copy(const PVMFDownloadDataSourceHTTP & aSourceData)1065 void PVMFDownloadDataSourceContainer::copy(const PVMFDownloadDataSourceHTTP& aSourceData)
1066 {
1067     iHasDataSource    = true;
1068     iIsNewSession     = aSourceData.bIsNewSession;
1069     iMaxFileSize      = aSourceData.iMaxFileSize;
1070     iPlaybackControl  = (uint32)convert(aSourceData.iPlaybackControl);
1071     if (aSourceData.iPlaybackControl == PVMFDownloadDataSourceHTTP::ENoSaveToFile) iIsNewSession = true; // always use new download session for progressive streaming
1072     iConfigFileName   = aSourceData.iConfigFileName;
1073     iDownloadFileName = aSourceData.iDownloadFileName;
1074     iProxyName        = aSourceData.iProxyName;
1075     iProxyPort        = aSourceData.iProxyPort;
1076     iPvxInfo          = NULL;
1077 }
1078 
copy(const PVMFDownloadDataSourcePVX & aSourceData)1079 void PVMFDownloadDataSourceContainer::copy(const PVMFDownloadDataSourcePVX& aSourceData)
1080 {
1081     iHasDataSource    = true;
1082     iIsNewSession     = aSourceData.bIsNewSession;
1083     iMaxFileSize      = aSourceData.iMaxFileSize;
1084     iPlaybackControl  = 0;
1085     iConfigFileName   = aSourceData.iConfigFileName;
1086     iDownloadFileName = aSourceData.iDownloadFileName;
1087     iProxyName        = aSourceData.iProxyName;
1088     iProxyPort        = aSourceData.iProxyPort;
1089     iPvxInfo          = &aSourceData.iPvxInfo;
1090 }
1091 
copy(const PVMFSourceContextDataDownloadHTTP & aSourceData)1092 void PVMFDownloadDataSourceContainer::copy(const PVMFSourceContextDataDownloadHTTP& aSourceData)
1093 {
1094     iHasDataSource    = true;
1095     iIsNewSession     = aSourceData.bIsNewSession;
1096     iMaxFileSize      = aSourceData.iMaxFileSize;
1097     iPlaybackControl  = (uint32)aSourceData.iPlaybackControl;
1098     if (aSourceData.iPlaybackControl == PVMFSourceContextDataDownloadHTTP::ENoSaveToFile) iIsNewSession = true; // always use new download session for progressive streaming
1099     iConfigFileName   = aSourceData.iConfigFileName;
1100     iDownloadFileName = aSourceData.iDownloadFileName;
1101     iProxyName        = aSourceData.iProxyName;
1102     iProxyPort        = aSourceData.iProxyPort;
1103     iUserID           = aSourceData.iUserID;
1104     iUserPasswd       = aSourceData.iUserPasswd;
1105     iPvxInfo          = NULL;
1106 }
1107 
copy(const PVMFSourceContextDataDownloadPVX & aSourceData)1108 void PVMFDownloadDataSourceContainer::copy(const PVMFSourceContextDataDownloadPVX& aSourceData)
1109 {
1110     iHasDataSource    = true;
1111     iIsNewSession     = aSourceData.bIsNewSession;
1112     iMaxFileSize      = aSourceData.iMaxFileSize;
1113     iPlaybackControl  = 0;
1114     iConfigFileName   = aSourceData.iConfigFileName;
1115     iDownloadFileName = aSourceData.iDownloadFileName;
1116     iProxyName        = aSourceData.iProxyName;
1117     iProxyPort        = aSourceData.iProxyPort;
1118     iPvxInfo          = aSourceData.iPvxInfo;
1119 }
1120 
convert(const PVMFDownloadDataSourceHTTP::TPVPlaybackControl aPlaybackControl)1121 PVMFSourceContextDataDownloadHTTP::TPVPlaybackControl PVMFDownloadDataSourceContainer::convert(const PVMFDownloadDataSourceHTTP::TPVPlaybackControl aPlaybackControl)
1122 {
1123     switch (aPlaybackControl)
1124     {
1125         case PVMFDownloadDataSourceHTTP::ENoPlayback:
1126             return PVMFSourceContextDataDownloadHTTP::ENoPlayback;
1127         case PVMFDownloadDataSourceHTTP::EAfterDownload:
1128             return PVMFSourceContextDataDownloadHTTP::EAfterDownload;
1129         case PVMFDownloadDataSourceHTTP::EAsap:
1130             return PVMFSourceContextDataDownloadHTTP::EAsap;
1131         case PVMFDownloadDataSourceHTTP::ENoSaveToFile:
1132             return PVMFSourceContextDataDownloadHTTP::ENoSaveToFile;
1133         case PVMFDownloadDataSourceHTTP::EReserve:
1134             return PVMFSourceContextDataDownloadHTTP::EReserve;
1135         default:
1136             break;
1137     };
1138     return PVMFSourceContextDataDownloadHTTP::EAsap;
1139 }
1140 
1141 
1142 ////////////////////////////////////////////////////////////////////////////////////
1143 //////  PVDlCfgFileContainer implementation
1144 ////////////////////////////////////////////////////////////////////////////////////
createCfgFile(OSCL_String & aUrl)1145 OSCL_EXPORT_REF PVMFStatus PVDlCfgFileContainer::createCfgFile(OSCL_String &aUrl)
1146 {
1147     // iDataSource should be ready at this point
1148     if (!iDataSource) return PVMFFailure;
1149 
1150     // create iCfgFileObj
1151     PVDlSharedPtrAlloc<PVDlCfgFile> alloc;
1152     PVDlCfgFile* myCfg = alloc.allocate();
1153     OsclRefCounterSA< PVDlSharedPtrAlloc<PVDlCfgFile> > *refcnt = new OsclRefCounterSA< PVDlSharedPtrAlloc<PVDlCfgFile> >(myCfg);
1154     OsclSharedPtr<PVDlCfgFile> myHandle(myCfg, refcnt);
1155     iCfgFileObj = myHandle;
1156 
1157     // set common stuff for progressive download and fasttrack
1158     OSCL_FastString player_version(_STRLIT_CHAR("4.0"));
1159     iCfgFileObj->SetPlayerVersion(player_version);
1160 
1161     OSCL_FastString user_network(_STRLIT_CHAR("UNKNOWN"));
1162     iCfgFileObj->SetUserNetwork(user_network);
1163 
1164     OSCL_FastString deviceInfo(_STRLIT_CHAR("MANUF=UNKNOWN;PROC=WINS EMULATOR;MEM=UNKNOWN;OS=EPOC;DISPLAY=TRUECOLOR16"));
1165     iCfgFileObj->SetDeviceInfo(deviceInfo);
1166 
1167     iCfgFileObj->SetNetworkTimeouts(30000, 30000, -1);
1168 
1169     iCfgFileObj->SetRangeStartTime(0);
1170 
1171     return configCfgFile(aUrl);
1172 }
1173 
loadOldConfig()1174 OSCL_EXPORT_REF PVMFStatus PVDlCfgFileContainer::loadOldConfig()
1175 {
1176     int32 status = iCfgFileObj->LoadConfig();
1177     LOGINFODATAPATH((0, "PVDlCfgFileContainer::loadOldConfig() status=%d(-1 critical, -2 non-critical), currFileSize=%d, totalFileSize=%d, rangeStartTime=%d",
1178                      status, iCfgFileObj->GetCurrentFileSize(), iCfgFileObj->GetOverallFileSize(), iCfgFileObj->GetRangeStartTime()));
1179 
1180     if (status == PVDlCfgFile::LoadConfigStatus_CriticalError) return PVMFFailure;
1181     if (status == PVDlCfgFile::LoadConfigStatus_NonCriticalError)
1182     {
1183         // set up a new download session
1184         iCfgFileObj->SetCurrentFileSize(0);
1185         iCfgFileObj->SetOverallFileSize(iCfgFileObj->GetMaxAllowedFileSize());
1186         iCfgFileObj->SetNewSession();
1187     }
1188 
1189     PVDlCfgFile::TPVDLPlaybackMode tmpPlaybackMode = iCfgFileObj->GetPlaybackMode();
1190     if (tmpPlaybackMode == PVDlCfgFile::EPVDL_ASAP)
1191     {
1192         iPlaybackMode = PVMFDownloadDataSourceHTTP::EAsap;;
1193     }
1194     else if (tmpPlaybackMode == PVDlCfgFile::EPVDL_PLAYBACK_AFTER_DOWNLOAD)
1195     {
1196         iPlaybackMode = PVMFDownloadDataSourceHTTP::EAfterDownload;
1197     }
1198     else if (tmpPlaybackMode == PVDlCfgFile::EPVDL_DOWNLOAD_ONLY)
1199     {
1200         iPlaybackMode = PVMFDownloadDataSourceHTTP::ENoPlayback;
1201     }
1202     else //if(tmpPlaybackMode == PVDlCfgFile::EReserve )
1203     {
1204         //iPlaybackMode = PVMFDownloadDataSourceHTTP::EReserve;
1205         return PVMFFailure;
1206     }
1207     return PVMFSuccess;
1208 }
1209 
configCfgFile(OSCL_String & aUrl)1210 OSCL_EXPORT_REF PVMFStatus PVDlCfgFileContainer::configCfgFile(OSCL_String &aUrl)
1211 {
1212     if (iDataSource->isEmpty()) return PVMFFailure;
1213     if (iDataSource->iMaxFileSize <= 0) return PVMFFailure;
1214     iCfgFileObj->SetOverallFileSize(iDataSource->iMaxFileSize);
1215     iCfgFileObj->SetMaxAllowedFileSize(iDataSource->iMaxFileSize);
1216 
1217     iCfgFileObj->SetConfigFileName(iDataSource->iConfigFileName);
1218     iCfgFileObj->SetDownloadFileName(iDataSource->iDownloadFileName);
1219 
1220     // save URL
1221     iCfgFileObj->SetUrl(aUrl);
1222 
1223     // for old session, load the config file
1224     if (!iDataSource->iIsNewSession) return loadOldConfig();
1225     return PVMFSuccess;
1226 }
1227 
1228 
1229 
1230 ////////////////////////////////////////////////////////////////////////////////////
1231 //////  downloadEventReporter implementation
1232 ////////////////////////////////////////////////////////////////////////////////////
downloadEventReporter(EventReporterObserver * aObserver)1233 OSCL_EXPORT_REF downloadEventReporter::downloadEventReporter(EventReporterObserver *aObserver) :
1234         EventReporter(aObserver),
1235         iDownloadProgress(NULL),
1236         iProtocol(NULL),
1237         iCfgFileContainer(NULL),
1238         iNodeTimer(NULL),
1239         iInterfacingObjectContainer(NULL),
1240         iNodeOutput(NULL)
1241 {
1242     clear();
1243 }
1244 
clear()1245 OSCL_EXPORT_REF void downloadEventReporter::clear()
1246 {
1247     iSendBufferStartInfoEvent       = false;
1248     iSendBufferCompleteInfoEvent    = false;
1249     iSendMovieAtomCompleteInfoEvent = false;
1250     iSendInitialDataReadyEvent      = false;
1251     iSendContentLengthEvent         = false;
1252     iSendContentTruncateEvent       = false;
1253     iSendContentTypeEvent           = false;
1254     iSendUnexpectedDataEvent        = false;
1255     iSendServerDisconnectEvent      = false;
1256     iPrevDownloadProgress = 0;
1257 
1258     EventReporter::clear();
1259 }
1260 
setSupportObject(OsclAny * aSupportObject,EventReporterSupportObjectType aType)1261 OSCL_EXPORT_REF void downloadEventReporter::setSupportObject(OsclAny *aSupportObject, EventReporterSupportObjectType aType)
1262 {
1263     switch (aType)
1264     {
1265         case EventReporterSupportObjectType_DownloadProgress:
1266             iDownloadProgress = (DownloadProgressInterface *)aSupportObject;
1267             break;
1268 
1269         case EventReporterSupportObjectType_ProtocolEngine:
1270             iProtocol = (HttpBasedProtocol *)aSupportObject;
1271             break;
1272 
1273         case EventReporterSupportObjectType_ConfigFileContainer:
1274             iCfgFileContainer = (PVDlCfgFileContainer *)aSupportObject;
1275             break;
1276 
1277         case EventReporterSupportObjectType_TimerObject:
1278             iNodeTimer = (PVMFProtocolEngineNodeTimer *)aSupportObject;
1279             break;
1280 
1281         case EventReporterSupportObjectType_OutputObject:
1282             iNodeOutput = (PVMFProtocolEngineNodeOutput *)aSupportObject;
1283             break;
1284 
1285         case EventReporterSupportObjectType_NodeInterfacingObject:
1286             iInterfacingObjectContainer = (InterfacingObjectContainer *)aSupportObject;
1287             break;
1288 
1289         default:
1290             break;
1291     }
1292 }
1293 
sendDataReadyEvent()1294 OSCL_EXPORT_REF void downloadEventReporter::sendDataReadyEvent()
1295 {
1296     iObserver->ReportEvent(PVMFInfoDataReady, (OsclAny*)iProtocol->getDownloadRate());
1297     iSendInitialDataReadyEvent = true;
1298     iNodeTimer->cancel(WALL_CLOCK_TIMER_ID);
1299 }
1300 
enableBufferingCompleteEvent()1301 OSCL_EXPORT_REF void downloadEventReporter::enableBufferingCompleteEvent()
1302 {
1303     iSendBufferCompleteInfoEvent = false;
1304 }
1305 
sendBufferStatusEvent()1306 OSCL_EXPORT_REF void downloadEventReporter::sendBufferStatusEvent()
1307 {
1308     sendBufferStatusEventBody(true);
1309 }
1310 
sendBufferStatusEventBody(const bool aForceToSend)1311 void downloadEventReporter::sendBufferStatusEventBody(const bool aForceToSend)
1312 {
1313     if (!iStarted || !iDownloadProgress) return;
1314 
1315     uint32 aProgessPercent = 0;
1316     bool status = iDownloadProgress->getNewProgressPercent(aProgessPercent);
1317 
1318     if (!status && aForceToSend) aProgessPercent = iPrevDownloadProgress;
1319 
1320     if ((status || aForceToSend))
1321     {
1322         reportBufferStatusEvent(aProgessPercent);
1323         iPrevDownloadProgress = aProgessPercent;
1324         if (iPrevDownloadProgress < 100) iNodeTimer->start(BUFFER_STATUS_TIMER_ID);
1325     }
1326 }
1327 
reportBufferStatusEvent(const uint32 aDownloadPercent)1328 OSCL_EXPORT_REF void downloadEventReporter::reportBufferStatusEvent(const uint32 aDownloadPercent)
1329 {
1330     iObserver->ReportEvent(PVMFInfoBufferingStatus,
1331                            NULL,
1332                            PVMFPROTOCOLENGINENODEInfo_BufferingStatus,
1333                            (uint8*)(&aDownloadPercent),
1334                            sizeof(aDownloadPercent));
1335     LOGINFODATAPATH((0, "downloadEventReporter::reportBufferStatusEvent() DOWNLOAD PERCENTAGE: %d", aDownloadPercent));
1336 }
1337 
1338 
checkReportEvent(const uint32 downloadStatus)1339 OSCL_EXPORT_REF bool downloadEventReporter::checkReportEvent(const uint32 downloadStatus)
1340 {
1341     // PVMFInfoContentLength, PVMFErrContentTooLarge and PVMFInfoContentTruncated
1342     if (!checkContentInfoEvent(downloadStatus)) return false;
1343 
1344     // PVMFInfoBufferingStart, PVMFInfoBufferingStatus and PVMFInfoBufferingComplete event
1345     return checkBufferInfoEvent(downloadStatus);
1346 }
1347 
checkBufferInfoEvent(const uint32 downloadStatus)1348 OSCL_EXPORT_REF bool downloadEventReporter::checkBufferInfoEvent(const uint32 downloadStatus)
1349 {
1350     // PVMFInfoBufferingStart event
1351     if (!iSendBufferStartInfoEvent)
1352     {
1353         iObserver->ReportEvent(PVMFInfoBufferingStart); // first coming media data triggers sending PVMFInfoBufferingStart event
1354         iSendBufferStartInfoEvent = true;
1355         if (!isDownloadComplete(downloadStatus))
1356         {
1357             iNodeTimer->start(BUFFER_STATUS_TIMER_ID);
1358             return true;
1359         }
1360     }
1361 
1362     // PVMFInfoBufferingStatus and PVMFInfoBufferingComplete event
1363     if (iStarted && iDownloadProgress)
1364     {
1365         sendBufferStatusEventBody();
1366 
1367         // check and send buffer complete, data ready and unexpected data events
1368         checkBufferCompleteEvent(downloadStatus);
1369     }
1370 
1371     return true;
1372 }
1373 
1374 // check and send buffer complete, data ready and unexpected data events
checkBufferCompleteEvent(const uint32 downloadStatus)1375 OSCL_EXPORT_REF void downloadEventReporter::checkBufferCompleteEvent(const uint32 downloadStatus)
1376 {
1377     if (!iSendBufferCompleteInfoEvent && isDownloadComplete(downloadStatus))
1378     {
1379         uint32 aProgessPercent = 0;
1380         iDownloadProgress->getNewProgressPercent(aProgessPercent);
1381         if (aProgessPercent < 100)
1382         {
1383             aProgessPercent = 100;
1384             reportBufferStatusEvent(aProgessPercent);
1385         }
1386 
1387         // send buffer complete event
1388         iObserver->ReportEvent(PVMFInfoBufferingComplete, (OsclAny*)iProtocol->getDownloadSize());
1389         iSendBufferCompleteInfoEvent = true;
1390 
1391         // check and send data ready event
1392         if (!iSendInitialDataReadyEvent)
1393         {
1394             iObserver->ReportEvent(PVMFInfoDataReady);
1395             iSendInitialDataReadyEvent = true;
1396         }
1397 
1398         // clear the timer again because of download completion
1399         iNodeTimer->clear();
1400     }
1401 
1402     checkUnexpectedDataAndServerDisconnectEvent(downloadStatus);
1403 }
1404 
checkUnexpectedDataAndServerDisconnectEvent(const uint32 downloadStatus)1405 OSCL_EXPORT_REF void downloadEventReporter::checkUnexpectedDataAndServerDisconnectEvent(const uint32 downloadStatus)
1406 {
1407     if (!iSendBufferCompleteInfoEvent && isDownloadComplete(downloadStatus))
1408     {
1409         // check and send unexpected data event
1410         checkUnexpectedDataEvent(downloadStatus);
1411     }
1412 
1413     // check and send unexpected data event, PVMFInfoUnexpectedData
1414     checkUnexpectedDataEvent(downloadStatus);
1415 
1416     // check and send server disconnect event, PVMFInfoSessionDisconnect
1417     // especially for no content length case
1418     checkServerDisconnectEvent(downloadStatus);
1419 }
1420 
checkUnexpectedDataEvent(const uint32 downloadStatus)1421 OSCL_EXPORT_REF void downloadEventReporter::checkUnexpectedDataEvent(const uint32 downloadStatus)
1422 {
1423     if (!iSendUnexpectedDataEvent && !iSendServerDisconnectEvent && // if PVMFInfoSessionDisconnect is sent, no need to send PVMFInfoUnexpectedData
1424             downloadStatus == PROCESS_SUCCESS_END_OF_MESSAGE_WITH_EXTRA_DATA)
1425     {
1426         iObserver->ReportEvent(PVMFInfoUnexpectedData);
1427         iSendUnexpectedDataEvent = true;
1428     }
1429 }
1430 
checkServerDisconnectEvent(const uint32 downloadStatus)1431 OSCL_EXPORT_REF void downloadEventReporter::checkServerDisconnectEvent(const uint32 downloadStatus)
1432 {
1433     if (!iSendServerDisconnectEvent)
1434     {
1435         if (downloadStatus == PROCESS_SUCCESS_END_OF_MESSAGE_BY_SERVER_DISCONNECT ||
1436                 (!iCfgFileContainer->getCfgFile()->IsNewSession() &&
1437                  downloadStatus == PROCESS_SUCCESS_END_OF_MESSAGE &&
1438                  iSendBufferCompleteInfoEvent))   // resume download and previous complete download
1439         {
1440             iObserver->ReportEvent(PVMFInfoSessionDisconnect);
1441             iSendServerDisconnectEvent = true;
1442         }
1443     }
1444 }
1445 
1446 
checkContentInfoEvent(const uint32 downloadStatus)1447 OSCL_EXPORT_REF bool downloadEventReporter::checkContentInfoEvent(const uint32 downloadStatus)
1448 {
1449     // short-cut
1450     if (!needToCheckContentInfoEvent()) return true;
1451 
1452     // PVMFInfoContentType
1453     if (!iSendContentTypeEvent)
1454     {
1455         OSCL_HeapString<OsclMemAllocator> aContentType;
1456         if (iProtocol->getContentType(aContentType))
1457         {
1458             iObserver->ReportEvent(PVMFInfoContentType, (void*)(aContentType.get_cstr()));
1459             iSendContentTypeEvent = true;
1460         }
1461     }
1462 
1463     // check and send PVMFInfoContentLength or PVMFErrContentTooLarge
1464     if (!checkContentLengthOrTooLarge()) return false;
1465 
1466     // check and send PVMFInfoContentTruncated
1467     return checkContentTruncated(downloadStatus);
1468 }
1469 
checkContentLengthOrTooLarge()1470 OSCL_EXPORT_REF bool downloadEventReporter::checkContentLengthOrTooLarge()
1471 {
1472     // PVMFInfoContentLength
1473     uint32 fileSize = iInterfacingObjectContainer->getFileSize();
1474     uint32 maxAllowedFileSize = iCfgFileContainer->getCfgFile()->GetMaxAllowedFileSize();
1475 
1476     if (!iSendContentLengthEvent && fileSize > 0)
1477     {
1478         iObserver->ReportEvent(PVMFInfoContentLength, (OsclAny*)fileSize);
1479         iSendContentLengthEvent = true;
1480 
1481         // PVMFErrContentTooLarge
1482         if (fileSize > maxAllowedFileSize)
1483         {
1484             iObserver->NotifyContentTooLarge();
1485             return false;
1486         }
1487     }
1488     return true;
1489 }
1490 
1491 // check and send PVMFInfoContentTruncated
checkContentTruncated(const uint32 downloadStatus)1492 OSCL_EXPORT_REF bool downloadEventReporter::checkContentTruncated(const uint32 downloadStatus)
1493 {
1494     if (!iStarted) return true;
1495     if (!iSendContentTruncateEvent)
1496     {
1497         int32 status = isDownloadFileTruncated(downloadStatus);
1498         if (status > 0)
1499         {
1500             if (status == 1) iObserver->ReportEvent(PVMFInfoContentTruncated, (OsclAny*)iProtocol->getDownloadSize());
1501             if (status == 2)
1502             {
1503                 iObserver->ReportEvent(PVMFInfoContentTruncated,
1504                                        (OsclAny*)iProtocol->getDownloadSize(),
1505                                        PVMFPROTOCOLENGINENODEInfo_TruncatedContentByServerDisconnect);
1506             }
1507             iSendContentTruncateEvent = true;
1508         }
1509     }
1510     return true;
1511 }
1512 
1513 // return code: 0 - no truncation,
1514 //              1 - truncation (download size >= maximum file size)
1515 //              2 - truncation (download size < content length, server disconnect)
isDownloadFileTruncated(const uint32 downloadStatus)1516 OSCL_EXPORT_REF int32 downloadEventReporter::isDownloadFileTruncated(const uint32 downloadStatus)
1517 {
1518     // 1. connection shutdown case with content length
1519     // if no content length and connection is done, this case should be download complete,
1520     // and the download size should be file size (this is NOT truncated case)
1521     uint32 currDownloadSize = iProtocol->getDownloadSize();
1522     uint32 contentLength = iInterfacingObjectContainer->getFileSize();
1523     if (isDownloadComplete(downloadStatus))
1524     {
1525         // short-cut: for resume download, if previous download is complete download, then return 0 (no truncation)
1526         if (!iCfgFileContainer->getCfgFile()->IsNewSession() && downloadStatus == PROCESS_SUCCESS_END_OF_MESSAGE) return 0;
1527         if (currDownloadSize < contentLength) return 2;
1528     }
1529 
1530     // 2. no content length case : download size > maximum file size (storage size)
1531     if (contentLength == 0)
1532     {
1533         if (downloadStatus == PROCESS_SUCCESS_END_OF_MESSAGE_TRUNCATED) return 1;
1534         uint32 maxFileSize = iCfgFileContainer->getCfgFile()->GetMaxAllowedFileSize();
1535         if (currDownloadSize <= maxFileSize) return 0;
1536         if (currDownloadSize > maxFileSize)  return 1;
1537     }
1538     return 0;
1539 }
1540