CSD: Enable the CSD only for MUSIC and GAME usage

Any mix that contain a track with MUSIC and GAME usage can have an
active CSD computation. This is a requirement of the IEC62368-1 3rd
edition and EN50332-3.

Also implemented logic to ignore the HAL MELs when there is no active
stream with MUSIC/GAME usage on the device that reports the values.

Test: dumpsys media.audio_flinger and logs
Bug: 265936306
Change-Id: I583de61c6917823522557ae5c1371d9242a273cb
diff --git a/services/audioflinger/MelReporter.cpp b/services/audioflinger/MelReporter.cpp
index bc5b5db..5dbcb33 100644
--- a/services/audioflinger/MelReporter.cpp
+++ b/services/audioflinger/MelReporter.cpp
@@ -100,14 +100,50 @@
     }
 }
 
+void AudioFlinger::MelReporter::updateMetadataForCsd(audio_io_handle_t streamHandle,
+        const std::vector<playback_track_metadata_v7_t>& metadataVec) {
+    std::lock_guard _laf(mAudioFlinger.mLock);
+    std::lock_guard _l(mLock);
+    auto activeMelPatchId = activePatchStreamHandle_l(streamHandle);
+    if (!activeMelPatchId) {
+        ALOGV("%s stream handle %d does not have an active patch", __func__, streamHandle);
+        return;
+    }
+
+    bool shouldActivateCsd = false;
+    for (const auto& metadata : metadataVec) {
+        if (metadata.base.usage == AUDIO_USAGE_GAME || metadata.base.usage == AUDIO_USAGE_MEDIA) {
+            shouldActivateCsd = true;
+        }
+    }
+
+    auto activeMelPatchIt = mActiveMelPatches.find(activeMelPatchId.value());
+    if (activeMelPatchIt != mActiveMelPatches.end()
+        && shouldActivateCsd != activeMelPatchIt->second.csdActive) {
+        if (activeMelPatchIt->second.csdActive) {
+            ALOGV("%s should not compute CSD for stream handle %d", __func__, streamHandle);
+            stopMelComputationForPatch_l(activeMelPatchIt->second);
+        } else {
+            ALOGV("%s should compute CSD for stream handle %d", __func__, streamHandle);
+            startMelComputationForActivePatch_l(activeMelPatchIt->second);
+        }
+        activeMelPatchIt->second.csdActive = shouldActivateCsd;
+    }
+}
+
 void AudioFlinger::MelReporter::onCreateAudioPatch(audio_patch_handle_t handle,
         const PatchPanel::Patch& patch) {
+    if (useHalSoundDoseInterface()) {
+        ALOGV("%s using HAL sound dose, ignore new patch", __func__);
+        return;
+    }
+
     ALOGV("%s: handle %d mHalHandle %d device sink %08x",
             __func__, handle, patch.mHalHandle,
             patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
     if (patch.mAudioPatch.num_sources == 0
         || patch.mAudioPatch.sources[0].type != AUDIO_PORT_TYPE_MIX) {
-        ALOGW("%s: patch does not contain any mix sources", __func__);
+        ALOGV("%s: patch does not contain any mix sources", __func__);
         return;
     }
 
@@ -122,49 +158,46 @@
             AudioDeviceTypeAddr adt{patch.mAudioPatch.sinks[i].ext.device.type,
                                     patch.mAudioPatch.sinks[i].ext.device.address};
             mSoundDoseManager->mapAddressToDeviceId(adt, deviceId);
-
-            bool useHalSoundDoseInterface = !mSoundDoseManager->forceUseFrameworkMel();
-            {
-                std::lock_guard _l(mLock);
-                useHalSoundDoseInterface &= mUseHalSoundDoseInterface;
-            }
-            if (!useHalSoundDoseInterface) {
-                startMelComputationForNewPatch(streamHandle, deviceId);
-            }
         }
     }
 
+    std::lock_guard _afl(mAudioFlinger.mLock);
     std::lock_guard _l(mLock);
