/*
 *  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 <memory>

#include "webrtc/base/rate_limiter.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
#include "webrtc/test/gmock.h"
#include "webrtc/test/gtest.h"
#include "webrtc/test/mock_transport.h"
#include "webrtc/test/rtcp_packet_parser.h"

using ::testing::_;
using ::testing::ElementsAre;
using ::testing::Invoke;

namespace webrtc {

TEST(NACKStringBuilderTest, TestCase1) {
  NACKStringBuilder builder;
  builder.PushNACK(5);
  builder.PushNACK(7);
  builder.PushNACK(9);
  builder.PushNACK(10);
  builder.PushNACK(11);
  builder.PushNACK(12);
  builder.PushNACK(15);
  builder.PushNACK(18);
  builder.PushNACK(19);
  EXPECT_EQ(std::string("5,7,9-12,15,18-19"), builder.GetResult());
}

TEST(NACKStringBuilderTest, TestCase2) {
  NACKStringBuilder builder;
  builder.PushNACK(5);
  builder.PushNACK(6);
  builder.PushNACK(7);
  builder.PushNACK(9);
  builder.PushNACK(10);
  builder.PushNACK(11);
  builder.PushNACK(12);
  builder.PushNACK(15);
  builder.PushNACK(18);
  builder.PushNACK(19);
  EXPECT_EQ(std::string("5-7,9-12,15,18-19"), builder.GetResult());
}

TEST(NACKStringBuilderTest, TestCase3) {
  NACKStringBuilder builder;
  builder.PushNACK(5);
  builder.PushNACK(7);
  builder.PushNACK(9);
  builder.PushNACK(10);
  builder.PushNACK(11);
  builder.PushNACK(12);
  builder.PushNACK(15);
  builder.PushNACK(18);
  builder.PushNACK(19);
  builder.PushNACK(21);
  EXPECT_EQ(std::string("5,7,9-12,15,18-19,21"), builder.GetResult());
}

TEST(NACKStringBuilderTest, TestCase4) {
  NACKStringBuilder builder;
  builder.PushNACK(5);
  builder.PushNACK(7);
  builder.PushNACK(8);
  builder.PushNACK(9);
  builder.PushNACK(10);
  builder.PushNACK(11);
  builder.PushNACK(12);
  builder.PushNACK(15);
  builder.PushNACK(18);
  builder.PushNACK(19);
  EXPECT_EQ(std::string("5,7-12,15,18-19"), builder.GetResult());
}

TEST(NACKStringBuilderTest, TestCase5) {
  NACKStringBuilder builder;
  builder.PushNACK(5);
  builder.PushNACK(7);
  builder.PushNACK(9);
  builder.PushNACK(10);
  builder.PushNACK(11);
  builder.PushNACK(12);
  builder.PushNACK(15);
  builder.PushNACK(16);
  builder.PushNACK(18);
  builder.PushNACK(19);
  EXPECT_EQ(std::string("5,7,9-12,15-16,18-19"), builder.GetResult());
}

TEST(NACKStringBuilderTest, TestCase6) {
  NACKStringBuilder builder;
  builder.PushNACK(5);
  builder.PushNACK(7);
  builder.PushNACK(9);
  builder.PushNACK(10);
  builder.PushNACK(11);
  builder.PushNACK(12);
  builder.PushNACK(15);
  builder.PushNACK(16);
  builder.PushNACK(17);
  builder.PushNACK(18);
  builder.PushNACK(19);
  EXPECT_EQ(std::string("5,7,9-12,15-19"), builder.GetResult());
}

TEST(NACKStringBuilderTest, TestCase7) {
  NACKStringBuilder builder;
  builder.PushNACK(5);
  builder.PushNACK(6);
  builder.PushNACK(7);
  builder.PushNACK(8);
  builder.PushNACK(11);
  builder.PushNACK(12);
  builder.PushNACK(13);
  builder.PushNACK(14);
  builder.PushNACK(15);
  EXPECT_EQ(std::string("5-8,11-15"), builder.GetResult());
}

TEST(NACKStringBuilderTest, TestCase8) {
  NACKStringBuilder builder;
  builder.PushNACK(5);
  builder.PushNACK(7);
  builder.PushNACK(9);
  builder.PushNACK(11);
  builder.PushNACK(15);
  builder.PushNACK(17);
  builder.PushNACK(19);
  EXPECT_EQ(std::string("5,7,9,11,15,17,19"), builder.GetResult());
}

TEST(NACKStringBuilderTest, TestCase9) {
  NACKStringBuilder builder;
  builder.PushNACK(5);
  builder.PushNACK(6);
  builder.PushNACK(7);
  builder.PushNACK(8);
  builder.PushNACK(9);
  builder.PushNACK(10);
  builder.PushNACK(11);
  builder.PushNACK(12);
  EXPECT_EQ(std::string("5-12"), builder.GetResult());
}

TEST(NACKStringBuilderTest, TestCase10) {
  NACKStringBuilder builder;
  builder.PushNACK(5);
  EXPECT_EQ(std::string("5"), builder.GetResult());
}

TEST(NACKStringBuilderTest, TestCase11) {
  NACKStringBuilder builder;
  EXPECT_EQ(std::string(""), builder.GetResult());
}

TEST(NACKStringBuilderTest, TestCase12) {
  NACKStringBuilder builder;
  builder.PushNACK(5);
  builder.PushNACK(6);
  EXPECT_EQ(std::string("5-6"), builder.GetResult());
}

TEST(NACKStringBuilderTest, TestCase13) {
  NACKStringBuilder builder;
  builder.PushNACK(5);
  builder.PushNACK(6);
  builder.PushNACK(9);
  EXPECT_EQ(std::string("5-6,9"), builder.GetResult());
}

class RtcpPacketTypeCounterObserverImpl : public RtcpPacketTypeCounterObserver {
 public:
  RtcpPacketTypeCounterObserverImpl() : ssrc_(0) {}
  virtual ~RtcpPacketTypeCounterObserverImpl() {}
  void RtcpPacketTypesCounterUpdated(
      uint32_t ssrc,
      const RtcpPacketTypeCounter& packet_counter) override {
    ssrc_ = ssrc;
    counter_ = packet_counter;
  }
  uint32_t ssrc_;
  RtcpPacketTypeCounter counter_;
};

class TestTransport : public Transport,
                      public NullRtpData {
 public:
  TestTransport() {}

  bool SendRtp(const uint8_t* /*data*/,
               size_t /*len*/,
               const PacketOptions& options) override {
    return false;
  }
  bool SendRtcp(const uint8_t* data, size_t len) override {
    parser_.Parse(data, len);
    return true;
  }
  int OnReceivedPayloadData(const uint8_t* payload_data,
                            const size_t payload_size,
                            const WebRtcRTPHeader* rtp_header) override {
    return 0;
  }
  test::RtcpPacketParser parser_;
};

