// 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 #include "base/test/simple_test_tick_clock.h" #include "base/time/time.h" #include "media/cast/rtp_receiver/receiver_stats.h" #include "media/cast/rtp_receiver/rtp_receiver_defines.h" namespace media { namespace cast { static const int64 kStartMillisecond = GG_INT64_C(12345678900000); static const uint32 kStdTimeIncrementMs = 33; class ReceiverStatsTest : public ::testing::Test { protected: ReceiverStatsTest() : stats_(&testing_clock_), rtp_header_(), fraction_lost_(0), cumulative_lost_(0), extended_high_sequence_number_(0), jitter_(0) { testing_clock_.Advance( base::TimeDelta::FromMilliseconds(kStartMillisecond)); start_time_ = testing_clock_.NowTicks(); delta_increments_ = base::TimeDelta::FromMilliseconds(kStdTimeIncrementMs); rtp_header_.webrtc.header.sequenceNumber = 0; rtp_header_.webrtc.header.timestamp = 0; } virtual ~ReceiverStatsTest() {} uint32 ExpectedJitter(uint32 const_interval, int num_packets) { float jitter = 0; // Assume timestamps have a constant kStdTimeIncrementMs interval. float float_interval = static_cast(const_interval - kStdTimeIncrementMs); for (int i = 0; i < num_packets; ++i) { jitter += (float_interval - jitter) / 16; } return static_cast(jitter + 0.5f); } ReceiverStats stats_; RtpCastHeader rtp_header_; uint8 fraction_lost_; uint32 cumulative_lost_; uint32 extended_high_sequence_number_; uint32 jitter_; base::SimpleTestTickClock testing_clock_; base::TimeTicks start_time_; base::TimeDelta delta_increments_; DISALLOW_COPY_AND_ASSIGN(ReceiverStatsTest); }; TEST_F(ReceiverStatsTest, ResetState) { stats_.GetStatistics(&fraction_lost_, &cumulative_lost_, &extended_high_sequence_number_, &jitter_); EXPECT_EQ(0u, fraction_lost_); EXPECT_EQ(0u, cumulative_lost_); EXPECT_EQ(0u, extended_high_sequence_number_); EXPECT_EQ(0u, jitter_); } TEST_F(ReceiverStatsTest, LossCount) { for (int i = 0; i < 300; ++i) { if (i % 4) stats_.UpdateStatistics(rtp_header_); if (i % 3) { rtp_header_.webrtc.header.timestamp += 33 * 90; } ++rtp_header_.webrtc.header.sequenceNumber; testing_clock_.Advance(delta_increments_); } stats_.GetStatistics(&fraction_lost_, &cumulative_lost_, &extended_high_sequence_number_, &jitter_); EXPECT_EQ(63u, fraction_lost_); EXPECT_EQ(74u, cumulative_lost_); // Build extended sequence number. uint32 extended_seq_num = rtp_header_.webrtc.header.sequenceNumber - 1; EXPECT_EQ(extended_seq_num, extended_high_sequence_number_); } TEST_F(ReceiverStatsTest, NoLossWrap) { rtp_header_.webrtc.header.sequenceNumber = 65500; for (int i = 0; i < 300; ++i) { stats_.UpdateStatistics(rtp_header_); if (i % 3) { rtp_header_.webrtc.header.timestamp += 33 * 90; } ++rtp_header_.webrtc.header.sequenceNumber; testing_clock_.Advance(delta_increments_); } stats_.GetStatistics(&fraction_lost_, &cumulative_lost_, &extended_high_sequence_number_, &jitter_); EXPECT_EQ(0u, fraction_lost_); EXPECT_EQ(0u, cumulative_lost_); // Build extended sequence number (one wrap cycle). uint32 extended_seq_num = (1 << 16) + rtp_header_.webrtc.header.sequenceNumber - 1; EXPECT_EQ(extended_seq_num, extended_high_sequence_number_); } TEST_F(ReceiverStatsTest, LossCountWrap) { const uint32 start_sequence_number = 65500; rtp_header_.webrtc.header.sequenceNumber = start_sequence_number; for (int i = 0; i < 300; ++i) { if (i % 4) stats_.UpdateStatistics(rtp_header_); if (i % 3) // Update timestamp. ++rtp_header_.webrtc.header.timestamp; ++rtp_header_.webrtc.header.sequenceNumber; testing_clock_.Advance(delta_increments_); } stats_.GetStatistics(&fraction_lost_, &cumulative_lost_, &extended_high_sequence_number_, &jitter_); EXPECT_EQ(63u, fraction_lost_); EXPECT_EQ(74u, cumulative_lost_); // Build extended sequence number (one wrap cycle). uint32 extended_seq_num = (1 << 16) + rtp_header_.webrtc.header.sequenceNumber - 1; EXPECT_EQ(extended_seq_num, extended_high_sequence_number_); } TEST_F(ReceiverStatsTest, BasicJitter) { for (int i = 0; i < 300; ++i) { stats_.UpdateStatistics(rtp_header_); ++rtp_header_.webrtc.header.sequenceNumber; rtp_header_.webrtc.header.timestamp += 33 * 90; testing_clock_.Advance(delta_increments_); } stats_.GetStatistics(&fraction_lost_, &cumulative_lost_, &extended_high_sequence_number_, &jitter_); EXPECT_FALSE(fraction_lost_); EXPECT_FALSE(cumulative_lost_); // Build extended sequence number (one wrap cycle). uint32 extended_seq_num = rtp_header_.webrtc.header.sequenceNumber - 1; EXPECT_EQ(extended_seq_num, extended_high_sequence_number_); EXPECT_EQ(ExpectedJitter(kStdTimeIncrementMs, 300), jitter_); } TEST_F(ReceiverStatsTest, NonTrivialJitter) { const int kAdditionalIncrement = 5; for (int i = 0; i < 300; ++i) { stats_.UpdateStatistics(rtp_header_); ++rtp_header_.webrtc.header.sequenceNumber; rtp_header_.webrtc.header.timestamp += 33 * 90; base::TimeDelta additional_delta = base::TimeDelta::FromMilliseconds(kAdditionalIncrement); testing_clock_.Advance(delta_increments_ + additional_delta); } stats_.GetStatistics(&fraction_lost_, &cumulative_lost_, &extended_high_sequence_number_, &jitter_); EXPECT_FALSE(fraction_lost_); EXPECT_FALSE(cumulative_lost_); // Build extended sequence number (one wrap cycle). uint32 extended_seq_num = rtp_header_.webrtc.header.sequenceNumber - 1; EXPECT_EQ(extended_seq_num, extended_high_sequence_number_); EXPECT_EQ(ExpectedJitter(kStdTimeIncrementMs + kAdditionalIncrement, 300), jitter_); } } // namespace cast } // namespace media