/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "critical_section_wrapper.h"

#include "frame_buffer.h"
#include "inter_frame_delay.h"
#include "internal_defines.h"
#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"
#include "trace.h"
#include "tick_time.h"
#include "list_wrapper.h"

#include <cassert>
#include <string.h>
#include <cmath>

#if defined(_WIN32)
    // VS 2005: Don't warn for default initialized arrays. See help for more info.
    #pragma warning(disable:4351)
#endif

namespace webrtc {

// Criteria used when searching for frames in the frame buffer list
bool
VCMJitterBuffer::FrameEqualTimestamp(VCMFrameBuffer* frame,
                                     const void* timestamp)
{
    if (timestamp == NULL)
    {
        return false;
    }
    return (*static_cast<const WebRtc_UWord32*>(timestamp)) == frame->TimeStamp();
}

bool
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 == kStateDecodable);
}

// Constructor
VCMJitterBuffer::VCMJitterBuffer(WebRtc_Word32 vcmId, WebRtc_Word32 receiverId,
                                 bool master) :
    _vcmId(vcmId),
    _receiverId(receiverId),
    _running(false),
    _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
    _master(master),
    _frameEvent(),
    _packetEvent(),
    _maxNumberOfFrames(kStartNumberOfFrames),
    _frameBuffers(),
    _frameBuffersTSOrder(),
    _lastDecodedSeqNum(-1),
    _lastDecodedTimeStamp(-1),
    _lastDecodedPictureId(-1),
    _packetsNotDecodable(0),
    _receiveStatistics(),
    _incomingFrameRate(0),
    _incomingFrameCount(0),
    _timeLastIncomingFrameCount(0),
    _incomingBitCount(0),
    _dropCount(0),
    _numConsecutiveOldFrames(0),
    _numConsecutiveOldPackets(0),
    _discardedPackets(0),
    _jitterEstimate(vcmId, receiverId),
    _rttMs(0),
    _nackMode(kNoNack),
    _NACKSeqNum(),
    _NACKSeqNumLength(0),
    _waitingForKeyFrame(false),
    _firstPacket(true)
{
    memset(_frameBuffers, 0, sizeof(_frameBuffers));
    memset(_receiveStatistics, 0, sizeof(_receiveStatistics));
    memset(_NACKSeqNumInternal, -1, sizeof(_NACKSeqNumInternal));

    for (int i = 0; i< kStartNumberOfFrames; i++)
    {
        _frameBuffers[i] = new VCMFrameBuffer();
    }
}

// Destructor
VCMJitterBuffer::~VCMJitterBuffer()
{
    Stop();
    for (int i = 0; i< kMaxNumberOfFrames; i++)
    {
        if (_frameBuffers[i])
        {
            delete _frameBuffers[i];
        }
    }
    delete &_critSect;
}

void
VCMJitterBuffer::CopyFrom(const VCMJitterBuffer& rhs)
{
    if (this != &rhs)
    {
        _critSect.Enter();
        rhs._critSect.Enter();
        _vcmId = rhs._vcmId;
        _receiverId = rhs._receiverId;
        _running = rhs._running;
        _master = !rhs._master;
        _maxNumberOfFrames = rhs._maxNumberOfFrames;
        _incomingFrameRate = rhs._incomingFrameRate;
        _incomingFrameCount = rhs._incomingFrameCount;
        _timeLastIncomingFrameCount = rhs._timeLastIncomingFrameCount;
        _incomingBitCount = rhs._incomingBitCount;
        _dropCount = rhs._dropCount;
        _numConsecutiveOldFrames = rhs._numConsecutiveOldFrames;
        _numConsecutiveOldPackets = rhs._numConsecutiveOldPackets;
        _discardedPackets = rhs._discardedPackets;
        _jitterEstimate = rhs._jitterEstimate;
        _delayEstimate = rhs._delayEstimate;
        _waitingForCompletion = rhs._waitingForCompletion;
        _rttMs = rhs._rttMs;
        _NACKSeqNumLength = rhs._NACKSeqNumLength;
        _waitingForKeyFrame = rhs._waitingForKeyFrame;
        _firstPacket = rhs._firstPacket;
        _lastDecodedSeqNum =  rhs._lastDecodedSeqNum;
        _lastDecodedTimeStamp = rhs._lastDecodedTimeStamp;
        _lastDecodedPictureId = rhs._lastDecodedPictureId;
        _packetsNotDecodable = rhs._packetsNotDecodable;
        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++)
        {
            if (_frameBuffers[i] != NULL)
            {
                delete _frameBuffers[i];
                _frameBuffers[i] = NULL;
            }
        }
        while(_frameBuffersTSOrder.Erase(_frameBuffersTSOrder.First()) != -1)
        { }
        for (int i = 0; i < _maxNumberOfFrames; i++)
        {
            _frameBuffers[i] = new VCMFrameBuffer(*(rhs._frameBuffers[i]));
            if (_frameBuffers[i]->Length() > 0)
            {
                _frameBuffersTSOrder.Insert(_frameBuffers[i]);
            }
        }
        rhs._critSect.Leave();
        _critSect.Leave();
    }
}

// Start jitter buffer
void
VCMJitterBuffer::Start()
{
    CriticalSectionScoped cs(_critSect);
    _running = true;
    _incomingFrameCount = 0;
    _incomingFrameRate = 0;
    _incomingBitCount = 0;
    _timeLastIncomingFrameCount = VCMTickTime::MillisecondTimestamp();
    memset(_receiveStatistics, 0, sizeof(_receiveStatistics));

    _numConsecutiveOldFrames = 0;
    _numConsecutiveOldPackets = 0;
    _discardedPackets = 0;

    _frameEvent.Reset(); // start in a non-signaled state
    _packetEvent.Reset(); // start in a non-signaled state
    _waitingForCompletion.frameSize = 0;
    _waitingForCompletion.timestamp = 0;
    _waitingForCompletion.latestPacketTime = -1;
    _firstPacket = true;
    _NACKSeqNumLength = 0;
    _waitingForKeyFrame = false;
    _rttMs = 0;
    _packetsNotDecodable = 0;

    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId,
                 _receiverId), "JB(0x%x): Jitter buffer: start", this);
}


// Stop jitter buffer
void
VCMJitterBuffer::Stop()
{
    _critSect.Enter();
    _running = false;
    _lastDecodedTimeStamp = -1;
    _lastDecodedSeqNum = -1;
    _lastDecodedPictureId = -1;
    _frameBuffersTSOrder.Flush();
    for (int i = 0; i < kMaxNumberOfFrames; i++)
    {
        if (_frameBuffers[i] != NULL)
        {
            static_cast<VCMFrameBuffer*>(_frameBuffers[i])->SetState(kStateFree);
        }
    }

    _critSect.Leave();
    _frameEvent.Set(); // Make sure we exit from trying to get a frame to decoder
    _packetEvent.Set(); // Make sure we exit from trying to get a sequence number
    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId,
                 _receiverId), "JB(0x%x): Jitter buffer: stop", this);
}

bool
VCMJitterBuffer::Running() const
{
    CriticalSectionScoped cs(_critSect);
    return _running;
}

// Flush jitter buffer
void
VCMJitterBuffer::Flush()
{
    CriticalSectionScoped cs(_critSect);
    FlushInternal();
}

