AudioFlinger: Improve effect compatibility with RAW and FAST

Effects without process function now are allowed with RAW
and FAST playback and record tracks.

Bug: 32053844
Change-Id: I58064eb2c357043c2da1a781a20988f42570d97e
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index aedde69..9711f2d 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -2032,15 +2032,49 @@
     }
 }
 
-bool AudioFlinger::EffectChain::hasSoftwareEffect() const
+void AudioFlinger::EffectChain::checkOutputFlagCompatibility(audio_output_flags_t *flags) const
+{
+    if ((*flags & AUDIO_OUTPUT_FLAG_RAW) != 0 && !isRawCompatible()) {
+        *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW);
+    }
+    if ((*flags & AUDIO_OUTPUT_FLAG_FAST) != 0 && !isFastCompatible()) {
+        *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST);
+    }
+}
+
+void AudioFlinger::EffectChain::checkInputFlagCompatibility(audio_input_flags_t *flags) const
+{
+    if ((*flags & AUDIO_INPUT_FLAG_RAW) != 0 && !isRawCompatible()) {
+        *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_RAW);
+    }
+    if ((*flags & AUDIO_INPUT_FLAG_FAST) != 0 && !isFastCompatible()) {
+        *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_FAST);
+    }
+}
+
+bool AudioFlinger::EffectChain::isRawCompatible() const
 {
     Mutex::Autolock _l(mLock);
-    for (size_t i = 0; i < mEffects.size(); i++) {
-        if (mEffects[i]->isImplementationSoftware()) {
-            return true;
+    for (const auto &effect : mEffects) {
+        if (effect->isProcessImplemented()) {
+            return false;
         }
     }
-    return false;
+    // Allow effects without processing.
+    return true;
+}
+
+bool AudioFlinger::EffectChain::isFastCompatible() const
+{
+    Mutex::Autolock _l(mLock);
+    for (const auto &effect : mEffects) {
+        if (effect->isProcessImplemented()
+                && effect->isImplementationSoftware()) {
+            return false;
+        }
+    }
+    // Allow effects without processing or hw accelerated effects.
+    return true;
 }
 
 // isCompatibleWithThread_l() must be called with thread->mLock held
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index da0f3c5..818bf94 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -328,7 +328,17 @@
 
     void syncHalEffectsState();
 
-    bool hasSoftwareEffect() const;
+    // flags is an ORed set of audio_output_flags_t which is updated on return.
+    void checkOutputFlagCompatibility(audio_output_flags_t *flags) const;
+
+    // flags is an ORed set of audio_input_flags_t which is updated on return.
+    void checkInputFlagCompatibility(audio_input_flags_t *flags) const;
+
+    // Is this EffectChain compatible with the RAW audio flag.
+    bool isRawCompatible() const;
+
+    // Is this EffectChain compatible with the FAST audio flag.
+    bool isFastCompatible() const;
 
     // isCompatibleWithThread_l() must be called with thread->mLock held
     bool isCompatibleWithThread_l(const sp<ThreadBase>& thread) const;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 897873b..0f403ae 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1918,34 +1918,19 @@
         // check compatibility with audio effects.
         { // scope for mLock
             Mutex::Autolock _l(mLock);
-            // do not accept RAW flag if post processing are present. Note that post processing on
-            // a fast mixer are necessarily hardware
-            sp<EffectChain> chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_STAGE);
-            if (chain != 0) {
-                ALOGV_IF((*flags & AUDIO_OUTPUT_FLAG_RAW) != 0,
-                        "AUDIO_OUTPUT_FLAG_RAW denied: post processing effect present");
-                *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW);
-            }
-            // Do not accept FAST flag if software global effects are present
-            chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
-            if (chain != 0) {
-                ALOGV_IF((*flags & AUDIO_OUTPUT_FLAG_RAW) != 0,
-                        "AUDIO_OUTPUT_FLAG_RAW denied: global effect present");
-                *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW);
-                if (chain->hasSoftwareEffect()) {
-                    ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: software global effect present");
-                    *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST);
-                }
-            }
-            // Do not accept FAST flag if the session has software effects
-            chain = getEffectChain_l(sessionId);
-            if (chain != 0) {
-                ALOGV_IF((*flags & AUDIO_OUTPUT_FLAG_RAW) != 0,
-                        "AUDIO_OUTPUT_FLAG_RAW denied: effect present on session");
-                *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW);
-                if (chain->hasSoftwareEffect()) {
-                    ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: software effect present on session");
-                    *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST);
+            for (audio_session_t session : {
+                    AUDIO_SESSION_OUTPUT_STAGE,
+                    AUDIO_SESSION_OUTPUT_MIX,
+                    sessionId,
+                }) {
+                sp<EffectChain> chain = getEffectChain_l(session);
+                if (chain.get() != nullptr) {
+                    audio_output_flags_t old = *flags;
+                    chain->checkOutputFlagCompatibility(flags);
+                    if (old != *flags) {
+                        ALOGV("AUDIO_OUTPUT_FLAGS denied by effect, session=%d old=%#x new=%#x",
+                                (int)session, (int)old, (int)*flags);
+                    }
                 }
             }
         }
@@ -6594,12 +6579,11 @@
           // Do not accept FAST flag if the session has software effects
           sp<EffectChain> chain = getEffectChain_l(sessionId);
           if (chain != 0) {
-              ALOGV_IF((*flags & AUDIO_INPUT_FLAG_RAW) != 0,
-                      "AUDIO_INPUT_FLAG_RAW denied: effect present on session");
-              *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_RAW);
-              if (chain->hasSoftwareEffect()) {
-                  ALOGV("AUDIO_INPUT_FLAG_FAST denied: software effect present on session");
-                  *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_FAST);
+              audio_input_flags_t old = *flags;
+              chain->checkInputFlagCompatibility(flags);
+              if (old != *flags) {
+                  ALOGV("AUDIO_INPUT_FLAGS denied by effect old=%#x new=%#x",
+                          (int)old, (int)*flags);
               }
           }
           ALOGV_IF((*flags & AUDIO_INPUT_FLAG_FAST) != 0,