Commit 680c2483 authored by Sharon Yang's avatar Sharon Yang Committed by Commit Bot

[fuchsia] Add media load blocking support to WebEngine

Implement media load blocking in WebEngine, using logic in
components/media_control.

WebEngineIntegrationTest

Test: Add BlockMediaPlaybackUnblocked and BlockMediaPlaybackBlocked to
Bug: 1057860
Change-Id: I055d170fc942b2f88598e95605a9886fea413026
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2131210Reviewed-by: default avatarYuchen Liu <yucliu@chromium.org>
Reviewed-by: default avatarDavid Dorwin <ddorwin@chromium.org>
Commit-Queue: Sharon Yang <yangsharon@chromium.org>
Cr-Commit-Position: refs/heads/master@{#760104}
parent 100210c4
......@@ -48,4 +48,10 @@ base::Optional<base::Value> ExecuteJavaScript(fuchsia::web::Frame* frame,
return base::JSONReader::Read(result_json);
}
fuchsia::web::LoadUrlParams CreateLoadUrlParamsWithUserActivation() {
fuchsia::web::LoadUrlParams load_url_params;
load_url_params.set_was_user_activated(true);
return load_url_params;
}
} // namespace cr_fuchsia
......@@ -26,6 +26,11 @@ bool LoadUrlAndExpectResponse(
base::Optional<base::Value> ExecuteJavaScript(fuchsia::web::Frame* frame,
base::StringPiece script);
// Creates and returns a LoadUrlParams with was_user_activated set to true.
// This allows user actions to propagate to the frame, allowing features such as
// autoplay to be used, which is used by many media tests.
fuchsia::web::LoadUrlParams CreateLoadUrlParamsWithUserActivation();
} // namespace cr_fuchsia
#endif // FUCHSIA_BASE_FRAME_TEST_UTIL_H_
......@@ -75,6 +75,8 @@ component("web_engine_core") {
"//base:base_static",
"//base/util/memory_pressure",
"//components/cdm/renderer",
"//components/media_control/browser",
"//components/media_control/renderer",
"//components/version_info",
"//content/public/app:both",
"//content/public/browser",
......
......@@ -2,6 +2,7 @@ include_rules = [
"+cc/base/switches.h",
"+components/version_info",
"+components/viz/common",
"+components/media_control",
"+content/public/app",
"+gpu/command_buffer/service",
"+gpu/config/gpu_finch_features.h",
......
......@@ -300,7 +300,8 @@ FrameImpl::FrameImpl(std::unique_ptr<content::WebContents> web_contents,
navigation_controller_(web_contents_.get()),
log_level_(kLogSeverityNone),
url_request_rewrite_rules_manager_(web_contents_.get()),
binding_(this, std::move(frame_request)) {
binding_(this, std::move(frame_request)),
media_blocker_(web_contents_.get()) {
DCHECK(!WebContentsToFrameImplMap()[web_contents_.get()]);
WebContentsToFrameImplMap()[web_contents_.get()] = this;
......@@ -889,6 +890,10 @@ void FrameImpl::CloseContents(content::WebContents* source) {
context_->DestroyFrame(this);
}
void FrameImpl::SetBlockMediaLoading(bool blocked) {
media_blocker_.BlockMediaLoading(blocked);
}
bool FrameImpl::DidAddMessageToConsole(
content::WebContents* source,
blink::mojom::ConsoleMessageLevel log_level,
......
......@@ -18,6 +18,7 @@
#include "base/macros.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "components/media_control/browser/media_blocker.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "fuchsia/engine/browser/accessibility_bridge.h"
......@@ -179,6 +180,7 @@ class FrameImpl : public fuchsia::web::Frame,
void SetPermissionState(fuchsia::web::PermissionDescriptor permission,
std::string web_origin,
fuchsia::web::PermissionState state) override;
void SetBlockMediaLoading(bool blocked) override;
// content::WebContentsDelegate implementation.
void CloseContents(content::WebContents* source) override;
......@@ -255,6 +257,7 @@ class FrameImpl : public fuchsia::web::Frame,
gfx::Size render_size_override_;
fidl::Binding<fuchsia::web::Frame> binding_;
media_control::MediaBlocker media_blocker_;
};
#endif // FUCHSIA_ENGINE_BROWSER_FRAME_IMPL_H_
......@@ -7,6 +7,7 @@
#include "base/feature_list.h"
#include "base/macros.h"
#include "components/cdm/renderer/widevine_key_system_properties.h"
#include "components/media_control/renderer/media_playback_options.h"
#include "content/public/renderer/render_frame.h"
#include "fuchsia/engine/renderer/on_load_script_injector.h"
#include "fuchsia/engine/renderer/web_engine_url_loader_throttle_provider.h"
......@@ -136,6 +137,9 @@ void WebEngineContentRendererClient::RenderFrameCreated(
auto iter = url_request_receivers_by_id_.emplace(render_frame_id,
std::move(rules_receiver));
DCHECK(iter.second);
// Lifetime is tied to |render_frame| via content::RenderFrameObserver.
new media_control::MediaPlaybackOptions(render_frame);
}
std::unique_ptr<content::URLLoaderThrottleProvider>
......@@ -221,3 +225,21 @@ bool WebEngineContentRendererClient::IsSupportedVideoType(
return IsSupportedHardwareVideoCodec(type);
}
// TODO(crbug.com/1067435): Look into the ChromiumContentRendererClient version
// of this method and how it may apply here.
bool WebEngineContentRendererClient::DeferMediaLoad(
content::RenderFrame* render_frame,
bool has_played_media_before,
base::OnceClosure closure) {
return RunClosureWhenInForeground(render_frame, std::move(closure));
}
bool WebEngineContentRendererClient::RunClosureWhenInForeground(
content::RenderFrame* render_frame,
base::OnceClosure closure) {
auto* playback_options =
media_control::MediaPlaybackOptions::Get(render_frame);
DCHECK(playback_options);
return playback_options->RunWhenInForeground(std::move(closure));
}
......@@ -32,6 +32,12 @@ class WebEngineContentRendererClient : public content::ContentRendererClient {
std::unique_ptr<content::URLLoaderThrottleProvider>
CreateURLLoaderThrottleProvider(
content::URLLoaderThrottleProviderType type) override;
bool DeferMediaLoad(content::RenderFrame* render_frame,
bool has_played_media_before,
base::OnceClosure closure) override;
bool RunClosureWhenInForeground(content::RenderFrame* render_frame,
base::OnceClosure closure);
// Map of rules receivers per RenderFrame ID.
std::map<int, std::unique_ptr<UrlRequestRulesReceiver>>
......
......@@ -4,7 +4,7 @@
.then(() => {
if (!haveAccess) {
throw "getUserMedia() succeeded when the page doesn't have " +
"micriphone access";
"microphone access";
}
})
.catch((e) => {
......
<html>
<head><title>initial title</title></head>
<body>
<script>
var bear = document.createElement('video');
var isMetadataLoaded = false;
var autoplay = (window.location.href.indexOf("autoplay") > 0);
if (autoplay) {
bear.autoplay = true;
}
bear.onerror = function() { document.title = 'error'; }
bear.onloadeddata = function() { document.title = 'loaded'; }
bear.onloadedmetadata = function() { isMetadataLoaded = true; }
bear.onpause = function () { isPlaying = false; }
bear.onplay = function() { document.title = 'playing'; }
bear.onstalled = function() { document.title = 'stalled'; }
bear.src = 'bear-vp8a.webm';
</script>
</body>
......
......@@ -163,6 +163,18 @@ class WebEngineIntegrationTest : public testing::Test {
return value ? value->GetString() : std::string();
}
double ExecuteJavaScriptWithDoubleResult(base::StringPiece script) {
base::Optional<base::Value> value =
cr_fuchsia::ExecuteJavaScript(frame_.get(), script);
return value ? value->GetDouble() : 0.0;
}
bool ExecuteJavaScriptWithBoolResult(base::StringPiece script) {
base::Optional<base::Value> value =
cr_fuchsia::ExecuteJavaScript(frame_.get(), script);
return value ? value->GetBool() : false;
}
protected:
void RunPermissionTest(bool grant);
......@@ -464,14 +476,9 @@ TEST_F(WebEngineIntegrationTest, PlayAudio) {
static uint16_t kTestMediaSessionId = 43;
frame_->SetMediaSessionId(kTestMediaSessionId);
fuchsia::web::LoadUrlParams load_url_params;
// |was_user_activated| needs to be set to ensure the page can play audio
// without user gesture.
load_url_params.set_was_user_activated(true);
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
navigation_controller_.get(), std::move(load_url_params),
navigation_controller_.get(),
cr_fuchsia::CreateLoadUrlParamsWithUserActivation(),
"fuchsia-dir://testdata/play_audio.html"));
navigation_listener_->RunUntilTitleEquals("ended");
......@@ -545,3 +552,77 @@ TEST_F(WebEngineIntegrationTest, MicrophoneAccess_WithoutPermission) {
navigation_listener_->RunUntilTitleEquals("ended");
}
TEST_F(WebEngineIntegrationTest, SetBlockMediaLoading_Blocked) {
StartWebEngine();
fuchsia::web::CreateContextParams create_params =
DefaultContextParamsWithTestData();
auto features = fuchsia::web::ContextFeatureFlags::AUDIO;
create_params.set_features(features);
CreateContextAndFrame(std::move(create_params));
frame_->SetBlockMediaLoading(true);
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
navigation_controller_.get(),
cr_fuchsia::CreateLoadUrlParamsWithUserActivation(),
"fuchsia-dir://testdata/play_vp8.html?autoplay"));
// Check different indicators that media has not loaded and is not playing.
navigation_listener_->RunUntilTitleEquals("stalled");
EXPECT_EQ(0 /*HAVE_NOTHING*/,
ExecuteJavaScriptWithDoubleResult("bear.readyState"));
EXPECT_EQ(0.0, ExecuteJavaScriptWithDoubleResult("bear.currentTime"));
EXPECT_FALSE(ExecuteJavaScriptWithBoolResult("isMetadataLoaded"));
}
// Initially, set media blocking to be true. When media is unblocked, check that
// it begins playing, since autoplay=true.
TEST_F(WebEngineIntegrationTest, SetBlockMediaLoading_AfterUnblock) {
StartWebEngine();
fuchsia::web::CreateContextParams create_params =
DefaultContextParamsWithTestData();
auto features = fuchsia::web::ContextFeatureFlags::AUDIO;
create_params.set_features(features);
CreateContextAndFrame(std::move(create_params));
frame_->SetBlockMediaLoading(true);
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
navigation_controller_.get(),
cr_fuchsia::CreateLoadUrlParamsWithUserActivation(),
"fuchsia-dir://testdata/play_vp8.html?autoplay"));
// Check that media loading has been blocked.
navigation_listener_->RunUntilTitleEquals("stalled");
// Unblock media from loading and see if media loads and plays, since
// autoplay=true.
frame_->SetBlockMediaLoading(false);
navigation_listener_->RunUntilTitleEquals("playing");
EXPECT_TRUE(ExecuteJavaScriptWithBoolResult("isMetadataLoaded"));
}
// Check that when autoplay=false and media loading was blocked after the
// element has started loading that media will play when play() is called.
TEST_F(WebEngineIntegrationTest, SetBlockMediaLoading_SetBlockedAfterLoading) {
StartWebEngine();
fuchsia::web::CreateContextParams create_params =
DefaultContextParamsWithTestData();
auto features = fuchsia::web::ContextFeatureFlags::AUDIO;
create_params.set_features(features);
CreateContextAndFrame(std::move(create_params));
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
navigation_controller_.get(),
cr_fuchsia::CreateLoadUrlParamsWithUserActivation(),
"fuchsia-dir://testdata/play_vp8.html"));
navigation_listener_->RunUntilTitleEquals("loaded");
frame_->SetBlockMediaLoading(true);
cr_fuchsia::ExecuteJavaScript(frame_.get(), "bear.play()");
navigation_listener_->RunUntilTitleEquals("playing");
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment