CSD: Add interface for attenuating the MEL

The sound dose interface allows to set an attenuation used in the
internal MEL computation. This can be used for example when absolute
volume mode is used.

Test: dumpsys and logs
Bug: 265928284
Change-Id: If1d2c44dd670f9a63249bf7ce6c48e1cc509bcc9
Merged-In: If1d2c44dd670f9a63249bf7ce6c48e1cc509bcc9
diff --git a/services/audioflinger/sounddose/SoundDoseManager.cpp b/services/audioflinger/sounddose/SoundDoseManager.cpp
index 6f9e11f..3dbe8d9 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.cpp
+++ b/services/audioflinger/sounddose/SoundDoseManager.cpp
@@ -64,6 +64,10 @@
     if (streamProcessor != mActiveProcessors.end() &&
             (processor = streamProcessor->second.promote())) {
         ALOGV("%s: found callback for stream %d", __func__, streamHandle);
+        const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
+        if (activeTypeIt != mActiveDeviceTypes.end()) {
+            processor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
+        }
         processor->setDeviceId(deviceId);
         processor->setOutputRs2(mRs2Value);
         return processor;
@@ -71,6 +75,10 @@
         ALOGV("%s: creating new callback for device %d", __func__, streamHandle);
         sp<audio_utils::MelProcessor> melProcessor = sp<audio_utils::MelProcessor>::make(
                 sampleRate, channelCount, format, *this, deviceId, mRs2Value);
+        const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
+        if (activeTypeIt != mActiveDeviceTypes.end()) {
+            melProcessor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
+        }
         mActiveProcessors[streamHandle] = melProcessor;
         return melProcessor;
     }
@@ -174,6 +182,7 @@
     std::lock_guard _l(mLock);
     ALOGI("%s: map address: %s to device id: %d", __func__, adt.toString().c_str(), deviceId);
     mActiveDevices[adt] = deviceId;
+    mActiveDeviceTypes[deviceId] = adt.mType;
 }
 
 void SoundDoseManager::clearMapDeviceIdEntries(audio_port_handle_t deviceId) {
@@ -187,6 +196,7 @@
         }
         ++activeDevice;
     }
+    mActiveDeviceTypes.erase(deviceId);
 }
 
 ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
@@ -272,6 +282,15 @@
     return binder::Status::ok();
 }
 
+binder::Status SoundDoseManager::SoundDose::updateAttenuation(float attenuationDB, int device) {
+    ALOGV("%s", __func__);
+    auto soundDoseManager = mSoundDoseManager.promote();
+    if (soundDoseManager != nullptr) {
+        soundDoseManager->updateAttenuation(attenuationDB, static_cast<audio_devices_t>(device));
+    }
+    return binder::Status::ok();
+}
+
 binder::Status SoundDoseManager::SoundDose::getOutputRs2(float* value) {
     ALOGV("%s", __func__);
     auto soundDoseManager = mSoundDoseManager.promote();
@@ -310,6 +329,24 @@
     return binder::Status::ok();
 }
 
+void SoundDoseManager::updateAttenuation(float attenuationDB, audio_devices_t deviceType) {
+    std::lock_guard _l(mLock);
+    ALOGV("%s: updating MEL processor attenuation for device %d to %f",
+            __func__, deviceType, attenuationDB);
+    mMelAttenuationDB[deviceType] = attenuationDB;
+    for (const auto& mp : mActiveProcessors) {
+        auto melProcessor = mp.second.promote();
+        if (melProcessor != nullptr) {
+            auto deviceId = melProcessor->getDeviceId();
+            if (mActiveDeviceTypes[deviceId] == deviceType) {
+                ALOGV("%s: updating MEL processor attenuation for deviceId %d to %f",
+                        __func__, deviceId, attenuationDB);
+                melProcessor->setAttenuation(attenuationDB);
+            }
+        }
+    }
+}
+
 void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
     // invalidate any HAL sound dose interface used
     setHalSoundDoseInterface(nullptr);
diff --git a/services/audioflinger/sounddose/SoundDoseManager.h b/services/audioflinger/sounddose/SoundDoseManager.h
index c12efc3..f31a5d9 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.h
+++ b/services/audioflinger/sounddose/SoundDoseManager.h
@@ -95,9 +95,8 @@
     audio_port_handle_t getIdForAudioDevice(
             const aidl::android::media::audio::common::AudioDevice& audioDevice) const;
 
-    /** Caches mapping between address and device port id. */
-    void mapAddressToDeviceId(const AudioDeviceTypeAddr& adt,
-                              const audio_port_handle_t deviceId);
+    /** Caches mapping between address, device port id and device type. */
+    void mapAddressToDeviceId(const AudioDeviceTypeAddr& adt, const audio_port_handle_t deviceId);
 
     /** Clear all map entries with passed audio_port_handle_t. */
     void clearMapDeviceIdEntries(audio_port_handle_t deviceId);
