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 "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/browser/media_device_id.h"
10 #include "content/public/test/mock_resource_context.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"
16 using ::testing::Invoke;
20 static const std::string kAudioLabel = "audio_label";
21 static const std::string kVideoLabel = "video_label";
23 class MockMediaStreamManager : public MediaStreamManager {
25 MockMediaStreamManager() {}
27 virtual ~MockMediaStreamManager() {}
29 MOCK_METHOD6(EnumerateDevices,
30 std::string(MediaStreamRequester* requester,
31 int render_process_id,
35 const GURL& security_origin));
36 MOCK_METHOD1(CancelRequest, void(const std::string& label));
38 std::string DoEnumerateDevices(MediaStreamRequester* requester,
39 int render_process_id,
43 const GURL& security_origin) {
44 if (type == MEDIA_DEVICE_AUDIO_CAPTURE) {
52 class MockDeviceRequestMessageFilter : public DeviceRequestMessageFilter {
54 MockDeviceRequestMessageFilter(MockResourceContext* context,
55 MockMediaStreamManager* manager)
56 : DeviceRequestMessageFilter(context, manager), received_id_(-1) {}
57 StreamDeviceInfoArray requested_devices() { return requested_devices_; }
58 int received_id() { return received_id_; }
61 virtual ~MockDeviceRequestMessageFilter() {}
63 // Override the Send() method to intercept the message that we're sending to
65 virtual bool Send(IPC::Message* reply_msg) OVERRIDE {
69 IPC_BEGIN_MESSAGE_MAP(MockDeviceRequestMessageFilter, *reply_msg)
70 IPC_MESSAGE_HANDLER(MediaStreamMsg_GetSourcesACK, SaveDevices)
71 IPC_MESSAGE_UNHANDLED(handled = false)
79 void SaveDevices(int request_id, const StreamDeviceInfoArray& devices) {
80 received_id_ = request_id;
81 requested_devices_ = devices;
85 StreamDeviceInfoArray requested_devices_;
88 class DeviceRequestMessageFilterTest : public testing::Test {
90 DeviceRequestMessageFilterTest() : next_device_id_(0) {}
92 void RunTest(int number_audio_devices, int number_video_devices) {
93 AddAudioDevices(number_audio_devices);
94 AddVideoDevices(number_video_devices);
95 GURL origin("https://test.com");
96 EXPECT_CALL(*media_stream_manager_,
97 EnumerateDevices(_, _, _, _, MEDIA_DEVICE_AUDIO_CAPTURE, _))
99 EXPECT_CALL(*media_stream_manager_,
100 EnumerateDevices(_, _, _, _, MEDIA_DEVICE_VIDEO_CAPTURE, _))
102 // Send message to get devices. Should trigger 2 EnumerateDevice() requests.
103 const int kRequestId = 123;
104 SendGetSourcesMessage(kRequestId, origin);
106 // Run audio callback. Because there's still an outstanding video request,
107 // this should not populate |message|.
108 FireAudioDeviceCallback();
109 EXPECT_EQ(0u, host_->requested_devices().size());
111 // After the video device callback is fired, |message| should be populated.
112 EXPECT_CALL(*media_stream_manager_, CancelRequest(kAudioLabel))
114 EXPECT_CALL(*media_stream_manager_, CancelRequest(kVideoLabel))
116 FireVideoDeviceCallback();
117 EXPECT_EQ(static_cast<size_t>(number_audio_devices + number_video_devices),
118 host_->requested_devices().size());
120 EXPECT_EQ(kRequestId, host_->received_id());
121 // Check to make sure no devices have raw ids.
122 EXPECT_FALSE(DoesContainRawIds(host_->requested_devices()));
124 // Check to make sure every GUID produced matches a raw device id.
125 EXPECT_TRUE(DoesEveryDeviceMapToRawId(host_->requested_devices(), origin));
128 bool AreLabelsPresent(MediaStreamType type) {
129 const StreamDeviceInfoArray& devices = host_->requested_devices();
130 for (size_t i = 0; i < devices.size(); i++) {
131 if (devices[i].device.type == type && !devices[i].device.name.empty())
138 virtual ~DeviceRequestMessageFilterTest() {}
140 virtual void SetUp() OVERRIDE {
141 message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_IO));
143 new TestBrowserThread(BrowserThread::IO, message_loop_.get()));
145 media_stream_manager_.reset(new MockMediaStreamManager());
146 ON_CALL(*media_stream_manager_, EnumerateDevices(_, _, _, _, _, _))
147 .WillByDefault(Invoke(media_stream_manager_.get(),
148 &MockMediaStreamManager::DoEnumerateDevices));
150 resource_context_.reset(new MockResourceContext(NULL));
151 host_ = new MockDeviceRequestMessageFilter(resource_context_.get(),
152 media_stream_manager_.get());
155 scoped_refptr<MockDeviceRequestMessageFilter> host_;
156 scoped_ptr<MockMediaStreamManager> media_stream_manager_;
157 scoped_ptr<MockResourceContext> resource_context_;
158 StreamDeviceInfoArray physical_audio_devices_;
159 StreamDeviceInfoArray physical_video_devices_;
160 scoped_ptr<base::MessageLoop> message_loop_;
161 scoped_ptr<TestBrowserThread> io_thread_;
164 void AddAudioDevices(int number_of_devices) {
165 for (int i = 0; i < number_of_devices; i++) {
166 physical_audio_devices_.push_back(
168 MEDIA_DEVICE_AUDIO_CAPTURE,
169 "/dev/audio/" + base::IntToString(next_device_id_),
170 "Audio Device" + base::IntToString(next_device_id_)));
175 void AddVideoDevices(int number_of_devices) {
176 for (int i = 0; i < number_of_devices; i++) {
177 physical_video_devices_.push_back(
179 MEDIA_DEVICE_VIDEO_CAPTURE,
180 "/dev/video/" + base::IntToString(next_device_id_),
181 "Video Device" + base::IntToString(next_device_id_)));
186 void SendGetSourcesMessage(int request_id, const GURL& origin) {
187 // Since we're not actually sending IPC messages, this is a throw-away
190 host_->OnMessageReceived(MediaStreamHostMsg_GetSources(request_id, origin),
194 void FireAudioDeviceCallback() {
195 host_->DevicesEnumerated(kAudioLabel, physical_audio_devices_);
198 void FireVideoDeviceCallback() {
199 host_->DevicesEnumerated(kVideoLabel, physical_video_devices_);
202 bool DoesContainRawIds(const StreamDeviceInfoArray& devices) {
203 for (size_t i = 0; i < devices.size(); i++) {
204 for (size_t j = 0; j < physical_audio_devices_.size(); ++j) {
205 if (physical_audio_devices_[j].device.id == devices[i].device.id)
208 for (size_t j = 0; j < physical_video_devices_.size(); ++j) {
209 if (physical_video_devices_[j].device.id == devices[i].device.id)
216 bool DoesEveryDeviceMapToRawId(const StreamDeviceInfoArray& devices,
217 const GURL& origin) {
218 for (size_t i = 0; i < devices.size(); i++) {
219 bool found_match = false;
220 for (size_t j = 0; j < physical_audio_devices_.size(); ++j) {
221 if (content::DoesMediaDeviceIDMatchHMAC(
223 devices[i].device.id,
224 physical_audio_devices_[j].device.id)) {
225 EXPECT_FALSE(found_match);
229 for (size_t j = 0; j < physical_video_devices_.size(); ++j) {
230 if (content::DoesMediaDeviceIDMatchHMAC(
232 devices[i].device.id,
233 physical_video_devices_[j].device.id)) {
234 EXPECT_FALSE(found_match);
247 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_AudioAndVideoDevices) {
248 // Runs through test with 1 audio and 1 video device.
252 TEST_F(DeviceRequestMessageFilterTest,
253 TestGetSources_MultipleAudioAndVideoDevices) {
254 // Runs through test with 3 audio devices and 2 video devices.
258 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_NoVideoDevices) {
259 // Runs through test with 4 audio devices and 0 video devices.
263 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_NoAudioDevices) {
264 // Runs through test with 0 audio devices and 3 video devices.
268 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_NoDevices) {
269 // Runs through test with no devices.
273 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_DenyMicDenyCamera) {
274 resource_context_->set_mic_access(false);
275 resource_context_->set_camera_access(false);
277 EXPECT_FALSE(AreLabelsPresent(MEDIA_DEVICE_AUDIO_CAPTURE));
278 EXPECT_FALSE(AreLabelsPresent(MEDIA_DEVICE_VIDEO_CAPTURE));
281 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_AllowMicDenyCamera) {
282 resource_context_->set_mic_access(true);
283 resource_context_->set_camera_access(false);
285 EXPECT_TRUE(AreLabelsPresent(MEDIA_DEVICE_AUDIO_CAPTURE));
286 EXPECT_FALSE(AreLabelsPresent(MEDIA_DEVICE_VIDEO_CAPTURE));
289 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_DenyMicAllowCamera) {
290 resource_context_->set_mic_access(false);
291 resource_context_->set_camera_access(true);
293 EXPECT_FALSE(AreLabelsPresent(MEDIA_DEVICE_AUDIO_CAPTURE));
294 EXPECT_TRUE(AreLabelsPresent(MEDIA_DEVICE_VIDEO_CAPTURE));
297 TEST_F(DeviceRequestMessageFilterTest, TestGetSources_AllowMicAllowCamera) {
298 resource_context_->set_mic_access(true);
299 resource_context_->set_camera_access(true);
301 EXPECT_TRUE(AreLabelsPresent(MEDIA_DEVICE_AUDIO_CAPTURE));
302 EXPECT_TRUE(AreLabelsPresent(MEDIA_DEVICE_VIDEO_CAPTURE));
305 }; // namespace content