APM: return compatibility score to indicate how the profile is compatible
for the given parameters.
Use compatibility score to describe how the profile is compatibile with
given parameters. In that way, it can help find the exactly matched
profile.
Bug: 322899696
Test: atest audiopolicy_tests
Change-Id: I968b705c81d467ca5952c408d6ee3152acef0fdd
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index f3a9518..688772c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -70,10 +70,17 @@
return mMixerBehaviors;
}
+ enum CompatibilityScore{
+ NO_MATCH = 0,
+ PARTIAL_MATCH = 1,
+ EXACT_MATCH = 2
+ };
+
/**
- * @brief isCompatibleProfile: This method is used for input and direct output,
+ * @brief compatibilityScore: This method is used for input and direct output,
* and is not used for other output.
- * Checks if the IO profile is compatible with specified parameters.
+ * Return the compatibility score to measure how much the IO profile is compatible
+ * with specified parameters.
* For input, flags is interpreted as audio_input_flags_t.
* TODO: merge audio_output_flags_t and audio_input_flags_t.
*
@@ -86,18 +93,18 @@
* @param updatedChannelMask if non-NULL, it is assigned the actual channel mask
* @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.
+ * @return how the IO profile is compatible with the given parameters.
*/
- bool isCompatibleProfile(const DeviceVector &devices,
- uint32_t samplingRate,
- uint32_t *updatedSamplingRate,
- audio_format_t format,
- audio_format_t *updatedFormat,
- audio_channel_mask_t channelMask,
- audio_channel_mask_t *updatedChannelMask,
- // FIXME parameter type
- uint32_t flags,
- bool exactMatchRequiredForInputFlags = false) const;
+ CompatibilityScore getCompatibilityScore(const DeviceVector &devices,
+ uint32_t samplingRate,
+ uint32_t *updatedSamplingRate,
+ audio_format_t format,
+ audio_format_t *updatedFormat,
+ audio_channel_mask_t channelMask,
+ audio_channel_mask_t *updatedChannelMask,
+ // FIXME parameter type
+ uint32_t flags,
+ bool exactMatchRequiredForInputFlags = false) const;
/**
* @brief areAllDevicesSupported: Checks if the given devices are supported by the IO profile.
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index dd222de..e6ac84c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -33,17 +33,17 @@
}
}
-bool IOProfile::isCompatibleProfile(const DeviceVector &devices,
- uint32_t samplingRate,
- uint32_t *updatedSamplingRate,
- audio_format_t format,
- audio_format_t *updatedFormat,
- audio_channel_mask_t channelMask,
- audio_channel_mask_t *updatedChannelMask,
- // FIXME type punning here
- uint32_t flags,
- bool exactMatchRequiredForInputFlags) const
-{
+IOProfile::CompatibilityScore IOProfile::getCompatibilityScore(
+ const android::DeviceVector &devices,
+ uint32_t samplingRate,
+ uint32_t *updatedSamplingRate,
+ audio_format_t format,
+ audio_format_t *updatedFormat,
+ audio_channel_mask_t channelMask,
+ audio_channel_mask_t *updatedChannelMask,
+ // FIXME type punning here
+ uint32_t flags,
+ bool exactMatchRequiredForInputFlags) const {
const bool isPlaybackThread =
getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
const bool isRecordThread =
@@ -51,13 +51,13 @@
ALOG_ASSERT(isPlaybackThread != isRecordThread);
if (!areAllDevicesSupported(devices) ||
!isCompatibleProfileForFlags(flags, exactMatchRequiredForInputFlags)) {
- return false;
+ return NO_MATCH;
}
if (!audio_is_valid_format(format) ||
(isPlaybackThread && (samplingRate == 0 || !audio_is_output_channel(channelMask))) ||
(isRecordThread && (!audio_is_input_channel(channelMask)))) {
- return false;
+ return NO_MATCH;
}
audio_format_t myUpdatedFormat = format;
@@ -69,32 +69,40 @@
.channel_mask = channelMask,
.format = format,
};
+ auto result = NO_MATCH;
if (isRecordThread)
{
if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
if (checkExactAudioProfile(&config) != NO_ERROR) {
- return false;
+ return result;
}
- } else if (checkExactAudioProfile(&config) != NO_ERROR && checkCompatibleAudioProfile(
- myUpdatedSamplingRate, myUpdatedChannelMask, myUpdatedFormat) != NO_ERROR) {
- return false;
+ result = EXACT_MATCH;
+ } else if (checkExactAudioProfile(&config) == NO_ERROR) {
+ result = EXACT_MATCH;
+ } else if (checkCompatibleAudioProfile(
+ myUpdatedSamplingRate, myUpdatedChannelMask, myUpdatedFormat) == NO_ERROR) {
+ result = PARTIAL_MATCH;
+ } else {
+ return result;
}
} else {
- if (checkExactAudioProfile(&config) != NO_ERROR) {
- return false;
+ if (checkExactAudioProfile(&config) == NO_ERROR) {
+ result = EXACT_MATCH;
+ } else {
+ return result;
}
}
- if (updatedSamplingRate != NULL) {
+ if (updatedSamplingRate != nullptr) {
*updatedSamplingRate = myUpdatedSamplingRate;
}
- if (updatedFormat != NULL) {
+ if (updatedFormat != nullptr) {
*updatedFormat = myUpdatedFormat;
}
- if (updatedChannelMask != NULL) {
+ if (updatedChannelMask != nullptr) {
*updatedChannelMask = myUpdatedChannelMask;
}
- return true;
+ return result;
}
bool IOProfile::areAllDevicesSupported(const DeviceVector &devices) const {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 0084273..4714623 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1050,11 +1050,11 @@
sp<IOProfile> profile;
for (const auto& hwModule : hwModules) {
for (const auto& curProfile : hwModule->getOutputProfiles()) {
- if (!curProfile->isCompatibleProfile(devices,
+ if (curProfile->getCompatibilityScore(devices,
samplingRate, NULL /*updatedSamplingRate*/,
format, NULL /*updatedFormat*/,
channelMask, NULL /*updatedChannelMask*/,
- flags)) {
+ flags) == IOProfile::NO_MATCH) {
continue;
}
// reject profiles not corresponding to a device currently available
@@ -4486,11 +4486,11 @@
outputDevices = getMsdAudioOutDevices();
}
for (const auto& curProfile : hwModule->getOutputProfiles()) {
- if (!curProfile->isCompatibleProfile(outputDevices,
+ if (curProfile->getCompatibilityScore(outputDevices,
config->sample_rate, nullptr /*updatedSamplingRate*/,
config->format, nullptr /*updatedFormat*/,
config->channel_mask, nullptr /*updatedChannelMask*/,
- flags)) {
+ flags) == IOProfile::NO_MATCH) {
continue;
}
// reject profiles not corresponding to a device currently available
@@ -4596,15 +4596,17 @@
for (const auto& hwModule : mHwModules) {
for (const auto& curProfile : hwModule->getOutputProfiles()) {
if (curProfile->hasDynamicAudioProfile()
- && curProfile->isCompatibleProfile(devices,
- mixerAttributes->config.sample_rate,
- nullptr /*updatedSamplingRate*/,
- mixerAttributes->config.format,
- nullptr /*updatedFormat*/,
- mixerAttributes->config.channel_mask,
- nullptr /*updatedChannelMask*/,
- flags,
- false /*exactMatchRequiredForInputFlags*/)) {
+ && curProfile->getCompatibilityScore(
+ devices,
+ mixerAttributes->config.sample_rate,
+ nullptr /*updatedSamplingRate*/,
+ mixerAttributes->config.format,
+ nullptr /*updatedFormat*/,
+ mixerAttributes->config.channel_mask,
+ nullptr /*updatedChannelMask*/,
+ flags,
+ false /*exactMatchRequiredForInputFlags*/)
+ != IOProfile::NO_MATCH) {
profile = curProfile;
break;
}
@@ -5009,14 +5011,15 @@
return BAD_VALUE;
}
- if (!outputDesc->mProfile->isCompatibleProfile(DeviceVector(devDesc),
- patch->sources[0].sample_rate,
- NULL, // updatedSamplingRate
- patch->sources[0].format,
- NULL, // updatedFormat
- patch->sources[0].channel_mask,
- NULL, // updatedChannelMask
- AUDIO_OUTPUT_FLAG_NONE /*FIXME*/)) {
+ if (outputDesc->mProfile->getCompatibilityScore(
+ DeviceVector(devDesc),
+ patch->sources[0].sample_rate,
+ nullptr, // updatedSamplingRate
+ patch->sources[0].format,
+ nullptr, // updatedFormat
+ patch->sources[0].channel_mask,
+ nullptr, // updatedChannelMask
+ AUDIO_OUTPUT_FLAG_NONE /*FIXME*/) == IOProfile::NO_MATCH) {
ALOGV("%s profile not supported for device %08x", __func__, devDesc->type());
return INVALID_OPERATION;
}
@@ -5064,17 +5067,18 @@
return BAD_VALUE;
}
- if (!inputDesc->mProfile->isCompatibleProfile(DeviceVector(device),
- patch->sinks[0].sample_rate,
- NULL, /*updatedSampleRate*/
- patch->sinks[0].format,
- NULL, /*updatedFormat*/
- patch->sinks[0].channel_mask,
- NULL, /*updatedChannelMask*/
- // FIXME for the parameter type,
- // and the NONE
- (audio_output_flags_t)
- AUDIO_INPUT_FLAG_NONE)) {
+ if (inputDesc->mProfile->getCompatibilityScore(
+ DeviceVector(device),
+ patch->sinks[0].sample_rate,
+ nullptr, /*updatedSampleRate*/
+ patch->sinks[0].format,
+ nullptr, /*updatedFormat*/
+ patch->sinks[0].channel_mask,
+ nullptr, /*updatedChannelMask*/
+ // FIXME for the parameter type,
+ // and the NONE
+ (audio_output_flags_t)
+ AUDIO_INPUT_FLAG_NONE) == IOProfile::NO_MATCH) {
return INVALID_OPERATION;
}
// TODO: reconfigure output format and channels here
@@ -7694,9 +7698,6 @@
// Choose an input profile based on the requested capture parameters: select the first available
// profile supporting all requested parameters.
// The flags can be ignored if it doesn't contain a much match flag.
- //
- // TODO: perhaps isCompatibleProfile should return a "matching" score so we can return
- // the best matching profile, not the first one.
using underlying_input_flag_t = std::underlying_type_t<audio_input_flags_t>;
const underlying_input_flag_t mustMatchFlag = AUDIO_INPUT_FLAG_MMAP_NOIRQ |
@@ -7713,27 +7714,35 @@
for (const auto& profile : hwModule->getInputProfiles()) {
// profile->log();
//updatedFormat = format;
- if (profile->isCompatibleProfile(DeviceVector(device), samplingRate,
- &samplingRate /*updatedSamplingRate*/,
- format,
- &format, /*updatedFormat*/
- channelMask,
- &channelMask /*updatedChannelMask*/,
- // FIXME ugly cast
- (audio_output_flags_t) flags,
- true /*exactMatchRequiredForInputFlags*/)) {
+ if (profile->getCompatibilityScore(
+ DeviceVector(device),
+ samplingRate,
+ &updatedSamplingRate,
+ format,
+ &updatedFormat,
+ channelMask,
+ &updatedChannelMask,
+ // FIXME ugly cast
+ (audio_output_flags_t) flags,
+ true /*exactMatchRequiredForInputFlags*/) == IOProfile::EXACT_MATCH) {
+ samplingRate = updatedSamplingRate;
+ format = updatedFormat;
+ channelMask = updatedChannelMask;
return profile;
}
- if (firstInexact == nullptr && profile->isCompatibleProfile(DeviceVector(device),
- samplingRate,
- &updatedSamplingRate,
- format,
- &updatedFormat,
- channelMask,
- &updatedChannelMask,
- // FIXME ugly cast
- (audio_output_flags_t) flags,
- false /*exactMatchRequiredForInputFlags*/)) {
+ if (firstInexact == nullptr
+ && profile->getCompatibilityScore(
+ DeviceVector(device),
+ samplingRate,
+ &updatedSamplingRate,
+ format,
+ &updatedFormat,
+ channelMask,
+ &updatedChannelMask,
+ // FIXME ugly cast
+ (audio_output_flags_t) flags,
+ false /*exactMatchRequiredForInputFlags*/)
+ != IOProfile::NO_MATCH) {
firstInexact = profile;
}
}
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index 31ee252..aa7c9cd 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -31,6 +31,7 @@
using AudioPolicyManager::getConfig;
using AudioPolicyManager::initialize;
using AudioPolicyManager::getOutputs;
+ using AudioPolicyManager::getInputs;
using AudioPolicyManager::getAvailableOutputDevices;
using AudioPolicyManager::getAvailableInputDevices;
using AudioPolicyManager::setSurroundFormatEnabled;
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 74d3474..065a3d8 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -92,6 +92,12 @@
return attributionSourceState;
}
+bool equals(const audio_config_base_t& config1, const audio_config_base_t& config2) {
+ return config1.format == config2.format
+ && config1.sample_rate == config2.sample_rate
+ && config1.channel_mask == config2.channel_mask;
+}
+
} // namespace
TEST(AudioPolicyConfigTest, DefaultConfigForTestsIsEmpty) {
@@ -1266,6 +1272,53 @@
"", "", AUDIO_FORMAT_LDAC));
}
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, PreferExactConfigForInput) {
+ const audio_channel_mask_t deviceChannelMask = AUDIO_CHANNEL_IN_3POINT1;
+ mClient->addSupportedFormat(AUDIO_FORMAT_PCM_16_BIT);
+ mClient->addSupportedChannelMask(deviceChannelMask);
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_IN_USB_DEVICE,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ "", "", AUDIO_FORMAT_DEFAULT));
+
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_attributes_t attr = {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_VOICE_COMMUNICATION,AUDIO_FLAG_NONE, ""};
+ AudioPolicyInterface::input_type_t inputType;
+ audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
+ AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
+ audio_config_base_t requestedConfig = {
+ .channel_mask = AUDIO_CHANNEL_IN_STEREO,
+ .format = AUDIO_FORMAT_PCM_16_BIT,
+ .sample_rate = 48000
+ };
+ audio_config_base_t config = requestedConfig;
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+ ASSERT_EQ(OK, mManager->getInputForAttr(
+ &attr, &input, 1 /*riid*/, AUDIO_SESSION_NONE, attributionSource, &config,
+ AUDIO_INPUT_FLAG_NONE,
+ &selectedDeviceId, &inputType, &portId));
+ ASSERT_NE(AUDIO_PORT_HANDLE_NONE, portId);
+ ASSERT_TRUE(equals(requestedConfig, config));
+
+ attr = {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+ AUDIO_SOURCE_VOICE_COMMUNICATION, AUDIO_FLAG_NONE, ""};
+ requestedConfig.channel_mask = deviceChannelMask;
+ config = requestedConfig;
+ selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ input = AUDIO_PORT_HANDLE_NONE;
+ portId = AUDIO_PORT_HANDLE_NONE;
+ ASSERT_EQ(OK, mManager->getInputForAttr(
+ &attr, &input, 1 /*riid*/, AUDIO_SESSION_NONE, attributionSource, &config,
+ AUDIO_INPUT_FLAG_NONE,
+ &selectedDeviceId, &inputType, &portId));
+ ASSERT_NE(AUDIO_PORT_HANDLE_NONE, portId);
+ ASSERT_TRUE(equals(requestedConfig, config));
+
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_IN_USB_DEVICE,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ "", "", AUDIO_FORMAT_DEFAULT));
+}
+
class AudioPolicyManagerTestDynamicPolicy : public AudioPolicyManagerTestWithConfigurationFile {
protected:
void TearDown() override;
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
index 4efdf8a..1a299c6 100644
--- a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
@@ -65,6 +65,7 @@
samplingRates="48000"
channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
</mixPort>
+ <mixPort name="hifi_input" role="sink" />
</mixPorts>
<devicePorts>
<devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
@@ -111,6 +112,8 @@
sources="primary output,hifi_output,mmap_no_irq_out"/>
<route type="mix" sink="mixport_bus_input"
sources="BUS Device In"/>
+ <route type="mix" sink="hifi_input"
+ sources="USB Device In" />
</routes>
</module>