10e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/* 20e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * libjingle 30e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Copyright 2004 Google Inc. 40e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * 50e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Redistribution and use in source and binary forms, with or without 60e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * modification, are permitted provided that the following conditions are met: 70e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * 80e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * 1. Redistributions of source code must retain the above copyright notice, 90e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * this list of conditions and the following disclaimer. 100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * 2. Redistributions in binary form must reproduce the above copyright notice, 110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * this list of conditions and the following disclaimer in the documentation 120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * and/or other materials provided with the distribution. 130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * 3. The name of the author may not be used to endorse or promote products 140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * derived from this software without specific prior written permission. 150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * 160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org */ 270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/devices/macdevicemanager.h" 290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <CoreAudio/CoreAudio.h> 310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <QuickTime/QuickTime.h> 320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 33cf81adffe15fa8ea0f333432e41f6d504148f18abuildbot@webrtc.org#include "talk/media/base/mediacommon.h" 342a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "webrtc/base/logging.h" 352a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "webrtc/base/stringutils.h" 362a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "webrtc/base/thread.h" 370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgclass DeviceWatcherImpl; 390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgnamespace cricket { 410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgDeviceManagerInterface* DeviceManagerFactory::Create() { 430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return new MacDeviceManager(); 440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgclass MacDeviceWatcher : public DeviceWatcher { 470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org public: 480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org explicit MacDeviceWatcher(DeviceManagerInterface* dm); 490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org virtual ~MacDeviceWatcher(); 500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org virtual bool Start(); 510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org virtual void Stop(); 520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org private: 540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org DeviceManagerInterface* manager_; 550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org DeviceWatcherImpl* impl_; 560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}; 570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const char* kFilteredAudioDevicesName[] = { 590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org NULL, 600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}; 610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// TODO(tommyw): Try to get hold of a copy of Final Cut to understand why we 620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// crash while scanning their components on OS X. 630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const char* const kFilteredVideoDevicesName[] = { 640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org "DVCPRO HD", // Final cut 650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org "Sonix SN9C201p", // Crashes in OpenAComponent and CloseComponent 660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org NULL, 670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}; 680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const UInt32 kAudioDeviceNameLength = 64; 690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Obj-C functions defined in macdevicemanagermm.mm 700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// TODO(ronghuawu): have a shared header for these function defines. 710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgextern DeviceWatcherImpl* CreateDeviceWatcherCallback( 720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org DeviceManagerInterface* dm); 730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgextern void ReleaseDeviceWatcherCallback(DeviceWatcherImpl* impl); 74117cae3746cccf546d80c625d0b4d92de83a3291buildbot@webrtc.orgextern bool GetAVFoundationVideoDevices(std::vector<Device>* out); 750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic bool GetAudioDeviceIDs(bool inputs, std::vector<AudioDeviceID>* out); 760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic bool GetAudioDeviceName(AudioDeviceID id, bool input, std::string* out); 770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgMacDeviceManager::MacDeviceManager() { 790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org set_watcher(new MacDeviceWatcher(this)); 800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgMacDeviceManager::~MacDeviceManager() { 830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool MacDeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) { 860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org devices->clear(); 87117cae3746cccf546d80c625d0b4d92de83a3291buildbot@webrtc.org if (!GetAVFoundationVideoDevices(devices)) { 880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return FilterDevices(devices, kFilteredVideoDevicesName); 910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool MacDeviceManager::GetAudioDevices(bool input, 940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org std::vector<Device>* devs) { 950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org devs->clear(); 960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org std::vector<AudioDeviceID> dev_ids; 970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org bool ret = GetAudioDeviceIDs(input, &dev_ids); 980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (!ret) { 990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 1000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org for (size_t i = 0; i < dev_ids.size(); ++i) { 1020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org std::string name; 1030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (GetAudioDeviceName(dev_ids[i], input, &name)) { 1040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org devs->push_back(Device(name, dev_ids[i])); 1050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return FilterDevices(devs, kFilteredAudioDevicesName); 1080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 1090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic bool GetAudioDeviceIDs(bool input, 1110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org std::vector<AudioDeviceID>* out_dev_ids) { 1120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org UInt32 propsize; 1130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org OSErr err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, 1140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org &propsize, NULL); 1150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (0 != err) { 1160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "Couldn't get information about property, " 1170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org << "so no device list acquired."; 1180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 1190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org size_t num_devices = propsize / sizeof(AudioDeviceID); 1222a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org rtc::scoped_ptr<AudioDeviceID[]> device_ids( 1230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org new AudioDeviceID[num_devices]); 1240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, 1260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org &propsize, device_ids.get()); 1270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (0 != err) { 1280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "Failed to get device ids, " 1290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org << "so no device listing acquired."; 1300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 1310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org for (size_t i = 0; i < num_devices; ++i) { 1340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org AudioDeviceID an_id = device_ids[i]; 1350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // find out the number of channels for this direction 1360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // (input/output) on this device - 1370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // we'll ignore anything with no channels. 1380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org err = AudioDeviceGetPropertyInfo(an_id, 0, input, 1390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org kAudioDevicePropertyStreams, 1400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org &propsize, NULL); 1410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (0 == err) { 1420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org unsigned num_channels = propsize / sizeof(AudioStreamID); 1430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (0 < num_channels) { 1440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org out_dev_ids->push_back(an_id); 1450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } else { 1470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "No property info for stream property for device id " 1480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org << an_id << "(is_input == " << input 1490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org << "), so not including it in the list."; 1500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return true; 1540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 1550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic bool GetAudioDeviceName(AudioDeviceID id, 1570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org bool input, 1580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org std::string* out_name) { 1590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org UInt32 nameLength = kAudioDeviceNameLength; 1600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org char name[kAudioDeviceNameLength + 1]; 1610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org OSErr err = AudioDeviceGetProperty(id, 0, input, 1620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org kAudioDevicePropertyDeviceName, 1630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org &nameLength, name); 1640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (0 != err) { 1650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "No name acquired for device id " << id; 1660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 1670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *out_name = name; 1700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return true; 1710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 1720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgMacDeviceWatcher::MacDeviceWatcher(DeviceManagerInterface* manager) 1740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org : DeviceWatcher(manager), 1750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org manager_(manager), 1760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org impl_(NULL) { 1770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 1780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgMacDeviceWatcher::~MacDeviceWatcher() { 1800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 1810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool MacDeviceWatcher::Start() { 1830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (!impl_) { 1840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org impl_ = CreateDeviceWatcherCallback(manager_); 1850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return impl_ != NULL; 1870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 1880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid MacDeviceWatcher::Stop() { 1900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (impl_) { 1910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org ReleaseDeviceWatcherCallback(impl_); 1920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org impl_ = NULL; 1930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 1950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}; // namespace cricket 197