Delete video_legacy build target

Bug: None
Change-Id: I8c3e7cb408ca09b5e60f72b103764e2b43a4d696
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/265843
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37243}
diff --git a/BUILD.gn b/BUILD.gn
index 3ad9c97..461138a 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -638,7 +638,6 @@
       "test:test_common",
       "test:test_main",
       "test:video_test_common",
-      "video:video_legacy_tests",
       "video:video_tests",
       "video/adaptation:video_adaptation_tests",
     ]
diff --git a/video/BUILD.gn b/video/BUILD.gn
index 381cad0..35e12e4 100644
--- a/video/BUILD.gn
+++ b/video/BUILD.gn
@@ -166,81 +166,6 @@
   }
 }
 
-rtc_source_set("video_legacy") {
-  sources = [
-    "call_stats.cc",
-    "call_stats.h",
-    "receive_statistics_proxy.cc",
-    "receive_statistics_proxy.h",
-    "video_quality_observer.cc",
-    "video_quality_observer.h",
-  ]
-  deps = [
-    ":frame_dumping_decoder",
-    ":unique_timestamp_counter",
-    ":video",
-    "../api:array_view",
-    "../api:field_trials_view",
-    "../api:scoped_refptr",
-    "../api:sequence_checker",
-    "../api/crypto:frame_decryptor_interface",
-    "../api/task_queue",
-    "../api/transport:field_trial_based_config",
-    "../api/units:timestamp",
-    "../api/video:encoded_image",
-    "../api/video:recordable_encoded_frame",
-    "../api/video:video_frame",
-    "../api/video:video_rtp_headers",
-    "../call:call_interfaces",
-    "../call:rtp_interfaces",
-    "../call:rtp_receiver",  # For RtxReceiveStream.
-    "../call:video_stream_api",
-    "../common_video",
-    "../modules:module_api",
-    "../modules/pacing",
-    "../modules/remote_bitrate_estimator",
-    "../modules/rtp_rtcp",
-    "../modules/rtp_rtcp:rtp_rtcp_format",
-    "../modules/rtp_rtcp:rtp_rtcp_legacy",
-    "../modules/rtp_rtcp:rtp_video_header",
-    "../modules/utility",
-    "../modules/video_coding",
-    "../modules/video_coding:packet_buffer",
-    "../modules/video_coding:video_codec_interface",
-    "../modules/video_coding:video_coding_utility",
-    "../modules/video_coding/deprecated:nack_module",
-    "../rtc_base:checks",
-    "../rtc_base:histogram_percentile_counter",
-    "../rtc_base:location",
-    "../rtc_base:logging",
-    "../rtc_base:macromagic",
-    "../rtc_base:moving_max_counter",
-    "../rtc_base:platform_thread",
-    "../rtc_base:rate_statistics",
-    "../rtc_base:rate_tracker",
-    "../rtc_base:rtc_numerics",
-    "../rtc_base:rtc_task_queue",
-    "../rtc_base:sample_counter",
-    "../rtc_base:stringutils",
-    "../rtc_base:timeutils",
-    "../rtc_base/experiments:field_trial_parser",
-    "../rtc_base/experiments:keyframe_interval_settings_experiment",
-    "../rtc_base/synchronization:mutex",
-    "../rtc_base/system:no_unique_address",
-    "../rtc_base/task_utils:to_queued_task",
-    "../system_wrappers",
-    "../system_wrappers:field_trial",
-    "../system_wrappers:metrics",
-  ]
-  if (!build_with_mozilla) {
-    deps += [ "../media:rtc_media_base" ]
-  }
-  absl_deps = [
-    "//third_party/abseil-cpp/absl/algorithm:container",
-    "//third_party/abseil-cpp/absl/types:optional",
-  ]
-}
-
 rtc_library("video_stream_decoder_impl") {
   visibility = [ "*" ]
 
@@ -1001,40 +926,4 @@
       deps += [ "../media:rtc_media_base" ]
     }
   }
-  rtc_library("video_legacy_tests") {
-    testonly = true
-    sources = [
-      "call_stats_unittest.cc",
-      "receive_statistics_proxy_unittest.cc",
-    ]
-    deps = [
-      ":video_legacy",
-      "../api:scoped_refptr",
-      "../api/video:video_frame",
-      "../api/video:video_frame_type",
-      "../api/video:video_rtp_headers",
-      "../call:mock_rtp_interfaces",
-      "../common_video",
-      "../media:rtc_media_base",
-      "../modules/rtp_rtcp",
-      "../modules/rtp_rtcp:rtp_rtcp_format",
-      "../modules/utility",
-      "../modules/video_coding",
-      "../modules/video_coding:video_codec_interface",
-      "../rtc_base:byte_buffer",
-      "../rtc_base:location",
-      "../rtc_base:logging",
-      "../rtc_base:rtc_event",
-      "../rtc_base/task_utils:to_queued_task",
-      "../system_wrappers",
-      "../system_wrappers:field_trial",
-      "../system_wrappers:metrics",
-      "../test:field_trial",
-      "../test:mock_frame_transformer",
-      "../test:mock_transport",
-      "../test:scoped_key_value_config",
-      "../test:test_support",
-    ]
-    absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
-  }
 }
