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/session/phone/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/session/phone/filevideocapturer.h"
36 #include "talk/session/phone/mediacommon.h"
37 
38 namespace cricket {
39 // Initialize to empty string.
40 const char DeviceManagerInterface::kDefaultDeviceName[] = "";
41 
DeviceManager()42 DeviceManager::DeviceManager()
43     : initialized_(false) {
44 }
45 
~DeviceManager()46 DeviceManager::~DeviceManager() {
47   if (initialized()) {
48     Terminate();
49   }
50 }
51 
Init()52 bool DeviceManager::Init() {
53   if (!initialized()) {
54     if (!watcher()->Start()) {
55       return false;
56     }
57     set_initialized(true);
58   }
59   return true;
60 }
61 
Terminate()62 void DeviceManager::Terminate() {
63   if (initialized()) {
64     watcher()->Stop();
65     set_initialized(false);
66   }
67 }
68 
GetCapabilities()69 int DeviceManager::GetCapabilities() {
70   std::vector<Device> devices;
71   int caps = VIDEO_RECV;
72   if (GetAudioInputDevices(&devices) && !devices.empty()) {
73     caps |= AUDIO_SEND;
74   }
75   if (GetAudioOutputDevices(&devices) && !devices.empty()) {
76     caps |= AUDIO_RECV;
77   }
78   if (GetVideoCaptureDevices(&devices) && !devices.empty()) {
79     caps |= VIDEO_SEND;
80   }
81   return caps;
82 }
83 
GetAudioInputDevices(std::vector<Device> * devices)84 bool DeviceManager::GetAudioInputDevices(std::vector<Device>* devices) {
85   return GetAudioDevices(true, devices);
86 }
87 
GetAudioOutputDevices(std::vector<Device> * devices)88 bool DeviceManager::GetAudioOutputDevices(std::vector<Device>* devices) {
89   return GetAudioDevices(false, devices);
90 }
91 
GetAudioInputDevice(const std::string & name,Device * out)92 bool DeviceManager::GetAudioInputDevice(const std::string& name, Device* out) {
93   return GetAudioDevice(true, name, out);
94 }
95 
GetAudioOutputDevice(const std::string & name,Device * out)96 bool DeviceManager::GetAudioOutputDevice(const std::string& name, Device* out) {
97   return GetAudioDevice(false, name, out);
98 }
99 
GetVideoCaptureDevices(std::vector<Device> * devices)100 bool DeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) {
101   devices->clear();
102 #if defined(ANDROID) || defined(IOS)
103   // TODO: Incomplete. Use ANDROID implementation for IOS
104   // to quiet compiler.
105   // On Android, we treat the camera(s) as a single device. Even if there are
106   // multiple cameras, that's abstracted away at a higher level.
107   Device dev("camera", "1");    // name and ID
108   devices->push_back(dev);
109 #else
110   return false;
111 #endif
112 }
113 
GetVideoCaptureDevice(const std::string & name,Device * out)114 bool DeviceManager::GetVideoCaptureDevice(const std::string& name,
115                                           Device* out) {
116   // If the name is empty, return the default device.
117   if (name.empty() || name == kDefaultDeviceName) {
118     LOG(LS_INFO) << "Creating default VideoCapturer";
119     return GetDefaultVideoCaptureDevice(out);
120   }
121 
122   std::vector<Device> devices;
123   if (!GetVideoCaptureDevices(&devices)) {
124     return false;
125   }
126 
127   for (std::vector<Device>::const_iterator it = devices.begin();
128       it != devices.end(); ++it) {
129     if (name == it->name) {
130       LOG(LS_INFO) << "Creating VideoCapturer for " << name;
131       *out = *it;
132       return true;
133     }
134   }
135 
136   // If the name is a valid path to a file, then we'll create a simulated device
137   // with the filename. The LmiMediaEngine will know to use a FileVideoCapturer
138   // for these devices.
139   if (talk_base::Filesystem::IsFile(name)) {
140     LOG(LS_INFO) << "Creating FileVideoCapturer";
141     *out = FileVideoCapturer::CreateFileVideoCapturerDevice(name);
142     return true;
143   }
144 
145   return false;
146 }
147 
GetAudioDevices(bool input,std::vector<Device> * devs)148 bool DeviceManager::GetAudioDevices(bool input,
149                                     std::vector<Device>* devs) {
150   devs->clear();
151 #ifdef ANDROID
152   // Under Android, we don't access the device file directly.
153   // Arbitrary use 0 for the mic and 1 for the output.
154   // These ids are used in MediaEngine::SetSoundDevices(in, out);
155   // The strings are for human consumption.
156   if (input) {
157       devs->push_back(Device("audiorecord", 0));
158   } else {
159       devs->push_back(Device("audiotrack", 1));
160   }
161   return true;
162 #else
163   return false;
164 #endif
165 }
166 
GetAudioDevice(bool is_input,const std::string & name,Device * out)167 bool DeviceManager::GetAudioDevice(bool is_input, const std::string& name,
168                                    Device* out) {
169   // If the name is empty, return the default device id.
170   if (name.empty() || name == kDefaultDeviceName) {
171     *out = Device(name, -1);
172     return true;
173   }
174 
175   std::vector<Device> devices;
176   bool ret = is_input ? GetAudioInputDevices(&devices) :
177                         GetAudioOutputDevices(&devices);
178   if (ret) {
179     ret = false;
180     for (size_t i = 0; i < devices.size(); ++i) {
181       if (devices[i].name == name) {
182         *out = devices[i];
183         ret = true;
184         break;
185       }
186     }
187   }
188   return ret;
189 }
190 
GetDefaultVideoCaptureDevice(Device * device)191 bool DeviceManager::GetDefaultVideoCaptureDevice(Device* device) {
192   bool ret = false;
193   // We just return the first device.
194   std::vector<Device> devices;
195   ret = (GetVideoCaptureDevices(&devices) && !devices.empty());
196   if (ret) {
197     *device = devices[0];
198   }
199   return ret;
200 }
201 
ShouldDeviceBeIgnored(const std::string & device_name,const char * const exclusion_list[])202 bool DeviceManager::ShouldDeviceBeIgnored(const std::string& device_name,
203     const char* const exclusion_list[]) {
204   // If exclusion_list is empty return directly.
205   if (!exclusion_list)
206     return false;
207 
208   int i = 0;
209   while (exclusion_list[i]) {
210     if (strnicmp(device_name.c_str(), exclusion_list[i],
211         strlen(exclusion_list[i])) == 0) {
212       LOG(LS_INFO) << "Ignoring device " << device_name;
213       return true;
214     }
215     ++i;
216   }
217   return false;
218 }
219 
FilterDevices(std::vector<Device> * devices,const char * const exclusion_list[])220 bool DeviceManager::FilterDevices(std::vector<Device>* devices,
221     const char* const exclusion_list[]) {
222   if (!devices) {
223     return false;
224   }
225 
226   for (std::vector<Device>::iterator it = devices->begin();
227        it != devices->end(); ) {
228     if (ShouldDeviceBeIgnored(it->name, exclusion_list)) {
229       it = devices->erase(it);
230     } else {
231       ++it;
232     }
233   }
234   return true;
235 }
236 
237 }  // namespace cricket
238