blob: 9363f7062ae7005833b266f430b7f9b900fc7871 [file] [log] [blame]
// 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 <stdint.h>
#include "base/test/simple_test_tick_clock.h"
#include "media/cast/cast_defines.h"
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/net/pacing/paced_sender.h"
#include "media/cast/net/rtcp/rtcp.h"
#include "media/cast/test/skewed_tick_clock.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace media {
namespace cast {
using testing::_;
static const uint32 kSenderSsrc = 0x10203;
static const uint32 kReceiverSsrc = 0x40506;
static const int kInitialReceiverClockOffsetSeconds = -5;
class FakeRtcpTransport : public PacedPacketSender {
public:
explicit FakeRtcpTransport(base::SimpleTestTickClock* clock)
: clock_(clock),
packet_delay_(base::TimeDelta::FromMilliseconds(42)) {}
void set_rtcp_destination(Rtcp* rtcp) { rtcp_ = rtcp; }
base::TimeDelta packet_delay() const { return packet_delay_; }
void set_packet_delay(base::TimeDelta delay) { packet_delay_ = delay; }
bool SendRtcpPacket(uint32 ssrc, PacketRef packet) override {
clock_->Advance(packet_delay_);
rtcp_->IncomingRtcpPacket(&packet->data[0], packet->data.size());
return true;
}
bool SendPackets(const SendPacketVector& packets) override { return false; }
bool ResendPackets(const SendPacketVector& packets,
const DedupInfo& dedup_info) override {
return false;
}
void CancelSendingPacket(const PacketKey& packet_key) override {}
private:
base::SimpleTestTickClock* const clock_;
base::TimeDelta packet_delay_;
Rtcp* rtcp_;
DISALLOW_COPY_AND_ASSIGN(FakeRtcpTransport);
};
class FakeReceiverStats : public RtpReceiverStatistics {
public:
FakeReceiverStats() {}
~FakeReceiverStats() override {}
void GetStatistics(uint8* fraction_lost,
uint32* cumulative_lost,
uint32* extended_high_sequence_number,
uint32* jitter) override {
*fraction_lost = 0;
*cumulative_lost = 0;
*extended_high_sequence_number = 0;
*jitter = 0;
}
private:
DISALLOW_COPY_AND_ASSIGN(FakeReceiverStats);
};
class MockFrameSender {
public:
MockFrameSender() {}
virtual ~MockFrameSender() {}
MOCK_METHOD1(OnReceivedCastFeedback,
void(const RtcpCastMessage& cast_message));
MOCK_METHOD1(OnMeasuredRoundTripTime, void(base::TimeDelta rtt));
private:
DISALLOW_COPY_AND_ASSIGN(MockFrameSender);
};
class RtcpTest : public ::testing::Test {
protected:
RtcpTest()
: sender_clock_(new base::SimpleTestTickClock()),
receiver_clock_(new test::SkewedTickClock(sender_clock_.get())),
sender_to_receiver_(sender_clock_.get()),
receiver_to_sender_(sender_clock_.get()),
rtcp_for_sender_(base::Bind(&MockFrameSender::OnReceivedCastFeedback,
base::Unretained(&mock_frame_sender_)),
base::Bind(&MockFrameSender::OnMeasuredRoundTripTime,
base::Unretained(&mock_frame_sender_)),
RtcpLogMessageCallback(),
sender_clock_.get(),
&sender_to_receiver_,
kSenderSsrc,
kReceiverSsrc),
rtcp_for_receiver_(RtcpCastMessageCallback(),
RtcpRttCallback(),
RtcpLogMessageCallback(),
receiver_clock_.get(),
&receiver_to_sender_,
kReceiverSsrc,
kSenderSsrc) {
sender_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
receiver_clock_->SetSkew(
1.0, // No skew.
base::TimeDelta::FromSeconds(kInitialReceiverClockOffsetSeconds));
sender_to_receiver_.set_rtcp_destination(&rtcp_for_receiver_);
receiver_to_sender_.set_rtcp_destination(&rtcp_for_sender_);
}
virtual ~RtcpTest() {}
scoped_ptr<base::SimpleTestTickClock> sender_clock_;
scoped_ptr<test::SkewedTickClock> receiver_clock_;
FakeRtcpTransport sender_to_receiver_;
FakeRtcpTransport receiver_to_sender_;
MockFrameSender mock_frame_sender_;
Rtcp rtcp_for_sender_;
Rtcp rtcp_for_receiver_;
FakeReceiverStats stats_;
DISALLOW_COPY_AND_ASSIGN(RtcpTest);
};
TEST_F(RtcpTest, LipSyncGleanedFromSenderReport) {
// Initially, expect no lip-sync info receiver-side without having first
// received a RTCP packet.
base::TimeTicks reference_time;
uint32 rtp_timestamp;
ASSERT_FALSE(rtcp_for_receiver_.GetLatestLipSyncTimes(&rtp_timestamp,
&reference_time));
// Send a Sender Report to the receiver.
const base::TimeTicks reference_time_sent = sender_clock_->NowTicks();
const uint32 rtp_timestamp_sent = 0xbee5;
rtcp_for_sender_.SendRtcpFromRtpSender(
reference_time_sent, rtp_timestamp_sent, 1, 1);
// Now the receiver should have lip-sync info. Confirm that the lip-sync
// reference time is the same as that sent.
EXPECT_TRUE(rtcp_for_receiver_.GetLatestLipSyncTimes(&rtp_timestamp,
&reference_time));
const base::TimeTicks rolled_back_time =
(reference_time -
// Roll-back relative clock offset:
base::TimeDelta::FromSeconds(kInitialReceiverClockOffsetSeconds) -
// Roll-back packet transmission time (because RTT is not yet known):
sender_to_receiver_.packet_delay());
EXPECT_NEAR(0, (reference_time_sent - rolled_back_time).InMicroseconds(), 5);
EXPECT_EQ(rtp_timestamp_sent, rtp_timestamp);
}
// TODO(miu): There were a few tests here that didn't actually test anything
// except that the code wouldn't crash and a callback method was invoked. We
// need to fill-in more testing of RTCP now that much of the refactoring work
// has been completed.
TEST_F(RtcpTest, RoundTripTimesDeterminedFromReportPingPong) {
const int iterations = 12;
EXPECT_CALL(mock_frame_sender_, OnMeasuredRoundTripTime(_))
.Times(iterations);
// Initially, neither side knows the round trip time.
ASSERT_EQ(base::TimeDelta(), rtcp_for_sender_.current_round_trip_time());
ASSERT_EQ(base::TimeDelta(), rtcp_for_receiver_.current_round_trip_time());
// Do a number of ping-pongs, checking how the round trip times are measured
// by the sender and receiver.
base::TimeDelta expected_rtt_according_to_sender;
base::TimeDelta expected_rtt_according_to_receiver;
for (int i = 0; i < iterations; ++i) {
const base::TimeDelta one_way_trip_time =
base::TimeDelta::FromMilliseconds(1 << i);
sender_to_receiver_.set_packet_delay(one_way_trip_time);
receiver_to_sender_.set_packet_delay(one_way_trip_time);
// Sender --> Receiver
base::TimeTicks reference_time_sent = sender_clock_->NowTicks();
uint32 rtp_timestamp_sent = 0xbee5 + i;
rtcp_for_sender_.SendRtcpFromRtpSender(
reference_time_sent, rtp_timestamp_sent, 1, 1);
EXPECT_EQ(expected_rtt_according_to_sender,
rtcp_for_sender_.current_round_trip_time());
#ifdef SENDER_PROVIDES_REPORT_BLOCK
EXPECT_EQ(expected_rtt_according_to_receiver,
rtcp_for_receiver_.current_round_trip_time());
#endif
// Receiver --> Sender
rtcp_for_receiver_.SendRtcpFromRtpReceiver(
NULL, base::TimeDelta(), NULL, &stats_);
expected_rtt_according_to_sender = one_way_trip_time * 2;
EXPECT_EQ(expected_rtt_according_to_sender,
rtcp_for_sender_.current_round_trip_time());
#ifdef SENDER_PROVIDES_REPORT_BLOCK
EXPECT_EQ(expected_rtt_according_to_receiver,
rtcp_for_receiver_.current_round_trip_time();
#endif
// In the next iteration of this loop, after the receiver gets the sender
// report, it will be measuring a round trip time consisting of two
// different one-way trip times.
expected_rtt_according_to_receiver =
(one_way_trip_time + one_way_trip_time * 2) / 2;
}
}
// TODO(miu): Find a better home for this test.
TEST(MisplacedCastTest, NtpAndTime) {
const int64 kSecondsbetweenYear1900and2010 = INT64_C(40176 * 24 * 60 * 60);
const int64 kSecondsbetweenYear1900and2030 = INT64_C(47481 * 24 * 60 * 60);
uint32 ntp_seconds_1 = 0;
uint32 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 ntp_seconds_2 = 0;
uint32 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 ntp_seconds_3 = 0;
uint32 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