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

Commit 53c3b5fc authored by Andy Hung's avatar Andy Hung
Browse files

Improve AudioTrack EVENT_LOOP_END and EVENT_BUFFER_END accuracy

Fix timing computation to consider current position.
Fix EVENT_LOOP_END count accuracy (some could be dropped before)
for non-infinite loop static AudioTracks.

Change-Id: I255f692915b55ab6f08ccd6a2365fee3f5d0a4fe
parent 4ede21d9
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -736,6 +736,10 @@ protected:
    int32_t                 mLoopCount;             // last setLoop loopCount; zero means disabled
    uint32_t                mLoopStart;             // last setLoop loopStart
    uint32_t                mLoopEnd;               // last setLoop loopEnd
    int32_t                 mLoopCountNotified;     // the last loopCount notified by callback.
                                                    // mLoopCountNotified counts down, matching
                                                    // the remaining loop count for static track
                                                    // playback.

    // These are private to processAudioBuffer(), and are not protected by a lock
    uint32_t                mRemainingFrames;       // number of frames to request in obtainBuffer()
+40 −11
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@

#define WAIT_PERIOD_MS                  10
#define WAIT_STREAM_END_TIMEOUT_SEC     120

static const int kMaxLoopCountNotifications = 32;

namespace android {
// ---------------------------------------------------------------------------
@@ -428,6 +428,7 @@ status_t AudioTrack::set(
    mLoopCount = 0;
    mLoopStart = 0;
    mLoopEnd = 0;
    mLoopCountNotified = 0;
    mMarkerPosition = 0;
    mMarkerReached = false;
    mNewPosition = 0;
@@ -750,6 +751,7 @@ void AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount)
    mLoopCount = loopCount;
    mLoopEnd = loopEnd;
    mLoopStart = loopStart;
    mLoopCountNotified = loopCount;
    mStaticProxy->setLoop(loopStart, loopEnd, loopCount);
}

@@ -899,10 +901,15 @@ status_t AudioTrack::reload()
    mNewPosition = mUpdatePeriod;
    (void) updateAndGetPosition_l();
    mPosition = 0;
#if 0
    // The documentation is not clear on the behavior of reload() and the restoration
    // of loop count. Historically we have not restored loop count, start, end;
    // rather we just reset the buffer position.  However, restoring the last setLoop
    // information makes sense if one desires to repeat playing a particular sound.
    // of loop count. Historically we have not restored loop count, start, end,
    // but it makes sense if one desires to repeat playing a particular sound.
    if (mLoopCount != 0) {
        mLoopCountNotified = mLoopCount;
        mStaticProxy->setLoop(mLoopStart, mLoopEnd, mLoopCount);
    }
#endif
    mStaticProxy->setBufferPosition(0);
    return NO_ERROR;
}
@@ -1566,9 +1573,8 @@ nsecs_t AudioTrack::processAudioBuffer()
        // that the upper layers can recreate the track
        if (!isOffloadedOrDirect_l() || (mSequence == mObservedSequence)) {
            status_t status = restoreTrack_l("processAudioBuffer");
            mLock.unlock();
            // Run again immediately, but with a new IAudioTrack
            return 0;
            // after restoration, continue below to make sure that the loop and buffer events
            // are notified because they have been cleared from mCblk->mFlags above.
        }
    }

@@ -1617,7 +1623,6 @@ nsecs_t AudioTrack::processAudioBuffer()
    }

    // Cache other fields that will be needed soon
    uint32_t loopPeriod = mLoopCount != 0 ? mLoopEnd - mLoopStart : 0;
    uint32_t sampleRate = mSampleRate;
    uint32_t notificationFrames = mNotificationFramesAct;
    if (mRefreshRemaining) {
@@ -1629,6 +1634,28 @@ nsecs_t AudioTrack::processAudioBuffer()
    uint32_t sequence = mSequence;
    sp<AudioTrackClientProxy> proxy = mProxy;

    // Determine the number of new loop callback(s) that will be needed, while locked.
    int loopCountNotifications = 0;
    uint32_t loopPeriod = 0; // time in frames for next EVENT_LOOP_END or EVENT_BUFFER_END

    if (mLoopCount > 0) {
        int loopCount;
        size_t bufferPosition;
        mStaticProxy->getBufferPositionAndLoopCount(&bufferPosition, &loopCount);
        loopPeriod = ((loopCount > 0) ? mLoopEnd : mFrameCount) - bufferPosition;
        loopCountNotifications = min(mLoopCountNotified - loopCount, kMaxLoopCountNotifications);
        mLoopCountNotified = loopCount; // discard any excess notifications
    } else if (mLoopCount < 0) {
        // FIXME: We're not accurate with notification count and position with infinite looping
        // since loopCount from server side will always return -1 (we could decrement it).
        size_t bufferPosition = mStaticProxy->getBufferPosition();
        loopCountNotifications = int((flags & (CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL)) != 0);
        loopPeriod = mLoopEnd - bufferPosition;
    } else if (/* mLoopCount == 0 && */ mSharedBuffer != 0) {
        size_t bufferPosition = mStaticProxy->getBufferPosition();
        loopPeriod = mFrameCount - bufferPosition;
    }

    // These fields don't need to be cached, because they are assigned only by set():
    //     mTransfer, mCbf, mUserData, mFormat, mFrameSize, mFrameSizeAF, mFlags
    // mFlags is also assigned by createTrack_l(), but not the bit we care about.
@@ -1669,10 +1696,9 @@ nsecs_t AudioTrack::processAudioBuffer()
    if (newUnderrun) {
        mCbf(EVENT_UNDERRUN, mUserData, NULL);
    }
    // FIXME we will miss loops if loop cycle was signaled several times since last call
    //       to processAudioBuffer()
    if (flags & (CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL)) {
    while (loopCountNotifications > 0) {
        mCbf(EVENT_LOOP_END, mUserData, NULL);
        --loopCountNotifications;
    }
    if (flags & CBLK_BUFFER_END) {
        mCbf(EVENT_BUFFER_END, mUserData, NULL);
@@ -1891,6 +1917,9 @@ status_t AudioTrack::restoreTrack_l(const char *from)
                        mLoopStart, mLoopEnd, loopCount);
            } else {
                mStaticProxy->setBufferPosition(bufferPosition);
                if (bufferPosition == mFrameCount) {
                    ALOGD("restoring track at end of static buffer");
                }
            }
        }
        if (mState == STATE_ACTIVE) {