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

Commit e13f8a60 authored by Andy Hung's avatar Andy Hung
Browse files

NuPlayer: Play out remaining audio data when recycling isn't possible

Don't flush it immediately.

Bug: 26530291
Change-Id: I0427633402fa251ec62e2b70e47a0a7b451d3ea2
parent ea2b9c07
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -771,6 +771,9 @@ public:
     *                     Use getTimestamp(AudioTimestamp& timestamp) instead.
     */
            status_t getTimestamp(ExtendedTimestamp *timestamp);
private:
            status_t getTimestamp_l(ExtendedTimestamp *timestamp);
public:

    /* Add an AudioDeviceCallback. The caller will be notified when the audio device to which this
     * AudioTrack is routed is updated.
@@ -794,6 +797,23 @@ public:
            status_t removeAudioDeviceCallback(
                    const sp<AudioSystem::AudioDeviceCallback>& callback);

    /* Obtain the pending duration in milliseconds for playback of pure PCM
     * (mixable without embedded timing) data remaining in AudioTrack.
     *
     * This is used to estimate the drain time for the client-server buffer
     * so the choice of ExtendedTimestamp::LOCATION_SERVER is default.
     * One may optionally request to find the duration to play through the HAL
     * by specifying a location ExtendedTimestamp::LOCATION_KERNEL; however,
     * INVALID_OPERATION may be returned if the kernel location is unavailable.
     *
     * Returns NO_ERROR  if successful.
     *         INVALID_OPERATION if ExtendedTimestamp::LOCATION_KERNEL cannot be obtained
     *                   or the AudioTrack does not contain pure PCM data.
     *         BAD_VALUE if msec is nullptr or location is invalid.
     */
            status_t pendingDuration(int32_t *msec,
                    ExtendedTimestamp::Location location = ExtendedTimestamp::LOCATION_SERVER);

protected:
    /* copying audio tracks is not allowed */
                        AudioTrack(const AudioTrack& other);
+55 −0
Original line number Diff line number Diff line
@@ -2188,6 +2188,11 @@ status_t AudioTrack::getTimestamp(ExtendedTimestamp *timestamp)
        return BAD_VALUE;
    }
    AutoMutex lock(mLock);
    return getTimestamp_l(timestamp);
}

status_t AudioTrack::getTimestamp_l(ExtendedTimestamp *timestamp)
{
    if (mCblk->mFlags & CBLK_INVALID) {
        const status_t status = restoreTrack_l("getTimestampExtended");
        if (status != OK) {
@@ -2515,6 +2520,56 @@ status_t AudioTrack::removeAudioDeviceCallback(
    return NO_ERROR;
}

status_t AudioTrack::pendingDuration(int32_t *msec, ExtendedTimestamp::Location location)
{
    if (msec == nullptr ||
            (location != ExtendedTimestamp::LOCATION_SERVER
                    && location != ExtendedTimestamp::LOCATION_KERNEL)) {
        return BAD_VALUE;
    }
    AutoMutex lock(mLock);
    // inclusive of offloaded and direct tracks.
    //
    // It is possible, but not enabled, to allow duration computation for non-pcm
    // audio_has_proportional_frames() formats because currently they have
    // the drain rate equivalent to the pcm sample rate * framesize.
    if (!isPurePcmData_l()) {
        return INVALID_OPERATION;
    }
    ExtendedTimestamp ets;
    if (getTimestamp_l(&ets) == OK
            && ets.mTimeNs[location] > 0) {
        int64_t diff = ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT]
                - ets.mPosition[location];
        if (diff < 0) {
            *msec = 0;
        } else {
            // ms is the playback time by frames
            int64_t ms = (int64_t)((double)diff * 1000 /
                    ((double)mSampleRate * mPlaybackRate.mSpeed));
            // clockdiff is the timestamp age (negative)
            int64_t clockdiff = (mState != STATE_ACTIVE) ? 0 :
                    ets.mTimeNs[location]
                    + ets.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_MONOTONIC]
                    - systemTime(SYSTEM_TIME_MONOTONIC);

            //ALOGV("ms: %lld  clockdiff: %lld", (long long)ms, (long long)clockdiff);
            static const int NANOS_PER_MILLIS = 1000000;
            *msec = (int32_t)(ms + clockdiff / NANOS_PER_MILLIS);
        }
        return NO_ERROR;
    }
    if (location != ExtendedTimestamp::LOCATION_SERVER) {
        return INVALID_OPERATION; // LOCATION_KERNEL is not available
    }
    // use server position directly (offloaded and direct arrive here)
    updateAndGetPosition_l();
    int32_t diff = (Modulo<uint32_t>(mFramesWritten) - mPosition).signedValue();
    *msec = (diff <= 0) ? 0
            : (int32_t)((double)diff * 1000 / ((double)mSampleRate * mPlaybackRate.mSpeed));
    return NO_ERROR;
}

// =========================================================================

void AudioTrack::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
+13 −1
Original line number Diff line number Diff line
@@ -1578,7 +1578,19 @@ void MediaPlayerService::AudioOutput::deleteRecycledTrack_l()
        }

        if ((mRecycledTrack->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) {
            mRecycledTrack->flush();
            int32_t msec = 0;
            if (!mRecycledTrack->stopped()) { // check if active
                 (void)mRecycledTrack->pendingDuration(&msec);
            }
            mRecycledTrack->stop(); // ensure full data drain
            ALOGD("deleting recycled track, waiting for data drain (%d msec)", msec);
            if (msec > 0) {
                static const int32_t WAIT_LIMIT_MS = 3000;
                if (msec > WAIT_LIMIT_MS) {
                    msec = WAIT_LIMIT_MS;
                }
                usleep(msec * 1000LL);
            }
        }
        // An offloaded track isn't flushed because the STREAM_END is reported
        // slightly prematurely to allow time for the gapless track switch