namespace {
static const uint32_t kSenderSsrc = 0x11111111;
static const uint32_t kRemoteSsrc = 0x22222222;
static const uint32_t kStartRtpTimestamp = 0x34567;
static const uint32_t kRtpTimestamp = 0x45678;
}

class RtcpSenderTest : public ::testing::Test {
 protected:
  RtcpSenderTest()
      : clock_(1335900000),
        receive_statistics_(ReceiveStatistics::Create(&clock_)),
        retransmission_rate_limiter_(&clock_, 1000) {
    RtpRtcp::Configuration configuration;
    configuration.audio = false;
    configuration.clock = &clock_;
    configuration.outgoing_transport = &test_transport_;
    configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;

    rtp_rtcp_impl_.reset(new ModuleRtpRtcpImpl(configuration));
    rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(),
                                      nullptr, nullptr, &test_transport_));
    rtcp_sender_->SetSSRC(kSenderSsrc);
    rtcp_sender_->SetRemoteSSRC(kRemoteSsrc);
    rtcp_sender_->SetTimestampOffset(kStartRtpTimestamp);
    rtcp_sender_->SetLastRtpTime(kRtpTimestamp, clock_.TimeInMilliseconds());
  }

  void InsertIncomingPacket(uint32_t remote_ssrc, uint16_t seq_num) {
    RTPHeader header;
    header.ssrc = remote_ssrc;
    header.sequenceNumber = seq_num;
    header.timestamp = 12345;
    header.headerLength = 12;
    size_t kPacketLength = 100;
    receive_statistics_->IncomingPacket(header, kPacketLength, false);
  }

  test::RtcpPacketParser* parser() { return &test_transport_.parser_; }

  RTCPSender::FeedbackState feedback_state() {
    return rtp_rtcp_impl_->GetFeedbackState();
  }

  SimulatedClock clock_;
  TestTransport test_transport_;
  std::unique_ptr<ReceiveStatistics> receive_statistics_;
  std::unique_ptr<ModuleRtpRtcpImpl> rtp_rtcp_impl_;
  std::unique_ptr<RTCPSender> rtcp_sender_;
  RateLimiter retransmission_rate_limiter_;
};

TEST_F(RtcpSenderTest, SetRtcpStatus) {
  EXPECT_EQ(RtcpMode::kOff, rtcp_sender_->Status());
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  EXPECT_EQ(RtcpMode::kReducedSize, rtcp_sender_->Status());
}

