3 * Copyright 2004 Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
28 #include "talk/media/devices/devicemanager.h"
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 #include "talk/media/devices/yuvframescapturer.h"
44 #if defined(HAVE_WEBRTC_VIDEO)
45 #include "talk/media/webrtc/webrtcvideocapturer.h"
49 #if defined(HAVE_WEBRTC_VIDEO)
50 #define VIDEO_CAPTURER_NAME WebRtcVideoCapturer
58 bool StringMatchWithWildcard(
59 const std::pair<const std::basic_string<char>, cricket::VideoFormat> key,
60 const std::string& val) {
61 return talk_base::string_match(val.c_str(), key.first.c_str());
68 // Initialize to empty string.
69 const char DeviceManagerInterface::kDefaultDeviceName[] = "";
71 class DefaultVideoCapturerFactory : public VideoCapturerFactory {
73 DefaultVideoCapturerFactory() {}
74 virtual ~DefaultVideoCapturerFactory() {}
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)) {
90 DeviceManager::DeviceManager()
91 : initialized_(false),
92 device_video_capturer_factory_(new DefaultVideoCapturerFactory),
93 window_picker_(talk_base::WindowPickerFactory::CreateWindowPicker()) {
96 DeviceManager::~DeviceManager() {
102 bool DeviceManager::Init() {
103 if (!initialized()) {
104 if (!watcher()->Start()) {
107 set_initialized(true);
112 void DeviceManager::Terminate() {
115 set_initialized(false);
119 int DeviceManager::GetCapabilities() {
120 std::vector<Device> devices;
121 int caps = VIDEO_RECV;
122 if (GetAudioInputDevices(&devices) && !devices.empty()) {
125 if (GetAudioOutputDevices(&devices) && !devices.empty()) {
128 if (GetVideoCaptureDevices(&devices) && !devices.empty()) {
134 bool DeviceManager::GetAudioInputDevices(std::vector<Device>* devices) {
135 return GetAudioDevices(true, devices);
138 bool DeviceManager::GetAudioOutputDevices(std::vector<Device>* devices) {
139 return GetAudioDevices(false, devices);
142 bool DeviceManager::GetAudioInputDevice(const std::string& name, Device* out) {
143 return GetAudioDevice(true, name, out);
146 bool DeviceManager::GetAudioOutputDevice(const std::string& name, Device* out) {
147 return GetAudioDevice(false, name, out);
150 bool DeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) {
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);
163 bool DeviceManager::GetVideoCaptureDevice(const std::string& name,
165 // If the name is empty, return the default device.
166 if (name.empty() || name == kDefaultDeviceName) {
167 return GetDefaultVideoCaptureDevice(out);
170 std::vector<Device> devices;
171 if (!GetVideoCaptureDevices(&devices)) {
175 for (std::vector<Device>::const_iterator it = devices.begin();
176 it != devices.end(); ++it) {
177 if (name == it->name) {
183 // If |name| is a valid name for a file or yuvframedevice,
184 // return a fake video capturer device.
185 if (GetFakeVideoCaptureDevice(name, out)) {
192 bool DeviceManager::GetFakeVideoCaptureDevice(const std::string& name,
194 if (talk_base::Filesystem::IsFile(name)) {
195 *out = FileVideoCapturer::CreateFileVideoCapturerDevice(name);
199 if (name == YuvFramesCapturer::kYuvFrameDeviceName) {
200 *out = YuvFramesCapturer::CreateYuvFramesCapturerDevice();
207 void DeviceManager::SetVideoCaptureDeviceMaxFormat(
208 const std::string& usb_id,
209 const VideoFormat& max_format) {
210 max_formats_[usb_id] = max_format;
213 void DeviceManager::ClearVideoCaptureDeviceMaxFormat(
214 const std::string& usb_id) {
215 max_formats_.erase(usb_id);
218 VideoCapturer* DeviceManager::CreateVideoCapturer(const Device& device) const {
220 LOG_F(LS_ERROR) << " should never be called!";
223 VideoCapturer* capturer = ConstructFakeVideoCapturer(device);
228 capturer = device_video_capturer_factory_->Create(device);
232 LOG(LS_INFO) << "Created VideoCapturer for " << device.name;
233 VideoFormat video_format;
234 bool has_max = GetMaxFormat(device, &video_format);
235 capturer->set_enable_camera_list(has_max);
237 capturer->ConstrainSupportedFormats(video_format);
243 VideoCapturer* DeviceManager::ConstructFakeVideoCapturer(
244 const Device& device) const {
245 // TODO(hellner): Throw out the creation of a file video capturer once the
246 // refactoring is completed.
247 if (FileVideoCapturer::IsFileVideoCapturerDevice(device)) {
248 FileVideoCapturer* capturer = new FileVideoCapturer;
249 if (!capturer->Init(device)) {
253 LOG(LS_INFO) << "Created file video capturer " << device.name;
254 capturer->set_repeat(talk_base::kForever);
258 if (YuvFramesCapturer::IsYuvFramesCapturerDevice(device)) {
259 YuvFramesCapturer* capturer = new YuvFramesCapturer();
266 bool DeviceManager::GetWindows(
267 std::vector<talk_base::WindowDescription>* descriptions) {
268 if (!window_picker_) {
271 return window_picker_->GetWindowList(descriptions);
274 VideoCapturer* DeviceManager::CreateWindowCapturer(talk_base::WindowId window) {
275 #if defined(WINDOW_CAPTURER_NAME)
276 WINDOW_CAPTURER_NAME* window_capturer = new WINDOW_CAPTURER_NAME();
277 if (!window_capturer->Init(window)) {
278 delete window_capturer;
281 return window_capturer;
287 bool DeviceManager::GetDesktops(
288 std::vector<talk_base::DesktopDescription>* descriptions) {
289 if (!window_picker_) {
292 return window_picker_->GetDesktopList(descriptions);
295 VideoCapturer* DeviceManager::CreateDesktopCapturer(
296 talk_base::DesktopId desktop) {
297 #if defined(DESKTOP_CAPTURER_NAME)
298 DESKTOP_CAPTURER_NAME* desktop_capturer = new DESKTOP_CAPTURER_NAME();
299 if (!desktop_capturer->Init(desktop.index())) {
300 delete desktop_capturer;
303 return desktop_capturer;
309 bool DeviceManager::GetAudioDevices(bool input,
310 std::vector<Device>* devs) {
313 // Under Android, 0 is always required for the playout device and 0 is the
314 // default for the recording device.
315 devs->push_back(Device("default-device", 0));
318 // Other platforms either have their own derived class implementation
319 // (desktop) or don't use device manager for audio devices (iOS).
324 bool DeviceManager::GetAudioDevice(bool is_input, const std::string& name,
326 // If the name is empty, return the default device id.
327 if (name.empty() || name == kDefaultDeviceName) {
328 *out = Device(name, -1);
332 std::vector<Device> devices;
333 bool ret = is_input ? GetAudioInputDevices(&devices) :
334 GetAudioOutputDevices(&devices);
337 for (size_t i = 0; i < devices.size(); ++i) {
338 if (devices[i].name == name) {
348 bool DeviceManager::GetDefaultVideoCaptureDevice(Device* device) {
350 // We just return the first device.
351 std::vector<Device> devices;
352 ret = (GetVideoCaptureDevices(&devices) && !devices.empty());
354 *device = devices[0];
359 bool DeviceManager::IsInWhitelist(const std::string& key,
360 VideoFormat* video_format) const {
361 std::map<std::string, VideoFormat>::const_iterator found =
362 std::search_n(max_formats_.begin(), max_formats_.end(), 1, key,
363 StringMatchWithWildcard);
364 if (found == max_formats_.end()) {
367 *video_format = found->second;
371 bool DeviceManager::GetMaxFormat(const Device& device,
372 VideoFormat* video_format) const {
373 // Match USB ID if available. Failing that, match device name.
375 if (GetUsbId(device, &usb_id) && IsInWhitelist(usb_id, video_format)) {
378 return IsInWhitelist(device.name, video_format);
381 bool DeviceManager::ShouldDeviceBeIgnored(const std::string& device_name,
382 const char* const exclusion_list[]) {
383 // If exclusion_list is empty return directly.
388 while (exclusion_list[i]) {
389 if (strnicmp(device_name.c_str(), exclusion_list[i],
390 strlen(exclusion_list[i])) == 0) {
391 LOG(LS_INFO) << "Ignoring device " << device_name;
399 bool DeviceManager::FilterDevices(std::vector<Device>* devices,
400 const char* const exclusion_list[]) {
405 for (std::vector<Device>::iterator it = devices->begin();
406 it != devices->end(); ) {
407 if (ShouldDeviceBeIgnored(it->name, exclusion_list)) {
408 it = devices->erase(it);
416 } // namespace cricket