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

Commit 1d5f0d5c authored by Vlad Popa's avatar Vlad Popa
Browse files

CSD: add logic for using HAL sound dose values

When the HAL supports the sound dose computation we prefer to use the
MEL value provided by the HAL. These should be more accurate and can be
used for certification with IEC62368-1 3rd edition and EN50332-3.
Current implementation supports the standalone sound dose HAL.

Test: sounddosemanager_tests UT & bluejay-userdebug with internal MEL
Bug: 252776298
Change-Id: Ibbda76781fc869ac457d03d4f9a871fb353a9ba8
parent 9321ea07
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ cc_library_shared {

    defaults: [
        "latest_android_media_audio_common_types_cpp_shared",
        "latest_android_hardware_audio_sounddose_ndk_shared",
    ],

    srcs: [
@@ -76,6 +77,7 @@ cc_library_shared {
        "libutils",
        "liblog",
        "libbinder",
        "libbinder_ndk",
        "libaudioclient",
        "libaudiomanager",
        "libmedialogservice",
@@ -105,11 +107,11 @@ cc_library_shared {
        "libaudiohal_headers",
        "libaudioutils_headers",
        "libmedia_headers",
        "libsounddose_headers",
    ],

    export_shared_lib_headers: [
        "libpermission",
        "android.hardware.audio.sounddose-V1-ndk",
    ],

    cflags: [
+3 −0
Original line number Diff line number Diff line
@@ -2573,6 +2573,9 @@ audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
        ALOGE("loadHwModule() error %d loading module %s", rc, name);
        return AUDIO_MODULE_HANDLE_NONE;
    }
    if (!mMelReporter->activateHalSoundDoseComputation(name)) {
        ALOGW("loadHwModule() sound dose reporting is not available");
    }

    mHardwareStatus = AUDIO_HW_INIT;
    rc = dev->initCheck();
+1 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include <sys/types.h>
#include <limits.h>

#include <aidl/android/hardware/audio/sounddose/ISoundDoseFactory.h>
#include <android/media/BnAudioTrack.h>
#include <android/media/IAudioFlingerClient.h>
#include <android/media/IAudioTrackCallback.h>
+118 −20
Original line number Diff line number Diff line
@@ -22,12 +22,73 @@

#include <android/media/ISoundDoseCallback.h>
#include <audio_utils/power.h>
#include <android/binder_manager.h>
#include <utils/Log.h>

using aidl::android::hardware::audio::core::ISoundDose;
using aidl::android::hardware::audio::sounddose::ISoundDoseFactory;

namespace android {

constexpr std::string_view kSoundDoseInterfaceModule = "/default";

bool AudioFlinger::MelReporter::activateHalSoundDoseComputation(const std::string& module) {
    if (mSoundDoseFactory == nullptr) {
        ALOGW("%s sound dose HAL reporting not available", __func__);
        activateInternalSoundDoseComputation();
        return false;
    }

    std::shared_ptr<ISoundDose> soundDoseInterface;
    auto result = mSoundDoseFactory->getSoundDose(module, &soundDoseInterface);
    if (!result.isOk()) {
        ALOGW("%s HAL cannot provide sound dose interface for module %s",
              __func__, module.c_str());
        activateInternalSoundDoseComputation();
        return false;
    }

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

    std::lock_guard _l(mLock);
    mUseHalSoundDoseInterface = true;
    stopInternalMelComputation();
    return true;
}

void AudioFlinger::MelReporter::activateInternalSoundDoseComputation() {
    mSoundDoseManager->setHalSoundDoseInterface(nullptr);

    std::lock_guard _l(mLock);
    mUseHalSoundDoseInterface = false;

    for (const auto& activePatches : mActiveMelPatches) {
        for (const auto& deviceId : activePatches.second.deviceHandles) {
            startMelComputationForNewPatch(activePatches.second.streamHandle, deviceId);
        }
    }
}

void AudioFlinger::MelReporter::onFirstRef() {
    mAudioFlinger.mPatchCommandThread->addListener(this);

    std::string interface =
        std::string(ISoundDoseFactory::descriptor) + kSoundDoseInterfaceModule.data();
    AIBinder* binder = AServiceManager_checkService(interface.c_str());
    if (binder == nullptr) {
        ALOGW("%s service %s doesn't exist", __func__, interface.c_str());
        return;
    }

    mSoundDoseFactory = ISoundDoseFactory::fromBinder(ndk::SpAIBinder(binder));
}

bool AudioFlinger::MelReporter::shouldComputeMelForDeviceType(audio_devices_t device) {
    if (mSoundDoseManager.computeCsdOnAllDevices()) {
    if (mSoundDoseManager->computeCsdOnAllDevices()) {
        return true;
    }

@@ -65,24 +126,39 @@ void AudioFlinger::MelReporter::onCreateAudioPatch(audio_patch_handle_t handle,
            && shouldComputeMelForDeviceType(patch.mAudioPatch.sinks[i].ext.device.type)) {
            audio_port_handle_t deviceId = patch.mAudioPatch.sinks[i].id;
            newPatch.deviceHandles.push_back(deviceId);
            AudioDeviceTypeAddr adt{patch.mAudioPatch.sinks[i].ext.device.type,
                                    patch.mAudioPatch.sinks[i].ext.device.address};
            mSoundDoseManager->mapAddressToDeviceId(adt, deviceId);

            bool useHalSoundDoseInterface;
            {
                std::lock_guard _l(mLock);
                useHalSoundDoseInterface = mUseHalSoundDoseInterface;
            }
            if (!useHalSoundDoseInterface) {
                startMelComputationForNewPatch(streamHandle, deviceId);
            }
        }
    }

    std::lock_guard _l(mLock);
    mActiveMelPatches[patch.mAudioPatch.id] = newPatch;
}

void AudioFlinger::MelReporter::startMelComputationForNewPatch(
        audio_io_handle_t streamHandle, audio_port_handle_t deviceId) {
    // Start the MEL calculation in the PlaybackThread
    std::lock_guard _lAf(mAudioFlinger.mLock);
    auto thread = mAudioFlinger.checkPlaybackThread_l(streamHandle);
    if (thread != nullptr) {
                thread->startMelComputation(mSoundDoseManager.getOrCreateProcessorForDevice(
        thread->startMelComputation(mSoundDoseManager->getOrCreateProcessorForDevice(
            deviceId,
                    newPatch.streamHandle,
            streamHandle,
            thread->mSampleRate,
            thread->mChannelCount,
            thread->mFormat));
    }
}
    }

    std::lock_guard _l(mLock);
    mActiveMelPatches[patch.mAudioPatch.id] = newPatch;
}

void AudioFlinger::MelReporter::onReleaseAudioPatch(audio_patch_handle_t handle) {
    ALOGV("%s", __func__);
@@ -103,25 +179,47 @@ void AudioFlinger::MelReporter::onReleaseAudioPatch(audio_patch_handle_t handle)
        mActiveMelPatches.erase(patchIt);
    }

    // Stop MEL calculation for the PlaybackThread
    std::lock_guard _lAf(mAudioFlinger.mLock);
    mSoundDoseManager.removeStreamProcessor(melPatch.streamHandle);
    auto thread = mAudioFlinger.checkPlaybackThread_l(melPatch.streamHandle);
    if (thread != nullptr) {
        thread->stopMelComputation();
    for (const auto& deviceId : melPatch.deviceHandles) {
        mSoundDoseManager->clearMapDeviceIdEntries(deviceId);
    }
    stopInternalMelComputationForStream(melPatch.streamHandle);
}

sp<media::ISoundDose> AudioFlinger::MelReporter::getSoundDoseInterface(
        const sp<media::ISoundDoseCallback>& callback) {
    // no need to lock since getSoundDoseInterface is synchronized
    return mSoundDoseManager.getSoundDoseInterface(callback);
    return mSoundDoseManager->getSoundDoseInterface(callback);
}

void AudioFlinger::MelReporter::stopInternalMelComputation() {
    ALOGV("%s", __func__);
    std::unordered_map<audio_patch_handle_t, ActiveMelPatch> activePatchesCopy;
    {
        std::lock_guard _l(mLock);
        activePatchesCopy = mActiveMelPatches;
        mActiveMelPatches.clear();
    }

    for (const auto& activePatch : activePatchesCopy) {
        stopInternalMelComputationForStream(activePatch.second.streamHandle);
    }
}

void AudioFlinger::MelReporter::stopInternalMelComputationForStream(audio_io_handle_t streamId) {
    ALOGV("%s: stop internal mel for stream id: %d", __func__, streamId);

    std::lock_guard _lAf(mAudioFlinger.mLock);
    mSoundDoseManager->removeStreamProcessor(streamId);
    auto thread = mAudioFlinger.checkPlaybackThread_l(streamId);
    if (thread != nullptr) {
        thread->stopMelComputation();
    }
}

std::string AudioFlinger::MelReporter::dump() {
    std::lock_guard _l(mLock);
    std::string output("\nSound Dose:\n");
    output.append(mSoundDoseManager.dump());
    output.append(mSoundDoseManager->dump());
    return output;
}

+33 −7
Original line number Diff line number Diff line
@@ -32,17 +32,34 @@ constexpr static int kMaxTimestampDeltaInSec = 120;
class MelReporter : public PatchCommandThread::PatchCommandListener {
public:
    explicit MelReporter(AudioFlinger& audioFlinger)
        : mAudioFlinger(audioFlinger) {}
        : mAudioFlinger(audioFlinger),
          mSoundDoseManager(sp<SoundDoseManager>::make()) {}

    void onFirstRef() override {
        mAudioFlinger.mPatchCommandThread->addListener(this);
    }
    void onFirstRef() override;

    /** Returns true if we should compute MEL for the given device. */
    bool shouldComputeMelForDeviceType(audio_devices_t device);

    // For now only support internal MelReporting
    [[nodiscard]] bool isHalReportingEnabled() const { return false; }
    /**
     * Activates the MEL reporting from the HAL sound dose interface. If the HAL
     * does not support the sound dose interface for this module, the internal MEL
     * calculation will be use.
     *
     * For now support internal MelReporting only if the sound dose standalone HAL
     * is not implemented
     *
     * @return true if the MEL reporting will be done from the sound dose HAL
     * interface
     */
    bool activateHalSoundDoseComputation(const std::string& module);

    /**
     * Activates the MEL reporting from internal framework values. These are used
     * as a fallback when there is no sound dose interface implementation from HAL.
     * Note: the internal CSD computation does not guarantee a certification with
     * IEC62368-1 3rd edition or EN50332-3
     */
    void activateInternalSoundDoseComputation();

    sp<media::ISoundDose> getSoundDoseInterface(const sp<media::ISoundDoseCallback>& callback);

@@ -54,9 +71,17 @@ public:
    void onReleaseAudioPatch(audio_patch_handle_t handle) override;

private:
    void stopInternalMelComputation();
    void stopInternalMelComputationForStream(audio_io_handle_t streamId);

    void startMelComputationForNewPatch(audio_io_handle_t streamHandle,
                                        audio_port_handle_t deviceId);

    AudioFlinger& mAudioFlinger;  // does not own the object
    std::shared_ptr<::aidl::android::hardware::audio::sounddose::ISoundDoseFactory>
        mSoundDoseFactory;

    SoundDoseManager mSoundDoseManager;
    sp<SoundDoseManager> mSoundDoseManager;

    struct ActiveMelPatch {
        audio_io_handle_t streamHandle{AUDIO_IO_HANDLE_NONE};
@@ -70,4 +95,5 @@ private:
    std::mutex mLock;
    std::unordered_map<audio_patch_handle_t, ActiveMelPatch>
        mActiveMelPatches GUARDED_BY(AudioFlinger::MelReporter::mLock);
    bool mUseHalSoundDoseInterface GUARDED_BY(AudioFlinger::MelReporter::mLock) = false;
};
Loading