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

Commit 7e81ceab authored by Vlad Popa's avatar Vlad Popa
Browse files

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
parent 91c813a9
Loading
Loading
Loading
Loading
+95 −34
Original line number Diff line number Diff line
@@ -100,14 +100,50 @@ bool AudioFlinger::MelReporter::shouldComputeMelForDeviceType(audio_devices_t de
    }
}

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,31 +158,31 @@ void AudioFlinger::MelReporter::onCreateAudioPatch(audio_patch_handle_t handle,
            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));
@@ -154,17 +190,14 @@ void AudioFlinger::MelReporter::startMelComputationForNewPatch(
}

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 @@ void AudioFlinger::MelReporter::onReleaseAudioPatch(audio_patch_handle_t handle)
        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 @@ void AudioFlinger::MelReporter::stopInternalMelComputation() {
    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");
+27 −11
Original line number Diff line number Diff line
@@ -37,9 +37,6 @@ public:

    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 @@ public:
                            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:
    struct ActiveMelPatch {
        audio_io_handle_t streamHandle{AUDIO_IO_HANDLE_NONE};
        std::vector<audio_port_handle_t> deviceHandles;
        bool csdActive;
    };

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

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

    void startMelComputationForNewPatch(audio_io_handle_t streamHandle,
                                        audio_port_handle_t deviceId);
    /** 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 @@ private:
    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;
};
+34 −13
Original line number Diff line number Diff line
@@ -3229,10 +3229,10 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
    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 @@ void AudioFlinger::PlaybackThread::updateMetadata_l()
        track->copyMetadataTo(backInserter);
    }
    sendMetadataToBackend_l(metadata);
    MetadataUpdate change;
    change.playbackMetadataUpdate = metadata.tracks;
    return change;
}

void AudioFlinger::PlaybackThread::sendMetadataToBackend_l(
@@ -3478,9 +3481,11 @@ void AudioFlinger::PlaybackThread::startMelComputation(
}

void AudioFlinger::PlaybackThread::stopMelComputation() {
    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 @@ bool AudioFlinger::PlaybackThread::threadLoop()
            checkOutputStageEffects();
        }

        MetadataUpdate metadataUpdate;
        { // scope for mLock

            Mutex::Autolock _l(mLock);
@@ -4033,7 +4039,7 @@ bool AudioFlinger::PlaybackThread::threadLoop()

            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 @@ bool AudioFlinger::PlaybackThread::threadLoop()
            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 @@ status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_pat
    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 @@ void AudioFlinger::RecordThread::resetAudioHistory_l() {
    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 @@ void AudioFlinger::RecordThread::updateMetadata_l()
        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::processVolume_l()
    }
}

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 @@ void AudioFlinger::MmapPlaybackThread::updateMetadata_l()
        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::processVolume_l()
    }
}

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 @@ void AudioFlinger::MmapCaptureThread::updateMetadata_l()
        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)
+9 −5
Original line number Diff line number Diff line
@@ -607,7 +607,11 @@ protected:
                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 @@ private:
    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 @@ public:
            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 @@ public:
    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 @@ public:

                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;
+3 −4
Original line number Diff line number Diff line
@@ -160,7 +160,7 @@ audio_port_handle_t SoundDoseManager::getIdForAudioDevice(const AudioDevice& aud
    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 @@ void SoundDoseManager::clearMapDeviceIdEntries(audio_port_handle_t deviceId) {
        }
        ++activeDevice;
    }
    return;
}

ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
@@ -203,7 +202,7 @@ ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWa

    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 @@ ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onNewMelValues(

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