TEST_F(RtcpSenderTest, SetSendingStatus) {
  EXPECT_FALSE(rtcp_sender_->Sending());
  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), true));
  EXPECT_TRUE(rtcp_sender_->Sending());
}

TEST_F(RtcpSenderTest, NoPacketSentIfOff) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kOff);
  EXPECT_EQ(-1, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSr));
}

TEST_F(RtcpSenderTest, SendSr) {
  const uint32_t kPacketCount = 0x12345;
  const uint32_t kOctetCount = 0x23456;
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  RTCPSender::FeedbackState feedback_state = rtp_rtcp_impl_->GetFeedbackState();
  rtcp_sender_->SetSendingStatus(feedback_state, true);
  feedback_state.packets_sent = kPacketCount;
  feedback_state.media_bytes_sent = kOctetCount;
  uint32_t ntp_secs;
  uint32_t ntp_frac;
  clock_.CurrentNtp(ntp_secs, ntp_frac);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpSr));
  EXPECT_EQ(1, parser()->sender_report()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->sender_report()->sender_ssrc());
  EXPECT_EQ(ntp_secs, parser()->sender_report()->ntp().seconds());
  EXPECT_EQ(ntp_frac, parser()->sender_report()->ntp().fractions());
  EXPECT_EQ(kPacketCount, parser()->sender_report()->sender_packet_count());
  EXPECT_EQ(kOctetCount, parser()->sender_report()->sender_octet_count());
  EXPECT_EQ(kStartRtpTimestamp + kRtpTimestamp,
            parser()->sender_report()->rtp_timestamp());
  EXPECT_EQ(0U, parser()->sender_report()->report_blocks().size());
}

TEST_F(RtcpSenderTest, DoNotSendSrBeforeRtp) {
  rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(),
                                    nullptr, nullptr, &test_transport_));
  rtcp_sender_->SetSSRC(kSenderSsrc);
  rtcp_sender_->SetRemoteSSRC(kRemoteSsrc);
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  rtcp_sender_->SetSendingStatus(feedback_state(), true);

  // Sender Report shouldn't be send as an SR nor as a Report.
  rtcp_sender_->SendRTCP(feedback_state(), kRtcpSr);
  EXPECT_EQ(0, parser()->sender_report()->num_packets());
  rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport);
  EXPECT_EQ(0, parser()->sender_report()->num_packets());
  // Other packets (e.g. Pli) are allowed, even if useless.
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpPli));
  EXPECT_EQ(1, parser()->pli()->num_packets());
}

TEST_F(RtcpSenderTest, DoNotSendCompundBeforeRtp) {
  rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(),
                                    nullptr, nullptr, &test_transport_));
  rtcp_sender_->SetSSRC(kSenderSsrc);
  rtcp_sender_->SetRemoteSSRC(kRemoteSsrc);
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  rtcp_sender_->SetSendingStatus(feedback_state(), true);

  // In compound mode no packets are allowed (e.g. Pli) because compound mode
  // should start with Sender Report.
  EXPECT_EQ(-1, rtcp_sender_->SendRTCP(feedback_state(), kRtcpPli));
  EXPECT_EQ(0, parser()->pli()->num_packets());
}

TEST_F(RtcpSenderTest, SendRr) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr));
  EXPECT_EQ(1, parser()->receiver_report()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->receiver_report()->sender_ssrc());
  EXPECT_EQ(0U, parser()->receiver_report()->report_blocks().size());
}

TEST_F(RtcpSenderTest, SendRrWithOneReportBlock) {
  const uint16_t kSeqNum = 11111;
  InsertIncomingPacket(kRemoteSsrc, kSeqNum);
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr));
  EXPECT_EQ(1, parser()->receiver_report()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->receiver_report()->sender_ssrc());
  ASSERT_EQ(1U, parser()->receiver_report()->report_blocks().size());
  const rtcp::ReportBlock& rb = parser()->receiver_report()->report_blocks()[0];
  EXPECT_EQ(kRemoteSsrc, rb.source_ssrc());
  EXPECT_EQ(0U, rb.fraction_lost());
  EXPECT_EQ(0U, rb.cumulative_lost());
  EXPECT_EQ(kSeqNum, rb.extended_high_seq_num());
}

