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