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

Commit bf5e2397 authored by Eric Laurent's avatar Eric Laurent Committed by Android Git Automerger
Browse files

am 5baf2af5: more support for audio effect offload

* commit '5baf2af5':
  more support for audio effect offload
parents 684e0ae8 5baf2af5
Loading
Loading
Loading
Loading
+48 −11
Original line number Diff line number Diff line
@@ -48,6 +48,21 @@ static const effect_descriptor_t *const gDescriptors[] =
    &gProxyDescriptor,
};

static inline bool isGetterCmd(uint32_t cmdCode)
{
    switch (cmdCode) {
    case EFFECT_CMD_GET_PARAM:
    case EFFECT_CMD_GET_CONFIG:
    case EFFECT_CMD_GET_CONFIG_REVERSE:
    case EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS:
    case EFFECT_CMD_GET_FEATURE_CONFIG:
        return true;
    default:
        return false;
    }
}


int EffectProxyCreate(const effect_uuid_t *uuid,
                            int32_t             sessionId,
                            int32_t             ioId,
@@ -155,7 +170,6 @@ int Effect_process(effect_handle_t self,
        int index = pContext->index;
        // if the index refers to HW , do not do anything. Just return.
        if (index == SUB_FX_HOST) {
            ALOGV("Calling CoreProcess");
            ret = (*pContext->eHandle[index])->process(pContext->eHandle[index],
                                                       inBuffer, outBuffer);
        }
@@ -172,7 +186,7 @@ int Effect_command(effect_handle_t self,
                              void                *pReplyData) {

    EffectContext *pContext = (EffectContext *) self;
    int status;
    int status = 0;
    if (pContext == NULL) {
        ALOGV("Effect_command() Proxy context is NULL");
        return -EINVAL;
@@ -237,23 +251,46 @@ int Effect_command(effect_handle_t self,
        ALOGV("Effect_command: effect index is neither offload nor host");
        return -EINVAL;
    }
    ALOGV("Effect_command: pContext->eHandle[%d]: %p",
            index, pContext->eHandle[index]);
    if (pContext->eHandle[SUB_FX_HOST])
         (*pContext->eHandle[SUB_FX_HOST])->command(

    // Getter commands are only sent to the active sub effect.
    uint32_t hostReplySize = replySize != NULL ? *replySize : 0;
    bool hostReplied = false;
    int hostStatus = 0;
    uint32_t offloadReplySize = replySize != NULL ? *replySize : 0;
    bool offloadReplied = false;
    int offloadStatus = 0;

    if (pContext->eHandle[SUB_FX_HOST] && (!isGetterCmd(cmdCode) || index == SUB_FX_HOST)) {
        hostStatus = (*pContext->eHandle[SUB_FX_HOST])->command(
                             pContext->eHandle[SUB_FX_HOST], cmdCode, cmdSize,
                             pCmdData, replySize, pReplyData);
    if (pContext->eHandle[SUB_FX_OFFLOAD]) {
                             pCmdData, replySize != NULL ? &hostReplySize : NULL, pReplyData);
        hostReplied = true;
    }
    if (pContext->eHandle[SUB_FX_OFFLOAD] && (!isGetterCmd(cmdCode) || index == SUB_FX_OFFLOAD)) {
        // In case of SET CMD, when the offload stream is unavailable,
        // we will store the effect param values in the DSP effect wrapper.
        // When the offload effects get enabled, we send these values to the
        // DSP during Effect_config.
        // So,we send the params to DSP wrapper also
        (*pContext->eHandle[SUB_FX_OFFLOAD])->command(
        offloadStatus = (*pContext->eHandle[SUB_FX_OFFLOAD])->command(
                         pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize,
                         pCmdData, replySize, pReplyData);
                         pCmdData, replySize != NULL ? &offloadReplySize : NULL, pReplyData);
        offloadReplied = true;
    }
    return 0;
    // By convention the offloaded implementation reply is returned if command is processed by both
    // host and offloaded sub effects
    if (offloadReplied){
        status = offloadStatus;
        if (replySize) {
            *replySize = offloadReplySize;
        }
    } else if (hostReplied) {
        status = hostStatus;
        if (replySize) {
            *replySize = hostReplySize;
        }
    }
    return status;
}    /* end Effect_command */


+2 −2
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ struct VisualizerContext {
    uint32_t mCaptureSize;
    uint32_t mScalingMode;
    uint8_t mState;
    uint8_t mLastCaptureIdx;
    uint32_t mLastCaptureIdx;
    uint32_t mLatency;
    struct timespec mBufferUpdateTime;
    uint8_t mCaptureBuf[CAPTURE_BUF_SIZE];
@@ -499,7 +499,7 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
                memcpy(pReplyData,
                       pContext->mCaptureBuf + CAPTURE_BUF_SIZE + capturePoint,
                       size);
                pReplyData += size;
                pReplyData = (char *)pReplyData + size;
                captureSize -= size;
                capturePoint = 0;
            }
+53 −36
Original line number Diff line number Diff line
@@ -98,7 +98,6 @@ size_t AudioFlinger::mTeeSinkOutputFrames = kTeeSinkOutputFramesDefault;
size_t AudioFlinger::mTeeSinkTrackFrames = kTeeSinkTrackFramesDefault;
#endif

//TODO: remove when effect offload is implemented
// In order to avoid invalidating offloaded tracks each time a Visualizer is turned on and off
// we define a minimum time during which a global effect is considered enabled.
static const nsecs_t kMinGlobalEffectEnabletimeNs = seconds(7200);
@@ -2084,20 +2083,6 @@ sp<IEffect> AudioFlinger::createEffect(
        goto Exit;
    }

    if (io == 0) {
        if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
            // output must be specified by AudioPolicyManager when using session
            // AUDIO_SESSION_OUTPUT_STAGE
            lStatus = BAD_VALUE;
            goto Exit;
        } else if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
            // if the output returned by getOutputForEffect() is removed before we lock the
            // mutex below, the call to checkPlaybackThread_l(io) below will detect it
            // and we will exit safely
            io = AudioSystem::getOutputForEffect(&desc);
        }
    }

    {
        Mutex::Autolock _l(mLock);

@@ -2180,6 +2165,20 @@ sp<IEffect> AudioFlinger::createEffect(
        // If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX
        // because of code checking output when entering the function.
        // Note: io is never 0 when creating an effect on an input
        if (io == 0) {
            if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
                // output must be specified by AudioPolicyManager when using session
                // AUDIO_SESSION_OUTPUT_STAGE
                lStatus = BAD_VALUE;
                goto Exit;
            }
            if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
                // if the output returned by getOutputForEffect() is removed before we lock the
                // mutex below, the call to checkPlaybackThread_l(io) below will detect it
                // and we will exit safely
                io = AudioSystem::getOutputForEffect(&desc);
                ALOGV("createEffect got output %d", io);
            }
            if (io == 0) {
                // look for the thread where the specified audio session is present
                for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
@@ -2196,6 +2195,7 @@ sp<IEffect> AudioFlinger::createEffect(
                        }
                    }
                }
            }
            // If no output thread contains the requested session ID, default to
            // first output. The effect chain will be moved to the correct output
            // thread when a track with the same session ID is created
@@ -2254,9 +2254,7 @@ status_t AudioFlinger::moveEffects(int sessionId, audio_io_handle_t srcOutput,

    Mutex::Autolock _dl(dstThread->mLock);
    Mutex::Autolock _sl(srcThread->mLock);
    moveEffectChain_l(sessionId, srcThread, dstThread, false);

    return NO_ERROR;
    return moveEffectChain_l(sessionId, srcThread, dstThread, false);
}

// moveEffectChain_l must be called with both srcThread and dstThread mLocks held
@@ -2283,13 +2281,18 @@ status_t AudioFlinger::moveEffectChain_l(int sessionId,

    // transfer all effects one by one so that new effect chain is created on new thread with
    // correct buffer sizes and audio parameters and effect engines reconfigured accordingly
    audio_io_handle_t dstOutput = dstThread->id();
    sp<EffectChain> dstChain;
    uint32_t strategy = 0; // prevent compiler warning
    sp<EffectModule> effect = chain->getEffectFromId_l(0);
    Vector< sp<EffectModule> > removed;
    status_t status = NO_ERROR;
    while (effect != 0) {
        srcThread->removeEffect_l(effect);
        dstThread->addEffect_l(effect);
        removed.add(effect);
        status = dstThread->addEffect_l(effect);
        if (status != NO_ERROR) {
            break;
        }
        // removeEffect_l() has stopped the effect if it was active so it must be restarted
        if (effect->state() == EffectModule::ACTIVE ||
                effect->state() == EffectModule::STOPPING) {
@@ -2301,15 +2304,15 @@ status_t AudioFlinger::moveEffectChain_l(int sessionId,
            dstChain = effect->chain().promote();
            if (dstChain == 0) {
                ALOGW("moveEffectChain_l() cannot get chain from effect %p", effect.get());
                srcThread->addEffect_l(effect);
                return NO_INIT;
                status = NO_INIT;
                break;
            }
            strategy = dstChain->strategy();
        }
        if (reRegister) {
            AudioSystem::unregisterEffect(effect->id());
            AudioSystem::registerEffect(&effect->desc(),
                                        dstOutput,
                                        dstThread->id(),
                                        strategy,
                                        sessionId,
                                        effect->id());
@@ -2317,10 +2320,24 @@ status_t AudioFlinger::moveEffectChain_l(int sessionId,
        effect = chain->getEffectFromId_l(0);
    }

    return NO_ERROR;
    if (status != NO_ERROR) {
        for (size_t i = 0; i < removed.size(); i++) {
            srcThread->addEffect_l(removed[i]);
            if (dstChain != 0 && reRegister) {
                AudioSystem::unregisterEffect(removed[i]->id());
                AudioSystem::registerEffect(&removed[i]->desc(),
                                            srcThread->id(),
                                            strategy,
                                            sessionId,
                                            removed[i]->id());
            }
        }
    }

    return status;
}

bool AudioFlinger::isGlobalEffectEnabled_l()
bool AudioFlinger::isNonOffloadableGlobalEffectEnabled_l()
{
    if (mGlobalEffectEnableTime != 0 &&
            ((systemTime() - mGlobalEffectEnableTime) < kMinGlobalEffectEnabletimeNs)) {
@@ -2330,14 +2347,14 @@ bool AudioFlinger::isGlobalEffectEnabled_l()
    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
        sp<EffectChain> ec =
                mPlaybackThreads.valueAt(i)->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
        if (ec != 0 && ec->isEnabled()) {
        if (ec != 0 && ec->isNonOffloadableEnabled()) {
            return true;
        }
    }
    return false;
}

void AudioFlinger::onGlobalEffectEnable()
void AudioFlinger::onNonOffloadableGlobalEffectEnable()
{
    Mutex::Autolock _l(mLock);

+2 −4
Original line number Diff line number Diff line
@@ -466,9 +466,8 @@ private:
                void        removeClient_l(pid_t pid);
                void        removeNotificationClient(pid_t pid);

                //TODO: remove when effect offload is implemented
                bool isGlobalEffectEnabled_l();
                void onGlobalEffectEnable();
                bool isNonOffloadableGlobalEffectEnabled_l();
                void onNonOffloadableGlobalEffectEnable();

    class AudioHwDevice {
    public:
@@ -645,7 +644,6 @@ public:
private:
    bool    mIsLowRamDevice;
    bool    mIsDeviceTypeKnown;
    //TODO: remove when effect offload is implemented
    nsecs_t mGlobalEffectEnableTime;  // when a global effect was last enabled
};

+44 −5
Original line number Diff line number Diff line
@@ -764,6 +764,46 @@ bool AudioFlinger::EffectModule::purgeHandles()
    return enabled;
}

status_t AudioFlinger::EffectModule::setOffloaded(bool offloaded, audio_io_handle_t io)
{
    Mutex::Autolock _l(mLock);
    if (mStatus != NO_ERROR) {
        return mStatus;
    }
    status_t status = NO_ERROR;
    if ((mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0) {
        status_t cmdStatus;
        uint32_t size = sizeof(status_t);
        effect_offload_param_t cmd;

        cmd.isOffload = offloaded;
        cmd.ioHandle = io;
        status = (*mEffectInterface)->command(mEffectInterface,
                                              EFFECT_CMD_OFFLOAD,
                                              sizeof(effect_offload_param_t),
                                              &cmd,
                                              &size,
                                              &cmdStatus);
        if (status == NO_ERROR) {
            status = cmdStatus;
        }
        mOffloaded = (status == NO_ERROR) ? offloaded : false;
    } else {
        if (offloaded) {
            status = INVALID_OPERATION;
        }
        mOffloaded = false;
    }
    ALOGV("setOffloaded() offloaded %d io %d status %d", offloaded, io, status);
    return status;
}

bool AudioFlinger::EffectModule::isOffloaded() const
{
    Mutex::Autolock _l(mLock);
    return mOffloaded;
}

void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
{
    const size_t SIZE = 256;
@@ -932,14 +972,13 @@ status_t AudioFlinger::EffectHandle::enable()
        }
        mEnabled = false;
    } else {
        //TODO: remove when effect offload is implemented
        if (thread != 0) {
        if (thread != 0 && !mEffect->isOffloadable()) {
            if ((thread->type() == ThreadBase::OFFLOAD)) {
                PlaybackThread *t = (PlaybackThread *)thread.get();
                t->invalidateTracks(AUDIO_STREAM_MUSIC);
            }
            if (mEffect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) {
                thread->mAudioFlinger->onGlobalEffectEnable();
                thread->mAudioFlinger->onNonOffloadableGlobalEffectEnable();
            }
        }
    }
@@ -1728,12 +1767,12 @@ void AudioFlinger::EffectChain::checkSuspendOnEffectEnabled(const sp<EffectModul
    }
}

bool AudioFlinger::EffectChain::isEnabled()
bool AudioFlinger::EffectChain::isNonOffloadableEnabled()
{
    Mutex::Autolock _l(mLock);
    size_t size = mEffects.size();
    for (size_t i = 0; i < size; i++) {
        if (mEffects[i]->isEnabled()) {
        if (mEffects[i]->isEnabled() && !mEffects[i]->isOffloadable()) {
            return true;
        }
    }
Loading