3 * Copyright 2004 Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
28 #include "talk/media/devices/macdevicemanager.h"
30 #include <CoreAudio/CoreAudio.h>
31 #include <QuickTime/QuickTime.h>
33 #include "talk/base/logging.h"
34 #include "talk/base/stringutils.h"
35 #include "talk/base/thread.h"
36 #include "talk/media/base/mediacommon.h"
38 class DeviceWatcherImpl;
42 DeviceManagerInterface* DeviceManagerFactory::Create() {
43 return new MacDeviceManager();
46 class MacDeviceWatcher : public DeviceWatcher {
48 explicit MacDeviceWatcher(DeviceManagerInterface* dm);
49 virtual ~MacDeviceWatcher();
54 DeviceManagerInterface* manager_;
55 DeviceWatcherImpl* impl_;
58 static const char* kFilteredAudioDevicesName[] = {
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
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 GetQTKitVideoDevices(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);
78 MacDeviceManager::MacDeviceManager() {
79 set_watcher(new MacDeviceWatcher(this));
82 MacDeviceManager::~MacDeviceManager() {
85 bool MacDeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) {
87 if (!GetQTKitVideoDevices(devices)) {
90 return FilterDevices(devices, kFilteredVideoDevicesName);
93 bool MacDeviceManager::GetAudioDevices(bool input,
94 std::vector<Device>* devs) {
96 std::vector<AudioDeviceID> dev_ids;
97 bool ret = GetAudioDeviceIDs(input, &dev_ids);
101 for (size_t i = 0; i < dev_ids.size(); ++i) {
103 if (GetAudioDeviceName(dev_ids[i], input, &name)) {
104 devs->push_back(Device(name, dev_ids[i]));
107 return FilterDevices(devs, kFilteredAudioDevicesName);
110 static bool GetAudioDeviceIDs(bool input,
111 std::vector<AudioDeviceID>* out_dev_ids) {
113 OSErr err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
116 LOG(LS_ERROR) << "Couldn't get information about property, "
117 << "so no device list acquired.";
121 size_t num_devices = propsize / sizeof(AudioDeviceID);
122 talk_base::scoped_ptr<AudioDeviceID[]> device_ids(
123 new AudioDeviceID[num_devices]);
125 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
126 &propsize, device_ids.get());
128 LOG(LS_ERROR) << "Failed to get device ids, "
129 << "so no device listing acquired.";
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,
142 unsigned num_channels = propsize / sizeof(AudioStreamID);
143 if (0 < num_channels) {
144 out_dev_ids->push_back(an_id);
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.";
156 static bool GetAudioDeviceName(AudioDeviceID id,
158 std::string* out_name) {
159 UInt32 nameLength = kAudioDeviceNameLength;
160 char name[kAudioDeviceNameLength + 1];
161 OSErr err = AudioDeviceGetProperty(id, 0, input,
162 kAudioDevicePropertyDeviceName,
165 LOG(LS_ERROR) << "No name acquired for device id " << id;
173 MacDeviceWatcher::MacDeviceWatcher(DeviceManagerInterface* manager)
174 : DeviceWatcher(manager),
179 MacDeviceWatcher::~MacDeviceWatcher() {
182 bool MacDeviceWatcher::Start() {
184 impl_ = CreateDeviceWatcherCallback(manager_);
186 return impl_ != NULL;
189 void MacDeviceWatcher::Stop() {
191 ReleaseDeviceWatcherCallback(impl_);
196 }; // namespace cricket