diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl index e8fdd7469c..45217e739a 100644 --- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl +++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl @@ -70,6 +70,10 @@ interface IModule { void removeDeviceEffect(int portConfigId, in android.hardware.audio.effect.IEffect effect); android.media.audio.common.AudioMMapPolicyInfo[] getMmapPolicyInfos(android.media.audio.common.AudioMMapPolicyType mmapPolicyType); boolean supportsVariableLatency(); + int getAAudioMixerBurstCount(); + int getAAudioHardwareBurstMinUsec(); + const int DEFAULT_AAUDIO_MIXER_BURST_COUNT = 2; + const int DEFAULT_AAUDIO_HARDWARE_BURST_MIN_DURATION_US = 1000; @VintfStability parcelable OpenInputStreamArguments { int portConfigId; diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl index 1b25f17805..968b5733f2 100644 --- a/audio/aidl/android/hardware/audio/core/IModule.aidl +++ b/audio/aidl/android/hardware/audio/core/IModule.aidl @@ -833,4 +833,31 @@ interface IModule { * @return Whether the module supports variable latency control. */ boolean supportsVariableLatency(); + + /** + * Default value for number of bursts per aaudio mixer cycle. This is a suggested value + * to return for the HAL module, unless it is known that a better option exists. + */ + const int DEFAULT_AAUDIO_MIXER_BURST_COUNT = 2; + /** + * Get the number of bursts per aaudio mixer cycle. + * + * @return The number of burst per aaudio mixer cycle. + * @throw EX_UNSUPPORTED_OPERATION If the module does not support aaudio MMAP. + */ + int getAAudioMixerBurstCount(); + + /** + * Default value for minimum duration in microseconds for a MMAP hardware burst. This + * is a suggested value to return for the HAL module, unless it is known that a better + * option exists. + */ + const int DEFAULT_AAUDIO_HARDWARE_BURST_MIN_DURATION_US = 1000; + /** + * Get the minimum duration in microseconds for a MMAP hardware burst. + * + * @return The minimum number of microseconds for a MMAP hardware burst. + * @throw EX_UNSUPPORTED_OPERATION If the module does not support aaudio MMAP. + */ + int getAAudioHardwareBurstMinUsec(); } diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index 40d32b35fc..7e829e3ef1 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -1151,4 +1151,41 @@ ndk::ScopedAStatus Module::supportsVariableLatency(bool* _aidl_return) { return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus Module::getAAudioMixerBurstCount(int32_t* _aidl_return) { + if (!isMmapSupported()) { + LOG(DEBUG) << __func__ << ": mmap is not supported "; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + *_aidl_return = DEFAULT_AAUDIO_MIXER_BURST_COUNT; + LOG(DEBUG) << __func__ << ": returning " << *_aidl_return; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Module::getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) { + if (!isMmapSupported()) { + LOG(DEBUG) << __func__ << ": mmap is not supported "; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + *_aidl_return = DEFAULT_AAUDIO_HARDWARE_BURST_MIN_DURATION_US; + LOG(DEBUG) << __func__ << ": returning " << *_aidl_return; + return ndk::ScopedAStatus::ok(); +} + +bool Module::isMmapSupported() { + if (mIsMmapSupported.has_value()) { + return mIsMmapSupported.value(); + } + std::vector mmapPolicyInfos; + if (!getMmapPolicyInfos(AudioMMapPolicyType::DEFAULT, &mmapPolicyInfos).isOk()) { + mIsMmapSupported = false; + } else { + mIsMmapSupported = + std::find_if(mmapPolicyInfos.begin(), mmapPolicyInfos.end(), [](const auto& info) { + return info.mmapPolicy == AudioMMapPolicy::AUTO || + info.mmapPolicy == AudioMMapPolicy::ALWAYS; + }) != mmapPolicyInfos.end(); + } + return mIsMmapSupported.value(); +} + } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h index c09520f19b..acdbe4fcbe 100644 --- a/audio/aidl/default/include/core-impl/Module.h +++ b/audio/aidl/default/include/core-impl/Module.h @@ -115,6 +115,8 @@ class Module : public BnModule { std::vector<::aidl::android::media::audio::common::AudioMMapPolicyInfo>* _aidl_return) override; ndk::ScopedAStatus supportsVariableLatency(bool* _aidl_return) override; + ndk::ScopedAStatus getAAudioMixerBurstCount(int32_t* _aidl_return) override; + ndk::ScopedAStatus getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) override; void cleanUpPatch(int32_t patchId); ndk::ScopedAStatus createStreamContext( @@ -132,6 +134,7 @@ class Module : public BnModule { std::set portIdsFromPortConfigIds(C portConfigIds); void registerPatch(const AudioPatch& patch); void updateStreamsConnectedState(const AudioPatch& oldPatch, const AudioPatch& newPatch); + bool isMmapSupported(); // This value is used for all AudioPatches. static constexpr int32_t kMinimumStreamBufferSizeFrames = 16; @@ -159,6 +162,7 @@ class Module : public BnModule { bool mMicMute = false; std::shared_ptr mSoundDose; ndk::SpAIBinder mSoundDoseBinder; + std::optional mIsMmapSupported; }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp index b48d1ba263..7b002ad1b3 100644 --- a/audio/aidl/vts/ModuleConfig.cpp +++ b/audio/aidl/vts/ModuleConfig.cpp @@ -438,3 +438,11 @@ std::vector ModuleConfig::generateAudioDevicePortConfigs( } return result; } + +bool ModuleConfig::isMmapSupported() const { + const std::vector mmapOutMixPorts = + getMmapOutMixPorts(false /*attachedOnly*/, false /*singlePort*/); + const std::vector mmapInMixPorts = + getMmapInMixPorts(false /*attachedOnly*/, false /*singlePort*/); + return !mmapOutMixPorts.empty() || !mmapInMixPorts.empty(); +} diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h index 8a557540b2..6a220756f3 100644 --- a/audio/aidl/vts/ModuleConfig.h +++ b/audio/aidl/vts/ModuleConfig.h @@ -139,6 +139,8 @@ class ModuleConfig { return *config.begin(); } + bool isMmapSupported() const; + std::string toString() const; private: diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp index c0908c081d..3ca51c730c 100644 --- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp @@ -1893,17 +1893,13 @@ TEST_P(AudioCoreModule, AddRemoveEffectInvalidArguments) { TEST_P(AudioCoreModule, GetMmapPolicyInfos) { ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig()); - const std::vector mmapOutMixPorts = - moduleConfig->getMmapOutMixPorts(true /*attachedOnly*/, false /*singlePort*/); - const std::vector mmapInMixPorts = - moduleConfig->getMmapInMixPorts(true /*attachedOnly*/, false /*singlePort*/); - const bool mmapSupported = (!mmapOutMixPorts.empty() || !mmapInMixPorts.empty()); + const bool isMmapSupported = moduleConfig->isMmapSupported(); for (const auto mmapPolicyType : {AudioMMapPolicyType::DEFAULT, AudioMMapPolicyType::EXCLUSIVE}) { std::vector policyInfos; EXPECT_IS_OK(module->getMmapPolicyInfos(mmapPolicyType, &policyInfos)) << toString(mmapPolicyType); - EXPECT_EQ(mmapSupported, !policyInfos.empty()); + EXPECT_EQ(isMmapSupported, !policyInfos.empty()); } } @@ -1913,6 +1909,33 @@ TEST_P(AudioCoreModule, BluetoothVariableLatency) { LOG(INFO) << "supportsVariableLatency: " << isSupported; } +TEST_P(AudioCoreModule, GetAAudioMixerBurstCount) { + ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig()); + const bool isMmapSupported = moduleConfig->isMmapSupported(); + int32_t mixerBursts = 0; + ndk::ScopedAStatus status = module->getAAudioMixerBurstCount(&mixerBursts); + EXPECT_EQ(isMmapSupported, status.getExceptionCode() != EX_UNSUPPORTED_OPERATION) + << "Support for AAudio MMAP and getting AAudio mixer burst count must be consistent"; + if (!isMmapSupported) { + GTEST_SKIP() << "AAudio MMAP is not supported"; + } + EXPECT_GE(mixerBursts, 0); +} + +TEST_P(AudioCoreModule, GetAAudioHardwareBurstMinUsec) { + ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig()); + const bool isMmapSupported = moduleConfig->isMmapSupported(); + int32_t aaudioHardwareBurstMinUsec = 0; + ndk::ScopedAStatus status = module->getAAudioHardwareBurstMinUsec(&aaudioHardwareBurstMinUsec); + EXPECT_EQ(isMmapSupported, status.getExceptionCode() != EX_UNSUPPORTED_OPERATION) + << "Support for AAudio MMAP and getting AAudio hardware burst minimum usec " + << "must be consistent"; + if (!isMmapSupported) { + GTEST_SKIP() << "AAudio MMAP is not supported"; + } + EXPECT_GE(aaudioHardwareBurstMinUsec, 0); +} + class AudioCoreBluetooth : public AudioCoreModuleBase, public testing::TestWithParam { public: void SetUp() override {