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