Use returned config to retry opening MMAP stream when fails.
When opening MMAP stream, it may fail at the first try as the requested
configuration may not match what the HAL supports. The audio policy
manager knows all the information that the HAL supports. In that case,
when it fails at the first try, audio policy manager is able to return
the supported configurations. After getting the supported
configuration, the aaudio service can retry opening MMAP stream with the
supported configuration.
Bug: 226190094
Test: atest AAudioTests AudioTrackTest AudioRecordTest
Test: atest DirectAudioProfilesForAttributesTest
Change-Id: Id6ccae3e26d7ffc8fe4c3c7babe825a08d22aa78
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 496591a..c4c27e8 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -134,17 +134,17 @@
// request an output appropriate for playback of the supplied stream type and parameters
virtual audio_io_handle_t getOutput(audio_stream_type_t stream) = 0;
virtual status_t getOutputForAttr(const audio_attributes_t *attr,
- audio_io_handle_t *output,
- audio_session_t session,
- audio_stream_type_t *stream,
- const AttributionSourceState& attributionSouce,
- const audio_config_t *config,
- audio_output_flags_t *flags,
- audio_port_handle_t *selectedDeviceId,
- audio_port_handle_t *portId,
- std::vector<audio_io_handle_t> *secondaryOutputs,
- output_type_t *outputType,
- bool *isSpatialized) = 0;
+ audio_io_handle_t *output,
+ audio_session_t session,
+ audio_stream_type_t *stream,
+ const AttributionSourceState& attributionSouce,
+ audio_config_t *config,
+ audio_output_flags_t *flags,
+ audio_port_handle_t *selectedDeviceId,
+ audio_port_handle_t *portId,
+ std::vector<audio_io_handle_t> *secondaryOutputs,
+ output_type_t *outputType,
+ bool *isSpatialized) = 0;
// indicates to the audio policy manager that the output starts being used by corresponding
// stream.
virtual status_t startOutput(audio_port_handle_t portId) = 0;
@@ -160,7 +160,7 @@
audio_unique_id_t riid,
audio_session_t session,
const AttributionSourceState& attributionSouce,
- const audio_config_base_t *config,
+ audio_config_base_t *config,
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
input_type_t *inputType,
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index 90b812d..37443ab 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -97,6 +97,25 @@
uint32_t flags,
bool exactMatchRequiredForInputFlags = false) const;
+ /**
+ * @brief areAllDevicesSupported: Checks if the given devices are supported by the IO profile.
+ *
+ * @param devices vector of devices to be checked for compatibility
+ * @return true if all devices are supported, false otherwise.
+ */
+ bool areAllDevicesSupported(const DeviceVector &devices) const;
+
+ /**
+ * @brief isCompatibleProfileForFlags: Checks if the IO profile is compatible with
+ * specified flags.
+ *
+ * @param flags to be checked for compatibility
+ * @param exactMatchRequiredForInputFlags true if exact match is required on flags
+ * @return true if the profile is compatible, false otherwise.
+ */
+ bool isCompatibleProfileForFlags(uint32_t flags,
+ bool exactMatchRequiredForInputFlags = false) const;
+
void dump(String8 *dst, int spaces) const;
void log();
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index 21f2018..7b4cecf 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -40,11 +40,9 @@
const bool isRecordThread =
getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SINK;
ALOG_ASSERT(isPlaybackThread != isRecordThread);
-
- if (!devices.isEmpty()) {
- if (!mSupportedDevices.containsAllDevices(devices)) {
- return false;
- }
+ if (!areAllDevicesSupported(devices) ||
+ !isCompatibleProfileForFlags(flags, exactMatchRequiredForInputFlags)) {
+ return false;
}
if (!audio_is_valid_format(format) ||
@@ -78,6 +76,33 @@
}
}
+ if (updatedSamplingRate != NULL) {
+ *updatedSamplingRate = myUpdatedSamplingRate;
+ }
+ if (updatedFormat != NULL) {
+ *updatedFormat = myUpdatedFormat;
+ }
+ if (updatedChannelMask != NULL) {
+ *updatedChannelMask = myUpdatedChannelMask;
+ }
+ return true;
+}
+
+bool IOProfile::areAllDevicesSupported(const DeviceVector &devices) const {
+ if (devices.empty()) {
+ return true;
+ }
+ return mSupportedDevices.containsAllDevices(devices);
+}
+
+bool IOProfile::isCompatibleProfileForFlags(uint32_t flags,
+ bool exactMatchRequiredForInputFlags) const {
+ const bool isPlaybackThread =
+ getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
+ const bool isRecordThread =
+ getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SINK;
+ ALOG_ASSERT(isPlaybackThread != isRecordThread);
+
const uint32_t mustMatchOutputFlags =
AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
if (isPlaybackThread && (((getFlags() ^ flags) & mustMatchOutputFlags)
@@ -93,15 +118,6 @@
return false;
}
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = myUpdatedSamplingRate;
- }
- if (updatedFormat != NULL) {
- *updatedFormat = myUpdatedFormat;
- }
- if (updatedChannelMask != NULL) {
- *updatedChannelMask = myUpdatedChannelMask;
- }
return true;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index c21c6a2..4a62eda 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1132,7 +1132,7 @@
const audio_attributes_t *attr,
audio_stream_type_t *stream,
uid_t uid,
- const audio_config_t *config,
+ audio_config_t *config,
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
bool *isRequestedDeviceForExclusiveUse,
@@ -1273,6 +1273,15 @@
flags, isSpatialized, resultAttr->flags & AUDIO_FLAG_MUTE_HAPTIC);
}
if (*output == AUDIO_IO_HANDLE_NONE) {
+ AudioProfileVector profiles;
+ status_t ret = getProfilesForDevices(outputDevices, profiles, *flags, false /*isInput*/);
+ if (ret == NO_ERROR && !profiles.empty()) {
+ config->channel_mask = profiles[0]->getChannels().empty() ? config->channel_mask
+ : *profiles[0]->getChannels().begin();
+ config->sample_rate = profiles[0]->getSampleRates().empty() ? config->sample_rate
+ : *profiles[0]->getSampleRates().begin();
+ config->format = profiles[0]->getFormat();
+ }
return INVALID_OPERATION;
}
@@ -1300,7 +1309,7 @@
audio_session_t session,
audio_stream_type_t *stream,
const AttributionSourceState& attributionSource,
- const audio_config_t *config,
+ audio_config_t *config,
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId,
@@ -2412,7 +2421,7 @@
audio_unique_id_t riid,
audio_session_t session,
const AttributionSourceState& attributionSource,
- const audio_config_base_t *config,
+ audio_config_base_t *config,
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
input_type_t *inputType,
@@ -2553,6 +2562,16 @@
*input = getInputForDevice(device, session, attributes, config, flags, policyMix);
if (*input == AUDIO_IO_HANDLE_NONE) {
status = INVALID_OPERATION;
+ AudioProfileVector profiles;
+ status_t ret = getProfilesForDevices(
+ DeviceVector(device), profiles, flags, true /*isInput*/);
+ if (ret == NO_ERROR && !profiles.empty()) {
+ config->channel_mask = profiles[0]->getChannels().empty() ? config->channel_mask
+ : *profiles[0]->getChannels().begin();
+ config->sample_rate = profiles[0]->getSampleRates().empty() ? config->sample_rate
+ : *profiles[0]->getSampleRates().begin();
+ config->format = profiles[0]->getFormat();
+ }
goto error;
}
@@ -2584,7 +2603,7 @@
audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescriptor> &device,
audio_session_t session,
const audio_attributes_t &attributes,
- const audio_config_base_t *config,
+ audio_config_base_t *config,
audio_input_flags_t flags,
const sp<AudioPolicyMix> &policyMix)
{
@@ -4085,8 +4104,8 @@
status_t AudioPolicyManager::getDirectProfilesForAttributes(const audio_attributes_t* attr,
AudioProfileVector& audioProfilesVector) {
- AudioDeviceTypeAddrVector devices;
- status_t status = getDevicesForAttributes(*attr, &devices, false /* forVolume */);
+ DeviceVector devices;
+ status_t status = getDevicesForAttributes(*attr, devices, false /* forVolume */);
if (status != OK) {
return status;
}
@@ -4094,44 +4113,8 @@
if (devices.empty()) {
return OK; // no output devices for the attributes
}
-
- for (const auto& hwModule : mHwModules) {
- // the MSD module checks for different conditions
- if (strcmp(hwModule->getName(), AUDIO_HARDWARE_MODULE_ID_MSD) == 0) {
- continue;
- }
- for (const auto& outputProfile : hwModule->getOutputProfiles()) {
- if (!outputProfile->asAudioPort()->isDirectOutput()) {
- continue;
- }
- // allow only profiles that support all the available and routed devices
- if (outputProfile->getSupportedDevices().getDevicesFromDeviceTypeAddrVec(devices).size()
- != devices.size()) {
- continue;
- }
- audioProfilesVector.addAllValidProfiles(
- outputProfile->asAudioPort()->getAudioProfiles());
- }
- }
-
- // add the direct profiles from MSD if present and has audio patches to all the output(s)
- const auto& msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
- if (msdModule != nullptr) {
- if (msdHasPatchesToAllDevices(devices)) {
- ALOGV("%s: MSD audio patches set to all output devices.", __func__);
- for (const auto& outputProfile : msdModule->getOutputProfiles()) {
- if (!outputProfile->asAudioPort()->isDirectOutput()) {
- continue;
- }
- audioProfilesVector.addAllValidProfiles(
- outputProfile->asAudioPort()->getAudioProfiles());
- }
- } else {
- ALOGV("%s: MSD audio patches NOT set to all output devices.", __func__);
- }
- }
-
- return NO_ERROR;
+ return getProfilesForDevices(devices, audioProfilesVector,
+ AUDIO_OUTPUT_FLAG_DIRECT /*flags*/, false /*isInput*/);
}
status_t AudioPolicyManager::listAudioPorts(audio_port_role_t role,
@@ -6680,70 +6663,15 @@
return (stream1 == stream2);
}
-// TODO - consider MSD routes b/214971780
status_t AudioPolicyManager::getDevicesForAttributes(
const audio_attributes_t &attr, AudioDeviceTypeAddrVector *devices, bool forVolume) {
if (devices == nullptr) {
return BAD_VALUE;
}
- // Devices are determined in the following precedence:
- //
- // 1) Devices associated with a dynamic policy matching the attributes. This is often
- // a remote submix from MIX_ROUTE_FLAG_LOOP_BACK.
- //
- // If no such dynamic policy then
- // 2) Devices containing an active client using setPreferredDevice
- // with same strategy as the attributes.
- // (from the default Engine::getOutputDevicesForAttributes() implementation).
- //
- // If no corresponding active client with setPreferredDevice then
- // 3) Devices associated with the strategy determined by the attributes
- // (from the default Engine::getOutputDevicesForAttributes() implementation).
- //
- // See related getOutputForAttrInt().
-
- // check dynamic policies but only for primary descriptors (secondary not used for audible
- // audio routing, only used for duplication for playback capture)
- sp<AudioPolicyMix> policyMix;
- status_t status = mPolicyMixes.getOutputForAttr(attr, AUDIO_CONFIG_BASE_INITIALIZER,
- 0 /*uid unknown here*/, AUDIO_OUTPUT_FLAG_NONE, policyMix, nullptr);
- if (status != OK) {
- return status;
- }
-
DeviceVector curDevices;
- if (policyMix != nullptr && policyMix->getOutput() != nullptr &&
- // For volume control, skip LOOPBACK mixes which use AUDIO_DEVICE_OUT_REMOTE_SUBMIX
- // as they are unaffected by device/stream volume
- // (per SwAudioOutputDescriptor::isFixedVolume()).
- (!forVolume || policyMix->mDeviceType != AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
- ) {
- sp<DeviceDescriptor> deviceDesc = mAvailableOutputDevices.getDevice(
- policyMix->mDeviceType, policyMix->mDeviceAddress, AUDIO_FORMAT_DEFAULT);
- curDevices.add(deviceDesc);
- } else {
- // The default Engine::getOutputDevicesForAttributes() uses findPreferredDevice()
- // which selects setPreferredDevice if active. This means forVolume call
- // will take an active setPreferredDevice, if such exists.
-
- curDevices = mEngine->getOutputDevicesForAttributes(
- attr, nullptr /* preferredDevice */, false /* fromCache */);
- }
-
- if (forVolume) {
- // We alias the device AUDIO_DEVICE_OUT_SPEAKER_SAFE to AUDIO_DEVICE_OUT_SPEAKER
- // for single volume control in AudioService (such relationship should exist if
- // SPEAKER_SAFE is present).
- //
- // (This is unrelated to a different device grouping as Volume::getDeviceCategory)
- DeviceVector speakerSafeDevices =
- curDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER_SAFE);
- if (!speakerSafeDevices.isEmpty()) {
- curDevices.merge(
- mAvailableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER));
- curDevices.remove(speakerSafeDevices);
- }
+ if (status_t status = getDevicesForAttributes(attr, curDevices, forVolume); status != OK) {
+ return status;
}
for (const auto& device : curDevices) {
devices->push_back(device->getDeviceTypeAddr());
@@ -7897,4 +7825,109 @@
return desc;
}
+status_t AudioPolicyManager::getDevicesForAttributes(
+ const audio_attributes_t &attr, DeviceVector &devices, bool forVolume) {
+ // Devices are determined in the following precedence:
+ //
+ // 1) Devices associated with a dynamic policy matching the attributes. This is often
+ // a remote submix from MIX_ROUTE_FLAG_LOOP_BACK.
+ //
+ // If no such dynamic policy then
+ // 2) Devices containing an active client using setPreferredDevice
+ // with same strategy as the attributes.
+ // (from the default Engine::getOutputDevicesForAttributes() implementation).
+ //
+ // If no corresponding active client with setPreferredDevice then
+ // 3) Devices associated with the strategy determined by the attributes
+ // (from the default Engine::getOutputDevicesForAttributes() implementation).
+ //
+ // See related getOutputForAttrInt().
+
+ // check dynamic policies but only for primary descriptors (secondary not used for audible
+ // audio routing, only used for duplication for playback capture)
+ sp<AudioPolicyMix> policyMix;
+ status_t status = mPolicyMixes.getOutputForAttr(attr, AUDIO_CONFIG_BASE_INITIALIZER,
+ 0 /*uid unknown here*/, AUDIO_OUTPUT_FLAG_NONE, policyMix,
+ nullptr /* secondaryMixes */);
+ if (status != OK) {
+ return status;
+ }
+
+ if (policyMix != nullptr && policyMix->getOutput() != nullptr &&
+ // For volume control, skip LOOPBACK mixes which use AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+ // as they are unaffected by device/stream volume
+ // (per SwAudioOutputDescriptor::isFixedVolume()).
+ (!forVolume || policyMix->mDeviceType != AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+ ) {
+ sp<DeviceDescriptor> deviceDesc = mAvailableOutputDevices.getDevice(
+ policyMix->mDeviceType, policyMix->mDeviceAddress, AUDIO_FORMAT_DEFAULT);
+ devices.add(deviceDesc);
+ } else {
+ // The default Engine::getOutputDevicesForAttributes() uses findPreferredDevice()
+ // which selects setPreferredDevice if active. This means forVolume call
+ // will take an active setPreferredDevice, if such exists.
+
+ devices = mEngine->getOutputDevicesForAttributes(
+ attr, nullptr /* preferredDevice */, false /* fromCache */);
+ }
+
+ if (forVolume) {
+ // We alias the device AUDIO_DEVICE_OUT_SPEAKER_SAFE to AUDIO_DEVICE_OUT_SPEAKER
+ // for single volume control in AudioService (such relationship should exist if
+ // SPEAKER_SAFE is present).
+ //
+ // (This is unrelated to a different device grouping as Volume::getDeviceCategory)
+ DeviceVector speakerSafeDevices =
+ devices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER_SAFE);
+ if (!speakerSafeDevices.isEmpty()) {
+ devices.merge(mAvailableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER));
+ devices.remove(speakerSafeDevices);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getProfilesForDevices(const DeviceVector& devices,
+ AudioProfileVector& audioProfiles,
+ uint32_t flags,
+ bool isInput) {
+ for (const auto& hwModule : mHwModules) {
+ // the MSD module checks for different conditions
+ if (strcmp(hwModule->getName(), AUDIO_HARDWARE_MODULE_ID_MSD) == 0) {
+ continue;
+ }
+ IOProfileCollection ioProfiles = isInput ? hwModule->getInputProfiles()
+ : hwModule->getOutputProfiles();
+ for (const auto& profile : ioProfiles) {
+ if (!profile->areAllDevicesSupported(devices) ||
+ !profile->isCompatibleProfileForFlags(
+ flags, false /*exactMatchRequiredForInputFlags*/)) {
+ continue;
+ }
+ audioProfiles.addAllValidProfiles(profile->asAudioPort()->getAudioProfiles());
+ }
+ }
+
+ if (!isInput) {
+ // add the direct profiles from MSD if present and has audio patches to all the output(s)
+ const auto &msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+ if (msdModule != nullptr) {
+ if (msdHasPatchesToAllDevices(devices.toTypeAddrVector())) {
+ ALOGV("%s: MSD audio patches set to all output devices.", __func__);
+ for (const auto &profile: msdModule->getOutputProfiles()) {
+ if (!profile->asAudioPort()->isDirectOutput()) {
+ continue;
+ }
+ audioProfiles.addAllValidProfiles(profile->asAudioPort()->getAudioProfiles());
+ }
+ } else {
+ ALOGV("%s: MSD audio patches NOT set to all output devices.", __func__);
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
} // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 87e6974..74460c7 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -117,7 +117,7 @@
audio_session_t session,
audio_stream_type_t *stream,
const AttributionSourceState& attributionSource,
- const audio_config_t *config,
+ audio_config_t *config,
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId,
@@ -132,7 +132,7 @@
audio_unique_id_t riid,
audio_session_t session,
const AttributionSourceState& attributionSource,
- const audio_config_base_t *config,
+ audio_config_base_t *config,
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
input_type_t *inputType,
@@ -1052,7 +1052,7 @@
const audio_attributes_t *attr,
audio_stream_type_t *stream,
uid_t uid,
- const audio_config_t *config,
+ audio_config_t *config,
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
bool *isRequestedDeviceForExclusiveUse,
@@ -1133,7 +1133,9 @@
* @param session requester session id
* @param uid requester uid
* @param attributes requester audio attributes (e.g. input source and tags matter)
- * @param config requester audio configuration (e.g. sample rate, format, channel mask).
+ * @param config requested audio configuration (e.g. sample rate, format, channel mask),
+ * will be updated if current configuration doesn't support but another
+ * one does
* @param flags requester input flags
* @param policyMix may be null, policy rules to be followed by the requester
* @return input io handle aka unique input identifier selected for this device.
@@ -1141,7 +1143,7 @@
audio_io_handle_t getInputForDevice(const sp<DeviceDescriptor> &device,
audio_session_t session,
const audio_attributes_t &attributes,
- const audio_config_base_t *config,
+ audio_config_base_t *config,
audio_input_flags_t flags,
const sp<AudioPolicyMix> &policyMix);
@@ -1260,6 +1262,15 @@
// Filters only the relevant flags for getProfileForOutput
audio_output_flags_t getRelevantFlags (audio_output_flags_t flags, bool directOnly);
+
+ status_t getDevicesForAttributes(const audio_attributes_t &attr,
+ DeviceVector &devices,
+ bool forVolume);
+
+ status_t getProfilesForDevices(const DeviceVector& devices,
+ AudioProfileVector& audioProfiles,
+ uint32_t flags,
+ bool isInput);
};
};
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index df49bba..b15b61d 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -443,6 +443,13 @@
convertContainer<std::vector<int32_t>>(secondaryOutputs,
legacy2aidl_audio_io_handle_t_int32_t));
_aidl_return->isSpatialized = isSpatialized;
+ } else {
+ _aidl_return->configBase.format = VALUE_OR_RETURN_BINDER_STATUS(
+ legacy2aidl_audio_format_t_AudioFormatDescription(config.format));
+ _aidl_return->configBase.channelMask = VALUE_OR_RETURN_BINDER_STATUS(
+ legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+ config.channel_mask, false /*isInput*/));
+ _aidl_return->configBase.sampleRate = config.sample_rate;
}
return binderStatusFromStatusT(result);
}
@@ -755,6 +762,9 @@
if (status == PERMISSION_DENIED) {
AutoCallerClear acc;
mAudioPolicyManager->releaseInput(portId);
+ } else {
+ _aidl_return->config = VALUE_OR_RETURN_BINDER_STATUS(
+ legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/));
}
return binderStatusFromStatusT(status);
}