root/media/cast/rtcp/rtcp_receiver_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. OnReceivedCastFeedback
  2. called
  3. called_on_received_receiver_log_
  4. OnReceivedSenderReport
  5. OnReceiverReferenceTimeReport
  6. OnReceivedSendReportRequest
  7. OnReceivedReceiverLog
  8. OnReceivedSenderLog
  9. OnReceivedSenderLogCalled
  10. OnReceivedReceiverLogCalled
  11. SetExpectedReceiverLog
  12. SetExpectedSenderLog
  13. rtcp_receiver_
  14. InjectRtcpPacket
  15. TEST_F
  16. TEST_F
  17. TEST_F
  18. TEST_F
  19. TEST_F
  20. TEST_F
  21. TEST_F
  22. TEST_F
  23. TEST_F
  24. TEST_F
  25. TEST_F
  26. TEST_F

// Copyright 2013 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 "base/memory/scoped_ptr.h"
#include "base/test/simple_test_tick_clock.h"
#include "media/cast/cast_environment.h"
#include "media/cast/rtcp/mock_rtcp_receiver_feedback.h"
#include "media/cast/rtcp/mock_rtcp_sender_feedback.h"
#include "media/cast/rtcp/rtcp_receiver.h"
#include "media/cast/rtcp/rtcp_utility.h"
#include "media/cast/rtcp/test_rtcp_packet_builder.h"
#include "media/cast/test/fake_single_thread_task_runner.h"
#include "media/cast/transport/cast_transport_defines.h"
#include "testing/gmock/include/gmock/gmock.h"

namespace media {
namespace cast {

using testing::_;

static const uint32 kSenderSsrc = 0x10203;
static const uint32 kSourceSsrc = 0x40506;
static const uint32 kUnknownSsrc = 0xDEAD;
static const uint16 kTargetDelayMs = 100;
static const std::string kCName("test@10.1.1.1");

namespace {
class SenderFeedbackCastVerification : public RtcpSenderFeedback {
 public:
  SenderFeedbackCastVerification() : called_(false) {}

  virtual void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback)
      OVERRIDE {
    EXPECT_EQ(cast_feedback.media_ssrc_, kSenderSsrc);
    EXPECT_EQ(cast_feedback.ack_frame_id_, kAckFrameId);

    MissingFramesAndPacketsMap::const_iterator frame_it =
        cast_feedback.missing_frames_and_packets_.begin();

    EXPECT_TRUE(frame_it != cast_feedback.missing_frames_and_packets_.end());
    EXPECT_EQ(kLostFrameId, frame_it->first);
    EXPECT_TRUE(frame_it->second.empty());
    ++frame_it;
    EXPECT_TRUE(frame_it != cast_feedback.missing_frames_and_packets_.end());
    EXPECT_EQ(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_EQ(frame_it, cast_feedback.missing_frames_and_packets_.end());
    called_ = true;
  }

  bool called() const { return called_; }

 private:
  bool called_;

  DISALLOW_COPY_AND_ASSIGN(SenderFeedbackCastVerification);
};

class RtcpReceiverCastLogVerification : public RtcpReceiverFeedback {
 public:
  RtcpReceiverCastLogVerification()
      : called_on_received_sender_log_(false),
        called_on_received_receiver_log_(false) {}

  virtual void OnReceivedSenderReport(
      const transport::RtcpSenderInfo& remote_sender_info) OVERRIDE{};

  virtual void OnReceiverReferenceTimeReport(
      const RtcpReceiverReferenceTimeReport& remote_time_report) OVERRIDE{};

  virtual void OnReceivedSendReportRequest() OVERRIDE{};

  virtual void OnReceivedReceiverLog(const RtcpReceiverLogMessage& receiver_log)
      OVERRIDE {
    EXPECT_EQ(expected_receiver_log_.size(), receiver_log.size());
    RtcpReceiverLogMessage::const_iterator expected_it =
        expected_receiver_log_.begin();
    RtcpReceiverLogMessage::const_iterator incoming_it = receiver_log.begin();
    for (; incoming_it != receiver_log.end(); ++incoming_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 == kVideoPacketReceived) {
          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);
        }
      }
      expected_receiver_log_.pop_front();
      expected_it = expected_receiver_log_.begin();
    }
    called_on_received_receiver_log_ = true;
  }

  virtual void OnReceivedSenderLog(
      const transport::RtcpSenderLogMessage& sender_log) OVERRIDE {
    EXPECT_EQ(expected_sender_log_.size(), sender_log.size());

    transport::RtcpSenderLogMessage::const_iterator expected_it =
        expected_sender_log_.begin();
    transport::RtcpSenderLogMessage::const_iterator incoming_it =
        sender_log.begin();
    for (; expected_it != expected_sender_log_.end();
         ++expected_it, ++incoming_it) {
      EXPECT_EQ(expected_it->frame_status, incoming_it->frame_status);
      EXPECT_EQ(0xffffff & expected_it->rtp_timestamp,
                incoming_it->rtp_timestamp);
    }
    called_on_received_sender_log_ = true;
  }

  bool OnReceivedSenderLogCalled() { return called_on_received_sender_log_; }

  bool OnReceivedReceiverLogCalled() {
    return called_on_received_receiver_log_ && expected_receiver_log_.empty();
  }

  void SetExpectedReceiverLog(const RtcpReceiverLogMessage& receiver_log) {
    expected_receiver_log_ = receiver_log;
  }

  void SetExpectedSenderLog(const transport::RtcpSenderLogMessage& sender_log) {
    expected_sender_log_ = sender_log;
  }

 private:
  RtcpReceiverLogMessage expected_receiver_log_;
  transport::RtcpSenderLogMessage expected_sender_log_;
  bool called_on_received_sender_log_;
  bool called_on_received_receiver_log_;

  DISALLOW_COPY_AND_ASSIGN(RtcpReceiverCastLogVerification);
};

}  // namespace

class RtcpReceiverTest : public ::testing::Test {
 protected:
  RtcpReceiverTest()
      : testing_clock_(new base::SimpleTestTickClock()),
        task_runner_(new test::FakeSingleThreadTaskRunner(testing_clock_)),
        cast_environment_(new CastEnvironment(
            scoped_ptr<base::TickClock>(testing_clock_).Pass(),
            task_runner_,
            task_runner_,
            task_runner_)),
        rtcp_receiver_(new RtcpReceiver(cast_environment_,
                                        &mock_sender_feedback_,
                                        &mock_receiver_feedback_,
                                        &mock_rtt_feedback_,
                                        kSourceSsrc)) {
    EXPECT_CALL(mock_receiver_feedback_, OnReceivedSenderReport(_)).Times(0);
    EXPECT_CALL(mock_receiver_feedback_, OnReceiverReferenceTimeReport(_))
        .Times(0);
    EXPECT_CALL(mock_receiver_feedback_, OnReceivedSendReportRequest())
        .Times(0);
    EXPECT_CALL(mock_sender_feedback_, OnReceivedCastFeedback(_)).Times(0);
    EXPECT_CALL(mock_rtt_feedback_, OnReceivedDelaySinceLastReport(_, _, _))
        .Times(0);

    expected_sender_info_.ntp_seconds = kNtpHigh;
    expected_sender_info_.ntp_fraction = kNtpLow;
    expected_sender_info_.rtp_timestamp = kRtpTimestamp;
    expected_sender_info_.send_packet_count = kSendPacketCount;
    expected_sender_info_.send_octet_count = kSendOctetCount;

    expected_report_block_.remote_ssrc = kSenderSsrc;
    expected_report_block_.media_ssrc = kSourceSsrc;
    expected_report_block_.fraction_lost = kLoss >> 24;
    expected_report_block_.cumulative_lost = kLoss & 0xffffff;
    expected_report_block_.extended_high_sequence_number = kExtendedMax;
    expected_report_block_.jitter = kTestJitter;
    expected_report_block_.last_sr = kLastSr;
    expected_report_block_.delay_since_last_sr = kDelayLastSr;
    expected_receiver_reference_report_.remote_ssrc = kSenderSsrc;
    expected_receiver_reference_report_.ntp_seconds = kNtpHigh;
    expected_receiver_reference_report_.ntp_fraction = kNtpLow;
  }