// Must be called under the critical section _critSect
void
VCMJitterBuffer::FlushInternal()
{
    // Erase all frames from the sorted list and set their state to free.
    _frameBuffersTSOrder.Flush();
    for (WebRtc_Word32 i = 0; i < _maxNumberOfFrames; i++)
    {
        ReleaseFrameInternal(_frameBuffers[i]);
    }
    _lastDecodedSeqNum = -1;
    _lastDecodedTimeStamp = -1;
    _lastDecodedPictureId = -1;
    _packetsNotDecodable = 0;

    _frameEvent.Reset();
    _packetEvent.Reset();

    _numConsecutiveOldFrames = 0;
    _numConsecutiveOldPackets = 0;

    // Also reset the jitter and delay estimates
    _jitterEstimate.Reset();
    _delayEstimate.Reset();

    _waitingForCompletion.frameSize = 0;
    _waitingForCompletion.timestamp = 0;
    _waitingForCompletion.latestPacketTime = -1;

    _firstPacket = true;

    _NACKSeqNumLength = 0;

    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId,
                 _receiverId), "JB(0x%x): Jitter buffer: flush", this);
}

// Set the frame state to free and remove it from the sorted
// frame list. Must be called from inside the critical section _critSect.
void
VCMJitterBuffer::ReleaseFrameInternal(VCMFrameBuffer* frame)
{
    if (frame != NULL && frame->GetState() != kStateDecoding)
    {
        frame->SetState(kStateFree);
    }
}

// Update frame state (set as complete if conditions are met)
// Doing it here increases the degree of freedom for e.g. future
// reconstructability of separate layers. Must be called under the
// critical section _critSect.
VCMFrameBufferEnum
VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame)
{
    if (frame == NULL)
    {
        WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding,
                     VCMId(_vcmId, _receiverId), "JB(0x%x) FB(0x%x): "
                         "UpdateFrameState NULL frame pointer", this, frame);
        return kNoError;
    }

    int length = frame->Length();
    if (_master)
    {
        // Only trace the primary jitter buffer to make it possible to parse
        // and plot the trace file.
        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
                     VCMId(_vcmId, _receiverId),
                     "JB(0x%x) FB(0x%x): Complete frame added to jitter buffer,"
                     " size:%d type %d",
                     this, frame,length,frame->FrameType());
    }

    if (length != 0 && !frame->GetCountedFrame())
    {
        // ignore Ack frames
        _incomingFrameCount++;
        frame->SetCountedFrame(true);
    }

    // Check if we should drop frame
    // an old complete frame can arrive too late
    if (_lastDecodedTimeStamp > 0 &&
            LatestTimestamp(static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp),
                            frame->TimeStamp(), NULL) == _lastDecodedTimeStamp)
    {
        // Frame is older than the latest decoded frame, drop it.
        // This will trigger a release in CleanUpSizeZeroFrames later.
        frame->Reset();
        frame->SetState(kStateEmpty);

        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
                     VCMId(_vcmId, _receiverId),
                     "JB(0x%x) FB(0x%x): Dropping old frame in Jitter buffer",
                     this, frame);
        _dropCount++;
        WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding,
                     VCMId(_vcmId, _receiverId),
                     "Jitter buffer drop count: %d, consecutive drops: %u",
                     _dropCount, _numConsecutiveOldFrames);
        // Flush() if this happens consistently.
        _numConsecutiveOldFrames++;
        if (_numConsecutiveOldFrames > kMaxConsecutiveOldFrames) {
          FlushInternal();
          return kFlushIndicator;
        }
        return kNoError;
    }
    _numConsecutiveOldFrames = 0;
    frame->SetState(kStateComplete);


    // Update receive statistics. We count all layers, thus when you use layers
    // adding all key and delta frames might differ from frame count
    if (frame->IsSessionComplete())
    {
        switch (frame->FrameType())
        {
        case kVideoFrameKey:
            {
                _receiveStatistics[0]++;
                break;
            }
        case kVideoFrameDelta:
            {
                _receiveStatistics[1]++;
                break;
            }
        case kVideoFrameGolden:
            {
                _receiveStatistics[2]++;
                break;
            }
        case kVideoFrameAltRef:
            {
                _receiveStatistics[3]++;
                break;
            }
        default:
            assert(false);

        }
    }
    const VCMFrameListItem*
      oldFrameListItem = FindOldestCompleteContinuousFrame(false);
    VCMFrameBuffer* oldFrame = NULL;
    if (oldFrameListItem != NULL)
    {
        oldFrame = oldFrameListItem->GetItem();
    }

    // Only signal if this is the oldest frame.
    // Not necessary the case due to packet reordering or NACK.
    if (!WaitForNack() || (oldFrame != NULL && oldFrame == frame))
    {
        _frameEvent.Set();
    }
    return kNoError;
}

// Get received key and delta frames
WebRtc_Word32
VCMJitterBuffer::GetFrameStatistics(WebRtc_UWord32& receivedDeltaFrames,
                                    WebRtc_UWord32& receivedKeyFrames) const
{
    {
        CriticalSectionScoped cs(_critSect);
        receivedDeltaFrames = _receiveStatistics[1] + _receiveStatistics[3];
        receivedKeyFrames = _receiveStatistics[0] + _receiveStatistics[2];
    }
    return 0;
}

WebRtc_UWord32 VCMJitterBuffer::NumNotDecodablePackets() const {
  CriticalSectionScoped cs(_critSect);
  return _packetsNotDecodable;
}

WebRtc_UWord32 VCMJitterBuffer::DiscardedPackets() const {
  CriticalSectionScoped cs(_critSect);
  return _discardedPackets;
}

// Gets frame to use for this timestamp. If no match, get empty frame.
WebRtc_Word32
VCMJitterBuffer::GetFrame(const VCMPacket& packet, VCMEncodedFrame*& frame)
{
    if (!_running) // don't accept incoming packets until we are started
    {
        return VCM_UNINITIALIZED;
    }

    _critSect.Enter();
    // Make sure that old empty packets are inserted.
    if (LatestTimestamp(static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp),
                        packet.timestamp, NULL) == _lastDecodedTimeStamp
        && packet.sizeBytes > 0)
    {
        _discardedPackets++;  // Only counts discarded media packets
        // Trying to get an old frame.
        _numConsecutiveOldPackets++;
        if (_numConsecutiveOldPackets > kMaxConsecutiveOldPackets)
        {
            FlushInternal();
            _critSect.Leave();
            return VCM_FLUSH_INDICATOR;
        }
        _critSect.Leave();
        return VCM_OLD_PACKET_ERROR;
    }
    _numConsecutiveOldPackets = 0;

    frame = _frameBuffersTSOrder.FindFrame(FrameEqualTimestamp,
                                           &packet.timestamp);

    _critSect.Leave();

    if (frame != NULL)
    {
        return VCM_OK;
    }

    // No match, return empty frame
    frame = GetEmptyFrame();
    if (frame != NULL)
    {
        return VCM_OK;
    }
    // No free frame! Try to reclaim some...
    _critSect.Enter();
    RecycleFramesUntilKeyFrame();
    _critSect.Leave();

    frame = GetEmptyFrame();
    if (frame != NULL)
    {
        return VCM_OK;
    }
    return VCM_JITTER_BUFFER_ERROR;
}

