OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <CoreAudio/AudioHardware.h> | 5 #include <CoreAudio/AudioHardware.h> |
6 | 6 |
7 #include "base/mac/mac_util.h" | 7 #include "base/mac/mac_util.h" |
| 8 #include "base/sys_string_conversions.h" |
8 #include "media/audio/fake_audio_input_stream.h" | 9 #include "media/audio/fake_audio_input_stream.h" |
9 #include "media/audio/fake_audio_output_stream.h" | 10 #include "media/audio/fake_audio_output_stream.h" |
10 #include "media/audio/mac/audio_input_mac.h" | 11 #include "media/audio/mac/audio_input_mac.h" |
11 #include "media/audio/mac/audio_low_latency_input_mac.h" | 12 #include "media/audio/mac/audio_low_latency_input_mac.h" |
12 #include "media/audio/mac/audio_low_latency_output_mac.h" | 13 #include "media/audio/mac/audio_low_latency_output_mac.h" |
13 #include "media/audio/mac/audio_manager_mac.h" | 14 #include "media/audio/mac/audio_manager_mac.h" |
14 #include "media/audio/mac/audio_output_mac.h" | 15 #include "media/audio/mac/audio_output_mac.h" |
15 #include "media/base/limits.h" | 16 #include "media/base/limits.h" |
16 | 17 |
17 static const int kMaxInputChannels = 2; | 18 static const int kMaxInputChannels = 2; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, | 59 OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, |
59 &property_address, | 60 &property_address, |
60 0, // inQualifierDataSize | 61 0, // inQualifierDataSize |
61 NULL, // inQualifierData | 62 NULL, // inQualifierData |
62 &output_device_id_size, | 63 &output_device_id_size, |
63 &output_device_id); | 64 &output_device_id); |
64 return err == kAudioHardwareNoError && | 65 return err == kAudioHardwareNoError && |
65 output_device_id != kAudioObjectUnknown; | 66 output_device_id != kAudioObjectUnknown; |
66 } | 67 } |
67 | 68 |
| 69 static void GetAudioDeviceInfo(bool is_input, |
| 70 media::AudioDeviceNames* device_names) { |
| 71 DCHECK(device_names); |
| 72 device_names->clear(); |
| 73 |
| 74 // Query the number of total devices. |
| 75 AudioObjectPropertyAddress property_address = { |
| 76 kAudioHardwarePropertyDevices, |
| 77 kAudioObjectPropertyScopeGlobal, |
| 78 kAudioObjectPropertyElementMaster |
| 79 }; |
| 80 UInt32 size = 0; |
| 81 OSStatus result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, |
| 82 &property_address, |
| 83 0, |
| 84 NULL, |
| 85 &size); |
| 86 if (result || !size) |
| 87 return; |
| 88 |
| 89 int device_count = size / sizeof(AudioDeviceID); |
| 90 |
| 91 // Get the array of device ids for all the devices, which includes both |
| 92 // input devices and output devices. |
| 93 scoped_ptr_malloc<AudioDeviceID> |
| 94 devices(reinterpret_cast<AudioDeviceID*>(malloc(size))); |
| 95 AudioDeviceID* device_ids = devices.get(); |
| 96 result = AudioObjectGetPropertyData(kAudioObjectSystemObject, |
| 97 &property_address, |
| 98 0, |
| 99 NULL, |
| 100 &size, |
| 101 device_ids); |
| 102 if (result) |
| 103 return; |
| 104 |
| 105 // Iterate over all available devices to gather information. |
| 106 for (int i = 0; i < device_count; ++i) { |
| 107 int channels = 0; |
| 108 // Get the number of input or output channels of the device. |
| 109 property_address.mScope = is_input ? |
| 110 kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; |
| 111 property_address.mSelector = kAudioDevicePropertyStreamConfiguration; |
| 112 result = AudioObjectGetPropertyDataSize(device_ids[i], |
| 113 &property_address, |
| 114 0, |
| 115 NULL, |
| 116 &size); |
| 117 if (result) |
| 118 continue; |
| 119 |
| 120 scoped_ptr_malloc<AudioBufferList> |
| 121 buffer(reinterpret_cast<AudioBufferList*>(malloc(size))); |
| 122 AudioBufferList* buffer_list = buffer.get(); |
| 123 result = AudioObjectGetPropertyData(device_ids[i], |
| 124 &property_address, |
| 125 0, |
| 126 NULL, |
| 127 &size, |
| 128 buffer_list); |
| 129 if (result) |
| 130 continue; |
| 131 |
| 132 for (uint32 j = 0; j < buffer_list->mNumberBuffers; ++j) |
| 133 channels += buffer_list->mBuffers[j].mNumberChannels; |
| 134 |
| 135 // Exclude those devices without the type of channel we are interested in. |
| 136 if (!channels) |
| 137 continue; |
| 138 |
| 139 // Get device UID. |
| 140 CFStringRef uid = NULL; |
| 141 size = sizeof(uid); |
| 142 property_address.mSelector = kAudioDevicePropertyDeviceUID; |
| 143 property_address.mScope = kAudioObjectPropertyScopeGlobal; |
| 144 result = AudioObjectGetPropertyData(device_ids[i], |
| 145 &property_address, |
| 146 0, |
| 147 NULL, |
| 148 &size, |
| 149 &uid); |
| 150 if (result) |
| 151 continue; |
| 152 |
| 153 // Get device name. |
| 154 CFStringRef name = NULL; |
| 155 property_address.mSelector = kAudioObjectPropertyName; |
| 156 property_address.mScope = kAudioObjectPropertyScopeGlobal; |
| 157 result = AudioObjectGetPropertyData(device_ids[i], |
| 158 &property_address, |
| 159 0, |
| 160 NULL, |
| 161 &size, |
| 162 &name); |
| 163 if (result) { |
| 164 if (uid) |
| 165 CFRelease(uid); |
| 166 continue; |
| 167 } |
| 168 |
| 169 // Store the device name and UID. |
| 170 media::AudioDeviceName device_name; |
| 171 device_name.device_name = base::SysCFStringRefToUTF8(name); |
| 172 device_name.unique_id = base::SysCFStringRefToUTF8(uid); |
| 173 device_names->push_back(device_name); |
| 174 |
| 175 // We are responsible for releasing the returned CFObject. See the |
| 176 // comment in the AudioHardware.h for constant |
| 177 // kAudioDevicePropertyDeviceUID. |
| 178 if (uid) |
| 179 CFRelease(uid); |
| 180 if (name) |
| 181 CFRelease(name); |
| 182 } |
| 183 } |
| 184 |
68 AudioManagerMac::AudioManagerMac() | 185 AudioManagerMac::AudioManagerMac() |
69 : num_output_streams_(0) { | 186 : num_output_streams_(0) { |
70 } | 187 } |
71 | 188 |
72 AudioManagerMac::~AudioManagerMac() { | 189 AudioManagerMac::~AudioManagerMac() { |
73 } | 190 } |
74 | 191 |
75 bool AudioManagerMac::HasAudioOutputDevices() { | 192 bool AudioManagerMac::HasAudioOutputDevices() { |
76 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); | 193 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); |
77 } | 194 } |
78 | 195 |
79 bool AudioManagerMac::HasAudioInputDevices() { | 196 bool AudioManagerMac::HasAudioInputDevices() { |
80 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); | 197 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); |
81 } | 198 } |
82 | 199 |
83 void AudioManagerMac::GetAudioInputDeviceNames( | 200 void AudioManagerMac::GetAudioInputDeviceNames( |
84 media::AudioDeviceNames* device_names) { | 201 media::AudioDeviceNames* device_names) { |
85 // TODO(xians): query a full list of valid devices. | 202 // This is needed because AudioObjectGetPropertyDataSize has memory leak |
86 if (HasAudioInputDevices()) { | 203 // when there is no soundcard in the machine. |
87 // Add the default device to the list. | 204 if (!HasAudioInputDevices()) |
88 // We use index 0 to make up the unique_id to identify the | 205 return; |
89 // default devices. | 206 |
| 207 GetAudioDeviceInfo(true, device_names); |
| 208 if (!device_names->empty()) { |
| 209 // Prepend the default device to the list since we always want it to be |
| 210 // on the top of the list for all platforms. There is no duplicate |
| 211 // counting here since the default device has been abstracted out before. |
90 media::AudioDeviceName name; | 212 media::AudioDeviceName name; |
91 name.device_name = AudioManagerBase::kDefaultDeviceName; | 213 name.device_name = AudioManagerBase::kDefaultDeviceName; |
92 name.unique_id = "0"; | 214 name.unique_id = "0"; |
93 device_names->push_back(name); | 215 device_names->push_front(name); |
94 } | 216 } |
95 } | 217 } |
96 | 218 |
97 AudioOutputStream* AudioManagerMac::MakeAudioOutputStream( | 219 AudioOutputStream* AudioManagerMac::MakeAudioOutputStream( |
98 const AudioParameters& params) { | 220 const AudioParameters& params) { |
99 if (!params.IsValid()) | 221 if (!params.IsValid()) |
100 return NULL; | 222 return NULL; |
101 | 223 |
102 // Limit the number of audio streams opened. This is to prevent using | 224 // Limit the number of audio streams opened. This is to prevent using |
103 // excessive resources for a large number of audio streams. More | 225 // excessive resources for a large number of audio streams. More |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 | 273 |
152 // Called by the stream when it has been released by calling Close(). | 274 // Called by the stream when it has been released by calling Close(). |
153 void AudioManagerMac::ReleaseInputStream(AudioInputStream* stream) { | 275 void AudioManagerMac::ReleaseInputStream(AudioInputStream* stream) { |
154 delete stream; | 276 delete stream; |
155 } | 277 } |
156 | 278 |
157 // static | 279 // static |
158 AudioManager* AudioManager::CreateAudioManager() { | 280 AudioManager* AudioManager::CreateAudioManager() { |
159 return new AudioManagerMac(); | 281 return new AudioManagerMac(); |
160 } | 282 } |
OLD | NEW |