@@ -133,10 +132,11 @@
         binder::Status setOutputRs2(float value) override;
         binder::Status resetCsd(float currentCsd,
                                 const std::vector<media::SoundDoseRecord>& records) override;
-        binder::Status getOutputRs2(float* value);
-        binder::Status getCsd(float* value);
-        binder::Status forceUseFrameworkMel(bool useFrameworkMel);
-        binder::Status forceComputeCsdOnAllDevices(bool computeCsdOnAllDevices);
+        binder::Status updateAttenuation(float attenuationDB, int device) override;
+        binder::Status getOutputRs2(float* value) override;
+        binder::Status getCsd(float* value) override;
+        binder::Status forceUseFrameworkMel(bool useFrameworkMel) override;
+        binder::Status forceComputeCsdOnAllDevices(bool computeCsdOnAllDevices) override;
 
         wp<SoundDoseManager> mSoundDoseManager;
         const sp<media::ISoundDoseCallback> mSoundDoseCallback;
@@ -163,6 +163,7 @@
 
     sp<media::ISoundDoseCallback> getSoundDoseCallback() const;
 
+    void updateAttenuation(float attenuationDB, audio_devices_t deviceType);
     void setUseFrameworkMel(bool useFrameworkMel);
     void setComputeCsdOnAllDevices(bool computeCsdOnAllDevices);
     /** Returns the HAL sound dose interface or null if internal MEL computation is used. */
@@ -180,8 +181,10 @@
     // logic for deviceId's that should not report MEL values (e.g.: do not have an active MUSIC
     // or GAME stream).
     std::map<AudioDeviceTypeAddr, audio_port_handle_t> mActiveDevices GUARDED_BY(mLock);
+    std::unordered_map<audio_port_handle_t, audio_devices_t> mActiveDeviceTypes GUARDED_BY(mLock);
 
     float mRs2Value GUARDED_BY(mLock);
+    std::unordered_map<audio_devices_t, float> mMelAttenuationDB GUARDED_BY(mLock);
 
     sp<SoundDose> mSoundDose GUARDED_BY(mLock);
 
diff --git a/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp b/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
index 4b1edf3..b18ca50 100644
--- a/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
+++ b/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
@@ -17,11 +17,16 @@
 // #define LOG_NDEBUG 0
 #define LOG_TAG "SoundDoseManager_tests"
 
+#include <SoundDoseManager.h>
+
 #include <aidl/android/hardware/audio/core/sounddose/BnSoundDose.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
-#include <SoundDoseManager.h>
+#if !defined(BACKEND_NDK)
+#define BACKEND_NDK
+#endif
+#include <media/AidlConversionCppNdk.h>
 
 namespace android {
 namespace {
@@ -199,26 +204,30 @@
 TEST_F(SoundDoseManagerTest, GetIdReturnsMappedAddress) {
     const std::string address = "testAddress";
     const audio_port_handle_t deviceId = 2;
-    const AudioDeviceTypeAddr adt{audio_devices_t{0}, address};
-    AudioDevice audioDevice;
-    audioDevice.address.set<AudioDeviceAddress::id>(address);
+    const audio_devices_t deviceType = AUDIO_DEVICE_OUT_WIRED_HEADSET;
+    const AudioDeviceTypeAddr adt{deviceType, address};
+    auto audioDevice = aidl::android::legacy2aidl_audio_device_AudioDevice(
+            deviceType, address.c_str());
+    ASSERT_TRUE(audioDevice.ok());
 
     mSoundDoseManager->mapAddressToDeviceId(adt, deviceId);
 
-    EXPECT_EQ(deviceId, mSoundDoseManager->getIdForAudioDevice(audioDevice));
+    EXPECT_EQ(deviceId, mSoundDoseManager->getIdForAudioDevice(audioDevice.value()));
 }
 
 TEST_F(SoundDoseManagerTest, GetAfterClearIdReturnsNone) {
     const std::string address = "testAddress";
-    const AudioDeviceTypeAddr adt {audio_devices_t{0}, address};
+    const audio_devices_t deviceType = AUDIO_DEVICE_OUT_WIRED_HEADSET;
+    const AudioDeviceTypeAddr adt{deviceType, address};
     const audio_port_handle_t deviceId = 2;
-    AudioDevice audioDevice;
-    audioDevice.address.set<AudioDeviceAddress::id>(address);
+    auto audioDevice = aidl::android::legacy2aidl_audio_device_AudioDevice(
+            deviceType, address.c_str());
+    ASSERT_TRUE(audioDevice.ok());
 
     mSoundDoseManager->mapAddressToDeviceId(adt, deviceId);
     mSoundDoseManager->clearMapDeviceIdEntries(deviceId);
 
-    EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, mSoundDoseManager->getIdForAudioDevice(audioDevice));
+    EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, mSoundDoseManager->getIdForAudioDevice(audioDevice.value()));
 }
 
 TEST_F(SoundDoseManagerTest, GetUnmappedIdReturnsHandleNone) {