// Deprecated! Kept for testing purposes.
VCMEncodedFrame*
VCMJitterBuffer::GetFrame(const VCMPacket& packet)
{
    VCMEncodedFrame* frame = NULL;
    if (GetFrame(packet, frame) < 0)
    {
        return NULL;
    }
    return frame;
}

// Get empty frame, creates new (i.e. increases JB size) if necessary
VCMFrameBuffer*
VCMJitterBuffer::GetEmptyFrame()
{
    if (!_running) // don't accept incoming packets until we are started
    {
        return NULL;
    }

    _critSect.Enter();

    for (int i = 0; i <_maxNumberOfFrames; ++i)
    {
        if (kStateFree == _frameBuffers[i]->GetState())
        {
            // found a free buffer
            _frameBuffers[i]->SetState(kStateEmpty);
            _critSect.Leave();
            return _frameBuffers[i];
        }
    }

    // Check if we can increase JB size
    if (_maxNumberOfFrames < kMaxNumberOfFrames)
    {
        VCMFrameBuffer* ptrNewBuffer = new VCMFrameBuffer();
        ptrNewBuffer->SetState(kStateEmpty);
        _frameBuffers[_maxNumberOfFrames] = ptrNewBuffer;
        _maxNumberOfFrames++;

        _critSect.Leave();
        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
        VCMId(_vcmId, _receiverId), "JB(0x%x) FB(0x%x): Jitter buffer "
        "increased to:%d frames", this, ptrNewBuffer, _maxNumberOfFrames);
        return ptrNewBuffer;
    }
    _critSect.Leave();

    // We have reached max size, cannot increase JB size
    return NULL;
}

// Must be called under the critical section _critSect.
VCMFrameListItem*
VCMJitterBuffer::FindOldestSequenceNum() const
{
    WebRtc_UWord16 currentLow = 0xffff;
    WebRtc_UWord16 sequenceNumber = 0;
    bool first = true;
    VCMFrameListItem* frameListItem = _frameBuffersTSOrder.First();
    VCMFrameListItem* oldestFrameListItem = NULL;

    while (frameListItem != NULL)
    {
        // if we have more than one frame done since last time,
        // pick oldest
        VCMFrameBuffer* ptrFrame = NULL;
        ptrFrame = frameListItem->GetItem();
        sequenceNumber = static_cast<WebRtc_UWord16>(ptrFrame->GetLowSeqNum());

        // Find the oldest, hence lowest, using sequence numbers
        if (first)
        {
            currentLow = sequenceNumber;
            oldestFrameListItem = frameListItem;
            first = false;
        }
        else if ((currentLow < 0x0fff) && (sequenceNumber > 0xf000))
        {
            // We have a wrap and this one is older
            currentLow = sequenceNumber;
            oldestFrameListItem = frameListItem;
        }
        else if ((sequenceNumber < 0x0fff) && (currentLow > 0xf000))
        {
            // This one is after a wrap, leave as is
        }
        else if (currentLow > sequenceNumber)
        {
            // Normal case, this one is lower.
            currentLow = sequenceNumber;
            oldestFrameListItem = frameListItem;
        }
        frameListItem = _frameBuffersTSOrder.Next(frameListItem);
    }
    return oldestFrameListItem;
}

// Find oldest complete frame used for getting next frame to decode
// Must be called under critical section
// Based on sequence number
// Return NULL for lost packets
VCMFrameListItem*
VCMJitterBuffer::FindOldestCompleteContinuousFrame(bool enableDecodable) {
  // If we have more than one frame done since last time, pick oldest.
  VCMFrameBuffer* oldestFrame = NULL;
  int currentLow = -1;

  VCMFrameListItem* oldestFrameItem = _frameBuffersTSOrder.First();
  if (oldestFrameItem != NULL) {
    oldestFrame = oldestFrameItem->GetItem();
  }
  if (oldestFrame != NULL) {
    // Check for a complete or decodable frame (when enabled).
    VCMFrameBufferStateEnum state = oldestFrame->GetState();
    bool decodable = enableDecodable && (state == kStateDecodable);
    if ((state != kStateComplete) && !decodable) {
      oldestFrame = NULL;
    }
  }
  if (oldestFrame == NULL) {
    // No complete frame no point to continue
    return NULL;
  }

  // We have a complete frame.
  // Check if it's continuous, otherwise we are missing a full frame.

  // Use pictureId if available. Otherwise use seqNum and not timestamps, as
  // a complete frame might be lost.
  // First determine if we are waiting for a key frame.
  if (_waitingForKeyFrame && oldestFrame->FrameType() != kVideoFrameKey) {
    return NULL;
  }
  // Is this the first frame to be decoded?
  // Otherwise, establish continuity - use PictureId when available.
  if (_lastDecodedSeqNum == -1) {
    return oldestFrameItem;
  } else if (oldestFrame->PictureId() == kNoPictureId) {
    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 (when applicable).
    if (((WebRtc_UWord16)(lastDecodedSeqNum + 1)) != currentLow) {
      // Wait since we want a complete continuous frame.
      return NULL;
    }
  } else if (!ContinuousPictureId(oldestFrame->PictureId())) {
    // We don't have a continuous frame.
    return NULL;
  }
  return oldestFrameItem;
}

// Call from inside the critical section _critSect
void
VCMJitterBuffer::RecycleFrame(VCMFrameBuffer* frame)
{
    if (frame == NULL)
    {
        return;
    }

    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
                 VCMId(_vcmId, _receiverId),
                 "JB(0x%x) FB(0x%x): RecycleFrame, size:%d",
                 this, frame, frame->Length());

    ReleaseFrameInternal(frame);
}

// Calculate frame and bit rates
WebRtc_Word32
VCMJitterBuffer::GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord32& bitRate)
{
    CriticalSectionScoped cs(_critSect);
    const WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
    WebRtc_Word64 diff = now - _timeLastIncomingFrameCount;
    if (diff < 1000 && _incomingFrameRate > 0 && _incomingBitRate > 0)
    {
        // Make sure we report something even though less than
        // 1 second has passed since last update.
        frameRate = _incomingFrameRate;
        bitRate = _incomingBitRate;
    }
    else if (_incomingFrameCount != 0)
    {
        // We have received frame(s) since last call to this function

        // Prepare calculations
        if (diff <= 0)
        {
            diff = 1;
        }
        // we add 0.5f for rounding
        float rate = 0.5f + ((_incomingFrameCount * 1000.0f) / diff);
        if (rate < 1.0f) // don't go below 1, can crash
        {
            rate = 1.0f;
        }

        // Calculate frame rate
        // Let r be rate.
        // r(0) = 1000*framecount/delta_time.
        // (I.e. frames per second since last calculation.)
        // frameRate = r(0)/2 + r(-1)/2
        // (I.e. fr/s average this and the previous calculation.)
        frameRate = (_incomingFrameRate + (WebRtc_Word32)rate) >> 1;
        _incomingFrameRate = (WebRtc_UWord8)rate;

        // Calculate bit rate
        if (_incomingBitCount == 0)
        {
            bitRate = 0;
        }
        else
        {
            bitRate = 10 * ((100 * _incomingBitCount) /
                      static_cast<WebRtc_UWord32>(diff));
        }
        _incomingBitRate = bitRate;

        // Reset count
        _incomingFrameCount = 0;
        _incomingBitCount = 0;
        _timeLastIncomingFrameCount = now;

    }
    else
    {
        // No frames since last call
        _timeLastIncomingFrameCount = VCMTickTime::MillisecondTimestamp();
        frameRate = 0;
        bitRate = 0;
        _incomingBitRate = 0;
    }

    return 0;
}

