blob: 75b935ce592eaadab544ddf9123f0226ad2b7e95 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
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#include "talk/base/fileutils.h"
31#include "talk/base/logging.h"
32#include "talk/base/pathutils.h"
33#include "talk/base/stringutils.h"
34#include "talk/base/thread.h"
35#include "talk/base/windowpicker.h"
36#include "talk/base/windowpickerfactory.h"
37#include "talk/media/base/mediacommon.h"
38#include "talk/media/devices/deviceinfo.h"
39#include "talk/media/devices/filevideocapturer.h"
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +000040#include "talk/media/devices/yuvframescapturer.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041
henrike@webrtc.org28e20752013-07-10 00:45:36 +000042#if defined(HAVE_WEBRTC_VIDEO)
43#include "talk/media/webrtc/webrtcvideocapturer.h"
44#endif
45
46
47#if defined(HAVE_WEBRTC_VIDEO)
48#define VIDEO_CAPTURER_NAME WebRtcVideoCapturer
49#endif
50
51
henrike@webrtc.org28e20752013-07-10 00:45:36 +000052namespace {
53
54bool StringMatchWithWildcard(
55 const std::pair<const std::basic_string<char>, cricket::VideoFormat> key,
56 const std::string& val) {
57 return talk_base::string_match(val.c_str(), key.first.c_str());
58}
59
60} // namespace
61
62namespace cricket {
63
64// Initialize to empty string.
65const char DeviceManagerInterface::kDefaultDeviceName[] = "";
66
henrike@webrtc.org28e20752013-07-10 00:45:36 +000067class DefaultVideoCapturerFactory : public VideoCapturerFactory {
68 public:
69 DefaultVideoCapturerFactory() {}
70 virtual ~DefaultVideoCapturerFactory() {}
71
72 VideoCapturer* Create(const Device& device) {
73#if defined(VIDEO_CAPTURER_NAME)
74 VIDEO_CAPTURER_NAME* return_value = new VIDEO_CAPTURER_NAME;
75 if (!return_value->Init(device)) {
76 delete return_value;
77 return NULL;
78 }
79 return return_value;
80#else
81 return NULL;
82#endif
83 }
84};
85
86DeviceManager::DeviceManager()
87 : initialized_(false),
88 device_video_capturer_factory_(new DefaultVideoCapturerFactory),
89 window_picker_(talk_base::WindowPickerFactory::CreateWindowPicker()) {
90}
91
92DeviceManager::~DeviceManager() {
93 if (initialized()) {
94 Terminate();
95 }
96}
97
98bool DeviceManager::Init() {
99 if (!initialized()) {
buildbot@webrtc.org861d4b02014-05-06 22:11:02 +0000100 if (!watcher()->Start()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000101 return false;
102 }
103 set_initialized(true);
104 }
105 return true;
106}
107
108void DeviceManager::Terminate() {
109 if (initialized()) {
buildbot@webrtc.org861d4b02014-05-06 22:11:02 +0000110 watcher()->Stop();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111 set_initialized(false);
112 }
113}
114
115int DeviceManager::GetCapabilities() {
116 std::vector<Device> devices;
117 int caps = VIDEO_RECV;
118 if (GetAudioInputDevices(&devices) && !devices.empty()) {
119 caps |= AUDIO_SEND;
120 }
121 if (GetAudioOutputDevices(&devices) && !devices.empty()) {
122 caps |= AUDIO_RECV;
123 }
124 if (GetVideoCaptureDevices(&devices) && !devices.empty()) {
125 caps |= VIDEO_SEND;
126 }
127 return caps;
128}
129
130bool DeviceManager::GetAudioInputDevices(std::vector<Device>* devices) {
131 return GetAudioDevices(true, devices);
132}
133
134bool DeviceManager::GetAudioOutputDevices(std::vector<Device>* devices) {
135 return GetAudioDevices(false, devices);
136}
137
138bool DeviceManager::GetAudioInputDevice(const std::string& name, Device* out) {
139 return GetAudioDevice(true, name, out);
140}
141
142bool DeviceManager::GetAudioOutputDevice(const std::string& name, Device* out) {
143 return GetAudioDevice(false, name, out);
144}
145
146bool DeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) {
147 devices->clear();
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000148#if defined(ANDROID) || defined(IOS)
149 // On Android and iOS, we treat the camera(s) as a single device. Even if
150 // there are multiple cameras, that's abstracted away at a higher level.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151 Device dev("camera", "1"); // name and ID
152 devices->push_back(dev);
153 return true;
154#else
155 return false;
156#endif
157}
158
159bool DeviceManager::GetVideoCaptureDevice(const std::string& name,
160 Device* out) {
161 // If the name is empty, return the default device.
162 if (name.empty() || name == kDefaultDeviceName) {
163 return GetDefaultVideoCaptureDevice(out);
164 }
165
166 std::vector<Device> devices;
167 if (!GetVideoCaptureDevices(&devices)) {
168 return false;
169 }
170
171 for (std::vector<Device>::const_iterator it = devices.begin();
172 it != devices.end(); ++it) {
173 if (name == it->name) {
174 *out = *it;
175 return true;
176 }
177 }
178
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000179 // If |name| is a valid name for a file or yuvframedevice,
180 // return a fake video capturer device.
181 if (GetFakeVideoCaptureDevice(name, out)) {
182 return true;
183 }
184
185 return false;
186}
187
188bool DeviceManager::GetFakeVideoCaptureDevice(const std::string& name,
189 Device* out) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000190 if (talk_base::Filesystem::IsFile(name)) {
191 *out = FileVideoCapturer::CreateFileVideoCapturerDevice(name);
192 return true;
193 }
194
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000195 if (name == YuvFramesCapturer::kYuvFrameDeviceName) {
196 *out = YuvFramesCapturer::CreateYuvFramesCapturerDevice();
197 return true;
198 }
199
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000200 return false;
201}
202
203void DeviceManager::SetVideoCaptureDeviceMaxFormat(
204 const std::string& usb_id,
205 const VideoFormat& max_format) {
206 max_formats_[usb_id] = max_format;
207}
208
209void DeviceManager::ClearVideoCaptureDeviceMaxFormat(
210 const std::string& usb_id) {
211 max_formats_.erase(usb_id);
212}
213
214VideoCapturer* DeviceManager::CreateVideoCapturer(const Device& device) const {
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000215 VideoCapturer* capturer = ConstructFakeVideoCapturer(device);
216 if (capturer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000217 return capturer;
218 }
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000219
220 capturer = device_video_capturer_factory_->Create(device);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000221 if (!capturer) {
222 return NULL;
223 }
224 LOG(LS_INFO) << "Created VideoCapturer for " << device.name;
225 VideoFormat video_format;
226 bool has_max = GetMaxFormat(device, &video_format);
227 capturer->set_enable_camera_list(has_max);
228 if (has_max) {
229 capturer->ConstrainSupportedFormats(video_format);
230 }
231 return capturer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000232}
233
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000234VideoCapturer* DeviceManager::ConstructFakeVideoCapturer(
235 const Device& device) const {
236 // TODO(hellner): Throw out the creation of a file video capturer once the
237 // refactoring is completed.
238 if (FileVideoCapturer::IsFileVideoCapturerDevice(device)) {
239 FileVideoCapturer* capturer = new FileVideoCapturer;
240 if (!capturer->Init(device)) {
241 delete capturer;
242 return NULL;
243 }
244 LOG(LS_INFO) << "Created file video capturer " << device.name;
245 capturer->set_repeat(talk_base::kForever);
246 return capturer;
247 }
248
249 if (YuvFramesCapturer::IsYuvFramesCapturerDevice(device)) {
250 YuvFramesCapturer* capturer = new YuvFramesCapturer();
251 capturer->Init();
252 return capturer;
253 }
254 return NULL;
255}
256
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000257bool DeviceManager::GetWindows(
258 std::vector<talk_base::WindowDescription>* descriptions) {
259 if (!window_picker_) {
260 return false;
261 }
262 return window_picker_->GetWindowList(descriptions);
263}
264
265VideoCapturer* DeviceManager::CreateWindowCapturer(talk_base::WindowId window) {
266#if defined(WINDOW_CAPTURER_NAME)
267 WINDOW_CAPTURER_NAME* window_capturer = new WINDOW_CAPTURER_NAME();
268 if (!window_capturer->Init(window)) {
269 delete window_capturer;
270 return NULL;
271 }
272 return window_capturer;
273#else
274 return NULL;
275#endif
276}
277
278bool DeviceManager::GetDesktops(
279 std::vector<talk_base::DesktopDescription>* descriptions) {
280 if (!window_picker_) {
281 return false;
282 }
283 return window_picker_->GetDesktopList(descriptions);
284}
285
286VideoCapturer* DeviceManager::CreateDesktopCapturer(
287 talk_base::DesktopId desktop) {
288#if defined(DESKTOP_CAPTURER_NAME)
289 DESKTOP_CAPTURER_NAME* desktop_capturer = new DESKTOP_CAPTURER_NAME();
290 if (!desktop_capturer->Init(desktop.index())) {
291 delete desktop_capturer;
292 return NULL;
293 }
294 return desktop_capturer;
295#else
296 return NULL;
297#endif
298}
299
300bool DeviceManager::GetAudioDevices(bool input,
301 std::vector<Device>* devs) {
302 devs->clear();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000303#if defined(ANDROID)
304 // Under Android, 0 is always required for the playout device and 0 is the
305 // default for the recording device.
306 devs->push_back(Device("default-device", 0));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000307 return true;
308#else
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000309 // Other platforms either have their own derived class implementation
310 // (desktop) or don't use device manager for audio devices (iOS).
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000311 return false;
312#endif
313}
314
315bool DeviceManager::GetAudioDevice(bool is_input, const std::string& name,
316 Device* out) {
317 // If the name is empty, return the default device id.
318 if (name.empty() || name == kDefaultDeviceName) {
319 *out = Device(name, -1);
320 return true;
321 }
322
323 std::vector<Device> devices;
324 bool ret = is_input ? GetAudioInputDevices(&devices) :
325 GetAudioOutputDevices(&devices);
326 if (ret) {
327 ret = false;
328 for (size_t i = 0; i < devices.size(); ++i) {
329 if (devices[i].name == name) {
330 *out = devices[i];
331 ret = true;
332 break;
333 }
334 }
335 }
336 return ret;
337}
338
339bool DeviceManager::GetDefaultVideoCaptureDevice(Device* device) {
340 bool ret = false;
341 // We just return the first device.
342 std::vector<Device> devices;
343 ret = (GetVideoCaptureDevices(&devices) && !devices.empty());
344 if (ret) {
345 *device = devices[0];
346 }
347 return ret;
348}
349
350bool DeviceManager::IsInWhitelist(const std::string& key,
351 VideoFormat* video_format) const {
352 std::map<std::string, VideoFormat>::const_iterator found =
353 std::search_n(max_formats_.begin(), max_formats_.end(), 1, key,
354 StringMatchWithWildcard);
355 if (found == max_formats_.end()) {
356 return false;
357 }
358 *video_format = found->second;
359 return true;
360}
361
362bool DeviceManager::GetMaxFormat(const Device& device,
363 VideoFormat* video_format) const {
364 // Match USB ID if available. Failing that, match device name.
365 std::string usb_id;
366 if (GetUsbId(device, &usb_id) && IsInWhitelist(usb_id, video_format)) {
367 return true;
368 }
369 return IsInWhitelist(device.name, video_format);
370}
371
372bool DeviceManager::ShouldDeviceBeIgnored(const std::string& device_name,
373 const char* const exclusion_list[]) {
374 // If exclusion_list is empty return directly.
375 if (!exclusion_list)
376 return false;
377
378 int i = 0;
379 while (exclusion_list[i]) {
380 if (strnicmp(device_name.c_str(), exclusion_list[i],
381 strlen(exclusion_list[i])) == 0) {
382 LOG(LS_INFO) << "Ignoring device " << device_name;
383 return true;
384 }
385 ++i;
386 }
387 return false;
388}
389
390bool DeviceManager::FilterDevices(std::vector<Device>* devices,
391 const char* const exclusion_list[]) {
392 if (!devices) {
393 return false;
394 }
395
396 for (std::vector<Device>::iterator it = devices->begin();
397 it != devices->end(); ) {
398 if (ShouldDeviceBeIgnored(it->name, exclusion_list)) {
399 it = devices->erase(it);
400 } else {
401 ++it;
402 }
403 }
404 return true;
405}
406
407} // namespace cricket