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

Commit 47d9971e authored by Andy Hung's avatar Andy Hung Committed by Automerger Merge Worker
Browse files

Merge "AudioTrack: presentationComplete by time for Direct Tracks." am: 6c003666

Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/1736355

Change-Id: Id1f8f5de4bd243029dc149b0795c7b81b4b82e69
parents 015598a6 6c003666
Loading
Loading
Loading
Loading
+22 −4
Original line number Diff line number Diff line
@@ -226,10 +226,23 @@ protected:

    sp<IMemory> sharedBuffer() const { return mSharedBuffer; }

    // presentationComplete checked by frames. (Mixed Tracks).
    // framesWritten is cumulative, never reset, and is shared all tracks
    // audioHalFrames is derived from output latency
    // FIXME parameters not needed, could get them from the thread
    bool presentationComplete(int64_t framesWritten, size_t audioHalFrames);

    // presentationComplete checked by time. (Direct Tracks).
    bool presentationComplete(uint32_t latencyMs);

    void resetPresentationComplete() {
        mPresentationCompleteFrames = 0;
        mPresentationCompleteTimeNs = 0;
    }

    // notifyPresentationComplete is called when presentationComplete() detects
    // that the track is finished stopping.
    void notifyPresentationComplete();

    void signalClientFlag(int32_t flag);

    /** Set that a metadata has changed and needs to be notified to backend. Thread safe. */
@@ -262,9 +275,6 @@ protected:
    int32_t             *mAuxBuffer;
    int                 mAuxEffectId;
    bool                mHasVolumeController;
    size_t              mPresentationCompleteFrames; // number of frames written to the
                                    // audio HAL when this track will be fully rendered
                                    // zero means not monitoring

    // access these three variables only when holding thread lock.
    LinearMap<int64_t> mFrameMap;           // track frame to server frame mapping
@@ -300,6 +310,14 @@ private:
        for (auto& tp : mTeePatches) { f(tp.patchTrack); }
    };

    size_t              mPresentationCompleteFrames = 0; // (Used for Mixed tracks)
                                    // The number of frames written to the
                                    // audio HAL when this track is considered fully rendered.
                                    // Zero means not monitoring.
    int64_t             mPresentationCompleteTimeNs = 0; // (Used for Direct tracks)
                                    // The time when this track is considered fully rendered.
                                    // Zero means not monitoring.

    // The following fields are only for fast tracks, and should be in a subclass
    int                 mFastIndex; // index within FastMixerState::mFastTracks[];
                                    // either mFastIndex == -1 if not isFastTrack()