// Returns immediately or a X ms event hang waiting for a complete frame,
// X decided by caller
VCMEncodedFrame*
VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
{
    if (!_running)
    {
        return NULL;
    }

    _critSect.Enter();

    CleanUpOldFrames();
    CleanUpSizeZeroFrames();

    if (_lastDecodedSeqNum == -1 && WaitForNack()) {
      _waitingForKeyFrame = true;
    }
    VCMFrameListItem*
      oldestFrameListItem = FindOldestCompleteContinuousFrame(false);
    VCMFrameBuffer* oldestFrame = NULL;
    if (oldestFrameListItem != NULL)
    {
        oldestFrame = oldestFrameListItem->GetItem();
    }

    if (oldestFrame == NULL)
    {
        if (maxWaitTimeMS == 0)
        {
            _critSect.Leave();
            return NULL;
        }
        const WebRtc_Word64 endWaitTimeMs = VCMTickTime::MillisecondTimestamp()
                                            + maxWaitTimeMS;
        WebRtc_Word64 waitTimeMs = maxWaitTimeMS;
        while (waitTimeMs > 0)
        {
            _critSect.Leave();
            const EventTypeWrapper ret =
                  _frameEvent.Wait(static_cast<WebRtc_UWord32>(waitTimeMs));
            _critSect.Enter();
            if (ret == kEventSignaled)
            {
                // are we closing down the Jitter buffer
                if (!_running)
                {
                    _critSect.Leave();
                    return NULL;
                }

                // Finding oldest frame ready for decoder, but check
                // sequence number and size
                CleanUpOldFrames();
                CleanUpSizeZeroFrames();
                oldestFrameListItem = FindOldestCompleteContinuousFrame(false);
                if (oldestFrameListItem != NULL)
                {
                    oldestFrame = oldestFrameListItem->GetItem();
                }
                if (oldestFrame == NULL)
                {
                    waitTimeMs = endWaitTimeMs -
                                 VCMTickTime::MillisecondTimestamp();
                }
                else
                {
                    break;
                }
            }
            else
            {
                _critSect.Leave();
                return NULL;
            }
        }
        // Inside critSect
    }
    else
    {
        // we already have a frame reset the event
        _frameEvent.Reset();
    }

    if (oldestFrame == NULL)
    {
        // Even after signaling we're still missing a complete continuous frame
        _critSect.Leave();
        return NULL;
    }

    // Update jitter estimate
    const bool retransmitted = (oldestFrame->GetNackCount() > 0);
    if (retransmitted)
    {
        _jitterEstimate.FrameNacked();
    }
    else if (oldestFrame->Length() > 0)
    {
        // Ignore retransmitted and empty frames.
        UpdateJitterAndDelayEstimates(*oldestFrame, false);
    }
    _frameBuffersTSOrder.Erase(oldestFrameListItem);
    oldestFrameListItem = NULL;

    oldestFrame->SetState(kStateDecoding);

    CleanUpOldFrames();
    CleanUpSizeZeroFrames();

    if (oldestFrame->FrameType() == kVideoFrameKey)
    {
        _waitingForKeyFrame = false;
    }

    _critSect.Leave();

    // We have a frame - store seqnum & timestamp
    _lastDecodedSeqNum = oldestFrame->GetHighSeqNum();
    _lastDecodedTimeStamp = oldestFrame->TimeStamp();
    _lastDecodedPictureId = oldestFrame->PictureId();

    return oldestFrame;
}

WebRtc_UWord32
VCMJitterBuffer::GetEstimatedJitterMS()
{
    CriticalSectionScoped cs(_critSect);
    return GetEstimatedJitterMsInternal();
}

WebRtc_UWord32
VCMJitterBuffer::GetEstimatedJitterMsInternal()
{
    WebRtc_UWord32 estimate = VCMJitterEstimator::OPERATING_SYSTEM_JITTER;

    // 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);
    return estimate;
}

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)
{
    if (!_running)
    {
        return -1;
    }

    _critSect.Enter();

    // Finding oldest frame ready for decoder, check sequence number and size
    CleanUpOldFrames();
    CleanUpSizeZeroFrames();

    VCMFrameBuffer* oldestFrame = _frameBuffersTSOrder.FirstFrame();

    if (oldestFrame == NULL)
    {
        _packetEvent.Reset();
        _critSect.Leave();

        if (_packetEvent.Wait(maxWaitTimeMS) == kEventSignaled)
        {
            // are we closing down the Jitter buffer
            if (!_running)
            {
                return -1;
            }
            _critSect.Enter();

            CleanUpOldFrames();
            CleanUpSizeZeroFrames();
            oldestFrame = _frameBuffersTSOrder.FirstFrame();
        }
        else
        {
            _critSect.Enter();
        }
    }

    if (oldestFrame == NULL)
    {
        _critSect.Leave();
        return -1;
    }
    // we have a frame

    // return frame type
    // All layers are assumed to have the same type
    incomingFrameType = oldestFrame->FrameType();

    renderTimeMs = oldestFrame->RenderTimeMs();

    const WebRtc_UWord32 timestamp = oldestFrame->TimeStamp();

    _critSect.Leave();

    // return current time
    return timestamp;
}

// Answers the question:
// 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()
{
    CriticalSectionScoped cs(_critSect);
    // Finding oldest frame ready for decoder, check sequence number and size
    CleanUpOldFrames();
    CleanUpSizeZeroFrames();

    VCMFrameListItem* oldestFrameListItem = _frameBuffersTSOrder.First();
    if (oldestFrameListItem == NULL)
    {
        // No frame found
        return true;
    }

    VCMFrameBuffer* oldestFrame = oldestFrameListItem->GetItem();
    const VCMFrameListItem* nextFrameItem =
                            _frameBuffersTSOrder.Next(oldestFrameListItem);
    if (nextFrameItem == NULL)
    {
        // Frame not ready to be decoded.
        return true;
    }
    if (!oldestFrame->Complete())
    {
        return false;
    }

    // See if we have lost a frame before this one.
    if (_lastDecodedSeqNum == -1)
    {
        // The sequence is not complete since we haven't yet.
        if (oldestFrame->FrameType() != kVideoFrameKey)
        {
            return false;
        }
    }
    else if (oldestFrame->GetLowSeqNum() == -1)
    {
        return false;
    }
    // We can't use sequence numbers to detect frame loss when FEC is enabled.
    // Assume FEC is only enabled for VP8 with picture ids, and use picture ids
    // to detect frame loss in that situation.
    else if (oldestFrame->PictureId() == kNoPictureId)
    {
        if (oldestFrame->GetLowSeqNum() !=
            (_lastDecodedSeqNum + 1) % 0x00010000)
        {
            return false;
        }
    }
    else if (!ContinuousPictureId(oldestFrame->PictureId()))
    {
        return false;
    }
    return true;
}

