Update audio playback session for fast compatible effects

Bug: 215781480
Test: atest audioeffect_tests

Merged-In: I651202acc7a1656fcc2b595db76a1f1c89449c91
Change-Id: I651202acc7a1656fcc2b595db76a1f1c89449c91
diff --git a/media/libaudioclient/tests/audioeffect_tests.cpp b/media/libaudioclient/tests/audioeffect_tests.cpp
index 93fe306..e6149e4 100644
--- a/media/libaudioclient/tests/audioeffect_tests.cpp
+++ b/media/libaudioclient/tests/audioeffect_tests.cpp
@@ -19,19 +19,43 @@
 
 #include <gtest/gtest.h>
 #include <media/AudioEffect.h>
+#include <system/audio_effects/effect_hapticgenerator.h>
+#include <system/audio_effects/effect_spatializer.h>
 #include <system/audio_effects/effect_visualizer.h>
 
 #include "audio_test_utils.h"
 
 using namespace android;
 
+class AudioEffectCallback : public AudioEffect::IAudioEffectCallback {
+  public:
+    bool receivedFramesProcessed = false;
+
+    void onFramesProcessed(int32_t framesProcessed) override {
+        ALOGE("number of frames processed %d", framesProcessed);
+        receivedFramesProcessed = true;
+    }
+};
+
 static constexpr int kDefaultInputEffectPriority = -1;
 static constexpr int kDefaultOutputEffectPriority = 0;
 
 static const char* gPackageName = "AudioEffectTest";
 
