/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 #define LOG_TAG "AudioEffectTests" #include #include #include #include #include #include #include "audio_test_utils.h" #include "test_execution_tracer.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 doesDeviceSupportLowLatencyMode(std::vector& 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 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& callback = nullptr) { 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::make(); sp effect = new AudioEffect(attributionSource); effect->set(type, uuid, priority, callback, sessionId, AUDIO_IO_HANDLE_NONE, {}, false, (callback != nullptr)); return effect; } status_t createAndInitCheckEffect(const effect_uuid_t* type, const effect_uuid_t* uuid, int priority, audio_session_t sessionId) { sp effect = createEffect(type, uuid, priority, sessionId); return effect->initCheck(); } bool isEffectDefaultOnRecord(const effect_uuid_t* type, const effect_uuid_t* uuid, const sp& audioRecord) { effect_descriptor_t descriptors[AudioEffect::kMaxPreProcessing]; uint32_t numEffects = AudioEffect::kMaxPreProcessing; status_t ret = AudioEffect::queryDefaultPreProcessing(audioRecord->getSessionId(), descriptors, &numEffects); if (ret != OK || numEffects > AudioEffect::kMaxPreProcessing) { return false; } for (int i = 0; i < numEffects; i++) { if ((memcmp(&descriptors[i].type, type, sizeof(effect_uuid_t)) == 0) && (memcmp(&descriptors[i].uuid, uuid, sizeof(effect_uuid_t)) == 0)) { return true; } } return false; } void listEffectsAvailable(std::vector& descriptors) { uint32_t numEffects = 0; 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); } } bool isPreprocessing(effect_descriptor_t& descriptor) { return ((descriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC); } bool isInsert(effect_descriptor_t& descriptor) { return ((descriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT); } 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 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 = { 0x81781c08, 0x93dd, 0x11ec, 0xb909, {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; effect_uuid_t randomUuid = { 0x653730e1, 0x1be1, 0x438e, 0xa35a, {0xfc, 0x9b, 0xa1, 0x2a, 0x5e, 0xc9}}; effect_uuid_t empty = EFFECT_UUID_INITIALIZER; effect_descriptor_t descriptor; EXPECT_EQ(NAME_NOT_FOUND, AudioEffect::getEffectDescriptor(&randomUuid, &randomType, EFFECT_FLAG_TYPE_MASK, &descriptor)); std::vector descriptors; ASSERT_NO_FATAL_FAILURE(listEffectsAvailable(descriptors)); for (auto i = 0; i < descriptors.size(); i++) { EXPECT_EQ(NO_ERROR, AudioEffect::getEffectDescriptor(&descriptors[i].uuid, &descriptors[i].type, EFFECT_FLAG_TYPE_MASK, &descriptor)); EXPECT_EQ(0, memcmp(&descriptor, &descriptors[i], sizeof(effect_uuid_t))); } // negative tests if (descriptors.size() > 0) { EXPECT_EQ(BAD_VALUE, AudioEffect::getEffectDescriptor(&descriptors[0].uuid, &descriptors[0].type, EFFECT_FLAG_TYPE_MASK, nullptr)); } EXPECT_EQ(BAD_VALUE, AudioEffect::getEffectDescriptor(nullptr, nullptr, EFFECT_FLAG_TYPE_PRE_PROC, &descriptor)); EXPECT_EQ(BAD_VALUE, AudioEffect::getEffectDescriptor(&empty, &randomType, EFFECT_FLAG_TYPE_MASK, nullptr)); EXPECT_EQ(BAD_VALUE, AudioEffect::getEffectDescriptor(nullptr, &randomType, EFFECT_FLAG_TYPE_POST_PROC, &descriptor)); EXPECT_EQ(BAD_VALUE, AudioEffect::getEffectDescriptor(&randomUuid, nullptr, EFFECT_FLAG_TYPE_INSERT, &descriptor)); } TEST(AudioEffectTest, DISABLED_GetSetParameterForEffect) { sp 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"; uint32_t buf32[3][sizeof(effect_param_t) / sizeof(uint32_t) + 2]; effect_param_t* vis_none = (effect_param_t*)(buf32[0]); effect_param_t* vis_rms = (effect_param_t*)(buf32[1]); effect_param_t* vis_tmp = (effect_param_t*)(buf32[2]); // Visualizer::setMeasurementMode() vis_none->psize = sizeof(uint32_t); vis_none->vsize = sizeof(uint32_t); *(int32_t*)vis_none->data = VISUALIZER_PARAM_MEASUREMENT_MODE; *((int32_t*)vis_none->data + 1) = MEASUREMENT_MODE_NONE; EXPECT_EQ(NO_ERROR, visualizer->setParameter(vis_none)) << "setMeasurementMode doesn't report success"; // Visualizer::getMeasurementMode() vis_tmp->psize = sizeof(uint32_t); vis_tmp->vsize = sizeof(uint32_t); *(int32_t*)vis_tmp->data = VISUALIZER_PARAM_MEASUREMENT_MODE; *((int32_t*)vis_tmp->data + 1) = 23; EXPECT_EQ(NO_ERROR, visualizer->getParameter(vis_tmp)) << "getMeasurementMode doesn't report success"; EXPECT_EQ(*((int32_t*)vis_tmp->data + 1), *((int32_t*)vis_none->data + 1)) << "target mode does not match set mode"; // Visualizer::setMeasurementModeDeferred() vis_rms->psize = sizeof(uint32_t); vis_rms->vsize = sizeof(uint32_t); *(int32_t*)vis_rms->data = VISUALIZER_PARAM_MEASUREMENT_MODE; *((int32_t*)vis_rms->data + 1) = MEASUREMENT_MODE_PEAK_RMS; EXPECT_EQ(NO_ERROR, visualizer->setParameterDeferred(vis_rms)) << "setMeasurementModeDeferred doesn't report success"; *((int32_t*)vis_tmp->data + 1) = 23; EXPECT_EQ(NO_ERROR, visualizer->getParameter(vis_tmp)) << "getMeasurementMode doesn't report success"; EXPECT_EQ(*((int32_t*)vis_tmp->data + 1), *((int32_t*)vis_none->data + 1)) << "target mode does not match set mode"; // setParameterCommit EXPECT_EQ(NO_ERROR, visualizer->setParameterCommit()) << "setMeasurementModeCommit does not report success"; // validate Params *((int32_t*)vis_tmp->data + 1) = 23; EXPECT_EQ(NO_ERROR, visualizer->getParameter(vis_tmp)) << "getMeasurementMode doesn't report success"; EXPECT_EQ(*((int32_t*)vis_tmp->data + 1), *((int32_t*)vis_rms->data + 1)) << "target mode does not match set mode"; } TEST(AudioEffectTest, ManageSourceDefaultEffects) { int32_t selectedEffect = -1; const uint32_t sampleRate = 44100; const audio_format_t format = AUDIO_FORMAT_PCM_16_BIT; const audio_channel_mask_t channelMask = AUDIO_CHANNEL_IN_STEREO; sp capture = nullptr; std::vector 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()); ASSERT_NE(capture->getAudioRecordHandle(), nullptr); if (!isEffectDefaultOnRecord(&descriptors[i].type, &descriptors[i].uuid, capture->getAudioRecordHandle())) { selectedEffect = i; EXPECT_EQ(OK, capture->stop()); break; } EXPECT_EQ(OK, capture->stop()); } } if (selectedEffect == -1) GTEST_SKIP() << " expected at least one preprocessing effect"; 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()); ASSERT_NE(capture->getAudioRecordHandle(), nullptr); EXPECT_FALSE(isEffectDefaultOnRecord(selectedEffectType, selectedEffectUuid, capture->getAudioRecordHandle())) << "Effect should not have been default on record. " << type; EXPECT_EQ(NO_ERROR, createAndInitCheckEffect(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.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()); ASSERT_NE(capture->getAudioRecordHandle(), nullptr); EXPECT_TRUE(isEffectDefaultOnRecord(selectedEffectType, selectedEffectUuid, capture->getAudioRecordHandle())) << "Effect should have been default on record. " << type; EXPECT_EQ(ALREADY_EXISTS, createAndInitCheckEffect(selectedEffectType, selectedEffectUuid, kDefaultInputEffectPriority - 1, capture->getAudioRecordHandle()->getSessionId())) << "Effect should have been added. " << type; EXPECT_EQ(OK, capture->audioProcess()); EXPECT_EQ(OK, capture->stop()); status = AudioEffect::removeSourceDefaultEffect(effectId); EXPECT_EQ(NO_ERROR, status); 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()); ASSERT_NE(capture->getAudioRecordHandle(), nullptr); EXPECT_FALSE(isEffectDefaultOnRecord(selectedEffectType, selectedEffectUuid, capture->getAudioRecordHandle())) << "Effect should not have been default on record. " << type; EXPECT_EQ(NO_ERROR, createAndInitCheckEffect(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, AuxEffectSanityTest) { int32_t selectedEffect = -1; std::vector 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"; 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 = 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 { 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 ports; ASSERT_EQ(OK, listAudioPorts(ports)); if (!doesDeviceSupportLowLatencyMode(ports)) { GTEST_SKIP() << "device does not support low latency mode"; } } int32_t selectedEffect = -1; std::vector 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::make( 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_EQ(compatCheck ? NO_ERROR : NO_INIT, createAndInitCheckEffect(&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(mTypeStr.c_str(), name, mUuidStr.c_str(), kDefaultOutputEffectPriority, AUDIO_USAGE_MEDIA, &id); EXPECT_EQ(NO_ERROR, status) << "Adding default effect failed: " << mTypeStr; playback = sp::make( 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()); // If effect chosen is not compatible with the session, then effect won't be applied EXPECT_EQ(compatCheck ? ALREADY_EXISTS : NO_INIT, createAndInitCheckEffect(&mType, &mUuid, kDefaultOutputEffectPriority - 1, playback->getAudioTrackHandle()->getSessionId())) << "Effect should have been added. " << mTypeStr; EXPECT_EQ(NO_ERROR, playback->waitForConsumption()); 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::make( 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_EQ(compatCheck ? NO_ERROR : NO_INIT, createAndInitCheckEffect(&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 cb = sp::make(); sp audioEffect = createEffect(&mType, &mUuid, kDefaultOutputEffectPriority, sessionId, cb); ASSERT_EQ(OK, audioEffect->initCheck()); ASSERT_EQ(NO_ERROR, audioEffect->setEnabled(true)); auto playback = sp::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, createAndInitCheckEffect(&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 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 cb = sp::make(); sp audioEffect = createEffect(selectedEffectType, selectedEffectUuid, kDefaultOutputEffectPriority, sessionId, cb); ASSERT_EQ(OK, audioEffect->initCheck()); ASSERT_EQ(NO_ERROR, audioEffect->setEnabled(true)); auto playback = sp::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()); ASSERT_EQ(ALREADY_EXISTS, createAndInitCheckEffect(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"; } int main(int argc, char** argv) { android::ProcessState::self()->startThreadPool(); ::testing::InitGoogleTest(&argc, argv); ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer()); return RUN_ALL_TESTS(); }