// Returns immediately
VCMEncodedFrame*
VCMJitterBuffer::GetFrameForDecoding()
{
    CriticalSectionScoped cs(_critSect);
    if (!_running)
    {
        return NULL;
    }

    if (WaitForNack())
    {
        return GetFrameForDecodingNACK();
    }

    CleanUpOldFrames();
    CleanUpSizeZeroFrames();

    VCMFrameListItem* oldestFrameListItem = _frameBuffersTSOrder.First();
    if (oldestFrameListItem == NULL)
    {
        return NULL;
    }
    VCMFrameBuffer* oldestFrame = oldestFrameListItem->GetItem();

    const VCMFrameListItem* nextFrameItem =
                            _frameBuffersTSOrder.Next(oldestFrameListItem);
    if (nextFrameItem == NULL)
    {
        return NULL;
    }

    // Incomplete frame pulled out from jitter buffer,
    // update the jitter estimate with what we currently know.
    // This frame shouldn't have been retransmitted, but if we recently
    // turned off NACK this might still happen.
    const bool retransmitted = (oldestFrame->GetNackCount() > 0);
    if (retransmitted)
    {
        _jitterEstimate.FrameNacked();
    }
    else if (oldestFrame->Length() > 0)
    {
        // Ignore retransmitted and empty frames.
        // Update with the previous incomplete frame first
        if (_waitingForCompletion.latestPacketTime >= 0)
        {
            UpdateJitterAndDelayEstimates(_waitingForCompletion, true);
        }
        // Then wait for this one to get complete
        _waitingForCompletion.frameSize = oldestFrame->Length();
        _waitingForCompletion.latestPacketTime =
                              oldestFrame->LatestPacketTimeMs();
        _waitingForCompletion.timestamp = oldestFrame->TimeStamp();
    }
    _frameBuffersTSOrder.Erase(oldestFrameListItem);
    oldestFrameListItem = NULL;

    // Look for previous frame loss
    VerifyAndSetPreviousFrameLost(*oldestFrame);

    // The state must be changed to decoding before cleaning up zero sized
    // frames to avoid empty frames being cleaned up and then given to the
    // decoder.
    // Set as decoding. Propagates the missingFrame bit.
    oldestFrame->SetState(kStateDecoding);

    CleanUpOldFrames();
    CleanUpSizeZeroFrames();

    if (oldestFrame->FrameType() == kVideoFrameKey)
    {
        _waitingForKeyFrame = false;
    }

    _packetsNotDecodable += oldestFrame->NotDecodablePackets();

    // Store current seqnum & time
    _lastDecodedSeqNum = oldestFrame->GetHighSeqNum();
    _lastDecodedTimeStamp = oldestFrame->TimeStamp();
    _lastDecodedPictureId = oldestFrame->PictureId();

    return oldestFrame;
}

VCMEncodedFrame*
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();
    CleanUpSizeZeroFrames();

    // First look for a complete _continuous_ frame.
    // When waiting for nack, wait for a key frame, if a continuous frame cannot
    // be determined (i.e. lastDecodedSeqNum = -1)
    if (_lastDecodedSeqNum == -1) {
      _waitingForKeyFrame = true;
    }

    // Allow for a decodable frame when in Hybrid mode.
    bool enableDecodable = _nackMode == kNackHybrid ? true : false;
    VCMFrameListItem*
    oldestFrameListItem = FindOldestCompleteContinuousFrame(enableDecodable);
    VCMFrameBuffer* oldestFrame = NULL;
    if (oldestFrameListItem != NULL)
    {
        oldestFrame = oldestFrameListItem->GetItem();
    }
    if (oldestFrame == NULL)
    {
        // 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();
        }
        if (oldestFrame == NULL)
        {
            return NULL;
        }
    }
    // Update jitter estimate
    const bool retransmitted = (oldestFrame->GetNackCount() > 0);
    if (retransmitted)
    {
        _jitterEstimate.FrameNacked();
    }
    else if (oldestFrame->Length() > 0)
    {
        // Ignore retransmitted and empty frames.
        UpdateJitterAndDelayEstimates(*oldestFrame, false);
    }
    _frameBuffersTSOrder.Erase(oldestFrameListItem);
    oldestFrameListItem = NULL;

    // Look for previous frame loss
    VerifyAndSetPreviousFrameLost(*oldestFrame);

    // The state must be changed to decoding before cleaning up zero sized
    // frames to avoid empty frames being cleaned up and then given to the
    // decoder.
    oldestFrame->SetState(kStateDecoding);

    // Clean up old frames and empty frames
    CleanUpOldFrames();
    CleanUpSizeZeroFrames();

    if (oldestFrame->FrameType() == kVideoFrameKey)
    {
        _waitingForKeyFrame = false;
    }

    // We have a complete/decodable continuous frame, decode it.
    // Store seqnum & timestamp
    _lastDecodedSeqNum = oldestFrame->GetHighSeqNum();
    _lastDecodedTimeStamp = oldestFrame->TimeStamp();
    _lastDecodedPictureId = oldestFrame->PictureId();

    return oldestFrame;
}

// 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(VCMJitterSample& sample,
                                               bool incompleteFrame)
{
    if (sample.latestPacketTime == -1)
    {
        return;
    }
    if (incompleteFrame)
    {
        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
                     VCMId(_vcmId, _receiverId), "Received incomplete frame "
                     "timestamp %u frame size %u at time %u",
                     sample.timestamp, sample.frameSize,
                     MaskWord64ToUWord32(sample.latestPacketTime));
    }
    else
    {
        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
                     VCMId(_vcmId, _receiverId), "Received complete frame "
                     "timestamp %u frame size %u at time %u",
                     sample.timestamp, sample.frameSize,
                     MaskWord64ToUWord32(sample.latestPacketTime));
    }
    UpdateJitterAndDelayEstimates(sample.latestPacketTime,
                                  sample.timestamp,
                                  sample.frameSize,
                                  incompleteFrame);
}

// 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(VCMFrameBuffer& frame,
                                               bool incompleteFrame)
{
    if (frame.LatestPacketTimeMs() == -1)
    {
        return;
    }
    // No retransmitted frames should be a part of the jitter
    // estimate.
    if (incompleteFrame)
    {
        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
                     VCMId(_vcmId, _receiverId),
                   "Received incomplete frame timestamp %u frame type %d "
                   "frame size %u at time %u, jitter estimate was %u",
                   frame.TimeStamp(), frame.FrameType(), frame.Length(),
                   MaskWord64ToUWord32(frame.LatestPacketTimeMs()),
                   GetEstimatedJitterMsInternal());
    }
    else
    {
        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
                     VCMId(_vcmId, _receiverId),"Received complete frame "
                     "timestamp %u frame type %d frame size %u at time %u, "
                     "jitter estimate was %u",
                     frame.TimeStamp(), frame.FrameType(), frame.Length(),
                     MaskWord64ToUWord32(frame.LatestPacketTimeMs()),
                     GetEstimatedJitterMsInternal());
    }
    UpdateJitterAndDelayEstimates(frame.LatestPacketTimeMs(), frame.TimeStamp(),
                                  frame.Length(), incompleteFrame);
}

