audioflinger: fix failure to indicate volume to effect

If an effect is added and enabled after a track is started
it will not receive current volume information because volume
is indicated only to active effects and if there is a volume change.

Add a flag to force EffectChain::setVolume_l() to pass volume indication
to all effects each time an effect is enabled.

Bug: 17572556.

Change-Id: I6b68488c9aca8b2095fb210aa124d02e4f759660
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 15f1f23..4678880 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -465,16 +465,21 @@
     if (status == 0) {
         status = cmdStatus;
     }
-    if (status == 0 &&
-            ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
-             (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC)) {
-        sp<ThreadBase> thread = mThread.promote();
-        if (thread != 0) {
-            audio_stream_t *stream = thread->stream();
-            if (stream != NULL) {
-                stream->add_audio_effect(stream, mEffectInterface);
+    if (status == 0) {
+        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
+             (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
+            sp<ThreadBase> thread = mThread.promote();
+            if (thread != 0) {
+                audio_stream_t *stream = thread->stream();
+                if (stream != NULL) {
+                    stream->add_audio_effect(stream, mEffectInterface);
+                }
             }
         }
+        sp<EffectChain> chain = mChain.promote();
+        if (chain != 0) {
+            chain->forceVolume();
+        }
     }
     return status;
 }
@@ -1326,7 +1331,7 @@
                                         int sessionId)
     : mThread(thread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
       mOwnInBuffer(false), mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
-      mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
+      mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX), mForceVolume(false)
 {
     mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
     if (thread == NULL) {
@@ -1649,7 +1654,8 @@
         }
     }
 
-    if (ctrlIdx == mVolumeCtrlIdx && *left == mLeftVolume && *right == mRightVolume) {
+    if (!isVolumeForced() && ctrlIdx == mVolumeCtrlIdx &&
+            *left == mLeftVolume && *right == mRightVolume) {
         if (hasControl) {
             *left = mNewLeftVolume;
             *right = mNewRightVolume;
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index eaf90e7..b87a1fd 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -318,6 +318,12 @@
     // At least one non offloadable effect in the chain is enabled
     bool isNonOffloadableEnabled();
 
+    // use release_cas because we don't care about the observed value, just want to make sure the
+    // new value is observable.
+    void forceVolume() { android_atomic_release_cas(false, true, &mForceVolume); }
+    // use acquire_cas because we are interested in the observed value and
+    // we are the only observers.
+    bool isVolumeForced() { return (android_atomic_acquire_cas(true, false, &mForceVolume) == 0); }
 
     void dump(int fd, const Vector<String16>& args);
 
@@ -375,4 +381,5 @@
     // timeLow fields among effect type UUIDs.
     // Updated by updateSuspendedSessions_l() only.
     KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
+    volatile int32_t mForceVolume; // force next volume command because a new effect was enabled
 };