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