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_METHOD1(OnSourceNameChanged
, void(int index
));
28 MOCK_METHOD1(OnSourceThumbnailChanged
, void(int index
));
31 class FakeScreenCapturer
: public webrtc::ScreenCapturer
{
33 FakeScreenCapturer() {}
34 virtual ~FakeScreenCapturer() {}
36 // webrtc::ScreenCapturer implementation.
37 virtual void Start(Callback
* callback
) OVERRIDE
{
41 virtual void Capture(const webrtc::DesktopRegion
& region
) OVERRIDE
{
43 webrtc::DesktopFrame
* frame
=
44 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
45 memset(frame
->data(), 0, frame
->stride() * frame
->size().height());
46 callback_
->OnCaptureCompleted(frame
);
49 virtual void SetMouseShapeObserver(
50 MouseShapeObserver
* mouse_shape_observer
) OVERRIDE
{
54 virtual bool GetScreenList(ScreenList
* screens
) OVERRIDE
{
58 virtual bool SelectScreen(webrtc::ScreenId id
) OVERRIDE
{
65 DISALLOW_COPY_AND_ASSIGN(FakeScreenCapturer
);
68 class FakeWindowCapturer
: public webrtc::WindowCapturer
{
73 virtual ~FakeWindowCapturer() {}
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 virtual void Start(Callback
* callback
) OVERRIDE
{
92 virtual void Capture(const webrtc::DesktopRegion
& region
) OVERRIDE
{
95 base::AutoLock
lock(frame_values_lock_
);
97 std::map
<WindowId
, int8_t>::iterator it
=
98 frame_values_
.find(selected_window_id_
);
99 int8_t value
= (it
!= frame_values_
.end()) ? it
->second
: 0;
100 webrtc::DesktopFrame
* frame
=
101 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
102 memset(frame
->data(), value
, frame
->stride() * frame
->size().height());
103 callback_
->OnCaptureCompleted(frame
);
106 virtual bool GetWindowList(WindowList
* windows
) OVERRIDE
{
107 base::AutoLock
lock(window_list_lock_
);
108 *windows
= window_list_
;
112 virtual bool SelectWindow(WindowId id
) OVERRIDE
{
113 selected_window_id_
= id
;
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 class DesktopMediaListTest
: public testing::Test
{
133 DesktopMediaListTest()
134 : window_capturer_(NULL
),
135 ui_thread_(content::BrowserThread::UI
,
139 void CreateWithDefaultCapturers() {
140 window_capturer_
= new FakeWindowCapturer();
141 model_
.reset(new NativeDesktopMediaList(
142 scoped_ptr
<webrtc::ScreenCapturer
>(new FakeScreenCapturer()),
143 scoped_ptr
<webrtc::WindowCapturer
>(window_capturer_
)));
145 // Set update period to reduce the time it takes to run tests.
146 model_
->SetUpdatePeriod(base::TimeDelta::FromMilliseconds(0));
150 // Must be listed before |model_|, so it's destroyed last.
151 MockObserver observer_
;
153 // Owned by |model_|;
154 FakeWindowCapturer
* window_capturer_
;
156 scoped_ptr
<NativeDesktopMediaList
> model_
;
158 base::MessageLoop message_loop_
;
159 content::TestBrowserThread ui_thread_
;
161 DISALLOW_COPY_AND_ASSIGN(DesktopMediaListTest
);
164 ACTION_P2(CheckListSize
, model
, expected_list_size
) {
165 EXPECT_EQ(expected_list_size
, model
->GetSourceCount());
168 ACTION_P(QuitMessageLoop
, message_loop
) {
169 message_loop
->PostTask(FROM_HERE
, base::MessageLoop::QuitClosure());
172 TEST_F(DesktopMediaListTest
, InitialSourceList
) {
173 CreateWithDefaultCapturers();
175 webrtc::WindowCapturer::WindowList list
;
176 webrtc::WindowCapturer::Window window
;
178 window
.title
= "Test window";
179 list
.push_back(window
);
180 window_capturer_
->SetWindowList(list
);
183 testing::InSequence dummy
;
184 EXPECT_CALL(observer_
, OnSourceAdded(0))
185 .WillOnce(CheckListSize(model_
.get(), 1));
186 EXPECT_CALL(observer_
, OnSourceAdded(1))
187 .WillOnce(CheckListSize(model_
.get(), 2));
188 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(0));
189 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(1))
190 .WillOnce(QuitMessageLoop(&message_loop_
));
192 model_
->StartUpdating(&observer_
);
196 EXPECT_EQ(model_
->GetSource(0).id
.type
, content::DesktopMediaID::TYPE_SCREEN
);
197 EXPECT_EQ(model_
->GetSource(0).id
.id
, 0);
198 EXPECT_EQ(model_
->GetSource(1).id
.type
, content::DesktopMediaID::TYPE_WINDOW
);
199 EXPECT_EQ(model_
->GetSource(1).id
.id
, 0);
200 EXPECT_EQ(model_
->GetSource(1).name
, base::UTF8ToUTF16(window
.title
));
203 // Verifies that the window specified with SetViewDialogWindowId() is filtered
205 TEST_F(DesktopMediaListTest
, Filtering
) {
206 CreateWithDefaultCapturers();
208 webrtc::WindowCapturer::WindowList list
;
209 webrtc::WindowCapturer::Window window
;
212 window
.title
= "Test window";
213 list
.push_back(window
);
216 list
.push_back(window
);
218 window_capturer_
->SetWindowList(list
);
221 testing::InSequence dummy
;
222 EXPECT_CALL(observer_
, OnSourceAdded(0))
223 .WillOnce(CheckListSize(model_
.get(), 1));
224 EXPECT_CALL(observer_
, OnSourceAdded(1))
225 .WillOnce(CheckListSize(model_
.get(), 2));
226 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(0));
227 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(1))
228 .WillOnce(QuitMessageLoop(&message_loop_
));
231 model_
->SetViewDialogWindowId(0);
233 model_
->StartUpdating(&observer_
);
236 EXPECT_EQ(model_
->GetSource(0).id
.type
, content::DesktopMediaID::TYPE_SCREEN
);
237 EXPECT_EQ(model_
->GetSource(0).id
.id
, 0);
238 EXPECT_EQ(model_
->GetSource(1).id
.type
, content::DesktopMediaID::TYPE_WINDOW
);
239 EXPECT_EQ(model_
->GetSource(1).id
.id
, 1);
240 EXPECT_EQ(model_
->GetSource(1).name
, base::UTF8ToUTF16(window
.title
));
243 TEST_F(DesktopMediaListTest
, WindowsOnly
) {
244 window_capturer_
= new FakeWindowCapturer();
245 model_
.reset(new NativeDesktopMediaList(
246 scoped_ptr
<webrtc::ScreenCapturer
>(),
247 scoped_ptr
<webrtc::WindowCapturer
>(window_capturer_
)));
249 webrtc::WindowCapturer::WindowList list
;
250 webrtc::WindowCapturer::Window window
;
252 window
.title
= "Test window";
253 list
.push_back(window
);
254 window_capturer_
->SetWindowList(list
);
257 testing::InSequence dummy
;
258 EXPECT_CALL(observer_
, OnSourceAdded(0))
259 .WillOnce(CheckListSize(model_
.get(), 1));
260 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(0))
261 .WillOnce(QuitMessageLoop(&message_loop_
));
263 model_
->StartUpdating(&observer_
);
267 EXPECT_EQ(model_
->GetSource(0).id
.type
, content::DesktopMediaID::TYPE_WINDOW
);
270 TEST_F(DesktopMediaListTest
, ScreenOnly
) {
271 model_
.reset(new NativeDesktopMediaList(
272 scoped_ptr
<webrtc::ScreenCapturer
>(new FakeScreenCapturer
),
273 scoped_ptr
<webrtc::WindowCapturer
>()));
276 testing::InSequence dummy
;
277 EXPECT_CALL(observer_
, OnSourceAdded(0))
278 .WillOnce(CheckListSize(model_
.get(), 1));
279 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(0))
280 .WillOnce(QuitMessageLoop(&message_loop_
));
282 model_
->StartUpdating(&observer_
);
286 EXPECT_EQ(model_
->GetSource(0).id
.type
, content::DesktopMediaID::TYPE_SCREEN
);
289 TEST_F(DesktopMediaListTest
, AddWindow
) {
290 CreateWithDefaultCapturers();
292 webrtc::WindowCapturer::WindowList list
;
293 webrtc::WindowCapturer::Window window
;
295 window
.title
= "Test window 1";
296 list
.push_back(window
);
297 window_capturer_
->SetWindowList(list
);
300 testing::InSequence dummy
;
301 EXPECT_CALL(observer_
, OnSourceAdded(0))
302 .WillOnce(CheckListSize(model_
.get(), 1));
303 EXPECT_CALL(observer_
, OnSourceAdded(1))
304 .WillOnce(CheckListSize(model_
.get(), 2));
305 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(0));
306 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(1))
307 .WillOnce(QuitMessageLoop(&message_loop_
));
309 model_
->StartUpdating(&observer_
);
313 testing::Mock::VerifyAndClearExpectations(&observer_
);
315 EXPECT_CALL(observer_
, OnSourceAdded(1))
316 .WillOnce(DoAll(CheckListSize(model_
.get(), 3),
317 QuitMessageLoop(&message_loop_
)));
320 window
.title
= "Test window 0";
321 list
.push_back(window
);
322 window_capturer_
->SetWindowList(list
);
326 EXPECT_EQ(model_
->GetSource(1).id
.type
, content::DesktopMediaID::TYPE_WINDOW
);
327 EXPECT_EQ(model_
->GetSource(1).id
.id
, 0);
330 TEST_F(DesktopMediaListTest
, RemoveWindow
) {
331 CreateWithDefaultCapturers();
333 webrtc::WindowCapturer::WindowList list
;
334 webrtc::WindowCapturer::Window window
;
336 window
.title
= "Test window 0";
337 list
.push_back(window
);
339 window
.title
= "Test window 1";
340 list
.push_back(window
);
341 window_capturer_
->SetWindowList(list
);
344 testing::InSequence dummy
;
345 EXPECT_CALL(observer_
, OnSourceAdded(0))
346 .WillOnce(CheckListSize(model_
.get(), 1));
347 EXPECT_CALL(observer_
, OnSourceAdded(1))
348 .WillOnce(CheckListSize(model_
.get(), 2));
349 EXPECT_CALL(observer_
, OnSourceAdded(2))
350 .WillOnce(CheckListSize(model_
.get(), 3));
351 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(0));
352 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(1));
353 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(2))
354 .WillOnce(QuitMessageLoop(&message_loop_
));
356 model_
->StartUpdating(&observer_
);
360 testing::Mock::VerifyAndClearExpectations(&observer_
);
362 EXPECT_CALL(observer_
, OnSourceRemoved(1))
363 .WillOnce(DoAll(CheckListSize(model_
.get(), 2),
364 QuitMessageLoop(&message_loop_
)));
366 list
.erase(list
.begin());
367 window_capturer_
->SetWindowList(list
);
372 TEST_F(DesktopMediaListTest
, UpdateTitle
) {
373 CreateWithDefaultCapturers();
375 webrtc::WindowCapturer::WindowList list
;
376 webrtc::WindowCapturer::Window window
;
378 window
.title
= "Test window";
379 list
.push_back(window
);
380 window_capturer_
->SetWindowList(list
);
383 testing::InSequence dummy
;
384 EXPECT_CALL(observer_
, OnSourceAdded(0))
385 .WillOnce(CheckListSize(model_
.get(), 1));
386 EXPECT_CALL(observer_
, OnSourceAdded(1))
387 .WillOnce(CheckListSize(model_
.get(), 2));
388 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(0));
389 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(1))
390 .WillOnce(QuitMessageLoop(&message_loop_
));
392 model_
->StartUpdating(&observer_
);
396 testing::Mock::VerifyAndClearExpectations(&observer_
);
398 EXPECT_CALL(observer_
, OnSourceNameChanged(1))
399 .WillOnce(QuitMessageLoop(&message_loop_
));
401 const std::string kTestTitle
= "New Title";
403 list
[0].title
= kTestTitle
;
404 window_capturer_
->SetWindowList(list
);
408 EXPECT_EQ(model_
->GetSource(1).name
, base::UTF8ToUTF16(kTestTitle
));
411 TEST_F(DesktopMediaListTest
, UpdateThumbnail
) {
412 CreateWithDefaultCapturers();
414 webrtc::WindowCapturer::WindowList list
;
415 webrtc::WindowCapturer::Window window
;
417 window
.title
= "Test window 1";
418 list
.push_back(window
);
420 window
.title
= "Test window 2";
421 list
.push_back(window
);
422 window_capturer_
->SetWindowList(list
);
425 testing::InSequence dummy
;
426 EXPECT_CALL(observer_
, OnSourceAdded(0))
427 .WillOnce(CheckListSize(model_
.get(), 1));
428 EXPECT_CALL(observer_
, OnSourceAdded(1))
429 .WillOnce(CheckListSize(model_
.get(), 2));
430 EXPECT_CALL(observer_
, OnSourceAdded(2))
431 .WillOnce(CheckListSize(model_
.get(), 3));
432 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(0));
433 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(1));
434 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(2))
435 .WillOnce(QuitMessageLoop(&message_loop_
));
437 model_
->StartUpdating(&observer_
);
441 testing::Mock::VerifyAndClearExpectations(&observer_
);
443 EXPECT_CALL(observer_
, OnSourceThumbnailChanged(1))
444 .WillOnce(QuitMessageLoop(&message_loop_
));
446 // Update frame for the window and verify that we get notification about it.
447 window_capturer_
->SetNextFrameValue(0, 1);