// 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)
{
    if (latestPacketTimeMs == -1)
    {
        return;
    }
    WebRtc_Word64 frameDelay;
    // Calculate the delay estimate
    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
                 VCMId(_vcmId, _receiverId),
                 "Packet received and sent to jitter estimate with: "
                 "timestamp=%u wallClock=%u", timestamp,
                 MaskWord64ToUWord32(latestPacketTimeMs));
    bool notReordered = _delayEstimate.CalculateDelay(timestamp,
                                                      &frameDelay,
                                                      latestPacketTimeMs);
    // Filter out frames which have been reordered in time by the network
    if (notReordered)
    {
        // Update the jitter estimate with the new samples
        _jitterEstimate.UpdateEstimate(frameDelay, frameSize, incompleteFrame);
    }
}

WebRtc_UWord16*
VCMJitterBuffer::GetNackList(WebRtc_UWord16& nackSize,bool& listExtended)
{
    return CreateNackList(nackSize,listExtended);
}

// Assume called internally with critsect
WebRtc_Word32
VCMJitterBuffer::GetLowHighSequenceNumbers(WebRtc_Word32& lowSeqNum,
                                           WebRtc_Word32& highSeqNum) const
{
    WebRtc_Word32 i = 0;
    WebRtc_Word32 seqNum = -1;

    highSeqNum = -1;
    lowSeqNum = _lastDecodedSeqNum;

    // find highest seq numbers
    for (i = 0; i < _maxNumberOfFrames; ++i)
    {
        seqNum = _frameBuffers[i]->GetHighSeqNum();

        // Ignore free / empty frames
        VCMFrameBufferStateEnum state = _frameBuffers[i]->GetState();

        if ((kStateFree != state) &&
            (kStateEmpty != state) &&
            (kStateDecoding != state) &&
             seqNum != -1)
        {
            bool wrap;
            highSeqNum = LatestSequenceNumber(seqNum, highSeqNum, &wrap);
        }
    } // for
    return 0;
}


WebRtc_UWord16*
VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
{
    CriticalSectionScoped cs(_critSect);
    int i = 0;
    WebRtc_Word32 lowSeqNum = -1;
    WebRtc_Word32 highSeqNum = -1;
    listExtended = false;

    // Don't create list, if we won't wait for it
    if (!WaitForNack())
    {
        nackSize = 0;
        return NULL;
    }

    // Find the lowest (last decoded) sequence number and
    // the highest (highest sequence number of the newest frame)
    // sequence number. The nack list is a subset of the range
    // between those two numbers.
    GetLowHighSequenceNumbers(lowSeqNum, highSeqNum);

    // write a list of all seq num we have
    if (lowSeqNum == -1 || highSeqNum == -1)
    {
        // This happens if we lose the first packet, nothing is popped
        if (highSeqNum == -1)
        {
            // we have not received any packets yet
            nackSize = 0;
        }
        else
        {
            // signal that we want a key frame request to be sent
            nackSize = 0xffff;
        }
        return NULL;
    }

    int numberOfSeqNum = 0;
    if (lowSeqNum > highSeqNum)
    {
        if (lowSeqNum - highSeqNum > 0x00ff)
        {
            // wrap
            numberOfSeqNum = (0xffff-lowSeqNum) + highSeqNum + 1;
        }
    }
    else
    {
        numberOfSeqNum = highSeqNum - lowSeqNum;
    }

    if (numberOfSeqNum > kNackHistoryLength)
    {
        // Nack list is too big, flush and try to restart.
        WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding,
                     VCMId(_vcmId, _receiverId),
                     "Nack list too large, try to find a key frame and restart "
                     "from seq: %d. Lowest seq in jb %d", highSeqNum,lowSeqNum);

        // This nack size will trigger a key request...
        bool foundIFrame = false;

        while (numberOfSeqNum > kNackHistoryLength)
        {
            foundIFrame = RecycleFramesUntilKeyFrame();

            if (!foundIFrame)
            {
                break;
            }

            // Check if we still have too many packets in JB
            lowSeqNum = -1;
            highSeqNum = -1;
            GetLowHighSequenceNumbers(lowSeqNum, highSeqNum);

            if (highSeqNum == -1)
            {
                assert(lowSeqNum != -1); // This should never happen
                // We can't calculate the nack list length...
                return NULL;
            }

            numberOfSeqNum = 0;
            if (lowSeqNum > highSeqNum)
            {
                if (lowSeqNum - highSeqNum > 0x00ff)
                {
                    // wrap
                    numberOfSeqNum = (0xffff-lowSeqNum) + highSeqNum + 1;
                    highSeqNum=lowSeqNum;
                }
            }
            else
            {
                numberOfSeqNum = highSeqNum - lowSeqNum;
            }

        } // end while

        if (!foundIFrame)
        {
            // No I frame in JB.

            // Set the last decoded sequence number to current high.
            // This is to not get a large nack list again right away
            _lastDecodedSeqNum = highSeqNum;
            _waitingForKeyFrame = true;
            // Set to trigger key frame signal
            nackSize = 0xffff;
            listExtended = true;
            WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, -1,
                    "\tNo key frame found, request one. _lastDecodedSeqNum[0] "
                    "%d", _lastDecodedSeqNum);
        }
        else
        {
            // 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);
            nackSize = 0;
        }

        return NULL;
    }

    WebRtc_UWord16 seqNumberIterator = (WebRtc_UWord16)(lowSeqNum + 1);
    for (i = 0; i < numberOfSeqNum; i++)
    {
        _NACKSeqNumInternal[i] = seqNumberIterator;
        seqNumberIterator++;
    }

    // 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 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))
        {
            // 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)
            {
                _frameBuffers[i]->ZeroOutSeqNumHybrid(_NACKSeqNumInternal,
                                                      numberOfSeqNum,
                                                      _rttMs);
            }
            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);
            }
        }
    }

    // compress list
    int emptyIndex = -1;
    for (i = 0; i < numberOfSeqNum; i++)
    {
        if (_NACKSeqNumInternal[i] == -1 || _NACKSeqNumInternal[i] == -2 )
        {
            // this is empty
            if (emptyIndex == -1)
            {
                // no empty index before, remember this position
                emptyIndex = i;
            }
        }
        else
        {
            // this is not empty
            if (emptyIndex == -1)
            {
                // no empty index, continue
            }
            else
            {
                _NACKSeqNumInternal[emptyIndex] = _NACKSeqNumInternal[i];
                _NACKSeqNumInternal[i] = -1;
                emptyIndex++;
            }
        }
    } // for

    if (emptyIndex == -1)
    {
        // no empty
        nackSize = numberOfSeqNum;
    }
    else
    {
        nackSize = emptyIndex;
    }

    if (nackSize > _NACKSeqNumLength)
    {
        // Larger list: 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)
        {
            WebRtc_UWord32 k = 0;
            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])
                {
                   break;
                }
            }
            if (k == _NACKSeqNumLength) // New item not found in last list.
            {
                listExtended = true;
            }
        }
        else
        {
            listExtended = true;
        }
        _NACKSeqNum[j] = (WebRtc_UWord16)_NACKSeqNumInternal[j];
    }

    _NACKSeqNumLength = nackSize;

    return _NACKSeqNum;
}

