Skip to content

Commit

Permalink
Add CastMediaBlocker and BrowserTest
Browse files Browse the repository at this point in the history
CastMediaBlocker is a class which can prevent media from being played
on a web page.

BUG=NONE
TEST=ChromecastShellMediaBlockingBrowserTest

Review-Url: https://codereview.chromium.org/2330243002
Cr-Commit-Position: refs/heads/master@{#418897}
  • Loading branch information
derekjchow authored and Commit bot committed Sep 15, 2016
1 parent ca7c2f9 commit 502bcc9
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 0 deletions.
3 changes: 3 additions & 0 deletions chromecast/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ source_set("browser") {
"cast_download_manager_delegate.h",
"cast_http_user_agent_settings.cc",
"cast_http_user_agent_settings.h",
"cast_media_blocker.cc",
"cast_media_blocker.h",
"cast_net_log.cc",
"cast_net_log.h",
"cast_network_delegate.cc",
Expand Down Expand Up @@ -179,6 +181,7 @@ config("browser_test_config") {
test("cast_shell_browser_test") {
sources = [
"test/chromecast_shell_browser_test.cc",
"test/chromecast_shell_media_blocking_browser_test.cc",
]

configs += [ ":browser_test_config" ]
Expand Down
58 changes: 58 additions & 0 deletions chromecast/browser/cast_media_blocker.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2016 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 "chromecast/browser/cast_media_blocker.h"

#include "base/threading/thread_checker.h"
#include "content/public/browser/web_contents.h"

namespace chromecast {
namespace shell {

CastMediaBlocker::CastMediaBlocker(content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
controllable_(false),
suspended_(false),
state_(UNBLOCKED) {}

CastMediaBlocker::~CastMediaBlocker() {}

void CastMediaBlocker::BlockMediaLoading(bool blocked) {
if (blocked) {
state_ = BLOCKED;
} else if (state_ == BLOCKED) {
state_ = UNBLOCKING;
}

UpdateMediaBlockedState();
}

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

if (!controllable_) {
return;
}

if (state_ == BLOCKED && !suspended_) {
web_contents()->SuspendMediaSession();
} else if (state_ == UNBLOCKING && suspended_) {
web_contents()->ResumeMediaSession();
state_ = UNBLOCKED;
}
}

void CastMediaBlocker::MediaSessionStateChanged(
bool is_controllable,
bool is_suspended,
const base::Optional<content::MediaMetadata>& metadata) {
controllable_ = is_controllable;
suspended_ = is_suspended;
UpdateMediaBlockedState();
}

} // namespace shell
} // namespace chromecast
62 changes: 62 additions & 0 deletions chromecast/browser/cast_media_blocker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2016 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 CHROMECAST_BROWSER_CAST_MEDIA_BLOCKER_H_
#define CHROMECAST_BROWSER_CAST_MEDIA_BLOCKER_H_

#include "base/macros.h"
#include "content/public/browser/web_contents_observer.h"

namespace content {
class WebContents;
} // namespace content

namespace chromecast {
namespace shell {

// This class implements a blocking mode for web applications and is used in
// Chromecast internal code.
class CastMediaBlocker : public content::WebContentsObserver {
public:
explicit CastMediaBlocker(content::WebContents* web_contents);
~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);

protected:
bool media_loading_blocked() const { return state_ == BLOCKED; }

// Blocks or unblocks the render process from loading new media
// according to |media_loading_blocked_|.
virtual void UpdateMediaBlockedState();

private:
enum BlockState {
BLOCKED, // All media playback should be blocked.
UNBLOCKING, // Media playback should be resumed at next oppurtunity.
UNBLOCKED, // Media playback should not be blocked.
};

// content::WebContentsObserver implementation:
void MediaSessionStateChanged(
bool is_controllable,
bool is_suspended,
const base::Optional<content::MediaMetadata>& metadata) override;

// Whether or not media in the app can be controlled and if media is currently
// suspended. These variables cache arguments from MediaSessionStateChanged().
bool controllable_;
bool suspended_;

BlockState state_;

DISALLOW_COPY_AND_ASSIGN(CastMediaBlocker);
};

} // namespace shell
} // namespace chromecast

#endif // CHROMECAST_BROWSER_CAST_MEDIA_BLOCKER_H_
1 change: 1 addition & 0 deletions chromecast/browser/test/chromecast_browser_test_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class ChromecastBrowserTestHelper {

virtual ~ChromecastBrowserTestHelper() {}
virtual content::WebContents* NavigateToURL(const GURL& url) = 0;
virtual void BlockMediaLoading(bool block) = 0;
};

} // namespace shell
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "chromecast/browser/cast_browser_context.h"
#include "chromecast/browser/cast_browser_process.h"
#include "chromecast/browser/cast_content_window.h"
#include "chromecast/browser/cast_media_blocker.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
Expand All @@ -26,6 +27,7 @@ class DefaultHelper : public ChromecastBrowserTestHelper {
web_contents_ = window_->CreateWebContents(
CastBrowserProcess::GetInstance()->browser_context());
window_->CreateWindowTree(web_contents_.get());
blocker_.reset(new CastMediaBlocker(web_contents_.get()));

content::WaitForLoadStop(web_contents_.get());
content::TestNavigationObserver same_tab_observer(web_contents_.get(), 1);
Expand All @@ -38,9 +40,14 @@ class DefaultHelper : public ChromecastBrowserTestHelper {
return web_contents_.get();
}

void BlockMediaLoading(bool block) override {
blocker_->BlockMediaLoading(block);
}

private:
std::unique_ptr<CastContentWindow> window_;
std::unique_ptr<content::WebContents> web_contents_;
std::unique_ptr<CastMediaBlocker> blocker_;
};

} // namespace
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2016 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 "base/macros.h"
#include "base/run_loop.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromecast/browser/test/chromecast_browser_test.h"
#include "chromecast/browser/test/chromecast_browser_test_helper.h"
#include "chromecast/chromecast_features.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "media/base/test_data_util.h"
#include "url/gurl.h"
#include "url/url_constants.h"

namespace chromecast {
namespace shell {

class ChromecastShellMediaBlockingBrowserTest : public ChromecastBrowserTest {
public:
ChromecastShellMediaBlockingBrowserTest() {}

protected:
void PlayMedia(const std::string& tag, const std::string& media_file) {
base::StringPairs query_params;
query_params.push_back(std::make_pair(tag, media_file));

std::string query = media::GetURLQueryString(query_params);
GURL gurl = content::GetFileUrlWithQuery(
media::GetTestDataFilePath("player.html"), query);

web_contents_ = helper_->NavigateToURL(gurl);
WaitForLoadStop(web_contents_);
}

void BlockAndTestPlayerState(const std::string& media_type, bool blocked) {
helper_->BlockMediaLoading(blocked);

// Changing states is not instant, but should be timely (< 0.5s).
for (size_t i = 0; i < 5; i++) {
base::RunLoop run_loop;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, run_loop.QuitClosure(),
base::TimeDelta::FromMilliseconds(50));
base::MessageLoop::ScopedNestableTaskAllower allow_nested(
base::MessageLoop::current());
run_loop.Run();

const std::string command =
"document.getElementsByTagName(\"" + media_type + "\")[0].paused";
const std::string js =
"window.domAutomationController.send(" + command + ");";

bool paused;
ASSERT_TRUE(ExecuteScriptAndExtractBool(web_contents_, js, &paused));

if (paused == blocked) {
SUCCEED() << "Media element has been successfullly "
<< (blocked ? "blocked" : "unblocked");
return;
}
}

FAIL() << "Could not successfullly " << (blocked ? "block" : "unblock")
<< " media element";
}

content::WebContents* web_contents_;

private:
DISALLOW_COPY_AND_ASSIGN(ChromecastShellMediaBlockingBrowserTest);
};

IN_PROC_BROWSER_TEST_F(ChromecastShellMediaBlockingBrowserTest,
Audio_BlockUnblock) {
PlayMedia("audio", "bear-audio-10s-CBR-has-TOC.mp3");

BlockAndTestPlayerState("audio", true);
BlockAndTestPlayerState("audio", false);
}

#if !BUILDFLAG(IS_CAST_AUDIO_ONLY)
IN_PROC_BROWSER_TEST_F(ChromecastShellMediaBlockingBrowserTest,
Video_BlockUnblock) {
PlayMedia("video", "tulip2.webm");

BlockAndTestPlayerState("video", true);
BlockAndTestPlayerState("video", false);
}
#endif

} // namespace shell
} // namespace chromecast

0 comments on commit 502bcc9

Please sign in to comment.