Commit 8b3f87d4 authored by Oskar Sundbom's avatar Oskar Sundbom Committed by Commit Bot

Filter private aggregate devices from macOS device enumerations

This is done specifically to filter out the aggregate devices created
when using kAudioUnitSubType_VoiceProcessingIO. Those should not be
directly user-selectable.

This CL allows other aggregate devices, but ensures they do not claim
to support native echo cancellation, since they don't. Those devices
will have to use software AEC.

Bug: 837227
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: Iebb5286cafebe40204899ee2b7f1e0ff263d1fd6
Reviewed-on: https://chromium-review.googlesource.com/1030170
Commit-Queue: Oskar Sundbom <ossu@chromium.org>
Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#555736}
parent b9111cee
...@@ -144,6 +144,11 @@ static void GetAudioDeviceInfo(bool is_input, ...@@ -144,6 +144,11 @@ static void GetAudioDeviceInfo(bool is_input,
if (!label) if (!label)
continue; continue;
// Filter out aggregate devices, e.g. those that get created by using
// kAudioUnitSubType_VoiceProcessingIO.
if (core_audio_mac::IsPrivateAggregateDevice(device_id))
continue;
device_names->emplace_back(std::move(*label), std::move(*unique_id)); device_names->emplace_back(std::move(*label), std::move(*unique_id));
} }
...@@ -639,9 +644,16 @@ AudioParameters AudioManagerMac::GetInputStreamParameters( ...@@ -639,9 +644,16 @@ AudioParameters AudioManagerMac::GetInputStreamParameters(
params.set_effects(AudioParameters::NOISE_SUPPRESSION); params.set_effects(AudioParameters::NOISE_SUPPRESSION);
} }
// VoiceProcessingIO is only supported on MacOS 10.12 and cannot be used on
// aggregate devices, since it creates an aggregate device itself. It also
// only runs in mono, but we allow upmixing to stereo since we can't claim a
// device works either in stereo without echo cancellation or mono with echo
// cancellation.
if (base::mac::IsAtLeastOS10_12() && if (base::mac::IsAtLeastOS10_12() &&
(params.channel_layout() == CHANNEL_LAYOUT_MONO || (params.channel_layout() == CHANNEL_LAYOUT_MONO ||
params.channel_layout() == CHANNEL_LAYOUT_STEREO)) { params.channel_layout() == CHANNEL_LAYOUT_STEREO) &&
core_audio_mac::GetDeviceTransportType(device) !=
kAudioDeviceTransportTypeAggregate) {
params.set_effects(params.effects() | params.set_effects(params.effects() |
AudioParameters::EXPERIMENTAL_ECHO_CANCELLER); AudioParameters::EXPERIMENTAL_ECHO_CANCELLER);
} }
......
...@@ -134,11 +134,6 @@ base::Optional<std::string> GetDeviceModel(AudioObjectID device_id) { ...@@ -134,11 +134,6 @@ base::Optional<std::string> GetDeviceModel(AudioObjectID device_id) {
return GetDeviceStringProperty(device_id, kAudioDevicePropertyModelUID); return GetDeviceStringProperty(device_id, kAudioDevicePropertyModelUID);
} }
base::Optional<uint32_t> GetDeviceTransportType(AudioObjectID device_id) {
return GetDeviceUint32Property(device_id, kAudioDevicePropertyTransportType,
kAudioObjectPropertyScopeGlobal);
}
bool ModelContainsVidPid(const std::string& model) { bool ModelContainsVidPid(const std::string& model) {
return model.size() > 10 && model[model.size() - 5] == ':' && return model.size() > 10 && model[model.size() - 5] == ':' &&
model[model.size() - 10] == ':'; model[model.size() - 10] == ':';
...@@ -273,5 +268,49 @@ base::Optional<uint32_t> GetDeviceSource(AudioObjectID device_id, ...@@ -273,5 +268,49 @@ base::Optional<uint32_t> GetDeviceSource(AudioObjectID device_id,
InputOutputScope(is_input)); InputOutputScope(is_input));
} }
base::Optional<uint32_t> GetDeviceTransportType(AudioObjectID device_id) {
return GetDeviceUint32Property(device_id, kAudioDevicePropertyTransportType,
kAudioObjectPropertyScopeGlobal);
}
bool IsPrivateAggregateDevice(AudioObjectID device_id) {
// Don't try to access aggregate device properties unless |device_id| is
// really an aggregate device.
if (GetDeviceTransportType(device_id) != kAudioDeviceTransportTypeAggregate)
return false;
const AudioObjectPropertyAddress property_address = {
kAudioAggregateDevicePropertyComposition, kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster};
CFDictionaryRef dictionary = nullptr;
UInt32 size = sizeof(dictionary);
OSStatus result = AudioObjectGetPropertyData(
device_id, &property_address, 0 /* inQualifierDataSize */,
nullptr /* inQualifierData */, &size, &dictionary);
if (result != noErr) {
OSSTATUS_LOG(WARNING, result) << "Failed to read property "
<< kAudioAggregateDevicePropertyComposition
<< " for device " << device_id;
return false;
}
DCHECK_EQ(CFGetTypeID(dictionary), CFDictionaryGetTypeID());
bool is_private = false;
CFTypeRef value = CFDictionaryGetValue(
dictionary, CFSTR(kAudioAggregateDeviceIsPrivateKey));
if (value && CFGetTypeID(value) == CFNumberGetTypeID()) {
int number = 0;
if (CFNumberGetValue(reinterpret_cast<CFNumberRef>(value), kCFNumberIntType,
&number)) {
is_private = number != 0;
}
}
CFRelease(dictionary);
return is_private;
}
} // namespace core_audio_mac } // namespace core_audio_mac
} // namespace media } // namespace media
...@@ -43,6 +43,15 @@ uint32_t GetNumStreams(AudioObjectID device_id, bool is_input); ...@@ -43,6 +43,15 @@ uint32_t GetNumStreams(AudioObjectID device_id, bool is_input);
base::Optional<uint32_t> GetDeviceSource(AudioObjectID device_id, base::Optional<uint32_t> GetDeviceSource(AudioObjectID device_id,
bool is_input); bool is_input);
// Returns the transport type of the given |device_id|, or no value if
// |device_id| has no source or if there is an error.
base::Optional<uint32_t> GetDeviceTransportType(AudioObjectID device_id);
// Returns whether or not the |device_id| corresponds to a private, aggregate
// device. Such a device gets created by instantiating a VoiceProcessingIO
// AudioUnit.
bool IsPrivateAggregateDevice(AudioObjectID device_id);
} // namespace core_audio_mac } // namespace core_audio_mac
} // namespace media } // namespace media
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment