git-svn-id: http://webrtc.googlecode.com/svn/trunk@74 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
mikhal@google.com
2011-06-14 17:54:20 +00:00
parent 0c08ed1ef9
commit 17705a9c5a
16 changed files with 998 additions and 729 deletions

View File

@@ -16,6 +16,7 @@
#include "jitter_buffer.h"
#include "jitter_buffer_common.h"
#include "jitter_estimator.h"
#include "media_optimization.h" // hybrid NACK/FEC thresholds.
#include "packet.h"
#include "event.h"
@@ -46,11 +47,14 @@ VCMJitterBuffer::FrameEqualTimestamp(VCMFrameBuffer* frame, const void* timestam
}
bool
VCMJitterBuffer::CompleteKeyFrameCriteria(VCMFrameBuffer* frame, const void* /*notUsed*/)
VCMJitterBuffer::CompleteDecodableKeyFrameCriteria(VCMFrameBuffer* frame,
const void* /*notUsed*/)
{
const VCMFrameBufferStateEnum state = frame->GetState();
// We can decode key frame or decodable/complete frames.
return (frame->FrameType() == kVideoFrameKey) &&
(state == kStateComplete);
((state == kStateComplete)
|| (state == kStateDecodable));
}
// Constructor
@@ -76,7 +80,8 @@ VCMJitterBuffer::VCMJitterBuffer(WebRtc_Word32 vcmId, WebRtc_Word32 receiverId,
_numConsecutiveOldFrames(0),
_numConsecutiveOldPackets(0),
_jitterEstimate(vcmId, receiverId),
_usingNACK(false),
_rttMs(0),
_nackMode(kNoNack),
_NACKSeqNum(),
_NACKSeqNumLength(0),
_missingMarkerBits(false),
@@ -87,7 +92,7 @@ VCMJitterBuffer::VCMJitterBuffer(WebRtc_Word32 vcmId, WebRtc_Word32 receiverId,
_lastDecodedSeqNum = -1;
memset(_NACKSeqNumInternal, -1, sizeof(_NACKSeqNumInternal));
for (int i=0; i< kStartNumberOfFrames; i++)
for (int i = 0; i< kStartNumberOfFrames; i++)
{
_frameBuffers[i] = new VCMFrameBuffer();
}
@@ -130,7 +135,8 @@ VCMJitterBuffer::operator=(const VCMJitterBuffer& rhs)
_jitterEstimate = rhs._jitterEstimate;
_delayEstimate = rhs._delayEstimate;
_waitingForCompletion = rhs._waitingForCompletion;
_usingNACK = rhs._usingNACK;
_nackMode = rhs._nackMode;
_rttMs = rhs._rttMs;
_NACKSeqNumLength = rhs._NACKSeqNumLength;
_missingMarkerBits = rhs._missingMarkerBits;
_firstPacket = rhs._firstPacket;
@@ -138,7 +144,7 @@ VCMJitterBuffer::operator=(const VCMJitterBuffer& rhs)
memcpy(_receiveStatistics, rhs._receiveStatistics, sizeof(_receiveStatistics));
memcpy(_NACKSeqNumInternal, rhs._NACKSeqNumInternal, sizeof(_NACKSeqNumInternal));
memcpy(_NACKSeqNum, rhs._NACKSeqNum, sizeof(_NACKSeqNum));
for (int i=0; i < kMaxNumberOfFrames; i++)
for (int i = 0; i < kMaxNumberOfFrames; i++)
{
if (_frameBuffers[i] != NULL)
{
@@ -147,7 +153,7 @@ VCMJitterBuffer::operator=(const VCMJitterBuffer& rhs)
}
}
while(_frameBuffersTSOrder.Erase(_frameBuffersTSOrder.First()) != -1) { }
for (int i=0; i < _maxNumberOfFrames; i++)
for (int i = 0; i < _maxNumberOfFrames; i++)
{
_frameBuffers[i] = new VCMFrameBuffer(*(rhs._frameBuffers[i]));
if (_frameBuffers[i]->Length() > 0)
@@ -162,7 +168,8 @@ VCMJitterBuffer::operator=(const VCMJitterBuffer& rhs)
}
WebRtc_UWord32
VCMJitterBuffer::LatestTimestamp(const WebRtc_UWord32 existingTimestamp, const WebRtc_UWord32 newTimestamp)
VCMJitterBuffer::LatestTimestamp(const WebRtc_UWord32 existingTimestamp,
const WebRtc_UWord32 newTimestamp)
{
bool wrap = (newTimestamp < 0x0000ffff && existingTimestamp > 0xffff0000) ||
(newTimestamp > 0xffff0000 && existingTimestamp < 0x0000ffff);
@@ -185,7 +192,8 @@ VCMJitterBuffer::LatestTimestamp(const WebRtc_UWord32 existingTimestamp, const W
}
// Start jitter buffer
void VCMJitterBuffer::Start()
void
VCMJitterBuffer::Start()
{
CriticalSectionScoped cs(_critSect);
_running = true;
@@ -205,12 +213,14 @@ void VCMJitterBuffer::Start()
_waitingForCompletion.latestPacketTime = -1;
_missingMarkerBits = false;
_firstPacket = true;
_rttMs = 0;
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), "JB(0x%x): Jitter buffer: start", this);
}
// Stop jitter buffer
void VCMJitterBuffer::Stop()
void
VCMJitterBuffer::Stop()
{
_critSect.Enter();
_running = false;
@@ -231,21 +241,24 @@ void VCMJitterBuffer::Stop()
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), "JB(0x%x): Jitter buffer: stop", this);
}
bool VCMJitterBuffer::Running() const
bool
VCMJitterBuffer::Running() const
{
CriticalSectionScoped cs(_critSect);
return _running;
}
// Flush jitter buffer
void VCMJitterBuffer::Flush()
void
VCMJitterBuffer::Flush()
{
CriticalSectionScoped cs(_critSect);
FlushInternal();
}
// Must be called under the critical section _critSect
void VCMJitterBuffer::FlushInternal()
void
VCMJitterBuffer::FlushInternal()
{
// Erase all frames from the sorted list and set their state to free.
_frameBuffersTSOrder.Flush();
@@ -292,7 +305,8 @@ VCMJitterBuffer::ReleaseFrameInternal(VCMFrameBuffer* frame)
// Doing it here increases the degree of freedom for e.g. future
// reconstructability of separate layers. Must be called under the
// critical section _critSect.
void VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame)
void
VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame)
{
if (frame == NULL)
{
@@ -385,8 +399,7 @@ void VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame)
// Only signal if this is the oldest frame.
// Not necessary the case due to packet reordering or NACK.
if(!_usingNACK ||
(oldFrame != NULL && oldFrame == frame))
if (!WaitForNack() || (oldFrame != NULL && oldFrame == frame))
{
_frameEvent.Set();
}
@@ -481,7 +494,7 @@ VCMJitterBuffer::GetEmptyFrame()
_critSect.Enter();
for (int i=0; i<_maxNumberOfFrames; ++i)
for (int i = 0; i <_maxNumberOfFrames; ++i)
{
if (kStateFree == _frameBuffers[i]->GetState())
{
@@ -512,7 +525,8 @@ VCMJitterBuffer::GetEmptyFrame()
}
// Must be called under the critical section _critSect.
VCMFrameListItem* VCMJitterBuffer::FindOldestSequenceNum() const
VCMFrameListItem*
VCMJitterBuffer::FindOldestSequenceNum() const
{
WebRtc_UWord16 currentLow = 0xffff;
VCMFrameBufferStateEnum state = kStateFree;
@@ -562,7 +576,8 @@ VCMFrameListItem* VCMJitterBuffer::FindOldestSequenceNum() const
// Must be called under critical section
// Based on sequence number
// Return NULL for lost packets
VCMFrameListItem* VCMJitterBuffer::FindOldestCompleteContinuousFrame()
VCMFrameListItem*
VCMJitterBuffer::FindOldestCompleteContinuousFrame()
{
// if we have more than one frame done since last time, pick oldest
VCMFrameBuffer* oldestFrame = NULL;
@@ -578,7 +593,8 @@ VCMFrameListItem* VCMJitterBuffer::FindOldestCompleteContinuousFrame()
{
if (kStateComplete != oldestFrame->GetState())
{
// Try to see if the frame is complete even though the state is not complete. Can happen if markerbit is not set.
// Try to see if the frame is complete even though the state is not
// complete. Can happen if markerbit is not set.
if (!CheckForCompleteFrame(oldestFrameItem))
{
oldestFrame = NULL;
@@ -590,7 +606,7 @@ VCMFrameListItem* VCMJitterBuffer::FindOldestCompleteContinuousFrame()
currentLow = oldestFrame->GetLowSeqNum();
}
}
if(oldestFrame == NULL)
if (oldestFrame == NULL)
{
// no complete frame no point to continue
return NULL;
@@ -601,15 +617,16 @@ VCMFrameListItem* VCMJitterBuffer::FindOldestCompleteContinuousFrame()
// Use seqNum not timestamp since a full frame might be lost
if (_lastDecodedSeqNum != -1)
{
// it's not enough that we have complete frame we need the seq numbers to be continuous too
// for layers it's not enough that we have complete frame we need the layers to be continuous too
// it's not enough that we have complete frame we need the seq numbers
// to be continuous too for layers it's not enough that we have complete
// frame we need the layers to be continuous too
currentLow = oldestFrame->GetLowSeqNum();
WebRtc_UWord16 lastDecodedSeqNum = (WebRtc_UWord16)_lastDecodedSeqNum;
// we could have received the first packet of the last frame before a long period
// if drop, that case is handled by GetNackList
if ( ((WebRtc_UWord16)(lastDecodedSeqNum + 1)) != currentLow)
// we could have received the first packet of the last frame before a
// long period if drop, that case is handled by GetNackList
if (((WebRtc_UWord16)(lastDecodedSeqNum + 1)) != currentLow)
{
// wait since we want a complete continuous frame
return NULL;
@@ -618,11 +635,12 @@ VCMFrameListItem* VCMJitterBuffer::FindOldestCompleteContinuousFrame()
return oldestFrameItem;
}
// Check if the oldest frame is complete even though it is not in a complete state.
// Check if the oldest frame is complete even though it isn't complete.
// This can happen when makerbit is not set
// Must be called under the critical section _critSect.
// Return false for lost packets
bool VCMJitterBuffer::CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem)
bool
VCMJitterBuffer::CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem)
{
const VCMFrameListItem* nextFrameItem = _frameBuffersTSOrder.Next(oldestFrameItem);
VCMFrameBuffer* oldestFrame = NULL;
@@ -630,7 +648,7 @@ bool VCMJitterBuffer::CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem)
{
oldestFrame = oldestFrameItem->GetItem();
}
if(nextFrameItem != NULL)
if (nextFrameItem != NULL)
{
// We have received at least one packet from a later frame.
if(!oldestFrame->HaveLastPacket()) // If we don't have the markerbit
@@ -638,7 +656,7 @@ bool VCMJitterBuffer::CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem)
VCMFrameBuffer* nextFrame = nextFrameItem->GetItem();
// Verify that we have received the first packet of the next frame.
// This is the only way we can be sure we're not missing the last packet.
if(nextFrame != NULL && nextFrame->GetLowSeqNum() ==
if (nextFrame != NULL && nextFrame->GetLowSeqNum() ==
static_cast<WebRtc_UWord16>(oldestFrame->GetHighSeqNum()+1)) // Sequence number is only 16 bit
{
_missingMarkerBits = true;
@@ -648,7 +666,7 @@ bool VCMJitterBuffer::CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem)
UpdateFrameState(oldestFrame);
}
const VCMFrameBufferStateEnum state = oldestFrame->GetState();
if(state == kStateComplete)
if (state == kStateComplete)
{
if(oldestFrame->Length() > 0)
{
@@ -663,7 +681,8 @@ bool VCMJitterBuffer::CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem)
}
// Call from inside the critical section _critSect
void VCMJitterBuffer::RecycleFrame(VCMFrameBuffer* frame)
void
VCMJitterBuffer::RecycleFrame(VCMFrameBuffer* frame)
{
if (frame == NULL)
{
@@ -679,7 +698,8 @@ void VCMJitterBuffer::RecycleFrame(VCMFrameBuffer* frame)
// Calculate frame and bit rates
WebRtc_Word32 VCMJitterBuffer::GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord32& bitRate)
WebRtc_Word32
VCMJitterBuffer::GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord32& bitRate)
{
CriticalSectionScoped cs(_critSect);
const WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
@@ -744,7 +764,8 @@ WebRtc_Word32 VCMJitterBuffer::GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord
}
// Returns immediately or a X ms event hang waiting for a decodable frame, X decided by caller
VCMEncodedFrame* VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
VCMEncodedFrame*
VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
{
if (!_running)
{
@@ -853,38 +874,54 @@ VCMEncodedFrame* VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 max
return oldestFrame;
}
WebRtc_UWord32 VCMJitterBuffer::GetEstimatedJitterMS()
WebRtc_UWord32
VCMJitterBuffer::GetEstimatedJitterMS()
{
CriticalSectionScoped cs(_critSect);
return GetEstimatedJitterMsInternal();
}
WebRtc_UWord32 VCMJitterBuffer::GetEstimatedJitterMsInternal()
WebRtc_UWord32
VCMJitterBuffer::GetEstimatedJitterMsInternal()
{
WebRtc_UWord32 estimate = VCMJitterEstimator::OPERATING_SYSTEM_JITTER;
estimate += static_cast<WebRtc_UWord32>(_jitterEstimate.GetJitterEstimate() + 0.5);
// compute RTT multiplier for estimation
double rttMult = 1.0f;
if (_nackMode == kNackHybrid && _rttMs > kLowRttNackMs)
{
// from here we count on FEC
rttMult = 0.0f;
}
estimate += static_cast<WebRtc_UWord32>
(_jitterEstimate.GetJitterEstimate(rttMult) + 0.5);
if (_missingMarkerBits)
{
// Since the incoming packets are all missing marker bits we have to wait until the first
// packet of the next frame arrives, before we can safely say that the frame is complete.
// Therefore we have to compensate the jitter buffer level with one frame period.
// TODO(holmer): The timestamp diff should probably be filtered (max filter) since
// the diff can alternate between e.g. 3000 and 6000 if we have a frame rate between
// 15 and 30 frames per seconds.
// Since the incoming packets are all missing marker bits we have to
// wait until the first packet of the next frame arrives, before we can
// safely say that the frame is complete. Therefore we have to compensate
// the jitter buffer level with one frame period.
// TODO(holmer): The timestamp diff should probably be filtered
// (max filter) since the diff can alternate between e.g. 3000 and 6000
// if we have a frame rate between 15 and 30 frames per seconds.
estimate += _delayEstimate.CurrentTimeStampDiffMs();
}
return estimate;
}
void VCMJitterBuffer::UpdateRtt(WebRtc_UWord32 rttMs)
void
VCMJitterBuffer::UpdateRtt(WebRtc_UWord32 rttMs)
{
CriticalSectionScoped cs(_critSect);
_rttMs = rttMs;
_jitterEstimate.UpdateRtt(rttMs);
}
// wait for the first packet in the next frame to arrive
WebRtc_Word64 VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS, FrameType& incomingFrameType, WebRtc_Word64& renderTimeMs)
WebRtc_Word64
VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS,
FrameType& incomingFrameType,
WebRtc_Word64& renderTimeMs)
{
if (!_running)
{
@@ -913,7 +950,6 @@ WebRtc_Word64 VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS, Fr
CleanUpOldFrames();
CleanUpSizeZeroFrames();
oldestFrame = _frameBuffersTSOrder.FirstFrame();
}else
{
@@ -946,7 +982,8 @@ WebRtc_Word64 VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS, Fr
// Will the packet sequence be complete if the next frame is grabbed for decoding right now?
// That is, have we lost a frame between the last decoded frame and the next, or is the next
// frame missing one or more packets?
bool VCMJitterBuffer::CompleteSequenceWithNextFrame()
bool
VCMJitterBuffer::CompleteSequenceWithNextFrame()
{
CriticalSectionScoped cs(_critSect);
// Finding oldest frame ready for decoder, but check sequence number and size
@@ -989,7 +1026,8 @@ bool VCMJitterBuffer::CompleteSequenceWithNextFrame()
}
// Returns immediately
VCMEncodedFrame* VCMJitterBuffer::GetFrameForDecoding()
VCMEncodedFrame*
VCMJitterBuffer::GetFrameForDecoding()
{
CriticalSectionScoped cs(_critSect);
if (!_running)
@@ -997,7 +1035,7 @@ VCMEncodedFrame* VCMJitterBuffer::GetFrameForDecoding()
return NULL;
}
if(_usingNACK)
if (WaitForNack())
{
return GetFrameForDecodingNACK();
}
@@ -1061,6 +1099,7 @@ VCMJitterBuffer::GetFrameForDecodingNACK()
{
// when we use NACK we don't release non complete frames
// unless we have a complete key frame.
// In hybrid mode, we may release decodable frames (non-complete)
// Clean up old frames and empty frames
CleanUpOldFrames();
@@ -1077,8 +1116,9 @@ VCMJitterBuffer::GetFrameForDecodingNACK()
if (oldestFrame == NULL)
{
continuous = false;
// If we didn't find one we're good with a complete key frame.
oldestFrameListItem = _frameBuffersTSOrder.FindFrameListItem(CompleteKeyFrameCriteria);
// If we didn't find one we're good with a complete key/decodable frame.
oldestFrameListItem = _frameBuffersTSOrder.FindFrameListItem(
CompleteDecodableKeyFrameCriteria);
if (oldestFrameListItem != NULL)
{
oldestFrame = oldestFrameListItem->GetItem();
@@ -1089,7 +1129,7 @@ VCMJitterBuffer::GetFrameForDecodingNACK()
}
}
// We have a complete continuous frame, decode it.
// We have a complete/decodable continuous frame, decode it.
// store seqnum
_lastDecodedSeqNum = oldestFrame->GetHighSeqNum();
// store current time
@@ -1181,7 +1221,10 @@ VCMJitterBuffer::UpdateJitterAndDelayEstimates(VCMFrameBuffer& frame, bool incom
// Must be called under the critical section _critSect. Should never be called with
// retransmitted frames, they must be filtered out before this function is called.
void
VCMJitterBuffer::UpdateJitterAndDelayEstimates(WebRtc_Word64 latestPacketTimeMs, WebRtc_UWord32 timestamp, WebRtc_UWord32 frameSize, bool incompleteFrame)
VCMJitterBuffer::UpdateJitterAndDelayEstimates(WebRtc_Word64 latestPacketTimeMs,
WebRtc_UWord32 timestamp,
WebRtc_UWord32 frameSize,
bool incompleteFrame)
{
if (latestPacketTimeMs == -1)
{
@@ -1217,17 +1260,18 @@ VCMJitterBuffer::GetLowHighSequenceNumbers(WebRtc_Word32& lowSeqNum, WebRtc_Word
highSeqNum = -1;
lowSeqNum = _lastDecodedSeqNum;
// find higest seqnumbers
for (i=0; i<_maxNumberOfFrames; ++i)
// find highest seqnumbers
for (i = 0; i < _maxNumberOfFrames; ++i)
{
seqNum = _frameBuffers[i]->GetHighSeqNum();
// Ignore free frames
// Ignore free / empty frames
VCMFrameBufferStateEnum state = _frameBuffers[i]->GetState();
if((kStateFree != state) &&
if ((kStateFree != state) &&
(kStateEmpty != state) &&
(kStateDecoding != state) &&
seqNum != -1)
seqNum != -1)
{
if (highSeqNum == -1)
{
@@ -1260,9 +1304,10 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
int i = 0;
WebRtc_Word32 lowSeqNum = -1;
WebRtc_Word32 highSeqNum = -1;
listExtended=false;
listExtended = false;
if (!_usingNACK)
// don't create list, if we won't wait for it
if (!WaitForNack())
{
nackSize = 0;
return NULL;
@@ -1277,11 +1322,10 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
// write a list of all seq num we have
if (lowSeqNum == -1 || highSeqNum == -1)
{
//This happens if we lose the first packet, nothing is poped
//This happens if we lose the first packet, nothing is popped
if (highSeqNum == -1)
{
nackSize = 0;// we have not received any packets yet
}
else
{
@@ -1371,7 +1415,8 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
// We have cleaned up the jb and found a key frame
// The function itself has set last decoded seq.
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, -1,
"\tKey frame found. _lastDecodedSeqNum[0] %d", _lastDecodedSeqNum);
"\tKey frame found. _lastDecodedSeqNum[0] %d",
_lastDecodedSeqNum);
nackSize = 0;
}
@@ -1379,27 +1424,51 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
}
WebRtc_UWord16 seqNumberIterator = (WebRtc_UWord16)(lowSeqNum + 1);
for (i=0; i < numberOfSeqNum; i++)
for (i = 0; i < numberOfSeqNum; i++)
{
_NACKSeqNumInternal[i] = seqNumberIterator;
seqNumberIterator++;
}
// now we have a list of all seq numbers that could have been sent
// now we have a list of all sequence numbers that could have been sent
// zero out the ones we have received
for (i = 0; i < _maxNumberOfFrames; i++)
{
// loop all created frames
// We dont need to check if frame is decoding since lowSeqNum is based on _lastDecodedSeqNum
// We don't need to check if frame is decoding since lowSeqNum is based
// on _lastDecodedSeqNum
// Ignore free frames
VCMFrameBufferStateEnum state = _frameBuffers[i]->GetState();
if ((kStateFree != state) &&
(kStateEmpty != state) &&
(kStateDecoding != state))
{
_frameBuffers[i]->ZeroOutSeqNum(_NACKSeqNumInternal, numberOfSeqNum);
// used when the frame is being processed by the decoding thread
// dont need to use that info in this loop
// Reaching thus far means we are going to update the nack list
// When in hybrid mode, we also need to check empty frames, so as not
// to add empty packets to the nack list
if (_nackMode == kNackHybrid)
{
// build external rttScore based on RTT value
float rttScore = 1.0f;
_frameBuffers[i]->ZeroOutSeqNumHybrid(_NACKSeqNumInternal,
numberOfSeqNum,
rttScore);
if (_frameBuffers[i]->IsRetransmitted() == false)
{
// if no retransmission required,set the state to decodable
// meaning that we will not wait for NACK
_frameBuffers[i]->SetState(kStateDecodable);
}
}
else
{
// used when the frame is being processed by the decoding thread
// don't need to use that info in this loop
_frameBuffers[i]->ZeroOutSeqNum(_NACKSeqNumInternal,
numberOfSeqNum);
}
}
}
@@ -1407,7 +1476,7 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
int emptyIndex = -1;
for (i = 0; i < numberOfSeqNum; i++)
{
if (_NACKSeqNumInternal[i] == -1)
if (_NACKSeqNumInternal[i] == -1 || _NACKSeqNumInternal[i] == -2 )
{
// this is empty
if (emptyIndex == -1)
@@ -1442,36 +1511,39 @@ VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
nackSize = emptyIndex;
}
// convert to unsigned short 16 bit and store in a list to be used externally.
if(nackSize > _NACKSeqNumLength)
if (nackSize > _NACKSeqNumLength)
{
listExtended=true; // Larger list means that the nack list has been extended since the last call.
// Larger list means that the nack list was extended since the last call.
listExtended = true;
}
for(WebRtc_UWord32 j = 0; j < nackSize; j++)
{
// Check if the list has been extended since it was last created. I.e, new items have been added
if(_NACKSeqNumLength > j && !listExtended)
// Check if the list has been extended since it was last created. I.e,
// new items have been added
if (_NACKSeqNumLength > j && !listExtended)
{
WebRtc_UWord32 k = 0;
for(k = j; k < _NACKSeqNumLength; k++)
for (k = j; k < _NACKSeqNumLength; k++)
{
// Found the item in the last list. I.e, no new items found yet.
if(_NACKSeqNum[k] == (WebRtc_UWord16)_NACKSeqNumInternal[j])
if (_NACKSeqNum[k] == (WebRtc_UWord16)_NACKSeqNumInternal[j])
{
break;
}
}
if(k == _NACKSeqNumLength) // New item not found in last list.
if (k == _NACKSeqNumLength) // New item not found in last list.
{
listExtended=true;
listExtended = true;
}
}
else
{
listExtended=true;
listExtended = true;
}
_NACKSeqNum[j] = (WebRtc_UWord16)_NACKSeqNumInternal[j];
}
_NACKSeqNumLength = nackSize;
return _NACKSeqNum;
@@ -1511,35 +1583,39 @@ VCMJitterBuffer::InsertPacket(VCMEncodedFrame* buffer, const VCMPacket& packet)
VCMFrameBufferEnum ret = kSizeError;
VCMFrameBuffer* frame = static_cast<VCMFrameBuffer*>(buffer);
if (_firstPacket)
// Empty packets may bias the jitter estimate (lacking size component),
// therefore don't let empty packet trigger the following updates:
if (packet.frameType != kFrameEmpty)
{
// Now it's time to start estimating jitter
// reset the delay estimate.
_delayEstimate.Reset();
_firstPacket = false;
}
if (_firstPacket)
{
// Now it's time to start estimating jitter
// reset the delay estimate.
_delayEstimate.Reset();
_firstPacket = false;
}
if (_waitingForCompletion.timestamp == packet.timestamp)
{
// This can get bad if we have a lot of duplicate packets,
// we will then count some packet multiple times.
_waitingForCompletion.frameSize += packet.sizeBytes;
_waitingForCompletion.latestPacketTime = nowMs;
}
else if (_waitingForCompletion.latestPacketTime >= 0 &&
_waitingForCompletion.latestPacketTime + 2000 <= nowMs)
{
// A packet should never be more than two seconds late
UpdateJitterAndDelayEstimates(_waitingForCompletion, true);
_waitingForCompletion.latestPacketTime = -1;
_waitingForCompletion.frameSize = 0;
_waitingForCompletion.timestamp = 0;
if (_waitingForCompletion.timestamp == packet.timestamp)
{
// This can get bad if we have a lot of duplicate packets,
// we will then count some packet multiple times.
_waitingForCompletion.frameSize += packet.sizeBytes;
_waitingForCompletion.latestPacketTime = nowMs;
}
else if (_waitingForCompletion.latestPacketTime >= 0 &&
_waitingForCompletion.latestPacketTime + 2000 <= nowMs)
{
// A packet should never be more than two seconds late
UpdateJitterAndDelayEstimates(_waitingForCompletion, true);
_waitingForCompletion.latestPacketTime = -1;
_waitingForCompletion.frameSize = 0;
_waitingForCompletion.timestamp = 0;
}
}
if (frame != NULL)
{
VCMFrameBufferStateEnum state = frame->GetState();
if (state == kStateDecoding && packet.sizeBytes == 0)
{
// Filler packet, make sure we update the last decoded seq num
@@ -1655,7 +1731,7 @@ VCMJitterBuffer::IsPacketRetransmitted(const VCMPacket& packet) const
{
if (_NACKSeqNum && _NACKSeqNumLength > 0)
{
for (WebRtc_UWord16 i=0; i < _NACKSeqNumLength; i++)
for (WebRtc_UWord16 i = 0; i < _NACKSeqNumLength; i++)
{
if (packet.seqNum == _NACKSeqNum[i])
{
@@ -1667,18 +1743,20 @@ VCMJitterBuffer::IsPacketRetransmitted(const VCMPacket& packet) const
}
// Get nack status (enabled/disabled)
bool VCMJitterBuffer::GetNackStatus()
VCMNackMode
VCMJitterBuffer::GetNackMode() const
{
CriticalSectionScoped cs(_critSect);
return _usingNACK;
return _nackMode;
}
// Enable/disable nack
void VCMJitterBuffer::SetNackStatus(bool enable)
// Set NACK mode
void
VCMJitterBuffer::SetNackMode(VCMNackMode mode)
{
CriticalSectionScoped cs(_critSect);
_usingNACK = enable;
if (!_usingNACK)
_nackMode = mode;
if (_nackMode == kNoNack)
{
_jitterEstimate.ResetNackCount();
}
@@ -1808,7 +1886,7 @@ VCMJitterBuffer::CleanUpSizeZeroFrames()
const WebRtc_Word32 frameHighSeqNum = ptrTempBuffer->GetHighSeqNum();
const WebRtc_Word32 frameLowSeqNum = ptrTempBuffer->GetLowSeqNum();
if ((frameLowSeqNum == (_lastDecodedSeqNum+ 1)) || // Frame is next in line
if ((frameLowSeqNum == (_lastDecodedSeqNum + 1)) || // Frame is next in line
((frameLowSeqNum == 0) && (_lastDecodedSeqNum== 0xffff)))
{
// This frame follows the last decoded frame, release it.
@@ -1878,4 +1956,33 @@ VCMJitterBuffer::VerifyAndSetPreviousFrameLost(VCMFrameBuffer& frame)
}
}
bool
VCMJitterBuffer::WaitForNack()
{
// NACK disabled -> can't wait
if (_nackMode == kNoNack)
{
return false;
}
// NACK only -> always wait
else if (_nackMode == kNackInfinite)
{
return true;
}
// else: hybrid mode, evaluate
// RTT high, don't wait
if (_rttMs >= kHighRttNackMs)
{
return false;
}
// RTT low, we can afford the wait
else if (_rttMs <= kLowRttNackMs)
{
return true;
}
// interim values - hybrid mode
return true;
}
}