-    mActiveMelPatches[patch.mAudioPatch.id] = newPatch;
+    ALOGV("%s add patch handle %d to active devices", __func__, handle);
+    startMelComputationForActivePatch_l(newPatch);
+    newPatch.csdActive = true;
+    mActiveMelPatches[handle] = 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) {
+void AudioFlinger::MelReporter::startMelComputationForActivePatch_l(const ActiveMelPatch& patch) {
+    auto thread = mAudioFlinger.checkPlaybackThread_l(patch.streamHandle);
+    if (thread == nullptr) {
+        ALOGE("%s cannot find thread for stream handle %d", __func__, patch.streamHandle);
+        return;
+    }
+
+    for (const auto& deviceHandle : patch.deviceHandles) {
+        ++mActiveDevices[deviceHandle];
+        ALOGI("%s add stream %d that uses device %d for CSD, nr of streams: %d", __func__,
+              patch.streamHandle, deviceHandle, mActiveDevices[deviceHandle]);
         thread->startMelComputation(mSoundDoseManager->getOrCreateProcessorForDevice(
-            deviceId,
-            streamHandle,
+            deviceHandle,
+            patch.streamHandle,
             thread->mSampleRate,
             thread->mChannelCount,
             thread->mFormat));
-    }
+        }
 }
 
 void AudioFlinger::MelReporter::onReleaseAudioPatch(audio_patch_handle_t handle) {
-    ALOGV("%s", __func__);
-
     ActiveMelPatch melPatch;
     {
         std::lock_guard _l(mLock);
 
         auto patchIt = mActiveMelPatches.find(handle);
         if (patchIt == mActiveMelPatches.end()) {
-            ALOGW(
-                "%s patch does not contain any mix sources with active MEL calculation",
-                __func__);
+            ALOGV("%s patch handle %d does not contain any mix sources with active MEL calculation",
+                    __func__, handle);
             return;
         }
 
@@ -172,10 +205,9 @@
         mActiveMelPatches.erase(patchIt);
     }
 
-    for (const auto& deviceId : melPatch.deviceHandles) {
-        mSoundDoseManager->clearMapDeviceIdEntries(deviceId);
-    }
-    stopInternalMelComputationForStream(melPatch.streamHandle);
+    std::lock_guard _afl(mAudioFlinger.mLock);
+    std::lock_guard _l(mLock);
+    stopMelComputationForPatch_l(melPatch);
 }
 
 sp<media::ISoundDose> AudioFlinger::MelReporter::getSoundDoseInterface(
@@ -191,17 +223,46 @@
     mUseHalSoundDoseInterface = true;
 }
 
-void AudioFlinger::MelReporter::stopInternalMelComputationForStream(audio_io_handle_t streamId) {
-    ALOGV("%s: stop internal mel for stream id: %d", __func__, streamId);
+void AudioFlinger::MelReporter::stopMelComputationForPatch_l(const ActiveMelPatch& patch) {
+    auto thread = mAudioFlinger.checkPlaybackThread_l(patch.streamHandle);
+    ALOGV("%s: stop MEL for stream id: %d", __func__, patch.streamHandle);
+    for (const auto& deviceId : patch.deviceHandles) {
+        if (mActiveDevices[deviceId] > 0) {
+            --mActiveDevices[deviceId];
+            if (mActiveDevices[deviceId] == 0) {
+                // no stream is using deviceId anymore
+                ALOGI("%s removing device %d from active CSD devices", __func__, deviceId);
+                mSoundDoseManager->clearMapDeviceIdEntries(deviceId);
+            }
+        }
+    }
 
-    std::lock_guard _lAf(mAudioFlinger.mLock);
-    mSoundDoseManager->removeStreamProcessor(streamId);
-    auto thread = mAudioFlinger.checkPlaybackThread_l(streamId);
+    mSoundDoseManager->removeStreamProcessor(patch.streamHandle);
     if (thread != nullptr) {
         thread->stopMelComputation();
     }
 }
 
+
+std::optional<audio_patch_handle_t> AudioFlinger::MelReporter::activePatchStreamHandle_l(
+        audio_io_handle_t streamHandle) {
+    for(const auto& patchIt : mActiveMelPatches) {
+        if (patchIt.second.streamHandle == streamHandle) {
+            return patchIt.first;
+        }
+    }
+    return std::nullopt;
+}
+
+bool AudioFlinger::MelReporter::useHalSoundDoseInterface() {
+    bool useHalSoundDoseInterface = !mSoundDoseManager->forceUseFrameworkMel();
+    {
+        std::lock_guard _l(mLock);
+        useHalSoundDoseInterface &= mUseHalSoundDoseInterface;
+    }
+    return useHalSoundDoseInterface;
+}
+
 std::string AudioFlinger::MelReporter::dump() {
     std::lock_guard _l(mLock);
     std::string output("\nSound Dose:\n");