TEST_F(RtcpSenderTest, SendRrWithTwoReportBlocks) {
  const uint16_t kSeqNum = 11111;
  InsertIncomingPacket(kRemoteSsrc, kSeqNum);
  InsertIncomingPacket(kRemoteSsrc + 1, kSeqNum + 1);
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr));
  EXPECT_EQ(1, parser()->receiver_report()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->receiver_report()->sender_ssrc());
  EXPECT_EQ(2U, parser()->receiver_report()->report_blocks().size());
  EXPECT_EQ(kRemoteSsrc,
            parser()->receiver_report()->report_blocks()[0].source_ssrc());
  EXPECT_EQ(kRemoteSsrc + 1,
            parser()->receiver_report()->report_blocks()[1].source_ssrc());
}

TEST_F(RtcpSenderTest, SendSdes) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  EXPECT_EQ(0, rtcp_sender_->SetCNAME("alice@host"));
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSdes));
  EXPECT_EQ(1, parser()->sdes()->num_packets());
  EXPECT_EQ(1U, parser()->sdes()->chunks().size());
  EXPECT_EQ(kSenderSsrc, parser()->sdes()->chunks()[0].ssrc);
  EXPECT_EQ("alice@host", parser()->sdes()->chunks()[0].cname);
}

TEST_F(RtcpSenderTest, SdesIncludedInCompoundPacket) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  EXPECT_EQ(0, rtcp_sender_->SetCNAME("alice@host"));
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
  EXPECT_EQ(1, parser()->receiver_report()->num_packets());
  EXPECT_EQ(1, parser()->sdes()->num_packets());
  EXPECT_EQ(1U, parser()->sdes()->chunks().size());
}

TEST_F(RtcpSenderTest, SendBye) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpBye));
  EXPECT_EQ(1, parser()->bye()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->bye()->sender_ssrc());
}

TEST_F(RtcpSenderTest, StopSendingTriggersBye) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), true));
  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), false));
  EXPECT_EQ(1, parser()->bye()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->bye()->sender_ssrc());
}

TEST_F(RtcpSenderTest, SendApp) {
  const uint8_t kSubType = 30;
  uint32_t name = 'n' << 24;
  name += 'a' << 16;
  name += 'm' << 8;
  name += 'e';
  const uint8_t kData[] = {'t', 'e', 's', 't', 'd', 'a', 't', 'a'};
  EXPECT_EQ(0, rtcp_sender_->SetApplicationSpecificData(kSubType, name, kData,
                                                        sizeof(kData)));
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpApp));
  EXPECT_EQ(1, parser()->app()->num_packets());
  EXPECT_EQ(kSubType, parser()->app()->sub_type());
  EXPECT_EQ(name, parser()->app()->name());
  EXPECT_EQ(sizeof(kData), parser()->app()->data_size());
  EXPECT_EQ(0, memcmp(kData, parser()->app()->data(), sizeof(kData)));
}

TEST_F(RtcpSenderTest, SendEmptyApp) {
  const uint8_t kSubType = 30;
  const uint32_t kName = 0x6E616D65;

  EXPECT_EQ(
      0, rtcp_sender_->SetApplicationSpecificData(kSubType, kName, nullptr, 0));

  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpApp));
  EXPECT_EQ(1, parser()->app()->num_packets());
  EXPECT_EQ(kSubType, parser()->app()->sub_type());
  EXPECT_EQ(kName, parser()->app()->name());
  EXPECT_EQ(0U, parser()->app()->data_size());
}

TEST_F(RtcpSenderTest, SetInvalidApplicationSpecificData) {
  const uint8_t kData[] = {'t', 'e', 's', 't', 'd', 'a', 't'};
  const uint16_t kInvalidDataLength = sizeof(kData) / sizeof(kData[0]);
  EXPECT_EQ(-1, rtcp_sender_->SetApplicationSpecificData(
      0, 0, kData, kInvalidDataLength));  // Should by multiple of 4.
}

TEST_F(RtcpSenderTest, SendFirNonRepeat) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpFir));
  EXPECT_EQ(1, parser()->fir()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->fir()->sender_ssrc());
  EXPECT_EQ(1U, parser()->fir()->requests().size());
  EXPECT_EQ(kRemoteSsrc, parser()->fir()->requests()[0].ssrc);
  uint8_t seq = parser()->fir()->requests()[0].seq_nr;
  // Sends non-repeat FIR as default.
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpFir));
  EXPECT_EQ(2, parser()->fir()->num_packets());
  EXPECT_EQ(seq + 1, parser()->fir()->requests()[0].seq_nr);
}

TEST_F(RtcpSenderTest, SendFirRepeat) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpFir));
  EXPECT_EQ(1, parser()->fir()->num_packets());
  EXPECT_EQ(1U, parser()->fir()->requests().size());
  uint8_t seq = parser()->fir()->requests()[0].seq_nr;
  const bool kRepeat = true;
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpFir, 0, nullptr,
                                      kRepeat));
  EXPECT_EQ(2, parser()->fir()->num_packets());
  EXPECT_EQ(seq, parser()->fir()->requests()[0].seq_nr);
}

