Only set initial volume to 0 for the effect that does volume control.

When the effect for doing volume control is changed, set volume for the
old one as full level and the new one as 0 for safe ramping.

Bug: 280641126
Test: repo steps in the bug
Change-Id: I0f843c8deae907f8584dc18d025ab499319784b5
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 5780d5d..d482d61 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -995,13 +995,6 @@
                     &size,
                     &cmdStatus);
         }
-
-        if (isVolumeControl()) {
-            // Force initializing the volume as 0 for volume control effect for safer ramping
-            uint32_t left = 0;
-            uint32_t right = 0;
-            setVolumeInternal(&left, &right, true /*controller*/);
-        }
     }
 
     // mConfig.outputCfg.buffer.frameCount cannot be zero.
@@ -2127,7 +2120,7 @@
 EffectChain::EffectChain(const wp<IAfThreadBase>& thread,
                                        audio_session_t sessionId)
     : mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
-      mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
+      mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
       mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX),
       mEffectCallback(new EffectCallback(wp<EffectChain>(this), thread))
 {
@@ -2373,6 +2366,15 @@
     return NO_ERROR;
 }
 
+std::optional<size_t> EffectChain::findVolumeControl_l(size_t from, size_t to) const {
+    for (size_t i = std::min(to, mEffects.size()); i > from; i--) {
+        if (mEffects[i - 1]->isVolumeControlEnabled()) {
+            return i - 1;
+        }
+    }
+    return std::nullopt;
+}
+
 ssize_t EffectChain::getInsertIndex(const effect_descriptor_t& desc) {
     // Insert effects are inserted at the end of mEffects vector as they are processed
     //  after track and auxiliary effects.
@@ -2542,29 +2544,38 @@
 {
     uint32_t newLeft = *left;
     uint32_t newRight = *right;
-    bool hasControl = false;
-    int ctrlIdx = -1;
-    size_t size = mEffects.size();
+    const size_t size = mEffects.size();
 
     // first update volume controller
-    for (size_t i = size; i > 0; i--) {
-        if (mEffects[i - 1]->isVolumeControlEnabled()) {
-            ctrlIdx = i - 1;
-            hasControl = true;
-            break;
-        }
-    }
+    const auto volumeControlIndex = findVolumeControl_l(0, size);
+    const int ctrlIdx = volumeControlIndex.value_or(-1);
+    const sp<IAfEffectModule> volumeControlEffect =
+            volumeControlIndex.has_value() ? mEffects[ctrlIdx] : nullptr;
+    const sp<IAfEffectModule> cachedVolumeControlEffect = mVolumeControlEffect.promote();
 
-    if (!force && ctrlIdx == mVolumeCtrlIdx &&
+    if (!force && volumeControlEffect == cachedVolumeControlEffect &&
             *left == mLeftVolume && *right == mRightVolume) {
-        if (hasControl) {
+        if (volumeControlIndex.has_value()) {
             *left = mNewLeftVolume;
             *right = mNewRightVolume;
         }
-        return hasControl;
+        return volumeControlIndex.has_value();
     }
 
-    mVolumeCtrlIdx = ctrlIdx;
+    if (volumeControlEffect != cachedVolumeControlEffect) {
+        // The volume control effect is a new one. Set the old one as full volume. Set the new onw
+        // as zero for safe ramping.
+        if (cachedVolumeControlEffect != nullptr) {
+            uint32_t leftMax = 1 << 24;
+            uint32_t rightMax = 1 << 24;
+            cachedVolumeControlEffect->setVolume(&leftMax, &rightMax, true /*controller*/);
+        }
+        if (volumeControlEffect != nullptr) {
+            uint32_t leftZero = 0;
+            uint32_t rightZero = 0;
+            volumeControlEffect->setVolume(&leftZero, &rightZero, true /*controller*/);
+        }
+    }
     mLeftVolume = newLeft;
     mRightVolume = newRight;
 
@@ -2601,7 +2612,7 @@
 
     setVolumeForOutput_l(*left, *right);
 
-    return hasControl;
+    return volumeControlIndex.has_value();
 }
 
 // resetVolume_l() must be called with IAfThreadBase::mutex() or EffectChain::mLock held