// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/cast/net/rtcp/rtcp_utility.h"

#include <stdint.h>

#include <memory>

#include "base/macros.h"
#include "base/test/simple_test_tick_clock.h"
#include "media/base/fake_single_thread_task_runner.h"
#include "media/cast/cast_environment.h"
#include "media/cast/net/cast_transport_defines.h"
#include "media/cast/net/rtcp/test_rtcp_packet_builder.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace media {
namespace cast {

static const uint32_t kRemoteSsrc = 0x10203;
static const uint32_t kLocalSsrc = 0x40506;
static const uint32_t kUnknownSsrc = 0xDEAD;
static const base::TimeDelta kTargetDelay =
    base::TimeDelta::FromMilliseconds(100);

class RtcpParserTest : public ::testing::Test {
 protected:
  RtcpParserTest()
      : testing_clock_(new base::SimpleTestTickClock()),
        task_runner_(new FakeSingleThreadTaskRunner(testing_clock_.get())) {}

  bool HasAnything(const RtcpParser& parser) {
    return parser.has_sender_report() ||
        parser.has_last_report() ||
        parser.has_receiver_log() ||
        parser.has_cast_message() ||
        parser.has_receiver_reference_time_report();
  }

  void ExpectSenderInfo(const RtcpParser& parser) {
    EXPECT_TRUE(parser.has_sender_report());
    EXPECT_EQ(kNtpHigh, parser.sender_report().ntp_seconds);
    EXPECT_EQ(kNtpLow, parser.sender_report().ntp_fraction);
    EXPECT_EQ(kRtpTimestamp,
              parser.sender_report().rtp_timestamp.lower_32_bits());
    EXPECT_EQ(kSendPacketCount, parser.sender_report().send_packet_count);
    EXPECT_EQ(kSendOctetCount, parser.sender_report().send_octet_count);
  }

  void ExpectLastReport(const RtcpParser& parser) {
    EXPECT_TRUE(parser.has_last_report());
    EXPECT_EQ(kLastSr, parser.last_report());
    EXPECT_EQ(kDelayLastSr, parser.delay_since_last_report());
  }

  void ExpectReceiverReference(const RtcpParser& parser) {
    EXPECT_TRUE(parser.has_receiver_reference_time_report());
    EXPECT_EQ(kRemoteSsrc, parser.receiver_reference_time_report().remote_ssrc);
    EXPECT_EQ(kNtpHigh, parser.receiver_reference_time_report().ntp_seconds);
    EXPECT_EQ(kNtpLow, parser.receiver_reference_time_report().ntp_fraction);
  }

  void ExpectCastFeedback(const RtcpParser& parser) {
    EXPECT_TRUE(parser.has_cast_message());
    EXPECT_EQ(kRemoteSsrc, parser.cast_message().remote_ssrc);
    EXPECT_EQ(FrameId::first() + kAckFrameId,
              parser.cast_message().ack_frame_id);

    MissingFramesAndPacketsMap::const_iterator frame_it =
        parser.cast_message().missing_frames_and_packets.begin();

    EXPECT_TRUE(
        frame_it != parser.cast_message().missing_frames_and_packets.end());
    EXPECT_EQ(FrameId::first() + kLostFrameId, frame_it->first);
    EXPECT_EQ(frame_it->second.size(), 1UL);
    EXPECT_EQ(*frame_it->second.begin(), kRtcpCastAllPacketsLost);
    ++frame_it;
    EXPECT_TRUE(
        frame_it != parser.cast_message().missing_frames_and_packets.end());
    EXPECT_EQ(FrameId::first() + kFrameIdWithLostPackets, frame_it->first);
    EXPECT_EQ(3UL, frame_it->second.size());
    PacketIdSet::const_iterator packet_it = frame_it->second.begin();
    EXPECT_EQ(kLostPacketId1, *packet_it);
    ++packet_it;
    EXPECT_EQ(kLostPacketId2, *packet_it);
    ++packet_it;
    EXPECT_EQ(kLostPacketId3, *packet_it);
    ++frame_it;
    EXPECT_TRUE(
        frame_it == parser.cast_message().missing_frames_and_packets.end());
  }

