Merge "VolumeShaper: Improve restore" into oc-dev
diff --git a/include/media/VolumeShaper.h b/include/media/VolumeShaper.h
index 4ddb8d3..1282124 100644
--- a/include/media/VolumeShaper.h
+++ b/include/media/VolumeShaper.h
@@ -528,6 +528,10 @@
         mDelayXOffset = xOffset;
     }
 
+    bool isStarted() const {
+        return mStartFrame >= 0;
+    }
+
     std::pair<T /* volume */, bool /* active */> getVolume(
             int64_t trackFrameCount, double trackSampleRate) {
         if ((getFlags() & VolumeShaper::Operation::FLAG_DELAY) != 0) {
@@ -752,6 +756,8 @@
         return it->getState();
     }
 
+    // getVolume() is not const, as it updates internal state.
+    // Once called, any VolumeShapers not already started begin running.
     std::pair<T /* volume */, bool /* active */> getVolume(int64_t trackFrameCount) {
         AutoMutex _l(mLock);
         mLastFrame = trackFrameCount;
@@ -768,6 +774,14 @@
         return mLastVolume;
     }
 
+    // Used by a client side VolumeHandler to ensure all the VolumeShapers
+    // indicate that they have been started.  Upon a change in audioserver
+    // output sink, this information is used for restoration of the server side
+    // VolumeHandler.
+    void setStarted() {
+        (void)getVolume(mLastFrame);  // getVolume() will start the individual VolumeShapers.
+    }
+
     std::pair<T /* volume */, bool /* active */> getLastVolume() const {
         AutoMutex _l(mLock);
         return mLastVolume;
@@ -784,14 +798,12 @@
         return ss.str();
     }
 
-    void forall(const std::function<VolumeShaper::Status (
-            const sp<VolumeShaper::Configuration> &configuration,
-            const sp<VolumeShaper::Operation> &operation)> &lambda) {
+    void forall(const std::function<VolumeShaper::Status (const VolumeShaper &)> &lambda) {
         AutoMutex _l(mLock);
         VS_LOG("forall: mVolumeShapers.size() %zu", mVolumeShapers.size());
         for (const auto &shaper : mVolumeShapers) {
-            VS_LOG("forall applying lambda");
-            (void)lambda(shaper.mConfiguration, shaper.mOperation);
+            VolumeShaper::Status status = lambda(shaper);
+            VS_LOG("forall applying lambda on shaper (%p): %d", &shaper, (int)status);
         }
     }
 
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)