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#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" 40 41#if !defined(IOS) 42 43#if defined(HAVE_WEBRTC_VIDEO) 44#include "talk/media/webrtc/webrtcvideocapturer.h" 45#endif 46 47 48#if defined(HAVE_WEBRTC_VIDEO) 49#define VIDEO_CAPTURER_NAME WebRtcVideoCapturer 50#endif 51 52 53#endif 54 55namespace { 56 57bool StringMatchWithWildcard( 58 const std::pair<const std::basic_string<char>, cricket::VideoFormat> key, 59 const std::string& val) { 60 return talk_base::string_match(val.c_str(), key.first.c_str()); 61} 62 63} // namespace 64 65namespace cricket { 66 67// Initialize to empty string. 68const char DeviceManagerInterface::kDefaultDeviceName[] = ""; 69 70 71class DefaultVideoCapturerFactory : public VideoCapturerFactory { 72 public: 73 DefaultVideoCapturerFactory() {} 74 virtual ~DefaultVideoCapturerFactory() {} 75 76 VideoCapturer* Create(const Device& device) { 77#if defined(VIDEO_CAPTURER_NAME) 78 VIDEO_CAPTURER_NAME* return_value = new VIDEO_CAPTURER_NAME; 79 if (!return_value->Init(device)) { 80 delete return_value; 81 return NULL; 82 } 83 return return_value; 84#else 85 return NULL; 86#endif 87 } 88}; 89 90DeviceManager::DeviceManager() 91 : initialized_(false), 92 device_video_capturer_factory_(new DefaultVideoCapturerFactory), 93 window_picker_(talk_base::WindowPickerFactory::CreateWindowPicker()) { 94} 95 96DeviceManager::~DeviceManager() { 97 if (initialized()) { 98 Terminate(); 99 } 100} 101 102bool DeviceManager::Init() { 103 if (!initialized()) { 104 if (!watcher()->Start()) { 105 return false; 106 } 107 set_initialized(true); 108 } 109 return true; 110} 111 112void DeviceManager::Terminate() { 113 if (initialized()) { 114 watcher()->Stop(); 115 set_initialized(false); 116 } 117} 118 119int DeviceManager::GetCapabilities() { 120 std::vector<Device> devices; 121 int caps = VIDEO_RECV; 122 if (GetAudioInputDevices(&devices) && !devices.empty()) { 123 caps |= AUDIO_SEND; 124 } 125 if (GetAudioOutputDevices(&devices) && !devices.empty()) { 126 caps |= AUDIO_RECV; 127 } 128 if (GetVideoCaptureDevices(&devices) && !devices.empty()) { 129 caps |= VIDEO_SEND; 130 } 131 return caps; 132} 133 134bool DeviceManager::GetAudioInputDevices(std::vector<Device>* devices) { 135 return GetAudioDevices(true, devices); 136} 137 138bool DeviceManager::GetAudioOutputDevices(std::vector<Device>* devices) { 139 return GetAudioDevices(false, devices); 140} 141 142bool DeviceManager::GetAudioInputDevice(const std::string& name, Device* out) { 143 return GetAudioDevice(true, name, out); 144} 145 146bool DeviceManager::GetAudioOutputDevice(const std::string& name, Device* out) { 147 return GetAudioDevice(false, name, out); 148} 149 150bool DeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) { 151 devices->clear(); 152#if defined(ANDROID) || defined(IOS) 153 // On Android and iOS, we treat the camera(s) as a single device. Even if 154 // there are multiple cameras, that's abstracted away at a higher level. 155 Device dev("camera", "1"); // name and ID 156 devices->push_back(dev); 157 return true; 158#else 159 return false; 160#endif 161} 162 163bool DeviceManager::GetVideoCaptureDevice(const std::string& name, 164 Device* out) { 165 // If the name is empty, return the default device. 166 if (name.empty() || name == kDefaultDeviceName) { 167 return GetDefaultVideoCaptureDevice(out); 168 } 169 170 std::vector<Device> devices; 171 if (!GetVideoCaptureDevices(&devices)) { 172 return false; 173 } 174 175 for (std::vector<Device>::const_iterator it = devices.begin(); 176 it != devices.end(); ++it) { 177 if (name == it->name) { 178 *out = *it; 179 return true; 180 } 181 } 182 183 // If |name| is a valid name for a file, return a file video capturer device. 184 if (talk_base::Filesystem::IsFile(name)) { 185 *out = FileVideoCapturer::CreateFileVideoCapturerDevice(name); 186 return true; 187 } 188 189 return false; 190} 191 192void DeviceManager::SetVideoCaptureDeviceMaxFormat( 193 const std::string& usb_id, 194 const VideoFormat& max_format) { 195 max_formats_[usb_id] = max_format; 196} 197 198void DeviceManager::ClearVideoCaptureDeviceMaxFormat( 199 const std::string& usb_id) { 200 max_formats_.erase(usb_id); 201} 202 203VideoCapturer* DeviceManager::CreateVideoCapturer(const Device& device) const { 204#if defined(IOS) 205 LOG_F(LS_ERROR) << " should never be called!"; 206 return NULL; 207#else 208 // TODO(hellner): Throw out the creation of a file video capturer once the 209 // refactoring is completed. 210 if (FileVideoCapturer::IsFileVideoCapturerDevice(device)) { 211 FileVideoCapturer* capturer = new FileVideoCapturer; 212 if (!capturer->Init(device)) { 213 delete capturer; 214 return NULL; 215 } 216 LOG(LS_INFO) << "Created file video capturer " << device.name; 217 capturer->set_repeat(talk_base::kForever); 218 return capturer; 219 } 220 VideoCapturer* capturer = device_video_capturer_factory_->Create(device); 221 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; 232#endif 233} 234 235bool DeviceManager::GetWindows( 236 std::vector<talk_base::WindowDescription>* descriptions) { 237 if (!window_picker_) { 238 return false; 239 } 240 return window_picker_->GetWindowList(descriptions); 241} 242 243VideoCapturer* DeviceManager::CreateWindowCapturer(talk_base::WindowId window) { 244#if defined(WINDOW_CAPTURER_NAME) 245 WINDOW_CAPTURER_NAME* window_capturer = new WINDOW_CAPTURER_NAME(); 246 if (!window_capturer->Init(window)) { 247 delete window_capturer; 248 return NULL; 249 } 250 return window_capturer; 251#else 252 return NULL; 253#endif 254} 255 256bool DeviceManager::GetDesktops( 257 std::vector<talk_base::DesktopDescription>* descriptions) { 258 if (!window_picker_) { 259 return false; 260 } 261 return window_picker_->GetDesktopList(descriptions); 262} 263 264VideoCapturer* DeviceManager::CreateDesktopCapturer( 265 talk_base::DesktopId desktop) { 266#if defined(DESKTOP_CAPTURER_NAME) 267 DESKTOP_CAPTURER_NAME* desktop_capturer = new DESKTOP_CAPTURER_NAME(); 268 if (!desktop_capturer->Init(desktop.index())) { 269 delete desktop_capturer; 270 return NULL; 271 } 272 return desktop_capturer; 273#else 274 return NULL; 275#endif 276} 277 278bool DeviceManager::GetAudioDevices(bool input, 279 std::vector<Device>* devs) { 280 devs->clear(); 281#if defined(ANDROID) 282 // Under Android, 0 is always required for the playout device and 0 is the 283 // default for the recording device. 284 devs->push_back(Device("default-device", 0)); 285 return true; 286#else 287 // Other platforms either have their own derived class implementation 288 // (desktop) or don't use device manager for audio devices (iOS). 289 return false; 290#endif 291} 292 293bool DeviceManager::GetAudioDevice(bool is_input, const std::string& name, 294 Device* out) { 295 // If the name is empty, return the default device id. 296 if (name.empty() || name == kDefaultDeviceName) { 297 *out = Device(name, -1); 298 return true; 299 } 300 301 std::vector<Device> devices; 302 bool ret = is_input ? GetAudioInputDevices(&devices) : 303 GetAudioOutputDevices(&devices); 304 if (ret) { 305 ret = false; 306 for (size_t i = 0; i < devices.size(); ++i) { 307 if (devices[i].name == name) { 308 *out = devices[i]; 309 ret = true; 310 break; 311 } 312 } 313 } 314 return ret; 315} 316 317bool DeviceManager::GetDefaultVideoCaptureDevice(Device* device) { 318 bool ret = false; 319 // We just return the first device. 320 std::vector<Device> devices; 321 ret = (GetVideoCaptureDevices(&devices) && !devices.empty()); 322 if (ret) { 323 *device = devices[0]; 324 } 325 return ret; 326} 327 328bool DeviceManager::IsInWhitelist(const std::string& key, 329 VideoFormat* video_format) const { 330 std::map<std::string, VideoFormat>::const_iterator found = 331 std::search_n(max_formats_.begin(), max_formats_.end(), 1, key, 332 StringMatchWithWildcard); 333 if (found == max_formats_.end()) { 334 return false; 335 } 336 *video_format = found->second; 337 return true; 338} 339 340bool DeviceManager::GetMaxFormat(const Device& device, 341 VideoFormat* video_format) const { 342 // Match USB ID if available. Failing that, match device name. 343 std::string usb_id; 344 if (GetUsbId(device, &usb_id) && IsInWhitelist(usb_id, video_format)) { 345 return true; 346 } 347 return IsInWhitelist(device.name, video_format); 348} 349 350bool DeviceManager::ShouldDeviceBeIgnored(const std::string& device_name, 351 const char* const exclusion_list[]) { 352 // If exclusion_list is empty return directly. 353 if (!exclusion_list) 354 return false; 355 356 int i = 0; 357 while (exclusion_list[i]) { 358 if (strnicmp(device_name.c_str(), exclusion_list[i], 359 strlen(exclusion_list[i])) == 0) { 360 LOG(LS_INFO) << "Ignoring device " << device_name; 361 return true; 362 } 363 ++i; 364 } 365 return false; 366} 367 368bool DeviceManager::FilterDevices(std::vector<Device>* devices, 369 const char* const exclusion_list[]) { 370 if (!devices) { 371 return false; 372 } 373 374 for (std::vector<Device>::iterator it = devices->begin(); 375 it != devices->end(); ) { 376 if (ShouldDeviceBeIgnored(it->name, exclusion_list)) { 377 it = devices->erase(it); 378 } else { 379 ++it; 380 } 381 } 382 return true; 383} 384 385} // namespace cricket 386