  void ExpectExtendedCastFeedback(
      const RtcpParser& parser,
      const std::vector<FrameId>& receiving_frames) {
    EXPECT_TRUE(parser.has_cst2_message());
    EXPECT_EQ(kFeedbackSeq, parser.cast_message().feedback_count);
    ASSERT_EQ(parser.cast_message().received_later_frames.size(),
              receiving_frames.size());
    for (size_t i = 0; i < receiving_frames.size(); ++i)
      EXPECT_EQ(parser.cast_message().received_later_frames[i],
                receiving_frames[i]);
  }

  void ExpectReceiverLog(const RtcpParser& parser,
                         const RtcpReceiverLogMessage& expected_receiver_log) {
    EXPECT_TRUE(parser.has_receiver_log());
    EXPECT_EQ(expected_receiver_log.size(), parser.receiver_log().size());
    RtcpReceiverLogMessage::const_iterator expected_it =
        expected_receiver_log.begin();
    RtcpReceiverLogMessage::const_iterator incoming_it =
        parser.receiver_log().begin();
    for (; incoming_it != parser.receiver_log().end();
         ++incoming_it, ++expected_it) {
      EXPECT_EQ(expected_it->rtp_timestamp_, incoming_it->rtp_timestamp_);
      EXPECT_EQ(expected_it->event_log_messages_.size(),
                incoming_it->event_log_messages_.size());

      RtcpReceiverEventLogMessages::const_iterator event_incoming_it =
          incoming_it->event_log_messages_.begin();
      RtcpReceiverEventLogMessages::const_iterator event_expected_it =
          expected_it->event_log_messages_.begin();
      for (; event_incoming_it != incoming_it->event_log_messages_.end();
           ++event_incoming_it, ++event_expected_it) {
        EXPECT_EQ(event_expected_it->type, event_incoming_it->type);
        EXPECT_EQ(event_expected_it->event_timestamp,
                  event_incoming_it->event_timestamp);
        if (event_expected_it->type == PACKET_RECEIVED) {
          EXPECT_EQ(event_expected_it->packet_id, event_incoming_it->packet_id);
        } else {
          EXPECT_EQ(event_expected_it->delay_delta,
                    event_incoming_it->delay_delta);
        }
      }
    }
  }

  std::unique_ptr<base::SimpleTestTickClock> testing_clock_;
  scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;

 private:
  DISALLOW_COPY_AND_ASSIGN(RtcpParserTest);
};

TEST_F(RtcpParserTest, BrokenPacketIsIgnored) {
  const char bad_packet[] = {0, 0, 0, 0};
  RtcpParser parser(kLocalSsrc, kRemoteSsrc);
  base::BigEndianReader reader(bad_packet, sizeof(bad_packet));
  EXPECT_FALSE(parser.Parse(&reader));
}

TEST_F(RtcpParserTest, UnknownBlockIgnored) {
  // Only unknown data, nothing happens.
  TestRtcpPacketBuilder p;
  p.AddUnknownBlock();
  RtcpParser parser1(kLocalSsrc, 0);
  EXPECT_TRUE(parser1.Parse(p.Reader()));
  EXPECT_FALSE(HasAnything(parser1));

  // Add valid sender report *after* unknown data - should work fine.
  p.AddSr(kRemoteSsrc, 0);
  RtcpParser parser2(kLocalSsrc, kRemoteSsrc);
  EXPECT_TRUE(parser2.Parse(p.Reader()));
  ExpectSenderInfo(parser2);
}

TEST_F(RtcpParserTest, InjectSenderReportPacket) {
  TestRtcpPacketBuilder p;
  p.AddSr(kRemoteSsrc, 0);

  // Expected to be ignored since the sender ssrc does not match our
  // remote ssrc.
  RtcpParser parser1(kLocalSsrc, 0);
  EXPECT_TRUE(parser1.Parse(p.Reader()));
  EXPECT_FALSE(HasAnything(parser1));

  // Expected to be pass through since the sender ssrc match our remote ssrc.
  RtcpParser parser2(kLocalSsrc, kRemoteSsrc);
  EXPECT_TRUE(parser2.Parse(p.Reader()));
  ExpectSenderInfo(parser2);
}

TEST_F(RtcpParserTest, InjectReceiveReportPacket) {
  TestRtcpPacketBuilder p1;
  p1.AddRr(kRemoteSsrc, 1);
  p1.AddRb(kUnknownSsrc);

  // Expected to be ignored since the source ssrc does not match our
  // local ssrc.
  RtcpParser parser1(kLocalSsrc, kRemoteSsrc);
  EXPECT_TRUE(parser1.Parse(p1.Reader()));
  EXPECT_FALSE(HasAnything(parser1));

  TestRtcpPacketBuilder p2;
  p2.AddRr(kRemoteSsrc, 1);
  p2.AddRb(kLocalSsrc);

  // Expected to be pass through since the sender ssrc match our local ssrc.
  RtcpParser parser2(kLocalSsrc, kRemoteSsrc);
  EXPECT_TRUE(parser2.Parse(p2.Reader()));
  ExpectLastReport(parser2);
}

TEST_F(RtcpParserTest, InjectSenderReportWithReportBlockPacket) {
  TestRtcpPacketBuilder p1;
  p1.AddSr(kRemoteSsrc, 1);
  p1.AddRb(kUnknownSsrc);

  // Sender report expected to be ignored since the sender ssrc does not match
  // our remote ssrc.
  // Report block expected to be ignored since the source ssrc does not match
  // our local ssrc.
  RtcpParser parser1(kLocalSsrc, 0);
  EXPECT_TRUE(parser1.Parse(p1.Reader()));
  EXPECT_FALSE(HasAnything(parser1));

  // Sender report expected to be pass through since the sender ssrc match our
  // remote ssrc.
  // Report block expected to be ignored since the source ssrc does not match
  // our local ssrc.
  RtcpParser parser2(kLocalSsrc, kRemoteSsrc);
  EXPECT_TRUE(parser2.Parse(p1.Reader()));
  ExpectSenderInfo(parser2);
  EXPECT_FALSE(parser2.has_last_report());

  // Sender report expected to be ignored since the sender ssrc does not match
  // our remote ssrc.
  // Report block expected to be ignored too since it's a part of the
  // sender report.
  TestRtcpPacketBuilder p2;
  p2.AddSr(kRemoteSsrc, 1);
  p2.AddRb(kLocalSsrc);

  RtcpParser parser3(kLocalSsrc, 0);
  EXPECT_TRUE(parser3.Parse(p2.Reader()));
  EXPECT_FALSE(parser3.has_last_report());

  // Sender report expected to be pass through since the sender ssrc match our
  // remote ssrc.
  // Report block expected to be pass through since the sender ssrc match
  // our local ssrc.
  RtcpParser parser4(kLocalSsrc, kRemoteSsrc);
  EXPECT_TRUE(parser4.Parse(p2.Reader()));
  ExpectSenderInfo(parser4);
  ExpectLastReport(parser4);
}

TEST_F(RtcpParserTest, InjectSenderReportPacketWithDlrr) {
  TestRtcpPacketBuilder p;
  p.AddSr(kRemoteSsrc, 0);
  p.AddXrHeader(kRemoteSsrc);
  p.AddXrUnknownBlock();
  p.AddXrExtendedDlrrBlock(kRemoteSsrc);
  p.AddXrUnknownBlock();

  // Expected to be ignored since the source ssrc does not match our
  // local ssrc.
  RtcpParser parser1(kLocalSsrc, 0);
  EXPECT_TRUE(parser1.Parse(p.Reader()));
  EXPECT_FALSE(HasAnything(parser1));

  // Expected to be pass through since the sender ssrc match our local ssrc.
  RtcpParser parser2(kLocalSsrc, kRemoteSsrc);
  EXPECT_TRUE(parser2.Parse(p.Reader()));
  ExpectSenderInfo(parser2);
  // DLRRs are ignored.
  EXPECT_FALSE(parser2.has_last_report());
}

TEST_F(RtcpParserTest, InjectReceiverReportPacketWithRrtr) {
  TestRtcpPacketBuilder p1;
  p1.AddRr(kRemoteSsrc, 1);
  p1.AddRb(kUnknownSsrc);
  p1.AddXrHeader(kRemoteSsrc);
  p1.AddXrRrtrBlock();

  // Expected to be ignored since the source ssrc does not match our
  // local ssrc.
  RtcpParser parser1(kLocalSsrc, 0);
  EXPECT_TRUE(parser1.Parse(p1.Reader()));
  EXPECT_FALSE(HasAnything(parser1));

  TestRtcpPacketBuilder p2;
  p2.AddRr(kRemoteSsrc, 1);
  p2.AddRb(kLocalSsrc);
  p2.AddXrHeader(kRemoteSsrc);
  p2.AddXrRrtrBlock();

  // Expected to be pass through since the sender ssrc match our local ssrc.
  RtcpParser parser2(kLocalSsrc, kRemoteSsrc);
  EXPECT_TRUE(parser2.Parse(p2.Reader()));
  ExpectLastReport(parser2);
  ExpectReceiverReference(parser2);
}

TEST_F(RtcpParserTest, InjectReceiverReportPacketWithIntraFrameRequest) {
  TestRtcpPacketBuilder p1;
  p1.AddRr(kRemoteSsrc, 1);
  p1.AddRb(kUnknownSsrc);

  // Expected to be ignored since the source ssrc does not match our
  // local ssrc.
  RtcpParser parser1(kLocalSsrc, 0);
  EXPECT_TRUE(parser1.Parse(p1.Reader()));
  EXPECT_FALSE(HasAnything(parser1));

  TestRtcpPacketBuilder p2;
  p2.AddRr(kRemoteSsrc, 1);
  p2.AddRb(kLocalSsrc);

  RtcpParser parser2(kLocalSsrc, kRemoteSsrc);
  EXPECT_TRUE(parser2.Parse(p2.Reader()));
  ExpectLastReport(parser2);
}

TEST_F(RtcpParserTest, InjectReceiverReportPacketWithCastFeedback) {
  TestRtcpPacketBuilder p1;
  p1.AddRr(kRemoteSsrc, 1);
  p1.AddRb(kUnknownSsrc);
  p1.AddCast(kRemoteSsrc, kUnknownSsrc, kTargetDelay);

  // Expected to be ignored since the source ssrc does not match our
  // local ssrc.
  RtcpParser parser1(kLocalSsrc, 0);
  EXPECT_TRUE(parser1.Parse(p1.Reader()));
  EXPECT_FALSE(HasAnything(parser1));

  TestRtcpPacketBuilder p2;
  p2.AddRr(kRemoteSsrc, 1);
  p2.AddRb(kLocalSsrc);
  p2.AddCast(kRemoteSsrc, kLocalSsrc, kTargetDelay);

  // Expected to be pass through since the sender ssrc match our local ssrc.
  RtcpParser parser2(kLocalSsrc, kRemoteSsrc);
  parser2.SetMaxValidFrameId(FrameId::first() + kAckFrameId);
  EXPECT_TRUE(parser2.Parse(p2.Reader()));
  ExpectLastReport(parser2);
  ExpectCastFeedback(parser2);
}

TEST_F(RtcpParserTest, ExtendedCastFeedbackParsing) {
  // Empty ACK field.
  TestRtcpPacketBuilder builder;
  builder.AddRr(kRemoteSsrc, 1);
  builder.AddRb(kLocalSsrc);
  builder.AddCast(kRemoteSsrc, kLocalSsrc, kTargetDelay);
  std::vector<FrameId> receiving_frames;
  builder.AddCst2(receiving_frames);
  RtcpParser parser(kLocalSsrc, kRemoteSsrc);
  parser.SetMaxValidFrameId(FrameId::first() + kAckFrameId + 3);
  EXPECT_TRUE(parser.Parse(builder.Reader()));
  ExpectLastReport(parser);
  ExpectCastFeedback(parser);
  ExpectExtendedCastFeedback(parser, receiving_frames);

  // One ACK bitmask.
  TestRtcpPacketBuilder builder2;
  builder2.AddRr(kRemoteSsrc, 1);
  builder2.AddRb(kLocalSsrc);
  builder2.AddCast(kRemoteSsrc, kLocalSsrc, kTargetDelay);
  receiving_frames.push_back(FrameId::first() + kAckFrameId + 2);
  receiving_frames.push_back(FrameId::first() + kAckFrameId + 3);
  builder2.AddCst2(receiving_frames);
  RtcpParser parser2(kLocalSsrc, kRemoteSsrc);
  parser2.SetMaxValidFrameId(FrameId::first() + kAckFrameId + 3);
  EXPECT_TRUE(parser2.Parse(builder2.Reader()));
  ExpectLastReport(parser2);
  ExpectCastFeedback(parser2);
  ExpectExtendedCastFeedback(parser2, receiving_frames);

  // Mutiple ACK bitmasks.
  TestRtcpPacketBuilder builder3;
  builder3.AddRr(kRemoteSsrc, 1);
  builder3.AddRb(kLocalSsrc);
  builder3.AddCast(kRemoteSsrc, kLocalSsrc, kTargetDelay);
  receiving_frames.clear();
  for (size_t i = 0; i < 15; ++i)
    receiving_frames.push_back(FrameId::first() + kAckFrameId + 2 + i * 10);
  builder3.AddCst2(receiving_frames);
  RtcpParser parser3(kLocalSsrc, kRemoteSsrc);
  parser3.SetMaxValidFrameId(FrameId::first() + kAckFrameId + 152);
  EXPECT_TRUE(parser3.Parse(builder3.Reader()));
  ExpectLastReport(parser3);
  ExpectCastFeedback(parser3);
  ExpectExtendedCastFeedback(parser3, receiving_frames);

  // Expected to be ignored if there is error in the extended ACK message.
  TestRtcpPacketBuilder builder4;
  builder4.AddRr(kRemoteSsrc, 1);
  builder4.AddRb(kLocalSsrc);
  builder4.AddCast(kRemoteSsrc, kLocalSsrc, kTargetDelay);
  builder4.AddErrorCst2();
  RtcpParser parser4(kLocalSsrc, kRemoteSsrc);
  parser4.SetMaxValidFrameId(FrameId::first() + kAckFrameId + 3);
  EXPECT_TRUE(parser4.Parse(builder4.Reader()));
  ExpectLastReport(parser4);
  ExpectCastFeedback(parser4);
  EXPECT_FALSE(parser4.has_cst2_message());

  // Expected to be ignored if there is only "CST2" identifier.
  TestRtcpPacketBuilder builder5;
  builder5.AddRr(kRemoteSsrc, 1);
  builder5.AddRb(kLocalSsrc);
  receiving_frames.clear();
  builder5.AddCst2(receiving_frames);
  RtcpParser parser5(kLocalSsrc, kRemoteSsrc);
  parser5.SetMaxValidFrameId(FrameId::first() + kAckFrameId + 3);
  EXPECT_TRUE(parser5.Parse(builder5.Reader()));
  ExpectLastReport(parser5);
  EXPECT_FALSE(parser5.has_cst2_message());
}

TEST_F(RtcpParserTest, InjectReceiverReportPli) {
  // Expect to be ignored since the sender ssrc does not match.
  TestRtcpPacketBuilder builder1;
  builder1.AddPli(kUnknownSsrc, kLocalSsrc);
  RtcpParser parser1(kLocalSsrc, kRemoteSsrc);
  EXPECT_TRUE(parser1.Parse(builder1.Reader()));
  EXPECT_FALSE(parser1.has_picture_loss_indicator());

  // Expect to be ignored since the receiver ssrc does not match.
  TestRtcpPacketBuilder builder2;
  builder2.AddPli(kRemoteSsrc, kUnknownSsrc);
  RtcpParser parser2(kLocalSsrc, kRemoteSsrc);
  EXPECT_TRUE(parser2.Parse(builder2.Reader()));
  EXPECT_FALSE(parser2.has_picture_loss_indicator());

  TestRtcpPacketBuilder builder3;
  builder3.AddPli(kRemoteSsrc, kLocalSsrc);
  RtcpParser parser3(kLocalSsrc, kRemoteSsrc);
  EXPECT_TRUE(parser3.Parse(builder3.Reader()));
  EXPECT_TRUE(parser3.has_picture_loss_indicator());
}

TEST_F(RtcpParserTest, InjectReceiverReportWithReceiverLogVerificationBase) {
  static const uint32_t kTimeBaseMs = 12345678;
  static const uint32_t kTimeDelayMs = 10;
  static const uint32_t kDelayDeltaMs = 123;
  base::SimpleTestTickClock testing_clock;
  testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));

  RtcpReceiverLogMessage receiver_log;
  RtcpReceiverFrameLogMessage frame_log(RtpTimeTicks().Expand(kRtpTimestamp));
  RtcpReceiverEventLogMessage event_log;

  event_log.type = FRAME_ACK_SENT;
  event_log.event_timestamp = testing_clock.NowTicks();
  event_log.delay_delta = base::TimeDelta::FromMilliseconds(kDelayDeltaMs);
  frame_log.event_log_messages_.push_back(event_log);

  testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs));
  event_log.type = PACKET_RECEIVED;
  event_log.event_timestamp = testing_clock.NowTicks();
  event_log.packet_id = kLostPacketId1;
  frame_log.event_log_messages_.push_back(event_log);

  event_log.type = PACKET_RECEIVED;
  event_log.event_timestamp = testing_clock.NowTicks();
  event_log.packet_id = kLostPacketId2;
  frame_log.event_log_messages_.push_back(event_log);

  receiver_log.push_back(frame_log);

  TestRtcpPacketBuilder p;
  p.AddRr(kRemoteSsrc, 1);
  p.AddRb(kLocalSsrc);
  p.AddReceiverLog(kRemoteSsrc);
  p.AddReceiverFrameLog(kRtpTimestamp, 3, kTimeBaseMs);
  p.AddReceiverEventLog(kDelayDeltaMs, FRAME_ACK_SENT, 0);
  p.AddReceiverEventLog(kLostPacketId1, PACKET_RECEIVED, kTimeDelayMs);
  p.AddReceiverEventLog(kLostPacketId2, PACKET_RECEIVED, kTimeDelayMs);

  RtcpParser parser(kLocalSsrc, kRemoteSsrc);
  EXPECT_TRUE(parser.Parse(p.Reader()));
  ExpectReceiverLog(parser, receiver_log);
}

