AudioTrack: Advance timestamp time during pause
Update MediaPlayer code to match.
This will change the behavior on the AudioTrack Java side,
but is within the API and should make timestamp handling easier.
Test: Photos app with pause and play.
Bug: 30502030
Change-Id: I0e9129ce6af5b920ad71e63ad0c205de7561acf2
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index c96f16a..96fe907 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -50,6 +50,8 @@
return x > y ? x : y;
}
+static const int32_t NANOS_PER_SECOND = 1000000000;
+
static inline nsecs_t framesToNanoseconds(ssize_t frames, uint32_t sampleRate, float speed)
{
return ((double)frames * 1000000000) / ((double)sampleRate * speed);
@@ -60,6 +62,11 @@
return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000;
}
+static inline nsecs_t convertTimespecToNs(const struct timespec &tv)
+{
+ return tv.tv_sec * (long long)NANOS_PER_SECOND + tv.tv_nsec;
+}
+
// current monotonic time in microseconds.
static int64_t getNowUs()
{
@@ -2393,6 +2400,26 @@
ALOGV_IF(mPreviousLocation == ExtendedTimestamp::LOCATION_SERVER,
"getTimestamp() location moved from server to kernel");
}
+
+ // We update the timestamp time even when paused.
+ if (mState == STATE_PAUSED /* not needed: STATE_PAUSED_STOPPING */) {
+ const int64_t now = systemTime();
+ const int64_t at = convertTimespecToNs(timestamp.mTime);
+ const int64_t lag =
+ (ets.mTimeNs[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK] < 0 ||
+ ets.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK] < 0)
+ ? int64_t(mAfLatency * 1000000LL)
+ : (ets.mPosition[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK]
+ - ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK])
+ * NANOS_PER_SECOND / mSampleRate;
+ const int64_t limit = now - lag; // no earlier than this limit
+ if (at < limit) {
+ ALOGV("timestamp pause lag:%lld adjusting from %lld to %lld",
+ (long long)lag, (long long)at, (long long)limit);
+ timestamp.mTime.tv_sec = limit / NANOS_PER_SECOND;
+ timestamp.mTime.tv_nsec = limit % NANOS_PER_SECOND; // compiler opt.
+ }
+ }
mPreviousLocation = location;
} else {
// right after AudioTrack is started, one may not find a timestamp
@@ -2412,6 +2439,7 @@
// use cached paused position in case another offloaded track is running.
timestamp.mPosition = mPausedPosition;
clock_gettime(CLOCK_MONOTONIC, ×tamp.mTime);
+ // TODO: adjust for delay
return NO_ERROR;
}
@@ -2498,21 +2526,18 @@
// This is sometimes caused by erratic reports of the available space in the ALSA drivers.
if (status == NO_ERROR) {
if (previousTimestampValid) {
-#define TIME_TO_NANOS(time) ((int64_t)(time).tv_sec * 1000000000 + (time).tv_nsec)
- const int64_t previousTimeNanos = TIME_TO_NANOS(mPreviousTimestamp.mTime);
- const int64_t currentTimeNanos = TIME_TO_NANOS(timestamp.mTime);
-#undef TIME_TO_NANOS
+ const int64_t previousTimeNanos = convertTimespecToNs(mPreviousTimestamp.mTime);
+ const int64_t currentTimeNanos = convertTimespecToNs(timestamp.mTime);
if (currentTimeNanos < previousTimeNanos) {
- ALOGW("retrograde timestamp time");
- // FIXME Consider blocking this from propagating upwards.
+ ALOGW("retrograde timestamp time corrected, %lld < %lld",
+ (long long)currentTimeNanos, (long long)previousTimeNanos);
+ timestamp.mTime = mPreviousTimestamp.mTime;
}
// Looking at signed delta will work even when the timestamps
// are wrapping around.
int32_t deltaPosition = (Modulo<uint32_t>(timestamp.mPosition)
- mPreviousTimestamp.mPosition).signedValue();
- // position can bobble slightly as an artifact; this hides the bobble
- static const int32_t MINIMUM_POSITION_DELTA = 8;
if (deltaPosition < 0) {
// Only report once per position instead of spamming the log.
if (!mRetrogradeMotionReported) {
@@ -2525,9 +2550,21 @@
} else {
mRetrogradeMotionReported = false;
}
- if (deltaPosition < MINIMUM_POSITION_DELTA) {
- timestamp = mPreviousTimestamp; // Use last valid timestamp.
+ if (deltaPosition < 0) {
+ timestamp.mPosition = mPreviousTimestamp.mPosition;
+ deltaPosition = 0;
}
+#if 0
+ // Uncomment this to verify audio timestamp rate.
+ const int64_t deltaTime =
+ convertTimespecToNs(timestamp.mTime) - previousTimeNanos;
+ if (deltaTime != 0) {
+ const int64_t computedSampleRate =
+ deltaPosition * (long long)NANOS_PER_SECOND / deltaTime;
+ ALOGD("computedSampleRate:%u sampleRate:%u",
+ (unsigned)computedSampleRate, mSampleRate);
+ }
+#endif
}
mPreviousTimestamp = timestamp;
mPreviousTimestampValid = true;