1 // Copyright 2013 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.
5 #include "chrome/browser/media/native_desktop_media_list.h"
7 #include "base/location.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/synchronization/lock.h"
12 #include "chrome/browser/media/desktop_media_list_observer.h"
13 #include "content/public/test/test_browser_thread.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
17 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
18 #include "third_party/webrtc/modules/desktop_capture/window_capturer.h"
25 class MockObserver
: public DesktopMediaListObserver
{
27 MOCK_METHOD1(OnSourceAdded
, void(int index
));
28 MOCK_METHOD1(OnSourceRemoved
, void(int index
));
29 MOCK_METHOD2(OnSourceMoved
, void(int old_index
, int new_index
));
30 MOCK_METHOD1(OnSourceNameChanged
, void(int index
));
31 MOCK_METHOD1(OnSourceThumbnailChanged
, void(int index
));
34 class FakeScreenCapturer
: public webrtc::ScreenCapturer
{
36 FakeScreenCapturer() {}
37 ~FakeScreenCapturer() override
{}
39 // webrtc::ScreenCapturer implementation.
40 void Start(Callback
* callback
) override
{ callback_
= callback
; }
42 void Capture(const webrtc::DesktopRegion
& region
) override
{
44 webrtc::DesktopFrame
* frame
=
45 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
46 memset(frame
->data(), 0, frame
->stride() * frame
->size().height());
47 callback_
->OnCaptureCompleted(frame
);
50 bool GetScreenList(ScreenList
* screens
) override
{
51 webrtc::ScreenCapturer::Screen screen
;
53 screens
->push_back(screen
);
57 bool SelectScreen(webrtc::ScreenId id
) override
{
65 DISALLOW_COPY_AND_ASSIGN(FakeScreenCapturer
);
68 class FakeWindowCapturer
: public webrtc::WindowCapturer
{
73 ~FakeWindowCapturer() override
{}
75 void SetWindowList(const WindowList
& list
) {
76 base::AutoLock
lock(window_list_lock_
);
80 // Sets |value| thats going to be used to memset() content of the frames
81 // generated for |window_id|. By default generated frames are set to zeros.
82 void SetNextFrameValue(WindowId window_id
, int8_t value
) {
83 base::AutoLock
lock(frame_values_lock_
);
84 frame_values_
[window_id
] = value
;
87 // webrtc::WindowCapturer implementation.
88 void Start(Callback
* callback
) override
{ callback_
= callback
; }
90 void Capture(const webrtc::DesktopRegion
& region
) override
{
93 base::AutoLock
lock(frame_values_lock_
);
95 std::map
<WindowId
, int8_t>::iterator it
=
96 frame_values_
.find(selected_window_id_
);
97 int8_t value
= (it
!= frame_values_
.end()) ? it
->second
: 0;
98 webrtc::DesktopFrame
* frame
=
99 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
100 memset(frame
->data(), value
, frame
->stride() * frame
->size().height());
101 callback_
->OnCaptureCompleted(frame
);
104 bool GetWindowList(WindowList
* windows
) override
{
105 base::AutoLock
lock(window_list_lock_
);
106 *windows
= window_list_
;
110 bool SelectWindow(WindowId id
) override
{
111 selected_window_id_
= id
;
115 bool BringSelectedWindowToFront() override
{ return true; }
119 WindowList window_list_
;
120 base::Lock window_list_lock_
;
122 WindowId selected_window_id_
;
124 // Frames to be captured per window.
125 std::map
<WindowId
, int8_t> frame_values_
;
126 base::Lock frame_values_lock_
;
128 DISALLOW_COPY_AND_ASSIGN(FakeWindowCapturer
);
131 ACTION_P2(CheckListSize
, model
, expected_list_size
) {
132 EXPECT_EQ(expected_list_size
, model
->GetSourceCount());
135 ACTION_P(QuitMessageLoop
, message_loop
) {
136 message_loop
->task_runner()->PostTask(FROM_HERE
,
137 base::MessageLoop::QuitClosure());
140 class DesktopMediaListTest
: public testing::Test
{
142 DesktopMediaListTest()
143 : window_capturer_(NULL
),
144 ui_thread_(content::BrowserThread::UI
,
148 void CreateWithDefaultCapturers() {
149 window_capturer_
= new FakeWindowCapturer();
150 model_
.reset(new NativeDesktopMediaList(
151 scoped_ptr
<webrtc::ScreenCapturer
>(new FakeScreenCapturer()),
152 scoped_ptr
<webrtc::WindowCapturer
>(window_capturer_
)));
154 // Set update period to reduce the time it takes to run tests.
155 model_
->SetUpdatePeriod(base::TimeDelta::FromMilliseconds(0));
158 webrtc::WindowCapturer::WindowList
AddWindowsAndVerify(
159 size_t count
, bool window_only
) {
160 webrtc::WindowCapturer::WindowList list
;
161 for (size_t i
= 0; i
< count
; ++i
) {
162 webrtc::WindowCapturer::Window window
;
164 window
.title
= "Test window";
165 list
.push_back(window
);
167 window_capturer_
->SetWindowList(list
);
170 testing::InSequence dummy
;
171 size_t source_count
= window_only
? count
: count
+ 1;
172 for (size_t i
= 0; i
< source_count
; ++i
) {
173 EXPECT_CALL(observer_
, OnSourceAdded(i
))
174 .WillOnce(CheckListSize(model_
.get(), static_cast<int>(i
+ 1)));
176 for (size_t i
= 0; i
< source_count
- 1; ++i
) {
177 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(i
));
179 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(source_count
- 1))
180 .WillOnce(QuitMessageLoop(&message_loop_
));
182 model_
->StartUpdating(&observer_
);
185 for (size_t i
= 0; i
< count
; ++i
) {
186 size_t source_index
= window_only
? i
: i
+ 1;
187 EXPECT_EQ(model_
->GetSource(source_index
).id
.type
,
188 content::DesktopMediaID::TYPE_WINDOW
);
189 EXPECT_EQ(model_
->GetSource(source_index
).id
.id
, static_cast<int>(i
+ 1));
190 EXPECT_EQ(model_
->GetSource(source_index
).name
,
191 base::UTF8ToUTF16("Test window"));
193 testing::Mock::VerifyAndClearExpectations(&observer_
);
198 // Must be listed before |model_|, so it's destroyed last.
199 MockObserver observer_
;
201 // Owned by |model_|;
202 FakeWindowCapturer
* window_capturer_
;
204 scoped_ptr
<NativeDesktopMediaList
> model_
;
206 base::MessageLoop message_loop_
;
207 content::TestBrowserThread ui_thread_
;
209 DISALLOW_COPY_AND_ASSIGN(DesktopMediaListTest
);
212 TEST_F(DesktopMediaListTest
, InitialSourceList
) {
213 CreateWithDefaultCapturers();
214 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(1, false);
216 EXPECT_EQ(model_
->GetSource(0).id
.type
, content::DesktopMediaID::TYPE_SCREEN
);
217 EXPECT_EQ(model_
->GetSource(0).id
.id
, 0);
220 // Verifies that the window specified with SetViewDialogWindowId() is filtered
222 TEST_F(DesktopMediaListTest
, Filtering
) {
223 CreateWithDefaultCapturers();
224 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(2, false);
226 EXPECT_EQ(model_
->GetSource(0).id
.type
, content::DesktopMediaID::TYPE_SCREEN
);
227 EXPECT_EQ(model_
->GetSource(0).id
.id
, 0);
230 TEST_F(DesktopMediaListTest
, WindowsOnly
) {
231 window_capturer_
= new FakeWindowCapturer();
232 model_
.reset(new NativeDesktopMediaList(
233 scoped_ptr
<webrtc::ScreenCapturer
>(),
234 scoped_ptr
<webrtc::WindowCapturer
>(window_capturer_
)));
235 AddWindowsAndVerify(1, true);
238 TEST_F(DesktopMediaListTest
, ScreenOnly
) {
239 model_
.reset(new NativeDesktopMediaList(
240 scoped_ptr
<webrtc::ScreenCapturer
>(new FakeScreenCapturer
),
241 scoped_ptr
<webrtc::WindowCapturer
>()));
244 testing::InSequence dummy
;
245 EXPECT_CALL(observer_
, OnSourceAdded(0))
246 .WillOnce(CheckListSize(model_
.get(), 1));
247 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(0))
248 .WillOnce(QuitMessageLoop(&message_loop_
));
250 model_
->StartUpdating(&observer_
);
254 EXPECT_EQ(model_
->GetSource(0).id
.type
, content::DesktopMediaID::TYPE_SCREEN
);
257 TEST_F(DesktopMediaListTest
, AddWindow
) {
258 CreateWithDefaultCapturers();
259 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(1, false);
261 EXPECT_CALL(observer_
, OnSourceAdded(2))
262 .WillOnce(DoAll(CheckListSize(model_
.get(), 3),
263 QuitMessageLoop(&message_loop_
)));
265 webrtc::WindowCapturer::Window window
;
267 window
.title
= "Test window 0";
268 list
.push_back(window
);
269 window_capturer_
->SetWindowList(list
);
273 EXPECT_EQ(model_
->GetSource(2).id
.type
, content::DesktopMediaID::TYPE_WINDOW
);
274 EXPECT_EQ(model_
->GetSource(2).id
.id
, 0);
277 TEST_F(DesktopMediaListTest
, RemoveWindow
) {
278 CreateWithDefaultCapturers();
279 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(2, false);
281 EXPECT_CALL(observer_
, OnSourceRemoved(2))
282 .WillOnce(DoAll(CheckListSize(model_
.get(), 2),
283 QuitMessageLoop(&message_loop_
)));
285 list
.erase(list
.begin() + 1);
286 window_capturer_
->SetWindowList(list
);
291 TEST_F(DesktopMediaListTest
, RemoveAllWindows
) {
292 CreateWithDefaultCapturers();
293 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(2, false);
295 testing::InSequence seq
;
296 EXPECT_CALL(observer_
, OnSourceRemoved(1))
297 .WillOnce(CheckListSize(model_
.get(), 2));
298 EXPECT_CALL(observer_
, OnSourceRemoved(1))
299 .WillOnce(DoAll(CheckListSize(model_
.get(), 1),
300 QuitMessageLoop(&message_loop_
)));
302 list
.erase(list
.begin(), list
.end());
303 window_capturer_
->SetWindowList(list
);
308 TEST_F(DesktopMediaListTest
, UpdateTitle
) {
309 CreateWithDefaultCapturers();
310 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(1, false);
312 EXPECT_CALL(observer_
, OnSourceNameChanged(1))
313 .WillOnce(QuitMessageLoop(&message_loop_
));
315 const std::string kTestTitle
= "New Title";
317 list
[0].title
= kTestTitle
;
318 window_capturer_
->SetWindowList(list
);
322 EXPECT_EQ(model_
->GetSource(1).name
, base::UTF8ToUTF16(kTestTitle
));
325 TEST_F(DesktopMediaListTest
, UpdateThumbnail
) {
326 CreateWithDefaultCapturers();
327 AddWindowsAndVerify(2, false);
329 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(1))
330 .WillOnce(QuitMessageLoop(&message_loop_
));
331 // Update frame for the window and verify that we get notification about it.
332 window_capturer_
->SetNextFrameValue(1, 1);
337 TEST_F(DesktopMediaListTest
, MoveWindow
) {
338 CreateWithDefaultCapturers();
339 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(2, false);
341 EXPECT_CALL(observer_
, OnSourceMoved(2, 1))
342 .WillOnce(DoAll(CheckListSize(model_
.get(), 3),
343 QuitMessageLoop(&message_loop_
)));
345 // Swap the two windows.
346 webrtc::WindowCapturer::Window temp
= list
[0];
349 window_capturer_
->SetWindowList(list
);