TEST_F(RtcpParserTest, InjectReceiverReportWithReceiverLogVerificationMulti) {
  static const uint32_t kTimeBaseMs = 12345678;
  static const uint32_t kTimeDelayMs = 10;
  static const int kDelayDeltaMs = 123;  // To be varied for every frame.
  base::SimpleTestTickClock testing_clock;
  testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));

  RtcpReceiverLogMessage receiver_log;

  for (int j = 0; j < 100; ++j) {
    RtcpReceiverFrameLogMessage frame_log(RtpTimeTicks().Expand(kRtpTimestamp));
    RtcpReceiverEventLogMessage event_log;
    event_log.type = FRAME_ACK_SENT;
    event_log.event_timestamp = testing_clock.NowTicks();
    event_log.delay_delta =
        base::TimeDelta::FromMilliseconds((j - 50) * kDelayDeltaMs);
    frame_log.event_log_messages_.push_back(event_log);
    receiver_log.push_back(frame_log);
    testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs));
  }

  TestRtcpPacketBuilder p;
  p.AddRr(kRemoteSsrc, 1);
  p.AddRb(kLocalSsrc);
  p.AddReceiverLog(kRemoteSsrc);
  for (int i = 0; i < 100; ++i) {
    p.AddReceiverFrameLog(kRtpTimestamp, 1, kTimeBaseMs + i * kTimeDelayMs);
    const int delay = (i - 50) * kDelayDeltaMs;
    p.AddReceiverEventLog(static_cast<uint16_t>(delay), FRAME_ACK_SENT, 0);
  }

  RtcpParser parser(kLocalSsrc, kRemoteSsrc);
  EXPECT_TRUE(parser.Parse(p.Reader()));
  ExpectReceiverLog(parser, receiver_log);
}

