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

Commit cd5fe6b0 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Audio policy: fix input preemption logic" into main

parents d21945cb c71b11be
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -41,7 +41,8 @@ class AudioInputDescriptor: public AudioPortConfig,
{
public:
    AudioInputDescriptor(const sp<IOProfile>& profile,
                         AudioPolicyClientInterface *clientInterface);
                         AudioPolicyClientInterface *clientInterface,
                         bool isPreemptor);

    virtual ~AudioInputDescriptor() = default;

@@ -127,6 +128,8 @@ public:
    // active use case
    void checkSuspendEffects();

    bool isPreemptor() const { return mIsPreemptor; }

 private:

    void updateClientRecordingConfiguration(int event, const sp<RecordClientDescriptor>& client);
@@ -145,6 +148,7 @@ public:
    int32_t mGlobalActiveCount = 0;  // non-client-specific activity ref count
    EffectDescriptorCollection mEnabledEffects;
    audio_input_flags_t& mFlags = AudioPortConfig::mFlags.input;
    bool mIsPreemptor; // true if this input was opened after preemting another one
};

class AudioInputCollection :
+6 −2
Original line number Diff line number Diff line
@@ -30,9 +30,10 @@
namespace android {

AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile,
                                           AudioPolicyClientInterface *clientInterface)
                                           AudioPolicyClientInterface *clientInterface,
                                           bool isPreemptor)
    : mProfile(profile)
    ,  mClientInterface(clientInterface)
    ,  mClientInterface(clientInterface), mIsPreemptor(isPreemptor)
{
    if (profile != NULL) {
        profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
@@ -275,6 +276,9 @@ void AudioInputDescriptor::stop()
                            "%s invalid profile active count %u",
                            __func__, mProfile->curActiveCount);
        mProfile->curActiveCount--;
        // allow preemption again now that at least one client was able to
        // capture on this input
        mIsPreemptor = false;
    }
}

+100 −28
Original line number Diff line number Diff line
@@ -3125,7 +3125,77 @@ audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescripto
        }
    }

    bool isPreemptor = false;
    if (!profile->canOpenNewIo()) {
        if (com::android::media::audioserver::fix_input_sharing_logic()) {
            //  First pick best candidate for preemption (there may not be any):
            //  - Preempt and input if:
            //     - It has only strictly lower priority use cases than the new client
            //     - It has equal priority use cases than the new client, was not
            //     opened thanks to preemption or has been active since opened.
            //  - Order the preemption candidates by inactive first and priority second
            sp<AudioInputDescriptor> closeCandidate;
            int leastCloseRank = INT_MAX;
            static const int sCloseActive = 0x100;

            for (size_t i = 0; i < mInputs.size(); i++) {
                sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
                if (desc->mProfile != profile) {
                    continue;
                }
                sp<RecordClientDescriptor> topPrioClient = desc->getHighestPriorityClient();
                if (topPrioClient == nullptr) {
                    continue;
                }
                int topPrio = source_priority(topPrioClient->source());
                if (topPrio < source_priority(attributes.source)
                      || (topPrio == source_priority(attributes.source)
                          && !desc->isPreemptor())) {
                    int closeRank = (desc->isActive() ? sCloseActive : 0) + topPrio;
                    if (closeRank < leastCloseRank) {
                        leastCloseRank = closeRank;
                        closeCandidate = desc;
                    }
                }
            }

            if (closeCandidate != nullptr) {
                closeInput(closeCandidate->mIoHandle);
                // Mark the new input as being issued from a preemption
                // so that is will not be preempted later
                isPreemptor = true;
            } else {
                // Then pick the best reusable input (There is always one)
                // The order of preference is:
                // 1) active inputs with same use case as the new client
                // 2) inactive inputs with same use case
                // 3) active inputs with different use cases
                // 4) inactive inputs with different use cases
                sp<AudioInputDescriptor> reuseCandidate;
                int leastReuseRank = INT_MAX;
                static const int sReuseDifferentUseCase = 0x100;

                for (size_t i = 0; i < mInputs.size(); i++) {
                    sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
                    if (desc->mProfile != profile) {
                        continue;
                    }
                    int reuseRank = sReuseDifferentUseCase;
                    for (const auto& client: desc->getClientIterable()) {
                        if (client->source() == attributes.source) {
                            reuseRank = 0;
                            break;
                        }
                    }
                    reuseRank += desc->isActive() ? 0 : 1;
                    if (reuseRank < leastReuseRank) {
                        leastReuseRank = reuseRank;
                        reuseCandidate = desc;
                    }
                }
                return reuseCandidate->mIoHandle;
            }
        } else { // fix_input_sharing_logic()
            for (size_t i = 0; i < mInputs.size(); ) {
                 sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
                 if (desc->mProfile != profile) {
@@ -3160,8 +3230,10 @@ audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescripto
                }
            }
        }
    }

    sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(profile, mpClientInterface);
    sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(
            profile, mpClientInterface, isPreemptor);

    audio_config_t lConfig = AUDIO_CONFIG_INITIALIZER;
    lConfig.sample_rate = profileSamplingRate;
