1 /*
2 * libjingle
3 * Copyright 2004--2008, 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 #ifdef WIN32
29 #include "talk/base/win32.h"
30 #include <objbase.h>
31 #endif
32 #include <string>
33
34 #include "talk/base/fileutils.h"
35 #include "talk/base/gunit.h"
36 #include "talk/base/logging.h"
37 #include "talk/base/pathutils.h"
38 #include "talk/base/scoped_ptr.h"
39 #include "talk/base/stream.h"
40 #include "talk/session/phone/devicemanager.h"
41 #include "talk/session/phone/filevideocapturer.h"
42 #include "talk/session/phone/testutils.h"
43 #include "talk/session/phone/v4llookup.h"
44
45 #ifdef LINUX
46 // TODO: Figure out why this doesn't compile on Windows.
47 #include "talk/base/fileutils_mock.h"
48 #endif // LINUX
49
50 #include "talk/session/phone/devicemanager.h"
51
52 using talk_base::Pathname;
53 using talk_base::FileTimeType;
54 using talk_base::scoped_ptr;
55 using cricket::Device;
56 using cricket::DeviceManager;
57 using cricket::DeviceManagerFactory;
58 using cricket::DeviceManagerInterface;
59
60 // Test that we startup/shutdown properly.
TEST(DeviceManagerTest,StartupShutdown)61 TEST(DeviceManagerTest, StartupShutdown) {
62 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
63 EXPECT_TRUE(dm->Init());
64 dm->Terminate();
65 }
66
67 // Test CoInitEx behavior
68 #ifdef WIN32
TEST(DeviceManagerTest,CoInitialize)69 TEST(DeviceManagerTest, CoInitialize) {
70 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
71 std::vector<Device> devices;
72 // Ensure that calls to video device work if COM is not yet initialized.
73 EXPECT_TRUE(dm->Init());
74 EXPECT_TRUE(dm->GetVideoCaptureDevices(&devices));
75 dm->Terminate();
76 // Ensure that the ref count is correct.
77 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED));
78 CoUninitialize();
79 // Ensure that Init works in COINIT_APARTMENTTHREADED setting.
80 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
81 EXPECT_TRUE(dm->Init());
82 dm->Terminate();
83 CoUninitialize();
84 // Ensure that the ref count is correct.
85 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
86 CoUninitialize();
87 // Ensure that Init works in COINIT_MULTITHREADED setting.
88 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED));
89 EXPECT_TRUE(dm->Init());
90 dm->Terminate();
91 CoUninitialize();
92 // Ensure that the ref count is correct.
93 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED));
94 CoUninitialize();
95 }
96 #endif
97
98 // Test enumerating devices (although we may not find any).
TEST(DeviceManagerTest,GetDevices)99 TEST(DeviceManagerTest, GetDevices) {
100 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
101 std::vector<Device> audio_ins, audio_outs, video_ins;
102 std::vector<cricket::Device> video_in_devs;
103 cricket::Device def_video;
104 EXPECT_TRUE(dm->Init());
105 EXPECT_TRUE(dm->GetAudioInputDevices(&audio_ins));
106 EXPECT_TRUE(dm->GetAudioOutputDevices(&audio_outs));
107 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
108 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_in_devs));
109 EXPECT_EQ(video_ins.size(), video_in_devs.size());
110 // If we have any video devices, we should be able to pick a default.
111 EXPECT_TRUE(dm->GetVideoCaptureDevice(
112 cricket::DeviceManagerInterface::kDefaultDeviceName, &def_video)
113 != video_ins.empty());
114 }
115
116 // Test that we return correct ids for default and bogus devices.
TEST(DeviceManagerTest,GetAudioDeviceIds)117 TEST(DeviceManagerTest, GetAudioDeviceIds) {
118 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
119 Device device;
120 EXPECT_TRUE(dm->Init());
121 EXPECT_TRUE(dm->GetAudioInputDevice(
122 cricket::DeviceManagerInterface::kDefaultDeviceName, &device));
123 EXPECT_EQ("-1", device.id);
124 EXPECT_TRUE(dm->GetAudioOutputDevice(
125 cricket::DeviceManagerInterface::kDefaultDeviceName, &device));
126 EXPECT_EQ("-1", device.id);
127 EXPECT_FALSE(dm->GetAudioInputDevice("_NOT A REAL DEVICE_", &device));
128 EXPECT_FALSE(dm->GetAudioOutputDevice("_NOT A REAL DEVICE_", &device));
129 }
130
131 // Test that we get the video capture device by name properly.
TEST(DeviceManagerTest,GetVideoDeviceIds)132 TEST(DeviceManagerTest, GetVideoDeviceIds) {
133 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
134 Device device;
135 EXPECT_TRUE(dm->Init());
136 EXPECT_FALSE(dm->GetVideoCaptureDevice("_NOT A REAL DEVICE_", &device));
137 std::vector<Device> video_ins;
138 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
139 if (!video_ins.empty()) {
140 // Get the default device with the parameter kDefaultDeviceName.
141 EXPECT_TRUE(dm->GetVideoCaptureDevice(
142 cricket::DeviceManagerInterface::kDefaultDeviceName, &device));
143
144 // Get the first device with the parameter video_ins[0].name.
145 EXPECT_TRUE(dm->GetVideoCaptureDevice(video_ins[0].name, &device));
146 EXPECT_EQ(device.name, video_ins[0].name);
147 EXPECT_EQ(device.id, video_ins[0].id);
148 }
149 }
150
TEST(DeviceManagerTest,GetVideoDeviceIds_File)151 TEST(DeviceManagerTest, GetVideoDeviceIds_File) {
152 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
153 EXPECT_TRUE(dm->Init());
154 Device device;
155 const std::string test_file =
156 cricket::GetTestFilePath("captured-320x240-2s-48.frames");
157 EXPECT_TRUE(dm->GetVideoCaptureDevice(test_file, &device));
158 EXPECT_TRUE(cricket::FileVideoCapturer::IsFileVideoCapturerDevice(device));
159 }
160
TEST(DeviceManagerTest,VerifyDevicesListsAreCleared)161 TEST(DeviceManagerTest, VerifyDevicesListsAreCleared) {
162 const std::string imaginary("_NOT A REAL DEVICE_");
163 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
164 std::vector<Device> audio_ins, audio_outs, video_ins;
165 audio_ins.push_back(Device(imaginary, imaginary));
166 audio_outs.push_back(Device(imaginary, imaginary));
167 video_ins.push_back(Device(imaginary, imaginary));
168 EXPECT_TRUE(dm->Init());
169 EXPECT_TRUE(dm->GetAudioInputDevices(&audio_ins));
170 EXPECT_TRUE(dm->GetAudioOutputDevices(&audio_outs));
171 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
172 for (size_t i = 0; i < audio_ins.size(); ++i) {
173 EXPECT_NE(imaginary, audio_ins[i].name);
174 }
175 for (size_t i = 0; i < audio_outs.size(); ++i) {
176 EXPECT_NE(imaginary, audio_outs[i].name);
177 }
178 for (size_t i = 0; i < video_ins.size(); ++i) {
179 EXPECT_NE(imaginary, video_ins[i].name);
180 }
181 }
182
CompareDeviceList(std::vector<Device> & devices,const char * const device_list[],int list_size)183 static bool CompareDeviceList(std::vector<Device>& devices,
184 const char* const device_list[], int list_size) {
185 if (list_size != static_cast<int>(devices.size())) {
186 return false;
187 }
188 for (int i = 0; i < list_size; ++i) {
189 if (devices[i].name.compare(device_list[i]) != 0) {
190 return false;
191 }
192 }
193 return true;
194 }
195
TEST(DeviceManagerTest,VerifyFilterDevices)196 TEST(DeviceManagerTest, VerifyFilterDevices) {
197 static const char* const kTotalDevicesName[] = {
198 "Google Camera Adapters are tons of fun.",
199 "device1",
200 "device2",
201 "device3",
202 "device4",
203 "device5",
204 "Google Camera Adapter 0",
205 "Google Camera Adapter 1",
206 };
207 static const char* const kFilteredDevicesName[] = {
208 "device2",
209 "device4",
210 "Google Camera Adapter",
211 NULL,
212 };
213 static const char* const kDevicesName[] = {
214 "device1",
215 "device3",
216 "device5",
217 };
218 std::vector<Device> devices;
219 for (int i = 0; i < ARRAY_SIZE(kTotalDevicesName); ++i) {
220 devices.push_back(Device(kTotalDevicesName[i], i));
221 }
222 EXPECT_TRUE(CompareDeviceList(devices, kTotalDevicesName,
223 ARRAY_SIZE(kTotalDevicesName)));
224 // Return false if given NULL as the exclusion list.
225 EXPECT_TRUE(DeviceManager::FilterDevices(&devices, NULL));
226 // The devices should not change.
227 EXPECT_TRUE(CompareDeviceList(devices, kTotalDevicesName,
228 ARRAY_SIZE(kTotalDevicesName)));
229 EXPECT_TRUE(DeviceManager::FilterDevices(&devices, kFilteredDevicesName));
230 EXPECT_TRUE(CompareDeviceList(devices, kDevicesName,
231 ARRAY_SIZE(kDevicesName)));
232 }
233
234 #ifdef LINUX
235 class FakeV4LLookup : public cricket::V4LLookup {
236 public:
FakeV4LLookup(std::vector<std::string> device_paths)237 explicit FakeV4LLookup(std::vector<std::string> device_paths)
238 : device_paths_(device_paths) {}
239
240 protected:
CheckIsV4L2Device(const std::string & device)241 bool CheckIsV4L2Device(const std::string& device) {
242 return std::find(device_paths_.begin(), device_paths_.end(), device)
243 != device_paths_.end();
244 }
245
246 private:
247 std::vector<std::string> device_paths_;
248 };
249
TEST(DeviceManagerTest,GetVideoCaptureDevices_K2_6)250 TEST(DeviceManagerTest, GetVideoCaptureDevices_K2_6) {
251 std::vector<std::string> devices;
252 devices.push_back("/dev/video0");
253 devices.push_back("/dev/video5");
254 cricket::V4LLookup::SetV4LLookup(new FakeV4LLookup(devices));
255
256 std::vector<talk_base::FakeFileSystem::File> files;
257 files.push_back(talk_base::FakeFileSystem::File("/dev/video0", ""));
258 files.push_back(talk_base::FakeFileSystem::File("/dev/video5", ""));
259 files.push_back(talk_base::FakeFileSystem::File(
260 "/sys/class/video4linux/video0/name", "Video Device 1"));
261 files.push_back(talk_base::FakeFileSystem::File(
262 "/sys/class/video4linux/video1/model", "Bad Device"));
263 files.push_back(
264 talk_base::FakeFileSystem::File("/sys/class/video4linux/video5/model",
265 "Video Device 2"));
266 talk_base::FilesystemScope fs(new talk_base::FakeFileSystem(files));
267
268 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
269 std::vector<Device> video_ins;
270 EXPECT_TRUE(dm->Init());
271 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
272 EXPECT_EQ(2u, video_ins.size());
273 EXPECT_EQ("Video Device 1", video_ins.at(0).name);
274 EXPECT_EQ("Video Device 2", video_ins.at(1).name);
275 }
276
TEST(DeviceManagerTest,GetVideoCaptureDevices_K2_4)277 TEST(DeviceManagerTest, GetVideoCaptureDevices_K2_4) {
278 std::vector<std::string> devices;
279 devices.push_back("/dev/video0");
280 devices.push_back("/dev/video5");
281 cricket::V4LLookup::SetV4LLookup(new FakeV4LLookup(devices));
282
283 std::vector<talk_base::FakeFileSystem::File> files;
284 files.push_back(talk_base::FakeFileSystem::File("/dev/video0", ""));
285 files.push_back(talk_base::FakeFileSystem::File("/dev/video5", ""));
286 files.push_back(talk_base::FakeFileSystem::File(
287 "/proc/video/dev/video0",
288 "param1: value1\nname: Video Device 1\n param2: value2\n"));
289 files.push_back(talk_base::FakeFileSystem::File(
290 "/proc/video/dev/video1",
291 "param1: value1\nname: Bad Device\n param2: value2\n"));
292 files.push_back(talk_base::FakeFileSystem::File(
293 "/proc/video/dev/video5",
294 "param1: value1\nname: Video Device 2\n param2: value2\n"));
295 talk_base::FilesystemScope fs(new talk_base::FakeFileSystem(files));
296
297 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
298 std::vector<Device> video_ins;
299 EXPECT_TRUE(dm->Init());
300 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
301 EXPECT_EQ(2u, video_ins.size());
302 EXPECT_EQ("Video Device 1", video_ins.at(0).name);
303 EXPECT_EQ("Video Device 2", video_ins.at(1).name);
304 }
305
TEST(DeviceManagerTest,GetVideoCaptureDevices_KUnknown)306 TEST(DeviceManagerTest, GetVideoCaptureDevices_KUnknown) {
307 std::vector<std::string> devices;
308 devices.push_back("/dev/video0");
309 devices.push_back("/dev/video5");
310 cricket::V4LLookup::SetV4LLookup(new FakeV4LLookup(devices));
311
312 std::vector<talk_base::FakeFileSystem::File> files;
313 files.push_back(talk_base::FakeFileSystem::File("/dev/video0", ""));
314 files.push_back(talk_base::FakeFileSystem::File("/dev/video1", ""));
315 files.push_back(talk_base::FakeFileSystem::File("/dev/video5", ""));
316 talk_base::FilesystemScope fs(new talk_base::FakeFileSystem(files));
317
318 scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
319 std::vector<Device> video_ins;
320 EXPECT_TRUE(dm->Init());
321 EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
322 EXPECT_EQ(2u, video_ins.size());
323 EXPECT_EQ("/dev/video0", video_ins.at(0).name);
324 EXPECT_EQ("/dev/video5", video_ins.at(1).name);
325 }
326 #endif // LINUX
327