VolumeShaper: Improve restore

Consider whether VolumeShaper has been started or not when
restoring (position). If the VolumeShaper hasn't been started
we restore in that state.  If it has been started already,
we advance to the end assuming the duration has been played out.

Test: CTS and headset / kill audioserver
Bug: 37536598
Change-Id: I4b55dca6f6a859563fd20bad4c8f67d2c92321c0
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 3a0ce5e..4baf253 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -652,6 +652,9 @@
             get_sched_policy(0, &mPreviousSchedulingGroup);
             androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
         }
+
+        // Start our local VolumeHandler for restoration purposes.
+        mVolumeHandler->setStarted();
     } else {
         ALOGE("start() status %d", status);
         mState = previousState;
@@ -2254,17 +2257,20 @@
             }
         }
         // restore volume handler
-        mVolumeHandler->forall([this](const sp<VolumeShaper::Configuration> &configuration,
-                const sp<VolumeShaper::Operation> &operation) -> VolumeShaper::Status {
-            sp<VolumeShaper::Operation> operationToEnd = new VolumeShaper::Operation(*operation);
+        mVolumeHandler->forall([this](const VolumeShaper &shaper) -> VolumeShaper::Status {
+            sp<VolumeShaper::Operation> operationToEnd =
+                    new VolumeShaper::Operation(shaper.mOperation);
             // TODO: Ideally we would restore to the exact xOffset position
             // as returned by getVolumeShaperState(), but we don't have that
             // information when restoring at the client unless we periodically poll
             // the server or create shared memory state.
             //
-            // For now, we simply advance to the end of the VolumeShaper effect.
-            operationToEnd->setXOffset(1.f);
-            return mAudioTrack->applyVolumeShaper(configuration, operationToEnd);
+            // For now, we simply advance to the end of the VolumeShaper effect
+            // if it has been started.
+            if (shaper.isStarted()) {
+                operationToEnd->setXOffset(1.f);
+            }
+            return mAudioTrack->applyVolumeShaper(shaper.mConfiguration, operationToEnd);
         });
 
         if (mState == STATE_ACTIVE) {
@@ -2334,19 +2340,36 @@
     AutoMutex lock(mLock);
     mVolumeHandler->setIdIfNecessary(configuration);
     VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(configuration, operation);
+
+    if (status == DEAD_OBJECT) {
+        if (restoreTrack_l("applyVolumeShaper") == OK) {
+            status = mAudioTrack->applyVolumeShaper(configuration, operation);
+        }
+    }
     if (status >= 0) {
         // save VolumeShaper for restore
         mVolumeHandler->applyVolumeShaper(configuration, operation);
+        if (mState == STATE_ACTIVE || mState == STATE_STOPPING) {
+            mVolumeHandler->setStarted();
+        }
+    } else {
+        // warn only if not an expected restore failure.
+        ALOGW_IF(!((isOffloadedOrDirect_l() || mDoNotReconnect) && status == DEAD_OBJECT),
+                "applyVolumeShaper failed: %d", status);
     }
     return status;
 }
 
 sp<VolumeShaper::State> AudioTrack::getVolumeShaperState(int id)
 {
-    // TODO: To properly restore the AudioTrack
-    // we will need to save the last state in AudioTrackShared.
     AutoMutex lock(mLock);
-    return mAudioTrack->getVolumeShaperState(id);
+    sp<VolumeShaper::State> state = mAudioTrack->getVolumeShaperState(id);
+    if (state.get() == nullptr && (mCblk->mFlags & CBLK_INVALID) != 0) {
+        if (restoreTrack_l("getVolumeShaperState") == OK) {
+            state = mAudioTrack->getVolumeShaperState(id);
+        }
+    }
+    return state;
 }
 
 status_t AudioTrack::getTimestamp(ExtendedTimestamp *timestamp)
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index b082654..cba5cf5 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -2029,12 +2029,23 @@
     ALOGV("setVolume");
     t->setVolume(mLeftVolume, mRightVolume);
 
-    // Dispatch any queued VolumeShapers when the track was not open.
-    mVolumeHandler->forall([&t](const sp<VolumeShaper::Configuration> &configuration,
-            const sp<VolumeShaper::Operation> &operation) -> VolumeShaper::Status {
-        return t->applyVolumeShaper(configuration, operation);
+    // Restore VolumeShapers for the MediaPlayer in case the track was recreated
+    // due to an output sink error (e.g. offload to non-offload switch).
+    mVolumeHandler->forall([&t](const VolumeShaper &shaper) -> VolumeShaper::Status {
+        sp<VolumeShaper::Operation> operationToEnd =
+                new VolumeShaper::Operation(shaper.mOperation);
+        // TODO: Ideally we would restore to the exact xOffset position
+        // as returned by getVolumeShaperState(), but we don't have that
+        // information when restoring at the client unless we periodically poll
+        // the server or create shared memory state.
+        //
+        // For now, we simply advance to the end of the VolumeShaper effect
+        // if it has been started.
+        if (shaper.isStarted()) {
+            operationToEnd->setXOffset(1.f);
+        }
+        return t->applyVolumeShaper(shaper.mConfiguration, operationToEnd);
     });
-    mVolumeHandler->reset(); // After dispatching, clear VolumeShaper queue.
 
     mSampleRateHz = sampleRate;
     mFlags = flags;
@@ -2075,7 +2086,11 @@
     if (mTrack != 0) {
         mTrack->setVolume(mLeftVolume, mRightVolume);
         mTrack->setAuxEffectSendLevel(mSendLevel);
-        return mTrack->start();
+        status_t status = mTrack->start();
+        if (status == NO_ERROR) {
+            mVolumeHandler->setStarted();
+        }
+        return status;
     }
     return NO_INIT;
 }
@@ -2279,13 +2294,20 @@
     Mutex::Autolock lock(mLock);
     ALOGV("AudioOutput::applyVolumeShaper");
 
-    // We take ownership of the VolumeShaper if set before the track is created.
     mVolumeHandler->setIdIfNecessary(configuration);
+
+    VolumeShaper::Status status;
     if (mTrack != 0) {
-        return mTrack->applyVolumeShaper(configuration, operation);
+        status = mTrack->applyVolumeShaper(configuration, operation);
+        if (status >= 0) {
+            (void)mVolumeHandler->applyVolumeShaper(configuration, operation);
+            // TODO: start on exact AudioTrack state (STATE_ACTIVE || STATE_STOPPING)
+            mVolumeHandler->setStarted();
+        }
     } else {
-        return mVolumeHandler->applyVolumeShaper(configuration, operation);
+        status = mVolumeHandler->applyVolumeShaper(configuration, operation);
     }
+    return status;
 }
 
 sp<VolumeShaper::State> MediaPlayerService::AudioOutput::getVolumeShaperState(int id)