OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2004 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/media/devices/devicemanager.h" | |
12 | |
13 #ifdef WIN32 | |
14 #include <objbase.h> | |
15 #include "webrtc/base/win32.h" | |
16 #endif | |
17 #include <string> | |
18 | |
19 #include "webrtc/base/arraysize.h" | |
20 #include "webrtc/base/fileutils.h" | |
21 #include "webrtc/base/gunit.h" | |
22 #include "webrtc/base/logging.h" | |
23 #include "webrtc/base/pathutils.h" | |
24 #include "webrtc/base/scoped_ptr.h" | |
25 #include "webrtc/base/stream.h" | |
26 #include "webrtc/base/windowpickerfactory.h" | |
27 #include "webrtc/media/base/fakevideocapturer.h" | |
28 #include "webrtc/media/base/screencastid.h" | |
29 #include "webrtc/media/base/testutils.h" | |
30 #include "webrtc/media/base/videocapturerfactory.h" | |
31 #include "webrtc/media/devices/v4llookup.h" | |
32 | |
33 #ifdef WEBRTC_LINUX | |
34 // TODO(juberti): Figure out why this doesn't compile on Windows. | |
35 #include "webrtc/base/fileutils_mock.h" | |
36 #endif // WEBRTC_LINUX | |
37 | |
38 using rtc::Pathname; | |
39 using rtc::FileTimeType; | |
40 using rtc::scoped_ptr; | |
41 using cricket::Device; | |
42 using cricket::DeviceManager; | |
43 using cricket::DeviceManagerFactory; | |
44 using cricket::DeviceManagerInterface; | |
45 | |
46 const cricket::VideoFormat kVgaFormat(640, 480, | |
47 cricket::VideoFormat::FpsToInterval(30), | |
48 cricket::FOURCC_I420); | |
49 const cricket::VideoFormat kHdFormat(1280, 720, | |
50 cricket::VideoFormat::FpsToInterval(30), | |
51 cricket::FOURCC_I420); | |
52 | |
53 class FakeVideoDeviceCapturerFactory : | |
54 public cricket::VideoDeviceCapturerFactory { | |
55 public: | |
56 FakeVideoDeviceCapturerFactory() {} | |
57 virtual ~FakeVideoDeviceCapturerFactory() {} | |
58 | |
59 virtual cricket::VideoCapturer* Create(const cricket::Device& device) { | |
60 return new cricket::FakeVideoCapturer; | |
61 } | |
62 }; | |
63 | |
64 class FakeScreenCapturerFactory : public cricket::ScreenCapturerFactory { | |
65 public: | |
66 FakeScreenCapturerFactory() {} | |
67 virtual ~FakeScreenCapturerFactory() {} | |
68 | |
69 virtual cricket::VideoCapturer* Create( | |
70 const cricket::ScreencastId& screenid) { | |
71 return new cricket::FakeVideoCapturer; | |
72 } | |
73 }; | |
74 | |
75 class DeviceManagerTestFake : public testing::Test { | |
76 public: | |
77 virtual void SetUp() { | |
78 dm_.reset(DeviceManagerFactory::Create()); | |
79 EXPECT_TRUE(dm_->Init()); | |
80 DeviceManager* device_manager = static_cast<DeviceManager*>(dm_.get()); | |
81 device_manager->SetVideoDeviceCapturerFactory( | |
82 new FakeVideoDeviceCapturerFactory()); | |
83 device_manager->SetScreenCapturerFactory( | |
84 new FakeScreenCapturerFactory()); | |
85 } | |
86 | |
87 virtual void TearDown() { | |
88 dm_->Terminate(); | |
89 } | |
90 | |
91 protected: | |
92 scoped_ptr<DeviceManagerInterface> dm_; | |
93 }; | |
94 | |
95 | |
96 // Test that we startup/shutdown properly. | |
97 TEST(DeviceManagerTest, StartupShutdown) { | |
98 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); | |
99 EXPECT_TRUE(dm->Init()); | |
100 dm->Terminate(); | |
101 } | |
102 | |
103 // Test CoInitEx behavior | |
104 #ifdef WIN32 | |
105 TEST(DeviceManagerTest, CoInitialize) { | |
106 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); | |
107 std::vector<Device> devices; | |
108 // Ensure that calls to video device work if COM is not yet initialized. | |
109 EXPECT_TRUE(dm->Init()); | |
110 EXPECT_TRUE(dm->GetVideoCaptureDevices(&devices)); | |
111 dm->Terminate(); | |
112 // Ensure that the ref count is correct. | |
113 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED)); | |
114 CoUninitialize(); | |
115 // Ensure that Init works in COINIT_APARTMENTTHREADED setting. | |
116 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)); | |
117 EXPECT_TRUE(dm->Init()); | |
118 dm->Terminate(); | |
119 CoUninitialize(); | |
120 // Ensure that the ref count is correct. | |
121 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)); | |
122 CoUninitialize(); | |
123 // Ensure that Init works in COINIT_MULTITHREADED setting. | |
124 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED)); | |
125 EXPECT_TRUE(dm->Init()); | |
126 dm->Terminate(); | |
127 CoUninitialize(); | |
128 // Ensure that the ref count is correct. | |
129 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED)); | |
130 CoUninitialize(); | |
131 } | |
132 #endif | |
133 | |
134 // Test enumerating devices (although we may not find any). | |
135 TEST(DeviceManagerTest, GetDevices) { | |
136 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); | |
137 std::vector<Device> audio_ins, audio_outs, video_ins; | |
138 std::vector<cricket::Device> video_in_devs; | |
139 cricket::Device def_video; | |
140 EXPECT_TRUE(dm->Init()); | |
141 EXPECT_TRUE(dm->GetAudioInputDevices(&audio_ins)); | |
142 EXPECT_TRUE(dm->GetAudioOutputDevices(&audio_outs)); | |
143 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins)); | |
144 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_in_devs)); | |
145 EXPECT_EQ(video_ins.size(), video_in_devs.size()); | |
146 // If we have any video devices, we should be able to pick a default. | |
147 EXPECT_TRUE(dm->GetVideoCaptureDevice( | |
148 cricket::DeviceManagerInterface::kDefaultDeviceName, &def_video) | |
149 != video_ins.empty()); | |
150 } | |
151 | |
152 // Test that we return correct ids for default and bogus devices. | |
153 TEST(DeviceManagerTest, GetAudioDeviceIds) { | |
154 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); | |
155 Device device; | |
156 EXPECT_TRUE(dm->Init()); | |
157 EXPECT_TRUE(dm->GetAudioInputDevice( | |
158 cricket::DeviceManagerInterface::kDefaultDeviceName, &device)); | |
159 EXPECT_EQ("-1", device.id); | |
160 EXPECT_TRUE(dm->GetAudioOutputDevice( | |
161 cricket::DeviceManagerInterface::kDefaultDeviceName, &device)); | |
162 EXPECT_EQ("-1", device.id); | |
163 EXPECT_FALSE(dm->GetAudioInputDevice("_NOT A REAL DEVICE_", &device)); | |
164 EXPECT_FALSE(dm->GetAudioOutputDevice("_NOT A REAL DEVICE_", &device)); | |
165 } | |
166 | |
167 // Test that we get the video capture device by name properly. | |
168 TEST(DeviceManagerTest, GetVideoDeviceIds) { | |
169 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); | |
170 Device device; | |
171 EXPECT_TRUE(dm->Init()); | |
172 EXPECT_FALSE(dm->GetVideoCaptureDevice("_NOT A REAL DEVICE_", &device)); | |
173 std::vector<Device> video_ins; | |
174 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins)); | |
175 if (!video_ins.empty()) { | |
176 // Get the default device with the parameter kDefaultDeviceName. | |
177 EXPECT_TRUE(dm->GetVideoCaptureDevice( | |
178 cricket::DeviceManagerInterface::kDefaultDeviceName, &device)); | |
179 | |
180 // Get the first device with the parameter video_ins[0].name. | |
181 EXPECT_TRUE(dm->GetVideoCaptureDevice(video_ins[0].name, &device)); | |
182 EXPECT_EQ(device.name, video_ins[0].name); | |
183 EXPECT_EQ(device.id, video_ins[0].id); | |
184 } | |
185 } | |
186 | |
187 TEST(DeviceManagerTest, VerifyDevicesListsAreCleared) { | |
188 const std::string imaginary("_NOT A REAL DEVICE_"); | |
189 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); | |
190 std::vector<Device> audio_ins, audio_outs, video_ins; | |
191 audio_ins.push_back(Device(imaginary, imaginary)); | |
192 audio_outs.push_back(Device(imaginary, imaginary)); | |
193 video_ins.push_back(Device(imaginary, imaginary)); | |
194 EXPECT_TRUE(dm->Init()); | |
195 EXPECT_TRUE(dm->GetAudioInputDevices(&audio_ins)); | |
196 EXPECT_TRUE(dm->GetAudioOutputDevices(&audio_outs)); | |
197 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins)); | |
198 for (size_t i = 0; i < audio_ins.size(); ++i) { | |
199 EXPECT_NE(imaginary, audio_ins[i].name); | |
200 } | |
201 for (size_t i = 0; i < audio_outs.size(); ++i) { | |
202 EXPECT_NE(imaginary, audio_outs[i].name); | |
203 } | |
204 for (size_t i = 0; i < video_ins.size(); ++i) { | |
205 EXPECT_NE(imaginary, video_ins[i].name); | |
206 } | |
207 } | |
208 | |
209 static bool CompareDeviceList(std::vector<Device>& devices, | |
210 const char* const device_list[], int list_size) { | |
211 if (list_size != static_cast<int>(devices.size())) { | |
212 return false; | |
213 } | |
214 for (int i = 0; i < list_size; ++i) { | |
215 if (devices[i].name.compare(device_list[i]) != 0) { | |
216 return false; | |
217 } | |
218 } | |
219 return true; | |
220 } | |
221 | |
222 TEST(DeviceManagerTest, VerifyFilterDevices) { | |
223 static const char* const kTotalDevicesName[] = { | |
224 "Google Camera Adapters are tons of fun.", | |
225 "device1", | |
226 "device2", | |
227 "device3", | |
228 "device4", | |
229 "device5", | |
230 "Google Camera Adapter 0", | |
231 "Google Camera Adapter 1", | |
232 }; | |
233 static const char* const kFilteredDevicesName[] = { | |
234 "device2", | |
235 "device4", | |
236 "Google Camera Adapter", | |
237 NULL, | |
238 }; | |
239 static const char* const kDevicesName[] = { | |
240 "device1", | |
241 "device3", | |
242 "device5", | |
243 }; | |
244 std::vector<Device> devices; | |
245 for (int i = 0; i < arraysize(kTotalDevicesName); ++i) { | |
246 devices.push_back(Device(kTotalDevicesName[i], i)); | |
247 } | |
248 EXPECT_TRUE(CompareDeviceList(devices, kTotalDevicesName, | |
249 arraysize(kTotalDevicesName))); | |
250 // Return false if given NULL as the exclusion list. | |
251 EXPECT_TRUE(DeviceManager::FilterDevices(&devices, NULL)); | |
252 // The devices should not change. | |
253 EXPECT_TRUE(CompareDeviceList(devices, kTotalDevicesName, | |
254 arraysize(kTotalDevicesName))); | |
255 EXPECT_TRUE(DeviceManager::FilterDevices(&devices, kFilteredDevicesName)); | |
256 EXPECT_TRUE(CompareDeviceList(devices, kDevicesName, | |
257 arraysize(kDevicesName))); | |
258 } | |
259 | |
260 #ifdef WEBRTC_LINUX | |
261 class FakeV4LLookup : public cricket::V4LLookup { | |
262 public: | |
263 explicit FakeV4LLookup(std::vector<std::string> device_paths) | |
264 : device_paths_(device_paths) {} | |
265 | |
266 protected: | |
267 bool CheckIsV4L2Device(const std::string& device) { | |
268 return std::find(device_paths_.begin(), device_paths_.end(), device) | |
269 != device_paths_.end(); | |
270 } | |
271 | |
272 private: | |
273 std::vector<std::string> device_paths_; | |
274 }; | |
275 | |
276 TEST(DeviceManagerTest, GetVideoCaptureDevices_K2_6) { | |
277 std::vector<std::string> devices; | |
278 devices.push_back("/dev/video0"); | |
279 devices.push_back("/dev/video5"); | |
280 cricket::V4LLookup::SetV4LLookup(new FakeV4LLookup(devices)); | |
281 | |
282 std::vector<rtc::FakeFileSystem::File> files; | |
283 files.push_back(rtc::FakeFileSystem::File("/dev/video0", "")); | |
284 files.push_back(rtc::FakeFileSystem::File("/dev/video5", "")); | |
285 files.push_back(rtc::FakeFileSystem::File( | |
286 "/sys/class/video4linux/video0/name", "Video Device 1")); | |
287 files.push_back(rtc::FakeFileSystem::File( | |
288 "/sys/class/video4linux/video1/model", "Bad Device")); | |
289 files.push_back( | |
290 rtc::FakeFileSystem::File("/sys/class/video4linux/video5/model", | |
291 "Video Device 2")); | |
292 rtc::FilesystemScope fs(new rtc::FakeFileSystem(files)); | |
293 | |
294 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); | |
295 std::vector<Device> video_ins; | |
296 EXPECT_TRUE(dm->Init()); | |
297 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins)); | |
298 EXPECT_EQ(2u, video_ins.size()); | |
299 EXPECT_EQ("Video Device 1", video_ins.at(0).name); | |
300 EXPECT_EQ("Video Device 2", video_ins.at(1).name); | |
301 } | |
302 | |
303 TEST(DeviceManagerTest, GetVideoCaptureDevices_K2_4) { | |
304 std::vector<std::string> devices; | |
305 devices.push_back("/dev/video0"); | |
306 devices.push_back("/dev/video5"); | |
307 cricket::V4LLookup::SetV4LLookup(new FakeV4LLookup(devices)); | |
308 | |
309 std::vector<rtc::FakeFileSystem::File> files; | |
310 files.push_back(rtc::FakeFileSystem::File("/dev/video0", "")); | |
311 files.push_back(rtc::FakeFileSystem::File("/dev/video5", "")); | |
312 files.push_back(rtc::FakeFileSystem::File( | |
313 "/proc/video/dev/video0", | |
314 "param1: value1\nname: Video Device 1\n param2: value2\n")); | |
315 files.push_back(rtc::FakeFileSystem::File( | |
316 "/proc/video/dev/video1", | |
317 "param1: value1\nname: Bad Device\n param2: value2\n")); | |
318 files.push_back(rtc::FakeFileSystem::File( | |
319 "/proc/video/dev/video5", | |
320 "param1: value1\nname: Video Device 2\n param2: value2\n")); | |
321 rtc::FilesystemScope fs(new rtc::FakeFileSystem(files)); | |
322 | |
323 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); | |
324 std::vector<Device> video_ins; | |
325 EXPECT_TRUE(dm->Init()); | |
326 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins)); | |
327 EXPECT_EQ(2u, video_ins.size()); | |
328 EXPECT_EQ("Video Device 1", video_ins.at(0).name); | |
329 EXPECT_EQ("Video Device 2", video_ins.at(1).name); | |
330 } | |
331 | |
332 TEST(DeviceManagerTest, GetVideoCaptureDevices_KUnknown) { | |
333 std::vector<std::string> devices; | |
334 devices.push_back("/dev/video0"); | |
335 devices.push_back("/dev/video5"); | |
336 cricket::V4LLookup::SetV4LLookup(new FakeV4LLookup(devices)); | |
337 | |
338 std::vector<rtc::FakeFileSystem::File> files; | |
339 files.push_back(rtc::FakeFileSystem::File("/dev/video0", "")); | |
340 files.push_back(rtc::FakeFileSystem::File("/dev/video1", "")); | |
341 files.push_back(rtc::FakeFileSystem::File("/dev/video5", "")); | |
342 rtc::FilesystemScope fs(new rtc::FakeFileSystem(files)); | |
343 | |
344 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); | |
345 std::vector<Device> video_ins; | |
346 EXPECT_TRUE(dm->Init()); | |
347 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins)); | |
348 EXPECT_EQ(2u, video_ins.size()); | |
349 EXPECT_EQ("/dev/video0", video_ins.at(0).name); | |
350 EXPECT_EQ("/dev/video5", video_ins.at(1).name); | |
351 } | |
352 #endif // WEBRTC_LINUX | |
353 | |
354 // TODO(noahric): These are flaky on windows on headless machines. | |
355 #ifndef WIN32 | |
356 TEST(DeviceManagerTest, GetWindows) { | |
357 if (!rtc::WindowPickerFactory::IsSupported()) { | |
358 LOG(LS_INFO) << "skipping test: window capturing is not supported with " | |
359 << "current configuration."; | |
360 return; | |
361 } | |
362 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); | |
363 dm->SetScreenCapturerFactory(new FakeScreenCapturerFactory()); | |
364 std::vector<rtc::WindowDescription> descriptions; | |
365 EXPECT_TRUE(dm->Init()); | |
366 if (!dm->GetWindows(&descriptions) || descriptions.empty()) { | |
367 LOG(LS_INFO) << "skipping test: window capturing. Does not have any " | |
368 << "windows to capture."; | |
369 return; | |
370 } | |
371 scoped_ptr<cricket::VideoCapturer> capturer(dm->CreateScreenCapturer( | |
372 cricket::ScreencastId(descriptions.front().id()))); | |
373 EXPECT_FALSE(capturer.get() == NULL); | |
374 // TODO(hellner): creating a window capturer and immediately deleting it | |
375 // results in "Continuous Build and Test Mainline - Mac opt" failure (crash). | |
376 // Remove the following line as soon as this has been resolved. | |
377 rtc::Thread::Current()->ProcessMessages(1); | |
378 } | |
379 | |
380 TEST(DeviceManagerTest, GetDesktops) { | |
381 if (!rtc::WindowPickerFactory::IsSupported()) { | |
382 LOG(LS_INFO) << "skipping test: desktop capturing is not supported with " | |
383 << "current configuration."; | |
384 return; | |
385 } | |
386 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); | |
387 dm->SetScreenCapturerFactory(new FakeScreenCapturerFactory()); | |
388 std::vector<rtc::DesktopDescription> descriptions; | |
389 EXPECT_TRUE(dm->Init()); | |
390 if (!dm->GetDesktops(&descriptions) || descriptions.empty()) { | |
391 LOG(LS_INFO) << "skipping test: desktop capturing. Does not have any " | |
392 << "desktops to capture."; | |
393 return; | |
394 } | |
395 scoped_ptr<cricket::VideoCapturer> capturer(dm->CreateScreenCapturer( | |
396 cricket::ScreencastId(descriptions.front().id()))); | |
397 EXPECT_FALSE(capturer.get() == NULL); | |
398 } | |
399 #endif // !WIN32 | |
400 | |
401 TEST_F(DeviceManagerTestFake, CaptureConstraintsWhitelisted) { | |
402 const Device device("white", "white_id"); | |
403 dm_->SetVideoCaptureDeviceMaxFormat(device.name, kHdFormat); | |
404 scoped_ptr<cricket::VideoCapturer> capturer( | |
405 dm_->CreateVideoCapturer(device)); | |
406 cricket::VideoFormat best_format; | |
407 capturer->set_enable_camera_list(true); | |
408 EXPECT_TRUE(capturer->GetBestCaptureFormat(kHdFormat, &best_format)); | |
409 EXPECT_EQ(kHdFormat, best_format); | |
410 } | |
411 | |
412 TEST_F(DeviceManagerTestFake, CaptureConstraintsNotWhitelisted) { | |
413 const Device device("regular", "regular_id"); | |
414 scoped_ptr<cricket::VideoCapturer> capturer( | |
415 dm_->CreateVideoCapturer(device)); | |
416 cricket::VideoFormat best_format; | |
417 capturer->set_enable_camera_list(true); | |
418 EXPECT_TRUE(capturer->GetBestCaptureFormat(kHdFormat, &best_format)); | |
419 EXPECT_EQ(kHdFormat, best_format); | |
420 } | |
421 | |
422 TEST_F(DeviceManagerTestFake, CaptureConstraintsUnWhitelisted) { | |
423 const Device device("un_white", "un_white_id"); | |
424 dm_->SetVideoCaptureDeviceMaxFormat(device.name, kHdFormat); | |
425 dm_->ClearVideoCaptureDeviceMaxFormat(device.name); | |
426 scoped_ptr<cricket::VideoCapturer> capturer( | |
427 dm_->CreateVideoCapturer(device)); | |
428 cricket::VideoFormat best_format; | |
429 capturer->set_enable_camera_list(true); | |
430 EXPECT_TRUE(capturer->GetBestCaptureFormat(kHdFormat, &best_format)); | |
431 EXPECT_EQ(kHdFormat, best_format); | |
432 } | |
433 | |
434 TEST_F(DeviceManagerTestFake, CaptureConstraintsWildcard) { | |
435 const Device device("any_device", "any_device"); | |
436 dm_->SetVideoCaptureDeviceMaxFormat("*", kHdFormat); | |
437 scoped_ptr<cricket::VideoCapturer> capturer( | |
438 dm_->CreateVideoCapturer(device)); | |
439 cricket::VideoFormat best_format; | |
440 capturer->set_enable_camera_list(true); | |
441 EXPECT_TRUE(capturer->GetBestCaptureFormat(kHdFormat, &best_format)); | |
442 EXPECT_EQ(kHdFormat, best_format); | |
443 } | |
OLD | NEW |