Home | History | Annotate | Download | only in media
      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/desktop_media_picker_model.h"
      6 
      7 #include "base/message_loop/message_loop.h"
      8 #include "base/stl_util.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "base/synchronization/lock.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::AtMost;
     20 using testing::DoAll;
     21 
     22 namespace {
     23 
     24 class MockObserver : public DesktopMediaPickerModel::Observer {
     25  public:
     26   MOCK_METHOD1(OnSourceAdded, void(int index));
     27   MOCK_METHOD1(OnSourceRemoved, void(int 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:
     34   FakeScreenCapturer() {}
     35   virtual ~FakeScreenCapturer() {}
     36 
     37   // webrtc::ScreenCapturer implementation.
     38   virtual void Start(Callback* callback) OVERRIDE {
     39     callback_ = callback;
     40   }
     41 
     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 
     50   virtual void SetMouseShapeObserver(
     51       MouseShapeObserver* mouse_shape_observer) OVERRIDE {
     52     NOTIMPLEMENTED();
     53   }
     54 
     55  protected:
     56   Callback* callback_;
     57 
     58   DISALLOW_COPY_AND_ASSIGN(FakeScreenCapturer);
     59 };
     60 
     61 class FakeWindowCapturer : public webrtc::WindowCapturer {
     62  public:
     63   FakeWindowCapturer()
     64       : callback_(NULL) {
     65   }
     66   virtual ~FakeWindowCapturer() {
     67     STLDeleteContainerPairSecondPointers(frames_.begin(), frames_.end());
     68   }
     69 
     70   void SetWindowList(const WindowList& list) {
     71     base::AutoLock lock(window_list_lock_);
     72     window_list_ = list;
     73   }
     74 
     75   void SetNextFrame(WindowId window_id,
     76                     scoped_ptr<webrtc::DesktopFrame> frame) {
     77       frames_[window_id] = frame.release();
     78   }
     79 
     80   // webrtc::WindowCapturer implementation.
     81   virtual void Start(Callback* callback) OVERRIDE {
     82     callback_ = callback;
     83   }
     84 
     85   virtual void Capture(const webrtc::DesktopRegion& region) OVERRIDE {
     86     DCHECK(callback_);
     87 
     88     webrtc::DesktopFrame* frame;
     89     std::map<WindowId, webrtc::DesktopFrame*>::iterator it =
     90         frames_.find(selected_window_id_);
     91     if (it == frames_.end()) {
     92       frame = new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
     93       memset(frame->data(), 0, frame->stride() * frame->size().height());
     94     } else {
     95       frame = it->second;
     96       frames_.erase(it);
     97     }
     98     callback_->OnCaptureCompleted(frame);
     99   }
    100 
    101   virtual bool GetWindowList(WindowList* windows) OVERRIDE {
    102     base::AutoLock lock(window_list_lock_);
    103     *windows = window_list_;
    104     return true;
    105   }
    106 
    107   virtual bool SelectWindow(WindowId id) OVERRIDE {
    108     selected_window_id_ = id;
    109     return true;
    110   }
    111 
    112  private:
    113   Callback* callback_;
    114   WindowList window_list_;
    115   base::Lock window_list_lock_;
    116 
    117   WindowId selected_window_id_;
    118 
    119   // Frames to be captured per window.
    120   std::map<WindowId, webrtc::DesktopFrame*> frames_;
    121 
    122   DISALLOW_COPY_AND_ASSIGN(FakeWindowCapturer);
    123 };
    124 
    125 class DesktopMediaPickerModelTest : public testing::Test {
    126  public:
    127   DesktopMediaPickerModelTest()
    128       : window_capturer_(NULL),
    129         ui_thread_(content::BrowserThread::UI,
    130                    &message_loop_) {
    131     // Set update period to reduce the time it takes to run tests.
    132     model_.SetUpdatePeriod(base::TimeDelta::FromMilliseconds(0));
    133   }
    134 
    135   void SetDefaultCapturers() {
    136     window_capturer_ = new FakeWindowCapturer();
    137     model_.SetCapturers(
    138         scoped_ptr<webrtc::ScreenCapturer>(new FakeScreenCapturer()),
    139         scoped_ptr<webrtc::WindowCapturer>(window_capturer_));
    140   }
    141 
    142  protected:
    143   // Must be listed before |model_|, so it's destroyed last.
    144   MockObserver observer_;
    145 
    146   // Owned by |model_|;
    147   FakeWindowCapturer* window_capturer_;
    148 
    149   DesktopMediaPickerModel model_;
    150 
    151   base::MessageLoop message_loop_;
    152   content::TestBrowserThread ui_thread_;
    153 
    154   DISALLOW_COPY_AND_ASSIGN(DesktopMediaPickerModelTest);
    155 };
    156 
    157 ACTION_P2(CheckListSize, model, expected_list_size) {
    158   EXPECT_EQ(expected_list_size, model->source_count());
    159 }
    160 
    161 ACTION_P(QuitMessageLoop, message_loop) {
    162   message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
    163 }
    164 
    165 TEST_F(DesktopMediaPickerModelTest, InitialSourceList) {
    166   SetDefaultCapturers();
    167 
    168   webrtc::WindowCapturer::WindowList list;
    169   webrtc::WindowCapturer::Window window;
    170   window.id = 0;
    171   window.title = "Test window";
    172   list.push_back(window);
    173   window_capturer_->SetWindowList(list);
    174 
    175   {
    176     testing::InSequence dummy;
    177     EXPECT_CALL(observer_, OnSourceAdded(0))
    178       .WillOnce(CheckListSize(&model_, 1));
    179     EXPECT_CALL(observer_, OnSourceAdded(1))
    180       .WillOnce(CheckListSize(&model_, 2));
    181     EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    182     EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
    183       .WillOnce(QuitMessageLoop(&message_loop_));
    184   }
    185   model_.StartUpdating(&observer_);
    186 
    187   message_loop_.Run();
    188 
    189   EXPECT_EQ(model_.source(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
    190   EXPECT_EQ(model_.source(0).id.id, 0);
    191   EXPECT_EQ(model_.source(1).id.type, content::DesktopMediaID::TYPE_WINDOW);
    192   EXPECT_EQ(model_.source(1).id.id, 0);
    193   EXPECT_EQ(model_.source(1).name, UTF8ToUTF16(window.title));
    194 }
    195 
    196 TEST_F(DesktopMediaPickerModelTest, WindowsOnly) {
    197   window_capturer_ = new FakeWindowCapturer();
    198   model_.SetCapturers(
    199       scoped_ptr<webrtc::ScreenCapturer>(),
    200       scoped_ptr<webrtc::WindowCapturer>(window_capturer_));
    201 
    202   webrtc::WindowCapturer::WindowList list;
    203   webrtc::WindowCapturer::Window window;
    204   window.id = 0;
    205   window.title = "Test window";
    206   list.push_back(window);
    207   window_capturer_->SetWindowList(list);
    208 
    209   {
    210     testing::InSequence dummy;
    211     EXPECT_CALL(observer_, OnSourceAdded(0))
    212       .WillOnce(CheckListSize(&model_, 1));
    213     EXPECT_CALL(observer_, OnSourceThumbnailChanged(0))
    214       .WillOnce(QuitMessageLoop(&message_loop_));
    215   }
    216   model_.StartUpdating(&observer_);
    217 
    218   message_loop_.Run();
    219 
    220   EXPECT_EQ(model_.source(0).id.type, content::DesktopMediaID::TYPE_WINDOW);
    221 }
    222 
    223 TEST_F(DesktopMediaPickerModelTest, ScreenOnly) {
    224   model_.SetCapturers(
    225       scoped_ptr<webrtc::ScreenCapturer>(new FakeScreenCapturer),
    226       scoped_ptr<webrtc::WindowCapturer>());
    227 
    228   {
    229     testing::InSequence dummy;
    230     EXPECT_CALL(observer_, OnSourceAdded(0))
    231       .WillOnce(CheckListSize(&model_, 1));
    232     EXPECT_CALL(observer_, OnSourceThumbnailChanged(0))
    233       .WillOnce(QuitMessageLoop(&message_loop_));
    234   }
    235   model_.StartUpdating(&observer_);
    236 
    237   message_loop_.Run();
    238 
    239   EXPECT_EQ(model_.source(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
    240 }
    241 
    242 TEST_F(DesktopMediaPickerModelTest, AddWindow) {
    243   SetDefaultCapturers();
    244 
    245   webrtc::WindowCapturer::WindowList list;
    246   webrtc::WindowCapturer::Window window;
    247   window.id = 1;
    248   window.title = "Test window 1";
    249   list.push_back(window);
    250   window_capturer_->SetWindowList(list);
    251 
    252   {
    253     testing::InSequence dummy;
    254     EXPECT_CALL(observer_, OnSourceAdded(0))
    255       .WillOnce(CheckListSize(&model_, 1));
    256     EXPECT_CALL(observer_, OnSourceAdded(1))
    257       .WillOnce(CheckListSize(&model_, 2));
    258     EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    259     EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
    260       .WillOnce(QuitMessageLoop(&message_loop_));
    261   }
    262   model_.StartUpdating(&observer_);
    263 
    264   message_loop_.Run();
    265 
    266   testing::Mock::VerifyAndClearExpectations(&observer_);
    267 
    268   EXPECT_CALL(observer_, OnSourceAdded(1))
    269     .WillOnce(DoAll(CheckListSize(&model_, 3),
    270                     QuitMessageLoop(&message_loop_)));
    271 
    272   window.id = 0;
    273   window.title = "Test window 0";
    274   list.push_back(window);
    275   window_capturer_->SetWindowList(list);
    276 
    277   message_loop_.Run();
    278 
    279   EXPECT_EQ(model_.source(1).id.type, content::DesktopMediaID::TYPE_WINDOW);
    280   EXPECT_EQ(model_.source(1).id.id, 0);
    281 }
    282 
    283 TEST_F(DesktopMediaPickerModelTest, RemoveWindow) {
    284   SetDefaultCapturers();
    285 
    286   webrtc::WindowCapturer::WindowList list;
    287   webrtc::WindowCapturer::Window window;
    288   window.id = 0;
    289   window.title = "Test window 0";
    290   list.push_back(window);
    291   window.id = 1;
    292   window.title = "Test window 1";
    293   list.push_back(window);
    294   window_capturer_->SetWindowList(list);
    295 
    296   {
    297     testing::InSequence dummy;
    298     EXPECT_CALL(observer_, OnSourceAdded(0))
    299       .WillOnce(CheckListSize(&model_, 1));
    300     EXPECT_CALL(observer_, OnSourceAdded(1))
    301       .WillOnce(CheckListSize(&model_, 2));
    302     EXPECT_CALL(observer_, OnSourceAdded(2))
    303       .WillOnce(CheckListSize(&model_, 3));
    304     EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    305     EXPECT_CALL(observer_, OnSourceThumbnailChanged(1));
    306     EXPECT_CALL(observer_, OnSourceThumbnailChanged(2))
    307       .WillOnce(QuitMessageLoop(&message_loop_));
    308   }
    309   model_.StartUpdating(&observer_);
    310 
    311   message_loop_.Run();
    312 
    313   testing::Mock::VerifyAndClearExpectations(&observer_);
    314 
    315   EXPECT_CALL(observer_, OnSourceRemoved(1))
    316     .WillOnce(DoAll(CheckListSize(&model_, 2),
    317                     QuitMessageLoop(&message_loop_)));
    318 
    319   list.erase(list.begin());
    320   window_capturer_->SetWindowList(list);
    321 
    322   message_loop_.Run();
    323 }
    324 
    325 TEST_F(DesktopMediaPickerModelTest, UpdateTitle) {
    326   SetDefaultCapturers();
    327 
    328   webrtc::WindowCapturer::WindowList list;
    329   webrtc::WindowCapturer::Window window;
    330   window.id = 0;
    331   window.title = "Test window";
    332   list.push_back(window);
    333   window_capturer_->SetWindowList(list);
    334 
    335   {
    336     testing::InSequence dummy;
    337     EXPECT_CALL(observer_, OnSourceAdded(0))
    338       .WillOnce(CheckListSize(&model_, 1));
    339     EXPECT_CALL(observer_, OnSourceAdded(1))
    340       .WillOnce(CheckListSize(&model_, 2));
    341     EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    342     EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
    343       .WillOnce(QuitMessageLoop(&message_loop_));
    344   }
    345   model_.StartUpdating(&observer_);
    346 
    347   message_loop_.Run();
    348 
    349   testing::Mock::VerifyAndClearExpectations(&observer_);
    350 
    351   EXPECT_CALL(observer_, OnSourceNameChanged(1))
    352     .WillOnce(QuitMessageLoop(&message_loop_));
    353 
    354   const std::string kTestTitle = "New Title";
    355 
    356   list[0].title = kTestTitle;
    357   window_capturer_->SetWindowList(list);
    358 
    359   message_loop_.Run();
    360 
    361   EXPECT_EQ(model_.source(1).name, base::UTF8ToUTF16(kTestTitle));
    362 }
    363 
    364 TEST_F(DesktopMediaPickerModelTest, UpdateThumbnail) {
    365   SetDefaultCapturers();
    366 
    367   webrtc::WindowCapturer::WindowList list;
    368   webrtc::WindowCapturer::Window window;
    369   window.id = 0;
    370   window.title = "Test window 1";
    371   list.push_back(window);
    372   window.id = 1;
    373   window.title = "Test window 2";
    374   list.push_back(window);
    375   window_capturer_->SetWindowList(list);
    376 
    377   {
    378     testing::InSequence dummy;
    379     EXPECT_CALL(observer_, OnSourceAdded(0))
    380       .WillOnce(CheckListSize(&model_, 1));
    381     EXPECT_CALL(observer_, OnSourceAdded(1))
    382       .WillOnce(CheckListSize(&model_, 2));
    383     EXPECT_CALL(observer_, OnSourceAdded(2))
    384       .WillOnce(CheckListSize(&model_, 3));
    385     EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    386     EXPECT_CALL(observer_, OnSourceThumbnailChanged(1));
    387     EXPECT_CALL(observer_, OnSourceThumbnailChanged(2))
    388       .WillOnce(QuitMessageLoop(&message_loop_));
    389   }
    390   model_.StartUpdating(&observer_);
    391 
    392   message_loop_.Run();
    393 
    394   testing::Mock::VerifyAndClearExpectations(&observer_);
    395 
    396   EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
    397     .WillOnce(QuitMessageLoop(&message_loop_));
    398 
    399   // Update frame for the window and verify that we get notification about it.
    400   scoped_ptr<webrtc::DesktopFrame> frame(
    401       new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10)));
    402   memset(frame->data(), 1, frame->stride() * frame->size().height());
    403   window_capturer_->SetNextFrame(0, frame.Pass());
    404 
    405   message_loop_.Run();
    406 }
    407 
    408 }  // namespace
    409