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
19#include "pvmf_downloadmanager_node.h"
20#include "pvmf_download_data_source.h"
21#include "pvmf_local_data_source.h"
22#include "pvmf_protocol_engine_factory.h"
23#include "pvmf_socket_factory.h"
24#include "pvmf_socket_node.h"
25#include "pvlogger.h"
26#include "oscl_error_codes.h"
27#include "oscl_str_ptr_len.h" // for OSCL_ASCII_CASE_MAGIC_BIT
28#include "pvmi_datastreamuser_interface.h"
29#include "pvpvxparser.h"
30#include "pv_mime_string_utils.h"
31#include "pvmi_kvp_util.h"
32#include "pvmf_source_context_data.h"
33
34//Log levels for node commands
35#define CMD_LOG_LEVEL PVLOGMSG_INFO
36//Log levels for subnode commands.
37#define SUB_CMD_LOG_LEVEL PVLOGMSG_INFO
38
39
40///////////////////////////////////////////////////////////////////////////////
41//
42// Capability and config interface related constants and definitions
43//   - based on pv_player_engine.h
44//
45///////////////////////////////////////////////////////////////////////////////
46
47static const DownloadManagerKeyStringData DownloadManagerConfig_BaseKeys[] =
48{
49    {"user-agent", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_WCHARPTR},
50    {"http-version", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_UINT32},
51    {"http-timeout", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_UINT32},
52    {"download-progress-info", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_CHARPTR},
53    {"protocol-extension-header", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_CHARPTR},
54    {"num-redirect-attempts", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_UINT32},
55    {"http-header-request-disabled", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_BOOL},
56    {"max-tcp-recv-buffer-size-download", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_UINT32},
57    {"max-tcp-recv-buffer-count-download", PVMI_KVPTYPE_VALUE, PVMI_KVPVALTYPE_UINT32}
58};
59
60static const uint DownloadManagerConfig_NumBaseKeys =
61    (sizeof(DownloadManagerConfig_BaseKeys) /
62     sizeof(DownloadManagerKeyStringData));
63
64enum BaseKeys_IndexMapType
65{
66    BASEKEY_SESSION_CONTROLLER_USER_AGENT = 0,
67    BASEKEY_SESSION_CONTROLLER_HTTP_VERSION,
68    BASEKEY_SESSION_CONTROLLER_HTTP_TIMEOUT,
69    BASEKEY_SESSION_CONTROLLER_DOWNLOAD_PROGRESS_INFO,
70    BASEKEY_SESSION_CONTROLLER_PROTOCOL_EXTENSION_HEADER,
71    BASEKEY_SESSION_CONTROLLER_NUM_REDIRECT_ATTEMPTS,
72    BASEKEY_SESSION_CONTROLLER_NUM_HTTP_HEADER_REQUEST_DISABLED,
73    BASEKEY_MAX_TCP_RECV_BUFFER_SIZE,
74    BASEKEY_MAX_TCP_RECV_BUFFER_COUNT
75};
76
77
78
79PVMFDownloadManagerNode::PVMFDownloadManagerNode(int32 aPriority)
80        : OsclActiveObject(aPriority, "PVMFDownloadManagerNode")
81{
82    int32 err;
83    OSCL_TRY(err, ConstructL(););
84    if (err != OsclErrNone)
85    {
86        //if a leave happened, cleanup and re-throw the error
87        iInputCommands.clear();
88        iCurrentCommand.clear();
89        iCancelCommand.clear();
90        iCapability.iInputFormatCapability.clear();
91        iCapability.iOutputFormatCapability.clear();
92        OSCL_CLEANUP_BASE_CLASS(PVMFNodeInterface);
93        OSCL_CLEANUP_BASE_CLASS(OsclActiveObject);
94        OSCL_LEAVE(err);
95    }
96
97    iDNodeUuids.clear();
98    iDNodeUuidCount = 0;
99}
100
101void PVMFDownloadManagerNode::ConstructL()
102{
103    iDebugMode = false;
104    iLogger = NULL;
105    iExtensionRefCount = 0;
106    iSourceFormat = PVMF_MIME_FORMAT_UNKNOWN;
107    iMimeType = PVMF_MIME_FORMAT_UNKNOWN;
108    iSourceData = NULL;
109    iPlayBackClock = NULL;
110    iClockNotificationsInf = NULL;
111
112    iNoPETrackSelect = false;
113    iMovieAtomComplete = false;
114    iParserInitAfterMovieAtom = false;
115    iParserPrepareAfterMovieAtom = false;
116
117    iParserInit = false;
118    iDataReady = false;
119    iDownloadComplete = false;
120    iRecognizerError = false;
121
122    iInitFailedLicenseRequired = false;
123
124    iProtocolEngineNodePort = NULL;
125    iSocketNodePort = NULL;
126    iPlayerNodeRegistry = NULL;
127
128    //create the sub-node command queue.  Use a reserve to avoid dynamic memory failure later.
129    //Max depth is the max number of sub-node commands for any one node command. Init command may take up to 15
130    iSubNodeCmdVec.reserve(15);
131
132    //Create the input command queue. Max depth is undetermined -- just reserve 10.
133    iInputCommands.Construct(1000 //start cmd id
134                             , 10);//reserve.
135
136    //Create the "current command" queue. Max depth is 1 for each of these.
137    iCurrentCommand.Construct(0, 1);
138    iCancelCommand.Construct(0, 1);
139
140    //create node containers.
141    //@TODO this will create unused node containers.  think about
142    //optimizing it.
143    iFormatParserNode.Construct(PVMFDownloadManagerSubNodeContainerBase::EFormatParser, this);
144    iProtocolEngineNode.Construct(PVMFDownloadManagerSubNodeContainerBase::EProtocolEngine, this);
145    iSocketNode.Construct(PVMFDownloadManagerSubNodeContainerBase::ESocket, this);
146    iRecognizerNode.Construct(PVMFDownloadManagerSubNodeContainerBase::ERecognizer, this);
147
148    //Set the node capability data.
149    iCapability.iCanSupportMultipleInputPorts = false;
150    iCapability.iCanSupportMultipleOutputPorts = true;
151    iCapability.iHasMaxNumberOfPorts = true;
152    iCapability.iMaxNumberOfPorts = 6;
153    iCapability.iInputFormatCapability.push_back(PVMF_MIME_MPEG4FF);
154    iCapability.iInputFormatCapability.push_back(PVMF_MIME_ASFFF);
155    iCapability.iInputFormatCapability.push_back(PVMF_MIME_RMFF);
156    iCapability.iOutputFormatCapability.push_back(PVMF_MIME_AMR_IETF);
157    iCapability.iOutputFormatCapability.push_back(PVMF_MIME_MPEG4_AUDIO);
158    iCapability.iOutputFormatCapability.push_back(PVMF_MIME_M4V);
159    iCapability.iOutputFormatCapability.push_back(PVMF_MIME_H2631998);
160    iCapability.iOutputFormatCapability.push_back(PVMF_MIME_H2632000);
161    iCapability.iOutputFormatCapability.push_back(PVMF_MIME_REAL_VIDEO);
162    iCapability.iOutputFormatCapability.push_back(PVMF_MIME_WMV);
163    iCapability.iOutputFormatCapability.push_back(PVMF_MIME_DIVXFF);
164
165    iFileBufferDatastreamFactory = NULL;
166#if(PVMF_DOWNLOADMANAGER_SUPPORT_PPB)
167    iMemoryBufferDatastreamFactory = NULL;
168#endif//PVMF_DOWNLOADMANAGER_SUPPORT_PPB
169
170    iDownloadFileName = NULL;
171    iContentTypeMIMEString = NULL;
172
173    iProtocolEngineNode.iNode = PVMFProtocolEngineNodeFactory::CreatePVMFProtocolEngineNode(OsclActiveObject::EPriorityNominal);
174    OsclError::LeaveIfNull(iProtocolEngineNode.iNode);
175    iProtocolEngineNode.Connect();
176
177    iSocketNode.iNode = PVMFSocketNodeFactory::CreatePVMFSocketNode(OsclActiveObject::EPriorityNominal);
178    OsclError::LeaveIfNull(iSocketNode.iNode);
179    iSocketNode.Connect();
180}
181
182PVMFDownloadManagerNode::~PVMFDownloadManagerNode()
183{
184    if (iPlayBackClock != NULL)
185    {
186        if (iClockNotificationsInf != NULL)
187        {
188            iClockNotificationsInf->RemoveClockStateObserver(*this);
189            iPlayBackClock->DestroyMediaClockNotificationsInterface(iClockNotificationsInf);
190        }
191    }
192
193    Cancel();
194    if (IsAdded())
195        RemoveFromScheduler();
196
197    //if any sub-node commands are outstanding, there will be
198    //a crash when they callback-- so panic here instead.
199
200    if (iFormatParserNode.CmdPending()
201            || iProtocolEngineNode.CmdPending()
202            || iSocketNode.CmdPending()
203            || iRecognizerNode.CmdPending()
204       )
205    {
206        OSCL_ASSERT(0);
207    }
208
209    //this is to ensure that there are no more callbacks from PE node to parser node,
210    //in case parser node had some outstanding request resume notifications
211    if (iProtocolEngineNode.DownloadProgress() != NULL)
212    {
213        (iProtocolEngineNode.DownloadProgress())->setFormatDownloadSupportInterface(NULL);
214    }
215
216    //make sure the subnodes got cleaned up
217    iFormatParserNode.Cleanup();
218    iProtocolEngineNode.Cleanup();
219    iSocketNode.Cleanup();
220    iRecognizerNode.Cleanup();
221
222    //delete the subnodes
223    if (iFormatParserNode.iNode)
224    {
225        iDNodeUuidCount--;
226
227        bool release_status = false;
228        int32 leavecode = 0;
229        OSCL_TRY(leavecode, release_status = iPlayerNodeRegistry->ReleaseNode(iDNodeUuids[iDNodeUuidCount], iFormatParserNode.iNode));
230        //ignore errors.
231        iDNodeUuids.clear();
232    }
233
234    if (iProtocolEngineNode.iNode)
235        PVMFProtocolEngineNodeFactory::DeletePVMFProtocolEngineNode(iProtocolEngineNode.iNode);
236
237    if (iSocketNode.iNode)
238        PVMFSocketNodeFactory::DeletePVMFSocketNode(iSocketNode.iNode);
239
240    // delete the data stream factory (This has to come after deleting anybody who uses it, like the protocol engine node or the parser node.)
241    if (iFileBufferDatastreamFactory)
242    {
243        OSCL_DELETE(iFileBufferDatastreamFactory);
244        iFileBufferDatastreamFactory = NULL;
245    }
246#if(PVMF_DOWNLOADMANAGER_SUPPORT_PPB)
247    if (iMemoryBufferDatastreamFactory)
248    {
249        OSCL_DELETE(iMemoryBufferDatastreamFactory);
250        iMemoryBufferDatastreamFactory = NULL;
251    }
252#endif//PVMF_DOWNLOADMANAGER_SUPPORT_PPB
253
254    //The command queues are self-deleting, but we want to notify the observer of unprocessed commands.
255    while (!iCurrentCommand.empty())
256        CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFFailure, NULL, NULL);
257    while (!iCancelCommand.empty())
258        CommandComplete(iCancelCommand, iCancelCommand.front(), PVMFFailure, NULL, NULL);
259    while (!iInputCommands.empty())
260        CommandComplete(iInputCommands, iInputCommands.front(), PVMFFailure, NULL, NULL);
261}
262
263//Public API From node interface.
264PVMFStatus PVMFDownloadManagerNode::ThreadLogon()
265{
266    if (iInterfaceState != EPVMFNodeCreated)
267        return PVMFErrInvalidState;
268
269    //logon this node.
270    if (!IsAdded())
271        AddToScheduler();
272
273    iLogger = PVLogger::GetLoggerObject("pvdownloadmanagernode");
274
275    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::ThreadLogon() called"));
276
277    //logon the sub-nodes.
278    if (iProtocolEngineNode.iNode)
279        iProtocolEngineNode.iNode->ThreadLogon();
280
281    if (iSocketNode.iNode)
282        iSocketNode.iNode->ThreadLogon();
283
284    ChangeNodeState(EPVMFNodeIdle);
285    return PVMFSuccess;
286}
287
288
289//Public API From node interface.
290PVMFStatus PVMFDownloadManagerNode::ThreadLogoff()
291{
292    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::ThreadLogoff() called"));
293
294    if (iInterfaceState != EPVMFNodeIdle)
295        return PVMFErrInvalidState;
296
297    //logoff this node.
298    if (IsAdded())
299        RemoveFromScheduler();
300
301    iLogger = NULL;
302
303    //logoff the sub-nodes.
304    if (iFormatParserNode.iNode)
305        iFormatParserNode.iNode->ThreadLogoff();
306    if (iProtocolEngineNode.iNode)
307        iProtocolEngineNode.iNode->ThreadLogoff();
308    if (iSocketNode.iNode)
309        iSocketNode.iNode->ThreadLogoff();
310
311    ChangeNodeState(EPVMFNodeCreated);
312    return PVMFSuccess;
313}
314
315
316//Public API From node interface.
317PVMFStatus PVMFDownloadManagerNode::GetCapability(PVMFNodeCapability& aNodeCapability)
318{
319    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::GetCapability() called"));
320
321    aNodeCapability = iCapability;
322
323    return PVMFSuccess;
324}
325
326
327//Public API From node interface.
328PVMFPortIter* PVMFDownloadManagerNode::GetPorts(const PVMFPortFilter* aFilter)
329{
330    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::GetPorts() called"));
331
332    if (iFormatParserNode.iNode)
333        return iFormatParserNode.iNode->GetPorts(aFilter);
334    return NULL;
335}
336
337
338//Public API From node interface.
339PVMFCommandId PVMFDownloadManagerNode::QueryUUID(PVMFSessionId aSessionId, const PvmfMimeString& aMimeType,
340        Oscl_Vector<PVUuid, OsclMemAllocator>& aUuids, bool aExactUuidsOnly, const OsclAny* aContext)
341{
342
343    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::QueryUUID() called"));
344
345    PVMFDownloadManagerNodeCommand cmd;
346    cmd.PVMFDownloadManagerNodeCommandBase::Construct(aSessionId, PVMF_GENERIC_NODE_QUERYUUID, aMimeType, aUuids, aExactUuidsOnly, aContext);
347    return QueueCommandL(cmd);
348}
349
350
351//Public API From node interface.
352PVMFCommandId PVMFDownloadManagerNode::QueryInterface(PVMFSessionId aSessionId, const PVUuid& aUuid,
353        PVInterface*& aInterfacePtr, const OsclAny* aContext)
354{
355    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::QueryInterface() called"));
356
357    PVMFDownloadManagerNodeCommand cmd;
358    cmd.PVMFDownloadManagerNodeCommandBase::Construct(aSessionId, PVMF_GENERIC_NODE_QUERYINTERFACE, aUuid, aInterfacePtr, aContext);
359    return QueueCommandL(cmd);
360}
361
362
363//Public API From node interface.
364PVMFCommandId PVMFDownloadManagerNode::RequestPort(PVMFSessionId aSessionId, int32 aPortTag,
365        const PvmfMimeString* aPortConfig, const OsclAny* aContext)
366{
367    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::RequestPort() called"));
368
369    PVMFDownloadManagerNodeCommand cmd;
370    cmd.PVMFDownloadManagerNodeCommandBase::Construct(aSessionId, PVMF_GENERIC_NODE_REQUESTPORT, aPortTag, aPortConfig, aContext);
371    return QueueCommandL(cmd);
372}
373
374
375//Public API From node interface.
376PVMFStatus PVMFDownloadManagerNode::ReleasePort(PVMFSessionId aSessionId, PVMFPortInterface& aPort, const OsclAny* aContext)
377{
378    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::ReleasePort() called"));
379
380    PVMFDownloadManagerNodeCommand cmd;
381    cmd.PVMFDownloadManagerNodeCommandBase::Construct(aSessionId, PVMF_GENERIC_NODE_RELEASEPORT, aPort, aContext);
382    return QueueCommandL(cmd);
383}
384
385
386//Public API From node interface.
387PVMFCommandId PVMFDownloadManagerNode::Init(PVMFSessionId aSessionId, const OsclAny* aContext)
388{
389    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::Init() called"));
390
391    PVMFDownloadManagerNodeCommand cmd;
392    cmd.PVMFDownloadManagerNodeCommandBase::Construct(aSessionId, PVMF_GENERIC_NODE_INIT, aContext);
393    return QueueCommandL(cmd);
394}
395
396
397//Public API From node interface.
398PVMFCommandId PVMFDownloadManagerNode::Prepare(PVMFSessionId aSessionId, const OsclAny* aContext)
399{
400    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::Prepare() called"));
401
402    PVMFDownloadManagerNodeCommand cmd;
403    cmd.PVMFDownloadManagerNodeCommandBase::Construct(aSessionId, PVMF_GENERIC_NODE_PREPARE, aContext);
404    return QueueCommandL(cmd);
405}
406
407
408//Public API From node interface.
409PVMFCommandId PVMFDownloadManagerNode::Start(PVMFSessionId aSessionId, const OsclAny* aContext)
410{
411    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::Start() called"));
412
413    PVMFDownloadManagerNodeCommand cmd;
414    cmd.PVMFDownloadManagerNodeCommandBase::Construct(aSessionId, PVMF_GENERIC_NODE_START, aContext);
415    return QueueCommandL(cmd);
416}
417
418
419//Public API From node interface.
420PVMFCommandId PVMFDownloadManagerNode::Stop(PVMFSessionId aSessionId, const OsclAny* aContext)
421{
422    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::Stop() called"));
423
424    PVMFDownloadManagerNodeCommand cmd;
425    cmd.PVMFDownloadManagerNodeCommandBase::Construct(aSessionId, PVMF_GENERIC_NODE_STOP, aContext);
426    return QueueCommandL(cmd);
427}
428
429
430//Public API From node interface.
431PVMFCommandId PVMFDownloadManagerNode::Flush(PVMFSessionId aSessionId, const OsclAny* aContext)
432{
433    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::Flush() called"));
434
435    PVMFDownloadManagerNodeCommand cmd;
436    cmd.PVMFDownloadManagerNodeCommandBase::Construct(aSessionId, PVMF_GENERIC_NODE_FLUSH, aContext);
437    return QueueCommandL(cmd);
438}
439
440
441//Public API From node interface.
442PVMFCommandId PVMFDownloadManagerNode::Pause(PVMFSessionId aSessionId, const OsclAny* aContext)
443{
444    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::Pause() called"));
445
446    PVMFDownloadManagerNodeCommand cmd;
447    cmd.PVMFDownloadManagerNodeCommandBase::Construct(aSessionId, PVMF_GENERIC_NODE_PAUSE, aContext);
448    return QueueCommandL(cmd);
449}
450
451
452//Public API From node interface.
453PVMFCommandId PVMFDownloadManagerNode::Reset(PVMFSessionId aSessionId, const OsclAny* aContext)
454{
455    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::Reset() called"));
456
457    PVMFDownloadManagerNodeCommand cmd;
458    cmd.PVMFDownloadManagerNodeCommandBase::Construct(aSessionId, PVMF_GENERIC_NODE_RESET, aContext);
459    return QueueCommandL(cmd);
460}
461
462
463//Public API From node interface.
464PVMFCommandId PVMFDownloadManagerNode::CancelAllCommands(PVMFSessionId aSessionId, const OsclAny* aContext)
465{
466    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::CancelAllCommands() called"));
467
468    PVMFDownloadManagerNodeCommand cmd;
469    cmd.PVMFDownloadManagerNodeCommandBase::Construct(aSessionId, PVMF_GENERIC_NODE_CANCELALLCOMMANDS, aContext);
470    return QueueCommandL(cmd);
471}
472
473
474//Public API From node interface.
475PVMFCommandId PVMFDownloadManagerNode::CancelCommand(PVMFSessionId aSessionId, PVMFCommandId aCmdId, const OsclAny* aContext)
476{
477    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::CancelCommand() called"));
478
479    PVMFDownloadManagerNodeCommand cmd;
480    cmd.PVMFDownloadManagerNodeCommandBase::Construct(aSessionId, PVMF_GENERIC_NODE_CANCELCOMMAND, aCmdId, aContext);
481    return QueueCommandL(cmd);
482}
483
484//public API from PVInterface
485void PVMFDownloadManagerNode::addRef()
486{
487    ++iExtensionRefCount;
488}
489
490//public API from PVInterface
491void PVMFDownloadManagerNode::removeRef()
492{
493    --iExtensionRefCount;
494}
495
496//public API from PVInterface
497bool PVMFDownloadManagerNode::queryInterface(const PVUuid& uuid, PVInterface*& iface)
498{
499    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::queryInterface() In"));
500
501    if (uuid == PVMF_TRACK_SELECTION_INTERFACE_UUID)
502    {
503        PVMFTrackSelectionExtensionInterface* myInterface = OSCL_STATIC_CAST(PVMFTrackSelectionExtensionInterface*, this);
504        iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
505    }
506    else if (uuid == PVMF_DATA_SOURCE_INIT_INTERFACE_UUID)
507    {
508        PVMFDataSourceInitializationExtensionInterface* myInterface = OSCL_STATIC_CAST(PVMFDataSourceInitializationExtensionInterface*, this);
509        iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
510    }
511    else if (uuid == KPVMFMetadataExtensionUuid)
512    {
513        PVMFMetadataExtensionInterface* myInterface = OSCL_STATIC_CAST(PVMFMetadataExtensionInterface*, this);
514        iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
515    }
516    else if (uuid == PVMF_DATA_SOURCE_NODE_REGISRTY_INIT_INTERFACE_UUID)
517    {
518        PVMFDataSourceNodeRegistryInitInterface* myInterface =
519            OSCL_STATIC_CAST(PVMFDataSourceNodeRegistryInitInterface*, this);
520        iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
521    }
522    else if (uuid == PvmfDataSourcePlaybackControlUuid)
523    {
524        PvmfDataSourcePlaybackControlInterface* myInterface = OSCL_STATIC_CAST(PvmfDataSourcePlaybackControlInterface*, this);
525        iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
526    }
527    else if (uuid == PVMI_CAPABILITY_AND_CONFIG_PVUUID)
528    {
529        PvmiCapabilityAndConfig* myInterface = OSCL_STATIC_CAST(PvmiCapabilityAndConfig*, this);
530        iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
531    }
532    else if (uuid == PVMFCPMPluginLicenseInterfaceUuid)
533    {
534        PVMFCPMPluginLicenseInterface* myInterface = OSCL_STATIC_CAST(PVMFCPMPluginLicenseInterface*, this);
535        iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
536    }
537    else
538    {
539        return false;
540    }
541
542    ++iExtensionRefCount;
543    return true;
544}
545
546
547//public API from data source initialization interface
548PVMFStatus PVMFDownloadManagerNode::SetSourceInitializationData(OSCL_wString& aSourceURL, PVMFFormatType& aSourceFormat, OsclAny* aSourceData)
549{
550    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::SetSourceInitializationData() called"));
551
552    //this method must be called before the Init command.
553    if (iInterfaceState != EPVMFNodeIdle && iInterfaceState != EPVMFNodeCreated)
554        return PVMFErrInvalidState;
555
556
557    // Pass the source info directly to the protocol engine node.
558
559    if (!iProtocolEngineNode.DataSourceInit())
560    {
561        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0,
562                        "PVMFDownloadManagerNode:SetSourceInitializationData() Can't find datasourceinit interface in protocol engine subnode container."));
563        return PVMFFailure; //no source init interface.
564    }
565
566    PVMFStatus status = (iProtocolEngineNode.DataSourceInit())->SetSourceInitializationData(aSourceURL, aSourceFormat, aSourceData);
567    if (status != PVMFSuccess)
568        return status;
569
570    if (!iProtocolEngineNode.ProtocolEngineExtension())
571    {
572        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0,
573                        "PVMFDownloadManagerNode:SetSourceInitializationData() Can't get ProtocolEngineExtension interface from protocol subnode container."));
574        return PVMFFailure; //no ProtocolNodeExtension interface.
575    }
576
577    bool socketConfigOK = (iProtocolEngineNode.ProtocolEngineExtension())->GetSocketConfig(iServerAddr);
578    if (!socketConfigOK)
579    {
580        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0,
581                        "PVMFDownloadManagerNode: SetSourceInitializationData() Call to GetSocketConfig() on protocol engine node returned failure."));
582        return PVMFErrProcessing;
583    }
584
585    if (aSourceFormat == PVMF_MIME_DATA_SOURCE_HTTP_URL)
586    {
587        if (!aSourceData)
588        {
589            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0,
590                            "PVMFDownloadManagerNode:SetSourceInitializationData() Missing source data"));
591            return PVMFErrArgument;
592        }
593        PVInterface* pvinterface = (PVInterface*)aSourceData;
594        PVUuid uuid(PVMF_DOWNLOAD_DATASOURCE_HTTP_UUID);
595        PVInterface* temp = NULL;
596        if (pvinterface->queryInterface(uuid, temp))
597        {
598            PVMFDownloadDataSourceHTTP* data = OSCL_STATIC_CAST(PVMFDownloadDataSourceHTTP*, temp);
599            //extract the download file name from the opaque data.
600            iDownloadFileName = data->iDownloadFileName;
601
602            //extract the playback mode
603            switch (data->iPlaybackControl)
604            {
605                case PVMFDownloadDataSourceHTTP::ENoPlayback:
606                    iPlaybackMode = EDownloadOnly;
607                    break;
608                case PVMFDownloadDataSourceHTTP::EAfterDownload:
609                    iPlaybackMode = EDownloadThenPlay;
610                    break;
611                case PVMFDownloadDataSourceHTTP::EAsap:
612                    iPlaybackMode = EPlayAsap;
613                    break;
614
615                case PVMFDownloadDataSourceHTTP::ENoSaveToFile:
616#if(PVMF_DOWNLOADMANAGER_SUPPORT_PPB)
617                    iPlaybackMode = EPlaybackOnly;
618                    break;
619#else
620                    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0,
621                                    "PVMFDownloadManagerNode:SetSourceInitializationData() NoSaveToFile is not supported!"));
622                    return PVMFErrArgument;//unsupported mode.
623#endif//PVMF_DOWNLOADMANAGER_SUPPORT_PPB
624
625                default:
626                    iPlaybackMode = EPlayAsap;
627                    break;
628            }
629        }
630        else
631        {
632            PVUuid uuid(PVMF_SOURCE_CONTEXT_DATA_DOWNLOAD_HTTP_UUID);
633            temp = NULL;
634            if (pvinterface->queryInterface(uuid, temp))
635            {
636                PVMFSourceContextDataDownloadHTTP* data = OSCL_STATIC_CAST(PVMFSourceContextDataDownloadHTTP*, temp);
637                //extract the download file name from the opaque data.
638                iDownloadFileName = data->iDownloadFileName;
639
640                //extract the playback mode
641                switch (data->iPlaybackControl)
642                {
643                    case PVMFSourceContextDataDownloadHTTP::ENoPlayback:
644                        iPlaybackMode = EDownloadOnly;
645                        break;
646                    case PVMFSourceContextDataDownloadHTTP::EAfterDownload:
647                        iPlaybackMode = EDownloadThenPlay;
648                        break;
649                    case PVMFSourceContextDataDownloadHTTP::EAsap:
650                        iPlaybackMode = EPlayAsap;
651                        break;
652
653                    case PVMFSourceContextDataDownloadHTTP::ENoSaveToFile:
654#if(PVMF_DOWNLOADMANAGER_SUPPORT_PPB)
655                        iPlaybackMode = EPlaybackOnly;
656                        break;
657#else
658                        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0,
659                                        "PVMFDownloadManagerNode:SetSourceInitializationData() NoSaveToFile is not supported!"));
660                        return PVMFErrArgument;//unsupported mode.
661#endif//PVMF_DOWNLOADMANAGER_SUPPORT_PPB
662
663                    default:
664                        iPlaybackMode = EPlayAsap;
665                        break;
666                }
667            }
668            else
669            {//invalid source data
670                return PVMFErrArgument;
671            }
672        }
673    }
674    else if (aSourceFormat == PVMF_MIME_DATA_SOURCE_PVX_FILE)
675    {
676        if (!aSourceData)
677        {
678            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0,
679                            "PVMFDownloadManagerNode:SetSourceInitializationData() Missing source data"));
680            return PVMFErrArgument;
681        }
682        PVInterface* pvinterface = (PVInterface*)aSourceData;
683        PVUuid uuid(PVMF_DOWNLOAD_DATASOURCE_PVX_UUID);
684        PVInterface* temp = NULL;
685        if (pvinterface->queryInterface(uuid, temp))
686        {
687            PVMFDownloadDataSourcePVX* data = OSCL_STATIC_CAST(PVMFDownloadDataSourcePVX*, temp);
688            iDownloadFileName = data->iDownloadFileName;
689            //get the playback mode from the PVX info
690            switch (data->iPvxInfo.iPlaybackControl)
691            {
692                case CPVXInfo::ENoPlayback:
693                    iPlaybackMode = EDownloadOnly;
694                    break;
695                case CPVXInfo::EAfterDownload:
696                    iPlaybackMode = EDownloadThenPlay;
697                    break;
698                case CPVXInfo::EAsap:
699                    iPlaybackMode = EPlayAsap;
700                    break;
701                default:
702                    iPlaybackMode = EPlayAsap;
703                    break;
704            }
705        }
706        else
707        {
708            PVUuid uuid(PVMF_SOURCE_CONTEXT_DATA_DOWNLOAD_PVX_UUID);
709            temp = NULL;
710            if (pvinterface->queryInterface(uuid, temp))
711            {
712                PVMFSourceContextDataDownloadPVX* data = OSCL_STATIC_CAST(PVMFSourceContextDataDownloadPVX*, temp);
713                iDownloadFileName = data->iDownloadFileName;
714                if (!data->iPvxInfo)
715                {//invalid source data
716                    return PVMFErrArgument;
717                }
718                //get the playback mode from the PVX info
719                switch (data->iPvxInfo->iPlaybackControl)
720                {
721                    case CPVXInfo::ENoPlayback:
722                        iPlaybackMode = EDownloadOnly;
723                        break;
724                    case CPVXInfo::EAfterDownload:
725                        iPlaybackMode = EDownloadThenPlay;
726                        break;
727                    case CPVXInfo::EAsap:
728                        iPlaybackMode = EPlayAsap;
729                        break;
730                    default:
731                        iPlaybackMode = EPlayAsap;
732                        break;
733                }
734            }
735            else
736            {//invalid source data
737                return PVMFErrArgument;
738            }
739        }
740    }
741    else if (aSourceFormat == PVMF_MIME_DATA_SOURCE_SHOUTCAST_URL)
742    {
743        if (!aSourceData)
744        {
745            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0,
746                            "PVMFDownloadManagerNode:SetSourceInitializationData() Missing source data"));
747            return PVMFErrArgument;
748        }
749        PVInterface* pvinterface = (PVInterface*)aSourceData;
750        PVUuid uuid(PVMF_DOWNLOAD_DATASOURCE_HTTP_UUID);
751        PVInterface* temp = NULL;
752        if (pvinterface->queryInterface(uuid, temp))
753        {
754            PVMFDownloadDataSourceHTTP* data = OSCL_STATIC_CAST(PVMFDownloadDataSourceHTTP*, temp);
755
756            //extract the download file name from the opaque data.
757            iDownloadFileName = data->iDownloadFileName;
758
759            //extract the playback mode
760            switch (data->iPlaybackControl)
761            {
762                case PVMFDownloadDataSourceHTTP::ENoSaveToFile:
763
764#if(PVMF_DOWNLOADMANAGER_SUPPORT_PPB)
765                    iPlaybackMode = EPlaybackOnly;
766                    break;
767#else
768                    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0,
769                                    "PVMFDownloadManagerNode:SetSourceInitializationData() NoSaveToFile is not supported!"));
770                    return PVMFErrArgument;//unsupported mode.
771#endif//PVMF_DOWNLOADMANAGER_SUPPORT_PPB
772
773                default:
774
775                    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0,
776                                    "PVMFDownloadManagerNode:SetSourceInitializationData() Only NoSaveToFile mode is supported for PVMF_MIME_DATA_SOURCE_SHOUTCAST_URL!"));
777                    return PVMFErrArgument;//unsupported mode.
778                    break;
779            }
780        }
781        else
782        {
783            PVUuid uuid(PVMF_SOURCE_CONTEXT_DATA_DOWNLOAD_HTTP_UUID);
784            if (pvinterface->queryInterface(uuid, temp))
785            {
786                PVMFSourceContextDataDownloadHTTP* data = OSCL_STATIC_CAST(PVMFSourceContextDataDownloadHTTP*, temp);
787                //extract the download file name from the opaque data.
788                iDownloadFileName = data->iDownloadFileName;
789
790                //extract the playback mode
791                switch (data->iPlaybackControl)
792                {
793                    case PVMFSourceContextDataDownloadHTTP::ENoSaveToFile:
794
795#if(PVMF_DOWNLOADMANAGER_SUPPORT_PPB)
796                        iPlaybackMode = EPlaybackOnly;
797                        break;
798#else
799                        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0,
800                                        "PVMFDownloadManagerNode:SetSourceInitializationData() NoSaveToFile is not supported!"));
801                        return PVMFErrArgument;//unsupported mode.
802#endif//PVMF_DOWNLOADMANAGER_SUPPORT_PPB
803
804                    default:
805                        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0,
806                                        "PVMFDownloadManagerNode:SetSourceInitializationData() Only NoSaveToFile mode is supported for PVMF_MIME_DATA_SOURCE_SHOUTCAST_URL!"));
807                        return PVMFErrArgument;//unsupported mode.
808                        break;
809                }
810            }
811            else
812            {//invalid source data
813                return PVMFErrArgument;
814            }
815        }
816    }
817    else
818    {
819        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0,
820                        "PVMFDownloadManagerNode:SetSourceInitializationData() Unsupported source type"));
821        return PVMFErrArgument;
822    }
823
824#if(PVMF_DOWNLOADMANAGER_SUPPORT_PPB)
825    //Configure the MBDS
826    if (iPlaybackMode == EPlaybackOnly)
827    {
828        // make sure we have enough TCP buffers for PPB and shoutcast
829        if (aSourceFormat == PVMF_MIME_DATA_SOURCE_SHOUTCAST_URL)
830        {
831            // calculate MBDS cache size in bytes
832            // max bitrate in bytes per second * cache size in secs
833            uint32 bitRate = PVMF_DOWNLOADMANAGER_MAX_BITRATE_FOR_SC * 1000 / 8;
834            uint32 cacheSize = bitRate * PVMF_DOWNLOADMANAGER_CACHE_SIZE_FOR_SC_IN_SECONDS;
835
836            if (iSocketNode.iNode)
837            {
838                // TCP buffer size for shoutcast is 1564 (1500 data + 64 overhead)
839                // add 1 second margin
840                ((PVMFSocketNode*)iSocketNode.iNode)->SetMaxTCPRecvBufferCount((cacheSize + bitRate) / PVMF_DOWNLOADMANAGER_TCP_BUFFER_SIZE_FOR_SC);
841
842                ((PVMFSocketNode*)iSocketNode.iNode)->SetMaxTCPRecvBufferSize(PVMF_DOWNLOADMANAGER_TCP_BUFFER_SIZE_FOR_SC + PVMF_DOWNLOADMANAGER_TCP_BUFFER_OVERHEAD);
843            }
844
845            // Use Memory Buffer Data Stream for progressive playback and Shoutcast
846            iMemoryBufferDatastreamFactory = OSCL_NEW(PVMFMemoryBufferDataStream, (aSourceFormat, cacheSize));
847        }
848        else
849        {
850            uint32 bufSize = PVMF_DOWNLOADMANAGER_TCP_BUFFER_SIZE_FOR_PPB;
851            if (iSocketNode.iNode)
852            {
853                ((PVMFSocketNode*)iSocketNode.iNode)->SetMaxTCPRecvBufferCount(PVMF_DOWNLOADMANAGER_MIN_TCP_BUFFERS_FOR_PPB);
854                // get buffer size
855                ((PVMFSocketNode*)iSocketNode.iNode)->GetMaxTCPRecvBufferSize(bufSize);
856            }
857
858            // MBDS cache size calculation
859            // TCP buffer size is 64000 (the default), assume worst case that the average packet size is 250 bytes
860            // Packet overhead is 64 bytes per packet
861            // 8 buffers will yield a cache of 305500, 13 buffers will yield a cache of 560500
862            uint32 totalPoolSizeMinusTwoBuffers = (PVMF_DOWNLOADMANAGER_MIN_TCP_BUFFERS_FOR_PPB - PVMF_DOWNLOADMANAGER_TCP_BUFFER_NOT_AVAILABLE) * bufSize;
863            uint32 numPacketsToFitInPool = totalPoolSizeMinusTwoBuffers / (PVMF_DOWNLOADMANAGER_TCP_AVG_SMALL_PACKET_SIZE + PVMF_DOWNLOADMANAGER_TCP_BUFFER_OVERHEAD);
864            uint32 maxDataMinusOverheadInPool = numPacketsToFitInPool * PVMF_DOWNLOADMANAGER_TCP_AVG_SMALL_PACKET_SIZE;
865
866            // Use Memory Buffer Data Stream for progressive playback and Shoutcast
867            iMemoryBufferDatastreamFactory = OSCL_NEW(PVMFMemoryBufferDataStream, (aSourceFormat, maxDataMinusOverheadInPool));
868        }
869
870        OSCL_ASSERT(iMemoryBufferDatastreamFactory != NULL);
871
872        iReadFactory  = iMemoryBufferDatastreamFactory->GetReadDataStreamFactoryPtr();
873        iWriteFactory = iMemoryBufferDatastreamFactory->GetWriteDataStreamFactoryPtr();
874    }
875    else
876#endif//PVMF_DOWNLOADMANAGER_SUPPORT_PPB
877    {
878        // Now that we have the download file name, we can instantiate the file buffer data stream object
879        // Create the filebuffer data stream factory
880        iFileBufferDatastreamFactory = OSCL_NEW(PVMFFileBufferDataStream, (iDownloadFileName));
881        OSCL_ASSERT(iFileBufferDatastreamFactory != NULL);
882        iReadFactory  = iFileBufferDatastreamFactory->GetReadDataStreamFactoryPtr();
883        iWriteFactory = iFileBufferDatastreamFactory->GetWriteDataStreamFactoryPtr();
884    }
885
886//save the source info
887    iSourceFormat = aSourceFormat;
888    iSourceURL = aSourceURL;
889    iSourceData = aSourceData;
890
891    return PVMFSuccess;
892}
893
894//public API from data source initialization interface
895PVMFStatus PVMFDownloadManagerNode::SetClientPlayBackClock(PVMFMediaClock* aClientClock)
896{
897    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::SetClientPlayBackClock() called"));
898
899    iPlayBackClock = aClientClock;
900    if (iPlayBackClock)
901    {
902        iPlayBackClock->ConstructMediaClockNotificationsInterface(iClockNotificationsInf, *this);
903    }
904
905    if (iClockNotificationsInf != NULL)
906    {
907        iClockNotificationsInf->SetClockStateObserver(*this);
908    }
909
910    //pass the source info directly to the download node.
911    if (NULL == iProtocolEngineNode.DataSourceInit())
912        return PVMFFailure;//no source init interface.
913
914    PVMFStatus status = (iProtocolEngineNode.DataSourceInit())->SetClientPlayBackClock(aClientClock);
915
916    return status;
917}
918
919//public API from data source initialization interface
920PVMFStatus PVMFDownloadManagerNode::SetEstimatedServerClock(PVMFMediaClock*)
921{
922    //not needed for download.
923    return PVMFErrNotSupported;
924}
925
926PVMFDownloadManagerSubNodeContainer& PVMFDownloadManagerNode::TrackSelectNode()
927{
928    //Decide which sub-node is supporting track selection.
929    if (iSourceFormat == PVMF_MIME_DATA_SOURCE_PVX_FILE)
930    {
931        //for pvx file, the PE node may or may not do track selection.
932        //the final decision isn't available until PE node prepare is done
933        //and we've queried for the TS interface, at which point the
934        //iNoPETrackSelect may be set.
935        if (iNoPETrackSelect)
936            return iFormatParserNode;
937
938        //if download is already complete, such as after a stop, then
939        //the parser node will do track selection.
940        if (iDownloadComplete && iPlaybackMode != EDownloadOnly)
941            return iFormatParserNode;
942
943        return iProtocolEngineNode;
944    }
945    else
946    {
947        //for 3gpp & shoutcast, parser does track selection.
948        return iFormatParserNode;
949    }
950}
951
952//Public API From track selection interface.
953PVMFStatus PVMFDownloadManagerNode::GetMediaPresentationInfo(PVMFMediaPresentationInfo& aInfo)
954{
955    //this is assumed to happen only after node initialization.
956    if (iInterfaceState != EPVMFNodeInitialized && iInterfaceState != EPVMFNodePrepared)
957        return PVMFErrInvalidState;
958
959    if (TrackSelectNode().TrackSelection())
960        return (TrackSelectNode().TrackSelection())->GetMediaPresentationInfo(aInfo);
961    else
962        return PVMFFailure; //no track selection interface!
963}
964
965//Public API From track selection interface.
966PVMFStatus PVMFDownloadManagerNode::SelectTracks(PVMFMediaPresentationInfo& aInfo)
967{
968    //this needs to happen after initialization.
969    if (iInterfaceState != EPVMFNodeInitialized && iInterfaceState != EPVMFNodePrepared)
970        return PVMFErrInvalidState;
971
972    if (TrackSelectNode().TrackSelection())
973        return (TrackSelectNode().TrackSelection())->SelectTracks(aInfo);
974    else
975        return PVMFFailure;//no track selection interface!
976}
977
978
979uint32 PVMFDownloadManagerNode::GetNumMetadataKeys(char* query_key)
980{
981    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::GetNumMetadataKeys() called"));
982    if (iFormatParserNode.Metadata())
983    {
984        return (iFormatParserNode.Metadata())->GetNumMetadataKeys(query_key);
985    }
986    return 0;
987}
988
989uint32 PVMFDownloadManagerNode::GetNumMetadataValues(PVMFMetadataList& aKeyList)
990{
991    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::GetNumMetadataValues() called"));
992    if (iFormatParserNode.Metadata())
993    {
994        return (iFormatParserNode.Metadata())->GetNumMetadataValues(aKeyList);
995    }
996    return 0;
997}
998
999
1000PVMFCommandId PVMFDownloadManagerNode::GetNodeMetadataKeys(PVMFSessionId aSessionId, PVMFMetadataList& aKeyList, uint32 starting_index, int32 max_entries, char* query_key, const OsclAny* aContext)
1001{
1002    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::GetNodeMetadataKeys() called"));
1003
1004    PVMFDownloadManagerNodeCommand cmd;
1005    cmd.PVMFDownloadManagerNodeCommand::Construct(aSessionId, PVDLM_NODE_CMD_GETNODEMETADATAKEY, aKeyList, starting_index, max_entries, query_key, aContext);
1006    return QueueCommandL(cmd);
1007}
1008
1009
1010PVMFCommandId PVMFDownloadManagerNode::GetNodeMetadataValues(PVMFSessionId aSessionId, PVMFMetadataList& aKeyList, Oscl_Vector<PvmiKvp, OsclMemAllocator>& aValueList, uint32 starting_index, int32 max_entries, const OsclAny* aContext)
1011{
1012    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::GetNodeMetadataValue() called"));
1013
1014    PVMFDownloadManagerNodeCommand cmd;
1015    cmd.PVMFDownloadManagerNodeCommand::Construct(aSessionId, PVDLM_NODE_CMD_GETNODEMETADATAVALUE, aKeyList, aValueList, starting_index, max_entries, aContext);
1016    return QueueCommandL(cmd);
1017}
1018
1019// From PVMFMetadataExtensionInterface
1020PVMFStatus PVMFDownloadManagerNode::ReleaseNodeMetadataKeys(PVMFMetadataList& keys,
1021        uint32 start ,
1022        uint32 end)
1023{
1024    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::ReleaseNodeMetadataKeys() called"));
1025    if (iFormatParserNode.Metadata())
1026    {
1027        return iFormatParserNode.Metadata()->ReleaseNodeMetadataKeys(keys, start, end);
1028    }
1029    return PVMFFailure;
1030}
1031
1032// From PVMFMetadataExtensionInterface
1033PVMFStatus PVMFDownloadManagerNode::ReleaseNodeMetadataValues(Oscl_Vector<PvmiKvp, OsclMemAllocator>& aValueList,
1034        uint32 start,
1035        uint32 end)
1036{
1037    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::ReleaseNodeMetadataValues() called"));
1038
1039    if (iFormatParserNode.Metadata())
1040    {
1041        return iFormatParserNode.Metadata()->ReleaseNodeMetadataValues(aValueList, start, end);
1042    }
1043    return PVMFFailure;
1044}
1045
1046//public API from data source playback interface
1047PVMFCommandId PVMFDownloadManagerNode::SetDataSourcePosition(PVMFSessionId aSessionId, PVMFTimestamp aTargetNPT,
1048        PVMFTimestamp& aActualNPT,
1049        PVMFTimestamp& aActualMediaDataTS,
1050        bool aSeekToSyncPoint,
1051        uint32 aStreamID,
1052        OsclAny* aContext)
1053{
1054    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
1055                    (0, "PVMFDownloadManagerNode::SetDataSourcePosition: aTargetNPT=%d, aSeekToSyncPoint=%d, aContext=0x%x",
1056                     aTargetNPT, aSeekToSyncPoint, aContext));
1057
1058    PVMFDownloadManagerNodeCommand cmd;
1059    cmd.PVMFDownloadManagerNodeCommand::Construct(aSessionId, PVDLM_NODE_CMD_SETDATASOURCEPOSITION, aTargetNPT, aActualNPT,
1060            aActualMediaDataTS, aSeekToSyncPoint, aStreamID, aContext);
1061    return QueueCommandL(cmd);
1062}
1063
1064PVMFCommandId PVMFDownloadManagerNode::QueryDataSourcePosition(PVMFSessionId aSessionId,
1065        PVMFTimestamp aTargetNPT,
1066        PVMFTimestamp& aSeekPointBeforeTargetNPT,
1067        PVMFTimestamp& aSeekPointAfterTargetNPT,
1068        OsclAny* aContextData,
1069        bool aSeekToSyncPoint)
1070{
1071    OSCL_UNUSED_ARG(aSeekPointAfterTargetNPT);
1072    // Implemented to complete interface file definition
1073    // Not tested on logical plane
1074    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
1075                    (0, "PVMFDownloadManagerNode::QueryDataSourcePosition: aTargetNPT=%d, aSeekToSyncPoint=%d, aContext=0x%x", aTargetNPT,
1076                     aContextData, aSeekToSyncPoint));
1077
1078    PVMFDownloadManagerNodeCommand cmd;
1079    cmd.PVMFDownloadManagerNodeCommand::Construct(aSessionId, PVDLM_NODE_CMD_QUERYDATASOURCEPOSITION, aTargetNPT, aSeekPointBeforeTargetNPT,
1080            aSeekToSyncPoint, aContextData);
1081    return QueueCommandL(cmd);
1082}
1083
1084PVMFCommandId PVMFDownloadManagerNode::QueryDataSourcePosition(PVMFSessionId aSessionId, PVMFTimestamp aTargetNPT,
1085        PVMFTimestamp& aActualNPT,
1086        bool aSeekToSyncPoint,
1087        OsclAny* aContext)
1088{
1089    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
1090                    (0, "PVMFDownloadManagerNode::QueryDataSourcePosition: aTargetNPT=%d, aSeekToSyncPoint=%d, aContext=0x%x",
1091                     aTargetNPT, aSeekToSyncPoint, aContext));
1092
1093    PVMFDownloadManagerNodeCommand cmd;
1094    cmd.PVMFDownloadManagerNodeCommand::Construct(aSessionId, PVDLM_NODE_CMD_QUERYDATASOURCEPOSITION, aTargetNPT, aActualNPT,
1095            aSeekToSyncPoint, aContext);
1096    return QueueCommandL(cmd);
1097}
1098
1099
1100PVMFCommandId PVMFDownloadManagerNode::SetDataSourceRate(PVMFSessionId aSessionId, int32 aRate, PVMFTimebase* aTimebase, OsclAny* aContext)
1101{
1102    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
1103                    (0, "PVMFDownloadManagerNode::SetDataSourceRate: aRate=%d", aRate));
1104
1105    PVMFDownloadManagerNodeCommand cmd;
1106    cmd.PVMFDownloadManagerNodeCommand::Construct(aSessionId, PVDLM_NODE_CMD_SETDATASOURCERATE, aRate, aTimebase, aContext);
1107    return QueueCommandL(cmd);
1108}
1109
1110PVMFStatus PVMFDownloadManagerNode::SetPlayerNodeRegistry(PVPlayerNodeRegistryInterface* aRegistry)
1111{
1112    iPlayerNodeRegistry = aRegistry;
1113    return PVMFSuccess;
1114}
1115
1116void PVMFDownloadManagerNode::Run()
1117{
1118    //Process async node commands.
1119    if (!iInputCommands.empty())
1120        ProcessCommand();
1121
1122    //Issue commands to the sub-nodes.
1123    if (!iProtocolEngineNode.CmdPending()
1124            && !iFormatParserNode.CmdPending()
1125            && !iSocketNode.CmdPending()
1126            && !iRecognizerNode.CmdPending()
1127            && !iSubNodeCmdVec.empty())
1128    {
1129        PVMFStatus status = iSubNodeCmdVec.front().iNC->IssueCommand(iSubNodeCmdVec.front().iCmd);
1130        if (status != PVMFPending)
1131            iSubNodeCmdVec.front().iNC->CommandDone(status, NULL, NULL);
1132    }
1133}
1134
1135PVMFCommandId PVMFDownloadManagerNode::QueueCommandL(PVMFDownloadManagerNodeCommand& aCmd)
1136{
1137    //add a command to the async node command queue and return command ID
1138
1139    PVMFCommandId id = iInputCommands.AddL(aCmd);
1140
1141    // Wakeup the AO
1142    RunIfNotReady();
1143
1144    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::QueueCommandL() returning %d", id));
1145
1146    return id;
1147}
1148
1149void PVMFDownloadManagerNode::ProcessCommand()
1150{
1151    //This call will process the first node command in the input queue.
1152
1153
1154    //Can't do anything when an asynchronous cancel is in progress -- just need to wait on completion.
1155    if (!iCancelCommand.empty())
1156        return; //keep waiting.
1157
1158    //If a command is in progress, only a hi-pri command can interrupt it.
1159    if (!iCurrentCommand.empty()
1160            && !iInputCommands.front().hipri()
1161       )
1162    {
1163        return; //keep waiting
1164    }
1165
1166    //The newest or highest pri command is in the front of the queue.
1167    OSCL_ASSERT(!iInputCommands.empty());
1168    PVMFDownloadManagerNodeCommand& aCmd = iInputCommands.front();
1169
1170    PVMFStatus cmdstatus;
1171    if (aCmd.hipri())
1172    {
1173        //Process the Hi-Pri commands.
1174        switch (aCmd.iCmd)
1175        {
1176            case PVMF_GENERIC_NODE_CANCELALLCOMMANDS:
1177                cmdstatus = DoCancelAllCommands(aCmd);
1178                break;
1179
1180            case PVMF_GENERIC_NODE_CANCELCOMMAND:
1181                cmdstatus = DoCancelCommand(aCmd);
1182                break;
1183
1184            case PVDLM_NODE_CMD_CANCEL_GET_LICENSE:
1185                cmdstatus = DoCancelGetLicense(aCmd);
1186                break;
1187
1188            default:
1189                cmdstatus = PVMFErrNotSupported;
1190                break;
1191        }
1192
1193        //If completion is pending, move the command from
1194        //the input queue to the cancel queue.
1195        //This is necessary since the input queue could get
1196        //rearranged by new commands coming in.
1197        if (cmdstatus == PVMFPending)
1198        {
1199            iCancelCommand.StoreL(aCmd);
1200            iInputCommands.Erase(&aCmd);
1201        }
1202    }
1203    else
1204    {
1205        //Process the normal pri commands.
1206        switch (aCmd.iCmd)
1207        {
1208            case PVMF_GENERIC_NODE_QUERYUUID:
1209                cmdstatus = DoQueryUuid(aCmd);
1210                break;
1211
1212            case PVMF_GENERIC_NODE_QUERYINTERFACE:
1213                cmdstatus = DoQueryInterface(aCmd);
1214                break;
1215
1216            case PVMF_GENERIC_NODE_REQUESTPORT:
1217                cmdstatus = DoRequestPort(aCmd);
1218                break;
1219
1220            case PVMF_GENERIC_NODE_RELEASEPORT:
1221                cmdstatus = DoReleasePort(aCmd);
1222                break;
1223
1224            case PVMF_GENERIC_NODE_INIT:
1225                cmdstatus = DoInitNode(aCmd);
1226                break;
1227
1228            case PVMF_GENERIC_NODE_PREPARE:
1229                cmdstatus = DoPrepareNode(aCmd);
1230                break;
1231
1232            case PVMF_GENERIC_NODE_START:
1233                cmdstatus = DoStartNode(aCmd);
1234                break;
1235
1236            case PVMF_GENERIC_NODE_STOP:
1237                cmdstatus = DoStopNode(aCmd);
1238                break;
1239
1240            case PVMF_GENERIC_NODE_FLUSH:
1241                cmdstatus = DoFlushNode(aCmd);
1242                break;
1243
1244            case PVMF_GENERIC_NODE_PAUSE:
1245                cmdstatus = DoPauseNode(aCmd);
1246                break;
1247
1248            case PVMF_GENERIC_NODE_RESET:
1249                cmdstatus = DoResetNode(aCmd);
1250                break;
1251
1252            case PVDLM_NODE_CMD_GETNODEMETADATAKEY:
1253                cmdstatus = DoGetNodeMetadataKey(aCmd);
1254                break;
1255
1256            case PVDLM_NODE_CMD_GETNODEMETADATAVALUE:
1257                cmdstatus = DoGetNodeMetadataValue(aCmd);
1258                break;
1259
1260            case PVDLM_NODE_CMD_SETDATASOURCEPOSITION:
1261                cmdstatus = DoSetDataSourcePosition(aCmd);
1262                break;
1263
1264            case PVDLM_NODE_CMD_QUERYDATASOURCEPOSITION:
1265                cmdstatus = DoQueryDataSourcePosition(aCmd);
1266                break;
1267
1268            case PVDLM_NODE_CMD_SETDATASOURCERATE:
1269                // Rate change not supported for download
1270                cmdstatus = PVMFErrNotSupported;
1271                break;
1272
1273            case PVDLM_NODE_CMD_GET_LICENSE_W:
1274                cmdstatus = DoGetLicense(aCmd, true);
1275                break;
1276
1277            case PVDLM_NODE_CMD_GET_LICENSE:
1278                cmdstatus = DoGetLicense(aCmd);
1279                break;
1280
1281            default:
1282                OSCL_ASSERT(false);
1283                cmdstatus = PVMFFailure;
1284                break;
1285        }
1286
1287        //If completion is pending, move the command from the input queue to the current command.
1288        //This is necessary since the input queue could get rearranged by new commands coming in.
1289        if (cmdstatus == PVMFPending)
1290        {
1291            iCurrentCommand.StoreL(aCmd);
1292            iInputCommands.Erase(&aCmd);
1293        }
1294    }
1295
1296    if (cmdstatus != PVMFPending)
1297        CommandComplete(iInputCommands, aCmd, cmdstatus, NULL, NULL);
1298}
1299
1300void PVMFDownloadManagerNode::CommandComplete(PVMFDownloadManagerNodeCmdQueue& aCmdQ, PVMFDownloadManagerNodeCommand& aCmd, PVMFStatus aStatus,
1301        PVInterface*aExtMsg, OsclAny* aEventData)
1302{
1303    //Complete a node command
1304
1305    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL, (0, "PVMFDownloadManagerNode::CommandComplete() In Id %d Cmd %d Status %d Context %d Data %d",
1306                    aCmd.iId, aCmd.iCmd, aStatus, aCmd.iContext, aEventData));
1307
1308    if (aStatus != PVMFSuccess)
1309    {
1310        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, CMD_LOG_LEVEL,
1311                        (0, "PVMFDownloadManagerNode::CommandComplete() Failure!"));
1312    }
1313
1314    //if the command failed or was cancelled there may be un-processed sub-node commands, so clear the vector now.
1315    if (!iSubNodeCmdVec.empty())
1316        iSubNodeCmdVec.clear();
1317
1318    //We may need to wait on the movie atom before the node cmd can complete.
1319    //This is a good place to catch that condition and suppress the node
1320    //cmd completion.
1321    if (iParserInitAfterMovieAtom
1322            || iParserPrepareAfterMovieAtom)
1323    {
1324        if (aStatus == PVMFSuccess)
1325        {
1326            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
1327                            (0, "PVMFDownloadManagerNode::CommandComplete() Blocking Command Completion until Movie Atom Downloaded."));
1328            return;//keep waiting on movie atom complete.
1329        }
1330        else
1331        {
1332            //if command failed or was cancelled then clear any movie atom wait
1333            //flags.
1334            iParserInitAfterMovieAtom = false;
1335            iParserPrepareAfterMovieAtom = false;
1336        }
1337    }
1338
1339    //Do the post-command state changes and anything else.
1340    if (aStatus == PVMFSuccess)
1341    {
1342        switch (aCmd.iCmd)
1343        {
1344            case PVMF_GENERIC_NODE_INIT:
1345                ChangeNodeState(EPVMFNodeInitialized);
1346                break;
1347            case PVMF_GENERIC_NODE_PREPARE:
1348                ChangeNodeState(EPVMFNodePrepared);
1349                break;
1350            case PVMF_GENERIC_NODE_START:
1351                ChangeNodeState(EPVMFNodeStarted);
1352                break;
1353            case PVMF_GENERIC_NODE_PAUSE:
1354                ChangeNodeState(EPVMFNodePaused);
1355                break;
1356            case PVMF_GENERIC_NODE_STOP:
1357                ChangeNodeState(EPVMFNodePrepared);
1358                break;
1359            case PVMF_GENERIC_NODE_FLUSH:
1360                ChangeNodeState(EPVMFNodePrepared);
1361                break;
1362            case PVMF_GENERIC_NODE_RESET:
1363                //drive this node back to Created state.
1364                ChangeNodeState(EPVMFNodeIdle);
1365                break;
1366        }
1367    }
1368
1369    //create response
1370    PVMFCmdResp resp(aCmd.iId, aCmd.iContext, aStatus, aExtMsg, aEventData);
1371    PVMFSessionId session = aCmd.iSession;
1372
1373    //Erase the command from the queue.
1374    aCmdQ.Erase(&aCmd);
1375
1376    //Report completion to the session observer.
1377    ReportCmdCompleteEvent(session, resp);
1378
1379    //re-schedule if there are more commands and node isn't logged off
1380    if (!iInputCommands.empty()
1381            && IsAdded())
1382        RunIfNotReady();
1383}
1384
1385
1386void PVMFDownloadManagerNode::ReportErrorEvent(PVMFEventType aEventType, PVInterface*aExtMsg, OsclAny* aEventData)
1387{
1388    //Report a node error event
1389
1390    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::ReportErrorEvent() In Type %d Data %d ExtMsg %d",
1391                    aEventType, aEventData, aExtMsg));
1392
1393    PVMFNodeInterface::ReportErrorEvent(aEventType, aEventData, aExtMsg);
1394}
1395
1396
1397void PVMFDownloadManagerNode::ReportInfoEvent(PVMFAsyncEvent &aEvent)
1398{
1399    //Report a node info event
1400
1401    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::ReportInfoEvent() In Type %d Data %d ExtMsg %d",
1402                    aEvent.GetEventType(), aEvent.GetEventData(), aEvent.GetEventExtensionInterface()));
1403
1404    PVMFNodeInterface::ReportInfoEvent(aEvent);
1405
1406    //For download-then-play mode, generate data ready event when buffering
1407    //is complete.  We will have suppressed the real initial data ready
1408    //event from PE node in this case.
1409    if (aEvent.GetEventType() == PVMFInfoBufferingComplete
1410            && iPlaybackMode == PVMFDownloadManagerNode::EDownloadThenPlay
1411            && !iDataReady)
1412    {
1413        GenerateDataReadyEvent();
1414    }
1415    else if (aEvent.GetEventType() == PVMFInfoContentType)
1416    {
1417        // copy and save MIME string for recognizer to use as hint
1418        iContentTypeMIMEString = (char *)aEvent.GetEventData();
1419    }
1420}
1421
1422void PVMFDownloadManagerNode::GenerateDataReadyEvent()
1423{
1424    PVMFAsyncEvent info(PVMFInfoEvent, PVMFInfoDataReady, NULL, NULL);
1425    ReportInfoEvent(info);
1426    iDataReady = true;
1427}
1428
1429bool PVMFDownloadManagerNode::FilterPlaybackEventsFromSubNodes(const PVMFAsyncEvent& aEvent)
1430{
1431    switch (aEvent.GetEventType())
1432    {
1433        case PVMFInfoUnderflow:
1434            //filter any underflow that happens before data ready
1435            if (!iDataReady)
1436                return true;
1437            else
1438                iDataReady = false;
1439            break;
1440        case PVMFInfoDataReady:
1441            //filter any data ready that happens before download complete
1442            //in dl-then-play mode
1443            if (iPlaybackMode == EDownloadThenPlay
1444                    && !iDownloadComplete)
1445            {
1446                return true;
1447            }
1448            //filter any data ready in dl-only mode, though I don't
1449            //think it's possible.
1450            if (iPlaybackMode == EDownloadOnly)
1451                return true;
1452
1453            iDataReady = true;
1454
1455            break;
1456        case PVMFInfoRemoteSourceNotification:
1457            //we get this event for "not pseudostreamable" for both PVX
1458            //and 3gpp.  Only pass it up for 3gpp.
1459            if (iSourceFormat != PVMF_MIME_DATA_SOURCE_HTTP_URL)
1460                return true;
1461            break;
1462        default:
1463            break;
1464    }
1465    return false;
1466}
1467
1468void PVMFDownloadManagerNode::ChangeNodeState(TPVMFNodeInterfaceState aNewState)
1469{
1470    //Update the node state
1471
1472    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::ChangeNodeState() Old %d New %d", iInterfaceState, aNewState));
1473
1474    PVMFNodeInterface::SetState(aNewState);
1475}
1476
1477
1478PVMFStatus PVMFDownloadManagerNode::DoQueryUuid(PVMFDownloadManagerNodeCommand& aCmd)
1479{
1480    //Start executing a node command
1481
1482    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoQueryUuid() In"));
1483
1484    OSCL_String* mimetype;
1485    Oscl_Vector<PVUuid, OsclMemAllocator> *uuidvec;
1486    bool exactmatch;
1487    aCmd.PVMFDownloadManagerNodeCommandBase::Parse(mimetype, uuidvec, exactmatch);
1488
1489    // @TODO Add MIME string matching
1490    // For now just return all available extension interface UUID
1491    uuidvec->push_back(PVMF_TRACK_SELECTION_INTERFACE_UUID);
1492    uuidvec->push_back(PVMF_DATA_SOURCE_INIT_INTERFACE_UUID);
1493    uuidvec->push_back(KPVMFMetadataExtensionUuid);
1494    uuidvec->push_back(PvmfDataSourcePlaybackControlUuid);
1495    uuidvec->push_back(PVMI_CAPABILITY_AND_CONFIG_PVUUID);
1496
1497    return PVMFSuccess;
1498}
1499
1500
1501PVMFStatus PVMFDownloadManagerNode::DoQueryInterface(PVMFDownloadManagerNodeCommand& aCmd)
1502{
1503    //Start executing a node command
1504
1505    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoQueryInterface() In"));
1506
1507    PVUuid* uuid;
1508    PVInterface** ptr;
1509    aCmd.PVMFDownloadManagerNodeCommandBase::Parse(uuid, ptr);
1510
1511    if (queryInterface(*uuid, *ptr))
1512    {
1513        //Schedule further queries on sub-nodes...
1514        return ScheduleSubNodeCommands(aCmd);
1515    }
1516    else
1517    {
1518        //interface not supported
1519        *ptr = NULL;
1520        return PVMFFailure;
1521    }
1522}
1523
1524PVMFStatus PVMFDownloadManagerNode::DoRequestPort(PVMFDownloadManagerNodeCommand& aCmd)
1525{
1526    //Start executing a node command
1527
1528    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoRequestPort() In"));
1529
1530    if (iInterfaceState != EPVMFNodePrepared)
1531        return PVMFErrInvalidState;
1532
1533    return ScheduleSubNodeCommands(aCmd);
1534}
1535
1536PVMFStatus PVMFDownloadManagerNode::DoReleasePort(PVMFDownloadManagerNodeCommand& aCmd)
1537{
1538    //Start executing a node command
1539
1540    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoReleasePort() In"));
1541
1542    return ScheduleSubNodeCommands(aCmd);
1543}
1544
1545PVMFStatus PVMFDownloadManagerNode::DoInitNode(PVMFDownloadManagerNodeCommand& aCmd)
1546{
1547    //Start executing a node command
1548
1549    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoInitNode() In"));
1550
1551    if (iInterfaceState != EPVMFNodeIdle)
1552        return PVMFErrInvalidState;
1553
1554    return ScheduleSubNodeCommands(aCmd);
1555}
1556
1557PVMFStatus PVMFDownloadManagerNode::DoPrepareNode(PVMFDownloadManagerNodeCommand& aCmd)
1558{
1559    //Start executing a node command
1560
1561    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoPrepareNode() In"));
1562
1563    if (iInterfaceState != EPVMFNodeInitialized)
1564        return PVMFErrInvalidState;
1565
1566    return ScheduleSubNodeCommands(aCmd);
1567}
1568
1569PVMFStatus PVMFDownloadManagerNode::DoStartNode(PVMFDownloadManagerNodeCommand& aCmd)
1570{
1571    //Start executing a node command
1572
1573    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoStartNode() In"));
1574
1575    if (iInterfaceState != EPVMFNodePrepared
1576            && iInterfaceState != EPVMFNodePaused)
1577        return PVMFErrInvalidState;
1578
1579    return ScheduleSubNodeCommands(aCmd);
1580}
1581
1582PVMFStatus PVMFDownloadManagerNode::DoStopNode(PVMFDownloadManagerNodeCommand& aCmd)
1583{
1584    //Start executing a node command
1585
1586    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoStopNode() In"));
1587
1588    if (iInterfaceState != EPVMFNodeStarted
1589            && iInterfaceState != EPVMFNodePaused
1590            && iInterfaceState != EPVMFNodeError)//allow a stop in error state.
1591        return PVMFErrInvalidState;
1592
1593    return ScheduleSubNodeCommands(aCmd);
1594}
1595
1596PVMFStatus PVMFDownloadManagerNode::DoFlushNode(PVMFDownloadManagerNodeCommand& aCmd)
1597{
1598    //Start executing a node command
1599
1600    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoFlushNode() In"));
1601
1602    if (iInterfaceState != EPVMFNodeStarted
1603            && iInterfaceState != EPVMFNodePaused)
1604        return PVMFErrInvalidState;
1605
1606    return ScheduleSubNodeCommands(aCmd);
1607}
1608
1609PVMFStatus PVMFDownloadManagerNode::DoPauseNode(PVMFDownloadManagerNodeCommand& aCmd)
1610{
1611    //Start executing a node command
1612
1613    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoPauseNode() In"));
1614
1615    if (iInterfaceState != EPVMFNodeStarted)
1616        return PVMFErrInvalidState;
1617
1618    return ScheduleSubNodeCommands(aCmd);
1619}
1620
1621PVMFStatus PVMFDownloadManagerNode::DoResetNode(PVMFDownloadManagerNodeCommand& aCmd)
1622{
1623    //remove the clock observer
1624    if (iPlayBackClock != NULL)
1625    {
1626        if (iClockNotificationsInf != NULL)
1627        {
1628            iClockNotificationsInf->RemoveClockStateObserver(*this);
1629            iPlayBackClock->DestroyMediaClockNotificationsInterface(iClockNotificationsInf);
1630            iClockNotificationsInf = NULL;
1631        }
1632    }
1633
1634    //Start executing a node command
1635    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoResetNode() In"));
1636
1637    //Reset the sub-nodes first.
1638    return ScheduleSubNodeCommands(aCmd);
1639}
1640
1641PVMFStatus PVMFDownloadManagerNode::DoCancelAllCommands(PVMFDownloadManagerNodeCommand& aCmd)
1642{
1643    OSCL_UNUSED_ARG(aCmd);
1644    //Start executing a node command
1645
1646    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoCancelAllCommands() In"));
1647
1648    //first cancel the current command if any
1649    while (!iCurrentCommand.empty())
1650    {
1651        if (iFormatParserNode.CancelPendingCommand()
1652                || iProtocolEngineNode.CancelPendingCommand()
1653                || iSocketNode.CancelPendingCommand()
1654                || iRecognizerNode.CancelPendingCommand()
1655           )
1656        {
1657            return PVMFPending;//wait on sub-node cancel to complete.
1658        }
1659        CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFErrCancelled, NULL, NULL);
1660    }
1661
1662    //next cancel all queued commands
1663    //start at element 1 since this cancel command is element 0.
1664    while (iInputCommands.size() > 1)
1665    {
1666        CommandComplete(iInputCommands, iInputCommands[1], PVMFErrCancelled, NULL, NULL);
1667    }
1668
1669    return PVMFSuccess;
1670}
1671
1672PVMFStatus PVMFDownloadManagerNode::DoCancelCommand(PVMFDownloadManagerNodeCommand& aCmd)
1673{
1674    //Start executing a node command
1675
1676    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoCancelCommand() In"));
1677
1678    //extract the command ID from the parameters.
1679    PVMFCommandId id;
1680    aCmd.PVMFDownloadManagerNodeCommandBase::Parse(id);
1681
1682    //first check "current" command if any
1683    PVMFDownloadManagerNodeCommand* cmd = iCurrentCommand.FindById(id);
1684    if (cmd)
1685    {
1686        if (iFormatParserNode.CancelPendingCommand()
1687                || iProtocolEngineNode.CancelPendingCommand()
1688                || iRecognizerNode.CancelPendingCommand()
1689           )
1690        {
1691            return PVMFPending;//wait on sub-node cancel to complete.
1692        }
1693        CommandComplete(iCurrentCommand, *cmd, PVMFErrCancelled, NULL, NULL);
1694        return PVMFSuccess;
1695    }
1696
1697    //next check input queue.
1698    //start at element 1 since this cancel command is element 0.
1699    cmd = iInputCommands.FindById(id, 1);
1700    if (cmd)
1701    {
1702        //cancel the queued command
1703        CommandComplete(iInputCommands, *cmd, PVMFErrCancelled, NULL, NULL);
1704        //report cancel success
1705        return PVMFSuccess;
1706    }
1707
1708    //if we get here the command isn't queued so the cancel fails.
1709    return PVMFFailure;
1710}
1711
1712
1713PVMFStatus PVMFDownloadManagerNode::DoGetNodeMetadataKey(PVMFDownloadManagerNodeCommand& aCmd)
1714{
1715    //Start executing a node command
1716
1717    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoGetNodeMetadataKey() In"));
1718
1719    return ScheduleSubNodeCommands(aCmd);
1720}
1721
1722
1723
1724PVMFStatus PVMFDownloadManagerNode::DoGetNodeMetadataValue(PVMFDownloadManagerNodeCommand& aCmd)
1725{
1726    //Start executing a node command
1727
1728    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoGetNodeMetadataValue() In"));
1729
1730    return ScheduleSubNodeCommands(aCmd);
1731}
1732
1733
1734
1735PVMFStatus PVMFDownloadManagerNode::DoSetDataSourcePosition(PVMFDownloadManagerNodeCommand& aCmd)
1736{
1737    //Start executing a node command
1738
1739    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoSetDataSourcePosition() In"));
1740
1741    return ScheduleSubNodeCommands(aCmd);
1742}
1743
1744
1745PVMFStatus PVMFDownloadManagerNode::DoQueryDataSourcePosition(PVMFDownloadManagerNodeCommand& aCmd)
1746{
1747    //Start executing a node command
1748
1749    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoQueryDataSourcePosition() In"));
1750
1751    return ScheduleSubNodeCommands(aCmd);
1752}
1753
1754void PVMFDownloadManagerNode::ContinueInitAfterTrackSelectDecision()
1755{
1756    //this is called during the Init sequence, once we have enough information
1757    //to make a definite track select decision.
1758
1759    //See whether we need to stop to allow track selection on the download server.
1760    //If it's download-only, we don't offer this option, since the download must
1761    //be started in the Init.
1762    if (iPlaybackMode != EDownloadOnly
1763            && TrackSelectNode().iType == PVMFDownloadManagerSubNodeContainerBase::EProtocolEngine)
1764    {
1765        //stop the Init sequence here so we can do track selection on the download
1766        //server.
1767        ;
1768    }
1769    else
1770    {
1771        //else download-only, or there's no track selection available from the
1772        //PE node.  Continue the Init or Prepare sequence.
1773        ContinueFromDownloadTrackSelectionPoint();
1774    }
1775}
1776
1777void PVMFDownloadManagerNode::ContinueFromDownloadTrackSelectionPoint()
1778{
1779    //Continue the Init or Prepare sequence, stopping at parser init.
1780
1781    //start the download.
1782    Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::EStart);
1783
1784    //initiate file recognize & parse, unless this is download-only mode.
1785    if (iPlaybackMode != EDownloadOnly)
1786    {
1787        //do recognizer sequence if needed.
1788        if (iSourceFormat == PVMF_MIME_DATA_SOURCE_PVX_FILE)
1789        {
1790            //PXV is always assumed to be MP4
1791            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,
1792                            "PVMFDownloadManagerNode::ContinueFromDownloadTrackSelectionPoint Setting format to MP4"));
1793            iMimeType = PVMF_MIME_MPEG4FF;
1794        }
1795        else
1796        {
1797            //for other source formats, use the recognizer to determine the format.
1798            Push(iRecognizerNode, PVMFDownloadManagerSubNodeContainerBase::ERecognizerStart);
1799            Push(iRecognizerNode, PVMFDownloadManagerSubNodeContainerBase::ERecognizerClose);
1800        }
1801
1802        //create parser
1803        Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EParserCreate);
1804
1805        // Send commands to the parser node to query these extension interfaces.
1806        Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EQueryDataSourceInit);
1807        Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EQueryTrackSelection);
1808        Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EQueryMetadata);
1809        Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EQueryDatastreamUser);
1810        Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EQueryDataSourcePlayback);
1811        Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EQueryFFProgDownload);
1812        Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::ESetFFProgDownloadSupport);
1813        Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::ECPMQueryLicenseInterface);
1814
1815        //if this is PVX, we need to wait on movie atom before we can
1816        //init parser.
1817        if (iSourceFormat == PVMF_MIME_DATA_SOURCE_PVX_FILE)
1818        {
1819            if (iMovieAtomComplete || iDownloadComplete)
1820            {
1821                iParserInit = true;
1822                Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EInit);
1823            }
1824            else
1825            {
1826                PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,
1827                                "PVMFDownloadManagerNode::ContinueFromDownloadTrackSelectionPoint Setting flag to Init Parser after Movie Atom Downloaded"));
1828                //set this flag to trigger parser init when movie atom is done.
1829                iParserInitAfterMovieAtom = true;
1830            }
1831        }
1832        else
1833        {
1834            //for other formats, go ahead and init parser.  Init will block until
1835            //receiving movie atom.
1836            iParserInit = true;
1837            Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EInit);
1838        }
1839    }
1840}
1841
1842//Called when movie atom is received, or when download is complete
1843//but movie atom was never received.
1844void PVMFDownloadManagerNode::ContinueAfterMovieAtom()
1845{
1846    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
1847                    (0, "PVMFDownloadManagerNode::ContinueAfterMovieAtom() "));
1848
1849    if (!iMovieAtomComplete)
1850    {
1851        iMovieAtomComplete = true;
1852        //see whether we need to continue with parser init
1853        if (iParserInitAfterMovieAtom)
1854        {
1855            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
1856                            (0, "PVMFDownloadManagerNode::ContinueAfterMovieAtom() Continuing to Parser Init"));
1857            iParserInitAfterMovieAtom = false;
1858            iParserInit = true;
1859            Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EInit);
1860            RunIfNotReady();
1861        }
1862        //see whether we need to continue with parser prepare
1863        if (iParserPrepareAfterMovieAtom)
1864        {
1865            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
1866                            (0, "PVMFDownloadManagerNode::ContinueAfterMovieAtom() Continuing to Parser Prepare"));
1867            iParserPrepareAfterMovieAtom = false;
1868            Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EPrepare);
1869            RunIfNotReady();
1870        }
1871    }
1872}
1873
1874PVMFNodeInterface* PVMFDownloadManagerNode::CreateParser()
1875{
1876    if (!(iMimeType == PVMF_MIME_FORMAT_UNKNOWN))
1877    {
1878        PVMFNodeInterface *iSourceNode = NULL;
1879        PVMFFormatType outputFormatType = PVMF_MIME_FORMAT_UNKNOWN;
1880        iFmt = iMimeType.get_str();
1881        PVMFStatus status =
1882            iPlayerNodeRegistry->QueryRegistry(iFmt, outputFormatType, iDNodeUuids);
1883        if ((status == PVMFSuccess) && (iDNodeUuids.size() > 0))
1884        {
1885            int32 leavecode = 0;
1886            OSCL_TRY(leavecode, iSourceNode = iPlayerNodeRegistry->CreateNode(iDNodeUuids[iDNodeUuidCount]));
1887            OSCL_FIRST_CATCH_ANY(leavecode, return NULL);
1888            iDNodeUuidCount++;
1889            return iSourceNode;
1890        }
1891    }
1892    return NULL;
1893}
1894
1895PVMFStatus PVMFDownloadManagerNode::ScheduleSubNodeCommands(PVMFDownloadManagerNodeCommand& aCmd)
1896{
1897    //given the node command ID, create the sub-node command vector, initiate the processing and return the node command status.
1898
1899    OSCL_ASSERT(iSubNodeCmdVec.empty());
1900
1901    //Create the vector of all the commands in the sequence.
1902    switch (aCmd.iCmd)
1903    {
1904
1905        case PVMF_GENERIC_NODE_QUERYINTERFACE:
1906        {
1907            //When we get here we've already called queryInterface on this node
1908            //for the interface.  This code schedules any additional sub-node commands
1909            //that are needed to support the interface.
1910
1911            //extract uuid from Node command...
1912            PVUuid*aUuid;
1913            PVInterface**aInterface;
1914            aCmd.PVMFDownloadManagerNodeCommandBase::Parse(aUuid, aInterface);
1915            OSCL_ASSERT(aUuid != NULL);
1916
1917            if (*aUuid == PVMF_DATA_SOURCE_INIT_INTERFACE_UUID)
1918            {
1919                //To support data source init interface we need a bunch of sub-node interfaces.
1920                Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::EQueryProtocolEngine);
1921                Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::EQueryDatastreamUser);
1922                Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::EQueryDataSourceInit);
1923                Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::EQueryDownloadProgress);
1924            }
1925            //else nothing else needed for other interfaces.
1926        }
1927        break;
1928
1929        case PVMF_GENERIC_NODE_INIT:
1930            //check for second "Init" command after a license acquire.
1931            if (iInitFailedLicenseRequired)
1932            {
1933                iParserInit = true;
1934                Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EInit);
1935            }
1936            else
1937
1938            {
1939                //reset any prior download/playback event
1940                iDownloadComplete = false;
1941                iParserInit = false;
1942                iDataReady = false;
1943                iMovieAtomComplete = false;
1944                iParserInitAfterMovieAtom = false;
1945                iParserPrepareAfterMovieAtom = false;
1946                iRecognizerError = false;
1947                iInitFailedLicenseRequired = false;
1948
1949                //reset any prior track select decisions.
1950                iFormatParserNode.iTrackSelection = NULL;
1951                iProtocolEngineNode.iTrackSelection = NULL;
1952                iNoPETrackSelect = false;
1953
1954                //reset any prior recognizer decisions.
1955                iMimeType = PVMF_MIME_FORMAT_UNKNOWN;
1956
1957                // Send the INIT command to the protocol engine node, followed by the Socket Node.
1958                Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::EInit);
1959                Push(iSocketNode, PVMFDownloadManagerSubNodeContainerBase::EInit);
1960                // Issue the port request to the Protocol Engine Node and the socket node
1961                // NOTE: The request for the socket node's port must come first, followed by the protocol node,
1962                // because the code to connect the two ports in CommandDone() will do so when the protocol node's port is returned.
1963                Push(iSocketNode, PVMFDownloadManagerSubNodeContainerBase::ERequestPort);
1964                Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::ERequestPort);
1965                // The two ports will be connected in CommandDone, when the 2nd port request completes.
1966                // After the ports are connected, the datastream factory is passed to the protocol engine node.
1967                Push(iSocketNode, PVMFDownloadManagerSubNodeContainerBase::EPrepare);
1968                Push(iSocketNode, PVMFDownloadManagerSubNodeContainerBase::EStart);
1969                Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::EPrepare);
1970
1971                if (TrackSelectNode().iType == PVMFDownloadManagerSubNodeContainerBase::EFormatParser)
1972                {
1973                    //parser is doing track selection, there's no question
1974                    ContinueInitAfterTrackSelectDecision();
1975                }
1976                else
1977                {
1978                    //PE node may be doing track selection, but to be sure, we need
1979                    //to wait until it is prepared, then request the track selection interface.
1980                    iProtocolEngineNode.iTrackSelection = NULL;
1981                    Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::EQueryTrackSelection);
1982                    //once this command is complete, we will call ContinueInitAfterTrackSelectDecision()
1983                }
1984            }
1985            break;
1986
1987        case PVMF_GENERIC_NODE_PREPARE:
1988            //if protocol engine node did track selection, then we need to continue
1989            //to the file parse stage here.  Otherwise it was already done in the Init.
1990            if (TrackSelectNode().iType == PVMFDownloadManagerSubNodeContainerBase::EProtocolEngine)
1991            {
1992                ContinueFromDownloadTrackSelectionPoint();
1993            }
1994            //if we initiated file parse sequence already, then go ahead and prepare
1995            //the parser node.
1996            if (iParserInit)
1997            {
1998                Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EPrepare);
1999            }
2000            //if we're waiting on movie atom to init parser, then set a flag so we'll
2001            //also do the parser prepare when it arrives.
2002            else if (iParserInitAfterMovieAtom)
2003            {
2004                PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,
2005                                "PVMFDownloadManagerNode::ScheduleSubNodeCommands Setting flag to Prepare Parser after Movie Atom Downloaded"));
2006                iParserPrepareAfterMovieAtom = true;
2007            }
2008            break;
2009
2010        case PVMF_GENERIC_NODE_REQUESTPORT:
2011            //if file isn't parsed (as in download-only), then fail command
2012            if (!iFormatParserNode.iNode)
2013                return PVMFErrNotSupported;
2014            Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::ERequestPort);
2015            break;
2016
2017        case PVMF_GENERIC_NODE_RELEASEPORT:
2018            //if file isn't parsed (as in download-only), then fail command
2019            if (!iFormatParserNode.iNode)
2020                return PVMFErrNotSupported;
2021            Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EReleasePort);
2022            break;
2023
2024        case PVMF_GENERIC_NODE_START:
2025            //Re-start socket node & PE node in case they were stopped by a prior
2026            //stop command.
2027            if (iSocketNode.iNode->GetState() == EPVMFNodePrepared)
2028                Push(iSocketNode, PVMFDownloadManagerSubNodeContainerBase::EStart);
2029            if (iProtocolEngineNode.iNode->GetState() == EPVMFNodePrepared)
2030                Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::EStart);
2031            //Start or re-start parser node (unless download-only)
2032            if (iFormatParserNode.iNode)
2033                Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EStart);
2034            break;
2035
2036        case PVMF_GENERIC_NODE_STOP:
2037            iDataReady = false;
2038            //Stop parser (unless download-only)
2039            if (iFormatParserNode.iNode)
2040                Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EStop);
2041            //Stop PE node & socket node.
2042            Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::EStop);
2043            Push(iSocketNode, PVMFDownloadManagerSubNodeContainerBase::EStop);
2044            break;
2045
2046        case PVMF_GENERIC_NODE_FLUSH:
2047            if (iFormatParserNode.iNode)
2048                Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EFlush);
2049            break;
2050
2051        case PVMF_GENERIC_NODE_PAUSE:
2052            //note: pause/resume download is not supported.
2053            if (iFormatParserNode.iNode)
2054                Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EPause);
2055            break;
2056
2057        case PVMF_GENERIC_NODE_RESET:
2058            //Stop socket node if needed.
2059            if (iSocketNode.iNode->GetState() == EPVMFNodeStarted
2060                    || iSocketNode.iNode->GetState() == EPVMFNodePaused)
2061            {
2062                Push(iSocketNode, PVMFDownloadManagerSubNodeContainerBase::EStop);
2063            }
2064            //Stop PE node if needed.
2065            if (iProtocolEngineNode.iNode->GetState() == EPVMFNodeStarted
2066                    || iProtocolEngineNode.iNode->GetState() == EPVMFNodePaused)
2067            {
2068                Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::EStop);
2069            }
2070            //Reset & cleanup all nodes.
2071            if (iFormatParserNode.iNode)
2072                Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EReset);
2073            Push(iSocketNode, PVMFDownloadManagerSubNodeContainerBase::EReset);
2074            Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::EReset);
2075            Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::ECleanup);
2076            Push(iProtocolEngineNode, PVMFDownloadManagerSubNodeContainerBase::ECleanup);
2077            Push(iSocketNode, PVMFDownloadManagerSubNodeContainerBase::ECleanup);
2078            break;
2079
2080        case PVDLM_NODE_CMD_SETDATASOURCEPOSITION:
2081            //if file isn't parsed (as in download-only), then fail command
2082            if (!iFormatParserNode.iNode)
2083                return PVMFErrNotSupported;
2084            Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::ESetDataSourcePosition);
2085            break;
2086
2087        case PVDLM_NODE_CMD_QUERYDATASOURCEPOSITION:
2088            //if file isn't parsed (as in download-only), then fail command
2089            if (!iFormatParserNode.iNode)
2090                return PVMFErrNotSupported;
2091            Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EQueryDataSourcePosition);
2092            break;
2093
2094        case PVDLM_NODE_CMD_GETNODEMETADATAKEY:
2095            //if file isn't parsed (as in download-only), then fail command
2096            if (!iFormatParserNode.iNode)
2097                return PVMFErrNotSupported;
2098            Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EGetMetadataKey);
2099            break;
2100
2101        case PVDLM_NODE_CMD_GETNODEMETADATAVALUE:
2102            //if file isn't parsed (as in download-only), then fail command
2103            if (!iFormatParserNode.iNode)
2104                return PVMFErrNotSupported;
2105            Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::EGetMetadataValue);
2106            break;
2107
2108        default:
2109            OSCL_ASSERT(false);
2110            break;
2111    }
2112
2113    if (iSubNodeCmdVec.empty())
2114    {
2115        //in a few cases there's nothing needed and no new commands
2116        //were issued-- so succeed here.
2117        return PVMFSuccess;
2118    }
2119    else
2120    {
2121        //Wakeup the node to start issuing the sub-node commands.
2122        RunIfNotReady();
2123
2124        //the node command is pending.
2125        return PVMFPending;
2126    }
2127}
2128
2129void PVMFDownloadManagerNode::Push(PVMFDownloadManagerSubNodeContainerBase& n, PVMFDownloadManagerSubNodeContainerBase::CmdType c)
2130{
2131    //push a sub-node command onto the cmd vector
2132    CmdElem elem;
2133    elem.iCmd = c;
2134    elem.iNC = &n;
2135    iSubNodeCmdVec.push_back(elem);
2136}
2137
2138PVMFCommandId
2139PVMFDownloadManagerNode::GetLicense(PVMFSessionId aSessionId,
2140                                    OSCL_wString& aContentName,
2141                                    OsclAny* aData,
2142                                    uint32 aDataSize,
2143                                    int32 aTimeoutMsec,
2144                                    OsclAny* aContextData)
2145{
2146    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::GetLicense - Wide called"));
2147    PVMFDownloadManagerNodeCommand cmd;
2148    cmd.PVMFDownloadManagerNodeCommand::Construct(aSessionId,
2149            PVDLM_NODE_CMD_GET_LICENSE_W,
2150            aContentName,
2151            aData,
2152            aDataSize,
2153            aTimeoutMsec,
2154            aContextData);
2155    return QueueCommandL(cmd);
2156}
2157
2158PVMFCommandId
2159PVMFDownloadManagerNode::GetLicense(PVMFSessionId aSessionId,
2160                                    OSCL_String&  aContentName,
2161                                    OsclAny* aData,
2162                                    uint32 aDataSize,
2163                                    int32 aTimeoutMsec,
2164                                    OsclAny* aContextData)
2165{
2166    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::GetLicense - Non-Wide called"));
2167    PVMFDownloadManagerNodeCommand cmd;
2168    cmd.PVMFDownloadManagerNodeCommand::Construct(aSessionId,
2169            PVDLM_NODE_CMD_GET_LICENSE,
2170            aContentName,
2171            aData,
2172            aDataSize,
2173            aTimeoutMsec,
2174            aContextData);
2175    return QueueCommandL(cmd);
2176}
2177
2178
2179PVMFCommandId
2180PVMFDownloadManagerNode::CancelGetLicense(PVMFSessionId aSessionId
2181        , PVMFCommandId aCmdId
2182        , OsclAny* aContextData)
2183{
2184    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::GetLicense - Non-Wide called"));
2185    PVMFDownloadManagerNodeCommand cmd;
2186    cmd.PVMFDownloadManagerNodeCommandBase::Construct(aSessionId,
2187            PVDLM_NODE_CMD_CANCEL_GET_LICENSE,
2188            aCmdId,
2189            aContextData);
2190    return QueueCommandL(cmd);
2191}
2192
2193PVMFStatus PVMFDownloadManagerNode::DoGetLicense(PVMFDownloadManagerNodeCommand& aCmd,
2194        bool aWideCharVersion)
2195{
2196    OSCL_UNUSED_ARG(aCmd);
2197    if (iFormatParserNode.LicenseInterface() == NULL)
2198    {
2199        return PVMFErrNotSupported;
2200    }
2201
2202    if (aWideCharVersion == true)
2203    {
2204        Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::ECPMGetLicenseW);
2205    }
2206    else
2207    {
2208        Push(iFormatParserNode, PVMFDownloadManagerSubNodeContainerBase::ECPMGetLicense);
2209    }
2210    RunIfNotReady();
2211    return PVMFPending;
2212}
2213
2214void PVMFDownloadManagerNode::CompleteGetLicense()
2215{
2216    CommandComplete(iCurrentCommand,
2217                    iCurrentCommand.front(),
2218                    PVMFSuccess, NULL, NULL);
2219}
2220
2221PVMFStatus PVMFDownloadManagerNode::DoCancelGetLicense(PVMFDownloadManagerNodeCommand& aCmd)
2222{
2223    OSCL_UNUSED_ARG(aCmd);
2224    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFDownloadManagerNode::DoCancelGetLicense called"));
2225    if (iFormatParserNode.LicenseInterface() == NULL)
2226    {
2227        return PVMFErrNotSupported;
2228    }
2229    else
2230    {
2231        iFormatParserNode.iCancelCmdState = PVMFDownloadManagerSubNodeContainerBase::EBusy;
2232        iFormatParserNode.iCPMCancelGetLicenseCmdId =
2233            iFormatParserNode.LicenseInterface()->CancelGetLicense(iFormatParserNode.iSessionId, iFormatParserNode.iCPMGetLicenseCmdId);
2234        RunIfNotReady();
2235    }
2236    return PVMFPending;
2237}
2238
2239//
2240// PVMFDownloadManagerSubNodeContainer Implementation.
2241//
2242
2243PVMFDownloadManagerSubNodeContainerBase::PVMFDownloadManagerSubNodeContainerBase()
2244{
2245    iCmdState = EIdle;
2246    iCancelCmdState = EIdle;
2247}
2248
2249void PVMFDownloadManagerSubNodeContainerBase::Construct(NodeType t, PVMFDownloadManagerNode* c)
2250{
2251    iContainer = c;
2252    iType = t;
2253}
2254
2255void PVMFDownloadManagerSubNodeContainer::Cleanup()
2256{
2257    //release all the queried interfaces.
2258    if (iDataSourceInit)
2259    {
2260        iDataSourceInit->removeRef();
2261        iDataSourceInit = NULL;
2262    }
2263    if (iProtocolEngineExtensionInt)
2264    {
2265        iProtocolEngineExtensionInt->removeRef();
2266        iProtocolEngineExtensionInt = NULL;
2267    }
2268    if (iDatastreamUser)
2269    {
2270        iDatastreamUser->removeRef();
2271        iDatastreamUser = NULL;
2272    }
2273    if (iTrackSelection)
2274    {
2275        iTrackSelection->removeRef();
2276        iTrackSelection = NULL;
2277    }
2278    if (iMetadata)
2279    {
2280        iMetadata->removeRef();
2281        iMetadata = NULL;
2282    }
2283    if (iDataSourcePlayback)
2284    {
2285        iDataSourcePlayback->removeRef();
2286        iDataSourcePlayback = NULL;
2287    }
2288    if (iFormatProgDownloadSupport)
2289    {
2290        iFormatProgDownloadSupport->removeRef();
2291        iFormatProgDownloadSupport = NULL;
2292    }
2293    if (iDownloadProgress)
2294    {
2295        iDownloadProgress->removeRef();
2296        iDownloadProgress = NULL;
2297    }
2298    if (iLicenseInterface)
2299    {
2300        iLicenseInterface->removeRef();
2301        iLicenseInterface = NULL;
2302    }
2303    //the node instance is cleaned up elsewhere.
2304}
2305
2306void PVMFDownloadManagerRecognizerContainer::Cleanup()
2307{
2308    // Nothing to do here 'til recognizer is integrated
2309}
2310
2311void PVMFDownloadManagerSubNodeContainer::Connect()
2312{
2313    //Issue connect command to the sub-node.
2314
2315    //This container class is the observer.
2316    PVMFNodeSessionInfo info(this //cmd
2317                             , this, NULL //info
2318                             , this, NULL); //err
2319
2320    if (iNode)
2321        iSessionId = iNode->Connect(info);
2322}
2323
2324#define LOGSUBCMD(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, SUB_CMD_LOG_LEVEL, x)
2325#define GETNODESTR (iType==EFormatParser)?"Parser":((iType==EProtocolEngine)?"ProtEngine":"SockNode")
2326
2327PVMFStatus PVMFDownloadManagerSubNodeContainer::IssueCommand(int32 aCmd)
2328{
2329    //Issue a command to the sub-node.
2330    //Return the sub-node completion status-- either pending, success, or failure.
2331
2332    LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s () In", GETNODESTR));
2333
2334    OSCL_ASSERT(!CmdPending());
2335
2336    //find the current node command since we may need its parameters.
2337
2338    OSCL_ASSERT(!iContainer->iCurrentCommand.empty());
2339    PVMFDownloadManagerNodeCommand* nodeCmd = &iContainer->iCurrentCommand.front();
2340
2341    //save the sub-node command code
2342    iCmd = aCmd;
2343
2344    switch (aCmd)
2345    {
2346        case ECleanup:
2347            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling Cleanup", GETNODESTR));
2348            Cleanup();
2349            return PVMFSuccess;
2350
2351        case EParserCreate:
2352            iNode = iContainer->CreateParser();
2353            if (iNode)
2354            {
2355                Connect();
2356                iNode->ThreadLogon();
2357                return PVMFSuccess;
2358            }
2359            return PVMFErrCorrupt;
2360
2361        case EQueryDataSourceInit:
2362            OSCL_ASSERT(iNode != NULL);
2363            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling QueryInterface(data source init)", GETNODESTR));
2364            iCmdState = EBusy;
2365            iCmdId = iNode->QueryInterface(iSessionId, PVMF_DATA_SOURCE_INIT_INTERFACE_UUID, iDataSourceInit);
2366            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2367            return PVMFPending;
2368
2369        case EQueryProtocolEngine:
2370            OSCL_ASSERT(iNode != NULL);
2371            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling QueryInterface(ProtocolEngine)", GETNODESTR));
2372            iCmdState = EBusy;
2373            iCmdId = iNode->QueryInterface(iSessionId, KPVMFProtocolEngineNodeExtensionUuid, iProtocolEngineExtensionInt);
2374            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2375            return PVMFPending;
2376
2377        case EQueryDatastreamUser:
2378            OSCL_ASSERT(iNode != NULL);
2379            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling QueryInterface(DatastreamUser)", GETNODESTR));
2380            iCmdState = EBusy;
2381            iCmdId = iNode->QueryInterface(iSessionId, PVMIDatastreamuserInterfaceUuid, iDatastreamUser);
2382            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2383            return PVMFPending;
2384
2385        case EQueryTrackSelection:
2386            OSCL_ASSERT(iNode != NULL);
2387            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling QueryInterface(track selection)", GETNODESTR));
2388            iCmdState = EBusy;
2389            iCmdId = iNode->QueryInterface(iSessionId, PVMF_TRACK_SELECTION_INTERFACE_UUID, iTrackSelection);
2390            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2391            return PVMFPending;
2392
2393        case EQueryMetadata:
2394            OSCL_ASSERT(iNode != NULL);
2395            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling QueryInterface(metadata)", GETNODESTR));
2396            iCmdState = EBusy;
2397            iCmdId = iNode->QueryInterface(iSessionId, KPVMFMetadataExtensionUuid, iMetadata);
2398            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2399            return PVMFPending;
2400
2401        case ECPMQueryLicenseInterface:
2402            OSCL_ASSERT(iNode != NULL);
2403            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling QueryInterface(License)", GETNODESTR));
2404            iCmdState = EBusy;
2405            iCmdId = iNode->QueryInterface(iSessionId, PVMFCPMPluginLicenseInterfaceUuid, iLicenseInterface);
2406            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2407            return PVMFPending;
2408
2409        case EQueryDataSourcePlayback:
2410            OSCL_ASSERT(iNode != NULL);
2411            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling QueryInterface(datasourcePB)", GETNODESTR));
2412            iCmdState = EBusy;
2413            iCmdId = iNode->QueryInterface(iSessionId, PvmfDataSourcePlaybackControlUuid, iDataSourcePlayback);
2414            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2415            return PVMFPending;
2416
2417        case EInit:
2418            OSCL_ASSERT(iNode != NULL);
2419            if (iType == EFormatParser)
2420            {
2421                // For this command, which gets pushed to the format parser node, we set the source init and also
2422                // set the datstream factory
2423                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling SetSourceInitializationData", GETNODESTR));
2424
2425                if (!DataSourceInit())
2426                    return PVMFFailure; //no source init interface?
2427                if (!DatastreamUser())
2428                    return PVMFFailure; //no datastreamuser interface?
2429
2430                //Pass data to the parser node.
2431                if (iContainer->iInitFailedLicenseRequired)
2432                {
2433                    ;//do nothing-- data was already set on the first init call.
2434                }
2435                else
2436                {
2437                    //Pass source data
2438                    if (iContainer->iSourceFormat == PVMF_MIME_DATA_SOURCE_PVX_FILE)
2439                    {
2440                        // let the parser know this is PVX format.
2441                        PVMFFormatType fmt = PVMF_MIME_DATA_SOURCE_PVX_FILE;
2442                        (DataSourceInit())->SetSourceInitializationData(iContainer->iDownloadFileName
2443                                , fmt
2444                                , (OsclAny*)&iContainer->iLocalDataSource);
2445                    }
2446                    else if (iContainer->iSourceFormat == PVMF_MIME_DATA_SOURCE_SHOUTCAST_URL)
2447                    {
2448                        // let the parser node know that it is playing from a shoutcast stream
2449                        (DataSourceInit())->SetSourceInitializationData(iContainer->iDownloadFileName
2450                                , iContainer->iSourceFormat
2451                                , (OsclAny*)iContainer->iSourceData);
2452                    }
2453                    else
2454                    {
2455                        // pass the recognized format to the parser.
2456                        (DataSourceInit())->SetSourceInitializationData(iContainer->iDownloadFileName
2457                                , iContainer->iFmt
2458                                , (OsclAny*)iContainer->iSourceData);
2459                    }
2460
2461                    //Pass datastream data.
2462                    (DatastreamUser())->PassDatastreamFactory(*(iContainer->iReadFactory), (int32)0);
2463                    PVMFFileBufferDataStreamWriteDataStreamFactoryImpl* wdsfactory =
2464                        OSCL_STATIC_CAST(PVMFFileBufferDataStreamWriteDataStreamFactoryImpl*, iContainer->iWriteFactory);
2465                    int32 leavecode = 0;
2466                    OSCL_TRY(leavecode,
2467                             PVMFDataStreamReadCapacityObserver* obs =
2468                                 OSCL_STATIC_CAST(PVMFDataStreamReadCapacityObserver*, wdsfactory);
2469                             (DatastreamUser())->PassDatastreamReadCapacityObserver(obs));
2470                    OSCL_FIRST_CATCH_ANY(leavecode,
2471                                         LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s PassDatastreamReadCapacityObserver not supported", GETNODESTR));
2472                                        );
2473                }
2474
2475                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling Init ", GETNODESTR));
2476                iCmdState = EBusy;
2477                iCmdId = iNode->Init(iSessionId);
2478                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2479                return PVMFPending;
2480            }
2481            else
2482            {
2483                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling Init ", GETNODESTR));
2484                iCmdState = EBusy;
2485                iCmdId = iNode->Init(iSessionId);
2486                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2487                return PVMFPending;
2488            }
2489
2490        case ECPMGetLicenseW:
2491        {
2492            OSCL_ASSERT(iNode != NULL);
2493            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling ECPMGetLicenseW", GETNODESTR));
2494            iCmdState = EBusy;
2495            OSCL_wString* contentName = NULL;
2496            OsclAny* data = NULL;
2497            uint32 dataSize = 0;
2498            int32 timeoutMsec = 0;
2499            nodeCmd->Parse(contentName,
2500                           data,
2501                           dataSize,
2502                           timeoutMsec);
2503            iCmdId =
2504                LicenseInterface()->GetLicense(iSessionId,
2505                                               *contentName,
2506                                               data,
2507                                               dataSize,
2508                                               timeoutMsec);
2509            iCPMGetLicenseCmdId = iCmdId;
2510
2511            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2512            return PVMFPending;
2513        }
2514        case ECPMGetLicense:
2515        {
2516            OSCL_ASSERT(iNode != NULL);
2517            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling ECPMGetLicense", GETNODESTR));
2518            iCmdState = EBusy;
2519            OSCL_String* contentName = NULL;
2520            OsclAny* data = NULL;
2521            uint32 dataSize = 0;
2522            int32 timeoutMsec = 0;
2523            nodeCmd->Parse(contentName,
2524                           data,
2525                           dataSize,
2526                           timeoutMsec);
2527            iCmdId =
2528                LicenseInterface()->GetLicense(iSessionId,
2529                                               *contentName,
2530                                               data,
2531                                               dataSize,
2532                                               timeoutMsec);
2533            iCPMGetLicenseCmdId = iCmdId;
2534
2535            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2536            return PVMFPending;
2537        }
2538
2539        case ERequestPort:
2540            OSCL_ASSERT(iNode != NULL);
2541            // The parameters to RequestPort vary depending on which node we're getting a port from, so we switch on it.
2542            switch (iType)
2543            {
2544                case EProtocolEngine:
2545                    LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling RequestPort ", GETNODESTR));
2546                    iCmdState = EBusy;
2547                    // For protocol engine port request, we don't need port tag or config info because it's the only port we ask it for.
2548                    iCmdId = iNode->RequestPort(iSessionId, (int32)0);
2549                    LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2550                    return PVMFPending;
2551
2552                case ESocket:
2553                    LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling RequestPort with port config %s", GETNODESTR, iContainer->iServerAddr.get_cstr()));
2554                    iCmdState = EBusy;
2555                    //append a mimestring to the port for socket node logging
2556                    iContainer->iServerAddr += ";mime=download";
2557                    iCmdId = iNode->RequestPort(iSessionId, PVMF_SOCKET_NODE_PORT_TYPE_PASSTHRU, &iContainer->iServerAddr);
2558                    LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2559                    return PVMFPending;
2560
2561                case EFormatParser:
2562                    //extract params from current Node command.
2563                    OSCL_ASSERT(nodeCmd->iCmd == PVMF_GENERIC_NODE_REQUESTPORT);
2564                    {
2565                        int32 aPortTag;
2566                        OSCL_String*aMimetype;
2567                        nodeCmd->PVMFDownloadManagerNodeCommandBase::Parse(aPortTag, aMimetype);
2568
2569                        LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling RequestPort ", GETNODESTR));
2570                        iCmdState = EBusy;
2571                        iCmdId = iNode->RequestPort(iSessionId, aPortTag, aMimetype);
2572                    }
2573                    LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2574                    return PVMFPending;
2575
2576                default:
2577                    OSCL_ASSERT(false);
2578                    return PVMFFailure;
2579            }
2580
2581        case EReleasePort:
2582            OSCL_ASSERT(iNode != NULL);
2583            {
2584                //extract params from current Node command.
2585                OSCL_ASSERT(nodeCmd->iCmd == PVMF_GENERIC_NODE_RELEASEPORT);
2586                PVMFPortInterface *port;
2587                nodeCmd->PVMFDownloadManagerNodeCommandBase::Parse(port);
2588                OSCL_ASSERT(port != NULL);
2589
2590                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling ReleasePort", GETNODESTR));
2591                iCmdState = EBusy;
2592                iCmdId = iNode->ReleasePort(iSessionId, *port);
2593                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2594                return PVMFPending;
2595            }
2596
2597        case EPrepare:
2598            OSCL_ASSERT(iNode != NULL);
2599            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling Prepare", GETNODESTR));
2600            iCmdState = EBusy;
2601            iCmdId = iNode->Prepare(iSessionId);
2602            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2603            return PVMFPending;
2604
2605        case EStop:
2606            OSCL_ASSERT(iNode != NULL);
2607            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling Stop", GETNODESTR));
2608            iCmdState = EBusy;
2609            iCmdId = iNode->Stop(iSessionId);
2610            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2611            return PVMFPending;
2612
2613        case EStart:
2614            OSCL_ASSERT(iNode != NULL);
2615            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling Start", GETNODESTR));
2616            iCmdState = EBusy;
2617            iCmdId = iNode->Start(iSessionId);
2618            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2619            return PVMFPending;
2620
2621        case EPause:
2622            OSCL_ASSERT(iNode != NULL);
2623            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling Pause", GETNODESTR));
2624            iCmdState = EBusy;
2625            iCmdId = iNode->Pause(iSessionId);
2626            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2627            return PVMFPending;
2628
2629        case EFlush:
2630            OSCL_ASSERT(iNode != NULL);
2631            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling Flush", GETNODESTR));
2632            iCmdState = EBusy;
2633            iCmdId = iNode->Flush(iSessionId);
2634            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2635            return PVMFPending;
2636
2637        case EReset:
2638            OSCL_ASSERT(iNode != NULL);
2639            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling Reset", GETNODESTR));
2640            iCmdState = EBusy;
2641            iCmdId = iNode->Reset(iSessionId);
2642            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2643            return PVMFPending;
2644
2645        case EGetMetadataKey:
2646            OSCL_ASSERT(iNode != NULL);
2647            {
2648                if (!Metadata())
2649                    return PVMFErrNotSupported;//no interface!
2650
2651                //extract params from current Node command.
2652                OSCL_ASSERT(nodeCmd->iCmd == PVDLM_NODE_CMD_GETNODEMETADATAKEY);
2653
2654                PVMFMetadataList* aKeyList;
2655                uint32 starting_index;
2656                int32 max_entries;
2657                char* query_key;
2658
2659                nodeCmd->Parse(aKeyList, starting_index, max_entries, query_key);
2660                OSCL_ASSERT(aKeyList != NULL);
2661                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling GetNodeMetadataKeys", GETNODESTR));
2662                iCmdState = EBusy;
2663                iCmdId = (Metadata())->GetNodeMetadataKeys(iSessionId, *aKeyList, starting_index, max_entries, query_key, NULL);
2664
2665                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2666                return PVMFPending;
2667            }
2668
2669
2670        case EGetMetadataValue:
2671            OSCL_ASSERT(iNode != NULL);
2672            {
2673                if (!Metadata())
2674                    return PVMFErrNotSupported;//no interface!
2675
2676                //extract params from current Node command.
2677                OSCL_ASSERT(nodeCmd->iCmd == PVDLM_NODE_CMD_GETNODEMETADATAVALUE);
2678                PVMFMetadataList* aKeyList;
2679                Oscl_Vector<PvmiKvp, OsclMemAllocator>* aValueList;
2680                uint32 starting_index;
2681                int32 max_entries;
2682                nodeCmd->Parse(aKeyList, aValueList, starting_index, max_entries);
2683                OSCL_ASSERT(aKeyList != NULL);
2684                OSCL_ASSERT(aValueList != NULL);
2685
2686                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling GetNodeMetadataValues", GETNODESTR));
2687                iCmdState = EBusy;
2688                iCmdId = (Metadata())->GetNodeMetadataValues(iSessionId, *aKeyList, *aValueList, starting_index, max_entries, NULL);
2689                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2690                return PVMFPending;
2691            }
2692
2693        case EQueryFFProgDownload:
2694            OSCL_ASSERT(iNode != NULL);
2695            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling QueryInterface (format prog dl)", GETNODESTR));
2696            iCmdState = EBusy;
2697            iCmdId = iNode->QueryInterface(iSessionId, PVMF_FF_PROGDOWNLOAD_SUPPORT_INTERFACE_UUID, iFormatProgDownloadSupport);
2698            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2699            return PVMFPending;
2700
2701        case EQueryDownloadProgress:
2702            OSCL_ASSERT(iNode != NULL);
2703            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling QueryInterface (dl prog)", GETNODESTR));
2704            iCmdState = EBusy;
2705            iCmdId = iNode->QueryInterface(iSessionId, PVMF_DOWNLOAD_PROGRESS_INTERFACE_UUID, iDownloadProgress);
2706            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2707            return PVMFPending;
2708
2709        case ESetFFProgDownloadSupport:
2710            OSCL_ASSERT(iNode != NULL);
2711
2712            if (!DownloadProgress() || !iContainer->iFormatParserNode.FormatProgDownloadSupport())
2713                return PVMFErrNotSupported;//no interface!
2714
2715            //pass parser node format prog download interface to the protocol node.
2716            LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling setFormatDownloadSupportInterface", GETNODESTR));
2717            (DownloadProgress())->setFormatDownloadSupportInterface(iContainer->iFormatParserNode.FormatProgDownloadSupport());
2718            return PVMFSuccess;
2719
2720        case ESetDataSourcePosition:
2721            OSCL_ASSERT(iNode != NULL);
2722            {
2723                if (!DataSourcePlayback())
2724                    return PVMFErrNotSupported;//no interface!
2725
2726                //extract params from current Node command.
2727                OSCL_ASSERT(nodeCmd->iCmd == PVDLM_NODE_CMD_SETDATASOURCEPOSITION);
2728                PVMFTimestamp aTargetNPT;
2729                PVMFTimestamp* aActualNPT;
2730                PVMFTimestamp* aActualMediaDataTS;
2731                uint32 streamID = 0;
2732                bool aJump;
2733                nodeCmd->Parse(aTargetNPT, aActualNPT, aActualMediaDataTS, aJump, streamID);
2734                OSCL_ASSERT(aActualNPT != NULL);
2735                OSCL_ASSERT(aActualMediaDataTS != NULL);
2736
2737                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling SetDataSourcePosition", GETNODESTR));
2738                iCmdState = EBusy;
2739                iCmdId = (DataSourcePlayback())->SetDataSourcePosition(iSessionId, aTargetNPT, *aActualNPT, *aActualMediaDataTS, aJump, streamID);
2740                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2741                return PVMFPending;
2742            }
2743
2744        case EQueryDataSourcePosition:
2745            OSCL_ASSERT(iNode != NULL);
2746            {
2747                if (!DataSourcePlayback())
2748                    return PVMFErrNotSupported;//no interface!
2749
2750                //extract params from current Node command.
2751                OSCL_ASSERT(nodeCmd->iCmd == PVDLM_NODE_CMD_QUERYDATASOURCEPOSITION);
2752                PVMFTimestamp aTargetNPT;
2753                PVMFTimestamp* aActualNPT;
2754                bool aJump;
2755                nodeCmd->Parse(aTargetNPT, aActualNPT, aJump);
2756                OSCL_ASSERT(aActualNPT != NULL);
2757
2758                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s Calling QueryDataSourcePosition", GETNODESTR));
2759                iCmdState = EBusy;
2760                iCmdId = (DataSourcePlayback())->QueryDataSourcePosition(iSessionId, aTargetNPT, *aActualNPT, aJump);
2761                LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::IssueCommand %s CmdId %d ", GETNODESTR, iCmdId));
2762                return PVMFPending;
2763            }
2764
2765        default:
2766            OSCL_ASSERT(false);
2767            return PVMFFailure;
2768    }
2769}
2770
2771
2772PVMFStatus PVMFDownloadManagerRecognizerContainer::IssueCommand(int32 aCmd)
2773{
2774    //Issue a command to the Recognizer.
2775    //Return the completion status-- either pending, success, or failure.
2776
2777    LOGSUBCMD((0, "PVMFDownloadManagerRecognizerContainer::IssueCommand In"));
2778
2779    OSCL_ASSERT(!CmdPending());
2780
2781    //save the sub-node command code
2782    iCmd = aCmd;
2783
2784    switch (aCmd)
2785    {
2786        case ERecognizerStart:
2787        {
2788            PVMFStatus status = PVMFRecognizerRegistry::OpenSession(iRecognizerSessionId, (*this));
2789            if (status == PVMFSuccess)
2790            {
2791                //Issue the asynchronous command to the recognizer.
2792                iCmdState = EBusy;
2793                iCmdId = PVMFRecognizerRegistry::Recognize(iRecognizerSessionId,
2794                         *(iContainer->iReadFactory),
2795                         NULL,
2796                         iRecognizerResultVec);
2797                LOGSUBCMD((0, "PVMFDownloadManagerRecognizerContainer::IssueCommand Recognize Pending Cmd ID %d", iCmdId));
2798                return PVMFPending;
2799                //wait on the RecognizerCommandCompleted callback.
2800            }
2801            else
2802            {
2803                PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_ERR, (0,
2804                                "PVMFDownloadManagerRecognizerContainer::IssueCommand Open Session Failed, status %d", status));
2805            }
2806            return status;
2807        }
2808        // break;   This statement was removed to avoid compiler warning for Unreachable Code
2809
2810        case ERecognizerClose:
2811            //close the recognizer session.
2812        {
2813            PVMFStatus status = PVMFRecognizerRegistry::CloseSession(iRecognizerSessionId);
2814            if (status != PVMFSuccess)
2815            {
2816                PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_ERR, (0,
2817                                "PVMFDownloadManagerRecognizerContainer::IssueCommand CloseSession status %d", status));
2818            }
2819            return status;
2820        }
2821
2822        default:
2823            LOGSUBCMD((0, "PVMFDownloadManagerRecognizerContainer::IssueCommand Error, Unknown Recognizer Command!"));
2824            OSCL_ASSERT(false);//unknown command type for recognizer.
2825            return PVMFFailure;
2826    }
2827}
2828
2829//this is the callback from the Recognizer::Recognize command.
2830void PVMFDownloadManagerRecognizerContainer::RecognizerCommandCompleted(const PVMFCmdResp& aResponse)
2831{
2832    if (aResponse.GetCmdId() == iCmdId
2833            && iCmdState == EBusy)
2834    {
2835        //save the result.
2836        if (aResponse.GetCmdStatus() == PVMFSuccess
2837                && iRecognizerResultVec.size() > 0)
2838        {
2839            // if there is only 1, use it
2840            // if more than 1, check the confidence level
2841            if (1 == iRecognizerResultVec.size())
2842            {
2843                iContainer->iMimeType = iRecognizerResultVec[0].iRecognizedFormat;
2844            }
2845            else
2846            {
2847                // if certain, use it
2848                // if possible, keep looking
2849                bool found = false;
2850                for (uint32 i = 0; i < iRecognizerResultVec.size(); i++)
2851                {
2852                    if (PVMFRecognizerConfidenceCertain == iRecognizerResultVec[i].iRecognitionConfidence)
2853                    {
2854                        found = true;
2855                        iContainer->iMimeType = iRecognizerResultVec[i].iRecognizedFormat;
2856                        break;
2857                    }
2858                }
2859
2860                // if Content-Type may not be known, just use the first result
2861                if (!found && (0 != iContainer->iContentTypeMIMEString.get_size()))
2862                {
2863                    // no certain, all possibles
2864                    // compare with the Content-Type hint, which is in IANA MIME string format
2865                    // these are file formats, does not include streaming formats
2866                    // @TODO: need to add the following to "pvmi/pvmf/include/pvmf_format_type.h"
2867                    //
2868                    // MP4 + 3GPP = "video/3gpp", "video/mp4", "audio/3gpp", "audio/mp4", "video/3gpp-tt"
2869                    // AMR = "audio/amr", "audio/amr-wb"
2870                    // AAC = "audio/aac", "audio/x-aac", "audio/aacp"
2871                    // MP3 = "audio/mpeg"
2872                    // WM + ASF = "video/x-ms-wmv", "video/x-ms-wm", "video/x-ms-asf","audio/x-ms-wma",
2873                    // RM = "video/vnd.rn-realvideo", "audio/vnd.rn-realaudio"
2874                    // WAV = "audio/wav", "audio/x-wav", "audio/wave"
2875                    //
2876                    // the recognizer plugins may return PV proprietary format, X-...
2877                    // in "pvmi/pvmf/include/pvmf_format_type.h"
2878                    // #define PVMF_MIME_MPEG4FF               "video/MP4"
2879                    // #define PVMF_MIME_AMRFF                 "X-AMR-FF"
2880                    // #define PVMF_MIME_AACFF                 "X-AAC-FF"
2881                    // #define PVMF_MIME_MP3FF                 "X-MP3-FF"
2882                    // #define PVMF_MIME_WAVFF                 "X-WAV-FF"
2883                    // #define PVMF_MIME_ASFFF                 "x-pvmf/mux/asf"
2884                    // #define PVMF_MIME_RMFF                  "x-pvmf/mux/rm"
2885
2886                    // need case insensitive compares
2887                    const char* mimeStr = iContainer->iContentTypeMIMEString.get_cstr();
2888
2889                    for (uint32 i = 0; !found && i < iRecognizerResultVec.size(); i++)
2890                    {
2891                        const char* recognizedStr = iRecognizerResultVec[i].iRecognizedFormat.get_cstr();
2892                        if (0 == oscl_CIstrcmp(recognizedStr, PVMF_MIME_MPEG4FF))
2893                        {
2894                            if ((0 == oscl_CIstrcmp(mimeStr, "video/3gpp"))    ||
2895                                    (0 == oscl_CIstrcmp(mimeStr, "video/mp4"))     ||
2896                                    (0 == oscl_CIstrcmp(mimeStr, "audio/3gpp"))    ||
2897                                    (0 == oscl_CIstrcmp(mimeStr, "audio/mp4"))     ||
2898                                    (0 == oscl_CIstrcmp(mimeStr, "video/3gpp-tt")))
2899                            {
2900                                found = true;
2901                                iContainer->iMimeType = iRecognizerResultVec[i].iRecognizedFormat;
2902                            }
2903                        }
2904                        else if (0 == oscl_CIstrcmp(recognizedStr, PVMF_MIME_MP3FF))
2905                        {
2906                            if ((0 == oscl_CIstrcmp(mimeStr, "audio/mpeg")))
2907                            {
2908                                found = true;
2909                                iContainer->iMimeType = iRecognizerResultVec[i].iRecognizedFormat;
2910                            }
2911                        }
2912                        else if (0 == oscl_CIstrcmp(recognizedStr, PVMF_MIME_AACFF))
2913                        {
2914                            if ((0 == oscl_CIstrcmp(mimeStr, "audio/aac"))   ||
2915                                    (0 == oscl_CIstrcmp(mimeStr, "audio/x-aac")) ||
2916                                    (0 == oscl_CIstrcmp(mimeStr, "audio/aacp")))
2917                            {
2918                                found = true;
2919                                iContainer->iMimeType = iRecognizerResultVec[i].iRecognizedFormat;
2920                            }
2921                        }
2922                        else if (0 == oscl_CIstrcmp(recognizedStr, PVMF_MIME_AMRFF))
2923                        {
2924                            if ((0 == oscl_CIstrcmp(mimeStr, "audio/amr"))  ||
2925                                    (0 == oscl_CIstrcmp(mimeStr, "audio/amr-wb")))
2926                            {
2927                                found = true;
2928                                iContainer->iMimeType = iRecognizerResultVec[i].iRecognizedFormat;
2929                            }
2930                        }
2931                        else if (0 == oscl_CIstrcmp(recognizedStr, PVMF_MIME_ASFFF))
2932                        {
2933                            if ((0 == oscl_CIstrcmp(mimeStr, "video/x-ms-wmv"))  ||
2934                                    (0 == oscl_CIstrcmp(mimeStr, "video/x-ms-wm"))   ||
2935                                    (0 == oscl_CIstrcmp(mimeStr, "video/x-ms-asf"))  ||
2936                                    (0 == oscl_CIstrcmp(mimeStr, "audio/x-ms-wma")))
2937                            {
2938                                found = true;
2939                                iContainer->iMimeType = iRecognizerResultVec[i].iRecognizedFormat;
2940                            }
2941                        }
2942                        else if (0 == oscl_CIstrcmp(recognizedStr, PVMF_MIME_RMFF))
2943                        {
2944                            if ((0 == oscl_CIstrcmp(mimeStr, "video/vnd.rn-realvideo"))  ||
2945                                    (0 == oscl_CIstrcmp(mimeStr, "audio/vnd.rn-realaudio")))
2946                            {
2947                                found = true;
2948                                iContainer->iMimeType = iRecognizerResultVec[i].iRecognizedFormat;
2949                            }
2950                        }
2951                        else if ((0 == oscl_CIstrcmp(recognizedStr, PVMF_MIME_WAVFF)))
2952                        {
2953                            if ((0 == oscl_CIstrcmp(mimeStr, "audio/wav"))    ||
2954                                    (0 == oscl_CIstrcmp(mimeStr, "audio/wave"))   ||
2955                                    (0 == oscl_CIstrcmp(mimeStr, "audio/x-wav")))
2956                            {
2957                                found = true;
2958                                iContainer->iMimeType = iRecognizerResultVec[i].iRecognizedFormat;
2959                            }
2960                        }
2961                        else
2962                        {
2963                            // some new format that this component does not know about
2964                            // we'll use it
2965                            found = true;
2966                            iContainer->iMimeType = iRecognizerResultVec[i].iRecognizedFormat;
2967                        }
2968                    }
2969                }
2970
2971                // if still no match found
2972                // need to wait for more data and run the recognizer again, will implement this later
2973                // just use the first one for now
2974                if (!found)
2975                {
2976                    // @TODO - implement the recognizer loop later
2977                    iContainer->iMimeType = iRecognizerResultVec[0].iRecognizedFormat;
2978                }
2979            }
2980        }
2981
2982        CommandDone(aResponse.GetCmdStatus(), aResponse.GetEventExtensionInterface(), aResponse.GetEventData());
2983
2984        //catch completion of cancel for recognizer commands
2985        //since there's no cancel to the recognizer module, the cancel
2986        //is done whenever the current recognizer command is done.
2987        if (iCancelCmdState != EIdle)
2988        {
2989            CancelCommandDone(PVMFSuccess, NULL, NULL);
2990        }
2991    }
2992    else
2993    {
2994        OSCL_ASSERT(false);//unexpected response.
2995    }
2996}
2997
2998//from PVMFNodeErrorEventObserver
2999void PVMFDownloadManagerSubNodeContainer::HandleNodeErrorEvent(const PVMFAsyncEvent& aEvent)
3000{
3001    //A sub-node is reporting an event.
3002
3003    //print events
3004    switch (iType)
3005    {
3006        case EFormatParser:
3007            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_ERR, (0,
3008                            "PVMFDownloadManagerSubNodeContainer::HandleNodeErrorEvent Parser Node Error Event %d", aEvent.GetEventType()));
3009            break;
3010        case EProtocolEngine:
3011            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_ERR, (0,
3012                            "PVMFDownloadManagerSubNodeContainer::HandleNodeErrorEvent ProtocolEngine Node Error Event %d", aEvent.GetEventType()));
3013            break;
3014        case ESocket:
3015            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_ERR, (0,
3016                            "PVMFDownloadManagerSubNodeContainer::HandleNodeErrorEvent Socket Node Error Event %d", aEvent.GetEventType()));
3017            if (iContainer->iDownloadComplete)
3018                return; // Suppress socket node error, if the download is already complete.
3019            break;
3020        default:
3021            OSCL_ASSERT(false);
3022            break;
3023    }
3024
3025    //duplicate any PVMF Error events from either node.
3026    if (IsPVMFErrCode(aEvent.GetEventType()))
3027        iContainer->ReportErrorEvent(aEvent.GetEventType(), aEvent.GetEventExtensionInterface(), aEvent.GetEventData());
3028}
3029
3030#include "pvmf_protocol_engine_node_events.h"
3031
3032//from PVMFNodeInfoEventObserver
3033void PVMFDownloadManagerSubNodeContainer::HandleNodeInformationalEvent(const PVMFAsyncEvent& aEvent)
3034{
3035    //A sub-node is reporting an event.
3036
3037    //detect sub-node error states.
3038    if (aEvent.GetEventType() == PVMFInfoStateChanged
3039            && iNode->GetState() == EPVMFNodeError)
3040    {
3041        iContainer->SetState(EPVMFNodeError);
3042    }
3043
3044    //detect important status events.
3045    if (iType == EProtocolEngine)
3046    {
3047        switch (aEvent.GetEventType())
3048        {
3049            case PVMFInfoBufferingComplete:
3050                iContainer->iDownloadComplete = true;
3051                iContainer->NotifyDownloadComplete();
3052                //not sure whether this is possible, but just in case download
3053                //completes before movie atom notice, go ahead and do anything
3054                //that was waiting on movie atom.
3055                if (!iContainer->iMovieAtomComplete)
3056                    iContainer->ContinueAfterMovieAtom();
3057                break;
3058            case PVMFPROTOCOLENGINE_INFO_MovieAtomCompleted:
3059                //we may be waiting on this event to continue Parser init.
3060                if (!iContainer->iMovieAtomComplete)
3061                    iContainer->ContinueAfterMovieAtom();
3062                if (iContainer->iDebugMode)
3063                {
3064                    iContainer->ReportInfoEvent((PVMFAsyncEvent&)aEvent);
3065                }
3066                break;
3067            default:
3068                break;
3069        }
3070    }
3071
3072    //filter out events that we don't want to pass up to observer
3073    bool filter = false;
3074    if (iType == ESocket)
3075    {
3076        switch (aEvent.GetEventType())
3077        {
3078            case PVMFInfoRemoteSourceNotification:  //To let the socket node events propagate to pvengine
3079                filter = false;
3080                break;
3081            default:
3082                filter = true;
3083        }
3084    }
3085    else
3086    {
3087        switch (aEvent.GetEventType())
3088        {
3089            case PVMFInfoStateChanged:
3090                filter = true;//always ignore
3091                break;
3092            case PVMFInfoPortDeleted:
3093            case PVMFInfoPortCreated:
3094            case PVMFInfoPortConnected:
3095            case PVMFInfoPortDisconnected:
3096                if (iType != EFormatParser)
3097                    filter = true;//ignore port events unless from format parser
3098                break;
3099            case PVMFInfoUnderflow:
3100            case PVMFInfoDataReady:
3101            case PVMFInfoRemoteSourceNotification:
3102                //apply some filtering to these
3103                if (iContainer->FilterPlaybackEventsFromSubNodes(aEvent))
3104                    filter = true;
3105                break;
3106            default:
3107                break;
3108        }
3109    }
3110
3111    //duplicate all remaining PVMFInfo events.
3112    if (!filter
3113            && IsPVMFInfoCode(aEvent.GetEventType()))
3114    {
3115        iContainer->ReportInfoEvent((PVMFAsyncEvent&)aEvent);
3116    }
3117
3118    //just print and ignore other events
3119    switch (iType)
3120    {
3121        case EFormatParser:
3122            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_DEBUG, (0,
3123                            "PVMFDownloadManagerSubNodeContainer::HandleNodeInfoEvent Parser Node Info Event %d", aEvent.GetEventType()));
3124            break;
3125        case EProtocolEngine:
3126            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_DEBUG, (0,
3127                            "PVMFDownloadManagerSubNodeContainer::HandleNodeInfoEvent ProtocolEngine Node Info Event %d", aEvent.GetEventType()));
3128            break;
3129        case ESocket:
3130            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_DEBUG, (0,
3131                            "PVMFDownloadManagerSubNodeContainer::HandleNodeInfoEvent Socket Node Info Event %d", aEvent.GetEventType()));
3132            break;
3133
3134        default:
3135            OSCL_ASSERT(false);
3136            break;
3137    }
3138}
3139
3140bool PVMFDownloadManagerSubNodeContainer::CancelPendingCommand()
3141{
3142    //initiate sub-node command cancel, return True if cancel initiated.
3143
3144    if (iCmdState != EBusy)
3145        return false;//nothing to cancel
3146
3147    iCancelCmdState = EBusy;
3148
3149    if (iNode)
3150    {
3151        LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::CancelPendingCommand Calling Cancel"));
3152        iCancelCmdId = iNode->CancelCommand(iSessionId, iCmdId, NULL);
3153        LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::CancelPendingCommand CmdId %d", iCancelCmdId));
3154    }
3155
3156    return true;//cancel initiated
3157}
3158
3159bool PVMFDownloadManagerRecognizerContainer::CancelPendingCommand()
3160{
3161    //initiate sub-node command cancel, return True if cancel initiated.
3162
3163    if (iCmdState != EBusy)
3164        return false;//nothing to cancel
3165
3166    iCancelCmdState = EBusy;
3167
3168    LOGSUBCMD((0, "PVMFDownloadManagerRecognizerContainer::CancelPendingCommand Calling Cancel"));
3169    iCancelCmdId = PVMFRecognizerRegistry::CancelCommand(iRecognizerSessionId, iCmdId, NULL);
3170    LOGSUBCMD((0, "PVMFDownloadManagerRecognizerContainer::CancelPendingCommand CmdId %d", iCancelCmdId));
3171
3172    return true;//cancel initiated
3173}
3174
3175
3176void PVMFDownloadManagerSubNodeContainerBase::CommandDone(PVMFStatus aStatus, PVInterface*aExtMsg, OsclAny*aEventData)
3177{
3178    //a sub-node command is done-- process the result.
3179
3180    OSCL_ASSERT(aStatus != PVMFPending);
3181
3182    //pop the sub-node command vector.
3183    OSCL_ASSERT(!iContainer->iSubNodeCmdVec.empty());
3184    iContainer->iSubNodeCmdVec.erase(&iContainer->iSubNodeCmdVec.front());
3185
3186    iCmdState = EIdle;
3187
3188    PVMFStatus status = aStatus;
3189
3190    // Set "Init Failed License Required" flag with the results of parser Init.
3191    if (iType == EFormatParser && iCmd == EInit)
3192    {
3193        iContainer->iInitFailedLicenseRequired = (status == PVMFErrLicenseRequired);
3194    }
3195
3196    // Watch for the request port command completion from the protocol node, because we need to save the port pointer
3197    if (iType == EProtocolEngine && iCmd == ERequestPort && status == PVMFSuccess)
3198    {
3199        iContainer->iProtocolEngineNodePort = (PVMFPortInterface*)aEventData;
3200        // If both ports are non-null, connect them.
3201        if (iContainer->iSocketNodePort && iContainer->iProtocolEngineNodePort)
3202        {
3203            iContainer->iSocketNodePort->Connect(iContainer->iProtocolEngineNodePort);
3204
3205            // The ports are connected, so now we pass the datastream factory to the protocol node via the extension interface, if it's available.
3206            if (iContainer->iProtocolEngineNode.iDatastreamUser)
3207            {
3208                ((PVMIDatastreamuserInterface*)iContainer->iProtocolEngineNode.iDatastreamUser)->PassDatastreamFactory(*(iContainer->iWriteFactory), (int32)0);
3209            }
3210        }
3211    }
3212
3213    // Watch for the request port command completion from the socket node, because we need to save the port pointer
3214    if (iType == ESocket && iCmd == ERequestPort && status == PVMFSuccess)
3215    {
3216        iContainer->iSocketNodePort = (PVMFPortInterface*)aEventData;
3217    }
3218
3219
3220    // Watch for the query track selection interface completion from the protocol engine node.
3221    if (iType == EProtocolEngine && iCmd == EQueryTrackSelection)
3222    {
3223        //see whether we got the TS interface from PE node.
3224        iContainer->iNoPETrackSelect = (status != PVMFSuccess || iContainer->iProtocolEngineNode.iTrackSelection == NULL);
3225        //ignore cmd failure so it won't terminate the Init sequence
3226        if (status != PVMFSuccess)
3227            status = PVMFSuccess;
3228        //Continue the Init sequence now that we have the track select decision.
3229        iContainer->ContinueInitAfterTrackSelectDecision();
3230    }
3231
3232    // Watch for recognizer start failure
3233    if (iType == ERecognizer && iCmd == ERecognizerStart && aStatus != PVMFSuccess)
3234    {
3235        iContainer->iRecognizerError = true;
3236        //save the error code to report after recognizer close.
3237        iContainer->iRecognizerStartStatus = status;
3238        //purge everything from the subnode command vector except the recognizer
3239        //close command
3240        iContainer->iSubNodeCmdVec.clear();
3241        iContainer->Push(iContainer->iRecognizerNode, PVMFDownloadManagerSubNodeContainerBase::ERecognizerClose);
3242        //set status to "success" so that we'll continue with processing
3243        status = PVMFSuccess;
3244    }
3245    // Watch for recognizer close completion after a start failure
3246    else if (iContainer->iRecognizerError)
3247    {
3248        OSCL_ASSERT(iCmd == ERecognizerClose);
3249        iContainer->iRecognizerError = false;
3250        //restore the original error code from the recognizer start.
3251        status = iContainer->iRecognizerStartStatus;
3252    }
3253
3254    //Check whether the node command is being cancelled.
3255    if (iCancelCmdState != EIdle)
3256    {
3257        if (!iContainer->iSubNodeCmdVec.empty())
3258        {
3259            //even if this command succeeded, we want to report
3260            //the node command status as cancelled since some sub-node
3261            //commands were not yet issued.
3262            status = PVMFErrCancelled;
3263            //go into an error state since it's not clear
3264            //how to recover from a partially completed command.
3265            iContainer->SetState(EPVMFNodeError);
3266        }
3267    }
3268
3269    //figure out the next step in the sequence...
3270    //A node command is done when either all sub-node commands are
3271    //done or when one fails.
3272    if (status == PVMFSuccess
3273            && !iContainer->iSubNodeCmdVec.empty())
3274    {
3275        //The node needs to issue the next sub-node command.
3276        iContainer->RunIfNotReady();
3277    }
3278    else
3279    {
3280        //node command is done.
3281        OSCL_ASSERT(!iContainer->iCurrentCommand.empty());
3282        iContainer->CommandComplete(iContainer->iCurrentCommand, iContainer->iCurrentCommand.front(), status, aExtMsg, aEventData);
3283    }
3284}
3285
3286void PVMFDownloadManagerSubNodeContainerBase::CancelCommandDone(PVMFStatus aStatus, PVInterface*aExtMsg, OsclAny*aEventData)
3287{
3288    OSCL_UNUSED_ARG(aExtMsg);
3289    OSCL_UNUSED_ARG(aEventData);
3290    //a sub-node cancel command is done-- process the result.
3291
3292    OSCL_ASSERT(aStatus != PVMFPending);
3293
3294    iCancelCmdState = EIdle;
3295    //print and ignore any failed sub-node cancel commands.
3296    if (aStatus != PVMFSuccess)
3297    {
3298        switch (iType)
3299        {
3300            case EFormatParser:
3301                PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_DEBUG, (0,
3302                                "PVMFDownloadManagerSubNodeContainer::CancelCommandDone Parser Node Cancel failed"));
3303                break;
3304            case EProtocolEngine:
3305                PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_DEBUG, (0,
3306                                "PVMFDownloadManagerSubNodeContainer::CancelCommandDone ProtocolEngine Node Cancel failed"));
3307                break;
3308            case ESocket:
3309                PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_DEBUG, (0,
3310                                "PVMFDownloadManagerSubNodeContainer::CancelCommandDone Socket Node Cancel failed"));
3311                break;
3312            default:
3313                OSCL_ASSERT(false);
3314                break;
3315        }
3316    }
3317
3318    //Node cancel command is now done.
3319    OSCL_ASSERT(!iContainer->iCancelCommand.empty());
3320    iContainer->CommandComplete(iContainer->iCancelCommand, iContainer->iCancelCommand.front(), aStatus, NULL, NULL);
3321}
3322
3323//from PVMFNodeCmdStatusObserver
3324void PVMFDownloadManagerSubNodeContainer::NodeCommandCompleted(const PVMFCmdResp& aResponse)
3325{
3326    //A command to a sub-node is complete
3327    LOGSUBCMD((0, "PVMFDownloadManagerSubNodeContainer::NodeCommandCompleted %s () In CmdId %d Status %d", GETNODESTR, aResponse.GetCmdId(), aResponse.GetCmdStatus()));
3328
3329    if (aResponse.GetCmdStatus() != PVMFSuccess)
3330    {
3331        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iContainer->iLogger, PVLOGMSG_DEBUG, (0, "PVMFDownloadManagerSubNodeContainer::NodeCommandCompleted Failure! %d", aResponse.GetCmdStatus()));
3332    }
3333
3334    if (aResponse.GetCmdId() == iCmdId
3335            && iCmdState == EBusy)
3336    {
3337        //Process normal command response.
3338        CommandDone(aResponse.GetCmdStatus(), aResponse.GetEventExtensionInterface(), aResponse.GetEventData());
3339    }
3340    else if (aResponse.GetCmdId() == iCancelCmdId
3341             && iCancelCmdState == EBusy)
3342    {
3343        //Process node cancel command response
3344        CancelCommandDone(aResponse.GetCmdStatus(), aResponse.GetEventExtensionInterface(), aResponse.GetEventData());
3345    }
3346    //Process Get License cancel command response.
3347    else if (aResponse.GetCmdId() == iCPMCancelGetLicenseCmdId
3348             && iCancelCmdState == EBusy)
3349    {
3350        CancelCommandDone(aResponse.GetCmdStatus(), aResponse.GetEventExtensionInterface(), aResponse.GetEventData());
3351    }
3352    else
3353    {
3354        OSCL_ASSERT(false);//unexpected response.
3355    }
3356}
3357
3358
3359//From capability and config interface
3360PVMFStatus PVMFDownloadManagerNode::getParametersSync(PvmiMIOSession aSession,
3361        PvmiKeyType aIdentifier,
3362        PvmiKvp*& aParameters,
3363        int& aNumParamElements,
3364        PvmiCapabilityContext aContext)
3365{
3366    OSCL_UNUSED_ARG(aSession);
3367    OSCL_UNUSED_ARG(aContext);
3368    // Initialize the output parameters
3369    aNumParamElements = 0;
3370    aParameters = NULL;
3371
3372    // Count the number of components and parameters in the key
3373    int compcount = pv_mime_string_compcnt(aIdentifier);
3374    // Retrieve the first component from the key string
3375    char* compstr = NULL;
3376    pv_mime_string_extract_type(0, aIdentifier, compstr);
3377
3378    if ((pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf")) < 0) || compcount < 2)
3379    {
3380        // First component should be "x-pvmf" and there must
3381        // be at least two components to go past x-pvmf
3382        PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFDownloadManagerNode::getParametersSync() Invalid key string"));
3383        return PVMFErrArgument;
3384    }
3385
3386    // Retrieve the second component from the key string
3387    pv_mime_string_extract_type(1, aIdentifier, compstr);
3388
3389    // Check if it is key string for Download manager
3390    if (pv_mime_strcmp(compstr, _STRLIT_CHAR("net")) < 0)
3391    {
3392        PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFDownloadManagerNode::getParametersSync() Unsupported key"));
3393        return PVMFFailure;
3394    }
3395
3396
3397    if (compcount == 2)
3398    {
3399        // Since key is "x-pvmf/net" return all
3400        // nodes available at this level. Ignore attribute
3401        // since capability is only allowed
3402
3403        // Allocate memory for the KVP list
3404        aParameters = (PvmiKvp*)oscl_malloc(DownloadManagerConfig_NumBaseKeys * sizeof(PvmiKvp));
3405        if (aParameters == NULL)
3406        {
3407            PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFDownloadManagerNode::getParametersSync() Memory allocation for KVP failed"));
3408            return PVMFErrNoMemory;
3409        }
3410        oscl_memset(aParameters, 0, DownloadManagerConfig_NumBaseKeys*sizeof(PvmiKvp));
3411        // Allocate memory for the key strings in each KVP
3412        PvmiKeyType memblock = (PvmiKeyType)oscl_malloc(DownloadManagerConfig_NumBaseKeys * DLMCONFIG_KEYSTRING_SIZE * sizeof(char));
3413        if (memblock == NULL)
3414        {
3415            oscl_free(aParameters);
3416            PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFDownloadManagerNode::getParametersSync() Memory allocation for key string failed"));
3417            return PVMFErrNoMemory;
3418        }
3419        oscl_strset(memblock, 0, DownloadManagerConfig_NumBaseKeys*DLMCONFIG_KEYSTRING_SIZE*sizeof(char));
3420        // Assign the key string buffer to each KVP
3421        uint32 j;
3422        for (j = 0; j < DownloadManagerConfig_NumBaseKeys; ++j)
3423        {
3424            aParameters[j].key = memblock + (j * DLMCONFIG_KEYSTRING_SIZE);
3425        }
3426        // Copy the requested info
3427        for (j = 0; j < DownloadManagerConfig_NumBaseKeys; ++j)
3428        {
3429            oscl_strncat(aParameters[j].key, _STRLIT_CHAR("x-pvmf/net/"), 17);
3430            oscl_strncat(aParameters[j].key, DownloadManagerConfig_BaseKeys[j].iString, oscl_strlen(DownloadManagerConfig_BaseKeys[j].iString));
3431            oscl_strncat(aParameters[j].key, _STRLIT_CHAR(";type="), 6);
3432            switch (DownloadManagerConfig_BaseKeys[j].iType)
3433            {
3434                case PVMI_KVPTYPE_AGGREGATE:
3435                    oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPTYPE_AGGREGATE_STRING), oscl_strlen(PVMI_KVPTYPE_AGGREGATE_STRING));
3436                    break;
3437
3438                case PVMI_KVPTYPE_POINTER:
3439                    oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPTYPE_POINTER_STRING), oscl_strlen(PVMI_KVPTYPE_POINTER_STRING));
3440                    break;
3441
3442                case PVMI_KVPTYPE_VALUE:
3443                default:
3444                    oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPTYPE_VALUE_STRING), oscl_strlen(PVMI_KVPTYPE_VALUE_STRING));
3445                    break;
3446            }
3447            oscl_strncat(aParameters[j].key, _STRLIT_CHAR(";valtype="), 9);
3448            switch (DownloadManagerConfig_BaseKeys[j].iValueType)
3449            {
3450                case PVMI_KVPVALTYPE_RANGE_INT32:
3451                    oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_RANGE_INT32_STRING), oscl_strlen(PVMI_KVPVALTYPE_RANGE_INT32_STRING));
3452                    break;
3453
3454                case PVMI_KVPVALTYPE_KSV:
3455                    oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_KSV_STRING), oscl_strlen(PVMI_KVPVALTYPE_KSV_STRING));
3456                    break;
3457
3458                case PVMI_KVPVALTYPE_CHARPTR:
3459                    oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_CHARPTR_STRING), oscl_strlen(PVMI_KVPVALTYPE_CHARPTR_STRING));
3460                    break;
3461
3462                case PVMI_KVPVALTYPE_WCHARPTR:
3463                    oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_WCHARPTR_STRING), oscl_strlen(PVMI_KVPVALTYPE_WCHARPTR_STRING));
3464                    break;
3465
3466                case PVMI_KVPVALTYPE_BOOL:
3467                    oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_BOOL_STRING), oscl_strlen(PVMI_KVPVALTYPE_BOOL_STRING));
3468                    break;
3469
3470                case PVMI_KVPVALTYPE_UINT32:
3471                default:
3472                    oscl_strncat(aParameters[j].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_UINT32_STRING), oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING));
3473                    break;
3474            }
3475            aParameters[j].key[DLMCONFIG_KEYSTRING_SIZE-1] = 0;
3476        }
3477
3478        aNumParamElements = DownloadManagerConfig_NumBaseKeys;
3479    }
3480    else if (compcount == 3)
3481    {
3482        pv_mime_string_extract_type(2, aIdentifier, compstr);
3483
3484        // Determine what is requested
3485        PvmiKvpAttr reqattr = GetAttrTypeFromKeyString(aIdentifier);
3486        if (reqattr == PVMI_KVPATTR_UNKNOWN)
3487        {
3488            reqattr = PVMI_KVPATTR_CUR;
3489        }
3490        uint i;
3491        for (i = 0; i < DownloadManagerConfig_NumBaseKeys; i++)
3492        {
3493            if (pv_mime_strcmp(compstr, (char*)(DownloadManagerConfig_BaseKeys[i].iString)) >= 0)
3494            {
3495                break;
3496            }
3497        }
3498
3499        if (i == DownloadManagerConfig_NumBaseKeys)
3500        {
3501            // no match found
3502            PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
3503                            (0, "PVMFDownloadManagerNode::getParametersSync() Unsupported key"));
3504            return PVMFErrNoMemory;
3505        }
3506    }
3507    else
3508    {
3509        oscl_free(aParameters);
3510        PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFDownloadManagerNode::getParametersSync() Unsupported key"));
3511        return PVMFErrNoMemory;
3512    }
3513
3514    return PVMFSuccess;
3515}
3516
3517
3518PVMFStatus PVMFDownloadManagerNode::releaseParameters(PvmiMIOSession aSession,
3519        PvmiKvp* aParameters,
3520        int num_elements)
3521{
3522    OSCL_UNUSED_ARG(aSession);
3523
3524    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
3525                    (0, "PVMFDownloadManagerNode::releaseParameters() In"));
3526
3527    if (aParameters == NULL || num_elements < 1)
3528    {
3529        PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
3530                        (0, "PVMFDownloadManagerNode::releaseParameters() KVP list is NULL or number of elements is 0"));
3531        return PVMFErrArgument;
3532    }
3533
3534    // Count the number of components and parameters in the key
3535    int compcount = pv_mime_string_compcnt(aParameters[0].key);
3536    // Retrieve the first component from the key string
3537    char* compstr = NULL;
3538    pv_mime_string_extract_type(0, aParameters[0].key, compstr);
3539
3540    if ((pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf")) < 0) || compcount < 2)
3541    {
3542        // First component should be "x-pvmf" and there must
3543        // be at least two components to go past x-pvmf
3544        PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
3545                        (0, "PVMFDownloadManagerNode::releaseParameters() Unsupported key"));
3546        return PVMFErrArgument;
3547    }
3548
3549    // Retrieve the second component from the key string
3550    pv_mime_string_extract_type(1, aParameters[0].key, compstr);
3551
3552    // Assume all the parameters come from the same component so the base components are the same
3553    if (pv_mime_strcmp(compstr, _STRLIT_CHAR("net")) >= 0)
3554    {
3555        // Go through each KVP and release memory for value if allocated from heap
3556        for (int32 i = 0; i < num_elements; ++i)
3557        {
3558            // Next check if it is a value type that allocated memory
3559            PvmiKvpType kvptype = GetTypeFromKeyString(aParameters[i].key);
3560            if (kvptype == PVMI_KVPTYPE_VALUE || kvptype == PVMI_KVPTYPE_UNKNOWN)
3561            {
3562                PvmiKvpValueType keyvaltype = GetValTypeFromKeyString(aParameters[i].key);
3563                if (keyvaltype == PVMI_KVPVALTYPE_UNKNOWN)
3564                {
3565                    PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
3566                                    (0, "PVMFDownloadManagerNode::releaseParameters() Valtype not specified in key string"));
3567                    return PVMFErrArgument;
3568                }
3569
3570                if (keyvaltype == PVMI_KVPVALTYPE_CHARPTR && aParameters[i].value.pChar_value != NULL)
3571                {
3572                    oscl_free(aParameters[i].value.pChar_value);
3573                    aParameters[i].value.pChar_value = NULL;
3574                }
3575                else if (keyvaltype == PVMI_KVPVALTYPE_WCHARPTR && aParameters[i].value.pWChar_value != NULL)
3576                {
3577                    oscl_free(aParameters[i].value.pWChar_value);
3578                    aParameters[i].value.pWChar_value = NULL;
3579                }
3580                else if (keyvaltype == PVMI_KVPVALTYPE_CHARPTR && aParameters[i].value.pChar_value != NULL)
3581                {
3582                    oscl_free(aParameters[i].value.pChar_value);
3583                    aParameters[i].value.pChar_value = NULL;
3584                }
3585                else if (keyvaltype == PVMI_KVPVALTYPE_KSV && aParameters[i].value.key_specific_value != NULL)
3586                {
3587                    oscl_free(aParameters[i].value.key_specific_value);
3588                    aParameters[i].value.key_specific_value = NULL;
3589                }
3590                else if (keyvaltype == PVMI_KVPVALTYPE_RANGE_INT32 && aParameters[i].value.key_specific_value != NULL)
3591                {
3592                    range_int32* ri32 = (range_int32*)aParameters[i].value.key_specific_value;
3593                    aParameters[i].value.key_specific_value = NULL;
3594                    oscl_free(ri32);
3595                }
3596                else if (keyvaltype == PVMI_KVPVALTYPE_RANGE_UINT32 && aParameters[i].value.key_specific_value != NULL)
3597                {
3598                    range_uint32* rui32 = (range_uint32*)aParameters[i].value.key_specific_value;
3599                    aParameters[i].value.key_specific_value = NULL;
3600                    oscl_free(rui32);
3601                }
3602            }
3603        }
3604
3605        oscl_free(aParameters[0].key);
3606
3607        // Free memory for the parameter list
3608        oscl_free(aParameters);
3609        aParameters = NULL;
3610    }
3611    else
3612    {
3613        // Unknown key string
3614        return PVMFErrArgument;
3615    }
3616
3617    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
3618                    (0, "PVMFDownloadManagerNode::releaseParameters() Out"));
3619    return PVMFSuccess;
3620
3621}
3622
3623void PVMFDownloadManagerNode::createContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext)
3624{
3625    OSCL_UNUSED_ARG(aSession);
3626    OSCL_UNUSED_ARG(aContext);
3627    // not supported
3628    OSCL_LEAVE(PVMFErrNotSupported);
3629}
3630
3631void PVMFDownloadManagerNode::setContextParameters(PvmiMIOSession aSession, PvmiCapabilityContext& aContext,
3632        PvmiKvp* aParameters, int num_parameter_elements)
3633{
3634    OSCL_UNUSED_ARG(aSession);
3635    OSCL_UNUSED_ARG(aContext);
3636    OSCL_UNUSED_ARG(aParameters);
3637    OSCL_UNUSED_ARG(num_parameter_elements);
3638    // not supported
3639    OSCL_LEAVE(PVMFErrNotSupported);
3640}
3641
3642void PVMFDownloadManagerNode::DeleteContext(PvmiMIOSession aSession,
3643        PvmiCapabilityContext& aContext)
3644{
3645    OSCL_UNUSED_ARG(aSession);
3646    OSCL_UNUSED_ARG(aContext);
3647    // not supported
3648    OSCL_LEAVE(PVMFErrNotSupported);
3649}
3650
3651void PVMFDownloadManagerNode::setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters,
3652        int num_elements, PvmiKvp * & aRet_kvp)
3653{
3654    OSCL_UNUSED_ARG(aSession);
3655
3656    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
3657                    (0, "PVMFDownloadManagerNode::setParametersSync() In"));
3658
3659    aRet_kvp = NULL;
3660
3661    // Go through each parameter
3662    for (int paramind = 0; paramind < num_elements; ++paramind)
3663    {
3664        // Count the number of components and parameters in the key
3665        int compcount = pv_mime_string_compcnt(aParameters[paramind].key);
3666
3667        // Retrieve the first component from the key string
3668        char* compstr = NULL;
3669        pv_mime_string_extract_type(0, aParameters[paramind].key, compstr);
3670
3671        if ((pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf")) < 0) || compcount < 2)
3672        {
3673            // First component should be "x-pvmf" and there must
3674            // be at least two components to go past x-pvmf
3675            aRet_kvp = &aParameters[paramind];
3676            PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
3677                            (0, "PVMFDownloadManagerNode::setParametersSync() Unsupported key"));
3678            return;
3679        }
3680
3681        // Retrieve the second component from the key string
3682        pv_mime_string_extract_type(1, aParameters[paramind].key, compstr);
3683
3684        // First check if it is key string for the Download manager
3685        if (pv_mime_strcmp(compstr, _STRLIT_CHAR("net")) >= 0)
3686        {
3687            if (compcount == 3)
3688            {
3689                pv_mime_string_extract_type(2, aParameters[paramind].key, compstr);
3690                uint i;
3691                for (i = 0; i < DownloadManagerConfig_NumBaseKeys; i++)
3692                {
3693                    if (pv_mime_strcmp(compstr, (char*)(DownloadManagerConfig_BaseKeys[i].iString)) >= 0)
3694                    {
3695                        break;
3696                    }
3697                }
3698
3699                if (DownloadManagerConfig_NumBaseKeys == i)
3700                {
3701                    // invalid third component
3702                    aRet_kvp = &aParameters[paramind];
3703                    PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
3704                                    (0, "PVMFDownloadManagerNode::setParametersSync() Unsupported key"));
3705                    return;
3706                }
3707
3708                // Verify and set the passed-in setting
3709                switch (i)
3710                {
3711                    case BASEKEY_SESSION_CONTROLLER_USER_AGENT:
3712                    {
3713                        if (IsDownloadExtensionHeaderValid(*aParameters))
3714                        {
3715                            //setting KVP string for download when mode applied for download or not applied at all.
3716                            OSCL_wHeapString<OsclMemAllocator> userAgent;
3717                            userAgent = aParameters[paramind].value.pWChar_value;
3718                            (iProtocolEngineNode.ProtocolEngineExtension())->SetUserAgent(userAgent, true);
3719                        }
3720                    }
3721                    break;
3722                    case BASEKEY_SESSION_CONTROLLER_HTTP_VERSION:
3723                    {
3724                        uint32 httpVersion;
3725                        httpVersion = aParameters[paramind].value.uint32_value;
3726                        (iProtocolEngineNode.ProtocolEngineExtension())->SetHttpVersion(httpVersion);
3727
3728                    }
3729                    break;
3730                    case BASEKEY_SESSION_CONTROLLER_HTTP_TIMEOUT:
3731                    {
3732                        uint32 httpTimeout;
3733                        httpTimeout = aParameters[paramind].value.uint32_value;
3734                        (iProtocolEngineNode.ProtocolEngineExtension())->SetNetworkTimeout(httpTimeout);
3735                    }
3736                    break;
3737                    case BASEKEY_SESSION_CONTROLLER_DOWNLOAD_PROGRESS_INFO:
3738                    {
3739                        OSCL_HeapString<OsclMemAllocator> downloadProgressInfo;
3740                        downloadProgressInfo = aParameters[paramind].value.pChar_value;
3741                        DownloadProgressMode aMode = DownloadProgressMode_TimeBased;
3742                        if (IsByteBasedDownloadProgress(downloadProgressInfo)) aMode = DownloadProgressMode_ByteBased;
3743                        (iProtocolEngineNode.ProtocolEngineExtension())->SetDownloadProgressMode(aMode);
3744                    }
3745                    break;
3746                    case BASEKEY_SESSION_CONTROLLER_PROTOCOL_EXTENSION_HEADER:
3747                    {
3748                        if (IsDownloadExtensionHeaderValid(aParameters[paramind]))
3749                        {
3750                            OSCL_HeapString<OsclMemAllocator> extensionHeaderKey;
3751                            OSCL_HeapString<OsclMemAllocator> extensionHeaderValue;
3752                            HttpMethod httpMethod = HTTP_GET;
3753                            bool aPurgeOnRedirect = false;
3754                            if (GetHttpExtensionHeaderParams(aParameters[paramind],
3755                                                             extensionHeaderKey,
3756                                                             extensionHeaderValue,
3757                                                             httpMethod,
3758                                                             aPurgeOnRedirect))
3759                            {
3760                                (iProtocolEngineNode.ProtocolEngineExtension())->SetHttpExtensionHeaderField(extensionHeaderKey,
3761                                        extensionHeaderValue,
3762                                        httpMethod,
3763                                        aPurgeOnRedirect);
3764                            }
3765                        }
3766
3767                    }
3768                    break;
3769
3770                    case BASEKEY_SESSION_CONTROLLER_NUM_REDIRECT_ATTEMPTS:
3771                    {
3772                        if (IsDownloadExtensionHeaderValid(*aParameters))
3773                        {
3774                            //setting KVP string for download when mode applied for download or not applied at all.
3775                            uint32 numRedirects = aParameters[paramind].value.uint32_value;
3776                            (iProtocolEngineNode.ProtocolEngineExtension())->SetNumRedirectTrials(numRedirects);
3777                        }
3778                    }
3779                    break;
3780
3781                    case BASEKEY_SESSION_CONTROLLER_NUM_HTTP_HEADER_REQUEST_DISABLED:
3782                    {
3783                        bool httpHeaderRequestDisabled = aParameters[paramind].value.bool_value;
3784                        (iProtocolEngineNode.ProtocolEngineExtension())->DisableHttpHeadRequest(httpHeaderRequestDisabled);
3785                    }
3786                    break;
3787
3788                    case BASEKEY_MAX_TCP_RECV_BUFFER_SIZE:
3789                    {
3790                        uint32 size = aParameters[paramind].value.uint32_value;
3791                        PVMFSocketNode* socketNode =
3792                            (PVMFSocketNode*)(iSocketNode.iNode);
3793                        if (socketNode != NULL)
3794                        {
3795                            socketNode->SetMaxTCPRecvBufferSize(size);
3796                        }
3797                    }
3798                    break;
3799
3800                    case BASEKEY_MAX_TCP_RECV_BUFFER_COUNT:
3801                    {
3802                        uint32 size = aParameters[paramind].value.uint32_value;
3803                        PVMFSocketNode* socketNode =
3804                            (PVMFSocketNode*)(iSocketNode.iNode);
3805                        if (socketNode != NULL)
3806                        {
3807                            socketNode->SetMaxTCPRecvBufferCount(size);
3808                        }
3809                    }
3810                    break;
3811
3812                    default:
3813                    {
3814                        aRet_kvp = &aParameters[paramind];
3815                        PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
3816                                        (0, "PVMFDownloadManagerNode::setParametersSync() Setting "
3817                                         "parameter %d failed", paramind));
3818                    }
3819                    break;
3820                }
3821            }
3822            else
3823            {
3824                // Do not support more than 3 components right now
3825                aRet_kvp = &aParameters[paramind];
3826                PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
3827                                (0, "PVMFDownloadManagerNode::setParametersSync() Unsupported key"));
3828                return;
3829            }
3830        }
3831        else
3832        {
3833            // Unknown key string
3834            aRet_kvp = &aParameters[paramind];
3835            PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
3836                            (0, "PVMFDownloadManagerNode::setParametersSync() Unsupported key"));
3837            return;
3838        }
3839    }
3840
3841    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
3842                    (0, "PVMFDownloadManagerNode::setParametersSync() Out"));
3843}
3844
3845bool PVMFDownloadManagerNode::IsByteBasedDownloadProgress(OSCL_String &aDownloadProgressInfo)
3846{
3847    if (aDownloadProgressInfo.get_size() < 4) return false; // 4 => byte
3848    char *ptr = (char*)aDownloadProgressInfo.get_cstr();
3849    uint32 len = aDownloadProgressInfo.get_size();
3850
3851    while (!(((ptr[0]  | OSCL_ASCII_CASE_MAGIC_BIT) == 'b') &&
3852             ((ptr[1]  | OSCL_ASCII_CASE_MAGIC_BIT) == 'y') &&
3853             ((ptr[2]  | OSCL_ASCII_CASE_MAGIC_BIT) == 't') &&
3854             ((ptr[3]  | OSCL_ASCII_CASE_MAGIC_BIT) == 'e')) &&
3855            len >= 4)
3856    {
3857        ptr++;
3858        len--;
3859    }
3860    if (len < 4) return false;
3861
3862    return true; // find case-insentive string "byte"
3863}
3864
3865bool PVMFDownloadManagerNode::GetHttpExtensionHeaderParams(PvmiKvp &aParameter,
3866        OSCL_String &extensionHeaderKey,
3867        OSCL_String &extensionHeaderValue,
3868        HttpMethod  &httpMethod,
3869        bool &aPurgeOnRedirect)
3870{
3871    // check if the extension header is meant for download
3872    if (!IsHttpExtensionHeaderValid(aParameter)) return false;
3873
3874    // get aPurgeOnRedirect
3875    aPurgeOnRedirect = false;
3876    OSCL_StackString<32> purgeOnRedirect(_STRLIT_CHAR("purge-on-redirect"));
3877    if (oscl_strstr(aParameter.key, purgeOnRedirect.get_cstr()) != NULL)
3878    {
3879        aPurgeOnRedirect = true;
3880    }
3881
3882    // get key, value and http method of protocol extension header
3883    // the string value needs to be structured as follows: "key=app-feature-tag;value=xyz"
3884    char* extensionHeader = aParameter.value.pChar_value;
3885    if (!extensionHeader) return false;
3886
3887    // (1) extract the key
3888    OSCL_StackString<8> keyTag(_STRLIT_CHAR("key="));
3889
3890    OSCL_StackString<8> valueTag(_STRLIT_CHAR("value="));
3891    char *keyStart = OSCL_CONST_CAST(char*, oscl_strstr(extensionHeader, keyTag.get_cstr()));
3892    if (!keyStart) return false;
3893
3894    keyStart += keyTag.get_size();
3895    char *keyEnd = OSCL_CONST_CAST(char*, oscl_strstr(extensionHeader, valueTag.get_cstr()));
3896    if (!keyEnd) return false;
3897    uint32 keyLen = getItemLen(keyStart, keyEnd);
3898    if (keyLen == 0) return false;
3899    extensionHeaderKey = OSCL_HeapString<OsclMemAllocator> (keyStart, keyLen);
3900
3901    // (2) extract the value
3902    char* valueStart = keyEnd;
3903    valueStart += valueTag.get_size();
3904
3905    OSCL_StackString<8> methodTag(_STRLIT_CHAR("method="));
3906    char* valueEnd = OSCL_CONST_CAST(char*, oscl_strstr(valueStart, methodTag.get_cstr()));
3907    if (!valueEnd) valueEnd = extensionHeader + aParameter.capacity;
3908    uint32 valueLen = getItemLen(valueStart, valueEnd);
3909    extensionHeaderValue = OSCL_HeapString<OsclMemAllocator> (valueStart, valueLen);
3910
3911    // (3) check for optional method
3912    const char *methodStart = oscl_strstr(extensionHeader, methodTag.get_cstr());
3913    if (!methodStart)
3914    {
3915        httpMethod = HTTP_GET;
3916        return true;
3917    }
3918    methodStart += methodTag.get_size();
3919
3920    OSCL_StackString<8> methodHttpGet(_STRLIT_CHAR("GET"));
3921    OSCL_StackString<8> methodHttpHead(_STRLIT_CHAR("HEAD"));
3922    OSCL_StackString<8> methodHttpPost(_STRLIT_CHAR("POST"));
3923
3924    const char* methodGet = oscl_strstr(methodStart, methodHttpGet.get_cstr());
3925    const char* methodHead = oscl_strstr(methodStart, methodHttpHead.get_cstr());
3926    const char* methodPost = oscl_strstr(methodStart, methodHttpPost.get_cstr());
3927
3928    httpMethod = HTTP_GET;
3929    if (methodPost != NULL) httpMethod = HTTP_POST;
3930    if (methodGet  != NULL) httpMethod = HTTP_GET;
3931    if (methodHead != NULL) httpMethod = HTTP_HEAD;
3932    if ((methodGet != NULL) && (methodHead != NULL)) httpMethod = HTTP_ALLMETHOD;
3933
3934    return true;
3935}
3936
3937bool PVMFDownloadManagerNode::IsHttpExtensionHeaderValid(PvmiKvp &aParameter)
3938{
3939    OSCL_StackString<32> downloadMode(_STRLIT_CHAR("mode=download"));
3940    OSCL_StackString<32> streamingMode(_STRLIT_CHAR("mode=streaming"));
3941
3942    bool isDownloadMode  = (oscl_strstr(aParameter.key, downloadMode.get_cstr())  != NULL);
3943    bool isStreamingMode = (oscl_strstr(aParameter.key, streamingMode.get_cstr()) != NULL);
3944
3945    // streaming mode only would fail, download mode specified or not specified will be viewed as true
3946    if (isStreamingMode && !isDownloadMode) return false;
3947
3948    return true;
3949}
3950
3951// remove the ending ';', ',' or ' ' and calulate value length
3952uint32 PVMFDownloadManagerNode::getItemLen(char *ptrItemStart, char *ptrItemEnd)
3953{
3954    char *ptr = ptrItemEnd - 1;
3955    uint32 itemLen = ptr - ptrItemStart;
3956    for (uint32 i = 0; i < itemLen; i++)
3957    {
3958        if (*ptr == ';' || *ptr == ',' || *ptr == ' ') --ptr;
3959        else break;
3960    }
3961    itemLen = ptr - ptrItemStart + 1;
3962    return itemLen;
3963}
3964
3965
3966PVMFCommandId PVMFDownloadManagerNode::setParametersAsync(PvmiMIOSession aSession,
3967        PvmiKvp* aParameters,
3968        int num_elements,
3969        PvmiKvp*& aRet_kvp,
3970        OsclAny* context)
3971{
3972    OSCL_UNUSED_ARG(aSession);
3973    OSCL_UNUSED_ARG(aParameters);
3974    OSCL_UNUSED_ARG(num_elements);
3975    OSCL_UNUSED_ARG(aRet_kvp);
3976    OSCL_UNUSED_ARG(context);
3977    // not supported
3978    OSCL_LEAVE(PVMFErrNotSupported);
3979    return 0;
3980}
3981
3982uint32 PVMFDownloadManagerNode::getCapabilityMetric(PvmiMIOSession aSession)
3983{
3984    OSCL_UNUSED_ARG(aSession);
3985    return 0;
3986}
3987
3988PVMFStatus PVMFDownloadManagerNode::verifyParametersSync(PvmiMIOSession aSession,
3989        PvmiKvp* aParameters,
3990        int num_elements)
3991{
3992    OSCL_UNUSED_ARG(aSession);
3993    OSCL_UNUSED_ARG(aParameters);
3994    OSCL_UNUSED_ARG(num_elements);
3995    // not supported
3996    OSCL_LEAVE(PVMFErrNotSupported);
3997    return 0;
3998}
3999
4000bool PVMFDownloadManagerNode::IsDownloadExtensionHeaderValid(PvmiKvp &aParameter)
4001{
4002    OSCL_StackString<32> downloadMode(_STRLIT_CHAR("mode=download"));
4003    OSCL_StackString<32> streamingMode(_STRLIT_CHAR("mode=streaming"));
4004    OSCL_StackString<32> dlaMode(_STRLIT_CHAR("mode=dla"));
4005
4006    bool isDownloadMode  = (oscl_strstr(aParameter.key, downloadMode.get_cstr())  != NULL);
4007    bool isStreamingMode = (oscl_strstr(aParameter.key, streamingMode.get_cstr()) != NULL);
4008    bool isDlaMode = (oscl_strstr(aParameter.key, dlaMode.get_cstr()) != NULL);
4009
4010
4011    // streaming mode only would fail, download mode specified or not specified will be viewed as true
4012    if (isStreamingMode && !isDownloadMode) return false;
4013
4014    // dla mode only would fail, download mode specified or not specified will be viewed as true
4015    if (isDlaMode && !isDownloadMode) return false;
4016
4017    return true;
4018}
4019
4020void PVMFDownloadManagerNode::NotificationsInterfaceDestroyed()
4021{
4022    iClockNotificationsInf = NULL;
4023}
4024
4025void PVMFDownloadManagerNode::ClockStateUpdated()
4026{
4027    if (!iDataReady)
4028    {
4029        // Don't let anyone start the clock while the source node is in underflow
4030        if (iPlayBackClock != NULL)
4031        {
4032            if (iPlayBackClock->GetState() == PVMFMediaClock::RUNNING)
4033            {
4034                iPlayBackClock->Pause();
4035            }
4036        }
4037    }
4038}
4039