Home | History | Annotate | Download | only in devices
      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(IOS)
    153   // On iOS, we treat the camera(s) as a single device. Even if there are
    154   // 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(IOS) || defined(ANDROID)
    282   // Under Android, we don't access the device file directly.
    283   // Arbitrary use 0 for the mic and 1 for the output.
    284   // These ids are used in MediaEngine::SetSoundDevices(in, out);
    285   // The strings are for human consumption.
    286   if (input) {
    287       devs->push_back(Device("audiorecord", 0));
    288   } else {
    289       devs->push_back(Device("audiotrack", 1));
    290   }
    291   return true;
    292 #else
    293   return false;
    294 #endif
    295 }
    296 
    297 bool DeviceManager::GetAudioDevice(bool is_input, const std::string& name,
    298                                    Device* out) {
    299   // If the name is empty, return the default device id.
    300   if (name.empty() || name == kDefaultDeviceName) {
    301     *out = Device(name, -1);
    302     return true;
    303   }
    304 
    305   std::vector<Device> devices;
    306   bool ret = is_input ? GetAudioInputDevices(&devices) :
    307                         GetAudioOutputDevices(&devices);
    308   if (ret) {
    309     ret = false;
    310     for (size_t i = 0; i < devices.size(); ++i) {
    311       if (devices[i].name == name) {
    312         *out = devices[i];
    313         ret = true;
    314         break;
    315       }
    316     }
    317   }
    318   return ret;
    319 }
    320 
    321 bool DeviceManager::GetDefaultVideoCaptureDevice(Device* device) {
    322   bool ret = false;
    323   // We just return the first device.
    324   std::vector<Device> devices;
    325   ret = (GetVideoCaptureDevices(&devices) && !devices.empty());
    326   if (ret) {
    327     *device = devices[0];
    328   }
    329   return ret;
    330 }
    331 
    332 bool DeviceManager::IsInWhitelist(const std::string& key,
    333                                   VideoFormat* video_format) const {
    334   std::map<std::string, VideoFormat>::const_iterator found =
    335       std::search_n(max_formats_.begin(), max_formats_.end(), 1, key,
    336                     StringMatchWithWildcard);
    337   if (found == max_formats_.end()) {
    338     return false;
    339   }
    340   *video_format = found->second;
    341   return true;
    342 }
    343 
    344 bool DeviceManager::GetMaxFormat(const Device& device,
    345                                  VideoFormat* video_format) const {
    346   // Match USB ID if available. Failing that, match device name.
    347   std::string usb_id;
    348   if (GetUsbId(device, &usb_id) && IsInWhitelist(usb_id, video_format)) {
    349       return true;
    350   }
    351   return IsInWhitelist(device.name, video_format);
    352 }
    353 
    354 bool DeviceManager::ShouldDeviceBeIgnored(const std::string& device_name,
    355     const char* const exclusion_list[]) {
    356   // If exclusion_list is empty return directly.
    357   if (!exclusion_list)
    358     return false;
    359 
    360   int i = 0;
    361   while (exclusion_list[i]) {
    362     if (strnicmp(device_name.c_str(), exclusion_list[i],
    363         strlen(exclusion_list[i])) == 0) {
    364       LOG(LS_INFO) << "Ignoring device " << device_name;
    365       return true;
    366     }
    367     ++i;
    368   }
    369   return false;
    370 }
    371 
    372 bool DeviceManager::FilterDevices(std::vector<Device>* devices,
    373     const char* const exclusion_list[]) {
    374   if (!devices) {
    375     return false;
    376   }
    377 
    378   for (std::vector<Device>::iterator it = devices->begin();
    379        it != devices->end(); ) {
    380     if (ShouldDeviceBeIgnored(it->name, exclusion_list)) {
    381       it = devices->erase(it);
    382     } else {
    383       ++it;
    384     }
    385   }
    386   return true;
    387 }
    388 
    389 }  // namespace cricket
    390