// Release frame when done with decoding. Should never be used to release
// frames from within the jitter buffer.
void
VCMJitterBuffer::ReleaseFrame(VCMEncodedFrame* frame)
{
    CriticalSectionScoped cs(_critSect);
    VCMFrameBuffer* frameBuffer = static_cast<VCMFrameBuffer*>(frame);
    if (frameBuffer != NULL)
        frameBuffer->SetState(kStateFree);
}

WebRtc_Word64
VCMJitterBuffer::LastPacketTime(VCMEncodedFrame* frame,
                                bool& retransmitted) const
{
    CriticalSectionScoped cs(_critSect);
    retransmitted = (static_cast<VCMFrameBuffer*>(frame)->GetNackCount() > 0);
    return static_cast<VCMFrameBuffer*>(frame)->LatestPacketTimeMs();
}

WebRtc_Word64
VCMJitterBuffer::LastDecodedTimestamp() const
{
    CriticalSectionScoped cs(_critSect);
    return _lastDecodedTimeStamp;
}

// Insert packet
// Takes crit sect, and inserts packet in frame buffer, possibly does logging
VCMFrameBufferEnum
VCMJitterBuffer::InsertPacket(VCMEncodedFrame* buffer, const VCMPacket& packet)
{
    CriticalSectionScoped cs(_critSect);
    WebRtc_Word64 nowMs = VCMTickTime::MillisecondTimestamp();
    VCMFrameBufferEnum bufferReturn = kSizeError;
    VCMFrameBufferEnum ret = kSizeError;
    VCMFrameBuffer* frame = static_cast<VCMFrameBuffer*>(buffer);

    // We are keeping track of the first seq num, the latest seq num and
    // the number of wraps to be able to calculate how many packets we expect.
    if (_firstPacket)
    {
        // Now it's time to start estimating jitter
        // reset the delay estimate.
        _delayEstimate.Reset();
        _firstPacket = false;
    }

    // Empty packets may bias the jitter estimate (lacking size component),
    // therefore don't let empty packet trigger the following updates:
    if (packet.frameType != kFrameEmpty)
    {
        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 (packet.sizeBytes == 0 && packet.timestamp == _lastDecodedTimeStamp)
        {
            // Empty packet (sizeBytes = 0), make sure we update the last
            // decoded sequence number
            _lastDecodedSeqNum = LatestSequenceNumber(packet.seqNum,
                                                      _lastDecodedSeqNum, NULL);
        }

        // Insert packet
        // Check for first packet
        // High sequence number will be -1 if neither an empty packet nor
        // a media packet has been inserted.
        bool first = (frame->GetHighSeqNum() == -1);
        // When in Hybrid mode, we allow for a decodable state
        // Note: Under current version, a decodable frame will never be
        // triggered, as the body of the function is empty.
        // TODO (mikhal): Update when decodable is enabled.
        bufferReturn = frame->InsertPacket(packet, nowMs,
                                           _nackMode == kNackHybrid,
                                           _rttMs);
        ret = bufferReturn;

        if (bufferReturn > 0)
        {
            _incomingBitCount += packet.sizeBytes << 3;

            // Has this packet been nacked or is it about to be nacked?
            if (IsPacketRetransmitted(packet))
            {
                frame->IncrementNackCount();
            }

            // Insert each frame once on the arrival of the first packet
            // belonging to that frame (media or empty)
            if (state == kStateEmpty && first)
            {
                ret = kFirstPacket;
                _frameBuffersTSOrder.Insert(frame);
            }
        }
    }
    switch(bufferReturn)
    {
    case kStateError:
    case kTimeStampError:
    case kSizeError:
        {
            // This will trigger a release in CleanUpSizeZeroFrames
            if (frame != NULL)
            {
                frame->Reset();
                frame->SetState(kStateEmpty);
            }
            break;
        }
    case kCompleteSession:
        {
            // Only update return value for a JB flush indicator.
            if (UpdateFrameState(frame) == kFlushIndicator)
              ret = kFlushIndicator;
            // Signal that we have a received packet
            _packetEvent.Set();
            break;
        }
    case kDecodableSession:
    case kIncomplete:
        {
          // Signal that we have a received packet
          _packetEvent.Set();
          break;
        }
    case kNoError:
    case kDuplicatePacket:
        {
            break;
        }
    default:
        {
            assert(!"JitterBuffer::InsertPacket: Undefined value");
        }
    }
   return ret;
}

// Must be called from within _critSect
void
VCMJitterBuffer::UpdateOldJitterSample(const VCMPacket& packet)
{
    if (_waitingForCompletion.timestamp != packet.timestamp &&
        LatestTimestamp(_waitingForCompletion.timestamp, packet.timestamp,
                        NULL) == packet.timestamp)
    {
        // This is a newer frame than the one waiting for completion.
        _waitingForCompletion.frameSize = packet.sizeBytes;
        _waitingForCompletion.timestamp = packet.timestamp;
    }
    else
    {
        // This can get bad if we have a lot of duplicate packets,
        // we will then count some packet multiple times.
        _waitingForCompletion.frameSize += packet.sizeBytes;
        _jitterEstimate.UpdateMaxFrameSize(_waitingForCompletion.frameSize);
    }
}

// Must be called from within _critSect
bool
VCMJitterBuffer::IsPacketRetransmitted(const VCMPacket& packet) const
{
    if (_NACKSeqNum && _NACKSeqNumLength > 0)
    {
        for (WebRtc_UWord16 i = 0; i < _NACKSeqNumLength; i++)
        {
            if (packet.seqNum == _NACKSeqNum[i])
            {
                return true;
            }
        }
    }
    return false;
}

// Get nack status (enabled/disabled)
VCMNackMode
VCMJitterBuffer::GetNackMode() const
{
    CriticalSectionScoped cs(_critSect);
    return _nackMode;
}

// Set NACK mode
void
VCMJitterBuffer::SetNackMode(VCMNackMode mode)
{
    CriticalSectionScoped cs(_critSect);
    _nackMode = mode;
    if (_nackMode == kNoNack)
    {
        _jitterEstimate.ResetNackCount();
    }
}


// Recycle oldest frames up to a key frame, used if JB is completely full
bool
VCMJitterBuffer::RecycleFramesUntilKeyFrame()
{
    // Throw at least one frame.
    VCMFrameListItem* oldestFrameListItem = _frameBuffersTSOrder.First();
    VCMFrameBuffer* oldestFrame = NULL;
    if (oldestFrameListItem != NULL)
    {
        oldestFrame = oldestFrameListItem->GetItem();
    }

    // Remove up to oldest key frame
    bool foundIFrame = false;
    while (oldestFrameListItem != NULL && !foundIFrame)
    {
        // Throw at least one frame.
        _dropCount++;
        WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding,
                     VCMId(_vcmId, _receiverId),
                     "Jitter buffer drop count:%d, lowSeq %d", _dropCount,
                     oldestFrame->GetLowSeqNum());
        _frameBuffersTSOrder.Erase(oldestFrameListItem);
        RecycleFrame(oldestFrame);

        oldestFrameListItem = _frameBuffersTSOrder.First();
        if (oldestFrameListItem != NULL)
        {
            oldestFrame = oldestFrameListItem->GetItem();
        }

        if (oldestFrame != NULL)
        {
            foundIFrame = foundIFrame ||
                          (oldestFrame->FrameType() != kVideoFrameDelta);
            if (foundIFrame)
            {
                // fake the last played out to match the start of this key frame
                _lastDecodedSeqNum = (WebRtc_UWord16)((WebRtc_UWord16)
                                     (oldestFrame->GetLowSeqNum()) - 1);
                _lastDecodedTimeStamp = (WebRtc_UWord32)
                                        (oldestFrame->TimeStamp() - 1);
                break;
            }
        }
    }
    _lastDecodedSeqNum = -1;
    return foundIFrame;
}

