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 virtual ~FakeScreenCapturer() {}
37 // webrtc::ScreenCapturer implementation.
38 virtual void Start(Callback
* callback
) OVERRIDE
{
42 virtual 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 virtual void SetMouseShapeObserver(
51 MouseShapeObserver
* mouse_shape_observer
) OVERRIDE
{
55 virtual bool GetScreenList(ScreenList
* screens
) OVERRIDE
{
56 webrtc::ScreenCapturer::Screen screen
;
58 screens
->push_back(screen
);
62 virtual bool SelectScreen(webrtc::ScreenId id
) OVERRIDE
{
70 DISALLOW_COPY_AND_ASSIGN(FakeScreenCapturer
);
73 class FakeWindowCapturer
: public webrtc::WindowCapturer
{
78 virtual ~FakeWindowCapturer() {}
80 void SetWindowList(const WindowList
& list
) {
81 base::AutoLock
lock(window_list_lock_
);
85 // Sets |value| thats going to be used to memset() content of the frames
86 // generated for |window_id|. By default generated frames are set to zeros.
87 void SetNextFrameValue(WindowId window_id
, int8_t value
) {
88 base::AutoLock
lock(frame_values_lock_
);
89 frame_values_
[window_id
] = value
;
92 // webrtc::WindowCapturer implementation.
93 virtual void Start(Callback
* callback
) OVERRIDE
{
97 virtual void Capture(const webrtc::DesktopRegion
& region
) OVERRIDE
{
100 base::AutoLock
lock(frame_values_lock_
);
102 std::map
<WindowId
, int8_t>::iterator it
=
103 frame_values_
.find(selected_window_id_
);
104 int8_t value
= (it
!= frame_values_
.end()) ? it
->second
: 0;
105 webrtc::DesktopFrame
* frame
=
106 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
107 memset(frame
->data(), value
, frame
->stride() * frame
->size().height());
108 callback_
->OnCaptureCompleted(frame
);
111 virtual bool GetWindowList(WindowList
* windows
) OVERRIDE
{
112 base::AutoLock
lock(window_list_lock_
);
113 *windows
= window_list_
;
117 virtual bool SelectWindow(WindowId id
) OVERRIDE
{
118 selected_window_id_
= id
;
122 virtual bool BringSelectedWindowToFront() OVERRIDE
{
128 WindowList window_list_
;
129 base::Lock window_list_lock_
;
131 WindowId selected_window_id_
;
133 // Frames to be captured per window.
134 std::map
<WindowId
, int8_t> frame_values_
;
135 base::Lock frame_values_lock_
;
137 DISALLOW_COPY_AND_ASSIGN(FakeWindowCapturer
);
140 ACTION_P2(CheckListSize
, model
, expected_list_size
) {
141 EXPECT_EQ(expected_list_size
, model
->GetSourceCount());
144 ACTION_P(QuitMessageLoop
, message_loop
) {
145 message_loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitClosure());
148 class DesktopMediaListTest
: public testing::Test
{
150 DesktopMediaListTest()
151 : window_capturer_(NULL
),
152 ui_thread_(content::BrowserThread::UI
,
156 void CreateWithDefaultCapturers() {
157 window_capturer_
= new FakeWindowCapturer();
158 model_
.reset(new NativeDesktopMediaList(
159 scoped_ptr
<webrtc::ScreenCapturer
>(new FakeScreenCapturer()),
160 scoped_ptr
<webrtc::WindowCapturer
>(window_capturer_
)));
162 // Set update period to reduce the time it takes to run tests.
163 model_
->SetUpdatePeriod(base::TimeDelta::FromMilliseconds(0));
166 webrtc::WindowCapturer::WindowList
AddWindowsAndVerify(
167 size_t count
, bool window_only
) {
168 webrtc::WindowCapturer::WindowList list
;
169 for (size_t i
= 0; i
< count
; ++i
) {
170 webrtc::WindowCapturer::Window window
;
172 window
.title
= "Test window";
173 list
.push_back(window
);
175 window_capturer_
->SetWindowList(list
);
178 testing::InSequence dummy
;
179 size_t source_count
= window_only
? count
: count
+ 1;
180 for (size_t i
= 0; i
< source_count
; ++i
) {
181 EXPECT_CALL(observer_
, OnSourceAdded(i
))
182 .WillOnce(CheckListSize(model_
.get(), static_cast<int>(i
+ 1)));
184 for (size_t i
= 0; i
< source_count
- 1; ++i
) {
185 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(i
));
187 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(source_count
- 1))
188 .WillOnce(QuitMessageLoop(&message_loop_
));
190 model_
->StartUpdating(&observer_
);
193 for (size_t i
= 0; i
< count
; ++i
) {
194 size_t source_index
= window_only
? i
: i
+ 1;
195 EXPECT_EQ(model_
->GetSource(source_index
).id
.type
,
196 content::DesktopMediaID::TYPE_WINDOW
);
197 EXPECT_EQ(model_
->GetSource(source_index
).id
.id
, static_cast<int>(i
+ 1));
198 EXPECT_EQ(model_
->GetSource(source_index
).name
,
199 base::UTF8ToUTF16("Test window"));
201 testing::Mock::VerifyAndClearExpectations(&observer_
);
206 // Must be listed before |model_|, so it's destroyed last.
207 MockObserver observer_
;
209 // Owned by |model_|;
210 FakeWindowCapturer
* window_capturer_
;
212 scoped_ptr
<NativeDesktopMediaList
> model_
;
214 base::MessageLoop message_loop_
;
215 content::TestBrowserThread ui_thread_
;
217 DISALLOW_COPY_AND_ASSIGN(DesktopMediaListTest
);
220 TEST_F(DesktopMediaListTest
, InitialSourceList
) {
221 CreateWithDefaultCapturers();
222 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(1, false);
224 EXPECT_EQ(model_
->GetSource(0).id
.type
, content::DesktopMediaID::TYPE_SCREEN
);
225 EXPECT_EQ(model_
->GetSource(0).id
.id
, 0);
228 // Verifies that the window specified with SetViewDialogWindowId() is filtered
230 TEST_F(DesktopMediaListTest
, Filtering
) {
231 CreateWithDefaultCapturers();
232 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(2, false);
234 EXPECT_EQ(model_
->GetSource(0).id
.type
, content::DesktopMediaID::TYPE_SCREEN
);
235 EXPECT_EQ(model_
->GetSource(0).id
.id
, 0);
238 TEST_F(DesktopMediaListTest
, WindowsOnly
) {
239 window_capturer_
= new FakeWindowCapturer();
240 model_
.reset(new NativeDesktopMediaList(
241 scoped_ptr
<webrtc::ScreenCapturer
>(),
242 scoped_ptr
<webrtc::WindowCapturer
>(window_capturer_
)));
243 AddWindowsAndVerify(1, true);
246 TEST_F(DesktopMediaListTest
, ScreenOnly
) {
247 model_
.reset(new NativeDesktopMediaList(
248 scoped_ptr
<webrtc::ScreenCapturer
>(new FakeScreenCapturer
),
249 scoped_ptr
<webrtc::WindowCapturer
>()));
252 testing::InSequence dummy
;
253 EXPECT_CALL(observer_
, OnSourceAdded(0))
254 .WillOnce(CheckListSize(model_
.get(), 1));
255 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(0))
256 .WillOnce(QuitMessageLoop(&message_loop_
));
258 model_
->StartUpdating(&observer_
);
262 EXPECT_EQ(model_
->GetSource(0).id
.type
, content::DesktopMediaID::TYPE_SCREEN
);
265 TEST_F(DesktopMediaListTest
, AddWindow
) {
266 CreateWithDefaultCapturers();
267 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(1, false);
269 EXPECT_CALL(observer_
, OnSourceAdded(2))
270 .WillOnce(DoAll(CheckListSize(model_
.get(), 3),
271 QuitMessageLoop(&message_loop_
)));
273 webrtc::WindowCapturer::Window window
;
275 window
.title
= "Test window 0";
276 list
.push_back(window
);
277 window_capturer_
->SetWindowList(list
);
281 EXPECT_EQ(model_
->GetSource(2).id
.type
, content::DesktopMediaID::TYPE_WINDOW
);
282 EXPECT_EQ(model_
->GetSource(2).id
.id
, 0);
285 TEST_F(DesktopMediaListTest
, RemoveWindow
) {
286 CreateWithDefaultCapturers();
287 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(2, false);
289 EXPECT_CALL(observer_
, OnSourceRemoved(2))
290 .WillOnce(DoAll(CheckListSize(model_
.get(), 2),
291 QuitMessageLoop(&message_loop_
)));
293 list
.erase(list
.begin() + 1);
294 window_capturer_
->SetWindowList(list
);
299 TEST_F(DesktopMediaListTest
, RemoveAllWindows
) {
300 CreateWithDefaultCapturers();
301 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(2, false);
303 testing::InSequence seq
;
304 EXPECT_CALL(observer_
, OnSourceRemoved(1))
305 .WillOnce(CheckListSize(model_
.get(), 2));
306 EXPECT_CALL(observer_
, OnSourceRemoved(1))
307 .WillOnce(DoAll(CheckListSize(model_
.get(), 1),
308 QuitMessageLoop(&message_loop_
)));
310 list
.erase(list
.begin(), list
.end());
311 window_capturer_
->SetWindowList(list
);
316 TEST_F(DesktopMediaListTest
, UpdateTitle
) {
317 CreateWithDefaultCapturers();
318 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(1, false);
320 EXPECT_CALL(observer_
, OnSourceNameChanged(1))
321 .WillOnce(QuitMessageLoop(&message_loop_
));
323 const std::string kTestTitle
= "New Title";
325 list
[0].title
= kTestTitle
;
326 window_capturer_
->SetWindowList(list
);
330 EXPECT_EQ(model_
->GetSource(1).name
, base::UTF8ToUTF16(kTestTitle
));
333 TEST_F(DesktopMediaListTest
, UpdateThumbnail
) {
334 CreateWithDefaultCapturers();
335 AddWindowsAndVerify(2, false);
337 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(1))
338 .WillOnce(QuitMessageLoop(&message_loop_
));
339 // Update frame for the window and verify that we get notification about it.
340 window_capturer_
->SetNextFrameValue(1, 1);
345 TEST_F(DesktopMediaListTest
, MoveWindow
) {
346 CreateWithDefaultCapturers();
347 webrtc::WindowCapturer::WindowList list
= AddWindowsAndVerify(2, false);
349 EXPECT_CALL(observer_
, OnSourceMoved(2, 1))
350 .WillOnce(DoAll(CheckListSize(model_
.get(), 3),
351 QuitMessageLoop(&message_loop_
)));
353 // Swap the two windows.
354 webrtc::WindowCapturer::Window temp
= list
[0];
357 window_capturer_
->SetWindowList(list
);