Merge "AudioTrack: Limit timestamp time lag after start" into oc-mr1-dev am: cea54cf940

am: 0fbd5badd5

Change-Id: I910d96c6901bad81987191ea2485435a6fcf8a7f
gugelfrei
Andy Hung 7 years ago committed by android-build-merger
commit e247023e78

@ -65,6 +65,14 @@ static int64_t convertTimespecToUs(const struct timespec &tv)
return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000;
}
// TODO move to audio_utils.
static inline struct timespec convertNsToTimespec(int64_t ns) {
struct timespec tv;
tv.tv_sec = static_cast<time_t>(ns / NANOS_PER_SECOND);
tv.tv_nsec = static_cast<long>(ns % NANOS_PER_SECOND);
return tv;
}
// current monotonic time in microseconds.
static int64_t getNowUs()
{
@ -541,7 +549,8 @@ status_t AudioTrack::set(
mUpdatePeriod = 0;
mPosition = 0;
mReleased = 0;
mStartUs = 0;
mStartNs = 0;
mStartFromZeroUs = 0;
AudioSystem::acquireAudioSessionId(mSessionId, mClientPid);
mSequence = 1;
mObservedSequence = mSequence;
@ -589,6 +598,7 @@ status_t AudioTrack::start()
mStartEts.clear();
}
}
mStartNs = systemTime(); // save this for timestamp adjustment after starting.
if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) {
// reset current position as seen by client to 0
mPosition = 0;
@ -617,7 +627,7 @@ status_t AudioTrack::start()
// since the flush is asynchronous and stop may not fully drain.
// We save the time when the track is started to later verify whether
// the counters are realistic (i.e. start from zero after this time).
mStartUs = getNowUs();
mStartFromZeroUs = mStartNs / 1000;
// force refresh of remaining frames by processAudioBuffer() as last
// write before stop could be partial.
@ -2573,8 +2583,7 @@ status_t AudioTrack::getTimestamp_l(AudioTimestamp& timestamp)
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.
timestamp.mTime = convertNsToTimespec(limit);
}
}
mPreviousLocation = location;
@ -2617,18 +2626,18 @@ status_t AudioTrack::getTimestamp_l(AudioTimestamp& timestamp)
// the previous song under gapless playback.
// However, we sometimes see zero timestamps, then a glitch of
// the previous song's position, and then correct timestamps afterwards.
if (mStartUs != 0 && mSampleRate != 0) {
if (mStartFromZeroUs != 0 && mSampleRate != 0) {
static const int kTimeJitterUs = 100000; // 100 ms
static const int k1SecUs = 1000000;
const int64_t timeNow = getNowUs();
if (timeNow < mStartUs + k1SecUs) { // within first second of starting
if (timeNow < mStartFromZeroUs + k1SecUs) { // within first second of starting
const int64_t timestampTimeUs = convertTimespecToUs(timestamp.mTime);
if (timestampTimeUs < mStartUs) {
if (timestampTimeUs < mStartFromZeroUs) {
return WOULD_BLOCK; // stale timestamp time, occurs before start.
}
const int64_t deltaTimeUs = timestampTimeUs - mStartUs;
const int64_t deltaTimeUs = timestampTimeUs - mStartFromZeroUs;
const int64_t deltaPositionByUs = (double)timestamp.mPosition * 1000000
/ ((double)mSampleRate * mPlaybackRate.mSpeed);
@ -2651,10 +2660,10 @@ status_t AudioTrack::getTimestamp_l(AudioTimestamp& timestamp)
return WOULD_BLOCK;
}
if (deltaPositionByUs != 0) {
mStartUs = 0; // don't check again, we got valid nonzero position.
mStartFromZeroUs = 0; // don't check again, we got valid nonzero position.
}
} else {
mStartUs = 0; // don't check again, start time expired.
mStartFromZeroUs = 0; // don't check again, start time expired.
}
mTimestampStartupGlitchReported = false;
}
@ -2692,14 +2701,33 @@ status_t AudioTrack::getTimestamp_l(AudioTimestamp& timestamp)
// Prevent retrograde motion in timestamp.
// This is sometimes caused by erratic reports of the available space in the ALSA drivers.
if (status == NO_ERROR) {
// previousTimestampValid is set to false when starting after a stop or flush.
if (previousTimestampValid) {
const int64_t previousTimeNanos =
audio_utils_ns_from_timespec(&mPreviousTimestamp.mTime);
const int64_t currentTimeNanos = audio_utils_ns_from_timespec(&timestamp.mTime);
int64_t currentTimeNanos = audio_utils_ns_from_timespec(&timestamp.mTime);
// Fix stale time when checking timestamp right after start().
//
// For offload compatibility, use a default lag value here.
// Any time discrepancy between this update and the pause timestamp is handled
// by the retrograde check afterwards.
const int64_t lagNs = int64_t(mAfLatency * 1000000LL);
const int64_t limitNs = mStartNs - lagNs;
if (currentTimeNanos < limitNs) {
ALOGD("correcting timestamp time for pause, "
"currentTimeNanos: %lld < limitNs: %lld < mStartNs: %lld",
(long long)currentTimeNanos, (long long)limitNs, (long long)mStartNs);
timestamp.mTime = convertNsToTimespec(limitNs);
currentTimeNanos = limitNs;
}
// retrograde check
if (currentTimeNanos < previousTimeNanos) {
ALOGW("retrograde timestamp time corrected, %lld < %lld",
(long long)currentTimeNanos, (long long)previousTimeNanos);
timestamp.mTime = mPreviousTimestamp.mTime;
// currentTimeNanos not used below.
}
// Looking at signed delta will work even when the timestamps
@ -2909,7 +2937,7 @@ bool AudioTrack::hasStarted()
case STATE_STOPPED:
if (isOffloadedOrDirect_l()) {
// check if we have started in the past to return true.
return mStartUs > 0;
return mStartFromZeroUs > 0;
}
// A normal audio track may still be draining, so
// check if stream has ended. This covers fasttrack position

@ -1085,8 +1085,10 @@ protected:
// reset by stop() but continues monotonically
// after new IAudioTrack to restore mPosition,
// and could be easily widened to uint64_t
int64_t mStartUs; // the start time after flush or stop.
int64_t mStartFromZeroUs; // the start time after flush or stop,
// when position should be 0.
// only used for offloaded and direct tracks.
int64_t mStartNs; // the time when start() is called.
ExtendedTimestamp mStartEts; // Extended timestamp at start for normal
// AudioTracks.
AudioTimestamp mStartTs; // Timestamp at start for offloaded or direct

@ -1153,7 +1153,18 @@ int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {
return writtenAudioDurationUs - (mediaUs - mAudioFirstAnchorTimeMediaUs);
}
}
return writtenAudioDurationUs - mAudioSink->getPlayedOutDurationUs(nowUs);
const int64_t audioSinkPlayedUs = mAudioSink->getPlayedOutDurationUs(nowUs);
int64_t pendingUs = writtenAudioDurationUs - audioSinkPlayedUs;
if (pendingUs < 0) {
// This shouldn't happen unless the timestamp is stale.
ALOGW("%s: pendingUs %lld < 0, clamping to zero, potential resume after pause "
"writtenAudioDurationUs: %lld, audioSinkPlayedUs: %lld",
__func__, (long long)pendingUs,
(long long)writtenAudioDurationUs, (long long)audioSinkPlayedUs);
pendingUs = 0;
}
return pendingUs;
}
int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {

Loading…
Cancel
Save