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