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/message_loop/message_loop.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/synchronization/lock.h"
10 #include "chrome/browser/media/desktop_media_list_observer.h"
11 #include "content/public/test/test_browser_thread.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
15 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
16 #include "third_party/webrtc/modules/desktop_capture/window_capturer.h"
23 class MockObserver
: public DesktopMediaListObserver
{
25 MOCK_METHOD1(OnSourceAdded
, void(int index
));
26 MOCK_METHOD1(OnSourceRemoved
, void(int index
));
27 MOCK_METHOD2(OnSourceMoved
, void(int old_index
, int new_index
));
28 MOCK_METHOD1(OnSourceNameChanged
, void(int index
));
29 MOCK_METHOD1(OnSourceThumbnailChanged
, void(int index
));
32 class FakeScreenCapturer
: public webrtc::ScreenCapturer
{
34 FakeScreenCapturer() {}
35 ~FakeScreenCapturer() override
{}
37 // webrtc::ScreenCapturer implementation.
38 void Start(Callback
* callback
) override
{ callback_
= callback
; }
40 void Capture(const webrtc::DesktopRegion
& region
) override
{
42 webrtc::DesktopFrame
* frame
=
43 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
44 memset(frame
->data(), 0, frame
->stride() * frame
->size().height());
45 callback_
->OnCaptureCompleted(frame
);
48 bool GetScreenList(ScreenList
* screens
) override
{
49 webrtc::ScreenCapturer::Screen screen
;
51 screens
->push_back(screen
);
55 bool SelectScreen(webrtc::ScreenId id
) override
{
63 DISALLOW_COPY_AND_ASSIGN(FakeScreenCapturer
);
66 class FakeWindowCapturer
: public webrtc::WindowCapturer
{
71 ~FakeWindowCapturer() override
{}
73 void SetWindowList(const WindowList
& list
) {
74 base::AutoLock
lock(window_list_lock_
);
78 // Sets |value| thats going to be used to memset() content of the frames
79 // generated for |window_id|. By default generated frames are set to zeros.
80 void SetNextFrameValue(WindowId window_id
, int8_t value
) {
81 base::AutoLock
lock(frame_values_lock_
);
82 frame_values_
[window_id
] = value
;
85 // webrtc::WindowCapturer implementation.
86 void Start(Callback
* callback
) override
{ callback_
= callback
; }
88 void Capture(const webrtc::DesktopRegion
& region
) override
{
91 base::AutoLock
lock(frame_values_lock_
);
93 std::map
<WindowId
, int8_t>::iterator it
=
94 frame_values_
.find(selected_window_id_
);
95 int8_t value
= (it
!= frame_values_
.end()) ? it
->second
: 0;
96 webrtc::DesktopFrame
* frame
=
97 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
98 memset(frame
->data(), value
, frame
->stride() * frame
->size().height());
99 callback_
->OnCaptureCompleted(frame
);
102 bool GetWindowList(WindowList
* windows
) override
{
103 base::AutoLock
lock(window_list_lock_
);
104 *windows
= window_list_
;
108 bool SelectWindow(WindowId id
) override
{
109 selected_window_id_
= id
;
113 bool BringSelectedWindowToFront() override
{ return true; }
117 WindowList window_list_
;
118 base::Lock window_list_lock_
;
120 WindowId selected_window_id_
;
122 // Frames to be captured per window.
123 std::map
<WindowId
, int8_t> frame_values_
;
124 base::Lock frame_values_lock_
;
126 DISALLOW_COPY_AND_ASSIGN(FakeWindowCapturer
);
129 ACTION_P2(CheckListSize
, model
, expected_list_size
) {
130 EXPECT_EQ(expected_list_size
, model
->GetSourceCount());
133 ACTION_P(QuitMessageLoop
, message_loop
) {
134 message_loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitClosure());
137 class DesktopMediaListTest
: public testing::Test
{
139 DesktopMediaListTest()
140 : window_capturer_(NULL
),
141 ui_thread_(content::BrowserThread::UI
,
145 void CreateWithDefaultCapturers() {
146 window_capturer_
= new FakeWindowCapturer();
147 model_
.reset(new NativeDesktopMediaList(
148 scoped_ptr
<webrtc::ScreenCapturer
>(new FakeScreenCapturer()),
149 scoped_ptr
<webrtc::WindowCapturer
>(window_capturer_
)));
151 // Set update period to reduce the time it takes to run tests.
152 model_
->SetUpdatePeriod(base::TimeDelta::FromMilliseconds(0));
155 webrtc::WindowCapturer::WindowList
AddWindowsAndVerify(
156 size_t count
, bool window_only
) {
157 webrtc::WindowCapturer::WindowList list
;
158 for (size_t i
= 0; i
< count
; ++i
) {
159 webrtc::WindowCapturer::Window window
;
161 window
.title
= "Test window";
162 list
.push_back(window
);
164 window_capturer_
->SetWindowList(list
);
167 testing::InSequence dummy
;
168 size_t source_count
= window_only
? count
: count
+ 1;
169 for (size_t i
= 0; i
< source_count
; ++i
) {
170 EXPECT_CALL(observer_
, OnSourceAdded(i
))
171 .WillOnce(CheckListSize(model_
.get(), static_cast<int>(i
+ 1)));
173 for (size_t i
= 0; i
< source_count
- 1; ++i
) {
174 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(i
));
176 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(source_count
- 1))
177 .WillOnce(QuitMessageLoop(&message_loop_
));
179 model_
->StartUpdating(&observer_
);
182 for (size_t i
= 0; i
< count
; ++i
) {
183 size_t source_index
= window_only
? i
: i
+ 1;
184 EXPECT_EQ(model_
->GetSource(source_index
).id
.type
,
185 content::DesktopMediaID::TYPE_WINDOW
);
186 EXPECT_EQ(model_
->GetSource(source_index
).id
.id
, static_cast<int>(i
+ 1));
187 EXPECT_EQ(model_
->GetSource(source_index
).name
,
188 base::UTF8ToUTF16("Test window"));
190 testing::Mock::VerifyAndClearExpectations(&observer_
);
195 // Must be listed before |model_|, so it's destroyed last.
196 MockObserver observer_
;
198 // Owned by |model_|;
199 FakeWindowCapturer
* window_capturer_
;
201 scoped_ptr
<NativeDesktopMediaList
> model_
;
203 base::MessageLoop message_loop_
;
204 content::TestBrowserThread ui_thread_
;
206 DISALLOW_COPY_AND_ASSIGN(DesktopMediaListTest
);
209 TEST_F(DesktopMediaListTest
, InitialSourceList
) {
210 CreateWithDefaultCapturers();
211 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(1, false);
213 EXPECT_EQ(model_
->GetSource(0).id
.type
, content::DesktopMediaID::TYPE_SCREEN
);
214 EXPECT_EQ(model_
->GetSource(0).id
.id
, 0);
217 // Verifies that the window specified with SetViewDialogWindowId() is filtered
219 TEST_F(DesktopMediaListTest
, Filtering
) {
220 CreateWithDefaultCapturers();
221 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(2, false);
223 EXPECT_EQ(model_
->GetSource(0).id
.type
, content::DesktopMediaID::TYPE_SCREEN
);
224 EXPECT_EQ(model_
->GetSource(0).id
.id
, 0);
227 TEST_F(DesktopMediaListTest
, WindowsOnly
) {
228 window_capturer_
= new FakeWindowCapturer();
229 model_
.reset(new NativeDesktopMediaList(
230 scoped_ptr
<webrtc::ScreenCapturer
>(),
231 scoped_ptr
<webrtc::WindowCapturer
>(window_capturer_
)));
232 AddWindowsAndVerify(1, true);
235 TEST_F(DesktopMediaListTest
, ScreenOnly
) {
236 model_
.reset(new NativeDesktopMediaList(
237 scoped_ptr
<webrtc::ScreenCapturer
>(new FakeScreenCapturer
),
238 scoped_ptr
<webrtc::WindowCapturer
>()));
241 testing::InSequence dummy
;
242 EXPECT_CALL(observer_
, OnSourceAdded(0))
243 .WillOnce(CheckListSize(model_
.get(), 1));
244 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(0))
245 .WillOnce(QuitMessageLoop(&message_loop_
));
247 model_
->StartUpdating(&observer_
);
251 EXPECT_EQ(model_
->GetSource(0).id
.type
, content::DesktopMediaID::TYPE_SCREEN
);
254 TEST_F(DesktopMediaListTest
, AddWindow
) {
255 CreateWithDefaultCapturers();
256 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(1, false);
258 EXPECT_CALL(observer_
, OnSourceAdded(2))
259 .WillOnce(DoAll(CheckListSize(model_
.get(), 3),
260 QuitMessageLoop(&message_loop_
)));
262 webrtc::WindowCapturer::Window window
;
264 window
.title
= "Test window 0";
265 list
.push_back(window
);
266 window_capturer_
->SetWindowList(list
);
270 EXPECT_EQ(model_
->GetSource(2).id
.type
, content::DesktopMediaID::TYPE_WINDOW
);
271 EXPECT_EQ(model_
->GetSource(2).id
.id
, 0);
274 TEST_F(DesktopMediaListTest
, RemoveWindow
) {
275 CreateWithDefaultCapturers();
276 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(2, false);
278 EXPECT_CALL(observer_
, OnSourceRemoved(2))
279 .WillOnce(DoAll(CheckListSize(model_
.get(), 2),
280 QuitMessageLoop(&message_loop_
)));
282 list
.erase(list
.begin() + 1);
283 window_capturer_
->SetWindowList(list
);
288 TEST_F(DesktopMediaListTest
, RemoveAllWindows
) {
289 CreateWithDefaultCapturers();
290 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(2, false);
292 testing::InSequence seq
;
293 EXPECT_CALL(observer_
, OnSourceRemoved(1))
294 .WillOnce(CheckListSize(model_
.get(), 2));
295 EXPECT_CALL(observer_
, OnSourceRemoved(1))
296 .WillOnce(DoAll(CheckListSize(model_
.get(), 1),
297 QuitMessageLoop(&message_loop_
)));
299 list
.erase(list
.begin(), list
.end());
300 window_capturer_
->SetWindowList(list
);
305 TEST_F(DesktopMediaListTest
, UpdateTitle
) {
306 CreateWithDefaultCapturers();
307 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(1, false);
309 EXPECT_CALL(observer_
, OnSourceNameChanged(1))
310 .WillOnce(QuitMessageLoop(&message_loop_
));
312 const std::string kTestTitle
= "New Title";
314 list
[0].title
= kTestTitle
;
315 window_capturer_
->SetWindowList(list
);
319 EXPECT_EQ(model_
->GetSource(1).name
, base::UTF8ToUTF16(kTestTitle
));
322 TEST_F(DesktopMediaListTest
, UpdateThumbnail
) {
323 CreateWithDefaultCapturers();
324 AddWindowsAndVerify(2, false);
326 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(1))
327 .WillOnce(QuitMessageLoop(&message_loop_
));
328 // Update frame for the window and verify that we get notification about it.
329 window_capturer_
->SetNextFrameValue(1, 1);
334 TEST_F(DesktopMediaListTest
, MoveWindow
) {
335 CreateWithDefaultCapturers();
336 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(2, false);
338 EXPECT_CALL(observer_
, OnSourceMoved(2, 1))
339 .WillOnce(DoAll(CheckListSize(model_
.get(), 3),
340 QuitMessageLoop(&message_loop_
)));
342 // Swap the two windows.
343 webrtc::WindowCapturer::Window temp
= list
[0];
346 window_capturer_
->SetWindowList(list
);