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