New method for precise packet reception time measurement.
Bug: webrtc:9054
Change-Id: I43a32122e9af992b5e0ba8b187c9ad4f22aba80d
Reviewed-on: https://webrtc-review.googlesource.com/c/104503
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Christoffer Rodbro <crodbro@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25167}
diff --git a/call/BUILD.gn b/call/BUILD.gn
index 611d9e8..b06dbbe 100644
--- a/call/BUILD.gn
+++ b/call/BUILD.gn
@@ -217,6 +217,7 @@
"../rtc_base:rtc_task_queue",
"../rtc_base:safe_minmax",
"../rtc_base:sequenced_task_checker",
+ "../rtc_base/experiments:field_trial_parser",
"../rtc_base/synchronization:rw_lock_wrapper",
"../system_wrappers",
"../system_wrappers:field_trial",
diff --git a/call/call.cc b/call/call.cc
index 635874b..fa20679 100644
--- a/call/call.cc
+++ b/call/call.cc
@@ -56,6 +56,7 @@
#include "rtc_base/synchronization/rw_lock_wrapper.h"
#include "rtc_base/task_queue.h"
#include "rtc_base/thread_annotations.h"
+#include "rtc_base/timeutils.h"
#include "rtc_base/trace_event.h"
#include "system_wrappers/include/clock.h"
#include "system_wrappers/include/cpu_info.h"
@@ -1215,8 +1216,10 @@
if (packet_time_us != -1) {
if (receive_time_calculator_) {
+ int64_t system_time_us =
+ rtc::SystemTimeNanos() / rtc::kNumNanosecsPerMicrosec;
packet_time_us = receive_time_calculator_->ReconcileReceiveTimes(
- packet_time_us, clock_->TimeInMicroseconds());
+ packet_time_us, system_time_us, clock_->TimeInMicroseconds());
}
parsed_packet.set_arrival_time_ms((packet_time_us + 500) / 1000);
} else {
diff --git a/call/receive_time_calculator.cc b/call/receive_time_calculator.cc
index 16c6a43..b705673 100644
--- a/call/receive_time_calculator.cc
+++ b/call/receive_time_calculator.cc
@@ -9,59 +9,112 @@
*/
#include "call/receive_time_calculator.h"
+
+#include <string>
+
#include "absl/memory/memory.h"
+#include "rtc_base/experiments/field_trial_parser.h"
#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_minmax.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
-using ::webrtc::field_trial::FindFullName;
using ::webrtc::field_trial::IsEnabled;
-const char kBweReceiveTimeCorrection[] = "WebRTC-BweReceiveTimeCorrection";
+const char kBweReceiveTimeCorrection[] = "WebRTC-Bwe-ReceiveTimeFix";
} // namespace
-ReceiveTimeCalculator::ReceiveTimeCalculator(int64_t min_delta_ms,
- int64_t max_delta_diff_ms)
- : min_delta_us_(min_delta_ms * 1000),
- max_delta_diff_us_(max_delta_diff_ms * 1000) {}
+ReceiveTimeCalculatorConfig::ReceiveTimeCalculatorConfig()
+ : max_packet_time_repair("maxrep", TimeDelta::ms(2000)),
+ stall_threshold("stall", TimeDelta::ms(5)),
+ tolerance("tol", TimeDelta::ms(1)),
+ max_stall("maxstall", TimeDelta::seconds(5)) {
+ std::string trial_string =
+ field_trial::FindFullName(kBweReceiveTimeCorrection);
+ ParseFieldTrial(
+ {&max_packet_time_repair, &stall_threshold, &tolerance, &max_stall},
+ trial_string);
+}
+ReceiveTimeCalculatorConfig::ReceiveTimeCalculatorConfig(
+ const ReceiveTimeCalculatorConfig&) = default;
+ReceiveTimeCalculatorConfig::~ReceiveTimeCalculatorConfig() = default;
+
+ReceiveTimeCalculator::ReceiveTimeCalculator()
+ : config_(ReceiveTimeCalculatorConfig()) {}
std::unique_ptr<ReceiveTimeCalculator>
ReceiveTimeCalculator::CreateFromFieldTrial() {
if (!IsEnabled(kBweReceiveTimeCorrection))
return nullptr;
- int min, max;
- if (sscanf(FindFullName(kBweReceiveTimeCorrection).c_str(), "Enabled,%d,%d",
- &min, &max) != 2) {
- RTC_LOG(LS_WARNING) << "Invalid number of parameters provided.";
- return nullptr;
- }
- return absl::make_unique<ReceiveTimeCalculator>(min, max);
+ return absl::make_unique<ReceiveTimeCalculator>();
}
-int64_t ReceiveTimeCalculator::ReconcileReceiveTimes(int64_t packet_time_us_,
- int64_t safe_time_us_) {
- if (!receive_time_offset_us_) {
- receive_time_offset_us_ = safe_time_us_ - packet_time_us_;
- } else {
- int64_t safe_delta_us = safe_time_us_ - last_safe_time_us_;
- int64_t packet_delta_us_ = packet_time_us_ - last_packet_time_us_;
- int64_t delta_diff = packet_delta_us_ - safe_delta_us;
- // Packet time should not decrease significantly, a large decrease indicates
- // a reset of the packet time clock and we should reset the offest
- // parameter. The safe reference time can increase in large jumps if the
- // thread measuring it is backgrounded for longer periods. But if the packet
- // time increases significantly more than the safe time, it indicates a
- // clock reset and we should reset the offset.
+int64_t ReceiveTimeCalculator::ReconcileReceiveTimes(int64_t packet_time_us,
+ int64_t system_time_us,
+ int64_t safe_time_us) {
+ int64_t stall_time_us = system_time_us - packet_time_us;
+ if (total_system_time_passed_us_ < config_.stall_threshold->us()) {
+ stall_time_us = rtc::SafeMin(stall_time_us, config_.max_stall->us());
+ }
+ int64_t corrected_time_us = safe_time_us - stall_time_us;
- if (packet_delta_us_ < min_delta_us_ || delta_diff > max_delta_diff_us_) {
- RTC_LOG(LS_WARNING) << "Received a clock jump of " << delta_diff
- << " resetting offset";
- receive_time_offset_us_ = safe_time_us_ - packet_time_us_;
+ if (last_packet_time_us_ == -1 && stall_time_us < 0) {
+ static_clock_offset_us_ = stall_time_us;
+ corrected_time_us += static_clock_offset_us_;
+ } else if (last_packet_time_us_ > 0) {
+ // All repairs depend on variables being intialized
+ int64_t packet_time_delta_us = packet_time_us - last_packet_time_us_;
+ int64_t system_time_delta_us = system_time_us - last_system_time_us_;
+ int64_t safe_time_delta_us = safe_time_us - last_safe_time_us_;
+
+ // Repair backwards clock resets during initial stall. In this case, the
+ // reset is observed only in packet time but never in system time.
+ if (system_time_delta_us < 0)
+ total_system_time_passed_us_ += config_.stall_threshold->us();
+ else
+ total_system_time_passed_us_ += system_time_delta_us;
+ if (packet_time_delta_us < 0 &&
+ total_system_time_passed_us_ < config_.stall_threshold->us()) {
+ static_clock_offset_us_ -= packet_time_delta_us;
+ }
+ corrected_time_us += static_clock_offset_us_;
+
+ // Detect resets inbetween clock readings in socket and app.
+ bool forward_clock_reset =
+ corrected_time_us + config_.tolerance->us() < last_corrected_time_us_;
+ bool obvious_backward_clock_reset = system_time_us < packet_time_us;
+
+ // Harder case with backward clock reset during stall, the reset being
+ // smaller than the stall. Compensate throughout the stall.
+ bool small_backward_clock_reset =
+ !obvious_backward_clock_reset &&
+ safe_time_delta_us > system_time_delta_us + config_.tolerance->us();
+ bool stall_start =
+ packet_time_delta_us >= 0 &&
+ system_time_delta_us > packet_time_delta_us + config_.tolerance->us();
+ bool stall_is_over = safe_time_delta_us > config_.stall_threshold->us();
+ bool packet_time_caught_up =
+ packet_time_delta_us < 0 && system_time_delta_us >= 0;
+ if (stall_start && small_backward_clock_reset)
+ small_reset_during_stall_ = true;
+ else if (stall_is_over || packet_time_caught_up)
+ small_reset_during_stall_ = false;
+
+ // If resets are detected, advance time by (capped) packet time increase.
+ if (forward_clock_reset || obvious_backward_clock_reset ||
+ small_reset_during_stall_) {
+ corrected_time_us = last_corrected_time_us_ +
+ rtc::SafeClamp(packet_time_delta_us, 0,
+ config_.max_packet_time_repair->us());
}
}
- last_packet_time_us_ = packet_time_us_;
- last_safe_time_us_ = safe_time_us_;
- return packet_time_us_ + *receive_time_offset_us_;
+
+ last_corrected_time_us_ = corrected_time_us;
+ last_packet_time_us_ = packet_time_us;
+ last_system_time_us_ = system_time_us;
+ last_safe_time_us_ = safe_time_us;
+ return corrected_time_us;
}
+
} // namespace webrtc
diff --git a/call/receive_time_calculator.h b/call/receive_time_calculator.h
index a8217cd..269d4ef 100644
--- a/call/receive_time_calculator.h
+++ b/call/receive_time_calculator.h
@@ -10,13 +10,24 @@
#ifndef CALL_RECEIVE_TIME_CALCULATOR_H_
#define CALL_RECEIVE_TIME_CALCULATOR_H_
-#include <stdint.h>
#include <memory>
-#include "absl/types/optional.h"
+#include "rtc_base/experiments/field_trial_units.h"
namespace webrtc {
+struct ReceiveTimeCalculatorConfig {
+ ReceiveTimeCalculatorConfig();
+ ReceiveTimeCalculatorConfig(const ReceiveTimeCalculatorConfig&);
+ ReceiveTimeCalculatorConfig& operator=(const ReceiveTimeCalculatorConfig&) =
+ default;
+ ~ReceiveTimeCalculatorConfig();
+ FieldTrialParameter<TimeDelta> max_packet_time_repair;
+ FieldTrialParameter<TimeDelta> stall_threshold;
+ FieldTrialParameter<TimeDelta> tolerance;
+ FieldTrialParameter<TimeDelta> max_stall;
+};
+
// The receive time calculator serves the purpose of combining packet time
// stamps with a safely incremental clock. This assumes that the packet time
// stamps are based on lower layer timestamps that have more accurate time
@@ -28,20 +39,20 @@
class ReceiveTimeCalculator {
public:
static std::unique_ptr<ReceiveTimeCalculator> CreateFromFieldTrial();
- // The min delta is used to correct for jumps backwards in time, to allow some
- // packet reordering a small negative value is appropriate to use. The max
- // delta difference is used as margin when detecting when packet time
- // increases more than the safe clock. This should be larger than the largest
- // expected sysmtem induced delay in the safe clock timestamp.
- ReceiveTimeCalculator(int64_t min_delta_ms, int64_t max_delta_diff_ms);
- int64_t ReconcileReceiveTimes(int64_t packet_time_us_, int64_t safe_time_us_);
+ ReceiveTimeCalculator();
+ int64_t ReconcileReceiveTimes(int64_t packet_time_us_,
+ int64_t system_time_us_,
+ int64_t safe_time_us_);
private:
- const int64_t min_delta_us_;
- const int64_t max_delta_diff_us_;
- absl::optional<int64_t> receive_time_offset_us_;
- int64_t last_packet_time_us_ = 0;
- int64_t last_safe_time_us_ = 0;
+ int64_t last_corrected_time_us_ = -1;
+ int64_t last_packet_time_us_ = -1;
+ int64_t last_system_time_us_ = -1;
+ int64_t last_safe_time_us_ = -1;
+ int64_t total_system_time_passed_us_ = 0;
+ int64_t static_clock_offset_us_ = 0;
+ int64_t small_reset_during_stall_ = false;
+ ReceiveTimeCalculatorConfig config_;
};
} // namespace webrtc
#endif // CALL_RECEIVE_TIME_CALCULATOR_H_
diff --git a/call/receive_time_calculator_unittest.cc b/call/receive_time_calculator_unittest.cc
index 92d5a27..38ef54e 100644
--- a/call/receive_time_calculator_unittest.cc
+++ b/call/receive_time_calculator_unittest.cc
@@ -10,65 +10,237 @@
#include "call/receive_time_calculator.h"
+#include <algorithm>
+#include <iostream>
+#include <tuple>
+#include <vector>
+
+#include "absl/memory/memory.h"
+#include "absl/types/optional.h"
+#include "rtc_base/random.h"
+#include "rtc_base/timeutils.h"
#include "test/gtest.h"
namespace webrtc {
namespace test {
namespace {
-int64_t ReconcileMs(ReceiveTimeCalculator* calc,
- int64_t packet_time_ms,
- int64_t safe_time_ms) {
- return calc->ReconcileReceiveTimes(packet_time_ms * 1000,
- safe_time_ms * 1000) /
- 1000;
+class EmulatedClock {
+ public:
+ explicit EmulatedClock(int seed, float drift = 0.0f)
+ : random_(seed), clock_us_(random_.Rand<uint32_t>()), drift_(drift) {}
+ virtual ~EmulatedClock() = default;
+ int64_t GetClockUs() const { return clock_us_; }
+
+ protected:
+ int64_t UpdateClock(int64_t time_us) {
+ if (!last_query_us_)
+ last_query_us_ = time_us;
+ int64_t skip_us = time_us - *last_query_us_;
+ accumulated_drift_us_ += skip_us * drift_;
+ int64_t drift_correction_us = static_cast<int64_t>(accumulated_drift_us_);
+ accumulated_drift_us_ -= drift_correction_us;
+ clock_us_ += skip_us + drift_correction_us;
+ last_query_us_ = time_us;
+ return skip_us;
+ }
+ Random random_;
+
+ private:
+ int64_t clock_us_;
+ absl::optional<int64_t> last_query_us_;
+ float drift_;
+ float accumulated_drift_us_ = 0;
+};
+
+class EmulatedMonotoneousClock : public EmulatedClock {
+ public:
+ explicit EmulatedMonotoneousClock(int seed) : EmulatedClock(seed) {}
+ ~EmulatedMonotoneousClock() = default;
+
+ int64_t Query(int64_t time_us) {
+ int64_t skip_us = UpdateClock(time_us);
+
+ // In a stall
+ if (stall_recovery_time_us_ > 0) {
+ if (GetClockUs() > stall_recovery_time_us_) {
+ stall_recovery_time_us_ = 0;
+ return GetClockUs();
+ } else {
+ return stall_recovery_time_us_;
+ }
+ }
+
+ // Check if we enter a stall
+ for (int k = 0; k < skip_us; ++k) {
+ if (random_.Rand<double>() < kChanceOfStallPerUs) {
+ int64_t stall_duration_us =
+ static_cast<int64_t>(random_.Rand<float>() * kMaxStallDurationUs);
+ stall_recovery_time_us_ = GetClockUs() + stall_duration_us;
+ return stall_recovery_time_us_;
+ }
+ }
+ return GetClockUs();
+ }
+
+ void ForceStallUs() {
+ int64_t stall_duration_us =
+ static_cast<int64_t>(random_.Rand<float>() * kMaxStallDurationUs);
+ stall_recovery_time_us_ = GetClockUs() + stall_duration_us;
+ }
+
+ bool Stalled() const { return stall_recovery_time_us_ > 0; }
+
+ int64_t GetRemainingStall(int64_t time_us) const {
+ return stall_recovery_time_us_ > 0 ? stall_recovery_time_us_ - GetClockUs()
+ : 0;
+ }
+
+ const int64_t kMaxStallDurationUs = rtc::kNumMicrosecsPerSec;
+
+ private:
+ const float kChanceOfStallPerUs = 5e-6f;
+ int64_t stall_recovery_time_us_ = 0;
+};
+
+class EmulatedNonMonotoneousClock : public EmulatedClock {
+ public:
+ EmulatedNonMonotoneousClock(int seed, int64_t duration_us, float drift = 0)
+ : EmulatedClock(seed, drift) {
+ Pregenerate(duration_us);
+ }
+ ~EmulatedNonMonotoneousClock() = default;
+
+ void Pregenerate(int64_t duration_us) {
+ int64_t time_since_reset_us = kMinTimeBetweenResetsUs;
+ int64_t clock_offset_us = 0;
+ for (int64_t time_us = 0; time_us < duration_us; time_us += kResolutionUs) {
+ int64_t skip_us = UpdateClock(time_us);
+ time_since_reset_us += skip_us;
+ int64_t reset_us = 0;
+ if (time_since_reset_us >= kMinTimeBetweenResetsUs) {
+ for (int k = 0; k < skip_us; ++k) {
+ if (random_.Rand<double>() < kChanceOfResetPerUs) {
+ reset_us = static_cast<int64_t>(2 * random_.Rand<float>() *
+ kMaxAbsResetUs) -
+ kMaxAbsResetUs;
+ clock_offset_us += reset_us;
+ time_since_reset_us = 0;
+ break;
+ }
+ }
+ }
+ pregenerated_clock_.emplace_back(GetClockUs() + clock_offset_us);
+ resets_us_.emplace_back(reset_us);
+ }
+ }
+
+ int64_t Query(int64_t time_us) {
+ size_t ixStart =
+ (last_reset_query_time_us_ + (kResolutionUs >> 1)) / kResolutionUs + 1;
+ size_t ixEnd = (time_us + (kResolutionUs >> 1)) / kResolutionUs;
+ if (ixEnd >= pregenerated_clock_.size())
+ return -1;
+ last_reset_size_us_ = 0;
+ for (size_t ix = ixStart; ix <= ixEnd; ++ix) {
+ if (resets_us_[ix] != 0) {
+ last_reset_size_us_ = resets_us_[ix];
+ }
+ }
+ last_reset_query_time_us_ = time_us;
+ return pregenerated_clock_[ixEnd];
+ }
+
+ bool WasReset() const { return last_reset_size_us_ != 0; }
+ bool WasNegativeReset() const { return last_reset_size_us_ < 0; }
+ int64_t GetLastResetUs() const { return last_reset_size_us_; }
+
+ private:
+ const float kChanceOfResetPerUs = 1e-6f;
+ const int64_t kMaxAbsResetUs = rtc::kNumMicrosecsPerSec;
+ const int64_t kMinTimeBetweenResetsUs = 3 * rtc::kNumMicrosecsPerSec;
+ const int64_t kResolutionUs = rtc::kNumMicrosecsPerMillisec;
+ int64_t last_reset_query_time_us_ = 0;
+ int64_t last_reset_size_us_ = 0;
+ std::vector<int64_t> pregenerated_clock_;
+ std::vector<int64_t> resets_us_;
+};
+
+TEST(ClockRepair, NoClockDrift) {
+ const int kSeeds = 10;
+ const int kFirstSeed = 1;
+ const int64_t kRuntimeUs = 10 * rtc::kNumMicrosecsPerSec;
+ const float kDrift = 0.0f;
+ const int64_t kMaxPacketInterarrivalUs = 50 * rtc::kNumMicrosecsPerMillisec;
+ for (int seed = kFirstSeed; seed < kSeeds + kFirstSeed; ++seed) {
+ EmulatedMonotoneousClock monotone_clock(seed);
+ EmulatedNonMonotoneousClock non_monotone_clock(
+ seed + 1, kRuntimeUs + rtc::kNumMicrosecsPerSec, kDrift);
+ ReceiveTimeCalculator reception_time_tracker;
+ int64_t corrected_clock_0 = 0;
+ int64_t reset_during_stall_tol_us = 0;
+ bool initial_clock_stall = true;
+ int64_t accumulated_upper_bound_tolerance_us = 0;
+ int64_t accumulated_lower_bound_tolerance_us = 0;
+ Random random(1);
+ monotone_clock.ForceStallUs();
+ int64_t last_time_us = 0;
+ bool add_tolerance_on_next_packet = false;
+ int64_t monotone_noise_us = 1000;
+
+ for (int64_t time_us = 0; time_us < kRuntimeUs;
+ time_us += static_cast<int64_t>(random.Rand<float>() *
+ kMaxPacketInterarrivalUs)) {
+ int64_t socket_time_us = non_monotone_clock.Query(time_us);
+ int64_t monotone_us = monotone_clock.Query(time_us) +
+ 2 * random.Rand<float>() * monotone_noise_us -
+ monotone_noise_us;
+ int64_t system_time_us = non_monotone_clock.Query(
+ time_us + monotone_clock.GetRemainingStall(time_us));
+
+ int64_t corrected_clock_us = reception_time_tracker.ReconcileReceiveTimes(
+ socket_time_us, system_time_us, monotone_us);
+ if (time_us == 0)
+ corrected_clock_0 = corrected_clock_us;
+
+ if (add_tolerance_on_next_packet)
+ accumulated_lower_bound_tolerance_us -= (time_us - last_time_us);
+
+ // Perfect repair cannot be achiveved if non-monotone clock resets during
+ // a monotone clock stall.
+ add_tolerance_on_next_packet = false;
+ if (monotone_clock.Stalled() && non_monotone_clock.WasReset()) {
+ reset_during_stall_tol_us =
+ std::max(reset_during_stall_tol_us, time_us - last_time_us);
+ if (non_monotone_clock.WasNegativeReset()) {
+ add_tolerance_on_next_packet = true;
+ }
+ if (initial_clock_stall && !non_monotone_clock.WasNegativeReset()) {
+ // Positive resets during an initial clock stall cannot be repaired
+ // and error will propagate through rest of trace.
+ accumulated_upper_bound_tolerance_us +=
+ std::abs(non_monotone_clock.GetLastResetUs());
+ }
+ } else {
+ reset_during_stall_tol_us = 0;
+ initial_clock_stall = false;
+ }
+ int64_t err = corrected_clock_us - corrected_clock_0 - time_us;
+
+ // Resets during stalls may lead to small errors temporarily.
+ int64_t lower_tol_us = accumulated_lower_bound_tolerance_us -
+ reset_during_stall_tol_us - monotone_noise_us -
+ 2 * rtc::kNumMicrosecsPerMillisec;
+ EXPECT_GE(err, lower_tol_us);
+ int64_t upper_tol_us = accumulated_upper_bound_tolerance_us +
+ monotone_noise_us +
+ 2 * rtc::kNumMicrosecsPerMillisec;
+ EXPECT_LE(err, upper_tol_us);
+
+ last_time_us = time_us;
+ }
+ }
}
} // namespace
-
-TEST(ReceiveTimeCalculatorTest, UsesSmallerIncrements) {
- int64_t kMinDeltaMs = -20;
- int64_t kMaxDeltaDiffMs = 100;
- ReceiveTimeCalculator calc(kMinDeltaMs, kMaxDeltaDiffMs);
- // Initialize offset.
- ReconcileMs(&calc, 10000, 20000);
-
- EXPECT_EQ(ReconcileMs(&calc, 10010, 20100), 20010);
- EXPECT_EQ(ReconcileMs(&calc, 10020, 20100), 20020);
- EXPECT_EQ(ReconcileMs(&calc, 10030, 20100), 20030);
-
- EXPECT_EQ(ReconcileMs(&calc, 10110, 20200), 20110);
- EXPECT_EQ(ReconcileMs(&calc, 10120, 20200), 20120);
- EXPECT_EQ(ReconcileMs(&calc, 10130, 20200), 20130);
-
- // Small jumps backwards are let trough, they might be due to reordering.
- EXPECT_EQ(ReconcileMs(&calc, 10120, 20200), 20120);
- // The safe clock might be smaller than the packet clock.
- EXPECT_EQ(ReconcileMs(&calc, 10210, 20200), 20210);
- EXPECT_EQ(ReconcileMs(&calc, 10240, 20200), 20240);
-}
-
-TEST(ReceiveTimeCalculatorTest, CorrectsJumps) {
- int64_t kMinDeltaMs = -20;
- int64_t kMaxDeltaDiffMs = 100;
- ReceiveTimeCalculator calc(kMinDeltaMs, kMaxDeltaDiffMs);
- // Initialize offset.
- ReconcileMs(&calc, 10000, 20000);
-
- EXPECT_EQ(ReconcileMs(&calc, 10010, 20100), 20010);
- EXPECT_EQ(ReconcileMs(&calc, 10020, 20100), 20020);
- EXPECT_EQ(ReconcileMs(&calc, 10030, 20100), 20030);
-
- // Jump forward in time.
- EXPECT_EQ(ReconcileMs(&calc, 10240, 20200), 20200);
- EXPECT_EQ(ReconcileMs(&calc, 10250, 20200), 20210);
- EXPECT_EQ(ReconcileMs(&calc, 10260, 20200), 20220);
-
- // Jump backward in time.
- EXPECT_EQ(ReconcileMs(&calc, 10230, 20300), 20300);
- EXPECT_EQ(ReconcileMs(&calc, 10240, 20300), 20310);
- EXPECT_EQ(ReconcileMs(&calc, 10250, 20300), 20320);
-}
-
} // namespace test
-
} // namespace webrtc
diff --git a/video/BUILD.gn b/video/BUILD.gn
index bd49b3d..5ac2383 100644
--- a/video/BUILD.gn
+++ b/video/BUILD.gn
@@ -399,7 +399,6 @@
"end_to_end_tests/multi_stream_tests.cc",
"end_to_end_tests/network_state_tests.cc",
"end_to_end_tests/probing_tests.cc",
- "end_to_end_tests/receive_time_tests.cc",
"end_to_end_tests/retransmission_tests.cc",
"end_to_end_tests/rtp_rtcp_tests.cc",
"end_to_end_tests/ssrc_tests.cc",
diff --git a/video/end_to_end_tests/receive_time_tests.cc b/video/end_to_end_tests/receive_time_tests.cc
deleted file mode 100644
index 10602b0..0000000
--- a/video/end_to_end_tests/receive_time_tests.cc
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2018 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 "api/test/simulated_network.h"
-#include "call/fake_network_pipe.h"
-#include "call/simulated_network.h"
-#include "rtc_base/criticalsection.h"
-#include "rtc_base/timeutils.h"
-#include "test/call_test.h"
-#include "test/field_trial.h"
-#include "test/rtcp_packet_parser.h"
-
-namespace webrtc {
-namespace {
-
-// This tester simulates a series of clock reset events where different offsets
-// are added to the receive time. It detects jumps in the resulting reported
-// receive times of more than 200 ms.
-class ReportedReceiveTimeTester : public test::EndToEndTest {
- public:
- struct TimeJump {
- int64_t at_send_time_ms;
- int64_t add_offset_ms;
- static constexpr int64_t kStop = 0;
- };
-
- ReportedReceiveTimeTester()
- : EndToEndTest(test::CallTest::kDefaultTimeoutMs) {
- // These should be let trough without correction and filtered if correction
- // is enabled.
- jumps_.push({500, 2000});
- jumps_.push({1000, -400});
- jumps_.push({1500, 2000000});
- jumps_.push({1700, TimeJump::kStop});
- }
- bool JumpInReportedTimes() { return jump_in_reported_times_; }
-
- protected:
- Action OnReceiveRtcp(const uint8_t* data, size_t length) override {
- test::RtcpPacketParser parser;
- EXPECT_TRUE(parser.Parse(data, length));
- const auto& fb = parser.transport_feedback();
- if (fb->num_packets() > 0) {
- int64_t arrival_time_us = fb->GetBaseTimeUs();
- for (const auto& pkt : fb->GetReceivedPackets()) {
- arrival_time_us += pkt.delta_us();
- if (last_arrival_time_us_ != 0) {
- int64_t delta_us = arrival_time_us - last_arrival_time_us_;
- rtc::CritScope crit(&send_times_crit_);
- if (send_times_us_.size() >= 2) {
- int64_t ground_truth_delta_us =
- send_times_us_[1] - send_times_us_[0];
- send_times_us_.pop_front();
- int64_t delta_diff_ms = (delta_us - ground_truth_delta_us) / 1000;
- if (std::abs(delta_diff_ms) > 200) {
- jump_in_reported_times_ = true;
- observation_complete_.Set();
- }
- }
- }
- last_arrival_time_us_ = arrival_time_us;
- }
- }
- return SEND_PACKET;
- }
- Action OnSendRtp(const uint8_t* data, size_t length) override {
- {
- rtc::CritScope crit(&send_times_crit_);
- send_times_us_.push_back(rtc::TimeMicros());
- }
- int64_t now_ms = rtc::TimeMillis();
- if (!first_send_time_ms_)
- first_send_time_ms_ = now_ms;
- int64_t send_time_ms = now_ms - first_send_time_ms_;
- if (send_time_ms >= jumps_.front().at_send_time_ms) {
- if (jumps_.front().add_offset_ms == TimeJump::kStop) {
- observation_complete_.Set();
- jumps_.pop();
- return SEND_PACKET;
- }
- clock_offset_ms_ += jumps_.front().add_offset_ms;
- send_pipe_->SetClockOffset(clock_offset_ms_);
- jumps_.pop();
- }
- return SEND_PACKET;
- }
- test::PacketTransport* CreateSendTransport(
- test::SingleThreadedTaskQueueForTesting* task_queue,
- Call* sender_call) override {
- auto pipe = absl::make_unique<FakeNetworkPipe>(
- Clock::GetRealTimeClock(),
- absl::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
- send_pipe_ = pipe.get();
- return send_transport_ = new test::PacketTransport(
- task_queue, sender_call, this, test::PacketTransport::kSender,
- test::CallTest::payload_type_map_, std::move(pipe));
- }
- void PerformTest() override {
- observation_complete_.Wait(test::CallTest::kDefaultTimeoutMs);
- }
- size_t GetNumVideoStreams() const override { return 1; }
- size_t GetNumAudioStreams() const override { return 0; }
-
- private:
- int64_t last_arrival_time_us_ = 0;
- int64_t first_send_time_ms_ = 0;
- rtc::CriticalSection send_times_crit_;
- std::deque<int64_t> send_times_us_ RTC_GUARDED_BY(send_times_crit_);
- bool jump_in_reported_times_ = false;
- FakeNetworkPipe* send_pipe_;
- test::PacketTransport* send_transport_;
- int64_t clock_offset_ms_ = 0;
- std::queue<TimeJump> jumps_;
-};
-} // namespace
-
-class ReceiveTimeEndToEndTest : public test::CallTest {
- public:
- ReceiveTimeEndToEndTest() {}
-
- virtual ~ReceiveTimeEndToEndTest() {}
-};
-
-TEST_F(ReceiveTimeEndToEndTest, ReceiveTimeJumpsWithoutFieldTrial) {
- // Without the field trial, the jumps in clock offset should be let trough and
- // be detected.
- ReportedReceiveTimeTester test;
- RunBaseTest(&test);
- EXPECT_TRUE(test.JumpInReportedTimes());
-}
-
-TEST_F(ReceiveTimeEndToEndTest, ReceiveTimeSteadyWithFieldTrial) {
- // Since all the added jumps by the tester are outside the interval of -100 ms
- // to 1000 ms, they should all be filtered by the field trial below, and no
- // jumps should be detected.
- test::ScopedFieldTrials field_trial(
- "WebRTC-BweReceiveTimeCorrection/Enabled,-100,1000/");
- ReportedReceiveTimeTester test;
- RunBaseTest(&test);
- EXPECT_FALSE(test.JumpInReportedTimes());
-}
-} // namespace webrtc