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

Commit eb3bda06 authored by jiabin's avatar jiabin
Browse files

Force selecting haptic supported thread when creating HapticGenerator.

HapticGenerator is the haptic-generating effect, which will generate
haptic data based on audio data. As haptic data will be truncated on
non-haptic supported thread, HapticGenerator makes sense only on haptic
supported thread. In that case, force selecting haptic supported thread
when creating HapticGenerator. If there is no thread supporting haptics
channel, return a failure.

Bug: 136490803
Test: make, manually
Change-Id: I865d211c613c793d75d23f5d10c9a01d294fdc36
parent 98b8a370
Loading
Loading
Loading
Loading
+51 −1
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@
#include <system/audio_effects/effect_visualizer.h>
#include <system/audio_effects/effect_ns.h>
#include <system/audio_effects/effect_aec.h>
#include <system/audio_effects/effect_hapticgenerator.h>

#include <audio_utils/primitives.h>

@@ -3297,6 +3298,16 @@ AudioFlinger::PlaybackThread *AudioFlinger::fastPlaybackThread_l() const
    return minThread;
}

AudioFlinger::ThreadBase *AudioFlinger::hapticPlaybackThread_l() const {
    for (size_t i  = 0; i < mPlaybackThreads.size(); ++i) {
        PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
        if (thread->hapticChannelMask() != AUDIO_CHANNEL_NONE) {
            return thread;
        }
    }
    return nullptr;
}

sp<AudioFlinger::SyncEvent> AudioFlinger::createSyncEvent(AudioSystem::sync_event_t type,
                                    audio_session_t triggerSession,
                                    audio_session_t listenerSession,
@@ -3538,6 +3549,16 @@ sp<IEffect> AudioFlinger::createEffect(
            goto Exit;
        }

        const bool hapticPlaybackRequired = EffectModule::isHapticGenerator(&desc.type);
        if (hapticPlaybackRequired
                && (sessionId == AUDIO_SESSION_DEVICE
                        || sessionId == AUDIO_SESSION_OUTPUT_MIX
                        || sessionId == AUDIO_SESSION_OUTPUT_STAGE)) {
            // haptic-generating effect is only valid when the session id is a general session id
            lStatus = INVALID_OPERATION;
            goto Exit;
        }

        // return effect descriptor
        *pDesc = desc;
        if (io == AUDIO_IO_HANDLE_NONE && sessionId == AUDIO_SESSION_OUTPUT_MIX) {
@@ -3612,7 +3633,17 @@ sp<IEffect> AudioFlinger::createEffect(
            // allow only one effect chain per sessionId on mPlaybackThreads.
            for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
                const audio_io_handle_t checkIo = mPlaybackThreads.keyAt(i);
                if (io == checkIo) continue;
                if (io == checkIo) {
                    if (hapticPlaybackRequired
                            && mPlaybackThreads.valueAt(i)
                                    ->hapticChannelMask() == AUDIO_CHANNEL_NONE) {
                        ALOGE("%s: haptic playback thread is required while the required playback "
                              "thread(io=%d) doesn't support", __func__, (int)io);
                        lStatus = BAD_VALUE;
                        goto Exit;
                    }
                    continue;
                }
                const uint32_t sessionType =
                        mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId);
                if ((sessionType & ThreadBase::EFFECT_SESSION) != 0) {
@@ -3649,6 +3680,20 @@ sp<IEffect> AudioFlinger::createEffect(

        // create effect on selected output thread
        bool pinned = !audio_is_global_session(sessionId) && isSessionAcquired_l(sessionId);
        ThreadBase *oriThread = nullptr;
        if (hapticPlaybackRequired && thread->hapticChannelMask() == AUDIO_CHANNEL_NONE) {
            ThreadBase *hapticThread = hapticPlaybackThread_l();
            if (hapticThread == nullptr) {
                ALOGE("%s haptic thread not found while it is required", __func__);
                lStatus = INVALID_OPERATION;
                goto Exit;
            }
            if (hapticThread != thread) {
                // Force to use haptic thread for haptic-generating effect.
                oriThread = thread;
                thread = hapticThread;
            }
        }
        handle = thread->createEffect_l(client, effectClient, priority, sessionId,
                &desc, enabled, &lStatus, pinned, probe);
        if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
@@ -3658,6 +3703,11 @@ sp<IEffect> AudioFlinger::createEffect(
        } else {
            // handle must be valid here, but check again to be safe.
            if (handle.get() != nullptr && id != nullptr) *id = handle->id();
            // Invalidate audio session when haptic playback is created.
            if (hapticPlaybackRequired && oriThread != nullptr) {
                // invalidateTracksForAudioSession will trigger locking the thread.
                oriThread->invalidateTracksForAudioSession(sessionId);
            }
        }
    }

+2 −0
Original line number Diff line number Diff line
@@ -756,6 +756,8 @@ using effect_buffer_t = int16_t;

              sp<ThreadBase> getEffectThread_l(audio_session_t sessionId, int effectId);

              ThreadBase *hapticPlaybackThread_l() const;


                void        removeClient_l(pid_t pid);
                void        removeNotificationClient(pid_t pid);
+1 −0
Original line number Diff line number Diff line
@@ -165,6 +165,7 @@ public:
    uint32_t  sampleRate() const override { return 0; }
    audio_channel_mask_t channelMask() const override { return AUDIO_CHANNEL_NONE; }
    uint32_t channelCount() const override { return 0; }
    audio_channel_mask_t hapticChannelMask() const override { return AUDIO_CHANNEL_NONE; }
    size_t    frameCount() const override  { return 0; }
    uint32_t  latency() const override  { return 0; }

+34 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <utils/Log.h>
#include <system/audio_effects/effect_aec.h>
#include <system/audio_effects/effect_dynamicsprocessing.h>
#include <system/audio_effects/effect_hapticgenerator.h>
#include <system/audio_effects/effect_ns.h>
#include <system/audio_effects/effect_visualizer.h>
#include <audio_utils/channels.h>
@@ -879,6 +880,11 @@ status_t AudioFlinger::EffectModule::configure()
        }
#endif
    }
    if (isHapticGenerator()) {
        audio_channel_mask_t hapticChannelMask = mCallback->hapticChannelMask();
        mConfig.inputCfg.channels |= hapticChannelMask;
        mConfig.outputCfg.channels |= hapticChannelMask;
    }
    mInChannelCountRequested =
            audio_channel_count_from_out_mask(mConfig.inputCfg.channels);
    mOutChannelCountRequested =
@@ -1522,6 +1528,15 @@ bool AudioFlinger::EffectModule::isOffloaded() const
    return mOffloaded;
}