TEST_F(RtcpSenderTest, SendPli) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpPli));
  EXPECT_EQ(1, parser()->pli()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->pli()->sender_ssrc());
  EXPECT_EQ(kRemoteSsrc, parser()->pli()->media_ssrc());
}

TEST_F(RtcpSenderTest, SendRpsi) {
  const uint64_t kPictureId = 0x41;
  const int8_t kPayloadType = 100;
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  RTCPSender::FeedbackState feedback_state = rtp_rtcp_impl_->GetFeedbackState();
  feedback_state.send_payload_type = kPayloadType;
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpRpsi, 0, nullptr,
                                      false, kPictureId));
  EXPECT_EQ(1, parser()->rpsi()->num_packets());
  EXPECT_EQ(kPayloadType, parser()->rpsi()->payload_type());
  EXPECT_EQ(kPictureId, parser()->rpsi()->picture_id());
}

TEST_F(RtcpSenderTest, SendSli) {
  const uint16_t kFirstMb = 0;
  const uint16_t kNumberOfMb = 0x1FFF;
  const uint8_t kPictureId = 60;
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSli, 0, nullptr,
                                      false, kPictureId));
  EXPECT_EQ(1, parser()->sli()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->sli()->sender_ssrc());
  EXPECT_EQ(kRemoteSsrc, parser()->sli()->media_ssrc());
  EXPECT_EQ(1U, parser()->sli()->macroblocks().size());
  EXPECT_EQ(kFirstMb, parser()->sli()->macroblocks()[0].first());
  EXPECT_EQ(kNumberOfMb, parser()->sli()->macroblocks()[0].number());
  EXPECT_EQ(kPictureId, parser()->sli()->macroblocks()[0].picture_id());
}

TEST_F(RtcpSenderTest, SendNack) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  const uint16_t kList[] = {0, 1, 16};
  const int32_t kListLength = sizeof(kList) / sizeof(kList[0]);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpNack, kListLength,
                                      kList));
  EXPECT_EQ(1, parser()->nack()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->nack()->sender_ssrc());
  EXPECT_EQ(kRemoteSsrc, parser()->nack()->media_ssrc());
  EXPECT_THAT(parser()->nack()->packet_ids(), ElementsAre(0, 1, 16));
}

TEST_F(RtcpSenderTest, RembStatus) {
  EXPECT_FALSE(rtcp_sender_->REMB());
  rtcp_sender_->SetREMBStatus(true);
  EXPECT_TRUE(rtcp_sender_->REMB());
  rtcp_sender_->SetREMBStatus(false);
  EXPECT_FALSE(rtcp_sender_->REMB());
}

TEST_F(RtcpSenderTest, SendRemb) {
  const uint64_t kBitrate = 261011;
  std::vector<uint32_t> ssrcs;
  ssrcs.push_back(kRemoteSsrc);
  ssrcs.push_back(kRemoteSsrc + 1);
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  rtcp_sender_->SetREMBData(kBitrate, ssrcs);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpRemb));
  EXPECT_EQ(1, parser()->remb()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->remb()->sender_ssrc());
  EXPECT_EQ(kBitrate, parser()->remb()->bitrate_bps());
  EXPECT_THAT(parser()->remb()->ssrcs(),
              ElementsAre(kRemoteSsrc, kRemoteSsrc + 1));
}

TEST_F(RtcpSenderTest, RembIncludedInCompoundPacketIfEnabled) {
  const int kBitrate = 261011;
  std::vector<uint32_t> ssrcs;
  ssrcs.push_back(kRemoteSsrc);
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  rtcp_sender_->SetREMBStatus(true);
  EXPECT_TRUE(rtcp_sender_->REMB());
  rtcp_sender_->SetREMBData(kBitrate, ssrcs);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
  EXPECT_EQ(1, parser()->remb()->num_packets());
  // REMB should be included in each compound packet.
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
  EXPECT_EQ(2, parser()->remb()->num_packets());
}

TEST_F(RtcpSenderTest, RembNotIncludedInCompoundPacketIfNotEnabled) {
  const int kBitrate = 261011;
  std::vector<uint32_t> ssrcs;
  ssrcs.push_back(kRemoteSsrc);
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  rtcp_sender_->SetREMBData(kBitrate, ssrcs);
  EXPECT_FALSE(rtcp_sender_->REMB());
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
  EXPECT_EQ(0, parser()->remb()->num_packets());
}