  virtual ~RtcpReceiverTest() {}

  // Injects an RTCP packet into the receiver.
  void InjectRtcpPacket(const uint8* packet, uint16 length) {
    RtcpParser rtcp_parser(packet, length);
    rtcp_receiver_->IncomingRtcpPacket(&rtcp_parser);
  }

  base::SimpleTestTickClock* testing_clock_;  // Owned by CastEnvironment.
  scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
  scoped_refptr<CastEnvironment> cast_environment_;
  MockRtcpReceiverFeedback mock_receiver_feedback_;
  MockRtcpRttFeedback mock_rtt_feedback_;
  MockRtcpSenderFeedback mock_sender_feedback_;
  scoped_ptr<RtcpReceiver> rtcp_receiver_;
  transport::RtcpSenderInfo expected_sender_info_;
  transport::RtcpReportBlock expected_report_block_;
  RtcpReceiverReferenceTimeReport expected_receiver_reference_report_;

  DISALLOW_COPY_AND_ASSIGN(RtcpReceiverTest);
};

TEST_F(RtcpReceiverTest, BrokenPacketIsIgnored) {
  const uint8 bad_packet[] = {0, 0, 0, 0};
  InjectRtcpPacket(bad_packet, sizeof(bad_packet));
}

TEST_F(RtcpReceiverTest, InjectSenderReportPacket) {
  TestRtcpPacketBuilder p;
  p.AddSr(kSenderSsrc, 0);

  // Expected to be ignored since the sender ssrc does not match our
  // remote ssrc.
  InjectRtcpPacket(p.Data(), p.Length());

  EXPECT_CALL(mock_receiver_feedback_,
              OnReceivedSenderReport(expected_sender_info_)).Times(1);
  rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);

  // Expected to be pass through since the sender ssrc match our remote ssrc.
  InjectRtcpPacket(p.Data(), p.Length());
}

