• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ------------------------------------------------------------------
2  * Copyright (C) 1998-2009 PacketVideo
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13  * express or implied.
14  * See the License for the specific language governing permissions
15  * and limitations under the License.
16  * -------------------------------------------------------------------
17  */
18 /**
19  *
20  * @file pvmi_io_interface_node_inport.cpp
21  * @brief Input port for media io interface wrapper node
22  *
23  */
24 
25 #include "pv_media_output_node_inport.h"
26 #include "pv_media_output_node.h"
27 #include "pvmf_common_audio_decnode.h"
28 #include "pvmf_video.h"
29 #include "pv_mime_string_utils.h"
30 #include "pvmf_media_cmd.h"
31 #include "pvmf_media_msg_format_ids.h"
32 #include "latmpayloadparser.h"
33 #include "media_clock_converter.h"
34 #include "time_comparison_utils.h"
35 
36 #define LOGDATAPATH(x)  PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iDatapathLogger, PVLOGMSG_INFO, x);
37 
38 #define PVMF_MOPORT_LOGDATAPATH(x)  PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iDatapathLogger, PVLOGMSG_INFO, x);
39 #define PVMF_MOPORT_LOGDATAPATH_IN(x)   PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iDatapathLoggerIn, PVLOGMSG_INFO, x);
40 #define PVMF_MOPORT_LOGDATAPATH_OUT(x)  PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iDatapathLoggerOut, PVLOGMSG_INFO, x);
41 #define PVMF_MOPORT_LOGREPOS(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iReposLogger, PVLOGMSG_INFO, x);
42 #define PVMF_MOPORT_LOGDEBUG(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, x);
43 #define PVMF_MOPORT_LOGERROR(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, x);
44 
45 
46 //for logging media data info
LogMediaDataInfo(const char * msg,PVMFSharedMediaDataPtr mediaData)47 void PVMediaOutputNodePort::LogMediaDataInfo(const char* msg, PVMFSharedMediaDataPtr mediaData)
48 {
49     if (!mediaData.GetRep())
50     {
51         OSCL_UNUSED_ARG(msg);
52         return;
53     }
54     LOGDATAPATH(
55         (0, "MOUT %s %s MediaData SeqNum %d, SId %d, TS %d"
56          , PortName()
57          , msg
58          , mediaData->getSeqNum()
59          , mediaData->getStreamID()
60          , mediaData->getTimestamp()
61         ));
62 }
63 
64 
65 //for logging media data info plus write ID and cleanup q depth
LogMediaDataInfo(const char * msg,PVMFSharedMediaDataPtr mediaData,int32 cmdid,int32 qdepth)66 void PVMediaOutputNodePort::LogMediaDataInfo(const char* msg, PVMFSharedMediaDataPtr mediaData, int32 cmdid, int32 qdepth)
67 {
68     if (!mediaData.GetRep())
69     {
70         OSCL_UNUSED_ARG(msg);
71         OSCL_UNUSED_ARG(cmdid);
72         OSCL_UNUSED_ARG(qdepth);
73         return;
74     }
75     LOGDATAPATH(
76         (0, "MOUT %s %s, Write Id %d, MediaData SeqNum %d, SId %d, TS %d, Cleanup Q-depth %d"
77          , PortName()
78          , msg
79          , cmdid
80          , mediaData->getSeqNum()
81          , mediaData->getStreamID()
82          , mediaData->getTimestamp()
83          , qdepth
84         ));
85 }
86 
87 
88 //for logging media xfer info
LogDatapath(const char * msg)89 void PVMediaOutputNodePort::LogDatapath(const char*msg)
90 {
91 
92     if (!iDatapathLogger)
93     {
94         OSCL_UNUSED_ARG(msg);
95         return; //unexpected call.
96     }
97     LOGDATAPATH(
98         (0, "MOUT %s %s"
99          , PortName()
100          , msg
101         ));
102 }
103 
104 
105 ////////////////////////////////////////////////////////////////////////////
PVMediaOutputNodePort(PVMediaOutputNode * aNode)106 PVMediaOutputNodePort::PVMediaOutputNodePort(PVMediaOutputNode* aNode)
107         : OsclTimerObject(OsclActiveObject::EPriorityNominal, "PVMediaOutputNodePort")
108         , PvmfPortBaseImpl(PVMF_MEDIAIO_NODE_INPUT_PORT_TAG
109                            //this port handles its own port activity
110                            , this
111                            , 10, 10, 70
112                            //output queue isn't needed.
113                            , 0, 0, 0, "MediaOut")
114         , iNode(aNode)
115 {
116     AddToScheduler();
117     isUnCompressedMIO = false;
118 
119     iExtensionRefCount = 0;
120     iPortFormat = PVMF_MIME_FORMAT_UNKNOWN;
121 
122     iMediaTransfer = NULL;
123     iMioInfoErrorCmdId = 0;
124     iMediaType = PVMF_MEDIA_UNKNOWN;
125     iWriteState = EWriteOK;
126     iCleanupQueue.reserve(1);
127     iWriteAsyncContext = 0;
128     iWriteAsyncEOSContext = 0;
129     iWriteAsyncReConfigContext = 0;
130     iClock = NULL;
131     iClockNotificationsInf = NULL;
132     oClockCallBackPending = false;
133     iDelayEarlyFrameCallBkId = 0;
134     iClockRate = 1;
135     iEarlyMargin = 0;
136     iLateMargin = 0;
137     oActiveMediaOutputComp = true; // By default we treat the MIO's to be active.
138 
139     // MIO node waits for MIO component configuration to complete before sending data. Once configuration is
140     // complete, MIO node waits for clock to start if mio component is passive. For active MIO's, it does not
141     // wait for clock to start before sending data. It sends data as soon as MIO component configuration is
142     // complete.
143 
144     oProcessIncomingMessage = false;
145 
146 
147     oMIOComponentConfigured = false;
148 
149     iConsecutiveFramesDropped = 0;
150     iLateFrameEventSent = false;
151 
152     iFragIndex = 0;
153 
154     iSkipTimestamp = 0;
155     iRecentStreamID = 0;
156     iSendStartOfDataEvent = false;
157 
158     iFrameStepMode = false;
159     iClockFrameCount = 0;
160     iSyncFrameCount = 0;
161     iFramesDropped = 0;
162     iTotalFrames = 0;
163 
164     iEosStreamIDVec.reserve(2);
165 
166     iOsclErrorTrapImp = OsclErrorTrap::GetErrorTrapImp();
167     iLogger = PVLogger::GetLoggerObject("PVMediaOutputNodePort");
168     iDatapathLogger = PVLogger::GetLoggerObject("datapath.sinknode");
169     iDatapathLoggerIn = PVLogger::GetLoggerObject("datapath.sinknode.in");
170     iDatapathLoggerOut = PVLogger::GetLoggerObject("datapath.sinknode.out");
171     iReposLogger = PVLogger::GetLoggerObject("pvplayerrepos.mionode");
172 }
173 
174 ////////////////////////////////////////////////////////////////////////////
ClearCleanupQueue()175 void PVMediaOutputNodePort::ClearCleanupQueue()
176 //clear the media transfer cleanup queue and log all messages.
177 {
178     while (!iCleanupQueue.empty())
179     {
180         PVMFSharedMediaDataPtr mediaData = iCleanupQueue.begin()->iData;
181         PVMFCommandId cmdId = iCleanupQueue.begin()->iCmdId;
182         iCleanupQueue.erase(iCleanupQueue.begin());
183         LogMediaDataInfo("Cleared"
184                          , mediaData
185                          , cmdId
186                          , iCleanupQueue.size()
187                         );
188     }
189 }
190 
191 ////////////////////////////////////////////////////////////////////////////
~PVMediaOutputNodePort()192 PVMediaOutputNodePort::~PVMediaOutputNodePort()
193 {
194     Disconnect();
195     PvmfPortBaseImpl::ClearMsgQueues();
196     //cancel any pending write operations
197     if (!iCleanupQueue.empty())
198     {
199         int32 err;
200         OSCL_TRY(err, iMediaTransfer->cancelAllCommands(););
201         ClearCleanupQueue();
202     }
203     if (iClock != NULL)
204     {
205         if (iClockNotificationsInf != NULL)
206         {
207             iClockNotificationsInf->RemoveClockObserver(*this);
208             iClockNotificationsInf->RemoveClockStateObserver(*this);
209             iClock->DestroyMediaClockNotificationsInterface(iClockNotificationsInf);
210             iClockNotificationsInf = NULL;
211         }
212     }
213     // we need to clear the activity handler, since otherwise the PvmfPortBaseImpl destructor
214     // ends up calling back onto our HandlePortActivity method, which no longer exists because
215     // this objects's destructor has already been called.
216     SetActivityHandler(NULL);
217 }
218 
219 ////////////////////////////////////////////////////////////////////////////
Configure(OSCL_String & fmtstr)220 PVMFStatus PVMediaOutputNodePort::Configure(OSCL_String& fmtstr)
221 {
222     //This is called when the format is being set.
223     if (iConnectedPort)
224     {
225         // Must disconnect before changing port properties, so return error
226         return PVMFFailure;
227     }
228     PVMFFormatType fmt = fmtstr.get_cstr();
229 
230     if (IsFormatSupported(fmt))
231     {
232         iPortFormat = fmt;
233         iSinkFormat = fmt;
234         iSinkFormatString = fmtstr;
235         FormatUpdated();
236         return PVMFSuccess;
237     }
238     else
239     {
240         iPortFormat = PVMF_MIME_FORMAT_UNKNOWN;
241         iSinkFormat = PVMF_MIME_FORMAT_UNKNOWN;
242         iSinkFormatString = fmtstr;
243         return PVMFFailure;
244     }
245 }
246 
247 ////////////////////////////////////////////////////////////////////////////
248 // override the PvmfPortBaseImpl routine
Connect(PVMFPortInterface * aPort)249 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::Connect(PVMFPortInterface* aPort)
250 {
251     PVMFStatus status = PvmfPortBaseImpl::Connect(aPort);
252     if (status != PVMFSuccess)
253     {
254         return status;
255     }
256 
257     if (iMediaTransfer == NULL)
258     {
259         iMediaTransfer = iNode->iMIOControl->createMediaTransfer(iNode->iMIOSession);
260         if (iMediaTransfer)
261         {
262             iMediaTransfer->setPeer(this);
263         }
264         else
265         {
266             return PVMFFailure;
267         }
268     }
269 
270     iSkipTimestamp = 0;
271 
272     OsclAny* temp = NULL;
273     aPort->QueryInterface(PVMI_CAPABILITY_AND_CONFIG_PVUUID, temp);
274     PvmiCapabilityAndConfig *config = OSCL_STATIC_CAST(PvmiCapabilityAndConfig*, temp);
275 
276     if (config != NULL)
277     {
278         PvmiKvp* configKvp = NULL;
279         PvmiKvp* aRet_kvp = NULL;
280         int num_elements = 0;
281         PVMFStatus status = config->getParametersSync(NULL, NULL, configKvp, num_elements, NULL);
282 
283         if (status == PVMFSuccess)
284         {
285             iNode->iMIOConfig->setParametersSync(iNode->iMIOSession,
286                                                  configKvp,
287                                                  num_elements,
288                                                  aRet_kvp);
289             config->releaseParameters(NULL, configKvp, num_elements);
290         }
291     }
292     return PVMFSuccess;
293 }
294 
295 ////////////////////////////////////////////////////////////////////////////
296 // override the PvmfPortBaseImpl routine
PeerConnect(PVMFPortInterface * aPort)297 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::PeerConnect(PVMFPortInterface* aPort)
298 {
299     PVMFStatus status = PvmfPortBaseImpl::PeerConnect(aPort);
300     if (status != PVMFSuccess)
301     {
302         return status;
303     }
304 
305     if (iMediaTransfer == NULL)
306     {
307         iMediaTransfer = iNode->iMIOControl->createMediaTransfer(iNode->iMIOSession);
308         if (iMediaTransfer)
309         {
310             iMediaTransfer->setPeer(this);
311         }
312         else
313         {
314             return PVMFFailure;
315         }
316     }
317     return PVMFSuccess;
318 }
319 
CleanupMediaTransfer()320 void PVMediaOutputNodePort::CleanupMediaTransfer()
321 {
322     int32 err;
323     //Just in case the media transfer did not report all the async write
324     //completes, cancel any pending write operations and clear up the cleanup queue
325     if (!iCleanupQueue.empty())
326     {
327         err = 0;
328         OSCL_TRY(err, iMediaTransfer->cancelAllCommands(););
329         ClearCleanupQueue();
330     }
331     if (iNode && iNode->iMIOControl && iMediaTransfer)
332     {
333         iMediaTransfer->setPeer(NULL);
334         err = 0;
335         OSCL_TRY(err, iNode->iMIOControl->deleteMediaTransfer(iNode->iMIOSession, iMediaTransfer));
336         OSCL_FIRST_CATCH_ANY(err,
337                              PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
338                                              (0, "PVMediaOutputNodePort::CleanupMediaTransfer Caught a leave when calling deleteMediaTransfer!"));
339                             );
340         iMediaTransfer = NULL;
341     }
342     if (iClock != NULL)
343     {
344         if (iClockNotificationsInf != NULL)
345         {
346             iClockNotificationsInf->RemoveClockObserver(*this);
347             iClockNotificationsInf->RemoveClockStateObserver(*this);
348             iClock->DestroyMediaClockNotificationsInterface(iClockNotificationsInf);
349         }
350         iClockNotificationsInf = NULL;
351         iClock = NULL;
352     }
353     if (iCurrentMediaMsg.GetRep() != NULL)
354     {
355         iCurrentMediaMsg.Unbind();
356     }
357 }
358 
359 ////////////////////////////////////////////////////////////////////////////
360 // override the PvmfPortBaseImpl routine
Disconnect()361 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::Disconnect()
362 {
363     CleanupMediaTransfer();
364     return PvmfPortBaseImpl::Disconnect();
365 }
366 
367 ////////////////////////////////////////////////////////////////////////////
368 // override the PvmfPortBaseImpl routine
PeerDisconnect()369 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::PeerDisconnect()
370 {
371     PVMFStatus status = PvmfPortBaseImpl::PeerDisconnect();
372     if (status != PVMFSuccess)
373     {
374         return status;
375     }
376     CleanupMediaTransfer();
377     return PVMFSuccess;
378 }
379 
380 ////////////////////////////////////////////////////////////////////////////
381 // override the PvmfPortBaseImpl routine
ClearMsgQueues()382 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::ClearMsgQueues()
383 {
384     if (iCurrentMediaMsg.GetRep() != NULL)
385     {
386         iCurrentMediaMsg.Unbind();
387     }
388 
389     PvmfPortBaseImpl::ClearMsgQueues();
390     //cancel any pending write operations
391     if (!iCleanupQueue.empty())
392     {
393         int32 err;
394         OSCL_TRY(err, iMediaTransfer->cancelAllCommands(););
395         ClearCleanupQueue();
396     }
397 
398     //may need to generate port flow control now
399     PvmfPortBaseImpl::EvaluateIncomingBusy();
400 
401     return PVMFSuccess;
402 }
403 
404 ////////////////////////////////////////////////////////////////////////////
addRef()405 void PVMediaOutputNodePort::addRef()
406 // for PVInterface
407 {
408     ++iExtensionRefCount;
409 }
410 
411 ///////////////////////////////////////////////////////////////////////////
removeRef()412 void PVMediaOutputNodePort::removeRef()
413 // for PVInterface
414 {
415     if (iExtensionRefCount > 0)
416     {
417         --iExtensionRefCount;
418     }
419 }
420 
421 ////////////////////////////////////////////////////////////////////////////
queryInterface(const PVUuid & uuid,PVInterface * & iface)422 bool PVMediaOutputNodePort::queryInterface(const PVUuid& uuid, PVInterface*& iface)
423 // for PVInterface
424 {
425     if (uuid == PvmfNodesSyncControlUuid)
426     {
427         PvmfNodesSyncControlInterface* myInterface = OSCL_STATIC_CAST(PvmfNodesSyncControlInterface*, this);
428         iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
429         addRef();
430     }
431     else
432     {
433         iface = NULL;
434         return false;
435     }
436     return true;
437 }
438 
439 ////////////////////////////////////////////////////////////////////////////
NodeStarted()440 void PVMediaOutputNodePort::NodeStarted()
441 {
442     //it is possible that we attempted to call writeasync
443     //before media output comp start (can happen for active components)
444     //in those cases the comp can either accept or reject data
445     //if it rejected it by doing a leave, attempt to send data again
446     //now that we are done with start. Do not do the same for passive
447     //comps since this method is called during a pause-resume, and we
448     //do not want to attempt sending media data to passive comps till
449     //clock has been started
450     if ((iWriteState == EWriteWait) &&
451             (true == oActiveMediaOutputComp))
452     {
453         iWriteState = EWriteOK;
454         PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::NodeStarted - WriteAsync Enabled - Fmt=%s, iWriteState=%d",
455                                  iSinkFormatString.get_str(),
456                                  iWriteState));
457         oProcessIncomingMessage = true;
458 
459         if (iCurrentMediaMsg.GetRep() != NULL)
460         {
461             //attempt to send data current media msg if any
462             SendData();
463         }
464     }
465 
466     RunIfNotReady();
467 }
468 
469 // Attempt to process incoming message only after the mio component is fully configured
470 // and the clock is set by the node.
ProcessIncomingMessageIfPossible()471 void PVMediaOutputNodePort::ProcessIncomingMessageIfPossible()
472 {
473     if (oMIOComponentConfigured && iClock)
474     {
475         PVMF_MOPORT_LOGDATAPATH(
476             (0, "PVMediaOutputNodePort::ProcessIncomingMessageIfPossible: Fmt - Fmt=%s, MIOCompConfigured=%d, ActiveMIO=%d, ClockState=%d",
477              iSinkFormatString.get_str(), oMIOComponentConfigured, oActiveMediaOutputComp, iClock->GetState()));
478 
479         PVMF_MOPORT_LOGDEBUG(
480             (0, "PVMediaOutputNodePort::ProcessIncomingMessageIfPossible: Fmt - Fmt=%s, MIOCompConfigured=%d, ActiveMIO=%d, ClockState=%d",
481              iSinkFormatString.get_str(), oMIOComponentConfigured, oActiveMediaOutputComp, iClock->GetState()));
482 
483         if (true == oActiveMediaOutputComp)
484         {
485             oProcessIncomingMessage = true;
486         }
487         else
488         {
489             if (iClock->GetState() == PVMFMediaClock::RUNNING)
490             {
491                 oProcessIncomingMessage = true;
492             }
493         }
494         RunIfNotReady();
495     }
496     else
497     {
498         PVMF_MOPORT_LOGDEBUG(
499             (0, "PVMediaOutputNodePort::ProcessIncomingMessageIfPossible: Fmt - Fmt=%s, MIOCompConfigured=%d, iClock=0x%x",
500              iSinkFormatString.get_str(), oMIOComponentConfigured, iClock));
501     }
502 }
503 
SetMIOComponentConfigStatus(bool aStatus)504 void PVMediaOutputNodePort::SetMIOComponentConfigStatus(bool aStatus)
505 {
506     oMIOComponentConfigured = aStatus;
507 
508     ProcessIncomingMessageIfPossible();
509 }
510 
511 
512 ////////////////////////////////////////////////////////////////////////////
513 //for sync control interface
SetClock(PVMFMediaClock * aClock)514 PVMFStatus PVMediaOutputNodePort::SetClock(PVMFMediaClock* aClock)
515 {
516     if (NULL == aClock)
517     {
518         return PVMFErrArgument;
519     }
520     iClock = aClock;
521 
522     ProcessIncomingMessageIfPossible();
523 
524     iClock->ConstructMediaClockNotificationsInterface(iClockNotificationsInf, *this);
525 
526     if (NULL == iClockNotificationsInf)
527     {
528         return PVMFErrNoMemory;
529     }
530 
531     iClockNotificationsInf->SetClockObserver(*this);
532     iClockNotificationsInf->SetClockStateObserver(*this);
533 
534     return PVMFSuccess;
535 }
536 
EnableMediaSync()537 void PVMediaOutputNodePort::EnableMediaSync()
538 {
539     //wait on play clock
540     oProcessIncomingMessage = false;
541     oActiveMediaOutputComp = false;
542 }
543 
544 ////////////////////////////////////////////////////////////////////////////
545 //for sync control interface
ChangeClockRate(int32 aRate)546 PVMFStatus PVMediaOutputNodePort::ChangeClockRate(int32 aRate)
547 {
548     if (0 == aRate)
549     {
550         // A 0 value of clockrate is not handled
551         return PVMFFailure;
552     }
553     iClockRate = aRate;
554 
555     PVMFStatus status;
556     status = SetMIOParameterInt32((char*)MOUT_MEDIAXFER_OUTPUT_RATE, aRate);
557 
558     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,
559                     "PVMediaOutputNodePort::ChangeClockRate rate %d",
560                     aRate));
561 
562     return status;
563 }
564 
565 ////////////////////////////////////////////////////////////////////////////
SetMargins(int32 aEarlyMargin,int32 aLateMargin)566 PVMFStatus PVMediaOutputNodePort::SetMargins(int32 aEarlyMargin, int32 aLateMargin)
567 //for sync control interface
568 {
569     iEarlyMargin = aEarlyMargin;
570     iLateMargin = aLateMargin;
571     return PVMFSuccess;
572 }
573 
574 ////////////////////////////////////////////////////////////////////////////
ClockStarted()575 void PVMediaOutputNodePort::ClockStarted()
576 //for sync control interface
577 {
578     if (IsBusy())
579     {
580         // Cancel any long waits due to data synchronization done
581         // before clock was set and started
582         Cancel();
583     }
584     RunIfNotReady();
585 }
586 
587 
588 ////////////////////////////////////////////////////////////////////////////
ClockStopped()589 void PVMediaOutputNodePort::ClockStopped()
590 //for sync control interface
591 {
592     ;//ignore
593 }
594 
595 ////////////////////////////////////////////////////////////////////////////
setPeer(PvmiMediaTransfer * aPeer)596 void PVMediaOutputNodePort::setPeer(PvmiMediaTransfer *aPeer)
597 //for PvmiMediaTransfer
598 {
599     OSCL_UNUSED_ARG(aPeer);
600 }
601 
602 ////////////////////////////////////////////////////////////////////////////
useMemoryAllocators(OsclMemAllocator * write_alloc)603 void PVMediaOutputNodePort::useMemoryAllocators(OsclMemAllocator* write_alloc)
604 //for PvmiMediaTransfer
605 {
606     OSCL_UNUSED_ARG(write_alloc);
607     OSCL_LEAVE(OsclErrNotSupported);
608 }
609 
610 
611 ////////////////////////////////////////////////////////////////////////////
writeAsync(uint8 format_type,int32 format_index,uint8 * data,uint32 data_len,const PvmiMediaXferHeader & data_header_info,OsclAny * context)612 PVMFCommandId PVMediaOutputNodePort::writeAsync(uint8 format_type, int32 format_index,
613         uint8* data, uint32 data_len,
614         const PvmiMediaXferHeader& data_header_info,
615         OsclAny* context)
616 //for PvmiMediaTransfer
617 {
618     OSCL_UNUSED_ARG(data_header_info);
619     OSCL_UNUSED_ARG(context);
620 
621     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
622                     (0, "PVMediaOutputNodePort::writeAsync: format_type=%d, format_index=%d, data=0x%x, data_len=%d",
623                      format_type, format_index, data, data_len));
624 
625     PVMFAsyncEvent* event = NULL;
626     switch (format_type)
627     {
628         case PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION:
629             switch (format_index)
630             {
631                 case PVMI_MEDIAXFER_FMT_INDEX_INFO_EVENT:
632                     OSCL_ASSERT(iNode);
633                     OSCL_ASSERT(iMediaTransfer);
634 
635                     if (!data)
636                     {
637                         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
638                                         (0, "PVMediaOutputNodePort::writeAsync: Error - data is NULL"));
639                         OSCL_LEAVE(OsclErrArgument);
640                         return -1;
641                     }
642 
643                     if (data_len != sizeof(PVMFAsyncEvent))
644                     {
645                         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
646                                         (0, "PVMediaOutputNodePort::writeAsync: Error - data length is not size of PVMFAsyncEvent"));
647                         OSCL_LEAVE(OsclErrArgument);
648                         return -1;
649                     }
650 
651                     event = OSCL_STATIC_CAST(PVMFAsyncEvent*, data);
652                     iNode->ReportInfoEvent((*event));
653 
654                     // Not really processing this asynchronously. Just call writeComplete
655                     // synchronously
656                     iMediaTransfer->writeComplete(PVMFSuccess, iMioInfoErrorCmdId, context);
657                     return iMioInfoErrorCmdId++;
658 
659                 case PVMI_MEDIAXFER_FMT_INDEX_ERROR_EVENT:
660                     OSCL_ASSERT(iNode);
661                     OSCL_ASSERT(iMediaTransfer);
662 
663                     if (!data)
664                     {
665                         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
666                                         (0, "PVMediaOutputNodePort::writeAsync: Error - data is NULL"));
667                         OSCL_LEAVE(OsclErrArgument);
668                         return -1;
669                     }
670 
671                     if (data_len != sizeof(PVMFAsyncEvent))
672                     {
673                         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
674                                         (0, "PVMediaOutputNodePort::writeAsync: Error - data length is not size of PVMFAsyncEvent"));
675                         OSCL_LEAVE(OsclErrArgument);
676                         return -1;
677                     }
678 
679                     event = OSCL_STATIC_CAST(PVMFAsyncEvent*, data);
680                     iNode->ReportErrorEvent((*event));
681 
682                     // Not really processing this asynchronously. Just call writeComplete
683                     // synchronously
684                     iMediaTransfer->writeComplete(PVMFSuccess, iMioInfoErrorCmdId, context);
685                     return iMioInfoErrorCmdId++;
686 
687                 default:
688                     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
689                                     (0, "PVMediaOutputNodePort::writeAsync: Error - Unsupported format_index"));
690                     OSCL_LEAVE(OsclErrNotSupported);
691                     break;
692             }
693 
694         default:
695             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
696                             (0, "PVMediaOutputNodePort::writeAsync: Error - Unsupported format_type"));
697             OSCL_LEAVE(OsclErrNotSupported);
698             break;
699     }
700 
701     return -1;
702 }
703 
704 
705 ////////////////////////////////////////////////////////////////////////////
writeComplete(PVMFStatus status,PVMFCommandId aCmdId,OsclAny * aContext)706 void PVMediaOutputNodePort::writeComplete(PVMFStatus status, PVMFCommandId aCmdId, OsclAny* aContext)
707 //for PvmiMediaTransfer
708 {
709     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
710                     (0, "PVMediaOutputNodePort::writeComplete status %d cmdId %d context 0x%x", status, aCmdId, aContext));
711 
712     // Check if the writeComplete is in response to EOS message
713     if (&iWriteAsyncEOSContext == (uint32*)aContext)
714     {
715         if (iWriteState == EWriteBusy)
716         {
717             // Synchronous completion
718             // Let EndOfData info event be sent out in EndOfData() function
719             iWriteState = EWriteOK;
720         }
721         else
722         {
723             // Report End of Data to the user of media output node
724             // only if the EOS media transfer completes successfully and
725             // there is no pending MIO control request
726             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::writeComplete For EOS - Fmt=%s",
727                                      iSinkFormatString.get_str()));
728             if (iEosStreamIDVec.size() != 0)
729             {
730                 //iEosStreamIDVec is used as a FIFO to store the steamids of eos sent to mio comp.
731                 //streamid is pushed in at front when call writeasync(eos) to mio comp.
732                 //streamid is poped out from end when mio comp. calls writecomplete(eos),
733                 //we report PVMFInfoEndOfData with the poped streamid.
734                 //This logic depends on Mio comp. process data(at least eos msg) in a sequencial style.
735                 uint32 EosStreamID = iEosStreamIDVec.back();
736 
737                 // Asynchronous completion
738                 if (status == PVMFSuccess)
739                 {
740                     // Report EndofData to engine only if MIO comp sends success for End Of Stream.
741                     // FOr other return codes just pop out the EOS from the vector.
742                     iNode->ReportInfoEvent(PVMFInfoEndOfData, (OsclAny*)&EosStreamID);
743                 }
744                 else
745                 {
746                     PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::writeComplete EOS media transfer completed but PVMFInfoEndOfData not sent"));
747                 }
748 
749                 iEosStreamIDVec.pop_back();
750             }
751             else
752             {
753                 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::writeComplete - Invalid iEosStreamIDVec size=0"));
754                 OSCL_ASSERT(false);
755             }
756 
757         }
758     }
759     // Check if the writeComplete is in response to Reconfig message
760     else if (&iWriteAsyncReConfigContext == (uint32*)aContext)
761     {
762         if (iWriteState == EWriteBusy)
763         {
764             // Synchronous completion
765             iWriteState = EWriteOK;
766         }
767         else
768         {
769             // Asynchronous completion
770             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::writeComplete For RECONFIG - Fmt=%s",
771                                      iSinkFormatString.get_str()));
772         }
773     }
774     //detect cases where the current SendData call is completing synchronously.
775     else if (iWriteState == EWriteBusy)
776     {
777         //synchronous completion
778         iWriteState = EWriteOK;
779     }
780     else
781     {
782         //asynchronous completion.
783         //do any memory cleanup
784         bool oCmdIdFound = false;
785         uint32 i;
786         for (i = 0; i < iCleanupQueue.size(); i++)
787         {
788             if (iCleanupQueue[i].iCmdId == aCmdId)
789             {
790                 PVMFSharedMediaDataPtr mediaData = iCleanupQueue[i].iData;
791                 iCleanupQueue.erase(&iCleanupQueue[i]);
792                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::writeComplete - Fmt=%s, Seq=%d, TS=%d, FIdx=%d, ClnUpQSize=%d",
793                                          iSinkFormatString.get_str(),
794                                          mediaData->getSeqNum(),
795                                          mediaData->getTimestamp(),
796                                          iFragIndex,
797                                          iCleanupQueue.size()));
798                 oCmdIdFound = true;
799                 break;
800             }
801         }
802         if (oCmdIdFound == false)
803         {
804             PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::writeComplete - CmdId Not Found - Fmt=%s, FIdx=%d, ClnUpQSize=%d",
805                                   iSinkFormatString.get_str(),
806                                   iFragIndex,
807                                   iCleanupQueue.size()));
808         }
809     }
810 }
811 
812 ////////////////////////////////////////////////////////////////////////////
readAsync(uint8 * data,uint32 max_data_len,OsclAny * context,int32 * formats,uint16 num_formats)813 PVMFCommandId PVMediaOutputNodePort::readAsync(uint8* data, uint32 max_data_len, OsclAny* context,
814         int32* formats, uint16 num_formats)
815 //for PvmiMediaTransfer
816 {
817     OSCL_UNUSED_ARG(data);
818     OSCL_UNUSED_ARG(max_data_len);
819     OSCL_UNUSED_ARG(context);
820     OSCL_UNUSED_ARG(formats);
821     OSCL_UNUSED_ARG(num_formats);
822     OSCL_LEAVE(OsclErrNotSupported);
823     return -1;
824 }
825 
826 
827 ////////////////////////////////////////////////////////////////////////////
readComplete(PVMFStatus status,PVMFCommandId read_cmd_id,int32 format_index,const PvmiMediaXferHeader & data_header_info,OsclAny * context)828 void PVMediaOutputNodePort::readComplete(PVMFStatus status, PVMFCommandId read_cmd_id,
829         int32 format_index, const PvmiMediaXferHeader& data_header_info,
830         OsclAny* context)
831 //for PvmiMediaTransfer
832 {
833     OSCL_UNUSED_ARG(status);
834     OSCL_UNUSED_ARG(read_cmd_id);
835     OSCL_UNUSED_ARG(format_index);
836     OSCL_UNUSED_ARG(data_header_info);
837     OSCL_UNUSED_ARG(context);
838     OSCL_LEAVE(OsclErrNotSupported);
839 }
840 
841 
842 ////////////////////////////////////////////////////////////////////////////
statusUpdate(uint32 status_flags)843 void PVMediaOutputNodePort::statusUpdate(uint32 status_flags)
844 //for PvmiMediaTransfer
845 {
846     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
847                     (0, "PVMediaOutputNodePort::statusUpdate flags %d", status_flags));
848 
849     if (status_flags & PVMI_MEDIAXFER_STATUS_WRITE)
850     {
851         //recover from a previous async write error.
852         if (iWriteState == EWriteWait)
853         {
854             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::statusUpdate - WriteAsync Enabled - Fmt=%s, iWriteState=%d",
855                                      iSinkFormatString.get_str(),
856                                      iWriteState));
857             iWriteState = EWriteOK;
858 
859             // Allow data to be processed if possible
860             ProcessIncomingMessageIfPossible();
861 
862             if (oProcessIncomingMessage == true)
863             {
864                 if (iCurrentMediaMsg.GetRep() != NULL)
865                 {
866                     //attempt to send data current media msg if any
867                     SendData();
868                 }
869                 //reschedule if there is more stuff waiting and
870                 //if we can process more data
871                 if (IncomingMsgQueueSize() > 0)
872                 {
873                     RunIfNotReady();
874                 }
875             }
876         }
877     }
878     else
879     {
880         //disable write
881         iWriteState = EWriteWait;
882         oProcessIncomingMessage = false;
883         PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::statusUpdate - WriteAsync Disabled - Fmt=%s, iWriteState=%d",
884                                  iSinkFormatString.get_str(),
885                                  iWriteState));
886     }
887 }
888 
889 
890 ////////////////////////////////////////////////////////////////////////////
cancelCommand(PVMFCommandId command_id)891 void PVMediaOutputNodePort::cancelCommand(PVMFCommandId command_id)
892 //for PvmiMediaTransfer
893 {
894     OSCL_UNUSED_ARG(command_id);
895     OSCL_LEAVE(OsclErrNotSupported);
896 }
897 
898 
899 ////////////////////////////////////////////////////////////////////////////
cancelAllCommands()900 void PVMediaOutputNodePort::cancelAllCommands()
901 //for PvmiMediaTransfer
902 {
903     OSCL_LEAVE(OsclErrNotSupported);
904 }
905 
906 
907 ////////////////////////////////////////////////////////////////////////////
IsFormatSupported(PVMFFormatType aFmt)908 bool PVMediaOutputNodePort::IsFormatSupported(PVMFFormatType aFmt)
909 // for PvmiCapabilityAndConfigPortFormatImpl interface
910 {
911     //Verify if the format is supported by the media I/O component.
912     PvmiKvp kvpFormatType;
913 
914     OSCL_StackString<64> iKVPFormatType = _STRLIT_CHAR(PVMF_FORMAT_TYPE_VALUE_KEY);
915 
916     kvpFormatType.key = NULL;
917     kvpFormatType.key = iKVPFormatType.get_str();
918     kvpFormatType.value.pChar_value = (char*)aFmt.getMIMEStrPtr();
919 
920     PVMFStatus status = iNode->iMIOConfig->verifyParametersSync(NULL, &kvpFormatType, 1);
921     if (status != PVMFSuccess)
922     {
923         return false;
924     }
925     return true;
926 }
927 
928 ////////////////////////////////////////////////////////////////////////////
FormatUpdated()929 void PVMediaOutputNodePort::FormatUpdated()
930 // for PvmiCapabilityAndConfigPortFormatImpl interface
931 {
932     //called when format was just set, either through capability and config,
933     //for by node during port request.
934     if (iSinkFormat.isAudio())
935     {
936         //set port name for datapath logging.
937         SetName("MediaOutIn(Audio)");
938 
939         //pass the selected format to the MIO component.
940         //ignore any failure since not all MIO may support the feature.
941         SetMIOParameterPchar((char*)MOUT_AUDIO_FORMAT_KEY, iSinkFormatString.get_str());
942 
943         //save the media type.
944         if (iSinkFormat.isCompressed())
945         {
946             iMediaType = PVMF_MEDIA_COMPRESSED_AUDIO;
947         }
948         else
949         {
950             iMediaType = PVMF_MEDIA_UNCOMPRESSED_AUDIO;
951             isUnCompressedMIO = true;
952         }
953     }
954     else if (iSinkFormat.isVideo())
955     {
956         //set port name for datapath logging.
957         SetName("MediaOutIn(Video)");
958 
959         //pass the selected format to the MIO component.
960         //ignore any failure since not all MIO may support the feature.
961         SetMIOParameterPchar((char*)MOUT_VIDEO_FORMAT_KEY, iSinkFormatString.get_str());
962 
963         //save the media type.
964         if (iSinkFormat.isCompressed())
965         {
966             iMediaType = PVMF_MEDIA_COMPRESSED_VIDEO;
967         }
968         else
969         {
970             iMediaType = PVMF_MEDIA_UNCOMPRESSED_VIDEO;
971             isUnCompressedMIO = true;
972         }
973     }
974     else if (iSinkFormat.isText())
975     {
976         //set port name for datapath logging.
977         SetName("MediaOutIn");
978 
979         //pass the selected format to the MIO component.
980         //ignore any failure since not all MIO may support the feature.
981         SetMIOParameterPchar((char*)MOUT_TEXT_FORMAT_KEY, iSinkFormatString.get_str());
982 
983         //save the media type.
984         iMediaType = PVMF_MEDIA_TEXT;
985     }
986 }
987 
988 ////////////////////////////////////////////////////////////////////////////
SendData()989 void PVMediaOutputNodePort::SendData()
990 //send data to the MIO componenent.
991 {
992     const int32 toleranceWndForCallback = 0;
993     if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
994     {
995         if (oActiveMediaOutputComp)
996         {
997             SendEndOfData();
998         }
999         else if (iFrameStepMode == false)
1000         {
1001             uint32 delta = 0;
1002             PVMFMediaOutputNodePortMediaTimeStatus status = CheckMediaTimeStamp(delta);
1003             if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME || status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE)
1004             {
1005                 SendEndOfData();
1006             }
1007             else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY)
1008             {
1009 
1010                 OSCL_ASSERT(false == oClockCallBackPending);
1011                 //stop processing input, since we are not done with the current media msg
1012                 oProcessIncomingMessage = false;
1013                 oClockCallBackPending = false;
1014 
1015                 if (NULL != iClockNotificationsInf)
1016                 {
1017                     PVMFStatus status =
1018                         iClockNotificationsInf->SetCallbackDeltaTime(delta, //delta time in clock when callBack should be called
1019                                 toleranceWndForCallback,
1020                                 this, //observer object to be called on timeout
1021                                 false, //no threadLock
1022                                 NULL, //no context
1023                                 iDelayEarlyFrameCallBkId); //ID used to identify the timer for cancellation
1024                     if (PVMFSuccess != status)
1025                     {
1026                         //If delta specified for the callback is too large, then callback to the Mediaclock notification interface does not succeed
1027                         //Possible reasons for huge difference between the playback clock and the timestamp could be
1028                         //Sample is intended to be played after a very long time from now (as indicated by the data source(streaming server/file)).
1029                         //Timestamp is corrupted in the source node.
1030                         PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendData - Could not set callback notification for send data %d delta %u", status, delta));
1031                         iNode->ReportErrorEvent(PVMFErrCorrupt, NULL, PVMFMoutNodeErr_Unexpected);
1032                         return;
1033                     }
1034                     else
1035                     {
1036                         oClockCallBackPending = true;
1037                     }
1038                 }
1039                 else
1040                 {
1041                     PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendData - Fmt=%s, No callback notification Intf ",
1042                                           iSinkFormatString.get_str()));
1043                     OSCL_ASSERT(false);
1044                 }
1045             }
1046         }
1047         else if (iFrameStepMode == true)
1048         {
1049             PVMFMediaOutputNodePortMediaTimeStatus status = CheckMediaFrameStep();
1050             if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME || status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE)
1051             {
1052                 SendEndOfData();
1053             }
1054             else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY)
1055             {
1056                 //stop processing input, since we are not done with the current media msg
1057                 oProcessIncomingMessage = false;
1058                 //wait on ClockCountUpdated call back from oscl clock
1059             }
1060         }
1061     }
1062     else if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_RE_CONFIG_FORMAT_ID)
1063     {
1064         SendReConfigNotification();
1065     }
1066     else if (iCurrentMediaMsg->getFormatID() < PVMF_MEDIA_CMD_FORMAT_IDS_START)
1067     {
1068         if (oActiveMediaOutputComp)
1069         {
1070             SendMediaData();
1071         }
1072         else if (iFrameStepMode == false)
1073         {
1074             uint32 delta = 0;
1075             PVMFMediaOutputNodePortMediaTimeStatus status = CheckMediaTimeStamp(delta);
1076             if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME)
1077             {
1078                 SendMediaData();
1079             }
1080             else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE)
1081             {
1082                 iCurrentMediaMsg.Unbind();
1083                 iFragIndex = 0;
1084             }
1085             else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY)
1086             {
1087 
1088                 OSCL_ASSERT(false == oClockCallBackPending);
1089                 //stop processing input, since we are not done with the current media msg
1090                 oProcessIncomingMessage = false;
1091                 oClockCallBackPending = false;
1092 
1093                 if (NULL != iClockNotificationsInf)
1094                 {
1095                     PVMFStatus status =
1096                         iClockNotificationsInf->SetCallbackDeltaTime(delta, //delta time in clock when callBack should be called
1097                                 toleranceWndForCallback,
1098                                 this, //observer object to be called on timeout
1099                                 false, //no threadLock
1100                                 NULL, //no context
1101                                 iDelayEarlyFrameCallBkId); //ID used to identify the timer for cancellation
1102                     if (PVMFSuccess != status)
1103                     {
1104                         PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendData - Could not set callback notification for early frame %d delta %u", status, delta));
1105                         iNode->ReportErrorEvent(PVMFErrCorrupt, NULL, PVMFMoutNodeErr_Unexpected);
1106                         return;
1107                     }
1108                     else
1109                     {
1110                         oClockCallBackPending = true;
1111                     }
1112                 }
1113                 else
1114                 {
1115                     PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendData - Fmt=%s, No callback notification Intf ",
1116                                           iSinkFormatString.get_str()));
1117                     OSCL_ASSERT(false);
1118                 }
1119             }
1120         }
1121         else if (iFrameStepMode == true)
1122         {
1123             PVMFMediaOutputNodePortMediaTimeStatus status = CheckMediaFrameStep();
1124             if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME)
1125             {
1126                 SendMediaData();
1127             }
1128             else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE)
1129             {
1130                 iCurrentMediaMsg.Unbind();
1131                 iFragIndex = 0;
1132             }
1133             else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY)
1134             {
1135                 //stop processing input, since we are not done with the current media msg
1136                 oProcessIncomingMessage = false;
1137                 //wait on ClockCountUpdated call back from oscl clock
1138             }
1139         }
1140     }
1141 }
1142 
1143 ////////////////////////////////////////////////////////////////////////////
SendMediaData()1144 void PVMediaOutputNodePort::SendMediaData()
1145 //send media data to the MIO componenent.
1146 {
1147     if (iWriteState != EWriteOK)
1148     {
1149         PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendMediaData - Fmt=%s - Invalid WriteAsync State - State=%d",
1150                                  iSinkFormatString.get_str(),
1151                                  iWriteState));
1152         PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendMediaData - Fmt=%s - Invalid WriteAsync State - State=%d",
1153                               iSinkFormatString.get_str(),
1154                               iWriteState));
1155         OSCL_ASSERT(false);
1156     }
1157 
1158     PVMFSharedMediaDataPtr mediaData;
1159     convertToPVMFMediaData(mediaData, iCurrentMediaMsg);
1160 
1161     uint32 duration = 0;
1162     if (mediaData->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_DURATION_AVAILABLE_BIT)
1163     {
1164         duration = mediaData->getDuration();
1165     }
1166 
1167     // extract private data (if it is in fsi)
1168     OsclAny *privatedataptr = NULL;
1169     uint32 privatedatalength = 0;
1170 
1171     OsclRefCounterMemFrag fsifrag;
1172     mediaData->getFormatSpecificInfo(fsifrag);
1173 
1174     uint32 *data = (uint32 *)fsifrag.getMemFragPtr();
1175     uint32 data_len = fsifrag.getMemFragSize();
1176     if (data && data_len > 0)
1177     {
1178         //data to extract
1179         privatedataptr = (OsclAny*)(*data);
1180         privatedatalength = data_len;
1181     }
1182 
1183 
1184     for (uint32 fragindex = iFragIndex; fragindex < mediaData->getNumFragments();)
1185     {
1186         OsclRefCounterMemFrag frag;
1187         mediaData->getMediaFragment(fragindex, frag);
1188 
1189         iWriteState = EWriteBusy;
1190         int32 err = OsclErrNone;
1191         int32 cmdId = 0;
1192 
1193         uint32 flags = PVMI_MEDIAXFER_MEDIA_DATA_FLAG_NONE;
1194 
1195         // The marker bit should only be set for the final frag to allow MIO to reassemble data properly
1196         if ((mediaData->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT) &&
1197                 (fragindex == (mediaData->getNumFragments() - 1)))
1198         {
1199             flags |= PVMI_MEDIAXFER_MEDIA_DATA_FLAG_MARKER_BIT;
1200         }
1201         if (mediaData->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_NO_RENDER_BIT)
1202         {
1203             flags |= PVMI_MEDIAXFER_MEDIA_DATA_FLAG_NO_RENDER_BIT;
1204         }
1205         PvmiMediaXferHeader mediaxferhdr;
1206         mediaxferhdr.seq_num = mediaData->getSeqNum();
1207         mediaxferhdr.timestamp = mediaData->getTimestamp();
1208         mediaxferhdr.duration = duration;
1209         mediaxferhdr.flags = flags;
1210         mediaxferhdr.stream_id = mediaData->getStreamID();
1211         mediaxferhdr.private_data_length = privatedatalength;
1212         mediaxferhdr.private_data_ptr = privatedataptr;
1213         err = WriteDataToMIO(cmdId, mediaxferhdr, frag);
1214 
1215         if (err != OsclErrNone)
1216         {
1217             // A Busy or an InvalidState leave can occur in a writeAsync call. If a leave occurs in writeasync call,
1218             // suspend data transfer.
1219             // A Busy leave is not an error and is a normal flow control mechanism.
1220             // Some MIO components can do a InvalidState leave if writeasyncs are called before calling Start on MIOs.
1221             // Data transfer to MIOs will resume when
1222             // 1) In case of Busy Leave: A statusUpdate call from the MIO component tells us to resume.
1223             // 2) In case of InvalidState Leave: A statusUpdate call from the MIO component tells us to resume. OR
1224             //                                   MIO sends the command complete for Start.
1225             iWriteState = EWriteWait;
1226 
1227             //stop processing input, since we are not done with the current media msg
1228             oProcessIncomingMessage = false;
1229 
1230             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendMediaData - WriteAsyncLeave - Fmt=%s, LeaveCode=%d",
1231                                      iSinkFormatString.get_str(),
1232                                      err));
1233 
1234             return ;//wait on statusUpdate call or start complete from the MIO component.
1235         }
1236         else
1237         {
1238             fragindex++;
1239             iFragIndex++;
1240             if (fragindex == mediaData->getNumFragments())
1241             {
1242                 //all fragments have been sent.  see whether completion
1243                 //is synchronous or asynchronous.
1244                 if (iWriteState == EWriteBusy)
1245                 {
1246                     //asynchronous completion.
1247                     //push the data onto the cleanup stack so it won't get cleaned
1248                     //up until the component consumes it.
1249                     iCleanupQueue.push_back(CleanupQueueElement(mediaData, cmdId));
1250                     PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendMediaData - AsyncWrite - Fmt=%s, Seq=%d, TS=%d, Dur=%d, FIdx=%d, ClnUpQSize=%d",
1251                                              iSinkFormatString.get_str(),
1252                                              mediaData->getSeqNum(),
1253                                              mediaData->getTimestamp(),
1254                                              duration,
1255                                              iFragIndex,
1256                                              iCleanupQueue.size()));
1257                 }
1258                 //else the write already completed synchronously.
1259                 else
1260                 {
1261                     PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendMediaData - SyncWrite - Fmt=%s, Seq=%d, TS=%d, Dur=%d, FIdx=%d, ClnUpQSize=%d",
1262                                              iSinkFormatString.get_str(),
1263                                              mediaData->getSeqNum(),
1264                                              mediaData->getTimestamp(),
1265                                              duration,
1266                                              iFragIndex,
1267                                              iCleanupQueue.size()));
1268                 }
1269                 //we are done with current media msg - either we are truly done (sync write complete) or we are
1270                 //waiting on async write complete in which case media msg has been pushed into the cleanup queue
1271                 iCurrentMediaMsg.Unbind();
1272                 iFragIndex = 0;
1273             }
1274             iWriteState = EWriteOK;
1275         }
1276     }
1277     return;
1278 }
1279 
1280 ////////////////////////////////////////////////////////////////////////////
SendEndOfData()1281 void PVMediaOutputNodePort::SendEndOfData()
1282 //send end of data notice to the MIO componenent.
1283 {
1284     if (iWriteState != EWriteOK)
1285     {
1286         PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendEndOfData - Invalid WriteAsync State - State=%d", iWriteState));
1287         OSCL_ASSERT(false);
1288     }
1289 
1290     uint32 eosseqnum = iCurrentMediaMsg->getSeqNum();
1291     uint32 eostimestamp = iCurrentMediaMsg->getTimestamp();
1292 
1293     iWriteState = EWriteBusy;
1294 
1295     int32 err;
1296     int32 cmdId = 0;
1297 
1298     PvmiMediaXferHeader mediaxferhdr;
1299     mediaxferhdr.seq_num = eosseqnum;
1300     mediaxferhdr.timestamp = eostimestamp;
1301     mediaxferhdr.duration = 0;
1302     mediaxferhdr.flags = PVMI_MEDIAXFER_MEDIA_DATA_FLAG_NONE;
1303     mediaxferhdr.stream_id = iCurrentMediaMsg->getStreamID();
1304     uint32 EosStreamId = mediaxferhdr.stream_id;
1305 
1306     //iEosStreamIDVec is used as a FIFO to store the steamids of eos sent to mio comp.
1307     //streamid is pushed in at front when call writeasync(eos) to mio comp.
1308     //streamid is poped out from end when mio comp. calls writecomplete(eos),
1309     //we report PVMFInfoEndOfData with the poped streamid.
1310     //This logic depends on Mio comp. process data(at least eos msg) in a sequencial style.
1311     iEosStreamIDVec.push_front(EosStreamId);
1312     OSCL_TRY(err,
1313              cmdId = iMediaTransfer->writeAsync(PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION,  /*format_type*/
1314                                                 PVMI_MEDIAXFER_FMT_INDEX_END_OF_STREAM, /*format_index*/
1315                                                 NULL,
1316                                                 0,
1317                                                 mediaxferhdr,
1318                                                 (OsclAny*) & iWriteAsyncEOSContext);
1319             );
1320 
1321     if (err != OsclErrNone)
1322     {
1323         // A Busy or an InvalidState leave can occur in a writeAsync call. If a leave occurs in writeasync call,
1324         // suspend data transfer.
1325         // A Busy leave is not an error and is a normal flow control mechanism.
1326         // Some MIO components can do a InvalidState leave if writeasyncs are called before calling Start on MIOs.
1327         // Data transfer to MIOs will resume when
1328         // 1) In case of Busy Leave: A statusUpdate call from the MIO component tells us to resume.
1329         // 2) In case of InvalidState Leave: A statusUpdate call from the MIO component tells us to resume. OR
1330         //                                   MIO sends the command complete for Start.
1331         iWriteState = EWriteWait;
1332 
1333         //stop processing input, since we are not done with the current media msg
1334         oProcessIncomingMessage = false;
1335 
1336         // StreamID popped from vector when leave occurs in the writeAsync call
1337         if (iEosStreamIDVec.size() != 0)
1338         {
1339             iEosStreamIDVec.erase(iEosStreamIDVec.begin());
1340         }
1341         else
1342         {
1343             PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendEndOfData - Invalid iEosStreamIDVec size=0"));
1344             OSCL_ASSERT(false);
1345         }
1346 
1347         PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendEndOfData - WriteAsyncLeave - Fmt=%s, LeaveCode=%d",
1348                                  iSinkFormatString.get_str(),
1349                                  err));
1350 
1351         return ;//wait on statusUpdate call or start complete from the MIO component.
1352     }
1353     else
1354     {
1355         if (iWriteState == EWriteBusy)
1356         {
1357             //asynchronous completion.
1358             //wait for writeComplete to be called for this request
1359             //log media data info.
1360             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendEndOfData - AsyncWrite - Fmt=%s, Seq=%d, TS=%d, ClnUpQSize=%d",
1361                                      iSinkFormatString.get_str(),
1362                                      iCurrentMediaMsg->getSeqNum(),
1363                                      iCurrentMediaMsg->getTimestamp(),
1364                                      iCleanupQueue.size()));
1365 
1366             iWriteState = EWriteOK;
1367 
1368         }
1369         //else the write already completed synchronously.
1370         else
1371         {
1372             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendEndOfData - SyncWrite - Fmt=%s, Seq=%d, TS=%d, ClnUpQSize=%d",
1373                                      iSinkFormatString.get_str(),
1374                                      iCurrentMediaMsg->getSeqNum(),
1375                                      iCurrentMediaMsg->getTimestamp(),
1376                                      iCleanupQueue.size()));
1377 
1378             // Report End of Data to the user of media output node
1379             if (iEosStreamIDVec.size() != 0)
1380             {
1381                 //iEosStreamIDVec is used as a FIFO to store the steamids of eos sent to mio comp.
1382                 //streamid is pushed in at front when call writeasync(eos) to mio comp.
1383                 //streamid is poped out from end when mio comp. calls writecomplete(eos),
1384                 //we report PVMFInfoEndOfData with the poped streamid.
1385                 //This logic depends on Mio comp. process data(at least eos msg) in a sequencial style.
1386                 uint32 EosStreamID = iEosStreamIDVec.back();
1387                 iNode->ReportInfoEvent(PVMFInfoEndOfData, (OsclAny*)&EosStreamID);
1388                 iEosStreamIDVec.pop_back();
1389             }
1390             else
1391             {
1392                 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendEndOfData - Invalid iEosStreamIDVec size=0"));
1393                 OSCL_ASSERT(false);
1394             }
1395         }
1396         //we are done with current media msg - either we are truly done (sync write complete) or we are
1397         //waiting on async write complete. there is no need to push this msg into cleanup queue since it
1398         //is a notification as opossed to media data
1399         iCurrentMediaMsg.Unbind();
1400         iFragIndex = 0;
1401     }
1402 }
1403 
1404 ////////////////////////////////////////////////////////////////////////////
SendReConfigNotification()1405 void PVMediaOutputNodePort::SendReConfigNotification()
1406 //send reconfig notice to the MIO componenent.
1407 {
1408     if (iWriteState != EWriteOK)
1409     {
1410         PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendReConfigNotification - Invalid WriteAsync State - State=%d", iWriteState));
1411         OSCL_ASSERT(false);
1412     }
1413 
1414     iWriteState = EWriteBusy;
1415     int32 err;
1416     int32 cmdId = 0;
1417     PvmiMediaXferHeader mediaxferhdr;
1418     mediaxferhdr.seq_num = iCurrentMediaMsg->getSeqNum();
1419     mediaxferhdr.timestamp = 0;
1420     mediaxferhdr.duration = 0;
1421     mediaxferhdr.flags = PVMI_MEDIAXFER_MEDIA_DATA_FLAG_NONE;
1422     mediaxferhdr.stream_id = iCurrentMediaMsg->getStreamID();
1423     OSCL_TRY(err,
1424              cmdId = iMediaTransfer->writeAsync(PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION,  /*format_type*/
1425                                                 PVMI_MEDIAXFER_FMT_INDEX_RE_CONFIG_NOTIFICATION, /*format_index*/
1426                                                 NULL, 0,
1427                                                 mediaxferhdr,
1428                                                 (OsclAny*) & iWriteAsyncReConfigContext);
1429             );
1430 
1431     if (err != OsclErrNone)
1432     {
1433         PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendReConfigNotification SendReConfigNotification leave code %d", err));
1434         PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendReConfigNotification SendReConfigNotification leave code %d", err));
1435         //we don't handle a leave here-- it's an error
1436         //media output comps should be open to recving reconfig anytime
1437         //they are free to process it at a later point in time and they may
1438         //choose to accept the reconfig and reject it. but there should never
1439         //be a case where cannot even queue the reconfig request
1440         iNode->ReportErrorEvent(PVMFErrResource, NULL, PVMFMoutNodeErr_WriteAsync);
1441     }
1442     else
1443     {
1444         if (iWriteState == EWriteBusy)
1445         {
1446             //asynchronous completion.
1447             //wait for writeComplete to be called for this request
1448             //log media data info.
1449             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendReConfigNotification - AsyncWrite - Fmt=%s, Seq=%d, TS=%d, ClnUpQSize=%d",
1450                                      iSinkFormatString.get_str(),
1451                                      iCurrentMediaMsg->getSeqNum(),
1452                                      iCurrentMediaMsg->getTimestamp(),
1453                                      iCleanupQueue.size()));
1454 
1455             iWriteState = EWriteOK;
1456 
1457         }
1458         //else the write already completed synchronously.
1459         else
1460         {
1461             //log media data info.
1462             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendEndOfData - SyncWrite - Fmt=%s, Seq=%d, TS=%d, ClnUpQSize=%d",
1463                                      iSinkFormatString.get_str(),
1464                                      iCurrentMediaMsg->getSeqNum(),
1465                                      iCurrentMediaMsg->getTimestamp(),
1466                                      iCleanupQueue.size()));
1467         }
1468         //we are done with current media msg - either we are truly done (sync write complete) or we are
1469         //waiting on async write complete. there is no need to push this msg into cleanup queue since it
1470         //is a notification as opossed to media data
1471         iCurrentMediaMsg.Unbind();
1472         iFragIndex = 0;
1473     }
1474 }
1475 
1476 ////////////////////////////////////////////////////////////////////////////
1477 PVMFMediaOutputNodePortMediaTimeStatus
CheckMediaTimeStamp(uint32 & aDelta)1478 PVMediaOutputNodePort::CheckMediaTimeStamp(uint32& aDelta)
1479 {
1480     PVMFTimestamp aTimeStamp = iCurrentMediaMsg->getTimestamp();
1481     aDelta = 0;
1482     //aTimeStamp is assumed to be in milliseconds
1483     if (iClock != NULL)
1484     {
1485         uint32 clock_msec32;
1486         bool overflowFlag = false;
1487 
1488         iClock->GetCurrentTime32(clock_msec32, overflowFlag, PVMF_MEDIA_CLOCK_MSEC);
1489 
1490 
1491         uint32 clock_adjforearlymargin = clock_msec32 + iEarlyMargin;
1492         uint32 ts_adjforlatemargin = aTimeStamp + iLateMargin;
1493 
1494         if ((clock_adjforearlymargin - aTimeStamp) > WRAP_THRESHOLD)
1495         {
1496             // This condition indicates that the timestamp is ahead of the adjusted playback clock
1497             // Note that since the computation is based on 32-bit values, it has a limitation that
1498             // it will not work for durations exceeding 2^32 milliseconds = 49+ days which is an acceptable
1499             // limit for this application.
1500             // Say clock is 1000ms, early margin is 200ms, then any timestamp later than 1200ms should be
1501             // held back. If ts is greater than 1200ms, then (1200 - ts) will be larger than wrap threshold
1502             uint32 deltaInMS = (aTimeStamp - clock_msec32);
1503             deltaInMS -= iEarlyMargin;
1504             if (iClockRate > 1)
1505             {
1506                 //In case of rate change, calculate delta to acct
1507                 //for clock rate
1508                 MediaClockConverter mcc;
1509                 mcc.set_timescale(iClockRate);
1510                 //delta is in milliseconds
1511                 mcc.set_clock_other_timescale(deltaInMS, 1000);
1512                 //get the value in milliseconds
1513                 aDelta = mcc.get_converted_ts(1000);
1514                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Early - Fmt=%s, Seq=%d, Ts=%d, Clock=%d, DeltaInMS=%d, ClkRate=%d, DeltaInClkUnits=%d",
1515                                          iSinkFormatString.get_str(),
1516                                          iCurrentMediaMsg->getSeqNum(),
1517                                          aTimeStamp,
1518                                          clock_msec32,
1519                                          deltaInMS,
1520                                          iClockRate,
1521                                          aDelta));
1522             }
1523             else
1524             {
1525                 aDelta = deltaInMS;
1526                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Early - Fmt=%s, Seq=%d, Ts=%d, Clock=%d, Delta=%d",
1527                                          iSinkFormatString.get_str(),
1528                                          iCurrentMediaMsg->getSeqNum(),
1529                                          aTimeStamp,
1530                                          clock_msec32,
1531                                          aDelta));
1532             }
1533             iConsecutiveFramesDropped = 0;
1534             return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY;
1535         }
1536         else if ((ts_adjforlatemargin - clock_msec32) > WRAP_THRESHOLD)
1537         {
1538             // This condition indicates that the clock is ahead of the adjusted timestamp
1539             // Note that since the computation is based on 32-bit values, it has a limitation that
1540             // it will not work for durations exceeding 2^32 milliseconds = 49+ days which is an acceptable
1541             // limit for this application.
1542             // Say clock is 1000ms, late margin is 200ms, then any timestamp earlier than 800ms should be
1543             // dropped, as late. If ts is less than 800ms, then (ts + 200 - 1000) will be larger than wrap threshold
1544             aDelta = (clock_msec32 - aTimeStamp);
1545             iFramesDropped++;
1546             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Late - Fmt=%s, Seq=%d, Ts=%d, Clock=%d, Delta=%d",
1547                                      iSinkFormatString.get_str(),
1548                                      iCurrentMediaMsg->getSeqNum(),
1549                                      aTimeStamp,
1550                                      clock_msec32,
1551                                      aDelta));
1552             iConsecutiveFramesDropped++;
1553             if (iMediaType == PVMF_MEDIA_UNCOMPRESSED_VIDEO)
1554             {
1555                 if ((iConsecutiveFramesDropped >= THRESHOLD_FOR_DROPPED_VIDEO_FRAMES) && (iLateFrameEventSent == false))
1556                 {
1557                     iLateFrameEventSent = true;
1558                     iNode->ReportInfoEvent(PVMFInfoVideoTrackFallingBehind, (OsclAny*)NULL);
1559                 }
1560             }
1561             return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE;
1562         }
1563         else
1564         {
1565             //ts falls in the interval (clock-latermargin, clock+earlymargin)
1566             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - OnTime - Fmt=%s, Seq=%d, Ts=%d, Clock=%d",
1567                                      iSinkFormatString.get_str(),
1568                                      iCurrentMediaMsg->getSeqNum(),
1569                                      aTimeStamp,
1570                                      clock_msec32));
1571             iConsecutiveFramesDropped = 0;
1572             return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME;
1573         }
1574     }
1575     else
1576     {
1577 
1578         PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Fmt=%s, No PlayBack Clock!!!",
1579                               iSinkFormatString.get_str()));
1580         OSCL_ASSERT(false);
1581         return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ERROR;
1582     }
1583 }
1584 
1585 ////////////////////////////////////////////////////////////////////////////
1586 PVMFMediaOutputNodePortMediaTimeStatus
CheckMediaFrameStep()1587 PVMediaOutputNodePort::CheckMediaFrameStep()
1588 {
1589     if (iClock != NULL)
1590     {
1591         if (iClockFrameCount > iSyncFrameCount)
1592         {
1593             //this condition implies that clock count has
1594             //gone past the sync frame count, late frame, drop it
1595             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaFrameStep - Late - Fmt=%s, Seq=%d, Ts=%d, iClockFrameCount=%d, iSyncFrameCount=%d",
1596                                      iSinkFormatString.get_str(),
1597                                      iCurrentMediaMsg->getSeqNum(),
1598                                      iCurrentMediaMsg->getTimestamp(),
1599                                      iClockFrameCount,
1600                                      iSyncFrameCount));
1601             iSyncFrameCount++;
1602             return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE;
1603         }
1604         else if (iClockFrameCount < iSyncFrameCount)
1605         {
1606             //this condition implies that clock count is less than
1607             //the sync frame count, early frame, hold it
1608             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaFrameStep - Early - Fmt=%s, Seq=%d, Ts=%d, iClockFrameCount=%d, iSyncFrameCount=%d",
1609                                      iSinkFormatString.get_str(),
1610                                      iCurrentMediaMsg->getSeqNum(),
1611                                      iCurrentMediaMsg->getTimestamp(),
1612                                      iClockFrameCount,
1613                                      iSyncFrameCount));
1614             return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY;
1615         }
1616         else
1617         {
1618             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaFrameStep - OnTime - Fmt=%s, Seq=%d, Ts=%d, iClockFrameCount=%d, iSyncFrameCount=%d",
1619                                      iSinkFormatString.get_str(),
1620                                      iCurrentMediaMsg->getSeqNum(),
1621                                      iCurrentMediaMsg->getTimestamp(),
1622                                      iClockFrameCount,
1623                                      iSyncFrameCount));
1624             iSyncFrameCount++;
1625             return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME;
1626         }
1627     }
1628     else
1629     {
1630 
1631         PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Fmt=%s, No PlayBack Clock!!!",
1632                               iSinkFormatString.get_str()));
1633         OSCL_ASSERT(false);
1634         return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ERROR;
1635     }
1636 }
1637 
1638 ////////////////////////////////////////////////////////////////////////////
Run()1639 void PVMediaOutputNodePort::Run()
1640 {
1641     /*
1642      * Media Output node inport does not process any more incoming messages
1643      * under following circumstances:
1644      * 1) Playback clock is NOT in RUNNING state
1645      * 2) Media output comp is in a STARTED state
1646      * 3) When waiting on media output comp to go ready from a busy state
1647      * Boolean "oProcessIncomingMessage" will be false if any of the above
1648      * conditions is true.
1649      * This while loop is intentional. This port doesnt do much in terms of
1650      * data processing. So we attempt to send as much data as we can in a
1651      * single Run call. Since we could process multiple media msgs per Run
1652      * we need to account for BOS and Skip as well.
1653      */
1654     while ((IncomingMsgQueueSize() > 0) || (iCurrentMediaMsg.GetRep() != NULL))
1655     {
1656         bool oMsgDqd = false;
1657         if (iCurrentMediaMsg.GetRep() == NULL)
1658         {
1659             //we are starting to process a new media msg
1660             iFragIndex = 0;
1661             if (DequeueIncomingMsg(iCurrentMediaMsg) != PVMFSuccess)
1662             {
1663                 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::Run: DequeueIncomingMsg Failed - Fmt=%s",
1664                                       iSinkFormatString.get_str()));
1665                 OSCL_ASSERT(0);
1666             }
1667             else
1668             {
1669                 //this boolean avoids duplicate logs in case we are skipping data
1670                 oMsgDqd = true;
1671             }
1672         }
1673         if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_BOS_FORMAT_ID)
1674         {
1675             uint32 msgStreamId = iCurrentMediaMsg->getStreamID();
1676             iBOSStreamIDVec.push_back(msgStreamId);
1677 
1678             PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::Run: BOS Recvd - Fmt=%s, TS=%d, StreamID=%d, Qs=%d",
1679                                   iSinkFormatString.get_str(),
1680                                   iCurrentMediaMsg->getTimestamp(),
1681                                   msgStreamId,
1682                                   IncomingMsgQueueSize()));
1683 
1684             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run: BOS Recvd - Fmt=%s, TS=%d, StreamID=%d, Qs=%d",
1685                                      iSinkFormatString.get_str(),
1686                                      iCurrentMediaMsg->getTimestamp(),
1687                                      msgStreamId,
1688                                      IncomingMsgQueueSize()));
1689 
1690             iNode->ReportBOS();
1691             iCurrentMediaMsg.Unbind();
1692             iFragIndex = 0;
1693         }
1694         else if (DataToSkip(iCurrentMediaMsg) == true)
1695         {
1696             //this condition implies that a skip timestamp has been set
1697             //and we are looking for a mediamsg whole timestamp is equal or greater than
1698             //iSkipTimestamp. All media msgs whose timestamps are less than iSkipTimestamp
1699             //will be dropped. There is no need for any additional checks. Just dequeue and toss
1700             if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
1701             {
1702                 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::Run: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
1703                                       iCurrentMediaMsg->getStreamID(),
1704                                       iCurrentMediaMsg->getSeqNum(),
1705                                       iCurrentMediaMsg->getTimestamp(),
1706                                       iSinkFormatString.get_str()));
1707 
1708                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
1709                                          iCurrentMediaMsg->getStreamID(),
1710                                          iCurrentMediaMsg->getSeqNum(),
1711                                          iCurrentMediaMsg->getTimestamp(),
1712                                          iSinkFormatString.get_str()));
1713             }
1714             else
1715             {
1716                 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::Run: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
1717                                       iCurrentMediaMsg->getStreamID(),
1718                                       iCurrentMediaMsg->getSeqNum(),
1719                                       iCurrentMediaMsg->getTimestamp(),
1720                                       iSinkFormatString.get_str()));
1721 
1722                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
1723                                          iCurrentMediaMsg->getStreamID(),
1724                                          iCurrentMediaMsg->getSeqNum(),
1725                                          iCurrentMediaMsg->getTimestamp(),
1726                                          iSinkFormatString.get_str()));
1727             }
1728 
1729             iCurrentMediaMsg.Unbind();
1730             iFragIndex = 0;
1731         }
1732         else
1733         {
1734             //implies that this message needs to be consumed
1735             if (oMsgDqd == true)
1736             {
1737                 //logging
1738                 if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
1739                 {
1740                     PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run - EOS Recvd - StreamID=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d",
1741                                              iCurrentMediaMsg->getStreamID(),
1742                                              iCurrentMediaMsg->getSeqNum(),
1743                                              iCurrentMediaMsg->getTimestamp(),
1744                                              iSinkFormatString.get_str(),
1745                                              IncomingMsgQueueSize()));
1746                 }
1747                 else if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_RE_CONFIG_FORMAT_ID)
1748                 {
1749                     PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run - RECONFIG Recvd - Seq=%d, TS=%d, Fmt=%s, Qs=%d",
1750                                              iCurrentMediaMsg->getSeqNum(),
1751                                              iCurrentMediaMsg->getTimestamp(),
1752                                              iSinkFormatString.get_str(),
1753                                              IncomingMsgQueueSize()));
1754                 }
1755                 else if (iCurrentMediaMsg->getFormatID() < PVMF_MEDIA_CMD_FORMAT_IDS_START)
1756                 {
1757                     iTotalFrames++;
1758                     PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run - MediaMsg Recvd - Seq=%d, TS=%d, Fmt=%s, Qs=%d",
1759                                              iCurrentMediaMsg->getSeqNum(),
1760                                              iCurrentMediaMsg->getTimestamp(),
1761                                              iSinkFormatString.get_str(),
1762                                              IncomingMsgQueueSize()));
1763                 }
1764             }
1765 
1766             if ((iSendStartOfDataEvent == true) && oMIOComponentConfigured)
1767             {
1768                 //implies that we are attempting to process the first media msg during
1769                 //after skip, a mediamsg whose timestamp is equal to or greater than
1770                 //iSkipTimestamp
1771                 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::Run: PVMFInfoStartOfData - Fmt=%s",
1772                                       iSinkFormatString.get_str()));
1773                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run: PVMFInfoStartOfData - Fmt=%s",
1774                                          iSinkFormatString.get_str()));
1775                 uint32 iStreamID = iRecentStreamID;
1776                 iNode->ReportInfoEvent(PVMFInfoStartOfData, (OsclAny*)&iStreamID);
1777                 iSendStartOfDataEvent = false;
1778             }
1779 
1780             // We need to check for valid CurrentMediaMsg because it is possible that SendData has been
1781             // called from ClockStateUpdated when all tracks report InfoStartofData and Engine starts the clock
1782             // If dequeued data has already been sent, we cant send that data again, it will crash
1783             // so just return and AO will be scheduled again for next data.
1784             if ((oProcessIncomingMessage == true) && (iCurrentMediaMsg.GetRep() != NULL))
1785             {
1786                 SendData();
1787             }
1788             else
1789             {
1790                 //implies that we cannot send out any more data
1791                 //no point continuing, just return
1792                 //Do not reschedule here. We need to wait for
1793                 //oProcessIncomingMessage to be true again
1794                 return;
1795             }
1796         }
1797     }
1798 }
1799 
1800 
1801 ////////////////////////////////////////////////////////////////////////////
HandlePortActivity(const PVMFPortActivity & aActivity)1802 void PVMediaOutputNodePort::HandlePortActivity(const PVMFPortActivity& aActivity)
1803 //from PVMFPortActivityHandler.  this port handles its own activity.
1804 {
1805     switch (aActivity.iType)
1806     {
1807         case PVMF_PORT_ACTIVITY_CREATED:
1808             iNode->ReportInfoEvent(PVMFInfoPortCreated, (OsclAny*)aActivity.iPort);
1809             break;
1810 
1811         case PVMF_PORT_ACTIVITY_DELETED:
1812             iNode->ReportInfoEvent(PVMFInfoPortDeleted, (OsclAny*)aActivity.iPort);
1813             break;
1814 
1815         case PVMF_PORT_ACTIVITY_CONNECT:
1816             iNode->ReportInfoEvent(PVMFInfoPortConnected, (OsclAny*)aActivity.iPort);
1817             break;
1818 
1819         case PVMF_PORT_ACTIVITY_DISCONNECT:
1820             iNode->ReportInfoEvent(PVMFInfoPortDisconnected, (OsclAny*)aActivity.iPort);
1821             break;
1822 
1823         case PVMF_PORT_ACTIVITY_INCOMING_MSG:
1824             if (IncomingMsgQueueSize() > 0)
1825             {
1826                 PVMFSharedMediaMsgPtr peekMsgPtr;
1827                 bool oBos = false;
1828                 bool oMIOAlreadyConfigured = false;
1829                 oMIOAlreadyConfigured = oMIOComponentConfigured;
1830                 if (peekHead(peekMsgPtr, oBos))
1831                 {
1832                     /*
1833                      * Media Output node inport does not process any more incoming messages
1834                      * under following circumstances:
1835                      * 1) Playback clock is NOT in RUNNING state
1836                      * 2) Media output comp is in a STARTED state
1837                      * 3) When waiting on media output comp to go ready from a busy state
1838                      * Boolean "oProcessIncomingMessage" will be false if any of the above
1839                      * conditions is true.
1840                      * However BOS is an exception to all of these. BOS is not sent to media output comp,
1841                      * nor should we worry about playback clock state or media output comp state while
1842                      * processing BOS. When we get BOS we always send a notification to mediaoutput node
1843                      * via the BOSObserver with BOS stream-id.
1844                      */
1845                     if (oBos)
1846                     {
1847                         if (DequeueIncomingMsg(iCurrentMediaMsg) == PVMFSuccess)
1848                         {
1849                             uint32 msgStreamId = peekMsgPtr->getStreamID();
1850                             iBOSStreamIDVec.push_back(msgStreamId);
1851 
1852                             PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::HPA: BOS Recvd - Fmt=%s, TS=%d, StreamID=%d, Qs=%d",
1853                                                   iSinkFormatString.get_str(),
1854                                                   peekMsgPtr->getTimestamp(),
1855                                                   msgStreamId,
1856                                                   IncomingMsgQueueSize()));
1857 
1858                             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: BOS Recvd - Fmt=%s, TS=%d, StreamID=%d, Qs=%d",
1859                                                      iSinkFormatString.get_str(),
1860                                                      peekMsgPtr->getTimestamp(),
1861                                                      msgStreamId,
1862                                                      IncomingMsgQueueSize()));
1863 
1864                             iNode->ReportBOS();
1865 
1866                             iCurrentMediaMsg.Unbind();
1867                             iFragIndex = 0;
1868                         }
1869                         else
1870                         {
1871                             PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg Failed - Fmt=%s",
1872                                                   iSinkFormatString.get_str()));
1873                             OSCL_ASSERT(false);
1874                         }
1875                     }
1876                     else if (DataToSkip(peekMsgPtr) == true)
1877                     {
1878                         //this condition implies that a skip timestamp has been set
1879                         //and we are looking for a mediamsg whole timestamp is equal or greater than
1880                         //iSkipTimestamp. All media msgs whose timestamps are less than iSkipTimestamp
1881                         //will be dropped. There is no need for any additional checks. Just dequeue and toss
1882                         iCurrentMediaMsg.Unbind();
1883                         iFragIndex = 0;
1884                         if (DequeueIncomingMsg(iCurrentMediaMsg) == PVMFSuccess)
1885                         {
1886                             if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
1887                             {
1888                                 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::HPA: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
1889                                                       iCurrentMediaMsg->getStreamID(),
1890                                                       iCurrentMediaMsg->getSeqNum(),
1891                                                       iCurrentMediaMsg->getTimestamp(),
1892                                                       iSinkFormatString.get_str()));
1893 
1894                                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
1895                                                          iCurrentMediaMsg->getStreamID(),
1896                                                          iCurrentMediaMsg->getSeqNum(),
1897                                                          iCurrentMediaMsg->getTimestamp(),
1898                                                          iSinkFormatString.get_str()));
1899                             }
1900                             else
1901                             {
1902                                 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::HPA: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d",
1903                                                       iCurrentMediaMsg->getStreamID(),
1904                                                       iCurrentMediaMsg->getSeqNum(),
1905                                                       iCurrentMediaMsg->getTimestamp(),
1906                                                       iSinkFormatString.get_str(),
1907                                                       IncomingMsgQueueSize()));
1908 
1909                                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d",
1910                                                          iCurrentMediaMsg->getStreamID(),
1911                                                          iCurrentMediaMsg->getSeqNum(),
1912                                                          iCurrentMediaMsg->getTimestamp(),
1913                                                          iSinkFormatString.get_str(),
1914                                                          IncomingMsgQueueSize()));
1915                             }
1916                             iCurrentMediaMsg.Unbind();
1917                             iFragIndex = 0;
1918                         }
1919                         else
1920                         {
1921                             PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg Failed - Fmt=%s",
1922                                                   iSinkFormatString.get_str()));
1923                             OSCL_ASSERT(false);
1924                         }
1925                     }
1926                     else
1927                     {
1928                         if ((iSendStartOfDataEvent == true) && oMIOComponentConfigured)
1929                         {
1930                             //implies that we are attempting to process the first media msg during
1931                             //after skip, a mediamsg whose timestamp is equal to or greater than
1932                             //iSkipTimestamp
1933                             PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::HPA: PVMFInfoStartOfData - Fmt=%s",
1934                                                   iSinkFormatString.get_str()));
1935                             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: PVMFInfoStartOfData - Fmt=%s",
1936                                                      iSinkFormatString.get_str()));
1937                             uint32 iStreamID = iRecentStreamID;
1938                             iNode->ReportInfoEvent(PVMFInfoStartOfData, (OsclAny*)&iStreamID);
1939                             iSendStartOfDataEvent = false;
1940                             // Now check if the media msg is EOS notification OR media data.
1941                             // If EOS then need to do writeComplete for EOS without sending it downstream
1942                             // This will happen in cases where the media output node is waiting on configuration,
1943                             // but for some reason the upstream node does not have a config to send.
1944                             // (Think of cases where we have empty tracks in a presentation OR reposition to EndofClip just after Prepare).
1945                             // In such cases, if we get EOS we want to notify the Engine with InfoEndofData for the track
1946                             // so that Engine does not wait for EndOfData from the track and be in a hang state.
1947                             if (peekMsgPtr->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
1948                             {
1949                                 // There could be cases where MIO was already configured and then a reposition to End cmd
1950                                 // was given to Engine. In this case again EOS will be the first msg after skip but in this
1951                                 // case we want to send EOS downstream rather than sending InfoEndofData from here.
1952                                 if (!oMIOAlreadyConfigured)
1953                                 {
1954                                     // EOS is the first media msg received after Skip
1955                                     if (iCurrentMediaMsg.GetRep() != NULL)
1956                                     {
1957                                         // This should never happen. We cannot have a media msg being processed in this condition.
1958                                         // Just assert and return
1959                                         OSCL_ASSERT(false);
1960                                         PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: Processing previous msg iCurrentMediaMsg: 0x%x - Fmt=%s \
1961 						    when 1st media msg after skip is EOS, wrong, asserting",
1962                                                                  iCurrentMediaMsg.GetRep(), iSinkFormatString.get_str()));
1963                                         return;
1964                                     }
1965                                     // Dequeue the Incoming msg and send EndofData
1966                                     if (DequeueIncomingMsg(iCurrentMediaMsg) == PVMFSuccess)
1967                                     {
1968                                         PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA - EOS Recvd - StreamID=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d",
1969                                                                  iCurrentMediaMsg->getStreamID(),
1970                                                                  iCurrentMediaMsg->getSeqNum(),
1971                                                                  iCurrentMediaMsg->getTimestamp(),
1972                                                                  iSinkFormatString.get_str(),
1973                                                                  IncomingMsgQueueSize()));
1974 
1975                                         uint32 eosStreamId = iCurrentMediaMsg->getStreamID();
1976 
1977                                         iNode->ReportInfoEvent(PVMFInfoEndOfData, (OsclAny*)&eosStreamId);
1978 
1979                                         iCurrentMediaMsg.Unbind();
1980                                         iFragIndex = 0;
1981                                     }
1982                                     else
1983                                     {
1984                                         PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg Failed - Fmt=%s",
1985                                                               iSinkFormatString.get_str()));
1986                                         OSCL_ASSERT(false);
1987                                     }
1988                                     return;
1989                                 }
1990                             }
1991                         }
1992                         if (oProcessIncomingMessage)
1993                         {
1994                             //we are starting to process a new media msg
1995                             if ((iCurrentMediaMsg.GetRep() != NULL) ||
1996                                     (iFragIndex != 0))
1997                             {
1998                                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg ignoring msg. Still processing previous msg iCurrentMediaMsg: 0x%x  iFragIndex: %d- Fmt=%s",
1999                                                          iCurrentMediaMsg.GetRep(), iFragIndex, iSinkFormatString.get_str()));
2000                                 return;
2001                             }
2002                             if (DequeueIncomingMsg(iCurrentMediaMsg) == PVMFSuccess)
2003                             {
2004                                 if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
2005                                 {
2006                                     PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA - EOS Recvd - StreamID=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d",
2007                                                              iCurrentMediaMsg->getStreamID(),
2008                                                              iCurrentMediaMsg->getSeqNum(),
2009                                                              iCurrentMediaMsg->getTimestamp(),
2010                                                              iSinkFormatString.get_str(),
2011                                                              IncomingMsgQueueSize()));
2012                                 }
2013                                 else if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_RE_CONFIG_FORMAT_ID)
2014                                 {
2015                                     PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA - RECONFIG Recvd - Seq=%d, TS=%d, Fmt=%s, Qs=%d",
2016                                                              iCurrentMediaMsg->getSeqNum(),
2017                                                              iCurrentMediaMsg->getTimestamp(),
2018                                                              iSinkFormatString.get_str(),
2019                                                              IncomingMsgQueueSize()));
2020                                 }
2021                                 else if (iCurrentMediaMsg->getFormatID() < PVMF_MEDIA_CMD_FORMAT_IDS_START)
2022                                 {
2023                                     iTotalFrames++;
2024                                     PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA - MediaMsg Recvd - Seq=%d, TS=%d, Fmt=%s, Qs=%d",
2025                                                              iCurrentMediaMsg->getSeqNum(),
2026                                                              iCurrentMediaMsg->getTimestamp(),
2027                                                              iSinkFormatString.get_str(),
2028                                                              IncomingMsgQueueSize()));
2029                                 }
2030 
2031                                 SendData();
2032 
2033 
2034 
2035                                 if ((oProcessIncomingMessage == true) &&
2036                                         (IncomingMsgQueueSize() > 0))
2037                                 {
2038                                     //implies that we can process more data, so reschedule
2039                                     //we could process all the messages in the incoming msg q
2040                                     //in a while loop here, but that might not be advisable
2041                                     //since this call is sort of an observer callback and
2042                                     //it might not be good idea to process more than one msg
2043                                     RunIfNotReady();
2044                                 }
2045                             }
2046                             else
2047                             {
2048                                 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg Failed - Fmt=%s",
2049                                                       iSinkFormatString.get_str()));
2050                                 OSCL_ASSERT(false);
2051                             }
2052                         }
2053                     }
2054                 }
2055             }
2056             break;
2057 
2058         default:
2059             break;
2060     }
2061 }
2062 
2063 
2064 ////////////////////////////////////////////////////////////////////////////
ConfigMIO(PvmiKvp * aParameters,PvmiKvp * & aRetParameters)2065 PVMFStatus PVMediaOutputNodePort::ConfigMIO(PvmiKvp* aParameters, PvmiKvp* &aRetParameters)
2066 //send config info to media I/O component.
2067 {
2068 
2069     if (iMediaTransfer == NULL)
2070     {
2071         iMediaTransfer = iNode->iMIOControl->createMediaTransfer(iNode->iMIOSession);
2072         if (iMediaTransfer)
2073         {
2074             iMediaTransfer->setPeer(this);
2075         }
2076         else
2077         {
2078             return PVMFFailure;
2079         }
2080     }
2081 
2082     if (0 == aParameters)
2083     {
2084         PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO: No format-specific info for this track."));
2085         return PVMFSuccess;//no format-specific info, so nothing needed.
2086     }
2087     uint8* data = (uint8*)aParameters->value.key_specific_value;
2088     PVMFStatus status = PVMFFailure;
2089 
2090     //formatted data gets sent to the MIO on first arrival
2091     switch (iMediaType)
2092     {
2093         case PVMF_MEDIA_UNCOMPRESSED_AUDIO:
2094         {
2095             //Send pcm16 info.
2096 
2097             if (pv_mime_strcmp(aParameters->key, PVMF_FORMAT_SPECIFIC_INFO_KEY) == 0)
2098             {
2099                 //ignore any failures since not all MIO may suppport the parameters.
2100                 //Note: send the parameters individually since some MIO may not know
2101                 //how to process arrays.
2102                 channelSampleInfo* pcm16Info = (channelSampleInfo*)data;
2103                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO - SamplingRate=%d, NumChannels=%d",
2104                                          pcm16Info->samplingRate, pcm16Info->desiredChannels));
2105 
2106                 status = SetMIOParameterUint32((char*)MOUT_AUDIO_SAMPLING_RATE_KEY,
2107                                                pcm16Info->samplingRate);
2108                 if (status == PVMFSuccess)
2109                 {
2110                     SetMIOParameterUint32((char*)MOUT_AUDIO_NUM_CHANNELS_KEY,
2111                                           pcm16Info->desiredChannels);
2112                 }
2113             }
2114             else if (pv_mime_strcmp(aParameters->key, PVMF_FORMAT_SPECIFIC_INFO_KEY_PCM) == 0)
2115             {
2116                 // this is
2117                 //Do not send individual parameters to MIO component, send them all at once
2118 
2119                 int32 err;
2120                 OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, aParameters, 1, aRetParameters););
2121 
2122                 if (err != OsclErrNone || aRetParameters)
2123                 {
2124                     PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY_AUDIO failed "));
2125                     PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY_AUDIO failed "));
2126 
2127                     iNode->ReportErrorEvent(PVMFErrPortProcessing, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync);
2128                     return PVMFFailure;
2129                 }
2130 
2131                 status = PVMFSuccess;
2132             }
2133         }
2134         break;
2135 
2136         case PVMF_MEDIA_UNCOMPRESSED_VIDEO:
2137         {
2138             //Send yuv info.
2139             if (pv_mime_strcmp(aParameters->key, PVMF_FORMAT_SPECIFIC_INFO_KEY) == 0)
2140             {
2141                 PVMFYuvFormatSpecificInfo0* yuvInfo = (PVMFYuvFormatSpecificInfo0*)data;
2142                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO - Width=%d, Height=%d, DispWidth=%d, DispHeight=%d",
2143                                          yuvInfo->width, yuvInfo->height, yuvInfo->display_width, yuvInfo->display_height));
2144                 //Send yuv info.
2145                 //ignore any failures since not all MIO may suppport the parameters.
2146                 //Note: send the parameters individually since some MIO may not know
2147                 //how to process arrays.
2148                 status = SetMIOParameterUint32((char*)MOUT_VIDEO_WIDTH_KEY,
2149                                                yuvInfo->width);
2150                 if (status == PVMFSuccess)
2151                 {
2152                     status = SetMIOParameterUint32((char*)MOUT_VIDEO_HEIGHT_KEY,
2153                                                    yuvInfo->height);
2154                 }
2155                 if (status == PVMFSuccess)
2156                 {
2157                     status = SetMIOParameterUint32((char*)MOUT_VIDEO_DISPLAY_WIDTH_KEY,
2158                                                    yuvInfo->display_width);
2159                 }
2160                 if (status == PVMFSuccess)
2161                 {
2162                     status = SetMIOParameterUint32((char*)MOUT_VIDEO_DISPLAY_HEIGHT_KEY,
2163                                                    yuvInfo->display_height);
2164                 }
2165                 if (status == PVMFSuccess)
2166                 {
2167                     // ignore status here
2168                     SetMIOParameterFormat((char*)MOUT_VIDEO_SUBFORMAT_KEY,
2169                                           yuvInfo->video_format);
2170                 }
2171 
2172 
2173             }
2174             else if (pv_mime_strcmp(aParameters->key, PVMF_FORMAT_SPECIFIC_INFO_KEY_YUV) == 0)
2175             {
2176 
2177                 //Do not send individual parameters to MIO component, send them all at once
2178 
2179                 int32 err;
2180                 OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, aParameters, 1, aRetParameters););
2181 
2182                 if (err != OsclErrNone || aRetParameters)
2183                 {
2184                     PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY_VIDEO failed "));
2185                     PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY_VIDEO failed "));
2186 
2187                     iNode->ReportErrorEvent(PVMFErrPortProcessing, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync);
2188                     return PVMFFailure;
2189                 }
2190 
2191                 status = PVMFSuccess;
2192             }
2193         }
2194         break;
2195         case PVMF_MEDIA_COMPRESSED_AUDIO:
2196         case PVMF_MEDIA_COMPRESSED_VIDEO:
2197             //for compressed formats, the format-specific info is sent as kvp
2198         {
2199             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO Setting Codec Header - Len=%d, Fmt=%s",
2200                                      aParameters->capacity, iSinkFormatString.get_str()));
2201 
2202             // We will enable the following line after source node fix KVP issue
2203             //oscl_assert(aParameters->length == aParameters->capacity)
2204 
2205             // We will remove the following line after source node fix KVP issue
2206             aParameters->length = aParameters->capacity;
2207 
2208             int32 err;
2209             OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, aParameters, 1, aRetParameters););
2210 
2211             if (err != OsclErrNone || aRetParameters)
2212             {
2213                 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY failed "));
2214                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY failed "));
2215                 //this is the first call, we don't handle a leave here-- it's an error
2216                 iNode->ReportErrorEvent(PVMFErrPortProcessing, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync);
2217                 return PVMFFailure;
2218             }
2219             status = PVMFSuccess;
2220 
2221         }
2222         break;
2223 
2224         case PVMF_MEDIA_TEXT:
2225             //for text formats, the format-specific info is sent as kvp
2226         {
2227             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO Setting Codec Header - Len=%d, Fmt=%s",
2228                                      aParameters->capacity, iSinkFormatString.get_str()));
2229 
2230             // We will enable the following line after source node fix KVP issue
2231             //oscl_assert(aParameters->length == aParameters->capacity)
2232 
2233             // We will remove the following line after source node fix KVP issue
2234             aParameters->length = aParameters->capacity;
2235 
2236             int32 err;
2237             OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, aParameters, 1, aRetParameters););
2238 
2239             if (err != OsclErrNone || aRetParameters)
2240             {
2241                 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY failed "));
2242                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY failed "));
2243                 //this is the first call, we don't handle a leave here-- it's an error
2244                 iNode->ReportErrorEvent(PVMFErrPortProcessing, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync);
2245                 return PVMFFailure;
2246             }
2247             status = PVMFSuccess;
2248         }
2249         break;
2250 
2251         default:
2252             status = PVMFErrNotSupported;
2253             OSCL_ASSERT(false);
2254             break;
2255     }
2256     if (status != PVMFSuccess)
2257     {
2258         iNode->ReportErrorEvent(PVMFErrResource, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync);
2259     }
2260 
2261     return status;
2262 }
2263 
2264 ////////////////////////////////////////////////////////////////////////////
SetMIOParameterInt32(PvmiKeyType aKey,int32 aValue)2265 PVMFStatus PVMediaOutputNodePort::SetMIOParameterInt32(PvmiKeyType aKey, int32 aValue)
2266 //to set parameters to the MIO component through its config interface.
2267 {
2268     OsclMemAllocator alloc;
2269     PvmiKvp kvp;
2270     PvmiKvp* retKvp = NULL; // for return value
2271 
2272     kvp.key = NULL;
2273     kvp.length = oscl_strlen(aKey) + 1; // +1 for \0
2274     kvp.capacity = kvp.length;
2275 
2276     kvp.key = (PvmiKeyType)alloc.ALLOCATE(kvp.length);
2277     if (!kvp.key)
2278         return PVMFErrNoMemory;
2279 
2280     oscl_strncpy(kvp.key, aKey, kvp.length);
2281     kvp.value.int32_value = aValue;
2282 
2283     int32 err;
2284     OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &kvp, 1, retKvp););
2285     alloc.deallocate(kvp.key);
2286 
2287     if (err != OsclErrNone || retKvp)
2288         return PVMFFailure;
2289 
2290     return PVMFSuccess;
2291 }
2292 
2293 ////////////////////////////////////////////////////////////////////////////
SetMIOParameterUint32(PvmiKeyType aKey,uint32 aValue)2294 PVMFStatus PVMediaOutputNodePort::SetMIOParameterUint32(PvmiKeyType aKey, uint32 aValue)
2295 //to set parameters to the MIO component through its config interface.
2296 {
2297     OsclMemAllocator alloc;
2298     PvmiKvp kvp;
2299     PvmiKvp* retKvp = NULL; // for return value
2300 
2301     kvp.key = NULL;
2302     kvp.length = oscl_strlen(aKey) + 1; // +1 for \0
2303     kvp.capacity = kvp.length;
2304 
2305     kvp.key = (PvmiKeyType)alloc.ALLOCATE(kvp.length);
2306     if (!kvp.key)
2307         return PVMFErrNoMemory;
2308 
2309     oscl_strncpy(kvp.key, aKey, kvp.length);
2310     kvp.value.uint32_value = aValue;
2311 
2312     int32 err;
2313     OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &kvp, 1, retKvp););
2314     alloc.deallocate(kvp.key);
2315 
2316     if (err != OsclErrNone || retKvp)
2317         return PVMFFailure;
2318 
2319     return PVMFSuccess;
2320 }
2321 
2322 
2323 ////////////////////////////////////////////////////////////////////////////
SetMIOParameterPchar(PvmiKeyType aKey,char * aValue)2324 PVMFStatus PVMediaOutputNodePort::SetMIOParameterPchar(PvmiKeyType aKey, char* aValue)
2325 //to set parameters to the MIO component through its config interface.
2326 {
2327     OsclMemAllocator alloc;
2328     PvmiKvp kvp;
2329     PvmiKvp* retKvp = NULL; // for return value
2330 
2331     kvp.key = NULL;
2332     kvp.length = oscl_strlen(aKey) + 1; // +1 for \0
2333     kvp.capacity = kvp.length;
2334 
2335     kvp.key = (PvmiKeyType)alloc.ALLOCATE(kvp.length);
2336     if (!kvp.key)
2337         return PVMFErrNoMemory;
2338 
2339     oscl_strncpy(kvp.key, aKey, kvp.length);
2340     kvp.value.pChar_value = aValue;
2341 
2342     int32 err;
2343     OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &kvp, 1, retKvp););
2344     alloc.deallocate(kvp.key);
2345 
2346     if (err != OsclErrNone || retKvp)
2347         return PVMFFailure;
2348 
2349     return PVMFSuccess;
2350 }
2351 
2352 ////////////////////////////////////////////////////////////////////////////
SetMIOParameterFormat(PvmiKeyType aKey,PVMFFormatType aFormatType)2353 PVMFStatus PVMediaOutputNodePort::SetMIOParameterFormat(PvmiKeyType aKey, PVMFFormatType aFormatType)
2354 //to set parameters to the MIO component through its config interface.
2355 {
2356     OsclMemAllocator alloc;
2357     PvmiKvp kvp;
2358     PvmiKvp* retKvp = NULL; // for return value
2359 
2360     kvp.key = NULL;
2361     kvp.length = oscl_strlen(aKey) + 1; // +1 for \0
2362     kvp.capacity = kvp.length;
2363 
2364     kvp.key = (PvmiKeyType)alloc.ALLOCATE(kvp.length);
2365     if (!kvp.key)
2366         return PVMFErrNoMemory;
2367 
2368     oscl_strncpy(kvp.key, aKey, kvp.length);
2369     kvp.value.pChar_value = (char*)aFormatType.getMIMEStrPtr();
2370 
2371     int32 err;
2372     OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &kvp, 1, retKvp););
2373     alloc.deallocate(kvp.key);
2374 
2375     if (err != OsclErrNone || retKvp)
2376         return PVMFFailure;
2377 
2378     return PVMFSuccess;
2379 }
2380 
2381 ////////////////////////////////////////////////////////////////////////////
getParametersSync(PvmiMIOSession aSession,PvmiKeyType aIdentifier,PvmiKvp * & aParameters,int & num_parameter_elements,PvmiCapabilityContext aContext)2382 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier,
2383         PvmiKvp*& aParameters, int& num_parameter_elements,
2384         PvmiCapabilityContext aContext)
2385 {
2386     PVMFStatus status = iNode->iMIOConfig->getParametersSync(aSession, aIdentifier, aParameters, num_parameter_elements,
2387                         aContext);
2388     return status;
2389 }
2390 
2391 
2392 ////////////////////////////////////////////////////////////////////////////
releaseParameters(PvmiMIOSession aSession,PvmiKvp * aParameters,int num_elements)2393 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements)
2394 {
2395     OSCL_UNUSED_ARG(aSession);
2396 
2397     if (aParameters && iNode)
2398     {
2399         return iNode->iMIOConfig->releaseParameters(aSession, aParameters, num_elements);
2400     }
2401     return PVMFFailure;
2402 }
2403 
2404 
2405 ////////////////////////////////////////////////////////////////////////////
setParametersSync(PvmiMIOSession aSession,PvmiKvp * aParameters,int num_elements,PvmiKvp * & aRet_kvp)2406 OSCL_EXPORT_REF void PVMediaOutputNodePort::setParametersSync(PvmiMIOSession aSession,
2407         PvmiKvp* aParameters,
2408         int num_elements,
2409         PvmiKvp * &aRet_kvp)
2410 {
2411     PVMFStatus status = PVMFSuccess;
2412     OSCL_UNUSED_ARG(aSession);
2413     for (int32 i = 0; i < num_elements; i++)
2414     {
2415         if (pv_mime_strcmp(aParameters[i].key, PVMF_FORMAT_SPECIFIC_INFO_KEY) == 0)
2416         {
2417             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::setParametersSync - FSI - Fmt=%s",
2418                                      iSinkFormatString.get_str()));
2419             ConfigMIO(&aParameters[i], aRet_kvp);
2420         }
2421         else if (pv_mime_strcmp(aParameters[i].key, PVMF_FORMAT_SPECIFIC_INFO_KEY_YUV) == 0)
2422         {
2423             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::setParametersSync - FSI - Fmt=%s",
2424                                      iSinkFormatString.get_str()));
2425             status = ConfigMIO(&aParameters[i], aRet_kvp);
2426             if (status != PVMFSuccess)
2427                 OSCL_LEAVE(PVMFFailure);
2428         }
2429         else if (pv_mime_strcmp(aParameters[i].key, PVMF_FORMAT_SPECIFIC_INFO_KEY_PCM) == 0)
2430         {
2431             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::setParametersSync - FSI - Fmt=%s",
2432                                      iSinkFormatString.get_str()));
2433             status = ConfigMIO(&aParameters[i], aRet_kvp);
2434             if (status != PVMFSuccess)
2435                 OSCL_LEAVE(PVMFFailure);
2436         }
2437         else if ((pv_mime_strcmp(aParameters[i].key, MOUT_AUDIO_SAMPLING_RATE_KEY) == 0) ||
2438                  (pv_mime_strcmp(aParameters[i].key, MOUT_AUDIO_NUM_CHANNELS_KEY) == 0) ||
2439                  (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_WIDTH_KEY) == 0) ||
2440                  (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_HEIGHT_KEY) == 0) ||
2441                  (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_DISPLAY_WIDTH_KEY) == 0) ||
2442                  (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_DISPLAY_HEIGHT_KEY) == 0))
2443         {
2444             PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::setParametersSync - FSI - Fmt=%s",
2445                                      iSinkFormatString.get_str()));
2446             //Null parameters, because we just notify that MIO has been configured.
2447             ConfigMIO(0, aRet_kvp);
2448             iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &aParameters[i], 1, aRet_kvp);
2449         }
2450         else
2451             iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &aParameters[i], 1, aRet_kvp);
2452     }
2453 }
2454 
2455 
2456 ////////////////////////////////////////////////////////////////////////////
verifyParametersSync(PvmiMIOSession aSession,PvmiKvp * aParameters,int num_elements)2457 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::verifyParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements)
2458 {
2459     OSCL_UNUSED_ARG(aSession);
2460     return (iNode->iMIOConfig->verifyParametersSync(iNode->iMIOSession, aParameters, num_elements));
2461 }
2462 
2463 
2464 ////////////////////////////////////////////////////////////////////////////
peekHead(PVMFSharedMediaMsgPtr & aMsgPtr,bool & bBos)2465 bool PVMediaOutputNodePort::peekHead(PVMFSharedMediaMsgPtr& aMsgPtr,
2466                                      bool& bBos)
2467 {
2468     if (iIncomingQueue.iQ.empty())
2469     {
2470         return false;
2471     }
2472     // get a pointer to the queue head
2473     aMsgPtr = iIncomingQueue.iQ.front();
2474     // check the format id first - treat BOS special
2475     if (aMsgPtr->getFormatID() == PVMF_MEDIA_CMD_BOS_FORMAT_ID)
2476     {
2477         bBos = true;
2478     }
2479     else
2480     {
2481         bBos = false;
2482     }
2483 
2484     // This check is needed to handle cases where the media output node is waiting on configuration,
2485     // but for some reason the upstream node does not have a config to send.
2486     // (Think of cases where we have empty tracks in a presentation). In such cases, if we get EOS we want
2487     // to notify the media output node that configuration is complete, so that media output node can complete its pending start
2488     if (aMsgPtr->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
2489     {
2490         if (false == oMIOComponentConfigured)
2491         {
2492             OSCL_ASSERT(oProcessIncomingMessage != true);
2493             oMIOComponentConfigured = true;
2494             oProcessIncomingMessage = true;
2495         }
2496     }
2497     return true;
2498 }
2499 
ProcessCallBack(uint32 callBackID,PVTimeComparisonUtils::MediaTimeStatus aTimerAccuracy,uint32 aDelta,const OsclAny * aContextData,PVMFStatus aStatus)2500 void PVMediaOutputNodePort::ProcessCallBack(uint32 callBackID,
2501         PVTimeComparisonUtils::MediaTimeStatus aTimerAccuracy,
2502         uint32 aDelta,
2503         const OsclAny* aContextData,
2504         PVMFStatus aStatus)
2505 {
2506     OSCL_UNUSED_ARG(aTimerAccuracy);
2507     OSCL_UNUSED_ARG(aDelta);
2508     OSCL_UNUSED_ARG(aContextData);
2509     PVMF_MOPORT_LOGDEBUG((0, "PVMediaOutputNodePort::ProcessCallBack In Callback id [%d] CallbackStatus [%d]", callBackID, aStatus));
2510     if (PVMFSuccess == aStatus)
2511     {
2512         if (iDelayEarlyFrameCallBkId == callBackID)
2513         {
2514             oClockCallBackPending = false;
2515             //timer expires, reset the boolean so that we can start processing more data if need be
2516             oProcessIncomingMessage = true;
2517             if (iCurrentMediaMsg.GetRep() != NULL)
2518             {
2519                 //attempt to send data current media msg if any
2520                 SendData();
2521             }
2522             //reschedule if there is more stuff waiting and
2523             //if we can process more data
2524             if ((oProcessIncomingMessage == true) &&
2525                     (IncomingMsgQueueSize() > 0))
2526             {
2527                 RunIfNotReady();
2528             }
2529         }
2530         else
2531         {
2532             PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ProcessCallBack- Error stray callback from iClockNotificationsInf callBackID[%d]", callBackID));
2533             OSCL_ASSERT(false);
2534         }
2535 
2536     }
2537 }
2538 
SetSkipTimeStamp(uint32 aSkipTS,uint32 aStreamID)2539 void PVMediaOutputNodePort::SetSkipTimeStamp(uint32 aSkipTS,
2540         uint32 aStreamID)
2541 {
2542     PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::SetSkipTimeStamp: TS=%d, Fmt=%s",
2543                           aSkipTS,
2544                           iSinkFormatString.get_str()));
2545     PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SetSkipTimeStamp: TS=%d, Fmt=%s",
2546                              aSkipTS,
2547                              iSinkFormatString.get_str()));
2548     iSkipTimestamp = aSkipTS;
2549     iRecentStreamID = aStreamID;
2550     iSendStartOfDataEvent = true;
2551     if (oClockCallBackPending)
2552     {
2553         iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false);
2554     }
2555     oClockCallBackPending = false;
2556     iDelayEarlyFrameCallBkId = 0;
2557 
2558     //release the current media msg right here instead of
2559     //waiting on a reschedule. this is to avoid deadlocks
2560     //in case the upstream node is just operating with a
2561     //single media msg
2562     if (iCurrentMediaMsg.GetRep() != NULL)
2563     {
2564         if (DataToSkip(iCurrentMediaMsg) == true)
2565         {
2566             if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
2567             {
2568                 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::SetSkipTimeStamp: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
2569                                       iCurrentMediaMsg->getStreamID(),
2570                                       iCurrentMediaMsg->getSeqNum(),
2571                                       iCurrentMediaMsg->getTimestamp(),
2572                                       iSinkFormatString.get_str()));
2573 
2574                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SetSkipTimeStamp: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
2575                                          iCurrentMediaMsg->getStreamID(),
2576                                          iCurrentMediaMsg->getSeqNum(),
2577                                          iCurrentMediaMsg->getTimestamp(),
2578                                          iSinkFormatString.get_str()));
2579             }
2580             else
2581             {
2582                 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::SetSkipTimeStamp: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
2583                                       iCurrentMediaMsg->getStreamID(),
2584                                       iCurrentMediaMsg->getSeqNum(),
2585                                       iCurrentMediaMsg->getTimestamp(),
2586                                       iSinkFormatString.get_str()));
2587 
2588                 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SetSkipTimeStamp: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
2589                                          iCurrentMediaMsg->getStreamID(),
2590                                          iCurrentMediaMsg->getSeqNum(),
2591                                          iCurrentMediaMsg->getTimestamp(),
2592                                          iSinkFormatString.get_str()));
2593             }
2594             iCurrentMediaMsg.Unbind();
2595             iFragIndex = 0;
2596         }
2597     }
2598     //wake up the AO to start processing messages
2599     RunIfNotReady();
2600 }
2601 
CancelSkip()2602 void PVMediaOutputNodePort::CancelSkip()
2603 {
2604     PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::CancelSkip: Fmt=%s",
2605                           iSinkFormatString.get_str()));
2606     PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CancelSkip: Fmt=%s",
2607                              iSinkFormatString.get_str()));
2608     iSkipTimestamp = 0;
2609     iRecentStreamID = 0;
2610     iSendStartOfDataEvent = false;
2611 }
2612 
DataToSkip(PVMFSharedMediaMsgPtr & aMsg)2613 bool PVMediaOutputNodePort::DataToSkip(PVMFSharedMediaMsgPtr& aMsg)
2614 {
2615     //iRecentStreamID reflects the latest stream
2616     //that is being played. Msg with a streamid less than
2617     //iRecentStreamID belongs to an older stream and should
2618     //be skipped. Do not skip Msg that belong to the current
2619     //stream or a future stream (future being the case where
2620     //msg arrives before a skip request. Pls note that we
2621     //assume that the stream ids are a montonically increasing
2622     //sequence
2623     uint32 delta = 0;
2624     bool oOldStream = PVTimeComparisonUtils::IsEarlier(aMsg->getStreamID(), iRecentStreamID, delta);
2625     if (oOldStream && delta > 0)
2626     {
2627         //a zero delta could mean the stream ids are equal
2628         return true;
2629     }
2630     //we typically do not do timestamp checks on EOS.
2631     //old EOSes that needed to be discarded during a repositioning
2632     //would not pass the stream id check above. If we get this far
2633     //it means that the EOS belong to the current stream id and its
2634     //timestamp does not really matter.
2635     if (aMsg->getFormatID() != PVMF_MEDIA_CMD_EOS_FORMAT_ID)
2636     {
2637         //if we get here it means that the msg belong to current or a
2638         //future media stream. check against skip timestamp if we are
2639         //required to send PVMFInfoStartOfData. If we are not reqd to
2640         //send the event, we intentionally by pass any timestamp checks
2641         if (iSendStartOfDataEvent == true)
2642         {
2643             delta = 0;
2644             bool tsEarly = PVTimeComparisonUtils::IsEarlier(aMsg->getTimestamp(), iSkipTimestamp, delta);
2645             if (tsEarly && delta > 0)
2646             {
2647                 //a zero delta could mean the timestamps are equal
2648                 return true;
2649             }
2650         }
2651     }
2652     return false;
2653 }
2654 
ClockTimebaseUpdated()2655 void PVMediaOutputNodePort::ClockTimebaseUpdated()
2656 {
2657     if (iClock == NULL)
2658         return;
2659 
2660     if (iClock->GetCountTimebase())
2661     {
2662         PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockTimebaseUpdated: CountTimeBase Added - Fmt=%s",
2663                               iSinkFormatString.get_str()));
2664         PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockTimebaseUpdated: CountTimeBase Added - Fmt=%s",
2665                                  iSinkFormatString.get_str()));
2666         //Reset the frame step delta to zero.
2667         iFrameStepMode = true;
2668         iClock->GetCountTimebase()->GetCount(iClockFrameCount);
2669         iSyncFrameCount = iClockFrameCount;
2670     }
2671     else
2672     {
2673         PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockTimebaseUpdated: CountTimeBase Removed - Fmt=%s",
2674                               iSinkFormatString.get_str()));
2675         PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockTimebaseUpdated: CountTimeBase Removed - Fmt=%s",
2676                                  iSinkFormatString.get_str()));
2677         //reset frame step variables.
2678         iFrameStepMode = false;
2679         iSyncFrameCount = 0;
2680         iClockFrameCount = 0;
2681     }
2682     if (oClockCallBackPending)
2683     {
2684         iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false);
2685     }
2686     oClockCallBackPending = false;
2687     iDelayEarlyFrameCallBkId = 0;
2688 
2689     //reschedule if there is more stuff waiting and
2690     //if we can process more data
2691     if ((oProcessIncomingMessage == true) &&
2692             (IncomingMsgQueueSize() > 0))
2693     {
2694         RunIfNotReady();
2695     }
2696 }
2697 
ClockCountUpdated()2698 void PVMediaOutputNodePort::ClockCountUpdated()
2699 {
2700     if (iClock && iClock->GetCountTimebase())
2701     {
2702         //read the new framecount
2703         iClock->GetCountTimebase()->GetCount(iClockFrameCount);
2704         //wake up the AO to process data
2705         oProcessIncomingMessage = true;
2706 
2707         if (iCurrentMediaMsg.GetRep() != NULL)
2708         {
2709             //attempt to send data current media msg if any
2710             SendData();
2711         }
2712         //reschedule if there is more stuff waiting and
2713         //if we can process more data
2714         if ((oProcessIncomingMessage == true) &&
2715                 (IncomingMsgQueueSize() > 0))
2716         {
2717             RunIfNotReady();
2718         }
2719     }
2720 }
2721 
ClockAdjusted()2722 void PVMediaOutputNodePort::ClockAdjusted()
2723 {
2724 }
2725 
NotificationsInterfaceDestroyed()2726 void PVMediaOutputNodePort::NotificationsInterfaceDestroyed()
2727 {
2728     iClockNotificationsInf = NULL;
2729 }
2730 
ClockStateUpdated()2731 void PVMediaOutputNodePort::ClockStateUpdated()
2732 {
2733     if (iClock == NULL)
2734         return;
2735 
2736     if (iClock->GetState() == PVMFMediaClock::PAUSED)
2737     {
2738         PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Paused - Fmt=%s",
2739                               iSinkFormatString.get_str()));
2740         PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Paused - Fmt=%s",
2741                                  iSinkFormatString.get_str()));
2742         //stop processing input msgs only for passive mediaoutput comps
2743         //for active ones continue to send, since the mediaoutput comp
2744         //is responsible for pacing of the data
2745         if (oActiveMediaOutputComp == false)
2746         {
2747             oProcessIncomingMessage = false;
2748             if (oClockCallBackPending)
2749             {
2750                 iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false);
2751             }
2752             oClockCallBackPending = false;
2753             iDelayEarlyFrameCallBkId = 0;
2754         }
2755     }
2756     else if (iClock->GetState() == PVMFMediaClock::RUNNING)
2757     {
2758         PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Running - Fmt=%s",
2759                               iSinkFormatString.get_str()));
2760         PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Running - Fmt=%s",
2761                                  iSinkFormatString.get_str()));
2762 
2763         //If MIO component is configured, messages can be processed now.
2764         if (oMIOComponentConfigured)
2765         {
2766             oProcessIncomingMessage = true;
2767         }
2768 
2769         if (oClockCallBackPending)
2770         {
2771             iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false);
2772         }
2773         oClockCallBackPending = false;
2774         iDelayEarlyFrameCallBkId = 0;
2775 
2776 
2777         //reset write state as well, in case mo comp is still busy
2778         //it will leave again, so that state will get reset
2779         iWriteState = EWriteOK;
2780 
2781         if (iCurrentMediaMsg.GetRep() != NULL)
2782         {
2783             //attempt to send data current media msg if any
2784             SendData();
2785         }
2786 
2787         //reschedule if there is more stuff waiting and
2788         //if we can process more data
2789         if ((oProcessIncomingMessage == true) &&
2790                 (IncomingMsgQueueSize() > 0))
2791         {
2792             RunIfNotReady();
2793         }
2794     }
2795     else if (iClock->GetState() == PVMFMediaClock::STOPPED)
2796     {
2797         PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Stopped - Fmt=%s",
2798                               iSinkFormatString.get_str()));
2799         PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Stopped - Fmt=%s",
2800                                  iSinkFormatString.get_str()));
2801         //stop processing input msgs only for passive mediaoutput comps
2802         //for active ones continue to send, since the mediaoutput comp
2803         //is responsible for pacing of the data, this is to account for a case when clock is stopped
2804         //after repositioning.
2805         if (oActiveMediaOutputComp == false)
2806         {
2807             oProcessIncomingMessage = false;
2808             if (oClockCallBackPending)
2809             {
2810                 iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false);
2811             }
2812             oClockCallBackPending = false;
2813             iDelayEarlyFrameCallBkId = 0;
2814         }
2815     }
2816     RunIfNotReady();
2817 }
2818 
ClearPreviousBOSStreamIDs(uint32 aID)2819 void PVMediaOutputNodePort::ClearPreviousBOSStreamIDs(uint32 aID)
2820 {
2821     //Pls note that we
2822     //assume that the stream ids are a montonically increasing
2823     //sequence
2824     Oscl_Vector<uint32, OsclMemAllocator>::iterator it;
2825     it = iBOSStreamIDVec.begin();
2826     while (it != iBOSStreamIDVec.end())
2827     {
2828         // iBOSStreamIDVec will contain the stream ID of the current stream being Played. On each skip call
2829         // all the previous streamid's will be removed from the vector leaving the current stream id. The
2830         // current stream id will be erased in the next skip media data call.
2831         if (*it < aID)
2832         {
2833             it = iBOSStreamIDVec.erase(it);
2834         }
2835         else
2836         {
2837             it++;
2838         }
2839     }
2840 }
2841 
WriteDataToMIO(int32 & aCmdId,PvmiMediaXferHeader & aMediaxferhdr,OsclRefCounterMemFrag & aFrag)2842 int32 PVMediaOutputNodePort::WriteDataToMIO(int32 &aCmdId, PvmiMediaXferHeader &aMediaxferhdr, OsclRefCounterMemFrag &aFrag)
2843 {
2844     int32 leavecode = OsclErrNone;
2845     OSCL_TRY_NO_TLS(iOsclErrorTrapImp, leavecode,
2846                     aCmdId = iMediaTransfer->writeAsync(PVMI_MEDIAXFER_FMT_TYPE_DATA,  /*format_type*/
2847                                                         PVMI_MEDIAXFER_FMT_INDEX_DATA, /*format_index*/
2848                                                         (uint8*)aFrag.getMemFragPtr(),
2849                                                         aFrag.getMemFragSize(),
2850                                                         aMediaxferhdr,
2851                                                         (OsclAny*) & iWriteAsyncContext););
2852     return leavecode;
2853 }
2854