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

Commit 8a4259fc authored by Eric Laurent's avatar Eric Laurent
Browse files

Spatializer: process callbacks in separate thread

Add a Looper and Handler to process events from the engine
and pose controler callback to avoid cross mutex deadlocks.

Bug: 188502620
Test: manual test with mock spatializer
Change-Id: I1342602259b147727c704ad7bbeb1b3a68c7b231
Merged-In: I1342602259b147727c704ad7bbeb1b3a68c7b231
parent 879f0910
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ cc_library_shared {
        "libsensorprivacy",
        "libshmemcompat",
        "libutils",
        "libstagefright_foundation",
        "audioclient-types-aidl-cpp",
        "audioflinger-aidl-cpp",
        "audiopolicy-aidl-cpp",
+138 −9
Original line number Diff line number Diff line
@@ -29,8 +29,10 @@
#include <audio_utils/fixedfft.h>
#include <cutils/bitops.h>
#include <hardware/sensors.h>
#include <media/ShmemCompat.h>
#include <media/audiohal/EffectsFactoryHalInterface.h>
#include <media/stagefright/foundation/AHandler.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/ShmemCompat.h>
#include <mediautils/ServiceUtilities.h>
#include <utils/Thread.h>

@@ -49,7 +51,6 @@ using media::SpatializationMode;
using media::SpatializerHeadTrackingMode;
using media::SensorPoseProvider;


using namespace std::chrono_literals;

#define VALUE_OR_RETURN_BINDER_STATUS(x) \
@@ -65,6 +66,90 @@ using namespace std::chrono_literals;

// ---------------------------------------------------------------------------

class Spatializer::EngineCallbackHandler : public AHandler {
public:
    EngineCallbackHandler(wp<Spatializer> spatializer)
            : mSpatializer(spatializer) {
    }

    enum {
        // Device state callbacks
        kWhatOnFramesProcessed,    // AudioEffect::EVENT_FRAMES_PROCESSED
        kWhatOnHeadToStagePose,    // SpatializerPoseController::Listener::onHeadToStagePose
        kWhatOnActualModeChange,   // SpatializerPoseController::Listener::onActualModeChange
    };
    static constexpr const char *kNumFramesKey = "numFrames";
    static constexpr const char *kModeKey = "mode";
    static constexpr const char *kTranslation0Key = "translation0";
    static constexpr const char *kTranslation1Key = "translation1";
    static constexpr const char *kTranslation2Key = "translation2";
    static constexpr const char *kRotation0Key = "rotation0";
    static constexpr const char *kRotation1Key = "rotation1";
    static constexpr const char *kRotation2Key = "rotation2";

    void onMessageReceived(const sp<AMessage> &msg) override {
        switch (msg->what()) {
            case kWhatOnFramesProcessed: {
                sp<Spatializer> spatializer = mSpatializer.promote();
                if (spatializer == nullptr) {
                    ALOGW("%s: Cannot promote spatializer", __func__);
                    return;
                }
                int numFrames;
                if (!msg->findInt32(kNumFramesKey, &numFrames)) {
                    ALOGE("%s: Cannot find num frames!", __func__);
                    return;
                }
                if (numFrames > 0) {
                    spatializer->calculateHeadPose();
                }
                } break;
            case kWhatOnHeadToStagePose: {
                sp<Spatializer> spatializer = mSpatializer.promote();
                if (spatializer == nullptr) {
                    ALOGW("%s: Cannot promote spatializer", __func__);
                    return;
                }
                std::vector<float> headToStage(sHeadPoseKeys.size());
                for (size_t i = 0 ; i < sHeadPoseKeys.size(); i++) {
                    if (!msg->findFloat(sHeadPoseKeys[i], &headToStage[i])) {
                        ALOGE("%s: Cannot find kTranslation0Key!", __func__);
                        return;
                    }
                }
                spatializer->onHeadToStagePoseMsg(headToStage);
                } break;
            case kWhatOnActualModeChange: {
                sp<Spatializer> spatializer = mSpatializer.promote();
                if (spatializer == nullptr) {
                    ALOGW("%s: Cannot promote spatializer", __func__);
                    return;
                }
                int mode;
                if (!msg->findInt32(EngineCallbackHandler::kModeKey, &mode)) {
                    ALOGE("%s: Cannot find actualMode!", __func__);
                    return;
                }
                spatializer->onActualModeChangeMsg(static_cast<HeadTrackingMode>(mode));
                } break;
            default:
                LOG_ALWAYS_FATAL("Invalid callback message %d", msg->what());
        }
    }
private:
    wp<Spatializer> mSpatializer;
};

const std::vector<const char *> Spatializer::sHeadPoseKeys = {
    Spatializer::EngineCallbackHandler::kTranslation0Key,
    Spatializer::EngineCallbackHandler::kTranslation1Key,
    Spatializer::EngineCallbackHandler::kTranslation2Key,
    Spatializer::EngineCallbackHandler::kRotation0Key,
    Spatializer::EngineCallbackHandler::kRotation1Key,
    Spatializer::EngineCallbackHandler::kRotation2Key,
};

// ---------------------------------------------------------------------------
sp<Spatializer> Spatializer::create(SpatializerPolicyCallback *callback) {
    sp<Spatializer> spatializer;

@@ -107,8 +192,26 @@ Spatializer::Spatializer(effect_descriptor_t engineDescriptor, SpatializerPolicy
    ALOGV("%s", __func__);
}

void Spatializer::onFirstRef() {
    mLooper = new ALooper;
    mLooper->setName("Spatializer-looper");
    mLooper->start(
            /*runOnCallingThread*/false,
            /*canCallJava*/       false,
            PRIORITY_AUDIO);

    mHandler = new EngineCallbackHandler(this);
    mLooper->registerHandler(mHandler);
}

Spatializer::~Spatializer() {
    ALOGV("%s", __func__);
    if (mLooper != nullptr) {
        mLooper->stop();
        mLooper->unregisterHandler(mHandler->id());
    }
    mLooper.clear();
    mHandler.clear();
}

status_t Spatializer::loadEngineConfiguration(sp<EffectHalInterface> effect) {
@@ -391,23 +494,44 @@ Status Spatializer::getSupportedModes(std::vector<SpatializationMode> *modes) {
// SpatializerPoseController::Listener
void Spatializer::onHeadToStagePose(const Pose3f& headToStage) {
    ALOGV("%s", __func__);
    sp<media::INativeSpatializerCallback> callback;
    auto vec = headToStage.toVector();
    LOG_ALWAYS_FATAL_IF(vec.size() != sHeadPoseKeys.size(),
            "%s invalid head to stage vector size %zu", __func__, vec.size());

    sp<AMessage> msg =
            new AMessage(EngineCallbackHandler::kWhatOnHeadToStagePose, mHandler);
    for (size_t i = 0 ; i < sHeadPoseKeys.size(); i++) {
        msg->setFloat(sHeadPoseKeys[i], vec[i]);
    }
    msg->post();
}

void Spatializer::onHeadToStagePoseMsg(const std::vector<float>& headToStage) {
    ALOGV("%s", __func__);
    sp<media::INativeSpatializerCallback> callback;
    {
        std::lock_guard lock(mLock);
        callback = mSpatializerCallback;
        if (mEngine != nullptr) {
            setEffectParameter_l(SPATIALIZER_PARAM_HEAD_TO_STAGE, vec);
            setEffectParameter_l(SPATIALIZER_PARAM_HEAD_TO_STAGE, headToStage);
        }
    }

    if (callback != nullptr) {
        callback->onHeadToSoundStagePoseUpdated(vec);
        callback->onHeadToSoundStagePoseUpdated(headToStage);
    }
}

void Spatializer::onActualModeChange(HeadTrackingMode mode) {
    ALOGV("onActualModeChange(%d)", (int) mode);
    ALOGV("%s(%d)", __func__, (int)mode);
    sp<AMessage> msg =
            new AMessage(EngineCallbackHandler::kWhatOnActualModeChange, mHandler);
    msg->setInt32(EngineCallbackHandler::kModeKey, static_cast<int>(mode));
    msg->post();
}

void Spatializer::onActualModeChangeMsg(HeadTrackingMode mode) {
    ALOGV("%s(%d)", __func__, (int) mode);
    sp<media::INativeSpatializerCallback> callback;
    SpatializerHeadTrackingMode spatializerMode;
    {
@@ -534,9 +658,7 @@ void Spatializer::engineCallback(int32_t event, void *user, void *info) {
        case AudioEffect::EVENT_FRAMES_PROCESSED: {
            int frames = info == nullptr ? 0 : *(int*)info;
            ALOGD("%s frames processed %d for me %p", __func__, frames, me);
            if (frames > 0) {
                me->calculateHeadPose();
            }
            me->postFramesProcessedMsg(frames);
        } break;
        default:
            ALOGD("%s event %d", __func__, event);
@@ -544,6 +666,13 @@ void Spatializer::engineCallback(int32_t event, void *user, void *info) {
    }
}

void Spatializer::postFramesProcessedMsg(int frames) {
    sp<AMessage> msg =
            new AMessage(EngineCallbackHandler::kWhatOnFramesProcessed, mHandler);
    msg->setInt32(EngineCallbackHandler::kNumFramesKey, frames);
    msg->post();
}

// ---------------------------------------------------------------------------

Spatializer::EffectClient::EffectClient(const sp<media::IEffectClient>& effectClient,
+19 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <android/media/SpatializerHeadTrackingMode.h>
#include <android/sensor.h>
#include <media/audiohal/EffectHalInterface.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/AudioEffect.h>
#include <system/audio_effects/effect_spatializer.h>

@@ -91,6 +92,9 @@ class Spatializer : public media::BnSpatializer,

           ~Spatializer() override;

    /** RefBase */
    void onFirstRef();

    /** ISpatializer, see ISpatializer.aidl */
    binder::Status release() override;
    binder::Status getSupportedLevels(std::vector<media::SpatializationLevel>* levels) override;
@@ -138,6 +142,8 @@ class Spatializer : public media::BnSpatializer,
    /** Gets the channel mask, sampling rate and format set for the spatializer input. */
    audio_config_base_t getAudioInConfig() const;

    void calculateHeadPose();

    /** An implementation of an IEffect interface that can be used to pass advanced parameters to
     * the spatializer engine. All APis are noop (i.e. the interface cannot be used to control
     * the effect) except for passing parameters via the command() API. */
@@ -176,7 +182,9 @@ private:
    void onHeadToStagePose(const media::Pose3f& headToStage) override;
    void onActualModeChange(media::HeadTrackingMode mode) override;

    void calculateHeadPose();
    void onHeadToStagePoseMsg(const std::vector<float>& headToStage);
    void onActualModeChangeMsg(media::HeadTrackingMode mode);


    static ConversionResult<ASensorRef> getSensorFromHandle(int handle);

@@ -251,6 +259,8 @@ private:
        return mEngine->setParameter(p);
    }

    void postFramesProcessedMsg(int frames);

    /** Effect engine descriptor */
    const effect_descriptor_t mEngineDescriptor;
    /** Callback interface to parent audio policy service */
@@ -298,6 +308,14 @@ private:
    std::vector<media::SpatializationMode> mSpatializationModes;
    std::vector<audio_channel_mask_t> mChannelMasks;
    bool mSupportsHeadTracking;

    // Looper thread for mEngine callbacks
    class EngineCallbackHandler;

    sp<ALooper> mLooper;
    sp<EngineCallbackHandler> mHandler;

    static const std::vector<const char *> sHeadPoseKeys;
};