blob: 33f106eec3fdbde0f14e89de74de0e4b5186cda5 [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 2008 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_JITTER_BUFFER_H_INCLUDED
#define PVMF_JITTER_BUFFER_H_INCLUDED
#ifndef OSCL_BASE_H_INCLUDED
#include "oscl_base.h"
#endif
#ifndef OSCL_VECTOR_H_INCLUDED
#include "oscl_vector.h"
#endif
#ifndef OSCL_STRING_CONTAINERS_H_INCLUDED
#include "oscl_string_containers.h"
#endif
#ifndef OSCL_MEM_MEMPOOL_H_INCLUDED
#include "oscl_mem_mempool.h"
#endif
#ifndef PVLOGGER_H_INCLUDED
#include "pvlogger.h"
#endif
#ifndef PVMF_TIMESTAMP_H_INCLUDED
#include "pvmf_timestamp.h"
#endif
#ifndef PVMF_MEDIA_DATA_H_INCLUDED
#include "pvmf_media_data.h"
#endif
#ifndef PVMF_MEDIA_FRAG_GROUP_H_INCLUDED
#include "pvmf_media_frag_group.h"
#endif
#ifndef PVMF_JITTER_BUFFER_EXT_INTERFACE_H_INCLUDED
#include "pvmf_jitter_buffer_ext_interface.h"
#endif
#ifndef PVMF_JITTER_BUFFER_INTERNAL_H_INCLUDED
#include "pvmf_jitter_buffer_internal.h"
#endif
#ifndef PVMF_SM_TUNABLES_H_INCLUDED
#include "pvmf_sm_tunables.h"
#endif
#ifndef __MEDIA_CLOCK_CONVERTER_H
#include "media_clock_converter.h"
#endif
#ifndef PVMF_MEDIA_MSG_FORMAT_IDS_H_INCLUDED
#include "pvmf_media_msg_format_ids.h"
#endif
#ifndef PVMF_SM_CONFIG_H_INCLUDED
#include "pvmf_sm_config.h"
#endif
#define PVMF_JITTER_BUFFER_ROLL_OVER_THRESHOLD_16BIT 2000
#define PVMF_JITTER_BUFFER_ROLL_OVER_THRESHOLD_32BIT 20000
/* RTP HEADER CONSTANTS */
#define SUPPORTED_RTP_HEADER_VERSION 2
#define RTP_FIXED_HEADER_SIZE 12
#define RTP_HEADER_V_BIT_MASK 0xC0
#define RTP_HEADER_V_BIT_OFFSET 6
#define RTP_HEADER_P_BIT_MASK 0x20
#define RTP_HEADER_P_BIT_OFFSET 5
#define RTP_HEADER_X_BIT_MASK 0x10
#define RTP_HEADER_X_BIT_OFFSET 4
#define RTP_HEADER_CC_BIT_MASK 0x0F
#define RTP_HEADER_M_BIT_MASK 0x80
#define RTP_HEADER_M_BIT_OFFSET 7
#define RTP_HEADER_PT_MASK 0x7F
/* ASF HEADER CONSTANTS */
#define ASF_DATA_PACKET_HEADER_ERROR_CORRECTION_PRESENT_MASK 0x80
#define ASF_DATA_PACKET_HEADER_ERROR_CORRECTION_DATA_LENGTH_MASK 0x07
#define ASF_DATA_PACKET_HEADER_SEQUENCE_LENGTH_TYPE_OFFSET 1
#define ASF_DATA_PACKET_HEADER_SEQUENCE_LENGTH_TYPE_MASK 0x06
#define ASF_DATA_PACKET_HEADER_PADDING_LENGTH_TYPE_OFFSET 3
#define ASF_DATA_PACKET_HEADER_PADDING_LENGTH_TYPE_MASK 0x18
#define ASF_DATA_PACKET_HEADER_PACKET_LENGTH_TYPE_OFFSET 5
#define ASF_DATA_PACKET_HEADER_PACKET_LENGTH_TYPE_MASK 0x60
/*
* 1 - Error correction flags
* 7 (worstcase) - Error correction data length
* 1 - Length Type;
* 1 - Property Flags;
* 4 each(worst case) - PacketLength, Sequence, PaddingLength
* 4 - Send Time
* 2 - Duration
*/
#define MAX_ASF_DATA_PACKET_HEADER_SIZE_IN_BYTES 28
#define PVMF_JITTER_BUFFER_BUFFERING_STATUS_TIMER_ID 1
enum PVMFJitterBufferDataState
{
PVMF_JITTER_BUFFER_STATE_UNKNOWN,
PVMF_JITTER_BUFFER_READY,
PVMF_JITTER_BUFFER_IN_TRANSITION
};
enum PVMFJitterBufferTransportHeaderFormat
{
PVMF_JITTER_BUFFER_TRANSPORT_HEADER_FORMAT_UNKNOWN,
PVMF_JITTER_BUFFER_TRANSPORT_HEADER_RTP,
PVMF_JITTER_BUFFER_TRANSPORT_HEADER_ASF
};
typedef enum
{
PVMF_JITTER_BUFFER_ADD_ELEM_ERROR,
PVMF_JITTER_BUFFER_ADD_ELEM_SUCCESS,
PVMF_JITTER_BUFFER_ADD_ELEM_UNEXPECTED_DATA
} PVMFJitterBufferAddElemStatus;
typedef struct tagPVMFJitterBufferStats
{
uint32 ssrc;
uint32 totalNumPacketsReceived;
uint32 totalNumPacketsRegistered;
uint32 totalNumPacketsRetrieved;
uint32 maxSeqNumReceived;
uint32 maxSeqNumRegistered;
uint32 totalPacketsLost;
uint32 seqNumBase;
uint32 currentOccupancy;
PVMFTimestamp maxTimeStampRegistered;
PVMFTimestamp maxTimeStampRetrieved;
PVMFTimestamp maxTimeStampRetrievedWithoutRTPOffset;
uint32 maxOccupancy;
uint32 lastRegisteredSeqNum;
uint32 lastRetrievedSeqNum;
uint32 totalNumBytesRecvd;
uint32 packetSizeInBytesLeftInBuffer;
} PVMFJitterBufferStats;
typedef struct tagPVMFRTPInfoParams
{
tagPVMFRTPInfoParams()
{
seqNumBaseSet = false;
seqNum = 0;
rtpTimeBaseSet = false;
rtpTime = 0;
nptTimeInMS = 0;
rtpTimeScale = 0;
nptTimeInRTPTimeScale = 0;
};
bool seqNumBaseSet;
uint32 seqNum;
bool rtpTimeBaseSet;
uint32 rtpTime;
uint32 nptTimeInMS;
uint32 rtpTimeScale;
uint32 nptTimeInRTPTimeScale;
} PVMFRTPInfoParams;
class MediaCommandMsgHolder
{
public:
MediaCommandMsgHolder()
{
iPreceedingMediaMsgSeqNumber = 0xFFFFFFFF;
};
MediaCommandMsgHolder(const MediaCommandMsgHolder& a)
{
iPreceedingMediaMsgSeqNumber = a.iPreceedingMediaMsgSeqNumber;
iCmdMsg = a.iCmdMsg ;
}
MediaCommandMsgHolder& operator=(const MediaCommandMsgHolder& a)
{
if (&a != this)
{
iPreceedingMediaMsgSeqNumber = a.iPreceedingMediaMsgSeqNumber;
iCmdMsg = a.iCmdMsg ;
}
return (*this);
}
uint32 iPreceedingMediaMsgSeqNumber;
PVMFSharedMediaMsgPtr iCmdMsg;
};
template<class Alloc>
class PVMFDynamicCircularArray
{
public:
PVMFDynamicCircularArray(const PvmfMimeString* aMimeType = NULL)
{
numElems = 0;
arraySize = 0;
maxSeqNumAdded = 0;
lastRetrievedSeqNum = 0;
lastRetrievedTS = 0;
readOffset = 0;
firstSeqNumAdded = 0;
sJitterBufferParams.ssrc = 0;
sJitterBufferParams.totalNumPacketsReceived = 0;
sJitterBufferParams.totalNumPacketsRegistered = 0;
sJitterBufferParams.totalNumPacketsRetrieved = 0;
sJitterBufferParams.maxSeqNumReceived = 0;
sJitterBufferParams.maxSeqNumRegistered = 0;
sJitterBufferParams.totalPacketsLost = 0;
sJitterBufferParams.seqNumBase = 0;
sJitterBufferParams.currentOccupancy = 0;
sJitterBufferParams.maxTimeStampRegistered = 0;
sJitterBufferParams.maxTimeStampRetrieved = 0;
sJitterBufferParams.maxTimeStampRetrievedWithoutRTPOffset = 0;
sJitterBufferParams.lastRegisteredSeqNum = 0;
sJitterBufferParams.lastRetrievedSeqNum = lastRetrievedSeqNum;
sJitterBufferParams.maxOccupancy = arraySize;
sJitterBufferParams.totalNumBytesRecvd = 0;
sJitterBufferParams.packetSizeInBytesLeftInBuffer = 0;
iLogger = PVLogger::GetLoggerObject("PVMFDynamicCircularArray");
iDataPathLoggerIn = PVLogger::GetLoggerObject("datapath.sourcenode.jitterbuffer.in");
iDataPathLoggerOut = PVLogger::GetLoggerObject("datapath.sourcenode.jitterbuffer.out");
if (aMimeType != NULL)
{
iMimeType = aMimeType->get_cstr();
}
iHeaderFormat = PVMF_JITTER_BUFFER_TRANSPORT_HEADER_FORMAT_UNKNOWN;
iBroadCastSession = false;
}
PVMFDynamicCircularArray(uint32 n,
const PvmfMimeString* aMimeType = NULL)
{
numElems = 0;
arraySize = n;
iMediaPtrVec.reserve(arraySize);
InitVector(arraySize);
maxSeqNumAdded = 0;
lastRetrievedSeqNum = 0;
lastRetrievedTS = 0;
readOffset = 0;
firstSeqNumAdded = 0;
sJitterBufferParams.ssrc = 0;
sJitterBufferParams.totalNumPacketsReceived = 0;
sJitterBufferParams.totalNumPacketsRegistered = 0;
sJitterBufferParams.totalNumPacketsRetrieved = 0;
sJitterBufferParams.maxSeqNumReceived = 0;
sJitterBufferParams.maxSeqNumRegistered = 0;
sJitterBufferParams.totalPacketsLost = 0;
sJitterBufferParams.seqNumBase = 0;
sJitterBufferParams.currentOccupancy = 0;
sJitterBufferParams.maxTimeStampRegistered = 0;
sJitterBufferParams.maxTimeStampRetrieved = 0;
sJitterBufferParams.maxTimeStampRetrievedWithoutRTPOffset = 0;
sJitterBufferParams.lastRegisteredSeqNum = 0;
sJitterBufferParams.lastRetrievedSeqNum = lastRetrievedSeqNum;
sJitterBufferParams.maxOccupancy = arraySize;
sJitterBufferParams.totalNumBytesRecvd = 0;
sJitterBufferParams.packetSizeInBytesLeftInBuffer = 0;
iLogger = PVLogger::GetLoggerObject("PVMFDynamicCircularArray");
iDataPathLoggerIn = PVLogger::GetLoggerObject("datapath.sourcenode.jitterbuffer.in");
iDataPathLoggerOut = PVLogger::GetLoggerObject("datapath.sourcenode.jitterbuffer.out");
if (aMimeType != NULL)
{
iMimeType = aMimeType->get_cstr();
}
iHeaderFormat = PVMF_JITTER_BUFFER_TRANSPORT_HEADER_FORMAT_UNKNOWN;
iBroadCastSession = false;
}
virtual ~PVMFDynamicCircularArray()
{
if (!iMediaPtrVec.empty())
{
typedef typename Oscl_Vector<PVMFSharedMediaDataPtr, Alloc>::iterator iterator_type;
iterator_type it;
for (it = iMediaPtrVec.begin(); it != iMediaPtrVec.end(); it++)
{
if (it->GetRep() != NULL)
{
it->Unbind();
}
}
}
}
void Clear()
{
typedef typename Oscl_Vector<PVMFSharedMediaDataPtr, Alloc>::iterator iterator_type;
iterator_type it;
for (it = iMediaPtrVec.begin(); it != iMediaPtrVec.end(); it++)
{
if (it->GetRep() != NULL)
{
it->Unbind();
}
}
numElems = 0;
iMediaPtrVec.clear();
InitVector(arraySize);
maxSeqNumAdded = 0;
lastRetrievedSeqNum = 0;
lastRetrievedTS = 0;
readOffset = 0;
firstSeqNumAdded = 0;
sJitterBufferParams.currentOccupancy = 0;
}
void ResetJitterBufferStats()
{
sJitterBufferParams.ssrc = 0;
sJitterBufferParams.totalNumPacketsReceived = 0;
sJitterBufferParams.totalNumPacketsRegistered = 0;
sJitterBufferParams.totalNumPacketsRetrieved = 0;
sJitterBufferParams.maxSeqNumReceived = 0;
sJitterBufferParams.maxSeqNumRegistered = 0;
sJitterBufferParams.totalPacketsLost = 0;
sJitterBufferParams.seqNumBase = 0;
sJitterBufferParams.currentOccupancy = 0;
sJitterBufferParams.maxTimeStampRegistered = 0;
sJitterBufferParams.maxTimeStampRetrieved = 0;
sJitterBufferParams.maxTimeStampRetrievedWithoutRTPOffset = 0;
sJitterBufferParams.lastRetrievedSeqNum = lastRetrievedSeqNum;
sJitterBufferParams.maxOccupancy = arraySize;
sJitterBufferParams.totalNumBytesRecvd = 0;
sJitterBufferParams.lastRegisteredSeqNum = 0;
sJitterBufferParams.totalNumBytesRecvd = 0;
sJitterBufferParams.packetSizeInBytesLeftInBuffer = 0;
}
uint32 getNumElements()
{
return numElems;
}
uint32 getArraySize()
{
return arraySize;
}
void growCircularArray(uint32 newSize)
{
if (newSize > arraySize)
{
/*
* This transfers the existing contents
* as well
*/
iMediaPtrVec.reserve(newSize);
/* Initialize the new space */
InitVector((newSize - arraySize));
arraySize = newSize;
}
}
void setFirstSeqNumAdded(uint32 aFirstSeqNumAdded)
{
firstSeqNumAdded = aFirstSeqNumAdded;
}
PVMFJitterBufferAddElemStatus addElement(PVMFSharedMediaDataPtr& elem, uint32 aSeqNumBase)
{
PVMFJitterBufferAddElemStatus oRet = PVMF_JITTER_BUFFER_ADD_ELEM_SUCCESS;
sJitterBufferParams.totalNumPacketsReceived++;
sJitterBufferParams.ssrc = elem->getStreamID();
uint32 seqNum = elem->getSeqNum();
/* Get packet size */
uint32 size = 0;
uint32 numFragments = elem->getNumFragments();
for (uint32 i = 0; i < numFragments; i++)
{
OsclRefCounterMemFrag memFragIn;
elem->getMediaFragment(i, memFragIn);
size += memFragIn.getMemFrag().len;
}
sJitterBufferParams.totalNumBytesRecvd += size;
sJitterBufferParams.packetSizeInBytesLeftInBuffer += size;
/* If it is the first packet always register it */
if (seqNum != aSeqNumBase)
{
if (elem->getTimestamp() < lastRetrievedTS)
{
if (seqNum > lastRetrievedSeqNum)
{
lastRetrievedSeqNum = seqNum;
readOffset = (seqNum - aSeqNumBase) % arraySize;
}
return PVMF_JITTER_BUFFER_ADD_ELEM_ERROR;
}
if ((iHeaderFormat == PVMF_JITTER_BUFFER_TRANSPORT_HEADER_RTP) &&
(iBroadCastSession == true))
{
/*
* This can happen when using prerecorded transport streams that loop
* If this happens, just signal an unexpected data event
*/
if (elem->getTimestamp() < sJitterBufferParams.maxTimeStampRegistered)
{
return PVMF_JITTER_BUFFER_ADD_ELEM_UNEXPECTED_DATA;
}
}
if (seqNum <= lastRetrievedSeqNum)
{
/*
* check for seqnum roll over. For RTP packets, seqnum is 16 bits
* therefore a typecast is needed before we check for rollover
*/
if (iHeaderFormat == PVMF_JITTER_BUFFER_TRANSPORT_HEADER_RTP)
{
uint16 seqNum16 = (uint16)seqNum;
uint16 lastRetrievedSeqNum16 = (uint16)(lastRetrievedSeqNum + 1);
uint16 diff16 = (seqNum16 - lastRetrievedSeqNum16);
if (diff16 > PVMF_JITTER_BUFFER_ROLL_OVER_THRESHOLD_16BIT)
{
/* too late - discard the packet */
oRet = PVMF_JITTER_BUFFER_ADD_ELEM_ERROR;
return (oRet);
}
else
{
/* Reset these variables to acct for seqnum rollover */
sJitterBufferParams.maxSeqNumRegistered = seqNum;
sJitterBufferParams.maxSeqNumReceived = seqNum;
sJitterBufferParams.maxTimeStampRegistered = elem->getTimestamp();
}
}
else
{
/* Seqnum is 32 bits, no typecase needed */
if ((seqNum - lastRetrievedSeqNum) > PVMF_JITTER_BUFFER_ROLL_OVER_THRESHOLD_32BIT)
{
/* too late - discard the packet */
oRet = PVMF_JITTER_BUFFER_ADD_ELEM_ERROR;
return (oRet);
}
else
{
/* Reset these variables to acct for seqnum rollover */
sJitterBufferParams.maxSeqNumRegistered = seqNum;
sJitterBufferParams.maxSeqNumReceived = seqNum;
sJitterBufferParams.maxTimeStampRegistered = elem->getTimestamp();
}
}
}
}
if (seqNum > sJitterBufferParams.maxSeqNumRegistered)
{
sJitterBufferParams.maxSeqNumReceived = seqNum;
}
uint32 offset = (seqNum - aSeqNumBase) % arraySize;
PVMFSharedMediaDataPtr currElem = iMediaPtrVec[offset];
if (currElem.GetRep() == NULL)
{
/* Register Packet */
iMediaPtrVec[offset] = elem;
numElems++;
sJitterBufferParams.totalNumPacketsRegistered++;
sJitterBufferParams.lastRegisteredSeqNum = seqNum;
if (seqNum > sJitterBufferParams.maxSeqNumRegistered)
{
sJitterBufferParams.maxSeqNumRegistered = seqNum;
sJitterBufferParams.maxTimeStampRegistered = elem->getTimestamp();
}
sJitterBufferParams.currentOccupancy = numElems;
return (oRet);
}
else if (currElem->getSeqNum() != seqNum)
{
PVMF_JBNODE_LOGDATATRAFFIC_IN((0, "JB OW: MimeType=%s, ReadOffset=%d, NumElemsLeft=%d, lastRetrievedSeqNum=%d, old seqNum=%d, new seqNum=%d",
iMimeType.get_cstr(),
readOffset,
numElems,
lastRetrievedSeqNum,
seqNum,
currElem->getSeqNum()));
/* Overwrite existing data */
currElem.Unbind();
/* Register Packet */
iMediaPtrVec[offset] = elem;
sJitterBufferParams.totalNumPacketsRegistered++;
sJitterBufferParams.lastRegisteredSeqNum = seqNum;
if (seqNum > sJitterBufferParams.maxSeqNumRegistered)
{
sJitterBufferParams.maxSeqNumRegistered = seqNum;
sJitterBufferParams.maxTimeStampRegistered = elem->getTimestamp();
}
sJitterBufferParams.currentOccupancy = numElems;
return (oRet);
}
/* Duplicate Packet - Ignore */
return (oRet);
}
PVMFSharedMediaDataPtr retrieveElement()
{
PVMFSharedMediaDataPtr dataPkt;
uint32 count = 0;
while (dataPkt.GetRep() == NULL)
{
/* No data */
if (count > arraySize)
{
dataPkt.Unbind();
return dataPkt;
}
/* Wrap around */
if (readOffset >= arraySize)
{
readOffset = 0;
}
dataPkt = iMediaPtrVec[readOffset];
readOffset++;
count++;
}
numElems--;
/* Mark the retrieved element location as free */
PVMFSharedMediaDataPtr retElem = iMediaPtrVec[readOffset-1];
retElem.Unbind();
iMediaPtrVec[readOffset-1] = retElem;
lastRetrievedSeqNum = (int32)(dataPkt.GetRep()->getSeqNum());
/* Check and register packet loss */
sJitterBufferParams.totalPacketsLost += (count - 1);
sJitterBufferParams.maxTimeStampRetrieved = dataPkt->getTimestamp();
sJitterBufferParams.currentOccupancy = numElems;
sJitterBufferParams.totalNumPacketsRetrieved++;
sJitterBufferParams.lastRetrievedSeqNum = lastRetrievedSeqNum;
/* Get packet size */
uint32 size = 0;
uint32 numFragments = dataPkt->getNumFragments();
for (uint32 i = 0; i < numFragments; i++)
{
OsclRefCounterMemFrag memFragIn;
dataPkt->getMediaFragment(i, memFragIn);
size += memFragIn.getMemFrag().len;
}
sJitterBufferParams.packetSizeInBytesLeftInBuffer -= size;
PVMF_JBNODE_LOGINFO((0, "PVMFDynamicCircularArray::retrieveElement: MimeType=%s, ReadOffset=%d, NumElemsLeft=%d, SeqNum=%d",
iMimeType.get_cstr(),
readOffset,
numElems,
lastRetrievedSeqNum));
return (dataPkt);
}
PVMFJitterBufferStats getStats()
{
return sJitterBufferParams;
}
PVMFJitterBufferStats* getStatsPtr()
{
return &sJitterBufferParams;
}
void peekNextElementTimeStamp(PVMFTimestamp& aTS,
uint32& aSeqNum)
{
PVMFSharedMediaDataPtr dataPkt;
uint32 peekOffset = readOffset;
uint32 count = 0;
while (dataPkt.GetRep() == NULL)
{
if (count > numElems)
{
aTS = 0xFFFFFFFF;
}
if (peekOffset >= arraySize)
{
peekOffset = 0;
}
dataPkt = iMediaPtrVec[peekOffset];
peekOffset++;
count++;
}
aTS = dataPkt.GetRep()->getTimestamp();
aSeqNum = dataPkt.GetRep()->getSeqNum();
return;
}
bool CheckCurrentReadPosition()
{
uint32 offset = readOffset;
if (offset >= arraySize)
{
offset = 0;
}
PVMFSharedMediaDataPtr dataPkt =
iMediaPtrVec[offset];
if (dataPkt.GetRep() == NULL)
{
return false;
}
return true;
}
bool CheckSpaceAvailability()
{
if (numElems < arraySize)
{
return true;
}
return false;
}
void setRTPInfoParams(PVMFRTPInfoParams rtpInfo)
{
sJitterBufferParams.seqNumBase = rtpInfo.seqNum;
}
PVMFSharedMediaDataPtr getElementAt(uint32 aIndex)
{
if (aIndex > arraySize) OSCL_LEAVE(OsclErrArgument);
return (iMediaPtrVec[aIndex]);
}
void AddElementAt(PVMFSharedMediaDataPtr aMediaPtr,
uint32 aIndex)
{
if (aIndex > arraySize) OSCL_LEAVE(OsclErrArgument);
iMediaPtrVec[aIndex] = aMediaPtr;
}
void PurgeElementsWithSeqNumsLessThan(uint32 aSeqNum)
{
if (!iMediaPtrVec.empty())
{
if (aSeqNum < lastRetrievedSeqNum)
{
typedef typename Oscl_Vector<PVMFSharedMediaDataPtr, Alloc>::iterator iterator_type;
iterator_type it;
for (it = iMediaPtrVec.begin(); it != iMediaPtrVec.end(); it++)
{
if (it->GetRep() != NULL)
{
it->Unbind();
}
}
numElems = 0;
//iMediaPtrVec.clear();
}
else if (aSeqNum > lastRetrievedSeqNum)
{
/*
* Start from last retrieved seq num and offset it by
* first seq number added
* This guarantees that we deallocate in the allocation
* sequence.
*/
uint32 startoffset = ((lastRetrievedSeqNum - firstSeqNumAdded) + 1) % arraySize;
PVMF_JBNODE_LOGDATATRAFFIC_OUT((0, "PVMFDynamicCircularArray::PurgeElementsWithSeqNumsLessThan: MimeType=%s, SeqNum=%d, StartOffset=%d, ArraySize=%d",
iMimeType.get_cstr(),
aSeqNum,
startoffset,
arraySize));
for (uint32 i = 0; i < aSeqNum - (lastRetrievedSeqNum + 1); i++)
{
uint32 offset = (startoffset + i) % arraySize;
/* Mark the retrieved element location as free */
PVMFSharedMediaDataPtr elem = iMediaPtrVec[offset];
if (elem.GetRep() != NULL)
{
if (elem->getSeqNum() < aSeqNum)
{
elem.Unbind();
iMediaPtrVec[offset] = elem;
numElems--;
}
}
}
}
}
/* To prevent us from registering any old packets */
lastRetrievedSeqNum = aSeqNum - 1;
sJitterBufferParams.lastRetrievedSeqNum = lastRetrievedSeqNum;
sJitterBufferParams.currentOccupancy = numElems;
SetReadOffset(aSeqNum);
}
void PurgeElementsWithTimestampLessThan(PVMFTimestamp aTS)
{
if (!iMediaPtrVec.empty())
{
while (numElems > 0)
{
/* Wrap around */
if (readOffset >= arraySize)
{
readOffset = 0;
}
PVMFSharedMediaDataPtr dataPkt = iMediaPtrVec[readOffset];
if (dataPkt.GetRep() != NULL)
{
PVMF_JBNODE_LOGDATATRAFFIC_IN((0, "JB Purge: MimeType=%s, ReadOffset=%d, NumElemsLeft=%d, lastRetrievedSeqNum=%d, seqNum=%d",
iMimeType.get_cstr(),
readOffset,
numElems,
lastRetrievedSeqNum,
dataPkt->getSeqNum()));
PVMFTimestamp tmpTS = dataPkt.GetRep()->getTimestamp();
if (tmpTS >= aTS)
break;
(iMediaPtrVec[readOffset]).Unbind();
numElems--;
}
readOffset++;
}
}
/* To prevent us from registering any old packets */
lastRetrievedTS = aTS;
sJitterBufferParams.currentOccupancy = numElems;
}
void SetReadOffset(uint32 aSeqNum)
{
readOffset = (aSeqNum - firstSeqNumAdded) % arraySize;
}
void setPacketHeaderFormat(PVMFJitterBufferTransportHeaderFormat aHeaderFormat)
{
iHeaderFormat = aHeaderFormat;
}
void SetBroadCastSession()
{
iBroadCastSession = true;
}
private:
Oscl_Vector<PVMFSharedMediaDataPtr, Alloc> iMediaPtrVec;
uint32 numElems;
uint32 arraySize;
uint32 readOffset;
bool iBroadCastSession;
void InitVector(uint32 size)
{
for (uint32 i = 0; i < size; i++)
{
PVMFSharedMediaDataPtr sharedMediaPtr;
iMediaPtrVec.push_back(sharedMediaPtr);
}
}
uint32 lastRetrievedSeqNum;
PVMFTimestamp lastRetrievedTS;
uint32 maxSeqNumAdded;
uint32 firstSeqNumAdded;
/* buffer statistics related params */
PVMFJitterBufferStats sJitterBufferParams;
PVLogger* iLogger;
PVLogger *iDataPathLoggerIn;
PVLogger *iDataPathLoggerOut;
OSCL_HeapString<PVMFJitterBufferNodeAllocator> iMimeType;
PVMFJitterBufferTransportHeaderFormat iHeaderFormat;
};
typedef enum
{
PVMF_JITTER_BUFFER_ADD_PKT_ERROR,
PVMF_JITTER_BUFFER_ADD_PKT_SUCCESS,
PVMF_JITTER_BUFFER_ADD_PKT_UNEXPECTED_DATA,
PVMF_JITTER_BUFFER_ADD_PKT_EOS_REACHED
} PVMFJitterBufferAddPktStatus;
class PVMFJitterBufferObserver
{
public:
virtual ~PVMFJitterBufferObserver() {}
virtual void JitterBufferFreeSpaceAvailable(OsclAny* aContext) = 0;
virtual void EstimatedServerClockUpdated(OsclAny* aContext) = 0;
};
class PVMFJitterBuffer
{
public:
virtual ~PVMFJitterBuffer() {}
virtual void SetEstimatedServerClock(OsclClock* aEstServClock) = 0;
virtual bool ParsePacketHeader(PVMFSharedMediaDataPtr& inDataPacket,
PVMFSharedMediaDataPtr& outDataPacket,
uint32 aFragIndex = 0) = 0;
virtual PVMFJitterBufferAddPktStatus addPacket(PVMFSharedMediaDataPtr& dataPacket) = 0;
virtual PVMFSharedMediaDataPtr retrievePacket() = 0;
virtual PVMFJitterBufferStats getJitterBufferStats() = 0;
virtual void FlushJitterBuffer() = 0;
virtual void ResetJitterBuffer() = 0;
virtual void setSSRC(uint32 aSSRC) = 0;
virtual void setRTPInfoParams(PVMFRTPInfoParams rtpInfoParams) = 0;
virtual bool CheckSpaceAvailability() = 0;
virtual bool CheckForMemoryAvailability() = 0;
virtual bool CheckCurrentReadPosition() = 0;
virtual PVMFTimestamp peekNextElementTimeStamp() = 0;
virtual bool IsEmpty() = 0;
virtual void SetEOS(bool aVal) = 0;
virtual bool GetEOS() = 0;
virtual uint32 getInterArrivalJitter() = 0;
virtual void setPlayRange(int32 aStartTimeInMS, int32 aStopTimeInMS) = 0;
virtual bool CheckForHighWaterMark() = 0;
virtual bool CheckForLowWaterMark() = 0;
virtual bool CheckNumElements() = 0;
virtual void PurgeElementsWithSeqNumsLessThan(uint32 aSeqNum, uint32 aPlayerClockMS) = 0;
virtual void PurgeElementsWithTimestampLessThan(PVMFTimestamp aTS) = 0;
virtual bool NotifyFreeSpaceAvailable(PVMFJitterBufferObserver* aObserver,
OsclAny* aContext) = 0;
virtual bool NotifyServerClockUpdates(PVMFJitterBufferObserver* aObserver,
OsclAny* aContext) = 0;
virtual bool CancelServerClockNotificationUpdates() = 0;
virtual void SetInPlaceProcessingMode(bool aInPlaceProcessingMode) = 0;
virtual bool addMediaCommand(PVMFSharedMediaMsgPtr& aMediaCmd) = 0;
virtual bool CheckForPendingCommands(PVMFSharedMediaMsgPtr& aCmdMsg) = 0;
virtual void SetAdjustedTSInMS(PVMFTimestamp aAdjustedTS) = 0;
virtual uint32 GetRTPTimeStampOffset(void) = 0;
virtual void SetRTPTimeStampOffset(uint32 newTSBase) = 0;
virtual PVMFSharedMediaDataPtr& GetFirstDataPacket(void) = 0;
virtual void AdjustRTPTimeStamp() = 0;
virtual void SetBroadCastSession() = 0;
};
class PVMFJitterBufferImpl : public PVMFJitterBuffer,
public OsclMemPoolFixedChunkAllocatorObserver
{
public:
PVMFJitterBufferImpl(const PvmfMimeString* aMimeType = NULL,
bool aInPlaceProcessing = true);
virtual ~PVMFJitterBufferImpl();
void SetEstimatedServerClock(OsclClock* aEstServClock)
{
iEstimatedServerClock = aEstServClock;
}
PVMFJitterBufferAddPktStatus addPacket(PVMFSharedMediaDataPtr& dataPacket);
PVMFSharedMediaDataPtr retrievePacket();
PVMFJitterBufferStats getJitterBufferStats()
{
return (iJitterBuffer->getStats());
}
void FlushJitterBuffer()
{
iFirstDataPackets.clear();
iJitterBuffer->Clear();
};
void ResetJitterBuffer();
void setSSRC(uint32 aSSRC)
{
PVMF_JBNODE_LOGDATATRAFFIC_IN((0, "PVMFJitterBufferImpl::setSSRC: Setting SSRCFromSetUpResponse - MimeType=%s, SSRC=%d", iMimeType.get_cstr(), aSSRC));
oSSRCFromSetUpResponseAvailable = true;
SSRCFromSetUpResponse = aSSRC;
SSRCLock = aSSRC;
}
void setRTPInfoParams(PVMFRTPInfoParams rtpInfo)
{
iJitterBuffer->setRTPInfoParams(rtpInfo);
PVMFRTPInfoParams iRTPInfoParams;
iRTPInfoParams.seqNumBaseSet = rtpInfo.seqNumBaseSet;
if (rtpInfo.seqNumBaseSet == true)
{
iRTPInfoParams.seqNum = rtpInfo.seqNum;
}
iRTPInfoParams.rtpTimeBaseSet = rtpInfo.rtpTimeBaseSet;
if (rtpInfo.rtpTimeBaseSet == true)
{
iRTPInfoParams.rtpTime = rtpInfo.rtpTime;
}
iRTPInfoParams.nptTimeInMS = rtpInfo.nptTimeInMS;
iRTPInfoParams.rtpTimeScale = rtpInfo.rtpTimeScale;
iRTPTimeScale = rtpInfo.rtpTimeScale;
iEstServClockMediaClockConvertor.set_timescale(iRTPTimeScale);
iMediaClockConvertor.set_timescale(1000);
iMediaClockConvertor.set_clock_other_timescale(0, iRTPInfoParams.rtpTimeScale);
iMediaClockConvertor.update_clock(iRTPInfoParams.nptTimeInMS);
iRTPInfoParams.nptTimeInRTPTimeScale =
iMediaClockConvertor.get_converted_ts(iRTPInfoParams.rtpTimeScale);
/* In case this is the first rtp info set TS calc variables */
if (iRTPInfoParamsVec.size() == 0)
{
if (iRTPInfoParams.rtpTimeBaseSet)
{
iPrevTSOut = iRTPInfoParams.rtpTime;
iPrevTSIn = iRTPInfoParams.rtpTime;
iPrevAdjustedRTPTS = iRTPInfoParams.rtpTime;
}
else
{
/* Use the value from the first packet */
if (seqNumLock)
{
iPrevTSOut = seqLockTimeStamp;
iPrevTSIn = seqLockTimeStamp;
iPrevAdjustedRTPTS = seqLockTimeStamp;
}
}
if (iRTPInfoParams.seqNumBaseSet)
{
iPrevSeqNumBaseOut = iRTPInfoParams.seqNum;
iPrevSeqNumBaseIn = iRTPInfoParams.seqNum;
}
else
{
/* Use the value from the first packet */
if (seqNumLock)
{
iPrevSeqNumBaseOut = iFirstSeqNum;
iPrevSeqNumBaseIn = iFirstSeqNum;
}
}
}
if (iRTPInfoParams.rtpTimeBaseSet)
{
iPrevAdjustedRTPTS = iRTPInfoParams.rtpTime;
}
iRTPInfoParamsVec.push_back(iRTPInfoParams);
}
bool IsEmpty()
{
uint32 elems = iJitterBuffer->getNumElements();
if (elems == 0)
{
return true;
}
return false;
};
bool CheckSpaceAvailability()
{
if (iJitterBuffer)
{
return (iJitterBuffer->CheckSpaceAvailability());
}
return false;
}
bool CheckForMemoryAvailability()
{
if (iInPlaceProcessing == false)
{
if (iMediaDataGroupAlloc)
{
return (iMediaDataGroupAlloc->IsMsgAvailable());
}
return false;
}
else
{
return true;
}
};
bool CheckCurrentReadPosition()
{
return iJitterBuffer->CheckCurrentReadPosition();
};
bool CheckNumElements()
{
if (iJitterBuffer->getNumElements() > 0)
{
return true;
}
else
{
return false;
}
};
PVMFTimestamp peekNextElementTimeStamp();
void SetEOS(bool aVal)
{
oEOS = aVal;
}
bool GetEOS()
{
return (oEOS);
}
uint32 getInterArrivalJitter()
{
return iInterArrivalJitter;
}
bool ParsePacketHeader(PVMFSharedMediaDataPtr& inDataPacket,
PVMFSharedMediaDataPtr& outDataPacket,
uint32 aFragIndex = 0);
bool ParseRTPHeader(PVMFSharedMediaDataPtr& rtpPacket,
PVMFSharedMediaDataPtr& dataPacket,
uint32 aFragIndex = 0);
void setPlayRange(int32 aStartTimeInMS, int32 aStopTimeInMS)
{
iStartTimeInMS = aStartTimeInMS;
iStopTimeInMS = aStopTimeInMS;
}
bool CheckForHighWaterMark()
{
PVMFJitterBufferStats stats = iJitterBuffer->getStats();
uint32 currOccupancy = stats.currentOccupancy;
uint32 maxOccupancy = stats.maxOccupancy;
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferImpl::CheckForHighWaterMark: CurrOccupancy = %d", currOccupancy));
if (currOccupancy >=
maxOccupancy*DEFAULT_JITTER_BUFFER_HIGH_WATER_MARK)
{
return true;
}
return false;
}
bool CheckForLowWaterMark()
{
PVMFJitterBufferStats stats = iJitterBuffer->getStats();
uint32 currOccupancy = stats.currentOccupancy;
uint32 maxOccupancy = stats.maxOccupancy;
PVMF_JBNODE_LOGINFO((0, "PVMFJitterBufferImpl::CheckForLowWaterMark: CurrOccupancy = %d", currOccupancy));
if (currOccupancy <=
maxOccupancy*DEFAULT_JITTER_BUFFER_LOW_WATER_MARK)
{
return true;
}
return false;
}
void PurgeElementsWithSeqNumsLessThan(uint32 aSeqNum, uint32 aPlayerClockMS);
void PurgeElementsWithTimestampLessThan(PVMFTimestamp aTS);
bool NotifyServerClockUpdates(PVMFJitterBufferObserver* aObserver,
OsclAny* aContext)
{
iServerClockUpdateNotificationObserver = aObserver;
iServerClockUpdateNotificationObserverContext = aContext;
return true;
}
bool CancelServerClockNotificationUpdates()
{
iServerClockUpdateNotificationObserver = NULL;
iServerClockUpdateNotificationObserverContext = NULL;
return true;
}
bool NotifyFreeSpaceAvailable(PVMFJitterBufferObserver* aObserver,
OsclAny* aContext)
{
iObserver = aObserver;
iObserverContext = aContext;
if (iMediaDataGroupAlloc)
{
iMediaDataGroupAlloc->notifyfreechunkavailable(*this);
return true;
}
return false;
}
void freechunkavailable(OsclAny*)
{
if (iObserver)
{
iObserver->JitterBufferFreeSpaceAvailable(iObserverContext);
}
}
void SetInPlaceProcessingMode(bool aInPlaceProcessingMode);
bool addMediaCommand(PVMFSharedMediaMsgPtr& aMediaCmd)
{
PVMFJitterBufferStats stats = getJitterBufferStats();
MediaCommandMsgHolder cmdHolder;
cmdHolder.iPreceedingMediaMsgSeqNumber = stats.lastRegisteredSeqNum;
cmdHolder.iCmdMsg = aMediaCmd;
iMediaCmdVec.push_back(cmdHolder);
return true;
}
bool CheckForPendingCommands(PVMFSharedMediaMsgPtr& aCmdMsg)
{
/*
* Parse the command queue to see if it is time to send out
* any pending ones. if last retrieved seq num is same as
* the seq num of media msg that preceeds this cmd, then
* it is time to send this cmd out
*/
PVMFJitterBufferStats stats = getJitterBufferStats();
Oscl_Vector<MediaCommandMsgHolder, OsclMemAllocator>::iterator it;
for (it = iMediaCmdVec.begin(); it != iMediaCmdVec.end(); it++)
{
if (it->iCmdMsg->getFormatID() == PVMF_MEDIA_CMD_BOS_FORMAT_ID)
{
aCmdMsg = it->iCmdMsg;
iMediaCmdVec.erase(it);
return true;
}
if (it->iPreceedingMediaMsgSeqNumber == stats.lastRetrievedSeqNum)
{
aCmdMsg = it->iCmdMsg;
iMediaCmdVec.erase(it);
return true;
}
}
return false;
}
void SetAdjustedTSInMS(PVMFTimestamp aAdjustedTSInMS)
{
// convert adjustedTS to RTP Timescale
uint32 in_wrap_count = 0;
MediaClockConverter clockConvertor;
clockConvertor.set_timescale(1000);
clockConvertor.set_clock(aAdjustedTSInMS, in_wrap_count);
uint32 adjustedTSInRTPTS = clockConvertor.get_converted_ts(iRTPTimeScale);
iMonotonicTimeStamp = adjustedTSInRTPTS;
PVMF_JBNODE_LOGDATATRAFFIC_OUT((0, "PVMFJitterBufferImpl::SetAdjustedTS(): adjustedTSInRTPTS=%d, iMonotonicTS=%d", adjustedTSInRTPTS, Oscl_Int64_Utils::get_uint64_lower32(iMonotonicTimeStamp)));
}
uint32 GetRTPTimeStampOffset(void)
{
return seqLockTimeStamp;
}
void SetRTPTimeStampOffset(uint32 newTSBase)
{
seqLockTimeStamp = newTSBase;
iMonotonicTimeStamp = 0;
}
PVMFSharedMediaDataPtr& GetFirstDataPacket(void)
{
return firstDataPacket;
}
void AdjustRTPTimeStamp()
{
// By the time this function is called, iMonotonicTimeStamp should be already normalized
// with the corresponding values from other jitterbuffers
iMaxAdjustedRTPTS = Oscl_Int64_Utils::get_uint64_lower32(iMonotonicTimeStamp);
UpdateEstimatedServerClock(true);
}
void SetBroadCastSession()
{
iBroadCastSession = true;
if (iJitterBuffer != NULL)
{
iJitterBuffer->SetBroadCastSession();
}
}
private:
void UpdateInterArrivalJitter(PVMFTimestamp currPacketTS);
PVMFRTPInfoParams *FindRTPInfoParams(uint32 aSeqNum)
{
if (iRTPInfoParamsVec.size() == 1)
{
return (iRTPInfoParamsVec.begin());
}
PVMFRTPInfoParams* retVal = NULL;
Oscl_Vector<PVMFRTPInfoParams, PVMFJitterBufferNodeAllocator>::iterator it;
for (it = iRTPInfoParamsVec.begin();
it != iRTPInfoParamsVec.end();
it++)
{
if (it->seqNum <= aSeqNum)
{
retVal = it;
}
}
return retVal;
}
void CheckForRTPTimeAndRTPSeqNumberBase()
{
if (iRTPInfoParamsVec.size() > 0)
{
Oscl_Vector<PVMFRTPInfoParams, PVMFJitterBufferNodeAllocator>::iterator it;
it = iRTPInfoParamsVec.begin();
if (it->rtpTimeBaseSet == false)
{
/* Use the value from the first packet */
if (seqNumLock)
{
iPrevTSOut = seqLockTimeStamp;
iPrevTSIn = seqLockTimeStamp;
iPrevAdjustedRTPTS = seqLockTimeStamp;
}
}
if (it->seqNumBaseSet == false)
{
/* Use the value from the first packet */
if (seqNumLock)
{
iPrevSeqNumBaseOut = iFirstSeqNum;
iPrevSeqNumBaseIn = iFirstSeqNum;
}
}
}
}
void DeterminePrevTimeStamp(uint32);
void DeterminePrevTimeStampPeek(uint32, PVMFTimestamp&);
void ComputeMaxAdjustedRTPTS();
void UpdateEstimatedServerClock(bool oFreshStart = false);
void UpdateEstimatedServerClockDiscrete(bool oFreshStart = false);
bool oFirstPacket;
bool seqNumLock;
bool oEOS;
uint32 SSRCLock;
bool oSSRCFromSetUpResponseAvailable;
uint32 SSRCFromSetUpResponse;
uint32 iFirstSeqNum;
PVMFSharedMediaDataPtr firstDataPacket;
Oscl_Vector<PVMFSharedMediaDataPtr, PVMFJitterBufferNodeAllocator> iFirstDataPackets;
typedef PVMFDynamicCircularArray<PVMFJitterBufferNodeAllocator> PVMFDynamicCircularArrayType;
PVMFDynamicCircularArrayType* iJitterBuffer;
typedef OsclMemPoolFixedChunkAllocator PoolMemAlloc;
PVMFMediaFragGroupCombinedAlloc<PoolMemAlloc>* iMediaDataGroupAlloc;
PoolMemAlloc* iMediaDataImplMemPool;
PoolMemAlloc* iMediaMsgMemPool;
Oscl_Vector<PVMFRTPInfoParams, PVMFJitterBufferNodeAllocator> iRTPInfoParamsVec;
MediaClockConverter iMediaClockConvertor;
PVMFTimestamp seqLockTimeStamp;
PVLogger *iLogger;
PVLogger *iDataPathLoggerIn;
PVLogger *iDataPathLoggerOut;
PVLogger *iClockLogger;
OSCL_HeapString<PVMFJitterBufferNodeAllocator> iMimeType;
uint32 iPrevPacketRecvTime;
PVMFTimestamp iPrevPacketTS;
double iInterArrivalJitterD;
int32 iInterArrivalJitter;
OsclClock *iPacketArrivalClock;
OsclTimebase_Tickcount iPacketArrivalTimeBase;
int32 iStartTimeInMS;
int32 iStopTimeInMS;
uint64 iMonotonicTimeStamp;
PVMFTimestamp iPrevTSOut;
uint32 iPrevSeqNumBaseOut;
PVMFTimestamp iMaxAdjustedRTPTS;
PVMFTimestamp iPrevAdjustedRTPTS;
PVMFTimestamp iPrevTSIn;
uint32 iPrevSeqNumBaseIn;
OsclClock* iEstimatedServerClock;
OsclTimebase_Tickcount iTickCount;
uint32 iRTPTimeScale;
MediaClockConverter iEstServClockMediaClockConvertor;
PVMFJitterBufferObserver* iObserver;
OsclAny* iObserverContext;
bool iInPlaceProcessing;
PVMFJitterBufferTransportHeaderFormat iHeaderFormat;
/* ASF Related */
uint32 iSeqNum;
bool iFirstASFPacketAfterRepos;
/* Media Command related */
Oscl_Vector<MediaCommandMsgHolder, OsclMemAllocator> iMediaCmdVec;
PVMFJitterBufferObserver* iServerClockUpdateNotificationObserver;
OsclAny* iServerClockUpdateNotificationObserverContext;
bool iBroadCastSession;
};
#endif