-bool isEffectExistsOnAudioSession(const effect_uuid_t* type, int priority,
-                                  audio_session_t sessionId) {
+bool doesDeviceSupportLowLatencyMode(std::vector<struct audio_port_v7>& ports) {
+    for (const auto& port : ports) {
+        if (port.role == AUDIO_PORT_ROLE_SOURCE && port.type == AUDIO_PORT_TYPE_MIX) {
+            if ((port.active_config.flags.output & AUDIO_OUTPUT_FLAG_FAST) != 0) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+sp<AudioEffect> createEffect(const effect_uuid_t* type, const effect_uuid_t* uuid = nullptr,
+                             int priority = 0, audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
+                             const wp<AudioEffectCallback>& callback = nullptr) {
     std::string packageName{gPackageName};
     AttributionSourceState attributionSource;
     attributionSource.packageName = packageName;
@@ -39,11 +63,19 @@
     attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
     attributionSource.token = sp<BBinder>::make();
     sp<AudioEffect> effect = new AudioEffect(attributionSource);
-    effect->set(type, nullptr /* uid */, priority, nullptr /* callback */, sessionId);
-    return effect->initCheck() == ALREADY_EXISTS;
+    effect->set(type, uuid, priority, callback, sessionId, AUDIO_IO_HANDLE_NONE, {}, false,
+                (callback != nullptr));
+    return effect;
 }
 
-bool isEffectDefaultOnRecord(const effect_uuid_t* type, const sp<AudioRecord>& audioRecord) {
+status_t isEffectExistsOnAudioSession(const effect_uuid_t* type, const effect_uuid_t* uuid,
+                                      int priority, audio_session_t sessionId) {
+    sp<AudioEffect> effect = createEffect(type, uuid, priority, sessionId);
+    return effect->initCheck();
+}
+
+bool isEffectDefaultOnRecord(const effect_uuid_t* type, const effect_uuid_t* uuid,
+                             const sp<AudioRecord>& audioRecord) {
     effect_descriptor_t descriptors[AudioEffect::kMaxPreProcessing];
     uint32_t numEffects = AudioEffect::kMaxPreProcessing;
     status_t ret = AudioEffect::queryDefaultPreProcessing(audioRecord->getSessionId(), descriptors,
@@ -52,7 +84,8 @@
         return false;
     }
     for (int i = 0; i < numEffects; i++) {
-        if (memcmp(&descriptors[i].type, type, sizeof(effect_uuid_t)) == 0) {
+        if ((memcmp(&descriptors[i].type, type, sizeof(effect_uuid_t)) == 0) &&
+            (memcmp(&descriptors[i].uuid, uuid, sizeof(effect_uuid_t)) == 0)) {
             return true;
         }
     }
@@ -61,11 +94,11 @@
 
 void listEffectsAvailable(std::vector<effect_descriptor_t>& descriptors) {
     uint32_t numEffects = 0;
-    if (NO_ERROR == AudioEffect::queryNumberEffects(&numEffects)) {
-        for (auto i = 0; i < numEffects; i++) {
-            effect_descriptor_t des;
-            if (NO_ERROR == AudioEffect::queryEffect(i, &des)) descriptors.push_back(des);
-        }
+    ASSERT_EQ(NO_ERROR, AudioEffect::queryNumberEffects(&numEffects));
+    for (auto i = 0; i < numEffects; i++) {
+        effect_descriptor_t des;
+        ASSERT_EQ(NO_ERROR, AudioEffect::queryEffect(i, &des));
+        descriptors.push_back(des);
     }
 }
 
@@ -81,11 +114,31 @@
     return ((descriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY);
 }
 
+bool isPostproc(effect_descriptor_t& descriptor) {
+    return ((descriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC);
+}
+
 bool isFastCompatible(effect_descriptor_t& descriptor) {
     return !(((descriptor.flags & EFFECT_FLAG_HW_ACC_MASK) == 0) &&
              ((descriptor.flags & EFFECT_FLAG_NO_PROCESS) == 0));
 }
 
+bool isSpatializer(effect_descriptor_t& descriptor) {
+    return (memcmp(&descriptor.type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0);
+}
+
+bool isHapticGenerator(effect_descriptor_t& descriptor) {
+    return (memcmp(&descriptor.type, FX_IID_HAPTICGENERATOR, sizeof(effect_uuid_t)) == 0);
+}
+
+std::tuple<std::string, std::string> typeAndUuidToString(const effect_descriptor_t& desc) {
+    char type[512];
+    AudioEffect::guidToString(&desc.type, type, sizeof(type));
+    char uuid[512];
+    AudioEffect::guidToString(&desc.uuid, uuid, sizeof(uuid));
+    return std::make_tuple(type, uuid);
+}
+
 // UNIT TESTS
 TEST(AudioEffectTest, getEffectDescriptor) {
     effect_uuid_t randomType = {
@@ -99,7 +152,7 @@
                                                                EFFECT_FLAG_TYPE_MASK, &descriptor));
 
     std::vector<effect_descriptor_t> descriptors;
-    listEffectsAvailable(descriptors);
+    ASSERT_NO_FATAL_FAILURE(listEffectsAvailable(descriptors));
 
     for (auto i = 0; i < descriptors.size(); i++) {
         EXPECT_EQ(NO_ERROR,
@@ -124,15 +177,7 @@
 }
 
 TEST(AudioEffectTest, DISABLED_GetSetParameterForEffect) {
-    std::string packageName{gPackageName};
-    AttributionSourceState attributionSource;
-    attributionSource.packageName = packageName;
-    attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
-    attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
-    attributionSource.token = sp<BBinder>::make();
-    sp<AudioEffect> visualizer = new AudioEffect(attributionSource);
-    ASSERT_NE(visualizer, nullptr) << "effect not created";
-    visualizer->set(SL_IID_VISUALIZATION);
+    sp<AudioEffect> visualizer = createEffect(SL_IID_VISUALIZATION);
     status_t status = visualizer->initCheck();
     ASSERT_TRUE(status == NO_ERROR || status == ALREADY_EXISTS) << "Init check error";
     ASSERT_EQ(NO_ERROR, visualizer->setEnabled(true)) << "visualizer not enabled";
@@ -195,51 +240,58 @@
     sp<AudioCapture> capture = nullptr;
 
     std::vector<effect_descriptor_t> descriptors;
-    listEffectsAvailable(descriptors);
+    ASSERT_NO_FATAL_FAILURE(listEffectsAvailable(descriptors));
     for (auto i = 0; i < descriptors.size(); i++) {
         if (isPreprocessing(descriptors[i])) {
             capture = new AudioCapture(AUDIO_SOURCE_MIC, sampleRate, format, channelMask);
             ASSERT_NE(capture, nullptr) << "Unable to create Record Application";
             EXPECT_EQ(NO_ERROR, capture->create());
             EXPECT_EQ(NO_ERROR, capture->start());
-            if (!isEffectDefaultOnRecord(&descriptors[i].type, capture->getAudioRecordHandle())) {
+            if (!isEffectDefaultOnRecord(&descriptors[i].type, &descriptors[i].uuid,
+                                         capture->getAudioRecordHandle())) {
                 selectedEffect = i;
                 break;
             }
         }
     }
     if (selectedEffect == -1) GTEST_SKIP() << " expected at least one preprocessing effect";
-    effect_uuid_t selectedEffectType = descriptors[selectedEffect].type;
 
-    char type[512];
-    AudioEffect::guidToString(&selectedEffectType, type, sizeof(type));
-
+    effect_uuid_t* selectedEffectType = &descriptors[selectedEffect].type;
+    effect_uuid_t* selectedEffectUuid = &descriptors[selectedEffect].uuid;
+    auto [type, uuid] = typeAndUuidToString(descriptors[selectedEffect]);
     capture = new AudioCapture(AUDIO_SOURCE_MIC, sampleRate, format, channelMask);
     ASSERT_NE(capture, nullptr) << "Unable to create Record Application";
     EXPECT_EQ(NO_ERROR, capture->create());
     EXPECT_EQ(NO_ERROR, capture->start());
-    EXPECT_FALSE(isEffectDefaultOnRecord(&selectedEffectType, capture->getAudioRecordHandle()))
+    EXPECT_FALSE(isEffectDefaultOnRecord(selectedEffectType, selectedEffectUuid,
+                                         capture->getAudioRecordHandle()))
             << "Effect should not have been default on record. " << type;
-    EXPECT_FALSE(isEffectExistsOnAudioSession(&selectedEffectType, kDefaultInputEffectPriority - 1,
-                                              capture->getAudioRecordHandle()->getSessionId()))
+    EXPECT_EQ(NO_ERROR,
+              isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid,
+                                           kDefaultInputEffectPriority - 1,
+                                           capture->getAudioRecordHandle()->getSessionId()))
             << "Effect should not have been added. " << type;
     EXPECT_EQ(OK, capture->audioProcess());
     EXPECT_EQ(OK, capture->stop());
 
     String16 name{gPackageName};
     audio_unique_id_t effectId;
-    status_t status = AudioEffect::addSourceDefaultEffect(
-            type, name, nullptr, kDefaultInputEffectPriority, AUDIO_SOURCE_MIC, &effectId);
+    status_t status = AudioEffect::addSourceDefaultEffect(type.c_str(), name, uuid.c_str(),
+                                                          kDefaultInputEffectPriority,
+                                                          AUDIO_SOURCE_MIC, &effectId);
     EXPECT_EQ(NO_ERROR, status) << "Adding default effect failed: " << type;
 
     capture = new AudioCapture(AUDIO_SOURCE_MIC, sampleRate, format, channelMask);
     ASSERT_NE(capture, nullptr) << "Unable to create Record Application";
     EXPECT_EQ(NO_ERROR, capture->create());
     EXPECT_EQ(NO_ERROR, capture->start());
-    EXPECT_TRUE(isEffectDefaultOnRecord(&selectedEffectType, capture->getAudioRecordHandle()))
+    EXPECT_TRUE(isEffectDefaultOnRecord(selectedEffectType, selectedEffectUuid,
+                                        capture->getAudioRecordHandle()))
             << "Effect should have been default on record. " << type;
-    EXPECT_TRUE(isEffectExistsOnAudioSession(&selectedEffectType, kDefaultInputEffectPriority - 1,
-                                             capture->getAudioRecordHandle()->getSessionId()))
+    EXPECT_EQ(ALREADY_EXISTS,
+              isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid,
+                                           kDefaultInputEffectPriority - 1,
+                                           capture->getAudioRecordHandle()->getSessionId()))
             << "Effect should have been added. " << type;
     EXPECT_EQ(OK, capture->audioProcess());
     EXPECT_EQ(OK, capture->stop());
@@ -250,86 +302,258 @@
     ASSERT_NE(capture, nullptr) << "Unable to create Record Application";
     EXPECT_EQ(NO_ERROR, capture->create());
     EXPECT_EQ(NO_ERROR, capture->start());
-    EXPECT_FALSE(isEffectDefaultOnRecord(&selectedEffectType, capture->getAudioRecordHandle()))
+    EXPECT_FALSE(isEffectDefaultOnRecord(selectedEffectType, selectedEffectUuid,
+                                         capture->getAudioRecordHandle()))
             << "Effect should not have been default on record. " << type;
-    EXPECT_FALSE(isEffectExistsOnAudioSession(&selectedEffectType, kDefaultInputEffectPriority - 1,
-                                              capture->getAudioRecordHandle()->getSessionId()))
+    EXPECT_EQ(NO_ERROR,
+              isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid,
+                                           kDefaultInputEffectPriority - 1,
+                                           capture->getAudioRecordHandle()->getSessionId()))
             << "Effect should not have been added. " << type;
     EXPECT_EQ(OK, capture->audioProcess());
     EXPECT_EQ(OK, capture->stop());
 }
 
-TEST(AudioEffectTest, ManageStreamDefaultEffects) {
+TEST(AudioEffectTest, AuxEffectSanityTest) {
     int32_t selectedEffect = -1;
-
     std::vector<effect_descriptor_t> descriptors;
-    listEffectsAvailable(descriptors);
+    ASSERT_NO_FATAL_FAILURE(listEffectsAvailable(descriptors));
     for (auto i = 0; i < descriptors.size(); i++) {
         if (isAux(descriptors[i])) {
             selectedEffect = i;
             break;
         }
     }
-    if (selectedEffect == -1) GTEST_SKIP() << " expected at least one Aux effect";
+    if (selectedEffect == -1) GTEST_SKIP() << "expected at least one aux effect";
     effect_uuid_t* selectedEffectType = &descriptors[selectedEffect].type;
+    effect_uuid_t* selectedEffectUuid = &descriptors[selectedEffect].uuid;
+    auto [type, uuid] = typeAndUuidToString(descriptors[selectedEffect]);
+    String16 name{gPackageName};
+    audio_session_t sessionId =
+            (audio_session_t)AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
+    sp<AudioEffect> audioEffect = createEffect(selectedEffectType, selectedEffectUuid,
+                                               kDefaultInputEffectPriority, sessionId);
+    EXPECT_EQ(NO_INIT, audioEffect->initCheck())
+            << "error, creating auxiliary effect (" << type << ") on session id " << (int)sessionId
+            << " successful ";
+    audio_unique_id_t id;
+    status_t status = AudioEffect::addStreamDefaultEffect(
+            type.c_str(), name, uuid.c_str(), kDefaultOutputEffectPriority, AUDIO_USAGE_MEDIA, &id);
+    if (status == NO_ERROR) {
+        EXPECT_EQ(NO_ERROR, AudioEffect::removeStreamDefaultEffect(id));
+        EXPECT_NE(NO_ERROR, status) << "error, adding auxiliary effect (" << type
+                                    << ") as stream default effect is successful";
+    }
+}
 
-    char type[512];
-    AudioEffect::guidToString(selectedEffectType, type, sizeof(type));
+class AudioPlaybackEffectTest : public ::testing::TestWithParam<bool> {
+  public:
+    AudioPlaybackEffectTest() : mSelectFastMode(GetParam()){};
+
+    const bool mSelectFastMode;
+
+    bool mIsFastCompatibleEffect;
+    effect_uuid_t mType;
+    effect_uuid_t mUuid;
+    std::string mTypeStr;
+    std::string mUuidStr;
+
+    void SetUp() override {
+        if (mSelectFastMode) {
+            std::vector<struct audio_port_v7> ports;
+            ASSERT_EQ(OK, listAudioPorts(ports));
+            if (!doesDeviceSupportLowLatencyMode(ports)) {
+                GTEST_SKIP() << "device does not support low latency mode";
+            }
+        }
+
+        int32_t selectedEffect = -1;
+        std::vector<effect_descriptor_t> descriptors;
+        ASSERT_NO_FATAL_FAILURE(listEffectsAvailable(descriptors));
+        for (auto i = 0; i < descriptors.size(); i++) {
+            if (isSpatializer(descriptors[i])) continue;
+            if (isHapticGenerator(descriptors[i]) && !AudioSystem::isHapticPlaybackSupported())
+                continue;
+            if (!isInsert(descriptors[i])) continue;
+            selectedEffect = i;
+            mIsFastCompatibleEffect = isFastCompatible(descriptors[i]);
+            // in fast mode, pick fast compatible effect if available
+            if (mSelectFastMode == mIsFastCompatibleEffect) break;
+        }
+        if (selectedEffect == -1) {
+            GTEST_SKIP() << "expected at least one valid effect";
+        }
+
+        mType = descriptors[selectedEffect].type;
+        mUuid = descriptors[selectedEffect].uuid;
+        std::tie(mTypeStr, mUuidStr) = typeAndUuidToString(descriptors[selectedEffect]);
+    }
+};
+
+TEST_P(AudioPlaybackEffectTest, StreamDefaultEffectTest) {
+    SCOPED_TRACE(testing::Message()
+                 << "\n selected effect type is :: " << mTypeStr
+                 << "\n selected effect uuid is :: " << mUuidStr
+                 << "\n audiotrack output flag : " << (mSelectFastMode ? "fast" : "default")
+                 << "\n audio effect is fast compatible : "
+                 << (mIsFastCompatibleEffect ? "yes" : "no"));
+
+    bool compatCheck = !mSelectFastMode || (mSelectFastMode && mIsFastCompatibleEffect);
+
     // create track
     audio_attributes_t attributes;
     attributes.usage = AUDIO_USAGE_MEDIA;
     attributes.content_type = AUDIO_CONTENT_TYPE_MUSIC;
     auto playback = sp<AudioPlayback>::make(
-            44100 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
-            AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE, AudioTrack::TRANSFER_SHARED, &attributes);
+            0 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+            mSelectFastMode ? AUDIO_OUTPUT_FLAG_FAST : AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE,
+            AudioTrack::TRANSFER_SHARED, &attributes);
     ASSERT_NE(nullptr, playback);
     ASSERT_EQ(NO_ERROR, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"));
     EXPECT_EQ(NO_ERROR, playback->create());
     EXPECT_EQ(NO_ERROR, playback->start());
-    EXPECT_FALSE(isEffectExistsOnAudioSession(selectedEffectType, kDefaultOutputEffectPriority - 1,
-                                              playback->getAudioTrackHandle()->getSessionId()))
-            << "Effect should not have been added. " << type;
+    EXPECT_EQ(compatCheck ? NO_ERROR : NO_INIT,
+              isEffectExistsOnAudioSession(&mType, &mUuid, kDefaultOutputEffectPriority - 1,
+                                           playback->getAudioTrackHandle()->getSessionId()))
+            << "Effect should not have been added. " << mTypeStr;
     EXPECT_EQ(NO_ERROR, playback->waitForConsumption());
     playback->stop();
     playback.clear();
 
     String16 name{gPackageName};
     audio_unique_id_t id;
-    status_t status = AudioEffect::addStreamDefaultEffect(
-            type, name, nullptr, kDefaultOutputEffectPriority, AUDIO_USAGE_MEDIA, &id);
-    EXPECT_EQ(NO_ERROR, status) << "Adding default effect failed: " << type;
+    status_t status = AudioEffect::addStreamDefaultEffect(mTypeStr.c_str(), name, mUuidStr.c_str(),
+                                                          kDefaultOutputEffectPriority,
+                                                          AUDIO_USAGE_MEDIA, &id);
+    EXPECT_EQ(NO_ERROR, status) << "Adding default effect failed: " << mTypeStr;
 
     playback = sp<AudioPlayback>::make(
-            44100 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
-            AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE, AudioTrack::TRANSFER_SHARED, &attributes);
+            0 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+            mSelectFastMode ? AUDIO_OUTPUT_FLAG_FAST : AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE,
+            AudioTrack::TRANSFER_SHARED, &attributes);
     ASSERT_NE(nullptr, playback);
     ASSERT_EQ(NO_ERROR, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"));
     EXPECT_EQ(NO_ERROR, playback->create());
-    float level = 0.2f, levelGot;
-    playback->getAudioTrackHandle()->setAuxEffectSendLevel(level);
     EXPECT_EQ(NO_ERROR, playback->start());
-    EXPECT_TRUE(isEffectExistsOnAudioSession(selectedEffectType, kDefaultOutputEffectPriority - 1,
-                                             playback->getAudioTrackHandle()->getSessionId()))
-            << "Effect should have been added. " << type;
+    // If effect chosen is not compatible with the session, then effect won't be applied
+    EXPECT_EQ(compatCheck ? ALREADY_EXISTS : NO_INIT,
+              isEffectExistsOnAudioSession(&mType, &mUuid, kDefaultOutputEffectPriority - 1,
+                                           playback->getAudioTrackHandle()->getSessionId()))
+            << "Effect should have been added. " << mTypeStr;
     EXPECT_EQ(NO_ERROR, playback->waitForConsumption());
-    playback->getAudioTrackHandle()->getAuxEffectSendLevel(&levelGot);
-    EXPECT_EQ(level, levelGot);
+    if (mSelectFastMode) {
+        EXPECT_EQ(AUDIO_OUTPUT_FLAG_FAST,
+                  playback->getAudioTrackHandle()->getFlags() & AUDIO_OUTPUT_FLAG_FAST);
+    }
     playback->stop();
     playback.clear();
 
     status = AudioEffect::removeStreamDefaultEffect(id);
     EXPECT_EQ(NO_ERROR, status);
     playback = sp<AudioPlayback>::make(
-            44100 /*sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
-            AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE, AudioTrack::TRANSFER_SHARED, &attributes);
+            0 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+            mSelectFastMode ? AUDIO_OUTPUT_FLAG_FAST : AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE,
+            AudioTrack::TRANSFER_SHARED, &attributes);
     ASSERT_NE(nullptr, playback);
     ASSERT_EQ(NO_ERROR, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"));
     EXPECT_EQ(NO_ERROR, playback->create());
     EXPECT_EQ(NO_ERROR, playback->start());
-    EXPECT_FALSE(isEffectExistsOnAudioSession(selectedEffectType, kDefaultOutputEffectPriority - 1,
-                                              playback->getAudioTrackHandle()->getSessionId()))
-            << "Effect should not have been added. " << type;
+    EXPECT_EQ(compatCheck ? NO_ERROR : NO_INIT,
+              isEffectExistsOnAudioSession(&mType, &mUuid, kDefaultOutputEffectPriority - 1,
+                                           playback->getAudioTrackHandle()->getSessionId()))
+            << "Effect should not have been added. " << mTypeStr;
     EXPECT_EQ(NO_ERROR, playback->waitForConsumption());
     playback->stop();
     playback.clear();
 }
+
+TEST_P(AudioPlaybackEffectTest, CheckOutputFlagCompatibility) {
+    SCOPED_TRACE(testing::Message()
+                 << "\n selected effect type is :: " << mTypeStr
+                 << "\n selected effect uuid is :: " << mUuidStr
+                 << "\n audiotrack output flag : " << (mSelectFastMode ? "fast" : "default")
+                 << "\n audio effect is fast compatible : "
+                 << (mIsFastCompatibleEffect ? "yes" : "no"));
+
+    audio_attributes_t attributes;
+    attributes.usage = AUDIO_USAGE_MEDIA;
+    attributes.content_type = AUDIO_CONTENT_TYPE_MUSIC;
+    audio_session_t sessionId =
+            (audio_session_t)AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
+    sp<AudioEffectCallback> cb = sp<AudioEffectCallback>::make();
+    sp<AudioEffect> audioEffect =
+            createEffect(&mType, &mUuid, kDefaultOutputEffectPriority, sessionId, cb);
+    ASSERT_EQ(OK, audioEffect->initCheck());
+    ASSERT_EQ(NO_ERROR, audioEffect->setEnabled(true));
+    auto playback = sp<AudioPlayback>::make(
+            0 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_MONO,
+            mSelectFastMode ? AUDIO_OUTPUT_FLAG_FAST : AUDIO_OUTPUT_FLAG_NONE, sessionId,
+            AudioTrack::TRANSFER_SHARED, &attributes);
+    ASSERT_NE(nullptr, playback);
+    ASSERT_EQ(NO_ERROR, playback->loadResource("/data/local/tmp/bbb_1ch_8kHz_s16le.raw"));
+    EXPECT_EQ(NO_ERROR, playback->create());
+    EXPECT_EQ(NO_ERROR, playback->start());
+
+    EXPECT_EQ(ALREADY_EXISTS, isEffectExistsOnAudioSession(
+                                      &mType, &mUuid, kDefaultOutputEffectPriority - 1, sessionId))
+            << "Effect should have been added. " << mTypeStr;
+    if (mSelectFastMode) {
+        EXPECT_EQ(mIsFastCompatibleEffect ? AUDIO_OUTPUT_FLAG_FAST : 0,
+                  playback->getAudioTrackHandle()->getFlags() & AUDIO_OUTPUT_FLAG_FAST);
+    }
+    EXPECT_EQ(NO_ERROR, playback->waitForConsumption());
+    EXPECT_EQ(NO_ERROR, playback->getAudioTrackHandle()->attachAuxEffect(0));
+    playback->stop();
+    playback.clear();
+    EXPECT_TRUE(cb->receivedFramesProcessed)
+            << "AudioEffect frames processed callback not received";
+}
+
+INSTANTIATE_TEST_SUITE_P(EffectParameterizedTests, AudioPlaybackEffectTest, ::testing::Bool());
+
+TEST(AudioEffectTest, TestHapticEffect) {
+    if (!AudioSystem::isHapticPlaybackSupported())
+        GTEST_SKIP() << "Haptic playback is not supported";
+    int32_t selectedEffect = -1;
+    std::vector<effect_descriptor_t> descriptors;
+    ASSERT_NO_FATAL_FAILURE(listEffectsAvailable(descriptors));
+    for (auto i = 0; i < descriptors.size(); i++) {
+        if (!isHapticGenerator(descriptors[i])) continue;
+        selectedEffect = i;
+        break;
+    }
+    if (selectedEffect == -1) GTEST_SKIP() << "expected at least one valid effect";
+
+    effect_uuid_t* selectedEffectType = &descriptors[selectedEffect].type;
+    effect_uuid_t* selectedEffectUuid = &descriptors[selectedEffect].uuid;
+    auto [type, uuid] = typeAndUuidToString(descriptors[selectedEffect]);
+
+    SCOPED_TRACE(testing::Message() << "\n selected effect type is :: " << type
+                                    << "\n selected effect uuid is :: " << uuid);
+
+    audio_attributes_t attributes;
+    attributes.usage = AUDIO_USAGE_MEDIA;
+    attributes.content_type = AUDIO_CONTENT_TYPE_MUSIC;
+    audio_session_t sessionId =
+            (audio_session_t)AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
+    sp<AudioEffectCallback> cb = sp<AudioEffectCallback>::make();
+    sp<AudioEffect> audioEffect = createEffect(selectedEffectType, selectedEffectUuid,
+                                               kDefaultOutputEffectPriority, sessionId, cb);
+    ASSERT_EQ(OK, audioEffect->initCheck());
+    ASSERT_EQ(NO_ERROR, audioEffect->setEnabled(true));
+    auto playback = sp<AudioPlayback>::make(0 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT,
+                                            AUDIO_CHANNEL_OUT_STEREO, AUDIO_OUTPUT_FLAG_NONE,
+                                            sessionId, AudioTrack::TRANSFER_SHARED, &attributes);
+    ASSERT_NE(nullptr, playback);
+    ASSERT_EQ(NO_ERROR, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"));
+    EXPECT_EQ(NO_ERROR, playback->create());
+    EXPECT_EQ(NO_ERROR, playback->start());
+    EXPECT_TRUE(isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid,
+                                             kDefaultOutputEffectPriority - 1, sessionId))
+            << "Effect should have been added. " << type;
+    EXPECT_EQ(NO_ERROR, playback->waitForConsumption());
+    playback->stop();
+    playback.clear();
+    EXPECT_TRUE(cb->receivedFramesProcessed)
+            << "AudioEffect frames processed callback not received";
+}