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

Commit 05559cd8 authored by Vlad Popa's avatar Vlad Popa
Browse files

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
parent ab23a3fe
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -35,6 +35,19 @@ interface ISoundDose {
     */
    oneway void resetCsd(float currentCsd, in SoundDoseRecord[] records);

    /**
     * Updates the attenuation used for the MEL calculation when the volume is
     * not applied by the audio framework. This can be the case when for example
     * the absolute volume is used for a particular device.
     *
     * @param attenuationDB the attenuation as a negative value in dB that will
     *                      be applied for the internal MEL when computing CSD.
     *                      A value of 0 represents no attenuation for the MELs
     * @param device        the audio_devices_t type for which we will apply the
     *                      attenuation
     */
    oneway void updateAttenuation(float attenuationDB, int device);

    /* -------------------------- Test API methods --------------------------
    /** Get the currently used RS2 value. */
    float getOutputRs2();
+37 −0
Original line number Diff line number Diff line
@@ -64,6 +64,10 @@ sp<audio_utils::MelProcessor> SoundDoseManager::getOrCreateProcessorForDevice(
    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 @@ sp<audio_utils::MelProcessor> SoundDoseManager::getOrCreateProcessorForDevice(
        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 @@ void SoundDoseManager::mapAddressToDeviceId(const AudioDeviceTypeAddr& adt,
    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 @@ void SoundDoseManager::clearMapDeviceIdEntries(audio_port_handle_t deviceId) {
        }
        ++activeDevice;
    }
    mActiveDeviceTypes.erase(deviceId);
}

ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
@@ -272,6 +282,15 @@ binder::Status SoundDoseManager::SoundDose::resetCsd(
    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 @@ binder::Status SoundDoseManager::SoundDose::forceComputeCsdOnAllDevices(
    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);
+10 −7
Original line number Diff line number Diff line
@@ -95,9 +95,8 @@ public:
    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 @@ private:
        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 @@ private:

    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 @@ private:
    // 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);

+18 −9
Original line number Diff line number Diff line
@@ -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, OnNewMelValuesFromHalWithNoAddressIllegalArgument)
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) {