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 #ifndef PVMF_MP3FFPARSER_NODE_H_INCLUDED
     19 #include "pvmf_mp3ffparser_node.h"
     20 #endif
     21 #ifndef PVLOGGER_H_INCLUDED
     22 #include "pvlogger.h"
     23 #endif
     24 #ifndef PVMF_MEDIA_CMD_H_INCLUDED
     25 #include "pvmf_media_cmd.h"
     26 #endif
     27 #ifndef PVMF_MEDIA_MSG_FORMAT_IDS_H_INCLUDED
     28 #include "pvmf_media_msg_format_ids.h"
     29 #endif
     30 #ifndef PVMF_DURATION_INFOMESSAGE_H_INCLUDED
     31 #include "pvmf_duration_infomessage.h"
     32 #endif
     33 #ifndef PVMF_METADATA_INFOMESSAGE_H_INCLUDED
     34 #include "pvmf_metadata_infomessage.h"
     35 #endif
     36 #ifndef OSCL_MIME_STRING_UTILS_H
     37 #include "pv_mime_string_utils.h"
     38 #endif
     39 #ifndef __MEDIA_CLOCK_CONVERTER_H
     40 #include "media_clock_converter.h"
     41 #endif
     42 #ifndef PV_GAU_H_
     43 #include "pv_gau.h"
     44 #endif
     45 #ifndef PVMF_SOURCE_CONTEXT_DATA_H_INCLUDED
     46 #include "pvmf_source_context_data.h"
     47 #endif
     48 #ifndef PVMF_RETURN_CODES_H_INCLUDED
     49 #include "pvmf_return_codes.h"
     50 #endif
     51 
     52 // Playback clock timescale
     53 #define COMMON_PLAYBACK_CLOCK_TIMESCALE 1000
     54 
     55 // Constants used for memory pools
     56 #define PVMP3FF_MEDIADATA_CHUNKS_IN_POOL    8
     57 #define PVMP3FF_MEDIADATA_CHUNKSIZE         256
     58 // the maximum frame size depends on K * bitrate/sampling_rate
     59 #define PVMP3FF_DEFAULT_MAX_FRAMESIZE       4096
     60 #define PVMF3FF_DEFAULT_NUM_OF_FRAMES       5
     61 #define PVMF3FF_DURATION_SCAN_AO_DELAY      1000
     62 
     63 #ifdef PV_HAS_SHOUTCAST_SUPPORT_ENABLED
     64 #define PVMF_MP3FFPARSER_NODE_METADATA_RESERVE 2
     65 #define SHOUTCAST_MEDIA_DATA_LENGTH_STRING "x-pvmf/net/shoutcast-media-data-length"
     66 #define SHOUTCAST_CLIP_BITRATE_STRING "x-pvmf/net/shoutcast-clip-bitrate"
     67 #define SHOUTCAST_IS_SHOUTCAST_SESSION_STRING "x-pvmf/net/is-shoutcast-session"
     68 #endif
     69 
     70 /**
     71  * Macros for calling PVLogger
     72  */
     73 #define LOGERROR(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iLogger,PVLOGMSG_ERR,m);
     74 #define LOGINFOHI(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG,iLogger,PVLOGMSG_INFO,m);
     75 #define LOGINFOMED(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG,iLogger,PVLOGMSG_INFO,m);
     76 #define LOGINFOLOW(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG,iLogger,PVLOGMSG_INFO,m);
     77 #define LOGINFO(m) LOGINFOMED(m)
     78 
     79 
     80 /**
     81  * Constructor
     82  */
     83 PVMFMP3FFParserNode::PVMFMP3FFParserNode(int32 aPriority)
     84         : OsclTimerObject(aPriority, "PVMFMP3FFParserNode"),
     85         iStreamID(0),
     86         iParseStatus(false),
     87         iSourceURLSet(false),
     88         iMP3File(NULL),
     89         iConfigOk(0),
     90         iExtensionRefCount(0),
     91         iMaxFrameSize(PVMP3FF_DEFAULT_MAX_FRAMESIZE),
     92         iMP3FormatBitrate(0),
     93         iLogger(NULL),
     94         iSendDecodeFormatSpecificInfo(true)
     95 {
     96 #if PV_HAS_SHOUTCAST_SUPPORT_ENABLED
     97     iMetadataBuf = NULL;
     98     iMetadataBufSize = 0;
     99     iMetadataSize = 0;
    100     iSCSPFactory = NULL;
    101     iSCSP = NULL;
    102     iClipByteRate = 0;
    103     iMetadataInterval = 0;
    104 #endif
    105 
    106     iCPMContainer.iCPMLicenseInterface = NULL;
    107     iCPMContainer.iCPMLicenseInterfacePVI = NULL;
    108     iCPMContainer.iCPMMetaDataExtensionInterface   = NULL;
    109     iCPMGetMetaDataKeysCmdId = 0;
    110     iCPMGetMetaDataValuesCmdId = 0;
    111     oWaitingOnLicense  = false;
    112     iFileHandle = NULL;
    113     iAutoPaused = false;
    114     iDownloadProgressInterface = NULL;
    115     iDataStreamFactory         = NULL;
    116     iDataStreamInterface = NULL;
    117     iDataStreamReadCapacityObserver = NULL;
    118     iMP3ParserNodeMetadataValueCount = 0;
    119     iDownloadComplete = false;
    120     iFileSizeRecvd = false;
    121     iFileSize = 0;
    122     iCheckForMP3HeaderDuringInit = false;
    123     iDurationCalcAO = NULL;
    124 
    125     int32 err;
    126 
    127     OSCL_TRY(err,
    128 
    129              // Create the "InputCommandQueue". Use a reserve to avoid lots of
    130              // dynamic memory allocation.
    131              iInputCommands.Construct(PVMF_MP3FFPARSER_NODE_COMMAND_ID_START,
    132                                       PVMF_MP3FFPARSER_NODE_COMMAND_VECTOR_RESERVE);
    133 
    134              // Create "CurrentCommandQueue" and "CancelCommandQueue".
    135              // Both will contain only one command at a time, so use a reserve of 1.
    136              iCurrentCommand.Construct(0, 1);
    137              iCancelCommand.Construct(0, 1);
    138 
    139              // Create the port vector.
    140              iPortVector.Construct(PVMF_MP3FFPARSER_NODE_PORT_VECTOR_RESERVE);
    141 
    142              // Set the node capability data.
    143              // This node can support an unlimited number of ports.
    144              iCapability.iCanSupportMultipleInputPorts = false;
    145              iCapability.iCanSupportMultipleOutputPorts = false;
    146              iCapability.iHasMaxNumberOfPorts = false;
    147              iCapability.iMaxNumberOfPorts = 0;//no maximum
    148              iCapability.iInputFormatCapability.push_back(PVMFFormatType(PVMF_MIME_MP3));
    149              iCapability.iOutputFormatCapability.push_back(PVMFFormatType(PVMF_MIME_MP3));
    150              // secondry construction
    151              Construct();
    152             );
    153 
    154     if (err != OsclErrNone)
    155     {
    156         //if a leave happened, cleanup and re-throw the error
    157         iInputCommands.clear();
    158         iCurrentCommand.clear();
    159         iCancelCommand.clear();
    160         iPortVector.clear();
    161         iCapability.iInputFormatCapability.clear();
    162         iCapability.iOutputFormatCapability.clear();
    163         OSCL_CLEANUP_BASE_CLASS(PVMFNodeInterface);
    164         OSCL_CLEANUP_BASE_CLASS(OsclTimerObject);
    165         iFileServer.Close();
    166         OSCL_LEAVE(err);
    167     }
    168 #if PV_HAS_SHOUTCAST_SUPPORT_ENABLED
    169     iMetadataVector.reserve(PVMF_MP3FFPARSER_NODE_METADATA_RESERVE);
    170 #endif
    171 }
    172 
    173 /**
    174  * Secondary constructor
    175  */
    176 void PVMFMP3FFParserNode::Construct()
    177 {
    178     iFileServer.Connect();
    179     iCPMContainer.Construct(PVMFSubNodeContainerBaseMp3::ECPM, this);
    180     //create the sub-node command queue.  Use a reserve to avoid
    181     //dynamic memory failure later.
    182     //Max depth is the max number of sub-node commands for any one node command.
    183     //Init command may take up to 9
    184     iSubNodeCmdVec.reserve(9);
    185 }
    186 
    187 /**
    188  * Destructor
    189  */
    190 PVMFMP3FFParserNode::~PVMFMP3FFParserNode()
    191 {
    192     if (IsAdded())
    193     {
    194         RemoveFromScheduler();
    195     }
    196 
    197     if (iDurationCalcAO)
    198     {
    199         OSCL_DELETE(iDurationCalcAO);
    200         iDurationCalcAO = NULL;
    201     }
    202 
    203     // Unbind the download progress clock
    204     iDownloadProgressClock.Unbind();
    205     // Release the download progress interface, if any
    206     if (iDownloadProgressInterface != NULL)
    207     {
    208         iDownloadProgressInterface->cancelResumeNotification();
    209         iDownloadProgressInterface->removeRef();
    210         iDownloadProgressInterface = NULL;
    211     }
    212 
    213     //if any CPM commands are pending, there will be a crash when they callback,
    214     //so panic here instead.
    215     if (iCPMContainer.CmdPending())
    216     {
    217         OSCL_ASSERT(0);
    218     }
    219 
    220     //Cleanup allocated ports
    221     while (!iPortVector.empty())
    222     {
    223         iPortVector.Erase(&iPortVector.front());
    224     }
    225 
    226     //Cleanup commands
    227     // The command queues are self-deleting, but we should notify the observer
    228     // of unprocessed commands.
    229     while (!iCancelCommand.empty())
    230     {
    231         CommandComplete(iCancelCommand, iCancelCommand.front(), PVMFFailure, NULL, NULL);
    232     }
    233     while (!iCurrentCommand.empty())
    234     {
    235         CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFFailure, NULL, NULL);
    236     }
    237     while (!iInputCommands.empty())
    238     {
    239         CommandComplete(iInputCommands, iInputCommands.front(), PVMFFailure, NULL, NULL);
    240     }
    241 
    242 #if PV_HAS_SHOUTCAST_SUPPORT_ENABLED
    243     while (!iMetadataVector.empty())
    244     {
    245         iMetadataVector.erase(iMetadataVector.begin());
    246     }
    247 #endif
    248 
    249     ReleaseTrack();
    250     // Clean up the file source
    251     CleanupFileSource();
    252     //CPM Cleanup should be done after CleanupFileSource
    253     iCPMContainer.Cleanup();
    254     // Disconnect fileserver
    255     iFileServer.Close();
    256 }
    257 
    258 /**
    259  * Public Node API implementation
    260  */
    261 
    262 /**
    263  * Do thread-specific node creation and go to "Idle" state.
    264  */
    265 PVMFStatus PVMFMP3FFParserNode::ThreadLogon()
    266 {
    267     LOGINFO((0, "PVMFMP3FFParserNode::ThreadLogon() iInterfaceState =%d", iInterfaceState));
    268     switch (iInterfaceState)
    269     {
    270         case EPVMFNodeCreated:
    271             if (!IsAdded())
    272             {
    273                 AddToScheduler();
    274             }
    275             iLogger = PVLogger::GetLoggerObject("PVMFMP3FFParserNode");
    276             SetState(EPVMFNodeIdle);
    277             return PVMFSuccess;
    278 
    279         default:
    280             LOGINFO((0, "PVMFMP3FFParserNode::ThreadLogon() iInterfaceState =%d is Invalid State", iInterfaceState));
    281             return PVMFErrInvalidState;
    282     }
    283 }
    284 
    285 /**
    286  * Do thread-specific node cleanup and go to "Created" state.
    287  */
    288 PVMFStatus PVMFMP3FFParserNode::ThreadLogoff()
    289 {
    290     LOGINFO((0, "PVMFMP3FFParserNode::ThreadLogoff() iInterfaceState =%d", iInterfaceState));
    291     switch (iInterfaceState)
    292     {
    293         case EPVMFNodeIdle:
    294             if (IsAdded())
    295             {
    296                 RemoveFromScheduler();
    297             }
    298             iLogger = NULL;
    299             SetState(EPVMFNodeCreated);
    300             return PVMFSuccess;
    301 
    302         default:
    303             LOGINFO((0, "PVMFMP3FFParserNode::ThreadLogoff() iInterfaceState =%d is Invalid State", iInterfaceState));
    304             return PVMFErrInvalidState;
    305     }
    306 }
    307 
    308 /**
    309  * Retrieve node capabilities.
    310  */
    311 PVMFStatus PVMFMP3FFParserNode::GetCapability(PVMFNodeCapability& aNodeCapability)
    312 {
    313     LOGINFO((0, "PVMFMP3FFParserNode::GetCapability()"));
    314     aNodeCapability = iCapability;
    315     return PVMFSuccess;
    316 }
    317 
    318 /**
    319  * Retrieve a port iterator.
    320  */
    321 PVMFPortIter* PVMFMP3FFParserNode::GetPorts(const PVMFPortFilter* aFilter)
    322 {
    323     LOGINFO((0, "PVMFMP3FFParserNode::GetPorts()"));
    324     //port filter is not implemented.
    325     OSCL_UNUSED_ARG(aFilter);
    326     iPortVector.Reset();
    327     return &iPortVector;
    328 }
    329 
    330 /**
    331  * Queue an asynchronous node command for QueryUUID
    332  */
    333 PVMFCommandId PVMFMP3FFParserNode::QueryUUID(PVMFSessionId aSession,
    334         const PvmfMimeString& aMimeType,
    335         Oscl_Vector<PVUuid, OsclMemAllocator>& aUuids,
    336         bool aExactUuidsOnly,
    337         const OsclAny* aContext)
    338 {
    339     LOGINFO((0, "PVMFMP3FFParserNode::QueryUUID()"));
    340     PVMFMP3FFParserNodeCommand cmd;
    341     cmd.PVMFMP3FFParserNodeCommandBase::Construct(aSession,
    342             PVMF_GENERIC_NODE_QUERYUUID,
    343             aMimeType,
    344             aUuids,
    345             aExactUuidsOnly,
    346             aContext);
    347     return QueueCommandL(cmd);
    348 }
    349 
    350 /**
    351  * Queue an asynchronous node command for QueryInterface
    352  */
    353 PVMFCommandId PVMFMP3FFParserNode::QueryInterface(PVMFSessionId aSession,
    354         const PVUuid& aUuid,
    355         PVInterface*& aInterfacePtr,
    356         const OsclAny* aContext)
    357 {
    358     LOGINFO((0, "PVMFMP3FFParserNode::QueryInterface()"));
    359     PVMFMP3FFParserNodeCommand cmd;
    360     cmd.PVMFMP3FFParserNodeCommandBase::Construct(aSession,
    361             PVMF_GENERIC_NODE_QUERYINTERFACE,
    362             aUuid,
    363             aInterfacePtr,
    364             aContext);
    365     return QueueCommandL(cmd);
    366 }
    367 
    368 /**
    369  * Queue an asynchronous node command for RequestPort
    370  */
    371 PVMFCommandId PVMFMP3FFParserNode::RequestPort(PVMFSessionId aSession,
    372         int32 aPortTag,
    373         const PvmfMimeString* aPortConfig,
    374         const OsclAny* aContext)
    375 {
    376     OSCL_UNUSED_ARG(aPortConfig);
    377     LOGINFO((0, "PVMFMP3FFParserNode::RequestPort()"));
    378     PVMFMP3FFParserNodeCommand cmd;
    379     cmd.PVMFMP3FFParserNodeCommandBase::Construct(aSession,
    380             PVMF_GENERIC_NODE_REQUESTPORT,
    381             aPortTag,
    382             aContext);
    383     return QueueCommandL(cmd);
    384 }
    385 
    386 /**
    387  * Queue an asynchronous node command for ReleasePort
    388  */
    389 PVMFCommandId PVMFMP3FFParserNode::ReleasePort(PVMFSessionId aSession,
    390         PVMFPortInterface& aPort,
    391         const OsclAny* aContext)
    392 {
    393     LOGINFO((0, "PVMFMP3FFParserNode::ReleasePort()"));
    394     PVMFMP3FFParserNodeCommand cmd;
    395     cmd.PVMFMP3FFParserNodeCommandBase::Construct(aSession,
    396             PVMF_GENERIC_NODE_RELEASEPORT,
    397             aPort,
    398             aContext);
    399     return QueueCommandL(cmd);
    400 }
    401 
    402 /**
    403  * Queue an asynchronous node command for Init
    404  */
    405 PVMFCommandId PVMFMP3FFParserNode::Init(PVMFSessionId aSession,
    406                                         const OsclAny* aContext)
    407 {
    408     LOGINFO((0, "PVMFMP3FFParserNode::Init()"));
    409     PVMFMP3FFParserNodeCommand cmd;
    410     cmd.PVMFMP3FFParserNodeCommandBase::Construct(aSession,
    411             PVMF_GENERIC_NODE_INIT,
    412             aContext);
    413     return QueueCommandL(cmd);
    414 }
    415 
    416 /**
    417  * Queue an asynchronous node command for Prepare
    418  */
    419 PVMFCommandId PVMFMP3FFParserNode::Prepare(PVMFSessionId aSession,
    420         const OsclAny* aContext)
    421 {
    422     LOGINFO((0, "PVMFMP3FFParserNode::Prepare()"));
    423     PVMFMP3FFParserNodeCommand cmd;
    424     cmd.PVMFMP3FFParserNodeCommandBase::Construct(aSession,
    425             PVMF_GENERIC_NODE_PREPARE,
    426             aContext);
    427     return QueueCommandL(cmd);
    428 }
    429 
    430 /**
    431  * Queue an asynchronous node command for Start
    432  */
    433 PVMFCommandId PVMFMP3FFParserNode::Start(PVMFSessionId aSession,
    434         const OsclAny* aContext)
    435 {
    436     LOGINFO((0, "PVMFMP3FFParserNode::Start()"));
    437     PVMFMP3FFParserNodeCommand cmd;
    438     cmd.PVMFMP3FFParserNodeCommandBase::Construct(aSession,
    439             PVMF_GENERIC_NODE_START,
    440             aContext);
    441     return QueueCommandL(cmd);
    442 }
    443 
    444 /**
    445  * Queue an asynchronous node command for Stop
    446  */
    447 PVMFCommandId PVMFMP3FFParserNode::Stop(PVMFSessionId aSession,
    448                                         const OsclAny* aContext)
    449 {
    450     LOGINFO((0, "PVMFMP3FFParserNode::Stop()"));
    451     PVMFMP3FFParserNodeCommand cmd;
    452     cmd.PVMFMP3FFParserNodeCommandBase::Construct(aSession,
    453             PVMF_GENERIC_NODE_STOP,
    454             aContext);
    455     return QueueCommandL(cmd);
    456 }
    457 
    458 /**
    459  * Queue an asynchronous node command for Flush
    460  */
    461 PVMFCommandId PVMFMP3FFParserNode::Flush(PVMFSessionId aSession,
    462         const OsclAny* aContext)
    463 {
    464     LOGINFO((0, "PVMFMP3FFParserNode::Flush()"));
    465     PVMFMP3FFParserNodeCommand cmd;
    466     cmd.PVMFMP3FFParserNodeCommandBase::Construct(aSession,
    467             PVMF_GENERIC_NODE_FLUSH,
    468             aContext);
    469     return QueueCommandL(cmd);
    470 }
    471 
    472 /**
    473  * Queue an asynchronous node command for Pause
    474  */
    475 PVMFCommandId PVMFMP3FFParserNode::Pause(PVMFSessionId aSession,
    476         const OsclAny* aContext)
    477 {
    478     LOGINFO((0, "PVMFMP3FFParserNode::Pause()"));
    479     PVMFMP3FFParserNodeCommand cmd;
    480     cmd.PVMFMP3FFParserNodeCommandBase::Construct(aSession,
    481             PVMF_GENERIC_NODE_PAUSE,
    482             aContext);
    483     return QueueCommandL(cmd);
    484 }
    485 
    486 /**
    487  * Queue an asynchronous node command for Reset
    488  */
    489 PVMFCommandId PVMFMP3FFParserNode::Reset(PVMFSessionId aSession,
    490         const OsclAny* aContext)
    491 {
    492     LOGINFO((0, "PVMFMP3FFParserNode::Reset()"));
    493     PVMFMP3FFParserNodeCommand cmd;
    494     cmd.PVMFMP3FFParserNodeCommandBase::Construct(aSession,
    495             PVMF_GENERIC_NODE_RESET,
    496             aContext);
    497     return QueueCommandL(cmd);
    498 }
    499 
    500 /**
    501  * Queue an asynchronous node command for CancelAllCommands
    502  */
    503 PVMFCommandId PVMFMP3FFParserNode::CancelAllCommands(PVMFSessionId aSession,
    504         const OsclAny* aContext)
    505 {
    506     LOGINFO((0, "PVMFMP3FFParserNode::CancelAllCommands()"));
    507     PVMFMP3FFParserNodeCommand cmd;
    508     cmd.PVMFMP3FFParserNodeCommandBase::Construct(aSession,
    509             PVMF_GENERIC_NODE_CANCELALLCOMMANDS,
    510             aContext);
    511     return QueueCommandL(cmd);
    512 }
    513 
    514 /**
    515  * Queue an asynchronous node command for CancelCommand
    516  */
    517 PVMFCommandId PVMFMP3FFParserNode::CancelCommand(PVMFSessionId aSession,
    518         PVMFCommandId aCmdId,
    519         const OsclAny* aContext)
    520 {
    521     LOGINFO((0, "PVMFMP3FFParserNode::CancelCommand()"));
    522     PVMFMP3FFParserNodeCommand cmd;
    523     cmd.PVMFMP3FFParserNodeCommandBase::Construct(aSession,
    524             PVMF_GENERIC_NODE_CANCELCOMMAND,
    525             aCmdId,
    526             aContext);
    527     return QueueCommandL(cmd);
    528 }
    529 
    530 /**
    531  * This routine is called by various command APIs to queue an
    532  * asynchronous command for processing by the command handler AO.
    533  * This function may leave if the command can't be queued due to
    534  * memory allocation failure.
    535  */
    536 PVMFCommandId PVMFMP3FFParserNode::QueueCommandL(PVMFMP3FFParserNodeCommand& aCmd)
    537 {
    538     if (IsAdded())
    539     {
    540         PVMFCommandId id;
    541         id = iInputCommands.AddL(aCmd);
    542         /* Wakeup the AO */
    543         RunIfNotReady();
    544         return id;
    545     }
    546     OSCL_LEAVE(OsclErrInvalidState);
    547     return -1;
    548 }
    549 
    550 /**
    551  * Asynchronous Command processing routines.
    552  * These routines are all called under the AO.
    553  */
    554 
    555 /**
    556  * Called by the command handler AO to process a command from
    557  * the input queue.
    558  */
    559 void PVMFMP3FFParserNode::ProcessCommand()
    560 {
    561     // Can't do anything when an asynchronous cancel is in progress
    562     // need to wait on completion
    563     if (!iCancelCommand.empty())
    564     {
    565         return; //keep waiting.
    566     }
    567 
    568     // If a command is in progress, only a hi-pri command can interrupt it.
    569     if (!iCurrentCommand.empty() && !iInputCommands.front().hipri() && iInputCommands.front().iCmd != PVMP3FF_NODE_CMD_CANCEL_GET_LICENSE)
    570     {
    571         return; //keep waiting
    572     }
    573 
    574     // InputCommandQueue shall have at least one command queued
    575     OSCL_ASSERT(!iInputCommands.empty());
    576     // This call will process the first node command in the input queue.
    577     // The newest or highest pri command is in the front of the queue.
    578     PVMFMP3FFParserNodeCommand& aCmd = iInputCommands.front();
    579 
    580     PVMFStatus cmdstatus;
    581     OsclAny* eventdata = NULL;
    582     PVInterface* extmsg = NULL;
    583     if (aCmd.hipri() || iInputCommands.front().iCmd == PVMP3FF_NODE_CMD_CANCEL_GET_LICENSE)
    584     {
    585         //Process the Hi-Pri commands
    586         switch (aCmd.iCmd)
    587         {
    588             case PVMF_GENERIC_NODE_CANCELALLCOMMANDS:
    589                 cmdstatus = DoCancelAllCommands(aCmd);
    590                 break;
    591             case PVMF_GENERIC_NODE_CANCELCOMMAND:
    592                 cmdstatus = DoCancelCommand(aCmd);
    593                 break;
    594             case PVMP3FF_NODE_CMD_CANCEL_GET_LICENSE:
    595                 cmdstatus = DoCancelGetLicense(aCmd);
    596                 break;
    597 
    598             default:
    599                 cmdstatus = PVMFErrNotSupported;
    600                 break;
    601         } // end switch, processing hi-priority commands
    602 
    603         // If completion is pending, move the command from the InputCommandQueue
    604         // to the CancelCommandQueue. This is necessary since the InputCommandQueue
    605         // could get rearranged by new in-coming commands.
    606         if (cmdstatus == PVMFPending)
    607         {
    608             iCancelCommand.StoreL(aCmd);
    609             iInputCommands.Erase(&aCmd);
    610         }
    611     }
    612     else
    613     {
    614         //Process the normal pri commands.
    615         switch (aCmd.iCmd)
    616         {
    617             case PVMF_GENERIC_NODE_QUERYUUID:
    618                 cmdstatus = DoQueryUuid(aCmd);
    619                 break;
    620             case PVMF_GENERIC_NODE_QUERYINTERFACE:
    621                 cmdstatus = DoQueryInterface(aCmd);
    622                 break;
    623             case PVMF_GENERIC_NODE_REQUESTPORT:
    624             {
    625                 PVMFPortInterface*port;
    626                 cmdstatus = DoRequestPort(aCmd, port);
    627                 eventdata = (OsclAny*)port;
    628             }
    629             break;
    630             case PVMF_GENERIC_NODE_RELEASEPORT:
    631                 cmdstatus = DoReleasePort(aCmd);
    632                 break;
    633             case PVMF_GENERIC_NODE_INIT:
    634                 cmdstatus = DoInit(aCmd);
    635                 break;
    636             case PVMF_GENERIC_NODE_PREPARE:
    637                 cmdstatus = DoPrepare(aCmd);
    638                 break;
    639             case PVMF_GENERIC_NODE_START:
    640                 cmdstatus = DoStart(aCmd);
    641                 break;
    642             case PVMF_GENERIC_NODE_STOP:
    643                 cmdstatus = DoStop(aCmd);
    644                 break;
    645             case PVMF_GENERIC_NODE_FLUSH:
    646                 cmdstatus = DoFlush(aCmd);
    647                 break;
    648             case PVMF_GENERIC_NODE_PAUSE:
    649                 cmdstatus = DoPause(aCmd);
    650                 break;
    651             case PVMF_GENERIC_NODE_RESET:
    652                 cmdstatus = DoReset(aCmd);
    653                 break;
    654             case PVMP3FF_NODE_CMD_GETNODEMETADATAKEY:
    655                 cmdstatus = DoGetMetadataKeys(aCmd);
    656                 break;
    657             case PVMP3FF_NODE_CMD_GETNODEMETADATAVALUE:
    658                 cmdstatus = DoGetMetadataValues(aCmd);
    659                 break;
    660             case PVMP3FF_NODE_CMD_SETDATASOURCEPOSITION:
    661                 cmdstatus = DoSetDataSourcePosition(aCmd);
    662                 break;
    663             case PVMP3FF_NODE_CMD_QUERYDATASOURCEPOSITION:
    664                 cmdstatus = DoQueryDataSourcePosition(aCmd);
    665                 break;
    666             case PVMP3FF_NODE_CMD_SETDATASOURCERATE:
    667                 cmdstatus = DoSetDataSourceRate(aCmd);
    668                 break;
    669             case PVMP3FF_NODE_CMD_GET_LICENSE_W:
    670                 cmdstatus = DoGetLicense(aCmd, true);
    671                 break;
    672 
    673             case PVMP3FF_NODE_CMD_GET_LICENSE:
    674                 cmdstatus = DoGetLicense(aCmd);
    675                 break;
    676             default:
    677                 // command not supported
    678                 OSCL_ASSERT(false);
    679                 cmdstatus = PVMFFailure;
    680                 break;
    681         } // end switch, processing low priority commands
    682 
    683         // If completion is pending, move the command from the InputCommandQueue
    684         // to the CurrentCommandQueue. This is necessary since the InputCommandQueue
    685         // could get rearranged by new in-coming commands.
    686         if (cmdstatus == PVMFPending)
    687         {
    688             iCurrentCommand.StoreL(aCmd);
    689             iInputCommands.Erase(&aCmd);
    690         }
    691     } // end else
    692 
    693     // The command has been processed, this means that the command might
    694     // have been failed/succeeded, but it is no more pending
    695     // report command complete to the observer
    696     if (cmdstatus != PVMFPending)
    697     {
    698         CommandComplete(iInputCommands, aCmd, cmdstatus, extmsg, eventdata);
    699     }
    700 }
    701 
    702 void PVMFMP3FFParserNode::CompleteInit(PVMFStatus aStatus)
    703 {
    704     if ((iCurrentCommand.empty() == false) &&
    705             (iCurrentCommand.front().iCmd == PVMF_GENERIC_NODE_INIT))
    706     {
    707         if (!iSubNodeCmdVec.empty())
    708         {
    709             iSubNodeCmdVec.front().iSubNodeContainer->CommandDone(PVMFSuccess, NULL, NULL);
    710         }
    711         else
    712         {
    713             CommandComplete(iCurrentCommand, iCurrentCommand.front(), aStatus, NULL, NULL);
    714         }
    715     }
    716 }
    717 
    718 /**
    719  * Reports command complete event to the observer, switches node state according to
    720  * the command processed, Erases the command from the queue and reports command
    721  * complete event to the Node Observer
    722  */
    723 void PVMFMP3FFParserNode::CommandComplete(PVMFMP3FFParserNodeCmdQ& aCmdQ,
    724         PVMFMP3FFParserNodeCommand& aCmd,
    725         PVMFStatus aStatus, PVInterface* aExtMsg,
    726         OsclAny* aEventData)
    727 {
    728     LOGINFO((0, "PVMFMP3FFParserNode::CommandComplete() Id %d Cmd %d Status %d Context %d Data %d"
    729              , aCmd.iId, aCmd.iCmd, aStatus, aCmd.iContext, aEventData));
    730 
    731     // If the command failed or was cancelled there may be un-processed
    732     // sub-node commands, so clear the vector now.
    733     if (!iSubNodeCmdVec.empty())
    734     {
    735         iSubNodeCmdVec.clear();
    736     }
    737 
    738     //Do state transitions according the command was processed successfully
    739     if (aStatus == PVMFSuccess)
    740     {
    741         switch (aCmd.iCmd)
    742         {
    743             case PVMF_GENERIC_NODE_INIT:
    744                 SetState(EPVMFNodeInitialized);
    745                 break;
    746             case PVMF_GENERIC_NODE_PREPARE:
    747                 SetState(EPVMFNodePrepared);
    748                 break;
    749             case PVMF_GENERIC_NODE_START:
    750                 SetState(EPVMFNodeStarted);
    751                 break;
    752             case PVMF_GENERIC_NODE_STOP:
    753             case PVMF_GENERIC_NODE_FLUSH:
    754                 SetState(EPVMFNodePrepared);
    755                 break;
    756             case PVMF_GENERIC_NODE_PAUSE:
    757                 SetState(EPVMFNodePaused);
    758                 break;
    759             case PVMF_GENERIC_NODE_RESET:
    760                 SetState(EPVMFNodeIdle);
    761                 break;
    762             default:
    763                 break;
    764         }
    765     }
    766     else
    767     {
    768         // Log that the command completion was failed
    769         PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMFMP3FFParserNode:CommandComplete Failed!"));
    770     }
    771 
    772     // Create response to notify the observer
    773     PVMFCmdResp resp(aCmd.iId, aCmd.iContext, aStatus, aExtMsg, aEventData);
    774     PVMFSessionId session = aCmd.iSession;
    775 
    776     // Erase the command from the queue
    777     aCmdQ.Erase(&aCmd);
    778 
    779     //Report command completion to the session observer
    780     ReportCmdCompleteEvent(session, resp);
    781 
    782     // Re-schedule Node if the AO is active and there are additional
    783     // commands to be processed.
    784     if (iInputCommands.size() > 0 && IsAdded())
    785     {
    786         RunIfNotReady();
    787     }
    788 }
    789 
    790 /**
    791  * CommandHandler for Reset command
    792  */
    793 PVMFStatus PVMFMP3FFParserNode::DoReset(PVMFMP3FFParserNodeCommand& aCmd)
    794 {
    795     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
    796                     (0, "PVMFMP3FFParserNode::DoReset() In"));
    797 
    798     OSCL_UNUSED_ARG(aCmd);
    799     // Check if the node can accept the Reset command in the current state
    800     PVMFStatus status;
    801     switch (iInterfaceState)
    802     {
    803         case EPVMFNodeCreated:
    804         case EPVMFNodeIdle:
    805         case EPVMFNodeInitialized:
    806         case EPVMFNodePrepared:
    807         case EPVMFNodeStarted:
    808         case EPVMFNodePaused:
    809         case EPVMFNodeError:
    810         {
    811             if (iDownloadProgressInterface != NULL)
    812             {
    813                 iDownloadProgressInterface->cancelResumeNotification();
    814             }
    815             if (iDurationCalcAO && iDurationCalcAO->IsBusy())
    816             {
    817                 iDurationCalcAO->Cancel();
    818             }
    819             // Delete all ports and notify observer
    820             while (!iPortVector.empty())
    821             {
    822                 iPortVector.Erase(&iPortVector.front());
    823             }
    824 
    825             // Restore original port vector reserve.
    826             iPortVector.Reconstruct();
    827             // Stop and cleanup
    828             ReleaseTrack();
    829             CleanupFileSource();
    830             // Cleanup CPM
    831             if (iCPMContainer.iCPM)
    832             {
    833                 Push(iCPMContainer, PVMFSubNodeContainerBaseMp3::ECPMUsageComplete);
    834                 Push(iCPMContainer, PVMFSubNodeContainerBaseMp3::ECPMCloseSession);
    835                 Push(iCPMContainer, PVMFSubNodeContainerBaseMp3::ECPMReset);
    836                 Push(iCPMContainer, PVMFSubNodeContainerBaseMp3::ECPMCleanup);
    837                 RunIfNotReady();
    838                 //wait on CPM commands to execute
    839                 status = PVMFPending;
    840             }
    841             else
    842             {
    843                 status = PVMFSuccess;
    844             }
    845         }
    846         break;
    847         default:
    848             // Reset was not processed becasue of Node's invalid state
    849             status = PVMFErrInvalidState;
    850             break;
    851     }
    852     return status;
    853 }
    854 
    855 /**
    856  * CommandHandler for Query UUID
    857  */
    858 PVMFStatus PVMFMP3FFParserNode::DoQueryUuid(PVMFMP3FFParserNodeCommand& aCmd)
    859 {
    860     // This node supports Query UUID from any state
    861     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
    862                     (0, "PVMFMP3FFParserNode::DoQueryUuid() In"));
    863 
    864     OSCL_String* mimetype;
    865     Oscl_Vector<PVUuid, OsclMemAllocator> *uuidvec;
    866     bool exactmatch;
    867     aCmd.PVMFMP3FFParserNodeCommandBase::Parse(mimetype, uuidvec, exactmatch);
    868 
    869     // Match the input mimetype against any of the custom interfaces
    870     // for this node
    871     if (*mimetype == PVMF_DATA_SOURCE_INIT_INTERFACE_MIMETYPE)
    872     {
    873         PVUuid uuid(PVMF_DATA_SOURCE_INIT_INTERFACE_UUID);
    874         uuidvec->push_back(uuid);
    875     }
    876     else if (*mimetype == PVMF_TRACK_SELECTION_INTERFACE_MIMETYPE)
    877     {
    878         PVUuid uuid(PVMF_TRACK_SELECTION_INTERFACE_UUID);
    879         uuidvec->push_back(uuid);
    880     }
    881     else if (*mimetype == PVMF_META_DATA_EXTENSION_INTERFACE_MIMETYPE)
    882     {
    883         PVUuid uuid(KPVMFMetadataExtensionUuid);
    884         uuidvec->push_back(uuid);
    885     }
    886     else if (*mimetype == PVMF_FF_PROGDOWNLOAD_SUPPORT_INTERFACE_MIMETYPE)
    887     {
    888         PVUuid uuid(PVMF_FF_PROGDOWNLOAD_SUPPORT_INTERFACE_UUID);
    889         uuidvec->push_back(uuid);
    890     }
    891     else if (*mimetype == PVMF_DATA_SOURCE_PLAYBACK_CONTROL_INTERFACE_MIMETYPE)
    892     {
    893         PVUuid uuid(PvmfDataSourcePlaybackControlUuid);
    894         uuidvec->push_back(uuid);
    895     }
    896     else if (*mimetype == PVMI_DATASTREAMUSER_INTERFACE_MIMETYPE)
    897     {
    898         PVUuid uuid(PVMIDatastreamuserInterfaceUuid);
    899         uuidvec->push_back(uuid);
    900     }
    901     return PVMFSuccess;
    902 }
    903 
    904 /**
    905  * CommandHandler for Query Interface
    906  */
    907 PVMFStatus PVMFMP3FFParserNode::DoQueryInterface(PVMFMP3FFParserNodeCommand& aCmd)
    908 {
    909     // This node supports Query Interface from any state
    910     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
    911                     (0, "PVMFMP3FFParserNode::DoQueryInterface() In"));
    912     PVUuid* uuid;
    913     PVInterface** ptr;
    914     aCmd.PVMFMP3FFParserNodeCommandBase::Parse(uuid, ptr);
    915     PVMFStatus status;
    916 
    917     if (queryInterface(*uuid, *ptr))
    918     {
    919         (*ptr)->addRef();
    920         status = PVMFSuccess;
    921     }
    922     else
    923     {
    924         // Interface not supported
    925         *ptr = NULL;
    926         status = PVMFFailure;
    927     }
    928     return status;
    929 }
    930 
    931 /**
    932  * CommandHandler for port request
    933  */
    934 PVMFStatus PVMFMP3FFParserNode::DoRequestPort(PVMFMP3FFParserNodeCommand& aCmd,
    935         PVMFPortInterface*&aPort)
    936 {
    937     // This node supports port request from any state
    938     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
    939                     (0, "PVMFMP3FFParserNode::DoRequestPort In"));
    940     aPort = NULL;
    941     // Retrieve port tag.
    942     int32 tag;
    943     OSCL_String* mimetype;
    944     aCmd.PVMFMP3FFParserNodeCommandBase::Parse(tag, mimetype);
    945 
    946     //mimetype is not used on this node
    947     //validate the tag
    948     if (tag != PVMF_MP3FFPARSER_NODE_PORT_TYPE_SOURCE)
    949     {
    950         // Invalid port tag
    951         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
    952                         (0, "PVMFMP3FFParserNode::DoRequestPort: Error - Invalid port tag"));
    953         return PVMFFailure;
    954     }
    955 
    956     //Allocate a new port
    957     OsclAny *ptr = NULL;
    958     int32 err = 0;
    959     OSCL_TRY(err, ptr = iPortVector.Allocate(););
    960     if (err != OsclErrNone || !ptr)
    961     {
    962         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
    963                         (0, "PVMFMP3FFParserNode::DoRequestPort: Error - iPortVector Out of memory"));
    964         return PVMFErrNoMemory;
    965     }
    966 
    967     // Create base port with default settings...
    968     PVMFMP3FFParserPort*outport = new(ptr) PVMFMP3FFParserPort(tag, this,
    969             0, 0, 0,    // input queue isn't needed.
    970             DEFAULT_DATA_QUEUE_CAPACITY,
    971             DEFAULT_DATA_QUEUE_CAPACITY,
    972             DEFAULT_READY_TO_RECEIVE_THRESHOLD_PERCENT);
    973 
    974     //Add the port to the port vector.
    975     err = 0;
    976     OSCL_TRY(err, iPortVector.AddL(outport););
    977     if (err != OsclErrNone)
    978     {
    979         return PVMFErrNoMemory;
    980     }
    981 
    982     OsclMemPoolResizableAllocator* trackdatamempool = NULL;
    983     PVMFResizableSimpleMediaMsgAlloc *mediadataimplalloc = NULL;
    984     PVMFMemPoolFixedChunkAllocator* mediadatamempool = NULL;
    985     MediaClockConverter* clockconv = NULL;
    986     err = 0;
    987     // Try block starts
    988     OSCL_TRY(err,
    989              // Instantiate the mem pool which will hold the actual track data
    990              trackdatamempool = OSCL_NEW(OsclMemPoolResizableAllocator,
    991                                          (2 * PVMF3FF_DEFAULT_NUM_OF_FRAMES * iMaxFrameSize, 2));
    992 
    993              // Instantiate an allocator for the mediadata implementation,
    994              // have it use the mem pool defined above as its allocator
    995              mediadataimplalloc = OSCL_NEW(PVMFResizableSimpleMediaMsgAlloc, (trackdatamempool));
    996 
    997              // Instantiate another memory pool for the media data structures.
    998              mediadatamempool = OSCL_NEW(PVMFMemPoolFixedChunkAllocator,
    999                                          ("Mp3FFPar", PVMP3FF_MEDIADATA_CHUNKS_IN_POOL,
   1000                                           PVMP3FF_MEDIADATA_CHUNKSIZE));
   1001              clockconv = OSCL_NEW(MediaClockConverter, (iMP3File->GetTimescale()));
   1002             ); // Try block end
   1003 
   1004     if (err != 0 || trackdatamempool == NULL || mediadataimplalloc == NULL || mediadatamempool == NULL || clockconv == NULL)
   1005     {
   1006         if (clockconv)
   1007         {
   1008             OSCL_DELETE(clockconv);
   1009         }
   1010         if (mediadatamempool)
   1011         {
   1012             OSCL_DELETE(mediadatamempool);
   1013         }
   1014         if (mediadataimplalloc)
   1015         {
   1016             OSCL_DELETE(mediadataimplalloc);
   1017         }
   1018         if (trackdatamempool)
   1019         {
   1020             trackdatamempool->removeRef();
   1021         }
   1022         iPortVector.Erase(&outport);
   1023 
   1024         return PVMFErrNoMemory;
   1025     }
   1026 
   1027     trackdatamempool->enablenullpointerreturn();
   1028     mediadatamempool->enablenullpointerreturn();
   1029 
   1030     // Instantiate the PVMP3FFNodeTrackPortInfo object that contains the port.
   1031     iTrack.iPort = outport;
   1032     iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_UNINITIALIZED;
   1033     iTrack.iClockConverter = clockconv;
   1034     iTrack.iMediaDataMemPool = mediadatamempool;
   1035     iTrack.iTrackDataMemoryPool = trackdatamempool;
   1036     iTrack.iMediaDataImplAlloc = mediadataimplalloc;
   1037     iTrack.timestamp_offset = 0;
   1038 
   1039     // Return the port pointer to the caller.
   1040     aPort = outport;
   1041     return PVMFSuccess;
   1042 }
   1043 
   1044 /**
   1045  * Called by the command handler AO to do the port release
   1046  */
   1047 PVMFStatus PVMFMP3FFParserNode::DoReleasePort(PVMFMP3FFParserNodeCommand& aCmd)
   1048 {
   1049     //This node supports release port from any state
   1050     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1051                     (0, "PVMFMP3FFParserNode::DoReleasePort() In"));
   1052     //Find the port in the port vector
   1053     PVMFStatus status;
   1054     PVMFPortInterface* p = NULL;
   1055     aCmd.PVMFMP3FFParserNodeCommandBase::Parse(p);
   1056 
   1057     PVMFMP3FFParserPort* port = (PVMFMP3FFParserPort*)p;
   1058 
   1059     PVMFMP3FFParserPort** portPtr = iPortVector.FindByValue(port);
   1060     if (iDurationCalcAO && iDurationCalcAO->IsBusy())
   1061     {
   1062         iDurationCalcAO->Cancel();
   1063     }
   1064     if (portPtr)
   1065     {
   1066         //delete the port.
   1067         iPortVector.Erase(portPtr);
   1068         ReleaseTrack();
   1069         status = PVMFSuccess;
   1070     }
   1071     else
   1072     {
   1073         //port not found.
   1074         status = PVMFFailure;
   1075     }
   1076     return status;
   1077 }
   1078 
   1079 /**
   1080  * Called by the command handler AO to do the node Init
   1081  */
   1082 PVMFStatus PVMFMP3FFParserNode::DoInit(PVMFMP3FFParserNodeCommand& aCmd)
   1083 {
   1084     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1085                     (0, "PVMFMP3FFParserNode::DoInit() In"));
   1086 
   1087     OSCL_UNUSED_ARG(aCmd);
   1088     PVMFStatus status = PVMFSuccess;
   1089     // Process Init according to the Node State
   1090     switch (iInterfaceState)
   1091     {
   1092         case EPVMFNodeIdle:
   1093             //we need to go through the CPM sequence to check access on the file.
   1094             if (oWaitingOnLicense == false)
   1095             {
   1096                 Push(iCPMContainer, PVMFSubNodeContainerBaseMp3::ECPMInit);
   1097             }
   1098             else
   1099             {
   1100                 Push(iCPMContainer, PVMFSubNodeContainerBaseMp3::ECPMApproveUsage);
   1101                 Push(iCPMContainer, PVMFSubNodeContainerBaseMp3::ECPMCheckUsage);
   1102             }
   1103 
   1104             RunIfNotReady();
   1105             status = PVMFPending;
   1106             break;
   1107 
   1108         default:
   1109             status = PVMFErrInvalidState;
   1110             break;
   1111     }
   1112     return status;
   1113 }
   1114 
   1115 /**
   1116  * CommandHandler for node Prepare
   1117  */
   1118 PVMFStatus PVMFMP3FFParserNode::DoPrepare(PVMFMP3FFParserNodeCommand& aCmd)
   1119 {
   1120     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1121                     (0, "PVMFMP3FFParserNode::DoPrepare() In"));
   1122 
   1123     OSCL_UNUSED_ARG(aCmd);
   1124     // Process Prepare according to the Node State
   1125     switch (iInterfaceState)
   1126     {
   1127         case EPVMFNodeInitialized:
   1128             //this node doesn't do anything to get ready to start.
   1129             break;
   1130 
   1131         default:
   1132             return PVMFErrInvalidState;
   1133             break;
   1134     }
   1135     // If this is an PDL session request callback from ProgressInterface when data with
   1136     // ts TimeStamp is downloaded, DPI shall callback the node once data is downloaded
   1137     if ((iDownloadProgressInterface != NULL) &&
   1138             (iDownloadComplete == false))
   1139     {
   1140         // check for download complete
   1141         // if download is not complete, request to be notified when data is ready
   1142         uint32 bytesReady = 0;
   1143         PvmiDataStreamStatus status = iDataStreamInterface->QueryReadCapacity(iDataStreamSessionID, bytesReady);
   1144         if (status == PVDS_END_OF_STREAM)
   1145         {
   1146             if (!iFileSizeRecvd)
   1147             {
   1148                 iFileSize = bytesReady;
   1149                 iFileSizeRecvd = true;
   1150             }
   1151             return PVMFSuccess;
   1152         }
   1153         if (bytesReady == 0)
   1154         {
   1155 
   1156             uint32 ts = 0;
   1157             iDownloadProgressInterface->requestResumeNotification(ts, iDownloadComplete);
   1158             // Data is not available, autopause the track.
   1159             iAutoPaused = true;
   1160             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFMP3FFParserNode::DoPrepare() - Auto Pause Triggered, TS = %d", ts));
   1161         }
   1162     }
   1163     return PVMFSuccess;
   1164 }
   1165 
   1166 /**
   1167  * CommandHandler for node Start
   1168  */
   1169 PVMFStatus PVMFMP3FFParserNode::DoStart(PVMFMP3FFParserNodeCommand& aCmd)
   1170 {
   1171     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1172                     (0, "PVMFMP3FFParserNode::DoStart() In"));
   1173 
   1174     OSCL_UNUSED_ARG(aCmd);
   1175     PVMFStatus status = PVMFSuccess;
   1176     // Process Start according to the Node State
   1177     switch (iInterfaceState)
   1178     {
   1179         case EPVMFNodePrepared:
   1180             break;
   1181 
   1182         case EPVMFNodePaused:
   1183         {
   1184             iAutoPaused = false;
   1185             // If track was in Autopause state, change track state to
   1186             // retrieve more data in case
   1187             if (PVMP3FFNodeTrackPortInfo::TRACKSTATE_DOWNLOAD_AUTOPAUSE == iTrack.iState)
   1188             {
   1189                 iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_GETDATA;
   1190             }
   1191             break;
   1192         }
   1193         default:
   1194             status = PVMFErrInvalidState;
   1195             break;
   1196     }
   1197     return status;
   1198 }
   1199 
   1200 /**
   1201  * CommandHandler for node Stop
   1202  */
   1203 PVMFStatus PVMFMP3FFParserNode::DoStop(PVMFMP3FFParserNodeCommand& aCmd)
   1204 {
   1205 
   1206     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1207                     (0, "PVMFMP3FFParserNode::DoStop() In"));
   1208 
   1209     OSCL_UNUSED_ARG(aCmd);
   1210     PVMFStatus status = PVMFSuccess;
   1211     // Process Stop according to the Node State
   1212     iStreamID = 0;
   1213     switch (iInterfaceState)
   1214     {
   1215         case EPVMFNodeStarted:
   1216         case EPVMFNodePaused:
   1217         {
   1218             // Clear queued messages in ports
   1219             uint32 index;
   1220             for (index = 0; index < iPortVector.size(); index++)
   1221             {
   1222                 iPortVector[index]->ClearMsgQueues();
   1223             }
   1224             // Position the parser to beginning of file
   1225             iMP3File->SeekToTimestamp(0);
   1226             // reset the track
   1227             ResetTrack();
   1228             status = PVMFSuccess;
   1229             iFileSizeRecvd = false;
   1230             iDownloadComplete = false;
   1231             if (iDurationCalcAO)
   1232             {
   1233                 iDurationCalcAO->Cancel();
   1234             }
   1235         }
   1236         break;
   1237         default:
   1238             status = PVMFErrInvalidState;
   1239             break;
   1240     }
   1241     return status;
   1242 }
   1243 
   1244 /**
   1245  * CommandHandler for node Flush
   1246  */
   1247 PVMFStatus PVMFMP3FFParserNode::DoFlush(PVMFMP3FFParserNodeCommand& aCmd)
   1248 {
   1249     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1250                     (0, "PVMFMP3FFParserNode::DoFlush() In"));
   1251 
   1252     // Process Flush according to the Node State
   1253     PVMFStatus status = PVMFSuccess;
   1254     switch (iInterfaceState)
   1255     {
   1256         case EPVMFNodeStarted:
   1257         case EPVMFNodePaused:
   1258         {
   1259             // Flush is asynchronous. Move the command from InputCommandQueue
   1260             // to the current command, where it will remain until the flush
   1261             // completes
   1262             int32 err;
   1263             OSCL_TRY(err, iCurrentCommand.StoreL(aCmd););
   1264             if (err != OsclErrNone)
   1265             {
   1266                 // Was unable to move the command to the CurrentCommandQueue
   1267                 // because of Memory unavailability
   1268                 status = PVMFErrNoMemory;
   1269                 break;
   1270             }
   1271             // Command copied to CurrentCommandQueue, now erase from InputCommandQueue
   1272             iInputCommands.Erase(&aCmd);
   1273 
   1274             // Notify all ports to suspend their input
   1275             for (uint32 index = 0; index < iPortVector.size(); index++)
   1276             {
   1277                 iPortVector[index]->SuspendInput();
   1278             }
   1279             // reset the track
   1280             ResetTrack();
   1281             if (iDurationCalcAO && iDurationCalcAO->IsBusy())
   1282             {
   1283                 iDurationCalcAO->Cancel();
   1284             }
   1285             // Completion of Flush shall be handled by Run()
   1286             status = PVMFPending;
   1287         }
   1288         break;
   1289         default:
   1290             // Could not perform flush in current state
   1291             status = PVMFErrInvalidState;
   1292             break;
   1293     }
   1294     return status;
   1295 }
   1296 
   1297 /**
   1298  * A routine to tell if a flush operation is in progress.
   1299  */
   1300 bool PVMFMP3FFParserNode::FlushPending()
   1301 {
   1302     // Check if current command is FLUSH
   1303     return (iCurrentCommand.size() > 0 &&
   1304             iCurrentCommand.front().iCmd == PVMF_GENERIC_NODE_FLUSH);
   1305 }
   1306 
   1307 
   1308 /**
   1309  * CommandHandler for node Pause
   1310  */
   1311 PVMFStatus PVMFMP3FFParserNode::DoPause(PVMFMP3FFParserNodeCommand& aCmd)
   1312 {
   1313     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1314                     (0, "PVMFMP3FFParserNode::DoPause() In"));
   1315 
   1316     OSCL_UNUSED_ARG(aCmd);
   1317     PVMFStatus status = PVMFSuccess;
   1318     // Process Pause according to the Node State
   1319     switch (iInterfaceState)
   1320     {
   1321         case EPVMFNodeStarted:
   1322             status = PVMFSuccess;
   1323             break;
   1324         default:
   1325             status = PVMFErrInvalidState;
   1326     }
   1327     return status;
   1328 }
   1329 
   1330 /**
   1331  * CommandHandler for Cancelling All Commands
   1332  */
   1333 PVMFStatus PVMFMP3FFParserNode::DoCancelAllCommands(PVMFMP3FFParserNodeCommand& aCmd)
   1334 {
   1335     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1336                     (0, "PVMFMP3FFParserNode::DoCancelAllCommands() In"));
   1337 
   1338     OSCL_UNUSED_ARG(aCmd);
   1339     // First cancel the current command if any
   1340     while (!iCurrentCommand.empty())
   1341     {
   1342         if (iCPMContainer.CancelPendingCommand())
   1343         {
   1344             return PVMFPending;//wait on sub-node cancel to complete.
   1345         }
   1346         CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFErrCancelled, NULL, NULL);
   1347     }
   1348 
   1349     // Next cancel all InputCommands, start at element 1 since
   1350     // this cancel command is element 0.
   1351     while (iInputCommands.size() > 1)
   1352     {
   1353         CommandComplete(iInputCommands, iInputCommands[1], PVMFErrCancelled, NULL, NULL);
   1354     }
   1355     return PVMFSuccess;
   1356 }
   1357 
   1358 /**
   1359  * CommandHandler for Cancelling a single command
   1360  */
   1361 PVMFStatus PVMFMP3FFParserNode::DoCancelCommand(PVMFMP3FFParserNodeCommand& aCmd)
   1362 {
   1363     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1364                     (0, "PVMFMP3FFParserNode::DoCancelCommand() In"));
   1365 
   1366     // Extract the command ID to be cancelled
   1367     PVMFCommandId id;
   1368     aCmd.PVMFMP3FFParserNodeCommandBase::Parse(id);
   1369 
   1370     //first check "current" command if any
   1371     PVMFMP3FFParserNodeCommand* cmd = iCurrentCommand.FindById(id);
   1372     if (cmd)
   1373     {
   1374         if (iCPMContainer.CancelPendingCommand())
   1375         {
   1376             return PVMFPending;//wait on sub-node cancel to complete.
   1377         }
   1378         CommandComplete(iCurrentCommand, *cmd, PVMFErrCancelled, NULL, NULL);
   1379         return PVMFSuccess;
   1380     }
   1381 
   1382     // Next cancel all InputCommands, start at element 1 since
   1383     // this cancel command is element 0.
   1384     cmd = iInputCommands.FindById(id, 1);
   1385     if (cmd)
   1386     {
   1387         //cancel the queued command
   1388         CommandComplete(iInputCommands, *cmd, PVMFErrCancelled, NULL, NULL);
   1389         //report cancel success
   1390         return PVMFSuccess;
   1391     }
   1392     //if we get here the command isn't queued so the cancel fails.
   1393     return PVMFFailure;
   1394 }
   1395 
   1396 /**
   1397  * CommandHandler for fetching Metadata Keys
   1398  */
   1399 PVMFStatus PVMFMP3FFParserNode::DoGetMetadataKeys(PVMFMP3FFParserNodeCommand& aCmd)
   1400 {
   1401     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1402                     (0, "PVMFMP3FFParserNode::DoGetMetadataKeys() In"));
   1403 
   1404     /* Get Metadata keys from CPM for protected content only */
   1405     if (iCPMContainer.iCPMMetaDataExtensionInterface != NULL)
   1406     {
   1407         GetCPMMetaDataKeys();
   1408         return PVMFPending;
   1409     }
   1410     return (CompleteGetMetadataKeys(aCmd));
   1411 }
   1412 
   1413 PVMFStatus
   1414 PVMFMP3FFParserNode::CompleteGetMetadataKeys(PVMFMP3FFParserNodeCommand& aCmd)
   1415 {
   1416     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1417                     (0, "PVMFMP3FFParserNode::CompleteGetMetadataKeys() In"));
   1418 
   1419     PVMFMetadataList* keylistptr = NULL;
   1420     uint32 starting_index;
   1421     int32 max_entries;
   1422     char* query_key;
   1423 
   1424     aCmd.PVMFMP3FFParserNodeCommand::Parse(keylistptr, starting_index, max_entries, query_key);
   1425     // Check parameters
   1426     if (keylistptr == NULL || !iMP3File)
   1427     {
   1428         // The list pointer is invalid
   1429         return PVMFErrArgument;
   1430     }
   1431     // The underlying mp3 ff library will fill in the keys.
   1432     iMP3File->GetMetadataKeys(*keylistptr, starting_index, max_entries, query_key);
   1433 
   1434     /* Copy the requested keys */
   1435     uint32 num_entries = 0;
   1436     int32 num_added = 0;
   1437     uint32 lcv = 0;
   1438     for (lcv = 0; lcv < iCPMMetadataKeys.size(); lcv++)
   1439     {
   1440         if (query_key == NULL)
   1441         {
   1442             /* No query key so this key is counted */
   1443             ++num_entries;
   1444             if (num_entries > (uint32)starting_index)
   1445             {
   1446                 /* Past the starting index so copy the key */
   1447                 PVMFStatus status = PushBackCPMMetadataKeys(keylistptr, lcv);
   1448                 if (PVMFErrNoMemory == status)
   1449                 {
   1450                     return status;
   1451                 }
   1452                 num_added++;
   1453             }
   1454         }
   1455         else
   1456         {
   1457             /* Check if the key matches the query key */
   1458             if (pv_mime_strcmp(iCPMMetadataKeys[lcv].get_cstr(), query_key) >= 0)
   1459             {
   1460                 /* This key is counted */
   1461                 ++num_entries;
   1462                 if (num_entries > (uint32)starting_index)
   1463                 {
   1464                     /* Past the starting index so copy the key */
   1465                     PVMFStatus status = PushBackCPMMetadataKeys(keylistptr, lcv);
   1466                     if (PVMFErrNoMemory == status)
   1467                     {
   1468                         return status;
   1469                     }
   1470                     num_added++;
   1471                 }
   1472             }
   1473         }
   1474         /* Check if max number of entries have been copied */
   1475         if ((max_entries > 0) && (num_added >= max_entries))
   1476         {
   1477             break;
   1478         }
   1479     }
   1480     return PVMFSuccess;
   1481 }
   1482 
   1483 
   1484 
   1485 
   1486 /**
   1487  * CommandHandler for fetching Metadata Values
   1488  */
   1489 PVMFStatus PVMFMP3FFParserNode::DoGetMetadataValues(PVMFMP3FFParserNodeCommand& aCmd)
   1490 {
   1491     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1492                     (0, "PVMFMP3FFParserNode::DoGetMetadataValues() In"));
   1493 
   1494     PVMFMetadataList* keylistptr_in = NULL;
   1495     PVMFMetadataList* keylistptr = NULL;
   1496     PVMFMetadataList completeKeyList;
   1497     Oscl_Vector<PvmiKvp, OsclMemAllocator>* valuelistptr = NULL;
   1498     uint32 starting_index;
   1499     int32 max_entries;
   1500 
   1501     // Extract parameters from command structure
   1502     aCmd.PVMFMP3FFParserNodeCommand::Parse(keylistptr_in,
   1503                                            valuelistptr,
   1504                                            starting_index,
   1505                                            max_entries);
   1506 
   1507     if (iMP3File == NULL || keylistptr_in == NULL || valuelistptr == NULL)
   1508     {
   1509         // The list pointer is invalid, or we cannot access the mp3 ff library.
   1510         return PVMFFailure;
   1511     }
   1512 
   1513     keylistptr = keylistptr_in;
   1514     if (keylistptr_in->size() == 1)
   1515     {
   1516         if (oscl_strncmp((*keylistptr_in)[0].get_cstr(),
   1517                          PVMF_MP3_PARSER_NODE_ALL_METADATA_KEY,
   1518                          oscl_strlen(PVMF_MP3_PARSER_NODE_ALL_METADATA_KEY)) == 0)
   1519         {
   1520             //check if the user passed in "all" metadata key, in which case get the complete
   1521             //key list from MP3 FF lib first
   1522             int32 max = 0x7FFFFFFF;
   1523             char* query = NULL;
   1524             iMP3File->GetMetadataKeys(completeKeyList, 0, max, query);
   1525             keylistptr = &completeKeyList;
   1526         }
   1527     }
   1528 
   1529     // The underlying mp3 ff library will fill in the values.
   1530     PVMFStatus status = iMP3File->GetMetadataValues(*keylistptr, *valuelistptr, starting_index, max_entries);
   1531 
   1532     iMP3ParserNodeMetadataValueCount = (*valuelistptr).size();
   1533 
   1534     if (iCPMContainer.iCPMMetaDataExtensionInterface != NULL)
   1535     {
   1536         iCPMGetMetaDataValuesCmdId =
   1537             (iCPMContainer.iCPMMetaDataExtensionInterface)->GetNodeMetadataValues(iCPMContainer.iSessionId,
   1538                     (*keylistptr_in),
   1539                     (*valuelistptr),
   1540                     0);
   1541         return PVMFPending;
   1542     }
   1543     return status;
   1544 }
   1545 
   1546 
   1547 /**
   1548  * Event reporting routines
   1549  */
   1550 void PVMFMP3FFParserNode::SetState(TPVMFNodeInterfaceState s)
   1551 {
   1552     LOGINFO((0, "PVMFMP3FFParserNode::SetState() %d", s));
   1553     PVMFNodeInterface::SetState(s);
   1554 }
   1555 
   1556 void PVMFMP3FFParserNode::ReportErrorEvent(PVMFEventType aEventType, OsclAny* aEventData)
   1557 {
   1558     LOGINFO((0, "PVMFMP3FFParserNode::ReportErrorEvent() Type %d Data %d"
   1559              , aEventType, aEventData));
   1560     PVMFNodeInterface::ReportErrorEvent(aEventType, aEventData);
   1561 }
   1562 
   1563 void PVMFMP3FFParserNode::ReportInfoEvent(PVMFEventType aEventType, OsclAny* aEventData, PVInterface*aExtMsg)
   1564 {
   1565     LOGINFO((0, "PVMFMP3FFParserNode::ReportInfoEvent() Type %d Data %d"
   1566              , aEventType, aEventData));
   1567     PVMFNodeInterface::ReportInfoEvent(aEventType, aEventData, aExtMsg);
   1568 }
   1569 ////////////////////////////////////////////////////////////////////////
   1570 /**
   1571  * Port Processing routines
   1572  */
   1573 ////////////////////////////////////////////////////////////////////////
   1574 
   1575 /**
   1576  * Port Activity Handler
   1577  */
   1578 void PVMFMP3FFParserNode::HandlePortActivity(const PVMFPortActivity &aActivity)
   1579 {
   1580     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1581                     (0, "PVMFMP3FFParserNode::PortActivity: port=0x%x, type=%d",
   1582                      aActivity.iPort, aActivity.iType));
   1583 
   1584     // A port has reported some activity or state change.
   1585     // Find out whether processing event needs to be queued
   1586     // and/or node event needs to be reported to the observer.
   1587     switch (aActivity.iType)
   1588     {
   1589         case PVMF_PORT_ACTIVITY_CREATED:
   1590             //Report port created info event to the node.
   1591             PVMFNodeInterface::ReportInfoEvent(PVMFInfoPortCreated,
   1592                                                (OsclAny*)aActivity.iPort);
   1593             break;
   1594         case PVMF_PORT_ACTIVITY_DELETED:
   1595             //Report port deleted info event to the node.
   1596             PVMFNodeInterface::ReportInfoEvent(PVMFInfoPortDeleted,
   1597                                                (OsclAny*)aActivity.iPort);
   1598             break;
   1599         case PVMF_PORT_ACTIVITY_CONNECT:
   1600         case PVMF_PORT_ACTIVITY_DISCONNECT:
   1601         case PVMF_PORT_ACTIVITY_INCOMING_MSG:
   1602             //nothing needed.
   1603             break;
   1604         case PVMF_PORT_ACTIVITY_OUTGOING_MSG:
   1605             //An outgoing message was queued on this port.
   1606             if (!aActivity.iPort->IsConnectedPortBusy())
   1607                 RunIfNotReady();
   1608             break;
   1609         case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_BUSY:
   1610             //No action is needed here, the node checks for
   1611             //outgoing queue busy as needed during data processing.
   1612             break;
   1613         case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_READY:
   1614             //Outgoing queue was previously busy, but is now ready.
   1615             HandleOutgoingQueueReady(aActivity.iPort);
   1616             break;
   1617         case PVMF_PORT_ACTIVITY_CONNECTED_PORT_BUSY:
   1618             // The connected port is busy
   1619             // No action is needed here, the port processing code
   1620             // checks for connected port busy during data processing.
   1621             break;
   1622         case PVMF_PORT_ACTIVITY_CONNECTED_PORT_READY:
   1623             // The connected port has transitioned from Busy to Ready.
   1624             // It's time to start processing outgoing messages again.
   1625             if (aActivity.iPort->OutgoingMsgQueueSize() > 0)
   1626             {
   1627                 RunIfNotReady();
   1628             }
   1629             break;
   1630         default:
   1631             break;
   1632     }
   1633 }
   1634 
   1635 /**
   1636  * Outgoing message handler
   1637  */
   1638 PVMFStatus PVMFMP3FFParserNode::ProcessOutgoingMsg(PVMFPortInterface* aPort)
   1639 {
   1640     // Called by the AO to process one message off the outgoing
   1641     // message queue for the given port.  This routine will
   1642     // try to send the data to the connected port.
   1643 
   1644     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1645                     (0, "PVMFMP3FFParserNode::ProcessOutgoingMsg: aPort=0x%x",
   1646                      aPort));
   1647 
   1648     PVMFStatus status = aPort->Send();
   1649     if (status == PVMFErrBusy)
   1650     {
   1651         // Port was busy
   1652         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
   1653                         (0, "PVMFMP3FFParserNode::ProcessOutgoingMsg: \
   1654                         Connected port goes into busy state"));
   1655     }
   1656     return status;
   1657 }
   1658 
   1659 ////////////////////////////////////////////////////////////////////////
   1660 /**
   1661  * Active object implementation
   1662  */
   1663 ////////////////////////////////////////////////////////////////////////
   1664 
   1665 /**
   1666  * AO's entry point
   1667  */
   1668 void PVMFMP3FFParserNode::Run()
   1669 {
   1670     if (iCheckForMP3HeaderDuringInit)
   1671     {
   1672         // Read capacity notification was delivered
   1673         iCheckForMP3HeaderDuringInit = false;
   1674         PVMFStatus cmdStatus = CheckForMP3HeaderAvailability();
   1675         if (PVMFSuccess == cmdStatus)
   1676         {
   1677             LOGINFO((0, "PVMFMP3FFParserNode::Run() CheckForMP3HeaderAvailability() succeeded"));
   1678             // complete init command
   1679             CompleteInit(cmdStatus);
   1680         }
   1681         else if (PVMFErrUnderflow == cmdStatus)
   1682         {
   1683             if (iMP3File)
   1684             {
   1685                 bool nextBytes = true;
   1686                 uint32 currCapacity = 0;
   1687                 uint32 minBytesRequired = iMP3File->GetMinBytesRequired(nextBytes);
   1688                 // CheckForMP3HeaderAvailability has failed because of underflow.
   1689                 // parser needs more bytes to do parsing and verification of the clip.
   1690                 PvmiDataStreamStatus status = iDataStreamInterface->QueryReadCapacity(iDataStreamSessionID,
   1691                                               currCapacity);
   1692 
   1693                 if (PVDS_SUCCESS == status && currCapacity < minBytesRequired + iMP3MetaDataSize)
   1694                 {
   1695                     // Request for read capacity notification was issued
   1696                     iRequestReadCapacityNotificationID =
   1697                         iDataStreamInterface->RequestReadCapacityNotification(iDataStreamSessionID,
   1698                                 *this,
   1699                                 iMP3MetaDataSize + minBytesRequired);
   1700                 }
   1701             }
   1702             LOGINFO((0, "PVMFMP3FFParserNode::Run() CheckForMP3HeaderAvailability() failed %d", cmdStatus));
   1703         }
   1704         return;
   1705     }
   1706 
   1707     // Check InputCommandQueue, If command present
   1708     // process commands
   1709     if (!iInputCommands.empty())
   1710     {
   1711         ProcessCommand();
   1712     }
   1713     //Issue commands to the sub-nodes.
   1714     if (!iCPMContainer.CmdPending() && !iSubNodeCmdVec.empty())
   1715     {
   1716         PVMFStatus status = iSubNodeCmdVec.front().iSubNodeContainer->IssueCommand(iSubNodeCmdVec.front().iCmd);
   1717         if (status != PVMFPending)
   1718         {
   1719             iSubNodeCmdVec.front().iSubNodeContainer->CommandDone(status, NULL, NULL);
   1720         }
   1721     }
   1722 
   1723     if ((iPortVector.empty()))
   1724         return;
   1725 
   1726     PVMFPortInterface*port = iPortVector.front();
   1727     // Send outgoing messages
   1728     if ((iInterfaceState == EPVMFNodeStarted || FlushPending()) &&
   1729             port &&
   1730             port->OutgoingMsgQueueSize() > 0 &&
   1731             !port->IsConnectedPortBusy())
   1732     {
   1733         ProcessOutgoingMsg(port);
   1734         // Re-schedule if there is additional data to send.
   1735         if (port->OutgoingMsgQueueSize() > 0 && !port->IsConnectedPortBusy())
   1736         {
   1737             RunIfNotReady();
   1738         }
   1739     }
   1740 
   1741     // Create new data and send to the output queue
   1742     if (iInterfaceState == EPVMFNodeStarted && !FlushPending())
   1743     {
   1744         if (HandleTrackState())  // Handle track state returns true if there is more data to be sent
   1745         {
   1746             // Re-schedule if there is more data to send out
   1747             RunIfNotReady();
   1748         }
   1749     }
   1750 
   1751     // If we get here we did not process any ports or commands.
   1752     // Check for completion of a flush command
   1753     if (FlushPending() &&
   1754             (!port || port->OutgoingMsgQueueSize() == 0))
   1755     {
   1756         //resume port input so the ports can be re-started.
   1757         port->ResumeInput();
   1758         CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess, NULL, NULL);
   1759     }
   1760 }
   1761 
   1762 void PVMFMP3FFParserNode::PassDatastreamFactory(PVMFDataStreamFactory& aFactory,
   1763         int32 aFactoryTag,
   1764         const PvmfMimeString* aFactoryConfig)
   1765 {
   1766     OSCL_UNUSED_ARG(aFactoryTag);
   1767     OSCL_UNUSED_ARG(aFactoryConfig);
   1768 
   1769     if (iDataStreamFactory == NULL)
   1770     {
   1771         PVUuid uuid = PVMIDataStreamSyncInterfaceUuid;
   1772         PVInterface* iFace = NULL;
   1773         iDataStreamFactory = &aFactory;
   1774 
   1775 #if PV_HAS_SHOUTCAST_SUPPORT_ENABLED
   1776         if (iSourceFormat == PVMF_MIME_DATA_SOURCE_SHOUTCAST_URL)
   1777         {
   1778             iSCSPFactory = OSCL_NEW(PVMFShoutcastStreamParserFactory, (&aFactory, iMetadataInterval));
   1779 
   1780             iFace = iSCSPFactory->CreatePVMFCPMPluginAccessInterface(uuid);
   1781             if (iFace != NULL)
   1782             {
   1783                 iSCSP = OSCL_STATIC_CAST(PVMFShoutcastStreamParser*, iFace);
   1784                 if (iMetadataBuf == NULL)
   1785                 {
   1786                     iMetadataBuf = (uint8*)oscl_malloc(PV_SCSP_MAX_METADATA_TAG_SIZE * sizeof(uint8));
   1787                     if (iMetadataBuf != NULL)
   1788                     {
   1789                         iMetadataBufSize = PV_SCSP_MAX_METADATA_TAG_SIZE;
   1790                     }
   1791                 }
   1792             }
   1793         }
   1794         else
   1795         {
   1796             iFace = iDataStreamFactory->CreatePVMFCPMPluginAccessInterface(uuid);
   1797         }
   1798 #else
   1799         iFace = iDataStreamFactory->CreatePVMFCPMPluginAccessInterface(uuid);
   1800 #endif
   1801 
   1802         if (iFace != NULL)
   1803         {
   1804             iDataStreamInterface = OSCL_STATIC_CAST(PVMIDataStreamSyncInterface*, iFace);
   1805             iDataStreamInterface->OpenSession(iDataStreamSessionID, PVDS_READ_ONLY);
   1806         }
   1807     }
   1808     else
   1809     {
   1810         OSCL_ASSERT(false);
   1811     }
   1812 }
   1813 
   1814 void
   1815 PVMFMP3FFParserNode::PassDatastreamReadCapacityObserver(PVMFDataStreamReadCapacityObserver* aObserver)
   1816 {
   1817     iDataStreamReadCapacityObserver = aObserver;
   1818 }
   1819 
   1820 int32 PVMFMP3FFParserNode::convertSizeToTime(uint32 aFileSize, uint32& aNPTInMS)
   1821 {
   1822     {
   1823         return -1;
   1824     }
   1825     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1826                     (0, "PVMFMP3FFParserNode::ConvertSizeToTime() aFileSize=%d, aNPTInMS=%d", aFileSize, aNPTInMS));
   1827 
   1828     return iMP3File->ConvertSizeToTime(aFileSize, aNPTInMS);
   1829 }
   1830 bool PVMFMP3FFParserNode::setProtocolInfo(Oscl_Vector<PvmiKvp*, OsclMemAllocator>& aInfoKvpVec)
   1831 {
   1832 #if PV_HAS_SHOUTCAST_SUPPORT_ENABLED
   1833 
   1834     if (aInfoKvpVec.empty())
   1835     {
   1836         return false;
   1837     }
   1838     for (uint32 i = 0; i < aInfoKvpVec.size(); i++)
   1839     {
   1840         if (!aInfoKvpVec[i])
   1841         {
   1842             return false;
   1843         }
   1844 
   1845         if (oscl_strstr(aInfoKvpVec[i]->key, SHOUTCAST_MEDIA_DATA_LENGTH_STRING))
   1846         {
   1847             iMetadataInterval = aInfoKvpVec[i]->value.uint32_value;
   1848         }
   1849         else if (oscl_strstr(aInfoKvpVec[i]->key, SHOUTCAST_CLIP_BITRATE_STRING))
   1850         {
   1851             iClipByteRate = aInfoKvpVec[i]->value.uint32_value;
   1852         }
   1853         else if (oscl_strstr(aInfoKvpVec[i]->key, SHOUTCAST_IS_SHOUTCAST_SESSION_STRING))
   1854         {
   1855         }
   1856     }
   1857 #else
   1858     OSCL_UNUSED_ARG(aInfoKvpVec);
   1859 #endif
   1860 
   1861     return true;
   1862 }
   1863 
   1864 void PVMFMP3FFParserNode::setFileSize(const uint32 aFileSize)
   1865 {
   1866     iFileSize = aFileSize;
   1867     iFileSizeRecvd = true;
   1868 }
   1869 
   1870 void PVMFMP3FFParserNode::setDownloadProgressInterface(PVMFDownloadProgressInterface* download_progress)
   1871 {
   1872     if (iDownloadProgressInterface)
   1873     {
   1874         iDownloadProgressInterface->removeRef();
   1875     }
   1876     iDownloadProgressInterface = download_progress;
   1877     // get the download clock
   1878     iDownloadProgressClock = iDownloadProgressInterface->getDownloadProgressClock();
   1879 }
   1880 
   1881 void PVMFMP3FFParserNode::playResumeNotification(bool aDownloadComplete)
   1882 
   1883 {
   1884     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   1885                     (0, "PVMFMP3FFParserNode::playResumeNotification() In"));
   1886 
   1887     // DownloadProgressInterface signalled for resuming the playback
   1888     iDownloadComplete = aDownloadComplete;
   1889     if (aDownloadComplete)
   1890     {
   1891         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFMP3FFParserNode::playResumeNotification Unbinding download clock"));
   1892         iDownloadProgressClock.Unbind();
   1893     }
   1894 
   1895     // Resume playback
   1896     if (iAutoPaused)
   1897     {
   1898         iAutoPaused = false;
   1899         switch (iTrack.iState)
   1900         {
   1901             case PVMP3FFNodeTrackPortInfo::TRACKSTATE_DOWNLOAD_AUTOPAUSE:
   1902                 iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_GETDATA;
   1903                 break;
   1904             default:
   1905                 break;
   1906         }
   1907         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFMP3FFParserNode::playResumeNotification() Sending PVMFInfoDataReady event"));
   1908         // Re-schedule AO
   1909         RunIfNotReady();
   1910     }
   1911 }
   1912 
   1913 ////////////////////////////////////////////////////////////////////////
   1914 /**
   1915  * Private section
   1916  */
   1917 ////////////////////////////////////////////////////////////////////////
   1918 
   1919 /**
   1920  * Handle Node's track state
   1921  */
   1922 bool PVMFMP3FFParserNode::HandleTrackState()
   1923 {
   1924     // Flag to be active again or not
   1925     bool ret_status = false;
   1926 
   1927     switch (iTrack.iState)
   1928     {
   1929         case PVMP3FFNodeTrackPortInfo::TRACKSTATE_UNINITIALIZED:
   1930             // Node doesnt need to do any format specific initialization
   1931             // just skip this step and set the state to GetData
   1932             iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_GETDATA;
   1933             // Continue on to retrieve and send the first frame
   1934         case PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_GETDATA:
   1935             // Check if node needs to send BOS
   1936             if (iTrack.iSendBOS)
   1937             {
   1938                 // Send BOS downstream on all available tracks
   1939                 if (!SendBeginOfMediaStreamCommand(iTrack))
   1940                 {
   1941                     return true;
   1942                 }
   1943             }
   1944             // First, grab some data from the core mp3 ff parser library
   1945             if (!RetrieveTrackData(iTrack))
   1946             {
   1947                 // If it returns false, break out of the switch and return false,
   1948                 // this means node doesn't need to be run again in the current state.
   1949                 if (iTrack.iState == PVMP3FFNodeTrackPortInfo::TRACKSTATE_SEND_ENDOFTRACK)
   1950                 {
   1951                     RunIfNotReady();
   1952                 }
   1953                 break;
   1954             }
   1955             iSendDecodeFormatSpecificInfo = true;
   1956             iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_SENDDATA;
   1957             // Continue to send data
   1958         case PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_SENDDATA:
   1959             if (SendTrackData(iTrack))
   1960             {
   1961                 iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_GETDATA;
   1962                 ret_status = true;
   1963             }
   1964             break;
   1965         case PVMP3FFNodeTrackPortInfo::TRACKSTATE_SEND_ENDOFTRACK:
   1966             // Check if node needs to send BOS
   1967             if (iTrack.iSendBOS)
   1968             {
   1969                 // Send BOS downstream on all available tracks
   1970                 if (!SendBeginOfMediaStreamCommand(iTrack))
   1971                 {
   1972                     return true;
   1973                 }
   1974             }
   1975             if (SendEndOfTrackCommand(iTrack))
   1976             {
   1977                 // EOS command sent successfully
   1978                 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_NOTICE, (0, "PVMFMP3FFParserNode::HandleTrackState() EOS media command sent successfully"));
   1979                 iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_ENDOFTRACK;
   1980                 ReportInfoEvent(PVMFInfoEndOfData);
   1981             }
   1982             else
   1983             {
   1984                 // EOS command sending failed -- wait on outgoing queue ready notice
   1985                 // before trying again.
   1986                 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_NOTICE, (0, "PVMFMP3FFParserNode::HandleTrackState() EOS media command sending failed"));
   1987                 return true;
   1988             }
   1989             break;
   1990         case PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRACKDATAPOOLEMPTY:
   1991         case PVMP3FFNodeTrackPortInfo::TRACKSTATE_MEDIADATAPOOLEMPTY:
   1992         case PVMP3FFNodeTrackPortInfo::TRACKSTATE_INITIALIZED:
   1993         case PVMP3FFNodeTrackPortInfo::TRACKSTATE_ENDOFTRACK:
   1994         case PVMP3FFNodeTrackPortInfo::TRACKSTATE_DESTFULL:
   1995         case PVMP3FFNodeTrackPortInfo::TRACKSTATE_SOURCEEMPTY:
   1996         case PVMP3FFNodeTrackPortInfo::TRACKSTATE_ERROR:
   1997         default:
   1998             break;
   1999     }
   2000     return ret_status;
   2001 }
   2002 
   2003 /**
   2004  * Retrieve Data from Mp3FF
   2005  */
   2006 bool PVMFMP3FFParserNode::RetrieveTrackData(PVMP3FFNodeTrackPortInfo& aTrackPortInfo)
   2007 {
   2008     // Parsing is successful, we must have estimated the duration by now.
   2009     // Pass the duration to download progress interface
   2010     if (iDownloadProgressInterface && iFileSizeRecvd && iFileSize > 0)
   2011     {
   2012         iMP3File->SetFileSize(iFileSize);
   2013         uint32 durationInMsec = iMP3File->GetDuration();
   2014         if (durationInMsec > 0)
   2015         {
   2016             iDownloadProgressInterface->setClipDuration(durationInMsec);
   2017             int32 leavecode = 0;
   2018             PVMFDurationInfoMessage* eventMsg = NULL;
   2019             OSCL_TRY(leavecode, eventMsg = OSCL_NEW(PVMFDurationInfoMessage, (durationInMsec)));
   2020             ReportInfoEvent(PVMFInfoDurationAvailable, NULL, OSCL_STATIC_CAST(PVInterface*, eventMsg));
   2021             if (eventMsg)
   2022             {
   2023                 eventMsg->removeRef();
   2024             }
   2025             iFileSize = 0;
   2026         }
   2027     }
   2028 
   2029     if (iAutoPaused == true)
   2030     {
   2031         aTrackPortInfo.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_DOWNLOAD_AUTOPAUSE;
   2032         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   2033                         (0, "PVMFMP3FFParserNode::RetrieveTrackData() Node in Auto pause"));
   2034         return false;
   2035     }
   2036 
   2037     //Maximum number of mp3 frames to be read at a time
   2038     uint32 numsamples = PVMF3FF_DEFAULT_NUM_OF_FRAMES;
   2039     // Create new media data buffer from pool
   2040     int errcode = 0;
   2041     OsclSharedPtr<PVMFMediaDataImpl> mediaDataImplOut;
   2042 
   2043     // Try block start
   2044     OSCL_TRY(errcode,
   2045              mediaDataImplOut = aTrackPortInfo.iMediaDataImplAlloc->allocate(numsamples * iMaxFrameSize)
   2046             );
   2047     // Try block end
   2048 
   2049     if (errcode != 0)
   2050     {
   2051         // There was an error while allocating MediaDataImpl
   2052         if (errcode == OsclErrNoResources)
   2053         {
   2054             aTrackPortInfo.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRACKDATAPOOLEMPTY;
   2055             aTrackPortInfo.iTrackDataMemoryPool->notifyfreeblockavailable(*this, numsamples*iMaxFrameSize); // Enable flag to receive event when next deallocate() is called on pool
   2056         }
   2057         else if (errcode == OsclErrNoMemory)
   2058         {
   2059             // Memory allocation for the pool failed
   2060             aTrackPortInfo.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_ERROR;
   2061             ReportErrorEvent(PVMFErrNoMemory, NULL);
   2062         }
   2063         else if (errcode == OsclErrArgument)
   2064         {
   2065             // Invalid parameters passed to mempool
   2066             aTrackPortInfo.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_ERROR;
   2067             ReportErrorEvent(PVMFErrArgument, NULL);
   2068         }
   2069         else
   2070         {
   2071             // General error
   2072             aTrackPortInfo.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_ERROR;
   2073             ReportErrorEvent(PVMFFailure, NULL);
   2074         }
   2075         // All above conditions were Error conditions
   2076         return false;
   2077     }
   2078 
   2079     if (mediaDataImplOut.GetRep() == NULL)
   2080     {
   2081         PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMFMP3FFParserNode::RetrieveTrackData() No Resource Found"));
   2082         aTrackPortInfo.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRACKDATAPOOLEMPTY;
   2083         aTrackPortInfo.iTrackDataMemoryPool->notifyfreeblockavailable(*this);
   2084         return false;
   2085     }
   2086 
   2087     // Reset error code for further processing
   2088     errcode = OsclErrNoResources;
   2089     PVMFSharedMediaDataPtr mediadataout;
   2090     mediadataout =
   2091         PVMFMediaData::createMediaData(mediaDataImplOut, aTrackPortInfo.iMediaDataMemPool);
   2092 
   2093     if (mediadataout.GetRep() == NULL)
   2094     {
   2095         aTrackPortInfo.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_MEDIADATAPOOLEMPTY;
   2096         aTrackPortInfo.iMediaDataMemPool->notifyfreechunkavailable(*this);
   2097         return false;
   2098     }
   2099 
   2100     // Retrieve memory fragment to write to
   2101     OsclRefCounterMemFrag refCtrMemFragOut;
   2102     OsclMemoryFragment memFragOut;
   2103     mediadataout->getMediaFragment(0, refCtrMemFragOut);
   2104     memFragOut.ptr = refCtrMemFragOut.getMemFrag().ptr;
   2105 
   2106     // Set up the GAU structure
   2107     GAU gau;
   2108     gau.numMediaSamples = numsamples;
   2109     gau.buf.num_fragments = 1;
   2110     gau.buf.buf_states[0] = NULL;
   2111     gau.buf.fragments[0].ptr = refCtrMemFragOut.getMemFrag().ptr;
   2112     gau.buf.fragments[0].len = refCtrMemFragOut.getCapacity();
   2113 
   2114     // Mp3FF ErrorCode
   2115     MP3ErrorType error = MP3_SUCCESS;
   2116     // Grab data from the mp3 ff parser library
   2117     int32 retval = iMP3File->GetNextBundledAccessUnits(&numsamples, &gau, error);
   2118 
   2119     // Determine actual size of the retrieved data by summing each sample length in GAU
   2120     uint32 actualdatasize = 0;
   2121     for (uint32 index = 0; index < numsamples; ++index)
   2122     {
   2123         actualdatasize += gau.info[index].len;
   2124     }
   2125 
   2126     if (retval > 0)
   2127     {
   2128         // Set buffer size
   2129         mediadataout->setMediaFragFilledLen(0, actualdatasize);
   2130         mediaDataImplOut->setCapacity(actualdatasize);
   2131         // Return the unused space from mempool back
   2132         if (refCtrMemFragOut.getCapacity() > actualdatasize)
   2133         {
   2134             // Need to go to the resizable memory pool and free some memory
   2135             aTrackPortInfo.iMediaDataImplAlloc->ResizeMemoryFragment(mediaDataImplOut);
   2136         }
   2137 
   2138         // Set format specific info for the first frame
   2139         if (iSendDecodeFormatSpecificInfo)
   2140         {
   2141             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
   2142                             (0, "PVMFMP3FFParserNode::RetrieveTrackData() Send channel sample info"));
   2143             iSendDecodeFormatSpecificInfo = false;
   2144             mediadataout->setFormatSpecificInfo(iDecodeFormatSpecificInfo);
   2145         }
   2146 
   2147         // Set M bit to 1 always - MP3 FF only outputs complete frames
   2148         uint32 markerInfo = 0;
   2149         markerInfo |= PVMF_MEDIA_DATA_MARKER_INFO_M_BIT;
   2150 
   2151         // Set Key Frame bit
   2152         if (aTrackPortInfo.iFirstFrame)
   2153         {
   2154             markerInfo |= PVMF_MEDIA_DATA_MARKER_INFO_RANDOM_ACCESS_POINT_BIT;
   2155             aTrackPortInfo.iFirstFrame = false;
   2156         }
   2157         mediaDataImplOut->setMarkerInfo(markerInfo);
   2158 
   2159 
   2160         // Save the media data in the trackport info
   2161         aTrackPortInfo.iMediaData = mediadataout;
   2162 
   2163         // Retrieve timestamp and convert to milliseconds
   2164         aTrackPortInfo.iClockConverter->update_clock(gau.info[0].ts);
   2165         uint32 timestamp = aTrackPortInfo.iClockConverter->get_converted_ts(COMMON_PLAYBACK_CLOCK_TIMESCALE);
   2166         timestamp += aTrackPortInfo.timestamp_offset;
   2167 
   2168         // Set the media data timestamp
   2169         aTrackPortInfo.iMediaData->setTimestamp(timestamp);
   2170 
   2171         // Set msg sequence number and stream id
   2172         aTrackPortInfo.iMediaData->setSeqNum(aTrackPortInfo.iSeqNum++);
   2173         aTrackPortInfo.iMediaData->setStreamID(iStreamID);
   2174         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
   2175                         (0, "PVMFMP3FFParserNode::RetrieveTrackData Seq=%d, TS=%d", aTrackPortInfo.iSeqNum, timestamp));
   2176         if (error == MP3_INSUFFICIENT_DATA && !iDownloadProgressInterface)
   2177         {
   2178             //parser reported underflow during local playback session
   2179             if (!SendTrackData(iTrack))
   2180             {
   2181                 // SendTrackData un-successful
   2182                 iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_SENDDATA;
   2183                 return false;
   2184             }
   2185         }
   2186     }
   2187     // EOS may occur even if some data was read
   2188     // Also handles the condition if somehow error was not set even
   2189     // if there is no data to read.
   2190     if ((retval <= 0) || (MP3_SUCCESS != error))
   2191     {
   2192         // ffparser was not able to read data
   2193         if (error == MP3_INSUFFICIENT_DATA) // mp3ff return insufficient data
   2194         {
   2195             // Check if DPI is present
   2196             if (iDownloadProgressInterface != NULL)
   2197             {
   2198                 if (retval > 0)
   2199                 {
   2200                     //parser reported underflow during download playback session
   2201                     if (!SendTrackData(iTrack))
   2202                     {
   2203                         // SendTrackData un-successful
   2204                         iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_SENDDATA;
   2205                         return true;
   2206                     }
   2207                 }
   2208 
   2209                 if (iDownloadComplete)
   2210                 {
   2211                     aTrackPortInfo.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_SEND_ENDOFTRACK;
   2212                     return false;
   2213                 }
   2214                 // ffparser ran out of data, need to request a call back from DPI
   2215                 // when data beyond current timestamp is downloaded
   2216                 uint32 timeStamp = iMP3File->GetTimestampForCurrentSample();
   2217                 iDownloadProgressInterface->requestResumeNotification(timeStamp, iDownloadComplete);
   2218                 // Change track state to Autopause and set iAutopause
   2219                 aTrackPortInfo.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_DOWNLOAD_AUTOPAUSE;
   2220                 iAutoPaused = true;
   2221                 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   2222                                 (0, "PVMFMP3FFParserNode::RetrieveTrackData() \
   2223                                 Auto pause Triggered"));
   2224                 return false;
   2225             }
   2226             else
   2227             {
   2228                 // if we recieve Insufficient data for local playback from parser library that means
   2229                 // its end of track, so change track state to send end of track.
   2230                 aTrackPortInfo.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_SEND_ENDOFTRACK;
   2231                 return false;
   2232             }
   2233         }
   2234         else if (error == MP3_END_OF_FILE) // mp3ff return EOF
   2235         {
   2236             aTrackPortInfo.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_SEND_ENDOFTRACK;
   2237             return false;
   2238         }
   2239         else
   2240         {
   2241             PVMFStatus errCode = PVMFErrArgument;
   2242             if (error == MP3_ERROR_UNKNOWN_OBJECT)
   2243             {
   2244                 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE,
   2245                                 (0, "PVMFMP3FFParserNode::RetrieveTrackData() \
   2246                                 Clip format not identified by parser %d", error));
   2247                 errCode = PVMFErrNotSupported;
   2248             }
   2249             else
   2250             {
   2251                 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE,
   2252                                 (0, "PVMFMP3FFParserNode::RetrieveTrackData() \
   2253                                 Unknown error code reported err code  %d", error));
   2254             }
   2255             aTrackPortInfo.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_SEND_ENDOFTRACK;
   2256             ReportErrorEvent(errCode);
   2257             return false;
   2258         }
   2259     }
   2260     return true;
   2261 }
   2262 
   2263 /**
   2264  * Send track data to output port
   2265  */
   2266 bool PVMFMP3FFParserNode::SendTrackData(PVMP3FFNodeTrackPortInfo& aTrackPortInfo)
   2267 {
   2268     // Send frame to downstream node via port
   2269     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
   2270                     (0, "PVMFMP3FFParserNode::SendTrackData: SeqNum %d", \
   2271                      aTrackPortInfo.iMediaData->getSeqNum()));
   2272 
   2273     PVMFSharedMediaMsgPtr mediaMsgOut;
   2274     // Convert media data to media message
   2275     convertToPVMFMediaMsg(mediaMsgOut, aTrackPortInfo.iMediaData);
   2276     // Queue media msg to port's outgoing queue
   2277     PVMFStatus status = aTrackPortInfo.iPort->QueueOutgoingMsg(mediaMsgOut);
   2278     if (status != PVMFSuccess)
   2279     {
   2280         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
   2281                         (0, "PVMFMP3FFParserNode::SendTrackData: Outgoing queue busy"));
   2282         return false;
   2283     }
   2284 
   2285     //keep count of the number of source frames generated on this port
   2286     aTrackPortInfo.iPort->iNumFramesGenerated++;
   2287     // Don't need reference to iMediaData so unbind it
   2288     aTrackPortInfo.iMediaData.Unbind();
   2289     return true;
   2290 }
   2291 
   2292 /**
   2293  * Send BOS command to output port
   2294  */
   2295 bool PVMFMP3FFParserNode::SendBeginOfMediaStreamCommand(PVMP3FFNodeTrackPortInfo& aTrackPortInfoPtr)
   2296 {
   2297     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   2298                     (0, "PVMFMP3FFParserNode::SendBeginOfMediaStreamCommand"));
   2299 
   2300     // Create media command
   2301     PVMFSharedMediaCmdPtr sharedMediaCmdPtr = PVMFMediaCmd::createMediaCmd();
   2302     // Set command id to BOS
   2303     sharedMediaCmdPtr->setFormatID(PVMF_MEDIA_CMD_BOS_FORMAT_ID);
   2304     // Set timestamp of the media command
   2305     sharedMediaCmdPtr->setTimestamp(aTrackPortInfoPtr.timestamp_offset);
   2306     // SeqNum of BOS doesnt play any role, set to 0
   2307     sharedMediaCmdPtr->setSeqNum(0);
   2308     // Convert media command to media message
   2309     PVMFSharedMediaMsgPtr mediaMsgOut;
   2310     convertToPVMFMediaCmdMsg(mediaMsgOut, sharedMediaCmdPtr);
   2311     // Set stream id
   2312     mediaMsgOut->setStreamID(iStreamID);
   2313     // Queue media msg to output pout
   2314     if (aTrackPortInfoPtr.iPort->QueueOutgoingMsg(mediaMsgOut) != PVMFSuccess)
   2315     {
   2316         // Output queue is busy, so wait for the output queue being ready
   2317         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
   2318                         (0, "PVMFMP3FFParserNode::SendBeginOfMediaStreamCommand: \
   2319                         Outgoing queue busy. "));
   2320         return false;
   2321     }
   2322     // BOS was sent successfully, reset the BOS flag
   2323     aTrackPortInfoPtr.iSendBOS = false;
   2324     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
   2325                     (0, "PVMFMP3FFParserNode::SendBeginOfMediaStreamCommand: \
   2326                     BOS Sent StreamID %d", iStreamID));
   2327     return true;
   2328 }
   2329 
   2330 /**
   2331  * Send EOS command to output port
   2332  */
   2333 bool PVMFMP3FFParserNode::SendEndOfTrackCommand(PVMP3FFNodeTrackPortInfo& aTrackPortInfo)
   2334 {
   2335     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   2336                     (0, "PVMFMP3FFParserNode::SendEndOfTrackCommand() In"));
   2337     // Create media command
   2338     PVMFSharedMediaCmdPtr sharedMediaCmdPtr = PVMFMediaCmd::createMediaCmd();
   2339     // Set command id to EOS
   2340     sharedMediaCmdPtr->setFormatID(PVMF_MEDIA_CMD_EOS_FORMAT_ID);
   2341     // Retrieve timestamp and convert to milliseconds
   2342     uint32 timestamp = aTrackPortInfo.iClockConverter->get_converted_ts(COMMON_PLAYBACK_CLOCK_TIMESCALE);
   2343     timestamp += aTrackPortInfo.timestamp_offset;
   2344     // Set the timestamp
   2345     sharedMediaCmdPtr->setTimestamp(timestamp);
   2346     // Set the sequence number
   2347     sharedMediaCmdPtr->setSeqNum(aTrackPortInfo.iSeqNum++);
   2348     //set stream id
   2349     sharedMediaCmdPtr->setStreamID(iStreamID);
   2350     // Convert media command to media message
   2351     PVMFSharedMediaMsgPtr mediaMsgOut;
   2352     convertToPVMFMediaCmdMsg(mediaMsgOut, sharedMediaCmdPtr);
   2353 
   2354     // Queue media msg to output pout
   2355     if (aTrackPortInfo.iPort->QueueOutgoingMsg(mediaMsgOut) != PVMFSuccess)
   2356     {
   2357         // Output queue is busy, so wait for the output queue being ready
   2358         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
   2359                         (0, "PVMFMP3FFParserNode::SendEndOfTrackCommand: Outgoing queue busy. "));
   2360         return false;
   2361     }
   2362     // EOS was sent successfully
   2363     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   2364                     (0, "PVMFMP3FFParserNode::SendEndOfTrackCommand() Out"));
   2365     return true;
   2366 }
   2367 
   2368 
   2369 /**
   2370  * Outgoing port queue handler
   2371  */
   2372 bool PVMFMP3FFParserNode::HandleOutgoingQueueReady(PVMFPortInterface* aPortInterface)
   2373 {
   2374     if (iTrack.iPort == aPortInterface &&
   2375             iTrack.iState == PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_SENDDATA)
   2376     {
   2377         // Found the element and right state
   2378         // re-send the data
   2379         if (!SendTrackData(iTrack))
   2380         {
   2381             // SendTrackData un-successful
   2382             return false;
   2383         }
   2384 
   2385         // Success in re-sending the data, change state to getdata
   2386         iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_GETDATA;
   2387         return true;
   2388     }
   2389     // Either the track was not in correct state or the port was not correct
   2390     return false;
   2391 }
   2392 
   2393 /**
   2394  * Parse the File
   2395  */
   2396 PVMFStatus PVMFMP3FFParserNode::ParseFile()
   2397 {
   2398     if (!iSourceURLSet)
   2399     {
   2400         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   2401                         (0, "PVMFMP3FFParserNode::ParseFile() SourceURL not set"));
   2402         // Can't init the node if the node, File name is not specified yet.
   2403         return PVMFFailure;
   2404     }
   2405 
   2406     MP3ErrorType mp3Err = iMP3File->ParseMp3File();
   2407 
   2408     if (mp3Err == MP3_INSUFFICIENT_DATA)
   2409     {
   2410         return PVMFPending;
   2411     }
   2412     else if (mp3Err == MP3_END_OF_FILE ||
   2413              mp3Err != MP3_SUCCESS)
   2414     {
   2415         SetState(EPVMFNodeError);
   2416         ReportErrorEvent(PVMFErrResource);
   2417         return PVMFErrUnderflow;
   2418     }
   2419 
   2420     // Find out what the largest frame in the file is. This information is used
   2421     // when allocating the buffers in DoRequestPort().
   2422     iMaxFrameSize = iMP3File->GetMaxBufferSizeDB();
   2423     if (iMaxFrameSize <= 0)
   2424     {
   2425         iMaxFrameSize = PVMP3FF_DEFAULT_MAX_FRAMESIZE;
   2426         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
   2427                         (0, "PVMFMP3FFParserNode::ParseFile() Mp3FF \
   2428                         MaxFrameSize %d", iMaxFrameSize));
   2429     }
   2430 
   2431     // get config Details from mp3ff
   2432     MP3ContentFormatType mp3format;
   2433     iConfigOk = iMP3File->GetConfigDetails(mp3format);
   2434     if (!iConfigOk)
   2435     {
   2436         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
   2437                         (0, "PVMFMP3FFParserNode::ParseFile() Mp3FF \
   2438                         Config Not returned", iMaxFrameSize));
   2439 
   2440     }
   2441     else
   2442     {
   2443         iMP3FormatBitrate = mp3format.Bitrate;
   2444     }
   2445     return PVMFSuccess;
   2446 }
   2447 
   2448 /**
   2449  * Reset the trackinfo
   2450  */
   2451 void PVMFMP3FFParserNode::ResetTrack()
   2452 {
   2453     iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_UNINITIALIZED;
   2454     iTrack.iMediaData.Unbind();
   2455     iTrack.iSeqNum = 0;
   2456     iTrack.timestamp_offset = 0;
   2457     iTrack.iSendBOS = false;
   2458     iTrack.iFirstFrame = false;
   2459     iAutoPaused = false;
   2460 
   2461 #if PV_HAS_SHOUTCAST_SUPPORT_ENABLED
   2462     // if this is shoutcast session,
   2463     // reset the stream and read pointers
   2464     if ((iSourceFormat == PVMF_MIME_DATA_SOURCE_SHOUTCAST_URL) && (iSCSPFactory != NULL))
   2465     {
   2466         iSCSPFactory->ResetShoutcastStream();
   2467     }
   2468 #endif
   2469 }
   2470 
   2471 /**
   2472  * Release the trackinfo and do necessary cleanup
   2473  */
   2474 void PVMFMP3FFParserNode::ReleaseTrack()
   2475 {
   2476     iTrack.iMediaData.Unbind();
   2477 
   2478     iTrack.iPort = NULL;
   2479 
   2480     if (iTrack.iTrackDataMemoryPool != NULL)
   2481     {
   2482         iTrack.iTrackDataMemoryPool->removeRef();
   2483         iTrack.iTrackDataMemoryPool = NULL;
   2484     }
   2485 
   2486     if (iTrack.iMediaDataImplAlloc != NULL)
   2487     {
   2488         OSCL_DELETE(iTrack.iMediaDataImplAlloc);
   2489         iTrack.iMediaDataImplAlloc = NULL;
   2490     }
   2491 
   2492     if (iTrack.iMediaDataMemPool != NULL)
   2493     {
   2494         iTrack.iMediaDataMemPool->CancelFreeChunkAvailableCallback();
   2495         iTrack.iMediaDataMemPool->removeRef();
   2496         iTrack.iMediaDataMemPool = NULL;
   2497     }
   2498 
   2499     if (iTrack.iClockConverter != NULL)
   2500     {
   2501         OSCL_DELETE(iTrack.iClockConverter);
   2502         iTrack.iClockConverter = NULL;
   2503     }
   2504 
   2505     return;
   2506 }
   2507 
   2508 /**
   2509  * Cleanup all file sources
   2510  */
   2511 void PVMFMP3FFParserNode::CleanupFileSource()
   2512 {
   2513     if (iDurationCalcAO && iDurationCalcAO->IsBusy())
   2514     {
   2515         iDurationCalcAO->Cancel();
   2516     }
   2517     if (iMP3File)
   2518     {
   2519         OSCL_DELETE(iMP3File);
   2520         iMP3File = NULL;
   2521     }
   2522 
   2523     if (iDataStreamInterface != NULL)
   2524     {
   2525         PVInterface* iFace = OSCL_STATIC_CAST(PVInterface*, iDataStreamInterface);
   2526         PVUuid uuid = PVMIDataStreamSyncInterfaceUuid;
   2527 
   2528 #if PV_HAS_SHOUTCAST_SUPPORT_ENABLED
   2529         if (iSCSPFactory != NULL)
   2530         {
   2531             iSCSPFactory->DestroyPVMFCPMPluginAccessInterface(uuid, iFace);
   2532             iSCSP = NULL;
   2533         }
   2534         else
   2535         {
   2536             iDataStreamFactory->DestroyPVMFCPMPluginAccessInterface(uuid, iFace);
   2537         }
   2538 #else
   2539         iDataStreamFactory->DestroyPVMFCPMPluginAccessInterface(uuid, iFace);
   2540 #endif
   2541         iDataStreamInterface = NULL;
   2542     }
   2543 
   2544 #if PV_HAS_SHOUTCAST_SUPPORT_ENABLED
   2545     if (iSCSPFactory != NULL)
   2546     {
   2547         OSCL_DELETE(iSCSPFactory);
   2548         iSCSPFactory = NULL;
   2549     }
   2550     if (iMetadataBuf != NULL)
   2551     {
   2552         oscl_free(iMetadataBuf);
   2553         iMetadataBuf = NULL;
   2554         iMetadataBufSize = 0;
   2555         iMetadataSize = 0;
   2556     }
   2557 #endif
   2558 
   2559     if (iDataStreamFactory != NULL)
   2560     {
   2561         iDataStreamFactory->removeRef();
   2562         iDataStreamFactory = NULL;
   2563     }
   2564     iMP3ParserNodeMetadataValueCount = 0;
   2565 
   2566     iCPMSourceData.iFileHandle = NULL;
   2567 
   2568     if (iFileHandle)
   2569     {
   2570         OSCL_DELETE(iFileHandle);
   2571         iFileHandle = NULL;
   2572     }
   2573     iSourceURLSet = false;
   2574     oWaitingOnLicense = false;
   2575     iDownloadComplete = false;
   2576 }
   2577 
   2578 /**
   2579  * From OsclMemPoolFixedChunkAllocatorObserver
   2580  * Call back is received when free mem-chunk is available
   2581  */
   2582 void PVMFMP3FFParserNode::freechunkavailable(OsclAny*)
   2583 {
   2584     if (iTrack.iState == PVMP3FFNodeTrackPortInfo::TRACKSTATE_MEDIADATAPOOLEMPTY)
   2585     {
   2586         iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_GETDATA;
   2587         if (IsAdded())
   2588         {
   2589             RunIfNotReady();
   2590         }
   2591     }
   2592 }
   2593 
   2594 /**
   2595  * From OsclMemPoolResizableAllocatorObserver
   2596  * Call back is received when free mem-block is available
   2597  */
   2598 void PVMFMP3FFParserNode::freeblockavailable(OsclAny*)
   2599 {
   2600     if (iTrack.iState == PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRACKDATAPOOLEMPTY)
   2601     {
   2602         iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_GETDATA;
   2603         if (IsAdded())
   2604         {
   2605             RunIfNotReady();
   2606         }
   2607     }
   2608 }
   2609 
   2610 
   2611 ////////////////////////////////////////////////////////////////////////
   2612 /**
   2613  * Extension interface implementation
   2614  */
   2615 ////////////////////////////////////////////////////////////////////////
   2616 
   2617 void PVMFMP3FFParserNode::addRef()
   2618 {
   2619     ++iExtensionRefCount;
   2620 }
   2621 
   2622 void PVMFMP3FFParserNode::removeRef()
   2623 {
   2624     --iExtensionRefCount;
   2625 }
   2626 
   2627 PVMFStatus PVMFMP3FFParserNode::QueryInterfaceSync(PVMFSessionId aSession,
   2628         const PVUuid& aUuid,
   2629         PVInterface*& aInterfacePtr)
   2630 {
   2631     OSCL_UNUSED_ARG(aSession);
   2632     aInterfacePtr = NULL;
   2633     if (queryInterface(aUuid, aInterfacePtr))
   2634     {
   2635         aInterfacePtr->addRef();
   2636         return PVMFSuccess;
   2637     }
   2638     return PVMFErrNotSupported;
   2639 }
   2640 
   2641 bool PVMFMP3FFParserNode::queryInterface(const PVUuid& uuid, PVInterface*& iface)
   2642 {
   2643     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFMP3FFParserNode::queryInterface() In"));
   2644 
   2645     if (uuid == PVMF_TRACK_SELECTION_INTERFACE_UUID)
   2646     {
   2647         PVMFTrackSelectionExtensionInterface* myInterface = OSCL_STATIC_CAST(PVMFTrackSelectionExtensionInterface*, this);
   2648         iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
   2649     }
   2650     else if (uuid == PVMF_DATA_SOURCE_INIT_INTERFACE_UUID)
   2651     {
   2652         PVMFDataSourceInitializationExtensionInterface* myInterface = OSCL_STATIC_CAST(PVMFDataSourceInitializationExtensionInterface*, this);
   2653         iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
   2654     }
   2655     else if (uuid == KPVMFMetadataExtensionUuid)
   2656     {
   2657         PVMFMetadataExtensionInterface* myInterface = OSCL_STATIC_CAST(PVMFMetadataExtensionInterface*, this);
   2658         iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
   2659     }
   2660     else if (PvmfDataSourcePlaybackControlUuid == uuid)
   2661     {
   2662         PvmfDataSourcePlaybackControlInterface* myInterface = OSCL_STATIC_CAST(PvmfDataSourcePlaybackControlInterface*, this);
   2663         iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
   2664     }
   2665     else if (uuid == PVMFCPMPluginLicenseInterfaceUuid)
   2666     {
   2667         PVMFCPMPluginLicenseInterface* myInterface = OSCL_STATIC_CAST(PVMFCPMPluginLicenseInterface*, this);
   2668         iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
   2669     }
   2670     else if (PVMF_FF_PROGDOWNLOAD_SUPPORT_INTERFACE_UUID == uuid)
   2671     {
   2672         PVMFFormatProgDownloadSupportInterface* myInterface = OSCL_STATIC_CAST(PVMFFormatProgDownloadSupportInterface*, this);
   2673         iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
   2674     }
   2675     else if (PVMIDatastreamuserInterfaceUuid == uuid)
   2676     {
   2677         PVMIDatastreamuserInterface* myInterface = OSCL_STATIC_CAST(PVMIDatastreamuserInterface*, this);
   2678         iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
   2679     }
   2680     else
   2681     {
   2682         return false;
   2683     }
   2684     return true;
   2685 }
   2686 
   2687 
   2688 /**
   2689  * From PVMFDataSourceInitializationExtensionInterface
   2690  */
   2691 PVMFStatus PVMFMP3FFParserNode::SetSourceInitializationData(OSCL_wString& aSourceURL,
   2692         PVMFFormatType& aSourceFormat,
   2693         OsclAny* aSourceData)
   2694 {
   2695     // Initialize the Source data
   2696     if (iSourceURLSet)
   2697     {
   2698         CleanupFileSource();
   2699     }
   2700 
   2701     if (aSourceFormat != PVMF_MIME_MP3FF &&
   2702             aSourceFormat != PVMF_MIME_DATA_SOURCE_SHOUTCAST_URL)
   2703     {
   2704         // Node doesnt support any other format than MP3/Shoutcast stream
   2705         return PVMFFailure;
   2706     }
   2707 
   2708     iSourceFormat = aSourceFormat;
   2709     iSourceURL = aSourceURL;
   2710     iSourceURLSet = true;
   2711     if (aSourceData)
   2712     {
   2713         PVInterface* pvInterface = OSCL_STATIC_CAST(PVInterface*, aSourceData);
   2714         PVInterface* localDataSrc = NULL;
   2715         PVUuid localDataSrcUuid(PVMF_LOCAL_DATASOURCE_UUID);
   2716         // Check if it is a local file
   2717         if (pvInterface->queryInterface(localDataSrcUuid, localDataSrc))
   2718         {
   2719             PVMFLocalDataSource* opaqueData = OSCL_STATIC_CAST(PVMFLocalDataSource*, localDataSrc);
   2720             if (opaqueData->iFileHandle)
   2721             {
   2722                 iFileHandle = OSCL_NEW(OsclFileHandle, (*(opaqueData->iFileHandle)));
   2723                 iCPMSourceData.iFileHandle = iFileHandle;
   2724             }
   2725             if (opaqueData->iContentAccessFactory != NULL)
   2726             {
   2727                 //Cannot have both plugin usage and a datastream factory
   2728                 return PVMFErrArgument;
   2729             }
   2730         }
   2731         else
   2732         {
   2733             PVInterface* sourceDataContext = NULL;
   2734             PVInterface* commonDataContext = NULL;
   2735             PVUuid sourceContextUuid(PVMF_SOURCE_CONTEXT_DATA_UUID);
   2736             PVUuid commonContextUuid(PVMF_SOURCE_CONTEXT_DATA_COMMON_UUID);
   2737             if (pvInterface->queryInterface(sourceContextUuid, sourceDataContext))
   2738             {
   2739                 if (sourceDataContext->queryInterface(commonContextUuid, commonDataContext))
   2740                 {
   2741                     PVMFSourceContextDataCommon* cContext = OSCL_STATIC_CAST(
   2742                                                                 PVMFSourceContextDataCommon*,
   2743                                                                 commonDataContext);
   2744                     if (cContext->iFileHandle)
   2745                     {
   2746                         iFileHandle = OSCL_NEW(OsclFileHandle, (*(cContext->iFileHandle)));
   2747                     }
   2748                     if (cContext->iContentAccessFactory != NULL)
   2749                     {
   2750                         //Cannot have both plugin usage and a datastream factory
   2751                         return PVMFErrArgument;
   2752                     }
   2753                     PVMFSourceContextData* sContext = OSCL_STATIC_CAST(
   2754                                                           PVMFSourceContextData*,
   2755                                                           sourceDataContext);
   2756                     iSourceContextData = *sContext;
   2757                     iSourceContextDataValid = true;
   2758                 }
   2759             }
   2760         }
   2761     }
   2762     return PVMFSuccess;
   2763 }
   2764 
   2765 PVMFStatus PVMFMP3FFParserNode::SetClientPlayBackClock(PVMFMediaClock* aClientClock)
   2766 {
   2767     OSCL_UNUSED_ARG(aClientClock);
   2768     return PVMFSuccess;
   2769 }
   2770 
   2771 PVMFStatus PVMFMP3FFParserNode::SetEstimatedServerClock(PVMFMediaClock* aClientClock)
   2772 {
   2773     OSCL_UNUSED_ARG(aClientClock);
   2774     return PVMFSuccess;
   2775 }
   2776 
   2777 /**
   2778  * From PVMFTrackSelectionExtensionInterface
   2779  */
   2780 PVMFStatus PVMFMP3FFParserNode::GetMediaPresentationInfo(PVMFMediaPresentationInfo& aInfo)
   2781 {
   2782     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   2783                     (0, "PVMFMP3FFParserNode::GetMediaPresentationInfo() In"));
   2784     if (!iMP3File)
   2785     {
   2786         return PVMFFailure;
   2787     }
   2788     aInfo.setDurationValue(iMP3File->GetDuration());
   2789 
   2790     int32 iNumTracks = iMP3File->GetNumTracks();
   2791     if (iNumTracks <= 0)
   2792     {
   2793         // Number of tracks is null
   2794         return PVMFFailure;
   2795     }
   2796 
   2797     int32 id;
   2798     for (id = 0; id < iNumTracks; id++)
   2799     {
   2800         PVMFTrackInfo tmpTrackInfo;
   2801         // set the port tag for this track
   2802         tmpTrackInfo.setPortTag(PVMF_MP3FFPARSER_NODE_PORT_TYPE_SOURCE);
   2803         // track id
   2804         tmpTrackInfo.setTrackID(0);
   2805         // bitrate
   2806         uint32 aBitRate = 0;
   2807         if (iConfigOk)
   2808         {
   2809             aBitRate = iMP3FormatBitrate;
   2810         }
   2811         tmpTrackInfo.setTrackBitRate(aBitRate);
   2812         // config info
   2813         MP3ContentFormatType mp3Config;
   2814         if (!iMP3File->GetConfigDetails(mp3Config))
   2815         {
   2816             // mp3 config not available
   2817             return PVMFFailure;
   2818         }
   2819 
   2820         if (!CreateFormatSpecificInfo(mp3Config.NumberOfChannels, mp3Config.SamplingRate))
   2821         {
   2822             return PVMFFailure;
   2823         }
   2824 
   2825         tmpTrackInfo.setTrackConfigInfo(iDecodeFormatSpecificInfo);
   2826         // timescale
   2827         uint64 timescale = (uint64)iMP3File->GetTimescale();
   2828         tmpTrackInfo.setTrackDurationTimeScale(timescale);
   2829         // in movie timescale
   2830         uint32 trackDuration = iMP3File->GetDuration();
   2831         tmpTrackInfo.setTrackDurationValue(trackDuration);
   2832         // mime type
   2833         OSCL_FastString mime_type = _STRLIT_CHAR(PVMF_MIME_MP3);
   2834         tmpTrackInfo.setTrackMimeType(mime_type);
   2835         // add the track
   2836         aInfo.addTrackInfo(tmpTrackInfo);
   2837     }
   2838     return PVMFSuccess;
   2839 }
   2840 
   2841 bool PVMFMP3FFParserNode::CreateFormatSpecificInfo(uint32 numChannels, uint32 samplingRate)
   2842 {
   2843     // Allocate memory for decode specific info and ref counter
   2844     OsclMemoryFragment frag;
   2845     frag.ptr = NULL;
   2846     frag.len = sizeof(channelSampleInfo);
   2847     uint refCounterSize = oscl_mem_aligned_size(sizeof(OsclRefCounterDA));
   2848     uint8* memBuffer = (uint8*)iDecodeFormatSpecificInfoAlloc.ALLOCATE(refCounterSize + frag.len);
   2849     if (!memBuffer)
   2850     {
   2851         // failure while allocating memory buffer
   2852         return false;
   2853     }
   2854 
   2855     oscl_memset(memBuffer, 0, refCounterSize + frag.len);
   2856     // Create ref counter
   2857     OsclRefCounter* refCounter = new(memBuffer) OsclRefCounterDA(memBuffer,
   2858             (OsclDestructDealloc*)&iDecodeFormatSpecificInfoAlloc);
   2859     memBuffer += refCounterSize;
   2860     // Create channel sample info
   2861     frag.ptr = (OsclAny*)(new(memBuffer) channelSampleInfo);
   2862     ((channelSampleInfo*)frag.ptr)->desiredChannels = numChannels;
   2863     ((channelSampleInfo*)frag.ptr)->samplingRate = samplingRate;
   2864 
   2865     // Store info in a ref counter memfrag
   2866     iDecodeFormatSpecificInfo = OsclRefCounterMemFrag(frag, refCounter,
   2867                                 sizeof(struct channelSampleInfo));
   2868     return true;
   2869 }
   2870 
   2871 PVMFStatus PVMFMP3FFParserNode::SelectTracks(PVMFMediaPresentationInfo& aInfo)
   2872 {
   2873     OSCL_UNUSED_ARG(aInfo);
   2874     return PVMFSuccess;
   2875 }
   2876 
   2877 // From PVMFMetadataExtensionInterface
   2878 uint32 PVMFMP3FFParserNode::GetNumMetadataKeys(char* aQueryString)
   2879 {
   2880     uint32 num_entries = 0;
   2881     if (iMP3File)
   2882     {
   2883         num_entries = iMP3File->GetNumMetadataKeys(aQueryString);
   2884     }
   2885 
   2886     if (iCPMContainer.iCPMMetaDataExtensionInterface != NULL)
   2887     {
   2888         num_entries +=
   2889             (iCPMContainer.iCPMMetaDataExtensionInterface)->GetNumMetadataKeys(aQueryString);
   2890     }
   2891     return num_entries;
   2892 }
   2893 
   2894 uint32 PVMFMP3FFParserNode::GetNumMetadataValues(PVMFMetadataList& aKeyList)
   2895 {
   2896     uint32 numvalentries = 0;
   2897     if (iMP3File)
   2898     {
   2899         numvalentries = iMP3File->GetNumMetadataValues(aKeyList);
   2900     }
   2901 
   2902     if (iCPMContainer.iCPMMetaDataExtensionInterface != NULL)
   2903     {
   2904         numvalentries +=
   2905             iCPMContainer.iCPMMetaDataExtensionInterface->GetNumMetadataValues(aKeyList);
   2906     }
   2907     return numvalentries;
   2908 }
   2909 
   2910 /**
   2911  * From PVMFMetadataExtensionInterface
   2912  * Queue an asynchronous node command for GetNodeMetadataKeys
   2913  */
   2914 PVMFCommandId PVMFMP3FFParserNode::GetNodeMetadataKeys(PVMFSessionId aSessionId,
   2915         PVMFMetadataList& aKeyList,
   2916         uint32 starting_index,
   2917         int32 max_entries,
   2918         char* query_key,
   2919         const OsclAny* aContext)
   2920 {
   2921     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   2922                     (0, "PVMFMP3FFParserNode::GetNodeMetadataKeys() In"));
   2923     PVMFMP3FFParserNodeCommand cmd;
   2924     cmd.PVMFMP3FFParserNodeCommand::Construct(aSessionId,
   2925             PVMP3FF_NODE_CMD_GETNODEMETADATAKEY,
   2926             aKeyList, starting_index,
   2927             max_entries, query_key,
   2928             aContext);
   2929     return QueueCommandL(cmd);
   2930 }
   2931 
   2932 /**
   2933  * From PVMFMetadataExtensionInterface
   2934  * Queue an asynchronous node command for GetNodeMetadataValues
   2935  */
   2936 PVMFCommandId PVMFMP3FFParserNode::GetNodeMetadataValues(PVMFSessionId aSessionId,
   2937         PVMFMetadataList& aKeyList,
   2938         Oscl_Vector<PvmiKvp, OsclMemAllocator>& aValueList,
   2939         uint32 starting_index,
   2940         int32 max_entries,
   2941         const OsclAny* aContext)
   2942 {
   2943     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   2944                     (0, "PVMFMP3FFParserNode::GetNodeMetadataValues() In"));
   2945 
   2946     PVMFMP3FFParserNodeCommand cmd;
   2947     cmd.PVMFMP3FFParserNodeCommand::Construct(aSessionId,
   2948             PVMP3FF_NODE_CMD_GETNODEMETADATAVALUE,
   2949             aKeyList, aValueList,
   2950             starting_index, max_entries,
   2951             aContext);
   2952     return QueueCommandL(cmd);
   2953 }
   2954 
   2955 /**
   2956  * From PVMFMetadataExtensionInterface
   2957  * Queue an asynchronous node command for ReleaseNodeMetadataKeys
   2958  */
   2959 PVMFStatus PVMFMP3FFParserNode::ReleaseNodeMetadataKeys(PVMFMetadataList& aMetaDataKeys,
   2960         uint32 , uint32)
   2961 {
   2962     OSCL_UNUSED_ARG(aMetaDataKeys);
   2963     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   2964                     (0, "PVMFMP3FFParserNode::ReleaseNodeMetadataKeys() In"));
   2965     return PVMFSuccess;
   2966 }
   2967 
   2968 /**
   2969  * From PVMFMetadataExtensionInterface
   2970  * Queue an asynchronous node command for ReleaseNodeMetadataValues
   2971  */
   2972 PVMFStatus PVMFMP3FFParserNode::ReleaseNodeMetadataValues(Oscl_Vector<PvmiKvp, OsclMemAllocator>& aValueList,
   2973         uint32 start, uint32 end)
   2974 {
   2975     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFMP3FFParserNode::ReleaseNodeMetadataValues() In"));
   2976     if (iMP3File == NULL)
   2977     {
   2978         PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
   2979                         (0, "PVMFMP3FFParserNode::ReleaseNodeMetadataValues() \
   2980                        MP3 file not parsed yet"));
   2981         return PVMFFailure;
   2982     }
   2983 
   2984     end = OSCL_MIN(aValueList.size(), iMP3ParserNodeMetadataValueCount);
   2985 
   2986     if (start > end || aValueList.size() == 0)
   2987     {
   2988         PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
   2989                         (0, "PVMFMP3FFParserNode::ReleaseNodeMetadataValues() \
   2990                         Invalid start/end index"));
   2991         return PVMFErrArgument;
   2992     }
   2993 
   2994     if (end >= aValueList.size())
   2995         // Go through the specified values and free it
   2996         for (uint32 i = start; i < end; i++)
   2997         {
   2998             iMP3File->ReleaseMetadataValue(aValueList[i]);
   2999         }
   3000     return PVMFSuccess;
   3001 }
   3002 
   3003 /**
   3004  * From PvmfDataSourcePlaybackControlInterface
   3005  * Queue an asynchronous node command for SetDataSourcePosition
   3006  */
   3007 PVMFCommandId PVMFMP3FFParserNode::SetDataSourcePosition(PVMFSessionId aSessionId,
   3008         PVMFTimestamp aTargetNPT,
   3009         PVMFTimestamp& aActualNPT,
   3010         PVMFTimestamp& aActualMediaDataTS,
   3011         bool aSeekToSyncPoint,
   3012         uint32 aStreamID,
   3013         OsclAny* aContext)
   3014 {
   3015     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   3016                     (0, "PVMFMP3FFParserNode::SetDataSourcePosition()"));
   3017     PVMFMP3FFParserNodeCommand cmd;
   3018     cmd.PVMFMP3FFParserNodeCommand::Construct(aSessionId,
   3019             PVMP3FF_NODE_CMD_SETDATASOURCEPOSITION,
   3020             aTargetNPT, &aActualNPT,
   3021             &aActualMediaDataTS, aSeekToSyncPoint,
   3022             aStreamID, aContext);
   3023     return QueueCommandL(cmd);
   3024 }
   3025 
   3026 /**
   3027  * From PvmfDataSourcePlaybackControlInterface
   3028  * Queue an asynchronous node command for QueryDataSourcePosition
   3029  */
   3030 PVMFCommandId PVMFMP3FFParserNode::QueryDataSourcePosition(PVMFSessionId aSessionId,
   3031         PVMFTimestamp aTargetNPT,
   3032         PVMFTimestamp& aActualNPT,
   3033         bool aSeekToSyncPoint,
   3034         OsclAny* aContext)
   3035 {
   3036     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   3037                     (0, "PVMFMP3FFParserNode::QueryDataSourcePosition()"));
   3038     PVMFMP3FFParserNodeCommand cmd;
   3039     cmd.PVMFMP3FFParserNodeCommand::Construct(aSessionId,
   3040             PVMP3FF_NODE_CMD_QUERYDATASOURCEPOSITION,
   3041             aTargetNPT, &aActualNPT,
   3042             aSeekToSyncPoint, aContext);
   3043     return QueueCommandL(cmd);
   3044 }
   3045 
   3046 /**
   3047  * From PvmfDataSourcePlaybackControlInterface
   3048  * Queue an asynchronous node command for QueryDataSourcePosition
   3049  */
   3050 PVMFCommandId PVMFMP3FFParserNode::QueryDataSourcePosition(PVMFSessionId aSessionId,
   3051         PVMFTimestamp aTargetNPT,
   3052         PVMFTimestamp& aSeekPointBeforeTargetNPT,
   3053         PVMFTimestamp& aSeekPointAfterTargetNPT,
   3054         OsclAny* aContextData,
   3055         bool aSeekToSyncPoint)
   3056 {
   3057     OSCL_UNUSED_ARG(aSeekPointAfterTargetNPT);
   3058     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   3059                     (0, "PVMFMP3FFParserNode::QueryDataSourcePosition()"));
   3060     PVMFMP3FFParserNodeCommand cmd;
   3061     // Construct call is not changed, the aSeekPointBeforeTargetNPT will
   3062     // contain the replaced actualNPT
   3063     cmd.PVMFMP3FFParserNodeCommand::Construct(aSessionId,
   3064             PVMP3FF_NODE_CMD_QUERYDATASOURCEPOSITION,
   3065             aTargetNPT, &aSeekPointBeforeTargetNPT,
   3066             aSeekToSyncPoint, aContextData);
   3067     return QueueCommandL(cmd);
   3068 }
   3069 
   3070 /**
   3071  * From PvmfDataSourcePlaybackControlInterface
   3072  * Queue an asynchronous node command for SetDataSourceRate
   3073  */
   3074 PVMFCommandId PVMFMP3FFParserNode::SetDataSourceRate(PVMFSessionId aSessionId,
   3075         int32 aRate,
   3076         PVMFTimebase* aTimebase,
   3077         OsclAny* aContext)
   3078 {
   3079     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   3080                     (0, "PVMFMP3FFParserNode::SetDataSourcePosition()"));
   3081     PVMFMP3FFParserNodeCommand cmd;
   3082     cmd.PVMFMP3FFParserNodeCommand::Construct(aSessionId,
   3083             PVMP3FF_NODE_CMD_SETDATASOURCERATE,
   3084             aRate, aTimebase,
   3085             aContext);
   3086     return QueueCommandL(cmd);
   3087 }
   3088 
   3089 /**
   3090  * Command Handler for SetDataSourceRate
   3091  */
   3092 PVMFStatus PVMFMP3FFParserNode::DoSetDataSourceRate(PVMFMP3FFParserNodeCommand& aCmd)
   3093 {
   3094     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   3095                     (0, "PVMFMP3FFParserNode::DoSetDataSourceRate() In"));
   3096     OSCL_UNUSED_ARG(aCmd);
   3097     return PVMFSuccess;
   3098 }
   3099 
   3100 /**
   3101  * Command Handler for SetDataSourcePosition
   3102  */
   3103 PVMFStatus PVMFMP3FFParserNode::DoSetDataSourcePosition(PVMFMP3FFParserNodeCommand& aCmd)
   3104 {
   3105     uint32 targetNPT = 0;
   3106     uint32* actualNPT = NULL;
   3107     uint32* actualMediaDataTS = NULL;
   3108     bool seektosyncpoint = false;
   3109     uint32 streamID = 0;
   3110 
   3111     // if progressive streaming, reset download complete flag
   3112     if ((NULL != iDataStreamInterface) && (0 != iDataStreamInterface->QueryBufferingCapacity()))
   3113     {
   3114         iDownloadComplete = false;
   3115     }
   3116 
   3117     aCmd.PVMFMP3FFParserNodeCommand::Parse(targetNPT, actualNPT,
   3118                                            actualMediaDataTS, seektosyncpoint,
   3119                                            streamID);
   3120 
   3121     iStreamID = streamID;
   3122     iTrack.iSendBOS = true;
   3123     iTrack.iFirstFrame = true;
   3124 
   3125     if (iDownloadProgressClock.GetRep())
   3126     {
   3127         // Get the amount downloaded so far
   3128         bool tmpbool = false;
   3129         uint32 dltime = 0;
   3130         iDownloadProgressClock->GetCurrentTime32(dltime, tmpbool, PVMF_MEDIA_CLOCK_MSEC);
   3131         // Check if the requested time is past the downloaded clip
   3132         if (targetNPT >= dltime)
   3133         {
   3134             // For now, fail in this case. In future, we want to reposition to valid location.
   3135             PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
   3136                             (0, "PVMFMP3FFParserNode::DoSetDataSourcePosition() \
   3137                             Positioning past the amount downloaded so return as \
   3138                             argument error"));
   3139             return PVMFErrArgument;
   3140         }
   3141     }
   3142     // get the clock offset
   3143     iTrack.iClockConverter->update_clock(iMP3File->GetTimestampForCurrentSample());
   3144     iTrack.timestamp_offset += iTrack.iClockConverter->get_converted_ts(COMMON_PLAYBACK_CLOCK_TIMESCALE);
   3145     // Set the timestamp
   3146     *actualMediaDataTS = iTrack.timestamp_offset;
   3147     // See if targetNPT is greater or equal to clip duration
   3148     uint32 duration = iMP3File->GetDuration();
   3149     if (duration > 0 && targetNPT >= duration)
   3150     {
   3151         // report End of Stream on the track and reset the track to zero.
   3152         iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_SEND_ENDOFTRACK;
   3153         iMP3File->SeekToTimestamp(0);
   3154         *actualNPT = duration;
   3155         iTrack.iClockConverter->set_clock_other_timescale(*actualMediaDataTS, COMMON_PLAYBACK_CLOCK_TIMESCALE);
   3156         PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
   3157                         (0, "PVMFMP3FFParserNode::DoSetDataSourcePosition: targetNPT=%d, actualNPT=%d, actualMediaTS=%d",
   3158                          targetNPT, *actualNPT, *actualMediaDataTS));
   3159         if (iAutoPaused)
   3160         {
   3161             PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFMP3FFParserNode::DoSetDataSourcePosition Track Autopaused"));
   3162             iAutoPaused = false;
   3163             if (iDownloadProgressInterface != NULL)
   3164             {
   3165                 iDownloadProgressInterface->cancelResumeNotification();
   3166             }
   3167         }
   3168         return PVMFSuccess;
   3169     }
   3170     // Seek to the next NPT
   3171     // MP3 FF seeks to the beginning if the requested time is past the end of clip
   3172     *actualNPT = iMP3File->SeekToTimestamp(targetNPT);
   3173 
   3174     if (duration > 0 && *actualNPT == duration)
   3175     {
   3176         // this means there was no data to render after the seek so just send End of Track
   3177         iTrack.iClockConverter->set_clock_other_timescale(*actualMediaDataTS, COMMON_PLAYBACK_CLOCK_TIMESCALE);
   3178         iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_SEND_ENDOFTRACK;
   3179         return PVMFSuccess;
   3180     }
   3181 
   3182     iTrack.iClockConverter->set_clock_other_timescale(*actualNPT, COMMON_PLAYBACK_CLOCK_TIMESCALE);
   3183     iTrack.timestamp_offset -= *actualNPT;
   3184 
   3185     // Reposition has occured, so reset the track state
   3186     if (iAutoPaused)
   3187     {
   3188         PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFMP3FFParserNode::DoSetDataSourcePosition Track Autopaused"));
   3189         iAutoPaused = false;
   3190         if (iDownloadProgressInterface != NULL)
   3191         {
   3192             iDownloadProgressInterface->cancelResumeNotification();
   3193         }
   3194     }
   3195     iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_GETDATA;
   3196 
   3197     PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
   3198                     (0, "PVMFMP3FFParserNode::DoSetDataSourcePosition: targetNPT=%d, actualNPT=%d, actualMediaTS=%d",
   3199                      targetNPT, *actualNPT, *actualMediaDataTS));
   3200     return PVMFSuccess;
   3201 }
   3202 
   3203 /**
   3204  * Command Handler for QueryDataSourcePosition
   3205  */
   3206 PVMFStatus PVMFMP3FFParserNode::DoQueryDataSourcePosition(PVMFMP3FFParserNodeCommand& aCmd)
   3207 {
   3208     uint32 targetNPT = 0;
   3209     uint32* actualNPT = NULL;
   3210     bool seektosyncpoint = false;
   3211 
   3212     aCmd.PVMFMP3FFParserNodeCommand::Parse(targetNPT, actualNPT, seektosyncpoint);
   3213     if (actualNPT == NULL)
   3214     {
   3215         return PVMFErrArgument;
   3216     }
   3217     // First check if MP3 file is being PDed to make sure the requested
   3218     // position is before amount downloaded
   3219     if (iDownloadProgressClock.GetRep())
   3220     {
   3221         // Get the amount downloaded so far
   3222         bool tmpbool = false;
   3223         uint32 dltime = 0;
   3224         iDownloadProgressClock->GetCurrentTime32(dltime, tmpbool, PVMF_MEDIA_CLOCK_MSEC);
   3225         // Check if the requested time is past clip dl
   3226         if (targetNPT >= dltime)
   3227         {
   3228             return PVMFErrArgument;
   3229         }
   3230     }
   3231     // Determine the actual NPT without actually repositioning
   3232     // MP3 FF goes to the beginning if the requested time is past the end of clip
   3233     *actualNPT = targetNPT;
   3234     uint32 duration = iMP3File->GetDuration();
   3235     if (duration > 0 && targetNPT >= duration)
   3236     {
   3237         // return without any call on parser library.
   3238         return PVMFSuccess;
   3239     }
   3240     iMP3File->SeekPointFromTimestamp(*actualNPT);
   3241     return PVMFSuccess;
   3242 }
   3243 
   3244 /**
   3245  * Queues SubNode Commands
   3246  */
   3247 void PVMFMP3FFParserNode::Push(PVMFSubNodeContainerBaseMp3& c, PVMFSubNodeContainerBaseMp3::CmdType cmd)
   3248 {
   3249     SubNodeCmd snc;
   3250     snc.iSubNodeContainer = &c;
   3251     snc.iCmd = cmd;
   3252     iSubNodeCmdVec.push_back(snc);
   3253 }
   3254 
   3255 
   3256 PVMFCommandId
   3257 PVMFMP3FFParserNode::GetLicense(PVMFSessionId aSessionId,
   3258                                 OSCL_wString& aContentName,
   3259                                 OsclAny* aData,
   3260                                 uint32 aDataSize,
   3261                                 int32 aTimeoutMsec,
   3262                                 OsclAny* aContextData)
   3263 {
   3264     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFMP3FFParserNode::GetLicense - Wide called"));
   3265     PVMFMP3FFParserNodeCommand cmd;
   3266     cmd.PVMFMP3FFParserNodeCommand::Construct(aSessionId,
   3267             PVMP3FF_NODE_CMD_GET_LICENSE_W,
   3268             aContentName,
   3269             aData,
   3270             aDataSize,
   3271             aTimeoutMsec,
   3272             aContextData);
   3273     return QueueCommandL(cmd);
   3274 }
   3275 
   3276 PVMFCommandId
   3277 PVMFMP3FFParserNode::GetLicense(PVMFSessionId aSessionId,
   3278                                 OSCL_String&  aContentName,
   3279                                 OsclAny* aData,
   3280                                 uint32 aDataSize,
   3281                                 int32 aTimeoutMsec,
   3282                                 OsclAny* aContextData)
   3283 {
   3284     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFMP3FFParserNode::GetLicense - Non-Wide called"));
   3285     PVMFMP3FFParserNodeCommand cmd;
   3286     cmd.PVMFMP3FFParserNodeCommand::Construct(aSessionId,
   3287             PVMP3FF_NODE_CMD_GET_LICENSE,
   3288             aContentName,
   3289             aData,
   3290             aDataSize,
   3291             aTimeoutMsec,
   3292             aContextData);
   3293     return QueueCommandL(cmd);
   3294 }
   3295 
   3296 
   3297 
   3298 PVMFStatus PVMFMP3FFParserNode::DoGetLicense(PVMFMP3FFParserNodeCommand& aCmd,
   3299         bool aWideCharVersion)
   3300 {
   3301     OSCL_UNUSED_ARG(aCmd);
   3302     if (iCPMContainer.iCPMLicenseInterface == NULL)
   3303     {
   3304         return PVMFErrNotSupported;
   3305     }
   3306 
   3307     if (aWideCharVersion == true)
   3308     {
   3309         Push(iCPMContainer, PVMFSubNodeContainerBaseMp3::ECPMGetLicenseW);
   3310     }
   3311     else
   3312     {
   3313         Push(iCPMContainer, PVMFSubNodeContainerBaseMp3::ECPMGetLicense);
   3314     }
   3315     RunIfNotReady();
   3316     return PVMFPending;
   3317 }
   3318 
   3319 void PVMFMP3FFParserNode::CompleteGetLicense()
   3320 {
   3321     CommandComplete(iCurrentCommand,
   3322                     iCurrentCommand.front(),
   3323                     PVMFSuccess, NULL, NULL);
   3324 }
   3325 
   3326 PVMFCommandId
   3327 PVMFMP3FFParserNode::CancelGetLicense(PVMFSessionId aSessionId, PVMFCommandId aCmdId, OsclAny* aContextData)
   3328 {
   3329     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFMP3FFParserNode::CancelGetLicense - called"));
   3330     PVMFMP3FFParserNodeCommand cmd;
   3331     cmd.PVMFMP3FFParserNodeCommandBase::Construct(aSessionId, PVMP3FF_NODE_CMD_CANCEL_GET_LICENSE, aCmdId, aContextData);
   3332     return QueueCommandL(cmd);
   3333 }
   3334 
   3335 PVMFStatus PVMFMP3FFParserNode::DoCancelGetLicense(PVMFMP3FFParserNodeCommand& aCmd)
   3336 {
   3337     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFMP3FFParserNode::DoCancelGetLicense() Called"));
   3338     PVMFStatus status = PVMFErrArgument;
   3339 
   3340     if (iCPMContainer.iCPMLicenseInterface == NULL)
   3341     {
   3342         status = PVMFErrNotSupported;
   3343     }
   3344     else
   3345     {
   3346         /* extract the command ID from the parameters.*/
   3347         PVMFCommandId id;
   3348         aCmd.PVMFMP3FFParserNodeCommandBase::Parse(id);
   3349 
   3350         /* first check "current" command if any */
   3351         PVMFMP3FFParserNodeCommand* cmd = iCurrentCommand.FindById(id);
   3352         if (cmd)
   3353         {
   3354             if (cmd->iCmd == PVMP3FF_NODE_CMD_GET_LICENSE_W || cmd->iCmd == PVMP3FF_NODE_CMD_GET_LICENSE)
   3355             {
   3356                 if (iCPMContainer.CancelPendingCommand())
   3357                 {
   3358                     return PVMFPending;//wait on sub-node cancel to complete.
   3359                 }
   3360                 CommandComplete(iCurrentCommand, *cmd, PVMFErrCancelled, NULL, NULL);
   3361                 return PVMFSuccess;
   3362             }
   3363         }
   3364 
   3365         /*
   3366          * next check input queue.
   3367          * start at element 1 since this cancel command is element 0.
   3368          */
   3369         cmd = iInputCommands.FindById(id, 1);
   3370         if (cmd)
   3371         {
   3372             if (cmd->iCmd == PVMP3FF_NODE_CMD_GET_LICENSE_W || cmd->iCmd == PVMP3FF_NODE_CMD_GET_LICENSE)
   3373             {
   3374                 /* cancel the queued command */
   3375                 CommandComplete(iInputCommands, *cmd, PVMFErrCancelled, NULL, NULL);
   3376                 /* report cancel success */
   3377                 return PVMFSuccess;
   3378             }
   3379         }
   3380     }
   3381     /* if we get here the command isn't queued so the cancel fails */
   3382     return status;
   3383 }
   3384 
   3385 PVMFCommandId PVMFCPMContainerMp3::GetCPMLicenseInterface()
   3386 {
   3387     iCPMLicenseInterfacePVI = NULL;
   3388     return (iCPM->QueryInterface(iSessionId,
   3389                                  PVMFCPMPluginLicenseInterfaceUuid,
   3390                                  iCPMLicenseInterfacePVI));
   3391 }
   3392 
   3393 
   3394 PVMFStatus PVMFCPMContainerMp3::CheckApprovedUsage()
   3395 {
   3396     //compare the approved and requested usage bitmaps
   3397     if ((iApprovedUsage.value.uint32_value & iRequestedUsage.value.uint32_value)
   3398             != iRequestedUsage.value.uint32_value)
   3399     {
   3400         return PVMFErrAccessDenied;//media access denied by CPM.
   3401     }
   3402     return PVMFSuccess;
   3403 }
   3404 
   3405 PVMFStatus PVMFCPMContainerMp3::CreateUsageKeys()
   3406 {
   3407     iCPMContentType = iCPM->GetCPMContentType(iSessionId);
   3408     if ((iCPMContentType != PVMF_CPM_FORMAT_OMA1) &&
   3409             (iCPMContentType != PVMF_CPM_FORMAT_AUTHORIZE_BEFORE_ACCESS))
   3410     {
   3411         return PVMFFailure;//invalid content type.
   3412     }
   3413 
   3414     //cleanup any old usage keys
   3415     if (iRequestedUsage.key)
   3416     {
   3417         OSCL_ARRAY_DELETE(iRequestedUsage.key);
   3418         iRequestedUsage.key = NULL;
   3419     }
   3420 
   3421     if (iApprovedUsage.key)
   3422     {
   3423         OSCL_ARRAY_DELETE(iApprovedUsage.key);
   3424         iApprovedUsage.key = NULL;
   3425     }
   3426 
   3427     if (iAuthorizationDataKvp.key)
   3428     {
   3429         OSCL_ARRAY_DELETE(iAuthorizationDataKvp.key);
   3430         iAuthorizationDataKvp.key = NULL;
   3431     }
   3432 
   3433     int32 UseKeyLen = oscl_strlen(_STRLIT_CHAR(PVMF_CPM_REQUEST_USE_KEY_STRING));
   3434     int32 AuthKeyLen = oscl_strlen(_STRLIT_CHAR(PVMF_CPM_AUTHORIZATION_DATA_KEY_STRING));
   3435     int32 leavecode = 0;
   3436 
   3437     OSCL_TRY(leavecode,
   3438              iRequestedUsage.key = OSCL_ARRAY_NEW(char, UseKeyLen + 1);
   3439              iApprovedUsage.key = OSCL_ARRAY_NEW(char, UseKeyLen + 1);
   3440              iAuthorizationDataKvp.key = OSCL_ARRAY_NEW(char, AuthKeyLen + 1);
   3441             );
   3442 
   3443     if (leavecode || !iRequestedUsage.key || !iApprovedUsage.key || !iAuthorizationDataKvp.key)
   3444     {
   3445         // Leave occured, do neccessary cleanup
   3446         if (iRequestedUsage.key)
   3447         {
   3448             OSCL_ARRAY_DELETE(iRequestedUsage.key);
   3449             iRequestedUsage.key = NULL;
   3450         }
   3451         if (iApprovedUsage.key)
   3452         {
   3453             OSCL_ARRAY_DELETE(iApprovedUsage.key);
   3454             iApprovedUsage.key = NULL;
   3455         }
   3456         if (iAuthorizationDataKvp.key)
   3457         {
   3458             OSCL_ARRAY_DELETE(iAuthorizationDataKvp.key);
   3459             iAuthorizationDataKvp.key = NULL;
   3460         }
   3461 
   3462         return PVMFErrNoMemory;
   3463     }
   3464 
   3465     oscl_strncpy(iRequestedUsage.key, PVMF_CPM_REQUEST_USE_KEY_STRING, UseKeyLen);
   3466     iRequestedUsage.key[UseKeyLen] = 0;
   3467     iRequestedUsage.length = 0;
   3468     iRequestedUsage.capacity = 0;
   3469     iRequestedUsage.value.uint32_value =
   3470         (BITMASK_PVMF_CPM_DRM_INTENT_PLAY |
   3471          BITMASK_PVMF_CPM_DRM_INTENT_PAUSE |
   3472          BITMASK_PVMF_CPM_DRM_INTENT_SEEK_FORWARD |
   3473          BITMASK_PVMF_CPM_DRM_INTENT_SEEK_BACK);
   3474 
   3475     oscl_strncpy(iApprovedUsage.key, PVMF_CPM_REQUEST_USE_KEY_STRING, UseKeyLen);
   3476     iApprovedUsage.key[UseKeyLen] = 0;
   3477     iApprovedUsage.length = 0;
   3478     iApprovedUsage.capacity = 0;
   3479     iApprovedUsage.value.uint32_value = 0;
   3480 
   3481     oscl_strncpy(iAuthorizationDataKvp.key, _STRLIT_CHAR(PVMF_CPM_AUTHORIZATION_DATA_KEY_STRING),
   3482                  AuthKeyLen);
   3483     iAuthorizationDataKvp.key[AuthKeyLen] = 0;
   3484 
   3485     if ((iCPMContentType == PVMF_CPM_FORMAT_OMA1) ||
   3486             (iCPMContentType == PVMF_CPM_FORMAT_AUTHORIZE_BEFORE_ACCESS))
   3487     {
   3488         iAuthorizationDataKvp.length = 0;
   3489         iAuthorizationDataKvp.capacity = 0;
   3490         iAuthorizationDataKvp.value.pUint8_value = NULL;
   3491     }
   3492     else
   3493     {
   3494         if (iRequestedUsage.key)
   3495         {
   3496             OSCL_ARRAY_DELETE(iRequestedUsage.key);
   3497             iRequestedUsage.key = NULL;
   3498         }
   3499         if (iApprovedUsage.key)
   3500         {
   3501             OSCL_ARRAY_DELETE(iApprovedUsage.key);
   3502             iApprovedUsage.key = NULL;
   3503         }
   3504         if (iAuthorizationDataKvp.key)
   3505         {
   3506             OSCL_ARRAY_DELETE(iAuthorizationDataKvp.key);
   3507             iAuthorizationDataKvp.key = NULL;
   3508         }
   3509         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3510                         (0, "PVMFCPMContainerMp3::CreateUsageKeys Usage key creation failed"));
   3511 
   3512         return PVMFFailure;
   3513     }
   3514     return PVMFSuccess;
   3515 }
   3516 
   3517 void PVMFCPMContainerMp3::Cleanup()
   3518 {
   3519     //cleanup usage keys
   3520     if (iRequestedUsage.key)
   3521     {
   3522         OSCL_ARRAY_DELETE(iRequestedUsage.key);
   3523         iRequestedUsage.key = NULL;
   3524     }
   3525 
   3526     if (iApprovedUsage.key)
   3527     {
   3528         OSCL_ARRAY_DELETE(iApprovedUsage.key);
   3529         iApprovedUsage.key = NULL;
   3530     }
   3531 
   3532     if (iAuthorizationDataKvp.key)
   3533     {
   3534         OSCL_ARRAY_DELETE(iAuthorizationDataKvp.key);
   3535         iAuthorizationDataKvp.key = NULL;
   3536     }
   3537 
   3538     //cleanup cpm access
   3539     if (iCPMContentAccessFactory)
   3540     {
   3541         iCPMContentAccessFactory->removeRef();
   3542         iCPMContentAccessFactory = NULL;
   3543     }
   3544 
   3545 
   3546     //cleanup CPM object.
   3547     if (iCPM)
   3548     {
   3549         iCPM->ThreadLogoff();
   3550         PVMFCPMFactory::DestroyContentPolicyManager(iCPM);
   3551         iCPM = NULL;
   3552     }
   3553 }
   3554 
   3555 PVMFStatus PVMFCPMContainerMp3::IssueCommand(int32 aCmd)
   3556 {
   3557     // Issue a command to the sub-node.
   3558     // Return the sub-node completion status: either pending, success, or failure.
   3559     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3560                     (0, "PVMFCPMContainerMp3::IssueCommand In"));
   3561 
   3562     OSCL_ASSERT(iCmdState == EIdle && iCancelCmdState == EIdle);
   3563     // Find the current node command since we may need its parameters.
   3564     OSCL_ASSERT(!iContainer->iCurrentCommand.empty());
   3565     PVMFMP3FFParserNodeCommand* nodeCmd = &iContainer->iCurrentCommand.front();
   3566 
   3567     //save the sub-node command code
   3568     iCmd = aCmd;
   3569 
   3570     switch (aCmd)
   3571     {
   3572         case ECPMCleanup:
   3573             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3574                             (0, "PVMFCPMContainerMp3::IssueCommand Calling Cleanup"));
   3575             Cleanup();
   3576             return PVMFSuccess;
   3577 
   3578         case ECPMInit:
   3579             //make sure any prior instance is cleaned up
   3580             Cleanup();
   3581             //Create a CPM instance.
   3582             OSCL_ASSERT(iCPM == NULL);
   3583             iCPM = PVMFCPMFactory::CreateContentPolicyManager(*this);
   3584             if (!iCPM)
   3585             {
   3586                 return PVMFErrNoMemory;
   3587             }
   3588             //thread logon may leave if there are no plugins
   3589             int32 err;
   3590             OSCL_TRY(err, iCPM->ThreadLogon(););
   3591             if (err != OsclErrNone)
   3592             {
   3593                 //end the sequence now.
   3594                 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3595                                 (0, "PVMFCPMContainerMp3::IssueCommand No plugins, ending CPM sequence"));
   3596 
   3597                 iCPM->ThreadLogoff();
   3598                 PVMFCPMFactory::DestroyContentPolicyManager(iCPM);
   3599                 iCPM = NULL;
   3600 
   3601                 //treat it as unprotected content.
   3602                 PVMFStatus status = iContainer->CheckForMP3HeaderAvailability();
   3603                 return status;
   3604             }
   3605             else
   3606             {
   3607                 //continue the sequence
   3608                 iContainer->Push(*this, PVMFSubNodeContainerBaseMp3::ECPMOpenSession);
   3609                 iContainer->Push(*this, PVMFSubNodeContainerBaseMp3::ECPMRegisterContent);
   3610 
   3611                 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3612                                 (0, "PVMFCPMContainerMp3::IssueCommand Calling Init"));
   3613 
   3614                 iCmdState = EBusy;
   3615                 iCmdId = iCPM->Init();
   3616                 return PVMFPending;
   3617             }
   3618 
   3619         case ECPMOpenSession:
   3620             OSCL_ASSERT(iCPM != NULL);
   3621             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3622                             (0, "PVMFCPMContainerMp3::IssueCommand Calling OpenSession"));
   3623             iCmdState = EBusy;
   3624             iCmdId = iCPM->OpenSession(iSessionId);
   3625             return PVMFPending;
   3626 
   3627         case ECPMRegisterContent:
   3628             OSCL_ASSERT(iCPM != NULL);
   3629             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3630                             (0, "PVMFCPMContainerMp3::IssueCommand Calling RegisterContent"));
   3631             iCmdState = EBusy;
   3632             iCmdId = iCPM->RegisterContent(iSessionId,
   3633                                            iContainer->iSourceURL,
   3634                                            iContainer->iSourceFormat,
   3635                                            (OsclAny*) & iContainer->iCPMSourceData);
   3636             return PVMFPending;
   3637 
   3638         case ECPMGetLicenseInterface:
   3639             OSCL_ASSERT(iCPM != NULL);
   3640             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3641                             (0, "PVMFCPMContainerMp3::IssueCommand Calling GetCPMLicenseInterface"));
   3642             iCmdState = EBusy;
   3643             iCmdId = GetCPMLicenseInterface();
   3644             return PVMFPending;
   3645 
   3646         case ECPMGetLicenseW:
   3647         {
   3648             OSCL_ASSERT(iCPM != NULL);
   3649             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3650                             (0, "PVMFCPMContainerMp3::IssueCommand Calling ECPMGetLicenseW"));
   3651             iCmdState = EBusy;
   3652             OSCL_wString* contentName = NULL;
   3653             OsclAny* data = NULL;
   3654             uint32 dataSize = 0;
   3655             int32 timeoutMsec = 0;
   3656             iCPMLicenseInterface = OSCL_STATIC_CAST(PVMFCPMPluginLicenseInterface*, iCPMLicenseInterfacePVI);
   3657             iCPMLicenseInterfacePVI = NULL;
   3658             nodeCmd->Parse(contentName,
   3659                            data,
   3660                            dataSize,
   3661                            timeoutMsec);
   3662             iCmdId =
   3663                 iCPMLicenseInterface->GetLicense(iSessionId,
   3664                                                  *contentName,
   3665                                                  data,
   3666                                                  dataSize,
   3667                                                  timeoutMsec);
   3668             return PVMFPending;
   3669         }
   3670         case ECPMGetLicense:
   3671         {
   3672             OSCL_ASSERT(iCPM != NULL);
   3673             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3674                             (0, "PVMFCPMContainerMp3::IssueCommand Calling ECPMGetLicense"));
   3675 
   3676             iCmdState = EBusy;
   3677             OSCL_String* contentName = NULL;
   3678             OsclAny* data = NULL;
   3679             uint32 dataSize = 0;
   3680             int32 timeoutMsec = 0;
   3681             iCPMLicenseInterface = OSCL_STATIC_CAST(PVMFCPMPluginLicenseInterface*, iCPMLicenseInterfacePVI);
   3682             iCPMLicenseInterfacePVI = NULL;
   3683             nodeCmd->Parse(contentName,
   3684                            data,
   3685                            dataSize,
   3686                            timeoutMsec);
   3687             iCmdId =
   3688                 iCPMLicenseInterface->GetLicense(iSessionId,
   3689                                                  *contentName,
   3690                                                  data,
   3691                                                  dataSize,
   3692                                                  timeoutMsec);
   3693 
   3694             return PVMFPending;
   3695         }
   3696         case ECPMApproveUsage:
   3697         {
   3698             OSCL_ASSERT(iCPM != NULL);
   3699             GetCPMMetaDataExtensionInterface();
   3700             iCPMContentType = iCPM->GetCPMContentType(iSessionId);
   3701             if ((iCPMContentType == PVMF_CPM_FORMAT_OMA1) ||
   3702                     (iCPMContentType == PVMF_CPM_FORMAT_AUTHORIZE_BEFORE_ACCESS))
   3703             {
   3704                 iCmdState = EBusy;
   3705                 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3706                                 (0, "PVMFCPMContainerMp3::IssueCommand Calling ApproveUsage"));
   3707 
   3708                 //Create the usage keys
   3709                 {
   3710                     PVMFStatus status = CreateUsageKeys();
   3711                     if (status != PVMFSuccess)
   3712                     {
   3713                         return status;
   3714                     }
   3715                 }
   3716                 iCPM->GetContentAccessFactory(iSessionId, iCPMContentAccessFactory);
   3717 
   3718                 if (iContainer->iDataStreamReadCapacityObserver != NULL)
   3719                 {
   3720                     iCPMContentAccessFactory->SetStreamReadCapacityObserver(iContainer->iDataStreamReadCapacityObserver);
   3721                 }
   3722 
   3723                 iCmdId = iCPM->ApproveUsage(iSessionId,
   3724                                             iRequestedUsage,
   3725                                             iApprovedUsage,
   3726                                             iAuthorizationDataKvp,
   3727                                             iUsageID);
   3728                 iContainer->oWaitingOnLicense = true;
   3729                 return PVMFPending;
   3730             }
   3731             else
   3732             {
   3733                 /* Unsupported format - use it as unprotected content */
   3734                 PVMFStatus status = iContainer->CheckForMP3HeaderAvailability();
   3735                 return status;
   3736 
   3737             }
   3738             return PVMFSuccess;
   3739         }
   3740 
   3741         case ECPMCheckUsage:
   3742         {
   3743             iContainer->oWaitingOnLicense = false;
   3744             PVMFStatus status = PVMFFailure;
   3745             //Check for usage approval, and if approved, parse the file.
   3746             if ((iCPMContentType == PVMF_CPM_FORMAT_OMA1) ||
   3747                     (iCPMContentType == PVMF_CPM_FORMAT_AUTHORIZE_BEFORE_ACCESS))
   3748             {
   3749                 status = CheckApprovedUsage();
   3750                 if (status != PVMFSuccess)
   3751                 {
   3752                     return status;
   3753                 }
   3754                 if (!iCPMContentAccessFactory)
   3755                 {
   3756                     return PVMFFailure;//unexpected, since ApproveUsage succeeded.
   3757                 }
   3758                 status = iContainer->CheckForMP3HeaderAvailability();
   3759                 return status;
   3760             }
   3761 
   3762             return status;
   3763         }
   3764 
   3765 
   3766         case ECPMUsageComplete:
   3767             if ((iCPMContentType == PVMF_CPM_FORMAT_OMA1) ||
   3768                     (iCPMContentType == PVMF_CPM_FORMAT_AUTHORIZE_BEFORE_ACCESS))
   3769             {
   3770                 OSCL_ASSERT(iCPM != NULL);
   3771                 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3772                                 (0, "PVMFCPMContainerMp3::IssueCommand Calling UsageComplete"));
   3773 
   3774                 iCmdState = EBusy;
   3775                 iCmdId = iCPM->UsageComplete(iSessionId, iUsageID);
   3776                 return PVMFPending;
   3777             }
   3778             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3779                             (0, "PVMFCPMContainerMp3::IssueCommand Calling UsageComplete"));
   3780             return PVMFSuccess;
   3781 
   3782         case ECPMCloseSession:
   3783             OSCL_ASSERT(iCPM != NULL);
   3784             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3785                             (0, "PVMFCPMContainerMp3::IssueCommand Calling CloseSession"));
   3786             iCmdState = EBusy;
   3787             iCmdId = iCPM->CloseSession(iSessionId);
   3788             return PVMFPending;
   3789         case ECPMReset:
   3790             OSCL_ASSERT(iCPM != NULL);
   3791             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3792                             (0, "PVMFCPMContainerMp3::IssueCommand Calling Reset"));
   3793             iCmdState = EBusy;
   3794             iCmdId = iCPM->Reset();
   3795             return PVMFPending;
   3796         default:
   3797             OSCL_ASSERT(false);
   3798             return PVMFFailure;
   3799     }
   3800 }
   3801 
   3802 bool PVMFCPMContainerMp3::CancelPendingCommand()
   3803 {
   3804     // Initiate sub-node command cancel, return True if cancel initiated.
   3805     if (iCmdState != EBusy)
   3806     {
   3807         return false;//nothing to cancel
   3808     }
   3809     iCancelCmdState = EBusy;
   3810     //no cancel available, just wait on current command to complete.
   3811     //no cancel available except for GetLicense-- just wait on current command to complete.
   3812     if (iCmd == ECPMGetLicense || iCmd == ECPMGetLicenseW)
   3813     {
   3814         if (iCPM && iCPMLicenseInterface)
   3815         {
   3816             iCancelCmdId = iCPMLicenseInterface->CancelGetLicense(iSessionId, iCmdId);
   3817         }
   3818     }
   3819     return true;//cancel initiated
   3820 }
   3821 
   3822 /**
   3823  * From PVMFCPMStatusObserver: callback from the CPM object.
   3824  */
   3825 OSCL_EXPORT_REF void PVMFCPMContainerMp3::CPMCommandCompleted(const PVMFCmdResp& aResponse)
   3826 {
   3827     //A command to the CPM node is complete
   3828     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_STACK_TRACE,
   3829                     (0, "PVMFCPMContainerMp3::CPMCommandCompleted "));
   3830 
   3831     PVMFCommandId aCmdId = aResponse.GetCmdId();
   3832 
   3833     if (aCmdId == iCmdId && iCmdState == EBusy)
   3834     {
   3835         //this is decision point, if CPM does not care about the content
   3836         //skip rest of the CPM steps
   3837         if (iCmd == ECPMRegisterContent)
   3838         {
   3839             PVMFStatus status = aResponse.GetCmdStatus();
   3840             if (status == PVMFErrNotSupported)
   3841             {
   3842                 //if CPM comes back as PVMFErrNotSupported then by pass rest of the CPM
   3843                 //sequence. Fake success here so that node doesnt treat this as an error
   3844                 status = iContainer->CheckForMP3HeaderAvailability();
   3845             }
   3846             else if (status == PVMFSuccess)
   3847             {
   3848                 //proceed with rest of the CPM steps
   3849                 iContainer->Push(iContainer->iCPMContainer,
   3850                                  PVMFSubNodeContainerBaseMp3::ECPMGetLicenseInterface);
   3851                 iContainer->Push(iContainer->iCPMContainer,
   3852                                  PVMFSubNodeContainerBaseMp3::ECPMApproveUsage);
   3853                 iContainer->Push(iContainer->iCPMContainer,
   3854                                  PVMFSubNodeContainerBaseMp3::ECPMCheckUsage);
   3855             }
   3856             CommandDone(status,
   3857                         aResponse.GetEventExtensionInterface(),
   3858                         aResponse.GetEventData());
   3859         }
   3860         else
   3861         {
   3862             CommandDone(aResponse.GetCmdStatus(),
   3863                         aResponse.GetEventExtensionInterface(),
   3864                         aResponse.GetEventData());
   3865         }
   3866         //catch completion of cancel for CPM commands
   3867         //since there's no cancel to the CPM module, the cancel
   3868         //is done whenever the current CPM command is done.
   3869         if (iCancelCmdState != EIdle)
   3870         {
   3871             if (iCmd != ECPMGetLicense && iCmd != ECPMGetLicenseW)
   3872                 CancelCommandDone(PVMFSuccess, NULL, NULL);
   3873         }
   3874     }
   3875     else if (aResponse.GetCmdId() == iCancelCmdId
   3876              && iCancelCmdState == EBusy)
   3877     {
   3878         //Process node cancel command response
   3879         CancelCommandDone(aResponse.GetCmdStatus(), aResponse.GetEventExtensionInterface(), aResponse.GetEventData());
   3880     }
   3881     else if (aResponse.GetCmdId() == iContainer->iCPMGetMetaDataKeysCmdId)
   3882     {
   3883         // End of GetNodeMetaDataKeys
   3884         PVMFStatus status =
   3885             iContainer->CompleteGetMetadataKeys(iContainer->iCurrentCommand.front());
   3886         iContainer->CommandComplete(iContainer->iCurrentCommand,
   3887                                     iContainer->iCurrentCommand.front(),
   3888                                     status,
   3889                                     NULL,
   3890                                     NULL);
   3891     }
   3892     else if (aResponse.GetCmdId() == iContainer->iCPMGetMetaDataValuesCmdId)
   3893     {
   3894         // End of GetNodeMetaDataValues
   3895         iContainer->CommandComplete(iContainer->iCurrentCommand,
   3896                                     iContainer->iCurrentCommand.front(),
   3897                                     aResponse.GetCmdStatus(),
   3898                                     NULL,
   3899                                     NULL);
   3900     }
   3901     else
   3902     {
   3903         OSCL_ASSERT(false);//unexpected response
   3904     }
   3905 }
   3906 
   3907 void PVMFSubNodeContainerBaseMp3::CommandDone(PVMFStatus aStatus, PVInterface*aExtMsg,
   3908         OsclAny*aEventData)
   3909 {
   3910     // Sub-node command is completed, process the result.
   3911     OSCL_ASSERT(aStatus != PVMFPending);
   3912     // Pop the sub-node command vector.
   3913     OSCL_ASSERT(!iContainer->iSubNodeCmdVec.empty());
   3914     iContainer->iSubNodeCmdVec.erase(&iContainer->iSubNodeCmdVec.front());
   3915 
   3916     iCmdState = EIdle;
   3917     PVMFStatus status = aStatus;
   3918     //Check whether the node command is being cancelled.
   3919     if (iCancelCmdState != EIdle)
   3920     {
   3921         if (!iContainer->iSubNodeCmdVec.empty())
   3922         {
   3923             //even if this command succeeded, we want to report
   3924             //the node command status as cancelled since some sub-node
   3925             //commands were not yet issued.
   3926             status = PVMFErrCancelled;
   3927             //go into an error state since the command is partially completed
   3928             iContainer->SetState(EPVMFNodeError);
   3929         }
   3930     }
   3931     //figure out the next step in the sequence
   3932     //A node command is done when either all sub-node commands are
   3933     //done or when one fails.
   3934     if (status == PVMFSuccess && !iContainer->iSubNodeCmdVec.empty())
   3935     {
   3936         //The node needs to issue the next sub-node command.
   3937         iContainer->RunIfNotReady();
   3938     }
   3939     else
   3940     {
   3941         //node command is done.
   3942         OSCL_ASSERT(!iContainer->iCurrentCommand.empty());
   3943         iContainer->CommandComplete(iContainer->iCurrentCommand, iContainer->iCurrentCommand.front(), status, aExtMsg, aEventData);
   3944     }
   3945 }
   3946 
   3947 void PVMFSubNodeContainerBaseMp3::CancelCommandDone(PVMFStatus aStatus, PVInterface*aExtMsg, OsclAny*aEventData)
   3948 {
   3949     // Sub-node cancel command is done: process the result
   3950     OSCL_UNUSED_ARG(aExtMsg);
   3951     OSCL_UNUSED_ARG(aEventData);
   3952 
   3953     OSCL_ASSERT(aStatus != PVMFPending);
   3954     iCancelCmdState = EIdle;
   3955     //print and ignore any failed sub-node cancel commands.
   3956     if (aStatus != PVMFSuccess)
   3957     {
   3958         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_ERR, (0,
   3959                         "PVMFCPMContainerMp3::CancelCommandDone CPM Node Cancel failed"));
   3960     }
   3961 
   3962     //Node cancel command is now done.
   3963     OSCL_ASSERT(!iContainer->iCancelCommand.empty());
   3964     iContainer->CommandComplete(iContainer->iCancelCommand, iContainer->iCancelCommand.front(), aStatus, NULL, NULL);
   3965 }
   3966 
   3967 /**
   3968  * From PvmiDataStreamObserver: callback when the DataStreamCommand is completed
   3969  */
   3970 void PVMFMP3FFParserNode::DataStreamCommandCompleted(const PVMFCmdResp& aResponse)
   3971 {
   3972     if ((iCurrentCommand.empty() == false) &&
   3973             (iCurrentCommand.front().iCmd == PVMF_GENERIC_NODE_INIT))
   3974     {
   3975         PVMFStatus cmdStatus = PVMFFailure;
   3976         if (aResponse.GetCmdId() == iRequestReadCapacityNotificationID)
   3977         {
   3978             cmdStatus = aResponse.GetCmdStatus();
   3979             if (cmdStatus == PVMFSuccess)
   3980             {
   3981                 // set flag
   3982                 iCheckForMP3HeaderDuringInit = true;
   3983                 // Re-schedule the node
   3984                 RunIfNotReady();
   3985             }
   3986             else
   3987             {
   3988                 LOGINFO((0, "PVMFMP3FFParserNode::DataStreamCommandCompleted() RequestReadCapacityNotification failed %d", cmdStatus));
   3989                 // command init command with some kind of failure
   3990                 CompleteInit(cmdStatus);
   3991             }
   3992         }
   3993         return;
   3994     }
   3995     // Handle Autopause
   3996     if (iAutoPaused)
   3997     {
   3998         if (aResponse.GetCmdStatus() == PVMFSuccess)
   3999         {
   4000             if (iTrack.iState == PVMP3FFNodeTrackPortInfo::TRACKSTATE_DOWNLOAD_AUTOPAUSE)
   4001             {
   4002                 iTrack.iState = PVMP3FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_GETDATA;
   4003             }
   4004 
   4005             iAutoPaused = false;
   4006             // Re-schedule the node
   4007             RunIfNotReady();
   4008             return;
   4009         }
   4010         else
   4011         {
   4012             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFMP3FFParserNode::DataStreamReadCapacityNotificationCallBack() Reporting failure"));
   4013             ReportErrorEvent(PVMFErrResource, NULL);
   4014         }
   4015         return;
   4016     }
   4017     else
   4018     {
   4019         /* unrecognized callback */
   4020         OSCL_ASSERT(false);
   4021     }
   4022 }
   4023 
   4024 /**
   4025  * From PvmiDataStreamObserver: callback for info event from DataStream
   4026  */
   4027 void PVMFMP3FFParserNode::DataStreamInformationalEvent(const PVMFAsyncEvent& aEvent)
   4028 {
   4029     //if Datadownload is complete then send PVMFInfoBufferingComplete event from DS to parser node
   4030     if (aEvent.GetEventType() == PVMFInfoBufferingComplete)
   4031     {
   4032         iDownloadComplete = true;
   4033     }
   4034 }
   4035 
   4036 /**
   4037  * From PvmiDataStreamObserver: callback for error event from DataStream
   4038  */
   4039 void PVMFMP3FFParserNode::DataStreamErrorEvent(const PVMFAsyncEvent& aEvent)
   4040 {
   4041     OSCL_UNUSED_ARG(aEvent);
   4042     //Should never be called
   4043     OSCL_ASSERT(false);
   4044 }
   4045 
   4046 PVMFStatus PVMFMP3FFParserNode::CheckForMP3HeaderAvailability()
   4047 {
   4048 
   4049     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   4050                     (0, "PVMFMP3FFParserNode::CheckForMP3HeaderAvailability In"));
   4051     if (iMP3File == NULL)
   4052     {
   4053         PVMFStatus retval = SetupParserObject();
   4054         if (retval != PVMFSuccess)
   4055         {
   4056             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   4057                             (0, "PVMFMP3FFParserNode::CheckForMP3HeaderAvailability setup parser object failed."));
   4058             return retval;
   4059         }
   4060     }
   4061 
   4062     if (iDataStreamInterface != NULL)
   4063     {
   4064         uint32 minBytesRequired = 0;
   4065         if (iMP3File)
   4066         {
   4067             minBytesRequired = iMP3File->GetMinBytesRequired();
   4068         }
   4069 
   4070         /*
   4071          * First check if we have minimum number of bytes to recognize
   4072          * the file and determine the header size.
   4073          */
   4074         uint32 currCapacity = 0;
   4075         PvmiDataStreamStatus status = iDataStreamInterface->QueryReadCapacity(iDataStreamSessionID,
   4076                                       currCapacity);
   4077 
   4078         if ((PVDS_SUCCESS == status) && (currCapacity <  minBytesRequired))
   4079         {
   4080             iRequestReadCapacityNotificationID =
   4081                 iDataStreamInterface->RequestReadCapacityNotification(iDataStreamSessionID,
   4082                         *this,
   4083                         minBytesRequired);
   4084             return PVMFPending;
   4085         }
   4086 
   4087         MP3ErrorType retCode = MP3_ERROR_UNKNOWN;
   4088         if (iMP3File)
   4089         {
   4090 
   4091             if (iSourceFormat != PVMF_MIME_DATA_SOURCE_SHOUTCAST_URL)
   4092             {
   4093                 retCode = iMP3File->GetMetadataSize(iMP3MetaDataSize);
   4094                 if (retCode == MP3_SUCCESS)
   4095                 {
   4096                     /* Fetch the id3 tag size, if any and make it persistent in cache*/
   4097                     iDataStreamInterface->MakePersistent(0, iMP3MetaDataSize);
   4098                     if (currCapacity < iMP3MetaDataSize)
   4099                     {
   4100                         iRequestReadCapacityNotificationID =
   4101                             iDataStreamInterface->RequestReadCapacityNotification(iDataStreamSessionID,
   4102                                     *this,
   4103                                     iMP3MetaDataSize + minBytesRequired);
   4104                         return PVMFPending;
   4105                     }
   4106                 }
   4107                 else
   4108                 {
   4109                     iDataStreamInterface->MakePersistent(0, 0);
   4110                 }
   4111             }
   4112             else
   4113             {
   4114                 iDataStreamInterface->MakePersistent(0, 0);
   4115             }
   4116         }
   4117     }
   4118     PVMFStatus status = ParseFile();
   4119     return status;
   4120 }
   4121 
   4122 void PVMFMP3FFParserNode::GetCPMMetaDataKeys()
   4123 {
   4124     if (iCPMContainer.iCPMMetaDataExtensionInterface != NULL)
   4125     {
   4126         iCPMMetadataKeys.clear();
   4127         iCPMGetMetaDataKeysCmdId =
   4128             iCPMContainer.iCPMMetaDataExtensionInterface->GetNodeMetadataKeys(iCPMContainer.iSessionId,
   4129                     iCPMMetadataKeys,
   4130                     0,
   4131                     PVMF_MP3_PARSER_NODE_MAX_CPM_METADATA_KEYS);
   4132     }
   4133 }
   4134 
   4135 bool PVMFCPMContainerMp3::GetCPMMetaDataExtensionInterface()
   4136 {
   4137     PVInterface* temp = NULL;
   4138     bool retVal =
   4139         iCPM->queryInterface(KPVMFMetadataExtensionUuid, temp);
   4140     iCPMMetaDataExtensionInterface = OSCL_STATIC_CAST(PVMFMetadataExtensionInterface*, temp);
   4141     return retVal;
   4142 }
   4143 PVMp3DurationCalculator::PVMp3DurationCalculator(int32 aPriority, IMpeg3File* aMP3File, PVMFNodeInterface* aNode, bool aScanEnabled):
   4144         OsclTimerObject(aPriority, "PVMp3DurationCalculator"), iNode(aNode)
   4145 {
   4146     iErrorCode = MP3_SUCCESS;
   4147     iMP3File = aMP3File;
   4148     iScanComplete = false;
   4149     iScanEnabled = aScanEnabled;
   4150     if (!IsAdded())
   4151     {
   4152         AddToScheduler();
   4153     }
   4154 }
   4155 
   4156 PVMp3DurationCalculator::~PVMp3DurationCalculator()
   4157 {
   4158     if (IsAdded())
   4159     {
   4160         RemoveFromScheduler();
   4161     }
   4162 }
   4163 
   4164 void PVMp3DurationCalculator::ScheduleAO()
   4165 {
   4166     totalticks = 0;
   4167     if (iScanEnabled && iMP3File)
   4168     {
   4169         RunIfNotReady();
   4170     }
   4171 }
   4172 
   4173 void PVMp3DurationCalculator::Run()
   4174 {
   4175     // dont do the duration calculation scan in case of PS/PD
   4176     if (((PVMFMP3FFParserNode*)iNode)->iDownloadProgressInterface)
   4177     {
   4178         return;
   4179     }
   4180 
   4181     if (iErrorCode == MP3_DURATION_PRESENT)
   4182     {
   4183         // A valid duration is already present no need to scan the file, just send the duration event and return
   4184         iScanComplete = true;
   4185         int32 durationInMsec = iMP3File->GetDuration();
   4186         int32 leavecode = 0;
   4187         PVMFDurationInfoMessage* eventmsg = NULL;
   4188         OSCL_TRY(leavecode, eventmsg = OSCL_NEW(PVMFDurationInfoMessage, (durationInMsec)));
   4189         ((PVMFMP3FFParserNode*)iNode)->ReportInfoEvent(PVMFInfoDurationAvailable, NULL, OSCL_STATIC_CAST(PVInterface*, eventmsg));
   4190         if (eventmsg)
   4191         {
   4192             eventmsg->removeRef();
   4193         }
   4194         return;
   4195     }
   4196     if (iErrorCode != MP3_SUCCESS)
   4197     {
   4198         iScanComplete = true;
   4199         int32 durationInMsec = iMP3File->GetDuration();
   4200         int32 leavecode = 0;
   4201         PVMFDurationInfoMessage* eventmsg = NULL;
   4202         OSCL_TRY(leavecode, eventmsg = OSCL_NEW(PVMFDurationInfoMessage, (durationInMsec)));
   4203         ((PVMFMP3FFParserNode*)iNode)->ReportInfoEvent(PVMFInfoDurationAvailable, NULL, OSCL_STATIC_CAST(PVInterface*, eventmsg));
   4204         if (eventmsg)
   4205         {
   4206             eventmsg->removeRef();
   4207         }
   4208         return;
   4209     }
   4210     else if (!iScanComplete)
   4211     {
   4212         RunIfNotReady(PVMF3FF_DURATION_SCAN_AO_DELAY);
   4213     }
   4214     else
   4215     {
   4216         return;
   4217     }
   4218 
   4219     if (!(((PVMFMP3FFParserNode*)iNode)->iTrack.iSendBOS))
   4220     {
   4221         // Start the scan only when we have send first audio sample
   4222         iErrorCode = iMP3File->ScanMP3File(PVMF3FF_DEFAULT_NUM_OF_FRAMES * 5);
   4223     }
   4224 }
   4225 
   4226 PVMFStatus PVMFMP3FFParserNode::CreateMP3FileObject(MP3ErrorType &aSuccess, PVMFCPMPluginAccessInterfaceFactory*aCPM)
   4227 {
   4228     int32 leavecode = 0;
   4229     OSCL_TRY(leavecode, iMP3File = OSCL_NEW(IMpeg3File,
   4230                                             (iSourceURL, aSuccess,
   4231                                              &iFileServer, aCPM,
   4232                                              iFileHandle, false)));
   4233     OSCL_FIRST_CATCH_ANY(leavecode, return PVMFErrNoMemory);
   4234     return PVMFSuccess;
   4235 }
   4236 
   4237 PVMFStatus PVMFMP3FFParserNode::PushBackCPMMetadataKeys(PVMFMetadataList *&aKeyListPtr, uint32 aLcv)
   4238 {
   4239     int32 leavecode = 0;
   4240     OSCL_TRY(leavecode, aKeyListPtr->push_back(iCPMMetadataKeys[aLcv]));
   4241     OSCL_FIRST_CATCH_ANY(leavecode, PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFMP3FFParserNode::CompleteGetMetadataKeys() Memory allocation failure when copying metadata key")); return PVMFErrNoMemory);
   4242     return PVMFSuccess;
   4243 }
   4244 
   4245 #if PV_HAS_SHOUTCAST_SUPPORT_ENABLED
   4246 void PVMFMP3FFParserNode::MetadataUpdated(uint32 aMetadataSize)
   4247 {
   4248     if (!iMetadataVector.empty())
   4249     {
   4250         iMetadataVector.clear();
   4251     }
   4252 
   4253     iMetadataSize = aMetadataSize;
   4254     int32 leavecode = OsclErrNone;
   4255     PVMFMetadataInfoMessage* eventMsg = NULL;
   4256     // parse the metadata to a kvp vector
   4257     ParseShoutcastMetadata((char*) iMetadataBuf, iMetadataSize, iMetadataVector);
   4258     // create a info msg
   4259     OSCL_TRY(leavecode, eventMsg = OSCL_NEW(PVMFMetadataInfoMessage, (iMetadataVector)));
   4260     // report the info msg to observer
   4261     ReportInfoEvent(PVMFInfoMetadataAvailable, NULL, OSCL_STATIC_CAST(PVInterface*, eventMsg));
   4262 
   4263     uint32 i = 0;
   4264     //cleanup the metadata vector
   4265     while (i < iMetadataVector.size())
   4266     {
   4267         PvmiKvp kvp = iMetadataVector[i];
   4268         if (kvp.key)
   4269         {
   4270             OSCL_ARRAY_DELETE(kvp.key);
   4271             kvp.key = NULL;
   4272         }
   4273         if (kvp.value.pChar_value)
   4274         {
   4275             OSCL_ARRAY_DELETE(kvp.value.pChar_value);
   4276             kvp.value.pChar_value = NULL;
   4277         }
   4278         i++;
   4279     }
   4280 
   4281     while (!iMetadataVector.empty())
   4282     {
   4283         iMetadataVector.erase(iMetadataVector.begin());
   4284     }
   4285     if (eventMsg)
   4286     {
   4287         eventMsg->removeRef();
   4288     }
   4289 }
   4290 #endif
   4291 
   4292 PVMFStatus PVMFMP3FFParserNode::ParseShoutcastMetadata(char* aMetadataBuf, uint32 aMetadataSize, Oscl_Vector<PvmiKvp, OsclMemAllocator>& aKvpVector)
   4293 {
   4294     // parse shoutcast metadata
   4295     char* metadataPtr = NULL;
   4296     metadataPtr = (char*)oscl_malloc(aMetadataSize);
   4297     oscl_strncpy(metadataPtr, aMetadataBuf, aMetadataSize);
   4298 
   4299     char* bufPtr = metadataPtr;
   4300 
   4301     PvmiKvp kvp;
   4302 
   4303     char* key = NULL;
   4304     char* valueStr = NULL;
   4305     while (true)
   4306     {
   4307         key = bufPtr;
   4308         char* tmpPtr = oscl_strchr(bufPtr, '=');
   4309         if (NULL == tmpPtr)
   4310         {
   4311             break;
   4312         }
   4313         *tmpPtr = '\0';
   4314         valueStr = tmpPtr + 2; // skip 2 bytes. '=' & '''
   4315         tmpPtr = oscl_strchr(valueStr, ';');
   4316         if (NULL == tmpPtr)
   4317         {
   4318             break;
   4319         }
   4320         *(tmpPtr - 1) = '\0'; // remove '''
   4321         *tmpPtr = '\0';
   4322 
   4323         bufPtr = tmpPtr + 1;
   4324 
   4325         // make kvp from key & valueStr info
   4326         OSCL_StackString<128> keyStr;
   4327         keyStr = _STRLIT_CHAR("");
   4328 
   4329         if (!(oscl_strncmp(key, "StreamTitle", oscl_strlen("StreamTitle"))))
   4330         {
   4331             keyStr += _STRLIT_CHAR(KVP_KEY_TITLE);
   4332             keyStr += SEMI_COLON;
   4333             keyStr += _STRLIT_CHAR(KVP_VALTYPE_ISO88591_CHAR);
   4334         }
   4335         else if (!(oscl_strncmp(key, "StreamUrl", oscl_strlen("StreamUrl"))))
   4336         {
   4337             keyStr += _STRLIT_CHAR(KVP_KEY_DESCRIPTION);
   4338             keyStr += SEMI_COLON;
   4339             keyStr += _STRLIT_CHAR(KVP_VALTYPE_ISO88591_CHAR);
   4340         }
   4341         else
   4342         {
   4343             //not supported
   4344         }
   4345 
   4346         keyStr += NULL_CHARACTER;
   4347 
   4348         int32 keylen = oscl_strlen(keyStr.get_cstr());
   4349         int32 valuelen = oscl_strlen(valueStr);
   4350 
   4351         kvp.key = OSCL_ARRAY_NEW(char, (keylen + 1));
   4352         kvp.value.pChar_value = OSCL_ARRAY_NEW(char, (valuelen + 1));
   4353 
   4354         oscl_strncpy(kvp.key, keyStr.get_cstr(), keylen + 1);
   4355         oscl_strncpy(kvp.value.pChar_value, valueStr, valuelen + 1);
   4356 
   4357         aKvpVector.push_back(kvp);
   4358     }
   4359 
   4360     if (metadataPtr)
   4361     {
   4362         oscl_free(metadataPtr);
   4363         metadataPtr = NULL;
   4364     }
   4365     return PVMFSuccess;
   4366 }
   4367 
   4368 PVMFStatus PVMFMP3FFParserNode::SetupParserObject()
   4369 {
   4370     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   4371                     (0, "PVMFMP3FFParserNode:SetupParserObject() In"));
   4372 
   4373     if (iMP3File == NULL)
   4374     {
   4375         // Instantiate the IMpeg3File object, this class represents the mp3ff library
   4376         MP3ErrorType bSuccess = MP3_SUCCESS;
   4377 
   4378         PVMFDataStreamFactory* dsFactory = iCPMContainer.iCPMContentAccessFactory;
   4379         if ((dsFactory == NULL) && (iDataStreamFactory != NULL))
   4380         {
   4381 #if PV_HAS_SHOUTCAST_SUPPORT_ENABLED
   4382             if (iSourceFormat == PVMF_MIME_DATA_SOURCE_SHOUTCAST_URL && iSCSPFactory != NULL && iSCSP != NULL)
   4383             {
   4384 
   4385                 dsFactory = iSCSPFactory;
   4386                 iSCSP->RequestMetadataUpdates(iDataStreamSessionID, *this, iMetadataBufSize, iMetadataBuf);
   4387             }
   4388             else
   4389             {
   4390                 dsFactory = iDataStreamFactory;
   4391             }
   4392 #else
   4393             dsFactory = iDataStreamFactory;
   4394 #endif
   4395         }
   4396 
   4397         // Try block start
   4398         PVMFStatus returncode = CreateMP3FileObject(bSuccess, dsFactory);
   4399         // Try block end
   4400 
   4401         if ((returncode != PVMFSuccess) || !iMP3File || (bSuccess != MP3_SUCCESS))
   4402         {
   4403             // creation of IMpeg3File object failed or resulted in error
   4404             SetState(EPVMFNodeError);
   4405             return PVMFErrResource;
   4406         }
   4407     }
   4408 
   4409     // enable the duration scanner for local playback only
   4410     if (!iDataStreamFactory)
   4411     {
   4412         int32 leavecode = 0;
   4413         OSCL_TRY(leavecode, iDurationCalcAO = OSCL_NEW(PVMp3DurationCalculator,
   4414                                               (OsclActiveObject::EPriorityIdle, iMP3File, this)));
   4415         if (leavecode)
   4416         {
   4417             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
   4418                             (0, "PVMFMP3FFParserNode::DoInit() Duration Scan is disabled. DurationCalcAO not created"));
   4419         }
   4420 
   4421         if (iDurationCalcAO)
   4422         {
   4423             iDurationCalcAO->ScheduleAO();
   4424         }
   4425     }
   4426     return PVMFSuccess;
   4427 }
   4428 
   4429 
   4430