• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/media/native_desktop_media_list.h"
6 
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"
17 
18 using testing::_;
19 using testing::DoAll;
20 
21 namespace {
22 
23 class MockObserver : public DesktopMediaListObserver {
24  public:
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));
30 };
31 
32 class FakeScreenCapturer : public webrtc::ScreenCapturer {
33  public:
FakeScreenCapturer()34   FakeScreenCapturer() {}
~FakeScreenCapturer()35   virtual ~FakeScreenCapturer() {}
36 
37   // webrtc::ScreenCapturer implementation.
Start(Callback * callback)38   virtual void Start(Callback* callback) OVERRIDE {
39     callback_ = callback;
40   }
41 
Capture(const webrtc::DesktopRegion & region)42   virtual void Capture(const webrtc::DesktopRegion& region) OVERRIDE {
43     DCHECK(callback_);
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);
48   }
49 
SetMouseShapeObserver(MouseShapeObserver * mouse_shape_observer)50   virtual void SetMouseShapeObserver(
51       MouseShapeObserver* mouse_shape_observer) OVERRIDE {
52     NOTIMPLEMENTED();
53   }
54 
GetScreenList(ScreenList * screens)55   virtual bool GetScreenList(ScreenList* screens) OVERRIDE {
56     webrtc::ScreenCapturer::Screen screen;
57     screen.id = 0;
58     screens->push_back(screen);
59     return true;
60   }
61 
SelectScreen(webrtc::ScreenId id)62   virtual bool SelectScreen(webrtc::ScreenId id) OVERRIDE {
63     EXPECT_EQ(0, id);
64     return true;
65   }
66 
67  protected:
68   Callback* callback_;
69 
70   DISALLOW_COPY_AND_ASSIGN(FakeScreenCapturer);
71 };
72 
73 class FakeWindowCapturer : public webrtc::WindowCapturer {
74  public:
FakeWindowCapturer()75   FakeWindowCapturer()
76       : callback_(NULL) {
77   }
~FakeWindowCapturer()78   virtual ~FakeWindowCapturer() {}
79 
SetWindowList(const WindowList & list)80   void SetWindowList(const WindowList& list) {
81     base::AutoLock lock(window_list_lock_);
82     window_list_ = list;
83   }
84 
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.
SetNextFrameValue(WindowId window_id,int8_t value)87   void SetNextFrameValue(WindowId window_id, int8_t value) {
88     base::AutoLock lock(frame_values_lock_);
89     frame_values_[window_id] = value;
90   }
91 
92   // webrtc::WindowCapturer implementation.
Start(Callback * callback)93   virtual void Start(Callback* callback) OVERRIDE {
94     callback_ = callback;
95   }
96 
Capture(const webrtc::DesktopRegion & region)97   virtual void Capture(const webrtc::DesktopRegion& region) OVERRIDE {
98     DCHECK(callback_);
99 
100     base::AutoLock lock(frame_values_lock_);
101 
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);
109   }
110 
GetWindowList(WindowList * windows)111   virtual bool GetWindowList(WindowList* windows) OVERRIDE {
112     base::AutoLock lock(window_list_lock_);
113     *windows = window_list_;
114     return true;
115   }
116 
SelectWindow(WindowId id)117   virtual bool SelectWindow(WindowId id) OVERRIDE {
118     selected_window_id_ = id;
119     return true;
120   }
121 
BringSelectedWindowToFront()122   virtual bool BringSelectedWindowToFront() OVERRIDE {
123     return true;
124   }
125 
126  private:
127   Callback* callback_;
128   WindowList window_list_;
129   base::Lock window_list_lock_;
130 
131   WindowId selected_window_id_;
132 
133   // Frames to be captured per window.
134   std::map<WindowId, int8_t> frame_values_;
135   base::Lock frame_values_lock_;
136 
137   DISALLOW_COPY_AND_ASSIGN(FakeWindowCapturer);
138 };
139 
ACTION_P2(CheckListSize,model,expected_list_size)140 ACTION_P2(CheckListSize, model, expected_list_size) {
141   EXPECT_EQ(expected_list_size, model->GetSourceCount());
142 }
143 
ACTION_P(QuitMessageLoop,message_loop)144 ACTION_P(QuitMessageLoop, message_loop) {
145   message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
146 }
147 
148 class DesktopMediaListTest : public testing::Test {
149  public:
DesktopMediaListTest()150   DesktopMediaListTest()
151       : window_capturer_(NULL),
152         ui_thread_(content::BrowserThread::UI,
153                    &message_loop_) {
154   }
155 
CreateWithDefaultCapturers()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_)));
161 
162     // Set update period to reduce the time it takes to run tests.
163     model_->SetUpdatePeriod(base::TimeDelta::FromMilliseconds(0));
164   }
165 
AddWindowsAndVerify(size_t count,bool window_only)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;
171       window.id = i + 1;
172       window.title = "Test window";
173       list.push_back(window);
174     }
175     window_capturer_->SetWindowList(list);
176 
177     {
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)));
183       }
184       for (size_t i = 0; i < source_count - 1; ++i) {
185         EXPECT_CALL(observer_, OnSourceThumbnailChanged(i));
186       }
187       EXPECT_CALL(observer_, OnSourceThumbnailChanged(source_count - 1))
188         .WillOnce(QuitMessageLoop(&message_loop_));
189     }
190     model_->StartUpdating(&observer_);
191     message_loop_.Run();
192 
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"));
200     }
201     testing::Mock::VerifyAndClearExpectations(&observer_);
202     return list;
203   }
204 
205  protected:
206   // Must be listed before |model_|, so it's destroyed last.
207   MockObserver observer_;
208 
209   // Owned by |model_|;
210   FakeWindowCapturer* window_capturer_;
211 
212   scoped_ptr<NativeDesktopMediaList> model_;
213 
214   base::MessageLoop message_loop_;
215   content::TestBrowserThread ui_thread_;
216 
217   DISALLOW_COPY_AND_ASSIGN(DesktopMediaListTest);
218 };
219 
TEST_F(DesktopMediaListTest,InitialSourceList)220 TEST_F(DesktopMediaListTest, InitialSourceList) {
221   CreateWithDefaultCapturers();
222   webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(1, false);
223 
224   EXPECT_EQ(model_->GetSource(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
225   EXPECT_EQ(model_->GetSource(0).id.id, 0);
226 }
227 
228 // Verifies that the window specified with SetViewDialogWindowId() is filtered
229 // from the results.
TEST_F(DesktopMediaListTest,Filtering)230 TEST_F(DesktopMediaListTest, Filtering) {
231   CreateWithDefaultCapturers();
232   webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(2, false);
233 
234   EXPECT_EQ(model_->GetSource(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
235   EXPECT_EQ(model_->GetSource(0).id.id, 0);
236 }
237 
TEST_F(DesktopMediaListTest,WindowsOnly)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);
244 }
245 
TEST_F(DesktopMediaListTest,ScreenOnly)246 TEST_F(DesktopMediaListTest, ScreenOnly) {
247   model_.reset(new NativeDesktopMediaList(
248       scoped_ptr<webrtc::ScreenCapturer>(new FakeScreenCapturer),
249       scoped_ptr<webrtc::WindowCapturer>()));
250 
251   {
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_));
257   }
258   model_->StartUpdating(&observer_);
259 
260   message_loop_.Run();
261 
262   EXPECT_EQ(model_->GetSource(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
263 }
264 
TEST_F(DesktopMediaListTest,AddWindow)265 TEST_F(DesktopMediaListTest, AddWindow) {
266   CreateWithDefaultCapturers();
267   webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(1, false);
268 
269   EXPECT_CALL(observer_, OnSourceAdded(2))
270     .WillOnce(DoAll(CheckListSize(model_.get(), 3),
271                     QuitMessageLoop(&message_loop_)));
272 
273   webrtc::WindowCapturer::Window window;
274   window.id = 0;
275   window.title = "Test window 0";
276   list.push_back(window);
277   window_capturer_->SetWindowList(list);
278 
279   message_loop_.Run();
280 
281   EXPECT_EQ(model_->GetSource(2).id.type, content::DesktopMediaID::TYPE_WINDOW);
282   EXPECT_EQ(model_->GetSource(2).id.id, 0);
283 }
284 
TEST_F(DesktopMediaListTest,RemoveWindow)285 TEST_F(DesktopMediaListTest, RemoveWindow) {
286   CreateWithDefaultCapturers();
287   webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(2, false);
288 
289   EXPECT_CALL(observer_, OnSourceRemoved(2))
290     .WillOnce(DoAll(CheckListSize(model_.get(), 2),
291                     QuitMessageLoop(&message_loop_)));
292 
293   list.erase(list.begin() + 1);
294   window_capturer_->SetWindowList(list);
295 
296   message_loop_.Run();
297 }
298 
TEST_F(DesktopMediaListTest,RemoveAllWindows)299 TEST_F(DesktopMediaListTest, RemoveAllWindows) {
300   CreateWithDefaultCapturers();
301   webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(2, false);
302 
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_)));
309 
310   list.erase(list.begin(), list.end());
311   window_capturer_->SetWindowList(list);
312 
313   message_loop_.Run();
314 }
315 
TEST_F(DesktopMediaListTest,UpdateTitle)316 TEST_F(DesktopMediaListTest, UpdateTitle) {
317   CreateWithDefaultCapturers();
318   webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(1, false);
319 
320   EXPECT_CALL(observer_, OnSourceNameChanged(1))
321     .WillOnce(QuitMessageLoop(&message_loop_));
322 
323   const std::string kTestTitle = "New Title";
324 
325   list[0].title = kTestTitle;
326   window_capturer_->SetWindowList(list);
327 
328   message_loop_.Run();
329 
330   EXPECT_EQ(model_->GetSource(1).name, base::UTF8ToUTF16(kTestTitle));
331 }
332 
TEST_F(DesktopMediaListTest,UpdateThumbnail)333 TEST_F(DesktopMediaListTest, UpdateThumbnail) {
334   CreateWithDefaultCapturers();
335   AddWindowsAndVerify(2, false);
336 
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);
341 
342   message_loop_.Run();
343 }
344 
TEST_F(DesktopMediaListTest,MoveWindow)345 TEST_F(DesktopMediaListTest, MoveWindow) {
346   CreateWithDefaultCapturers();
347   webrtc::WindowCapturer::WindowList list = AddWindowsAndVerify(2, false);
348 
349   EXPECT_CALL(observer_, OnSourceMoved(2, 1))
350     .WillOnce(DoAll(CheckListSize(model_.get(), 3),
351                     QuitMessageLoop(&message_loop_)));
352 
353   // Swap the two windows.
354   webrtc::WindowCapturer::Window temp = list[0];
355   list[0] = list[1];
356   list[1] = temp;
357   window_capturer_->SetWindowList(list);
358 
359   message_loop_.Run();
360 }
361 
362 }  // namespace
363