Merge "CSD: add support for multiple sound dose HALs" into udc-qpr-dev-plus-aosp
diff --git a/services/audioflinger/MelReporter.cpp b/services/audioflinger/MelReporter.cpp
index 64a5843..77bd45b 100644
--- a/services/audioflinger/MelReporter.cpp
+++ b/services/audioflinger/MelReporter.cpp
@@ -38,24 +38,21 @@
 
     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 @@
         mUseHalSoundDoseInterface = false;
     }
 
-    mSoundDoseManager->setHalSoundDoseInterface(nullptr);
+    // reset the HAL interfaces and use internal MELs
+    mSoundDoseManager->resetHalSoundDoseInterfaces();
 }
 
 void MelReporter::onFirstRef() {
@@ -247,6 +245,9 @@
 void MelReporter::stopInternalMelComputation() {
     ALOGV("%s", __func__);
     std::lock_guard _l(mLock);
+    if (mUseHalSoundDoseInterface) {
+        return;
+    }
     mActiveMelPatches.clear();
     mUseHalSoundDoseInterface = true;
 }
diff --git a/services/audioflinger/sounddose/SoundDoseManager.cpp b/services/audioflinger/sounddose/SoundDoseManager.cpp
index 97470a2..097ce50 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.cpp
+++ b/services/audioflinger/sounddose/SoundDoseManager.cpp
@@ -49,7 +49,7 @@
         size_t channelCount, audio_format_t format) {
     const 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;
     }
@@ -82,20 +82,27 @@
     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;
     {
         const 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);
@@ -121,16 +128,26 @@
     return true;
 }
 
+void SoundDoseManager::resetHalSoundDoseInterfaces() {
+    ALOGV("%s", __func__);
+
+    const std::lock_guard _l(mLock);
+    mHalSoundDose.clear();
+}
+
 void SoundDoseManager::setOutputRs2UpperBound(float rs2Value) {
     ALOGV("%s", __func__);
     const std::lock_guard _l(mLock);
 
-    if (mHalSoundDose != nullptr) {
-        // using the HAL sound dose interface
-        if (!mHalSoundDose->setOutputRs2UpperBound(rs2Value).isOk()) {
-            ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
-            return;
+    if (mHalSoundDose.size() > 0) {
+        for (auto& halSoundDose : mHalSoundDose) {
+            // using the HAL sound dose interface
+            if (!halSoundDose.second->setOutputRs2UpperBound(rs2Value).isOk()) {
+                ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
+                continue;
+            }
         }
+
         mRs2UpperBound = rs2Value;
         return;
     }
@@ -202,14 +219,16 @@
 
 ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
         float in_currentDbA, const AudioDevice& in_audioDevice) {
-    auto soundDoseManager = mSoundDoseManager.promote();
-    if (soundDoseManager == nullptr) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    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);
     }
@@ -229,14 +248,16 @@
 ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onNewMelValues(
         const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
         const AudioDevice& in_audioDevice) {
-    auto soundDoseManager = mSoundDoseManager.promote();
-    if (soundDoseManager == nullptr) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    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);
     }
@@ -510,7 +531,7 @@
 
 void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
     // invalidate any HAL sound dose interface used
-    setHalSoundDoseInterface(nullptr);
+    resetHalSoundDoseInterfaces();
 
     const std::lock_guard _l(mLock);
     mUseFrameworkMel = useFrameworkMel;
@@ -537,14 +558,12 @@
         if (!mEnabledCsd) return false;
     }
 
-    std::shared_ptr<ISoundDose> halSoundDose;
-    getHalSoundDose(&halSoundDose);
-    return halSoundDose != nullptr;
+    return useHalSoundDose();
 }
 
-void SoundDoseManager::getHalSoundDose(std::shared_ptr<ISoundDose>* halSoundDose) const {
+bool SoundDoseManager::useHalSoundDose() const {
     const std::lock_guard _l(mLock);
-    *halSoundDose = mHalSoundDose;
+    return mHalSoundDose.size() > 0;
 }
 
 void SoundDoseManager::resetSoundDose() {
diff --git a/services/audioflinger/sounddose/SoundDoseManager.h b/services/audioflinger/sounddose/SoundDoseManager.h
index b5a1362..6e0bc34 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.h
+++ b/services/audioflinger/sounddose/SoundDoseManager.h
@@ -94,12 +94,15 @@
     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 @@
                 const aidl::android::media::audio::common::AudioDevice& in_audioDevice) override;
 
         wp<SoundDoseManager> mSoundDoseManager;
+        std::mutex mCbLock;
     };
 
     void resetSoundDose();
@@ -206,8 +210,11 @@
     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 @@
 
     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;
diff --git a/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp b/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
index 5860d96..5f6dcb9 100644
--- a/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
+++ b/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
@@ -45,6 +45,8 @@
     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 @@
         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, InvalidHalInterfaceIsNotSet) {
-    EXPECT_FALSE(mSoundDoseManager->setHalSoundDoseInterface(nullptr));
+    EXPECT_FALSE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, nullptr));
 }
 
 TEST_F(SoundDoseManagerTest, SetHalSoundDoseDisablesNewMelProcessorCallbacks) {
@@ -122,7 +131,7 @@
             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 @@
             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 @@
            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 @@
            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 @@
            return ndk::ScopedAStatus::ok();
        });
 
-    EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
+    EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));
 
     EXPECT_NE(nullptr, halCallback);
     AudioDevice audioDevice = {};