Home | History | Annotate | Download | only in devices
      1 /*
      2  * libjingle
      3  * Copyright 2012 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/deviceinfo.h"
     29 
     30 #include "talk/media/devices/libudevsymboltable.h"
     31 #include "webrtc/base/common.h"  // for ASSERT
     32 
     33 namespace cricket {
     34 
     35 class ScopedLibUdev {
     36  public:
     37   static ScopedLibUdev* Create() {
     38     ScopedLibUdev* ret_val = new ScopedLibUdev();
     39     if (!ret_val->Init()) {
     40       delete ret_val;
     41       return NULL;
     42     }
     43     return ret_val;
     44   }
     45   ~ScopedLibUdev() {
     46     libudev_.Unload();
     47   }
     48 
     49   LibUDevSymbolTable* instance() { return &libudev_; }
     50 
     51  private:
     52   ScopedLibUdev() {}
     53 
     54   bool Init() {
     55     return libudev_.Load() &&
     56            !IsWrongLibUDevAbiVersion(libudev_.GetDllHandle());
     57   }
     58 
     59   LibUDevSymbolTable libudev_;
     60 };
     61 
     62 class ScopedUdev {
     63  public:
     64   explicit ScopedUdev(LibUDevSymbolTable* libudev) : libudev_(libudev) {
     65     udev_ = libudev_->udev_new()();
     66   }
     67   ~ScopedUdev() {
     68     if (udev_) libudev_->udev_unref()(udev_);
     69   }
     70 
     71   udev* instance() { return udev_; }
     72 
     73  private:
     74   LibUDevSymbolTable* libudev_;
     75   udev* udev_;
     76 };
     77 
     78 class ScopedUdevEnumerate {
     79  public:
     80   ScopedUdevEnumerate(LibUDevSymbolTable* libudev, udev* udev)
     81       : libudev_(libudev) {
     82     enumerate_ = libudev_->udev_enumerate_new()(udev);
     83   }
     84   ~ScopedUdevEnumerate() {
     85     if (enumerate_) libudev_->udev_enumerate_unref()(enumerate_);
     86   }
     87 
     88   udev_enumerate* instance() { return enumerate_; }
     89 
     90  private:
     91   LibUDevSymbolTable* libudev_;
     92   udev_enumerate* enumerate_;
     93 };
     94 
     95 bool GetUsbProperty(const Device& device, const char* property_name,
     96                     std::string* property) {
     97   rtc::scoped_ptr<ScopedLibUdev> libudev_context(ScopedLibUdev::Create());
     98   if (!libudev_context) {
     99     return false;
    100   }
    101   ScopedUdev udev_context(libudev_context->instance());
    102   if (!udev_context.instance()) {
    103     return false;
    104   }
    105   ScopedUdevEnumerate enumerate_context(libudev_context->instance(),
    106                                         udev_context.instance());
    107   if (!enumerate_context.instance()) {
    108     return false;
    109   }
    110   libudev_context->instance()->udev_enumerate_add_match_subsystem()(
    111       enumerate_context.instance(), "video4linux");
    112   libudev_context->instance()->udev_enumerate_scan_devices()(
    113       enumerate_context.instance());
    114   udev_list_entry* devices =
    115       libudev_context->instance()->udev_enumerate_get_list_entry()(
    116           enumerate_context.instance());
    117   if (!devices) {
    118     return false;
    119   }
    120   udev_list_entry* dev_list_entry = NULL;
    121   const char* property_value = NULL;
    122   // Macro that expands to a for-loop over the devices.
    123   for (dev_list_entry = devices; dev_list_entry != NULL;
    124        dev_list_entry = libudev_context->instance()->
    125            udev_list_entry_get_next()(dev_list_entry)) {
    126     const char* path = libudev_context->instance()->udev_list_entry_get_name()(
    127         dev_list_entry);
    128     if (!path) continue;
    129     udev_device* dev =
    130         libudev_context->instance()->udev_device_new_from_syspath()(
    131             udev_context.instance(), path);
    132     if (!dev) continue;
    133     const char* device_node =
    134         libudev_context->instance()->udev_device_get_devnode()(dev);
    135     if (!device_node || device.id.compare(device_node) != 0) {
    136       continue;
    137     }
    138     dev = libudev_context->instance()->
    139         udev_device_get_parent_with_subsystem_devtype()(
    140             dev, "usb", "usb_device");
    141     if (!dev) continue;
    142     property_value = libudev_context->instance()->
    143         udev_device_get_sysattr_value()(
    144             dev, property_name);
    145     break;
    146   }
    147   if (!property_value) {
    148     return false;
    149   }
    150   property->assign(property_value);
    151   return true;
    152 }
    153 
    154 bool GetUsbId(const Device& device, std::string* usb_id) {
    155   std::string id_vendor;
    156   std::string id_product;
    157   if (!GetUsbProperty(device, "idVendor", &id_vendor)) {
    158     return false;
    159   }
    160   if (!GetUsbProperty(device, "idProduct", &id_product)) {
    161     return false;
    162   }
    163   usb_id->clear();
    164   usb_id->append(id_vendor);
    165   usb_id->append(":");
    166   usb_id->append(id_product);
    167   return true;
    168 }
    169 
    170 bool GetUsbVersion(const Device& device, std::string* usb_version) {
    171   return GetUsbProperty(device, "version", usb_version);
    172 }
    173 
    174 }  // namespace cricket
    175