TEST_F(RtcpSenderTest, SendXrWithVoipMetric) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  RTCPVoIPMetric metric;
  metric.lossRate = 1;
  metric.discardRate = 2;
  metric.burstDensity = 3;
  metric.gapDensity = 4;
  metric.burstDuration = 0x1111;
  metric.gapDuration = 0x2222;
  metric.roundTripDelay = 0x3333;
  metric.endSystemDelay = 0x4444;
  metric.signalLevel = 5;
  metric.noiseLevel = 6;
  metric.RERL = 7;
  metric.Gmin = 8;
  metric.Rfactor = 9;
  metric.extRfactor = 10;
  metric.MOSLQ = 11;
  metric.MOSCQ = 12;
  metric.RXconfig = 13;
  metric.JBnominal = 0x5555;
  metric.JBmax = 0x6666;
  metric.JBabsMax = 0x7777;
  EXPECT_EQ(0, rtcp_sender_->SetRTCPVoIPMetrics(&metric));
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpXrVoipMetric));
  EXPECT_EQ(1, parser()->xr()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
  ASSERT_TRUE(parser()->xr()->voip_metric());
  EXPECT_EQ(kRemoteSsrc, parser()->xr()->voip_metric()->ssrc());
  const auto& parsed_metric = parser()->xr()->voip_metric()->voip_metric();
  EXPECT_EQ(metric.lossRate, parsed_metric.lossRate);
  EXPECT_EQ(metric.discardRate, parsed_metric.discardRate);
  EXPECT_EQ(metric.burstDensity, parsed_metric.burstDensity);
  EXPECT_EQ(metric.gapDensity, parsed_metric.gapDensity);
  EXPECT_EQ(metric.burstDuration, parsed_metric.burstDuration);
  EXPECT_EQ(metric.gapDuration, parsed_metric.gapDuration);
  EXPECT_EQ(metric.roundTripDelay, parsed_metric.roundTripDelay);
  EXPECT_EQ(metric.endSystemDelay, parsed_metric.endSystemDelay);
  EXPECT_EQ(metric.signalLevel, parsed_metric.signalLevel);
  EXPECT_EQ(metric.noiseLevel, parsed_metric.noiseLevel);
  EXPECT_EQ(metric.RERL, parsed_metric.RERL);
  EXPECT_EQ(metric.Gmin, parsed_metric.Gmin);
  EXPECT_EQ(metric.Rfactor, parsed_metric.Rfactor);
  EXPECT_EQ(metric.extRfactor, parsed_metric.extRfactor);
  EXPECT_EQ(metric.MOSLQ, parsed_metric.MOSLQ);
  EXPECT_EQ(metric.MOSCQ, parsed_metric.MOSCQ);
  EXPECT_EQ(metric.RXconfig, parsed_metric.RXconfig);
  EXPECT_EQ(metric.JBnominal, parsed_metric.JBnominal);
  EXPECT_EQ(metric.JBmax, parsed_metric.JBmax);
  EXPECT_EQ(metric.JBabsMax, parsed_metric.JBabsMax);
}

TEST_F(RtcpSenderTest, SendXrWithDlrr) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  RTCPSender::FeedbackState feedback_state = rtp_rtcp_impl_->GetFeedbackState();
  feedback_state.has_last_xr_rr = true;
  rtcp::ReceiveTimeInfo last_xr_rr;
  last_xr_rr.ssrc = 0x11111111;
  last_xr_rr.last_rr = 0x22222222;
  last_xr_rr.delay_since_last_rr = 0x33333333;
  feedback_state.last_xr_rr = last_xr_rr;
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpReport));
  EXPECT_EQ(1, parser()->xr()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
  EXPECT_EQ(1U, parser()->xr()->dlrr().sub_blocks().size());
  EXPECT_EQ(last_xr_rr.ssrc, parser()->xr()->dlrr().sub_blocks()[0].ssrc);
  EXPECT_EQ(last_xr_rr.last_rr, parser()->xr()->dlrr().sub_blocks()[0].last_rr);
  EXPECT_EQ(last_xr_rr.delay_since_last_rr,
            parser()->xr()->dlrr().sub_blocks()[0].delay_since_last_rr);
}

TEST_F(RtcpSenderTest, SendXrWithRrtr) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), false));
  rtcp_sender_->SendRtcpXrReceiverReferenceTime(true);
  uint32_t ntp_secs;
  uint32_t ntp_frac;
  clock_.CurrentNtp(ntp_secs, ntp_frac);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
  EXPECT_EQ(1, parser()->xr()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
  EXPECT_FALSE(parser()->xr()->dlrr());
  EXPECT_FALSE(parser()->xr()->voip_metric());
  ASSERT_TRUE(parser()->xr()->rrtr());
  EXPECT_EQ(ntp_secs, parser()->xr()->rrtr()->ntp().seconds());
  EXPECT_EQ(ntp_frac, parser()->xr()->rrtr()->ntp().fractions());
}

