Skip to content

Commit

Permalink
[Chromecast] Add CastMediaBlocker to CastWebContents
Browse files Browse the repository at this point in the history
This adds CastMediaBlocker as a built-in capability for CastWebContents.
CastWebView::CreateParams is restructured to allow passing in
CastWebContents::InitParams directly, rather than with duplicate fields.

Merge-With: eureka-internal/269059

Bug: internal b/77879457
Test: CQ

Change-Id: I2ebd547e7c9ecb7f1f417616d18fb28629b29157
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1600160
Commit-Queue: Sean Topping <seantopping@chromium.org>
Reviewed-by: Luke Halliwell <halliwell@chromium.org>
Reviewed-by: Junbo Ke <juke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#658305}
  • Loading branch information
Sean Topping authored and Commit Bot committed May 9, 2019
1 parent d67e9bf commit 8a34386
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 32 deletions.
68 changes: 66 additions & 2 deletions chromecast/browser/cast_media_blocker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,24 @@
#include <utility>

#include "base/threading/thread_checker.h"
#include "chromecast/common/mojom/media_playback_options.mojom.h"
#include "content/public/browser/media_session.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"

namespace chromecast {
namespace shell {

CastMediaBlocker::CastMediaBlocker(content::WebContents* web_contents)
: CastMediaBlocker(content::MediaSession::Get(web_contents)) {
content::WebContentsObserver::Observe(web_contents);
}

CastMediaBlocker::CastMediaBlocker(content::MediaSession* media_session)
: blocked_(false),
paused_by_user_(true),
suspended_(true),
controllable_(false),
background_video_playback_enabled_(false),
media_session_(media_session) {
media_session::mojom::MediaSessionObserverPtr observer;
observer_binding_.Bind(mojo::MakeRequest(&observer));
Expand Down Expand Up @@ -52,6 +59,14 @@ void CastMediaBlocker::BlockMediaLoading(bool blocked) {
}
}

void CastMediaBlocker::EnableBackgroundVideoPlayback(bool enabled) {
if (!web_contents())
return;

background_video_playback_enabled_ = enabled;
UpdateBackgroundVideoPlaybackState();
}

void CastMediaBlocker::MediaSessionInfoChanged(
media_session::mojom::MediaSessionInfoPtr session_info) {
bool is_suspended = session_info->playback_state ==
Expand Down Expand Up @@ -115,5 +130,54 @@ void CastMediaBlocker::Resume() {
media_session_->Resume(content::MediaSession::SuspendType::kSystem);
}

} // namespace shell
void CastMediaBlocker::RenderFrameCreated(
content::RenderFrameHost* render_frame_host) {
UpdateRenderFrameMediaBlockedState(render_frame_host);
UpdateRenderFrameBackgroundVideoPlaybackState(render_frame_host);
}

void CastMediaBlocker::RenderViewReady() {
UpdateMediaBlockedState();
}

void CastMediaBlocker::UpdateMediaBlockedState() {
if (!web_contents())
return;

const std::vector<content::RenderFrameHost*> frames =
web_contents()->GetAllFrames();
for (content::RenderFrameHost* frame : frames) {
UpdateRenderFrameMediaBlockedState(frame);
}
}

void CastMediaBlocker::UpdateBackgroundVideoPlaybackState() {
if (!web_contents())
return;
const std::vector<content::RenderFrameHost*> frames =
web_contents()->GetAllFrames();
for (content::RenderFrameHost* frame : frames) {
UpdateRenderFrameBackgroundVideoPlaybackState(frame);
}
}

void CastMediaBlocker::UpdateRenderFrameMediaBlockedState(
content::RenderFrameHost* render_frame_host) {
DCHECK(render_frame_host);
chromecast::shell::mojom::MediaPlaybackOptionsAssociatedPtr
media_playback_options;
render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
&media_playback_options);
media_playback_options->SetMediaLoadingBlocked(media_loading_blocked());
}

void CastMediaBlocker::UpdateRenderFrameBackgroundVideoPlaybackState(
content::RenderFrameHost* frame) {
chromecast::shell::mojom::MediaPlaybackOptionsAssociatedPtr
media_playback_options;
frame->GetRemoteAssociatedInterfaces()->GetInterface(&media_playback_options);
media_playback_options->SetBackgroundVideoPlaybackEnabled(
background_video_playback_enabled_);
}

} // namespace chromecast
35 changes: 27 additions & 8 deletions chromecast/browser/cast_media_blocker.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,24 @@ class MediaSession;
} // namespace content

