/*
 *  Copyright (c) 2012 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 "rtcp_receiver.h"

#include <string.h> //memset
#include <cassert> //assert

#include "trace.h"
#include "critical_section_wrapper.h"
#include "rtcp_utility.h"
#include "rtp_rtcp_impl.h"

namespace
{
    const float FRAC = 4.294967296E9;
}

namespace webrtc {
using namespace RTCPUtility;
using namespace RTCPHelp;

RTCPReceiver::RTCPReceiver(const WebRtc_Word32 id, RtpRtcpClock* clock,
                           ModuleRtpRtcpImpl* owner)
    : TMMBRHelp(),
      _id(id),
      _clock(*clock),
      _method(kRtcpOff),
      _lastReceived(0),
      _rtpRtcp(*owner),
      _criticalSectionFeedbacks(
          CriticalSectionWrapper::CreateCriticalSection()),
      _cbRtcpFeedback(NULL),
      _cbVideoFeedback(NULL),
      _criticalSectionRTCPReceiver(
          CriticalSectionWrapper::CreateCriticalSection()),
      _SSRC(0),
      _remoteSSRC(0),
      _remoteSenderInfo(),
      _lastReceivedSRNTPsecs(0),
      _lastReceivedSRNTPfrac(0),
      _receivedInfoMap(),
      _packetTimeOutMS(0),
      _rtt(0) {
    memset(&_remoteSenderInfo, 0, sizeof(_remoteSenderInfo));
    WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
}

RTCPReceiver::~RTCPReceiver() {
  delete _criticalSectionRTCPReceiver;
  delete _criticalSectionFeedbacks;

  while (!_receivedReportBlockMap.empty()) {
    std::map<WebRtc_UWord32, RTCPReportBlockInformation*>::iterator first =
        _receivedReportBlockMap.begin();
    delete first->second;
    _receivedReportBlockMap.erase(first);
  }
  while (!_receivedInfoMap.empty()) {
    std::map<WebRtc_UWord32, RTCPReceiveInformation*>::iterator first =
        _receivedInfoMap.begin();
    delete first->second;
    _receivedInfoMap.erase(first);
  }
  while (!_receivedCnameMap.empty()) {
    std::map<WebRtc_UWord32, RTCPCnameInformation*>::iterator first =
        _receivedCnameMap.begin();
    delete first->second;
    _receivedCnameMap.erase(first);
  }
  WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, _id,
               "%s deleted", __FUNCTION__);
}

void
RTCPReceiver::ChangeUniqueId(const WebRtc_Word32 id)
{
    _id = id;
}

RTCPMethod
RTCPReceiver::Status() const
{
    CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
    return _method;
}

WebRtc_Word32
RTCPReceiver::SetRTCPStatus(const RTCPMethod method)
{
    CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
    _method = method;
    return 0;
}

WebRtc_UWord32
RTCPReceiver::LastReceived()
{
    CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
    return _lastReceived;
}

WebRtc_Word32
RTCPReceiver::SetRemoteSSRC( const WebRtc_UWord32 ssrc)
{
    CriticalSectionScoped lock(_criticalSectionRTCPReceiver);

    // new SSRC reset old reports
    memset(&_remoteSenderInfo, 0, sizeof(_remoteSenderInfo));
    _lastReceivedSRNTPsecs = 0;
    _lastReceivedSRNTPfrac = 0;

    _remoteSSRC = ssrc;
    return 0;
}

WebRtc_Word32
RTCPReceiver::RegisterIncomingRTCPCallback(RtcpFeedback* incomingMessagesCallback)
{
    CriticalSectionScoped lock(_criticalSectionFeedbacks);
    _cbRtcpFeedback = incomingMessagesCallback;
    return 0;
}

WebRtc_Word32
RTCPReceiver::RegisterIncomingVideoCallback(RtpVideoFeedback* incomingMessagesCallback)
{
    CriticalSectionScoped lock(_criticalSectionFeedbacks);
    _cbVideoFeedback = incomingMessagesCallback;
    return 0;
}

void
RTCPReceiver::SetSSRC( const WebRtc_UWord32 ssrc)
{
    CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
    _SSRC = ssrc;
}

WebRtc_Word32 RTCPReceiver::ResetRTT(const WebRtc_UWord32 remoteSSRC) {
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
  RTCPReportBlockInformation* reportBlock =
      GetReportBlockInformation(remoteSSRC);
  if (reportBlock == NULL) {
    WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
                 "\tfailed to GetReportBlockInformation(%u)", remoteSSRC);
    return -1;
  }
  reportBlock->RTT = 0;
  reportBlock->avgRTT = 0;
  reportBlock->minRTT = 0;
  reportBlock->maxRTT = 0;

  return 0;
}

WebRtc_Word32 RTCPReceiver::RTT(const WebRtc_UWord32 remoteSSRC,
                                WebRtc_UWord16* RTT,
                                WebRtc_UWord16* avgRTT,
                                WebRtc_UWord16* minRTT,
                                WebRtc_UWord16* maxRTT) const {
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);

  RTCPReportBlockInformation* reportBlock =
      GetReportBlockInformation(remoteSSRC);

  if (reportBlock == NULL) {
    WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
                 "\tfailed to GetReportBlockInformation(%u)",
                 remoteSSRC);
    return -1;
  }
  if (RTT) {
    *RTT = reportBlock->RTT;
  }
  if (avgRTT) {
    *avgRTT = reportBlock->avgRTT;
  }
  if (minRTT) {
    *minRTT = reportBlock->minRTT;
  }
  if (maxRTT) {
    *maxRTT = reportBlock->maxRTT;
  }
  return 0;
}

WebRtc_UWord16 RTCPReceiver::RTT() const {
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
  if (!_receivedReportBlockMap.empty()) {
    return 0;
  }
  return _rtt;
}

int RTCPReceiver::SetRTT(WebRtc_UWord16 rtt) {
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
  if (!_receivedReportBlockMap.empty()) {
    return -1;
  }
  _rtt = rtt;
  return 0;
}

void
RTCPReceiver::UpdateLipSync(const WebRtc_Word32 audioVideoOffset) const
{
    CriticalSectionScoped lock(_criticalSectionFeedbacks);
    if(_cbRtcpFeedback)
    {
        _cbRtcpFeedback->OnLipSyncUpdate(_id,audioVideoOffset);
    }
};

WebRtc_Word32
RTCPReceiver::NTP(WebRtc_UWord32 *ReceivedNTPsecs,
                  WebRtc_UWord32 *ReceivedNTPfrac,
                  WebRtc_UWord32 *RTCPArrivalTimeSecs,
                  WebRtc_UWord32 *RTCPArrivalTimeFrac) const
{
    CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
    if(ReceivedNTPsecs)
    {
        *ReceivedNTPsecs = _remoteSenderInfo.NTPseconds; // NTP from incoming SendReport
    }
    if(ReceivedNTPfrac)
    {
        *ReceivedNTPfrac = _remoteSenderInfo.NTPfraction;
    }
    if(RTCPArrivalTimeFrac)
    {
        *RTCPArrivalTimeFrac = _lastReceivedSRNTPfrac; // local NTP time when we received a RTCP packet with a send block
    }
    if(RTCPArrivalTimeSecs)
    {
        *RTCPArrivalTimeSecs = _lastReceivedSRNTPsecs;
    }
    return 0;
}

WebRtc_Word32
RTCPReceiver::SenderInfoReceived(RTCPSenderInfo* senderInfo) const
{
    if(senderInfo == NULL)
    {
        WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
        return -1;
    }
    CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
    if(_lastReceivedSRNTPsecs == 0)
    {
        WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "%s No received SR", __FUNCTION__);
        return -1;
    }
    memcpy(senderInfo, &(_remoteSenderInfo), sizeof(RTCPSenderInfo));
    return 0;
}

// statistics
// we can get multiple receive reports when we receive the report from a CE
WebRtc_Word32 RTCPReceiver::StatisticsReceived(
    std::vector<RTCPReportBlock>* receiveBlocks) const {
  assert(receiveBlocks);
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);

  std::map<WebRtc_UWord32, RTCPReportBlockInformation*>::const_iterator it =
      _receivedReportBlockMap.begin();

  while (it != _receivedReportBlockMap.end()) {
    receiveBlocks->push_back(it->second->remoteReceiveBlock);
    it++;
  }
  return 0;
}

WebRtc_Word32
RTCPReceiver::IncomingRTCPPacket(RTCPPacketInformation& rtcpPacketInformation,
                                 RTCPUtility::RTCPParserV2* rtcpParser)
{
    CriticalSectionScoped lock(_criticalSectionRTCPReceiver);

    _lastReceived = _clock.GetTimeInMS();

    RTCPUtility::RTCPPacketTypes pktType = rtcpParser->Begin();
    while (pktType != RTCPUtility::kRtcpNotValidCode)
    {
        // Each "case" is responsible for iterate the parser to the
        // next top level packet.
        switch (pktType)
        {
        case RTCPUtility::kRtcpSrCode:
        case RTCPUtility::kRtcpRrCode:
            HandleSenderReceiverReport(*rtcpParser, rtcpPacketInformation);
            break;
        case RTCPUtility::kRtcpSdesCode:
            HandleSDES(*rtcpParser);
            break;
        case RTCPUtility::kRtcpXrVoipMetricCode:
            HandleXRVOIPMetric(*rtcpParser, rtcpPacketInformation);
            break;
        case RTCPUtility::kRtcpByeCode:
            HandleBYE(*rtcpParser);
            break;
        case RTCPUtility::kRtcpRtpfbNackCode:
            HandleNACK(*rtcpParser, rtcpPacketInformation);
            break;
        case RTCPUtility::kRtcpRtpfbTmmbrCode:
            HandleTMMBR(*rtcpParser, rtcpPacketInformation);
            break;
        case RTCPUtility::kRtcpRtpfbTmmbnCode:
            HandleTMMBN(*rtcpParser);
            break;
        case RTCPUtility::kRtcpRtpfbSrReqCode:
            HandleSR_REQ(*rtcpParser, rtcpPacketInformation);
            break;
        case RTCPUtility::kRtcpPsfbPliCode:
            HandlePLI(*rtcpParser, rtcpPacketInformation);
            break;
        case RTCPUtility::kRtcpPsfbSliCode:
            HandleSLI(*rtcpParser, rtcpPacketInformation);
            break;
        case RTCPUtility::kRtcpPsfbRpsiCode:
            HandleRPSI(*rtcpParser, rtcpPacketInformation);
            break;
        case RTCPUtility::kRtcpExtendedIjCode:
            HandleIJ(*rtcpParser, rtcpPacketInformation);
            break;
        case RTCPUtility::kRtcpPsfbFirCode:
            HandleFIR(*rtcpParser, rtcpPacketInformation);
            break;
        case RTCPUtility::kRtcpPsfbAppCode:
            HandlePsfbApp(*rtcpParser, rtcpPacketInformation);
            break;
        case RTCPUtility::kRtcpAppCode:
            // generic application messages
            HandleAPP(*rtcpParser, rtcpPacketInformation);
            break;
        case RTCPUtility::kRtcpAppItemCode:
            // generic application messages
            HandleAPPItem(*rtcpParser, rtcpPacketInformation);
            break;
        default:
            rtcpParser->Iterate();
            break;
        }
        pktType = rtcpParser->PacketType();
    }
    return 0;
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleSenderReceiverReport(RTCPUtility::RTCPParserV2& rtcpParser,
                                         RTCPPacketInformation& rtcpPacketInformation)
{
    RTCPUtility::RTCPPacketTypes rtcpPacketType = rtcpParser.PacketType();
    const RTCPUtility::RTCPPacket& rtcpPacket   = rtcpParser.Packet();

    assert((rtcpPacketType == RTCPUtility::kRtcpRrCode) || (rtcpPacketType == RTCPUtility::kRtcpSrCode));

    // SR.SenderSSRC
    // The synchronization source identifier for the originator of this SR packet

    // rtcpPacket.RR.SenderSSRC
    // The source of the packet sender, same as of SR? or is this a CE?

    const WebRtc_UWord32 remoteSSRC = (rtcpPacketType == RTCPUtility::kRtcpRrCode) ? rtcpPacket.RR.SenderSSRC:rtcpPacket.SR.SenderSSRC;
    const WebRtc_UWord8  numberOfReportBlocks = (rtcpPacketType == RTCPUtility::kRtcpRrCode) ? rtcpPacket.RR.NumberOfReportBlocks:rtcpPacket.SR.NumberOfReportBlocks;

    rtcpPacketInformation.remoteSSRC = remoteSSRC;

    RTCPReceiveInformation* ptrReceiveInfo = CreateReceiveInformation(remoteSSRC);
    if (!ptrReceiveInfo)
    {
        rtcpParser.Iterate();
        return;
    }

    if (rtcpPacketType == RTCPUtility::kRtcpSrCode)
    {
        WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, _id,
            "Received SR(%d). SSRC:0x%x, from SSRC:0x%x, to us %d.", _id, _SSRC, remoteSSRC, (_remoteSSRC == remoteSSRC)?1:0);

        if (_remoteSSRC == remoteSSRC) // have I received RTP packets from this party
        {
            // only signal that we have received a SR when we accept one
            rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpSr;

            // We will only store the send report from one source, but
            // we will store all the receive block

            // Save the NTP time of this report
            _remoteSenderInfo.NTPseconds = rtcpPacket.SR.NTPMostSignificant;
            _remoteSenderInfo.NTPfraction = rtcpPacket.SR.NTPLeastSignificant;
            _remoteSenderInfo.RTPtimeStamp = rtcpPacket.SR.RTPTimestamp;
            _remoteSenderInfo.sendPacketCount = rtcpPacket.SR.SenderPacketCount;
            _remoteSenderInfo.sendOctetCount = rtcpPacket.SR.SenderOctetCount;

            _clock.CurrentNTP(_lastReceivedSRNTPsecs, _lastReceivedSRNTPfrac);
        }
        else
        {
            rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRr;
        }
    } else
    {
        WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, _id,
            "Received RR(%d). SSRC:0x%x, from SSRC:0x%x", _id, _SSRC, remoteSSRC);

        rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRr;
    }
    UpdateReceiveInformation(*ptrReceiveInfo);

    rtcpPacketType = rtcpParser.Iterate();

    while (rtcpPacketType == RTCPUtility::kRtcpReportBlockItemCode)
    {
        HandleReportBlock(rtcpPacket, rtcpPacketInformation, remoteSSRC, numberOfReportBlocks);
        rtcpPacketType = rtcpParser.Iterate();
    }
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleReportBlock(const RTCPUtility::RTCPPacket& rtcpPacket,
                                RTCPPacketInformation& rtcpPacketInformation,
                                const WebRtc_UWord32 remoteSSRC,
                                const WebRtc_UWord8 numberOfReportBlocks) {
  // This will be called once per report block in the RTCP packet.
  // We filter out all report blocks that are not for us.
  // Each packet has max 31 RR blocks.
  //
  // We can calc RTT if we send a send report and get a report block back.

  // |rtcpPacket.ReportBlockItem.SSRC| is the SSRC identifier of the source to
  // which the information in this reception report block pertains.

  // Filter out all report blocks that are not for us.
  if (rtcpPacket.ReportBlockItem.SSRC != _SSRC) {
    // This block is not for us ignore it.
    return;
  }

  // To avoid problem with acquiring _criticalSectionRTCPSender while holding
  // _criticalSectionRTCPReceiver.
  _criticalSectionRTCPReceiver->Leave();
  WebRtc_UWord32 sendTimeMS =
      _rtpRtcp.SendTimeOfSendReport(rtcpPacket.ReportBlockItem.LastSR);
  _criticalSectionRTCPReceiver->Enter();

  RTCPReportBlockInformation* reportBlock =
      CreateReportBlockInformation(remoteSSRC);
  if (reportBlock == NULL) {
    WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
                 "\tfailed to CreateReportBlockInformation(%u)", remoteSSRC);
    return;
  }
  const RTCPPacketReportBlockItem& rb = rtcpPacket.ReportBlockItem;
  reportBlock->remoteReceiveBlock.remoteSSRC = remoteSSRC;
  reportBlock->remoteReceiveBlock.sourceSSRC = rb.SSRC;
  reportBlock->remoteReceiveBlock.fractionLost = rb.FractionLost;
  reportBlock->remoteReceiveBlock.cumulativeLost =
      rb.CumulativeNumOfPacketsLost;
  reportBlock->remoteReceiveBlock.extendedHighSeqNum =
      rb.ExtendedHighestSequenceNumber;
  reportBlock->remoteReceiveBlock.jitter = rb.Jitter;
  reportBlock->remoteReceiveBlock.delaySinceLastSR = rb.DelayLastSR;
  reportBlock->remoteReceiveBlock.lastSR = rb.LastSR;

  if (rtcpPacket.ReportBlockItem.Jitter > reportBlock->remoteMaxJitter) {
    reportBlock->remoteMaxJitter = rtcpPacket.ReportBlockItem.Jitter;
  }

  WebRtc_UWord32 delaySinceLastSendReport =
      rtcpPacket.ReportBlockItem.DelayLastSR;

  // local NTP time when we received this
  WebRtc_UWord32 lastReceivedRRNTPsecs = 0;
  WebRtc_UWord32 lastReceivedRRNTPfrac = 0;

  _clock.CurrentNTP(lastReceivedRRNTPsecs, lastReceivedRRNTPfrac);

  // time when we received this in MS
  WebRtc_UWord32 receiveTimeMS = ModuleRTPUtility::ConvertNTPTimeToMS(
      lastReceivedRRNTPsecs, lastReceivedRRNTPfrac);

  // Estimate RTT
  WebRtc_UWord32 d = (delaySinceLastSendReport & 0x0000ffff) * 1000;
  d /= 65536;
  d += ((delaySinceLastSendReport & 0xffff0000) >> 16) * 1000;

  WebRtc_Word32 RTT = 0;

  if (sendTimeMS > 0) {
    RTT = receiveTimeMS - d - sendTimeMS;
    if (RTT <= 0) {
      RTT = 1;
    }
    if (RTT > reportBlock->maxRTT) {
      // store max RTT
      reportBlock->maxRTT = (WebRtc_UWord16) RTT;
    }
    if (reportBlock->minRTT == 0) {
      // first RTT
      reportBlock->minRTT = (WebRtc_UWord16) RTT;
    } else if (RTT < reportBlock->minRTT) {
      // Store min RTT
      reportBlock->minRTT = (WebRtc_UWord16) RTT;
    }
    // store last RTT
    reportBlock->RTT = (WebRtc_UWord16) RTT;

    // store average RTT
    if (reportBlock->numAverageCalcs != 0) {
      float ac = static_cast<float> (reportBlock->numAverageCalcs);
      float newAverage = ((ac / (ac + 1)) * reportBlock->avgRTT)
          + ((1 / (ac + 1)) * RTT);
      reportBlock->avgRTT = static_cast<int> (newAverage + 0.5f);
    } else {
      // first RTT
      reportBlock->avgRTT = (WebRtc_UWord16) RTT;
    }
    reportBlock->numAverageCalcs++;
  }

  WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, _id,
               " -> Received report block(%d), from SSRC:0x%x, RTT:%d, loss:%d",
               _id, remoteSSRC, RTT, rtcpPacket.ReportBlockItem.FractionLost);

  // rtcpPacketInformation
  rtcpPacketInformation.AddReportInfo(
      reportBlock->remoteReceiveBlock.fractionLost, (WebRtc_UWord16) RTT,
      reportBlock->remoteReceiveBlock.extendedHighSeqNum,
      reportBlock->remoteReceiveBlock.jitter);
}

RTCPReportBlockInformation*
RTCPReceiver::CreateReportBlockInformation(WebRtc_UWord32 remoteSSRC) {
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);

  std::map<WebRtc_UWord32, RTCPReportBlockInformation*>::iterator it =
      _receivedReportBlockMap.find(remoteSSRC);

  RTCPReportBlockInformation* ptrReportBlockInfo = NULL;
  if (it != _receivedReportBlockMap.end()) {
    ptrReportBlockInfo = it->second;
  } else {
    ptrReportBlockInfo = new RTCPReportBlockInformation;
    _receivedReportBlockMap[remoteSSRC] = ptrReportBlockInfo;
  }
  return ptrReportBlockInfo;
}

RTCPReportBlockInformation*
RTCPReceiver::GetReportBlockInformation(WebRtc_UWord32 remoteSSRC) const {
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);

  std::map<WebRtc_UWord32, RTCPReportBlockInformation*>::const_iterator it =
      _receivedReportBlockMap.find(remoteSSRC);

  if (it == _receivedReportBlockMap.end()) {
    return NULL;
  }
  return it->second;
}

RTCPCnameInformation*
RTCPReceiver::CreateCnameInformation(WebRtc_UWord32 remoteSSRC) {
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);

  std::map<WebRtc_UWord32, RTCPCnameInformation*>::iterator it =
      _receivedCnameMap.find(remoteSSRC);

  if (it != _receivedCnameMap.end()) {
    return it->second;
  }
  RTCPCnameInformation* cnameInfo = new RTCPCnameInformation;
  memset(cnameInfo->name, 0, RTCP_CNAME_SIZE);
  _receivedCnameMap[remoteSSRC] = cnameInfo;
  return cnameInfo;
}

RTCPCnameInformation*
RTCPReceiver::GetCnameInformation(WebRtc_UWord32 remoteSSRC) const {
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);

  std::map<WebRtc_UWord32, RTCPCnameInformation*>::const_iterator it =
      _receivedCnameMap.find(remoteSSRC);

  if (it == _receivedCnameMap.end()) {
    return NULL;
  }
  return it->second;
}

RTCPReceiveInformation*
RTCPReceiver::CreateReceiveInformation(WebRtc_UWord32 remoteSSRC) {
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);

  std::map<WebRtc_UWord32, RTCPReceiveInformation*>::iterator it =
      _receivedInfoMap.find(remoteSSRC);

  if (it != _receivedInfoMap.end()) {
    return it->second;
  }
  RTCPReceiveInformation* receiveInfo = new RTCPReceiveInformation;
  _receivedInfoMap[remoteSSRC] = receiveInfo;
  return receiveInfo;
}

RTCPReceiveInformation*
RTCPReceiver::GetReceiveInformation(WebRtc_UWord32 remoteSSRC) {
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);

  std::map<WebRtc_UWord32, RTCPReceiveInformation*>::iterator it =
      _receivedInfoMap.find(remoteSSRC);
  if (it == _receivedInfoMap.end()) {
    return NULL;
  }
  return it->second;
}

void RTCPReceiver::UpdateReceiveInformation(
    RTCPReceiveInformation& receiveInformation) {
  // Update that this remote is alive
  receiveInformation.lastTimeReceived = _clock.GetTimeInMS();
}

bool RTCPReceiver::UpdateRTCPReceiveInformationTimers() {
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);

  bool updateBoundingSet = false;
  WebRtc_UWord32 timeNow = _clock.GetTimeInMS();

  std::map<WebRtc_UWord32, RTCPReceiveInformation*>::iterator receiveInfoIt =
      _receivedInfoMap.begin();

  while (receiveInfoIt != _receivedInfoMap.end()) {
    RTCPReceiveInformation* receiveInfo = receiveInfoIt->second;
    if (receiveInfo == NULL) {
      return updateBoundingSet;
    }
    // time since last received rtcp packet
    // when we dont have a lastTimeReceived and the object is marked
    // readyForDelete it's removed from the map
    if (receiveInfo->lastTimeReceived) {
      /// use audio define since we don't know what interval the remote peer is
      // using
      if ((timeNow - receiveInfo->lastTimeReceived) >
          5 * RTCP_INTERVAL_AUDIO_MS) {
        // no rtcp packet for the last five regular intervals, reset limitations
        receiveInfo->TmmbrSet.lengthOfSet = 0;
        // prevent that we call this over and over again
        receiveInfo->lastTimeReceived = 0;
        // send new TMMBN to all channels using the default codec
        updateBoundingSet = true;
      }
      receiveInfoIt++;
    } else if (receiveInfo->readyForDelete) {
      // store our current receiveInfoItem
      std::map<WebRtc_UWord32, RTCPReceiveInformation*>::iterator
      receiveInfoItemToBeErased = receiveInfoIt;
      receiveInfoIt++;
      delete receiveInfoItemToBeErased->second;
      _receivedInfoMap.erase(receiveInfoItemToBeErased);
    } else {
      receiveInfoIt++;
    }
  }
  return updateBoundingSet;
}

WebRtc_Word32 RTCPReceiver::BoundingSet(bool &tmmbrOwner,
                                        TMMBRSet*& boundingSetRec) {
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);

  std::map<WebRtc_UWord32, RTCPReceiveInformation*>::iterator receiveInfoIt =
      _receivedInfoMap.find(_remoteSSRC);

  if (receiveInfoIt == _receivedInfoMap.end()) {
    return -1;
  }
  RTCPReceiveInformation* receiveInfo = receiveInfoIt->second;
  if (receiveInfo == NULL) {
    WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
                 "%s failed to get RTCPReceiveInformation",
                 __FUNCTION__);
    return -1;
  }
  if (receiveInfo->TmmbnBoundingSet.lengthOfSet > 0) {
    boundingSetRec->VerifyAndAllocateSet(
        receiveInfo->TmmbnBoundingSet.lengthOfSet + 1);
    for(WebRtc_UWord32 i=0; i< receiveInfo->TmmbnBoundingSet.lengthOfSet; i++) {
      if(receiveInfo->TmmbnBoundingSet.ptrSsrcSet[i] == _SSRC) {
        // owner of bounding set
        tmmbrOwner = true;
      }
      boundingSetRec->ptrTmmbrSet[i] =
          receiveInfo->TmmbnBoundingSet.ptrTmmbrSet[i];
      boundingSetRec->ptrPacketOHSet[i] =
          receiveInfo->TmmbnBoundingSet.ptrPacketOHSet[i];
      boundingSetRec->ptrSsrcSet[i] =
          receiveInfo->TmmbnBoundingSet.ptrSsrcSet[i];
    }
  }
  return receiveInfo->TmmbnBoundingSet.lengthOfSet;
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleSDES(RTCPUtility::RTCPParserV2& rtcpParser)
{
    RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
    while (pktType == RTCPUtility::kRtcpSdesChunkCode)
    {
        HandleSDESChunk(rtcpParser);
        pktType = rtcpParser.Iterate();
    }
}

// no need for critsect we have _criticalSectionRTCPReceiver
void RTCPReceiver::HandleSDESChunk(RTCPUtility::RTCPParserV2& rtcpParser) {
  const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
  RTCPCnameInformation* cnameInfo =
      CreateCnameInformation(rtcpPacket.CName.SenderSSRC);
  assert(cnameInfo);

  cnameInfo->name[RTCP_CNAME_SIZE - 1] = 0;
  strncpy(cnameInfo->name, rtcpPacket.CName.CName, RTCP_CNAME_SIZE - 1);
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleNACK(RTCPUtility::RTCPParserV2& rtcpParser,
                         RTCPPacketInformation& rtcpPacketInformation)
{
    const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();

    RTCPReceiveInformation* ptrReceiveInfo = GetReceiveInformation(rtcpPacket.NACK.SenderSSRC);
    if (ptrReceiveInfo == NULL)
    {
        // This remote SSRC must be saved before.
        rtcpParser.Iterate();
        return;
    }
    if (_SSRC != rtcpPacket.NACK.MediaSSRC)
    {
        // Not to us.
        rtcpParser.Iterate();
        return;
    }

    rtcpPacketInformation.ResetNACKPacketIdArray();

    RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
    while (pktType == RTCPUtility::kRtcpRtpfbNackItemCode)
    {
        HandleNACKItem(rtcpPacket, rtcpPacketInformation);
        pktType = rtcpParser.Iterate();
    }
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleNACKItem(const RTCPUtility::RTCPPacket& rtcpPacket,
                             RTCPPacketInformation& rtcpPacketInformation)
{
    rtcpPacketInformation.AddNACKPacket(rtcpPacket.NACKItem.PacketID);

    WebRtc_UWord16 bitMask = rtcpPacket.NACKItem.BitMask;
    if(bitMask)
    {
        for(int i=1; i <= 16; ++i)
        {
            if(bitMask & 0x01)
            {
                rtcpPacketInformation.AddNACKPacket(rtcpPacket.NACKItem.PacketID + i);
            }
            bitMask = bitMask >>1;
        }
    }

    rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpNack;
}

// no need for critsect we have _criticalSectionRTCPReceiver
void RTCPReceiver::HandleBYE(RTCPUtility::RTCPParserV2& rtcpParser) {
  const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();

  // clear our lists
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
  std::map<WebRtc_UWord32, RTCPReportBlockInformation*>::iterator
      reportBlockInfoIt = _receivedReportBlockMap.find(
          rtcpPacket.BYE.SenderSSRC);

  if (reportBlockInfoIt != _receivedReportBlockMap.end()) {
    delete reportBlockInfoIt->second;
    _receivedReportBlockMap.erase(reportBlockInfoIt);
  }
  //  we can't delete it due to TMMBR
  std::map<WebRtc_UWord32, RTCPReceiveInformation*>::iterator receiveInfoIt =
      _receivedInfoMap.find(rtcpPacket.BYE.SenderSSRC);

  if (receiveInfoIt != _receivedInfoMap.end()) {
    receiveInfoIt->second->readyForDelete = true;
  }

  std::map<WebRtc_UWord32, RTCPCnameInformation*>::iterator cnameInfoIt =
      _receivedCnameMap.find(rtcpPacket.BYE.SenderSSRC);

  if (cnameInfoIt != _receivedCnameMap.end()) {
    delete cnameInfoIt->second;
    _receivedCnameMap.erase(cnameInfoIt);
  }
  rtcpParser.Iterate();
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleXRVOIPMetric(RTCPUtility::RTCPParserV2& rtcpParser,
                                 RTCPPacketInformation& rtcpPacketInformation)
{
    const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();

    CriticalSectionScoped lock(_criticalSectionRTCPReceiver);

    if(rtcpPacket.XRVOIPMetricItem.SSRC == _SSRC)
    {
        // Store VoIP metrics block if it's about me
        // from OriginatorSSRC do we filter it?
        // rtcpPacket.XR.OriginatorSSRC;

        RTCPVoIPMetric receivedVoIPMetrics;
        receivedVoIPMetrics.burstDensity = rtcpPacket.XRVOIPMetricItem.burstDensity;
        receivedVoIPMetrics.burstDuration = rtcpPacket.XRVOIPMetricItem.burstDuration;
        receivedVoIPMetrics.discardRate = rtcpPacket.XRVOIPMetricItem.discardRate;
        receivedVoIPMetrics.endSystemDelay = rtcpPacket.XRVOIPMetricItem.endSystemDelay;
        receivedVoIPMetrics.extRfactor = rtcpPacket.XRVOIPMetricItem.extRfactor;
        receivedVoIPMetrics.gapDensity = rtcpPacket.XRVOIPMetricItem.gapDensity;
        receivedVoIPMetrics.gapDuration = rtcpPacket.XRVOIPMetricItem.gapDuration;
        receivedVoIPMetrics.Gmin = rtcpPacket.XRVOIPMetricItem.Gmin;
        receivedVoIPMetrics.JBabsMax = rtcpPacket.XRVOIPMetricItem.JBabsMax;
        receivedVoIPMetrics.JBmax = rtcpPacket.XRVOIPMetricItem.JBmax;
        receivedVoIPMetrics.JBnominal = rtcpPacket.XRVOIPMetricItem.JBnominal;
        receivedVoIPMetrics.lossRate = rtcpPacket.XRVOIPMetricItem.lossRate;
        receivedVoIPMetrics.MOSCQ = rtcpPacket.XRVOIPMetricItem.MOSCQ;
        receivedVoIPMetrics.MOSLQ = rtcpPacket.XRVOIPMetricItem.MOSLQ;
        receivedVoIPMetrics.noiseLevel = rtcpPacket.XRVOIPMetricItem.noiseLevel;
        receivedVoIPMetrics.RERL = rtcpPacket.XRVOIPMetricItem.RERL;
        receivedVoIPMetrics.Rfactor = rtcpPacket.XRVOIPMetricItem.Rfactor;
        receivedVoIPMetrics.roundTripDelay = rtcpPacket.XRVOIPMetricItem.roundTripDelay;
        receivedVoIPMetrics.RXconfig = rtcpPacket.XRVOIPMetricItem.RXconfig;
        receivedVoIPMetrics.signalLevel = rtcpPacket.XRVOIPMetricItem.signalLevel;

        rtcpPacketInformation.AddVoIPMetric(&receivedVoIPMetrics);

        rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpXrVoipMetric; // received signal
    }
    rtcpParser.Iterate();
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandlePLI(RTCPUtility::RTCPParserV2& rtcpParser,
                        RTCPPacketInformation& rtcpPacketInformation)
{
    const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();

    RTCPReceiveInformation* ptrReceiveInfo = GetReceiveInformation(rtcpPacket.PLI.SenderSSRC);
    if (ptrReceiveInfo == NULL)
    {
        // This remote SSRC must be saved before.
        rtcpParser.Iterate();
        return;
    }
    if (_SSRC != rtcpPacket.PLI.MediaSSRC)
    {
        // Not to us.
        rtcpParser.Iterate();
        return;
    }
    rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpPli; // received signal that we need to send a new key frame
    rtcpParser.Iterate();
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleTMMBR(RTCPUtility::RTCPParserV2& rtcpParser,
                          RTCPPacketInformation& rtcpPacketInformation)
{
    const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();

    WebRtc_UWord32 senderSSRC = rtcpPacket.TMMBR.SenderSSRC;
    RTCPReceiveInformation* ptrReceiveInfo = GetReceiveInformation(senderSSRC);
    if (ptrReceiveInfo == NULL)
    {
        // This remote SSRC must be saved before.
        rtcpParser.Iterate();
        return;
    }
    if(rtcpPacket.TMMBR.MediaSSRC)
    {
        // rtcpPacket.TMMBR.MediaSSRC SHOULD be 0 if same as SenderSSRC
        // in relay mode this is a valid number
        senderSSRC = rtcpPacket.TMMBR.MediaSSRC;
    }

    // Use packet length to calc max number of TMMBR blocks
    // each TMMBR block is 8 bytes
    ptrdiff_t maxNumOfTMMBRBlocks = rtcpParser.LengthLeft() / 8;

    // sanity
    if(maxNumOfTMMBRBlocks > 200) // we can't have more than what's in one packet
    {
        assert(false);
        rtcpParser.Iterate();
        return;
    }
    ptrReceiveInfo->VerifyAndAllocateTMMBRSet((WebRtc_UWord32)maxNumOfTMMBRBlocks);

    RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
    while (pktType == RTCPUtility::kRtcpRtpfbTmmbrItemCode)
    {
        HandleTMMBRItem(*ptrReceiveInfo, rtcpPacket, rtcpPacketInformation, senderSSRC);
        pktType = rtcpParser.Iterate();
    }
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleTMMBRItem(RTCPReceiveInformation& receiveInfo,
                              const RTCPUtility::RTCPPacket& rtcpPacket,
                              RTCPPacketInformation& rtcpPacketInformation,
                              const WebRtc_UWord32 senderSSRC)
{
    if (_SSRC == rtcpPacket.TMMBRItem.SSRC &&
        rtcpPacket.TMMBRItem.MaxTotalMediaBitRate > 0)
    {
        receiveInfo.InsertTMMBRItem(senderSSRC, rtcpPacket.TMMBRItem,
                                    _clock.GetTimeInMS());
        rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpTmmbr;
    }
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleTMMBN(RTCPUtility::RTCPParserV2& rtcpParser)
{
    const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
    RTCPReceiveInformation* ptrReceiveInfo = GetReceiveInformation(rtcpPacket.TMMBN.SenderSSRC);
    if (ptrReceiveInfo == NULL)
    {
        // This remote SSRC must be saved before.
        rtcpParser.Iterate();
        return;
    }
    // Use packet length to calc max number of TMMBN blocks
    // each TMMBN block is 8 bytes
    ptrdiff_t maxNumOfTMMBNBlocks = rtcpParser.LengthLeft() / 8;

    // sanity
    if(maxNumOfTMMBNBlocks > 200) // we cant have more than what's in one packet
    {
        assert(false);
        rtcpParser.Iterate();
        return;
    }

    ptrReceiveInfo->VerifyAndAllocateBoundingSet((WebRtc_UWord32)maxNumOfTMMBNBlocks);

    RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
    while (pktType == RTCPUtility::kRtcpRtpfbTmmbnItemCode)
    {
        HandleTMMBNItem(*ptrReceiveInfo, rtcpPacket);
        pktType = rtcpParser.Iterate();
    }
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleSR_REQ(RTCPUtility::RTCPParserV2& rtcpParser,
                           RTCPPacketInformation& rtcpPacketInformation)
{
    rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpSrReq;
    rtcpParser.Iterate();
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleTMMBNItem(RTCPReceiveInformation& receiveInfo,
                              const RTCPUtility::RTCPPacket& rtcpPacket)
{
    const unsigned int idx = receiveInfo.TmmbnBoundingSet.lengthOfSet;

    receiveInfo.TmmbnBoundingSet.ptrTmmbrSet[idx]    = rtcpPacket.TMMBNItem.MaxTotalMediaBitRate;
    receiveInfo.TmmbnBoundingSet.ptrPacketOHSet[idx] = rtcpPacket.TMMBNItem.MeasuredOverhead;
    receiveInfo.TmmbnBoundingSet.ptrSsrcSet[idx]     = rtcpPacket.TMMBNItem.SSRC;

    ++receiveInfo.TmmbnBoundingSet.lengthOfSet;
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleSLI(RTCPUtility::RTCPParserV2& rtcpParser,
                        RTCPPacketInformation& rtcpPacketInformation)
{
    const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();

    RTCPReceiveInformation* ptrReceiveInfo = GetReceiveInformation(rtcpPacket.SLI.SenderSSRC);
    if (ptrReceiveInfo == NULL)
    {
        // This remote SSRC must be saved before.
        rtcpParser.Iterate();
        return;
    }

    RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
    while (pktType == RTCPUtility::kRtcpPsfbSliItemCode)
    {
        HandleSLIItem(rtcpPacket, rtcpPacketInformation);
        pktType = rtcpParser.Iterate();
    }
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleSLIItem(const RTCPUtility::RTCPPacket& rtcpPacket,
                            RTCPPacketInformation& rtcpPacketInformation)
{
    // in theory there could be multiple slices lost
    rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpSli; // received signal that we need to refresh a slice
    rtcpPacketInformation.sliPictureId = rtcpPacket.SLIItem.PictureId;
}

void
RTCPReceiver::HandleRPSI(RTCPUtility::RTCPParserV2& rtcpParser,
                         RTCPHelp::RTCPPacketInformation& rtcpPacketInformation)
{
    const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();

    RTCPReceiveInformation* ptrReceiveInfo = GetReceiveInformation(rtcpPacket.RPSI.SenderSSRC);
    if (ptrReceiveInfo == NULL)
    {
        // This remote SSRC must be saved before.
        rtcpParser.Iterate();
        return;
    }
    RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
    if(pktType == RTCPUtility::kRtcpPsfbRpsiCode)
    {
        rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRpsi; // received signal that we have a confirmed reference picture
        if(rtcpPacket.RPSI.NumberOfValidBits%8 != 0)
        {
            // to us unknown
            // continue
            rtcpParser.Iterate();
            return;
        }
        rtcpPacketInformation.rpsiPictureId = 0;

        // convert NativeBitString to rpsiPictureId
        WebRtc_UWord8 numberOfBytes = rtcpPacket.RPSI.NumberOfValidBits /8;
        for(WebRtc_UWord8 n = 0; n < (numberOfBytes-1); n++)
        {
            rtcpPacketInformation.rpsiPictureId += (rtcpPacket.RPSI.NativeBitString[n] & 0x7f);
            rtcpPacketInformation.rpsiPictureId <<= 7; // prepare next
        }
        rtcpPacketInformation.rpsiPictureId += (rtcpPacket.RPSI.NativeBitString[numberOfBytes-1] & 0x7f);
    }
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandlePsfbApp(RTCPUtility::RTCPParserV2& rtcpParser,
                            RTCPPacketInformation& rtcpPacketInformation)
{
    RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
    if (pktType == RTCPUtility::kRtcpPsfbRembItemCode)
    {
        HandleREMBItem(rtcpParser, rtcpPacketInformation);
        rtcpParser.Iterate();
    }
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleIJ(RTCPUtility::RTCPParserV2& rtcpParser,
                       RTCPPacketInformation& rtcpPacketInformation)
{
    const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();

    RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
    while (pktType == RTCPUtility::kRtcpExtendedIjItemCode)
    {
        HandleIJItem(rtcpPacket, rtcpPacketInformation);
        pktType = rtcpParser.Iterate();
    }
}

void
RTCPReceiver::HandleIJItem(const RTCPUtility::RTCPPacket& rtcpPacket,
                           RTCPPacketInformation& rtcpPacketInformation)
{
    rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset;
    rtcpPacketInformation.interArrivalJitter =
    rtcpPacket.ExtendedJitterReportItem.Jitter;
}

void
RTCPReceiver::HandleREMBItem(RTCPUtility::RTCPParserV2& rtcpParser,
                             RTCPPacketInformation& rtcpPacketInformation)
{
    rtcpParser.Iterate();
    const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();

    rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRemb;
    rtcpPacketInformation.receiverEstimatedMaxBitrate = rtcpPacket.REMB.BitRate;
    // TODO(pwestin) send up SSRCs and do a sanity check
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleFIR(RTCPUtility::RTCPParserV2& rtcpParser,
                        RTCPPacketInformation& rtcpPacketInformation)
{
    const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();

    RTCPReceiveInformation* ptrReceiveInfo = GetReceiveInformation(rtcpPacket.FIR.SenderSSRC);
    if (ptrReceiveInfo == NULL)
    {
        // This remote SSRC must be saved before.
        rtcpParser.Iterate();
        return;
    }

    RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
    while (pktType == RTCPUtility::kRtcpPsfbFirItemCode)
    {
        HandleFIRItem(*ptrReceiveInfo, rtcpPacket, rtcpPacketInformation);
        pktType = rtcpParser.Iterate();
    }
}

// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleFIRItem(RTCPReceiveInformation& receiveInfo,
                            const RTCPUtility::RTCPPacket& rtcpPacket,
                            RTCPPacketInformation& rtcpPacketInformation)
{
    if (_SSRC == rtcpPacket.FIRItem.SSRC) // is it our sender that is requested to generate a new keyframe
    {
        // rtcpPacket.FIR.MediaSSRC SHOULD be 0 but we ignore to check it
        // we don't know who this originate from

        // check if we have reported this FIRSequenceNumber before
        if (rtcpPacket.FIRItem.CommandSequenceNumber != receiveInfo.lastFIRSequenceNumber)
        {
            //
            WebRtc_UWord32 now = _clock.GetTimeInMS();

            // extra sanity don't go crazy with the callbacks
            if( (now - receiveInfo.lastFIRRequest) > RTCP_MIN_FRAME_LENGTH_MS)
            {
                receiveInfo.lastFIRRequest = now;
                receiveInfo.lastFIRSequenceNumber = rtcpPacket.FIRItem.CommandSequenceNumber;

                rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpFir; // received signal that we need to send a new key frame
            }
        }
    }
}

void
RTCPReceiver::HandleAPP(RTCPUtility::RTCPParserV2& rtcpParser,
                        RTCPPacketInformation& rtcpPacketInformation)
{
    const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();

    rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpApp;
    rtcpPacketInformation.applicationSubType = rtcpPacket.APP.SubType;
    rtcpPacketInformation.applicationName = rtcpPacket.APP.Name;

    rtcpParser.Iterate();
}

void
RTCPReceiver::HandleAPPItem(RTCPUtility::RTCPParserV2& rtcpParser,
                           RTCPPacketInformation& rtcpPacketInformation)
{
    const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();

    rtcpPacketInformation.AddApplicationData(rtcpPacket.APP.Data, rtcpPacket.APP.Size);

    rtcpParser.Iterate();
}

void
RTCPReceiver::OnReceivedIntraFrameRequest(const FrameType frameType,
                                          const WebRtc_UWord8 streamIdx) const
{
    CriticalSectionScoped lock(_criticalSectionFeedbacks);

    if(_cbVideoFeedback)
    {
        _cbVideoFeedback->OnReceivedIntraFrameRequest(_id, frameType, streamIdx);
    }
}

void
RTCPReceiver::OnReceivedSliceLossIndication(const WebRtc_UWord8 pitureID) const
{
    CriticalSectionScoped lock(_criticalSectionFeedbacks);

    if(_cbRtcpFeedback)
    {
        _cbRtcpFeedback->OnSLIReceived(_id, pitureID);
    }
}

void RTCPReceiver::OnReceivedReferencePictureSelectionIndication(
    const WebRtc_UWord64 pitureID) const {
  CriticalSectionScoped lock(_criticalSectionFeedbacks);

  if (_cbRtcpFeedback) {
    _cbRtcpFeedback->OnRPSIReceived(_id, pitureID);
  }
}

WebRtc_Word32 RTCPReceiver::UpdateTMMBR() {
  WebRtc_Word32 numBoundingSet = 0;
  WebRtc_UWord32 minBitrateKbit = 0;
  WebRtc_UWord32 maxBitrateKbit = 0;
  WebRtc_UWord32 accNumCandidates = 0;

  WebRtc_Word32 size = TMMBRReceived(0, 0, NULL);
  if (size > 0) {
    TMMBRSet* candidateSet = VerifyAndAllocateCandidateSet(size);
    // Get candidate set from receiver.
    accNumCandidates = TMMBRReceived(size, accNumCandidates, candidateSet);
  } else {
    // Candidate set empty.
    VerifyAndAllocateCandidateSet(0);  // resets candidate set
  }
  // Find bounding set
  TMMBRSet* boundingSet = NULL;
  numBoundingSet = FindTMMBRBoundingSet(boundingSet);
  if (numBoundingSet == -1) {
    WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
                 "Failed to find TMMBR bounding set.");
    return -1;
  }
  // Set bounding set
  // Inform remote clients about the new bandwidth
  // inform the remote client
  _rtpRtcp.SetTMMBN(boundingSet);

  // might trigger a TMMBN
  if (numBoundingSet == 0) {
    // owner of max bitrate request has timed out
    // empty bounding set has been sent
    return 0;
  }
  // Get net bitrate from bounding set depending on sent packet rate
  if (CalcMinBitRate(&minBitrateKbit)) {
    // we have a new bandwidth estimate on this channel
    _rtpRtcp.OnReceivedBandwidthEstimateUpdate((WebRtc_UWord16)minBitrateKbit);
    WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
                 "Set TMMBR request min:%d kbps max:%d kbps, channel: %d",
                 minBitrateKbit, maxBitrateKbit, _id);
  }
  return 0;
}

// Holding no Critical section
void RTCPReceiver::TriggerCallbacksFromRTCPPacket(
    RTCPPacketInformation& rtcpPacketInformation)
{
    // Process TMMBR and REMB first to avoid multiple callbacks
    // to OnNetworkChanged.  
    if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpTmmbr)
    {
        WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
                     "SIG [RTCP] Incoming TMMBR to id:%d", _id);

        // Might trigger a OnReceivedBandwidthEstimateUpdate.
        UpdateTMMBR();
    }
    if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRemb)
    {
        WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
                     "SIG [RTCP] Incoming REMB to id:%d", _id);

       // We need to bounce this to the default channel.
        _rtpRtcp.OnReceivedEstimatedMaxBitrate(
            rtcpPacketInformation.receiverEstimatedMaxBitrate);
    }
    if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSr ||
        rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRr)
    {
        if (rtcpPacketInformation.reportBlock)
        {
            _rtpRtcp.OnPacketLossStatisticsUpdate(
                rtcpPacketInformation.fractionLost,
                rtcpPacketInformation.roundTripTime,
                rtcpPacketInformation.lastReceivedExtendedHighSeqNum);
        }
    }
    if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSr)
    {
        _rtpRtcp.OnReceivedNTP();
    }
    if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSrReq)
    {
        _rtpRtcp.OnRequestSendReport();
    }
    if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpNack)
    {
        if (rtcpPacketInformation.nackSequenceNumbersLength > 0)
        {
            WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
                         "SIG [RTCP] Incoming NACK to id:%d", _id);
            _rtpRtcp.OnReceivedNACK(
                rtcpPacketInformation.nackSequenceNumbersLength,
                rtcpPacketInformation.nackSequenceNumbers);
        }
    }
    if ((rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpPli) ||
        (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpFir))
    {
        if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpPli)
        {
            WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
                         "SIG [RTCP] Incoming PLI to id:%d", _id);
        } else
        {
            WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
                         "SIG [RTCP] Incoming FIR to id:%d", _id);
        }
        _rtpRtcp.OnReceivedIntraFrameRequest(&_rtpRtcp);
    }
    if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSli)
    {
         // we need use a bounce it up to handle default channel
        _rtpRtcp.OnReceivedSliceLossIndication(
            rtcpPacketInformation.sliPictureId);
    }
    if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRpsi)
    {
         // we need use a bounce it up to handle default channel
        _rtpRtcp.OnReceivedReferencePictureSelectionIndication(
            rtcpPacketInformation.rpsiPictureId);
    }
    {
        CriticalSectionScoped lock(_criticalSectionFeedbacks);

        // we need a feedback that we have received a report block(s) so that we can generate a new packet
        // in a conference relay scenario, one received report can generate several RTCP packets, based
        // on number relayed/mixed
        // a send report block should go out to all receivers
        if(_cbRtcpFeedback)
        {
            if(rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSr)
            {
                _cbRtcpFeedback->OnSendReportReceived(_id, rtcpPacketInformation.remoteSSRC);
            } else
            {
                _cbRtcpFeedback->OnReceiveReportReceived(_id, rtcpPacketInformation.remoteSSRC);
            }
            if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRemb)
            {
                _cbRtcpFeedback->OnReceiverEstimatedMaxBitrateReceived(_id,
                    rtcpPacketInformation.receiverEstimatedMaxBitrate);
            }
            if(rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpXrVoipMetric)
            {
                WebRtc_Word8 VoIPmetricBuffer[7*4];
                VoIPmetricBuffer[0] = rtcpPacketInformation.VoIPMetric->lossRate;
                VoIPmetricBuffer[1] = rtcpPacketInformation.VoIPMetric->discardRate;
                VoIPmetricBuffer[2] = rtcpPacketInformation.VoIPMetric->burstDensity;
                VoIPmetricBuffer[3] = rtcpPacketInformation.VoIPMetric->gapDensity;

                VoIPmetricBuffer[4] = (WebRtc_UWord8)(rtcpPacketInformation.VoIPMetric->burstDuration >> 8);
                VoIPmetricBuffer[5] = (WebRtc_UWord8)(rtcpPacketInformation.VoIPMetric->burstDuration);
                VoIPmetricBuffer[6] = (WebRtc_UWord8)(rtcpPacketInformation.VoIPMetric->gapDuration >> 8);
                VoIPmetricBuffer[7] = (WebRtc_UWord8)(rtcpPacketInformation.VoIPMetric->gapDuration);

                VoIPmetricBuffer[8] = (WebRtc_UWord8)(rtcpPacketInformation.VoIPMetric->roundTripDelay >> 8);
                VoIPmetricBuffer[9] = (WebRtc_UWord8)(rtcpPacketInformation.VoIPMetric->roundTripDelay);
                VoIPmetricBuffer[10] = (WebRtc_UWord8)(rtcpPacketInformation.VoIPMetric->endSystemDelay >> 8);
                VoIPmetricBuffer[11] = (WebRtc_UWord8)(rtcpPacketInformation.VoIPMetric->endSystemDelay);

                VoIPmetricBuffer[12] = rtcpPacketInformation.VoIPMetric->signalLevel;
                VoIPmetricBuffer[13] = rtcpPacketInformation.VoIPMetric->noiseLevel;
                VoIPmetricBuffer[14] = rtcpPacketInformation.VoIPMetric->RERL;
                VoIPmetricBuffer[15] = rtcpPacketInformation.VoIPMetric->Gmin;

                VoIPmetricBuffer[16] = rtcpPacketInformation.VoIPMetric->Rfactor;
                VoIPmetricBuffer[17] = rtcpPacketInformation.VoIPMetric->extRfactor;
                VoIPmetricBuffer[18] = rtcpPacketInformation.VoIPMetric->MOSLQ;
                VoIPmetricBuffer[19] = rtcpPacketInformation.VoIPMetric->MOSCQ;

                VoIPmetricBuffer[20] = rtcpPacketInformation.VoIPMetric->RXconfig;
                VoIPmetricBuffer[21] = 0; // reserved
                VoIPmetricBuffer[22] = (WebRtc_UWord8)(rtcpPacketInformation.VoIPMetric->JBnominal >> 8);
                VoIPmetricBuffer[23] = (WebRtc_UWord8)(rtcpPacketInformation.VoIPMetric->JBnominal);

                VoIPmetricBuffer[24] = (WebRtc_UWord8)(rtcpPacketInformation.VoIPMetric->JBmax >> 8);
                VoIPmetricBuffer[25] = (WebRtc_UWord8)(rtcpPacketInformation.VoIPMetric->JBmax);
                VoIPmetricBuffer[26] = (WebRtc_UWord8)(rtcpPacketInformation.VoIPMetric->JBabsMax >> 8);
                VoIPmetricBuffer[27] = (WebRtc_UWord8)(rtcpPacketInformation.VoIPMetric->JBabsMax);

                _cbRtcpFeedback->OnXRVoIPMetricReceived(_id, rtcpPacketInformation.VoIPMetric, VoIPmetricBuffer);
            }
            if(rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpApp)
            {
                _cbRtcpFeedback->OnApplicationDataReceived(_id,
                                                           rtcpPacketInformation.applicationSubType,
                                                           rtcpPacketInformation.applicationName,
                                                           rtcpPacketInformation.applicationLength,
                                                           rtcpPacketInformation.applicationData);
            }
        }
    }
}

WebRtc_Word32 RTCPReceiver::CNAME(const WebRtc_UWord32 remoteSSRC,
                                  char cName[RTCP_CNAME_SIZE]) const {
  if (cName == NULL) {
    WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
                 "%s invalid argument", __FUNCTION__);
    return -1;
  }
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
  RTCPCnameInformation* cnameInfo = GetCnameInformation(remoteSSRC);
  assert(cnameInfo);

  cName[RTCP_CNAME_SIZE - 1] = 0;
  strncpy(cName, cnameInfo->name, RTCP_CNAME_SIZE - 1);
  return 0;
}

// no callbacks allowed inside this function
WebRtc_Word32 RTCPReceiver::TMMBRReceived(const WebRtc_UWord32 size,
                                          const WebRtc_UWord32 accNumCandidates,
                                          TMMBRSet* candidateSet) const {
  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);

  std::map<WebRtc_UWord32, RTCPReceiveInformation*>::const_iterator
      receiveInfoIt = _receivedInfoMap.begin();
  if (receiveInfoIt == _receivedInfoMap.end()) {
    return -1;
  }
  WebRtc_UWord32 num = accNumCandidates;
  if (candidateSet) {
    while( num < size && receiveInfoIt != _receivedInfoMap.end()) {
      RTCPReceiveInformation* receiveInfo = receiveInfoIt->second;
      if (receiveInfo == NULL) {
        return 0;
      }
      for (WebRtc_UWord32 i = 0;
          (num < size) && (i < receiveInfo->TmmbrSet.lengthOfSet); i++) {
        if (receiveInfo->GetTMMBRSet(i, num, candidateSet,
                                     _clock.GetTimeInMS()) == 0) {
          num++;
        }
      }
      receiveInfoIt++;
    }
  } else {
    while (receiveInfoIt != _receivedInfoMap.end()) {
      RTCPReceiveInformation* receiveInfo = receiveInfoIt->second;
      if(receiveInfo == NULL) {
        WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
                     "%s failed to get RTCPReceiveInformation",
                     __FUNCTION__);
        return -1;
      }
      num += receiveInfo->TmmbrSet.lengthOfSet;
      receiveInfoIt++;
    }
  }
  return num;
}

WebRtc_Word32
RTCPReceiver::SetPacketTimeout(const WebRtc_UWord32 timeoutMS)
{
    CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
    _packetTimeOutMS = timeoutMS;
    return 0;
}

void RTCPReceiver::PacketTimeout()
{
    if(_packetTimeOutMS == 0)
    {
        // not configured
        return;
    }

    bool packetTimeOut = false;
    {
        CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
        if(_lastReceived == 0)
        {
            // not active
            return;
        }

        WebRtc_UWord32 now = _clock.GetTimeInMS();

        if(now - _lastReceived > _packetTimeOutMS)
        {
            packetTimeOut = true;
            _lastReceived = 0;  // only one callback
        }
    }
    CriticalSectionScoped lock(_criticalSectionFeedbacks);
    if(packetTimeOut && _cbRtcpFeedback)
    {
        _cbRtcpFeedback->OnRTCPPacketTimeout(_id);
    }
}
} // namespace webrtc
