Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: content/browser/media/session/media_session_visibility_browsertest.cc

Issue 2453623003: Decouple MediaSession messages from WebContents (full patch) (Closed)
Patch Set: nit Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <tuple>
6
7 #include "base/command_line.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/threading/thread_task_runner_handle.h"
12 #include "content/browser/media/session/media_session.h"
13 #include "content/public/browser/web_contents.h"
14 #include "content/public/common/content_switches.h"
15 #include "content/public/test/browser_test_utils.h"
16 #include "content/public/test/content_browser_test.h"
17 #include "content/public/test/content_browser_test_utils.h"
18 #include "content/public/test/test_navigation_observer.h"
19 #include "content/shell/browser/shell.h"
20 #include "media/base/media_switches.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace content {
24 namespace {
25 static const char kStartPlayerScript[] =
26 "document.getElementById('long-video').play()";
27 static const char kPausePlayerScript[] =
28 "document.getElementById('long-video').pause()";
29
30 enum class MediaSuspend {
31 ENABLED,
32 DISABLED,
33 };
34
35 enum class Pipeline {
36 WMPI,
37 WMPA,
38 };
39
40 enum class BackgroundResuming {
41 ENABLED,
42 DISABLED,
43 };
44
45 enum class SessionState {
46 ACTIVE,
47 SUSPENDED,
48 INACTIVE,
49 };
50
51 struct VisibilityTestData {
52 MediaSuspend media_suspend;
53 BackgroundResuming background_resuming;
54 SessionState session_state_before_hide;
55 SessionState session_state_after_hide;
56 };
57
58 }
59
60
61 // Base class of MediaSession visibility tests. The class is intended
62 // to be used to run tests under different configurations. Tests
63 // should inheret from this class, set up their own command line per
64 // their configuration, and use macro INCLUDE_TEST_FROM_BASE_CLASS to
65 // include required tests. See
66 // media_session_visibility_browsertest_instances.cc for examples.
67 class MediaSessionVisibilityBrowserTest
68 : public ContentBrowserTest,
69 public ::testing::WithParamInterface<
70 std::tr1::tuple<VisibilityTestData, Pipeline>> {
71 public:
72 MediaSessionVisibilityBrowserTest() = default;
73 ~MediaSessionVisibilityBrowserTest() override = default;
74
75 void SetUpOnMainThread() override {
76 ContentBrowserTest::SetUpOnMainThread();
77 web_contents_ = shell()->web_contents();
78 media_session_ = MediaSession::Get(web_contents_);
79
80 media_session_state_loop_runners_[MediaSession::State::ACTIVE] =
81 new MessageLoopRunner();
82 media_session_state_loop_runners_[MediaSession::State::SUSPENDED] =
83 new MessageLoopRunner();
84 media_session_state_loop_runners_[MediaSession::State::INACTIVE] =
85 new MessageLoopRunner();
86 media_session_state_callback_subscription_ =
87 media_session_->RegisterMediaSessionStateChangedCallbackForTest(
88 base::Bind(&MediaSessionVisibilityBrowserTest::
89 OnMediaSessionStateChanged,
90 base::Unretained(this)));
91 }
92
93 void TearDownOnMainThread() override {
94 // Unsubscribe the callback subscription before tearing down, so that the
95 // CallbackList in MediaSession will be empty when it is destroyed.
96 media_session_state_callback_subscription_.reset();
97 }
98
99 void EnableDisableResumingBackgroundVideos(bool enable) {
100 std::string enabled_features;
101 std::string disabled_features;
102 if (enable)
103 enabled_features = media::kResumeBackgroundVideo.name;
104 else
105 disabled_features = media::kResumeBackgroundVideo.name;
106
107 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
108 feature_list->InitializeFromCommandLine(
109 enabled_features, disabled_features);
110 base::FeatureList::ClearInstanceForTesting();
111 base::FeatureList::SetInstance(std::move(feature_list));
112 }
113
114 void SetUpCommandLine(base::CommandLine* command_line) override {
115 command_line->AppendSwitch(
116 switches::kDisableGestureRequirementForMediaPlayback);
117 #if !defined(OS_ANDROID)
118 command_line->AppendSwitch(
119 switches::kEnableDefaultMediaSession);
120 #endif // !defined(OS_ANDROID)
121
122 VisibilityTestData params = GetVisibilityTestData();
123
124 if (params.media_suspend == MediaSuspend::ENABLED)
125 command_line->AppendSwitch(switches::kEnableMediaSuspend);
126 else
127 command_line->AppendSwitch(switches::kDisableMediaSuspend);
128
129 #if defined(OS_ANDROID)
130 Pipeline pipeline = std::tr1::get<1>(GetParam());
131 if (pipeline == Pipeline::WMPA)
132 command_line->AppendSwitch(switches::kDisableUnifiedMediaPipeline);
133 #endif // defined(OS_ANDROID)
134
135 if (params.background_resuming == BackgroundResuming::ENABLED) {
136 command_line->AppendSwitchASCII(switches::kEnableFeatures,
137 media::kResumeBackgroundVideo.name);
138 } else {
139 command_line->AppendSwitchASCII(switches::kDisableFeatures,
140 media::kResumeBackgroundVideo.name);
141 }
142 }
143
144 const VisibilityTestData& GetVisibilityTestData() {
145 return std::tr1::get<0>(GetParam());
146 }
147
148 void StartPlayer() {
149 LoadTestPage();
150
151 LOG(INFO) << "Starting player";
152 ClearMediaSessionStateLoopRunners();
153 RunScript(kStartPlayerScript);
154 LOG(INFO) << "Waiting for session to be active";
155 WaitForMediaSessionState(MediaSession::State::ACTIVE);
156 }
157
158 // Maybe pause the player depending on whether the session state before hide
159 // is SUSPENDED.
160 void MaybePausePlayer() {
161 ASSERT_TRUE(GetVisibilityTestData().session_state_before_hide
162 != SessionState::INACTIVE);
163 if (GetVisibilityTestData().session_state_before_hide
164 == SessionState::ACTIVE)
165 return;
166
167 LOG(INFO) << "Pausing player";
168 ClearMediaSessionStateLoopRunners();
169 RunScript(kPausePlayerScript);
170 LOG(INFO) << "Waiting for session to be suspended";
171 WaitForMediaSessionState(MediaSession::State::SUSPENDED);
172 }
173
174 void HideTab() {
175 LOG(INFO) << "Hiding the tab";
176 ClearMediaSessionStateLoopRunners();
177 web_contents_->WasHidden();
178 }
179
180 void CheckSessionStateAfterHide() {
181 MediaSession::State state_before_hide =
182 ToMediaSessionState(GetVisibilityTestData().session_state_before_hide);
183 MediaSession::State state_after_hide =
184 ToMediaSessionState(GetVisibilityTestData().session_state_after_hide);
185
186 if (state_before_hide == state_after_hide) {
187 LOG(INFO) << "Waiting for 1 second and check session state is unchanged";
188 Wait(base::TimeDelta::FromSeconds(1));
189 ASSERT_EQ(media_session_->audio_focus_state_, state_after_hide);
190 } else {
191 LOG(INFO) << "Waiting for Session to change";
192 WaitForMediaSessionState(state_after_hide);
193 }
194
195 LOG(INFO) << "Test succeeded";
196 }
197
198 private:
199 void LoadTestPage() {
200 TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
201 shell()->LoadURL(GetTestUrl("media/session", "media-session.html"));
202 navigation_observer.Wait();
203 }
204
205 void RunScript(const std::string& script) {
206 ASSERT_TRUE(ExecuteScript(web_contents_->GetMainFrame(), script));
207 }
208
209 void ClearMediaSessionStateLoopRunners() {
210 for (auto& state_loop_runner : media_session_state_loop_runners_)
211 state_loop_runner.second = new MessageLoopRunner();
212 }
213
214 void OnMediaSessionStateChanged(MediaSession::State state) {
215 ASSERT_TRUE(media_session_state_loop_runners_.count(state));
216 media_session_state_loop_runners_[state]->Quit();
217 }
218
219 // TODO(zqzhang): This method is shared with
220 // MediaRouterIntegrationTests. Move it into a general place.
221 void Wait(base::TimeDelta timeout) {
222 base::RunLoop run_loop;
223 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
224 FROM_HERE, run_loop.QuitClosure(), timeout);
225 run_loop.Run();
226 }
227
228 void WaitForMediaSessionState(MediaSession::State state) {
229 ASSERT_TRUE(media_session_state_loop_runners_.count(state));
230 media_session_state_loop_runners_[state]->Run();
231 }
232
233 MediaSession::State ToMediaSessionState(SessionState state) {
234 switch (state) {
235 case SessionState::ACTIVE:
236 return MediaSession::State::ACTIVE;
237 break;
238 case SessionState::SUSPENDED:
239 return MediaSession::State::SUSPENDED;
240 break;
241 case SessionState::INACTIVE:
242 return MediaSession::State::INACTIVE;
243 break;
244 default:
245 ADD_FAILURE() << "invalid SessionState to convert";
246 return MediaSession::State::INACTIVE;
247 }
248 }
249
250 WebContents* web_contents_;
251 MediaSession* media_session_;
252 // MessageLoopRunners for waiting MediaSession state to change. Note that the
253 // MessageLoopRunners can accept Quit() before calling Run(), thus the state
254 // change can still be captured before waiting. For example, the MediaSession
255 // might go active immediately after calling HTMLMediaElement.play(). A test
256 // can listen to the state change before calling play(), and then wait for the
257 // state change after play().
258 std::map<MediaSession::State, scoped_refptr<MessageLoopRunner> >
259 media_session_state_loop_runners_;
260 std::unique_ptr<base::CallbackList<void(MediaSession::State)>::Subscription>
261 media_session_state_callback_subscription_;
262
263 DISALLOW_COPY_AND_ASSIGN(MediaSessionVisibilityBrowserTest);
264 };
265
266 namespace {
267
268 VisibilityTestData kTestParams[] = {
269 { MediaSuspend::ENABLED, BackgroundResuming::DISABLED,
270 SessionState::SUSPENDED, SessionState::INACTIVE },
271 { MediaSuspend::ENABLED, BackgroundResuming::DISABLED,
272 SessionState::ACTIVE, SessionState::INACTIVE },
273 { MediaSuspend::ENABLED, BackgroundResuming::ENABLED,
274 SessionState::ACTIVE, SessionState::SUSPENDED },
275 { MediaSuspend::ENABLED, BackgroundResuming::ENABLED,
276 SessionState::SUSPENDED, SessionState::SUSPENDED },
277 { MediaSuspend::DISABLED, BackgroundResuming::DISABLED,
278 SessionState::SUSPENDED, SessionState::SUSPENDED },
279 { MediaSuspend::DISABLED, BackgroundResuming::DISABLED,
280 SessionState::ACTIVE, SessionState::ACTIVE },
281 { MediaSuspend::DISABLED, BackgroundResuming::ENABLED,
282 SessionState::ACTIVE, SessionState::ACTIVE },
283 { MediaSuspend::DISABLED, BackgroundResuming::ENABLED,
284 SessionState::SUSPENDED, SessionState::SUSPENDED },
285 };
286
287 Pipeline kPipelines[] = {
288 Pipeline::WMPI,
289 #if defined(OS_ANDROID)
290 // Disabling WMPA tests because of https://crbug.com/646312
291 // Pipeline::WMPA,
292 #endif // defined(OS_ANDROID)
293 };
294
295 } // anonymous namespace
296
297 IN_PROC_BROWSER_TEST_P(MediaSessionVisibilityBrowserTest,
298 TestEntryPoint) {
299 StartPlayer();
300 MaybePausePlayer();
301 HideTab();
302 CheckSessionStateAfterHide();
303 }
304
305 INSTANTIATE_TEST_CASE_P(MediaSessionVisibilityBrowserTestInstances,
306 MediaSessionVisibilityBrowserTest,
307 ::testing::Combine(::testing::ValuesIn(kTestParams),
308 ::testing::ValuesIn(kPipelines)));
309
310 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/media/session/media_session_service_impl.cc ('k') | content/browser/media/session/pepper_playback_observer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698