summaryrefslogtreecommitdiff
path: root/chromium/chrome/renderer/lite_video
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/chrome/renderer/lite_video
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-85-based.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/chrome/renderer/lite_video')
-rw-r--r--chromium/chrome/renderer/lite_video/DEPS3
-rw-r--r--chromium/chrome/renderer/lite_video/OWNERS3
-rw-r--r--chromium/chrome/renderer/lite_video/lite_video_hint_agent.cc99
-rw-r--r--chromium/chrome/renderer/lite_video/lite_video_hint_agent.h94
-rw-r--r--chromium/chrome/renderer/lite_video/lite_video_hint_agent_browsertest.cc236
-rw-r--r--chromium/chrome/renderer/lite_video/lite_video_url_loader_throttle.cc121
-rw-r--r--chromium/chrome/renderer/lite_video/lite_video_url_loader_throttle.h56
-rw-r--r--chromium/chrome/renderer/lite_video/lite_video_util.cc17
-rw-r--r--chromium/chrome/renderer/lite_video/lite_video_util.h15
9 files changed, 644 insertions, 0 deletions
diff --git a/chromium/chrome/renderer/lite_video/DEPS b/chromium/chrome/renderer/lite_video/DEPS
new file mode 100644
index 00000000000..6511c3d7aac
--- /dev/null
+++ b/chromium/chrome/renderer/lite_video/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+"+services/network/test",
+]
diff --git a/chromium/chrome/renderer/lite_video/OWNERS b/chromium/chrome/renderer/lite_video/OWNERS
new file mode 100644
index 00000000000..d5e2286a680
--- /dev/null
+++ b/chromium/chrome/renderer/lite_video/OWNERS
@@ -0,0 +1,3 @@
+file://components/data_reduction_proxy/OWNERS
+
+# COMPONENT: Internal>Network>DataUse
diff --git a/chromium/chrome/renderer/lite_video/lite_video_hint_agent.cc b/chromium/chrome/renderer/lite_video/lite_video_hint_agent.cc
new file mode 100644
index 00000000000..4f4840c349e
--- /dev/null
+++ b/chromium/chrome/renderer/lite_video/lite_video_hint_agent.cc
@@ -0,0 +1,99 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/lite_video/lite_video_hint_agent.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "chrome/renderer/lite_video/lite_video_util.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+
+namespace lite_video {
+
+LiteVideoHintAgent::LiteVideoHintAgent(content::RenderFrame* render_frame)
+ : content::RenderFrameObserver(render_frame),
+ content::RenderFrameObserverTracker<LiteVideoHintAgent>(render_frame) {
+ DCHECK(render_frame);
+}
+
+LiteVideoHintAgent::~LiteVideoHintAgent() = default;
+
+void LiteVideoHintAgent::OnDestruct() {
+ delete this;
+}
+
+void LiteVideoHintAgent::AddThrottle(LiteVideoURLLoaderThrottle* throttle) {
+ DCHECK(HasLiteVideoHint());
+ active_throttles_.insert(throttle);
+ UMA_HISTOGRAM_COUNTS("LiteVideo.HintAgent.ActiveThrottleSize",
+ active_throttles_.size());
+}
+
+void LiteVideoHintAgent::RemoveThrottle(LiteVideoURLLoaderThrottle* throttle) {
+ active_throttles_.erase(throttle);
+}
+
+base::TimeDelta LiteVideoHintAgent::CalculateLatencyForResourceResponse(
+ const network::mojom::URLResponseHead& response_head) {
+ if (!HasLiteVideoHint())
+ return base::TimeDelta();
+
+ int64_t recv_bytes = response_head.content_length;
+ if (recv_bytes == -1)
+ recv_bytes = response_head.encoded_body_length;
+ if (recv_bytes == -1)
+ return base::TimeDelta();
+
+ if (kilobytes_buffered_before_throttle_ <
+ *kilobytes_to_buffer_before_throttle_) {
+ kilobytes_buffered_before_throttle_ += recv_bytes / 1024;
+ return base::TimeDelta();
+ }
+
+ // The total RTT for this media response should be based on how much time it
+ // took to transfer the packet in the target bandwidth, and the per RTT
+ // latency. For example, assuming 100KBPS target bandwidth and target RTT of 1
+ // second, an 400KB response should have total delay of 5 seconds
+ // (400/100 + 1).
+ auto delay_for_throttled_response =
+ base::TimeDelta::FromSecondsD(
+ recv_bytes / (*target_downlink_bandwidth_kbps_ * 1024.0)) +
+ *target_downlink_rtt_latency_;
+ auto response_delay =
+ response_head.response_time - response_head.request_time;
+ if (delay_for_throttled_response <= response_delay)
+ return base::TimeDelta();
+
+ return std::min(delay_for_throttled_response - response_delay,
+ *max_throttling_delay_);
+}
+
+bool LiteVideoHintAgent::HasLiteVideoHint() const {
+ return target_downlink_bandwidth_kbps_ && target_downlink_rtt_latency_ &&
+ kilobytes_to_buffer_before_throttle_ && max_throttling_delay_;
+}
+
+void LiteVideoHintAgent::SetLiteVideoHint(
+ blink::mojom::LiteVideoHintPtr lite_video_hint) {
+ if (!lite_video_hint)
+ return;
+ target_downlink_bandwidth_kbps_ =
+ lite_video_hint->target_downlink_bandwidth_kbps;
+ kilobytes_to_buffer_before_throttle_ =
+ lite_video_hint->kilobytes_to_buffer_before_throttle;
+ target_downlink_rtt_latency_ = lite_video_hint->target_downlink_rtt_latency;
+ max_throttling_delay_ = lite_video_hint->max_throttling_delay;
+ LOCAL_HISTOGRAM_BOOLEAN("LiteVideo.HintAgent.HasHint", true);
+}
+
+void LiteVideoHintAgent::StopThrottling() {
+ // TODO(rajendrant): Send the stop throttling signal to browser process, after
+ // some K rebuffer events had occurred.
+ DCHECK(HasLiteVideoHint());
+ for (auto* throttle : active_throttles_) {
+ throttle->ResumeIfThrottled();
+ }
+ kilobytes_buffered_before_throttle_ = 0;
+}
+
+} // namespace lite_video
diff --git a/chromium/chrome/renderer/lite_video/lite_video_hint_agent.h b/chromium/chrome/renderer/lite_video/lite_video_hint_agent.h
new file mode 100644
index 00000000000..023150bb979
--- /dev/null
+++ b/chromium/chrome/renderer/lite_video/lite_video_hint_agent.h
@@ -0,0 +1,94 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_RENDERER_LITE_VIDEO_LITE_VIDEO_HINT_AGENT_H_
+#define CHROME_RENDERER_LITE_VIDEO_LITE_VIDEO_HINT_AGENT_H_
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "chrome/renderer/lite_video/lite_video_url_loader_throttle.h"
+#include "content/public/renderer/render_frame_observer.h"
+#include "content/public/renderer/render_frame_observer_tracker.h"
+#include "third_party/blink/public/mojom/loader/previews_resource_loading_hints.mojom.h"
+#include "url/gurl.h"
+
+namespace lite_video {
+
+// The renderer-side agent for LiteVideos. There is one instance per frame (main
+// frame and subframes), to receive LiteVideo throttling parameters from
+// browser.
+class LiteVideoHintAgent
+ : public content::RenderFrameObserver,
+ public content::RenderFrameObserverTracker<LiteVideoHintAgent> {
+ public:
+ explicit LiteVideoHintAgent(content::RenderFrame* render_frame);
+ ~LiteVideoHintAgent() override;
+
+ LiteVideoHintAgent(const LiteVideoHintAgent&) = delete;
+ LiteVideoHintAgent& operator=(const LiteVideoHintAgent&) = delete;
+
+ // Returns how much time the media response should get throttled. This is the
+ // difference between the target latency based on target bandwidth, RTT, and
+ // the latency the response has already spent. Empty duration is returned when
+ // the response should not be throttled. The first
+ // |kilobytes_buffered_before_throttle_| for this render frame should not be
+ // throttled. This function also updates
+ // |kilobytes_buffered_before_throttle_|.
+ base::TimeDelta CalculateLatencyForResourceResponse(
+ const network::mojom::URLResponseHead& response_head);
+
+ // Updates the LiteVideo throttling parameters for calculating
+ // the latency to add to media requests.
+ void SetLiteVideoHint(blink::mojom::LiteVideoHintPtr lite_video_hint);
+
+ // Returns whether |this| has been provided a LiteVideoHint and
+ // has the parameters needed for calculating the throttling latency.
+ bool HasLiteVideoHint() const;
+
+ void AddThrottle(LiteVideoURLLoaderThrottle* throttle);
+ void RemoveThrottle(LiteVideoURLLoaderThrottle* throttle);
+
+ const std::set<LiteVideoURLLoaderThrottle*>& GetActiveThrottlesForTesting()
+ const {
+ return active_throttles_;
+ }
+
+ // Stop throttling and resume the current throttled media requests
+ // immediately. Throttling could start again for new requests
+ void StopThrottling();
+
+ private:
+ friend class LiteVideoHintAgentTest;
+
+ // content::RenderFrameObserver overrides
+ void OnDestruct() override;
+
+ // The network downlink bandwidth target in kilobytes per second used to
+ // calculate the throttling delay on media requests
+ base::Optional<int> target_downlink_bandwidth_kbps_;
+
+ // The network downlink rtt target latency used to calculate the
+ // throttling delay on media requests
+ base::Optional<base::TimeDelta> target_downlink_rtt_latency_;
+
+ // The number of kilobytes for media to be observed before starting to
+ // throttle requests.
+ base::Optional<int> kilobytes_to_buffer_before_throttle_;
+
+ // The maximum delay a throttle can introduce for a media request in
+ // milliseconds.
+ base::Optional<base::TimeDelta> max_throttling_delay_;
+
+ // The number of media KB that have been left unthrottled before starting
+ // to introduce a throttling delay.
+ int kilobytes_buffered_before_throttle_ = 0;
+
+ // Set of media requests that are throttled currently. These are maintained
+ // here to resume them immediately upon StopThrottling()
+ std::set<LiteVideoURLLoaderThrottle*> active_throttles_;
+};
+
+} // namespace lite_video
+
+#endif // CHROME_RENDERER_LITE_VIDEO_LITE_VIDEO_HINT_AGENT_H_
diff --git a/chromium/chrome/renderer/lite_video/lite_video_hint_agent_browsertest.cc b/chromium/chrome/renderer/lite_video/lite_video_hint_agent_browsertest.cc
new file mode 100644
index 00000000000..b22f60d9b5d
--- /dev/null
+++ b/chromium/chrome/renderer/lite_video/lite_video_hint_agent_browsertest.cc
@@ -0,0 +1,236 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/lite_video/lite_video_hint_agent.h"
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/common/chrome_features.h"
+#include "chrome/renderer/lite_video/lite_video_url_loader_throttle.h"
+#include "chrome/test/base/chrome_render_view_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_view.h"
+#include "services/network/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/web_network_state_notifier.h"
+
+namespace lite_video {
+
+namespace {
+constexpr char kTestURL[] = "https://litevideo.test.com";
+
+}
+
+// Encapsulates the media URLLoader throttle, its delegate, and maintains the
+// current throttling state.
+class MediaLoaderThrottleInfo : public blink::URLLoaderThrottle::Delegate {
+ public:
+ explicit MediaLoaderThrottleInfo(
+ std::unique_ptr<LiteVideoURLLoaderThrottle> throttle)
+ : throttle_(std::move(throttle)) {
+ throttle_->set_delegate(this);
+ }
+
+ void SendResponse(network::mojom::URLResponseHead* response_head) {
+ throttle_->WillProcessResponse(GURL(kTestURL), response_head,
+ &is_throttled_);
+ }
+
+ // Implements blink::URLLoaderThrottle::Delegate.
+ void CancelWithError(int error_code,
+ base::StringPiece custom_reason) override {
+ NOTIMPLEMENTED();
+ }
+ void Resume() override {
+ ASSERT_TRUE(is_throttled_);
+ is_throttled_ = false;
+ }
+
+ bool is_throttled() { return is_throttled_; }
+
+ private:
+ // Current throttling state.
+ bool is_throttled_ = false;
+
+ std::unique_ptr<LiteVideoURLLoaderThrottle> throttle_;
+};
+
+class LiteVideoHintAgentTest : public ChromeRenderViewTest {
+ public:
+ void DisableLiteVideoFeature() {
+ scoped_feature_list_.Reset();
+ scoped_feature_list_.InitAndDisableFeature(features::kLiteVideo);
+ }
+
+ std::unique_ptr<LiteVideoURLLoaderThrottle> CreateLiteVideoURLLoaderThrottle(
+ blink::mojom::RequestContextType request_context_type) {
+ blink::WebURLRequest request;
+ request.SetUrl(GURL(kTestURL));
+ request.SetRequestContext(request_context_type);
+ return LiteVideoURLLoaderThrottle::MaybeCreateThrottle(
+ request, view_->GetMainRenderFrame()->GetRoutingID());
+ }
+
+ std::unique_ptr<MediaLoaderThrottleInfo> CreateThrottleAndSendResponse(
+ net::HttpStatusCode response_code,
+ const std::string& mime_type,
+ int content_length) {
+ auto throttle_info = std::make_unique<MediaLoaderThrottleInfo>(
+ CreateLiteVideoURLLoaderThrottle(
+ blink::mojom::RequestContextType::FETCH));
+ network::mojom::URLResponseHeadPtr response_head =
+ network::CreateURLResponseHead(response_code);
+ response_head->mime_type = mime_type;
+ response_head->mime_type = mime_type;
+ response_head->content_length = content_length;
+ response_head->network_accessed = true;
+ response_head->was_fetched_via_cache = false;
+
+ throttle_info->SendResponse(response_head.get());
+ return throttle_info;
+ }
+
+ const std::set<LiteVideoURLLoaderThrottle*>& GetActiveThrottledResponses()
+ const {
+ return lite_video_hint_agent_->GetActiveThrottlesForTesting();
+ }
+
+ const base::HistogramTester& histogram_tester() { return histogram_tester_; }
+
+ void StopThrottling() { lite_video_hint_agent_->StopThrottling(); }
+
+ protected:
+ void SetUp() override {
+ ChromeRenderViewTest::SetUp();
+ scoped_feature_list_.InitAndEnableFeature(features::kLiteVideo);
+ blink::WebNetworkStateNotifier::SetSaveDataEnabled(true);
+ lite_video_hint_agent_ =
+ new LiteVideoHintAgent(view_->GetMainRenderFrame());
+
+ // Set some default hints.
+ blink::mojom::LiteVideoHintPtr hint = blink::mojom::LiteVideoHint::New();
+ hint->kilobytes_to_buffer_before_throttle = 10;
+ hint->target_downlink_bandwidth_kbps = 60;
+ hint->target_downlink_rtt_latency = base::TimeDelta::FromMilliseconds(500);
+ hint->max_throttling_delay = base::TimeDelta::FromSeconds(5);
+ lite_video_hint_agent_->SetLiteVideoHint(std::move(hint));
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+
+ base::HistogramTester histogram_tester_;
+
+ // Owned by the RenderFrame.
+ LiteVideoHintAgent* lite_video_hint_agent_;
+};
+
+TEST_F(LiteVideoHintAgentTest, LiteVideoDisabled) {
+ DisableLiteVideoFeature();
+ EXPECT_FALSE(CreateLiteVideoURLLoaderThrottle(
+ blink::mojom::RequestContextType::FETCH));
+}
+
+TEST_F(LiteVideoHintAgentTest, SaveDataDisabled) {
+ blink::WebNetworkStateNotifier::SetSaveDataEnabled(false);
+ EXPECT_FALSE(CreateLiteVideoURLLoaderThrottle(
+ blink::mojom::RequestContextType::FETCH));
+}
+
+TEST_F(LiteVideoHintAgentTest, OnlyFetchAPIResponseThrottled) {
+ EXPECT_FALSE(CreateLiteVideoURLLoaderThrottle(
+ blink::mojom::RequestContextType::IMAGE));
+}
+
+TEST_F(LiteVideoHintAgentTest, OnlyMediaMimeTypeThrottled) {
+ histogram_tester().ExpectUniqueSample("LiteVideo.HintAgent.HasHint", true, 1);
+
+ auto throttle_info =
+ CreateThrottleAndSendResponse(net::HTTP_OK, "image/jpeg", 11000);
+ EXPECT_FALSE(throttle_info->is_throttled());
+
+ throttle_info =
+ CreateThrottleAndSendResponse(net::HTTP_OK, "image/jpeg", 11000);
+ EXPECT_FALSE(throttle_info->is_throttled());
+ histogram_tester().ExpectTotalCount("LiteVideo.URLLoader.ThrottleLatency", 0);
+}
+
+TEST_F(LiteVideoHintAgentTest, FailedMediaResponseNotThrottled) {
+ histogram_tester().ExpectUniqueSample("LiteVideo.HintAgent.HasHint", true, 1);
+
+ auto throttle_info = CreateThrottleAndSendResponse(
+ net::HTTP_INTERNAL_SERVER_ERROR, "video/mp4", 11000);
+ EXPECT_FALSE(throttle_info->is_throttled());
+
+ throttle_info = CreateThrottleAndSendResponse(net::HTTP_INTERNAL_SERVER_ERROR,
+ "video/mp4", 11000);
+ EXPECT_FALSE(throttle_info->is_throttled());
+ histogram_tester().ExpectTotalCount("LiteVideo.URLLoader.ThrottleLatency", 0);
+}
+
+TEST_F(LiteVideoHintAgentTest, MediaResponseThrottled) {
+ histogram_tester().ExpectUniqueSample("LiteVideo.HintAgent.HasHint", true, 1);
+
+ // Initial k media bytes will not be throttled.
+ auto throttle_info =
+ CreateThrottleAndSendResponse(net::HTTP_OK, "video/mp4", 11000);
+ EXPECT_FALSE(throttle_info->is_throttled());
+ histogram_tester().ExpectTotalCount("LiteVideo.URLLoader.ThrottleLatency", 0);
+ EXPECT_TRUE(GetActiveThrottledResponses().empty());
+
+ // Verify if a response gets throttled and eventually resumed.
+ throttle_info =
+ CreateThrottleAndSendResponse(net::HTTP_OK, "video/mp4", 440000);
+ histogram_tester().ExpectTotalCount("LiteVideo.URLLoader.ThrottleLatency", 1);
+ EXPECT_TRUE(throttle_info->is_throttled());
+ // This is to wait until the throttle resumes, cannot fast-forward in
+ // RenderViewTest.
+ while (throttle_info->is_throttled())
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(throttle_info->is_throttled());
+
+ // Verify a response that wasn't yet resumed, gets cleared from hint agent
+ // when its destroyed.
+ throttle_info =
+ CreateThrottleAndSendResponse(net::HTTP_OK, "video/mp4", 440000);
+ EXPECT_TRUE(throttle_info->is_throttled());
+ histogram_tester().ExpectTotalCount("LiteVideo.URLLoader.ThrottleLatency", 2);
+
+ EXPECT_FALSE(GetActiveThrottledResponses().empty());
+ throttle_info.reset();
+ EXPECT_TRUE(GetActiveThrottledResponses().empty());
+}
+
+TEST_F(LiteVideoHintAgentTest, StopThrottlingResumesResponsesImmediately) {
+ histogram_tester().ExpectUniqueSample("LiteVideo.HintAgent.HasHint", true, 1);
+
+ // Initial response is not throttled, and the next two are throttled.
+ auto throttle_info1 =
+ CreateThrottleAndSendResponse(net::HTTP_OK, "video/mp4", 11000);
+ auto throttle_info2 =
+ CreateThrottleAndSendResponse(net::HTTP_OK, "video/mp4", 11000);
+ auto throttle_info3 =
+ CreateThrottleAndSendResponse(net::HTTP_OK, "video/mp4", 11000);
+ EXPECT_FALSE(throttle_info1->is_throttled());
+ EXPECT_TRUE(throttle_info2->is_throttled());
+ EXPECT_TRUE(throttle_info3->is_throttled());
+ histogram_tester().ExpectTotalCount("LiteVideo.URLLoader.ThrottleLatency", 2);
+ EXPECT_EQ(2U, GetActiveThrottledResponses().size());
+
+ // Stop throttling will immediately resume.
+ StopThrottling();
+ EXPECT_FALSE(throttle_info2->is_throttled());
+ EXPECT_FALSE(throttle_info3->is_throttled());
+
+ // When the throttle destroys it should get removed from active throttles.
+ throttle_info2.reset();
+ throttle_info3.reset();
+ EXPECT_TRUE(GetActiveThrottledResponses().empty());
+}
+
+} // namespace lite_video
diff --git a/chromium/chrome/renderer/lite_video/lite_video_url_loader_throttle.cc b/chromium/chrome/renderer/lite_video/lite_video_url_loader_throttle.cc
new file mode 100644
index 00000000000..acde3638f64
--- /dev/null
+++ b/chromium/chrome/renderer/lite_video/lite_video_url_loader_throttle.cc
@@ -0,0 +1,121 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/lite_video/lite_video_url_loader_throttle.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "chrome/renderer/lite_video/lite_video_hint_agent.h"
+#include "chrome/renderer/lite_video/lite_video_util.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_thread.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+
+namespace lite_video {
+
+LiteVideoHintAgent* GetLiteVideoHintAgent(int render_frame_id) {
+ DCHECK_NE(MSG_ROUTING_NONE, render_frame_id);
+ if (auto* render_frame =
+ content::RenderFrame::FromRoutingID(render_frame_id)) {
+ return LiteVideoHintAgent::Get(render_frame);
+ }
+ return nullptr;
+}
+
+// static
+std::unique_ptr<LiteVideoURLLoaderThrottle>
+LiteVideoURLLoaderThrottle::MaybeCreateThrottle(
+ const blink::WebURLRequest& request,
+ int render_frame_id) {
+ auto request_context = request.GetRequestContext();
+ if (request_context != blink::mojom::RequestContextType::FETCH &&
+ request_context != blink::mojom::RequestContextType::XML_HTTP_REQUEST) {
+ return nullptr;
+ }
+ // TODO(rajendrant): Also allow the throttle to be stopped when LiteMode gets
+ // disabled or ECT worsens. This logic should probably be in the browser
+ // process.
+ if (!IsLiteVideoEnabled())
+ return nullptr;
+
+ auto* lite_video_hint_agent = GetLiteVideoHintAgent(render_frame_id);
+ if (lite_video_hint_agent && lite_video_hint_agent->HasLiteVideoHint())
+ return std::make_unique<LiteVideoURLLoaderThrottle>(render_frame_id);
+
+ return nullptr;
+}
+
+LiteVideoURLLoaderThrottle::LiteVideoURLLoaderThrottle(int render_frame_id)
+ : render_frame_id_(render_frame_id) {
+ DCHECK(IsLiteVideoEnabled());
+}
+
+LiteVideoURLLoaderThrottle::~LiteVideoURLLoaderThrottle() {
+ // Existence of |response_delay_timer_| indicates throttling has been
+ // attempted on this media response. Remove the throttle on this case.
+ if (response_delay_timer_) {
+ DCHECK(render_frame_id_);
+ auto* lite_video_hint_agent = GetLiteVideoHintAgent(render_frame_id_);
+ if (lite_video_hint_agent)
+ lite_video_hint_agent->RemoveThrottle(this);
+ }
+}
+
+void LiteVideoURLLoaderThrottle::WillProcessResponse(
+ const GURL& response_url,
+ network::mojom::URLResponseHead* response_head,
+ bool* defer) {
+ if (!response_head || !response_head->headers)
+ return;
+ // Do not throttle on 4xx, 5xx failures.
+ if (response_head->headers->response_code() != 200)
+ return;
+ if (!response_head->network_accessed ||
+ response_head->was_fetched_via_cache) {
+ return;
+ }
+ if (!base::StartsWith(response_head->mime_type, "video/",
+ base::CompareCase::SENSITIVE)) {
+ return;
+ }
+
+ auto* lite_video_hint_agent = GetLiteVideoHintAgent(render_frame_id_);
+ if (!lite_video_hint_agent)
+ return;
+
+ auto latency = lite_video_hint_agent->CalculateLatencyForResourceResponse(
+ *response_head);
+ if (latency.is_zero())
+ return;
+
+ UMA_HISTOGRAM_TIMES("LiteVideo.URLLoader.ThrottleLatency", latency);
+
+ *defer = true;
+ // The timer may have already started and running, and the below restart will
+ // lose that elapsed time. However the elapsed time will be small since this
+ // case happens if some other url loader throttle is restarting the request.
+ response_delay_timer_ = std::make_unique<base::OneShotTimer>();
+ response_delay_timer_->Start(
+ FROM_HERE, latency,
+ base::BindOnce(&LiteVideoURLLoaderThrottle::ResumeThrottledMediaResponse,
+ base::Unretained(this)));
+
+ lite_video_hint_agent->AddThrottle(this);
+}
+
+void LiteVideoURLLoaderThrottle::ResumeIfThrottled() {
+ if (response_delay_timer_ && response_delay_timer_->IsRunning()) {
+ response_delay_timer_->Stop();
+ ResumeThrottledMediaResponse();
+ }
+}
+
+void LiteVideoURLLoaderThrottle::ResumeThrottledMediaResponse() {
+ DCHECK(!response_delay_timer_->IsRunning());
+ delegate_->Resume();
+}
+
+void LiteVideoURLLoaderThrottle::DetachFromCurrentSequence() {}
+
+} // namespace lite_video
diff --git a/chromium/chrome/renderer/lite_video/lite_video_url_loader_throttle.h b/chromium/chrome/renderer/lite_video/lite_video_url_loader_throttle.h
new file mode 100644
index 00000000000..ec353aa16c4
--- /dev/null
+++ b/chromium/chrome/renderer/lite_video/lite_video_url_loader_throttle.h
@@ -0,0 +1,56 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_RENDERER_LITE_VIDEO_LITE_VIDEO_URL_LOADER_THROTTLE_H_
+#define CHROME_RENDERER_LITE_VIDEO_LITE_VIDEO_URL_LOADER_THROTTLE_H_
+
+#include "base/callback.h"
+#include "base/timer/timer.h"
+#include "third_party/blink/public/common/loader/url_loader_throttle.h"
+
+namespace blink {
+class WebURLRequest;
+} // namespace blink
+
+namespace lite_video {
+
+// This class throttles media url requests that have audio/video mime-type in
+// response headers, to simulate low bandwidth conditions. This allows MSE video
+// players to adapt and play the lower resolution videos.
+class LiteVideoURLLoaderThrottle : public blink::URLLoaderThrottle {
+ public:
+ explicit LiteVideoURLLoaderThrottle(int render_frame_id);
+ ~LiteVideoURLLoaderThrottle() override;
+
+ // Creates throttle for |request| if LiteVideo is enabled for LiteMode users,
+ // and LiteVideoHintAgent has received hints for the navigation. Throttle will
+ // be created only for Fetch/XHR requests.
+ static std::unique_ptr<LiteVideoURLLoaderThrottle> MaybeCreateThrottle(
+ const blink::WebURLRequest& request,
+ int render_frame_id);
+
+ // Resumes the media response if it was currently throttled. Otherwise its a
+ // no-op.
+ void ResumeIfThrottled();
+
+ // blink::URLLoaderThrottle:
+ void WillProcessResponse(const GURL& response_url,
+ network::mojom::URLResponseHead* response_head,
+ bool* defer) override;
+ void DetachFromCurrentSequence() override;
+
+ private:
+ // Resumes the media response immediately.
+ void ResumeThrottledMediaResponse();
+
+ // Render frame id to get the media throttle observer of the render frame.
+ const int render_frame_id_;
+
+ // Timer to introduce latency for the response.
+ std::unique_ptr<base::OneShotTimer> response_delay_timer_;
+};
+
+} // namespace lite_video
+
+#endif // CHROME_RENDERER_LITE_VIDEO_LITE_VIDEO_URL_LOADER_THROTTLE_H_
diff --git a/chromium/chrome/renderer/lite_video/lite_video_util.cc b/chromium/chrome/renderer/lite_video/lite_video_util.cc
new file mode 100644
index 00000000000..69c483cb1a1
--- /dev/null
+++ b/chromium/chrome/renderer/lite_video/lite_video_util.cc
@@ -0,0 +1,17 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/lite_video/lite_video_util.h"
+
+#include "chrome/common/chrome_features.h"
+#include "third_party/blink/public/platform/web_network_state_notifier.h"
+
+namespace lite_video {
+
+bool IsLiteVideoEnabled() {
+ return base::FeatureList::IsEnabled(features::kLiteVideo) &&
+ blink::WebNetworkStateNotifier::SaveDataEnabled();
+}
+
+} // namespace lite_video
diff --git a/chromium/chrome/renderer/lite_video/lite_video_util.h b/chromium/chrome/renderer/lite_video/lite_video_util.h
new file mode 100644
index 00000000000..35c4603be9d
--- /dev/null
+++ b/chromium/chrome/renderer/lite_video/lite_video_util.h
@@ -0,0 +1,15 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_RENDERER_LITE_VIDEO_LITE_VIDEO_UTIL_H_
+#define CHROME_RENDERER_LITE_VIDEO_LITE_VIDEO_UTIL_H_
+
+namespace lite_video {
+
+// Returns whether LiteVideo is enabled.
+bool IsLiteVideoEnabled();
+
+} // namespace lite_video
+
+#endif // CHROME_RENDERER_LITE_VIDEO_LITE_VIDEO_UTIL_H_