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