NuPlayer: Play out remaining audio data when recycling isn't possible
Don't flush it immediately.
Bug: 26530291
Change-Id: I0427633402fa251ec62e2b70e47a0a7b451d3ea2
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index b96a450..eaaef4a 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -771,6 +771,9 @@
* 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 @@
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);
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 1de91bf..e757c7c 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -2188,6 +2188,11 @@
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 @@
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)
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 0025660..251fc53 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1578,7 +1578,19 @@
}
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