Commit 7a8a8980 authored by Luke Halliwell's avatar Luke Halliwell Committed by Commit Bot

Allow content embedder to control backgrounded media suspend

Currently, it's controlled by switches, which can be used for
global control of the feature, but don't work well for per-tab
configuration.

Move the decision to ContentRendererClient and use the switches
in default implementation to maintain existing default behaviour.

Bug: 862698
Change-Id: I917e21ec8d8e493eef53113fe667d45ab17a48b5
Reviewed-on: https://chromium-review.googlesource.com/1133975
Commit-Queue: Luke Halliwell <halliwell@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577759}
parent 0719dbdc
......@@ -284,7 +284,7 @@ bool CastContentRendererClient::RunWhenInForeground(
return media_load_deferrer->RunWhenInForeground(std::move(closure));
}
bool CastContentRendererClient::AllowIdleMediaSuspend() {
bool CastContentRendererClient::IsIdleMediaSuspendEnabled() {
return false;
}
......
......@@ -66,7 +66,7 @@ class CastContentRendererClient
bool DeferMediaLoad(content::RenderFrame* render_frame,
bool render_frame_has_played_media_before,
base::OnceClosure closure) override;
bool AllowIdleMediaSuspend() override;
bool IsIdleMediaSuspendEnabled() override;
void SetRuntimeFeaturesDefaultsBeforeBlinkInitialization() override;
protected:
......
......@@ -240,10 +240,18 @@ ContentRendererClient::GetTaskSchedulerInitParams() {
return nullptr;
}
bool ContentRendererClient::AllowIdleMediaSuspend() {
bool ContentRendererClient::IsIdleMediaSuspendEnabled() {
return true;
}
bool ContentRendererClient::IsBackgroundMediaSuspendEnabled() {
#if defined(OS_ANDROID)
return true;
#else
return false;
#endif
}
bool ContentRendererClient::OverrideLegacySymantecCertConsoleMessage(
const GURL& url,
std::string* console_messsage) {
......
......@@ -381,7 +381,11 @@ class CONTENT_EXPORT ContentRendererClient {
// Whether the renderer allows idle media players to be automatically
// suspended after a period of inactivity.
virtual bool AllowIdleMediaSuspend();
virtual bool IsIdleMediaSuspendEnabled();
// Whether the renderer should automatically suspend media playback on
// background tabs.
virtual bool IsBackgroundMediaSuspendEnabled();
// Called when a resource at |url| is loaded using an otherwise-valid legacy
// Symantec certificate that will be distrusted in future. Allows the embedder
......
......@@ -38,7 +38,10 @@ RendererWebMediaPlayerDelegate::RendererWebMediaPlayerDelegate(
content::RenderFrame* render_frame)
: RenderFrameObserver(render_frame),
allow_idle_cleanup_(
content::GetContentClient()->renderer()->AllowIdleMediaSuspend()),
content::GetContentClient()->renderer()->IsIdleMediaSuspendEnabled()),
background_suspend_enabled_(content::GetContentClient()
->renderer()
->IsBackgroundMediaSuspendEnabled()),
tick_clock_(base::DefaultTickClock::GetInstance()) {
idle_cleanup_interval_ = base::TimeDelta::FromSeconds(5);
idle_timeout_ = base::TimeDelta::FromSeconds(15);
......@@ -156,6 +159,10 @@ void RendererWebMediaPlayerDelegate::
std::make_pair(player_id, std::move(callback));
}
bool RendererWebMediaPlayerDelegate::IsBackgroundMediaSuspendEnabled() {
return background_suspend_enabled_;
}
void RendererWebMediaPlayerDelegate::DidPause(int player_id) {
DVLOG(2) << __func__ << "(" << player_id << ")";
DCHECK(id_map_.Lookup(player_id));
......
......@@ -77,6 +77,7 @@ class CONTENT_EXPORT RendererWebMediaPlayerDelegate
void RegisterPictureInPictureWindowResizeCallback(
int player_id,
blink::WebMediaPlayer::PipWindowResizedCallback) override;
bool IsBackgroundMediaSuspendEnabled() override;
// content::RenderFrameObserver overrides.
void WasHidden() override;
......@@ -146,6 +147,9 @@ class CONTENT_EXPORT RendererWebMediaPlayerDelegate
// period of inactivity.
bool allow_idle_cleanup_ = true;
// Flag for whether players should suspend when tab is in background.
bool background_suspend_enabled_ = true;
// Tracks which players have entered an idle state. After some period of
// inactivity these players will be notified and become stale.
std::map<int, base::TimeTicks> idle_player_map_;
......
......@@ -143,6 +143,8 @@ class FakeWebMediaPlayerDelegate
EXPECT_EQ(delegate_id_, delegate_id);
}
bool IsBackgroundMediaSuspendEnabled() override { return true; }
bool IsFrameHidden() override { return is_hidden_; }
bool IsFrameClosed() override { return false; }
......
......@@ -145,7 +145,7 @@ void LayoutTestContentRendererClient::
}
}
bool LayoutTestContentRendererClient::AllowIdleMediaSuspend() {
bool LayoutTestContentRendererClient::IsIdleMediaSuspendEnabled() {
// Disable idle media suspend to avoid layout tests getting into accidentally
// bad states if they take too long to run.
return false;
......
......@@ -32,7 +32,7 @@ class LayoutTestContentRendererClient : public ShellContentRendererClient {
void DidInitializeWorkerContextOnWorkerThread(
v8::Local<v8::Context> context) override;
void SetRuntimeFeaturesDefaultsBeforeBlinkInitialization() override;
bool AllowIdleMediaSuspend() override;
bool IsIdleMediaSuspendEnabled() override;
private:
std::unique_ptr<LayoutTestRenderThreadObserver> shell_observer_;
......
......@@ -31,6 +31,7 @@ MEDIA_EXPORT extern const char kFailAudioStreamCreation[];
MEDIA_EXPORT extern const char kVideoThreads[];
// TODO(crbug.com/867146): remove these switches.
MEDIA_EXPORT extern const char kEnableMediaSuspend[];
MEDIA_EXPORT extern const char kDisableMediaSuspend[];
......
......@@ -177,6 +177,10 @@ class WebMediaPlayerDelegate {
int player_id,
blink::WebFullscreenVideoStatus fullscreen_video_status) = 0;
// Returns |true| if player should be suspended automatically when tab is
// in background.
virtual bool IsBackgroundMediaSuspendEnabled() = 0;
protected:
WebMediaPlayerDelegate() = default;
virtual ~WebMediaPlayerDelegate() = default;
......
......@@ -97,15 +97,16 @@ void SetSinkIdOnMediaThread(scoped_refptr<WebAudioSourceProviderImpl> sink,
sink->SwitchOutputDevice(device_id, callback);
}
bool IsBackgroundedSuspendEnabled() {
#if !defined(OS_ANDROID)
// Suspend/Resume is only enabled by default on Android.
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableMediaSuspend);
#else
return !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableMediaSuspend);
#endif
bool IsBackgroundSuspendEnabled(WebMediaPlayerDelegate* delegate) {
// TODO(crbug.com/867146): remove these switches.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableMediaSuspend))
return false;
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableMediaSuspend))
return true;
return delegate->IsBackgroundMediaSuspendEnabled();
}
bool IsResumeBackgroundVideosEnabled() {
......@@ -2528,7 +2529,7 @@ void WebMediaPlayerImpl::UpdatePlayState() {
#endif
bool is_suspended = pipeline_controller_.IsSuspended();
bool is_backgrounded = IsBackgroundedSuspendEnabled() && IsHidden();
bool is_backgrounded = IsBackgroundSuspendEnabled(delegate_) && IsHidden();
PlayState state = UpdatePlayState_ComputePlayState(
is_remote, can_auto_suspend, is_suspended, is_backgrounded);
SetDelegateState(state.delegate_state, state.is_idle);
......@@ -2717,8 +2718,8 @@ WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
// suspend is enabled and resuming background videos is not (original Android
// behavior).
bool backgrounded_video_has_no_remote_controls =
IsBackgroundedSuspendEnabled() && !IsResumeBackgroundVideosEnabled() &&
is_backgrounded && HasVideo();
IsBackgroundSuspendEnabled(delegate_) &&
!IsResumeBackgroundVideosEnabled() && is_backgrounded && HasVideo();
bool can_play = !has_error && !is_remote && have_future_data;
bool has_remote_controls =
HasAudio() && !backgrounded_video_has_no_remote_controls;
......@@ -2933,7 +2934,7 @@ bool WebMediaPlayerImpl::IsSuspendedForTesting() {
bool WebMediaPlayerImpl::ShouldPauseVideoWhenHidden() const {
// If suspending background video, pause any video that's not remoted or
// not unlocked to play in the background.
if (IsBackgroundedSuspendEnabled()) {
if (IsBackgroundSuspendEnabled(delegate_)) {
if (!HasVideo())
return false;
......
......@@ -258,6 +258,10 @@ class MockWebMediaPlayerDelegate : public WebMediaPlayerDelegate {
bool IsFrameClosed() override { return is_closed_; }
bool IsBackgroundMediaSuspendEnabled() override {
return is_background_media_suspend_enabled_;
}
void SetIdleForTesting(bool is_idle) { is_idle_ = is_idle; }
void SetStaleForTesting(bool is_stale) {
......@@ -279,6 +283,10 @@ class MockWebMediaPlayerDelegate : public WebMediaPlayerDelegate {
void SetFrameClosedForTesting(bool is_closed) { is_closed_ = is_closed; }
void SetBackgroundMediaSuspendEnabledForTesting(bool enable) {
is_background_media_suspend_enabled_ = enable;
}
int player_id() { return player_id_; }
private:
......@@ -288,6 +296,7 @@ class MockWebMediaPlayerDelegate : public WebMediaPlayerDelegate {
bool is_stale_ = false;
bool is_hidden_ = false;
bool is_closed_ = false;
bool is_background_media_suspend_enabled_ = false;
};
class MockSurfaceLayerBridge : public blink::WebSurfaceLayerBridge {
......@@ -531,17 +540,7 @@ class WebMediaPlayerImplTest : public testing::Test {
}
void SetUpMediaSuspend(bool enable) {
#if defined(OS_ANDROID)
if (!enable) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kDisableMediaSuspend);
}
#else
if (enable) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableMediaSuspend);
}
#endif
delegate_.SetBackgroundMediaSuspendEnabledForTesting(enable);
}
bool IsVideoLockedWhenPausedWhenHidden() const {
......
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