150b55855d9dd395c03afeade601cbb6c9151885
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / media / devices / devicemanager.cc
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
55 namespace {
56
57 bool 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
65 namespace cricket {
66
67 // Initialize to empty string.
68 const char DeviceManagerInterface::kDefaultDeviceName[] = "";
69
70
71 class 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
90 DeviceManager::DeviceManager()
91     : initialized_(false),
92       device_video_capturer_factory_(new DefaultVideoCapturerFactory),
93       window_picker_(talk_base::WindowPickerFactory::CreateWindowPicker()) {
94 }
95
96 DeviceManager::~DeviceManager() {
97   if (initialized()) {
98     Terminate();
99   }
100 }
101
102 bool DeviceManager::Init() {
103   if (!initialized()) {
104     if (!watcher()->Start()) {
105       return false;
106     }
107     set_initialized(true);
108   }
109   return true;
110 }
111
112 void DeviceManager::Terminate() {
113   if (initialized()) {
114     watcher()->Stop();
115     set_initialized(false);
116   }
117 }
118
119 int 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
134 bool DeviceManager::GetAudioInputDevices(std::vector<Device>* devices) {
135   return GetAudioDevices(true, devices);
136 }
137
138 bool DeviceManager::GetAudioOutputDevices(std::vector<Device>* devices) {
139   return GetAudioDevices(false, devices);
140 }
141
142 bool DeviceManager::GetAudioInputDevice(const std::string& name, Device* out) {
143   return GetAudioDevice(true, name, out);
144 }
145
146 bool DeviceManager::GetAudioOutputDevice(const std::string& name, Device* out) {
147   return GetAudioDevice(false, name, out);
148 }
149
150 bool 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
163 bool 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
192 void DeviceManager::SetVideoCaptureDeviceMaxFormat(
193     const std::string& usb_id,
194     const VideoFormat& max_format) {
195   max_formats_[usb_id] = max_format;
196 }
197
198 void DeviceManager::ClearVideoCaptureDeviceMaxFormat(
199     const std::string& usb_id) {
200   max_formats_.erase(usb_id);
201 }
202
203 VideoCapturer* 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
235 bool 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
243 VideoCapturer* 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
256 bool 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
264 VideoCapturer* 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
278 bool 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
293 bool 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
317 bool 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
328 bool 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
340 bool 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
350 bool 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
368 bool 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