Implement client playback timestamps with 64 bit accuracy
Provide server timestamps if the HAL doesn't provide it.
Provide monotonic - boottime translation.
Bug: 17472992
Bug: 26682703
Bug: 27749434
Change-Id: I6c9b213d9f9284092e34d57f52870e02c72df62a
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index e70c611..1de91bf 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -500,6 +500,8 @@
mTimestampStartupGlitchReported = false;
mRetrogradeMotionReported = false;
mUnderrunCountOffset = 0;
+ mFramesWritten = 0;
+ mFramesWrittenServerOffset = 0;
return NO_ERROR;
}
@@ -537,6 +539,14 @@
// 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 @@
releaseBuffer(&audioBuffer);
}
+ if (written > 0) {
+ mFramesWritten += written / mFrameSize;
+ }
return written;
}
@@ -1923,6 +1936,7 @@
requested = &timeout;
}
+ size_t writtenFrames = 0;
while (mRemainingFrames > 0) {
Buffer audioBuffer;
@@ -2024,6 +2038,7 @@
}
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 @@
#endif
}
+ if (writtenFrames > 0) {
+ AutoMutex lock(mLock);
+ mFramesWritten += writtenFrames;
+ }
mRemainingFrames = notificationFrames;
mRetryOnPartialBuffer = true;
@@ -2109,6 +2128,7 @@
}
if (mState == STATE_ACTIVE) {
result = mAudioTrack->start();
+ mFramesWrittenServerOffset = mFramesWritten; // server resets to zero so we offset
}
}
if (result != NO_ERROR) {
@@ -2162,6 +2182,42 @@
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);