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");
diff --git a/services/audioflinger/MelReporter.h b/services/audioflinger/MelReporter.h
index 5e7f0cc..c1b291f 100644
--- a/services/audioflinger/MelReporter.h
+++ b/services/audioflinger/MelReporter.h
@@ -37,9 +37,6 @@
 
     void onFirstRef() override;
 
-    /** Returns true if we should compute MEL for the given device. */
-    bool shouldComputeMelForDeviceType(audio_devices_t device);
-
     /**
      * 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
@@ -73,22 +70,39 @@
                             const PatchPanel::Patch& patch) override;
     void onReleaseAudioPatch(audio_patch_handle_t handle) override;
 
+    /**
+     * The new metadata can determine whether we should compute MEL for the given thread.
+     * This is the case only if one of the tracks in the thread mix is using MEDIA or GAME.
+     * Otherwise, this method will disable CSD.
+     **/
+    void updateMetadataForCsd(audio_io_handle_t streamHandle,
+                              const std::vector<playback_track_metadata_v7_t>& metadataVec);
 private:
-    void stopInternalMelComputation();
-    void stopInternalMelComputationForStream(audio_io_handle_t streamId);
+    struct ActiveMelPatch {
+        audio_io_handle_t streamHandle{AUDIO_IO_HANDLE_NONE};
+        std::vector<audio_port_handle_t> deviceHandles;
+        bool csdActive;
+    };
 
-    void startMelComputationForNewPatch(audio_io_handle_t streamHandle,
-                                        audio_port_handle_t deviceId);
+    /** Returns true if we should compute MEL for the given device. */
+    bool shouldComputeMelForDeviceType(audio_devices_t device);
+
+    void stopInternalMelComputation();
+
+    /** Should be called with the following order of locks: mAudioFlinger.mLock -> mLock. */
+    void stopMelComputationForPatch_l(const ActiveMelPatch& patch);
+
+    /** Should be called with the following order of locks: mAudioFlinger.mLock -> mLock. */
+    void startMelComputationForActivePatch_l(const ActiveMelPatch& patch);
+
+    std::optional<audio_patch_handle_t> activePatchStreamHandle_l(audio_io_handle_t streamHandle);
+
+    bool useHalSoundDoseInterface();
 
     AudioFlinger& mAudioFlinger;  // does not own the object
 
     sp<SoundDoseManager> mSoundDoseManager;
 
