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.h"
19 #include "pvmf_protocol_engine_command_format_ids.h"
20 #include "pvmf_protocolengine_node_tunables.h"
21
22 #include "pvlogger.h"
23 #include "oscl_utf8conv.h"
24
25 /**
26 //Macros for calling PVLogger
27 */
28 #define LOGERROR(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iLogger,PVLOGMSG_ERR,m);
29 #define LOGINFOHI(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG,iLogger,PVLOGMSG_INFO,m);
30 #define LOGINFOMED(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG,iLogger,PVLOGMSG_INFO,m);
31 #define LOGINFOLOW(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG,iLogger,PVLOGMSG_INFO,m);
32 #define LOGINFO(m) LOGINFOMED(m)
33 #define LOGINFODATAPATH(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG,iDataPathLogger,PVLOGMSG_INFO,m);
34 #define LOGERRORDATAPATH(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iDataPathLogger,PVLOGMSG_ERR,m);
35 #define LOGINFOCLOCK(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG,iClockLogger,PVLOGMSG_INFO,m);
36 #define PVMF_PROTOCOL_ENGINE_LOGBIN(iPortLogger, m) PVLOGGER_LOGBIN(PVLOGMSG_INST_LLDBG, iPortLogger, PVLOGMSG_ERR, m);
37 #define NODEDATAPATHLOGGER_TAG "datapath.sourcenode.protocolenginenode"
38
39 ////////////////////////////////////////////////////////////////////////////////////
40 ////// ProtocolContainer implementation
41 ////////////////////////////////////////////////////////////////////////////////////
42
43 // constructor
ProtocolContainer(PVMFProtocolEngineNode * aNode)44 OSCL_EXPORT_REF ProtocolContainer::ProtocolContainer(PVMFProtocolEngineNode *aNode) : iNode(aNode)
45 {
46 clear();
47 iDataPathLogger = PVLogger::GetLoggerObject(NODEDATAPATHLOGGER_TAG);
48 }
49
clear()50 OSCL_EXPORT_REF void ProtocolContainer::clear()
51 {
52 iProtocol = NULL;
53 iNodeOutput = NULL;
54 iDownloadControl = NULL;
55 iDownloadProgess = NULL;
56 iEventReport = NULL;
57 iCfgFileContainer = NULL;
58 iDownloadSource = NULL;
59 iNodeTimer = NULL;
60 iInterfacingObjectContainer = NULL;
61 iUserAgentField = NULL;
62 iPortInForData = iPortInForLogging = iPortOut = NULL;
63 iInternalEventQueue = NULL;
64 }
65
getObject(const NodeObjectType aObjectType)66 OSCL_EXPORT_REF OsclAny* ProtocolContainer::getObject(const NodeObjectType aObjectType)
67 {
68 switch (aObjectType)
69 {
70 case NodeObjectType_Protocol:
71 return (OsclAny*)iProtocol;
72 break;
73
74 case NodeObjectType_Output:
75 return (OsclAny*)iNodeOutput;
76 break;
77
78 case NodeObjectType_DownloadControl:
79 return (OsclAny*)iDownloadControl;
80 break;
81
82 case NodeObjectType_DownloadProgress:
83 return (OsclAny*)iDownloadProgess;
84 break;
85
86 case NodeObjectType_EventReport:
87 return (OsclAny*)iEventReport;
88 break;
89
90 case NodeObjectType_DlCfgFileContainer:
91 return (OsclAny*)iCfgFileContainer;
92 break;
93
94 case NodeObjectType_DataSourceContainer:
95 return (OsclAny*)iDownloadSource;
96 break;
97
98 case NodeObjectType_Timer:
99 return (OsclAny*)iNodeTimer;
100 break;
101
102 case NodeObjectType_InterfacingObjectContainer:
103 return (OsclAny*)iInterfacingObjectContainer;
104 break;
105
106 case NodeObjectType_UseAgentField:
107 return (OsclAny*)iUserAgentField;
108 break;
109
110 default:
111 break;
112 }
113 return NULL;
114 }
115
isObjectsReady()116 OSCL_EXPORT_REF bool ProtocolContainer::isObjectsReady()
117 {
118 if (!iProtocol ||
119 !iNodeOutput ||
120 !iInterfacingObjectContainer ||
121 iInterfacingObjectContainer->getURIObject().empty() ||
122 !iInterfacingObjectContainer->getDataStreamFactory() ||
123 !iPortInForData) return false;
124 return true;
125 }
126
setSupportObject(OsclAny * aSupportObject,const uint32 aType)127 OSCL_EXPORT_REF void ProtocolContainer::setSupportObject(OsclAny* aSupportObject, const uint32 aType)
128 {
129 switch ((NodeObjectType)aType)
130 {
131 case NodeObjectType_InputPortForData:
132 iPortInForData = (PVMFProtocolEnginePort*)aSupportObject;
133 break;
134
135 case NodeObjectType_InputPortForLogging:
136 iPortInForLogging = (PVMFProtocolEnginePort*)aSupportObject;
137 break;
138
139 case NodeObjectType_OutPort:
140 iPortOut = (PVMFProtocolEnginePort*)aSupportObject;
141 break;
142
143 case NodeObjectType_InternalEventQueue:
144 iInternalEventQueue = (Oscl_Vector<PVProtocolEngineNodeInternalEvent, PVMFProtocolEngineNodeAllocator>*)aSupportObject;
145 break;
146 default:
147 break;
148 }
149 }
150
doPrepare()151 OSCL_EXPORT_REF PVMFStatus ProtocolContainer::doPrepare()
152 {
153 return initImpl();
154 }
155
initImpl()156 OSCL_EXPORT_REF PVMFStatus ProtocolContainer::initImpl()
157 {
158 if (!isObjectsReady())
159 {
160 return PVMFErrNotReady;
161 }
162
163 // initialize output object
164 int32 status = initNodeOutput();
165 if (status != PVMFSuccess) return status;
166
167 // initialize protocol object
168 if (!initProtocol()) return PVMFFailure;
169
170 // initialize download control object
171 initDownloadControl();
172
173 // start data flow
174 // if the current socket connection is down, then do socket reconnect
175 bool needSocketReconnect = !iInterfacingObjectContainer->isSocketConnectionUp();
176 startDataFlowByCommand(needSocketReconnect);
177
178 return PVMFPending;
179 }
180
181
initProtocol()182 OSCL_EXPORT_REF bool ProtocolContainer::initProtocol()
183 {
184 // then pass objects to protocol object (note that the order matters)
185 iProtocol->setURI(iInterfacingObjectContainer->getURIObject());
186
187 // update user-agent field
188 if (!initProtocol_SetConfigInfo()) return false;
189 iProtocol->setObserver(iNode);
190
191 // protocol initialization and objects dispatch
192 iProtocol->initialize();
193 return true;
194 }
195
doStop()196 OSCL_EXPORT_REF PVMFStatus ProtocolContainer::doStop()
197 {
198 // send socket disconnect command if necessary
199 sendSocketDisconnectCmd();
200
201 // disable sending logging message, but try to disconnect socket
202 // use end of processing event to streamline all end of processing cases for stop
203 EndOfDataProcessingInfo *aEOPInfo = iInterfacingObjectContainer->getEOPInfo();
204 aEOPInfo->clear();
205 aEOPInfo->iForceStop = true;
206 PVProtocolEngineNodeInternalEvent aEvent(PVProtocolEngineNodeInternalEventType_EndOfProcessing, (OsclAny*)aEOPInfo);
207 iObserver->DispatchEvent(&aEvent);
208
209 return PVMFSuccess;
210 }
211
sendSocketDisconnectCmd()212 OSCL_EXPORT_REF void ProtocolContainer::sendSocketDisconnectCmd()
213 {
214 if (iObserver->SendMediaCommand(iPortInForData, PVMF_MEDIA_CMD_SOCKET_DISCONNECT_FORMAT_ID))
215 {
216 if (iPortInForData->Send())
217 {
218 LOGINFODATAPATH((0, "ProtocolContainer::doStop()->sendSocketDisconnectCmd(), Send() SUCCESS: MsgID=%d(SOCKET DISCONNECT)", (uint32)PVMF_MEDIA_CMD_SOCKET_DISCONNECT_FORMAT_ID));
219 }
220 }
221 }
222
startDataFlowByCommand(const bool needDoSocketReconnect)223 void ProtocolContainer::startDataFlowByCommand(const bool needDoSocketReconnect)
224 {
225 // flush out existing data at this point
226 checkEOSMsgFromInputPort();
227 iObserver->ClearRest();
228
229 // cancel all the existing timers
230 iNodeTimer->clear();
231
232 // disable info update at this point, will be enabled when new response comes in
233 enableInfoUpdate(false);
234
235 // socket reconnect
236 if (needDoSocketReconnect) reconnectSocket();
237
238 iObserver->RecheduleDataFlow();
239 }
240
checkEOSMsgFromInputPort()241 void ProtocolContainer::checkEOSMsgFromInputPort()
242 {
243 if (iPortInForData->IncomingMsgQueueSize() == 0) return;
244
245 // input port has media message
246 while (iPortInForData->IncomingMsgQueueSize() > 0)
247 {
248 PVMFSharedMediaMsgPtr msg;
249 PVMFStatus status = iPortInForData->DequeueIncomingMsg(msg);
250 if (status != PVMFSuccess) continue;
251 if (msg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
252 {
253 iInterfacingObjectContainer->updateSocketConnectFlags(true);
254 return;
255 }
256 }
257 }
258
doClear(const bool aNeedDelete)259 OSCL_EXPORT_REF void ProtocolContainer::doClear(const bool aNeedDelete)
260 {
261 iObserver->ClearRest(aNeedDelete);
262 if (iInternalEventQueue) iInternalEventQueue->clear();
263 if (iInterfacingObjectContainer) iInterfacingObjectContainer->clear();
264 if (iNodeTimer) iNodeTimer->clear();
265 }
266
doStopClear()267 OSCL_EXPORT_REF void ProtocolContainer::doStopClear()
268 {
269 doClear();
270 if (iDownloadControl) iDownloadControl->clear();
271 iEventReport->clear();
272 }
273
doCancelClear()274 OSCL_EXPORT_REF void ProtocolContainer::doCancelClear()
275 {
276 iObserver->ClearRest();
277 if (iInternalEventQueue) iInternalEventQueue->clear();
278 if (iNodeTimer) iNodeTimer->clear();
279 if (iDownloadControl) iDownloadControl->clear();
280 if (iEventReport) iEventReport->clear();
281 //if (iInterfacingObjectContainer) iInterfacingObjectContainer->setInputDataUnwanted();
282
283 // if re-do cancelled command, start from sending http request
284 if (iProtocol) iProtocol->sendRequest();
285 }
286
reconnectSocket(const bool aForceSocketReconnect)287 OSCL_EXPORT_REF bool ProtocolContainer::reconnectSocket(const bool aForceSocketReconnect)
288 {
289 if (!aForceSocketReconnect)
290 {
291 // Do not force to do socket reconnect, and then need to check the possibility
292 if (iInterfacingObjectContainer->isSocketReconnectCmdSent()) return true;
293 }
294 if (!iObserver->SendMediaCommand(iPortInForData, PVMF_MEDIA_CMD_SOCKET_CONNECT_FORMAT_ID)) return false;
295 iProtocol->sendRequest();
296 iInterfacingObjectContainer->setSocketReconnectCmdSent();
297 return true;
298 }
299
doEOS(const bool isTrueEOS)300 OSCL_EXPORT_REF bool ProtocolContainer::doEOS(const bool isTrueEOS)
301 {
302 // download done
303 if (isTrueEOS)
304 {
305 iObserver->SendMediaCommand(iPortInForData, PVMF_MEDIA_CMD_SOCKET_DISCONNECT_FORMAT_ID);
306 }
307 else // EOS packet hasn't been received, so re-connect socket
308 {
309 bool aForceSocketReconnect = false;
310 if (!iInterfacingObjectContainer->isPrevSocketConnectionUp())
311 {
312 // the situation is, previous connection is down and the current connection is down.
313 // then force reconnect
314 aForceSocketReconnect = true;
315 }
316 reconnectSocket(aForceSocketReconnect);
317 }
318
319 return true;
320 }
321
getBitMaskForHTTPMethod(const HttpMethod aMethod)322 OSCL_EXPORT_REF uint32 ProtocolContainer::getBitMaskForHTTPMethod(const HttpMethod aMethod)
323 {
324 uint32 bitMaskForHttpMethod = 0;
325 if (aMethod == HTTP_GET) bitMaskForHttpMethod = BITMASK_HTTPGET;
326 if (aMethod == HTTP_POST) bitMaskForHttpMethod = BITMASK_HTTPPOST;
327 if (aMethod == HTTP_HEAD) bitMaskForHttpMethod = BITMASK_HTTPHEAD;
328 if (aMethod == HTTP_ALLMETHOD) bitMaskForHttpMethod = ~0;
329 return bitMaskForHttpMethod;
330 }
331
createProtocolObjects()332 OSCL_EXPORT_REF bool ProtocolContainer::createProtocolObjects()
333 {
334 // create iInterfacingObjectContainer
335 iInterfacingObjectContainer = OSCL_NEW(InterfacingObjectContainer, ());
336 if (!iInterfacingObjectContainer) return false;
337
338 // create iNodeTimer
339 return createNetworkTimer();
340 }
341
createNetworkTimer()342 bool ProtocolContainer::createNetworkTimer()
343 {
344 iNodeTimer = PVMFProtocolEngineNodeTimer::create(iNode);
345 if (!iNodeTimer) return false;
346 iNodeTimer->set(SERVER_RESPONSE_TIMER_ID);
347 iNodeTimer->set(SERVER_INACTIVITY_TIMER_ID);
348 iNodeTimer->set(SERVER_RESPONSE_TIMER_ID_FOR_STOPEOS_LOGGING);
349 iNodeTimer->set(WALL_CLOCK_TIMER_ID);
350 iNodeTimer->set(BUFFER_STATUS_TIMER_ID);
351 return true;
352 }
353
deleteProtocolObjects()354 OSCL_EXPORT_REF void ProtocolContainer::deleteProtocolObjects()
355 {
356 if (iInterfacingObjectContainer) OSCL_DELETE(iInterfacingObjectContainer);
357 iInterfacingObjectContainer = NULL;
358
359 if (iNodeTimer) OSCL_DELETE(iNodeTimer);
360 iNodeTimer = NULL;
361
362
363 if (iProtocol) OSCL_DELETE(iProtocol);
364 iProtocol = NULL;
365 if (iNodeOutput) OSCL_DELETE(iNodeOutput);
366 iNodeOutput = NULL;
367 if (iDownloadControl) OSCL_DELETE(iDownloadControl);
368 iDownloadControl = NULL;
369 if (iDownloadProgess) OSCL_DELETE(iDownloadProgess);
370 iDownloadProgess = NULL;
371 if (iUserAgentField) OSCL_DELETE(iUserAgentField);
372 iUserAgentField = NULL;
373 if (iEventReport) OSCL_DELETE(iEventReport);
374 iEventReport = NULL;
375 }
376
handleTimeout(const int32 timerID)377 OSCL_EXPORT_REF void ProtocolContainer::handleTimeout(const int32 timerID)
378 {
379 if (ignoreThisTimeout(timerID)) return;
380 handleTimeoutErr(timerID);
381
382 // currently for wm http streaming only
383 handleTimeoutInPause(timerID);
384 // may clean flags to cause handleTimeoutErr() to get excecuted, so move handleTimeoutErr() above
385 handleTimeoutInDownloadStreamingDone(timerID);
386 }
387
ignoreThisTimeout(const int32 timerID)388 OSCL_EXPORT_REF bool ProtocolContainer::ignoreThisTimeout(const int32 timerID)
389 {
390 // check the end processing status: EOS recved and whole session is done
391 if (iInterfacingObjectContainer->isEOSAchieved() &&
392 iInterfacingObjectContainer->isWholeSessionDone()) return true;
393
394 // Next, all focus on checking server inactivity timeout
395 if (timerID != (int32)SERVER_INACTIVITY_TIMER_ID) return false;
396
397 // inactivity timeout should be ignored in the following cases:
398 // (i) input/output port queue still has data,
399 // (ii) buffer full in progressive streaming
400 if (iPortInForData)
401 {
402 if (iPortInForData->IncomingMsgQueueSize() > 0) return true;
403 }
404 if (iPortOut)
405 {
406 if (iPortOut->OutgoingMsgQueueSize() > 0) return true;
407 }
408
409 if (iNodeOutput)
410 {
411 if (iNodeOutput->getAvailableOutputSize() == 0) return true;
412 }
413 return false;
414 }
415
handleTimeoutErr(const int32 timerID)416 bool ProtocolContainer::handleTimeoutErr(const int32 timerID)
417 {
418 if (iInterfacingObjectContainer->isDownloadStreamingDone() ||
419 iObserver->GetObserverState() == EPVMFNodePaused) return false;
420
421 int32 timeoutErr = PVMFErrTimeout;
422 if (timerID == SERVER_RESPONSE_TIMER_ID) timeoutErr = PROCESS_TIMEOUT_SERVER_NO_RESPONCE;
423 if (timerID == SERVER_INACTIVITY_TIMER_ID) timeoutErr = PROCESS_TIMEOUT_SERVER_INACTIVITY;
424
425 ProtocolStateErrorInfo aInfo(timeoutErr);
426 PVProtocolEngineNodeInternalEvent aEvent(PVProtocolEngineNodeInternalEventType_ProtocolStateError, (OsclAny*)(&aInfo));
427 iObserver->DispatchEvent(&aEvent);
428 return true;
429 }
430
handleProtocolStateComplete(PVProtocolEngineNodeInternalEvent & aEvent,PVProtocolEngineNodeInternalEventHandler * aEventHandler)431 OSCL_EXPORT_REF bool ProtocolContainer::handleProtocolStateComplete(PVProtocolEngineNodeInternalEvent &aEvent, PVProtocolEngineNodeInternalEventHandler *aEventHandler)
432 {
433 bool aSessionDone = iInterfacingObjectContainer->isWholeSessionDone();
434 bool aDownloadStreamingDone = iInterfacingObjectContainer->isDownloadStreamingDone();
435 OSCL_UNUSED_ARG(aDownloadStreamingDone);
436 bool aEOSArrived = iInterfacingObjectContainer->isEOSAchieved();
437
438 iInterfacingObjectContainer->setInputDataUnwanted();
439 if (aSessionDone)
440 {
441 // flush all the remaining output
442 iNodeOutput->flushData();
443 iNodeTimer->clear();
444 if (aEOSArrived && iInterfacingObjectContainer->getOutputPortConnect())
445 {
446 doEOS(); // true EOS
447 return aEventHandler->completePendingCommand(aEvent);
448 }
449 }
450 return aEventHandler->completePendingCommand(aEvent);
451 }
452
453
454 ////////////////////////////////////////////////////////////////////////////////////
455 ////// PVMFProtocolEngineNodeOutput implementation
456 ////////////////////////////////////////////////////////////////////////////////////
457
458 // constructor
PVMFProtocolEngineNodeOutput(PVMFProtocolEngineNodeOutputObserver * aObserver)459 OSCL_EXPORT_REF PVMFProtocolEngineNodeOutput::PVMFProtocolEngineNodeOutput(PVMFProtocolEngineNodeOutputObserver *aObserver) :
460 iPortIn(NULL),
461 iContentDataMemPool(NULL),
462 iMediaDataAlloc(NULL),
463 iMediaDataMemPool("PVMFProtocolEngineNodeOutput(PVMFProtocolEngineNode)",
464 PVHTTPDOWNLOADOUTPUT_CONTENTDATA_POOLNUM,
465 PVHTTPDOWNLOADOUTPUT_MEDIADATA_CHUNKSIZE),
466 iObserver(aObserver),
467 iCurrTotalOutputSize(0)
468
469 {
470 iOutputFramesQueue.reserve(PVPROTOCOLENGINE_RESERVED_NUMBER_OF_FRAMES);
471 iLogger = PVLogger::GetLoggerObject("PVMFProtocolEngineNode");
472 iDataPathLogger = PVLogger::GetLoggerObject(NODEDATAPATHLOGGER_TAG);
473 iClockLogger = PVLogger::GetLoggerObject("clock");
474 iMediaDataMemPool.enablenullpointerreturn();
475 }
476
~PVMFProtocolEngineNodeOutput()477 OSCL_EXPORT_REF PVMFProtocolEngineNodeOutput::~PVMFProtocolEngineNodeOutput()
478 {
479 reset();
480 }
481
482 // reset
reset()483 OSCL_EXPORT_REF void PVMFProtocolEngineNodeOutput::reset()
484 {
485 iPortIn = NULL;
486 iLogger = NULL;
487 iDataPathLogger = NULL;
488 iClockLogger = NULL;
489 iOutputFramesQueue.clear();
490 iMediaData.Unbind();
491 deleteMemPool();
492 }
493
setOutputObject(OsclAny * aOutputObject,const uint32 aObjectType)494 OSCL_EXPORT_REF void PVMFProtocolEngineNodeOutput::setOutputObject(OsclAny* aOutputObject, const uint32 aObjectType)
495 {
496 if (aObjectType == NodeOutputType_InputPortForData && aOutputObject) iPortIn = (PVMFProtocolEnginePort *)aOutputObject;
497 }
498
499
sendToPort(PVMFSharedMediaDataPtr & aMediaData,const uint32 aPortType)500 OSCL_EXPORT_REF bool PVMFProtocolEngineNodeOutput::sendToPort(PVMFSharedMediaDataPtr &aMediaData, const uint32 aPortType)
501 {
502 OSCL_UNUSED_ARG(aPortType);
503 return sendToDestPort(aMediaData, iPortIn);
504 }
505
createMediaData(PVMFSharedMediaDataPtr & aMediaData,uint32 aRequestSize)506 OSCL_EXPORT_REF bool PVMFProtocolEngineNodeOutput::createMediaData(PVMFSharedMediaDataPtr &aMediaData, uint32 aRequestSize)
507 {
508 // check if need to create memory pool
509 int32 errcode = OsclErrNone;
510 if (!iMediaDataAlloc)
511 {
512 errcode = createMemPool();
513 if (errcode != PVMFSuccess) return false;
514 }
515
516 OsclSharedPtr<PVMFMediaDataImpl> mediadataImpl;
517 errcode = 0;
518 OSCL_TRY(errcode, mediadataImpl = iMediaDataAlloc->allocate(aRequestSize));
519 if (errcode != OsclErrNone) return false;
520
521
522 // Then wrap it around with PVMFMediaData
523 iMediaData.Unbind();
524
525 errcode = OsclErrNoResources;
526
527 iMediaData = PVMFMediaData::createMediaData(mediadataImpl, &iMediaDataMemPool);
528
529 if (iMediaData.GetRep() != NULL)
530 {
531 errcode = OsclErrNone;
532 }
533
534 if (errcode != OsclErrNone) return false;
535
536 aMediaData = iMediaData;
537 return true;
538 }
539
createMemPool()540 OSCL_EXPORT_REF PVMFStatus PVMFProtocolEngineNodeOutput::createMemPool()
541 {
542 // Create the memory pool
543 int32 errcode = 0;
544 OSCL_TRY(errcode, iContentDataMemPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (PVHTTPDOWNLOADOUTPUT_CONTENTDATA_POOLNUM)));
545 if (errcode || iContentDataMemPool == NULL) return PVMFErrNoMemory;
546
547
548 OSCL_TRY(errcode, iMediaDataAlloc = OSCL_NEW(PVMFSimpleMediaBufferCombinedAlloc, (iContentDataMemPool)));
549 if (errcode || iMediaDataAlloc == NULL) return PVMFErrNoMemory;
550
551 return PVMFSuccess;
552 }
553
deleteMemPool()554 OSCL_EXPORT_REF void PVMFProtocolEngineNodeOutput::deleteMemPool()
555 {
556 // Cleanup output media data memory pool
557 if (iMediaDataAlloc != NULL)
558 {
559 OSCL_DELETE(iMediaDataAlloc);
560 iMediaDataAlloc = NULL;
561 }
562
563 if (iContentDataMemPool != NULL)
564 {
565 OSCL_DELETE(iContentDataMemPool);
566 iContentDataMemPool = NULL;
567 }
568 }
569
sendToDestPort(PVMFSharedMediaDataPtr & aMediaData,PVMFProtocolEnginePort * aPort)570 OSCL_EXPORT_REF bool PVMFProtocolEngineNodeOutput::sendToDestPort(PVMFSharedMediaDataPtr &aMediaData, PVMFProtocolEnginePort *aPort)
571 {
572 // compute data frag size for log purposes
573 uint32 dataSize = 0;
574 uint32 numFrags = aMediaData->getNumFragments();
575 for (uint32 i = 0; i < numFrags; i++)
576 {
577 OsclRefCounterMemFrag memFragIn;
578 aMediaData->getMediaFragment(i, memFragIn);
579 uint32 fragLen = memFragIn.getMemFrag().len;
580 dataSize += fragLen;
581 }
582
583 // Send frame to downstream node
584 PVMFSharedMediaMsgPtr mediaMsgOut;
585 convertToPVMFMediaMsg(mediaMsgOut, aMediaData);
586
587 LOGINFODATAPATH((0, "PVMFProtocolEngineNodeOutput::sendToDestPort() SEQNUM= %d, SIZE= %d, port = 0x%x",
588 mediaMsgOut->getSeqNum(), dataSize, aPort));
589
590 PVMFStatus status = aPort->QueueOutgoingMsg(mediaMsgOut);
591 return iObserver->QueueOutgoingMsgSentComplete(aPort, mediaMsgOut, status);
592 }
593
passDownNewOutputData(OUTPUT_DATA_QUEUE & aOutputQueue,OsclAny * aSideInfo)594 OSCL_EXPORT_REF bool PVMFProtocolEngineNodeOutput::passDownNewOutputData(OUTPUT_DATA_QUEUE &aOutputQueue, OsclAny* aSideInfo)
595 {
596 OSCL_UNUSED_ARG(aSideInfo);
597 int32 err = 0;
598 OSCL_TRY(err, iOutputFramesQueue.push_back(aOutputQueue););
599 return (err == 0);
600 }
601
flushData(const uint32 aOutputType)602 OSCL_EXPORT_REF int32 PVMFProtocolEngineNodeOutput::flushData(const uint32 aOutputType)
603 {
604 if (iMediaData.GetRep() == NULL) return PROCESS_SUCCESS;
605
606 // send to port
607 if (!sendToPort(iMediaData, aOutputType)) return PROCESS_OUTPUT_PORT_IS_BUSY;
608 iMediaData.Unbind();
609 return PROCESS_SUCCESS;
610 }
611
getBuffer(PVMFSharedMediaDataPtr & aMediaData,uint32 aRequestSize)612 OSCL_EXPORT_REF bool PVMFProtocolEngineNodeOutput::getBuffer(PVMFSharedMediaDataPtr &aMediaData, uint32 aRequestSize)
613 {
614 if (!createMediaData(aMediaData, aRequestSize)) return false;
615 return true;
616 }
617
discardData(const bool aNeedReopen)618 OSCL_EXPORT_REF void PVMFProtocolEngineNodeOutput::discardData(const bool aNeedReopen)
619 {
620 OSCL_UNUSED_ARG(aNeedReopen);
621 iOutputFramesQueue.clear();
622 iMediaData.Unbind();
623 }
624
isPortBusy()625 OSCL_EXPORT_REF bool PVMFProtocolEngineNodeOutput::isPortBusy()
626 {
627 return iPortIn->IsOutgoingQueueBusy();
628 }
629
630
631
632 ////////////////////////////////////////////////////////////////////////////////////
633 ////// UserAgentField implementation
634 ////////////////////////////////////////////////////////////////////////////////////
635 // constructor
UserAgentField(OSCL_wString & aUserAgent,const bool isOverwritable)636 OSCL_EXPORT_REF UserAgentField::UserAgentField(OSCL_wString &aUserAgent, const bool isOverwritable)
637 {
638 setUserAgent(aUserAgent, isOverwritable);
639 }
640
UserAgentField(OSCL_String & aUserAgent,const bool isOverwritable)641 OSCL_EXPORT_REF UserAgentField::UserAgentField(OSCL_String &aUserAgent, const bool isOverwritable)
642 {
643 setUserAgent(aUserAgent, isOverwritable);
644 }
645
646 // set user agent
setUserAgent(OSCL_wString & aUserAgent,const bool isOverwritable)647 OSCL_EXPORT_REF bool UserAgentField::setUserAgent(OSCL_wString &aUserAgent, const bool isOverwritable)
648 {
649 iOverwritable = isOverwritable;
650
651 // check for empty string
652 if (aUserAgent.get_size() == 0) return true;
653
654 OsclMemAllocator alloc;
655 char *buf = (char*)alloc.allocate(aUserAgent.get_size() + 1);
656 if (!buf) return false;
657 uint32 size = 0;
658 if ((size = oscl_UnicodeToUTF8(aUserAgent.get_cstr(), aUserAgent.get_size(), buf, aUserAgent.get_size() + 1)) == 0)
659 {
660 alloc.deallocate(buf);
661 return false;
662 }
663 iInputUserAgent = OSCL_HeapString<OsclMemAllocator> (buf, size);
664 alloc.deallocate(buf);
665 return true;
666 }
667
setUserAgent(OSCL_String & aUserAgent,const bool isOverwritable)668 OSCL_EXPORT_REF bool UserAgentField::setUserAgent(OSCL_String &aUserAgent, const bool isOverwritable)
669 {
670 iOverwritable = isOverwritable;
671 // check for empty string
672 if (aUserAgent.get_size() == 0) return true;
673
674 iInputUserAgent = OSCL_HeapString<OsclMemAllocator> (aUserAgent.get_str(), aUserAgent.get_size());
675 return true;
676 }
677
678 // get the actual user agent (not wide string version) based on overwrite mode or replace mode (set the input user agent to the default one)
getUserAgent(OSCL_String & aUserAgent)679 OSCL_EXPORT_REF bool UserAgentField::getUserAgent(OSCL_String &aUserAgent)
680 {
681 if (iActualUserAgent.get_size() > 0)
682 {
683 aUserAgent = iActualUserAgent;
684 return true;
685 }
686
687 // create iActualUserAgent at the first call
688 if (iOverwritable && iInputUserAgent.get_size() > 0)
689 {
690 iActualUserAgent = iInputUserAgent;
691 }
692 else // append
693 {
694 //OSCL_FastString defaultUserAgent(_STRLIT_CHAR("PVPlayer/4.0 (Beta release)"));
695 OSCL_HeapString<OsclMemAllocator> defaultUserAgent;
696 getDefaultUserAgent(defaultUserAgent);
697 uint32 size = defaultUserAgent.get_size() + iInputUserAgent.get_size() + 1; // 1 => space
698 OsclMemAllocator alloc;
699 char *buf = (char*)alloc.allocate(size + 1);
700 if (!buf) return false;
701 oscl_memcpy(buf, defaultUserAgent.get_cstr(), defaultUserAgent.get_size());
702 buf[defaultUserAgent.get_size()] = PROTOCOLENGINENODE_SPACE_ASCIICODE;
703 if (iInputUserAgent.get_size() > 0)
704 {
705 oscl_memcpy(buf + defaultUserAgent.get_size() + 1, iInputUserAgent.get_cstr(), iInputUserAgent.get_size());
706 }
707 buf[size] = 0;
708 iActualUserAgent = OSCL_HeapString<OsclMemAllocator> (buf, size);
709 alloc.deallocate(buf);
710 }
711 aUserAgent = iActualUserAgent;
712 return true;
713 }
714
715 ////////////////////////////////////////////////////////////////////////////////////
716 ////// EventReporter implementation
717 ////////////////////////////////////////////////////////////////////////////////////
EventReporter(EventReporterObserver * aObserver)718 OSCL_EXPORT_REF EventReporter::EventReporter(EventReporterObserver *aObserver) : iObserver(aObserver)
719 {
720 clear();
721 iDataPathLogger = PVLogger::GetLoggerObject(NODEDATAPATHLOGGER_TAG);
722 }
723
clear()724 OSCL_EXPORT_REF void EventReporter::clear()
725 {
726 iStarted = false;
727 }
728
startRealDataflow()729 OSCL_EXPORT_REF void EventReporter::startRealDataflow()
730 {
731 iStarted = true;
732 }
733
734
735 ////////////////////////////////////////////////////////////////////////////////////
736 ////// InterfacingObjectContainer implementation
737 ////////////////////////////////////////////////////////////////////////////////////
738
739 // constructor
InterfacingObjectContainer()740 InterfacingObjectContainer::InterfacingObjectContainer() :
741 iDownloadFormat(PVMF_MIME_DATA_SOURCE_HTTP_URL),
742 iDataStreamFactory(NULL),
743 iNumBuffersInAllocator(PVHTTPSTREAMINGOUTPUT_CONTENTDATA_POOLNUM),
744 iNumRedirectTrials(PVPROTOCOLENGINE_DEFAULT_NUMBER_OF_REDIRECT_TRIALS),
745 iNumBuffersInMediaDataPoolSMCalc(PVHTTPSTREAMINGOUTPUT_CONTENTDATA_POOLNUM),
746 iCurrSocketConnection(true),
747 iPrevSocketConnection(true),
748 iLatestDataPacketNumSent(0),
749 iOutputPortConnected(false)
750 {
751 clear();
752 iOutgoingMsgSentSuccessInfoVec.reserve(PVMF_PROTOCOLENGINE_NODE_COMMAND_VECTOR_RESERVE / 4);
753 }
754
755 // set and get http header
setHttpHeader(OUTPUT_DATA_QUEUE & aHttpHeader)756 OSCL_EXPORT_REF uint32 InterfacingObjectContainer::setHttpHeader(OUTPUT_DATA_QUEUE &aHttpHeader)
757 {
758 iHttpHeaderLength = 0;
759 uint32 i = 0;
760 char *ptr = (char*)iHttpHeaderBuffer;
761 for (i = 0; i < aHttpHeader.size(); i++)
762 {
763 uint32 fragSize = aHttpHeader[i].getMemFragSize();
764 oscl_memcpy(ptr, (char*)aHttpHeader[i].getMemFragPtr(), fragSize);
765 iHttpHeaderLength += fragSize;
766 ptr += fragSize;
767 }
768 iHttpHeaderBuffer[iHttpHeaderLength] = 0;
769 return iHttpHeaderLength;
770 }
771
setStreamingProxy(OSCL_wString & aProxyName,const uint32 aProxyPort)772 OSCL_EXPORT_REF bool InterfacingObjectContainer::setStreamingProxy(OSCL_wString& aProxyName, const uint32 aProxyPort)
773 {
774 if (aProxyName.get_size() == 0) return false;
775
776 OsclMemAllocator alloc;
777 char *buf = (char*)alloc.allocate(aProxyName.get_size() + 1);
778 if (!buf) return false;
779 uint32 size = oscl_UnicodeToUTF8(aProxyName.get_cstr(), aProxyName.get_size(), buf, aProxyName.get_size() + 1);
780 if (size == 0)
781 {
782 alloc.deallocate(buf);
783 return false;
784 }
785 iProxyName = OSCL_HeapString<OsclMemAllocator> (buf, size);
786 iProxyPort = aProxyPort;
787 alloc.deallocate(buf);
788 return true;
789 }
790
setNumBuffersInMediaDataPoolSMCalc(uint32 aVal)791 OSCL_EXPORT_REF void InterfacingObjectContainer::setNumBuffersInMediaDataPoolSMCalc(uint32 aVal)
792 {
793 iNumBuffersInMediaDataPoolSMCalc = aVal;
794 }
795
796
797 ////////////////////////////////////////////////////////////////////////////////////
798 ////// PVMFProtocolEngineNodeTimer implementation
799 ////////////////////////////////////////////////////////////////////////////////////
800
create(OsclTimerObserver * aObserver)801 OSCL_EXPORT_REF PVMFProtocolEngineNodeTimer* PVMFProtocolEngineNodeTimer::create(OsclTimerObserver *aObserver)
802 {
803 PVMFProtocolEngineNodeTimer *timer = OSCL_NEW(PVMFProtocolEngineNodeTimer, ());
804 if (!timer) return NULL;
805 if (!timer->construct(aObserver))
806 {
807 OSCL_DELETE(timer);
808 return NULL;
809 }
810 return timer;
811 }
812
construct(OsclTimerObserver * aObserver)813 bool PVMFProtocolEngineNodeTimer::construct(OsclTimerObserver *aObserver)
814 {
815 // create iWatchdogTimer
816 iWatchdogTimer = OSCL_NEW(OsclTimer<PVMFProtocolEngineNodeAllocator>, ("ProtEngineNodeWatchdogTimer"));
817 if (!iWatchdogTimer) return false;
818 iWatchdogTimer->SetObserver(aObserver);
819 iWatchdogTimer->SetFrequency(PVPROTOCOLENGINENODE_TIMER_FREQUENCY);
820
821 int32 err = 0;
822 OSCL_TRY(err, iTimerVec.reserve(DEFAULT_TIMER_VECTOR_RESERVE_NUMBER);)
823 return (err ? false : true);
824 }
825
~PVMFProtocolEngineNodeTimer()826 OSCL_EXPORT_REF PVMFProtocolEngineNodeTimer::~PVMFProtocolEngineNodeTimer()
827 {
828 if (iWatchdogTimer)
829 {
830 OSCL_DELETE(iWatchdogTimer);
831 iWatchdogTimer = NULL;
832 }
833
834 iTimerVec.clear();
835 }
836
set(const uint32 aTimerID,const int32 aTimeout)837 OSCL_EXPORT_REF void PVMFProtocolEngineNodeTimer::set(const uint32 aTimerID, const int32 aTimeout)
838 {
839 uint32 index = getTimerVectorIndex(aTimerID);
840 if (index == 0xffffffff)
841 {
842 // attach the new timer
843 uint32 timeout = aTimeout;
844 if (timeout == 0) timeout = getDefaultTimeout(aTimerID);
845 TimerUnit timerUnit(aTimerID, timeout);
846 iTimerVec.push_back(timerUnit);
847 }
848 else
849 {
850 // existing timer
851 uint32 timeout = iTimerVec[index].iTimeout;
852 if (aTimeout > 0 || (aTimeout == 0 && aTimerID == SERVER_RESPONSE_TIMER_ID_FOR_STOPEOS_LOGGING))
853 {
854 // for stop/eos logging timeout, allow zero timeout
855 iTimerVec[index].iTimeout = aTimeout;
856 }
857 timeout = iTimerVec[index].iTimeout;
858 }
859 }
860
getTimeout(const uint32 aTimerID)861 OSCL_EXPORT_REF uint32 PVMFProtocolEngineNodeTimer::getTimeout(const uint32 aTimerID)
862 {
863 uint32 aTimeout = 0xffffffff;
864 uint32 index = getTimerVectorIndex(aTimerID);
865 if (index != 0xffffffff)
866 {
867 // existing timer
868 aTimeout = iTimerVec[index].iTimeout;
869 }
870 return aTimeout;
871 }
872
873
cancel(const uint32 aTimerID)874 OSCL_EXPORT_REF void PVMFProtocolEngineNodeTimer::cancel(const uint32 aTimerID)
875 {
876 uint32 index = getTimerVectorIndex(aTimerID);
877 if (index != 0xffffffff)
878 {
879 // find this timer and cancel it
880 iWatchdogTimer->Cancel(aTimerID);
881 }
882 }
883
clear()884 void PVMFProtocolEngineNodeTimer::clear()
885 {
886 for (uint32 i = 0; i < iTimerVec.size(); i++)
887 {
888 iWatchdogTimer->Cancel(iTimerVec[i].iTimerID);
889 }
890 }
891
clearExcept(const uint32 aTimerID)892 OSCL_EXPORT_REF void PVMFProtocolEngineNodeTimer::clearExcept(const uint32 aTimerID)
893 {
894 for (uint32 i = 0; i < iTimerVec.size(); i++)
895 {
896 if (iTimerVec[i].iTimerID != aTimerID)
897 {
898 iWatchdogTimer->Cancel(iTimerVec[i].iTimerID);
899 }
900 }
901 }
902
start(const uint32 aTimerID,const int32 aTimeout)903 OSCL_EXPORT_REF bool PVMFProtocolEngineNodeTimer::start(const uint32 aTimerID, const int32 aTimeout)
904 {
905 uint32 index = getTimerVectorIndex(aTimerID);
906 if (index == 0xffffffff) return false;
907 if (aTimeout) iTimerVec[index].iTimeout = aTimeout;
908 if (iTimerVec[index].iTimeout == 0)
909 {
910 iTimerVec[index].iTimeout = getDefaultTimeout(aTimerID);
911 }
912
913 iWatchdogTimer->Cancel(iTimerVec[index].iTimerID);
914 iWatchdogTimer->Request(iTimerVec[index].iTimerID, 0, iTimerVec[index].iTimeout);
915 return true;
916 }
917
getDefaultTimeout(const uint32 aTimerID)918 uint32 PVMFProtocolEngineNodeTimer::getDefaultTimeout(const uint32 aTimerID)
919 {
920 switch (aTimerID)
921 {
922 case SERVER_RESPONSE_TIMER_ID:
923 return DEFAULT_MAX_SERVER_RESPONSE_DURATION_IN_SEC;
924 case SERVER_INACTIVITY_TIMER_ID:
925 return DEFAULT_MAX_SERVER_INACTIVITY_DURATION_IN_SEC;
926 case SERVER_KEEPALIVE_TIMER_ID:
927 return DEFAULT_KEEPALIVE_TIMEOUT_IN_SEC;
928 case SERVER_RESPONSE_TIMER_ID_FOR_STOPEOS_LOGGING:
929 return DEFAULT_MAX_SERVER_RESPONSE_DURATION_IN_SEC_FOR_STOPEOS_LOGGING;
930 case WALL_CLOCK_TIMER_ID:
931 return DEFAULT_WALLCLOCK_TIMEOUT_IN_SEC;
932 case BUFFER_STATUS_TIMER_ID:
933 return DEFAULT_BUFFER_STATUS_CLOCK_TIMEOUT_IN_SEC;
934 default:
935 break;
936 }
937 return 0;
938 }
939
getTimerVectorIndex(const uint32 aTimerID)940 uint32 PVMFProtocolEngineNodeTimer::getTimerVectorIndex(const uint32 aTimerID)
941 {
942 for (uint32 i = 0; i < iTimerVec.size(); i++)
943 {
944 if (iTimerVec[i].iTimerID == aTimerID) return i;
945 }
946 return ~0;
947 }
948
949