/* * Copyright (c) 2013 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 "modules/remote_bitrate_estimator/inter_arrival.h" #include #include "test/gtest.h" namespace webrtc { namespace testing { enum { kTimestampGroupLengthUs = 5000, kMinStep = 20, kTriggerNewGroupUs = kTimestampGroupLengthUs + kMinStep, kBurstThresholdMs = 5, kAbsSendTimeFraction = 18, kAbsSendTimeInterArrivalUpshift = 8, kInterArrivalShift = kAbsSendTimeFraction + kAbsSendTimeInterArrivalUpshift, }; const double kRtpTimestampToMs = 1.0 / 90.0; const double kAstToMs = 1000.0 / static_cast(1 << kInterArrivalShift); class InterArrivalTest : public ::testing::Test { protected: virtual void SetUp() { inter_arrival_.reset(new InterArrival(kTimestampGroupLengthUs / 1000, 1.0)); inter_arrival_rtp_.reset(new InterArrival( MakeRtpTimestamp(kTimestampGroupLengthUs), kRtpTimestampToMs)); inter_arrival_ast_.reset( new InterArrival(MakeAbsSendTime(kTimestampGroupLengthUs), kAstToMs)); } // Test that neither inter_arrival instance complete the timestamp group from // the given data. void ExpectFalse(int64_t timestamp_us, int64_t arrival_time_ms, size_t packet_size) { InternalExpectFalse(inter_arrival_rtp_.get(), MakeRtpTimestamp(timestamp_us), arrival_time_ms, packet_size); InternalExpectFalse(inter_arrival_ast_.get(), MakeAbsSendTime(timestamp_us), arrival_time_ms, packet_size); } // Test that both inter_arrival instances complete the timestamp group from // the given data and that all returned deltas are as expected (except // timestamp delta, which is rounded from us to different ranges and must // match within an interval, given in |timestamp_near]. void ExpectTrue(int64_t timestamp_us, int64_t arrival_time_ms, size_t packet_size, int64_t expected_timestamp_delta_us, int64_t expected_arrival_time_delta_ms, int expected_packet_size_delta, uint32_t timestamp_near) { InternalExpectTrue(inter_arrival_rtp_.get(), MakeRtpTimestamp(timestamp_us), arrival_time_ms, packet_size, MakeRtpTimestamp(expected_timestamp_delta_us), expected_arrival_time_delta_ms, expected_packet_size_delta, timestamp_near); InternalExpectTrue(inter_arrival_ast_.get(), MakeAbsSendTime(timestamp_us), arrival_time_ms, packet_size, MakeAbsSendTime(expected_timestamp_delta_us), expected_arrival_time_delta_ms, expected_packet_size_delta, timestamp_near << 8); } void WrapTestHelper(int64_t wrap_start_us, uint32_t timestamp_near, bool unorderly_within_group) { // Step through the range of a 32 bit int, 1/4 at a time to not cause // packets close to wraparound to be judged as out of order. // G1 int64_t arrival_time = 17; ExpectFalse(0, arrival_time, 1); // G2 arrival_time += kBurstThresholdMs + 1; ExpectFalse(wrap_start_us / 4, arrival_time, 1); // G3 arrival_time += kBurstThresholdMs + 1; ExpectTrue(wrap_start_us / 2, arrival_time, 1, wrap_start_us / 4, 6, 0, // Delta G2-G1 0); // G4 arrival_time += kBurstThresholdMs + 1; int64_t g4_arrival_time = arrival_time; ExpectTrue(wrap_start_us / 2 + wrap_start_us / 4, arrival_time, 1, wrap_start_us / 4, 6, 0, // Delta G3-G2 timestamp_near); // G5 arrival_time += kBurstThresholdMs + 1; ExpectTrue(wrap_start_us, arrival_time, 2, wrap_start_us / 4, 6, 0, // Delta G4-G3 timestamp_near); for (int i = 0; i < 10; ++i) { // Slowly step across the wrap point. arrival_time += kBurstThresholdMs + 1; if (unorderly_within_group) { // These packets arrive with timestamps in decreasing order but are // nevertheless accumulated to group because their timestamps are higher // than the initial timestamp of the group. ExpectFalse(wrap_start_us + kMinStep * (9 - i), arrival_time, 1); } else { ExpectFalse(wrap_start_us + kMinStep * i, arrival_time, 1); } } int64_t g5_arrival_time = arrival_time; // This packet is out of order and should be dropped. arrival_time += kBurstThresholdMs + 1; ExpectFalse(wrap_start_us - 100, arrival_time, 100); // G6 arrival_time += kBurstThresholdMs + 1; int64_t g6_arrival_time = arrival_time; ExpectTrue(wrap_start_us + kTriggerNewGroupUs, arrival_time, 10, wrap_start_us / 4 + 9 * kMinStep, g5_arrival_time - g4_arrival_time, (2 + 10) - 1, // Delta G5-G4 timestamp_near); // This packet is out of order and should be dropped. arrival_time += kBurstThresholdMs + 1; ExpectFalse(wrap_start_us + kTimestampGroupLengthUs, arrival_time, 100); // G7 arrival_time += kBurstThresholdMs + 1; ExpectTrue(wrap_start_us + 2 * kTriggerNewGroupUs, arrival_time, 100, // Delta G6-G5 kTriggerNewGroupUs - 9 * kMinStep, g6_arrival_time - g5_arrival_time, 10 - (2 + 10), timestamp_near); } std::unique_ptr inter_arrival_; private: static uint32_t MakeRtpTimestamp(int64_t us) { return static_cast(static_cast(us * 90 + 500) / 1000); } static uint32_t MakeAbsSendTime(int64_t us) { uint32_t absolute_send_time = static_cast(((static_cast(us) << 18) + 500000) / 1000000) & 0x00FFFFFFul; return absolute_send_time << 8; } static void InternalExpectFalse(InterArrival* inter_arrival, uint32_t timestamp, int64_t arrival_time_ms, size_t packet_size) { uint32_t dummy_timestamp = 101; int64_t dummy_arrival_time_ms = 303; int dummy_packet_size = 909; bool computed = inter_arrival->ComputeDeltas( timestamp, arrival_time_ms, arrival_time_ms, packet_size, &dummy_timestamp, &dummy_arrival_time_ms, &dummy_packet_size); EXPECT_EQ(computed, false); EXPECT_EQ(101ul, dummy_timestamp); EXPECT_EQ(303, dummy_arrival_time_ms); EXPECT_EQ(909, dummy_packet_size); } static void InternalExpectTrue(InterArrival* inter_arrival, uint32_t timestamp, int64_t arrival_time_ms, size_t packet_size, uint32_t expected_timestamp_delta, int64_t expected_arrival_time_delta_ms, int expected_packet_size_delta, uint32_t timestamp_near) { uint32_t delta_timestamp = 101; int64_t delta_arrival_time_ms = 303; int delta_packet_size = 909; bool computed = inter_arrival->ComputeDeltas( timestamp, arrival_time_ms, arrival_time_ms, packet_size, &delta_timestamp, &delta_arrival_time_ms, &delta_packet_size); EXPECT_EQ(true, computed); EXPECT_NEAR(expected_timestamp_delta, delta_timestamp, timestamp_near); EXPECT_EQ(expected_arrival_time_delta_ms, delta_arrival_time_ms); EXPECT_EQ(expected_packet_size_delta, delta_packet_size); } std::unique_ptr inter_arrival_rtp_; std::unique_ptr inter_arrival_ast_; }; TEST_F(InterArrivalTest, FirstPacket) { ExpectFalse(0, 17, 1); } TEST_F(InterArrivalTest, FirstGroup) { // G1 int64_t arrival_time = 17; int64_t g1_arrival_time = arrival_time; ExpectFalse(0, arrival_time, 1); // G2 arrival_time += kBurstThresholdMs + 1; int64_t g2_arrival_time = arrival_time; ExpectFalse(kTriggerNewGroupUs, arrival_time, 2); // G3 // Only once the first packet of the third group arrives, do we see the deltas // between the first two. arrival_time += kBurstThresholdMs + 1; ExpectTrue(2 * kTriggerNewGroupUs, arrival_time, 1, // Delta G2-G1 kTriggerNewGroupUs, g2_arrival_time - g1_arrival_time, 1, 0); } TEST_F(InterArrivalTest, SecondGroup) { // G1 int64_t arrival_time = 17; int64_t g1_arrival_time = arrival_time; ExpectFalse(0, arrival_time, 1); // G2 arrival_time += kBurstThresholdMs + 1; int64_t g2_arrival_time = arrival_time; ExpectFalse(kTriggerNewGroupUs, arrival_time, 2); // G3 arrival_time += kBurstThresholdMs + 1; int64_t g3_arrival_time = arrival_time; ExpectTrue(2 * kTriggerNewGroupUs, arrival_time, 1, // Delta G2-G1 kTriggerNewGroupUs, g2_arrival_time - g1_arrival_time, 1, 0); // G4 // First packet of 4th group yields deltas between group 2 and 3. arrival_time += kBurstThresholdMs + 1; ExpectTrue(3 * kTriggerNewGroupUs, arrival_time, 2, // Delta G3-G2 kTriggerNewGroupUs, g3_arrival_time - g2_arrival_time, -1, 0); } TEST_F(InterArrivalTest, AccumulatedGroup) { // G1 int64_t arrival_time = 17; int64_t g1_arrival_time = arrival_time; ExpectFalse(0, arrival_time, 1); // G2 arrival_time += kBurstThresholdMs + 1; ExpectFalse(kTriggerNewGroupUs, 28, 2); int64_t timestamp = kTriggerNewGroupUs; for (int i = 0; i < 10; ++i) { // A bunch of packets arriving within the same group. arrival_time += kBurstThresholdMs + 1; timestamp += kMinStep; ExpectFalse(timestamp, arrival_time, 1); } int64_t g2_arrival_time = arrival_time; int64_t g2_timestamp = timestamp; // G3 arrival_time = 500; ExpectTrue(2 * kTriggerNewGroupUs, arrival_time, 100, g2_timestamp, g2_arrival_time - g1_arrival_time, (2 + 10) - 1, // Delta G2-G1 0); } TEST_F(InterArrivalTest, OutOfOrderPacket) { // G1 int64_t arrival_time = 17; int64_t timestamp = 0; ExpectFalse(timestamp, arrival_time, 1); int64_t g1_timestamp = timestamp; int64_t g1_arrival_time = arrival_time; // G2 arrival_time += 11; timestamp += kTriggerNewGroupUs; ExpectFalse(timestamp, 28, 2); for (int i = 0; i < 10; ++i) { arrival_time += kBurstThresholdMs + 1; timestamp += kMinStep; ExpectFalse(timestamp, arrival_time, 1); } int64_t g2_timestamp = timestamp; int64_t g2_arrival_time = arrival_time; // This packet is out of order and should be dropped. arrival_time = 281; ExpectFalse(g1_timestamp, arrival_time, 100); // G3 arrival_time = 500; timestamp = 2 * kTriggerNewGroupUs; ExpectTrue(timestamp, arrival_time, 100, // Delta G2-G1 g2_timestamp - g1_timestamp, g2_arrival_time - g1_arrival_time, (2 + 10) - 1, 0); } TEST_F(InterArrivalTest, OutOfOrderWithinGroup) { // G1 int64_t arrival_time = 17; int64_t timestamp = 0; ExpectFalse(timestamp, arrival_time, 1); int64_t g1_timestamp = timestamp; int64_t g1_arrival_time = arrival_time; // G2 timestamp += kTriggerNewGroupUs; arrival_time += 11; ExpectFalse(kTriggerNewGroupUs, 28, 2); timestamp += 10 * kMinStep; int64_t g2_timestamp = timestamp; for (int i = 0; i < 10; ++i) { // These packets arrive with timestamps in decreasing order but are // nevertheless accumulated to group because their timestamps are higher // than the initial timestamp of the group. arrival_time += kBurstThresholdMs + 1; ExpectFalse(timestamp, arrival_time, 1); timestamp -= kMinStep; } int64_t g2_arrival_time = arrival_time; // However, this packet is deemed out of order and should be dropped. arrival_time = 281; timestamp = g1_timestamp; ExpectFalse(timestamp, arrival_time, 100); // G3 timestamp = 2 * kTriggerNewGroupUs; arrival_time = 500; ExpectTrue(timestamp, arrival_time, 100, g2_timestamp - g1_timestamp, g2_arrival_time - g1_arrival_time, (2 + 10) - 1, 0); } TEST_F(InterArrivalTest, TwoBursts) { // G1 int64_t g1_arrival_time = 17; ExpectFalse(0, g1_arrival_time, 1); // G2 int64_t timestamp = kTriggerNewGroupUs; int64_t arrival_time = 100; // Simulate no packets arriving for 100 ms. for (int i = 0; i < 10; ++i) { // A bunch of packets arriving in one burst (within 5 ms apart). timestamp += 30000; arrival_time += kBurstThresholdMs; ExpectFalse(timestamp, arrival_time, 1); } int64_t g2_arrival_time = arrival_time; int64_t g2_timestamp = timestamp; // G3 timestamp += 30000; arrival_time += kBurstThresholdMs + 1; ExpectTrue(timestamp, arrival_time, 100, g2_timestamp, g2_arrival_time - g1_arrival_time, 10 - 1, // Delta G2-G1 0); } TEST_F(InterArrivalTest, NoBursts) { // G1 ExpectFalse(0, 17, 1); // G2 int64_t timestamp = kTriggerNewGroupUs; int64_t arrival_time = 28; ExpectFalse(timestamp, arrival_time, 2); // G3 ExpectTrue(kTriggerNewGroupUs + 30000, arrival_time + kBurstThresholdMs + 1, 100, timestamp - 0, arrival_time - 17, 2 - 1, // Delta G2-G1 0); } // Yields 0xfffffffe when converted to internal representation in // inter_arrival_rtp_ and inter_arrival_ast_ respectively. static const int64_t kStartRtpTimestampWrapUs = 47721858827; static const int64_t kStartAbsSendTimeWrapUs = 63999995; TEST_F(InterArrivalTest, RtpTimestampWrap) { WrapTestHelper(kStartRtpTimestampWrapUs, 1, false); } TEST_F(InterArrivalTest, AbsSendTimeWrap) { WrapTestHelper(kStartAbsSendTimeWrapUs, 1, false); } TEST_F(InterArrivalTest, RtpTimestampWrapOutOfOrderWithinGroup) { WrapTestHelper(kStartRtpTimestampWrapUs, 1, true); } TEST_F(InterArrivalTest, AbsSendTimeWrapOutOfOrderWithinGroup) { WrapTestHelper(kStartAbsSendTimeWrapUs, 1, true); } TEST_F(InterArrivalTest, PositiveArrivalTimeJump) { const size_t kPacketSize = 1000; uint32_t send_time_ms = 10000; int64_t arrival_time_ms = 20000; int64_t system_time_ms = 30000; uint32_t send_delta; int64_t arrival_delta; int size_delta; EXPECT_FALSE(inter_arrival_->ComputeDeltas( send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, &arrival_delta, &size_delta)); const int kTimeDeltaMs = 30; send_time_ms += kTimeDeltaMs; arrival_time_ms += kTimeDeltaMs; system_time_ms += kTimeDeltaMs; EXPECT_FALSE(inter_arrival_->ComputeDeltas( send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, &arrival_delta, &size_delta)); send_time_ms += kTimeDeltaMs; arrival_time_ms += kTimeDeltaMs + InterArrival::kArrivalTimeOffsetThresholdMs; system_time_ms += kTimeDeltaMs; EXPECT_TRUE(inter_arrival_->ComputeDeltas( send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, &arrival_delta, &size_delta)); EXPECT_EQ(kTimeDeltaMs, static_cast(send_delta)); EXPECT_EQ(kTimeDeltaMs, arrival_delta); EXPECT_EQ(size_delta, 0); send_time_ms += kTimeDeltaMs; arrival_time_ms += kTimeDeltaMs; system_time_ms += kTimeDeltaMs; // The previous arrival time jump should now be detected and cause a reset. EXPECT_FALSE(inter_arrival_->ComputeDeltas( send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, &arrival_delta, &size_delta)); // The two next packets will not give a valid delta since we're in the initial // state. for (int i = 0; i < 2; ++i) { send_time_ms += kTimeDeltaMs; arrival_time_ms += kTimeDeltaMs; system_time_ms += kTimeDeltaMs; EXPECT_FALSE(inter_arrival_->ComputeDeltas( send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, &arrival_delta, &size_delta)); } send_time_ms += kTimeDeltaMs; arrival_time_ms += kTimeDeltaMs; system_time_ms += kTimeDeltaMs; EXPECT_TRUE(inter_arrival_->ComputeDeltas( send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, &arrival_delta, &size_delta)); EXPECT_EQ(kTimeDeltaMs, static_cast(send_delta)); EXPECT_EQ(kTimeDeltaMs, arrival_delta); EXPECT_EQ(size_delta, 0); } TEST_F(InterArrivalTest, NegativeArrivalTimeJump) { const size_t kPacketSize = 1000; uint32_t send_time_ms = 10000; int64_t arrival_time_ms = 20000; int64_t system_time_ms = 30000; uint32_t send_delta; int64_t arrival_delta; int size_delta; EXPECT_FALSE(inter_arrival_->ComputeDeltas( send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, &arrival_delta, &size_delta)); const int kTimeDeltaMs = 30; send_time_ms += kTimeDeltaMs; arrival_time_ms += kTimeDeltaMs; system_time_ms += kTimeDeltaMs; EXPECT_FALSE(inter_arrival_->ComputeDeltas( send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, &arrival_delta, &size_delta)); send_time_ms += kTimeDeltaMs; arrival_time_ms += kTimeDeltaMs; system_time_ms += kTimeDeltaMs; EXPECT_TRUE(inter_arrival_->ComputeDeltas( send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, &arrival_delta, &size_delta)); EXPECT_EQ(kTimeDeltaMs, static_cast(send_delta)); EXPECT_EQ(kTimeDeltaMs, arrival_delta); EXPECT_EQ(size_delta, 0); // Three out of order will fail, after that we will be reset and two more will // fail before we get our first valid delta after the reset. arrival_time_ms -= 1000; for (int i = 0; i < InterArrival::kReorderedResetThreshold + 3; ++i) { send_time_ms += kTimeDeltaMs; arrival_time_ms += kTimeDeltaMs; system_time_ms += kTimeDeltaMs; // The previous arrival time jump should now be detected and cause a reset. EXPECT_FALSE(inter_arrival_->ComputeDeltas( send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, &arrival_delta, &size_delta)); } send_time_ms += kTimeDeltaMs; arrival_time_ms += kTimeDeltaMs; system_time_ms += kTimeDeltaMs; EXPECT_TRUE(inter_arrival_->ComputeDeltas( send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, &arrival_delta, &size_delta)); EXPECT_EQ(kTimeDeltaMs, static_cast(send_delta)); EXPECT_EQ(kTimeDeltaMs, arrival_delta); EXPECT_EQ(size_delta, 0); } } // namespace testing } // namespace webrtc