-    struct ActiveMelPatch {
-        audio_io_handle_t streamHandle{AUDIO_IO_HANDLE_NONE};
-        std::vector<audio_port_handle_t> deviceHandles;
-    };
-
     /**
      * Lock for protecting the active mel patches. Do not mix with the AudioFlinger lock.
      * Locking order AudioFlinger::mLock -> PatchCommandThread::mLock -> MelReporter::mLock.
@@ -96,5 +110,7 @@
     std::mutex mLock;
     std::unordered_map<audio_patch_handle_t, ActiveMelPatch>
         mActiveMelPatches GUARDED_BY(AudioFlinger::MelReporter::mLock);
+    std::unordered_map<audio_port_handle_t, int>
+        mActiveDevices GUARDED_BY(AudioFlinger::MelReporter::mLock);
     bool mUseHalSoundDoseInterface GUARDED_BY(AudioFlinger::MelReporter::mLock) = false;
 };
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index f850ede..f517a0b 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3229,10 +3229,10 @@
     item.record();
 }
 
-void AudioFlinger::PlaybackThread::updateMetadata_l()
+AudioFlinger::ThreadBase::MetadataUpdate AudioFlinger::PlaybackThread::updateMetadata_l()
 {
     if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
-        return; // nothing to do
+        return {}; // nothing to do
     }
     StreamOutHalInterface::SourceMetadata metadata;
     auto backInserter = std::back_inserter(metadata.tracks);
@@ -3241,6 +3241,9 @@
         track->copyMetadataTo(backInserter);
     }
     sendMetadataToBackend_l(metadata);
+    MetadataUpdate change;
+    change.playbackMetadataUpdate = metadata.tracks;
+    return change;
 }
 
 void AudioFlinger::PlaybackThread::sendMetadataToBackend_l(
@@ -3478,8 +3481,10 @@
 }
 
 void AudioFlinger::PlaybackThread::stopMelComputation() {
-    ALOGV("%s: stopping mel processor for thread %d", __func__, id());
-    mMelProcessor = nullptr;
+    if (mMelProcessor.load() != nullptr) {
+        ALOGV("%s: stopping mel processor for thread %d", __func__, id());
+        mMelProcessor = nullptr;
+    }
 }
 
 void AudioFlinger::PlaybackThread::threadLoop_drain()
@@ -3932,6 +3937,7 @@
             checkOutputStageEffects();
         }
 
+        MetadataUpdate metadataUpdate;
         { // scope for mLock
 
             Mutex::Autolock _l(mLock);
@@ -4033,7 +4039,7 @@
 
             mActiveTracks.updatePowerState(this);
 
-            updateMetadata_l();
+            metadataUpdate = updateMetadata_l();
 
             // prevent any changes in effect chain list and in each effect chain
             // during mixing and effect process as the audio buffers could be deleted
@@ -4073,6 +4079,11 @@
             setHalLatencyMode_l();
         } // mLock scope ends
 
+        if (!metadataUpdate.playbackMetadataUpdate.empty()) {
+            mAudioFlinger->mMelReporter->updateMetadataForCsd(id(),
+                    metadataUpdate.playbackMetadataUpdate);
+        }
+
         if (mBytesRemaining == 0) {
             mCurrentWriteLength = 0;
             if (mMixerStatus == MIXER_TRACKS_READY) {
@@ -4782,7 +4793,7 @@
     if (configChanged) {
         sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
     }
-    // Force meteadata update after a route change
+    // Force metadata update after a route change
     mActiveTracks.setHasChanged();
 
     return status;
@@ -9022,10 +9033,10 @@
     mSharedAudioPackageName = "";
 }
 
-void AudioFlinger::RecordThread::updateMetadata_l()
+AudioFlinger::ThreadBase::MetadataUpdate AudioFlinger::RecordThread::updateMetadata_l()
 {
     if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
-        return; // nothing to do
+        return {}; // nothing to do
     }
     StreamInHalInterface::SinkMetadata metadata;
     auto backInserter = std::back_inserter(metadata.tracks);
@@ -9033,6 +9044,9 @@
         track->copyMetadataTo(backInserter);
     }
     mInput->stream->updateSinkMetadata(metadata);
+    MetadataUpdate change;
+    change.recordMetadataUpdate = metadata.tracks;
+    return change;
 }
 
 // destroyTrack_l() must be called with ThreadBase::mLock held
@@ -10732,10 +10746,10 @@
     }
 }
 
-void AudioFlinger::MmapPlaybackThread::updateMetadata_l()
+AudioFlinger::ThreadBase::MetadataUpdate AudioFlinger::MmapPlaybackThread::updateMetadata_l()
 {
     if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
-        return; // nothing to do
+        return {}; // nothing to do
     }
     StreamOutHalInterface::SourceMetadata metadata;
     for (const sp<MmapTrack> &track : mActiveTracks) {
@@ -10751,7 +10765,11 @@
         metadata.tracks.push_back(trackMetadata);
     }
     mOutput->stream->updateSourceMetadata(metadata);
-}
+
+    MetadataUpdate change;
+    change.playbackMetadataUpdate = metadata.tracks;
+    return change;
+};
 
 void AudioFlinger::MmapPlaybackThread::checkSilentMode_l()
 {
@@ -10859,10 +10877,10 @@
     }
 }
 
-void AudioFlinger::MmapCaptureThread::updateMetadata_l()
+AudioFlinger::ThreadBase::MetadataUpdate AudioFlinger::MmapCaptureThread::updateMetadata_l()
 {
     if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
-        return; // nothing to do
+        return {}; // nothing to do
     }
     StreamInHalInterface::SinkMetadata metadata;
     for (const sp<MmapTrack> &track : mActiveTracks) {
@@ -10877,6 +10895,9 @@
         metadata.tracks.push_back(trackMetadata);
     }
     mInput->stream->updateSinkMetadata(metadata);
+    MetadataUpdate change;
+    change.recordMetadataUpdate = metadata.tracks;
+    return change;
 }
 
 void AudioFlinger::MmapCaptureThread::setRecordSilenced(audio_port_handle_t portId, bool silenced)
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 4ab4557..f829efc 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -607,7 +607,11 @@
                 void checkSuspendOnAddEffectChain_l(const sp<EffectChain>& chain);
 
                 // sends the metadata of the active tracks to the HAL
-    virtual     void        updateMetadata_l() = 0;
+                struct MetadataUpdate {
+                    std::vector<playback_track_metadata_v7_t> playbackMetadataUpdate;
+                    std::vector<record_track_metadata_v7_t>   recordMetadataUpdate;
+                };
+    virtual     MetadataUpdate           updateMetadata_l() = 0;
 
                 String16 getWakeLockTag();
 
@@ -1277,7 +1281,7 @@
     void        removeTrack_l(const sp<Track>& track);
 
     void        readOutputParameters_l();
-    void        updateMetadata_l() final;
+    MetadataUpdate          updateMetadata_l() final;
     virtual void sendMetadataToBackend_l(const StreamOutHalInterface::SourceMetadata& metadata);
 
     void        collectTimestamps_l();
@@ -1983,7 +1987,7 @@
             status_t    setPreferredMicrophoneDirection(audio_microphone_direction_t direction);
             status_t    setPreferredMicrophoneFieldDimension(float zoom);
 
-            void        updateMetadata_l() override;
+            MetadataUpdate        updateMetadata_l() override;
 
             bool        fastTrackAvailable() const { return mFastTrackAvail; }
 
@@ -2257,7 +2261,7 @@
     virtual     void        checkSilentMode_l();
                 void        processVolume_l() override;
 
-                void        updateMetadata_l() override;
+                MetadataUpdate        updateMetadata_l() override;
 
     virtual     void        toAudioPortConfig(struct audio_port_config *config);
 
@@ -2290,7 +2294,7 @@
 
                 status_t       exitStandby_l() REQUIRES(mLock) override;
 
-                void           updateMetadata_l() override;
+                MetadataUpdate           updateMetadata_l() override;
                 void           processVolume_l() override;
                 void           setRecordSilenced(audio_port_handle_t portId,
                                                  bool silenced) override;
diff --git a/services/audioflinger/sounddose/SoundDoseManager.cpp b/services/audioflinger/sounddose/SoundDoseManager.cpp
index df6eb5b..1c75119 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.cpp
+++ b/services/audioflinger/sounddose/SoundDoseManager.cpp
@@ -160,7 +160,7 @@
     auto adt = AudioDeviceTypeAddr(type, address);
     auto deviceIt = mActiveDevices.find(adt);
     if (deviceIt == mActiveDevices.end()) {
-        ALOGE("%s: could not find port id for device %s", __func__, adt.toString().c_str());
+        ALOGI("%s: could not find port id for device %s", __func__, adt.toString().c_str());
         return AUDIO_PORT_HANDLE_NONE;
     }
     return deviceIt->second;
@@ -184,7 +184,6 @@
         }
         ++activeDevice;
     }
-    return;
 }
 
 ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
@@ -203,7 +202,7 @@
 
     auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
     if (id == AUDIO_PORT_HANDLE_NONE) {
-        ALOGW("%s: no mapped id for audio device with type %d and address %s",
+        ALOGI("%s: no mapped id for audio device with type %d and address %s",
                 __func__, in_audioDevice.type.type,
                 in_audioDevice.address.get<AudioDeviceAddress::id>().c_str());
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
@@ -230,7 +229,7 @@
 
     auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
     if (id == AUDIO_PORT_HANDLE_NONE) {
-        ALOGW("%s: no mapped id for audio device with type %d and address %s",
+        ALOGI("%s: no mapped id for audio device with type %d and address %s",
                 __func__, in_audioDevice.type.type,
                 in_audioDevice.address.get<AudioDeviceAddress::id>().c_str());
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
diff --git a/services/audioflinger/sounddose/SoundDoseManager.h b/services/audioflinger/sounddose/SoundDoseManager.h
index db87ad8..c12efc3 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.h
+++ b/services/audioflinger/sounddose/SoundDoseManager.h
@@ -176,7 +176,9 @@
     std::unordered_map<audio_io_handle_t, wp<audio_utils::MelProcessor>> mActiveProcessors
             GUARDED_BY(mLock);
 
-    // map active device address and type to device id
+    // map active device address and type to device id, used also for managing the pause/resume
+    // 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);
 
     float mRs2Value GUARDED_BY(mLock);