// Must be called under the critical section _critSect.
void
VCMJitterBuffer::CleanUpOldFrames()
{
    VCMFrameListItem* oldestFrameListItem = _frameBuffersTSOrder.First();
    VCMFrameBuffer* oldestFrame = NULL;

    if (_lastDecodedTimeStamp == -1)
    {
        return;
    }

    while (oldestFrameListItem != NULL)
    {
        oldestFrame = oldestFrameListItem->GetItem();
        WebRtc_UWord32 frameTimeStamp = oldestFrame->TimeStamp();

        // Release the frame if it's older than the last decoded frame.
        if (_lastDecodedTimeStamp > -1 &&
            LatestTimestamp(static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp),
                            frameTimeStamp, NULL) ==
                            static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp))
        {
            const WebRtc_Word32 frameLowSeqNum = oldestFrame->GetLowSeqNum();
            const WebRtc_Word32 frameHighSeqNum = oldestFrame->GetHighSeqNum();
            if (frameTimeStamp == _lastDecodedTimeStamp &&
                ((frameLowSeqNum == (_lastDecodedSeqNum + 1)) ||
                ((frameLowSeqNum == 0) &&
                (_lastDecodedSeqNum == 0xffff))))
            {
                // Could happen when sending empty packets
                // Empty packet (size = 0) belonging to last decoded frame.
                // Frame: | packet | packet | packet M=1 |
                // empty data (size = 0) | empty data (size = 0)| ...

                // This frame follows the last decoded frame
                _lastDecodedSeqNum = frameHighSeqNum;
            }

            _frameBuffersTSOrder.Erase(oldestFrameListItem);
            ReleaseFrameInternal(oldestFrame);
            oldestFrameListItem = _frameBuffersTSOrder.First();
        }
        else
        {
            break;
        }
    }
}

// This function has changed to use sequence numbers
// Using timestamp won't work since can get
// nack requests with a higher time stamp than
// the following encoded frame, but with a lower sequence number.
// Must be called under _critSect.
void
VCMJitterBuffer::CleanUpSizeZeroFrames()
{
    VCMFrameListItem* frameListItem = FindOldestSequenceNum();

    while (frameListItem != NULL)
    {
        VCMFrameBuffer* ptrTempBuffer = frameListItem->GetItem();

        // pop frame if its size zero but store seqnum
        if (ptrTempBuffer->Length() == 0)
        {
            WebRtc_Word32 frameHighSeqNum = ptrTempBuffer->GetHighSeqNum();
            if (frameHighSeqNum == -1)
            {
                // This frame has been Reset for this function to clean it up
                _frameBuffersTSOrder.Erase(frameListItem);
                ReleaseFrameInternal(ptrTempBuffer);
                frameListItem = FindOldestSequenceNum();
            }
            else
            {
                bool releaseFrame = false;
                const WebRtc_Word32 frameHighSeqNum =
                                    ptrTempBuffer->GetHighSeqNum();
                const WebRtc_Word32 frameLowSeqNum =
                                    ptrTempBuffer->GetLowSeqNum();

                if ((frameLowSeqNum == (_lastDecodedSeqNum + 1)) ||
                    // Frame is next in line
                    ((frameLowSeqNum == 0) && (_lastDecodedSeqNum== 0xffff)))
                {
                    // This frame follows the last decoded frame, release it.
                    _lastDecodedSeqNum = frameHighSeqNum;
                    releaseFrame = true;
                }
                // If frameHighSeqNum < _lastDecodedSeqNum
                // but need to take wrap into account.
                else if (frameHighSeqNum < _lastDecodedSeqNum)
                {
                    if (frameHighSeqNum < 0x0fff &&
                        _lastDecodedSeqNum> 0xf000)
                    {
                        // Wrap, we don't want release this one. It's newer...
                    }
                    else
                    {
                        // This frame has lower seq than last decoded,
                        // and we have no wrap -> it's older.
                        releaseFrame = true;
                    }
                }
                else if (frameHighSeqNum > _lastDecodedSeqNum &&
                        _lastDecodedSeqNum < 0x0fff &&
                        frameHighSeqNum > 0xf000)
                {
                    // Higher seq than last decoded,
                    // but last decoded has recently wrapped.
                    releaseFrame = true;
                }

                if (releaseFrame)
                {
                    _frameBuffersTSOrder.Erase(frameListItem);
                    ReleaseFrameInternal(ptrTempBuffer);
                    frameListItem = FindOldestSequenceNum();
                }
                else
                {
                    // We couldn't release this one and we're using nack,
                    // stop trying...
                    frameListItem = NULL;
                }
            }
        }
        else
        {
            // we have a length
            break;
        }
    }
}

// Used in GetFrameForDecoding
void
VCMJitterBuffer::VerifyAndSetPreviousFrameLost(VCMFrameBuffer& frame)
{
    frame.MakeSessionDecodable(); // make sure the session can be decoded.
    if (frame.FrameType() == kVideoFrameKey)
        return;

    if (_lastDecodedSeqNum == -1)
    {
        // First frame is not a key frame
        frame.SetPreviousFrameLoss();
        return;
    }
    // We can't use sequence numbers to detect frame loss when FEC is enabled.
    // Assume FEC is only enabled for VP8 with picture ids, and use picture ids
    // to detect frame loss in that situation.
    if (frame.PictureId() == kNoPictureId)
    {
        WebRtc_UWord16 nextExpectedSeqNum =
            static_cast<WebRtc_UWord16>(_lastDecodedSeqNum + 1);
        if (static_cast<WebRtc_UWord16>(frame.GetLowSeqNum()) !=
            nextExpectedSeqNum)
        {
            frame.SetPreviousFrameLoss();
        }
    }
    else if (!ContinuousPictureId(frame.PictureId()))
    {
        frame.SetPreviousFrameLoss();
    }
}

bool VCMJitterBuffer::ContinuousPictureId(int pictureId) const {
  if (pictureId < _lastDecodedPictureId) {
    // Wrap
    if (_lastDecodedPictureId >= (1<<8)) {
      // 15 bits used for picture id
      return (((_lastDecodedPictureId + 1) % 0x7FFF) == pictureId);
    } else {
      // 7 bits used for picture id
      return (((_lastDecodedPictureId + 1) % 0x7F) == pictureId);
    }
  }
  // No wrap
  return (_lastDecodedPictureId + 1 == pictureId);
}

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;
     }
     // Either NACK only or hybrid
     return true;
}


}
