blob: 2fbf03b313f7b505755a169822bed65c2216f105 [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#ifndef PVMF_JB_JITTERBUFFERMISC_H_INCLUDED
#include "pvmf_jitter_buffer_node.h"
#endif
#ifndef PVMF_JITTER_BUFFER_COMMON_TYPES_H_INCLUDED
#include "pvmf_jitter_buffer_common_types.h"
#endif
#ifndef OSCL_EXCLUSIVE_PTR_H_INCLUDED
#include "oscl_exclusive_ptr.h"
#endif
#ifndef PVMF_MEDIA_CLOCK_H_INCLUDED
#include "pvmf_media_clock.h"
#endif
#ifndef __MEDIA_CLOCK_CONVERTER_H
#include "media_clock_converter.h"
#endif
#ifndef PVMF_STREAMING_MANAGER_NODE_H_INCLUDED
#include "pvmf_jitter_buffer_node.h"
#endif
#ifndef PVMF_JITTER_BUFFER_FACTORY_H
#include "pvmf_jitter_buffer_factory.h"
#endif
#ifndef PVMF_MEDIA_DATA_H_INCLUDED
#include "pvmf_media_data.h"
#endif
#ifndef PVMF_MEDIA_CMD_H_INCLUDED
#include "pvmf_media_cmd.h"
#endif
#ifndef PVMF_MEDIA_MSG_FORMAT_IDS_H_INCLUDED
#include "pvmf_media_msg_format_ids.h"
#endif
#ifndef PVLOGGER_H_INCLUDED
#include "pvlogger.h"
#endif
#ifndef PVMF_SM_TUNABLES_H_INCLUDED
#include "pvmf_sm_tunables.h"
#endif
#ifndef PVMF_BASIC_ERRORINFOMESSAGE_H_INCLUDED
#include "pvmf_basic_errorinfomessage.h"
#endif
#ifndef OSCL_DLL_H_INCLUDED
#include "oscl_dll.h"
#endif
#ifndef OSCL_MIME_STRING_UTILS_H
#include "pv_mime_string_utils.h"
#endif
#ifndef OSCL_RAND_H_INCLUDED
#include "oscl_rand.h"
#endif
// Define entry point for this DLL
OSCL_DLL_ENTRY_POINT_DEFAULT()
//Construction and Destruction
OSCL_EXPORT_REF PVMFJitterBufferNode::PVMFJitterBufferNode(int32 aPriority,
JitterBufferFactory* aJBFactory): OsclActiveObject(aPriority, "JitterBufferNode")
{
//Initialize capability
iCapability.iCanSupportMultipleInputPorts = true;
iCapability.iCanSupportMultipleOutputPorts = true;
iCapability.iHasMaxNumberOfPorts = false;
iCapability.iMaxNumberOfPorts = 0;//no maximum
iCapability.iInputFormatCapability.push_back(PVMF_MIME_RTP);
iCapability.iInputFormatCapability.push_back(PVMF_MIME_ASFFF);
iCapability.iInputFormatCapability.push_back(PVMF_MIME_RMFF);
iCapability.iOutputFormatCapability.push_back(PVMF_MIME_RTP);
iCapability.iOutputFormatCapability.push_back(PVMF_MIME_ASFFF);
//Jitter buffer factory
ipJitterBufferFactory = aJBFactory;
//Initialize loggers
ipLogger = NULL;
ipDataPathLogger = NULL;
ipDataPathLoggerIn = NULL;
ipDataPathLoggerOut = NULL;
ipDataPathLoggerFlowCtrl = NULL;
ipClockLogger = NULL;
ipClockLoggerSessionDuration = NULL;
ipClockLoggerRebuff = NULL;
ipDiagnosticsLogger = NULL;
ipJBEventsClockLogger = NULL;
//Diagniostics related
iDiagnosticsLogged = false;
iNumRunL = 0;
Construct();
ResetNodeParams(false);
}
void PVMFJitterBufferNode::Construct()
{
//creation and initialization of objects that need to be created on heap in the ctor is done here
iInputCommands.Construct(PVMF_JITTER_BUFFER_NODE_COMMAND_ID_START,
PVMF_JITTER_BUFFER_VECTOR_RESERVE);
iCurrentCommand.Construct(0, 1);
iPortVector.Construct(PVMF_JITTER_BUFFER_NODE_PORT_VECTOR_RESERVE);
}
void PVMFJitterBufferNode::ResetNodeParams(bool aReleaseMemory)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::ResetNodeParams In aReleaseMemory[%d]", aReleaseMemory));
//Session specific initializations and resetting
oStartPending = false;
oStopOutputPorts = true;
iPauseTime = 0;
ipClientPlayBackClock = NULL;
iMediaReceiveingChannelPrepared = false;
iBroadCastSession = false;
iDelayEstablished = false;
iJitterBufferState = PVMF_JITTER_BUFFER_READY;
iJitterDelayPercent = 0;
//Extension interface initializations
if (ipExtensionInterface && aReleaseMemory)
{
ipExtensionInterface->removeRef();
}
ipExtensionInterface = NULL;
//Variables to persist info passed on by the extension interface
iRebufferingThreshold = DEFAULT_JITTER_BUFFER_UNDERFLOW_THRESHOLD_IN_MS;
iJitterBufferDurationInMilliSeconds = DEFAULT_JITTER_BUFFER_DURATION_IN_MS;
iMaxInactivityDurationForMediaInMs = DEFAULT_MAX_INACTIVITY_DURATION_IN_MS;
iEstimatedServerKeepAheadInMilliSeconds = DEFAULT_ESTIMATED_SERVER_KEEPAHEAD_FOR_OOO_SYNC_IN_MS;
iJitterBufferSz = 0;
iMaxNumBufferResizes = DEFAULT_MAX_NUM_SOCKETMEMPOOL_RESIZES;
iBufferResizeSize = DEFAULT_MAX_SOCKETMEMPOOL_RESIZELEN_INPUT_PORT;
iBufferingStatusIntervalInMs =
(PVMF_JITTER_BUFFER_BUFFERING_STATUS_EVENT_CYCLES * 1000) / PVMF_JITTER_BUFFER_BUFFERING_STATUS_EVENT_FREQUENCY;
iDisableFireWallPackets = false;
//iPlayingAfterSeek = false;
//Event Notifier initialization/reseting
iIncomingMediaInactivityDurationCallBkId = 0;
iIncomingMediaInactivityDurationCallBkPending = false;
iNotifyBufferingStatusCallBkId = 0;
iNotifyBufferingStatusCallBkPending = false;
if (aReleaseMemory)
{
if (ipJitterBufferMisc)
OSCL_DELETE(ipJitterBufferMisc);
}
ipJitterBufferMisc = NULL;
ipEventNotifier = NULL;
/* Clear queued messages in ports */
uint32 i;
for (i = 0; i < iPortVector.size(); i++)
{
PVMFJitterBufferPortParams* pPortParams = NULL;
bool bRet = getPortContainer(iPortVector[i], pPortParams);
if (bRet)
{
if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
{
pPortParams->ipJitterBuffer->ResetJitterBuffer();
}
pPortParams->ResetParams();
}
iPortVector[i]->ClearMsgQueues();
}
//Cleaning up of conatiner objects
/* delete corresponding port params */
if (aReleaseMemory)
{
//port vect and port params Q
Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator it;
for (it = iPortParamsQueue.begin();
it != iPortParamsQueue.end();
it++)
{
PVMFJitterBufferPortParams* pPortParams = *it;
if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
{
if (ipJitterBufferFactory)
ipJitterBufferFactory->Destroy(pPortParams->ipJitterBuffer);
}
OSCL_DELETE(&pPortParams->irPort);
OSCL_DELETE(pPortParams);
}
iPortParamsQueue.clear();
iPortVector.clear();
iPortVector.Reconstruct();
}
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::ResetNodeParams Out -"));
return;
}
PVMFJitterBufferNode::~PVMFJitterBufferNode()
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::~PVMFJitterBufferNode In"));
LogSessionDiagnostics();
ResetNodeParams();
/*
* Cleanup commands
* The command queues are self-deleting, but we want to
* notify the observer of unprocessed commands.
*/
while (!iCurrentCommand.empty())
{
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFFailure);
}
while (!iInputCommands.empty())
{
CommandComplete(iInputCommands, iInputCommands.front(), PVMFFailure);
}
Cancel();
/* thread logoff */
if (IsAdded())
RemoveFromScheduler();
CleanUp();
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::~PVMFJitterBufferNode Out"));
}
void PVMFJitterBufferNode::CleanUp() //Reverse of Construct
{
//noop
}
///////////////////////////////////////////////////////////////////////////////
//Implementation of overrides from PVInterface
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//Checks if the instance of PVMFJitterBufferExtensionInterfaceImpl is existing
//If existing: Query from this interface if UUID mentioned is supported
//If not existing: Instantiate PVMFJitterBufferExtensionInterfaceImpl
//and query requested interface from the PVMFJitterBufferExtensionInterfaceImpl
//Return Values:true/false
//Leave Codes: OsclErrNoMemory
//Leave Condition: If instance of PVMFJitterBufferExtensionInterfaceImpl cannot
//be instantiated.
///////////////////////////////////////////////////////////////////////////////
bool PVMFJitterBufferNode::queryInterface(const PVUuid& uuid, PVInterface*& iface)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::queryInterface In"));
iface = NULL;
if (uuid == PVUuid(PVMF_JITTERBUFFERNODE_EXTENSIONINTERFACE_UUID))
{
if (!ipExtensionInterface)
{
OsclMemAllocator alloc;
int32 err;
OsclAny*ptr = NULL;
OSCL_TRY(err,
ptr = alloc.ALLOCATE(sizeof(PVMFJitterBufferExtensionInterfaceImpl));
);
if (err != OsclErrNone || !ptr)
{
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::queryInterface: Error - Out of memory"));
OSCL_LEAVE(OsclErrNoMemory);
}
ipExtensionInterface =
OSCL_PLACEMENT_NEW(ptr, PVMFJitterBufferExtensionInterfaceImpl(this));
}
return (ipExtensionInterface->queryInterface(uuid, iface));
}
else
{
return false;
}
}
///////////////////////////////////////////////////////////////////////////////
//Implementation of overrides from PVMFNodeInterface
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//Does thread-specific node creation and go to "Idle" state.
//Creates logger objects
//Adds the AO to the scheduler
//Return values: PVMFSuccess/PVMFErrInvalidState
//PVMFSuccess: If API call is successful and was made in EPVMFNodeCreated state
//PVMFErrInvalidState: If API is called in the invalid state
//Leave Codes: NA
///////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFJitterBufferNode::ThreadLogon()
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::ThreadLogon In"));
PVMFStatus status;
switch (iInterfaceState)
{
case EPVMFNodeCreated:
{
if (!IsAdded())
AddToScheduler();
ipLogger = PVLogger::GetLoggerObject("jitterbuffernode");
ipDataPathLogger = PVLogger::GetLoggerObject("datapath.sourcenode.jitterbuffernode");
ipDataPathLoggerIn = PVLogger::GetLoggerObject("datapath.sourcenode.jitterbuffernode.in");
ipDataPathLoggerOut = PVLogger::GetLoggerObject("datapath.sourcenode.jitterbuffernode.out");
ipDataPathLoggerFlowCtrl = PVLogger::GetLoggerObject("datapath.sourcenode.jitterbuffernode.flowctrl");
ipClockLogger = PVLogger::GetLoggerObject("clock.jitterbuffernode");
ipClockLoggerSessionDuration = PVLogger::GetLoggerObject("clock.streaming_manager.sessionduration");
ipClockLoggerRebuff = PVLogger::GetLoggerObject("clock.jitterbuffernode.rebuffer");
ipDiagnosticsLogger = PVLogger::GetLoggerObject("pvplayerdiagnostics.streamingmanager");
ipJBEventsClockLogger = PVLogger::GetLoggerObject("jitterbuffernode.eventsclock");
iDiagnosticsLogged = false;
SetState(EPVMFNodeIdle);
status = PVMFSuccess;
}
break;
default:
status = PVMFErrInvalidState;
break;
}
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::ThreadLogon Out retval - %d", status));
return status;
}
///////////////////////////////////////////////////////////////////////////////
//Does thread-specific node cleanup and go to "Created" state.
//Releases logger objects
//Removes the AO to the scheduler
//Return values: PVMFSuccess/PVMFErrInvalidState
//PVMFSuccess: If API call is successful and was made in EPVMFNodeIdle state
//PVMFErrInvalidState: If API is called in the invalid state
//Leave Codes: NA
///////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFJitterBufferNode::ThreadLogoff()
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::ThreadLogoff In"));
PVMFStatus status = PVMFFailure;
switch (iInterfaceState)
{
case EPVMFNodeIdle:
{
ResetNodeParams();
ipLogger = NULL;
ipDataPathLogger = NULL;
ipDataPathLoggerIn = NULL;
ipDataPathLoggerOut = NULL;
ipClockLogger = NULL;
ipClockLoggerSessionDuration = NULL;
ipDiagnosticsLogger = NULL;
ipDataPathLoggerFlowCtrl = NULL;
if (IsAdded())
{
RemoveFromScheduler();
}
SetState(EPVMFNodeCreated);
status = PVMFSuccess;
}
break;
default:
status = PVMFErrInvalidState;
break;
}
return status;
}
///////////////////////////////////////////////////////////////////////////////
//Retrieves node capabilities.
//Decides supported input/output formats and provides node capabilities
//Return values: PVMFSuccess/PVMFErrInvalidState
//PVMFSuccess: If API call is successful
//If Input/Output format could not be determined
//Leave Codes: NA
///////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFJitterBufferNode::GetCapability(PVMFNodeCapability& aNodeCapability)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::GetCapability In"));
aNodeCapability = iCapability;
return PVMFSuccess;
}
///////////////////////////////////////////////////////////////////////////////
//Retrives a port iterator.
//Can Leave:No
//Return values: PVMFSuccess/PVMFErrInvalidState
//PVMFSuccess - If API call is successful
////////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFPortIter* PVMFJitterBufferNode::GetPorts(const PVMFPortFilter* aFilter)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::GetPorts"));
OSCL_UNUSED_ARG(aFilter);//port filter is not implemented.
iPortVector.Reset();
return &iPortVector;
}
///////////////////////////////////////////////////////////////////////////////
//Retrives a port iterator.
//Can Leave:No
//Return values: PVMFSuccess/PVMFErrInvalidState
//PVMFSuccess - If API call is successful
//PVMFErrInvalidState - If API is called in the invalid state
////////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFJitterBufferNode::QueryUUID(PVMFSessionId s,
const PvmfMimeString& aMimeType,
Oscl_Vector< PVUuid, OsclMemAllocator >& aUuids,
bool aExactUuidsOnly ,
const OsclAny* aContext)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::QueryUUID"));
PVMFJitterBufferNodeCommand cmd;
cmd.PVMFJitterBufferNodeCommandBase::Construct(s,
PVMF_JITTER_BUFFER_NODE_QUERYUUID,
aMimeType,
aUuids,
aExactUuidsOnly,
aContext);
return QueueCommandL(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVMFJitterBufferNode::QueryInterface(PVMFSessionId s,
const PVUuid& aUuid,
PVInterface*& aInterfacePtr,
const OsclAny* aContext)
{
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:QueryInterface"));
PVMFJitterBufferNodeCommand cmd;
cmd.PVMFJitterBufferNodeCommandBase::Construct(s,
PVMF_JITTER_BUFFER_NODE_QUERYINTERFACE,
aUuid,
aInterfacePtr,
aContext);
return QueueCommandL(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVMFJitterBufferNode::RequestPort(PVMFSessionId s,
int32 aPortTag,
const PvmfMimeString* aPortConfig,
const OsclAny* aContext)
{
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:RequestPort"));
PVMFJitterBufferNodeCommand cmd;
cmd.PVMFJitterBufferNodeCommandBase::Construct(s,
PVMF_JITTER_BUFFER_NODE_REQUESTPORT,
aPortTag,
aPortConfig,
aContext);
return QueueCommandL(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVMFJitterBufferNode::ReleasePort(PVMFSessionId s,
PVMFPortInterface& aPort,
const OsclAny* aContext)
{
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:ReleasePort"));
PVMFJitterBufferNodeCommand cmd;
cmd.PVMFJitterBufferNodeCommandBase::Construct(s,
PVMF_JITTER_BUFFER_NODE_RELEASEPORT,
aPort,
aContext);
return QueueCommandL(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVMFJitterBufferNode::Init(PVMFSessionId s,
const OsclAny* aContext)
{
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:Init"));
PVMFJitterBufferNodeCommand cmd;
cmd.PVMFJitterBufferNodeCommandBase::Construct(s,
PVMF_JITTER_BUFFER_NODE_INIT,
aContext);
return QueueCommandL(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVMFJitterBufferNode::Prepare(PVMFSessionId s,
const OsclAny* aContext)
{
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:Prepare"));
PVMFJitterBufferNodeCommand cmd;
cmd.PVMFJitterBufferNodeCommandBase::Construct(s,
PVMF_JITTER_BUFFER_NODE_PREPARE,
aContext);
return QueueCommandL(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVMFJitterBufferNode::Start(PVMFSessionId s,
const OsclAny* aContext)
{
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:Start"));
PVMFJitterBufferNodeCommand cmd;
cmd.PVMFJitterBufferNodeCommandBase::Construct(s,
PVMF_JITTER_BUFFER_NODE_START,
aContext);
return QueueCommandL(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVMFJitterBufferNode::Stop(PVMFSessionId s,
const OsclAny* aContext)
{
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:Stop"));
PVMFJitterBufferNodeCommand cmd;
cmd.PVMFJitterBufferNodeCommandBase::Construct(s,
PVMF_JITTER_BUFFER_NODE_STOP,
aContext);
return QueueCommandL(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVMFJitterBufferNode::Flush(PVMFSessionId s,
const OsclAny* aContext)
{
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:Flush"));
PVMFJitterBufferNodeCommand cmd;
cmd.PVMFJitterBufferNodeCommandBase::Construct(s,
PVMF_JITTER_BUFFER_NODE_FLUSH,
aContext);
return QueueCommandL(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVMFJitterBufferNode::Pause(PVMFSessionId s,
const OsclAny* aContext)
{
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:Pause"));
PVMFJitterBufferNodeCommand cmd;
cmd.PVMFJitterBufferNodeCommandBase::Construct(s,
PVMF_JITTER_BUFFER_NODE_PAUSE,
aContext);
return QueueCommandL(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVMFJitterBufferNode::Reset(PVMFSessionId s,
const OsclAny* aContext)
{
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:Reset"));
PVMFJitterBufferNodeCommand cmd;
cmd.PVMFJitterBufferNodeCommandBase::Construct(s,
PVMF_JITTER_BUFFER_NODE_RESET,
aContext);
return QueueCommandL(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVMFJitterBufferNode::CancelAllCommands(PVMFSessionId s,
const OsclAny* aContextData)
{
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:CancelAllCommands"));
PVMFJitterBufferNodeCommand cmd;
cmd.PVMFJitterBufferNodeCommandBase::Construct(s,
PVMF_JITTER_BUFFER_NODE_CANCELALLCOMMANDS,
aContextData);
return QueueCommandL(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVMFJitterBufferNode::CancelCommand(PVMFSessionId s,
PVMFCommandId aCmdId,
const OsclAny* aContextData)
{
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:CancelCommand"));
PVMFJitterBufferNodeCommand cmd;
cmd.PVMFJitterBufferNodeCommandBase::Construct(s,
PVMF_JITTER_BUFFER_NODE_CANCELCOMMAND,
aCmdId,
aContextData);
return QueueCommandL(cmd);
}
void PVMFJitterBufferNode::HandlePortActivity(const PVMFPortActivity& aActivity)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::PortActivity: port=0x%x, type=%d",
aActivity.iPort, aActivity.iType));
PVMFJitterBufferPortParams* portParamsPtr = NULL;
PVMFJitterBufferPort* jbPort = OSCL_STATIC_CAST(PVMFJitterBufferPort*, aActivity.iPort);
portParamsPtr = jbPort->iPortParams;
if (aActivity.iType != PVMF_PORT_ACTIVITY_DELETED)
{
if (portParamsPtr == NULL)
{
ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)(aActivity.iPort));
PVMF_JBNODE_LOGERROR((0, "0x%x PVMFJitterBufferNode::HandlePortActivity - getPortContainer Failed", this));
return;
}
}
/*
* A port is reporting some activity or state change. This code
* figures out whether we need to queue a processing event
* for the AO, and/or report a node event to the observer.
*/
switch (aActivity.iType)
{
case PVMF_PORT_ACTIVITY_CREATED:
/*
* Report port created info event to the node.
*/
ReportInfoEvent(PVMFInfoPortCreated, (OsclAny*)aActivity.iPort);
break;
case PVMF_PORT_ACTIVITY_DELETED:
/*
* Report port deleted info event to the node.
*/
ReportInfoEvent(PVMFInfoPortDeleted, (OsclAny*)aActivity.iPort);
break;
case PVMF_PORT_ACTIVITY_CONNECT:
//nothing needed.
break;
case PVMF_PORT_ACTIVITY_DISCONNECT:
{
if (ipJitterBufferMisc)
{
LogSessionDiagnostics();
ipJitterBufferMisc->StreamingSessionStopped();
}
}
break;
case PVMF_PORT_ACTIVITY_OUTGOING_MSG:
{
if (portParamsPtr->iProcessOutgoingMessages)
{
/*
* An outgoing message was queued on this port.
* All ports have outgoing messages
* in this node
*/
QueuePortActivity(portParamsPtr, aActivity);
}
}
break;
case PVMF_PORT_ACTIVITY_INCOMING_MSG:
{
/*
* An outgoing message was queued on this port.
* Only input and feedback ports have incoming messages
* in this node
*/
int32 portTag = portParamsPtr->iTag;
switch (portTag)
{
case PVMF_JITTER_BUFFER_PORT_TYPE_INPUT:
case PVMF_JITTER_BUFFER_PORT_TYPE_FEEDBACK:
if (portParamsPtr->iProcessIncomingMessages)
{
QueuePortActivity(portParamsPtr, aActivity);
}
break;
default:
OSCL_ASSERT(false);
break;
}
}
break;
case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_BUSY:
{
int32 portTag = portParamsPtr->iTag;
switch (portTag)
{
case PVMF_JITTER_BUFFER_PORT_TYPE_INPUT:
/*
* We typically use incoming port's outgoing q
* only in case of 3GPP streaming, wherein we
* send firewall packets. If it is busy, it does
* not stop us from registering incoming data pkts.
* so do nothing.
*/
break;
case PVMF_JITTER_BUFFER_PORT_TYPE_OUTPUT:
{
/*
* This implies that this output port cannot accept any more
* msgs on its outgoing queue. This would usually imply that
* the corresponding input port must stop processing messages,
* however in case of jitter buffer the input and output ports
* are separated by a huge jitter buffer. Therefore continue
* to process the input.
*/
}
break;
case PVMF_JITTER_BUFFER_PORT_TYPE_FEEDBACK:
portParamsPtr->iProcessIncomingMessages = false;
break;
default:
OSCL_ASSERT(false);
break;
}
}
break;
case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_READY:
{
int32 portTag = portParamsPtr->iTag;
/*
* Outgoing queue was previously busy, but is now ready.
* We may need to schedule new processing events depending
* on the port type.
*/
switch (portTag)
{
case PVMF_JITTER_BUFFER_PORT_TYPE_INPUT:
/*
* We never did anything in PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_BUSY
* so do nothing
*/
break;
case PVMF_JITTER_BUFFER_PORT_TYPE_OUTPUT:
{
/*
* This implies that this output port can accept more
* msgs on its outgoing queue. This implies that the corresponding
* input port can start processing messages again.
*/
PVMFJitterBufferPort* jbPort = OSCL_STATIC_CAST(PVMFJitterBufferPort*, aActivity.iPort);
PVMFJitterBufferPortParams* inPortParams = jbPort->iCounterpartPortParams;
if (inPortParams != NULL)
{
inPortParams->iProcessIncomingMessages = true;
}
else
{
OSCL_ASSERT(false);
}
}
break;
case PVMF_JITTER_BUFFER_PORT_TYPE_FEEDBACK:
portParamsPtr->iProcessIncomingMessages = true;
break;
default:
OSCL_ASSERT(false);
break;
}
if (IsAdded())
{
RunIfNotReady();
}
}
break;
case PVMF_PORT_ACTIVITY_CONNECTED_PORT_BUSY:
{
/*
* The connected port has become busy (its incoming queue is
* busy).
*/
int32 portTag = portParamsPtr->iTag;
switch (portTag)
{
case PVMF_JITTER_BUFFER_PORT_TYPE_INPUT:
break;
case PVMF_JITTER_BUFFER_PORT_TYPE_OUTPUT:
{
/*
* This implies that this output port cannot send any more
* msgs from its outgoing queue. It should stop processing
* messages till the connect port is ready.
*/
portParamsPtr->iProcessOutgoingMessages = false;
}
break;
case PVMF_JITTER_BUFFER_PORT_TYPE_FEEDBACK:
portParamsPtr->iProcessOutgoingMessages = false;
break;
default:
OSCL_ASSERT(false);
break;
}
}
break;
case PVMF_PORT_ACTIVITY_CONNECTED_PORT_READY:
{
/*
* The connected port has transitioned from Busy to Ready.
* It's time to start processing messages outgoing again.
*/
int32 portTag = portParamsPtr->iTag;
switch (portTag)
{
case PVMF_JITTER_BUFFER_PORT_TYPE_INPUT:
break;
case PVMF_JITTER_BUFFER_PORT_TYPE_OUTPUT:
/*
* This implies that this output port can now send
* msgs from its outgoing queue. It can start processing
* messages now.
*/
portParamsPtr->iProcessOutgoingMessages = true;
break;
case PVMF_JITTER_BUFFER_PORT_TYPE_FEEDBACK:
portParamsPtr->iProcessOutgoingMessages = true;
break;
default:
OSCL_ASSERT(false);
break;
}
if (IsAdded())
{
RunIfNotReady();
}
}
break;
default:
break;
}
}
/////////////////////////////////////////////////////
// Port Processing routines
/////////////////////////////////////////////////////
void PVMFJitterBufferNode::QueuePortActivity(PVMFJitterBufferPortParams* aPortParams,
const PVMFPortActivity &aActivity)
{
OSCL_UNUSED_ARG(aPortParams);
OSCL_UNUSED_ARG(aActivity);
if (IsAdded())
{
/*
* wake up the AO to process the port activity event.
*/
RunIfNotReady();
}
}
///////////////////////////////////////////////////////////////////////////////
//Extension interfaces function implementation
///////////////////////////////////////////////////////////////////////////////
void PVMFJitterBufferNode::SetRTCPIntervalInMicroSecs(uint32 aRTCPInterval)
{
OSCL_UNUSED_ARG(aRTCPInterval);
}
bool PVMFJitterBufferNode::SetPortParams(PVMFPortInterface* aPort,
uint32 aTimeScale,
uint32 aBitRate,
OsclRefCounterMemFrag& aConfig,
bool aRateAdaptation,
uint32 aRateAdaptationFeedBackFrequency)
{
return SetPortParams(aPort, aTimeScale, aBitRate, aConfig, aRateAdaptation,
aRateAdaptationFeedBackFrequency, false);
}
bool PVMFJitterBufferNode::SetPlayRange(int32 aStartTimeInMS,
int32 aStopTimeInMS,
bool aPlayAfterASeek,
bool aStopTimeAvailable)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SetPlayRange In StartTime[%d], StopTime[%d] StopTimeValid[%d] PlayingAfterSeek[%d]", aStartTimeInMS, aStopTimeInMS, aStopTimeAvailable, aPlayAfterASeek));
ipJitterBufferMisc->SetPlayRange(aStartTimeInMS, aStopTimeInMS, aPlayAfterASeek, aStopTimeAvailable);
return true;
}
void PVMFJitterBufferNode::SetPlayBackThresholdInMilliSeconds(uint32 aThreshold)
{
OSCL_UNUSED_ARG(aThreshold);
}
void PVMFJitterBufferNode::SetJitterBufferRebufferingThresholdInMilliSeconds(uint32 aThreshold)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SetJitterBufferRebufferingThresholdInMilliSeconds Threshhold[%d]", aThreshold));
if (aThreshold < iJitterBufferDurationInMilliSeconds)
{
iRebufferingThreshold = aThreshold;
Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator it;
for (it = iPortParamsQueue.begin(); it != iPortParamsQueue.end(); it++)
{
PVMFJitterBufferPortParams* pPortParams = *it;
if ((pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT))
{
PVMFJitterBuffer* jitterBuffer = pPortParams->ipJitterBuffer;
if (jitterBuffer)
{
jitterBuffer->SetRebufferingThresholdInMilliSeconds(aThreshold);
}
}
}
}
}
void PVMFJitterBufferNode::GetJitterBufferRebufferingThresholdInMilliSeconds(uint32& aThreshold)
{
aThreshold = iRebufferingThreshold;
}
void PVMFJitterBufferNode::SetJitterBufferDurationInMilliSeconds(uint32 aDuration)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SetJitterBufferDurationInMilliSeconds Duration [%d]", aDuration));
uint32 duration = iJitterBufferDurationInMilliSeconds;
if (aDuration > iRebufferingThreshold)
{
duration = aDuration;
iJitterBufferDurationInMilliSeconds = duration;
}
Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator it;
for (it = iPortParamsQueue.begin(); it != iPortParamsQueue.end(); it++)
{
PVMFJitterBufferPortParams* pPortParams = *it;
if ((pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT))
{
PVMFJitterBuffer* jitterBuffer = pPortParams->ipJitterBuffer;
if (jitterBuffer)
{
jitterBuffer->SetDurationInMilliSeconds(duration);
}
}
}
}
void PVMFJitterBufferNode::GetJitterBufferDurationInMilliSeconds(uint32& duration)
{
duration = iJitterBufferDurationInMilliSeconds;
}
void PVMFJitterBufferNode::SetEarlyDecodingTimeInMilliSeconds(uint32 duration)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SetEarlyDecodingTimeInMilliSeconds - Early Decoding Time [%d]", duration));
Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
for (iter = iPortParamsQueue.begin(); iter != iPortParamsQueue.end(); iter++)
{
PVMFJitterBufferPortParams* pPortParams = *iter;
if (pPortParams && (pPortParams->ipJitterBuffer) && (PVMF_JITTER_BUFFER_PORT_TYPE_INPUT == pPortParams->iTag))
{
pPortParams->ipJitterBuffer->SetEarlyDecodingTimeInMilliSeconds(duration);
}
}
}
void PVMFJitterBufferNode::SetBurstThreshold(float burstThreshold)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SetBurstThreshold burstThreshold[%f]", burstThreshold));
Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
for (iter = iPortParamsQueue.begin(); iter != iPortParamsQueue.end(); iter++)
{
PVMFJitterBufferPortParams* pPortParams = *iter;
if (pPortParams && (pPortParams->ipJitterBuffer) && (PVMF_JITTER_BUFFER_PORT_TYPE_INPUT == pPortParams->iTag))
{
pPortParams->ipJitterBuffer->SetBurstThreshold(burstThreshold);
}
}
}
void PVMFJitterBufferNode::SetMaxInactivityDurationForMediaInMs(uint32 aDuration)
{
iMaxInactivityDurationForMediaInMs = aDuration;
}
void PVMFJitterBufferNode::GetMaxInactivityDurationForMediaInMs(uint32& aDuration)
{
aDuration = iMaxInactivityDurationForMediaInMs;
}
void PVMFJitterBufferNode::SetClientPlayBackClock(PVMFMediaClock* aClientClock)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SetClientPlayBackClock %x", aClientClock));
//remove ourself as observer of old clock, if any.
//Todo: Repetition should make sence only after call to Reset function.
ipClientPlayBackClock = aClientClock;
}
bool PVMFJitterBufferNode::PrepareForRepositioning(bool oUseExpectedClientClockVal ,
uint32 aExpectedClientClockVal)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::PrepareForRepositioning oUseExpectedClientClockVal[%d], aExpectedClientClockVal[%d]", oUseExpectedClientClockVal, aExpectedClientClockVal));
iJitterBufferState = PVMF_JITTER_BUFFER_IN_TRANSITION;
ipJitterBufferMisc->PrepareForRepositioning(oUseExpectedClientClockVal, aExpectedClientClockVal);
return true;
}
bool PVMFJitterBufferNode::SetPortSSRC(PVMFPortInterface* aPort, uint32 aSSRC)
{
bool retval = false;
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SetPortSSRC aPort[%x], aSSRC[%d]", aPort, aSSRC));
if(aPort)
{
Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::const_iterator iter;
for (iter = iPortParamsQueue.begin(); iter != iPortParamsQueue.end() ; ++iter)
{
if (iter && (*iter) && (&((*iter)->irPort) == aPort))
{
retval = true;
ipJitterBufferMisc->SetPortSSRC(aPort, aSSRC);
break;
}
}
}
return retval;
}
bool PVMFJitterBufferNode::SetPortRTPParams(PVMFPortInterface* aPort,
bool aSeqNumBasePresent,
uint32 aSeqNumBase,
bool aRTPTimeBasePresent,
uint32 aRTPTimeBase,
bool aNPTTimeBasePresent,
uint32 aNPTInMS,
bool oPlayAfterASeek)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SetPortRTPParams In Port - 0x%x", aPort));
uint32 i;
//The above method is called only during 3GPP repositioning, however, since the aPort param in the signature
// takes care only of the input port, the output port msg queues aren't cleared.
// As a result ClearMsgQueues need to be called explicity on all the ports.
//The oPlayAfterASeek check is necessary since the clearing of msg queues has to be carried out only during repositioning,
// not otherwise
if (oPlayAfterASeek)
{
for (i = 0; i < iPortParamsQueue.size(); i++)
{
PVMFJitterBufferPortParams* pPortParams = iPortParamsQueue[i];
pPortParams->irPort.ClearMsgQueues();
}
}
for (i = 0; i < iPortParamsQueue.size(); i++)
{
PVMFJitterBufferPortParams* pPortParams = iPortParamsQueue[i];
if (&pPortParams->irPort == aPort)
{
if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
{
if (pPortParams->ipJitterBuffer != NULL)
{
PVMFRTPInfoParams rtpInfoParams;
rtpInfoParams.seqNumBaseSet = aSeqNumBasePresent;
rtpInfoParams.seqNum = aSeqNumBase;
rtpInfoParams.rtpTimeBaseSet = aRTPTimeBasePresent;
rtpInfoParams.rtpTime = aRTPTimeBase;
rtpInfoParams.nptTimeBaseSet = aNPTTimeBasePresent;
rtpInfoParams.nptTimeInMS = aNPTInMS;
rtpInfoParams.rtpTimeScale = pPortParams->iTimeScale;
pPortParams->ipJitterBuffer->setRTPInfoParams(rtpInfoParams, oPlayAfterASeek);
/* In case this is after a reposition purge the jitter buffer */
if (oPlayAfterASeek)
{
uint32 timebase32 = 0;
uint32 clientClock32 = 0;
bool overflowFlag = false;
if (ipClientPlayBackClock != NULL)
ipClientPlayBackClock->GetCurrentTime32(clientClock32, overflowFlag, PVMF_MEDIA_CLOCK_MSEC, timebase32);
#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
PVMF_JBNODE_LOGCLOCK_REBUFF((0, "PVMFJitterBufferNode::setPortRTPParams - Purging Upto SeqNum =%d", aSeqNumBase));
PVMF_JBNODE_LOGCLOCK_REBUFF((0, "PVMFJitterBufferNode::setPortRTPParams - Before Purge - ClientClock=%d",
clientClock32));
#endif
pPortParams->ipJitterBuffer->PurgeElementsWithSeqNumsLessThan(aSeqNumBase,
clientClock32);
#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
PVMF_JBNODE_LOGCLOCK_REBUFF((0, "PVMFJitterBufferNode::setPortRTPParams - After Purge - ClientClock=%d",
clientClock32));
#endif
/*
* Since we flushed the jitter buffer, set it to ready state,
* reset the delay flag
*/
iDelayEstablished = false;
iJitterBufferState = PVMF_JITTER_BUFFER_READY;
//iPlayingAfterSeek = true;
}
}
return true;
}
}
}
return false;
}
bool PVMFJitterBufferNode::SetPortRTCPParams(PVMFPortInterface* aPort,
int aNumSenders,
uint32 aRR,
uint32 aRS)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SetPortRTCPParams aPort - [0x%x]", aPort));
return ipJitterBufferMisc->SetPortRTCPParams(aPort, aNumSenders, aRR, aRS);
}
PVMFTimestamp PVMFJitterBufferNode::GetActualMediaDataTSAfterSeek()
{
return ipJitterBufferMisc->GetActualMediaDataTSAfterSeek();
}
PVMFTimestamp PVMFJitterBufferNode::GetMaxMediaDataTS()
{
return ipJitterBufferMisc->GetMaxMediaDataTS();
}
PVMFStatus PVMFJitterBufferNode::SetServerInfo(PVMFJitterBufferFireWallPacketInfo& aServerInfo)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SetServerInfo In"));
if (iDisableFireWallPackets == false)
{
ipJitterBufferMisc->SetServerInfo(aServerInfo);
}
else
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::setServerInfo: FW Pkts Disabled"));
if (iCurrentCommand.size() > 0)
{
if (iCurrentCommand.front().iCmd == PVMF_JITTER_BUFFER_NODE_PREPARE)
{
/* No firewall packet exchange - Complete Prepare */
CompletePrepare();
}
}
}
return PVMFSuccess;
}
PVMFStatus PVMFJitterBufferNode::NotifyOutOfBandEOS()
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::NotifyOutOfBandEOS In"));
// Ignore Out Of Band EOS for any Non Live stream
if (ipJitterBufferMisc && (!ipJitterBufferMisc->PlayStopTimeAvailable()))
{
if (iJitterBufferState != PVMF_JITTER_BUFFER_IN_TRANSITION)
{
ipJitterBufferMisc->SetSessionDurationExpired();
CancelEventCallBack(JB_INCOMING_MEDIA_INACTIVITY_DURATION_EXPIRED);
PVMF_JBNODE_LOGDATATRAFFIC((0, "PVMFJitterBufferNode::NotifyOutOfBandEOS - Out Of Band EOS Recvd"));
PVMF_JBNODE_LOGCLOCK_SESSION_DURATION((0, "PVMFJitterBufferNode::NotifyOutOfBandEOS - Out Of Band EOS Recvd"));
}
else
{
PVMF_JBNODE_LOGDATATRAFFIC((0, "PVMFJitterBufferNode::NotifyOutOfBandEOS - Ignoring Out Of Band EOS in Transition State"));
PVMF_JBNODE_LOGCLOCK_SESSION_DURATION((0, "PVMFJitterBufferNode::NotifyOutOfBandEOS - Ignoring Out Of Band EOS in Transition State"));
}
}
else
{
PVMF_JBNODE_LOGDATATRAFFIC((0, "PVMFJitterBufferNode::NotifyOutOfBandEOS - Ignoring Out Of Band EOS for Non Live Stream"));
PVMF_JBNODE_LOGCLOCK_SESSION_DURATION((0, "PVMFJitterBufferNode::NotifyOutOfBandEOS - Ignoring Out Of Band EOS for Non Live Stream"));
}
return PVMFSuccess;
}
PVMFStatus PVMFJitterBufferNode::SendBOSMessage(uint32 aStreamID)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SendBOSMessage In"));
Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator it;
for (it = iPortParamsQueue.begin();
it != iPortParamsQueue.end();
it++)
{
PVMFJitterBufferPortParams* pPortParams = *it;
if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
{
if (pPortParams->ipJitterBuffer)
{
pPortParams->ipJitterBuffer->QueueBOSCommand(aStreamID);
}
}
}
PVMF_JBNODE_LOGDATATRAFFIC((0, "PVMFJitterBufferNode::SendBOSMessage - BOS Recvd"));
return PVMFSuccess;
}
void PVMFJitterBufferNode::SetJitterBufferChunkAllocator(OsclMemPoolResizableAllocator*
aDataBufferAllocator, const PVMFPortInterface* aPort)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SetJitterBufferChunkAllocator -aPort 0x%x", aPort));
PVMFJitterBufferPort* port = OSCL_STATIC_CAST(PVMFJitterBufferPort*, aPort);
if (port->iPortParams->ipJitterBuffer)
{
port->iPortParams->ipJitterBuffer->SetJitterBufferChunkAllocator(aDataBufferAllocator);
}
}
void PVMFJitterBufferNode::SetJitterBufferMemPoolInfo(const PvmfPortBaseImpl* aPort,
uint32 aSize,
uint32 aResizeSize,
uint32 aMaxNumResizes,
uint32 aExpectedNumberOfBlocksPerBuffer)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SetJitterBufferMemPoolInfo Port 0x%x", aPort));
PVMFJitterBufferPort* port = OSCL_STATIC_CAST(PVMFJitterBufferPort*, aPort);
if (port->iPortParams->ipJitterBuffer)
{
port->iPortParams->ipJitterBuffer->SetJitterBufferMemPoolInfo(aSize, aResizeSize, aMaxNumResizes, aExpectedNumberOfBlocksPerBuffer);
}
}
void PVMFJitterBufferNode::GetJitterBufferMemPoolInfo(const PvmfPortBaseImpl* aPort,
uint32& aSize,
uint32& aResizeSize,
uint32& aMaxNumResizes,
uint32& aExpectedNumberOfBlocksPerBuffer) const
{
PVMFJitterBufferPort* port = OSCL_STATIC_CAST(PVMFJitterBufferPort*, aPort);
if (port->iPortParams->ipJitterBuffer)
{
port->iPortParams->ipJitterBuffer->GetJitterBufferMemPoolInfo(aSize, aResizeSize, aMaxNumResizes, aExpectedNumberOfBlocksPerBuffer);
}
}
void PVMFJitterBufferNode::SetSharedBufferResizeParams(uint32 maxNumResizes,
uint32 resizeSize)
{
// make sure we're in a state that makes sense
OSCL_ASSERT((iInterfaceState == EPVMFNodeCreated) ||
(iInterfaceState == EPVMFNodeIdle) ||
(iInterfaceState == EPVMFNodeInitialized));
iMaxNumBufferResizes = maxNumResizes;
iBufferResizeSize = resizeSize;
}
void PVMFJitterBufferNode::GetSharedBufferResizeParams(uint32& maxNumResizes,
uint32& resizeSize)
{
maxNumResizes = iMaxNumBufferResizes;
resizeSize = iBufferResizeSize;
}
bool PVMFJitterBufferNode::ClearJitterBuffer(PVMFPortInterface* aPort,
uint32 aSeqNum)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::ClearJitterBuffer Port 0x%x aSeqNum[%d]", aPort, aSeqNum));
/* Typically called only for HTTP streaming sessions */
Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator it;
for (it = iPortParamsQueue.begin(); it != iPortParamsQueue.end(); it++)
{
PVMFJitterBufferPortParams* pPortParams = *it;
pPortParams->irPort.ClearMsgQueues();
}
for (it = iPortParamsQueue.begin(); it != iPortParamsQueue.end(); it++)
{
PVMFJitterBufferPortParams* pPortParams = *it;
if (&pPortParams->irPort == aPort && (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT) && (pPortParams->ipJitterBuffer != NULL))
{
uint32 timebase32 = 0;
uint32 clientClock32 = 0;
bool overflowFlag = false;
if (ipClientPlayBackClock != NULL)
ipClientPlayBackClock->GetCurrentTime32(clientClock32, overflowFlag, PVMF_MEDIA_CLOCK_MSEC, timebase32);
pPortParams->ipJitterBuffer->PurgeElementsWithSeqNumsLessThan(aSeqNum,
clientClock32);
ipJitterBufferMisc->ResetSession();
iJitterBufferState = PVMF_JITTER_BUFFER_READY;
return true;
}
}
return false;
}
void PVMFJitterBufferNode::FlushJitterBuffer()
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::FlushJitterBuffer In"));
for (uint32 i = 0; i < iPortParamsQueue.size(); i++)
{
PVMFJitterBufferPortParams* pPortParams = iPortParamsQueue[i];
if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
{
if (pPortParams->ipJitterBuffer != NULL)
{
pPortParams->ipJitterBuffer->FlushJitterBuffer();
}
}
}
}
PVMFStatus PVMFJitterBufferNode::SetInputMediaHeaderPreParsed(PVMFPortInterface* aPort,
bool aHeaderPreParsed)
{
PVMFStatus status = PVMFFailure;
PVMFJitterBufferPort *port = OSCL_STATIC_CAST(PVMFJitterBufferPort*, aPort);
if (port)
{
PVMFJitterBufferPortParams* portParams = port->GetPortParams();
if (portParams && portParams->ipJitterBuffer)
{
status = portParams->ipJitterBuffer->SetInputPacketHeaderPreparsed(aHeaderPreParsed);
}
}
return status;
}
PVMFStatus PVMFJitterBufferNode::HasSessionDurationExpired(bool& aExpired)
{
aExpired = ipJitterBufferMisc->IsSessionExpired();
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::HasSessionDurationExpired %d", aExpired));
return PVMFSuccess;
}
bool PVMFJitterBufferNode::PurgeElementsWithNPTLessThan(NptTimeFormat &aNPTTime)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::PurgeElementsWithNPTLessThan"));
bool retval = false;
if (ipJitterBufferMisc)
{
retval = ipJitterBufferMisc->PurgeElementsWithNPTLessThan(aNPTTime);
}
iJitterBufferState = PVMF_JITTER_BUFFER_READY;
return retval;
}
void PVMFJitterBufferNode::SetBroadCastSession()
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SetBroadCastSession"));
iBroadCastSession = true;
if (ipJitterBufferMisc)
{
ipJitterBufferMisc->SetBroadcastSession();
}
}
void PVMFJitterBufferNode::DisableFireWallPackets()
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::DisableFireWallPackets"));
if (ipJitterBufferMisc)
ipJitterBufferMisc->MediaReceivingChannelPreparationRequired(false);
}
void PVMFJitterBufferNode::UpdateJitterBufferState()
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::UpdateJitterBufferState"));
Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
for (iter = iPortParamsQueue.begin(); iter != iPortParamsQueue.end(); iter ++)
{
PVMFJitterBufferPortParams* ptr = *iter;
if (PVMF_JITTER_BUFFER_PORT_TYPE_INPUT == ptr->iTag)
{
ptr->ipJitterBuffer->SetJitterBufferState(PVMF_JITTER_BUFFER_READY);
}
}
iDelayEstablished = true;
}
void PVMFJitterBufferNode::StartOutputPorts()
{
oStopOutputPorts = false;
}
void PVMFJitterBufferNode::StopOutputPorts()
{
oStopOutputPorts = true;
}
///////////////////////////////////////////////////////////////////////////////
//Used for the implementation of extension interface functions
///////////////////////////////////////////////////////////////////////////////
bool
PVMFJitterBufferNode::SetPortParams(PVMFPortInterface* aPort,
uint32 aTimeScale,
uint32 aBitRate,
OsclRefCounterMemFrag& aConfig,
bool aRateAdaptation,
uint32 aRateAdaptationFeedBackFrequency,
uint aMaxNumBuffResizes, uint aBuffResizeSize)
{
return SetPortParams(aPort, aTimeScale, aBitRate, aConfig, aRateAdaptation,
aRateAdaptationFeedBackFrequency, true,
aMaxNumBuffResizes, aBuffResizeSize);
}
bool
PVMFJitterBufferNode::SetPortParams(PVMFPortInterface* aPort,
uint32 aTimeScale,
uint32 aBitRate,
OsclRefCounterMemFrag& aConfig,
bool aRateAdaptation,
uint32 aRateAdaptationFeedBackFrequency,
bool aUserSpecifiedBuffParams,
uint aMaxNumBuffResizes, uint aBuffResizeSize)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::SetPortParams"));
OSCL_UNUSED_ARG(aUserSpecifiedBuffParams);
uint32 ii;
for (ii = 0; ii < iPortParamsQueue.size(); ii++)
{
PVMFJitterBufferPortParams* pPortParams = iPortParamsQueue[ii];
if (&pPortParams->irPort == aPort)
{
pPortParams->iTimeScale = aTimeScale;
pPortParams->iMediaClockConverter.set_timescale(aTimeScale);
pPortParams->iBitrate = aBitRate;
if (pPortParams->ipJitterBuffer)
{
pPortParams->ipJitterBuffer->SetTrackConfig(aConfig);
pPortParams->ipJitterBuffer->SetTimeScale(aTimeScale);
pPortParams->ipJitterBuffer->SetMediaClockConverter(&pPortParams->iMediaClockConverter);
}
/* Compute buffer size based on bitrate and jitter duration*/
uint32 sizeInBytes = 0;
if (((int32)iJitterBufferDurationInMilliSeconds > 0) &&
((int32)aBitRate > 0))
{
uint32 byteRate = aBitRate / 8;
uint32 overhead = (byteRate * PVMF_JITTER_BUFFER_NODE_MEM_POOL_OVERHEAD) / 100;
uint32 durationInSec = iJitterBufferDurationInMilliSeconds / 1000;
sizeInBytes = ((byteRate + overhead) * durationInSec);
if (sizeInBytes < MIN_RTP_SOCKET_MEM_POOL_SIZE_IN_BYTES)
{
sizeInBytes = MIN_RTP_SOCKET_MEM_POOL_SIZE_IN_BYTES;
}
sizeInBytes += (2 * MAX_SOCKET_BUFFER_SIZE);
}
if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
{
PVMFJitterBuffer* jitterBuffer = NULL;
jitterBuffer = pPortParams->ipJitterBuffer;
if (jitterBuffer)
{
pPortParams->ipJitterBuffer->SetJitterBufferMemPoolInfo(sizeInBytes, aBuffResizeSize, aMaxNumBuffResizes, 3000);
}
if (ipJitterBufferMisc)
ipJitterBufferMisc->SetRateAdaptationInfo(&pPortParams->irPort, aRateAdaptation, aRateAdaptationFeedBackFrequency, sizeInBytes);
}
iPortParamsQueue[ii] = pPortParams;
return true;
}
}
return false;
}
// This routine is called by various command APIs to queue an
// asynchronous command for processing by the command handler AO.
// This function may leave if the command can't be queued due to
// memory allocation failure.
PVMFCommandId PVMFJitterBufferNode::QueueCommandL(PVMFJitterBufferNodeCommand& aCmd)
{
PVMFCommandId id;
id = iInputCommands.AddL(aCmd);
if (IsAdded())
{
//wakeup the AO
RunIfNotReady();
}
return id;
}
///////////////////////////////////////////////////////////////////////////////
//OsclActiveObject Implementation
///////////////////////////////////////////////////////////////////////////////
/**
* This AO handles both API commands and port activity.
* The AO will either process one command or service one connected
* port per call. It will re-schedule itself and run continuously
* until it runs out of things to do.
*/
void PVMFJitterBufferNode::Run()
{
iNumRunL++;
/*
* Process commands.
*/
if (!iInputCommands.empty())
{
if (ProcessCommand(iInputCommands.front()))
{
/*
* note: need to check the state before re-scheduling
* since the node could have been reset in the ProcessCommand
* call.
*/
if (iInterfaceState != EPVMFNodeCreated)
{
if (IsAdded())
{
RunIfNotReady();
}
}
return;
}
}
/*
* Process port activity
*/
if (((iInterfaceState == EPVMFNodeInitialized) ||
(iInterfaceState == EPVMFNodePrepared) ||
(iInterfaceState == EPVMFNodeStarted) ||
(iInterfaceState == EPVMFNodePaused)) ||
FlushPending())
{
uint32 i;
for (i = 0; i < iPortVector.size(); i++)
{
PVMFJitterBufferPortParams* portContainerPtr =
iPortVector[i]->iPortParams;
if (portContainerPtr == NULL)
{
if (!getPortContainer(iPortVector[i], portContainerPtr))
{
PVMF_JBNODE_LOGERROR((0, "0x%x PVMFJitterBufferNode::Run: Error - getPortContainer failed", this));
return;
}
iPortVector[i]->iPortParams = portContainerPtr;
}
ProcessPortActivity(portContainerPtr);
}
if (CheckForPortRescheduling())
{
if (IsAdded())
{
/*
* Re-schedule since there is atleast one port that needs processing
*/
RunIfNotReady();
}
return;
}
}
/*
* If we get here we did not process any ports or commands.
* Check for completion of a flush command...
*/
if (FlushPending() && (!CheckForPortActivityQueues()))
{
uint32 i;
/*
* Debug check-- all the port queues should be empty at
* this point.
*/
for (i = 0; i < iPortVector.size(); i++)
{
if (iPortVector[i]->IncomingMsgQueueSize() > 0 ||
iPortVector[i]->OutgoingMsgQueueSize() > 0)
{
OSCL_ASSERT(false);
}
}
/*
* Flush is complete. Go to prepared state.
*/
SetState(EPVMFNodePrepared);
/*
* resume port input so the ports can be re-started.
*/
for (i = 0; i < iPortVector.size(); i++)
{
iPortVector[i]->ResumeInput();
}
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
if (IsAdded())
{
RunIfNotReady();
}
}
return;
}
void PVMFJitterBufferNode::DoCancel()
{
/*
* the base class cancel operation is sufficient.
*/
OsclActiveObject::DoCancel();
}
bool PVMFJitterBufferNode::ProcessPortActivity(PVMFJitterBufferPortParams* aPortParams)
{
if (!aPortParams)
{
return false;
}
PVMFStatus status = PVMFSuccess;
switch (aPortParams->iTag)
{
case PVMF_JITTER_BUFFER_PORT_TYPE_OUTPUT:
{
if ((aPortParams->iProcessOutgoingMessages) &&
(aPortParams->irPort.OutgoingMsgQueueSize() > 0))
{
status = ProcessOutgoingMsg(aPortParams);
}
/*
* Send data out of jitter buffer as long as there's:
* - more data to send
* - outgoing queue isn't in a Busy state.
* - ports are not paused
*/
PVMFJitterBufferPort* outPort = OSCL_STATIC_CAST(PVMFJitterBufferPort*, &aPortParams->irPort);
PVMFJitterBufferPortParams* inPortParamsPtr = outPort->iCounterpartPortParams;
if (aPortParams->iProcessOutgoingMessages)
{
if ((oStopOutputPorts == false) && (inPortParamsPtr->iCanReceivePktFromJB))
{
SendData(OSCL_STATIC_CAST(PVMFPortInterface*, &inPortParamsPtr->irPort));
}
}
}
break;
case PVMF_JITTER_BUFFER_PORT_TYPE_INPUT:
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::ProcessPortActivity: input port- aPortParams->iProcessIncomingMessages %d aPortParams->iPort->IncomingMsgQueueSize() %d" ,
aPortParams->iProcessIncomingMessages, aPortParams->irPort.IncomingMsgQueueSize()));
if ((aPortParams->iProcessIncomingMessages) &&
(aPortParams->irPort.IncomingMsgQueueSize() > 0))
{
status = ProcessIncomingMsg(aPortParams);
}
if ((aPortParams->iProcessOutgoingMessages) &&
(aPortParams->irPort.OutgoingMsgQueueSize() > 0))
{
status = ProcessOutgoingMsg(aPortParams);
}
}
break;
case PVMF_JITTER_BUFFER_PORT_TYPE_FEEDBACK:
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::ProcessPortActivity: - aPortParams->iProcessIncomingMessages %d aPortParams->iPort->IncomingMsgQueueSize() %d" ,
aPortParams->iProcessIncomingMessages, aPortParams->irPort.IncomingMsgQueueSize()));
if ((aPortParams->iProcessIncomingMessages) &&
(aPortParams->irPort.IncomingMsgQueueSize() > 0))
{
status = ProcessIncomingMsg(aPortParams);
}
if ((aPortParams->iProcessOutgoingMessages) &&
(aPortParams->irPort.OutgoingMsgQueueSize() > 0))
{
status = ProcessOutgoingMsg(aPortParams);
}
}
break;
default:
break;
}
/*
* Report any unexpected failure in port processing...
* (the InvalidState error happens when port input is suspended,
* so don't report it.)
*/
if (status != PVMFErrBusy
&& status != PVMFSuccess
&& status != PVMFErrInvalidState)
{
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::ProcessPortActivity: Error - ProcessPortActivity failed. port=0x%x",
&aPortParams->irPort));
ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)(&aPortParams->irPort));
}
/*
* return true if we processed an activity...
*/
return (status != PVMFErrBusy);
}
///////////////////////////////////////////////////////////////////////////////
//Processing of incoming msg
///////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFJitterBufferNode::ProcessIncomingMsg(PVMFJitterBufferPortParams* aPortParams)
{
PVUuid eventuuid = PVMFJitterBufferNodeEventTypeUUID;
PVMFPortInterface* aPort = &aPortParams->irPort;
PVMF_JBNODE_LOGDATATRAFFIC_IN((0, "PVMFJitterBufferNode::ProcessIncomingMsg: %s Tag %d", aPortParams->iMimeType.get_cstr(), aPortParams->iTag));
aPortParams->iNumMediaMsgsRecvd++;
if (aPortParams->iMonitorForRemoteActivity == true)
{
CancelEventCallBack(JB_INCOMING_MEDIA_INACTIVITY_DURATION_EXPIRED);
RequestEventCallBack(JB_INCOMING_MEDIA_INACTIVITY_DURATION_EXPIRED);
}
switch (aPortParams->iTag)
{
case PVMF_JITTER_BUFFER_PORT_TYPE_INPUT:
{
/* Parse packet header - mainly to retrieve time stamp */
PVMFJitterBuffer* jitterBuffer = aPortParams->ipJitterBuffer;
if (jitterBuffer == NULL)
{
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::ProcessIncomingMsg: findJitterBuffer failed"));
int32 errcode = PVMFJitterBufferNodeUnableToRegisterIncomingPacket;
ReportErrorEvent(PVMFErrArgument, (OsclAny*)(aPort), &eventuuid, &errcode);
return PVMFErrArgument;
}
/*
* Incoming message recvd on the input port.
* Dequeue the message
*/
PVMFSharedMediaMsgPtr msg;
PVMFStatus status = aPort->DequeueIncomingMsg(msg);
if (status != PVMFSuccess)
{
ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)(aPort));
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::ProcessIncomingMsg: Error - INPUT PORT - DequeueIncomingMsg failed"));
return status;
}
PVMFJitterBufferRegisterMediaMsgStatus regStatus = jitterBuffer->RegisterMediaMsg(msg);
switch (regStatus)
{
case PVMF_JB_REGISTER_MEDIA_MSG_SUCCESS:
{
PVMF_JBNODE_LOGDATATRAFFIC_IN((0, "PVMFJitterBufferNode::ProcessIncomingMsg: Packet registered successfully Mime %s", aPortParams->iMimeType.get_cstr()));
}
break;
case PVMF_JB_REGISTER_MEDIA_MSG_FAILURE_JB_FULL:
{
aPortParams->iProcessIncomingMessages = false;
jitterBuffer->NotifyFreeSpaceAvailable();
int32 infocode = PVMFJitterBufferNodeJitterBufferFull;
ReportInfoEvent(PVMFInfoOverflow, (OsclAny*)(aPort), &eventuuid, &infocode);
PVMF_JBNODE_LOGDATATRAFFIC_IN((0, "PVMFJitterBufferNode::ProcessIncomingMsg: Jitter Buffer full"));
PVMF_JBNODE_LOGDATATRAFFIC_FLOWCTRL_E((0, "PVMFJitterBufferNode::ProcessIncomingMsg: Jitter Buffer full"));
return PVMFErrBusy;
}
break;
case PVMF_JB_REGISTER_MEDIA_MSG_FAILURE_INSUFFICIENT_MEMORY_FOR_PACKETIZATION:
{
aPortParams->iProcessIncomingMessages = false;
jitterBuffer->NotifyFreeSpaceAvailable();
return PVMFErrBusy;
}
break;
case PVMF_JB_REGISTER_MEDIA_MSG_ERR_CORRUPT_PACKET:
{
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::ProcessIncomingMsg: unable to register packet"));
int32 errcode = PVMFJitterBufferNodeUnableToRegisterIncomingPacket;
ReportErrorEvent(PVMFErrArgument, (OsclAny*)(aPort), &eventuuid, &errcode);
return PVMFErrArgument;
}
case PVMF_JB_REGISTER_MEDIA_MSG_ERR_EOS_SIGNALLED:
{
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::ProcessIncomingMsg: data received after signalling EOS"));
}
break;
default:
{
PVMF_JBNODE_LOGDATATRAFFIC_IN((0, "PVMFJitterBufferNode::ProcessIncomingMsg: Packet could not be registered Register packet returned status %d", regStatus));
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::ProcessIncomingMsg: Packet could not be registered Register packet returned status %d", regStatus));
}
}
SendData(aPort);
}
break;
case PVMF_JITTER_BUFFER_PORT_TYPE_FEEDBACK:
{
/*
* Incoming RTCP reports - recvd on the input port.
* Dequeue the message - Need to fully implement
* RTCP
*/
PVMFSharedMediaMsgPtr msg;
PVMFStatus status = aPort->DequeueIncomingMsg(msg);
if (status != PVMFSuccess)
{
ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)(aPort));
PVMF_JBNODE_LOGERROR((0, "0x%x PVMFJitterBufferNode::ProcessIncomingMsg: Error - FB PORT - DequeueIncomingMsg failed", this));
return status;
}
status = ipJitterBufferMisc->ProcessFeedbackMessage(*aPortParams, msg);
PVMF_JBNODE_LOGDATATRAFFIC_IN((0, "PVMFJitterBufferNode::ProcessIncomingMsg: Feedback Packet registered with status code status %d", status));
}
break;
default:
{
ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)(aPort));
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::ProcessIncomingMsg - Invalid Port Tag"));
return PVMFFailure;
}
}
return (PVMFSuccess);
}
///////////////////////////////////////////////////////////////////////////////
//Processing of outgoing msg
///////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFJitterBufferNode::ProcessOutgoingMsg(PVMFJitterBufferPortParams* aPortParams)
{
PVMFPortInterface* aPort = &aPortParams->irPort;
/*
* Called by the AO to process one message off the outgoing
* message queue for the given port. This routine will
* try to send the data to the connected port.
*/
PVMF_JBNODE_LOGINFO((0, "0x%x PVMFJitterBufferNode::ProcessOutgoingMsg: aPort=0x%x", this, aPort));
/*
* If connected port is busy, the outgoing message cannot be process. It will be
* queued to be processed again after receiving PORT_ACTIVITY_CONNECTED_PORT_READY
* from this port.
*/
if (aPort->IsConnectedPortBusy())
{
PVMF_JBNODE_LOGDATATRAFFIC_OUT((0, "0x%x PVMFJitterBufferNode::ProcessOutgoingMsg: Connected port is busy", this));
aPortParams->iProcessOutgoingMessages = false;
return PVMFErrBusy;
}
PVMFStatus status = PVMFSuccess;
status = aPort->Send();
if (status == PVMFErrBusy)
{
PVMF_JBNODE_LOGDATATRAFFIC((0, "PVMFJitterBufferNode::ProcessOutgoingMsg: Connected port goes into busy state"));
aPortParams->iProcessOutgoingMessages = false;
}
else
{
aPortParams->iNumMediaMsgsSent++;
}
return status;
}
PVMFStatus
PVMFJitterBufferNode::SendData(PVMFPortInterface* aPort)
{
PVMFJitterBufferPort* jbPort =
OSCL_STATIC_CAST(PVMFJitterBufferPort*, aPort);
PVMFPortInterface* outputPort = jbPort->iPortCounterpart;
PVMFJitterBufferPortParams* portParamsPtr = jbPort->iPortParams;
PVMFJitterBufferPortParams* outPortParamsPtr = jbPort->iCounterpartPortParams;
PVMFJitterBuffer* jitterBuffer = portParamsPtr->ipJitterBuffer;
PVMF_JBNODE_LOGDATATRAFFIC_OUT((0, "PVMFJitterBufferNode::SendData In %s", outPortParamsPtr->iMimeType.get_cstr())) ;
if (!(portParamsPtr->iCanReceivePktFromJB))
{
PVMF_JBNODE_LOGDATATRAFFIC_OUT((0, "PVMFJitterBufferNode::SendData - Cant retrieve pkt from JB"));
return PVMFFailure;
}
if (outPortParamsPtr->irPort.IsOutgoingQueueBusy())
{
outPortParamsPtr->iProcessOutgoingMessages = false;
PVMF_JBNODE_LOGDATATRAFFIC_OUT((0, "PVMFJitterBufferNode::SendData - Port found to be busy %s", outPortParamsPtr->iMimeType.get_cstr())) ;
return PVMFErrBusy;
}
if (oStopOutputPorts)
{
PVMF_JBNODE_LOGDATATRAFFIC_OUT((0, "PVMFJitterBufferNode::SendData from Mime[%s] Output ports Stopped--", jbPort->iPortParams->iMimeType.get_cstr()));
return PVMFSuccess;
}
PVMFSharedMediaMsgPtr mediaOutMsg;
bool cmdPacket = false;
PVMFStatus status = jbPort->iPortParams->ipJitterBuffer->RetrievePacket(mediaOutMsg, cmdPacket);
while (PVMFSuccess == status)
{
if (!cmdPacket)
{
//media msg
outPortParamsPtr->iLastMsgTimeStamp = mediaOutMsg->getTimestamp();
}
status = outputPort->QueueOutgoingMsg(mediaOutMsg);
PVMF_JBNODE_LOGDATATRAFFIC_OUT((0, "PVMFJitterBufferNode::SendData from Mime[%s] MediaMsg SeqNum[%d], Ts[%d]", jbPort->iPortParams->iMimeType.get_cstr(), mediaOutMsg->getSeqNum(), mediaOutMsg->getTimestamp()));
if (outPortParamsPtr->irPort.IsOutgoingQueueBusy())
{
outPortParamsPtr->iProcessOutgoingMessages = false;
PVMFJitterBufferStats stats = jbPort->iPortParams->ipJitterBuffer->getJitterBufferStats();
PVMF_JBNODE_LOGDATATRAFFIC_OUT((0, "Send Data Mime %s stats.currentOccupancy[%d], stats.maxSeqNumRegistered[%d], stats.lastRetrievedSeqNum[%d] stats.maxTimeStampRetrievedWithoutRTPOffset[%d] SendOut Pkt[%d]", jbPort->iPortParams->iMimeType.get_cstr(), stats.currentOccupancy, stats.maxSeqNumRegistered, stats.lastRetrievedSeqNum, stats.maxTimeStampRetrievedWithoutRTPOffset, outPortParamsPtr->iNumMediaMsgsSent));
return PVMFErrBusy;
}
status = jbPort->iPortParams->ipJitterBuffer->RetrievePacket(mediaOutMsg, cmdPacket);
}
if (PVMFErrNotReady == status)
{
PVMF_JBNODE_LOGDATATRAFFIC_OUT((0, "PVMFJitterBufferNode::SendData from Mime[%s] JB not ready", jbPort->iPortParams->iMimeType.get_cstr()));
uint32 currentTime32 = 0;
uint32 currentTimeBase32 = 0;
bool overflowFlag = false;
ipJitterBufferMisc->GetEstimatedServerClock().GetCurrentTime32(currentTime32,
overflowFlag,
PVMF_MEDIA_CLOCK_MSEC,
currentTimeBase32);
PVMF_JBNODE_LOGDATATRAFFIC_OUT((0, "PVMFJitterBufferNode::SendData - Estimated serv clock %d", currentTime32));
currentTime32 = 0;
currentTimeBase32 = 0;
ipClientPlayBackClock->GetCurrentTime32(currentTime32,
overflowFlag,
PVMF_MEDIA_CLOCK_MSEC,
currentTimeBase32);
PVMF_JBNODE_LOGDATATRAFFIC_OUT((0, "PVMFJitterBufferNode::SendData - Client serv clock %d", currentTime32));
PVMF_JBNODE_LOGDATATRAFFIC_OUT((0, "PVMFJitterBufferNode::SendData - Occupancy is %d delayestablish %d", jbPort->iPortParams->ipJitterBuffer->getJitterBufferStats().currentOccupancy, iDelayEstablished));
portParamsPtr->iCanReceivePktFromJB = false;
jitterBuffer->NotifyCanRetrievePacket();
return PVMFErrNotReady;
}
return status;
}
bool PVMFJitterBufferNode::CheckForPortRescheduling()
{
//This method is only called from JB Node AO's Run.
//Purpose of this method is to determine whether the node
//needs scheduling based on any outstanding port activities
//Here is the scheduling criteria for different port types:
//a) PVMF_JITTER_BUFFER_PORT_TYPE_INPUT - If there are incoming
//msgs waiting in incoming msg queue then node needs scheduling,
//as long oProcessIncomingMessages is true. This boolean stays true
//as long we can register packets in JB. If JB is full this boolean
//is made false (when CheckForSpaceInJitterBuffer() returns false)
//and is once again made true in JitterBufferFreeSpaceAvailable() callback.
//We also use the input port briefly as a bidirectional port in case of
//RTSP streaming to do firewall packet exchange. So if there are outgoing
//msgs and oProcessOutgoingMessages is true then node needs scheduling.
//b) PVMF_JITTER_BUFFER_PORT_TYPE_OUTPUT - As long as:
// - there are msgs in outgoing queue
// - oProcessOutgoingMessages is true
// - and as long as there is data in JB and we are not in buffering
//then node needs scheduling.
//c) PVMF_JITTER_BUFFER_PORT_TYPE_FEEDBACK - As long as:
// - there are msgs in incoming queue and oProcessIncomingMessages is true
// - there are msgs in outgoing queue and oProcessOutgoingMessages is true
uint32 i;
for (i = 0; i < iPortVector.size(); i++)
{
PVMFJitterBufferPortParams* portContainerPtr = iPortVector[i]->iPortParams;
if (portContainerPtr == NULL)
{
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::CheckForPortRescheduling: Error - GetPortContainer failed"));
return false;
}
if (portContainerPtr->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
{
if (portContainerPtr->irPort.IncomingMsgQueueSize() > 0)
{
if (portContainerPtr->iProcessIncomingMessages)
{
/*
* Found a port that has outstanding activity and
* is not busy.
*/
return true;
}
}
if (portContainerPtr->irPort.OutgoingMsgQueueSize() > 0)
{
if (portContainerPtr->iProcessOutgoingMessages)
{
/*
* Found a port that has outstanding activity and
* is not busy.
*/
return true;
}
}
}
else if (portContainerPtr->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_OUTPUT)
{
PVMFJitterBufferPort* jbPort =
OSCL_STATIC_CAST(PVMFJitterBufferPort*, &portContainerPtr->irPort);
PVMFJitterBufferPortParams* inPortParamsPtr = jbPort->iCounterpartPortParams;
if ((portContainerPtr->irPort.OutgoingMsgQueueSize() > 0) ||
(inPortParamsPtr->iCanReceivePktFromJB))
{
if ((portContainerPtr->iProcessOutgoingMessages) && (oStopOutputPorts == false))
{
/*
* Found a port that has outstanding activity and
* is not busy.
*/
return true;
}
}
}
else if (portContainerPtr->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_FEEDBACK)
{
if (portContainerPtr->irPort.IncomingMsgQueueSize() > 0)
{
if (portContainerPtr->iProcessIncomingMessages)
{
/*
* Found a port that has outstanding activity and
* is not busy.
*/
return true;
}
}
if (portContainerPtr->irPort.OutgoingMsgQueueSize() > 0)
{
if (portContainerPtr->iProcessOutgoingMessages)
{
/*
* Found a port that has outstanding activity and
* is not busy.
*/
return true;
}
}
}
}
/*
* No port processing needed - either all port activity queues are empty
* or the ports are backed up due to flow control.
*/
return false;
}
bool PVMFJitterBufferNode::CheckForPortActivityQueues()
{
uint32 i;
for (i = 0; i < iPortVector.size(); i++)
{
PVMFJitterBufferPortParams* portContainerPtr = NULL;
if (!getPortContainer(iPortVector[i], portContainerPtr))
{
PVMF_JBNODE_LOGERROR((0, "0x%x PVMFJitterBufferNode::CheckForPortActivityQueues: Error - GetPortContainer failed", this));
return false;
}
if ((portContainerPtr->irPort.IncomingMsgQueueSize() > 0) ||
(portContainerPtr->irPort.OutgoingMsgQueueSize() > 0))
{
/*
* Found a port that still has an outstanding activity.
*/
return true;
}
}
return false;
}
/**
* A routine to tell if a flush operation is in progress.
*/
bool PVMFJitterBufferNode::FlushPending()
{
return (iCurrentCommand.size() > 0
&& iCurrentCommand.front().iCmd == PVMF_JITTER_BUFFER_NODE_FLUSH);
}
// Called by the command handler AO to process a command from
// the input queue.
// Return true if a command was processed, false if the command
// processor is busy and can't process another command now.
bool PVMFJitterBufferNode::ProcessCommand(PVMFJitterBufferNodeCommand& aCmd)
{
/*
* normally this node will not start processing one command
* until the prior one is finished. However, a hi priority
* command such as Cancel must be able to interrupt a command
* in progress.
*/
if (!iCurrentCommand.empty() && !aCmd.hipri())
return false;
switch (aCmd.iCmd)
{
case PVMF_JITTER_BUFFER_NODE_QUERYUUID:
DoQueryUuid(aCmd);
break;
case PVMF_JITTER_BUFFER_NODE_QUERYINTERFACE:
DoQueryInterface(aCmd);
break;
case PVMF_JITTER_BUFFER_NODE_REQUESTPORT:
DoRequestPort(aCmd);
break;
case PVMF_JITTER_BUFFER_NODE_RELEASEPORT:
DoReleasePort(aCmd);
break;
case PVMF_JITTER_BUFFER_NODE_INIT:
DoInit(aCmd);
break;
case PVMF_JITTER_BUFFER_NODE_PREPARE:
DoPrepare(aCmd);
break;
case PVMF_JITTER_BUFFER_NODE_START:
DoStart(aCmd);
break;
case PVMF_JITTER_BUFFER_NODE_STOP:
DoStop(aCmd);
break;
case PVMF_JITTER_BUFFER_NODE_FLUSH:
DoFlush(aCmd);
break;
case PVMF_JITTER_BUFFER_NODE_PAUSE:
DoPause(aCmd);
break;
case PVMF_JITTER_BUFFER_NODE_RESET:
DoReset(aCmd);
break;
case PVMF_JITTER_BUFFER_NODE_CANCELALLCOMMANDS:
DoCancelAllCommands(aCmd);
break;
case PVMF_JITTER_BUFFER_NODE_CANCELCOMMAND:
DoCancelCommand(aCmd);
break;
default:
{
/* unknown command type */
CommandComplete(iInputCommands, aCmd, PVMFErrNotSupported);
}
break;
}
return true;
}
void
PVMFJitterBufferNode::MoveCmdToCurrentQueue(PVMFJitterBufferNodeCommand& aCmd)
{
int32 err;
OSCL_TRY(err, iCurrentCommand.StoreL(aCmd););
if (err != OsclErrNone)
{
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
return;
}
iInputCommands.Erase(&aCmd);
return;
}
void PVMFJitterBufferNode::CommandComplete(PVMFJitterBufferNodeCmdQ& aCmdQ,
PVMFJitterBufferNodeCommand& aCmd,
PVMFStatus aStatus,
OsclAny* aEventData,
PVUuid* aEventUUID,
int32* aEventCode)
{
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:CommandComplete Id %d Cmd %d Status %d Context %d Data %d"
, aCmd.iId, aCmd.iCmd, aStatus, aCmd.iContext, aEventData));
PVInterface* extif = NULL;
PVMFBasicErrorInfoMessage* errormsg = NULL;
if (aEventUUID && aEventCode)
{
PVMF_JITTER_BUFFER_NEW(NULL, PVMFBasicErrorInfoMessage, (*aEventCode, *aEventUUID, NULL), errormsg);
extif = OSCL_STATIC_CAST(PVInterface*, errormsg);
}
/* create response */
PVMFCmdResp resp(aCmd.iId, aCmd.iContext, aStatus, extif, aEventData);
PVMFSessionId session = aCmd.iSession;
/* Erase the command from the queue */
aCmdQ.Erase(&aCmd);
/* Report completion to the session observer */
ReportCmdCompleteEvent(session, resp);
if (errormsg)
{
errormsg->removeRef();
}
/*
* Transition to error state in case of select errors only, viz.
* PVMFFailure, PVMFErrNoMemory, PVMFErrNoResources
* Any other status implies that the node is probably in a recoverable
* state
*/
if ((aStatus == PVMFFailure) ||
(aStatus == PVMFErrNoMemory) ||
(aStatus == PVMFErrNoResources))
{
SetState(EPVMFNodeError);
}
}
void PVMFJitterBufferNode::CommandComplete(PVMFJitterBufferNodeCommand& aCmd,
PVMFStatus aStatus,
OsclAny* aEventData,
PVUuid* aEventUUID,
int32* aEventCode)
{
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:CommandComplete Id %d Cmd %d Status %d Context %d Data %d"
, aCmd.iId, aCmd.iCmd, aStatus, aCmd.iContext, aEventData));
PVInterface* extif = NULL;
PVMFBasicErrorInfoMessage* errormsg = NULL;
if (aEventUUID && aEventCode)
{
PVMF_JITTER_BUFFER_NEW(NULL, PVMFBasicErrorInfoMessage, (*aEventCode, *aEventUUID, NULL), errormsg);
extif = OSCL_STATIC_CAST(PVInterface*, errormsg);
}
/* create response */
PVMFCmdResp resp(aCmd.iId, aCmd.iContext, aStatus, extif, aEventData);
PVMFSessionId session = aCmd.iSession;
/* Report completion to the session observer */
ReportCmdCompleteEvent(session, resp);
if (errormsg)
{
errormsg->removeRef();
}
/*
* Transition to error state in case of select errors only, viz.
* PVMFFailure, PVMFErrNoMemory, PVMFErrNoResources
* Any other status implies that the node is probably in a recoverable
* state
*/
if ((aStatus == PVMFFailure) ||
(aStatus == PVMFErrNoMemory) ||
(aStatus == PVMFErrNoResources))
{
SetState(EPVMFNodeError);
}
}
/**
* The various command handlers call this when a INTERNAL command is complete.
* Does not report completion as it is an internal command
*/
void PVMFJitterBufferNode::InternalCommandComplete(PVMFJitterBufferNodeCmdQ& aCmdQ,
PVMFJitterBufferNodeCommand& aCmd,
PVMFStatus aStatus,
OsclAny* aEventData)
{
OSCL_UNUSED_ARG(aEventData);
PVMF_JBNODE_LOGINFO((0, "JitterBufferNode:InternalCommandComplete Id %d Cmd %d Status %d Context %d Data %d"
, aCmd.iId, aCmd.iCmd, aStatus, aCmd.iContext, aEventData));
/* Erase the command from the queue */
aCmdQ.Erase(&aCmd);
/*
* Transition to error state in case of select errors only, viz.
* PVMFFailure, PVMFErrNoMemory, PVMFErrNoResources
* Any other status implies that the node is probably in a recoverable
* state
*/
if ((aStatus == PVMFFailure) ||
(aStatus == PVMFErrNoMemory) ||
(aStatus == PVMFErrNoResources))
{
SetState(EPVMFNodeError);
}
}
///////////////////////////////////////////////////////////////////////////////
//Called by the command handler AO to do the Query UUID
///////////////////////////////////////////////////////////////////////////////
void PVMFJitterBufferNode::DoQueryUuid(PVMFJitterBufferNodeCommand& aCmd)
{
// This node supports Query UUID from any state
OSCL_String* mimetype;
Oscl_Vector<PVUuid, OsclMemAllocator> *uuidvec;
bool exactmatch;
aCmd.PVMFJitterBufferNodeCommandBase::Parse(mimetype, uuidvec, exactmatch);
// Try to match the input mimetype against any of
// the custom interfaces for this node
// Match against custom interface1...
// also match against base mimetypes for custom interface1,
// unless exactmatch is set.
if (*mimetype == PVMF_JITTERBUFFER_CUSTOMINTERFACE_MIMETYPE
|| (!exactmatch && *mimetype == PVMF_JITTERBUFFER_MIMETYPE)
|| (!exactmatch && *mimetype == PVMF_JITTERBUFFER_BASEMIMETYPE))
{
PVUuid uuid(PVMF_JITTERBUFFERNODE_EXTENSIONINTERFACE_UUID);
uuidvec->push_back(uuid);
}
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
///////////////////////////////////////////////////////////////////////////////
//Called by the command handler AO to do the Query Interface.
///////////////////////////////////////////////////////////////////////////////
void PVMFJitterBufferNode::DoQueryInterface(PVMFJitterBufferNodeCommand& aCmd)
{
//This node supports Query Interface from any state
PVUuid* uuid;
PVInterface** ptr;
aCmd.PVMFJitterBufferNodeCommandBase::Parse(uuid, ptr);
if (*uuid == PVUuid(PVMF_JITTERBUFFERNODE_EXTENSIONINTERFACE_UUID))
{
if (!ipExtensionInterface)
{
OsclMemAllocator alloc;
int32 err;
OsclAny*ptr = NULL;
OSCL_TRY(err,
ptr = alloc.ALLOCATE(sizeof(PVMFJitterBufferExtensionInterfaceImpl));
);
if (err != OsclErrNone || !ptr)
{
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::DoQueryInterface: Error - Out of memory"));
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
return;
}
ipExtensionInterface =
OSCL_PLACEMENT_NEW(ptr, PVMFJitterBufferExtensionInterfaceImpl(this));
}
if (ipExtensionInterface->queryInterface(*uuid, *ptr))
{
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
else
{
CommandComplete(iInputCommands, aCmd, PVMFErrNotSupported);
}
}
else
{
// not supported
*ptr = NULL;
CommandComplete(iInputCommands, aCmd, PVMFErrNotSupported);
}
}
///////////////////////////////////////////////////////////////////////////////
// Called by the command handler AO to do the port request
// Decides the type of requested port
// Reserve space in port vector for the new port
// Instantiate the port and push it in the port vector
// Populate portparms for tag (port type), jitterbuffer, port, iId,
//
///////////////////////////////////////////////////////////////////////////////
void PVMFJitterBufferNode::DoRequestPort(PVMFJitterBufferNodeCommand& aCmd)
{
// This node supports port request from any state
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::DoRequestPort"));
// retrieve port tag
int32 tag;
OSCL_String* mimetype;
aCmd.PVMFJitterBufferNodeCommandBase::Parse(tag, mimetype);
PVMFJitterBufferNodePortTag jitterbufferPortTag = PVMF_JITTER_BUFFER_PORT_TYPE_INPUT;
if (tag % 3)
{
if (tag % 3 == 1)
{
jitterbufferPortTag = PVMF_JITTER_BUFFER_PORT_TYPE_OUTPUT;
}
else if (tag % 3 == 2)
{
jitterbufferPortTag = PVMF_JITTER_BUFFER_PORT_TYPE_FEEDBACK;
}
}
else
{
jitterbufferPortTag = PVMF_JITTER_BUFFER_PORT_TYPE_INPUT;
}
// Input ports have tags: 0, 3, 6, ...
// Output ports have tags: 1, 4, 7, ...
// Feedback ports have tags: 2, 5, 8, ...
//set port name for datapath logging.
OSCL_StackString<20> portname;
switch (jitterbufferPortTag)
{
case PVMF_JITTER_BUFFER_PORT_TYPE_OUTPUT:
portname = "JitterBufOut";
break;
case PVMF_JITTER_BUFFER_PORT_TYPE_FEEDBACK:
//don't log this port for now...
//portname="JitterBufFeedback";
break;
case PVMF_JITTER_BUFFER_PORT_TYPE_INPUT:
//don't log this port for now...
//portname="JitterBufIn";
break;
default:
// avoid compiler warning
break;
}
// Allocate a new port
OsclAny *ptr = AllocatePort();
if (!ptr)
{
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::DoRequestPort: Error - iPortVector Out of memory"));
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
return;
}
OsclExclusivePtr<PVMFJitterBufferPort> portAutoPtr;
PVMFJitterBufferPort* port = NULL;
OsclExclusivePtr<PVMFJitterBuffer> jitterBufferAutoPtr;
// create base port with default settings
port = OSCL_PLACEMENT_NEW(ptr, PVMFJitterBufferPort(tag, *this, portname.get_str()));
portAutoPtr.set(port);
/* Add the port to the port vector. */
if (!PushPortToVect(port))
{
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
return;
}
PVMFJitterBufferPortParams* pPortParams = OSCL_NEW(PVMFJitterBufferPortParams, (*port));
pPortParams->iTag = jitterbufferPortTag;
PVMFJitterBuffer* jbPtr = NULL;
pPortParams->ipJitterBuffer = NULL;
pPortParams->iId = tag;
if (mimetype != NULL)
{
pPortParams->iMimeType = mimetype->get_str();
}
// create jitter buffer if input port
if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
{
PVMFJitterBufferConstructParams jbConstructParams(ipJitterBufferMisc->GetEstimatedServerClock(), *ipClientPlayBackClock, pPortParams->iMimeType, *ipJitterBufferMisc->GetEventNotifier(), iDelayEstablished, iJitterDelayPercent, iJitterBufferState, this, port);
jbPtr = ipJitterBufferFactory->Create(jbConstructParams);
if (jbPtr)
jbPtr->SetDurationInMilliSeconds(iJitterBufferDurationInMilliSeconds);
jitterBufferAutoPtr.set(jbPtr);
pPortParams->ipJitterBuffer = jbPtr;
if (iBroadCastSession == true)
{
jbPtr->SetBroadCastSession();
}
}
if (!PushPortParamsToQ(pPortParams))
{
PVMF_JBNODE_LOGERROR((0, "0x%x PVMFJitterBufferNode::DoRequestPort: Error - iPortParamsQueue.push_back() failed", this));
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
return;
}
// Update the iPortParams for all existing ports since adding a new Port Parameters element might
// have caused reallocation of the vector elements.
Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator it;
for (it = iPortParamsQueue.begin();
it != iPortParamsQueue.end();
it++)
{
PVMFJitterBufferPortParams* portParametersPtr = *it;
PVMFJitterBufferPort* portPtr = OSCL_REINTERPRET_CAST(PVMFJitterBufferPort*, &portParametersPtr->irPort);
portPtr->iPortParams = portParametersPtr;
// Update also the port counterpart and port counterpart parameters
PVMFPortInterface* cpPort = getPortCounterpart(portPtr);
if (cpPort != NULL)
{
portPtr->iPortCounterpart = (PVMFJitterBufferPort*)cpPort;
PVMFJitterBufferPortParams* cpPortContainerPtr = NULL;
if (getPortContainer(portPtr->iPortCounterpart, cpPortContainerPtr))
{
portPtr->iCounterpartPortParams = cpPortContainerPtr;
}
else
{
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::DoRequestPort: getPortContainer for port counterpart failed"));
CommandComplete(iInputCommands, aCmd, PVMFFailure);
return;
}
}
}
portAutoPtr.release();
jitterBufferAutoPtr.release();
/* Return the port pointer to the caller. */
CommandComplete(iInputCommands, aCmd, PVMFSuccess, (OsclAny*)port);
}
OsclAny* PVMFJitterBufferNode::AllocatePort()
{
OsclAny *ptr = NULL;
int32 err;
OSCL_TRY(err, ptr = iPortVector.Allocate(););
if (err != OsclErrNone)
{
ptr = NULL;
}
return ptr;
}
bool PVMFJitterBufferNode::PushPortToVect(PVMFJitterBufferPort*& aPort)
{
int32 err;
OSCL_TRY(err, iPortVector.AddL(aPort););
if (err != OsclErrNone)
{
return false;
}
return true;
}
bool PVMFJitterBufferNode::PushPortParamsToQ(PVMFJitterBufferPortParams*& aPortParams)
{
int32 err;
OSCL_TRY(err, iPortParamsQueue.push_back(aPortParams););
if (err != OsclErrNone)
{
return false;
}
return true;
}
/**
* Called by the command handler AO to do the port release
*/
void PVMFJitterBufferNode::DoReleasePort(PVMFJitterBufferNodeCommand& aCmd)
{
/*This node supports release port from any state*/
/* Find the port in the port vector */
ResetNodeParams();
PVMFPortInterface* p = NULL;
aCmd.PVMFJitterBufferNodeCommandBase::Parse(p);
PVMFJitterBufferPort* port = (PVMFJitterBufferPort*)p;
PVMFJitterBufferPort** portPtr = iPortVector.FindByValue(port);
if (portPtr)
{
/* delete corresponding port params */
Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator it;
for (it = iPortParamsQueue.begin();
it != iPortParamsQueue.end();
it++)
{
PVMFJitterBufferPortParams* pPortParams = *it;
if (&pPortParams->irPort == iPortVector.front())
{
if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
{
ipJitterBufferFactory->Destroy(pPortParams->ipJitterBuffer);
}
iPortParamsQueue.erase(it);
break;
}
}
/* delete the port */
iPortVector.Erase(portPtr);
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
else
{
/* port not found */
CommandComplete(iInputCommands, aCmd, PVMFErrArgument);
}
}
///////////////////////////////////////////////////////////////////////////////
// Called by the command handler AO to initialize the node
// Decides the type of requested port
// Reserve space in port vector for the new port
// Instantiate the port and push it in the port vector
// Populate portparms for tag (port type), jitterbuffer, port, iId,
//
///////////////////////////////////////////////////////////////////////////////
void PVMFJitterBufferNode::DoInit(PVMFJitterBufferNodeCommand& aCmd)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::DoInit"));
switch (iInterfaceState)
{
case EPVMFNodeIdle:
if (ipJitterBufferMisc)
{
ipJitterBufferMisc->Reset();
OSCL_DELETE(ipJitterBufferMisc);
ipJitterBufferMisc = NULL;
}
ipJitterBufferMisc = PVMFJitterBufferMisc::New(this, *ipClientPlayBackClock, iPortParamsQueue);
if (ipJitterBufferMisc)
{
ipEventNotifier = ipJitterBufferMisc->GetEventNotifier();
if (iBroadCastSession == true)
ipJitterBufferMisc->SetBroadcastSession();
}
SetState(EPVMFNodeInitialized);
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
break;
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
/**
* Called by the command handler AO to do the node Prepare
*/
void PVMFJitterBufferNode::DoPrepare(PVMFJitterBufferNodeCommand& aCmd)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::DoPrepare"));
switch (iInterfaceState)
{
case EPVMFNodeInitialized:
{
uint32 i;
for (i = 0; i < iPortVector.size(); i++)
{
PVMFJitterBufferPortParams* portContainerPtr1 = NULL;
if (getPortContainer(iPortVector[i], portContainerPtr1))
{
iPortVector[i]->iPortParams = portContainerPtr1;
}
else
{
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::DoPrepare: getPortContainer - Self"));
CommandComplete(iInputCommands, aCmd, PVMFFailure);
break;
}
PVMFPortInterface* cpPort = getPortCounterpart(iPortVector[i]);
if (cpPort != NULL)
{
iPortVector[i]->iPortCounterpart = (PVMFJitterBufferPort*)cpPort;
PVMFJitterBufferPortParams* portContainerPtr2 = NULL;
if (getPortContainer(iPortVector[i]->iPortCounterpart, portContainerPtr2))
{
iPortVector[i]->iCounterpartPortParams = portContainerPtr2;
}
else
{
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::DoPrepare: getPortContainer - Counterpart"));
CommandComplete(iInputCommands, aCmd, PVMFFailure);
break;
}
}
}
ipJitterBufferMisc->Prepare();
PVMFStatus status = ipJitterBufferMisc->PrepareMediaReceivingChannel();
if (PVMFPending == status)
{
MoveCmdToCurrentQueue(aCmd);
}
else
{
if (PVMFSuccess == status)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::DoPrepare: FW Pkts Disabled"));
/* Complete prepare */
SetState(EPVMFNodePrepared);
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
else
{
CommandComplete(iInputCommands, aCmd, status);
}
}
}
break;
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
void PVMFJitterBufferNode::CompletePrepare()
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::CompletePrepare"));
SetState(EPVMFNodePrepared);
PVMFJitterBufferNodeCommand cmd = iCurrentCommand.front();
CommandComplete(cmd, PVMFSuccess);
iCurrentCommand.Erase(&iCurrentCommand.front());
return;
}
void PVMFJitterBufferNode::CancelPrepare()
{
ipJitterBufferMisc->CancelMediaReceivingChannelPreparation();
PVMFJitterBufferNodeCommand cmd = iCurrentCommand.front();
CommandComplete(cmd, PVMFErrCancelled);
iCurrentCommand.Erase(&iCurrentCommand.front());
return;
}
/**
* Called by the command handler AO to do the node Start
*/
void PVMFJitterBufferNode::DoStart(PVMFJitterBufferNodeCommand& aCmd)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::DoStart"));
PVMFStatus status = PVMFSuccess;
switch (iInterfaceState)
{
case EPVMFNodePrepared:
case EPVMFNodePaused:
{
ipJitterBufferMisc->StreamingSessionStarted();
/* Diagnostic logging */
iDiagnosticsLogged = false;
iMediaReceiveingChannelPrepared = true;
if (iInterfaceState == EPVMFNodePaused)
{
uint32 currticks = OsclTickCount::TickCount();
uint32 startTime = OsclTickCount::TicksToMsec(currticks);
uint32 diff = (startTime - iPauseTime);
if (diff > PVMF_JITTER_BUFFER_NODE_FIREWALL_PKT_DEFAULT_PAUSE_DURATION_IN_MS)
{
if (PVMFPending == ipJitterBufferMisc->PrepareMediaReceivingChannel())
{
iMediaReceiveingChannelPrepared = false;
}
}
}
if (!ipJitterBufferMisc->IsSessionExpired())
RequestEventCallBack(JB_INCOMING_MEDIA_INACTIVITY_DURATION_EXPIRED);
/* If auto paused, implies jitter buffer is not empty */
if ((iDelayEstablished == false) ||
(iJitterBufferState == PVMF_JITTER_BUFFER_IN_TRANSITION))
{
Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
for (iter = iPortParamsQueue.begin(); iter != iPortParamsQueue.end(); iter++)
{
PVMFJitterBufferPortParams* pPortParams = *iter;
if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
{
pPortParams->ipJitterBuffer->NotifyCanRetrievePacket();
}
}
/*
* Move start to current msg queue where it would stay
* jitter buffer is full.
*/
oStartPending = true;
MoveCmdToCurrentQueue(aCmd);
ReportInfoEvent(PVMFInfoBufferingStart);
RequestEventCallBack(JB_NOTIFY_REPORT_BUFFERING_STATUS);
}
else
{
if (false == iMediaReceiveingChannelPrepared)
{
oStartPending = true;
MoveCmdToCurrentQueue(aCmd);
}
else
{
/* Just resuming from a paused state with enough data in jitter buffer */
oStartPending = false;
SetState(EPVMFNodeStarted);
/* Enable Output Ports */
StartOutputPorts();
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
}
}
break;
default:
status = PVMFErrInvalidState;
CommandComplete(iInputCommands, aCmd, status);
break;
}
return;
}
void PVMFJitterBufferNode::CompleteStart()
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::CompleteStart"));
PVMF_JBNODE_LOGDATATRAFFIC((0, "PVMFJitterBufferNode::CompleteStart"));
if (!iMediaReceiveingChannelPrepared)
return;
PVMFJitterBufferNodeCommand aCmd = iCurrentCommand.front();
if (iJitterBufferState == PVMF_JITTER_BUFFER_READY)
{
switch (iInterfaceState)
{
case EPVMFNodePrepared:
case EPVMFNodePaused:
case EPVMFNodeStarted:
{
/* transition to Started */
oStartPending = false;
SetState(EPVMFNodeStarted);
/* Enable Output Ports */
StartOutputPorts();
/* Enable remote activity monitoring */
Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator it;
for (it = iPortParamsQueue.begin(); it != iPortParamsQueue.end(); it++)
{
PVMFJitterBufferPortParams* pPortParams = *it;
if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
{
pPortParams->iMonitorForRemoteActivity = true;
}
}
CommandComplete(aCmd, PVMFSuccess);
/* Erase the command from the current queue */
iCurrentCommand.Erase(&iCurrentCommand.front());
}
break;
default:
{
SetState(EPVMFNodeError);
CommandComplete(aCmd, PVMFErrInvalidState);
/* Erase the command from the current queue */
iCurrentCommand.Erase(&iCurrentCommand.front());
}
break;
}
}
else
{
SetState(EPVMFNodeError);
CommandComplete(aCmd, PVMFErrInvalidState);
/* Erase the command from the current queue */
iCurrentCommand.Erase(&iCurrentCommand.front());
}
}
void PVMFJitterBufferNode::CancelStart()
{
if (ipJitterBufferMisc)
ipJitterBufferMisc->Reset();
PVMFJitterBufferNodeCommand aCmd = iCurrentCommand.front();
oStartPending = false;
CommandComplete(aCmd, PVMFErrCancelled);
/* Erase the command from the current queue */
iCurrentCommand.Erase(&iCurrentCommand.front());
return;
}
void PVMFJitterBufferNode::DoStop(PVMFJitterBufferNodeCommand& aCmd)
{
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::DoStop"));
LogSessionDiagnostics();
PVMFStatus aStatus = PVMFSuccess;
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
{
if (ipJitterBufferMisc)
ipJitterBufferMisc->StreamingSessionStopped();
/* Clear queued messages in ports */
for (uint32 i = 0; i < iPortVector.size(); i++)
{
PVMFJitterBufferPortParams* pPortParams = NULL;
bool bRet = getPortContainer(iPortVector[i], pPortParams);
if (bRet)
{
if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
{
pPortParams->ipJitterBuffer->ResetJitterBuffer();
}
pPortParams->ResetParams();
}
iPortVector[i]->ClearMsgQueues();
}
if (aStatus == PVMFSuccess)
{
/* Reset State Variables */
iDelayEstablished = false;
if (ipJitterBufferMisc)
ipJitterBufferMisc->SetSessionDurationExpired();
oStopOutputPorts = true;
oStartPending = false;
iJitterBufferState = PVMF_JITTER_BUFFER_READY;
iJitterDelayPercent = 0;
/* transition to Prepared state */
SetState(EPVMFNodePrepared);
}
CommandComplete(iInputCommands, aCmd, aStatus);
}
break;
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
/**
* Called by the command handler AO to do the node Flush
*/
void PVMFJitterBufferNode::DoFlush(PVMFJitterBufferNodeCommand& aCmd)
{
OSCL_UNUSED_ARG(aCmd);
}
/**
* Called by the command handler AO to do the node Pause
*/
void PVMFJitterBufferNode::DoPause(PVMFJitterBufferNodeCommand& aCmd)
{
iPauseTime = 0;
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
{
uint32 currticks = OsclTickCount::TickCount();
iPauseTime = OsclTickCount::TicksToMsec(currticks);
ipJitterBufferMisc->StreamingSessionPaused();
SetState(EPVMFNodePaused);
StopOutputPorts();
CancelEventCallBack(JB_INCOMING_MEDIA_INACTIVITY_DURATION_EXPIRED);
CancelEventCallBack(JB_NOTIFY_REPORT_BUFFERING_STATUS);
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::DoPause Success"));
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
break;
default:
PVMF_JBNODE_LOGERROR((0, "PVMFJitterBufferNode::DoPause PVMFErrInvalidState iInterfaceState %d", iInterfaceState));
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
/**
* Called by the command handler AO to do the node Reset.
*/
void PVMFJitterBufferNode::DoReset(PVMFJitterBufferNodeCommand& aCmd)
{
PVMF_JBNODE_LOGERROR((0, "JitterBufferNode:DoReset %d", iInterfaceState));
LogSessionDiagnostics();
ResetNodeParams();
SetState(EPVMFNodeIdle);
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
/**
* Called by the command handler AO to do the Cancel single command
*/
void PVMFJitterBufferNode::DoCancelCommand(PVMFJitterBufferNodeCommand& aCmd)
{
/* extract the command ID from the parameters.*/
PVMFCommandId id;
aCmd.PVMFJitterBufferNodeCommandBase::Parse(id);
/* first check "current" command if any */
{
PVMFJitterBufferNodeCommand* cmd = iCurrentCommand.FindById(id);
if (cmd)
{
/* cancel the queued command */
CommandComplete(iCurrentCommand, *cmd, PVMFErrCancelled);
/* report cancel success */
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
return;
}
}
/* next check input queue */
{
/* start at element 1 since this cancel command is element 0 */
PVMFJitterBufferNodeCommand* cmd = iInputCommands.FindById(id, 1);
if (cmd)
{
/* cancel the queued command */
CommandComplete(iInputCommands, *cmd, PVMFErrCancelled);
/* report cancel success */
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
return;
}
}
/* if we get here the command isn't queued so the cancel fails */
CommandComplete(iInputCommands, aCmd, PVMFErrArgument);
}
/**
* Called by the command handler AO to do the Cancel All
*/
void PVMFJitterBufferNode::DoCancelAllCommands(PVMFJitterBufferNodeCommand& aCmd)
{
/* first cancel the current command if any */
if (!iCurrentCommand.empty())
{
if (iCurrentCommand.front().iCmd == PVMF_JITTER_BUFFER_NODE_PREPARE)
{
CancelPrepare();
}
else if (iCurrentCommand.front().iCmd == PVMF_JITTER_BUFFER_NODE_START)
{
CancelStart();
}
else
{
OSCL_ASSERT(false);
}
}
/* next cancel all queued commands */
{
/* start at element 1 since this cancel command is element 0. */
while (iInputCommands.size() > 1)
CommandComplete(iInputCommands, iInputCommands[1], PVMFErrCancelled);
}
uint32 i;
for (i = 0; i < iPortVector.size(); i++)
{
PVMFJitterBufferPortParams* pPortParams = NULL;
bool bRet = getPortContainer(iPortVector[i], pPortParams);
if (bRet)
{
if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
{
pPortParams->ipJitterBuffer->ResetJitterBuffer();
}
pPortParams->ResetParams();
}
iPortVector[i]->ClearMsgQueues();
}
/* finally, report cancel complete.*/
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
PVMFPortInterface*
PVMFJitterBufferNode::getPortCounterpart(PVMFPortInterface* aPort)
{
uint32 ii;
/*
* Get port params
*/
for (ii = 0; ii < iPortParamsQueue.size(); ii++)
{
if (&iPortParamsQueue[ii]->irPort == aPort)
{
break;
}
}
if (ii >= iPortParamsQueue.size())
{
return NULL;
}
PVMFJitterBufferNodePortTag tag = iPortParamsQueue[ii]->iTag;
int32 id = iPortParamsQueue[ii]->iId;
uint32 jj;
/* Even numbered ports are input ports */
if (tag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
{
for (jj = 0; jj < iPortParamsQueue.size(); jj++)
{
if ((id + 1) == iPortParamsQueue[jj]->iId)
{
return (&iPortParamsQueue[jj]->irPort);
}
}
}
/* odd numbered ports are output ports */
else if (tag == PVMF_JITTER_BUFFER_PORT_TYPE_OUTPUT)
{
for (jj = 0; jj < iPortParamsQueue.size(); jj++)
{
if ((id - 1) == iPortParamsQueue[jj]->iId)
{
return (&iPortParamsQueue[jj]->irPort);
}
}
}
return NULL;
}
///////////////////////////////////////////////////////////////////////////////
//Jitter Buffer Extension Interface Implementation
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//OsclActiveObject
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//PVMFJitterBufferObserver Implementation
///////////////////////////////////////////////////////////////////////////////
void PVMFJitterBufferNode::JitterBufferFreeSpaceAvailable(OsclAny* aContext)
{
PVMFPortInterface* port = OSCL_STATIC_CAST(PVMFPortInterface*, aContext);
PVMFJitterBufferPort* jbPort = OSCL_STATIC_CAST(PVMFJitterBufferPort*, port);
PVMFJitterBufferPortParams* portParams = jbPort->iPortParams;
if (portParams)
portParams->iProcessIncomingMessages = true;
if (IsAdded())
{
RunIfNotReady();
}
}
void PVMFJitterBufferNode::ProcessJBInfoEvent(PVMFAsyncEvent& aEvent)
{
PVMF_JBNODE_LOGCLOCK_REBUFF((0, "PVMFJitterBufferNode::ProcessJBInfoEvent: Event Type [%d]", aEvent.GetEventType()));
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferNode::ProcessJBInfoEvent Event: Type [%d]", aEvent.GetEventType()));
switch (aEvent.GetEventType())
{
case PVMFInfoUnderflow:
{
RequestEventCallBack(JB_NOTIFY_REPORT_BUFFERING_STATUS);
if (oStartPending == false)
{
UpdateRebufferingStats(PVMFInfoUnderflow);