@@ -6672,8 +6744,8 @@ void AudioPolicyManager::onNewAudioModulesAvailableInt(DeviceVector *newDevices)
                    __func__, inProfile->getTagName().c_str());
                continue;
            }
            sp<AudioInputDescriptor> inputDesc =
                    new AudioInputDescriptor(inProfile, mpClientInterface);
            sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(
                    inProfile, mpClientInterface, false /*isPreemptor*/);

            audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
            status_t status = inputDesc->open(nullptr,
@@ -6983,7 +7055,7 @@ status_t AudioPolicyManager::checkInputsForDevice(const sp<DeviceDescriptor>& de
                continue;
            }

            desc = new AudioInputDescriptor(profile, mpClientInterface);
            desc = new AudioInputDescriptor(profile, mpClientInterface, false  /*isPreemptor*/);
            audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
            status = desc->open(nullptr, device, AUDIO_SOURCE_MIC, AUDIO_INPUT_FLAG_NONE, &input);

+16 −0
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ public:
        *input = mNextIoHandle++;
        mOpenedInputs.insert(*input);
        ALOGD("%s: opened input %d", __func__, *input);
        mOpenInputCallsCount++;
        return NO_ERROR;
    }

@@ -86,6 +87,7 @@ public:
            return BAD_VALUE;
        }
        ALOGD("%s: closed input %d", __func__, input);
        mCloseInputCallsCount++;
        return NO_ERROR;
    }

@@ -260,6 +262,18 @@ public:
        auto it = mTracksInternalMute.find(portId);
        return it == mTracksInternalMute.end() ? false : it->second;
    }
    void resetInputApiCallsCounters() {
        mOpenInputCallsCount = 0;
        mCloseInputCallsCount = 0;
    }

    size_t getCloseInputCallsCount() const {
        return mCloseInputCallsCount;
    }

    size_t getOpenInputCallsCount() const {
        return mOpenInputCallsCount;
    }

private:
    audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
@@ -275,6 +289,8 @@ private:
    std::set<audio_channel_mask_t> mSupportedChannelMasks;
    std::map<audio_port_handle_t, bool> mTracksInternalMute;
    std::set<audio_io_handle_t> mOpenedInputs;
    size_t mOpenInputCallsCount = 0;
    size_t mCloseInputCallsCount = 0;
};

} // namespace android
+89 −0
Original line number Diff line number Diff line
@@ -3830,3 +3830,92 @@ INSTANTIATE_TEST_CASE_P(
        testing::Values(AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
                        AUDIO_USAGE_ALARM)
);

class AudioPolicyManagerInputPreemptionTest : public AudioPolicyManagerTestWithConfigurationFile {
};

TEST_F_WITH_FLAGS(
        AudioPolicyManagerInputPreemptionTest,
        SameSessionReusesInput,
        REQUIRES_FLAGS_ENABLED(
                ACONFIG_FLAG(com::android::media::audioserver, fix_input_sharing_logic))
) {
    mClient->resetInputApiCallsCounters();

    audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
    attr.source = AUDIO_SOURCE_MIC;
    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
    audio_io_handle_t input1 = AUDIO_PORT_HANDLE_NONE;
    ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input1, TEST_SESSION_ID, 1, &selectedDeviceId,
                                            AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
                                            48000));

    EXPECT_EQ(1, mClient->getOpenInputCallsCount());

    audio_io_handle_t input2 = AUDIO_PORT_HANDLE_NONE;
    ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input2, TEST_SESSION_ID, 1, &selectedDeviceId,
                                        AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
                                        48000));

    EXPECT_EQ(1, mClient->getOpenInputCallsCount());
    EXPECT_EQ(0, mClient->getCloseInputCallsCount());
    EXPECT_EQ(input1, input2);
}

TEST_F_WITH_FLAGS(
        AudioPolicyManagerInputPreemptionTest,
        LesserPriorityReusesInput,
        REQUIRES_FLAGS_ENABLED(
                ACONFIG_FLAG(com::android::media::audioserver, fix_input_sharing_logic))
) {
    mClient->resetInputApiCallsCounters();

    audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
    attr.source = AUDIO_SOURCE_MIC;
    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
    audio_io_handle_t input1 = AUDIO_PORT_HANDLE_NONE;
    ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input1, TEST_SESSION_ID, 1, &selectedDeviceId,
                                            AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
                                            48000));

    EXPECT_EQ(1, mClient->getOpenInputCallsCount());

    audio_io_handle_t input2 = AUDIO_PORT_HANDLE_NONE;
    attr.source = AUDIO_SOURCE_VOICE_RECOGNITION;
    ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input2, OTHER_SESSION_ID, 1, &selectedDeviceId,
                                        AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
                                        48000));

    EXPECT_EQ(1, mClient->getOpenInputCallsCount());
    EXPECT_EQ(0, mClient->getCloseInputCallsCount());
    EXPECT_EQ(input1, input2);
}

TEST_F_WITH_FLAGS(
        AudioPolicyManagerInputPreemptionTest,
        HigherPriorityPreemptsInput,
        REQUIRES_FLAGS_ENABLED(
                ACONFIG_FLAG(com::android::media::audioserver, fix_input_sharing_logic))
) {
    mClient->resetInputApiCallsCounters();

    audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
    attr.source = AUDIO_SOURCE_MIC;
    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
    audio_io_handle_t input1 = AUDIO_PORT_HANDLE_NONE;
    ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input1, TEST_SESSION_ID, 1, &selectedDeviceId,
                                            AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
                                            48000));

    EXPECT_EQ(1, mClient->getOpenInputCallsCount());

    audio_io_handle_t input2 = AUDIO_PORT_HANDLE_NONE;
    attr.source = AUDIO_SOURCE_CAMCORDER;
    ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input2, OTHER_SESSION_ID, 1, &selectedDeviceId,
                                        AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
                                        48000));

    EXPECT_EQ(2, mClient->getOpenInputCallsCount());
    EXPECT_EQ(1, mClient->getCloseInputCallsCount());
    EXPECT_NE(input1, input2);
}
Loading