+3 −18
Original line number Diff line number Diff line
@@ -2568,7 +2568,7 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
        }

        track->mResetDone = false;
        track->mPresentationCompleteFrames = 0;
        track->resetPresentationComplete();
        mActiveTracks.add(track);
        sp<EffectChain> chain = getEffectChain_l(track->sessionId());
        if (chain != 0) {
@@ -5958,16 +5958,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
                    track->isStopping_2() || track->isPaused()) {
                // We have consumed all the buffers of this track.
                // Remove it from the list of active tracks.
                size_t audioHALFrames;
                if (audio_has_proportional_frames(mFormat)) {
                    audioHALFrames = (latency_l() * mSampleRate) / 1000;
                } else {
                    audioHALFrames = 0;
                }

                int64_t framesWritten = mBytesWritten / mFrameSize;
                if (mStandby || !last ||
                        track->presentationComplete(framesWritten, audioHALFrames) ||
                        track->presentationComplete(latency_l()) ||
                        track->isPaused() || mHwPaused) {
                    if (track->isStopping_2()) {
                        track->mState = TrackBase::STOPPED;
@@ -6541,14 +6533,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr
                // Drain has completed or we are in standby, signal presentation complete
                if (!(mDrainSequence & 1) || !last || mStandby) {
                    track->mState = TrackBase::STOPPED;
                    uint32_t latency = 0;
                    status_t result = mOutput->stream->getLatency(&latency);
                    ALOGE_IF(result != OK,
                            "Error when retrieving output stream latency: %d", result);
                    size_t audioHALFrames = (latency * mSampleRate) / 1000;
                    int64_t framesWritten =
                            mBytesWritten / mOutput->getFrameSize();
                    track->presentationComplete(framesWritten, audioHALFrames);
                    track->presentationComplete(latency_l());
                    track->reset();
                    tracksToRemove->add(track);
                    // OFFLOADED stop resets frame counts.
+48 −7
Original line number Diff line number Diff line
@@ -632,7 +632,6 @@ AudioFlinger::PlaybackThread::Track::Track(
    mMainBuffer(thread->sinkBuffer()),
    mAuxBuffer(NULL),
    mAuxEffectId(0), mHasVolumeController(false),
    mPresentationCompleteFrames(0),
    mFrameMap(16 /* sink-frame-to-track-frame map memory */),
    mVolumeHandler(new media::VolumeHandler(sampleRate)),
    mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(
@@ -1433,6 +1432,7 @@ void AudioFlinger::PlaybackThread::Track::setAuxBuffer(int EffectId, int32_t *bu
    mAuxBuffer = buffer;
}

// presentationComplete verified by frames, used by Mixed tracks.
bool AudioFlinger::PlaybackThread::Track::presentationComplete(
        int64_t framesWritten, size_t audioHalFrames)
{
@@ -1451,30 +1451,71 @@ bool AudioFlinger::PlaybackThread::Track::presentationComplete(
            (long long)mPresentationCompleteFrames, (long long)framesWritten);
    if (mPresentationCompleteFrames == 0) {
        mPresentationCompleteFrames = framesWritten + audioHalFrames;
        ALOGV("%s(%d): presentationComplete() reset:"
        ALOGV("%s(%d): set:"
                " mPresentationCompleteFrames %lld audioHalFrames %zu",
                __func__, mId,
                (long long)mPresentationCompleteFrames, audioHalFrames);
    }

    bool complete;
    if (isOffloaded()) {
        complete = true;
    } else if (isDirect() || isFastTrack()) { // these do not go through linear map
    if (isFastTrack()) { // does not go through linear map
        complete = framesWritten >= (int64_t) mPresentationCompleteFrames;
        ALOGV("%s(%d): %s framesWritten:%lld  mPresentationCompleteFrames:%lld",
                __func__, mId, (complete ? "complete" : "waiting"),
                (long long) framesWritten, (long long) mPresentationCompleteFrames);
    } else {  // Normal tracks, OutputTracks, and PatchTracks
        complete = framesWritten >= (int64_t) mPresentationCompleteFrames
                && mAudioTrackServerProxy->isDrained();
    }

    if (complete) {
        triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE);
        mAudioTrackServerProxy->setStreamEndDone();
        notifyPresentationComplete();
        return true;
    }
    return false;
}

// presentationComplete checked by time, used by DirectTracks.
bool AudioFlinger::PlaybackThread::Track::presentationComplete(uint32_t latencyMs)
{
    // For Offloaded or Direct tracks.

    // For a direct track, we incorporated time based testing for presentationComplete.

    // For an offloaded track the HAL+h/w delay is variable so a HAL drain() is used
    // to detect when all frames have been played. In this case latencyMs isn't
    // useful because it doesn't always reflect whether there is data in the h/w
    // buffers, particularly if a track has been paused and resumed during draining

    // Scaling exists on internal branch.
    //constexpr float MIN_SPEED = 0.125f; // min speed scaling allowed for timely response.
    if (mPresentationCompleteTimeNs == 0) {
        mPresentationCompleteTimeNs = systemTime() + latencyMs * 1e6; // / fmax(mSpeed, MIN_SPEED);
        ALOGV("%s(%d): set: latencyMs %u  mPresentationCompleteTimeNs:%lld",
                __func__, mId, latencyMs, (long long) mPresentationCompleteTimeNs);
    }

    bool complete;
    if (isOffloaded()) {
        complete = true;
    } else { // Direct
        complete = systemTime() >= mPresentationCompleteTimeNs;
        ALOGV("%s(%d): %s", __func__, mId, (complete ? "complete" : "waiting"));
    }
    if (complete) {
        notifyPresentationComplete();
        return true;
    }
    return false;
}

void AudioFlinger::PlaybackThread::Track::notifyPresentationComplete()
{
    // This only triggers once. TODO: should we enforce this?
    triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE);
    mAudioTrackServerProxy->setStreamEndDone();
}

void AudioFlinger::PlaybackThread::Track::triggerEvents(AudioSystem::sync_event_t type)
{
    for (size_t i = 0; i < mSyncEvents.size();) {