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 "base/strings/string_number_conversions.h"
      6 #include "content/browser/renderer_host/media/device_request_message_filter.h"
      7 #include "content/browser/renderer_host/media/media_stream_manager.h"
      8 #include "content/common/media/media_stream_messages.h"
      9 #include "content/public/test/mock_resource_context.h"
     10 #include "content/public/test/test_browser_thread.h"
     11 #include "testing/gmock/include/gmock/gmock.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 using ::testing::_;
     15 using ::testing::Invoke;
     16 
     17 namespace content {
     18 
     19 static const std::string kAudioLabel = "audio_label";
     20 static const std::string kVideoLabel = "video_label";
     21 
     22 class MockMediaStreamManager : public MediaStreamManager {
     23  public:
     24   MockMediaStreamManager() {}
     25 
     26   virtual ~MockMediaStreamManager() {}
     27 
     28   MOCK_METHOD6(EnumerateDevices,
     29                std::string(MediaStreamRequester* requester,
     30                            int render_process_id,
     31                            int render_view_id,
     32                            int page_request_id,
     33                            MediaStreamType type,
     34                            const GURL& security_origin));
     35   MOCK_METHOD1(StopGeneratedStream, void(const std::string& label));
     36 
     37   std::string DoEnumerateDevices(MediaStreamRequester* requester,
     38                                  int render_process_id,
     39                                  int render_view_id,
     40                                  int page_request_id,
     41                                  MediaStreamType type,
     42                                  const GURL& security_origin) {
     43     if (type == MEDIA_DEVICE_AUDIO_CAPTURE) {
     44       return kAudioLabel;
     45     } else {
     46       return kVideoLabel;
     47     }
     48   }
     49 };
     50 
     51 class MockDeviceRequestMessageFilter : public DeviceRequestMessageFilter {
     52  public:
     53   MockDeviceRequestMessageFilter(MockResourceContext* context,
     54                                  MockMediaStreamManager* manager)
     55       : DeviceRequestMessageFilter(context, manager), received_id_(-1) {}
     56   StreamDeviceInfoArray requested_devices() { return requested_devices_; }
     57   int received_id() { return received_id_; }
     58 
     59  private:
     60   virtual ~MockDeviceRequestMessageFilter() {}
     61 
     62   // Override the Send() method to intercept the message that we're sending to
     63   // the renderer.
     64   virtual bool Send(IPC::Message* reply_msg) OVERRIDE {
     65     CHECK(reply_msg);
     66 
     67     bool handled = true;
     68     IPC_BEGIN_MESSAGE_MAP(MockDeviceRequestMessageFilter, *reply_msg)
     69       IPC_MESSAGE_HANDLER(MediaStreamMsg_GetSourcesACK, SaveDevices)
     70       IPC_MESSAGE_UNHANDLED(handled = false)
     71     IPC_END_MESSAGE_MAP()
     72     EXPECT_TRUE(handled);
     73 
     74     delete reply_msg;
     75     return true;
     76   }
     77 
     78   void SaveDevices(int request_id, const StreamDeviceInfoArray& devices) {
     79     received_id_ = request_id;
     80     requested_devices_ = devices;
     81   }
     82 
     83   int received_id_;
     84   StreamDeviceInfoArray requested_devices_;
     85 };
     86 
     87 class DeviceRequestMessageFilterTest : public testing::Test {
     88  public:
     89   DeviceRequestMessageFilterTest() : next_device_id_(0) {}
     90 
     91   void RunTest(int number_audio_devices, int number_video_devices) {
     92     AddAudioDevices(number_audio_devices);
     93     AddVideoDevices(number_video_devices);
     94     GURL origin("https://test.com");
     95     EXPECT_CALL(*media_stream_manager_,
     96                 EnumerateDevices(_, _, _, _, MEDIA_DEVICE_AUDIO_CAPTURE, _))
     97         .Times(1);
     98     EXPECT_CALL(*media_stream_manager_,
     99                 EnumerateDevices(_, _, _, _, MEDIA_DEVICE_VIDEO_CAPTURE, _))
    100         .Times(1);
    101     // Send message to get devices. Should trigger 2 EnumerateDevice() requests.
    102     const int kRequestId = 123;
    103     SendGetSourcesMessage(kRequestId, origin);
    104 
    105     // Run audio callback. Because there's still an outstanding video request,
    106     // this should not populate |message|.
    107     FireAudioDeviceCallback();
    108     EXPECT_EQ(0u, host_->requested_devices().size());
    109 
    110     // After the video device callback is fired, |message| should be populated.
    111     EXPECT_CALL(*media_stream_manager_, StopGeneratedStream(kAudioLabel))
    112         .Times(1);
    113     EXPECT_CALL(*media_stream_manager_, StopGeneratedStream(kVideoLabel))
    114         .Times(1);
    115     FireVideoDeviceCallback();
    116     EXPECT_EQ(static_cast<size_t>(number_audio_devices + number_video_devices),
    117               host_->requested_devices().size());
    118 
    119     EXPECT_EQ(kRequestId, host_->received_id());
    120     // Check to make sure no devices have raw ids.
    121     EXPECT_FALSE(DoesContainRawIds(host_->requested_devices()));
    122 
    123     // Check to make sure every GUID produced matches a raw device id.
    124     EXPECT_TRUE(DoesEveryDeviceMapToRawId(host_->requested_devices(), origin));
    125   }
    126 
    127   bool AreLabelsPresent(MediaStreamType type) {
    128     const StreamDeviceInfoArray& devices = host_->requested_devices();
    129     for (size_t i = 0; i < devices.size(); i++) {
    130       if (devices[i].device.type == type && !devices[i].device.name.empty())
    131         return true;
    132     }
    133     return false;
    134   }
    135 
    136  protected:
    137   virtual ~DeviceRequestMessageFilterTest() {}
    138 
    139   virtual void SetUp() OVERRIDE {
    140     message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_IO));
    141     io_thread_.reset(
    142         new TestBrowserThread(BrowserThread::IO, message_loop_.get()));
    143 
    144     media_stream_manager_.reset(new MockMediaStreamManager());
    145     ON_CALL(*media_stream_manager_, EnumerateDevices(_, _, _, _, _, _))
    146         .WillByDefault(Invoke(media_stream_manager_.get(),
    147                               &MockMediaStreamManager::DoEnumerateDevices));
    148 
    149     resource_context_.reset(new MockResourceContext(NULL));
    150     host_ = new MockDeviceRequestMessageFilter(resource_context_.get(),
    151                                                media_stream_manager_.get());
    152   }
    153 
    154   scoped_refptr<MockDeviceRequestMessageFilter> host_;
    155   scoped_ptr<MockMediaStreamManager> media_stream_manager_;
    156   scoped_ptr<MockResourceContext> resource_context_;
    157   StreamDeviceInfoArray physical_audio_devices_;
    158   StreamDeviceInfoArray physical_video_devices_;
    159   scoped_ptr<base::MessageLoop> message_loop_;
    160   scoped_ptr<TestBrowserThread> io_thread_;
    161 
    162  private:
    163   void AddAudioDevices(int number_of_devices) {
    164     for (int i = 0; i < number_of_devices; i++) {
    165       physical_audio_devices_.push_back(
    166           StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE,
    167                            "/dev/audio/" + base::IntToString(next_device_id_),
    168                            "Audio Device" + base::IntToString(next_device_id_),
    169                            false));
    170       next_device_id_++;
    171     }
    172   }
    173 
    174   void AddVideoDevices(int number_of_devices) {
    175     for (int i = 0; i < number_of_devices; i++) {
    176       physical_video_devices_.push_back(
    177           StreamDeviceInfo(MEDIA_DEVICE_VIDEO_CAPTURE,
    178                            "/dev/video/" + base::IntToString(next_device_id_),
    179                            "Video Device" + base::IntToString(next_device_id_),
    180                            false));
    181       next_device_id_++;
    182     }
    183   }
    184 
    185   void SendGetSourcesMessage(int request_id, const GURL& origin) {
    186     // Since we're not actually sending IPC messages, this is a throw-away
    187     // value.
    188     bool message_was_ok;
    189     host_->OnMessageReceived(MediaStreamHostMsg_GetSources(request_id, origin),
    190                              &message_was_ok);
    191   }
    192 
    193   void FireAudioDeviceCallback() {
    194     host_->DevicesEnumerated(kAudioLabel, physical_audio_devices_);
    195   }
    196 
    197   void FireVideoDeviceCallback() {
    198     host_->DevicesEnumerated(kVideoLabel, physical_video_devices_);
    199   }
    200 
    201   bool DoesContainRawIds(const StreamDeviceInfoArray& devices) {
    202     for (size_t i = 0; i < devices.size(); i++) {
    203       for (size_t j = 0; j < physical_audio_devices_.size(); ++j) {
    204         if (physical_audio_devices_[j].device.id == devices[i].device.id)
    205           return true;
    206       }
    207       for (size_t j = 0; j < physical_video_devices_.size(); ++j) {
    208         if (physical_video_devices_[j].device.id == devices[i].device.id)
    209           return true;
    210       }
    211     }
    212     return false;
    213   }
    214 
    215   bool DoesEveryDeviceMapToRawId(const StreamDeviceInfoArray& devices,
    216                                  const GURL& origin) {
    217     for (size_t i = 0; i < devices.size(); i++) {
    218       bool found_match = false;
    219       for (size_t j = 0; j < physical_audio_devices_.size(); ++j) {
    220         if (DeviceRequestMessageFilter::DoesRawIdMatchGuid(
    221                 origin,
    222                 devices[i].device.id,
    223                 physical_audio_devices_[j].device.id)) {
    224           EXPECT_FALSE(found_match);
    225           found_match = true;
    226         }
    227       }
    228       for (size_t j = 0; j < physical_video_devices_.size(); ++j) {
    229         if (DeviceRequestMessageFilter::DoesRawIdMatchGuid(
    230                 origin,
    231                 devices[i].device.id,
    232                 physical_video_devices_[j].device.id)) {
    233           EXPECT_FALSE(found_match);
    234           found_match = true;
    235         }
    236       }
    237       if (!found_match)
    238         return false;
    239     }
    240     return true;
    241   }
    242 
    243   int next_device_id_;
    244 };
    245 
    246 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_AudioAndVideoDevices) {
    247   // Runs through test with 1 audio and 1 video device.
    248   RunTest(1, 1);
    249 }
    250 
    251 TEST_F(DeviceRequestMessageFilterTest,
    252        TestGetSources_MultipleAudioAndVideoDevices) {
    253   // Runs through test with 3 audio devices and 2 video devices.
    254   RunTest(3, 2);
    255 }
    256 
    257 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_NoVideoDevices) {
    258   // Runs through test with 4 audio devices and 0 video devices.
    259   RunTest(4, 0);
    260 }
    261 
    262 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_NoAudioDevices) {
    263   // Runs through test with 0 audio devices and 3 video devices.
    264   RunTest(0, 3);
    265 }
    266 
    267 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_NoDevices) {
    268   // Runs through test with no devices.
    269   RunTest(0, 0);
    270 }
    271 
    272 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_DenyMicDenyCamera) {
    273   resource_context_->set_mic_access(false);
    274   resource_context_->set_camera_access(false);
    275   RunTest(3, 3);
    276   EXPECT_FALSE(AreLabelsPresent(MEDIA_DEVICE_AUDIO_CAPTURE));
    277   EXPECT_FALSE(AreLabelsPresent(MEDIA_DEVICE_VIDEO_CAPTURE));
    278 }
    279 
    280 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_AllowMicDenyCamera) {
    281   resource_context_->set_mic_access(true);
    282   resource_context_->set_camera_access(false);
    283   RunTest(3, 3);
    284   EXPECT_TRUE(AreLabelsPresent(MEDIA_DEVICE_AUDIO_CAPTURE));
    285   EXPECT_FALSE(AreLabelsPresent(MEDIA_DEVICE_VIDEO_CAPTURE));
    286 }
    287 
    288 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_DenyMicAllowCamera) {
    289   resource_context_->set_mic_access(false);
    290   resource_context_->set_camera_access(true);
    291   RunTest(3, 3);
    292   EXPECT_FALSE(AreLabelsPresent(MEDIA_DEVICE_AUDIO_CAPTURE));
    293   EXPECT_TRUE(AreLabelsPresent(MEDIA_DEVICE_VIDEO_CAPTURE));
    294 }
    295 
    296 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_AllowMicAllowCamera) {
    297   resource_context_->set_mic_access(true);
    298   resource_context_->set_camera_access(true);
    299   RunTest(3, 3);
    300   EXPECT_TRUE(AreLabelsPresent(MEDIA_DEVICE_AUDIO_CAPTURE));
    301   EXPECT_TRUE(AreLabelsPresent(MEDIA_DEVICE_VIDEO_CAPTURE));
    302 }
    303 
    304 };  // namespace content
    305