TEST_F(RtcpSenderTest, TestNoXrRrtrSentIfSending) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), true));
  rtcp_sender_->SendRtcpXrReceiverReferenceTime(true);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
  EXPECT_EQ(0, parser()->xr()->num_packets());
}

TEST_F(RtcpSenderTest, TestNoXrRrtrSentIfNotEnabled) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), false));
  rtcp_sender_->SendRtcpXrReceiverReferenceTime(false);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
  EXPECT_EQ(0, parser()->xr()->num_packets());
}

TEST_F(RtcpSenderTest, TestRegisterRtcpPacketTypeObserver) {
  RtcpPacketTypeCounterObserverImpl observer;
  rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(),
                                    &observer, nullptr, &test_transport_));
  rtcp_sender_->SetRemoteSSRC(kRemoteSsrc);
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpPli));
  EXPECT_EQ(1, parser()->pli()->num_packets());
  EXPECT_EQ(kRemoteSsrc, observer.ssrc_);
  EXPECT_EQ(1U, observer.counter_.pli_packets);
  EXPECT_EQ(clock_.TimeInMilliseconds(),
            observer.counter_.first_packet_time_ms);
}

TEST_F(RtcpSenderTest, SendTmmbr) {
  const unsigned int kBitrateBps = 312000;
  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
  rtcp_sender_->SetTargetBitrate(kBitrateBps);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpTmmbr));
  EXPECT_EQ(1, parser()->tmmbr()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->tmmbr()->sender_ssrc());
  EXPECT_EQ(1U, parser()->tmmbr()->requests().size());
  EXPECT_EQ(kBitrateBps, parser()->tmmbr()->requests()[0].bitrate_bps());
  // TODO(asapersson): tmmbr_item()->Overhead() looks broken, always zero.
}

TEST_F(RtcpSenderTest, TmmbrIncludedInCompoundPacketIfEnabled) {
  const unsigned int kBitrateBps = 312000;
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  EXPECT_FALSE(rtcp_sender_->TMMBR());
  rtcp_sender_->SetTMMBRStatus(true);
  EXPECT_TRUE(rtcp_sender_->TMMBR());
  rtcp_sender_->SetTargetBitrate(kBitrateBps);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
  EXPECT_EQ(1, parser()->tmmbr()->num_packets());
  EXPECT_EQ(1U, parser()->tmmbr()->requests().size());
  // TMMBR should be included in each compound packet.
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
  EXPECT_EQ(2, parser()->tmmbr()->num_packets());

  rtcp_sender_->SetTMMBRStatus(false);
  EXPECT_FALSE(rtcp_sender_->TMMBR());
}

TEST_F(RtcpSenderTest, SendTmmbn) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  rtcp_sender_->SetSendingStatus(feedback_state(), true);
  std::vector<rtcp::TmmbItem> bounding_set;
  const uint32_t kBitrateBps = 32768000;
  const uint32_t kPacketOh = 40;
  const uint32_t kSourceSsrc = 12345;
  const rtcp::TmmbItem tmmbn(kSourceSsrc, kBitrateBps, kPacketOh);
  bounding_set.push_back(tmmbn);
  rtcp_sender_->SetTmmbn(bounding_set);

  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSr));
  EXPECT_EQ(1, parser()->sender_report()->num_packets());
  EXPECT_EQ(1, parser()->tmmbn()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->tmmbn()->sender_ssrc());
  EXPECT_EQ(1U, parser()->tmmbn()->items().size());
  EXPECT_EQ(kBitrateBps, parser()->tmmbn()->items()[0].bitrate_bps());
  EXPECT_EQ(kPacketOh, parser()->tmmbn()->items()[0].packet_overhead());
  EXPECT_EQ(kSourceSsrc, parser()->tmmbn()->items()[0].ssrc());
}

// This test is written to verify actual behaviour. It does not seem
// to make much sense to send an empty TMMBN, since there is no place
// to put an actual limit here. It's just information that no limit
// is set, which is kind of the starting assumption.
// See http://code.google.com/p/webrtc/issues/detail?id=468 for one
// situation where this caused confusion.
TEST_F(RtcpSenderTest, SendsTmmbnIfSetAndEmpty) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  rtcp_sender_->SetSendingStatus(feedback_state(), true);
  std::vector<rtcp::TmmbItem> bounding_set;
  rtcp_sender_->SetTmmbn(bounding_set);
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSr));
  EXPECT_EQ(1, parser()->sender_report()->num_packets());
  EXPECT_EQ(1, parser()->tmmbn()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->tmmbn()->sender_ssrc());
  EXPECT_EQ(0U, parser()->tmmbn()->items().size());
}

