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

Commit 39399b6b authored by Andy Hung's avatar Andy Hung
Browse files

VolumeShaper: Improve restore

Consider whether VolumeShaper has been started or not when
restoring (position). If the VolumeShaper hasn't been started
we restore in that state.  If it has been started already,
we advance to the end assuming the duration has been played out.

Test: CTS and headset / kill audioserver
Bug: 37536598
Change-Id: I4b55dca6f6a859563fd20bad4c8f67d2c92321c0
parent 94cfe137
Loading
Loading
Loading
Loading
+17 −5
Original line number Diff line number Diff line
@@ -528,6 +528,10 @@ public:
        mDelayXOffset = xOffset;
    }

    bool isStarted() const {
        return mStartFrame >= 0;
    }

    std::pair<T /* volume */, bool /* active */> getVolume(
            int64_t trackFrameCount, double trackSampleRate) {
        if ((getFlags() & VolumeShaper::Operation::FLAG_DELAY) != 0) {
@@ -752,6 +756,8 @@ public:
        return it->getState();
    }

    // getVolume() is not const, as it updates internal state.
    // Once called, any VolumeShapers not already started begin running.
    std::pair<T /* volume */, bool /* active */> getVolume(int64_t trackFrameCount) {
        AutoMutex _l(mLock);
        mLastFrame = trackFrameCount;
@@ -768,6 +774,14 @@ public:
        return mLastVolume;
    }

    // Used by a client side VolumeHandler to ensure all the VolumeShapers
    // indicate that they have been started.  Upon a change in audioserver
    // output sink, this information is used for restoration of the server side
    // VolumeHandler.
    void setStarted() {
        (void)getVolume(mLastFrame);  // getVolume() will start the individual VolumeShapers.
    }

    std::pair<T /* volume */, bool /* active */> getLastVolume() const {
        AutoMutex _l(mLock);
        return mLastVolume;
@@ -784,14 +798,12 @@ public:
        return ss.str();
    }

    void forall(const std::function<VolumeShaper::Status (
            const sp<VolumeShaper::Configuration> &configuration,
            const sp<VolumeShaper::Operation> &operation)> &lambda) {
    void forall(const std::function<VolumeShaper::Status (const VolumeShaper &)> &lambda) {
        AutoMutex _l(mLock);
        VS_LOG("forall: mVolumeShapers.size() %zu", mVolumeShapers.size());
        for (const auto &shaper : mVolumeShapers) {
            VS_LOG("forall applying lambda");
            (void)lambda(shaper.mConfiguration, shaper.mOperation);
            VolumeShaper::Status status = lambda(shaper);
            VS_LOG("forall applying lambda on shaper (%p): %d", &shaper, (int)status);
        }
    }

+32 −9
Original line number Diff line number Diff line
@@ -652,6 +652,9 @@ status_t AudioTrack::start()
            get_sched_policy(0, &mPreviousSchedulingGroup);
            androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
        }

        // Start our local VolumeHandler for restoration purposes.
        mVolumeHandler->setStarted();
    } else {
        ALOGE("start() status %d", status);
        mState = previousState;
@@ -2254,17 +2257,20 @@ status_t AudioTrack::restoreTrack_l(const char *from)
            }
        }
        // restore volume handler
        mVolumeHandler->forall([this](const sp<VolumeShaper::Configuration> &configuration,
                const sp<VolumeShaper::Operation> &operation) -> VolumeShaper::Status {
            sp<VolumeShaper::Operation> operationToEnd = new VolumeShaper::Operation(*operation);
        mVolumeHandler->forall([this](const VolumeShaper &shaper) -> VolumeShaper::Status {
            sp<VolumeShaper::Operation> operationToEnd =
                    new VolumeShaper::Operation(shaper.mOperation);
            // TODO: Ideally we would restore to the exact xOffset position
            // as returned by getVolumeShaperState(), but we don't have that
            // information when restoring at the client unless we periodically poll
            // the server or create shared memory state.
            //
            // For now, we simply advance to the end of the VolumeShaper effect.
            // For now, we simply advance to the end of the VolumeShaper effect
            // if it has been started.
            if (shaper.isStarted()) {
                operationToEnd->setXOffset(1.f);
            return mAudioTrack->applyVolumeShaper(configuration, operationToEnd);
            }
            return mAudioTrack->applyVolumeShaper(shaper.mConfiguration, operationToEnd);
        });

        if (mState == STATE_ACTIVE) {
@@ -2334,19 +2340,36 @@ VolumeShaper::Status AudioTrack::applyVolumeShaper(
    AutoMutex lock(mLock);
    mVolumeHandler->setIdIfNecessary(configuration);
    VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(configuration, operation);

    if (status == DEAD_OBJECT) {
        if (restoreTrack_l("applyVolumeShaper") == OK) {
            status = mAudioTrack->applyVolumeShaper(configuration, operation);
        }
    }
    if (status >= 0) {
        // save VolumeShaper for restore
        mVolumeHandler->applyVolumeShaper(configuration, operation);
        if (mState == STATE_ACTIVE || mState == STATE_STOPPING) {
            mVolumeHandler->setStarted();
        }
    } else {
        // warn only if not an expected restore failure.
        ALOGW_IF(!((isOffloadedOrDirect_l() || mDoNotReconnect) && status == DEAD_OBJECT),
                "applyVolumeShaper failed: %d", status);
    }
    return status;
}

sp<VolumeShaper::State> AudioTrack::getVolumeShaperState(int id)
{
    // TODO: To properly restore the AudioTrack
    // we will need to save the last state in AudioTrackShared.
    AutoMutex lock(mLock);
    return mAudioTrack->getVolumeShaperState(id);
    sp<VolumeShaper::State> state = mAudioTrack->getVolumeShaperState(id);
    if (state.get() == nullptr && (mCblk->mFlags & CBLK_INVALID) != 0) {
        if (restoreTrack_l("getVolumeShaperState") == OK) {
            state = mAudioTrack->getVolumeShaperState(id);
        }
    }
    return state;
}

status_t AudioTrack::getTimestamp(ExtendedTimestamp *timestamp)
+31 −9
Original line number Diff line number Diff line
@@ -2029,12 +2029,23 @@ status_t MediaPlayerService::AudioOutput::open(
    ALOGV("setVolume");
    t->setVolume(mLeftVolume, mRightVolume);

    // Dispatch any queued VolumeShapers when the track was not open.
    mVolumeHandler->forall([&t](const sp<VolumeShaper::Configuration> &configuration,
            const sp<VolumeShaper::Operation> &operation) -> VolumeShaper::Status {
        return t->applyVolumeShaper(configuration, operation);
    // Restore VolumeShapers for the MediaPlayer in case the track was recreated
    // due to an output sink error (e.g. offload to non-offload switch).
    mVolumeHandler->forall([&t](const VolumeShaper &shaper) -> VolumeShaper::Status {
        sp<VolumeShaper::Operation> operationToEnd =
                new VolumeShaper::Operation(shaper.mOperation);
        // TODO: Ideally we would restore to the exact xOffset position
        // as returned by getVolumeShaperState(), but we don't have that
        // information when restoring at the client unless we periodically poll
        // the server or create shared memory state.
        //
        // For now, we simply advance to the end of the VolumeShaper effect
        // if it has been started.
        if (shaper.isStarted()) {
            operationToEnd->setXOffset(1.f);
        }
        return t->applyVolumeShaper(shaper.mConfiguration, operationToEnd);
    });
    mVolumeHandler->reset(); // After dispatching, clear VolumeShaper queue.

    mSampleRateHz = sampleRate;
    mFlags = flags;
@@ -2075,7 +2086,11 @@ status_t MediaPlayerService::AudioOutput::start()
    if (mTrack != 0) {
        mTrack->setVolume(mLeftVolume, mRightVolume);
        mTrack->setAuxEffectSendLevel(mSendLevel);
        return mTrack->start();
        status_t status = mTrack->start();
        if (status == NO_ERROR) {
            mVolumeHandler->setStarted();
        }
        return status;
    }
    return NO_INIT;
}
@@ -2279,13 +2294,20 @@ VolumeShaper::Status MediaPlayerService::AudioOutput::applyVolumeShaper(
    Mutex::Autolock lock(mLock);
    ALOGV("AudioOutput::applyVolumeShaper");

    // We take ownership of the VolumeShaper if set before the track is created.
    mVolumeHandler->setIdIfNecessary(configuration);

    VolumeShaper::Status status;
    if (mTrack != 0) {
        return mTrack->applyVolumeShaper(configuration, operation);
        status = mTrack->applyVolumeShaper(configuration, operation);
        if (status >= 0) {
            (void)mVolumeHandler->applyVolumeShaper(configuration, operation);
            // TODO: start on exact AudioTrack state (STATE_ACTIVE || STATE_STOPPING)
            mVolumeHandler->setStarted();
        }
    } else {
        return mVolumeHandler->applyVolumeShaper(configuration, operation);
        status = mVolumeHandler->applyVolumeShaper(configuration, operation);
    }
    return status;
}

sp<VolumeShaper::State> MediaPlayerService::AudioOutput::getVolumeShaperState(int id)