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 Original line Diff line number Diff line
@@ -38,24 +38,21 @@ bool AudioFlinger::MelReporter::activateHalSoundDoseComputation(const std::strin


    ndk::SpAIBinder soundDoseBinder;
    ndk::SpAIBinder soundDoseBinder;
    if (device->getSoundDoseInterface(module, &soundDoseBinder) != OK) {
    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());
              __func__, module.c_str());
        activateInternalSoundDoseComputation();
        return false;
        return false;
    }
    }


    if (soundDoseBinder == nullptr) {
    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());
              __func__, module.c_str());
        activateInternalSoundDoseComputation();
        return false;
        return false;
    }
    }


    std::shared_ptr<ISoundDose> soundDoseInterface = ISoundDose::fromBinder(soundDoseBinder);
    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());
        ALOGW("%s: cannot activate HAL MEL reporting for module %s", __func__, module.c_str());
        activateInternalSoundDoseComputation();
        return false;
        return false;
    }
    }


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


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


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


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


        mHalSoundDose = halSoundDose;
        if (mHalSoundDose.find(module) != mHalSoundDose.end()) {
        if (halSoundDose == nullptr) {
            ALOGW("%s: Module %s already has a sound dose HAL assigned, skipping", __func__,
            ALOGI("%s: passed ISoundDose object is null, switching to internal CSD", __func__);
                  module.c_str());
            return false;
            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",
            ALOGW("%s: Cannot set RS2 value for momentary exposure %f",
                  __func__,
                  __func__,
                  mRs2UpperBound);
                  mRs2UpperBound);
@@ -119,16 +127,26 @@ bool SoundDoseManager::setHalSoundDoseInterface(const std::shared_ptr<ISoundDose
    return true;
    return true;
}
}


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

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

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


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

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


ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
        float in_currentDbA, const AudioDevice& in_audioDevice) {
        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) {
        if (soundDoseManager == nullptr) {
            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
        }
        }
    }


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


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


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


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


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


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


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


    /**
    /**
     * Sets the HAL sound dose interface to use for the MEL computation. Use nullptr
     * Sets the HAL sound dose interface for a specific module to use for the MEL computation.
     * for using the internal MEL computation.
     *
     *
     * @return true if setting the HAL sound dose value was successful, false otherwise.
     * @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. */
    /** Returns the cached audio port id from the active devices. */
    audio_port_handle_t getIdForAudioDevice(
    audio_port_handle_t getIdForAudioDevice(
@@ -193,6 +196,7 @@ private:
                const aidl::android::media::audio::common::AudioDevice& in_audioDevice) override;
                const aidl::android::media::audio::common::AudioDevice& in_audioDevice) override;


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


    void resetSoundDose();
    void resetSoundDose();
@@ -206,8 +210,11 @@ private:
    void setUseFrameworkMel(bool useFrameworkMel);
    void setUseFrameworkMel(bool useFrameworkMel);
    void setComputeCsdOnAllDevices(bool computeCsdOnAllDevices);
    void setComputeCsdOnAllDevices(bool computeCsdOnAllDevices);
    bool isSoundDoseHalSupported() const;
    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;
    mutable std::mutex mLock;


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


    sp<SoundDose> mSoundDose GUARDED_BY(mLock);
    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);
    std::shared_ptr<HalSoundDoseCallback> mHalSoundDoseCallback GUARDED_BY(mLock);


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


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


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


        ON_CALL(*mHalSoundDose.get(), setOutputRs2UpperBound)
        ON_CALL(*mHalSoundDose.get(), setOutputRs2UpperBound)
            .WillByDefault([] (float rs2) {
            .WillByDefault([] (float rs2) {
                EXPECT_EQ(rs2, ISoundDose::DEFAULT_MAX_RS2);
                EXPECT_EQ(rs2, ISoundDose::DEFAULT_MAX_RS2);
                return ndk::ScopedAStatus::ok();
                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<MelReporterCallback> mMelReporterCallback;
    sp<SoundDoseManager> mSoundDoseManager;
    sp<SoundDoseManager> mSoundDoseManager;
    std::shared_ptr<HalSoundDoseMock> mHalSoundDose;
    std::shared_ptr<HalSoundDoseMock> mHalSoundDose;
    std::shared_ptr<HalSoundDoseMock> mSecondaryHalSoundDose;
};
};


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


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


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


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


    EXPECT_EQ(nullptr, mSoundDoseManager->getOrCreateProcessorForDevice(/*deviceId=*/2,
    EXPECT_EQ(nullptr, mSoundDoseManager->getOrCreateProcessorForDevice(/*deviceId=*/2,
            /*streamHandle=*/1,
            /*streamHandle=*/1,
@@ -139,8 +148,17 @@ TEST_F(SoundDoseManagerTest, SetHalSoundDoseRegistersHalCallbacks) {
            EXPECT_NE(nullptr, callback);
            EXPECT_NE(nullptr, callback);
            return ndk::ScopedAStatus::ok();
            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) {
TEST_F(SoundDoseManagerTest, MomentaryExposureFromHalWithNoAddressIllegalArgument) {
@@ -154,7 +172,7 @@ TEST_F(SoundDoseManagerTest, MomentaryExposureFromHalWithNoAddressIllegalArgumen
           return ndk::ScopedAStatus::ok();
           return ndk::ScopedAStatus::ok();
       });
       });


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


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


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


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


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


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