Home | History | Annotate | Download | only in src
      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
     44 OSCL_EXPORT_REF ProtocolContainer::ProtocolContainer(PVMFProtocolEngineNode *aNode) : iNode(aNode)
     45 {
     46     clear();
     47     iDataPathLogger = PVLogger::GetLoggerObject(NODEDATAPATHLOGGER_TAG);
     48 }
     49 
     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 
     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 
    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 
    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 
    151 OSCL_EXPORT_REF PVMFStatus ProtocolContainer::doPrepare()
    152 {
    153     return initImpl();
    154 }
    155 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    267 OSCL_EXPORT_REF void ProtocolContainer::doStopClear()
    268 {
    269     doClear();
    270     if (iDownloadControl) iDownloadControl->clear();
    271     iEventReport->clear();
    272 }
    273 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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
    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 
    477 OSCL_EXPORT_REF PVMFProtocolEngineNodeOutput::~PVMFProtocolEngineNodeOutput()
    478 {
    479     reset();
    480 }
    481 
    482 // 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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    612 OSCL_EXPORT_REF bool PVMFProtocolEngineNodeOutput::getBuffer(PVMFSharedMediaDataPtr &aMediaData, uint32 aRequestSize)
    613 {
    614     if (!createMediaData(aMediaData, aRequestSize)) return false;
    615     return true;
    616 }
    617 
    618 OSCL_EXPORT_REF void PVMFProtocolEngineNodeOutput::discardData(const bool aNeedReopen)
    619 {
    620     OSCL_UNUSED_ARG(aNeedReopen);
    621     iOutputFramesQueue.clear();
    622     iMediaData.Unbind();
    623 }
    624 
    625 OSCL_EXPORT_REF bool PVMFProtocolEngineNodeOutput::isPortBusy()
    626 {
    627     return iPortIn->IsOutgoingQueueBusy();
    628 }
    629 
    630 
    631 
    632 ////////////////////////////////////////////////////////////////////////////////////
    633 //////  UserAgentField implementation
    634 ////////////////////////////////////////////////////////////////////////////////////
    635 // constructor
    636 OSCL_EXPORT_REF UserAgentField::UserAgentField(OSCL_wString &aUserAgent, const bool isOverwritable)
    637 {
    638     setUserAgent(aUserAgent, isOverwritable);
    639 }
    640 
    641 OSCL_EXPORT_REF UserAgentField::UserAgentField(OSCL_String &aUserAgent, const bool isOverwritable)
    642 {
    643     setUserAgent(aUserAgent, isOverwritable);
    644 }
    645 
    646 // set user agent
    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 
    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)
    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 ////////////////////////////////////////////////////////////////////////////////////
    718 OSCL_EXPORT_REF EventReporter::EventReporter(EventReporterObserver *aObserver) : iObserver(aObserver)
    719 {
    720     clear();
    721     iDataPathLogger = PVLogger::GetLoggerObject(NODEDATAPATHLOGGER_TAG);
    722 }
    723 
    724 OSCL_EXPORT_REF void EventReporter::clear()
    725 {
    726     iStarted = false;
    727 }
    728 
    729 OSCL_EXPORT_REF void EventReporter::startRealDataflow()
    730 {
    731     iStarted = true;
    732 }
    733 
    734 
    735 ////////////////////////////////////////////////////////////////////////////////////
    736 //////  InterfacingObjectContainer implementation
    737 ////////////////////////////////////////////////////////////////////////////////////
    738 
    739 // constructor
    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
    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 
    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 
    791 OSCL_EXPORT_REF void InterfacingObjectContainer::setNumBuffersInMediaDataPoolSMCalc(uint32 aVal)
    792 {
    793     iNumBuffersInMediaDataPoolSMCalc = aVal;
    794 }
    795 
    796 
    797 ////////////////////////////////////////////////////////////////////////////////////
    798 //////  PVMFProtocolEngineNodeTimer implementation
    799 ////////////////////////////////////////////////////////////////////////////////////
    800 
    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 
    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 
    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 
    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 
    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 
    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 
    884 void PVMFProtocolEngineNodeTimer::clear()
    885 {
    886     for (uint32 i = 0; i < iTimerVec.size(); i++)
    887     {
    888         iWatchdogTimer->Cancel(iTimerVec[i].iTimerID);
    889     }
    890 }
    891 
    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 
    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 
    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 
    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