namespace chromecast {
namespace shell {

// This class implements a blocking mode for web applications and is used in
// Chromecast internal code. Media is unblocked by default.
class CastMediaBlocker : public media_session::mojom::MediaSessionObserver {
class CastMediaBlocker : public content::WebContentsObserver,
public media_session::mojom::MediaSessionObserver {
public:
// Observes WebContents and MediaSession.
explicit CastMediaBlocker(content::WebContents* web_contents);

// Observes only the MediaSession.
explicit CastMediaBlocker(content::MediaSession* media_session);

~CastMediaBlocker() override;

// Sets if the web contents is allowed to play media or not. If media is
// unblocked, previously suspended elements should begin playing again.
void BlockMediaLoading(bool blocked);
void EnableBackgroundVideoPlayback(bool enabled);

// media_session::mojom::MediaSessionObserver implementation:
void MediaSessionInfoChanged(
Expand All @@ -43,18 +49,27 @@ class CastMediaBlocker : public media_session::mojom::MediaSessionObserver {
std::vector<media_session::MediaImage>>& images)
override {}

protected:
private:
bool media_loading_blocked() const { return blocked_; }

// Blocks or unblocks the render process from loading new media
// according to |media_loading_blocked_|.
virtual void UpdateMediaBlockedState() {}
// content::WebContentsObserver implementation:
void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
void RenderViewReady() override;

private:
// Suspends or resumes the media session for the web contents.
void Suspend();
void Resume();

// Blocks or unblocks the render process from loading new media
// according to |blocked_|.
void UpdateMediaBlockedState();
void UpdateRenderFrameMediaBlockedState(
content::RenderFrameHost* render_frame_host);

void UpdateBackgroundVideoPlaybackState();
void UpdateRenderFrameBackgroundVideoPlaybackState(
content::RenderFrameHost* frame);

// Whether or not media should be blocked. This value cache's the last call to
// BlockMediaLoading. Is false by default.
bool blocked_;
Expand All @@ -67,6 +82,11 @@ class CastMediaBlocker : public media_session::mojom::MediaSessionObserver {
bool suspended_;
bool controllable_;

// Setting for whether or not the WebContents should suspend video when the
// content is put into the background. For most content, this setting should
// be disabled.
bool background_video_playback_enabled_;

content::MediaSession* const media_session_;

mojo::Binding<media_session::mojom::MediaSessionObserver> observer_binding_{
Expand All @@ -75,7 +95,6 @@ class CastMediaBlocker : public media_session::mojom::MediaSessionObserver {
DISALLOW_COPY_AND_ASSIGN(CastMediaBlocker);
};

} // namespace shell
} // namespace chromecast

#endif // CHROMECAST_BROWSER_CAST_MEDIA_BLOCKER_H_
3 changes: 1 addition & 2 deletions chromecast/browser/cast_media_blocker_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ class CastMediaBlockerBrowserTest : public CastBrowserTest {
web_contents_ = NavigateToURL(gurl);
WaitForLoadStop(web_contents_);

blocker_ = std::make_unique<CastMediaBlocker>(
content::MediaSession::Get(web_contents_));
blocker_ = std::make_unique<CastMediaBlocker>(web_contents_);
}

void BlockAndTestPlayerState(const std::string& media_type, bool blocked) {
Expand Down
29 changes: 25 additions & 4 deletions chromecast/browser/cast_web_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,23 @@ class CastWebContents {

// Initialization parameters for CastWebContents.
struct InitParams {
Delegate* delegate;
// Whether the underlying WebContents is exposed to the remote debugger.
bool enabled_for_dev;
// Delegate for CastWebContents. This can be null for an inner WebContents.
Delegate* delegate = nullptr;
// Enable development mode for this CastWebCastWebContents. Whitelists
// certain functionality for the WebContents, like remote debugging and
// debugging interfaces.
bool enabled_for_dev = false;
// Chooses a media renderer for the WebContents.
bool use_cma_renderer;
bool use_cma_renderer = false;
// Whether the WebContents is a root native window, or if it is embedded in
// another WebContents (see Delegate::InnerContentsCreated()).
bool is_root_window = false;
// Whether inner WebContents events should be handled. If this is set to
// true, then inner WebContents will automatically have a CastWebContents
// created and notify the delegate.
bool handle_inner_contents = false;
// Construct internal media blocker and enable BlockMediaLoading().
bool use_media_blocker = false;
};

// Page state for the main frame.
Expand Down Expand Up @@ -220,6 +229,18 @@ class CastWebContents {
// page.
virtual void Stop(int error_code) = 0;

// ===========================================================================
// Media Management
// ===========================================================================

// Block/unblock media from loading in all RenderFrames for the WebContents.
virtual void BlockMediaLoading(bool blocked) = 0;
virtual void EnableBackgroundVideoPlayback(bool enabled) = 0;

// ===========================================================================
// Utility Methods
// ===========================================================================

// Used to add or remove |observer| to the ObserverList in the implementation.
// These functions should only be invoked by CastWebContents::Observer in a
// valid sequence, enforced via SequenceChecker.
Expand Down
25 changes: 22 additions & 3 deletions chromecast/browser/cast_web_contents_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,12 @@ CastWebContentsImpl::CastWebContentsImpl(content::WebContents* web_contents,
last_state_(PageState::IDLE),
enabled_for_dev_(init_params.enabled_for_dev),
use_cma_renderer_(init_params.use_cma_renderer),
handle_inner_contents_(init_params.handle_inner_contents),
remote_debugging_server_(
shell::CastBrowserProcess::GetInstance()->remote_debugging_server()),
media_blocker_(init_params.use_media_blocker
? std::make_unique<CastMediaBlocker>(web_contents_)
: nullptr),
tab_id_(init_params.is_root_window ? 0 : next_tab_id++),
main_frame_loaded_(false),
closing_(false),
Expand Down Expand Up @@ -175,6 +179,16 @@ void CastWebContentsImpl::Stop(int error_code) {
NotifyObservers();
}

void CastWebContentsImpl::BlockMediaLoading(bool blocked) {
if (media_blocker_)
media_blocker_->BlockMediaLoading(blocked);
}

void CastWebContentsImpl::EnableBackgroundVideoPlayback(bool enabled) {
if (media_blocker_)
media_blocker_->EnableBackgroundVideoPlayback(enabled);
}

void CastWebContentsImpl::SetDelegate(CastWebContents::Delegate* delegate) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
delegate_ = delegate;
Expand Down Expand Up @@ -511,16 +525,21 @@ void CastWebContentsImpl::ResourceLoadComplete(

void CastWebContentsImpl::InnerWebContentsCreated(
content::WebContents* inner_web_contents) {
if (!handle_inner_contents_ || !delegate_)
return;
auto result = inner_contents_.insert(std::make_unique<CastWebContentsImpl>(
inner_web_contents, InitParams{nullptr, enabled_for_dev_}));
if (delegate_)
delegate_->InnerContentsCreated(result.first->get(), this);
inner_web_contents,
InitParams{nullptr, enabled_for_dev_, false /* use_cma_renderer */,
false /* is_root_window */, false /* handle_inner_contents */,
false /* use_media_blocker */}));
delegate_->InnerContentsCreated(result.first->get(), this);
}

void CastWebContentsImpl::WebContentsDestroyed() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
closing_ = false;
DisableDebugging();
media_blocker_.reset();
content::WebContentsObserver::Observe(nullptr);
web_contents_ = nullptr;
Stop(net::OK);
Expand Down
5 changes: 5 additions & 0 deletions chromecast/browser/cast_web_contents_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "chromecast/browser/cast_media_blocker.h"
#include "chromecast/browser/cast_web_contents.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
Expand Down Expand Up @@ -52,6 +53,8 @@ class CastWebContentsImpl : public CastWebContents,
const InterfaceSet& interface_set,
service_manager::InterfaceProvider* interface_provider) override;
service_manager::BinderRegistry* binder_registry() override;
void BlockMediaLoading(bool blocked) override;
void EnableBackgroundVideoPlayback(bool enabled) override;

// Observer interface:
void AddObserver(Observer* observer) override;
Expand Down Expand Up @@ -99,7 +102,9 @@ class CastWebContentsImpl : public CastWebContents,
PageState last_state_;
const bool enabled_for_dev_;
bool use_cma_renderer_;
const bool handle_inner_contents_;
shell::RemoteDebuggingServer* const remote_debugging_server_;
std::unique_ptr<CastMediaBlocker> media_blocker_;

base::flat_set<std::unique_ptr<CastWebContents>> inner_contents_;
std::vector<RendererFeature> renderer_features_;
Expand Down
13 changes: 5 additions & 8 deletions chromecast/browser/cast_web_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ class CastWebView {
// The delegate for the CastWebView. Must be non-null.
Delegate* delegate = nullptr;

// Parameters for initializing CastWebContents. These will be passed as-is
// to a CastWebContents instance, which should be used by all CastWebView
// implementations.
CastWebContents::InitParams web_contents_params;

// Parameters for creating the content window for this CastWebView.
shell::CastContentWindow::CreateParams window_params;

Expand All @@ -80,14 +85,6 @@ class CastWebView {
// Whether this CastWebView is granted media access.
bool allow_media_access = false;

// Whether this CastWebView will use CMA for media playback.
bool use_cma_renderer = true;

// Enable development mode for this CastWebView. Whitelists certain
// functionality for the WebContents, like remote debugging and debugging
// interfaces.
bool enabled_for_dev = false;

// Enable/Force 720p resolution for this CastWebView instance.
bool force_720p_resolution = false;

Expand Down
4 changes: 1 addition & 3 deletions chromecast/browser/cast_web_view_default.cc
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,7 @@ CastWebViewDefault::CastWebViewDefault(
transparent_(params.transparent),
allow_media_access_(params.allow_media_access),
web_contents_(CreateWebContents(browser_context_, site_instance_)),
cast_web_contents_(
web_contents_.get(),
{delegate_, params.enabled_for_dev, params.use_cma_renderer}),
cast_web_contents_(web_contents_.get(), params.web_contents_params),
window_(shell::CastContentWindow::Create(params.window_params)),
resize_window_when_navigation_starts_(true) {
DCHECK(delegate_);
Expand Down
3 changes: 2 additions & 1 deletion chromecast/browser/service/cast_service_simple.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ void CastServiceSimple::StartInternal() {

CastWebView::CreateParams params;
params.delegate = this;
params.enabled_for_dev = true;
params.web_contents_params.delegate = this;
params.web_contents_params.enabled_for_dev = true;
params.window_params.delegate = this;
cast_web_view_ =
web_contents_manager_->CreateWebView(params, nullptr, /* site_instance */
Expand Down
4 changes: 3 additions & 1 deletion chromecast/browser/test/cast_browser_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ void CastBrowserTest::PostRunTestOnMainThread() {
content::WebContents* CastBrowserTest::CreateWebView() {
CastWebView::CreateParams params;
params.delegate = this;
params.enabled_for_dev = true;
params.web_contents_params.delegate = this;
params.web_contents_params.use_cma_renderer = true;
params.web_contents_params.enabled_for_dev = true;
params.window_params.delegate = this;
cast_web_view_ =
web_contents_manager_->CreateWebView(params, nullptr, /* site_instance */
Expand Down

0 comments on commit 8a34386

Please sign in to comment.