AudioTrack: Improve pause handling.
Add pauseAndWait() method to ensure that the pause is completed
(ramped to silence) before any other operation, especially flush().
Incorporate into MediaPlayer pause().
Test: Clarity video with scrubbing bar.
Test: Ringtone and Alarm playback.
Bug: 196194083
Change-Id: Id8842c6c8abfd76d11b8316a95052c2e0da7fb7c
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index b9cdab8..746d875 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -5089,7 +5089,7 @@
break;
case TrackBase::IDLE:
default:
- LOG_ALWAYS_FATAL("unexpected track state %d", track->mState);
+ LOG_ALWAYS_FATAL("unexpected track state %d", (int)track->mState);
}
if (isActive) {
@@ -5148,7 +5148,7 @@
// TODO Remove the ALOGW when this theory is confirmed.
ALOGW("fast track %d should have been active; "
"mState=%d, mTrackMask=%#x, recentUnderruns=%u, isShared=%d",
- j, track->mState, state->mTrackMask, recentUnderruns,
+ j, (int)track->mState, state->mTrackMask, recentUnderruns,
track->sharedBuffer() != 0);
// Since the FastMixer state already has the track inactive, do nothing here.
}
@@ -8041,7 +8041,7 @@
ALOGV("active record track PAUSING -> ACTIVE");
recordTrack->mState = TrackBase::ACTIVE;
} else {
- ALOGV("active record track state %d", recordTrack->mState);
+ ALOGV("active record track state %d", (int)recordTrack->mState);
}
return status;
}
@@ -8067,7 +8067,7 @@
}
if (recordTrack->mState != TrackBase::STARTING_1) {
ALOGW("%s(%d): unsynchronized mState:%d change",
- __func__, recordTrack->id(), recordTrack->mState);
+ __func__, recordTrack->id(), (int)recordTrack->mState);
// Someone else has changed state, let them take over,
// leave mState in the new state.
recordTrack->clearSyncStartEvent();
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 92f129c..5311fe2 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -23,7 +23,7 @@
class TrackBase : public ExtendedAudioBufferProvider, public RefBase {
public:
- enum track_state {
+ enum track_state : int32_t {
IDLE,
FLUSHED, // for PlaybackTracks only
STOPPED,
@@ -271,6 +271,7 @@
void releaseCblk() {
if (mCblk != nullptr) {
+ mState.clear();
mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
if (mClient == 0) {
free(mCblk);
@@ -355,7 +356,7 @@
// except for OutputTrack when it is in local memory
size_t mBufferSize; // size of mBuffer in bytes
// we don't really need a lock for these
- track_state mState;
+ MirroredVariable<track_state> mState;
const audio_attributes_t mAttr;
const uint32_t mSampleRate; // initial sample rate only; for tracks which
// support dynamic rates, the current value is in control block
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index d2a30b1..e0c5fa5 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -234,7 +234,11 @@
#ifdef TEE_SINK
mTee.set(sampleRate, mChannelCount, format, NBAIO_Tee::TEE_FLAG_TRACK);
#endif
-
+ // mState is mirrored for the client to read.
+ mState.setMirror(&mCblk->mState);
+ // ensure our state matches up until we consolidate the enumeration.
+ static_assert(CBLK_STATE_IDLE == IDLE);
+ static_assert(CBLK_STATE_PAUSING == PAUSING);
}
}
@@ -933,7 +937,7 @@
buffer->raw = buf.mRaw;
if (buf.mFrameCount == 0 && !isStopping() && !isStopped() && !isPaused() && !isOffloaded()) {
ALOGV("%s(%d): underrun, framesReady(%zu) < framesDesired(%zd), state: %d",
- __func__, mId, buf.mFrameCount, desiredFrames, mState);
+ __func__, mId, buf.mFrameCount, desiredFrames, (int)mState);
mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
} else {
mAudioTrackServerProxy->tallyUnderrunFrames(0);
@@ -1590,7 +1594,7 @@
(mState == STOPPED)))) {
ALOGW("%s(%d): in invalid state %d on session %d %s mode, framesReady %zu",
__func__, mId,
- mState, mSessionId, (mSharedBuffer != 0) ? "static" : "stream", framesReady());
+ (int)mState, mSessionId, (mSharedBuffer != 0) ? "static" : "stream", framesReady());
event->cancel();
return INVALID_OPERATION;
}