devicemanager_unittest.cc revision 65b98d12c3b6b9ca0ded669d0a0811d2bb1712b3
1/* 2 * libjingle 3 * Copyright 2004 Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "talk/media/devices/devicemanager.h" 29 30#ifdef WIN32 31#include "webrtc/base/win32.h" 32#include <objbase.h> 33#endif 34#include <string> 35 36#include "talk/media/base/fakevideocapturer.h" 37#include "talk/media/base/screencastid.h" 38#include "talk/media/base/testutils.h" 39#include "talk/media/base/videocapturerfactory.h" 40#include "talk/media/devices/filevideocapturer.h" 41#include "talk/media/devices/v4llookup.h" 42#include "webrtc/base/fileutils.h" 43#include "webrtc/base/gunit.h" 44#include "webrtc/base/logging.h" 45#include "webrtc/base/pathutils.h" 46#include "webrtc/base/scoped_ptr.h" 47#include "webrtc/base/stream.h" 48#include "webrtc/base/windowpickerfactory.h" 49 50#ifdef LINUX 51// TODO(juberti): Figure out why this doesn't compile on Windows. 52#include "webrtc/base/fileutils_mock.h" 53#endif // LINUX 54 55using rtc::Pathname; 56using rtc::FileTimeType; 57using rtc::scoped_ptr; 58using cricket::Device; 59using cricket::DeviceManager; 60using cricket::DeviceManagerFactory; 61using cricket::DeviceManagerInterface; 62 63const cricket::VideoFormat kVgaFormat(640, 480, 64 cricket::VideoFormat::FpsToInterval(30), 65 cricket::FOURCC_I420); 66const cricket::VideoFormat kHdFormat(1280, 720, 67 cricket::VideoFormat::FpsToInterval(30), 68 cricket::FOURCC_I420); 69 70class FakeVideoDeviceCapturerFactory : 71 public cricket::VideoDeviceCapturerFactory { 72 public: 73 FakeVideoDeviceCapturerFactory() {} 74 virtual ~FakeVideoDeviceCapturerFactory() {} 75 76 virtual cricket::VideoCapturer* Create(const cricket::Device& device) { 77 return new cricket::FakeVideoCapturer; 78 } 79}; 80 81class FakeScreenCapturerFactory : public cricket::ScreenCapturerFactory { 82 public: 83 FakeScreenCapturerFactory() {} 84 virtual ~FakeScreenCapturerFactory() {} 85 86 virtual cricket::VideoCapturer* Create( 87 const cricket::ScreencastId& screenid) { 88 return new cricket::FakeVideoCapturer; 89 } 90}; 91 92class DeviceManagerTestFake : public testing::Test { 93 public: 94 virtual void SetUp() { 95 dm_.reset(DeviceManagerFactory::Create()); 96 EXPECT_TRUE(dm_->Init()); 97 DeviceManager* device_manager = static_cast<DeviceManager*>(dm_.get()); 98 device_manager->SetVideoDeviceCapturerFactory( 99 new FakeVideoDeviceCapturerFactory()); 100 device_manager->SetScreenCapturerFactory( 101 new FakeScreenCapturerFactory()); 102 } 103 104 virtual void TearDown() { 105 dm_->Terminate(); 106 } 107 108 protected: 109 scoped_ptr<DeviceManagerInterface> dm_; 110}; 111 112 113// Test that we startup/shutdown properly. 114TEST(DeviceManagerTest, StartupShutdown) { 115 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); 116 EXPECT_TRUE(dm->Init()); 117 dm->Terminate(); 118} 119 120// Test CoInitEx behavior 121#ifdef WIN32 122TEST(DeviceManagerTest, CoInitialize) { 123 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); 124 std::vector<Device> devices; 125 // Ensure that calls to video device work if COM is not yet initialized. 126 EXPECT_TRUE(dm->Init()); 127 EXPECT_TRUE(dm->GetVideoCaptureDevices(&devices)); 128 dm->Terminate(); 129 // Ensure that the ref count is correct. 130 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED)); 131 CoUninitialize(); 132 // Ensure that Init works in COINIT_APARTMENTTHREADED setting. 133 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)); 134 EXPECT_TRUE(dm->Init()); 135 dm->Terminate(); 136 CoUninitialize(); 137 // Ensure that the ref count is correct. 138 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)); 139 CoUninitialize(); 140 // Ensure that Init works in COINIT_MULTITHREADED setting. 141 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED)); 142 EXPECT_TRUE(dm->Init()); 143 dm->Terminate(); 144 CoUninitialize(); 145 // Ensure that the ref count is correct. 146 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED)); 147 CoUninitialize(); 148} 149#endif 150 151// Test enumerating devices (although we may not find any). 152TEST(DeviceManagerTest, GetDevices) { 153 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); 154 std::vector<Device> audio_ins, audio_outs, video_ins; 155 std::vector<cricket::Device> video_in_devs; 156 cricket::Device def_video; 157 EXPECT_TRUE(dm->Init()); 158 EXPECT_TRUE(dm->GetAudioInputDevices(&audio_ins)); 159 EXPECT_TRUE(dm->GetAudioOutputDevices(&audio_outs)); 160 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins)); 161 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_in_devs)); 162 EXPECT_EQ(video_ins.size(), video_in_devs.size()); 163 // If we have any video devices, we should be able to pick a default. 164 EXPECT_TRUE(dm->GetVideoCaptureDevice( 165 cricket::DeviceManagerInterface::kDefaultDeviceName, &def_video) 166 != video_ins.empty()); 167} 168 169// Test that we return correct ids for default and bogus devices. 170TEST(DeviceManagerTest, GetAudioDeviceIds) { 171 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); 172 Device device; 173 EXPECT_TRUE(dm->Init()); 174 EXPECT_TRUE(dm->GetAudioInputDevice( 175 cricket::DeviceManagerInterface::kDefaultDeviceName, &device)); 176 EXPECT_EQ("-1", device.id); 177 EXPECT_TRUE(dm->GetAudioOutputDevice( 178 cricket::DeviceManagerInterface::kDefaultDeviceName, &device)); 179 EXPECT_EQ("-1", device.id); 180 EXPECT_FALSE(dm->GetAudioInputDevice("_NOT A REAL DEVICE_", &device)); 181 EXPECT_FALSE(dm->GetAudioOutputDevice("_NOT A REAL DEVICE_", &device)); 182} 183 184// Test that we get the video capture device by name properly. 185TEST(DeviceManagerTest, GetVideoDeviceIds) { 186 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); 187 Device device; 188 EXPECT_TRUE(dm->Init()); 189 EXPECT_FALSE(dm->GetVideoCaptureDevice("_NOT A REAL DEVICE_", &device)); 190 std::vector<Device> video_ins; 191 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins)); 192 if (!video_ins.empty()) { 193 // Get the default device with the parameter kDefaultDeviceName. 194 EXPECT_TRUE(dm->GetVideoCaptureDevice( 195 cricket::DeviceManagerInterface::kDefaultDeviceName, &device)); 196 197 // Get the first device with the parameter video_ins[0].name. 198 EXPECT_TRUE(dm->GetVideoCaptureDevice(video_ins[0].name, &device)); 199 EXPECT_EQ(device.name, video_ins[0].name); 200 EXPECT_EQ(device.id, video_ins[0].id); 201 } 202} 203 204TEST(DeviceManagerTest, GetVideoDeviceIds_File) { 205 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); 206 EXPECT_TRUE(dm->Init()); 207 Device device; 208 const std::string test_file = 209 cricket::GetTestFilePath("captured-320x240-2s-48.frames"); 210 EXPECT_TRUE(dm->GetVideoCaptureDevice(test_file, &device)); 211 EXPECT_TRUE(cricket::FileVideoCapturer::IsFileVideoCapturerDevice(device)); 212} 213 214TEST(DeviceManagerTest, VerifyDevicesListsAreCleared) { 215 const std::string imaginary("_NOT A REAL DEVICE_"); 216 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); 217 std::vector<Device> audio_ins, audio_outs, video_ins; 218 audio_ins.push_back(Device(imaginary, imaginary)); 219 audio_outs.push_back(Device(imaginary, imaginary)); 220 video_ins.push_back(Device(imaginary, imaginary)); 221 EXPECT_TRUE(dm->Init()); 222 EXPECT_TRUE(dm->GetAudioInputDevices(&audio_ins)); 223 EXPECT_TRUE(dm->GetAudioOutputDevices(&audio_outs)); 224 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins)); 225 for (size_t i = 0; i < audio_ins.size(); ++i) { 226 EXPECT_NE(imaginary, audio_ins[i].name); 227 } 228 for (size_t i = 0; i < audio_outs.size(); ++i) { 229 EXPECT_NE(imaginary, audio_outs[i].name); 230 } 231 for (size_t i = 0; i < video_ins.size(); ++i) { 232 EXPECT_NE(imaginary, video_ins[i].name); 233 } 234} 235 236static bool CompareDeviceList(std::vector<Device>& devices, 237 const char* const device_list[], int list_size) { 238 if (list_size != static_cast<int>(devices.size())) { 239 return false; 240 } 241 for (int i = 0; i < list_size; ++i) { 242 if (devices[i].name.compare(device_list[i]) != 0) { 243 return false; 244 } 245 } 246 return true; 247} 248 249TEST(DeviceManagerTest, VerifyFilterDevices) { 250 static const char* const kTotalDevicesName[] = { 251 "Google Camera Adapters are tons of fun.", 252 "device1", 253 "device2", 254 "device3", 255 "device4", 256 "device5", 257 "Google Camera Adapter 0", 258 "Google Camera Adapter 1", 259 }; 260 static const char* const kFilteredDevicesName[] = { 261 "device2", 262 "device4", 263 "Google Camera Adapter", 264 NULL, 265 }; 266 static const char* const kDevicesName[] = { 267 "device1", 268 "device3", 269 "device5", 270 }; 271 std::vector<Device> devices; 272 for (int i = 0; i < ARRAY_SIZE(kTotalDevicesName); ++i) { 273 devices.push_back(Device(kTotalDevicesName[i], i)); 274 } 275 EXPECT_TRUE(CompareDeviceList(devices, kTotalDevicesName, 276 ARRAY_SIZE(kTotalDevicesName))); 277 // Return false if given NULL as the exclusion list. 278 EXPECT_TRUE(DeviceManager::FilterDevices(&devices, NULL)); 279 // The devices should not change. 280 EXPECT_TRUE(CompareDeviceList(devices, kTotalDevicesName, 281 ARRAY_SIZE(kTotalDevicesName))); 282 EXPECT_TRUE(DeviceManager::FilterDevices(&devices, kFilteredDevicesName)); 283 EXPECT_TRUE(CompareDeviceList(devices, kDevicesName, 284 ARRAY_SIZE(kDevicesName))); 285} 286 287#ifdef LINUX 288class FakeV4LLookup : public cricket::V4LLookup { 289 public: 290 explicit FakeV4LLookup(std::vector<std::string> device_paths) 291 : device_paths_(device_paths) {} 292 293 protected: 294 bool CheckIsV4L2Device(const std::string& device) { 295 return std::find(device_paths_.begin(), device_paths_.end(), device) 296 != device_paths_.end(); 297 } 298 299 private: 300 std::vector<std::string> device_paths_; 301}; 302 303TEST(DeviceManagerTest, GetVideoCaptureDevices_K2_6) { 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 "/sys/class/video4linux/video0/name", "Video Device 1")); 314 files.push_back(rtc::FakeFileSystem::File( 315 "/sys/class/video4linux/video1/model", "Bad Device")); 316 files.push_back( 317 rtc::FakeFileSystem::File("/sys/class/video4linux/video5/model", 318 "Video Device 2")); 319 rtc::FilesystemScope fs(new rtc::FakeFileSystem(files)); 320 321 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); 322 std::vector<Device> video_ins; 323 EXPECT_TRUE(dm->Init()); 324 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins)); 325 EXPECT_EQ(2u, video_ins.size()); 326 EXPECT_EQ("Video Device 1", video_ins.at(0).name); 327 EXPECT_EQ("Video Device 2", video_ins.at(1).name); 328} 329 330TEST(DeviceManagerTest, GetVideoCaptureDevices_K2_4) { 331 std::vector<std::string> devices; 332 devices.push_back("/dev/video0"); 333 devices.push_back("/dev/video5"); 334 cricket::V4LLookup::SetV4LLookup(new FakeV4LLookup(devices)); 335 336 std::vector<rtc::FakeFileSystem::File> files; 337 files.push_back(rtc::FakeFileSystem::File("/dev/video0", "")); 338 files.push_back(rtc::FakeFileSystem::File("/dev/video5", "")); 339 files.push_back(rtc::FakeFileSystem::File( 340 "/proc/video/dev/video0", 341 "param1: value1\nname: Video Device 1\n param2: value2\n")); 342 files.push_back(rtc::FakeFileSystem::File( 343 "/proc/video/dev/video1", 344 "param1: value1\nname: Bad Device\n param2: value2\n")); 345 files.push_back(rtc::FakeFileSystem::File( 346 "/proc/video/dev/video5", 347 "param1: value1\nname: Video Device 2\n param2: value2\n")); 348 rtc::FilesystemScope fs(new rtc::FakeFileSystem(files)); 349 350 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); 351 std::vector<Device> video_ins; 352 EXPECT_TRUE(dm->Init()); 353 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins)); 354 EXPECT_EQ(2u, video_ins.size()); 355 EXPECT_EQ("Video Device 1", video_ins.at(0).name); 356 EXPECT_EQ("Video Device 2", video_ins.at(1).name); 357} 358 359TEST(DeviceManagerTest, GetVideoCaptureDevices_KUnknown) { 360 std::vector<std::string> devices; 361 devices.push_back("/dev/video0"); 362 devices.push_back("/dev/video5"); 363 cricket::V4LLookup::SetV4LLookup(new FakeV4LLookup(devices)); 364 365 std::vector<rtc::FakeFileSystem::File> files; 366 files.push_back(rtc::FakeFileSystem::File("/dev/video0", "")); 367 files.push_back(rtc::FakeFileSystem::File("/dev/video1", "")); 368 files.push_back(rtc::FakeFileSystem::File("/dev/video5", "")); 369 rtc::FilesystemScope fs(new rtc::FakeFileSystem(files)); 370 371 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); 372 std::vector<Device> video_ins; 373 EXPECT_TRUE(dm->Init()); 374 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins)); 375 EXPECT_EQ(2u, video_ins.size()); 376 EXPECT_EQ("/dev/video0", video_ins.at(0).name); 377 EXPECT_EQ("/dev/video5", video_ins.at(1).name); 378} 379#endif // LINUX 380 381// TODO(noahric): These are flaky on windows on headless machines. 382#ifndef WIN32 383TEST(DeviceManagerTest, GetWindows) { 384 if (!rtc::WindowPickerFactory::IsSupported()) { 385 LOG(LS_INFO) << "skipping test: window capturing is not supported with " 386 << "current configuration."; 387 return; 388 } 389 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); 390 dm->SetScreenCapturerFactory(new FakeScreenCapturerFactory()); 391 std::vector<rtc::WindowDescription> descriptions; 392 EXPECT_TRUE(dm->Init()); 393 if (!dm->GetWindows(&descriptions) || descriptions.empty()) { 394 LOG(LS_INFO) << "skipping test: window capturing. Does not have any " 395 << "windows to capture."; 396 return; 397 } 398 scoped_ptr<cricket::VideoCapturer> capturer(dm->CreateScreenCapturer( 399 cricket::ScreencastId(descriptions.front().id()))); 400 EXPECT_FALSE(capturer.get() == NULL); 401 // TODO(hellner): creating a window capturer and immediately deleting it 402 // results in "Continuous Build and Test Mainline - Mac opt" failure (crash). 403 // Remove the following line as soon as this has been resolved. 404 rtc::Thread::Current()->ProcessMessages(1); 405} 406 407TEST(DeviceManagerTest, GetDesktops) { 408 if (!rtc::WindowPickerFactory::IsSupported()) { 409 LOG(LS_INFO) << "skipping test: desktop capturing is not supported with " 410 << "current configuration."; 411 return; 412 } 413 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create()); 414 dm->SetScreenCapturerFactory(new FakeScreenCapturerFactory()); 415 std::vector<rtc::DesktopDescription> descriptions; 416 EXPECT_TRUE(dm->Init()); 417 if (!dm->GetDesktops(&descriptions) || descriptions.empty()) { 418 LOG(LS_INFO) << "skipping test: desktop capturing. Does not have any " 419 << "desktops to capture."; 420 return; 421 } 422 scoped_ptr<cricket::VideoCapturer> capturer(dm->CreateScreenCapturer( 423 cricket::ScreencastId(descriptions.front().id()))); 424 EXPECT_FALSE(capturer.get() == NULL); 425} 426#endif // !WIN32 427 428TEST_F(DeviceManagerTestFake, CaptureConstraintsWhitelisted) { 429 const Device device("white", "white_id"); 430 dm_->SetVideoCaptureDeviceMaxFormat(device.name, kHdFormat); 431 scoped_ptr<cricket::VideoCapturer> capturer( 432 dm_->CreateVideoCapturer(device)); 433 cricket::VideoFormat best_format; 434 capturer->set_enable_camera_list(true); 435 EXPECT_TRUE(capturer->GetBestCaptureFormat(kHdFormat, &best_format)); 436 EXPECT_EQ(kHdFormat, best_format); 437} 438 439TEST_F(DeviceManagerTestFake, CaptureConstraintsNotWhitelisted) { 440 const Device device("regular", "regular_id"); 441 scoped_ptr<cricket::VideoCapturer> capturer( 442 dm_->CreateVideoCapturer(device)); 443 cricket::VideoFormat best_format; 444 capturer->set_enable_camera_list(true); 445 EXPECT_TRUE(capturer->GetBestCaptureFormat(kHdFormat, &best_format)); 446 EXPECT_EQ(kHdFormat, best_format); 447} 448 449TEST_F(DeviceManagerTestFake, CaptureConstraintsUnWhitelisted) { 450 const Device device("un_white", "un_white_id"); 451 dm_->SetVideoCaptureDeviceMaxFormat(device.name, kHdFormat); 452 dm_->ClearVideoCaptureDeviceMaxFormat(device.name); 453 scoped_ptr<cricket::VideoCapturer> capturer( 454 dm_->CreateVideoCapturer(device)); 455 cricket::VideoFormat best_format; 456 capturer->set_enable_camera_list(true); 457 EXPECT_TRUE(capturer->GetBestCaptureFormat(kHdFormat, &best_format)); 458 EXPECT_EQ(kHdFormat, best_format); 459} 460 461TEST_F(DeviceManagerTestFake, CaptureConstraintsWildcard) { 462 const Device device("any_device", "any_device"); 463 dm_->SetVideoCaptureDeviceMaxFormat("*", kHdFormat); 464 scoped_ptr<cricket::VideoCapturer> capturer( 465 dm_->CreateVideoCapturer(device)); 466 cricket::VideoFormat best_format; 467 capturer->set_enable_camera_list(true); 468 EXPECT_TRUE(capturer->GetBestCaptureFormat(kHdFormat, &best_format)); 469 EXPECT_EQ(kHdFormat, best_format); 470} 471