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;
124 WindowList window_list_;
125 base::Lock window_list_lock_;
127 WindowId selected_window_id_;
129 // Frames to be captured per window.
130 std::map<WindowId, int8_t> frame_values_;
131 base::Lock frame_values_lock_;
133 DISALLOW_COPY_AND_ASSIGN(FakeWindowCapturer);
136 ACTION_P2(CheckListSize, model, expected_list_size) {
137 EXPECT_EQ(expected_list_size, model->GetSourceCount());
140 ACTION_P(QuitMessageLoop, message_loop) {
141 message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
144 class DesktopMediaListTest : public testing::Test {
146 DesktopMediaListTest()
147 : window_capturer_(NULL),
148 ui_thread_(content::BrowserThread::UI,
152 void CreateWithDefaultCapturers() {
153 window_capturer_ = new FakeWindowCapturer();
154 model_.reset(new NativeDesktopMediaList(
155 scoped_ptr<webrtc::ScreenCapturer>(new FakeScreenCapturer()),
156 scoped_ptr<webrtc::WindowCapturer>(window_capturer_)));
158 // Set update period to reduce the time it takes to run tests.
159 model_->SetUpdatePeriod(base::TimeDelta::FromMilliseconds(0));
162 webrtc::WindowCapturer::WindowList AddWindowsAndVerify(
163 size_t count, bool window_only) {
164 webrtc::WindowCapturer::WindowList list;
165 for (size_t i = 0; i < count; ++i) {
166 webrtc::WindowCapturer::Window window;
168 window.title = "Test window";
169 list.push_back(window);
171 window_capturer_->SetWindowList(list);
174 testing::InSequence dummy;
175 size_t source_count = window_only ? count : count + 1;
176 for (size_t i = 0; i < source_count; ++i) {
177 EXPECT_CALL(observer_, OnSourceAdded(i))
178 .WillOnce(CheckListSize(model_.get(), static_cast<int>(i + 1)));
180 for (size_t i = 0; i < source_count - 1; ++i) {
181 EXPECT_CALL(observer_, OnSourceThumbnailChanged(i));
183 EXPECT_CALL(observer_, OnSourceThumbnailChanged(source_count - 1))
184 .WillOnce(QuitMessageLoop(&message_loop_));
186 model_->StartUpdating(&observer_);
189 for (size_t i = 0; i < count; ++i) {
190 size_t source_index = window_only ? i : i + 1;
191 EXPECT_EQ(model_->GetSource(source_index).id.type,
192 content::DesktopMediaID::TYPE_WINDOW);
193 EXPECT_EQ(model_->GetSource(source_index).id.id, static_cast<int>(i + 1));
194 EXPECT_EQ(model_->GetSource(source_index).name,
195 base::UTF8ToUTF16("Test window"));
197 testing::Mock::VerifyAndClearExpectations(&observer_);
202 // Must be listed before |model_|, so it's destroyed last.
203 MockObserver observer_;
205 // Owned by |model_|;
206 FakeWindowCapturer* window_capturer_;
208 scoped_ptr<NativeDesktopMediaList> model_;
210 base::MessageLoop message_loop_;
211 content::TestBrowserThread ui_thread_;
213 DISALLOW_COPY_AND_ASSIGN(DesktopMediaListTest);
216 TEST_F(DesktopMediaListTest, InitialSourceList) {
217 CreateWithDefaultCapturers();
218 webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(1, false);
220 EXPECT_EQ(model_->GetSource(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
221 EXPECT_EQ(model_->GetSource(0).id.id, 0);
224 // Verifies that the window specified with SetViewDialogWindowId() is filtered
226 TEST_F(DesktopMediaListTest, Filtering) {
227 CreateWithDefaultCapturers();
228 webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(2, false);
230 EXPECT_EQ(model_->GetSource(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
231 EXPECT_EQ(model_->GetSource(0).id.id, 0);
234 TEST_F(DesktopMediaListTest, WindowsOnly) {
235 window_capturer_ = new FakeWindowCapturer();
236 model_.reset(new NativeDesktopMediaList(
237 scoped_ptr<webrtc::ScreenCapturer>(),
238 scoped_ptr<webrtc::WindowCapturer>(window_capturer_)));
239 AddWindowsAndVerify(1, true);
242 TEST_F(DesktopMediaListTest, ScreenOnly) {
243 model_.reset(new NativeDesktopMediaList(
244 scoped_ptr<webrtc::ScreenCapturer>(new FakeScreenCapturer),
245 scoped_ptr<webrtc::WindowCapturer>()));
248 testing::InSequence dummy;
249 EXPECT_CALL(observer_, OnSourceAdded(0))
250 .WillOnce(CheckListSize(model_.get(), 1));
251 EXPECT_CALL(observer_, OnSourceThumbnailChanged(0))
252 .WillOnce(QuitMessageLoop(&message_loop_));
254 model_->StartUpdating(&observer_);
258 EXPECT_EQ(model_->GetSource(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
261 TEST_F(DesktopMediaListTest, AddWindow) {
262 CreateWithDefaultCapturers();
263 webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(1, false);
265 EXPECT_CALL(observer_, OnSourceAdded(2))
266 .WillOnce(DoAll(CheckListSize(model_.get(), 3),
267 QuitMessageLoop(&message_loop_)));
269 webrtc::WindowCapturer::Window window;
271 window.title = "Test window 0";
272 list.push_back(window);
273 window_capturer_->SetWindowList(list);
277 EXPECT_EQ(model_->GetSource(2).id.type, content::DesktopMediaID::TYPE_WINDOW);
278 EXPECT_EQ(model_->GetSource(2).id.id, 0);
281 TEST_F(DesktopMediaListTest, RemoveWindow) {
282 CreateWithDefaultCapturers();
283 webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(2, false);
285 EXPECT_CALL(observer_, OnSourceRemoved(2))
286 .WillOnce(DoAll(CheckListSize(model_.get(), 2),
287 QuitMessageLoop(&message_loop_)));
289 list.erase(list.begin() + 1);
290 window_capturer_->SetWindowList(list);
295 TEST_F(DesktopMediaListTest, RemoveAllWindows) {
296 CreateWithDefaultCapturers();
297 webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(2, false);
299 testing::InSequence seq;
300 EXPECT_CALL(observer_, OnSourceRemoved(1))
301 .WillOnce(CheckListSize(model_.get(), 2));
302 EXPECT_CALL(observer_, OnSourceRemoved(1))
303 .WillOnce(DoAll(CheckListSize(model_.get(), 1),
304 QuitMessageLoop(&message_loop_)));
306 list.erase(list.begin(), list.end());
307 window_capturer_->SetWindowList(list);
312 TEST_F(DesktopMediaListTest, UpdateTitle) {
313 CreateWithDefaultCapturers();
314 webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(1, false);
316 EXPECT_CALL(observer_, OnSourceNameChanged(1))
317 .WillOnce(QuitMessageLoop(&message_loop_));
319 const std::string kTestTitle = "New Title";
321 list[0].title = kTestTitle;
322 window_capturer_->SetWindowList(list);
326 EXPECT_EQ(model_->GetSource(1).name, base::UTF8ToUTF16(kTestTitle));
329 TEST_F(DesktopMediaListTest, UpdateThumbnail) {
330 CreateWithDefaultCapturers();
331 AddWindowsAndVerify(2, false);
333 EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
334 .WillOnce(QuitMessageLoop(&message_loop_));
335 // Update frame for the window and verify that we get notification about it.
336 window_capturer_->SetNextFrameValue(1, 1);
341 TEST_F(DesktopMediaListTest, MoveWindow) {
342 CreateWithDefaultCapturers();
343 webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(2, false);
345 EXPECT_CALL(observer_, OnSourceMoved(2, 1))
346 .WillOnce(DoAll(CheckListSize(model_.get(), 3),
347 QuitMessageLoop(&message_loop_)));
349 // Swap the two windows.
350 webrtc::WindowCapturer::Window temp = list[0];
353 window_capturer_->SetWindowList(list);