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

Commit 08c8c4b8 authored by Vlad Popa's avatar Vlad Popa
Browse files

CSD: add support for multiple sound dose HALs

Initial implementation to support multiple sound dose HALs. Also not
falling back to internal MELs in case one module is not supporting the
sound dose HAL

Test: manual + atest sounddosemanager_tests
Bug: 297057693
Merged-In: I7941e34c08496781f4393358d1ce2845d525b86c
Change-Id: I7941e34c08496781f4393358d1ce2845d525b86c
parent efa8c657
Loading
Loading
Loading
Loading
+8 −7
Original line number Diff line number Diff line
@@ -38,24 +38,21 @@ bool AudioFlinger::MelReporter::activateHalSoundDoseComputation(const std::strin

    ndk::SpAIBinder soundDoseBinder;
    if (device->getSoundDoseInterface(module, &soundDoseBinder) != OK) {
        ALOGW("%s: HAL cannot provide sound dose interface for module %s, use internal MEL",
        ALOGW("%s: HAL cannot provide sound dose interface for module %s",
              __func__, module.c_str());
        activateInternalSoundDoseComputation();
        return false;
    }

    if (soundDoseBinder == nullptr) {
         ALOGW("%s: HAL doesn't implement a sound dose interface for module %s, use internal MEL",
         ALOGW("%s: HAL doesn't implement a sound dose interface for module %s",
              __func__, module.c_str());
        activateInternalSoundDoseComputation();
        return false;
    }

    std::shared_ptr<ISoundDose> soundDoseInterface = ISoundDose::fromBinder(soundDoseBinder);

    if (!mSoundDoseManager->setHalSoundDoseInterface(soundDoseInterface)) {
    if (!mSoundDoseManager->setHalSoundDoseInterface(module, soundDoseInterface)) {
        ALOGW("%s: cannot activate HAL MEL reporting for module %s", __func__, module.c_str());
        activateInternalSoundDoseComputation();
        return false;
    }

@@ -73,7 +70,8 @@ void AudioFlinger::MelReporter::activateInternalSoundDoseComputation() {
        mUseHalSoundDoseInterface = false;
    }

    mSoundDoseManager->setHalSoundDoseInterface(nullptr);
    // reset the HAL interfaces and use internal MELs
    mSoundDoseManager->resetHalSoundDoseInterfaces();
}

void AudioFlinger::MelReporter::onFirstRef() {
@@ -251,6 +249,9 @@ sp<media::ISoundDose> AudioFlinger::MelReporter::getSoundDoseInterface(
void AudioFlinger::MelReporter::stopInternalMelComputation() {
    ALOGV("%s", __func__);
    std::lock_guard _l(mLock);
    if (mUseHalSoundDoseInterface) {
        return;
    }
    mActiveMelPatches.clear();
    mUseHalSoundDoseInterface = true;
}
+50 −33
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ sp<audio_utils::MelProcessor> SoundDoseManager::getOrCreateProcessorForDevice(
        size_t channelCount, audio_format_t format) {
    std::lock_guard _l(mLock);

    if (mHalSoundDose != nullptr && mEnabledCsd) {
    if (mHalSoundDose.size() > 0 && mEnabledCsd) {
        ALOGD("%s: using HAL MEL computation, no MelProcessor needed.", __func__);
        return nullptr;
    }
@@ -83,19 +83,27 @@ sp<audio_utils::MelProcessor> SoundDoseManager::getOrCreateProcessorForDevice(
    return melProcessor;
}

bool SoundDoseManager::setHalSoundDoseInterface(const std::shared_ptr<ISoundDose>& halSoundDose) {
bool SoundDoseManager::setHalSoundDoseInterface(const std::string &module,
                                                const std::shared_ptr<ISoundDose> &halSoundDose) {
    ALOGV("%s", __func__);

    if (halSoundDose == nullptr) {
        ALOGI("%s: passed ISoundDose object is null", __func__);
        return false;
    }

    std::shared_ptr<HalSoundDoseCallback> halSoundDoseCallback;
    {
        std::lock_guard _l(mLock);

        mHalSoundDose = halSoundDose;
        if (halSoundDose == nullptr) {
            ALOGI("%s: passed ISoundDose object is null, switching to internal CSD", __func__);
        if (mHalSoundDose.find(module) != mHalSoundDose.end()) {
            ALOGW("%s: Module %s already has a sound dose HAL assigned, skipping", __func__,
                  module.c_str());
            return false;
        }
        mHalSoundDose[module] = halSoundDose;

        if (!mHalSoundDose->setOutputRs2UpperBound(mRs2UpperBound).isOk()) {
        if (!halSoundDose->setOutputRs2UpperBound(mRs2UpperBound).isOk()) {
            ALOGW("%s: Cannot set RS2 value for momentary exposure %f",
                  __func__,
                  mRs2UpperBound);
@@ -119,16 +127,26 @@ bool SoundDoseManager::setHalSoundDoseInterface(const std::shared_ptr<ISoundDose
    return true;
}

void SoundDoseManager::resetHalSoundDoseInterfaces() {
    ALOGV("%s", __func__);

    const std::lock_guard _l(mLock);
    mHalSoundDose.clear();
}

void SoundDoseManager::setOutputRs2UpperBound(float rs2Value) {
    ALOGV("%s", __func__);
    std::lock_guard _l(mLock);

    if (mHalSoundDose != nullptr) {
    if (mHalSoundDose.size() > 0) {
        for (auto& halSoundDose : mHalSoundDose) {
            // using the HAL sound dose interface
        if (!mHalSoundDose->setOutputRs2UpperBound(rs2Value).isOk()) {
            if (!halSoundDose.second->setOutputRs2UpperBound(rs2Value).isOk()) {
                ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
            return;
                continue;
            }
        }

        mRs2UpperBound = rs2Value;
        return;
    }
@@ -200,14 +218,16 @@ void SoundDoseManager::clearMapDeviceIdEntries(audio_port_handle_t deviceId) {

ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
        float in_currentDbA, const AudioDevice& in_audioDevice) {
    auto soundDoseManager = mSoundDoseManager.promote();
    sp<SoundDoseManager> soundDoseManager;
    {
        const std::lock_guard _l(mCbLock);
        soundDoseManager = mSoundDoseManager.promote();
        if (soundDoseManager == nullptr) {
            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
        }
    }

    std::shared_ptr<ISoundDose> halSoundDose;
    soundDoseManager->getHalSoundDose(&halSoundDose);
    if(halSoundDose == nullptr) {
    if (!soundDoseManager->useHalSoundDose()) {
        ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
@@ -227,14 +247,16 @@ ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWa
ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onNewMelValues(
        const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
        const AudioDevice& in_audioDevice) {
    auto soundDoseManager = mSoundDoseManager.promote();
    sp<SoundDoseManager> soundDoseManager;
    {
        const std::lock_guard _l(mCbLock);
        soundDoseManager = mSoundDoseManager.promote();
        if (soundDoseManager == nullptr) {
            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
        }
    }

    std::shared_ptr<ISoundDose> halSoundDose;
    soundDoseManager->getHalSoundDose(&halSoundDose);
    if(halSoundDose == nullptr) {
    if (!soundDoseManager->useHalSoundDose()) {
        ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
@@ -508,7 +530,7 @@ bool SoundDoseManager::shouldComputeCsdForDeviceWithAddress(const audio_devices_

void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
    // invalidate any HAL sound dose interface used
    setHalSoundDoseInterface(nullptr);
    resetHalSoundDoseInterfaces();

    std::lock_guard _l(mLock);
    mUseFrameworkMel = useFrameworkMel;
@@ -534,17 +556,12 @@ bool SoundDoseManager::isSoundDoseHalSupported() const {
        return false;
    }

    std::shared_ptr<ISoundDose> halSoundDose;
    getHalSoundDose(&halSoundDose);
    if (mHalSoundDose == nullptr) {
        return false;
    }
    return true;
    return useHalSoundDose();
}

void SoundDoseManager::getHalSoundDose(std::shared_ptr<ISoundDose>* halSoundDose) const {
    std::lock_guard _l(mLock);
    *halSoundDose = mHalSoundDose;
bool SoundDoseManager::useHalSoundDose() const {
    const std::lock_guard _l(mLock);
    return mHalSoundDose.size() > 0;
}

void SoundDoseManager::resetSoundDose() {
+13 −6
Original line number Diff line number Diff line
@@ -94,12 +94,15 @@ public:
    sp<media::ISoundDose> getSoundDoseInterface(const sp<media::ISoundDoseCallback>& callback);

    /**
     * Sets the HAL sound dose interface to use for the MEL computation. Use nullptr
     * for using the internal MEL computation.
     * Sets the HAL sound dose interface for a specific module to use for the MEL computation.
     *
     * @return true if setting the HAL sound dose value was successful, false otherwise.
     */
    bool setHalSoundDoseInterface(const std::shared_ptr<ISoundDose>& halSoundDose);
    bool setHalSoundDoseInterface(const std::string &module,
                                  const std::shared_ptr<ISoundDose> &halSoundDose);

    /** Reset all the stored HAL sound dose interface. */
    void resetHalSoundDoseInterfaces();

    /** Returns the cached audio port id from the active devices. */
    audio_port_handle_t getIdForAudioDevice(
@@ -193,6 +196,7 @@ private:
                const aidl::android::media::audio::common::AudioDevice& in_audioDevice) override;

        wp<SoundDoseManager> mSoundDoseManager;
        std::mutex mCbLock;
    };

    void resetSoundDose();
@@ -206,8 +210,11 @@ private:
    void setUseFrameworkMel(bool useFrameworkMel);
    void setComputeCsdOnAllDevices(bool computeCsdOnAllDevices);
    bool isSoundDoseHalSupported() const;
    /** Returns the HAL sound dose interface or null if internal MEL computation is used. */
    void getHalSoundDose(std::shared_ptr<ISoundDose>* halSoundDose) const;
    /**
     * Returns true if there is one active HAL sound dose interface or null if internal MEL
     * computation is used.
     **/
    bool useHalSoundDose() const;

    mutable std::mutex mLock;

@@ -241,7 +248,7 @@ private:

    sp<SoundDose> mSoundDose GUARDED_BY(mLock);

    std::shared_ptr<ISoundDose> mHalSoundDose GUARDED_BY(mLock);
    std::unordered_map<std::string, std::shared_ptr<ISoundDose>> mHalSoundDose GUARDED_BY(mLock);
    std::shared_ptr<HalSoundDoseCallback> mHalSoundDoseCallback GUARDED_BY(mLock);

    bool mUseFrameworkMel GUARDED_BY(mLock) = false;
+25 −7
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ public:
    MOCK_METHOD(void, stopMelComputationForDeviceId, (audio_port_handle_t), (override));
};

constexpr char kPrimaryModule[] = "primary";
constexpr char kSecondaryModule[] = "secondary";

class SoundDoseManagerTest : public ::testing::Test {
protected:
@@ -52,17 +54,24 @@ protected:
        mMelReporterCallback = sp<MelReporterCallback>::make();
        mSoundDoseManager = sp<SoundDoseManager>::make(mMelReporterCallback);
        mHalSoundDose = ndk::SharedRefBase::make<HalSoundDoseMock>();
        mSecondaryHalSoundDose = ndk::SharedRefBase::make<HalSoundDoseMock>();

        ON_CALL(*mHalSoundDose.get(), setOutputRs2UpperBound)
            .WillByDefault([] (float rs2) {
                EXPECT_EQ(rs2, ISoundDose::DEFAULT_MAX_RS2);
                return ndk::ScopedAStatus::ok();
            });
        ON_CALL(*mSecondaryHalSoundDose.get(), setOutputRs2UpperBound)
                .WillByDefault([] (float rs2) {
                    EXPECT_EQ(rs2, ISoundDose::DEFAULT_MAX_RS2);
                    return ndk::ScopedAStatus::ok();
                });
    }

    sp<MelReporterCallback> mMelReporterCallback;
    sp<SoundDoseManager> mSoundDoseManager;
    std::shared_ptr<HalSoundDoseMock> mHalSoundDose;
    std::shared_ptr<HalSoundDoseMock> mSecondaryHalSoundDose;
};

TEST_F(SoundDoseManagerTest, GetProcessorForExistingStream) {
@@ -110,7 +119,7 @@ TEST_F(SoundDoseManagerTest, NewMelValuesCacheNewRecord) {
}

TEST_F(SoundDoseManagerTest, InvalidHalInterfaceIsNotSet) {
    EXPECT_FALSE(mSoundDoseManager->setHalSoundDoseInterface(nullptr));
    EXPECT_FALSE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, nullptr));
}

TEST_F(SoundDoseManagerTest, SetHalSoundDoseDisablesNewMelProcessorCallbacks) {
@@ -122,7 +131,7 @@ TEST_F(SoundDoseManagerTest, SetHalSoundDoseDisablesNewMelProcessorCallbacks) {
            return ndk::ScopedAStatus::ok();
        });

    EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
    EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));

    EXPECT_EQ(nullptr, mSoundDoseManager->getOrCreateProcessorForDevice(/*deviceId=*/2,
            /*streamHandle=*/1,
@@ -139,8 +148,17 @@ TEST_F(SoundDoseManagerTest, SetHalSoundDoseRegistersHalCallbacks) {
            EXPECT_NE(nullptr, callback);
            return ndk::ScopedAStatus::ok();
        });
    EXPECT_CALL(*mSecondaryHalSoundDose.get(), setOutputRs2UpperBound).Times(1);
    EXPECT_CALL(*mSecondaryHalSoundDose.get(), registerSoundDoseCallback)
            .Times(1)
            .WillOnce([&] (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& callback) {
                EXPECT_NE(nullptr, callback);
                return ndk::ScopedAStatus::ok();
        });

    EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
    EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));
    EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kSecondaryModule,
                                                            mSecondaryHalSoundDose));
}

TEST_F(SoundDoseManagerTest, MomentaryExposureFromHalWithNoAddressIllegalArgument) {
@@ -154,7 +172,7 @@ TEST_F(SoundDoseManagerTest, MomentaryExposureFromHalWithNoAddressIllegalArgumen
           return ndk::ScopedAStatus::ok();
       });

    EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
    EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));

    EXPECT_NE(nullptr, halCallback);
    AudioDevice audioDevice = {};
@@ -175,9 +193,9 @@ TEST_F(SoundDoseManagerTest, MomentaryExposureFromHalAfterInternalSelectedReturn
           return ndk::ScopedAStatus::ok();
       });

    EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
    EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));
    EXPECT_NE(nullptr, halCallback);
    EXPECT_FALSE(mSoundDoseManager->setHalSoundDoseInterface(nullptr));
    mSoundDoseManager->resetHalSoundDoseInterfaces();

    AudioDevice audioDevice = {};
    audioDevice.address.set<AudioDeviceAddress::id>("test");
@@ -197,7 +215,7 @@ TEST_F(SoundDoseManagerTest, OnNewMelValuesFromHalWithNoAddressIllegalArgument)
           return ndk::ScopedAStatus::ok();
       });

    EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
    EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));

    EXPECT_NE(nullptr, halCallback);
    AudioDevice audioDevice = {};