Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 66acc439 authored by jiabin's avatar jiabin
Browse files

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
parent 7709d8f3
Loading
Loading
Loading
Loading
+20 −13
Original line number Diff line number Diff line
@@ -70,10 +70,17 @@ public:
        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,9 +93,9 @@ public:
     * @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,
    CompatibilityScore getCompatibilityScore(const DeviceVector &devices,
                                             uint32_t samplingRate,
                                             uint32_t *updatedSamplingRate,
                                             audio_format_t format,
+31 −23
Original line number Diff line number Diff line
@@ -33,7 +33,8 @@ IOProfile::IOProfile(const std::string &name, audio_port_role_t role)
    }
}

bool IOProfile::isCompatibleProfile(const DeviceVector &devices,
IOProfile::CompatibilityScore IOProfile::getCompatibilityScore(
        const android::DeviceVector &devices,
        uint32_t samplingRate,
        uint32_t *updatedSamplingRate,
        audio_format_t format,
@@ -42,8 +43,7 @@ bool IOProfile::isCompatibleProfile(const DeviceVector &devices,
        audio_channel_mask_t *updatedChannelMask,
        // FIXME type punning here
        uint32_t flags,
                                    bool exactMatchRequiredForInputFlags) const
{
        bool exactMatchRequiredForInputFlags) const {
    const bool isPlaybackThread =
            getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
    const bool isRecordThread =
@@ -51,13 +51,13 @@ bool IOProfile::isCompatibleProfile(const DeviceVector &devices,
    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 @@ bool IOProfile::isCompatibleProfile(const DeviceVector &devices,
        .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;
            }
        } else if (checkExactAudioProfile(&config) != NO_ERROR && checkCompatibleAudioProfile(
                myUpdatedSamplingRate, myUpdatedChannelMask, myUpdatedFormat) != NO_ERROR) {
            return false;
                return result;
            }
            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 {
+63 −54
Original line number Diff line number Diff line
@@ -1050,11 +1050,11 @@ sp<IOProfile> AudioPolicyManager::searchCompatibleProfileHwModules (
    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 @@ audio_direct_mode_t AudioPolicyManager::getDirectPlaybackSupport(const audio_att
            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,7 +4596,8 @@ status_t AudioPolicyManager::setPreferredMixerAttributes(
    for (const auto& hwModule : mHwModules) {
        for (const auto& curProfile : hwModule->getOutputProfiles()) {
            if (curProfile->hasDynamicAudioProfile()
                    && curProfile->isCompatibleProfile(devices,
                    && curProfile->getCompatibilityScore(
                            devices,
                            mixerAttributes->config.sample_rate,
                            nullptr /*updatedSamplingRate*/,
                            mixerAttributes->config.format,
@@ -4604,7 +4605,8 @@ status_t AudioPolicyManager::setPreferredMixerAttributes(
                            mixerAttributes->config.channel_mask,
                            nullptr /*updatedChannelMask*/,
                            flags,
                                                       false /*exactMatchRequiredForInputFlags*/)) {
                            false /*exactMatchRequiredForInputFlags*/)
                            != IOProfile::NO_MATCH) {
                profile = curProfile;
                break;
            }
@@ -5009,14 +5011,15 @@ status_t AudioPolicyManager::createAudioPatchInternal(const struct audio_patch *
                return BAD_VALUE;
            }

            if (!outputDesc->mProfile->isCompatibleProfile(DeviceVector(devDesc),
            if (outputDesc->mProfile->getCompatibilityScore(
                    DeviceVector(devDesc),
                    patch->sources[0].sample_rate,
                                                           NULL,  // updatedSamplingRate
                    nullptr,  // updatedSamplingRate
                    patch->sources[0].format,
                                                           NULL,  // updatedFormat
                    nullptr,  // updatedFormat
                    patch->sources[0].channel_mask,
                                                           NULL,  // updatedChannelMask
                                                           AUDIO_OUTPUT_FLAG_NONE /*FIXME*/)) {
                    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 @@ status_t AudioPolicyManager::createAudioPatchInternal(const struct audio_patch *
                return BAD_VALUE;
            }

            if (!inputDesc->mProfile->isCompatibleProfile(DeviceVector(device),
            if (inputDesc->mProfile->getCompatibilityScore(
                    DeviceVector(device),
                    patch->sinks[0].sample_rate,
                                                          NULL, /*updatedSampleRate*/
                    nullptr, /*updatedSampleRate*/
                    patch->sinks[0].format,
                                                          NULL, /*updatedFormat*/
                    nullptr, /*updatedFormat*/
                    patch->sinks[0].channel_mask,
                                                          NULL, /*updatedChannelMask*/
                    nullptr, /*updatedChannelMask*/
                    // FIXME for the parameter type,
                    // and the NONE
                    (audio_output_flags_t)
                                                            AUDIO_INPUT_FLAG_NONE)) {
                    AUDIO_INPUT_FLAG_NONE) == IOProfile::NO_MATCH) {
                return INVALID_OPERATION;
            }
            // TODO: reconfigure output format and channels here
@@ -7694,9 +7698,6 @@ sp<IOProfile> AudioPolicyManager::getInputProfile(const sp<DeviceDescriptor> &de
    // 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,18 +7714,25 @@ sp<IOProfile> AudioPolicyManager::getInputProfile(const sp<DeviceDescriptor> &de
            for (const auto& profile : hwModule->getInputProfiles()) {
                // profile->log();
                //updatedFormat = format;
                if (profile->isCompatibleProfile(DeviceVector(device), samplingRate,
                                                 &samplingRate  /*updatedSamplingRate*/,
                if (profile->getCompatibilityScore(
                        DeviceVector(device),
                        samplingRate,
                        &updatedSamplingRate,
                        format,
                                                 &format,       /*updatedFormat*/
                        &updatedFormat,
                        channelMask,
                                                 &channelMask   /*updatedChannelMask*/,
                        &updatedChannelMask,
                        // FIXME ugly cast
                        (audio_output_flags_t) flags,
                                                 true /*exactMatchRequiredForInputFlags*/)) {
                        true /*exactMatchRequiredForInputFlags*/) == IOProfile::EXACT_MATCH) {
                    samplingRate = updatedSamplingRate;
                    format = updatedFormat;
                    channelMask = updatedChannelMask;
                    return profile;
                }
                if (firstInexact == nullptr && profile->isCompatibleProfile(DeviceVector(device),
                if (firstInexact == nullptr
                        && profile->getCompatibilityScore(
                                DeviceVector(device),
                                samplingRate,
                                &updatedSamplingRate,
                                format,
@@ -7733,7 +7741,8 @@ sp<IOProfile> AudioPolicyManager::getInputProfile(const sp<DeviceDescriptor> &de
                                &updatedChannelMask,
                                // FIXME ugly cast
                                (audio_output_flags_t) flags,
                                                 false /*exactMatchRequiredForInputFlags*/)) {
                                false /*exactMatchRequiredForInputFlags*/)
                                != IOProfile::NO_MATCH) {
                    firstInexact = profile;
                }
            }
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ class AudioPolicyTestManager : public AudioPolicyManager {
    using AudioPolicyManager::getConfig;
    using AudioPolicyManager::initialize;
    using AudioPolicyManager::getOutputs;
    using AudioPolicyManager::getInputs;
    using AudioPolicyManager::getAvailableOutputDevices;
    using AudioPolicyManager::getAvailableInputDevices;
    using AudioPolicyManager::setSurroundFormatEnabled;
+53 −0
Original line number Diff line number Diff line
@@ -92,6 +92,12 @@ AttributionSourceState createAttributionSourceState(uid_t uid) {
    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 @@ TEST_F(AudioPolicyManagerTestWithConfigurationFile, BitPerfectPlayback) {
                                                           "", "", 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;
Loading