• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "talk/media/devices/yuvframescapturer.h"
41 
42 #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 
52 namespace {
53 
StringMatchWithWildcard(const std::pair<const std::basic_string<char>,cricket::VideoFormat> key,const std::string & val)54 bool 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 
62 namespace cricket {
63 
64 // Initialize to empty string.
65 const char DeviceManagerInterface::kDefaultDeviceName[] = "";
66 
67 class DefaultVideoCapturerFactory : public VideoCapturerFactory {
68  public:
DefaultVideoCapturerFactory()69   DefaultVideoCapturerFactory() {}
~DefaultVideoCapturerFactory()70   virtual ~DefaultVideoCapturerFactory() {}
71 
Create(const Device & device)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 
DeviceManager()86 DeviceManager::DeviceManager()
87     : initialized_(false),
88       device_video_capturer_factory_(new DefaultVideoCapturerFactory),
89       window_picker_(talk_base::WindowPickerFactory::CreateWindowPicker()) {
90 }
91 
~DeviceManager()92 DeviceManager::~DeviceManager() {
93   if (initialized()) {
94     Terminate();
95   }
96 }
97 
Init()98 bool DeviceManager::Init() {
99   if (!initialized()) {
100     if (!watcher()->Start()) {
101       return false;
102     }
103     set_initialized(true);
104   }
105   return true;
106 }
107 
Terminate()108 void DeviceManager::Terminate() {
109   if (initialized()) {
110     watcher()->Stop();
111     set_initialized(false);
112   }
113 }
114 
GetCapabilities()115 int 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 
GetAudioInputDevices(std::vector<Device> * devices)130 bool DeviceManager::GetAudioInputDevices(std::vector<Device>* devices) {
131   return GetAudioDevices(true, devices);
132 }
133 
GetAudioOutputDevices(std::vector<Device> * devices)134 bool DeviceManager::GetAudioOutputDevices(std::vector<Device>* devices) {
135   return GetAudioDevices(false, devices);
136 }
137 
GetAudioInputDevice(const std::string & name,Device * out)138 bool DeviceManager::GetAudioInputDevice(const std::string& name, Device* out) {
139   return GetAudioDevice(true, name, out);
140 }
141 
GetAudioOutputDevice(const std::string & name,Device * out)142 bool DeviceManager::GetAudioOutputDevice(const std::string& name, Device* out) {
143   return GetAudioDevice(false, name, out);
144 }
145 
GetVideoCaptureDevices(std::vector<Device> * devices)146 bool DeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) {
147   devices->clear();
148 #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.
151   Device dev("camera", "1");    // name and ID
152   devices->push_back(dev);
153   return true;
154 #else
155   return false;
156 #endif
157 }
158 
GetVideoCaptureDevice(const std::string & name,Device * out)159 bool 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 
179   // 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 
GetFakeVideoCaptureDevice(const std::string & name,Device * out) const188 bool DeviceManager::GetFakeVideoCaptureDevice(const std::string& name,
189                                               Device* out) const {
190   if (talk_base::Filesystem::IsFile(name)) {
191     *out = FileVideoCapturer::CreateFileVideoCapturerDevice(name);
192     return true;
193   }
194 
195   if (name == YuvFramesCapturer::kYuvFrameDeviceName) {
196     *out = YuvFramesCapturer::CreateYuvFramesCapturerDevice();
197     return true;
198   }
199 
200   return false;
201 }
202 
SetVideoCaptureDeviceMaxFormat(const std::string & usb_id,const VideoFormat & max_format)203 void DeviceManager::SetVideoCaptureDeviceMaxFormat(
204     const std::string& usb_id,
205     const VideoFormat& max_format) {
206   max_formats_[usb_id] = max_format;
207 }
208 
ClearVideoCaptureDeviceMaxFormat(const std::string & usb_id)209 void DeviceManager::ClearVideoCaptureDeviceMaxFormat(
210     const std::string& usb_id) {
211   max_formats_.erase(usb_id);
212 }
213 
CreateVideoCapturer(const Device & device) const214 VideoCapturer* DeviceManager::CreateVideoCapturer(const Device& device) const {
215   VideoCapturer* capturer = ConstructFakeVideoCapturer(device);
216   if (capturer) {
217     return capturer;
218   }
219 
220   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 }
233 
ConstructFakeVideoCapturer(const Device & device) const234 VideoCapturer* 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 
GetWindows(std::vector<talk_base::WindowDescription> * descriptions)257 bool 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 
CreateWindowCapturer(talk_base::WindowId window)265 VideoCapturer* 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 
GetDesktops(std::vector<talk_base::DesktopDescription> * descriptions)278 bool 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 
CreateDesktopCapturer(talk_base::DesktopId desktop)286 VideoCapturer* 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 
GetAudioDevices(bool input,std::vector<Device> * devs)300 bool DeviceManager::GetAudioDevices(bool input,
301                                     std::vector<Device>* devs) {
302   devs->clear();
303 #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));
307   return true;
308 #else
309   // Other platforms either have their own derived class implementation
310   // (desktop) or don't use device manager for audio devices (iOS).
311   return false;
312 #endif
313 }
314 
GetAudioDevice(bool is_input,const std::string & name,Device * out)315 bool 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 
GetDefaultVideoCaptureDevice(Device * device)339 bool 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 
IsInWhitelist(const std::string & key,VideoFormat * video_format) const350 bool 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 
GetMaxFormat(const Device & device,VideoFormat * video_format) const362 bool 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 
ShouldDeviceBeIgnored(const std::string & device_name,const char * const exclusion_list[])372 bool 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 
FilterDevices(std::vector<Device> * devices,const char * const exclusion_list[])390 bool 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
408