TEST(RtcpUtilityTest, NtpAndTime) {
  const int64_t kSecondsbetweenYear1900and2010 = INT64_C(40176 * 24 * 60 * 60);
  const int64_t kSecondsbetweenYear1900and2030 = INT64_C(47481 * 24 * 60 * 60);

  uint32_t ntp_seconds_1 = 0;
  uint32_t ntp_fraction_1 = 0;
  base::TimeTicks input_time = base::TimeTicks::Now();
  ConvertTimeTicksToNtp(input_time, &ntp_seconds_1, &ntp_fraction_1);

  // Verify absolute value.
  EXPECT_GT(ntp_seconds_1, kSecondsbetweenYear1900and2010);
  EXPECT_LT(ntp_seconds_1, kSecondsbetweenYear1900and2030);

  base::TimeTicks out_1 = ConvertNtpToTimeTicks(ntp_seconds_1, ntp_fraction_1);
  EXPECT_EQ(input_time, out_1);  // Verify inverse.

  base::TimeDelta time_delta = base::TimeDelta::FromMilliseconds(1000);
  input_time += time_delta;

  uint32_t ntp_seconds_2 = 0;
  uint32_t ntp_fraction_2 = 0;

  ConvertTimeTicksToNtp(input_time, &ntp_seconds_2, &ntp_fraction_2);
  base::TimeTicks out_2 = ConvertNtpToTimeTicks(ntp_seconds_2, ntp_fraction_2);
  EXPECT_EQ(input_time, out_2);  // Verify inverse.

  // Verify delta.
  EXPECT_EQ((out_2 - out_1), time_delta);
  EXPECT_EQ((ntp_seconds_2 - ntp_seconds_1), UINT32_C(1));
  EXPECT_NEAR(ntp_fraction_2, ntp_fraction_1, 1);

  time_delta = base::TimeDelta::FromMilliseconds(500);
  input_time += time_delta;

  uint32_t ntp_seconds_3 = 0;
  uint32_t ntp_fraction_3 = 0;

  ConvertTimeTicksToNtp(input_time, &ntp_seconds_3, &ntp_fraction_3);
  base::TimeTicks out_3 = ConvertNtpToTimeTicks(ntp_seconds_3, ntp_fraction_3);
  EXPECT_EQ(input_time, out_3);  // Verify inverse.

  // Verify delta.
  EXPECT_EQ((out_3 - out_2), time_delta);
  EXPECT_NEAR((ntp_fraction_3 - ntp_fraction_2), 0xffffffff / 2, 1);
}

}  // namespace cast
}  // namespace media
