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

Commit 2fe0acd0 authored by Eric Laurent's avatar Eric Laurent
Browse files

audioflinger: add effect creation probe mode

Add an argument to IAudioFlinger::createEffect() API to
ask AudioFlinger to just run the pre flight checks but not
create the actual audio effect instance and allocate resources.
This is the basis of an API for apps to query if a given
effect can be created without having to allocate the resources
and risk an exception when calling the constructor.

Bug: 150699608
Test: CTS and GTS Tests for audio effects
Change-Id: Ibdda22fd945c88c33e3c7342a7a5ed3e02d399ac
parent 90334d0f
Loading
Loading
Loading
Loading
+40 −16
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ namespace android {
// ---------------------------------------------------------------------------

AudioEffect::AudioEffect(const String16& opPackageName)
    : mStatus(NO_INIT), mOpPackageName(opPackageName)
    : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName)
{
}

@@ -49,12 +49,13 @@ AudioEffect::AudioEffect(const effect_uuid_t *type,
                void* user,
                audio_session_t sessionId,
                audio_io_handle_t io,
                const AudioDeviceTypeAddr& device
                const AudioDeviceTypeAddr& device,
                bool probe
                )
    : mStatus(NO_INIT), mOpPackageName(opPackageName)
    : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName)
{
    AutoMutex lock(mConstructLock);
    mStatus = set(type, uuid, priority, cbf, user, sessionId, io, device);
    mStatus = set(type, uuid, priority, cbf, user, sessionId, io, device, probe);
}

AudioEffect::AudioEffect(const char *typeStr,
@@ -65,9 +66,10 @@ AudioEffect::AudioEffect(const char *typeStr,
                void* user,
                audio_session_t sessionId,
                audio_io_handle_t io,
                const AudioDeviceTypeAddr& device
                const AudioDeviceTypeAddr& device,
                bool probe
                )
    : mStatus(NO_INIT), mOpPackageName(opPackageName)
    : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName)
{
    effect_uuid_t type;
    effect_uuid_t *pType = NULL;
@@ -89,7 +91,7 @@ AudioEffect::AudioEffect(const char *typeStr,
    }

    AutoMutex lock(mConstructLock);
    mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io, device);
    mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io, device, probe);
}

