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

Commit ba27fff4 authored by Andy Hung's avatar Andy Hung Committed by android-build-merger
Browse files

Merge "Implement client playback timestamps with 64 bit accuracy" into nyc-dev

am: f3bcfebc

* commit 'f3bcfebc':
  Implement client playback timestamps with 64 bit accuracy

Change-Id: I77ef69988b0eb0cb5b24626c2984498304b42f68
parents a6078f7c f3bcfebc
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -69,12 +69,23 @@ struct ExtendedTimestamp {
    // or NTP adjustment.
    int64_t mTimebaseOffset[TIMEBASE_MAX];

    // Playback only:
    // mFlushed is number of flushed frames before entering the server mix;
    // hence not included in mPosition. This is used for adjusting server positions
    // information for frames "dropped".
    // FIXME: This variable should be eliminated, with the offset added on the server side
    // before sending to client, but differences in legacy position offset handling
    // and new extended timestamps require this to be maintained as a separate quantity.
    int64_t mFlushed;

    // Call to reset the timestamp to the original (invalid) state
    void clear() {
        memset(mPosition, 0, sizeof(mPosition)); // actually not necessary if time is -1
        for (int i = 0; i < LOCATION_MAX; ++i) {
            mTimeNs[i] = -1;
        }
        memset(mTimebaseOffset, 0, sizeof(mTimebaseOffset));
        mFlushed = 0;
    }

    // Returns the best timestamp as judged from the closest-to-hw stage in the
+47 −1
Original line number Diff line number Diff line
@@ -727,12 +727,51 @@ public:
     *                     because the audio device changed or AudioFlinger died.
     *                     This typically occurs for direct or offload tracks
     *                     or if mDoNotReconnect is true.
     *         INVALID_OPERATION  if called on a FastTrack, wrong state, or some other error.
     *         INVALID_OPERATION  wrong state, or some other error.
     *
     * The timestamp parameter is undefined on return, if status is not NO_ERROR.
     */
            status_t    getTimestamp(AudioTimestamp& timestamp);

    /* Return the extended timestamp, with additional timebase info and improved drain behavior.
     *
     * This is similar to the AudioTrack.java API:
     * getTimestamp(@NonNull AudioTimestamp timestamp, @AudioTimestamp.Timebase int timebase)
     *
     * Some differences between this method and the getTimestamp(AudioTimestamp& timestamp) method
     *
     *   1. stop() by itself does not reset the frame position.
     *      A following start() resets the frame position to 0.
     *   2. flush() by itself does not reset the frame position.
     *      The frame position advances by the number of frames flushed,
     *      when the first frame after flush reaches the audio sink.
     *   3. BOOTTIME clock offsets are provided to help synchronize with
     *      non-audio streams, e.g. sensor data.
     *   4. Position is returned with 64 bits of resolution.
     *
     * Parameters:
     *  timestamp: A pointer to the caller allocated ExtendedTimestamp.
     *
     * Returns NO_ERROR    on success; timestamp is filled with valid data.
     *         BAD_VALUE   if timestamp is NULL.
     *         WOULD_BLOCK if called immediately after start() when the number
     *                     of frames consumed is less than the
     *                     overall hardware latency to physical output. In WOULD_BLOCK cases,
     *                     one might poll again, or use getPosition(), or use 0 position and
     *                     current time for the timestamp.
     *                     If WOULD_BLOCK is returned, the timestamp is still
     *                     modified with the LOCATION_CLIENT portion filled.
     *         DEAD_OBJECT if AudioFlinger dies or the output device changes and
     *                     the track cannot be automatically restored.
     *                     The application needs to recreate the AudioTrack
     *                     because the audio device changed or AudioFlinger died.
     *                     This typically occurs for direct or offloaded tracks
     *                     or if mDoNotReconnect is true.
     *         INVALID_OPERATION  if called on a offloaded or direct track.
     *                     Use getTimestamp(AudioTimestamp& timestamp) instead.
     */
            status_t getTimestamp(ExtendedTimestamp *timestamp);

    /* Add an AudioDeviceCallback. The caller will be notified when the audio device to which this
     * AudioTrack is routed is updated.
     * Replaces any previously installed callback.
@@ -956,6 +995,13 @@ protected:

    uint32_t                mUnderrunCountOffset;   // updated when restoring tracks

    int64_t                 mFramesWritten;         // total frames written. reset to zero after
                                                    // the start() following stop(). It is not
                                                    // changed after restoring the track or
                                                    // after flush.
    int64_t                 mFramesWrittenServerOffset; // An offset to server frames due to
                                                    // restoring AudioTrack, or stop/start.

    audio_output_flags_t    mFlags;                 // same as mOrigFlags, except for bits that may
                                                    // be denied by client or server, such as
                                                    // AUDIO_OUTPUT_FLAG_FAST.  mLock must be
+4 −1
Original line number Diff line number Diff line
@@ -522,6 +522,9 @@ public:
        mTimestampMutator.push(timestamp);
    }

    // Total count of the number of flushed frames since creation (never reset).
    virtual int64_t     framesFlushed() const { return mFlushed; }

    // Get dynamic buffer size from the shared control block.
    uint32_t            getBufferSizeInFrames() const {
        return android_atomic_acquire_load((int32_t *)&mCblk->mBufferSizeInFrames);
@@ -531,7 +534,7 @@ protected:
    size_t      mAvailToClient; // estimated frames available to client prior to releaseBuffer()
    int32_t     mFlush;         // our copy of cblk->u.mStreaming.mFlush, for streaming output only
    int64_t     mReleased;      // our copy of cblk->mServer, at 64 bit resolution

    int64_t     mFlushed;       // flushed frames to account for client-server discrepancy
    ExtendedTimestampQueue::Mutator mTimestampMutator;
};

+56 −0
Original line number Diff line number Diff line
@@ -500,6 +500,8 @@ status_t AudioTrack::set(
    mTimestampStartupGlitchReported = false;
    mRetrogradeMotionReported = false;
    mUnderrunCountOffset = 0;
    mFramesWritten = 0;
    mFramesWrittenServerOffset = 0;

    return NO_ERROR;
}
@@ -537,6 +539,14 @@ status_t AudioTrack::start()
        // Note: the if is technically unnecessary because previousState == STATE_FLUSHED
        // is only for streaming tracks, and mMarkerReached is already set to false.
        if (previousState == STATE_STOPPED) {
            // read last server side position change via timestamp
            ExtendedTimestamp ets;
            if (mProxy->getTimestamp(&ets) == OK &&
                    ets.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] > 0) {
                mFramesWrittenServerOffset = -(ets.mPosition[ExtendedTimestamp::LOCATION_SERVER]
                                                             + ets.mFlushed);
            }
            mFramesWritten = 0;
            mProxy->clearTimestamp(); // need new server push for valid timestamp
            mMarkerReached = false;
        }
@@ -1657,6 +1667,9 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)
        releaseBuffer(&audioBuffer);
    }

    if (written > 0) {
        mFramesWritten += written / mFrameSize;
    }
    return written;
}

@@ -1923,6 +1936,7 @@ nsecs_t AudioTrack::processAudioBuffer()
        requested = &timeout;
    }

    size_t writtenFrames = 0;
    while (mRemainingFrames > 0) {

        Buffer audioBuffer;
@@ -2024,6 +2038,7 @@ nsecs_t AudioTrack::processAudioBuffer()
        }

        releaseBuffer(&audioBuffer);
        writtenFrames += releasedFrames;

        // FIXME here is where we would repeat EVENT_MORE_DATA again on same advanced buffer
        // if callback doesn't like to accept the full chunk
@@ -2047,6 +2062,10 @@ nsecs_t AudioTrack::processAudioBuffer()
#endif

    }
    if (writtenFrames > 0) {
        AutoMutex lock(mLock);
        mFramesWritten += writtenFrames;
    }
    mRemainingFrames = notificationFrames;
    mRetryOnPartialBuffer = true;

@@ -2109,6 +2128,7 @@ status_t AudioTrack::restoreTrack_l(const char *from)
        }
        if (mState == STATE_ACTIVE) {
            result = mAudioTrack->start();
            mFramesWrittenServerOffset = mFramesWritten; // server resets to zero so we offset
        }
    }
    if (result != NO_ERROR) {
@@ -2162,6 +2182,42 @@ status_t AudioTrack::setParameters(const String8& keyValuePairs)
    return mAudioTrack->setParameters(keyValuePairs);
}

status_t AudioTrack::getTimestamp(ExtendedTimestamp *timestamp)
{
    if (timestamp == nullptr) {
        return BAD_VALUE;
    }
    AutoMutex lock(mLock);
    if (mCblk->mFlags & CBLK_INVALID) {
        const status_t status = restoreTrack_l("getTimestampExtended");
        if (status != OK) {
            // per getTimestamp() API doc in header, we return DEAD_OBJECT here,
            // recommending that the track be recreated.
            return DEAD_OBJECT;
        }
    }
    // check for offloaded/direct here in case restoring somehow changed those flags.
    if (isOffloadedOrDirect_l()) {
        return INVALID_OPERATION; // not supported
    }
    status_t status = mProxy->getTimestamp(timestamp);
    bool found = false;
    if (status == OK) {
        timestamp->mPosition[ExtendedTimestamp::LOCATION_CLIENT] = mFramesWritten;
        timestamp->mTimeNs[ExtendedTimestamp::LOCATION_CLIENT] = 0;
        // server side frame offset in case AudioTrack has been restored.
        for (int i = ExtendedTimestamp::LOCATION_SERVER;
                i < ExtendedTimestamp::LOCATION_MAX; ++i) {
            if (timestamp->mTimeNs[i] >= 0) {
                // apply server offset and the "flush frame correction here"
                timestamp->mPosition[i] += mFramesWrittenServerOffset + timestamp->mFlushed;
                found = true;
            }
        }
    }
    return found ? OK : WOULD_BLOCK;
}

status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
{
    AutoMutex lock(mLock);
+2 −1
Original line number Diff line number Diff line
@@ -615,7 +615,7 @@ void StaticAudioTrackClientProxy::getBufferPositionAndLoopCount(
ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
        size_t frameSize, bool isOut, bool clientInServer)
    : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer),
      mAvailToClient(0), mFlush(0), mReleased(0)
      mAvailToClient(0), mFlush(0), mReleased(0), mFlushed(0)
    , mTimestampMutator(&cblk->mExtendedTimestampQueue)
{
    cblk->mBufferSizeInFrames = frameCount;
@@ -671,6 +671,7 @@ status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
                            mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
                }
            }
            mFlushed += (newFront - front) & mask;
            front = newFront;
        }
    } else {
Loading