Loading media/libaudioclient/tests/audioeffect_tests.cpp +290 −66 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -39,11 +63,19 @@ bool isEffectExistsOnAudioSession(const effect_uuid_t* type, int priority, 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, Loading @@ -52,7 +84,8 @@ bool isEffectDefaultOnRecord(const effect_uuid_t* type, const sp<AudioRecord>& a 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; } } Loading @@ -61,11 +94,11 @@ bool isEffectDefaultOnRecord(const effect_uuid_t* type, const sp<AudioRecord>& a void listEffectsAvailable(std::vector<effect_descriptor_t>& descriptors) { uint32_t numEffects = 0; if (NO_ERROR == AudioEffect::queryNumberEffects(&numEffects)) { ASSERT_EQ(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::queryEffect(i, &des)); descriptors.push_back(des); } } Loading @@ -81,11 +114,31 @@ bool isAux(effect_descriptor_t& descriptor) { 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 = { Loading @@ -99,7 +152,7 @@ TEST(AudioEffectTest, getEffectDescriptor) { 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, Loading @@ -124,15 +177,7 @@ TEST(AudioEffectTest, getEffectDescriptor) { } 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"; Loading Loading @@ -195,32 +240,35 @@ TEST(AudioEffectTest, ManageSourceDefaultEffects) { 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, EXPECT_EQ(NO_ERROR, isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid, kDefaultInputEffectPriority - 1, capture->getAudioRecordHandle()->getSessionId())) << "Effect should not have been added. " << type; EXPECT_EQ(OK, capture->audioProcess()); Loading @@ -228,17 +276,21 @@ TEST(AudioEffectTest, ManageSourceDefaultEffects) { 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, EXPECT_EQ(ALREADY_EXISTS, isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid, kDefaultInputEffectPriority - 1, capture->getAudioRecordHandle()->getSessionId())) << "Effect should have been added. " << type; EXPECT_EQ(OK, capture->audioProcess()); Loading @@ -250,86 +302,258 @@ TEST(AudioEffectTest, ManageSourceDefaultEffects) { 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, 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"; } } 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); char type[512]; AudioEffect::guidToString(selectedEffectType, type, sizeof(type)); // 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, EXPECT_EQ(compatCheck ? NO_ERROR : NO_INIT, isEffectExistsOnAudioSession(&mType, &mUuid, kDefaultOutputEffectPriority - 1, playback->getAudioTrackHandle()->getSessionId())) << "Effect should not have been added. " << type; << "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, // 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. " << type; << "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, EXPECT_EQ(compatCheck ? NO_ERROR : NO_INIT, isEffectExistsOnAudioSession(&mType, &mUuid, kDefaultOutputEffectPriority - 1, playback->getAudioTrackHandle()->getSessionId())) << "Effect should not have been added. " << type; << "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"; } Loading
media/libaudioclient/tests/audioeffect_tests.cpp +290 −66 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -39,11 +63,19 @@ bool isEffectExistsOnAudioSession(const effect_uuid_t* type, int priority, 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, Loading @@ -52,7 +84,8 @@ bool isEffectDefaultOnRecord(const effect_uuid_t* type, const sp<AudioRecord>& a 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; } } Loading @@ -61,11 +94,11 @@ bool isEffectDefaultOnRecord(const effect_uuid_t* type, const sp<AudioRecord>& a void listEffectsAvailable(std::vector<effect_descriptor_t>& descriptors) { uint32_t numEffects = 0; if (NO_ERROR == AudioEffect::queryNumberEffects(&numEffects)) { ASSERT_EQ(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::queryEffect(i, &des)); descriptors.push_back(des); } } Loading @@ -81,11 +114,31 @@ bool isAux(effect_descriptor_t& descriptor) { 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 = { Loading @@ -99,7 +152,7 @@ TEST(AudioEffectTest, getEffectDescriptor) { 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, Loading @@ -124,15 +177,7 @@ TEST(AudioEffectTest, getEffectDescriptor) { } 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"; Loading Loading @@ -195,32 +240,35 @@ TEST(AudioEffectTest, ManageSourceDefaultEffects) { 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, EXPECT_EQ(NO_ERROR, isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid, kDefaultInputEffectPriority - 1, capture->getAudioRecordHandle()->getSessionId())) << "Effect should not have been added. " << type; EXPECT_EQ(OK, capture->audioProcess()); Loading @@ -228,17 +276,21 @@ TEST(AudioEffectTest, ManageSourceDefaultEffects) { 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, EXPECT_EQ(ALREADY_EXISTS, isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid, kDefaultInputEffectPriority - 1, capture->getAudioRecordHandle()->getSessionId())) << "Effect should have been added. " << type; EXPECT_EQ(OK, capture->audioProcess()); Loading @@ -250,86 +302,258 @@ TEST(AudioEffectTest, ManageSourceDefaultEffects) { 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, 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"; } } 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); char type[512]; AudioEffect::guidToString(selectedEffectType, type, sizeof(type)); // 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, EXPECT_EQ(compatCheck ? NO_ERROR : NO_INIT, isEffectExistsOnAudioSession(&mType, &mUuid, kDefaultOutputEffectPriority - 1, playback->getAudioTrackHandle()->getSessionId())) << "Effect should not have been added. " << type; << "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, // 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. " << type; << "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, EXPECT_EQ(compatCheck ? NO_ERROR : NO_INIT, isEffectExistsOnAudioSession(&mType, &mUuid, kDefaultOutputEffectPriority - 1, playback->getAudioTrackHandle()->getSessionId())) << "Effect should not have been added. " << type; << "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"; }