diff --git a/video/call_stats.cc b/video/call_stats.cc
deleted file mode 100644
index 9fd6802..0000000
--- a/video/call_stats.cc
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- *  Copyright (c) 2012 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 "video/call_stats.h"
-
-#include <algorithm>
-#include <memory>
-
-#include "absl/algorithm/container.h"
-#include "modules/utility/include/process_thread.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/location.h"
-#include "rtc_base/task_utils/to_queued_task.h"
-#include "system_wrappers/include/metrics.h"
-
-namespace webrtc {
-namespace {
-
-void RemoveOldReports(int64_t now, std::list<CallStats::RttTime>* reports) {
-  static constexpr const int64_t kRttTimeoutMs = 1500;
-  reports->remove_if(
-      [&now](CallStats::RttTime& r) { return now - r.time > kRttTimeoutMs; });
-}
-
-int64_t GetMaxRttMs(const std::list<CallStats::RttTime>& reports) {
-  int64_t max_rtt_ms = -1;
-  for (const CallStats::RttTime& rtt_time : reports)
-    max_rtt_ms = std::max(rtt_time.rtt, max_rtt_ms);
-  return max_rtt_ms;
-}
-
-int64_t GetAvgRttMs(const std::list<CallStats::RttTime>& reports) {
-  RTC_DCHECK(!reports.empty());
-  int64_t sum = 0;
-  for (std::list<CallStats::RttTime>::const_iterator it = reports.begin();
-       it != reports.end(); ++it) {
-    sum += it->rtt;
-  }
-  return sum / reports.size();
-}
-
-int64_t GetNewAvgRttMs(const std::list<CallStats::RttTime>& reports,
-                       int64_t prev_avg_rtt) {
-  if (reports.empty())
-    return -1;  // Reset (invalid average).
-
-  int64_t cur_rtt_ms = GetAvgRttMs(reports);
-  if (prev_avg_rtt == -1)
-    return cur_rtt_ms;  // New initial average value.
-
-  // Weight factor to apply to the average rtt.
-  // We weigh the old average at 70% against the new average (30%).
-  constexpr const float kWeightFactor = 0.3f;
-  return prev_avg_rtt * (1.0f - kWeightFactor) + cur_rtt_ms * kWeightFactor;
-}
-
-// This class is used to de-register a Module from a ProcessThread to satisfy
-// threading requirements of the Module (CallStats).
-// The guarantee offered by TemporaryDeregistration is that while its in scope,
-// no calls to `TimeUntilNextProcess` or `Process()` will occur and therefore
-// synchronization with those methods, is not necessary.
-class TemporaryDeregistration {
- public:
-  TemporaryDeregistration(Module* module,
-                          ProcessThread* process_thread,
-                          bool thread_running)
-      : module_(module),
-        process_thread_(process_thread),
-        deregistered_(thread_running) {
-    if (thread_running)
-      process_thread_->DeRegisterModule(module_);
-  }
-  ~TemporaryDeregistration() {
-    if (deregistered_)
-      process_thread_->RegisterModule(module_, RTC_FROM_HERE);
-  }
-
- private:
-  Module* const module_;
-  ProcessThread* const process_thread_;
-  const bool deregistered_;
-};
-
-}  // namespace
-
-CallStats::CallStats(Clock* clock, ProcessThread* process_thread)
-    : clock_(clock),
-      last_process_time_(clock_->TimeInMilliseconds()),
-      max_rtt_ms_(-1),
-      avg_rtt_ms_(-1),
-      sum_avg_rtt_ms_(0),
-      num_avg_rtt_(0),
-      time_of_first_rtt_ms_(-1),
-      process_thread_(process_thread),
-      process_thread_running_(false) {
-  RTC_DCHECK(process_thread_);
-  process_thread_checker_.Detach();
-}
-
-CallStats::~CallStats() {
-  RTC_DCHECK_RUN_ON(&construction_thread_checker_);
-  RTC_DCHECK(!process_thread_running_);
-  RTC_DCHECK(observers_.empty());
-
-  UpdateHistograms();
-}
-
-int64_t CallStats::TimeUntilNextProcess() {
-  RTC_DCHECK_RUN_ON(&process_thread_checker_);
-  return last_process_time_ + kUpdateIntervalMs - clock_->TimeInMilliseconds();
-}
-
-void CallStats::Process() {
-  RTC_DCHECK_RUN_ON(&process_thread_checker_);
-  int64_t now = clock_->TimeInMilliseconds();
-  last_process_time_ = now;
-
-  // `avg_rtt_ms_` is allowed to be read on the process thread since that's the
-  // only thread that modifies the value.
-  int64_t avg_rtt_ms = avg_rtt_ms_;
-  RemoveOldReports(now, &reports_);
-  max_rtt_ms_ = GetMaxRttMs(reports_);
-  avg_rtt_ms = GetNewAvgRttMs(reports_, avg_rtt_ms);
-  {
-    MutexLock lock(&avg_rtt_ms_lock_);
-    avg_rtt_ms_ = avg_rtt_ms;
-  }
-
-  // If there is a valid rtt, update all observers with the max rtt.
-  if (max_rtt_ms_ >= 0) {
-    RTC_DCHECK_GE(avg_rtt_ms, 0);
-    for (CallStatsObserver* observer : observers_)
-      observer->OnRttUpdate(avg_rtt_ms, max_rtt_ms_);
-    // Sum for Histogram of average RTT reported over the entire call.
-    sum_avg_rtt_ms_ += avg_rtt_ms;
-    ++num_avg_rtt_;
-  }
-}
-
-void CallStats::ProcessThreadAttached(ProcessThread* process_thread) {
-  RTC_DCHECK_RUN_ON(&construction_thread_checker_);
-  RTC_DCHECK(!process_thread || process_thread_ == process_thread);
-  process_thread_running_ = process_thread != nullptr;
-
-  // Whether we just got attached or detached, we clear the
-  // `process_thread_checker_` so that it can be used to protect variables
-  // in either the process thread when it starts again, or UpdateHistograms()
-  // (mutually exclusive).
-  process_thread_checker_.Detach();
-}
-
-void CallStats::RegisterStatsObserver(CallStatsObserver* observer) {
-  RTC_DCHECK_RUN_ON(&construction_thread_checker_);
-  TemporaryDeregistration deregister(this, process_thread_,
-                                     process_thread_running_);
-
-  if (!absl::c_linear_search(observers_, observer))
-    observers_.push_back(observer);
-}
-
-void CallStats::DeregisterStatsObserver(CallStatsObserver* observer) {
-  RTC_DCHECK_RUN_ON(&construction_thread_checker_);
-  TemporaryDeregistration deregister(this, process_thread_,
-                                     process_thread_running_);
-  observers_.remove(observer);
-}
-
-int64_t CallStats::LastProcessedRtt() const {
-  // TODO(tommi): This currently gets called from the construction thread of
-  // Call as well as from the process thread. Look into restricting this to
-  // allow only reading this from the process thread (or TQ once we get there)
-  // so that the lock isn't necessary.
-
-  MutexLock lock(&avg_rtt_ms_lock_);
-  return avg_rtt_ms_;
-}
-
-void CallStats::OnRttUpdate(int64_t rtt) {
-  RTC_DCHECK_RUN_ON(&process_thread_checker_);
-
-  int64_t now_ms = clock_->TimeInMilliseconds();
-  reports_.push_back(RttTime(rtt, now_ms));
-  if (time_of_first_rtt_ms_ == -1)
-    time_of_first_rtt_ms_ = now_ms;
-
-  // Make sure Process() will be called and deliver the updates asynchronously.
-  last_process_time_ -= kUpdateIntervalMs;
-  process_thread_->WakeUp(this);
-}
-
-void CallStats::UpdateHistograms() {
-  RTC_DCHECK_RUN_ON(&construction_thread_checker_);
-  RTC_DCHECK(!process_thread_running_);
-
-  // The extra scope is because we have two 'dcheck run on' thread checkers.
-  // This is a special case since it's safe to access variables on the current
-  // thread that normally are only touched on the process thread.
-  // Since we're not attached to the process thread and/or the process thread
-  // isn't running, it's OK to touch these variables here.
-  {
-    // This method is called on the ctor thread (usually from the dtor, unless
-    // a test calls it). It's a requirement that the function be called when
-    // the process thread is not running (a condition that's met at destruction
-    // time), and thanks to that, we don't need a lock to synchronize against
-    // it.
-    RTC_DCHECK_RUN_ON(&process_thread_checker_);
-
-    if (time_of_first_rtt_ms_ == -1 || num_avg_rtt_ < 1)
-      return;
-
-    int64_t elapsed_sec =
-        (clock_->TimeInMilliseconds() - time_of_first_rtt_ms_) / 1000;
-    if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
-      int64_t avg_rtt_ms = (sum_avg_rtt_ms_ + num_avg_rtt_ / 2) / num_avg_rtt_;
-      RTC_HISTOGRAM_COUNTS_10000(
-          "WebRTC.Video.AverageRoundTripTimeInMilliseconds", avg_rtt_ms);
-    }
-  }
-}
-
-}  // namespace webrtc
diff --git a/video/call_stats.h b/video/call_stats.h
deleted file mode 100644
index d198223..0000000
--- a/video/call_stats.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- *  Copyright (c) 2012 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.
- */
-
-#ifndef VIDEO_CALL_STATS_H_
-#define VIDEO_CALL_STATS_H_
-
-#include <list>
-#include <memory>
-
-#include "api/sequence_checker.h"
-#include "modules/include/module.h"
-#include "modules/include/module_common_types.h"
-#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
-#include "rtc_base/synchronization/mutex.h"
-#include "system_wrappers/include/clock.h"
-
-namespace webrtc {
-
-// CallStats keeps track of statistics for a call.
-// TODO(webrtc:11489): Make call_stats_ not depend on ProcessThread and
-// make callbacks on the worker thread (TQ).
-class CallStats : public Module, public RtcpRttStats {
- public:
-  // Time interval for updating the observers.
-  static constexpr int64_t kUpdateIntervalMs = 1000;
-
-  CallStats(Clock* clock, ProcessThread* process_thread);
-  ~CallStats() override;
-
-  CallStats(const CallStats&) = delete;
-  CallStats& operator=(const CallStats&) = delete;
-
-  // Registers/deregisters a new observer to receive statistics updates.
-  // Must be called from the construction thread.
-  void RegisterStatsObserver(CallStatsObserver* observer);
-  void DeregisterStatsObserver(CallStatsObserver* observer);
-
-  // Expose `LastProcessedRtt()` from RtcpRttStats to the public interface, as
-  // it is the part of the API that is needed by direct users of CallStats.
-  // TODO(tommi): Threading or lifetime guarantees are not explicit in how
-  // CallStats is used as RtcpRttStats or how pointers are cached in a
-  // few different places (distributed via Call). It would be good to clarify
-  // from what thread/TQ calls to OnRttUpdate and LastProcessedRtt need to be
-  // allowed.
-  int64_t LastProcessedRtt() const override;
-
-  // Exposed for tests to test histogram support.
-  void UpdateHistogramsForTest() { UpdateHistograms(); }
-
-  // Helper struct keeping track of the time a rtt value is reported.
-  struct RttTime {
-    RttTime(int64_t new_rtt, int64_t rtt_time) : rtt(new_rtt), time(rtt_time) {}
-    const int64_t rtt;
-    const int64_t time;
-  };
-
- private:
-  // RtcpRttStats implementation.
-  void OnRttUpdate(int64_t rtt) override;
-
-  // Implements Module, to use the process thread.
-  int64_t TimeUntilNextProcess() override;
-  void Process() override;
-
-  // TODO(tommi): Use this to know when we're attached to the process thread?
-  // Alternatively, inject that pointer via the ctor since the call_stats
-  // test code, isn't using a processthread atm.
-  void ProcessThreadAttached(ProcessThread* process_thread) override;
-
-  // This method must only be called when the process thread is not
-  // running, and from the construction thread.
-  void UpdateHistograms();
-
-  Clock* const clock_;
-
-  // The last time 'Process' resulted in statistic update.
-  int64_t last_process_time_ RTC_GUARDED_BY(process_thread_checker_);
-  // The last RTT in the statistics update (zero if there is no valid estimate).
-  int64_t max_rtt_ms_ RTC_GUARDED_BY(process_thread_checker_);
-
-  // Accessed from random threads (seemingly). Consider atomic.
-  // `avg_rtt_ms_` is allowed to be read on the process thread without a lock.
-  // `avg_rtt_ms_lock_` must be held elsewhere for reading.
-  // `avg_rtt_ms_lock_` must be held on the process thread for writing.
-  int64_t avg_rtt_ms_;
-
-  // Protects `avg_rtt_ms_`.
-  mutable Mutex avg_rtt_ms_lock_;
-
-  // `sum_avg_rtt_ms_`, `num_avg_rtt_` and `time_of_first_rtt_ms_` are only used
-  // on the ProcessThread when running. When the Process Thread is not running,
-  // (and only then) they can be used in UpdateHistograms(), usually called from
-  // the dtor.
-  int64_t sum_avg_rtt_ms_ RTC_GUARDED_BY(process_thread_checker_);
-  int64_t num_avg_rtt_ RTC_GUARDED_BY(process_thread_checker_);
-  int64_t time_of_first_rtt_ms_ RTC_GUARDED_BY(process_thread_checker_);
-
-  // All Rtt reports within valid time interval, oldest first.
-  std::list<RttTime> reports_ RTC_GUARDED_BY(process_thread_checker_);
-
-  // Observers getting stats reports.
-  // When attached to ProcessThread, this is read-only. In order to allow
-  // modification, we detach from the process thread while the observer
-  // list is updated, to avoid races. This allows us to not require a lock
-  // for the observers_ list, which makes the most common case lock free.
-  std::list<CallStatsObserver*> observers_;
-
-  SequenceChecker construction_thread_checker_;
-  SequenceChecker process_thread_checker_;
-  ProcessThread* const process_thread_;
-  bool process_thread_running_ RTC_GUARDED_BY(construction_thread_checker_);
-};
-
-}  // namespace webrtc
-
-#endif  // VIDEO_CALL_STATS_H_
diff --git a/video/call_stats_unittest.cc b/video/call_stats_unittest.cc
deleted file mode 100644
index e85c4f8..0000000
--- a/video/call_stats_unittest.cc
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- *  Copyright (c) 2012 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 "video/call_stats.h"
-
-#include <memory>
-
-#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
-#include "modules/utility/include/process_thread.h"
-#include "rtc_base/event.h"
-#include "rtc_base/location.h"
-#include "rtc_base/task_utils/to_queued_task.h"
-#include "system_wrappers/include/metrics.h"
-#include "test/gmock.h"
-#include "test/gtest.h"
-
-using ::testing::AnyNumber;
-using ::testing::InvokeWithoutArgs;
-using ::testing::Return;
-
-namespace webrtc {
-
-class MockStatsObserver : public CallStatsObserver {
- public:
-  MockStatsObserver() {}
-  virtual ~MockStatsObserver() {}
-
-  MOCK_METHOD(void, OnRttUpdate, (int64_t, int64_t), (override));
-};
-
-class CallStatsTest : public ::testing::Test {
- public:
-  CallStatsTest() {
-    process_thread_->RegisterModule(&call_stats_, RTC_FROM_HERE);
-    process_thread_->Start();
-  }
-  ~CallStatsTest() override {
-    process_thread_->Stop();
-    process_thread_->DeRegisterModule(&call_stats_);
-  }
-
-  // Queues an rtt update call on the process thread.
-  void AsyncSimulateRttUpdate(int64_t rtt) {
-    RtcpRttStats* rtcp_rtt_stats = &call_stats_;
-    process_thread_->PostTask(ToQueuedTask(
-        [rtcp_rtt_stats, rtt] { rtcp_rtt_stats->OnRttUpdate(rtt); }));
-  }
-
- protected:
-  std::unique_ptr<ProcessThread> process_thread_{
-      ProcessThread::Create("CallStats")};
-  SimulatedClock fake_clock_{12345};
-  CallStats call_stats_{&fake_clock_, process_thread_.get()};
-};
-
-TEST_F(CallStatsTest, AddAndTriggerCallback) {
-  rtc::Event event;
-
-  static constexpr const int64_t kRtt = 25;
-
-  MockStatsObserver stats_observer;
-  EXPECT_CALL(stats_observer, OnRttUpdate(kRtt, kRtt))
-      .Times(1)
-      .WillOnce(InvokeWithoutArgs([&event] { event.Set(); }));
-
-  RtcpRttStats* rtcp_rtt_stats = &call_stats_;
-  call_stats_.RegisterStatsObserver(&stats_observer);
-  EXPECT_EQ(-1, rtcp_rtt_stats->LastProcessedRtt());
-
-  AsyncSimulateRttUpdate(kRtt);
-
-  EXPECT_TRUE(event.Wait(1000));
-
-  EXPECT_EQ(kRtt, rtcp_rtt_stats->LastProcessedRtt());
-
-  call_stats_.DeregisterStatsObserver(&stats_observer);
-}
-
-TEST_F(CallStatsTest, ProcessTime) {
-  rtc::Event event;
-
-  static constexpr const int64_t kRtt = 100;
-  static constexpr const int64_t kRtt2 = 80;
-
-  RtcpRttStats* rtcp_rtt_stats = &call_stats_;
-
-  MockStatsObserver stats_observer;
-
-  EXPECT_CALL(stats_observer, OnRttUpdate(kRtt, kRtt))
-      .Times(2)
-      .WillOnce(InvokeWithoutArgs([this] {
-        // Advance clock and verify we get an update.
-        fake_clock_.AdvanceTimeMilliseconds(CallStats::kUpdateIntervalMs);
-      }))
-      .WillRepeatedly(InvokeWithoutArgs([this, rtcp_rtt_stats] {
-        rtcp_rtt_stats->OnRttUpdate(kRtt2);
-        // Advance clock just too little to get an update.
-        fake_clock_.AdvanceTimeMilliseconds(CallStats::kUpdateIntervalMs - 1);
-      }));
-
-  // In case you're reading this and wondering how this number is arrived at,
-  // please see comments in the ChangeRtt test that go into some detail.
-  static constexpr const int64_t kLastAvg = 94;
-  EXPECT_CALL(stats_observer, OnRttUpdate(kLastAvg, kRtt2))
-      .Times(1)
-      .WillOnce(InvokeWithoutArgs([&event] { event.Set(); }));
-
-  call_stats_.RegisterStatsObserver(&stats_observer);
-
-  AsyncSimulateRttUpdate(kRtt);
-  EXPECT_TRUE(event.Wait(1000));
-
-  call_stats_.DeregisterStatsObserver(&stats_observer);
-}
-
-// Verify all observers get correct estimates and observers can be added and
-// removed.
-TEST_F(CallStatsTest, MultipleObservers) {
-  MockStatsObserver stats_observer_1;
-  call_stats_.RegisterStatsObserver(&stats_observer_1);
-  // Add the second observer twice, there should still be only one report to the
-  // observer.
-  MockStatsObserver stats_observer_2;
-  call_stats_.RegisterStatsObserver(&stats_observer_2);
-  call_stats_.RegisterStatsObserver(&stats_observer_2);
-
-  static constexpr const int64_t kRtt = 100;
-
-  // Verify both observers are updated.
-  rtc::Event ev1;
-  rtc::Event ev2;
-  EXPECT_CALL(stats_observer_1, OnRttUpdate(kRtt, kRtt))
-      .Times(AnyNumber())
-      .WillOnce(InvokeWithoutArgs([&ev1] { ev1.Set(); }))
-      .WillRepeatedly(Return());
-  EXPECT_CALL(stats_observer_2, OnRttUpdate(kRtt, kRtt))
-      .Times(AnyNumber())
-      .WillOnce(InvokeWithoutArgs([&ev2] { ev2.Set(); }))
-      .WillRepeatedly(Return());
-  AsyncSimulateRttUpdate(kRtt);
-  ASSERT_TRUE(ev1.Wait(100));
-  ASSERT_TRUE(ev2.Wait(100));
-
-  // Deregister the second observer and verify update is only sent to the first
-  // observer.
-  call_stats_.DeregisterStatsObserver(&stats_observer_2);
-
-  EXPECT_CALL(stats_observer_1, OnRttUpdate(kRtt, kRtt))
-      .Times(AnyNumber())
-      .WillOnce(InvokeWithoutArgs([&ev1] { ev1.Set(); }))
-      .WillRepeatedly(Return());
-  EXPECT_CALL(stats_observer_2, OnRttUpdate(kRtt, kRtt)).Times(0);
-  AsyncSimulateRttUpdate(kRtt);
-  ASSERT_TRUE(ev1.Wait(100));
-
-  // Deregister the first observer.
-  call_stats_.DeregisterStatsObserver(&stats_observer_1);
-
-  // Now make sure we don't get any callbacks.
-  EXPECT_CALL(stats_observer_1, OnRttUpdate(kRtt, kRtt)).Times(0);
-  EXPECT_CALL(stats_observer_2, OnRttUpdate(kRtt, kRtt)).Times(0);
-  AsyncSimulateRttUpdate(kRtt);
-
-  // Force a call to Process().
-  process_thread_->WakeUp(&call_stats_);
-
-  // Flush the queue on the process thread to make sure we return after
-  // Process() has been called.
-  rtc::Event event;
-  process_thread_->PostTask(ToQueuedTask([&event] { event.Set(); }));
-  event.Wait(rtc::Event::kForever);
-}
-
-// Verify increasing and decreasing rtt triggers callbacks with correct values.
-TEST_F(CallStatsTest, ChangeRtt) {
-  // TODO(tommi): This test assumes things about how old reports are removed
-  // inside of call_stats.cc. The threshold ms value is 1500ms, but it's not
-  // clear here that how the clock is advanced, affects that algorithm and
-  // subsequently the average reported rtt.
-
-  MockStatsObserver stats_observer;
-  call_stats_.RegisterStatsObserver(&stats_observer);
-  RtcpRttStats* rtcp_rtt_stats = &call_stats_;
-
-  rtc::Event event;
-
-  static constexpr const int64_t kFirstRtt = 100;
-  static constexpr const int64_t kLowRtt = kFirstRtt - 20;
-  static constexpr const int64_t kHighRtt = kFirstRtt + 20;
-
-  EXPECT_CALL(stats_observer, OnRttUpdate(kFirstRtt, kFirstRtt))
-      .Times(1)
-      .WillOnce(InvokeWithoutArgs([&rtcp_rtt_stats, this] {
-        fake_clock_.AdvanceTimeMilliseconds(1000);
-        rtcp_rtt_stats->OnRttUpdate(kHighRtt);  // Reported at T1 (1000ms).
-      }));
-
-  // TODO(tommi): This relies on the internal algorithms of call_stats.cc.
-  // There's a weight factor there (0.3), that weighs the previous average to
-  // the new one by 70%, so the number 103 in this case is arrived at like so:
-  // (100) / 1 * 0.7 + (100+120)/2 * 0.3 = 103
-  static constexpr const int64_t kAvgRtt1 = 103;
-  EXPECT_CALL(stats_observer, OnRttUpdate(kAvgRtt1, kHighRtt))
-      .Times(1)
-      .WillOnce(InvokeWithoutArgs([&rtcp_rtt_stats, this] {
-        // This interacts with an internal implementation detail in call_stats
-        // that decays the oldest rtt value. See more below.
-        fake_clock_.AdvanceTimeMilliseconds(1000);
-        rtcp_rtt_stats->OnRttUpdate(kLowRtt);  // Reported at T2 (2000ms).
-      }));
-
-  // Increase time enough for a new update, but not too much to make the
-  // rtt invalid. Report a lower rtt and verify the old/high value still is sent
-  // in the callback.
-
-  // Here, enough time must have passed in order to remove exactly the first
-  // report and nothing else (>1500ms has passed since the first rtt).
-  // So, this value is arrived by doing:
-  // (kAvgRtt1)/1 * 0.7 + (kHighRtt+kLowRtt)/2 * 0.3 = 102.1
-  static constexpr const int64_t kAvgRtt2 = 102;
-  EXPECT_CALL(stats_observer, OnRttUpdate(kAvgRtt2, kHighRtt))
-      .Times(1)
-      .WillOnce(InvokeWithoutArgs([this] {
-        // Advance time to make the high report invalid, the lower rtt should
-        // now be in the callback.
-        fake_clock_.AdvanceTimeMilliseconds(1000);
-      }));
-
-  static constexpr const int64_t kAvgRtt3 = 95;
-  EXPECT_CALL(stats_observer, OnRttUpdate(kAvgRtt3, kLowRtt))
-      .Times(1)
-      .WillOnce(InvokeWithoutArgs([&event] { event.Set(); }));
-
-  // Trigger the first rtt value and set off the chain of callbacks.
-  AsyncSimulateRttUpdate(kFirstRtt);  // Reported at T0 (0ms).
-  EXPECT_TRUE(event.Wait(1000));
-
-  call_stats_.DeregisterStatsObserver(&stats_observer);
-}
-
-TEST_F(CallStatsTest, LastProcessedRtt) {
-  rtc::Event event;
-  MockStatsObserver stats_observer;
-  call_stats_.RegisterStatsObserver(&stats_observer);
-  RtcpRttStats* rtcp_rtt_stats = &call_stats_;
-
-  static constexpr const int64_t kRttLow = 10;
-  static constexpr const int64_t kRttHigh = 30;
-  // The following two average numbers dependend on average + weight
-  // calculations in call_stats.cc.
-  static constexpr const int64_t kAvgRtt1 = 13;
-  static constexpr const int64_t kAvgRtt2 = 15;
-
-  EXPECT_CALL(stats_observer, OnRttUpdate(kRttLow, kRttLow))
-      .Times(1)
-      .WillOnce(InvokeWithoutArgs([rtcp_rtt_stats] {
-        EXPECT_EQ(kRttLow, rtcp_rtt_stats->LastProcessedRtt());
-        // Don't advance the clock to make sure that low and high rtt values
-        // are associated with the same time stamp.
-        rtcp_rtt_stats->OnRttUpdate(kRttHigh);
-      }));
-
-  EXPECT_CALL(stats_observer, OnRttUpdate(kAvgRtt1, kRttHigh))
-      .Times(1)
-      .WillOnce(InvokeWithoutArgs([rtcp_rtt_stats, this] {
-        EXPECT_EQ(kAvgRtt1, rtcp_rtt_stats->LastProcessedRtt());
-        fake_clock_.AdvanceTimeMilliseconds(CallStats::kUpdateIntervalMs);
-        rtcp_rtt_stats->OnRttUpdate(kRttLow);
-        rtcp_rtt_stats->OnRttUpdate(kRttHigh);
-      }));
-
-  EXPECT_CALL(stats_observer, OnRttUpdate(kAvgRtt2, kRttHigh))
-      .Times(1)
-      .WillOnce(InvokeWithoutArgs([rtcp_rtt_stats, &event] {
-        EXPECT_EQ(kAvgRtt2, rtcp_rtt_stats->LastProcessedRtt());
-        event.Set();
-      }));
-
-  // Set a first values and verify that LastProcessedRtt initially returns the
-  // average rtt.
-  fake_clock_.AdvanceTimeMilliseconds(CallStats::kUpdateIntervalMs);
-  AsyncSimulateRttUpdate(kRttLow);
-  EXPECT_TRUE(event.Wait(1000));
-  EXPECT_EQ(kAvgRtt2, rtcp_rtt_stats->LastProcessedRtt());
-
-  call_stats_.DeregisterStatsObserver(&stats_observer);
-}
-
-TEST_F(CallStatsTest, ProducesHistogramMetrics) {
-  metrics::Reset();
-  rtc::Event event;
-  static constexpr const int64_t kRtt = 123;
-  MockStatsObserver stats_observer;
-  call_stats_.RegisterStatsObserver(&stats_observer);
-  EXPECT_CALL(stats_observer, OnRttUpdate(kRtt, kRtt))
-      .Times(AnyNumber())
-      .WillRepeatedly(InvokeWithoutArgs([&event] { event.Set(); }));
-
-  AsyncSimulateRttUpdate(kRtt);
-  EXPECT_TRUE(event.Wait(1000));
-  fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds *
-                                      CallStats::kUpdateIntervalMs);
-  AsyncSimulateRttUpdate(kRtt);
-  EXPECT_TRUE(event.Wait(1000));
-
-  call_stats_.DeregisterStatsObserver(&stats_observer);
-
-  process_thread_->Stop();
-  call_stats_.UpdateHistogramsForTest();
-
-  EXPECT_METRIC_EQ(1, metrics::NumSamples(
-                          "WebRTC.Video.AverageRoundTripTimeInMilliseconds"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.AverageRoundTripTimeInMilliseconds",
-                            kRtt));
-}
-
-}  // namespace webrtc
diff --git a/video/receive_statistics_proxy.cc b/video/receive_statistics_proxy.cc
deleted file mode 100644
index 06873d8..0000000
--- a/video/receive_statistics_proxy.cc
+++ /dev/null
@@ -1,945 +0,0 @@
-/*
- *  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 "video/receive_statistics_proxy.h"
-
-#include <algorithm>
-#include <cmath>
-#include <utility>
-
-#include "modules/video_coding/include/video_codec_interface.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/logging.h"
-#include "rtc_base/strings/string_builder.h"
-#include "rtc_base/time_utils.h"
-#include "system_wrappers/include/clock.h"
-#include "system_wrappers/include/metrics.h"
-
-namespace webrtc {
-namespace {
-// Periodic time interval for processing samples for `freq_offset_counter_`.
-const int64_t kFreqOffsetProcessIntervalMs = 40000;
-
-// Configuration for bad call detection.
-const int kBadCallMinRequiredSamples = 10;
-const int kMinSampleLengthMs = 990;
-const int kNumMeasurements = 10;
-const int kNumMeasurementsVariance = kNumMeasurements * 1.5;
-const float kBadFraction = 0.8f;
-// For fps:
-// Low means low enough to be bad, high means high enough to be good
-const int kLowFpsThreshold = 12;
-const int kHighFpsThreshold = 14;
-// For qp and fps variance:
-// Low means low enough to be good, high means high enough to be bad
-const int kLowQpThresholdVp8 = 60;
-const int kHighQpThresholdVp8 = 70;
-const int kLowVarianceThreshold = 1;
-const int kHighVarianceThreshold = 2;
-
-// Some metrics are reported as a maximum over this period.
-// This should be synchronized with a typical getStats polling interval in
-// the clients.
-const int kMovingMaxWindowMs = 1000;
-
-// How large window we use to calculate the framerate/bitrate.
-const int kRateStatisticsWindowSizeMs = 1000;
-
-// Some sane ballpark estimate for maximum common value of inter-frame delay.
-// Values below that will be stored explicitly in the array,
-// values above - in the map.
-const int kMaxCommonInterframeDelayMs = 500;
-
-const char* UmaPrefixForContentType(VideoContentType content_type) {
-  if (videocontenttypehelpers::IsScreenshare(content_type))
-    return "WebRTC.Video.Screenshare";
-  return "WebRTC.Video";
-}
-
-std::string UmaSuffixForContentType(VideoContentType content_type) {
-  char ss_buf[1024];
-  rtc::SimpleStringBuilder ss(ss_buf);
-  int simulcast_id = videocontenttypehelpers::GetSimulcastId(content_type);
-  if (simulcast_id > 0) {
-    ss << ".S" << simulcast_id - 1;
-  }
-  int experiment_id = videocontenttypehelpers::GetExperimentId(content_type);
-  if (experiment_id > 0) {
-    ss << ".ExperimentGroup" << experiment_id - 1;
-  }
-  return ss.str();
-}
-
-bool EnableDecodeTimeHistogram(const FieldTrialsView* field_trials) {
-  if (field_trials == nullptr) {
-    return true;
-  }
-  return !field_trials->IsEnabled("WebRTC-DecodeTimeHistogramsKillSwitch");
-}
-
-}  // namespace
-
-ReceiveStatisticsProxy::ReceiveStatisticsProxy(
-    uint32_t remote_ssrc,
-    Clock* clock,
-    const FieldTrialsView* field_trials)
-    : clock_(clock),
-      start_ms_(clock->TimeInMilliseconds()),
-      enable_decode_time_histograms_(EnableDecodeTimeHistogram(field_trials)),
-      last_sample_time_(clock->TimeInMilliseconds()),
-      fps_threshold_(kLowFpsThreshold,
-                     kHighFpsThreshold,
-                     kBadFraction,
-                     kNumMeasurements),
-      qp_threshold_(kLowQpThresholdVp8,
-                    kHighQpThresholdVp8,
-                    kBadFraction,
-                    kNumMeasurements),
-      variance_threshold_(kLowVarianceThreshold,
-                          kHighVarianceThreshold,
-                          kBadFraction,
-                          kNumMeasurementsVariance),
-      num_bad_states_(0),
-      num_certain_states_(0),
-      // 1000ms window, scale 1000 for ms to s.
-      decode_fps_estimator_(1000, 1000),
-      renders_fps_estimator_(1000, 1000),
-      render_fps_tracker_(100, 10u),
-      render_pixel_tracker_(100, 10u),
-      video_quality_observer_(
-          new VideoQualityObserver(VideoContentType::UNSPECIFIED)),
-      interframe_delay_max_moving_(kMovingMaxWindowMs),
-      freq_offset_counter_(clock, nullptr, kFreqOffsetProcessIntervalMs),
-      avg_rtt_ms_(0),
-      last_content_type_(VideoContentType::UNSPECIFIED),
-      last_codec_type_(kVideoCodecVP8),
-      num_delayed_frames_rendered_(0),
-      sum_missed_render_deadline_ms_(0),
-      timing_frame_info_counter_(kMovingMaxWindowMs) {
-  decode_thread_.Detach();
-  network_thread_.Detach();
-  stats_.ssrc = remote_ssrc;
-}
-
-void ReceiveStatisticsProxy::UpdateHistograms(
-    absl::optional<int> fraction_lost,
-    const StreamDataCounters& rtp_stats,
-    const StreamDataCounters* rtx_stats) {
-  // Not actually running on the decoder thread, but must be called after
-  // DecoderThreadStopped, which detaches the thread checker. It is therefore
-  // safe to access `qp_counters_`, which were updated on the decode thread
-  // earlier.
-  RTC_DCHECK_RUN_ON(&decode_thread_);
-
-  MutexLock lock(&mutex_);
-
-  char log_stream_buf[8 * 1024];
-  rtc::SimpleStringBuilder log_stream(log_stream_buf);
-  int stream_duration_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000;
-  if (stats_.frame_counts.key_frames > 0 ||
-      stats_.frame_counts.delta_frames > 0) {
-    RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.ReceiveStreamLifetimeInSeconds",
-                                stream_duration_sec);
-    log_stream << "WebRTC.Video.ReceiveStreamLifetimeInSeconds "
-               << stream_duration_sec << '\n';
-  }
-
-  log_stream << "Frames decoded " << stats_.frames_decoded << '\n';
-
-  if (num_unique_frames_) {
-    int num_dropped_frames = *num_unique_frames_ - stats_.frames_decoded;
-    RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.DroppedFrames.Receiver",
-                              num_dropped_frames);
-    log_stream << "WebRTC.Video.DroppedFrames.Receiver " << num_dropped_frames
-               << '\n';
-  }
-
-  if (fraction_lost && stream_duration_sec >= metrics::kMinRunTimeInSeconds) {
-    RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.ReceivedPacketsLostInPercent",
-                             *fraction_lost);
-    log_stream << "WebRTC.Video.ReceivedPacketsLostInPercent " << *fraction_lost
-               << '\n';
-  }
-
-  if (first_decoded_frame_time_ms_) {
-    const int64_t elapsed_ms =
-        (clock_->TimeInMilliseconds() - *first_decoded_frame_time_ms_);
-    if (elapsed_ms >=
-        metrics::kMinRunTimeInSeconds * rtc::kNumMillisecsPerSec) {
-      int decoded_fps = static_cast<int>(
-          (stats_.frames_decoded * 1000.0f / elapsed_ms) + 0.5f);
-      RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.DecodedFramesPerSecond",
-                               decoded_fps);
-      log_stream << "WebRTC.Video.DecodedFramesPerSecond " << decoded_fps
-                 << '\n';
-
-      const uint32_t frames_rendered = stats_.frames_rendered;
-      if (frames_rendered > 0) {
-        RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.DelayedFramesToRenderer",
-                                 static_cast<int>(num_delayed_frames_rendered_ *
-                                                  100 / frames_rendered));
-        if (num_delayed_frames_rendered_ > 0) {
-          RTC_HISTOGRAM_COUNTS_1000(
-              "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs",
-              static_cast<int>(sum_missed_render_deadline_ms_ /
-                               num_delayed_frames_rendered_));
-        }
-      }
-    }
-  }
-
-  const int kMinRequiredSamples = 200;
-  int samples = static_cast<int>(render_fps_tracker_.TotalSampleCount());
-  if (samples >= kMinRequiredSamples) {
-    int rendered_fps = round(render_fps_tracker_.ComputeTotalRate());
-    RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.RenderFramesPerSecond",
-                             rendered_fps);
-    log_stream << "WebRTC.Video.RenderFramesPerSecond " << rendered_fps << '\n';
-    RTC_HISTOGRAM_COUNTS_100000(
-        "WebRTC.Video.RenderSqrtPixelsPerSecond",
-        round(render_pixel_tracker_.ComputeTotalRate()));
-  }
-
-  absl::optional<int> sync_offset_ms =
-      sync_offset_counter_.Avg(kMinRequiredSamples);
-  if (sync_offset_ms) {
-    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.AVSyncOffsetInMs",
-                               *sync_offset_ms);
-    log_stream << "WebRTC.Video.AVSyncOffsetInMs " << *sync_offset_ms << '\n';
-  }
-  AggregatedStats freq_offset_stats = freq_offset_counter_.GetStats();
-  if (freq_offset_stats.num_samples > 0) {
-    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtpToNtpFreqOffsetInKhz",
-                               freq_offset_stats.average);
-    log_stream << "WebRTC.Video.RtpToNtpFreqOffsetInKhz "
-               << freq_offset_stats.ToString() << '\n';
-  }
-
-  int num_total_frames =
-      stats_.frame_counts.key_frames + stats_.frame_counts.delta_frames;
-  if (num_total_frames >= kMinRequiredSamples) {
-    int num_key_frames = stats_.frame_counts.key_frames;
-    int key_frames_permille =
-        (num_key_frames * 1000 + num_total_frames / 2) / num_total_frames;
-    RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.KeyFramesReceivedInPermille",
-                              key_frames_permille);
-    log_stream << "WebRTC.Video.KeyFramesReceivedInPermille "
-               << key_frames_permille << '\n';
-  }
-
-  absl::optional<int> qp = qp_counters_.vp8.Avg(kMinRequiredSamples);
-  if (qp) {
-    RTC_HISTOGRAM_COUNTS_200("WebRTC.Video.Decoded.Vp8.Qp", *qp);
-    log_stream << "WebRTC.Video.Decoded.Vp8.Qp " << *qp << '\n';
-  }
-  absl::optional<int> decode_ms = decode_time_counter_.Avg(kMinRequiredSamples);
-  if (decode_ms) {
-    RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.DecodeTimeInMs", *decode_ms);
-    log_stream << "WebRTC.Video.DecodeTimeInMs " << *decode_ms << '\n';
-  }
-  absl::optional<int> jb_delay_ms =
-      jitter_buffer_delay_counter_.Avg(kMinRequiredSamples);
-  if (jb_delay_ms) {
-    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.JitterBufferDelayInMs",
-                               *jb_delay_ms);
-    log_stream << "WebRTC.Video.JitterBufferDelayInMs " << *jb_delay_ms << '\n';
-  }
-
-  absl::optional<int> target_delay_ms =
-      target_delay_counter_.Avg(kMinRequiredSamples);
-  if (target_delay_ms) {
-    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.TargetDelayInMs",
-                               *target_delay_ms);
-    log_stream << "WebRTC.Video.TargetDelayInMs " << *target_delay_ms << '\n';
-  }
-  absl::optional<int> current_delay_ms =
-      current_delay_counter_.Avg(kMinRequiredSamples);
-  if (current_delay_ms) {
-    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.CurrentDelayInMs",
-                               *current_delay_ms);
-    log_stream << "WebRTC.Video.CurrentDelayInMs " << *current_delay_ms << '\n';
-  }
-  absl::optional<int> delay_ms = delay_counter_.Avg(kMinRequiredSamples);
-  if (delay_ms)
-    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.OnewayDelayInMs", *delay_ms);
-
-  // Aggregate content_specific_stats_ by removing experiment or simulcast
-  // information;
-  std::map<VideoContentType, ContentSpecificStats> aggregated_stats;
-  for (const auto& it : content_specific_stats_) {
-    // Calculate simulcast specific metrics (".S0" ... ".S2" suffixes).
-    VideoContentType content_type = it.first;
-    if (videocontenttypehelpers::GetSimulcastId(content_type) > 0) {
-      // Aggregate on experiment id.
-      videocontenttypehelpers::SetExperimentId(&content_type, 0);
-      aggregated_stats[content_type].Add(it.second);
-    }
-    // Calculate experiment specific metrics (".ExperimentGroup[0-7]" suffixes).
-    content_type = it.first;
-    if (videocontenttypehelpers::GetExperimentId(content_type) > 0) {
-      // Aggregate on simulcast id.
-      videocontenttypehelpers::SetSimulcastId(&content_type, 0);
-      aggregated_stats[content_type].Add(it.second);
-    }
-    // Calculate aggregated metrics (no suffixes. Aggregated on everything).
-    content_type = it.first;
-    videocontenttypehelpers::SetSimulcastId(&content_type, 0);
-    videocontenttypehelpers::SetExperimentId(&content_type, 0);
-    aggregated_stats[content_type].Add(it.second);
-  }
-
-  for (const auto& it : aggregated_stats) {
-    // For the metric Foo we report the following slices:
-    // WebRTC.Video.Foo,
-    // WebRTC.Video.Screenshare.Foo,
-    // WebRTC.Video.Foo.S[0-3],
-    // WebRTC.Video.Foo.ExperimentGroup[0-7],
-    // WebRTC.Video.Screenshare.Foo.S[0-3],
-    // WebRTC.Video.Screenshare.Foo.ExperimentGroup[0-7].
-    auto content_type = it.first;
-    auto stats = it.second;
-    std::string uma_prefix = UmaPrefixForContentType(content_type);
-    std::string uma_suffix = UmaSuffixForContentType(content_type);
-    // Metrics can be sliced on either simulcast id or experiment id but not
-    // both.
-    RTC_DCHECK(videocontenttypehelpers::GetExperimentId(content_type) == 0 ||
-               videocontenttypehelpers::GetSimulcastId(content_type) == 0);
-
-    absl::optional<int> e2e_delay_ms =
-        stats.e2e_delay_counter.Avg(kMinRequiredSamples);
-    if (e2e_delay_ms) {
-      RTC_HISTOGRAM_COUNTS_SPARSE_10000(
-          uma_prefix + ".EndToEndDelayInMs" + uma_suffix, *e2e_delay_ms);
-      log_stream << uma_prefix << ".EndToEndDelayInMs" << uma_suffix << " "
-                 << *e2e_delay_ms << '\n';
-    }
-    absl::optional<int> e2e_delay_max_ms = stats.e2e_delay_counter.Max();
-    if (e2e_delay_max_ms && e2e_delay_ms) {
-      RTC_HISTOGRAM_COUNTS_SPARSE_100000(
-          uma_prefix + ".EndToEndDelayMaxInMs" + uma_suffix, *e2e_delay_max_ms);
-      log_stream << uma_prefix << ".EndToEndDelayMaxInMs" << uma_suffix << " "
-                 << *e2e_delay_max_ms << '\n';
-    }
-    absl::optional<int> interframe_delay_ms =
-        stats.interframe_delay_counter.Avg(kMinRequiredSamples);
-    if (interframe_delay_ms) {
-      RTC_HISTOGRAM_COUNTS_SPARSE_10000(
-          uma_prefix + ".InterframeDelayInMs" + uma_suffix,
-          *interframe_delay_ms);
-      log_stream << uma_prefix << ".InterframeDelayInMs" << uma_suffix << " "
-                 << *interframe_delay_ms << '\n';
-    }
-    absl::optional<int> interframe_delay_max_ms =
-        stats.interframe_delay_counter.Max();
-    if (interframe_delay_max_ms && interframe_delay_ms) {
-      RTC_HISTOGRAM_COUNTS_SPARSE_10000(
-          uma_prefix + ".InterframeDelayMaxInMs" + uma_suffix,
-          *interframe_delay_max_ms);
-      log_stream << uma_prefix << ".InterframeDelayMaxInMs" << uma_suffix << " "
-                 << *interframe_delay_max_ms << '\n';
-    }
-
-    absl::optional<uint32_t> interframe_delay_95p_ms =
-        stats.interframe_delay_percentiles.GetPercentile(0.95f);
-    if (interframe_delay_95p_ms && interframe_delay_ms != -1) {
-      RTC_HISTOGRAM_COUNTS_SPARSE_10000(
-          uma_prefix + ".InterframeDelay95PercentileInMs" + uma_suffix,
-          *interframe_delay_95p_ms);
-      log_stream << uma_prefix << ".InterframeDelay95PercentileInMs"
-                 << uma_suffix << " " << *interframe_delay_95p_ms << '\n';
-    }
-
-    absl::optional<int> width = stats.received_width.Avg(kMinRequiredSamples);
-    if (width) {
-      RTC_HISTOGRAM_COUNTS_SPARSE_10000(
-          uma_prefix + ".ReceivedWidthInPixels" + uma_suffix, *width);
-      log_stream << uma_prefix << ".ReceivedWidthInPixels" << uma_suffix << " "
-                 << *width << '\n';
-    }
-
-    absl::optional<int> height = stats.received_height.Avg(kMinRequiredSamples);
-    if (height) {
-      RTC_HISTOGRAM_COUNTS_SPARSE_10000(
-          uma_prefix + ".ReceivedHeightInPixels" + uma_suffix, *height);
-      log_stream << uma_prefix << ".ReceivedHeightInPixels" << uma_suffix << " "
-                 << *height << '\n';
-    }
-
-    if (content_type != VideoContentType::UNSPECIFIED) {
-      // Don't report these 3 metrics unsliced, as more precise variants
-      // are reported separately in this method.
-      float flow_duration_sec = stats.flow_duration_ms / 1000.0;
-      if (flow_duration_sec >= metrics::kMinRunTimeInSeconds) {
-        int media_bitrate_kbps = static_cast<int>(stats.total_media_bytes * 8 /
-                                                  flow_duration_sec / 1000);
-        RTC_HISTOGRAM_COUNTS_SPARSE_10000(
-            uma_prefix + ".MediaBitrateReceivedInKbps" + uma_suffix,
-            media_bitrate_kbps);
-        log_stream << uma_prefix << ".MediaBitrateReceivedInKbps" << uma_suffix
-                   << " " << media_bitrate_kbps << '\n';
-      }
-
-      int num_total_frames2 =
-          stats.frame_counts.key_frames + stats.frame_counts.delta_frames;
-      if (num_total_frames2 >= kMinRequiredSamples) {
-        int num_key_frames = stats.frame_counts.key_frames;
-        int key_frames_permille =
-            (num_key_frames * 1000 + num_total_frames2 / 2) / num_total_frames2;
-        RTC_HISTOGRAM_COUNTS_SPARSE_1000(
-            uma_prefix + ".KeyFramesReceivedInPermille" + uma_suffix,
-            key_frames_permille);
-        log_stream << uma_prefix << ".KeyFramesReceivedInPermille" << uma_suffix
-                   << " " << key_frames_permille << '\n';
-      }
-
-      absl::optional<int> qp2 = stats.qp_counter.Avg(kMinRequiredSamples);
-      if (qp2) {
-        RTC_HISTOGRAM_COUNTS_SPARSE_200(
-            uma_prefix + ".Decoded.Vp8.Qp" + uma_suffix, *qp2);
-        log_stream << uma_prefix << ".Decoded.Vp8.Qp" << uma_suffix << " "
-                   << *qp2 << '\n';
-      }
-    }
-  }
-
-  StreamDataCounters rtp_rtx_stats = rtp_stats;
-  if (rtx_stats)
-    rtp_rtx_stats.Add(*rtx_stats);
-  int64_t elapsed_sec =
-      rtp_rtx_stats.TimeSinceFirstPacketInMs(clock_->TimeInMilliseconds()) /
-      1000;
-  if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
-    RTC_HISTOGRAM_COUNTS_10000(
-        "WebRTC.Video.BitrateReceivedInKbps",
-        static_cast<int>(rtp_rtx_stats.transmitted.TotalBytes() * 8 /
-                         elapsed_sec / 1000));
-    int media_bitrate_kbs = static_cast<int>(rtp_stats.MediaPayloadBytes() * 8 /
-                                             elapsed_sec / 1000);
-    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.MediaBitrateReceivedInKbps",
-                               media_bitrate_kbs);
-    log_stream << "WebRTC.Video.MediaBitrateReceivedInKbps "
-               << media_bitrate_kbs << '\n';
-    RTC_HISTOGRAM_COUNTS_10000(
-        "WebRTC.Video.PaddingBitrateReceivedInKbps",
-        static_cast<int>(rtp_rtx_stats.transmitted.padding_bytes * 8 /
-                         elapsed_sec / 1000));
-    RTC_HISTOGRAM_COUNTS_10000(
-        "WebRTC.Video.RetransmittedBitrateReceivedInKbps",
-        static_cast<int>(rtp_rtx_stats.retransmitted.TotalBytes() * 8 /
-                         elapsed_sec / 1000));
-    if (rtx_stats) {
-      RTC_HISTOGRAM_COUNTS_10000(
-          "WebRTC.Video.RtxBitrateReceivedInKbps",
-          static_cast<int>(rtx_stats->transmitted.TotalBytes() * 8 /
-                           elapsed_sec / 1000));
-    }
-    const RtcpPacketTypeCounter& counters = stats_.rtcp_packet_type_counts;
-    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.NackPacketsSentPerMinute",
-                               counters.nack_packets * 60 / elapsed_sec);
-    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FirPacketsSentPerMinute",
-                               counters.fir_packets * 60 / elapsed_sec);
-    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsSentPerMinute",
-                               counters.pli_packets * 60 / elapsed_sec);
-    if (counters.nack_requests > 0) {
-      RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.UniqueNackRequestsSentInPercent",
-                               counters.UniqueNackRequestsInPercent());
-    }
-  }
-
-  if (num_certain_states_ >= kBadCallMinRequiredSamples) {
-    RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.BadCall.Any",
-                             100 * num_bad_states_ / num_certain_states_);
-  }
-  absl::optional<double> fps_fraction =
-      fps_threshold_.FractionHigh(kBadCallMinRequiredSamples);
-  if (fps_fraction) {
-    RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.BadCall.FrameRate",
-                             static_cast<int>(100 * (1 - *fps_fraction)));
-  }
-  absl::optional<double> variance_fraction =
-      variance_threshold_.FractionHigh(kBadCallMinRequiredSamples);
-  if (variance_fraction) {
-    RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.BadCall.FrameRateVariance",
-                             static_cast<int>(100 * *variance_fraction));
-  }
-  absl::optional<double> qp_fraction =
-      qp_threshold_.FractionHigh(kBadCallMinRequiredSamples);
-  if (qp_fraction) {
-    RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.BadCall.Qp",
-                             static_cast<int>(100 * *qp_fraction));
-  }
-
-  RTC_LOG(LS_INFO) << log_stream.str();
-  video_quality_observer_->UpdateHistograms();
-}
-
-void ReceiveStatisticsProxy::QualitySample() {
-  int64_t now = clock_->TimeInMilliseconds();
-  if (last_sample_time_ + kMinSampleLengthMs > now)
-    return;
-
-  double fps =
-      render_fps_tracker_.ComputeRateForInterval(now - last_sample_time_);
-  absl::optional<int> qp = qp_sample_.Avg(1);
-
-  bool prev_fps_bad = !fps_threshold_.IsHigh().value_or(true);
-  bool prev_qp_bad = qp_threshold_.IsHigh().value_or(false);
-  bool prev_variance_bad = variance_threshold_.IsHigh().value_or(false);
-  bool prev_any_bad = prev_fps_bad || prev_qp_bad || prev_variance_bad;
-
-  fps_threshold_.AddMeasurement(static_cast<int>(fps));
-  if (qp)
-    qp_threshold_.AddMeasurement(*qp);
-  absl::optional<double> fps_variance_opt = fps_threshold_.CalculateVariance();
-  double fps_variance = fps_variance_opt.value_or(0);
-  if (fps_variance_opt) {
-    variance_threshold_.AddMeasurement(static_cast<int>(fps_variance));
-  }
-
-  bool fps_bad = !fps_threshold_.IsHigh().value_or(true);
-  bool qp_bad = qp_threshold_.IsHigh().value_or(false);
-  bool variance_bad = variance_threshold_.IsHigh().value_or(false);
-  bool any_bad = fps_bad || qp_bad || variance_bad;
-
-  if (!prev_any_bad && any_bad) {
-    RTC_LOG(LS_INFO) << "Bad call (any) start: " << now;
-  } else if (prev_any_bad && !any_bad) {
-    RTC_LOG(LS_INFO) << "Bad call (any) end: " << now;
-  }
-
-  if (!prev_fps_bad && fps_bad) {
-    RTC_LOG(LS_INFO) << "Bad call (fps) start: " << now;
-  } else if (prev_fps_bad && !fps_bad) {
-    RTC_LOG(LS_INFO) << "Bad call (fps) end: " << now;
-  }
-
-  if (!prev_qp_bad && qp_bad) {
-    RTC_LOG(LS_INFO) << "Bad call (qp) start: " << now;
-  } else if (prev_qp_bad && !qp_bad) {
-    RTC_LOG(LS_INFO) << "Bad call (qp) end: " << now;
-  }
-
-  if (!prev_variance_bad && variance_bad) {
-    RTC_LOG(LS_INFO) << "Bad call (variance) start: " << now;
-  } else if (prev_variance_bad && !variance_bad) {
-    RTC_LOG(LS_INFO) << "Bad call (variance) end: " << now;
-  }
-
-  RTC_LOG(LS_VERBOSE) << "SAMPLE: sample_length: " << (now - last_sample_time_)
-                      << " fps: " << fps << " fps_bad: " << fps_bad
-                      << " qp: " << qp.value_or(-1) << " qp_bad: " << qp_bad
-                      << " variance_bad: " << variance_bad
-                      << " fps_variance: " << fps_variance;
-
-  last_sample_time_ = now;
-  qp_sample_.Reset();
-
-  if (fps_threshold_.IsHigh() || variance_threshold_.IsHigh() ||
-      qp_threshold_.IsHigh()) {
-    if (any_bad)
-      ++num_bad_states_;
-    ++num_certain_states_;
-  }
-}
-
-void ReceiveStatisticsProxy::UpdateFramerate(int64_t now_ms) const {
-  int64_t old_frames_ms = now_ms - kRateStatisticsWindowSizeMs;
-  while (!frame_window_.empty() &&
-         frame_window_.begin()->first < old_frames_ms) {
-    frame_window_.erase(frame_window_.begin());
-  }
-
-  size_t framerate =
-      (frame_window_.size() * 1000 + 500) / kRateStatisticsWindowSizeMs;
-  stats_.network_frame_rate = static_cast<int>(framerate);
-}
-
-void ReceiveStatisticsProxy::UpdateDecodeTimeHistograms(
-    int width,
-    int height,
-    int decode_time_ms) const {
-  bool is_4k = (width == 3840 || width == 4096) && height == 2160;
-  bool is_hd = width == 1920 && height == 1080;
-  // Only update histograms for 4k/HD and VP9/H264.
-  if ((is_4k || is_hd) && (last_codec_type_ == kVideoCodecVP9 ||
-                           last_codec_type_ == kVideoCodecH264)) {
-    const std::string kDecodeTimeUmaPrefix =
-        "WebRTC.Video.DecodeTimePerFrameInMs.";
-
-    // Each histogram needs its own line for it to not be reused in the wrong
-    // way when the format changes.
-    if (last_codec_type_ == kVideoCodecVP9) {
-      bool is_sw_decoder =
-          stats_.decoder_implementation_name.compare(0, 6, "libvpx") == 0;
-      if (is_4k) {
-        if (is_sw_decoder)
-          RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "Vp9.4k.Sw",
-                                    decode_time_ms);
-        else
-          RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "Vp9.4k.Hw",
-                                    decode_time_ms);
-      } else {
-        if (is_sw_decoder)
-          RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "Vp9.Hd.Sw",
-                                    decode_time_ms);
-        else
-          RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "Vp9.Hd.Hw",
-                                    decode_time_ms);
-      }
-    } else {
-      bool is_sw_decoder =
-          stats_.decoder_implementation_name.compare(0, 6, "FFmpeg") == 0;
-      if (is_4k) {
-        if (is_sw_decoder)
-          RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "H264.4k.Sw",
-                                    decode_time_ms);
-        else
-          RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "H264.4k.Hw",
-                                    decode_time_ms);
-
-      } else {
-        if (is_sw_decoder)
-          RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "H264.Hd.Sw",
-                                    decode_time_ms);
-        else
-          RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "H264.Hd.Hw",
-                                    decode_time_ms);
-      }
-    }
-  }
-}
-
-absl::optional<int64_t>
-ReceiveStatisticsProxy::GetCurrentEstimatedPlayoutNtpTimestampMs(
-    int64_t now_ms) const {
-  if (!last_estimated_playout_ntp_timestamp_ms_ ||
-      !last_estimated_playout_time_ms_) {
-    return absl::nullopt;
-  }
-  int64_t elapsed_ms = now_ms - *last_estimated_playout_time_ms_;
-  return *last_estimated_playout_ntp_timestamp_ms_ + elapsed_ms;
-}
-
-VideoReceiveStreamInterface::Stats ReceiveStatisticsProxy::GetStats() const {
-  MutexLock lock(&mutex_);
-  // Get current frame rates here, as only updating them on new frames prevents
-  // us from ever correctly displaying frame rate of 0.
-  int64_t now_ms = clock_->TimeInMilliseconds();
-  UpdateFramerate(now_ms);
-  stats_.render_frame_rate = renders_fps_estimator_.Rate(now_ms).value_or(0);
-  stats_.decode_frame_rate = decode_fps_estimator_.Rate(now_ms).value_or(0);
-  stats_.interframe_delay_max_ms =
-      interframe_delay_max_moving_.Max(now_ms).value_or(-1);
-  stats_.freeze_count = video_quality_observer_->NumFreezes();
-  stats_.pause_count = video_quality_observer_->NumPauses();
-  stats_.total_freezes_duration_ms =
-      video_quality_observer_->TotalFreezesDurationMs();
-  stats_.total_pauses_duration_ms =
-      video_quality_observer_->TotalPausesDurationMs();
-  stats_.total_frames_duration_ms =
-      video_quality_observer_->TotalFramesDurationMs();
-  stats_.sum_squared_frame_durations =
-      video_quality_observer_->SumSquaredFrameDurationsSec();
-  stats_.content_type = last_content_type_;
-  stats_.timing_frame_info = timing_frame_info_counter_.Max(now_ms);
-  stats_.jitter_buffer_delay_seconds =
-      static_cast<double>(current_delay_counter_.Sum(1).value_or(0)) /
-      rtc::kNumMillisecsPerSec;
-  stats_.jitter_buffer_emitted_count = current_delay_counter_.NumSamples();
-  stats_.estimated_playout_ntp_timestamp_ms =
-      GetCurrentEstimatedPlayoutNtpTimestampMs(now_ms);
-  return stats_;
-}
-
-void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) {
-  MutexLock lock(&mutex_);
-  stats_.current_payload_type = payload_type;
-}
-
-void ReceiveStatisticsProxy::OnDecoderImplementationName(
-    const char* implementation_name) {
-  MutexLock lock(&mutex_);
-  stats_.decoder_implementation_name = implementation_name;
-}
-
-void ReceiveStatisticsProxy::OnFrameBufferTimingsUpdated(
-    int max_decode_ms,
-    int current_delay_ms,
-    int target_delay_ms,
-    int jitter_buffer_ms,
-    int min_playout_delay_ms,
-    int render_delay_ms) {
-  MutexLock lock(&mutex_);
-  stats_.max_decode_ms = max_decode_ms;
-  stats_.current_delay_ms = current_delay_ms;
-  stats_.target_delay_ms = target_delay_ms;
-  stats_.jitter_buffer_ms = jitter_buffer_ms;
-  stats_.min_playout_delay_ms = min_playout_delay_ms;
-  stats_.render_delay_ms = render_delay_ms;
-  jitter_buffer_delay_counter_.Add(jitter_buffer_ms);
-  target_delay_counter_.Add(target_delay_ms);
-  current_delay_counter_.Add(current_delay_ms);
-  // Network delay (rtt/2) + target_delay_ms (jitter delay + decode time +
-  // render delay).
-  delay_counter_.Add(target_delay_ms + avg_rtt_ms_ / 2);
-}
-
-void ReceiveStatisticsProxy::OnUniqueFramesCounted(int num_unique_frames) {
-  MutexLock lock(&mutex_);
-  num_unique_frames_.emplace(num_unique_frames);
-}
-
-void ReceiveStatisticsProxy::OnTimingFrameInfoUpdated(
-    const TimingFrameInfo& info) {
-  MutexLock lock(&mutex_);
-  if (info.flags != VideoSendTiming::kInvalid) {
-    int64_t now_ms = clock_->TimeInMilliseconds();
-    timing_frame_info_counter_.Add(info, now_ms);
-  }
-
-  // Measure initial decoding latency between the first frame arriving and the
-  // first frame being decoded.
-  if (!first_frame_received_time_ms_.has_value()) {
-    first_frame_received_time_ms_ = info.receive_finish_ms;
-  }
-  if (stats_.first_frame_received_to_decoded_ms == -1 &&
-      first_decoded_frame_time_ms_) {
-    stats_.first_frame_received_to_decoded_ms =
-        *first_decoded_frame_time_ms_ - *first_frame_received_time_ms_;
-  }
-}
-
-void ReceiveStatisticsProxy::RtcpPacketTypesCounterUpdated(
-    uint32_t ssrc,
-    const RtcpPacketTypeCounter& packet_counter) {
-  MutexLock lock(&mutex_);
-  if (stats_.ssrc != ssrc)
-    return;
-  stats_.rtcp_packet_type_counts = packet_counter;
-}
-
-void ReceiveStatisticsProxy::OnCname(uint32_t ssrc, absl::string_view cname) {
-  MutexLock lock(&mutex_);
-  // TODO(pbos): Handle both local and remote ssrcs here and RTC_DCHECK that we
-  // receive stats from one of them.
-  if (stats_.ssrc != ssrc)
-    return;
-  stats_.c_name = std::string(cname);
-}
-
-void ReceiveStatisticsProxy::OnDecodedFrame(const VideoFrame& frame,
-                                            absl::optional<uint8_t> qp,
-                                            int32_t decode_time_ms,
-                                            VideoContentType content_type) {
-  MutexLock lock(&mutex_);
-
-  uint64_t now_ms = clock_->TimeInMilliseconds();
-
-  if (videocontenttypehelpers::IsScreenshare(content_type) !=
-      videocontenttypehelpers::IsScreenshare(last_content_type_)) {
-    // Reset the quality observer if content type is switched. But first report
-    // stats for the previous part of the call.
-    video_quality_observer_->UpdateHistograms();
-    video_quality_observer_.reset(new VideoQualityObserver(content_type));
-  }
-
-  video_quality_observer_->OnDecodedFrame(frame, qp, last_codec_type_);
-
-  ContentSpecificStats* content_specific_stats =
-      &content_specific_stats_[content_type];
-  ++stats_.frames_decoded;
-  if (qp) {
-    if (!stats_.qp_sum) {
-      if (stats_.frames_decoded != 1) {
-        RTC_LOG(LS_WARNING)
-            << "Frames decoded was not 1 when first qp value was received.";
-      }
-      stats_.qp_sum = 0;
-    }
-    *stats_.qp_sum += *qp;
-    content_specific_stats->qp_counter.Add(*qp);
-  } else if (stats_.qp_sum) {
-    RTC_LOG(LS_WARNING)
-        << "QP sum was already set and no QP was given for a frame.";
-    stats_.qp_sum.reset();
-  }
-  decode_time_counter_.Add(decode_time_ms);
-  stats_.decode_ms = decode_time_ms;
-  stats_.total_decode_time_ms += decode_time_ms;
-  if (enable_decode_time_histograms_) {
-    UpdateDecodeTimeHistograms(frame.width(), frame.height(), decode_time_ms);
-  }
-
-  last_content_type_ = content_type;
-  decode_fps_estimator_.Update(1, now_ms);
-  if (last_decoded_frame_time_ms_) {
-    int64_t interframe_delay_ms = now_ms - *last_decoded_frame_time_ms_;
-    RTC_DCHECK_GE(interframe_delay_ms, 0);
-    double interframe_delay = interframe_delay_ms / 1000.0;
-    stats_.total_inter_frame_delay += interframe_delay;
-    stats_.total_squared_inter_frame_delay +=
-        interframe_delay * interframe_delay;
-    interframe_delay_max_moving_.Add(interframe_delay_ms, now_ms);
-    content_specific_stats->interframe_delay_counter.Add(interframe_delay_ms);
-    content_specific_stats->interframe_delay_percentiles.Add(
-        interframe_delay_ms);
-    content_specific_stats->flow_duration_ms += interframe_delay_ms;
-  }
-  if (stats_.frames_decoded == 1) {
-    first_decoded_frame_time_ms_.emplace(now_ms);
-  }
-  last_decoded_frame_time_ms_.emplace(now_ms);
-}
-
-void ReceiveStatisticsProxy::OnRenderedFrame(const VideoFrame& frame) {
-  int width = frame.width();
-  int height = frame.height();
-  RTC_DCHECK_GT(width, 0);
-  RTC_DCHECK_GT(height, 0);
-  int64_t now_ms = clock_->TimeInMilliseconds();
-  MutexLock lock(&mutex_);
-
-  video_quality_observer_->OnRenderedFrame(frame, now_ms);
-
-  ContentSpecificStats* content_specific_stats =
-      &content_specific_stats_[last_content_type_];
-  renders_fps_estimator_.Update(1, now_ms);
-  ++stats_.frames_rendered;
-  stats_.width = width;
-  stats_.height = height;
-  render_fps_tracker_.AddSamples(1);
-  render_pixel_tracker_.AddSamples(sqrt(width * height));
-  content_specific_stats->received_width.Add(width);
-  content_specific_stats->received_height.Add(height);
-
-  // Consider taking stats_.render_delay_ms into account.
-  const int64_t time_until_rendering_ms = frame.render_time_ms() - now_ms;
-  if (time_until_rendering_ms < 0) {
-    sum_missed_render_deadline_ms_ += -time_until_rendering_ms;
-    ++num_delayed_frames_rendered_;
-  }
-
-  if (frame.ntp_time_ms() > 0) {
-    int64_t delay_ms = clock_->CurrentNtpInMilliseconds() - frame.ntp_time_ms();
-    if (delay_ms >= 0) {
-      content_specific_stats->e2e_delay_counter.Add(delay_ms);
-    }
-  }
-  QualitySample();
-}
-
-void ReceiveStatisticsProxy::OnSyncOffsetUpdated(int64_t video_playout_ntp_ms,
-                                                 int64_t sync_offset_ms,
-                                                 double estimated_freq_khz) {
-  MutexLock lock(&mutex_);
-  sync_offset_counter_.Add(std::abs(sync_offset_ms));
-  stats_.sync_offset_ms = sync_offset_ms;
-  last_estimated_playout_ntp_timestamp_ms_ = video_playout_ntp_ms;
-  last_estimated_playout_time_ms_ = clock_->TimeInMilliseconds();
-
-  const double kMaxFreqKhz = 10000.0;
-  int offset_khz = kMaxFreqKhz;
-  // Should not be zero or negative. If so, report max.
-  if (estimated_freq_khz < kMaxFreqKhz && estimated_freq_khz > 0.0)
-    offset_khz = static_cast<int>(std::fabs(estimated_freq_khz - 90.0) + 0.5);
-
-  freq_offset_counter_.Add(offset_khz);
-}
-
-void ReceiveStatisticsProxy::OnCompleteFrame(bool is_keyframe,
-                                             size_t size_bytes,
-                                             VideoContentType content_type) {
-  MutexLock lock(&mutex_);
-  if (is_keyframe) {
-    ++stats_.frame_counts.key_frames;
-  } else {
-    ++stats_.frame_counts.delta_frames;
-  }
-
-  // Content type extension is set only for keyframes and should be propagated
-  // for all the following delta frames. Here we may receive frames out of order
-  // and miscategorise some delta frames near the layer switch.
-  // This may slightly offset calculated bitrate and keyframes permille metrics.
-  VideoContentType propagated_content_type =
-      is_keyframe ? content_type : last_content_type_;
-
-  ContentSpecificStats* content_specific_stats =
-      &content_specific_stats_[propagated_content_type];
-
-  content_specific_stats->total_media_bytes += size_bytes;
-  if (is_keyframe) {
-    ++content_specific_stats->frame_counts.key_frames;
-  } else {
-    ++content_specific_stats->frame_counts.delta_frames;
-  }
-
-  int64_t now_ms = clock_->TimeInMilliseconds();
-  frame_window_.insert(std::make_pair(now_ms, size_bytes));
-  UpdateFramerate(now_ms);
-}
-
-void ReceiveStatisticsProxy::OnDroppedFrames(uint32_t frames_dropped) {
-  MutexLock lock(&mutex_);
-  stats_.frames_dropped += frames_dropped;
-}
-
-void ReceiveStatisticsProxy::OnPreDecode(VideoCodecType codec_type, int qp) {
-  RTC_DCHECK_RUN_ON(&decode_thread_);
-  MutexLock lock(&mutex_);
-  last_codec_type_ = codec_type;
-  if (last_codec_type_ == kVideoCodecVP8 && qp != -1) {
-    qp_counters_.vp8.Add(qp);
-    qp_sample_.Add(qp);
-  }
-}
-
-void ReceiveStatisticsProxy::OnStreamInactive() {
-  // TODO(sprang): Figure out any other state that should be reset.
-
-  MutexLock lock(&mutex_);
-  // Don't report inter-frame delay if stream was paused.
-  last_decoded_frame_time_ms_.reset();
-  video_quality_observer_->OnStreamInactive();
-}
-
-void ReceiveStatisticsProxy::OnRttUpdate(int64_t avg_rtt_ms,
-                                         int64_t max_rtt_ms) {
-  MutexLock lock(&mutex_);
-  avg_rtt_ms_ = avg_rtt_ms;
-}
-
-void ReceiveStatisticsProxy::DecoderThreadStarting() {
-  RTC_DCHECK_RUN_ON(&main_thread_);
-}
-
-void ReceiveStatisticsProxy::DecoderThreadStopped() {
-  RTC_DCHECK_RUN_ON(&main_thread_);
-  decode_thread_.Detach();
-}
-
-ReceiveStatisticsProxy::ContentSpecificStats::ContentSpecificStats()
-    : interframe_delay_percentiles(kMaxCommonInterframeDelayMs) {}
-
-ReceiveStatisticsProxy::ContentSpecificStats::~ContentSpecificStats() = default;
-
-void ReceiveStatisticsProxy::ContentSpecificStats::Add(
-    const ContentSpecificStats& other) {
-  e2e_delay_counter.Add(other.e2e_delay_counter);
-  interframe_delay_counter.Add(other.interframe_delay_counter);
-  flow_duration_ms += other.flow_duration_ms;
-  total_media_bytes += other.total_media_bytes;
-  received_height.Add(other.received_height);
-  received_width.Add(other.received_width);
-  qp_counter.Add(other.qp_counter);
-  frame_counts.key_frames += other.frame_counts.key_frames;
-  frame_counts.delta_frames += other.frame_counts.delta_frames;
-  interframe_delay_percentiles.Add(other.interframe_delay_percentiles);
-}
-}  // namespace webrtc
diff --git a/video/receive_statistics_proxy.h b/video/receive_statistics_proxy.h
deleted file mode 100644
index f0b5148..0000000
--- a/video/receive_statistics_proxy.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- *  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.
- */
-
-#ifndef VIDEO_RECEIVE_STATISTICS_PROXY_H_
-#define VIDEO_RECEIVE_STATISTICS_PROXY_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "absl/types/optional.h"
-#include "api/field_trials_view.h"
-#include "api/sequence_checker.h"
-#include "call/video_receive_stream.h"
-#include "modules/include/module_common_types.h"
-#include "modules/video_coding/include/video_coding_defines.h"
-#include "rtc_base/numerics/histogram_percentile_counter.h"
-#include "rtc_base/numerics/moving_max_counter.h"
-#include "rtc_base/numerics/sample_counter.h"
-#include "rtc_base/rate_statistics.h"
-#include "rtc_base/rate_tracker.h"
-#include "rtc_base/synchronization/mutex.h"
-#include "rtc_base/thread_annotations.h"
-#include "video/quality_threshold.h"
-#include "video/stats_counter.h"
-#include "video/video_quality_observer.h"
-
-namespace webrtc {
-
-class Clock;
-struct CodecSpecificInfo;
-
-class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
-                               public RtcpCnameCallback,
-                               public RtcpPacketTypeCounterObserver,
-                               public CallStatsObserver {
- public:
-  ReceiveStatisticsProxy(uint32_t remote_ssrc,
-                         Clock* clock,
-                         const FieldTrialsView* field_trials = nullptr);
-  ~ReceiveStatisticsProxy() = default;
-
-  VideoReceiveStreamInterface::Stats GetStats() const;
-
-  void OnDecodedFrame(const VideoFrame& frame,
-                      absl::optional<uint8_t> qp,
-                      int32_t decode_time_ms,
-                      VideoContentType content_type);
-  void OnSyncOffsetUpdated(int64_t video_playout_ntp_ms,
-                           int64_t sync_offset_ms,
-                           double estimated_freq_khz);
-  void OnRenderedFrame(const VideoFrame& frame);
-  void OnIncomingPayloadType(int payload_type);
-  void OnDecoderImplementationName(const char* implementation_name);
-
-  void OnPreDecode(VideoCodecType codec_type, int qp);
-
-  void OnUniqueFramesCounted(int num_unique_frames);
-
-  // Indicates video stream has been paused (no incoming packets).
-  void OnStreamInactive();
-
-  // Overrides VCMReceiveStatisticsCallback.
-  void OnCompleteFrame(bool is_keyframe,
-                       size_t size_bytes,
-                       VideoContentType content_type) override;
-  void OnDroppedFrames(uint32_t frames_dropped) override;
-  void OnFrameBufferTimingsUpdated(int max_decode_ms,
-                                   int current_delay_ms,
-                                   int target_delay_ms,
-                                   int jitter_buffer_ms,
-                                   int min_playout_delay_ms,
-                                   int render_delay_ms) override;
-
-  void OnTimingFrameInfoUpdated(const TimingFrameInfo& info) override;
-
-  // Overrides RtcpCnameCallback.
-  void OnCname(uint32_t ssrc, absl::string_view cname) override;
-
-  // Overrides RtcpPacketTypeCounterObserver.
-  void RtcpPacketTypesCounterUpdated(
-      uint32_t ssrc,
-      const RtcpPacketTypeCounter& packet_counter) override;
-
-  // Implements CallStatsObserver.
-  void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override;
-
-  // Notification methods that are used to check our internal state and validate
-  // threading assumptions. These are called by VideoReceiveStreamInterface.
-  void DecoderThreadStarting();
-  void DecoderThreadStopped();
-
-  // Produce histograms. Must be called after DecoderThreadStopped(), typically
-  // at the end of the call.
-  void UpdateHistograms(absl::optional<int> fraction_lost,
-                        const StreamDataCounters& rtp_stats,
-                        const StreamDataCounters* rtx_stats);
-
- private:
-  struct QpCounters {
-    rtc::SampleCounter vp8;
-  };
-
-  struct ContentSpecificStats {
-    ContentSpecificStats();
-    ~ContentSpecificStats();
-
-    void Add(const ContentSpecificStats& other);
-
-    rtc::SampleCounter e2e_delay_counter;
-    rtc::SampleCounter interframe_delay_counter;
-    int64_t flow_duration_ms = 0;
-    int64_t total_media_bytes = 0;
-    rtc::SampleCounter received_width;
-    rtc::SampleCounter received_height;
-    rtc::SampleCounter qp_counter;
-    FrameCounts frame_counts;
-    rtc::HistogramPercentileCounter interframe_delay_percentiles;
-  };
-
-  void QualitySample() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
-
-  // Removes info about old frames and then updates the framerate.
-  void UpdateFramerate(int64_t now_ms) const
-      RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
-
-  void UpdateDecodeTimeHistograms(int width,
-                                  int height,
-                                  int decode_time_ms) const
-      RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
-
-  absl::optional<int64_t> GetCurrentEstimatedPlayoutNtpTimestampMs(
-      int64_t now_ms) const RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
-
-  Clock* const clock_;
-  const int64_t start_ms_;
-  const bool enable_decode_time_histograms_;
-
-  mutable Mutex mutex_;
-  int64_t last_sample_time_ RTC_GUARDED_BY(mutex_);
-  QualityThreshold fps_threshold_ RTC_GUARDED_BY(mutex_);
-  QualityThreshold qp_threshold_ RTC_GUARDED_BY(mutex_);
-  QualityThreshold variance_threshold_ RTC_GUARDED_BY(mutex_);
-  rtc::SampleCounter qp_sample_ RTC_GUARDED_BY(mutex_);
-  int num_bad_states_ RTC_GUARDED_BY(mutex_);
-  int num_certain_states_ RTC_GUARDED_BY(mutex_);
-  // Note: The `stats_.rtp_stats` member is not used or populated by this class.
-  mutable VideoReceiveStreamInterface::Stats stats_ RTC_GUARDED_BY(mutex_);
-  RateStatistics decode_fps_estimator_ RTC_GUARDED_BY(mutex_);
-  RateStatistics renders_fps_estimator_ RTC_GUARDED_BY(mutex_);
-  rtc::RateTracker render_fps_tracker_ RTC_GUARDED_BY(mutex_);
-  rtc::RateTracker render_pixel_tracker_ RTC_GUARDED_BY(mutex_);
-  rtc::SampleCounter sync_offset_counter_ RTC_GUARDED_BY(mutex_);
-  rtc::SampleCounter decode_time_counter_ RTC_GUARDED_BY(mutex_);
-  rtc::SampleCounter jitter_buffer_delay_counter_ RTC_GUARDED_BY(mutex_);
-  rtc::SampleCounter target_delay_counter_ RTC_GUARDED_BY(mutex_);
-  rtc::SampleCounter current_delay_counter_ RTC_GUARDED_BY(mutex_);
-  rtc::SampleCounter delay_counter_ RTC_GUARDED_BY(mutex_);
-  std::unique_ptr<VideoQualityObserver> video_quality_observer_
-      RTC_GUARDED_BY(mutex_);
-  mutable rtc::MovingMaxCounter<int> interframe_delay_max_moving_
-      RTC_GUARDED_BY(mutex_);
-  std::map<VideoContentType, ContentSpecificStats> content_specific_stats_
-      RTC_GUARDED_BY(mutex_);
-  MaxCounter freq_offset_counter_ RTC_GUARDED_BY(mutex_);
-  QpCounters qp_counters_ RTC_GUARDED_BY(decode_thread_);
-  int64_t avg_rtt_ms_ RTC_GUARDED_BY(mutex_);
-  mutable std::map<int64_t, size_t> frame_window_ RTC_GUARDED_BY(&mutex_);
-  VideoContentType last_content_type_ RTC_GUARDED_BY(&mutex_);
-  VideoCodecType last_codec_type_ RTC_GUARDED_BY(&mutex_);
-  absl::optional<int64_t> first_frame_received_time_ms_ RTC_GUARDED_BY(&mutex_);
-  absl::optional<int64_t> first_decoded_frame_time_ms_ RTC_GUARDED_BY(&mutex_);
-  absl::optional<int64_t> last_decoded_frame_time_ms_ RTC_GUARDED_BY(&mutex_);
-  size_t num_delayed_frames_rendered_ RTC_GUARDED_BY(&mutex_);
-  int64_t sum_missed_render_deadline_ms_ RTC_GUARDED_BY(&mutex_);
-  // Mutable because calling Max() on MovingMaxCounter is not const. Yet it is
-  // called from const GetStats().
-  mutable rtc::MovingMaxCounter<TimingFrameInfo> timing_frame_info_counter_
-      RTC_GUARDED_BY(&mutex_);
-  absl::optional<int> num_unique_frames_ RTC_GUARDED_BY(mutex_);
-  absl::optional<int64_t> last_estimated_playout_ntp_timestamp_ms_
-      RTC_GUARDED_BY(&mutex_);
-  absl::optional<int64_t> last_estimated_playout_time_ms_
-      RTC_GUARDED_BY(&mutex_);
-  SequenceChecker decode_thread_;
-  SequenceChecker network_thread_;
-  SequenceChecker main_thread_;
-};
-
-}  // namespace webrtc
-#endif  // VIDEO_RECEIVE_STATISTICS_PROXY_H_
diff --git a/video/receive_statistics_proxy_unittest.cc b/video/receive_statistics_proxy_unittest.cc
deleted file mode 100644
index 1bef646..0000000
--- a/video/receive_statistics_proxy_unittest.cc
+++ /dev/null
@@ -1,1827 +0,0 @@
-/*
- *  Copyright 2016 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 "video/receive_statistics_proxy.h"
-
-#include <limits>
-#include <memory>
-#include <string>
-#include <tuple>
-#include <utility>
-
-#include "absl/types/optional.h"
-#include "api/scoped_refptr.h"
-#include "api/video/i420_buffer.h"
-#include "api/video/video_frame.h"
-#include "api/video/video_frame_buffer.h"
-#include "api/video/video_rotation.h"
-#include "system_wrappers/include/metrics.h"
-#include "test/gtest.h"
-#include "test/scoped_key_value_config.h"
-
-namespace webrtc {
-namespace {
-const int64_t kFreqOffsetProcessIntervalInMs = 40000;
-const uint32_t kLocalSsrc = 123;
-const uint32_t kRemoteSsrc = 456;
-const int kMinRequiredSamples = 200;
-const int kWidth = 1280;
-const int kHeight = 720;
-}  // namespace
-
-// TODO(sakal): ReceiveStatisticsProxy is lacking unittesting.
-class ReceiveStatisticsProxyTest : public ::testing::Test {
- public:
-  explicit ReceiveStatisticsProxyTest(std::string field_trials = "")
-      : field_trials_(field_trials),
-        fake_clock_(1234),
-        config_(GetTestConfig()) {}
-  virtual ~ReceiveStatisticsProxyTest() {}
-
- protected:
-  virtual void SetUp() {
-    metrics::Reset();
-    statistics_proxy_.reset(new ReceiveStatisticsProxy(
-        config_.rtp.remote_ssrc, &fake_clock_, &field_trials_));
-  }
-
-  VideoReceiveStreamInterface::Config GetTestConfig() {
-    VideoReceiveStreamInterface::Config config(nullptr);
-    config.rtp.local_ssrc = kLocalSsrc;
-    config.rtp.remote_ssrc = kRemoteSsrc;
-    return config;
-  }
-
-  VideoFrame CreateFrame(int width, int height) {
-    return CreateVideoFrame(width, height, 0);
-  }
-
-  VideoFrame CreateFrameWithRenderTimeMs(int64_t render_time_ms) {
-    return CreateVideoFrame(kWidth, kHeight, render_time_ms);
-  }
-
-  VideoFrame CreateVideoFrame(int width, int height, int64_t render_time_ms) {
-    VideoFrame frame =
-        VideoFrame::Builder()
-            .set_video_frame_buffer(I420Buffer::Create(width, height))
-            .set_timestamp_rtp(0)
-            .set_timestamp_ms(render_time_ms)
-            .set_rotation(kVideoRotation_0)
-            .build();
-    frame.set_ntp_time_ms(fake_clock_.CurrentNtpInMilliseconds());
-    return frame;
-  }
-
-  test::ScopedKeyValueConfig field_trials_;
-  SimulatedClock fake_clock_;
-  const VideoReceiveStreamInterface::Config config_;
-  std::unique_ptr<ReceiveStatisticsProxy> statistics_proxy_;
-};
-
-TEST_F(ReceiveStatisticsProxyTest, OnDecodedFrameIncreasesFramesDecoded) {
-  EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_decoded);
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  for (uint32_t i = 1; i <= 3; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                      VideoContentType::UNSPECIFIED);
-    EXPECT_EQ(i, statistics_proxy_->GetStats().frames_decoded);
-  }
-}
-
-TEST_F(ReceiveStatisticsProxyTest, DecodedFpsIsReported) {
-  const int kFps = 20;
-  const int kRequiredSamples = metrics::kMinRunTimeInSeconds * kFps;
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  for (int i = 0; i < kRequiredSamples; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                      VideoContentType::UNSPECIFIED);
-    fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
-  }
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(1,
-                   metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.DecodedFramesPerSecond", kFps));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, DecodedFpsIsNotReportedForTooFewSamples) {
-  const int kFps = 20;
-  const int kRequiredSamples = metrics::kMinRunTimeInSeconds * kFps;
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  for (int i = 0; i < kRequiredSamples - 1; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                      VideoContentType::UNSPECIFIED);
-    fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
-  }
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(0,
-                   metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond"));
-}
-
-TEST_F(ReceiveStatisticsProxyTest,
-       OnDecodedFrameWithQpDoesNotResetFramesDecodedOrTotalDecodeTime) {
-  EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_decoded);
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  unsigned int expected_total_decode_time_ms = 0;
-  unsigned int expected_frames_decoded = 0;
-  for (uint32_t i = 1; i <= 3; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 1,
-                                      VideoContentType::UNSPECIFIED);
-    expected_total_decode_time_ms += 1;
-    ++expected_frames_decoded;
-    EXPECT_EQ(expected_frames_decoded,
-              statistics_proxy_->GetStats().frames_decoded);
-    EXPECT_EQ(expected_total_decode_time_ms,
-              statistics_proxy_->GetStats().total_decode_time_ms);
-  }
-  statistics_proxy_->OnDecodedFrame(frame, 1u, 3,
-                                    VideoContentType::UNSPECIFIED);
-  ++expected_frames_decoded;
-  expected_total_decode_time_ms += 3;
-  EXPECT_EQ(expected_frames_decoded,
-            statistics_proxy_->GetStats().frames_decoded);
-  EXPECT_EQ(expected_total_decode_time_ms,
-            statistics_proxy_->GetStats().total_decode_time_ms);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, OnDecodedFrameIncreasesQpSum) {
-  EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
-                                    VideoContentType::UNSPECIFIED);
-  EXPECT_EQ(3u, statistics_proxy_->GetStats().qp_sum);
-  statistics_proxy_->OnDecodedFrame(frame, 127u, 0,
-                                    VideoContentType::UNSPECIFIED);
-  EXPECT_EQ(130u, statistics_proxy_->GetStats().qp_sum);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, OnDecodedFrameIncreasesTotalDecodeTime) {
-  EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  statistics_proxy_->OnDecodedFrame(frame, 3u, 4,
-                                    VideoContentType::UNSPECIFIED);
-  EXPECT_EQ(4u, statistics_proxy_->GetStats().total_decode_time_ms);
-  statistics_proxy_->OnDecodedFrame(frame, 127u, 7,
-                                    VideoContentType::UNSPECIFIED);
-  EXPECT_EQ(11u, statistics_proxy_->GetStats().total_decode_time_ms);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, ReportsContentType) {
-  const std::string kRealtimeString("realtime");
-  const std::string kScreenshareString("screen");
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  EXPECT_EQ(kRealtimeString, videocontenttypehelpers::ToString(
-                                 statistics_proxy_->GetStats().content_type));
-  statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
-                                    VideoContentType::SCREENSHARE);
-  EXPECT_EQ(kScreenshareString,
-            videocontenttypehelpers::ToString(
-                statistics_proxy_->GetStats().content_type));
-  statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
-                                    VideoContentType::UNSPECIFIED);
-  EXPECT_EQ(kRealtimeString, videocontenttypehelpers::ToString(
-                                 statistics_proxy_->GetStats().content_type));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, ReportsMaxTotalInterFrameDelay) {
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  const TimeDelta kInterFrameDelay1 = TimeDelta::Millis(100);
-  const TimeDelta kInterFrameDelay2 = TimeDelta::Millis(200);
-  const TimeDelta kInterFrameDelay3 = TimeDelta::Millis(300);
-  double expected_total_inter_frame_delay = 0;
-  double expected_total_squared_inter_frame_delay = 0;
-  EXPECT_EQ(expected_total_inter_frame_delay,
-            statistics_proxy_->GetStats().total_inter_frame_delay);
-  EXPECT_EQ(expected_total_squared_inter_frame_delay,
-            statistics_proxy_->GetStats().total_squared_inter_frame_delay);
-
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-  EXPECT_DOUBLE_EQ(expected_total_inter_frame_delay,
-                   statistics_proxy_->GetStats().total_inter_frame_delay);
-  EXPECT_DOUBLE_EQ(
-      expected_total_squared_inter_frame_delay,
-      statistics_proxy_->GetStats().total_squared_inter_frame_delay);
-
-  fake_clock_.AdvanceTime(kInterFrameDelay1);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-  expected_total_inter_frame_delay += kInterFrameDelay1.seconds<double>();
-  expected_total_squared_inter_frame_delay +=
-      pow(kInterFrameDelay1.seconds<double>(), 2.0);
-  EXPECT_DOUBLE_EQ(expected_total_inter_frame_delay,
-                   statistics_proxy_->GetStats().total_inter_frame_delay);
-  EXPECT_DOUBLE_EQ(
-      expected_total_squared_inter_frame_delay,
-      statistics_proxy_->GetStats().total_squared_inter_frame_delay);
-
-  fake_clock_.AdvanceTime(kInterFrameDelay2);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-  expected_total_inter_frame_delay += kInterFrameDelay2.seconds<double>();
-  expected_total_squared_inter_frame_delay +=
-      pow(kInterFrameDelay2.seconds<double>(), 2.0);
-  EXPECT_DOUBLE_EQ(expected_total_inter_frame_delay,
-                   statistics_proxy_->GetStats().total_inter_frame_delay);
-  EXPECT_DOUBLE_EQ(
-      expected_total_squared_inter_frame_delay,
-      statistics_proxy_->GetStats().total_squared_inter_frame_delay);
-
-  fake_clock_.AdvanceTime(kInterFrameDelay3);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-  expected_total_inter_frame_delay += kInterFrameDelay3.seconds<double>();
-  expected_total_squared_inter_frame_delay +=
-      pow(kInterFrameDelay3.seconds<double>(), 2.0);
-  EXPECT_DOUBLE_EQ(expected_total_inter_frame_delay,
-                   statistics_proxy_->GetStats().total_inter_frame_delay);
-  EXPECT_DOUBLE_EQ(
-      expected_total_squared_inter_frame_delay,
-      statistics_proxy_->GetStats().total_squared_inter_frame_delay);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, ReportsMaxInterframeDelay) {
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  const int64_t kInterframeDelayMs1 = 100;
-  const int64_t kInterframeDelayMs2 = 200;
-  const int64_t kInterframeDelayMs3 = 100;
-  EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-  EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms);
-
-  fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs1);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-  EXPECT_EQ(kInterframeDelayMs1,
-            statistics_proxy_->GetStats().interframe_delay_max_ms);
-
-  fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs2);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-  EXPECT_EQ(kInterframeDelayMs2,
-            statistics_proxy_->GetStats().interframe_delay_max_ms);
-
-  fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs3);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-  // kInterframeDelayMs3 is smaller than kInterframeDelayMs2.
-  EXPECT_EQ(kInterframeDelayMs2,
-            statistics_proxy_->GetStats().interframe_delay_max_ms);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, ReportInterframeDelayInWindow) {
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  const int64_t kInterframeDelayMs1 = 900;
-  const int64_t kInterframeDelayMs2 = 750;
-  const int64_t kInterframeDelayMs3 = 700;
-  EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-  EXPECT_EQ(-1, statistics_proxy_->GetStats().interframe_delay_max_ms);
-
-  fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs1);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-  EXPECT_EQ(kInterframeDelayMs1,
-            statistics_proxy_->GetStats().interframe_delay_max_ms);
-
-  fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs2);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-  // Still first delay is the maximum
-  EXPECT_EQ(kInterframeDelayMs1,
-            statistics_proxy_->GetStats().interframe_delay_max_ms);
-
-  fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs3);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-  // Now the first sample is out of the window, so the second is the maximum.
-  EXPECT_EQ(kInterframeDelayMs2,
-            statistics_proxy_->GetStats().interframe_delay_max_ms);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, ReportsFreezeMetrics) {
-  const int64_t kFreezeDurationMs = 1000;
-
-  VideoReceiveStreamInterface::Stats stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(0u, stats.freeze_count);
-  EXPECT_FALSE(stats.total_freezes_duration_ms);
-
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  for (size_t i = 0; i < VideoQualityObserver::kMinFrameSamplesToDetectFreeze;
-       ++i) {
-    fake_clock_.AdvanceTimeMilliseconds(30);
-    statistics_proxy_->OnRenderedFrame(frame);
-  }
-
-  // Freeze.
-  fake_clock_.AdvanceTimeMilliseconds(kFreezeDurationMs);
-  statistics_proxy_->OnRenderedFrame(frame);
-
-  stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(1u, stats.freeze_count);
-  EXPECT_EQ(kFreezeDurationMs, stats.total_freezes_duration_ms);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, ReportsPauseMetrics) {
-  VideoReceiveStreamInterface::Stats stats = statistics_proxy_->GetStats();
-  ASSERT_EQ(0u, stats.pause_count);
-  ASSERT_EQ(0u, stats.total_pauses_duration_ms);
-
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  statistics_proxy_->OnRenderedFrame(frame);
-
-  // Pause.
-  fake_clock_.AdvanceTimeMilliseconds(5432);
-  statistics_proxy_->OnStreamInactive();
-  statistics_proxy_->OnRenderedFrame(frame);
-
-  stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(1u, stats.pause_count);
-  EXPECT_EQ(5432u, stats.total_pauses_duration_ms);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, PauseBeforeFirstAndAfterLastFrameIgnored) {
-  VideoReceiveStreamInterface::Stats stats = statistics_proxy_->GetStats();
-  ASSERT_EQ(0u, stats.pause_count);
-  ASSERT_EQ(0u, stats.total_pauses_duration_ms);
-
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  // Pause -> Frame -> Pause
-  fake_clock_.AdvanceTimeMilliseconds(5000);
-  statistics_proxy_->OnStreamInactive();
-  statistics_proxy_->OnRenderedFrame(frame);
-
-  fake_clock_.AdvanceTimeMilliseconds(30);
-  statistics_proxy_->OnRenderedFrame(frame);
-
-  fake_clock_.AdvanceTimeMilliseconds(5000);
-  statistics_proxy_->OnStreamInactive();
-
-  stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(0u, stats.pause_count);
-  EXPECT_EQ(0u, stats.total_pauses_duration_ms);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, ReportsFramesDuration) {
-  VideoReceiveStreamInterface::Stats stats = statistics_proxy_->GetStats();
-  ASSERT_EQ(0u, stats.total_frames_duration_ms);
-
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  // Emulate delay before first frame is rendered. This is needed to ensure
-  // that frame duration only covers time since first frame is rendered and
-  // not the total time.
-  fake_clock_.AdvanceTimeMilliseconds(5432);
-
-  for (int i = 0; i <= 10; ++i) {
-    fake_clock_.AdvanceTimeMilliseconds(30);
-    statistics_proxy_->OnRenderedFrame(frame);
-  }
-
-  stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(10 * 30u, stats.total_frames_duration_ms);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, ReportsSumSquaredFrameDurations) {
-  VideoReceiveStreamInterface::Stats stats = statistics_proxy_->GetStats();
-  ASSERT_EQ(0u, stats.sum_squared_frame_durations);
-
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  for (int i = 0; i <= 10; ++i) {
-    fake_clock_.AdvanceTimeMilliseconds(30);
-    statistics_proxy_->OnRenderedFrame(frame);
-  }
-
-  stats = statistics_proxy_->GetStats();
-  const double kExpectedSumSquaredFrameDurationsSecs =
-      10 * (30 / 1000.0 * 30 / 1000.0);
-  EXPECT_EQ(kExpectedSumSquaredFrameDurationsSecs,
-            stats.sum_squared_frame_durations);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, OnDecodedFrameWithoutQpQpSumWontExist) {
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-  EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, OnDecodedFrameWithoutQpResetsQpSum) {
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
-  statistics_proxy_->OnDecodedFrame(frame, 3u, 0,
-                                    VideoContentType::UNSPECIFIED);
-  EXPECT_EQ(3u, statistics_proxy_->GetStats().qp_sum);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-  EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, OnRenderedFrameIncreasesFramesRendered) {
-  EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_rendered);
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  for (uint32_t i = 1; i <= 3; ++i) {
-    statistics_proxy_->OnRenderedFrame(frame);
-    EXPECT_EQ(i, statistics_proxy_->GetStats().frames_rendered);
-  }
-}
-
-TEST_F(ReceiveStatisticsProxyTest, GetStatsReportsSsrc) {
-  EXPECT_EQ(kRemoteSsrc, statistics_proxy_->GetStats().ssrc);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, GetStatsReportsIncomingPayloadType) {
-  const int kPayloadType = 111;
-  statistics_proxy_->OnIncomingPayloadType(kPayloadType);
-  EXPECT_EQ(kPayloadType, statistics_proxy_->GetStats().current_payload_type);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, GetStatsReportsDecoderImplementationName) {
-  const char* kName = "decoderName";
-  statistics_proxy_->OnDecoderImplementationName(kName);
-  EXPECT_STREQ(
-      kName, statistics_proxy_->GetStats().decoder_implementation_name.c_str());
-}
-
-TEST_F(ReceiveStatisticsProxyTest, GetStatsReportsOnCompleteFrame) {
-  const int kFrameSizeBytes = 1000;
-  statistics_proxy_->OnCompleteFrame(true, kFrameSizeBytes,
-                                     VideoContentType::UNSPECIFIED);
-  VideoReceiveStreamInterface::Stats stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(1, stats.network_frame_rate);
-  EXPECT_EQ(1, stats.frame_counts.key_frames);
-  EXPECT_EQ(0, stats.frame_counts.delta_frames);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, GetStatsReportsOnDroppedFrame) {
-  unsigned int dropped_frames = 0;
-  for (int i = 0; i < 10; ++i) {
-    statistics_proxy_->OnDroppedFrames(i);
-    dropped_frames += i;
-  }
-  VideoReceiveStreamInterface::Stats stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(dropped_frames, stats.frames_dropped);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, GetStatsReportsDecodeTimingStats) {
-  const int kMaxDecodeMs = 2;
-  const int kCurrentDelayMs = 3;
-  const int kTargetDelayMs = 4;
-  const int kJitterBufferMs = 5;
-  const int kMinPlayoutDelayMs = 6;
-  const int kRenderDelayMs = 7;
-  const int64_t kRttMs = 8;
-  statistics_proxy_->OnRttUpdate(kRttMs, 0);
-  statistics_proxy_->OnFrameBufferTimingsUpdated(
-      kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs, kJitterBufferMs,
-      kMinPlayoutDelayMs, kRenderDelayMs);
-  VideoReceiveStreamInterface::Stats stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(kMaxDecodeMs, stats.max_decode_ms);
-  EXPECT_EQ(kCurrentDelayMs, stats.current_delay_ms);
-  EXPECT_EQ(kTargetDelayMs, stats.target_delay_ms);
-  EXPECT_EQ(kJitterBufferMs, stats.jitter_buffer_ms);
-  EXPECT_EQ(kMinPlayoutDelayMs, stats.min_playout_delay_ms);
-  EXPECT_EQ(kRenderDelayMs, stats.render_delay_ms);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, GetStatsReportsRtcpPacketTypeCounts) {
-  const uint32_t kFirPackets = 33;
-  const uint32_t kPliPackets = 44;
-  const uint32_t kNackPackets = 55;
-  RtcpPacketTypeCounter counter;
-  counter.fir_packets = kFirPackets;
-  counter.pli_packets = kPliPackets;
-  counter.nack_packets = kNackPackets;
-  statistics_proxy_->RtcpPacketTypesCounterUpdated(kRemoteSsrc, counter);
-  VideoReceiveStreamInterface::Stats stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(kFirPackets, stats.rtcp_packet_type_counts.fir_packets);
-  EXPECT_EQ(kPliPackets, stats.rtcp_packet_type_counts.pli_packets);
-  EXPECT_EQ(kNackPackets, stats.rtcp_packet_type_counts.nack_packets);
-}
-
-TEST_F(ReceiveStatisticsProxyTest,
-       GetStatsReportsNoRtcpPacketTypeCountsForUnknownSsrc) {
-  RtcpPacketTypeCounter counter;
-  counter.fir_packets = 33;
-  statistics_proxy_->RtcpPacketTypesCounterUpdated(kRemoteSsrc + 1, counter);
-  EXPECT_EQ(0u,
-            statistics_proxy_->GetStats().rtcp_packet_type_counts.fir_packets);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, GetStatsReportsFrameCounts) {
-  const int kKeyFrames = 3;
-  const int kDeltaFrames = 22;
-  for (int i = 0; i < kKeyFrames; i++) {
-    statistics_proxy_->OnCompleteFrame(true, 0, VideoContentType::UNSPECIFIED);
-  }
-  for (int i = 0; i < kDeltaFrames; i++) {
-    statistics_proxy_->OnCompleteFrame(false, 0, VideoContentType::UNSPECIFIED);
-  }
-
-  VideoReceiveStreamInterface::Stats stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(kKeyFrames, stats.frame_counts.key_frames);
-  EXPECT_EQ(kDeltaFrames, stats.frame_counts.delta_frames);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, GetStatsReportsCName) {
-  const char* kName = "cName";
-  statistics_proxy_->OnCname(kRemoteSsrc, kName);
-  EXPECT_STREQ(kName, statistics_proxy_->GetStats().c_name.c_str());
-}
-
-TEST_F(ReceiveStatisticsProxyTest, GetStatsReportsNoCNameForUnknownSsrc) {
-  const char* kName = "cName";
-  statistics_proxy_->OnCname(kRemoteSsrc + 1, kName);
-  EXPECT_STREQ("", statistics_proxy_->GetStats().c_name.c_str());
-}
-
-TEST_F(ReceiveStatisticsProxyTest, ReportsLongestTimingFrameInfo) {
-  const int64_t kShortEndToEndDelay = 10;
-  const int64_t kMedEndToEndDelay = 20;
-  const int64_t kLongEndToEndDelay = 100;
-  const uint32_t kExpectedRtpTimestamp = 2;
-  TimingFrameInfo info;
-  absl::optional<TimingFrameInfo> result;
-  info.rtp_timestamp = kExpectedRtpTimestamp - 1;
-  info.capture_time_ms = 0;
-  info.decode_finish_ms = kShortEndToEndDelay;
-  statistics_proxy_->OnTimingFrameInfoUpdated(info);
-  info.rtp_timestamp =
-      kExpectedRtpTimestamp;  // this frame should be reported in the end.
-  info.capture_time_ms = 0;
-  info.decode_finish_ms = kLongEndToEndDelay;
-  statistics_proxy_->OnTimingFrameInfoUpdated(info);
-  info.rtp_timestamp = kExpectedRtpTimestamp + 1;
-  info.capture_time_ms = 0;
-  info.decode_finish_ms = kMedEndToEndDelay;
-  statistics_proxy_->OnTimingFrameInfoUpdated(info);
-  result = statistics_proxy_->GetStats().timing_frame_info;
-  EXPECT_TRUE(result);
-  EXPECT_EQ(kExpectedRtpTimestamp, result->rtp_timestamp);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, RespectsReportingIntervalForTimingFrames) {
-  TimingFrameInfo info;
-  const int64_t kShortEndToEndDelay = 10;
-  const uint32_t kExpectedRtpTimestamp = 2;
-  const int64_t kShortDelayMs = 1000;
-  const int64_t kLongDelayMs = 10000;
-  absl::optional<TimingFrameInfo> result;
-  info.rtp_timestamp = kExpectedRtpTimestamp;
-  info.capture_time_ms = 0;
-  info.decode_finish_ms = kShortEndToEndDelay;
-  statistics_proxy_->OnTimingFrameInfoUpdated(info);
-  fake_clock_.AdvanceTimeMilliseconds(kShortDelayMs);
-  result = statistics_proxy_->GetStats().timing_frame_info;
-  EXPECT_TRUE(result);
-  EXPECT_EQ(kExpectedRtpTimestamp, result->rtp_timestamp);
-  fake_clock_.AdvanceTimeMilliseconds(kLongDelayMs);
-  result = statistics_proxy_->GetStats().timing_frame_info;
-  EXPECT_FALSE(result);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, LifetimeHistogramIsUpdated) {
-  const int64_t kTimeSec = 3;
-  fake_clock_.AdvanceTimeMilliseconds(kTimeSec * 1000);
-  // Need at least one frame to report stream lifetime.
-  statistics_proxy_->OnCompleteFrame(true, 1000, VideoContentType::UNSPECIFIED);
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(
-      1, metrics::NumSamples("WebRTC.Video.ReceiveStreamLifetimeInSeconds"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.ReceiveStreamLifetimeInSeconds",
-                            kTimeSec));
-}
-
-TEST_F(ReceiveStatisticsProxyTest,
-       LifetimeHistogramNotReportedForEmptyStreams) {
-  const int64_t kTimeSec = 3;
-  fake_clock_.AdvanceTimeMilliseconds(kTimeSec * 1000);
-  // No frames received.
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(
-      0, metrics::NumSamples("WebRTC.Video.ReceiveStreamLifetimeInSeconds"));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, BadCallHistogramsAreUpdated) {
-  // Based on the tuning parameters this will produce 7 uncertain states,
-  // then 10 certainly bad states. There has to be 10 certain states before
-  // any histograms are recorded.
-  const int kNumBadSamples = 17;
-  // We only count one sample per second.
-  const int kBadFameIntervalMs = 1100;
-
-  StreamDataCounters counters;
-  counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
-
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  for (int i = 0; i < kNumBadSamples; ++i) {
-    fake_clock_.AdvanceTimeMilliseconds(kBadFameIntervalMs);
-    statistics_proxy_->OnRenderedFrame(frame);
-  }
-  statistics_proxy_->UpdateHistograms(absl::nullopt, counters, nullptr);
-  EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.BadCall.Any"));
-  EXPECT_METRIC_EQ(1, metrics::NumEvents("WebRTC.Video.BadCall.Any", 100));
-
-  EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.BadCall.FrameRate"));
-  EXPECT_METRIC_EQ(1,
-                   metrics::NumEvents("WebRTC.Video.BadCall.FrameRate", 100));
-
-  EXPECT_METRIC_EQ(
-      0, metrics::NumSamples("WebRTC.Video.BadCall.FrameRateVariance"));
-
-  EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.BadCall.Qp"));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, PacketLossHistogramIsUpdated) {
-  statistics_proxy_->UpdateHistograms(10, StreamDataCounters(), nullptr);
-  EXPECT_METRIC_EQ(
-      0, metrics::NumSamples("WebRTC.Video.ReceivedPacketsLostInPercent"));
-
-  // Restart
-  SetUp();
-
-  // Min run time has passed.
-  fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
-  statistics_proxy_->UpdateHistograms(10, StreamDataCounters(), nullptr);
-  EXPECT_METRIC_EQ(
-      1, metrics::NumSamples("WebRTC.Video.ReceivedPacketsLostInPercent"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.ReceivedPacketsLostInPercent", 10));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, GetStatsReportsPlayoutTimestamp) {
-  const int64_t kVideoNtpMs = 21;
-  const int64_t kSyncOffsetMs = 22;
-  const double kFreqKhz = 90.0;
-  EXPECT_EQ(absl::nullopt,
-            statistics_proxy_->GetStats().estimated_playout_ntp_timestamp_ms);
-  statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs, kFreqKhz);
-  EXPECT_EQ(kVideoNtpMs,
-            statistics_proxy_->GetStats().estimated_playout_ntp_timestamp_ms);
-  fake_clock_.AdvanceTimeMilliseconds(13);
-  EXPECT_EQ(kVideoNtpMs + 13,
-            statistics_proxy_->GetStats().estimated_playout_ntp_timestamp_ms);
-  fake_clock_.AdvanceTimeMilliseconds(5);
-  EXPECT_EQ(kVideoNtpMs + 13 + 5,
-            statistics_proxy_->GetStats().estimated_playout_ntp_timestamp_ms);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, GetStatsReportsAvSyncOffset) {
-  const int64_t kVideoNtpMs = 21;
-  const int64_t kSyncOffsetMs = 22;
-  const double kFreqKhz = 90.0;
-  EXPECT_EQ(std::numeric_limits<int>::max(),
-            statistics_proxy_->GetStats().sync_offset_ms);
-  statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs, kFreqKhz);
-  EXPECT_EQ(kSyncOffsetMs, statistics_proxy_->GetStats().sync_offset_ms);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, AvSyncOffsetHistogramIsUpdated) {
-  const int64_t kVideoNtpMs = 21;
-  const int64_t kSyncOffsetMs = 22;
-  const double kFreqKhz = 90.0;
-  for (int i = 0; i < kMinRequiredSamples; ++i)
-    statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
-                                           kFreqKhz);
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.AVSyncOffsetInMs"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.AVSyncOffsetInMs", kSyncOffsetMs));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, RtpToNtpFrequencyOffsetHistogramIsUpdated) {
-  const int64_t kVideoNtpMs = 21;
-  const int64_t kSyncOffsetMs = 22;
-  const double kFreqKhz = 90.0;
-  statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs, kFreqKhz);
-  statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
-                                         kFreqKhz + 2.2);
-  fake_clock_.AdvanceTimeMilliseconds(kFreqOffsetProcessIntervalInMs);
-  // Process interval passed, max diff: 2.
-  statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
-                                         kFreqKhz + 1.1);
-  statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
-                                         kFreqKhz - 4.2);
-  statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs,
-                                         kFreqKhz - 0.9);
-  fake_clock_.AdvanceTimeMilliseconds(kFreqOffsetProcessIntervalInMs);
-  // Process interval passed, max diff: 4.
-  statistics_proxy_->OnSyncOffsetUpdated(kVideoNtpMs, kSyncOffsetMs, kFreqKhz);
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  // Average reported: (2 + 4) / 2 = 3.
-  EXPECT_METRIC_EQ(1,
-                   metrics::NumSamples("WebRTC.Video.RtpToNtpFreqOffsetInKhz"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.RtpToNtpFreqOffsetInKhz", 3));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, Vp8QpHistogramIsUpdated) {
-  const int kQp = 22;
-
-  for (int i = 0; i < kMinRequiredSamples; ++i)
-    statistics_proxy_->OnPreDecode(kVideoCodecVP8, kQp);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.Decoded.Vp8.Qp"));
-  EXPECT_METRIC_EQ(1, metrics::NumEvents("WebRTC.Video.Decoded.Vp8.Qp", kQp));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, Vp8QpHistogramIsNotUpdatedForTooFewSamples) {
-  const int kQp = 22;
-
-  for (int i = 0; i < kMinRequiredSamples - 1; ++i)
-    statistics_proxy_->OnPreDecode(kVideoCodecVP8, kQp);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.Decoded.Vp8.Qp"));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, Vp8QpHistogramIsNotUpdatedIfNoQpValue) {
-  for (int i = 0; i < kMinRequiredSamples; ++i)
-    statistics_proxy_->OnPreDecode(kVideoCodecVP8, -1);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.Decoded.Vp8.Qp"));
-}
-
-TEST_F(ReceiveStatisticsProxyTest,
-       KeyFrameHistogramNotUpdatedForTooFewSamples) {
-  const bool kIsKeyFrame = false;
-  const int kFrameSizeBytes = 1000;
-
-  for (int i = 0; i < kMinRequiredSamples - 1; ++i)
-    statistics_proxy_->OnCompleteFrame(kIsKeyFrame, kFrameSizeBytes,
-                                       VideoContentType::UNSPECIFIED);
-
-  EXPECT_EQ(0, statistics_proxy_->GetStats().frame_counts.key_frames);
-  EXPECT_EQ(kMinRequiredSamples - 1,
-            statistics_proxy_->GetStats().frame_counts.delta_frames);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(
-      0, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille"));
-}
-
-TEST_F(ReceiveStatisticsProxyTest,
-       KeyFrameHistogramUpdatedForMinRequiredSamples) {
-  const bool kIsKeyFrame = false;
-  const int kFrameSizeBytes = 1000;
-
-  for (int i = 0; i < kMinRequiredSamples; ++i)
-    statistics_proxy_->OnCompleteFrame(kIsKeyFrame, kFrameSizeBytes,
-                                       VideoContentType::UNSPECIFIED);
-
-  EXPECT_EQ(0, statistics_proxy_->GetStats().frame_counts.key_frames);
-  EXPECT_EQ(kMinRequiredSamples,
-            statistics_proxy_->GetStats().frame_counts.delta_frames);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(
-      1, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.KeyFramesReceivedInPermille", 0));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, KeyFrameHistogramIsUpdated) {
-  const int kFrameSizeBytes = 1000;
-
-  for (int i = 0; i < kMinRequiredSamples; ++i)
-    statistics_proxy_->OnCompleteFrame(true, kFrameSizeBytes,
-                                       VideoContentType::UNSPECIFIED);
-
-  for (int i = 0; i < kMinRequiredSamples; ++i)
-    statistics_proxy_->OnCompleteFrame(false, kFrameSizeBytes,
-                                       VideoContentType::UNSPECIFIED);
-
-  EXPECT_EQ(kMinRequiredSamples,
-            statistics_proxy_->GetStats().frame_counts.key_frames);
-  EXPECT_EQ(kMinRequiredSamples,
-            statistics_proxy_->GetStats().frame_counts.delta_frames);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(
-      1, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.KeyFramesReceivedInPermille", 500));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, TimingHistogramsNotUpdatedForTooFewSamples) {
-  const int kMaxDecodeMs = 2;
-  const int kCurrentDelayMs = 3;
-  const int kTargetDelayMs = 4;
-  const int kJitterBufferMs = 5;
-  const int kMinPlayoutDelayMs = 6;
-  const int kRenderDelayMs = 7;
-
-  for (int i = 0; i < kMinRequiredSamples - 1; ++i) {
-    statistics_proxy_->OnFrameBufferTimingsUpdated(
-        kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs, kJitterBufferMs,
-        kMinPlayoutDelayMs, kRenderDelayMs);
-  }
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.DecodeTimeInMs"));
-  EXPECT_METRIC_EQ(0,
-                   metrics::NumSamples("WebRTC.Video.JitterBufferDelayInMs"));
-  EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.TargetDelayInMs"));
-  EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.CurrentDelayInMs"));
-  EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.OnewayDelayInMs"));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, TimingHistogramsAreUpdated) {
-  const int kMaxDecodeMs = 2;
-  const int kCurrentDelayMs = 3;
-  const int kTargetDelayMs = 4;
-  const int kJitterBufferMs = 5;
-  const int kMinPlayoutDelayMs = 6;
-  const int kRenderDelayMs = 7;
-
-  for (int i = 0; i < kMinRequiredSamples; ++i) {
-    statistics_proxy_->OnFrameBufferTimingsUpdated(
-        kMaxDecodeMs, kCurrentDelayMs, kTargetDelayMs, kJitterBufferMs,
-        kMinPlayoutDelayMs, kRenderDelayMs);
-  }
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(1,
-                   metrics::NumSamples("WebRTC.Video.JitterBufferDelayInMs"));
-  EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.TargetDelayInMs"));
-  EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.CurrentDelayInMs"));
-  EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.OnewayDelayInMs"));
-
-  EXPECT_METRIC_EQ(1, metrics::NumEvents("WebRTC.Video.JitterBufferDelayInMs",
-                                         kJitterBufferMs));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.TargetDelayInMs", kTargetDelayMs));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.CurrentDelayInMs", kCurrentDelayMs));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.OnewayDelayInMs", kTargetDelayMs));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, DoesNotReportStaleFramerates) {
-  const int kDefaultFps = 30;
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  for (int i = 0; i < kDefaultFps; ++i) {
-    // Since OnRenderedFrame is never called the fps in each sample will be 0,
-    // i.e. bad
-    frame.set_ntp_time_ms(fake_clock_.CurrentNtpInMilliseconds());
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                      VideoContentType::UNSPECIFIED);
-    statistics_proxy_->OnRenderedFrame(frame);
-    fake_clock_.AdvanceTimeMilliseconds(1000 / kDefaultFps);
-  }
-
-  EXPECT_EQ(kDefaultFps, statistics_proxy_->GetStats().decode_frame_rate);
-  EXPECT_EQ(kDefaultFps, statistics_proxy_->GetStats().render_frame_rate);
-
-  // FPS trackers in stats proxy have a 1000ms sliding window.
-  fake_clock_.AdvanceTimeMilliseconds(1000);
-  EXPECT_EQ(0, statistics_proxy_->GetStats().decode_frame_rate);
-  EXPECT_EQ(0, statistics_proxy_->GetStats().render_frame_rate);
-}
-
-TEST_F(ReceiveStatisticsProxyTest, GetStatsReportsReceivedFrameStats) {
-  EXPECT_EQ(0, statistics_proxy_->GetStats().width);
-  EXPECT_EQ(0, statistics_proxy_->GetStats().height);
-  EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_rendered);
-
-  statistics_proxy_->OnRenderedFrame(CreateFrame(kWidth, kHeight));
-
-  EXPECT_EQ(kWidth, statistics_proxy_->GetStats().width);
-  EXPECT_EQ(kHeight, statistics_proxy_->GetStats().height);
-  EXPECT_EQ(1u, statistics_proxy_->GetStats().frames_rendered);
-}
-
-TEST_F(ReceiveStatisticsProxyTest,
-       ReceivedFrameHistogramsAreNotUpdatedForTooFewSamples) {
-  for (int i = 0; i < kMinRequiredSamples - 1; ++i)
-    statistics_proxy_->OnRenderedFrame(CreateFrame(kWidth, kHeight));
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(0,
-                   metrics::NumSamples("WebRTC.Video.ReceivedWidthInPixels"));
-  EXPECT_METRIC_EQ(0,
-                   metrics::NumSamples("WebRTC.Video.ReceivedHeightInPixels"));
-  EXPECT_METRIC_EQ(0,
-                   metrics::NumSamples("WebRTC.Video.RenderFramesPerSecond"));
-  EXPECT_METRIC_EQ(
-      0, metrics::NumSamples("WebRTC.Video.RenderSqrtPixelsPerSecond"));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, ReceivedFrameHistogramsAreUpdated) {
-  for (int i = 0; i < kMinRequiredSamples; ++i)
-    statistics_proxy_->OnRenderedFrame(CreateFrame(kWidth, kHeight));
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(1,
-                   metrics::NumSamples("WebRTC.Video.ReceivedWidthInPixels"));
-  EXPECT_METRIC_EQ(1,
-                   metrics::NumSamples("WebRTC.Video.ReceivedHeightInPixels"));
-  EXPECT_METRIC_EQ(1,
-                   metrics::NumSamples("WebRTC.Video.RenderFramesPerSecond"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumSamples("WebRTC.Video.RenderSqrtPixelsPerSecond"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.ReceivedWidthInPixels", kWidth));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.ReceivedHeightInPixels", kHeight));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, ZeroDelayReportedIfFrameNotDelayed) {
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-
-  // Frame not delayed, delayed frames to render: 0%.
-  const int64_t kNowMs = fake_clock_.TimeInMilliseconds();
-  statistics_proxy_->OnRenderedFrame(CreateFrameWithRenderTimeMs(kNowMs));
-
-  // Min run time has passed.
-  fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(1,
-                   metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer", 0));
-  EXPECT_METRIC_EQ(0, metrics::NumSamples(
-                          "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
-}
-
-TEST_F(ReceiveStatisticsProxyTest,
-       DelayedFrameHistogramsAreNotUpdatedIfMinRuntimeHasNotPassed) {
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-
-  // Frame not delayed, delayed frames to render: 0%.
-  const int64_t kNowMs = fake_clock_.TimeInMilliseconds();
-  statistics_proxy_->OnRenderedFrame(CreateFrameWithRenderTimeMs(kNowMs));
-
-  // Min run time has not passed.
-  fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000) -
-                                      1);
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(0,
-                   metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
-  EXPECT_METRIC_EQ(0, metrics::NumSamples(
-                          "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
-}
-
-TEST_F(ReceiveStatisticsProxyTest,
-       DelayedFramesHistogramsAreNotUpdatedIfNoRenderedFrames) {
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-
-  // Min run time has passed. No rendered frames.
-  fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(0,
-                   metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
-  EXPECT_METRIC_EQ(0, metrics::NumSamples(
-                          "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, DelayReportedIfFrameIsDelayed) {
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-
-  // Frame delayed 1 ms, delayed frames to render: 100%.
-  const int64_t kNowMs = fake_clock_.TimeInMilliseconds();
-  statistics_proxy_->OnRenderedFrame(CreateFrameWithRenderTimeMs(kNowMs - 1));
-
-  // Min run time has passed.
-  fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(1,
-                   metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer", 100));
-  EXPECT_METRIC_EQ(1, metrics::NumSamples(
-                          "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs",
-                            1));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, AverageDelayOfDelayedFramesIsReported) {
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0,
-                                    VideoContentType::UNSPECIFIED);
-
-  // Two frames delayed (6 ms, 10 ms), delayed frames to render: 50%.
-  const int64_t kNowMs = fake_clock_.TimeInMilliseconds();
-  statistics_proxy_->OnRenderedFrame(CreateFrameWithRenderTimeMs(kNowMs - 10));
-  statistics_proxy_->OnRenderedFrame(CreateFrameWithRenderTimeMs(kNowMs - 6));
-  statistics_proxy_->OnRenderedFrame(CreateFrameWithRenderTimeMs(kNowMs));
-  statistics_proxy_->OnRenderedFrame(CreateFrameWithRenderTimeMs(kNowMs + 1));
-
-  // Min run time has passed.
-  fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000));
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(1,
-                   metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer", 50));
-  EXPECT_METRIC_EQ(1, metrics::NumSamples(
-                          "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs",
-                            8));
-}
-
-TEST_F(ReceiveStatisticsProxyTest,
-       RtcpHistogramsNotUpdatedIfMinRuntimeHasNotPassed) {
-  StreamDataCounters data_counters;
-  data_counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
-
-  fake_clock_.AdvanceTimeMilliseconds((metrics::kMinRunTimeInSeconds * 1000) -
-                                      1);
-
-  RtcpPacketTypeCounter counter;
-  statistics_proxy_->RtcpPacketTypesCounterUpdated(kRemoteSsrc, counter);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, data_counters, nullptr);
-  EXPECT_METRIC_EQ(0,
-                   metrics::NumSamples("WebRTC.Video.FirPacketsSentPerMinute"));
-  EXPECT_METRIC_EQ(0,
-                   metrics::NumSamples("WebRTC.Video.PliPacketsSentPerMinute"));
-  EXPECT_METRIC_EQ(
-      0, metrics::NumSamples("WebRTC.Video.NackPacketsSentPerMinute"));
-}
-
-TEST_F(ReceiveStatisticsProxyTest, RtcpHistogramsAreUpdated) {
-  StreamDataCounters data_counters;
-  data_counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
-  fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
-
-  const uint32_t kFirPackets = 100;
-  const uint32_t kPliPackets = 200;
-  const uint32_t kNackPackets = 300;
-
-  RtcpPacketTypeCounter counter;
-  counter.fir_packets = kFirPackets;
-  counter.pli_packets = kPliPackets;
-  counter.nack_packets = kNackPackets;
-  statistics_proxy_->RtcpPacketTypesCounterUpdated(kRemoteSsrc, counter);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, data_counters, nullptr);
-  EXPECT_METRIC_EQ(1,
-                   metrics::NumSamples("WebRTC.Video.FirPacketsSentPerMinute"));
-  EXPECT_METRIC_EQ(1,
-                   metrics::NumSamples("WebRTC.Video.PliPacketsSentPerMinute"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumSamples("WebRTC.Video.NackPacketsSentPerMinute"));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.FirPacketsSentPerMinute",
-                            kFirPackets * 60 / metrics::kMinRunTimeInSeconds));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.PliPacketsSentPerMinute",
-                            kPliPackets * 60 / metrics::kMinRunTimeInSeconds));
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.NackPacketsSentPerMinute",
-                            kNackPackets * 60 / metrics::kMinRunTimeInSeconds));
-}
-
-class ReceiveStatisticsProxyTestWithFreezeDuration
-    : public ReceiveStatisticsProxyTest,
-      public ::testing::WithParamInterface<
-          std::tuple<uint32_t, uint32_t, uint32_t>> {
- protected:
-  const uint32_t frame_duration_ms_ = {std::get<0>(GetParam())};
-  const uint32_t freeze_duration_ms_ = {std::get<1>(GetParam())};
-  const uint32_t expected_freeze_count_ = {std::get<2>(GetParam())};
-};
-
-// It is a freeze if:
-// frame_duration_ms >= max(3 * avg_frame_duration, avg_frame_duration + 150)
-// where avg_frame_duration is average duration of last 30 frames including
-// the current one.
-//
-// Condition 1: 3 * avg_frame_duration > avg_frame_duration + 150
-const auto kFreezeDetectionCond1Freeze = std::make_tuple(150, 483, 1);
-const auto kFreezeDetectionCond1NotFreeze = std::make_tuple(150, 482, 0);
-// Condition 2: 3 * avg_frame_duration < avg_frame_duration + 150
-const auto kFreezeDetectionCond2Freeze = std::make_tuple(30, 185, 1);
-const auto kFreezeDetectionCond2NotFreeze = std::make_tuple(30, 184, 0);
-
-INSTANTIATE_TEST_SUITE_P(_,
-                         ReceiveStatisticsProxyTestWithFreezeDuration,
-                         ::testing::Values(kFreezeDetectionCond1Freeze,
-                                           kFreezeDetectionCond1NotFreeze,
-                                           kFreezeDetectionCond2Freeze,
-                                           kFreezeDetectionCond2NotFreeze));
-
-TEST_P(ReceiveStatisticsProxyTestWithFreezeDuration, FreezeDetection) {
-  VideoReceiveStreamInterface::Stats stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(0u, stats.freeze_count);
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  // Add a very long frame. This is need to verify that average frame
-  // duration, which is supposed to be calculated as mean of durations of
-  // last 30 frames, is calculated correctly.
-  statistics_proxy_->OnRenderedFrame(frame);
-  fake_clock_.AdvanceTimeMilliseconds(2000);
-
-  for (size_t i = 0;
-       i <= VideoQualityObserver::kAvgInterframeDelaysWindowSizeFrames; ++i) {
-    fake_clock_.AdvanceTimeMilliseconds(frame_duration_ms_);
-    statistics_proxy_->OnRenderedFrame(frame);
-  }
-
-  fake_clock_.AdvanceTimeMilliseconds(freeze_duration_ms_);
-  statistics_proxy_->OnRenderedFrame(frame);
-
-  stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(stats.freeze_count, expected_freeze_count_);
-}
-
-class ReceiveStatisticsProxyTestWithContent
-    : public ReceiveStatisticsProxyTest,
-      public ::testing::WithParamInterface<webrtc::VideoContentType> {
- protected:
-  const webrtc::VideoContentType content_type_{GetParam()};
-};
-
-INSTANTIATE_TEST_SUITE_P(ContentTypes,
-                         ReceiveStatisticsProxyTestWithContent,
-                         ::testing::Values(VideoContentType::UNSPECIFIED,
-                                           VideoContentType::SCREENSHARE));
-
-TEST_P(ReceiveStatisticsProxyTestWithContent, InterFrameDelaysAreReported) {
-  const int kInterFrameDelayMs = 33;
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  for (int i = 0; i < kMinRequiredSamples; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-  }
-  // One extra with double the interval.
-  fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  const int kExpectedInterFrame =
-      (kInterFrameDelayMs * (kMinRequiredSamples - 1) +
-       kInterFrameDelayMs * 2) /
-      kMinRequiredSamples;
-  if (videocontenttypehelpers::IsScreenshare(content_type_)) {
-    EXPECT_METRIC_EQ(
-        kExpectedInterFrame,
-        metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs"));
-    EXPECT_METRIC_EQ(
-        kInterFrameDelayMs * 2,
-        metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
-  } else {
-    EXPECT_METRIC_EQ(kExpectedInterFrame,
-                     metrics::MinSample("WebRTC.Video.InterframeDelayInMs"));
-    EXPECT_METRIC_EQ(kInterFrameDelayMs * 2,
-                     metrics::MinSample("WebRTC.Video.InterframeDelayMaxInMs"));
-  }
-}
-
-TEST_P(ReceiveStatisticsProxyTestWithContent,
-       InterFrameDelaysPercentilesAreReported) {
-  const int kInterFrameDelayMs = 33;
-  const int kLastFivePercentsSamples = kMinRequiredSamples * 5 / 100;
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  for (int i = 0; i <= kMinRequiredSamples - kLastFivePercentsSamples; ++i) {
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-  }
-  // Last 5% of intervals are double in size.
-  for (int i = 0; i < kLastFivePercentsSamples; ++i) {
-    fake_clock_.AdvanceTimeMilliseconds(2 * kInterFrameDelayMs);
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-  }
-  // Final sample is outlier and 10 times as big.
-  fake_clock_.AdvanceTimeMilliseconds(10 * kInterFrameDelayMs);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  const int kExpectedInterFrame = kInterFrameDelayMs * 2;
-  if (videocontenttypehelpers::IsScreenshare(content_type_)) {
-    EXPECT_METRIC_EQ(
-        kExpectedInterFrame,
-        metrics::MinSample(
-            "WebRTC.Video.Screenshare.InterframeDelay95PercentileInMs"));
-  } else {
-    EXPECT_METRIC_EQ(
-        kExpectedInterFrame,
-        metrics::MinSample("WebRTC.Video.InterframeDelay95PercentileInMs"));
-  }
-}
-
-TEST_P(ReceiveStatisticsProxyTestWithContent,
-       MaxInterFrameDelayOnlyWithValidAverage) {
-  const int kInterFrameDelayMs = 33;
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  for (int i = 0; i < kMinRequiredSamples; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-  }
-
-  // `kMinRequiredSamples` samples, and thereby intervals, is required. That
-  // means we're one frame short of having a valid data set.
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.InterframeDelayInMs"));
-  EXPECT_METRIC_EQ(0,
-                   metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs"));
-  EXPECT_METRIC_EQ(
-      0, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayInMs"));
-  EXPECT_METRIC_EQ(0, metrics::NumSamples(
-                          "WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
-}
-
-TEST_P(ReceiveStatisticsProxyTestWithContent, MaxInterFrameDelayOnlyWithPause) {
-  const int kInterFrameDelayMs = 33;
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  for (int i = 0; i <= kMinRequiredSamples; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-  }
-
-  // At this state, we should have a valid inter-frame delay.
-  // Indicate stream paused and make a large jump in time.
-  statistics_proxy_->OnStreamInactive();
-  fake_clock_.AdvanceTimeMilliseconds(5000);
-
-  // Insert two more frames. The interval during the pause should be disregarded
-  // in the stats.
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-  fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  if (videocontenttypehelpers::IsScreenshare(content_type_)) {
-    EXPECT_METRIC_EQ(
-        1, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayInMs"));
-    EXPECT_METRIC_EQ(1, metrics::NumSamples(
-                            "WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
-    EXPECT_METRIC_EQ(
-        kInterFrameDelayMs,
-        metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs"));
-    EXPECT_METRIC_EQ(
-        kInterFrameDelayMs,
-        metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
-  } else {
-    EXPECT_METRIC_EQ(1,
-                     metrics::NumSamples("WebRTC.Video.InterframeDelayInMs"));
-    EXPECT_METRIC_EQ(
-        1, metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs"));
-    EXPECT_METRIC_EQ(kInterFrameDelayMs,
-                     metrics::MinSample("WebRTC.Video.InterframeDelayInMs"));
-    EXPECT_METRIC_EQ(kInterFrameDelayMs,
-                     metrics::MinSample("WebRTC.Video.InterframeDelayMaxInMs"));
-  }
-}
-
-TEST_P(ReceiveStatisticsProxyTestWithContent, FreezesAreReported) {
-  const int kInterFrameDelayMs = 33;
-  const int kFreezeDelayMs = 200;
-  const int kCallDurationMs =
-      kMinRequiredSamples * kInterFrameDelayMs + kFreezeDelayMs;
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  for (int i = 0; i < kMinRequiredSamples; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-    statistics_proxy_->OnRenderedFrame(frame);
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-  }
-  // Add extra freeze.
-  fake_clock_.AdvanceTimeMilliseconds(kFreezeDelayMs);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-  statistics_proxy_->OnRenderedFrame(frame);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  const int kExpectedTimeBetweenFreezes =
-      kInterFrameDelayMs * (kMinRequiredSamples - 1);
-  const int kExpectedNumberFreezesPerMinute = 60 * 1000 / kCallDurationMs;
-  if (videocontenttypehelpers::IsScreenshare(content_type_)) {
-    EXPECT_METRIC_EQ(
-        kFreezeDelayMs + kInterFrameDelayMs,
-        metrics::MinSample("WebRTC.Video.Screenshare.MeanFreezeDurationMs"));
-    EXPECT_METRIC_EQ(kExpectedTimeBetweenFreezes,
-                     metrics::MinSample(
-                         "WebRTC.Video.Screenshare.MeanTimeBetweenFreezesMs"));
-    EXPECT_METRIC_EQ(
-        kExpectedNumberFreezesPerMinute,
-        metrics::MinSample("WebRTC.Video.Screenshare.NumberFreezesPerMinute"));
-  } else {
-    EXPECT_METRIC_EQ(kFreezeDelayMs + kInterFrameDelayMs,
-                     metrics::MinSample("WebRTC.Video.MeanFreezeDurationMs"));
-    EXPECT_METRIC_EQ(
-        kExpectedTimeBetweenFreezes,
-        metrics::MinSample("WebRTC.Video.MeanTimeBetweenFreezesMs"));
-    EXPECT_METRIC_EQ(kExpectedNumberFreezesPerMinute,
-                     metrics::MinSample("WebRTC.Video.NumberFreezesPerMinute"));
-  }
-}
-
-TEST_P(ReceiveStatisticsProxyTestWithContent, HarmonicFrameRateIsReported) {
-  const int kFrameDurationMs = 33;
-  const int kFreezeDurationMs = 200;
-  const int kPauseDurationMs = 10000;
-  const int kCallDurationMs = kMinRequiredSamples * kFrameDurationMs +
-                              kFreezeDurationMs + kPauseDurationMs;
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  for (int i = 0; i < kMinRequiredSamples; ++i) {
-    fake_clock_.AdvanceTimeMilliseconds(kFrameDurationMs);
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-    statistics_proxy_->OnRenderedFrame(frame);
-  }
-
-  // Freezes and pauses should be included into harmonic frame rate.
-  // Add freeze.
-  fake_clock_.AdvanceTimeMilliseconds(kFreezeDurationMs);
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-  statistics_proxy_->OnRenderedFrame(frame);
-
-  // Add pause.
-  fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs);
-  statistics_proxy_->OnStreamInactive();
-  statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-  statistics_proxy_->OnRenderedFrame(frame);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  double kSumSquaredFrameDurationSecs =
-      (kMinRequiredSamples - 1) *
-      (kFrameDurationMs / 1000.0 * kFrameDurationMs / 1000.0);
-  kSumSquaredFrameDurationSecs +=
-      kFreezeDurationMs / 1000.0 * kFreezeDurationMs / 1000.0;
-  kSumSquaredFrameDurationSecs +=
-      kPauseDurationMs / 1000.0 * kPauseDurationMs / 1000.0;
-  const int kExpectedHarmonicFrameRateFps =
-      std::round(kCallDurationMs / (1000 * kSumSquaredFrameDurationSecs));
-  if (videocontenttypehelpers::IsScreenshare(content_type_)) {
-    EXPECT_METRIC_EQ(
-        kExpectedHarmonicFrameRateFps,
-        metrics::MinSample("WebRTC.Video.Screenshare.HarmonicFrameRate"));
-  } else {
-    EXPECT_METRIC_EQ(kExpectedHarmonicFrameRateFps,
-                     metrics::MinSample("WebRTC.Video.HarmonicFrameRate"));
-  }
-}
-
-TEST_P(ReceiveStatisticsProxyTestWithContent, PausesAreIgnored) {
-  const int kInterFrameDelayMs = 33;
-  const int kPauseDurationMs = 10000;
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  for (int i = 0; i <= kMinRequiredSamples; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-    statistics_proxy_->OnRenderedFrame(frame);
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-  }
-  // Add a pause.
-  fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs);
-  statistics_proxy_->OnStreamInactive();
-
-  // Second playback interval with triple the length.
-  for (int i = 0; i <= kMinRequiredSamples * 3; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-    statistics_proxy_->OnRenderedFrame(frame);
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-  }
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  // Average of two playback intervals.
-  const int kExpectedTimeBetweenFreezes =
-      kInterFrameDelayMs * kMinRequiredSamples * 2;
-  if (videocontenttypehelpers::IsScreenshare(content_type_)) {
-    EXPECT_METRIC_EQ(-1, metrics::MinSample(
-                             "WebRTC.Video.Screenshare.MeanFreezeDurationMs"));
-    EXPECT_METRIC_EQ(kExpectedTimeBetweenFreezes,
-                     metrics::MinSample(
-                         "WebRTC.Video.Screenshare.MeanTimeBetweenFreezesMs"));
-  } else {
-    EXPECT_METRIC_EQ(-1,
-                     metrics::MinSample("WebRTC.Video.MeanFreezeDurationMs"));
-    EXPECT_METRIC_EQ(
-        kExpectedTimeBetweenFreezes,
-        metrics::MinSample("WebRTC.Video.MeanTimeBetweenFreezesMs"));
-  }
-}
-
-TEST_P(ReceiveStatisticsProxyTestWithContent, ManyPausesAtTheBeginning) {
-  const int kInterFrameDelayMs = 33;
-  const int kPauseDurationMs = 10000;
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  for (int i = 0; i <= kMinRequiredSamples; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-
-    statistics_proxy_->OnStreamInactive();
-    fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs);
-
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type_);
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-  }
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  // No freezes should be detected, as all long inter-frame delays were pauses.
-  if (videocontenttypehelpers::IsScreenshare(content_type_)) {
-    EXPECT_METRIC_EQ(-1, metrics::MinSample(
-                             "WebRTC.Video.Screenshare.MeanFreezeDurationMs"));
-  } else {
-    EXPECT_METRIC_EQ(-1,
-                     metrics::MinSample("WebRTC.Video.MeanFreezeDurationMs"));
-  }
-}
-
-TEST_P(ReceiveStatisticsProxyTestWithContent, TimeInHdReported) {
-  const int kInterFrameDelayMs = 20;
-  webrtc::VideoFrame frame_hd = CreateFrame(1280, 720);
-  webrtc::VideoFrame frame_sd = CreateFrame(640, 360);
-
-  // HD frames.
-  for (int i = 0; i < kMinRequiredSamples; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame_hd, absl::nullopt, 0,
-                                      content_type_);
-    statistics_proxy_->OnRenderedFrame(frame_hd);
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-  }
-  // SD frames.
-  for (int i = 0; i < 2 * kMinRequiredSamples; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame_sd, absl::nullopt, 0,
-                                      content_type_);
-    statistics_proxy_->OnRenderedFrame(frame_sd);
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-  }
-  // Extra last frame.
-  statistics_proxy_->OnRenderedFrame(frame_sd);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  const int kExpectedTimeInHdPercents = 33;
-  if (videocontenttypehelpers::IsScreenshare(content_type_)) {
-    EXPECT_METRIC_EQ(
-        kExpectedTimeInHdPercents,
-        metrics::MinSample("WebRTC.Video.Screenshare.TimeInHdPercentage"));
-  } else {
-    EXPECT_METRIC_EQ(kExpectedTimeInHdPercents,
-                     metrics::MinSample("WebRTC.Video.TimeInHdPercentage"));
-  }
-}
-
-TEST_P(ReceiveStatisticsProxyTestWithContent, TimeInBlockyVideoReported) {
-  const int kInterFrameDelayMs = 20;
-  const int kHighQp = 80;
-  const int kLowQp = 30;
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  // High quality frames.
-  for (int i = 0; i < kMinRequiredSamples; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, kLowQp, 0, content_type_);
-    statistics_proxy_->OnRenderedFrame(frame);
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-  }
-  // Blocky frames.
-  for (int i = 0; i < 2 * kMinRequiredSamples; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, kHighQp, 0, content_type_);
-    statistics_proxy_->OnRenderedFrame(frame);
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-  }
-  // Extra last frame.
-  statistics_proxy_->OnDecodedFrame(frame, kHighQp, 0, content_type_);
-  statistics_proxy_->OnRenderedFrame(frame);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  const int kExpectedTimeInHdPercents = 66;
-  if (videocontenttypehelpers::IsScreenshare(content_type_)) {
-    EXPECT_METRIC_EQ(
-        kExpectedTimeInHdPercents,
-        metrics::MinSample(
-            "WebRTC.Video.Screenshare.TimeInBlockyVideoPercentage"));
-  } else {
-    EXPECT_METRIC_EQ(
-        kExpectedTimeInHdPercents,
-        metrics::MinSample("WebRTC.Video.TimeInBlockyVideoPercentage"));
-  }
-}
-
-TEST_P(ReceiveStatisticsProxyTestWithContent, DownscalesReported) {
-  const int kInterFrameDelayMs = 2000;  // To ensure long enough call duration.
-
-  webrtc::VideoFrame frame_hd = CreateFrame(1280, 720);
-  webrtc::VideoFrame frame_sd = CreateFrame(640, 360);
-  webrtc::VideoFrame frame_ld = CreateFrame(320, 180);
-
-  // Call once to pass content type.
-  statistics_proxy_->OnDecodedFrame(frame_hd, absl::nullopt, 0, content_type_);
-
-  statistics_proxy_->OnRenderedFrame(frame_hd);
-  fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-
-  // Downscale.
-  statistics_proxy_->OnRenderedFrame(frame_sd);
-  fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-
-  // Downscale.
-  statistics_proxy_->OnRenderedFrame(frame_ld);
-  fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  const int kExpectedDownscales = 30;  // 2 per 4 seconds = 30 per minute.
-  if (videocontenttypehelpers::IsScreenshare(content_type_)) {
-    EXPECT_METRIC_EQ(
-        kExpectedDownscales,
-        metrics::MinSample(
-            "WebRTC.Video.Screenshare.NumberResolutionDownswitchesPerMinute"));
-  } else {
-    EXPECT_METRIC_EQ(kExpectedDownscales,
-                     metrics::MinSample(
-                         "WebRTC.Video.NumberResolutionDownswitchesPerMinute"));
-  }
-}
-
-TEST_P(ReceiveStatisticsProxyTestWithContent, DecodeTimeReported) {
-  const int kInterFrameDelayMs = 20;
-  const int kLowQp = 30;
-  const int kDecodeMs = 7;
-
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  for (int i = 0; i < kMinRequiredSamples; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, kLowQp, kDecodeMs, content_type_);
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
-  }
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-  EXPECT_METRIC_EQ(
-      1, metrics::NumEvents("WebRTC.Video.DecodeTimeInMs", kDecodeMs));
-}
-
-TEST_P(ReceiveStatisticsProxyTestWithContent,
-       StatsAreSlicedOnSimulcastAndExperiment) {
-  const uint8_t experiment_id = 1;
-  webrtc::VideoContentType content_type = content_type_;
-  videocontenttypehelpers::SetExperimentId(&content_type, experiment_id);
-  const int kInterFrameDelayMs1 = 30;
-  const int kInterFrameDelayMs2 = 50;
-  webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
-
-  videocontenttypehelpers::SetSimulcastId(&content_type, 1);
-  for (int i = 0; i <= kMinRequiredSamples; ++i) {
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs1);
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type);
-  }
-
-  videocontenttypehelpers::SetSimulcastId(&content_type, 2);
-  for (int i = 0; i <= kMinRequiredSamples; ++i) {
-    fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs2);
-    statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, 0, content_type);
-  }
-  statistics_proxy_->UpdateHistograms(absl::nullopt, StreamDataCounters(),
-                                      nullptr);
-
-  if (videocontenttypehelpers::IsScreenshare(content_type)) {
-    EXPECT_METRIC_EQ(
-        1, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayInMs"));
-    EXPECT_METRIC_EQ(1, metrics::NumSamples(
-                            "WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
-    EXPECT_METRIC_EQ(1, metrics::NumSamples(
-                            "WebRTC.Video.Screenshare.InterframeDelayInMs.S0"));
-    EXPECT_METRIC_EQ(1,
-                     metrics::NumSamples(
-                         "WebRTC.Video.Screenshare.InterframeDelayMaxInMs.S0"));
-    EXPECT_METRIC_EQ(1, metrics::NumSamples(
-                            "WebRTC.Video.Screenshare.InterframeDelayInMs.S1"));
-    EXPECT_METRIC_EQ(1,
-                     metrics::NumSamples(
-                         "WebRTC.Video.Screenshare.InterframeDelayMaxInMs.S1"));
-    EXPECT_METRIC_EQ(
-        1, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayInMs"
-                               ".ExperimentGroup0"));
-    EXPECT_METRIC_EQ(
-        1, metrics::NumSamples("WebRTC.Video.Screenshare.InterframeDelayMaxInMs"
-                               ".ExperimentGroup0"));
-    EXPECT_METRIC_EQ(
-        kInterFrameDelayMs1,
-        metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs.S0"));
-    EXPECT_METRIC_EQ(
-        kInterFrameDelayMs2,
-        metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs.S1"));
-    EXPECT_METRIC_EQ(
-        (kInterFrameDelayMs1 + kInterFrameDelayMs2) / 2,
-        metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayInMs"));
-    EXPECT_METRIC_EQ(
-        kInterFrameDelayMs2,
-        metrics::MinSample("WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
-    EXPECT_METRIC_EQ(
-        (kInterFrameDelayMs1 + kInterFrameDelayMs2) / 2,
-        metrics::MinSample(
-            "WebRTC.Video.Screenshare.InterframeDelayInMs.ExperimentGroup0"));
-  } else {
-    EXPECT_METRIC_EQ(1,
-                     metrics::NumSamples("WebRTC.Video.InterframeDelayInMs"));
-    EXPECT_METRIC_EQ(
-        1, metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs"));
-    EXPECT_METRIC_EQ(
-        1, metrics::NumSamples("WebRTC.Video.InterframeDelayInMs.S0"));
-    EXPECT_METRIC_EQ(
-        1, metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs.S0"));
-    EXPECT_METRIC_EQ(
-        1, metrics::NumSamples("WebRTC.Video.InterframeDelayInMs.S1"));
-    EXPECT_METRIC_EQ(
-        1, metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs.S1"));
-    EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.InterframeDelayInMs"
-                                            ".ExperimentGroup0"));
-    EXPECT_METRIC_EQ(1,
-                     metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs"
-                                         ".ExperimentGroup0"));
-    EXPECT_METRIC_EQ(kInterFrameDelayMs1,
-                     metrics::MinSample("WebRTC.Video.InterframeDelayInMs.S0"));
-    EXPECT_METRIC_EQ(kInterFrameDelayMs2,
-                     metrics::MinSample("WebRTC.Video.InterframeDelayInMs.S1"));
-    EXPECT_METRIC_EQ((kInterFrameDelayMs1 + kInterFrameDelayMs2) / 2,
-                     metrics::MinSample("WebRTC.Video.InterframeDelayInMs"));
-    EXPECT_METRIC_EQ(kInterFrameDelayMs2,
-                     metrics::MinSample("WebRTC.Video.InterframeDelayMaxInMs"));
-    EXPECT_METRIC_EQ((kInterFrameDelayMs1 + kInterFrameDelayMs2) / 2,
-                     metrics::MinSample(
-                         "WebRTC.Video.InterframeDelayInMs.ExperimentGroup0"));
-  }
-}
-
-class ReceiveStatisticsProxyTestWithDecodeTimeHistograms
-    : public ::testing::WithParamInterface<
-          std::tuple<bool, int, int, int, VideoCodecType, std::string>>,
-      public ReceiveStatisticsProxyTest {
- public:
-  ReceiveStatisticsProxyTestWithDecodeTimeHistograms()
-      : ReceiveStatisticsProxyTest(
-            std::get<0>(GetParam())
-                ? "WebRTC-DecodeTimeHistogramsKillSwitch/Enabled/"
-                : "") {}
-
- protected:
-  const std::string kUmaPrefix = "WebRTC.Video.DecodeTimePerFrameInMs.";
-  const int expected_number_of_samples_ = {std::get<1>(GetParam())};
-  const int width_ = {std::get<2>(GetParam())};
-  const int height_ = {std::get<3>(GetParam())};
-  const VideoCodecType codec_type_ = {std::get<4>(GetParam())};
-  const std::string implementation_name_ = {std::get<5>(GetParam())};
-  const std::string uma_histogram_name_ =
-      kUmaPrefix + (codec_type_ == kVideoCodecVP9 ? "Vp9." : "H264.") +
-      (height_ == 2160 ? "4k." : "Hd.") +
-      (implementation_name_.compare("ExternalDecoder") == 0 ? "Hw" : "Sw");
-};
-
-TEST_P(ReceiveStatisticsProxyTestWithDecodeTimeHistograms,
-       DecodeTimeHistogramsUpdated) {
-  constexpr int kNumberOfFrames = 10;
-  constexpr int kDecodeTimeMs = 7;
-  constexpr int kFrameDurationMs = 1000 / 60;
-
-  webrtc::VideoFrame frame = CreateFrame(width_, height_);
-
-  statistics_proxy_->OnDecoderImplementationName(implementation_name_.c_str());
-  statistics_proxy_->OnPreDecode(codec_type_, /*qp=*/0);
-
-  for (int i = 0; i < kNumberOfFrames; ++i) {
-    statistics_proxy_->OnDecodedFrame(frame, /*qp=*/absl::nullopt,
-                                      kDecodeTimeMs,
-                                      VideoContentType::UNSPECIFIED);
-    fake_clock_.AdvanceTimeMilliseconds(kFrameDurationMs);
-  }
-
-  EXPECT_METRIC_EQ(expected_number_of_samples_,
-                   metrics::NumSamples(uma_histogram_name_));
-  EXPECT_METRIC_EQ(expected_number_of_samples_,
-                   metrics::NumEvents(uma_histogram_name_, kDecodeTimeMs));
-}
-
-const auto kVp94kHw = std::make_tuple(/*killswitch=*/false,
-                                      /*expected_number_of_samples=*/10,
-                                      /*width=*/3840,
-                                      /*height=*/2160,
-                                      kVideoCodecVP9,
-                                      /*implementation=*/"ExternalDecoder");
-const auto kVp94kSw = std::make_tuple(/*killswitch=*/false,
-                                      /*expected_number_of_samples=*/10,
-                                      /*width=*/3840,
-                                      /*height=*/2160,
-                                      kVideoCodecVP9,
-                                      /*implementation=*/"libvpx");
-const auto kVp9HdHw = std::make_tuple(/*killswitch=*/false,
-                                      /*expected_number_of_samples=*/10,
-                                      /*width=*/1920,
-                                      /*height=*/1080,
-                                      kVideoCodecVP9,
-                                      /*implementation=*/"ExternalDecoder");
-const auto kVp9HdSw = std::make_tuple(/*killswitch=*/false,
-                                      /*expected_number_of_samples=*/10,
-                                      /*width=*/1920,
-                                      /*height=*/1080,
-                                      kVideoCodecVP9,
-                                      /*implementation=*/"libvpx");
-const auto kH2644kHw = std::make_tuple(/*killswitch=*/false,
-                                       /*expected_number_of_samples=*/10,
-                                       /*width=*/3840,
-                                       /*height=*/2160,
-                                       kVideoCodecH264,
-                                       /*implementation=*/"ExternalDecoder");
-const auto kH2644kSw = std::make_tuple(/*killswitch=*/false,
-                                       /*expected_number_of_samples=*/10,
-                                       /*width=*/3840,
-                                       /*height=*/2160,
-                                       kVideoCodecH264,
-                                       /*implementation=*/"FFmpeg");
-const auto kH264HdHw = std::make_tuple(/*killswitch=*/false,
-                                       /*expected_number_of_samples=*/10,
-                                       /*width=*/1920,
-                                       /*height=*/1080,
-                                       kVideoCodecH264,
-                                       /*implementation=*/"ExternalDecoder");
-const auto kH264HdSw = std::make_tuple(/*killswitch=*/false,
-                                       /*expected_number_of_samples=*/10,
-                                       /*width=*/1920,
-                                       /*height=*/1080,
-                                       kVideoCodecH264,
-                                       /*implementation=*/"FFmpeg");
-
-INSTANTIATE_TEST_SUITE_P(AllHistogramsPopulated,
-                         ReceiveStatisticsProxyTestWithDecodeTimeHistograms,
-                         ::testing::Values(kVp94kHw,
-                                           kVp94kSw,
-                                           kVp9HdHw,
-                                           kVp9HdSw,
-                                           kH2644kHw,
-                                           kH2644kSw,
-                                           kH264HdHw,
-                                           kH264HdSw));
-
-const auto kKillswitchDisabled =
-    std::make_tuple(/*killswitch=*/false,
-                    /*expected_number_of_samples=*/10,
-                    /*width=*/1920,
-                    /*height=*/1080,
-                    kVideoCodecVP9,
-                    /*implementation=*/"libvpx");
-const auto kKillswitchEnabled =
-    std::make_tuple(/*killswitch=*/true,
-                    /*expected_number_of_samples=*/0,
-                    /*width=*/1920,
-                    /*height=*/1080,
-                    kVideoCodecVP9,
-                    /*implementation=*/"libvpx");
-
-INSTANTIATE_TEST_SUITE_P(KillswitchEffective,
-                         ReceiveStatisticsProxyTestWithDecodeTimeHistograms,
-                         ::testing::Values(kKillswitchDisabled,
-                                           kKillswitchEnabled));
-
-}  // namespace webrtc
diff --git a/video/video_quality_observer.cc b/video/video_quality_observer.cc
deleted file mode 100644
index be7b08c..0000000
--- a/video/video_quality_observer.cc
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- *  Copyright (c) 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 "video/video_quality_observer.h"
-
-#include <algorithm>
-#include <cmath>
-#include <cstdint>
-#include <string>
-
-#include "rtc_base/logging.h"
-#include "rtc_base/strings/string_builder.h"
-#include "system_wrappers/include/metrics.h"
-
-namespace webrtc {
-const uint32_t VideoQualityObserver::kMinFrameSamplesToDetectFreeze = 5;
-const uint32_t VideoQualityObserver::kMinIncreaseForFreezeMs = 150;
-const uint32_t VideoQualityObserver::kAvgInterframeDelaysWindowSizeFrames = 30;
-
-namespace {
-constexpr int kMinVideoDurationMs = 3000;
-constexpr int kMinRequiredSamples = 1;
-constexpr int kPixelsInHighResolution =
-    960 * 540;  // CPU-adapted HD still counts.
-constexpr int kPixelsInMediumResolution = 640 * 360;
-constexpr int kBlockyQpThresholdVp8 = 70;
-constexpr int kBlockyQpThresholdVp9 = 180;
-constexpr int kMaxNumCachedBlockyFrames = 100;
-// TODO(ilnik): Add H264/HEVC thresholds.
-}  // namespace
-
-VideoQualityObserver::VideoQualityObserver(VideoContentType content_type)
-    : last_frame_rendered_ms_(-1),
-      num_frames_rendered_(0),
-      first_frame_rendered_ms_(-1),
-      last_frame_pixels_(0),
-      is_last_frame_blocky_(false),
-      last_unfreeze_time_ms_(0),
-      render_interframe_delays_(kAvgInterframeDelaysWindowSizeFrames),
-      sum_squared_interframe_delays_secs_(0.0),
-      time_in_resolution_ms_(3, 0),
-      current_resolution_(Resolution::Low),
-      num_resolution_downgrades_(0),
-      time_in_blocky_video_ms_(0),
-      content_type_(content_type),
-      is_paused_(false) {}
-
-void VideoQualityObserver::UpdateHistograms() {
-  // Don't report anything on an empty video stream.
-  if (num_frames_rendered_ == 0) {
-    return;
-  }
-
-  char log_stream_buf[2 * 1024];
-  rtc::SimpleStringBuilder log_stream(log_stream_buf);
-
-  if (last_frame_rendered_ms_ > last_unfreeze_time_ms_) {
-    smooth_playback_durations_.Add(last_frame_rendered_ms_ -
-                                   last_unfreeze_time_ms_);
-  }
-
-  std::string uma_prefix = videocontenttypehelpers::IsScreenshare(content_type_)
-                               ? "WebRTC.Video.Screenshare"
-                               : "WebRTC.Video";
-
-  auto mean_time_between_freezes =
-      smooth_playback_durations_.Avg(kMinRequiredSamples);
-  if (mean_time_between_freezes) {
-    RTC_HISTOGRAM_COUNTS_SPARSE_100000(uma_prefix + ".MeanTimeBetweenFreezesMs",
-                                       *mean_time_between_freezes);
-    log_stream << uma_prefix << ".MeanTimeBetweenFreezesMs "
-               << *mean_time_between_freezes << "\n";
-  }
-  auto avg_freeze_length = freezes_durations_.Avg(kMinRequiredSamples);
-  if (avg_freeze_length) {
-    RTC_HISTOGRAM_COUNTS_SPARSE_100000(uma_prefix + ".MeanFreezeDurationMs",
-                                       *avg_freeze_length);
-    log_stream << uma_prefix << ".MeanFreezeDurationMs " << *avg_freeze_length
-               << "\n";
-  }
-
-  int64_t video_duration_ms =
-      last_frame_rendered_ms_ - first_frame_rendered_ms_;
-
-  if (video_duration_ms >= kMinVideoDurationMs) {
-    int time_spent_in_hd_percentage = static_cast<int>(
-        time_in_resolution_ms_[Resolution::High] * 100 / video_duration_ms);
-    RTC_HISTOGRAM_COUNTS_SPARSE_100(uma_prefix + ".TimeInHdPercentage",
-                                    time_spent_in_hd_percentage);
-    log_stream << uma_prefix << ".TimeInHdPercentage "
-               << time_spent_in_hd_percentage << "\n";
-
-    int time_with_blocky_video_percentage =
-        static_cast<int>(time_in_blocky_video_ms_ * 100 / video_duration_ms);
-    RTC_HISTOGRAM_COUNTS_SPARSE_100(uma_prefix + ".TimeInBlockyVideoPercentage",
-                                    time_with_blocky_video_percentage);
-    log_stream << uma_prefix << ".TimeInBlockyVideoPercentage "
-               << time_with_blocky_video_percentage << "\n";
-
-    int num_resolution_downgrades_per_minute =
-        num_resolution_downgrades_ * 60000 / video_duration_ms;
-    RTC_HISTOGRAM_COUNTS_SPARSE_100(
-        uma_prefix + ".NumberResolutionDownswitchesPerMinute",
-        num_resolution_downgrades_per_minute);
-    log_stream << uma_prefix << ".NumberResolutionDownswitchesPerMinute "
-               << num_resolution_downgrades_per_minute << "\n";
-
-    int num_freezes_per_minute =
-        freezes_durations_.NumSamples() * 60000 / video_duration_ms;
-    RTC_HISTOGRAM_COUNTS_SPARSE_100(uma_prefix + ".NumberFreezesPerMinute",
-                                    num_freezes_per_minute);
-    log_stream << uma_prefix << ".NumberFreezesPerMinute "
-               << num_freezes_per_minute << "\n";
-
-    if (sum_squared_interframe_delays_secs_ > 0.0) {
-      int harmonic_framerate_fps = std::round(
-          video_duration_ms / (1000 * sum_squared_interframe_delays_secs_));
-      RTC_HISTOGRAM_COUNTS_SPARSE_100(uma_prefix + ".HarmonicFrameRate",
-                                      harmonic_framerate_fps);
-      log_stream << uma_prefix << ".HarmonicFrameRate "
-                 << harmonic_framerate_fps << "\n";
-    }
-  }
-  RTC_LOG(LS_INFO) << log_stream.str();
-}
-
-void VideoQualityObserver::OnRenderedFrame(const VideoFrame& frame,
-                                           int64_t now_ms) {
-  RTC_DCHECK_LE(last_frame_rendered_ms_, now_ms);
-  RTC_DCHECK_LE(last_unfreeze_time_ms_, now_ms);
-
-  if (num_frames_rendered_ == 0) {
-    first_frame_rendered_ms_ = last_unfreeze_time_ms_ = now_ms;
-  }
-
-  auto blocky_frame_it = blocky_frames_.find(frame.timestamp());
-
-  if (num_frames_rendered_ > 0) {
-    // Process inter-frame delay.
-    const int64_t interframe_delay_ms = now_ms - last_frame_rendered_ms_;
-    const double interframe_delays_secs = interframe_delay_ms / 1000.0;
-
-    // Sum of squared inter frame intervals is used to calculate the harmonic
-    // frame rate metric. The metric aims to reflect overall experience related
-    // to smoothness of video playback and includes both freezes and pauses.
-    sum_squared_interframe_delays_secs_ +=
-        interframe_delays_secs * interframe_delays_secs;
-
-    if (!is_paused_) {
-      render_interframe_delays_.AddSample(interframe_delay_ms);
-
-      bool was_freeze = false;
-      if (render_interframe_delays_.Size() >= kMinFrameSamplesToDetectFreeze) {
-        const absl::optional<int64_t> avg_interframe_delay =
-            render_interframe_delays_.GetAverageRoundedDown();
-        RTC_DCHECK(avg_interframe_delay);
-        was_freeze = interframe_delay_ms >=
-                     std::max(3 * *avg_interframe_delay,
-                              *avg_interframe_delay + kMinIncreaseForFreezeMs);
-      }
-
-      if (was_freeze) {
-        freezes_durations_.Add(interframe_delay_ms);
-        smooth_playback_durations_.Add(last_frame_rendered_ms_ -
-                                       last_unfreeze_time_ms_);
-        last_unfreeze_time_ms_ = now_ms;
-      } else {
-        // Count spatial metrics if there were no freeze.
-        time_in_resolution_ms_[current_resolution_] += interframe_delay_ms;
-
-        if (is_last_frame_blocky_) {
-          time_in_blocky_video_ms_ += interframe_delay_ms;
-        }
-      }
-    }
-  }
-
-  if (is_paused_) {
-    // If the stream was paused since the previous frame, do not count the
-    // pause toward smooth playback. Explicitly count the part before it and
-    // start the new smooth playback interval from this frame.
-    is_paused_ = false;
-    if (last_frame_rendered_ms_ > last_unfreeze_time_ms_) {
-      smooth_playback_durations_.Add(last_frame_rendered_ms_ -
-                                     last_unfreeze_time_ms_);
-    }
-    last_unfreeze_time_ms_ = now_ms;
-
-    if (num_frames_rendered_ > 0) {
-      pauses_durations_.Add(now_ms - last_frame_rendered_ms_);
-    }
-  }
-
-  int64_t pixels = frame.width() * frame.height();
-  if (pixels >= kPixelsInHighResolution) {
-    current_resolution_ = Resolution::High;
-  } else if (pixels >= kPixelsInMediumResolution) {
-    current_resolution_ = Resolution::Medium;
-  } else {
-    current_resolution_ = Resolution::Low;
-  }
-
-  if (pixels < last_frame_pixels_) {
-    ++num_resolution_downgrades_;
-  }
-
-  last_frame_pixels_ = pixels;
-  last_frame_rendered_ms_ = now_ms;
-
-  is_last_frame_blocky_ = blocky_frame_it != blocky_frames_.end();
-  if (is_last_frame_blocky_) {
-    blocky_frames_.erase(blocky_frames_.begin(), ++blocky_frame_it);
-  }
-
-  ++num_frames_rendered_;
-}
-
-void VideoQualityObserver::OnDecodedFrame(const VideoFrame& frame,
-                                          absl::optional<uint8_t> qp,
-                                          VideoCodecType codec) {
-  if (qp) {
-    absl::optional<int> qp_blocky_threshold;
-    // TODO(ilnik): add other codec types when we have QP for them.
-    switch (codec) {
-      case kVideoCodecVP8:
-        qp_blocky_threshold = kBlockyQpThresholdVp8;
-        break;
-      case kVideoCodecVP9:
-        qp_blocky_threshold = kBlockyQpThresholdVp9;
-        break;
-      default:
-        qp_blocky_threshold = absl::nullopt;
-    }
-
-    RTC_DCHECK(blocky_frames_.find(frame.timestamp()) == blocky_frames_.end());
-
-    if (qp_blocky_threshold && *qp > *qp_blocky_threshold) {
-      // Cache blocky frame. Its duration will be calculated in render callback.
-      if (blocky_frames_.size() > kMaxNumCachedBlockyFrames) {
-        RTC_LOG(LS_WARNING) << "Overflow of blocky frames cache.";
-        blocky_frames_.erase(
-            blocky_frames_.begin(),
-            std::next(blocky_frames_.begin(), kMaxNumCachedBlockyFrames / 2));
-      }
-
-      blocky_frames_.insert(frame.timestamp());
-    }
-  }
-}
-
-void VideoQualityObserver::OnStreamInactive() {
-  is_paused_ = true;
-}
-
-uint32_t VideoQualityObserver::NumFreezes() const {
-  return freezes_durations_.NumSamples();
-}
-
-uint32_t VideoQualityObserver::NumPauses() const {
-  return pauses_durations_.NumSamples();
-}
-
-uint32_t VideoQualityObserver::TotalFreezesDurationMs() const {
-  return freezes_durations_.Sum(kMinRequiredSamples).value_or(0);
-}
-
-uint32_t VideoQualityObserver::TotalPausesDurationMs() const {
-  return pauses_durations_.Sum(kMinRequiredSamples).value_or(0);
-}
-
-uint32_t VideoQualityObserver::TotalFramesDurationMs() const {
-  return last_frame_rendered_ms_ - first_frame_rendered_ms_;
-}
-
-double VideoQualityObserver::SumSquaredFrameDurationsSec() const {
-  return sum_squared_interframe_delays_secs_;
-}
-
-}  // namespace webrtc
diff --git a/video/video_quality_observer.h b/video/video_quality_observer.h
deleted file mode 100644
index 6494a6f..0000000
--- a/video/video_quality_observer.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- *  Copyright (c) 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.
- */
-
-#ifndef VIDEO_VIDEO_QUALITY_OBSERVER_H_
-#define VIDEO_VIDEO_QUALITY_OBSERVER_H_
-
-#include <stdint.h>
-
-#include <set>
-#include <vector>
-
-#include "absl/types/optional.h"
-#include "api/video/video_codec_type.h"
-#include "api/video/video_content_type.h"
-#include "api/video/video_frame.h"
-#include "rtc_base/numerics/moving_average.h"
-#include "rtc_base/numerics/sample_counter.h"
-
-namespace webrtc {
-
-// Calculates spatial and temporal quality metrics and reports them to UMA
-// stats.
-class VideoQualityObserver {
- public:
-  // Use either VideoQualityObserver::kBlockyQpThresholdVp8 or
-  // VideoQualityObserver::kBlockyQpThresholdVp9.
-  explicit VideoQualityObserver(VideoContentType content_type);
-  ~VideoQualityObserver() = default;
-
-  void OnDecodedFrame(const VideoFrame& frame,
-                      absl::optional<uint8_t> qp,
-                      VideoCodecType codec);
-
-  void OnRenderedFrame(const VideoFrame& frame, int64_t now_ms);
-
-  void OnStreamInactive();
-
-  uint32_t NumFreezes() const;
-  uint32_t NumPauses() const;
-  uint32_t TotalFreezesDurationMs() const;
-  uint32_t TotalPausesDurationMs() const;
-  uint32_t TotalFramesDurationMs() const;
-  double SumSquaredFrameDurationsSec() const;
-
-  void UpdateHistograms();
-
-  static const uint32_t kMinFrameSamplesToDetectFreeze;
-  static const uint32_t kMinIncreaseForFreezeMs;
-  static const uint32_t kAvgInterframeDelaysWindowSizeFrames;
-
- private:
-  enum Resolution {
-    Low = 0,
-    Medium = 1,
-    High = 2,
-  };
-
-  int64_t last_frame_rendered_ms_;
-  int64_t num_frames_rendered_;
-  int64_t first_frame_rendered_ms_;
-  int64_t last_frame_pixels_;
-  bool is_last_frame_blocky_;
-  // Decoded timestamp of the last delayed frame.
-  int64_t last_unfreeze_time_ms_;
-  rtc::MovingAverage render_interframe_delays_;
-  double sum_squared_interframe_delays_secs_;
-  // An inter-frame delay is counted as a freeze if it's significantly longer
-  // than average inter-frame delay.
-  rtc::SampleCounter freezes_durations_;
-  rtc::SampleCounter pauses_durations_;
-  // Time between freezes.
-  rtc::SampleCounter smooth_playback_durations_;
-  // Counters for time spent in different resolutions. Time between each two
-  // Consecutive frames is counted to bin corresponding to the first frame
-  // resolution.
-  std::vector<int64_t> time_in_resolution_ms_;
-  // Resolution of the last decoded frame. Resolution enum is used as an index.
-  Resolution current_resolution_;
-  int num_resolution_downgrades_;
-  // Similar to resolution, time spent in high-QP video.
-  int64_t time_in_blocky_video_ms_;
-  // Content type of the last decoded frame.
-  VideoContentType content_type_;
-  bool is_paused_;
-
-  // Set of decoded frames with high QP value.
-  std::set<int64_t> blocky_frames_;
-};
-
-}  // namespace webrtc
-
-#endif  // VIDEO_VIDEO_QUALITY_OBSERVER_H_