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/macdevicemanager.h"
     29 
     30 #include <CoreAudio/CoreAudio.h>
     31 #include <QuickTime/QuickTime.h>
     32 
     33 #include "talk/media/base/mediacommon.h"
     34 #include "webrtc/base/logging.h"
     35 #include "webrtc/base/stringutils.h"
     36 #include "webrtc/base/thread.h"
     37 
     38 class DeviceWatcherImpl;
     39 
     40 namespace cricket {
     41 
     42 DeviceManagerInterface* DeviceManagerFactory::Create() {
     43   return new MacDeviceManager();
     44 }
     45 
     46 class MacDeviceWatcher : public DeviceWatcher {
     47  public:
     48   explicit MacDeviceWatcher(DeviceManagerInterface* dm);
     49   virtual ~MacDeviceWatcher();
     50   virtual bool Start();
     51   virtual void Stop();
     52 
     53  private:
     54   DeviceManagerInterface* manager_;
     55   DeviceWatcherImpl* impl_;
     56 };
     57 
     58 static const char* kFilteredAudioDevicesName[] = {
     59     NULL,
     60 };
     61 // TODO(tommyw): Try to get hold of a copy of Final Cut to understand why we
     62 //               crash while scanning their components on OS X.
     63 static const char* const kFilteredVideoDevicesName[] =  {
     64     "DVCPRO HD",               // Final cut
     65     "Sonix SN9C201p",          // Crashes in OpenAComponent and CloseComponent
     66     NULL,
     67 };
     68 static const UInt32 kAudioDeviceNameLength = 64;
     69 // Obj-C functions defined in macdevicemanagermm.mm
     70 // TODO(ronghuawu): have a shared header for these function defines.
     71 extern DeviceWatcherImpl* CreateDeviceWatcherCallback(
     72     DeviceManagerInterface* dm);
     73 extern void ReleaseDeviceWatcherCallback(DeviceWatcherImpl* impl);
     74 extern bool GetAVFoundationVideoDevices(std::vector<Device>* out);
     75 static bool GetAudioDeviceIDs(bool inputs, std::vector<AudioDeviceID>* out);
     76 static bool GetAudioDeviceName(AudioDeviceID id, bool input, std::string* out);
     77 
     78 MacDeviceManager::MacDeviceManager() {
     79   set_watcher(new MacDeviceWatcher(this));
     80 }
     81 
     82 MacDeviceManager::~MacDeviceManager() {
     83 }
     84 
     85 bool MacDeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) {
     86   devices->clear();
     87   if (!GetAVFoundationVideoDevices(devices)) {
     88     return false;
     89   }
     90   return FilterDevices(devices, kFilteredVideoDevicesName);
     91 }
     92 
     93 bool MacDeviceManager::GetAudioDevices(bool input,
     94                                        std::vector<Device>* devs) {
     95   devs->clear();
     96   std::vector<AudioDeviceID> dev_ids;
     97   bool ret = GetAudioDeviceIDs(input, &dev_ids);
     98   if (!ret) {
     99     return false;
    100   }
    101   for (size_t i = 0; i < dev_ids.size(); ++i) {
    102     std::string name;
    103     if (GetAudioDeviceName(dev_ids[i], input, &name)) {
    104       devs->push_back(Device(name, dev_ids[i]));
    105     }
    106   }
    107   return FilterDevices(devs, kFilteredAudioDevicesName);
    108 }
    109 
    110 static bool GetAudioDeviceIDs(bool input,
    111                               std::vector<AudioDeviceID>* out_dev_ids) {
    112   UInt32 propsize;
    113   OSErr err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
    114                                            &propsize, NULL);
    115   if (0 != err) {
    116     LOG(LS_ERROR) << "Couldn't get information about property, "
    117                   << "so no device list acquired.";
    118     return false;
    119   }
    120 
    121   size_t num_devices = propsize / sizeof(AudioDeviceID);
    122   rtc::scoped_ptr<AudioDeviceID[]> device_ids(
    123       new AudioDeviceID[num_devices]);
    124 
    125   err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
    126                                  &propsize, device_ids.get());
    127   if (0 != err) {
    128     LOG(LS_ERROR) << "Failed to get device ids, "
    129                   << "so no device listing acquired.";
    130     return false;
    131   }
    132 
    133   for (size_t i = 0; i < num_devices; ++i) {
    134     AudioDeviceID an_id = device_ids[i];
    135     // find out the number of channels for this direction
    136     // (input/output) on this device -
    137     // we'll ignore anything with no channels.
    138     err = AudioDeviceGetPropertyInfo(an_id, 0, input,
    139                                      kAudioDevicePropertyStreams,
    140                                      &propsize, NULL);
    141     if (0 == err) {
    142       unsigned num_channels = propsize / sizeof(AudioStreamID);
    143       if (0 < num_channels) {
    144         out_dev_ids->push_back(an_id);
    145       }
    146     } else {
    147       LOG(LS_ERROR) << "No property info for stream property for device id "
    148                     << an_id << "(is_input == " << input
    149                     << "), so not including it in the list.";
    150     }
    151   }
    152 
    153   return true;
    154 }
    155 
    156 static bool GetAudioDeviceName(AudioDeviceID id,
    157                                bool input,
    158                                std::string* out_name) {
    159   UInt32 nameLength = kAudioDeviceNameLength;
    160   char name[kAudioDeviceNameLength + 1];
    161   OSErr err = AudioDeviceGetProperty(id, 0, input,
    162                                      kAudioDevicePropertyDeviceName,
    163                                      &nameLength, name);
    164   if (0 != err) {
    165     LOG(LS_ERROR) << "No name acquired for device id " << id;
    166     return false;
    167   }
    168 
    169   *out_name = name;
    170   return true;
    171 }
    172 
    173 MacDeviceWatcher::MacDeviceWatcher(DeviceManagerInterface* manager)
    174     : DeviceWatcher(manager),
    175       manager_(manager),
    176       impl_(NULL) {
    177 }
    178 
    179 MacDeviceWatcher::~MacDeviceWatcher() {
    180 }
    181 
    182 bool MacDeviceWatcher::Start() {
    183   if (!impl_) {
    184     impl_ = CreateDeviceWatcherCallback(manager_);
    185   }
    186   return impl_ != NULL;
    187 }
    188 
    189 void MacDeviceWatcher::Stop() {
    190   if (impl_) {
    191     ReleaseDeviceWatcherCallback(impl_);
    192     impl_ = NULL;
    193   }
    194 }
    195 
    196 };  // namespace cricket
    197