15976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org/* 25976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * libjingle 35976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Copyright 2004 Google Inc. 45976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 55976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Redistribution and use in source and binary forms, with or without 65976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * modification, are permitted provided that the following conditions are met: 75976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 85976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 1. Redistributions of source code must retain the above copyright notice, 95976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * this list of conditions and the following disclaimer. 105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 2. Redistributions in binary form must reproduce the above copyright notice, 115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * this list of conditions and the following disclaimer in the documentation 125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * and/or other materials provided with the distribution. 135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 3. The name of the author may not be used to endorse or promote products 145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * derived from this software without specific prior written permission. 155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org */ 275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/media/devices/macdevicemanager.h" 295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <CoreAudio/CoreAudio.h> 315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <QuickTime/QuickTime.h> 325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/logging.h" 345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/stringutils.h" 355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/thread.h" 365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/media/base/mediacommon.h" 375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass DeviceWatcherImpl; 395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgnamespace cricket { 415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgDeviceManagerInterface* DeviceManagerFactory::Create() { 435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return new MacDeviceManager(); 445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass MacDeviceWatcher : public DeviceWatcher { 475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public: 485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org explicit MacDeviceWatcher(DeviceManagerInterface* dm); 495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual ~MacDeviceWatcher(); 505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual bool Start(); 515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org virtual void Stop(); 525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org private: 545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org DeviceManagerInterface* manager_; 555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org DeviceWatcherImpl* impl_; 565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}; 575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const char* kFilteredAudioDevicesName[] = { 595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org NULL, 605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}; 615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// TODO(tommyw): Try to get hold of a copy of Final Cut to understand why we 625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// crash while scanning their components on OS X. 635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const char* const kFilteredVideoDevicesName[] = { 645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org "DVCPRO HD", // Final cut 655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org "Sonix SN9C201p", // Crashes in OpenAComponent and CloseComponent 665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org NULL, 675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}; 685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int kVideoDeviceOpenAttempts = 3; 695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const UInt32 kAudioDeviceNameLength = 64; 705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Obj-C functions defined in macdevicemanagermm.mm 715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// TODO(ronghuawu): have a shared header for these function defines. 725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgextern DeviceWatcherImpl* CreateDeviceWatcherCallback( 735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org DeviceManagerInterface* dm); 745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgextern void ReleaseDeviceWatcherCallback(DeviceWatcherImpl* impl); 755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgextern bool GetQTKitVideoDevices(std::vector<Device>* out); 765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool GetAudioDeviceIDs(bool inputs, std::vector<AudioDeviceID>* out); 775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool GetAudioDeviceName(AudioDeviceID id, bool input, std::string* out); 785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgMacDeviceManager::MacDeviceManager() { 805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_watcher(new MacDeviceWatcher(this)); 815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgMacDeviceManager::~MacDeviceManager() { 845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool MacDeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) { 875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org devices->clear(); 885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!GetQTKitVideoDevices(devices)) { 895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return FilterDevices(devices, kFilteredVideoDevicesName); 925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool MacDeviceManager::GetAudioDevices(bool input, 955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org std::vector<Device>* devs) { 965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org devs->clear(); 975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org std::vector<AudioDeviceID> dev_ids; 985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org bool ret = GetAudioDeviceIDs(input, &dev_ids); 995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!ret) { 1005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 1015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org for (size_t i = 0; i < dev_ids.size(); ++i) { 1035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org std::string name; 1045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (GetAudioDeviceName(dev_ids[i], input, &name)) { 1055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org devs->push_back(Device(name, dev_ids[i])); 1065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return FilterDevices(devs, kFilteredAudioDevicesName); 1095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool GetAudioDeviceIDs(bool input, 1125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org std::vector<AudioDeviceID>* out_dev_ids) { 1135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org UInt32 propsize; 1145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org OSErr err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, 1155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org &propsize, NULL); 1165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (0 != err) { 1175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG(LS_ERROR) << "Couldn't get information about property, " 1185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "so no device list acquired."; 1195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 1205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org size_t num_devices = propsize / sizeof(AudioDeviceID); 123582fe818e571fa2571267f5e369715188472f352wu@webrtc.org talk_base::scoped_ptr<AudioDeviceID[]> device_ids( 1245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org new AudioDeviceID[num_devices]); 1255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, 1275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org &propsize, device_ids.get()); 1285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (0 != err) { 1295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG(LS_ERROR) << "Failed to get device ids, " 1305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "so no device listing acquired."; 1315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 1325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org for (size_t i = 0; i < num_devices; ++i) { 1355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org AudioDeviceID an_id = device_ids[i]; 1365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // find out the number of channels for this direction 1375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // (input/output) on this device - 1385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // we'll ignore anything with no channels. 1395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org err = AudioDeviceGetPropertyInfo(an_id, 0, input, 1405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org kAudioDevicePropertyStreams, 1415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org &propsize, NULL); 1425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (0 == err) { 1435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org unsigned num_channels = propsize / sizeof(AudioStreamID); 1445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (0 < num_channels) { 1455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org out_dev_ids->push_back(an_id); 1465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 1485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG(LS_ERROR) << "No property info for stream property for device id " 1495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << an_id << "(is_input == " << input 1505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "), so not including it in the list."; 1515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 1555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool GetAudioDeviceName(AudioDeviceID id, 1585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org bool input, 1595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org std::string* out_name) { 1605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org UInt32 nameLength = kAudioDeviceNameLength; 1615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org char name[kAudioDeviceNameLength + 1]; 1625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org OSErr err = AudioDeviceGetProperty(id, 0, input, 1635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org kAudioDevicePropertyDeviceName, 1645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org &nameLength, name); 1655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (0 != err) { 1665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG(LS_ERROR) << "No name acquired for device id " << id; 1675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 1685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *out_name = name; 1715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 1725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgMacDeviceWatcher::MacDeviceWatcher(DeviceManagerInterface* manager) 1755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org : DeviceWatcher(manager), 1765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org manager_(manager), 1775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org impl_(NULL) { 1785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgMacDeviceWatcher::~MacDeviceWatcher() { 1815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool MacDeviceWatcher::Start() { 1845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!impl_) { 1855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org impl_ = CreateDeviceWatcherCallback(manager_); 1865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return impl_ != NULL; 1885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid MacDeviceWatcher::Stop() { 1915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (impl_) { 1925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ReleaseDeviceWatcherCallback(impl_); 1935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org impl_ = NULL; 1945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}; // namespace cricket 198