Index: media/audio/mac/audio_manager_mac.cc |
diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc |
index a4a621725a1371da8f75753e74d876cef8025c39..152375b095641f57fb8abb949de418bd23fe0ba9 100644 |
--- a/media/audio/mac/audio_manager_mac.cc |
+++ b/media/audio/mac/audio_manager_mac.cc |
@@ -5,6 +5,7 @@ |
#include <CoreAudio/AudioHardware.h> |
#include "base/mac/mac_util.h" |
+#include "base/sys_string_conversions.h" |
#include "media/audio/fake_audio_input_stream.h" |
#include "media/audio/fake_audio_output_stream.h" |
#include "media/audio/mac/audio_input_mac.h" |
@@ -65,6 +66,122 @@ static bool HasAudioHardware(AudioObjectPropertySelector selector) { |
output_device_id != kAudioObjectUnknown; |
} |
+static void GetAudioDeviceInfo(bool is_input, |
+ media::AudioDeviceNames* device_names) { |
+ DCHECK(device_names); |
+ device_names->clear(); |
+ |
+ // Query the number of total devices. |
+ AudioObjectPropertyAddress property_address = { |
+ kAudioHardwarePropertyDevices, |
+ kAudioObjectPropertyScopeGlobal, |
+ kAudioObjectPropertyElementMaster |
+ }; |
+ UInt32 size = 0; |
+ OSStatus result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, |
+ &property_address, |
+ 0, |
+ NULL, |
+ &size); |
+ if (result || !size) |
+ return; |
+ |
+ int device_count = size / sizeof(AudioDeviceID); |
+ |
+ // Get the array of device ids for all the devices, which includes both |
+ // input devices and output devices. |
+ scoped_ptr_malloc<AudioDeviceID> |
+ devices(reinterpret_cast<AudioDeviceID*>(malloc(size))); |
+ AudioDeviceID* device_ids = devices.get(); |
+ result = AudioObjectGetPropertyData(kAudioObjectSystemObject, |
+ &property_address, |
+ 0, |
+ NULL, |
+ &size, |
+ device_ids); |
+ if (result) |
+ return; |
+ |
+ // Iterate over all available devices to gather information. |
+ for (int i = 0; i < device_count; ++i) { |
+ int channels = 0; |
+ // Get the number of input or output channels of the device. |
+ property_address.mScope = is_input ? |
+ kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; |
+ property_address.mSelector = kAudioDevicePropertyStreamConfiguration; |
+ result = AudioObjectGetPropertyDataSize(device_ids[i], |
+ &property_address, |
+ 0, |
+ NULL, |
+ &size); |
+ if (result) |
+ continue; |
+ |
+ scoped_ptr_malloc<AudioBufferList> |
+ buffer(reinterpret_cast<AudioBufferList*>(malloc(size))); |
+ AudioBufferList* buffer_list = buffer.get(); |
+ result = AudioObjectGetPropertyData(device_ids[i], |
+ &property_address, |
+ 0, |
+ NULL, |
+ &size, |
+ buffer_list); |
+ if (result) |
+ continue; |
+ |
+ for (uint32 j = 0; j < buffer_list->mNumberBuffers; ++j) |
+ channels += buffer_list->mBuffers[j].mNumberChannels; |
+ |
+ // Exclude those devices without the type of channel we are interested in. |
+ if (!channels) |
+ continue; |
+ |
+ // Get device UID. |
+ CFStringRef uid = NULL; |
+ size = sizeof(uid); |
+ property_address.mSelector = kAudioDevicePropertyDeviceUID; |
+ property_address.mScope = kAudioObjectPropertyScopeGlobal; |
+ result = AudioObjectGetPropertyData(device_ids[i], |
+ &property_address, |
+ 0, |
+ NULL, |
+ &size, |
+ &uid); |
+ if (result) |
+ continue; |
+ |
+ // Get device name. |
+ CFStringRef name = NULL; |
+ property_address.mSelector = kAudioObjectPropertyName; |
+ property_address.mScope = kAudioObjectPropertyScopeGlobal; |
+ result = AudioObjectGetPropertyData(device_ids[i], |
+ &property_address, |
+ 0, |
+ NULL, |
+ &size, |
+ &name); |
+ if (result) { |
+ if (uid) |
+ CFRelease(uid); |
+ continue; |
+ } |
+ |
+ // Store the device name and UID. |
+ media::AudioDeviceName device_name; |
+ device_name.device_name = base::SysCFStringRefToUTF8(name); |
+ device_name.unique_id = base::SysCFStringRefToUTF8(uid); |
+ device_names->push_back(device_name); |
+ |
+ // We are responsible for releasing the returned CFObject. See the |
+ // comment in the AudioHardware.h for constant |
+ // kAudioDevicePropertyDeviceUID. |
+ if (uid) |
+ CFRelease(uid); |
+ if (name) |
+ CFRelease(name); |
+ } |
+} |
+ |
AudioManagerMac::AudioManagerMac() |
: num_output_streams_(0) { |
} |
@@ -82,15 +199,20 @@ bool AudioManagerMac::HasAudioInputDevices() { |
void AudioManagerMac::GetAudioInputDeviceNames( |
media::AudioDeviceNames* device_names) { |
- // TODO(xians): query a full list of valid devices. |
- if (HasAudioInputDevices()) { |
- // Add the default device to the list. |
- // We use index 0 to make up the unique_id to identify the |
- // default devices. |
+ // This is needed because AudioObjectGetPropertyDataSize has memory leak |
+ // when there is no soundcard in the machine. |
+ if (!HasAudioInputDevices()) |
+ return; |
+ |
+ GetAudioDeviceInfo(true, device_names); |
+ if (!device_names->empty()) { |
+ // Prepend the default device to the list since we always want it to be |
+ // on the top of the list for all platforms. There is no duplicate |
+ // counting here since the default device has been abstracted out before. |
media::AudioDeviceName name; |
name.device_name = AudioManagerBase::kDefaultDeviceName; |
name.unique_id = "0"; |
- device_names->push_back(name); |
+ device_names->push_front(name); |
} |
} |