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);