TEST_F(RtcpReceiverTest, InjectReceiveReportPacket) {
  TestRtcpPacketBuilder p1;
  p1.AddRr(kSenderSsrc, 1);
  p1.AddRb(kUnknownSsrc);

  // Expected to be ignored since the source ssrc does not match our
  // local ssrc.
  InjectRtcpPacket(p1.Data(), p1.Length());

  EXPECT_CALL(mock_rtt_feedback_,
              OnReceivedDelaySinceLastReport(
                  kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);

  TestRtcpPacketBuilder p2;
  p2.AddRr(kSenderSsrc, 1);
  p2.AddRb(kSourceSsrc);

  // Expected to be pass through since the sender ssrc match our local ssrc.
  InjectRtcpPacket(p2.Data(), p2.Length());
}

TEST_F(RtcpReceiverTest, InjectSenderReportWithReportBlockPacket) {
  TestRtcpPacketBuilder p1;
  p1.AddSr(kSenderSsrc, 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.
  InjectRtcpPacket(p1.Data(), p1.Length());

  EXPECT_CALL(mock_receiver_feedback_,
              OnReceivedSenderReport(expected_sender_info_)).Times(1);
  rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);

  // 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.
  InjectRtcpPacket(p1.Data(), p1.Length());

  EXPECT_CALL(mock_receiver_feedback_, OnReceivedSenderReport(_)).Times(0);
  EXPECT_CALL(mock_rtt_feedback_,
              OnReceivedDelaySinceLastReport(
                  kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);

  rtcp_receiver_->SetRemoteSSRC(0);

  TestRtcpPacketBuilder p2;
  p2.AddSr(kSenderSsrc, 1);
  p2.AddRb(kSourceSsrc);

  // Sender report expected to be ignored since the sender ssrc does not match
  // our remote ssrc.
  // Receiver report expected to be pass through since the sender ssrc match
  // our local ssrc.
  InjectRtcpPacket(p2.Data(), p2.Length());

  EXPECT_CALL(mock_receiver_feedback_,
              OnReceivedSenderReport(expected_sender_info_)).Times(1);
  EXPECT_CALL(mock_rtt_feedback_,
              OnReceivedDelaySinceLastReport(
                  kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);

  rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);

  // Sender report expected to be pass through since the sender ssrc match our
  // remote ssrc.
  // Receiver report expected to be pass through since the sender ssrc match
  // our local ssrc.
  InjectRtcpPacket(p2.Data(), p2.Length());
}

TEST_F(RtcpReceiverTest, InjectSenderReportPacketWithDlrr) {
  TestRtcpPacketBuilder p;
  p.AddSr(kSenderSsrc, 0);
  p.AddXrHeader(kSenderSsrc);
  p.AddXrUnknownBlock();
  p.AddXrExtendedDlrrBlock(kSenderSsrc);
  p.AddXrUnknownBlock();
  p.AddSdesCname(kSenderSsrc, kCName);

  // Expected to be ignored since the source ssrc does not match our
  // local ssrc.
  InjectRtcpPacket(p.Data(), p.Length());

  EXPECT_CALL(mock_receiver_feedback_,
              OnReceivedSenderReport(expected_sender_info_)).Times(1);
  EXPECT_CALL(mock_rtt_feedback_,
              OnReceivedDelaySinceLastReport(
                  kSenderSsrc, kLastSr, kDelayLastSr)).Times(1);

  // Enable receiving sender report.
  rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);

  // Expected to be pass through since the sender ssrc match our local ssrc.
  InjectRtcpPacket(p.Data(), p.Length());
}

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

  // Expected to be ignored since the source ssrc does not match our
  // local ssrc.
  InjectRtcpPacket(p1.Data(), p1.Length());

  EXPECT_CALL(mock_rtt_feedback_,
              OnReceivedDelaySinceLastReport(
                  kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);
  EXPECT_CALL(mock_receiver_feedback_,
              OnReceiverReferenceTimeReport(
                  expected_receiver_reference_report_)).Times(1);

  // Enable receiving reference time report.
  rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);

  TestRtcpPacketBuilder p2;
  p2.AddRr(kSenderSsrc, 1);
  p2.AddRb(kSourceSsrc);
  p2.AddXrHeader(kSenderSsrc);
  p2.AddXrRrtrBlock();

  // Expected to be pass through since the sender ssrc match our local ssrc.
  InjectRtcpPacket(p2.Data(), p2.Length());
}

TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithIntraFrameRequest) {
  TestRtcpPacketBuilder p1;
  p1.AddRr(kSenderSsrc, 1);
  p1.AddRb(kUnknownSsrc);
  p1.AddPli(kSenderSsrc, kUnknownSsrc);

  // Expected to be ignored since the source ssrc does not match our
  // local ssrc.
  InjectRtcpPacket(p1.Data(), p1.Length());

  EXPECT_CALL(mock_rtt_feedback_,
              OnReceivedDelaySinceLastReport(
                  kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);

  TestRtcpPacketBuilder p2;
  p2.AddRr(kSenderSsrc, 1);
  p2.AddRb(kSourceSsrc);
  p2.AddPli(kSenderSsrc, kSourceSsrc);

  // Expected to be pass through since the sender ssrc match our local ssrc.
  InjectRtcpPacket(p2.Data(), p2.Length());
}

TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithCastFeedback) {
  TestRtcpPacketBuilder p1;
  p1.AddRr(kSenderSsrc, 1);
  p1.AddRb(kUnknownSsrc);
  p1.AddCast(kSenderSsrc, kUnknownSsrc, kTargetDelayMs);

  // Expected to be ignored since the source ssrc does not match our
  // local ssrc.
  InjectRtcpPacket(p1.Data(), p1.Length());

  EXPECT_CALL(mock_rtt_feedback_,
              OnReceivedDelaySinceLastReport(
                  kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);
  EXPECT_CALL(mock_sender_feedback_, OnReceivedCastFeedback(_)).Times(1);

  // Enable receiving the cast feedback.
  rtcp_receiver_->SetRemoteSSRC(kSenderSsrc);

  TestRtcpPacketBuilder p2;
  p2.AddRr(kSenderSsrc, 1);
  p2.AddRb(kSourceSsrc);
  p2.AddCast(kSenderSsrc, kSourceSsrc, kTargetDelayMs);

  // Expected to be pass through since the sender ssrc match our local ssrc.
  InjectRtcpPacket(p2.Data(), p2.Length());
}

TEST_F(RtcpReceiverTest, InjectReceiverReportPacketWithCastVerification) {
  SenderFeedbackCastVerification sender_feedback_cast_verification;
  RtcpReceiver rtcp_receiver(cast_environment_,
                             &sender_feedback_cast_verification,
                             &mock_receiver_feedback_,
                             &mock_rtt_feedback_,
                             kSourceSsrc);

  EXPECT_CALL(mock_rtt_feedback_,
              OnReceivedDelaySinceLastReport(
                  kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);

  // Enable receiving the cast feedback.
  rtcp_receiver.SetRemoteSSRC(kSenderSsrc);

  TestRtcpPacketBuilder p;
  p.AddRr(kSenderSsrc, 1);
  p.AddRb(kSourceSsrc);
  p.AddCast(kSenderSsrc, kSourceSsrc, kTargetDelayMs);

  // Expected to be pass through since the sender ssrc match our local ssrc.
  RtcpParser rtcp_parser(p.Data(), p.Length());
  rtcp_receiver.IncomingRtcpPacket(&rtcp_parser);

  EXPECT_TRUE(sender_feedback_cast_verification.called());
}

TEST_F(RtcpReceiverTest, InjectSenderReportWithCastSenderLogVerification) {
  RtcpReceiverCastLogVerification cast_log_verification;
  RtcpReceiver rtcp_receiver(cast_environment_,
                             &mock_sender_feedback_,
                             &cast_log_verification,
                             &mock_rtt_feedback_,
                             kSourceSsrc);
  rtcp_receiver.SetRemoteSSRC(kSenderSsrc);

  transport::RtcpSenderLogMessage sender_log;
  for (int j = 0; j < 359; ++j) {
    transport::RtcpSenderFrameLogMessage sender_frame_log;
    sender_frame_log.frame_status =
        transport::kRtcpSenderFrameStatusSentToNetwork;
    sender_frame_log.rtp_timestamp = kRtpTimestamp + j * 90;
    sender_log.push_back(sender_frame_log);
  }
  cast_log_verification.SetExpectedSenderLog(sender_log);

  TestRtcpPacketBuilder p;
  p.AddSr(kSenderSsrc, 0);
  p.AddSdesCname(kSenderSsrc, kCName);
  p.AddSenderLog(kSenderSsrc);

  for (int i = 0; i < 359; ++i) {
    p.AddSenderFrameLog(transport::kRtcpSenderFrameStatusSentToNetwork,
                        kRtpTimestamp + i * 90);
  }
  RtcpParser rtcp_parser(p.Data(), p.Length());
  rtcp_receiver.IncomingRtcpPacket(&rtcp_parser);

  EXPECT_TRUE(cast_log_verification.OnReceivedSenderLogCalled());
}

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

  RtcpReceiverCastLogVerification cast_log_verification;
  RtcpReceiver rtcp_receiver(cast_environment_,
                             &mock_sender_feedback_,
                             &cast_log_verification,
                             &mock_rtt_feedback_,
                             kSourceSsrc);
  rtcp_receiver.SetRemoteSSRC(kSenderSsrc);
  rtcp_receiver.SetCastReceiverEventHistorySize(100);

  RtcpReceiverLogMessage receiver_log;
  RtcpReceiverFrameLogMessage frame_log(kRtpTimestamp);
  RtcpReceiverEventLogMessage event_log;

  event_log.type = kVideoAckSent;
  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 = kVideoPacketReceived;
  event_log.event_timestamp = testing_clock.NowTicks();
  event_log.packet_id = kLostPacketId1;
  frame_log.event_log_messages_.push_back(event_log);
  receiver_log.push_back(frame_log);

  cast_log_verification.SetExpectedReceiverLog(receiver_log);

  TestRtcpPacketBuilder p;
  p.AddRr(kSenderSsrc, 1);
  p.AddRb(kSourceSsrc);
  p.AddReceiverLog(kSenderSsrc);
  p.AddReceiverFrameLog(kRtpTimestamp, 2, kTimeBaseMs);
  p.AddReceiverEventLog(kDelayDeltaMs, 5, 0);
  p.AddReceiverEventLog(kLostPacketId1, 8, kTimeDelayMs);

  // Adds duplicated receiver event.
  p.AddReceiverFrameLog(kRtpTimestamp, 2, kTimeBaseMs);
  p.AddReceiverEventLog(kDelayDeltaMs, 5, 0);
  p.AddReceiverEventLog(kLostPacketId1, 8, kTimeDelayMs);

  EXPECT_CALL(mock_rtt_feedback_,
              OnReceivedDelaySinceLastReport(
                  kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);

  RtcpParser rtcp_parser(p.Data(), p.Length());
  rtcp_receiver.IncomingRtcpPacket(&rtcp_parser);

  EXPECT_TRUE(cast_log_verification.OnReceivedReceiverLogCalled());
}

TEST_F(RtcpReceiverTest, InjectReceiverReportWithReceiverLogVerificationMulti) {
  static const uint32 kTimeBaseMs = 12345678;
  static const uint32 kTimeDelayMs = 10;
  static const uint32 kDelayDeltaMs = 123;
  base::SimpleTestTickClock testing_clock;
  testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));

  RtcpReceiverCastLogVerification cast_log_verification;
  RtcpReceiver rtcp_receiver(cast_environment_,
                             &mock_sender_feedback_,
                             &cast_log_verification,
                             &mock_rtt_feedback_,
                             kSourceSsrc);
  rtcp_receiver.SetRemoteSSRC(kSenderSsrc);

  RtcpReceiverLogMessage receiver_log;

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

  cast_log_verification.SetExpectedReceiverLog(receiver_log);

  TestRtcpPacketBuilder p;
  p.AddRr(kSenderSsrc, 1);
  p.AddRb(kSourceSsrc);
  p.AddReceiverLog(kSenderSsrc);
  for (int i = 0; i < 100; ++i) {
    p.AddReceiverFrameLog(kRtpTimestamp, 1, kTimeBaseMs + i * kTimeDelayMs);
    p.AddReceiverEventLog(kDelayDeltaMs, 5, 0);
  }

  EXPECT_CALL(mock_rtt_feedback_,
              OnReceivedDelaySinceLastReport(
                  kSourceSsrc, kLastSr, kDelayLastSr)).Times(1);

  RtcpParser rtcp_parser(p.Data(), p.Length());
  rtcp_receiver.IncomingRtcpPacket(&rtcp_parser);

  EXPECT_TRUE(cast_log_verification.OnReceivedReceiverLogCalled());
}

}  // namespace cast
}  // namespace media

/* [<][>][^][v][top][bottom][index][help] */