/*static*/
bool AudioFlinger::EffectModule::isHapticGenerator(const effect_uuid_t *type) {
    return memcmp(type, FX_IID_HAPTICGENERATOR, sizeof(effect_uuid_t)) == 0;
}

bool AudioFlinger::EffectModule::isHapticGenerator() const {
    return isHapticGenerator(&mDescriptor.type);
}

static std::string dumpInOutBuffer(bool isInput, const sp<EffectBufferHalInterface> &buffer) {
    std::stringstream ss;

@@ -2385,6 +2400,17 @@ void AudioFlinger::EffectChain::resetVolume_l()
    }
}

// containsHapticGeneratingEffect_l must be called with ThreadBase::mLock or EffectChain::mLock held
bool AudioFlinger::EffectChain::containsHapticGeneratingEffect_l()
{
    for (size_t i = 0; i < mEffects.size(); ++i) {
        if (mEffects[i]->isHapticGenerator()) {
            return true;
        }
    }
    return false;
}

void AudioFlinger::EffectChain::syncHalEffectsState()
{
    Mutex::Autolock _l(mLock);
@@ -2839,6 +2865,14 @@ uint32_t AudioFlinger::EffectChain::EffectCallback::channelCount() const {
    return t->channelCount();
}

audio_channel_mask_t AudioFlinger::EffectChain::EffectCallback::hapticChannelMask() const {
    sp<ThreadBase> t = mThread.promote();
    if (t == nullptr) {
        return AUDIO_CHANNEL_NONE;
    }
    return t->hapticChannelMask();
}

size_t AudioFlinger::EffectChain::EffectCallback::frameCount() const {
    sp<ThreadBase> t = mThread.promote();
    if (t == nullptr) {
+8 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ public:
    virtual uint32_t sampleRate() const = 0;
    virtual audio_channel_mask_t channelMask() const = 0;
    virtual uint32_t channelCount() const = 0;
    virtual audio_channel_mask_t hapticChannelMask() const = 0;
    virtual size_t frameCount() const = 0;

    // Non trivial methods usually implemented with help from ThreadBase:
@@ -257,6 +258,9 @@ public:

    sp<EffectModule> asEffectModule() override { return this; }

    static bool      isHapticGenerator(const effect_uuid_t* type);
    bool             isHapticGenerator() const;

    void             dump(int fd, const Vector<String16>& args);

private:
@@ -503,6 +507,8 @@ public:
    // isCompatibleWithThread_l() must be called with thread->mLock held
    bool isCompatibleWithThread_l(const sp<ThreadBase>& thread) const;

    bool containsHapticGeneratingEffect_l();

    sp<EffectCallbackInterface> effectCallback() const { return mEffectCallback; }
    wp<ThreadBase> thread() const { return mEffectCallback->thread(); }

@@ -534,6 +540,7 @@ private:
        uint32_t sampleRate() const override;
        audio_channel_mask_t channelMask() const override;
        uint32_t channelCount() const override;
        audio_channel_mask_t hapticChannelMask() const override;
        size_t frameCount() const override;
        uint32_t latency() const override;

@@ -685,6 +692,7 @@ private:
        uint32_t sampleRate() const override;
        audio_channel_mask_t channelMask() const override;
        uint32_t channelCount() const override;
        audio_channel_mask_t hapticChannelMask() const override { return AUDIO_CHANNEL_NONE; }
        size_t frameCount() const override  { return 0; }
        uint32_t latency() const override  { return 0; }

Loading