audioflinger: fix noise when skipping to next song

When audio effects are enabled, a noise can be heard at the
beginning of the new song when skipping to next song in music app.

This is because some effects (especially virtualizer) have a tail.
This tail was not played when previous song was stopped because effects were
not processed when no tracks were present on a given session. This is to
reduce CPU load when effects are enabled but no audio is playing.
The tail was then rendered when the new song was started.

Added a delay before stopping effect process after all tracks have been removed from a session.

Issue 5584880.

Change-Id: I815e0f7441f9302e8dfe413dc269a94e4cc6fd95
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index ff262f1..780c0d2 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -7028,11 +7028,17 @@
 
 AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& wThread,
                                         int sessionId)
-    : mThread(wThread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0),
+    : mThread(wThread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
       mOwnInBuffer(false), mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
       mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
 {
     mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread == 0) {
+        return;
+    }
+    mMaxTailBuffers = ((kProcessTailDurationMs * thread->sampleRate()) / 1000) /
+                                    thread->frameCount();
 }
 
 AudioFlinger::EffectChain::~EffectChain()
@@ -7100,22 +7106,31 @@
     }
     bool isGlobalSession = (mSessionId == AUDIO_SESSION_OUTPUT_MIX) ||
             (mSessionId == AUDIO_SESSION_OUTPUT_STAGE);
-    bool tracksOnSession = false;
+    // always process effects unless no more tracks are on the session and the effect tail
+    // has been rendered
+    bool doProcess = true;
     if (!isGlobalSession) {
-        tracksOnSession = (trackCnt() != 0);
-    }
+        bool tracksOnSession = (trackCnt() != 0);
 
-    // if no track is active, input buffer must be cleared here as the mixer process
-    // will not do it
-    if (tracksOnSession &&
-            activeTrackCnt() == 0) {
-        size_t numSamples = thread->frameCount() * thread->channelCount();
-        memset(mInBuffer, 0, numSamples * sizeof(int16_t));
+        if (!tracksOnSession && mTailBufferCount == 0) {
+            doProcess = false;
+        }
+
+        if (activeTrackCnt() == 0) {
+            // if no track is active and the effect tail has not been rendered,
+            // the input buffer must be cleared here as the mixer process will not do it
+            if (tracksOnSession || mTailBufferCount > 0) {
+                size_t numSamples = thread->frameCount() * thread->channelCount();
+                memset(mInBuffer, 0, numSamples * sizeof(int16_t));
+                if (mTailBufferCount > 0) {
+                    mTailBufferCount--;
+                }
+            }
+        }
     }
 
     size_t size = mEffects.size();
-    // do not process effect if no track is present in same audio session
-    if (isGlobalSession || tracksOnSession) {
+    if (doProcess) {
         for (size_t i = 0; i < size; i++) {
             mEffects[i]->process();
         }