TEST_F(RtcpSenderTest, SendCompoundPliRemb) {
  const int kBitrate = 261011;
  std::vector<uint32_t> ssrcs;
  ssrcs.push_back(kRemoteSsrc);
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  rtcp_sender_->SetREMBData(kBitrate, ssrcs);
  std::set<RTCPPacketType> packet_types;
  packet_types.insert(kRtcpRemb);
  packet_types.insert(kRtcpPli);
  EXPECT_EQ(0, rtcp_sender_->SendCompoundRTCP(feedback_state(), packet_types));
  EXPECT_EQ(1, parser()->remb()->num_packets());
  EXPECT_EQ(1, parser()->pli()->num_packets());
}


// This test is written to verify that BYE is always the last packet
// type in a RTCP compoud packet.  The rtcp_sender_ is recreated with
// mock_transport, which is used to check for whether BYE at the end
// of a RTCP compound packet.
TEST_F(RtcpSenderTest, ByeMustBeLast) {
  MockTransport mock_transport;
  EXPECT_CALL(mock_transport, SendRtcp(_, _))
    .WillOnce(Invoke([](const uint8_t* data, size_t len) {
    const uint8_t* next_packet = data;
    const uint8_t* const packet_end = data + len;
    rtcp::CommonHeader packet;
    while (next_packet < packet_end) {
      EXPECT_TRUE(packet.Parse(next_packet, packet_end - next_packet));
      next_packet = packet.NextPacket();
      if (packet.type() == rtcp::Bye::kPacketType)  // Main test expectation.
        EXPECT_EQ(0, packet_end - next_packet)
            << "Bye packet should be last in a compound RTCP packet.";
      if (next_packet == packet_end)  // Validate test was set correctly.
        EXPECT_EQ(packet.type(), rtcp::Bye::kPacketType)
            << "Last packet in this test expected to be Bye.";
    }

    return true;
  }));

  // Re-configure rtcp_sender_ with mock_transport_
  rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(),
                                    nullptr, nullptr, &mock_transport));
  rtcp_sender_->SetSSRC(kSenderSsrc);
  rtcp_sender_->SetRemoteSSRC(kRemoteSsrc);
  rtcp_sender_->SetTimestampOffset(kStartRtpTimestamp);
  rtcp_sender_->SetLastRtpTime(kRtpTimestamp, clock_.TimeInMilliseconds());

  // Set up XR VoIP metric to be included with BYE
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  RTCPVoIPMetric metric;
  EXPECT_EQ(0, rtcp_sender_->SetRTCPVoIPMetrics(&metric));
  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpBye));
}

TEST_F(RtcpSenderTest, SendXrWithTargetBitrate) {
  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
  const size_t kNumSpatialLayers = 2;
  const size_t kNumTemporalLayers = 2;
  BitrateAllocation allocation;
  for (size_t sl = 0; sl < kNumSpatialLayers; ++sl) {
    uint32_t start_bitrate_bps = (sl + 1) * 100000;
    for (size_t tl = 0; tl < kNumTemporalLayers; ++tl)
      allocation.SetBitrate(sl, tl, start_bitrate_bps + (tl * 20000));
  }
  rtcp_sender_->SetVideoBitrateAllocation(allocation);

  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
  EXPECT_EQ(1, parser()->xr()->num_packets());
  EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
  const rtc::Optional<rtcp::TargetBitrate>& target_bitrate =
      parser()->xr()->target_bitrate();
  ASSERT_TRUE(target_bitrate);
  const std::vector<rtcp::TargetBitrate::BitrateItem>& bitrates =
      target_bitrate->GetTargetBitrates();
  EXPECT_EQ(kNumSpatialLayers * kNumTemporalLayers, bitrates.size());

  for (size_t sl = 0; sl < kNumSpatialLayers; ++sl) {
    uint32_t start_bitrate_bps = (sl + 1) * 100000;
    for (size_t tl = 0; tl < kNumTemporalLayers; ++tl) {
      size_t index = (sl * kNumSpatialLayers) + tl;
      const rtcp::TargetBitrate::BitrateItem& item = bitrates[index];
      EXPECT_EQ(sl, item.spatial_layer);
      EXPECT_EQ(tl, item.temporal_layer);
      EXPECT_EQ(start_bitrate_bps + (tl * 20000),
                item.target_bitrate_kbps * 1000);
    }
  }
}

}  // namespace webrtc