status_t AudioEffect::set(const effect_uuid_t *type,
@@ -99,7 +101,8 @@ status_t AudioEffect::set(const effect_uuid_t *type,
                void* user,
                audio_session_t sessionId,
                audio_io_handle_t io,
                const AudioDeviceTypeAddr& device)
                const AudioDeviceTypeAddr& device,
                bool probe)
{
    sp<IEffect> iEffect;
    sp<IMemory> cblk;
@@ -126,7 +129,7 @@ status_t AudioEffect::set(const effect_uuid_t *type,
        ALOGW("Must specify at least type or uuid");
        return BAD_VALUE;
    }

    mProbe = probe;
    mPriority = priority;
    mCbf = cbf;
    mUserData = user;
@@ -142,15 +145,18 @@ status_t AudioEffect::set(const effect_uuid_t *type,

    iEffect = audioFlinger->createEffect((effect_descriptor_t *)&mDescriptor,
            mIEffectClient, priority, io, mSessionId, device, mOpPackageName, mClientPid,
            &mStatus, &mId, &enabled);
            probe, &mStatus, &mId, &enabled);

    if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
    // In probe mode, we stop here and return the status: the IEffect interface to
    // audio flinger will not be retained. initCheck() will return the creation status
    // but all other APIs will return invalid operation.
    if (probe || iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
        char typeBuffer[64], uuidBuffer[64];
        guidToString(type, typeBuffer, sizeof(typeBuffer));
        guidToString(uuid, uuidBuffer, sizeof(uuidBuffer));
        ALOGE("set(): AudioFlinger could not create effect %s / %s, status: %d",
        ALOGE_IF(!probe, "set(): AudioFlinger could not create effect %s / %s, status: %d",
                typeBuffer, uuidBuffer, mStatus);
        if (iEffect == 0) {
        if (!probe && iEffect == 0) {
            mStatus = NO_INIT;
        }
        return mStatus;
@@ -191,7 +197,7 @@ AudioEffect::~AudioEffect()
{
    ALOGV("Destructor %p", this);

    if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) {
    if (!mProbe && (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS)) {
        if (!audio_is_global_session(mSessionId)) {
            AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
        }
@@ -201,10 +207,10 @@ AudioEffect::~AudioEffect()
        }
        mIEffect.clear();
        mCblkMemory.clear();
    }
    mIEffectClient.clear();
    IPCThreadState::self()->flushCommands();
}
}


status_t AudioEffect::initCheck() const
@@ -226,6 +232,9 @@ bool AudioEffect::getEnabled() const

status_t AudioEffect::setEnabled(bool enabled)
{
    if (mProbe) {
        return INVALID_OPERATION;
    }
    if (mStatus != NO_ERROR) {
        return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
    }
@@ -254,6 +263,9 @@ status_t AudioEffect::command(uint32_t cmdCode,
                              uint32_t *replySize,
                              void *replyData)
{
    if (mProbe) {
        return INVALID_OPERATION;
    }
    if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
        ALOGV("command() bad status %d", mStatus);
        return mStatus;
@@ -287,6 +299,9 @@ status_t AudioEffect::command(uint32_t cmdCode,

status_t AudioEffect::setParameter(effect_param_t *param)
{
    if (mProbe) {
        return INVALID_OPERATION;
    }
    if (mStatus != NO_ERROR) {
        return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
    }
@@ -307,6 +322,9 @@ status_t AudioEffect::setParameter(effect_param_t *param)

status_t AudioEffect::setParameterDeferred(effect_param_t *param)
{
    if (mProbe) {
        return INVALID_OPERATION;
    }
    if (mStatus != NO_ERROR) {
        return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
    }
@@ -333,6 +351,9 @@ status_t AudioEffect::setParameterDeferred(effect_param_t *param)

status_t AudioEffect::setParameterCommit()
{
    if (mProbe) {
        return INVALID_OPERATION;
    }
    if (mStatus != NO_ERROR) {
        return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
    }
@@ -347,6 +368,9 @@ status_t AudioEffect::setParameterCommit()

status_t AudioEffect::getParameter(effect_param_t *param)
{
    if (mProbe) {
        return INVALID_OPERATION;
    }
    if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
        return mStatus;
    }
+4 −1
Original line number Diff line number Diff line
@@ -662,6 +662,7 @@ public:
                                    const AudioDeviceTypeAddr& device,
                                    const String16& opPackageName,
                                    pid_t pid,
                                    bool probe,
                                    status_t *status,
                                    int *id,
                                    int *enabled)
@@ -689,6 +690,7 @@ public:
        }
        data.writeString16(opPackageName);
        data.writeInt32((int32_t) pid);
        data.writeInt32(probe ? 1 : 0);

        status_t lStatus = remote()->transact(CREATE_EFFECT, data, &reply);
        if (lStatus != NO_ERROR) {
@@ -1395,12 +1397,13 @@ status_t BnAudioFlinger::onTransact(
            }
            const String16 opPackageName = data.readString16();
            pid_t pid = (pid_t)data.readInt32();
            bool probe = data.readInt32() == 1;

            int id = 0;
            int enabled = 0;

            sp<IEffect> effect = createEffect(&desc, client, priority, output, sessionId, device,
                    opPackageName, pid, &status, &id, &enabled);
                    opPackageName, pid, probe, &status, &id, &enabled);
            reply->writeInt32(status);
            reply->writeInt32(id);
            reply->writeInt32(enabled);
+12 −6
Original line number Diff line number Diff line
@@ -365,6 +365,10 @@ public:
     * device: An audio device descriptor. Only used when "sessionID" is AUDIO_SESSION_DEVICE.
     *         Specifies the audio device type and address the effect must be attached to.
     *         If "sessionID" is AUDIO_SESSION_DEVICE then "io" must be AUDIO_IO_HANDLE_NONE.
     * probe: true if created in a degraded mode to only verify if effect creation is possible.
     *        In this mode, no IEffect interface to AudioFlinger is created and all actions
     *        besides getters implemented in client AudioEffect object are no ops
     *        after effect creation.
     */

    AudioEffect(const effect_uuid_t *type,
@@ -375,8 +379,8 @@ public:
                void* user = NULL,
                audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
                audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
                const AudioDeviceTypeAddr& device = {}
                );
                const AudioDeviceTypeAddr& device = {},
                bool probe = false);

    /* Constructor.
     *      Same as above but with type and uuid specified by character strings
@@ -389,8 +393,8 @@ public:
                    void* user = NULL,
                    audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
                    audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
                    const AudioDeviceTypeAddr& device = {}
                    );
                    const AudioDeviceTypeAddr& device = {},
                    bool probe = false);

    /* Terminates the AudioEffect and unregisters it from AudioFlinger.
     * The effect engine is also destroyed if this AudioEffect was the last controlling
@@ -412,8 +416,8 @@ public:
                            void* user = NULL,
                            audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
                            audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
                            const AudioDeviceTypeAddr& device = {}
                            );
                            const AudioDeviceTypeAddr& device = {},
                            bool probe = false);

    /* Result of constructing the AudioEffect. This must be checked
     * before using any AudioEffect API.
@@ -547,6 +551,8 @@ protected:
     audio_session_t         mSessionId;         // audio session ID
     int32_t                 mPriority;          // priority for effect control
     status_t                mStatus;            // effect status
     bool                    mProbe;             // effect created in probe mode: all commands
                                                 // are no ops because mIEffect is NULL
     effect_callback_t       mCbf;               // callback function for status, control and
                                                 // parameter changes notifications
     void*                   mUserData;          // client context for callback function
+1 −0
Original line number Diff line number Diff line
@@ -476,6 +476,7 @@ public:
                                    const AudioDeviceTypeAddr& device,
                                    const String16& callingPackage,
                                    pid_t pid,
                                    bool probe,
                                    status_t *status,
                                    int *id,
                                    int *enabled) = 0;
+5 −4
Original line number Diff line number Diff line
@@ -3375,6 +3375,7 @@ sp<IEffect> AudioFlinger::createEffect(
        const AudioDeviceTypeAddr& device,
        const String16& opPackageName,
        pid_t pid,
        bool probe,
        status_t *status,
        int *id,
        int *enabled)
@@ -3490,10 +3491,10 @@ sp<IEffect> AudioFlinger::createEffect(

        if (sessionId == AUDIO_SESSION_DEVICE) {
            sp<Client> client = registerPid(pid);
            ALOGV("%s device type %d address %s", __func__, device.mType, device.getAddress());
            ALOGV("%s device type %#x address %s", __func__, device.mType, device.getAddress());
            handle = mDeviceEffectManager.createEffect_l(
                    &desc, device, client, effectClient, mPatchPanel.patches_l(),
                    enabled, &lStatus);
                    enabled, &lStatus, probe);
            if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
                // remove local strong reference to Client with mClientLock held
                Mutex::Autolock _cl(mClientLock);
@@ -3588,7 +3589,7 @@ sp<IEffect> AudioFlinger::createEffect(
        // create effect on selected output thread
        bool pinned = !audio_is_global_session(sessionId) && isSessionAcquired_l(sessionId);
        handle = thread->createEffect_l(client, effectClient, priority, sessionId,
                &desc, enabled, &lStatus, pinned);
                &desc, enabled, &lStatus, pinned, probe);
        if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
            // remove local strong reference to Client with mClientLock held
            Mutex::Autolock _cl(mClientLock);
@@ -3600,7 +3601,7 @@ sp<IEffect> AudioFlinger::createEffect(
    }

Register:
    if (lStatus == NO_ERROR || lStatus == ALREADY_EXISTS) {
    if (!probe && (lStatus == NO_ERROR || lStatus == ALREADY_EXISTS)) {
        // Check CPU and memory usage
        sp<EffectBase> effect = handle->effect().promote();
        if (effect != nullptr) {
Loading