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 void SetMouseShapeObserver(
49 MouseShapeObserver* mouse_shape_observer) override {
53 bool GetScreenList(ScreenList* screens) override {
54 webrtc::ScreenCapturer::Screen screen;
56 screens->push_back(screen);
60 bool SelectScreen(webrtc::ScreenId id) override {
68 DISALLOW_COPY_AND_ASSIGN(FakeScreenCapturer);
71 class FakeWindowCapturer : public webrtc::WindowCapturer {
76 ~FakeWindowCapturer() override {}
78 void SetWindowList(const WindowList& list) {
79 base::AutoLock lock(window_list_lock_);
83 // Sets |value| thats going to be used to memset() content of the frames
84 // generated for |window_id|. By default generated frames are set to zeros.
85 void SetNextFrameValue(WindowId window_id, int8_t value) {
86 base::AutoLock lock(frame_values_lock_);
87 frame_values_[window_id] = value;
90 // webrtc::WindowCapturer implementation.
91 void Start(Callback* callback) override { callback_ = callback; }
93 void Capture(const webrtc::DesktopRegion& region) override {
96 base::AutoLock lock(frame_values_lock_);
98 std::map<WindowId, int8_t>::iterator it =
99 frame_values_.find(selected_window_id_);
100 int8_t value = (it != frame_values_.end()) ? it->second : 0;
101 webrtc::DesktopFrame* frame =
102 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
103 memset(frame->data(), value, frame->stride() * frame->size().height());
104 callback_->OnCaptureCompleted(frame);
107 bool GetWindowList(WindowList* windows) override {
108 base::AutoLock lock(window_list_lock_);
109 *windows = window_list_;
113 bool SelectWindow(WindowId id) override {
114 selected_window_id_ = id;
118 bool BringSelectedWindowToFront() override { return true; }
122 WindowList window_list_;
123 base::Lock window_list_lock_;
125 WindowId selected_window_id_;
127 // Frames to be captured per window.
128 std::map<WindowId, int8_t> frame_values_;
129 base::Lock frame_values_lock_;
131 DISALLOW_COPY_AND_ASSIGN(FakeWindowCapturer);
134 ACTION_P2(CheckListSize, model, expected_list_size) {
135 EXPECT_EQ(expected_list_size, model->GetSourceCount());
138 ACTION_P(QuitMessageLoop, message_loop) {
139 message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
142 class DesktopMediaListTest : public testing::Test {
144 DesktopMediaListTest()
145 : window_capturer_(NULL),
146 ui_thread_(content::BrowserThread::UI,
150 void CreateWithDefaultCapturers() {
151 window_capturer_ = new FakeWindowCapturer();
152 model_.reset(new NativeDesktopMediaList(
153 scoped_ptr<webrtc::ScreenCapturer>(new FakeScreenCapturer()),
154 scoped_ptr<webrtc::WindowCapturer>(window_capturer_)));
156 // Set update period to reduce the time it takes to run tests.
157 model_->SetUpdatePeriod(base::TimeDelta::FromMilliseconds(0));
160 webrtc::WindowCapturer::WindowList AddWindowsAndVerify(
161 size_t count, bool window_only) {
162 webrtc::WindowCapturer::WindowList list;
163 for (size_t i = 0; i < count; ++i) {
164 webrtc::WindowCapturer::Window window;
166 window.title = "Test window";
167 list.push_back(window);
169 window_capturer_->SetWindowList(list);
172 testing::InSequence dummy;
173 size_t source_count = window_only ? count : count + 1;
174 for (size_t i = 0; i < source_count; ++i) {
175 EXPECT_CALL(observer_, OnSourceAdded(i))
176 .WillOnce(CheckListSize(model_.get(), static_cast<int>(i + 1)));
178 for (size_t i = 0; i < source_count - 1; ++i) {
179 EXPECT_CALL(observer_, OnSourceThumbnailChanged(i));
181 EXPECT_CALL(observer_, OnSourceThumbnailChanged(source_count - 1))
182 .WillOnce(QuitMessageLoop(&message_loop_));
184 model_->StartUpdating(&observer_);
187 for (size_t i = 0; i < count; ++i) {
188 size_t source_index = window_only ? i : i + 1;
189 EXPECT_EQ(model_->GetSource(source_index).id.type,
190 content::DesktopMediaID::TYPE_WINDOW);
191 EXPECT_EQ(model_->GetSource(source_index).id.id, static_cast<int>(i + 1));
192 EXPECT_EQ(model_->GetSource(source_index).name,
193 base::UTF8ToUTF16("Test window"));
195 testing::Mock::VerifyAndClearExpectations(&observer_);
200 // Must be listed before |model_|, so it's destroyed last.
201 MockObserver observer_;
203 // Owned by |model_|;
204 FakeWindowCapturer* window_capturer_;
206 scoped_ptr<NativeDesktopMediaList> model_;
208 base::MessageLoop message_loop_;
209 content::TestBrowserThread ui_thread_;
211 DISALLOW_COPY_AND_ASSIGN(DesktopMediaListTest);
214 TEST_F(DesktopMediaListTest, InitialSourceList) {
215 CreateWithDefaultCapturers();
216 webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(1, false);
218 EXPECT_EQ(model_->GetSource(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
219 EXPECT_EQ(model_->GetSource(0).id.id, 0);
222 // Verifies that the window specified with SetViewDialogWindowId() is filtered
224 TEST_F(DesktopMediaListTest, Filtering) {
225 CreateWithDefaultCapturers();
226 webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(2, false);
228 EXPECT_EQ(model_->GetSource(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
229 EXPECT_EQ(model_->GetSource(0).id.id, 0);
232 TEST_F(DesktopMediaListTest, WindowsOnly) {
233 window_capturer_ = new FakeWindowCapturer();
234 model_.reset(new NativeDesktopMediaList(
235 scoped_ptr<webrtc::ScreenCapturer>(),
236 scoped_ptr<webrtc::WindowCapturer>(window_capturer_)));
237 AddWindowsAndVerify(1, true);
240 TEST_F(DesktopMediaListTest, ScreenOnly) {
241 model_.reset(new NativeDesktopMediaList(
242 scoped_ptr<webrtc::ScreenCapturer>(new FakeScreenCapturer),
243 scoped_ptr<webrtc::WindowCapturer>()));
246 testing::InSequence dummy;
247 EXPECT_CALL(observer_, OnSourceAdded(0))
248 .WillOnce(CheckListSize(model_.get(), 1));
249 EXPECT_CALL(observer_, OnSourceThumbnailChanged(0))
250 .WillOnce(QuitMessageLoop(&message_loop_));
252 model_->StartUpdating(&observer_);
256 EXPECT_EQ(model_->GetSource(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
259 TEST_F(DesktopMediaListTest, AddWindow) {
260 CreateWithDefaultCapturers();
261 webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(1, false);
263 EXPECT_CALL(observer_, OnSourceAdded(2))
264 .WillOnce(DoAll(CheckListSize(model_.get(), 3),
265 QuitMessageLoop(&message_loop_)));
267 webrtc::WindowCapturer::Window window;
269 window.title = "Test window 0";
270 list.push_back(window);
271 window_capturer_->SetWindowList(list);
275 EXPECT_EQ(model_->GetSource(2).id.type, content::DesktopMediaID::TYPE_WINDOW);
276 EXPECT_EQ(model_->GetSource(2).id.id, 0);
279 TEST_F(DesktopMediaListTest, RemoveWindow) {
280 CreateWithDefaultCapturers();
281 webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(2, false);
283 EXPECT_CALL(observer_, OnSourceRemoved(2))
284 .WillOnce(DoAll(CheckListSize(model_.get(), 2),
285 QuitMessageLoop(&message_loop_)));
287 list.erase(list.begin() + 1);
288 window_capturer_->SetWindowList(list);
293 TEST_F(DesktopMediaListTest, RemoveAllWindows) {
294 CreateWithDefaultCapturers();
295 webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(2, false);
297 testing::InSequence seq;
298 EXPECT_CALL(observer_, OnSourceRemoved(1))
299 .WillOnce(CheckListSize(model_.get(), 2));
300 EXPECT_CALL(observer_, OnSourceRemoved(1))
301 .WillOnce(DoAll(CheckListSize(model_.get(), 1),
302 QuitMessageLoop(&message_loop_)));
304 list.erase(list.begin(), list.end());
305 window_capturer_->SetWindowList(list);
310 TEST_F(DesktopMediaListTest, UpdateTitle) {
311 CreateWithDefaultCapturers();
312 webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(1, false);
314 EXPECT_CALL(observer_, OnSourceNameChanged(1))
315 .WillOnce(QuitMessageLoop(&message_loop_));
317 const std::string kTestTitle = "New Title";
319 list[0].title = kTestTitle;
320 window_capturer_->SetWindowList(list);
324 EXPECT_EQ(model_->GetSource(1).name, base::UTF8ToUTF16(kTestTitle));
327 TEST_F(DesktopMediaListTest, UpdateThumbnail) {
328 CreateWithDefaultCapturers();
329 AddWindowsAndVerify(2, false);
331 EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
332 .WillOnce(QuitMessageLoop(&message_loop_));
333 // Update frame for the window and verify that we get notification about it.
334 window_capturer_->SetNextFrameValue(1, 1);
339 TEST_F(DesktopMediaListTest, MoveWindow) {
340 CreateWithDefaultCapturers();
341 webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(2, false);
343 EXPECT_CALL(observer_, OnSourceMoved(2, 1))
344 .WillOnce(DoAll(CheckListSize(model_.get(), 3),
345 QuitMessageLoop(&message_loop_)));
347 // Swap the two windows.
348 webrtc::WindowCapturer::Window temp = list[0];
351 window_capturer_->SetWindowList(list);