CSD: add support for multiple sound dose HALs
Initial implementation to support multiple sound dose HALs. Also not
falling back to internal MELs in case one module is not supporting the
sound dose HAL
Test: manual + atest sounddosemanager_tests
Bug: 297057693
Merged-In: I7941e34c08496781f4393358d1ce2845d525b86c
Change-Id: I7941e34c08496781f4393358d1ce2845d525b86c
diff --git a/services/audioflinger/MelReporter.cpp b/services/audioflinger/MelReporter.cpp
index 3af8828..23dfb7f 100644
--- a/services/audioflinger/MelReporter.cpp
+++ b/services/audioflinger/MelReporter.cpp
@@ -38,24 +38,21 @@
ndk::SpAIBinder soundDoseBinder;
if (device->getSoundDoseInterface(module, &soundDoseBinder) != OK) {
- ALOGW("%s: HAL cannot provide sound dose interface for module %s, use internal MEL",
+ ALOGW("%s: HAL cannot provide sound dose interface for module %s",
__func__, module.c_str());
- activateInternalSoundDoseComputation();
return false;
}
if (soundDoseBinder == nullptr) {
- ALOGW("%s: HAL doesn't implement a sound dose interface for module %s, use internal MEL",
+ ALOGW("%s: HAL doesn't implement a sound dose interface for module %s",
__func__, module.c_str());
- activateInternalSoundDoseComputation();
return false;
}
std::shared_ptr<ISoundDose> soundDoseInterface = ISoundDose::fromBinder(soundDoseBinder);
- if (!mSoundDoseManager->setHalSoundDoseInterface(soundDoseInterface)) {
+ if (!mSoundDoseManager->setHalSoundDoseInterface(module, soundDoseInterface)) {
ALOGW("%s: cannot activate HAL MEL reporting for module %s", __func__, module.c_str());
- activateInternalSoundDoseComputation();
return false;
}
@@ -73,7 +70,8 @@
mUseHalSoundDoseInterface = false;
}
- mSoundDoseManager->setHalSoundDoseInterface(nullptr);
+ // reset the HAL interfaces and use internal MELs
+ mSoundDoseManager->resetHalSoundDoseInterfaces();
}
void AudioFlinger::MelReporter::onFirstRef() {
@@ -251,6 +249,9 @@
void AudioFlinger::MelReporter::stopInternalMelComputation() {
ALOGV("%s", __func__);
std::lock_guard _l(mLock);
+ if (mUseHalSoundDoseInterface) {
+ return;
+ }
mActiveMelPatches.clear();
mUseHalSoundDoseInterface = true;
}
diff --git a/services/audioflinger/sounddose/SoundDoseManager.cpp b/services/audioflinger/sounddose/SoundDoseManager.cpp
index a551857..697d028 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.cpp
+++ b/services/audioflinger/sounddose/SoundDoseManager.cpp
@@ -50,7 +50,7 @@
size_t channelCount, audio_format_t format) {
std::lock_guard _l(mLock);
- if (mHalSoundDose != nullptr && mEnabledCsd) {
+ if (mHalSoundDose.size() > 0 && mEnabledCsd) {
ALOGD("%s: using HAL MEL computation, no MelProcessor needed.", __func__);
return nullptr;
}
@@ -83,19 +83,27 @@
return melProcessor;
}
-bool SoundDoseManager::setHalSoundDoseInterface(const std::shared_ptr<ISoundDose>& halSoundDose) {
+bool SoundDoseManager::setHalSoundDoseInterface(const std::string &module,
+ const std::shared_ptr<ISoundDose> &halSoundDose) {
ALOGV("%s", __func__);
+ if (halSoundDose == nullptr) {
+ ALOGI("%s: passed ISoundDose object is null", __func__);
+ return false;
+ }
+
+ std::shared_ptr<HalSoundDoseCallback> halSoundDoseCallback;
{
std::lock_guard _l(mLock);
- mHalSoundDose = halSoundDose;
- if (halSoundDose == nullptr) {
- ALOGI("%s: passed ISoundDose object is null, switching to internal CSD", __func__);
+ if (mHalSoundDose.find(module) != mHalSoundDose.end()) {
+ ALOGW("%s: Module %s already has a sound dose HAL assigned, skipping", __func__,
+ module.c_str());
return false;
}
+ mHalSoundDose[module] = halSoundDose;
- if (!mHalSoundDose->setOutputRs2UpperBound(mRs2UpperBound).isOk()) {
+ if (!halSoundDose->setOutputRs2UpperBound(mRs2UpperBound).isOk()) {
ALOGW("%s: Cannot set RS2 value for momentary exposure %f",
__func__,
mRs2UpperBound);
@@ -119,16 +127,26 @@
return true;
}
+void SoundDoseManager::resetHalSoundDoseInterfaces() {
+ ALOGV("%s", __func__);
+
+ const std::lock_guard _l(mLock);
+ mHalSoundDose.clear();
+}
+
void SoundDoseManager::setOutputRs2UpperBound(float rs2Value) {
ALOGV("%s", __func__);
std::lock_guard _l(mLock);
- if (mHalSoundDose != nullptr) {
- // using the HAL sound dose interface
- if (!mHalSoundDose->setOutputRs2UpperBound(rs2Value).isOk()) {
- ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
- return;
+ if (mHalSoundDose.size() > 0) {
+ for (auto& halSoundDose : mHalSoundDose) {
+ // using the HAL sound dose interface
+ if (!halSoundDose.second->setOutputRs2UpperBound(rs2Value).isOk()) {
+ ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
+ continue;
+ }
}
+
mRs2UpperBound = rs2Value;
return;
}
@@ -200,14 +218,16 @@
ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
float in_currentDbA, const AudioDevice& in_audioDevice) {
- auto soundDoseManager = mSoundDoseManager.promote();
- if (soundDoseManager == nullptr) {
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ sp<SoundDoseManager> soundDoseManager;
+ {
+ const std::lock_guard _l(mCbLock);
+ soundDoseManager = mSoundDoseManager.promote();
+ if (soundDoseManager == nullptr) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
}
- std::shared_ptr<ISoundDose> halSoundDose;
- soundDoseManager->getHalSoundDose(&halSoundDose);
- if(halSoundDose == nullptr) {
+ if (!soundDoseManager->useHalSoundDose()) {
ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
@@ -227,14 +247,16 @@
ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onNewMelValues(
const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
const AudioDevice& in_audioDevice) {
- auto soundDoseManager = mSoundDoseManager.promote();
- if (soundDoseManager == nullptr) {
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ sp<SoundDoseManager> soundDoseManager;
+ {
+ const std::lock_guard _l(mCbLock);
+ soundDoseManager = mSoundDoseManager.promote();
+ if (soundDoseManager == nullptr) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
}
- std::shared_ptr<ISoundDose> halSoundDose;
- soundDoseManager->getHalSoundDose(&halSoundDose);
- if(halSoundDose == nullptr) {
+ if (!soundDoseManager->useHalSoundDose()) {
ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
@@ -508,7 +530,7 @@
void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
// invalidate any HAL sound dose interface used
- setHalSoundDoseInterface(nullptr);
+ resetHalSoundDoseInterfaces();
std::lock_guard _l(mLock);
mUseFrameworkMel = useFrameworkMel;
@@ -534,17 +556,12 @@
return false;
}
- std::shared_ptr<ISoundDose> halSoundDose;
- getHalSoundDose(&halSoundDose);
- if (mHalSoundDose == nullptr) {
- return false;
- }
- return true;
+ return useHalSoundDose();
}
-void SoundDoseManager::getHalSoundDose(std::shared_ptr<ISoundDose>* halSoundDose) const {
- std::lock_guard _l(mLock);
- *halSoundDose = mHalSoundDose;
+bool SoundDoseManager::useHalSoundDose() const {
+ const std::lock_guard _l(mLock);
+ return mHalSoundDose.size() > 0;
}
void SoundDoseManager::resetSoundDose() {
diff --git a/services/audioflinger/sounddose/SoundDoseManager.h b/services/audioflinger/sounddose/SoundDoseManager.h
index 42a793d..43175f1 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.h
+++ b/services/audioflinger/sounddose/SoundDoseManager.h
@@ -94,12 +94,15 @@
sp<media::ISoundDose> getSoundDoseInterface(const sp<media::ISoundDoseCallback>& callback);
/**
- * Sets the HAL sound dose interface to use for the MEL computation. Use nullptr
- * for using the internal MEL computation.
+ * Sets the HAL sound dose interface for a specific module to use for the MEL computation.
*
* @return true if setting the HAL sound dose value was successful, false otherwise.
*/
- bool setHalSoundDoseInterface(const std::shared_ptr<ISoundDose>& halSoundDose);
+ bool setHalSoundDoseInterface(const std::string &module,
+ const std::shared_ptr<ISoundDose> &halSoundDose);
+
+ /** Reset all the stored HAL sound dose interface. */
+ void resetHalSoundDoseInterfaces();
/** Returns the cached audio port id from the active devices. */
audio_port_handle_t getIdForAudioDevice(
@@ -193,6 +196,7 @@
const aidl::android::media::audio::common::AudioDevice& in_audioDevice) override;
wp<SoundDoseManager> mSoundDoseManager;
+ std::mutex mCbLock;
};
void resetSoundDose();
@@ -206,8 +210,11 @@
void setUseFrameworkMel(bool useFrameworkMel);
void setComputeCsdOnAllDevices(bool computeCsdOnAllDevices);
bool isSoundDoseHalSupported() const;
- /** Returns the HAL sound dose interface or null if internal MEL computation is used. */
- void getHalSoundDose(std::shared_ptr<ISoundDose>* halSoundDose) const;
+ /**
+ * Returns true if there is one active HAL sound dose interface or null if internal MEL
+ * computation is used.
+ **/
+ bool useHalSoundDose() const;
mutable std::mutex mLock;
@@ -241,7 +248,7 @@
sp<SoundDose> mSoundDose GUARDED_BY(mLock);
- std::shared_ptr<ISoundDose> mHalSoundDose GUARDED_BY(mLock);
+ std::unordered_map<std::string, std::shared_ptr<ISoundDose>> mHalSoundDose GUARDED_BY(mLock);
std::shared_ptr<HalSoundDoseCallback> mHalSoundDoseCallback GUARDED_BY(mLock);
bool mUseFrameworkMel GUARDED_BY(mLock) = false;
diff --git a/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp b/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
index 5860d96..5f6dcb9 100644
--- a/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
+++ b/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
@@ -45,6 +45,8 @@
MOCK_METHOD(void, stopMelComputationForDeviceId, (audio_port_handle_t), (override));
};
+constexpr char kPrimaryModule[] = "primary";
+constexpr char kSecondaryModule[] = "secondary";
class SoundDoseManagerTest : public ::testing::Test {
protected:
@@ -52,17 +54,24 @@
mMelReporterCallback = sp<MelReporterCallback>::make();
mSoundDoseManager = sp<SoundDoseManager>::make(mMelReporterCallback);
mHalSoundDose = ndk::SharedRefBase::make<HalSoundDoseMock>();
+ mSecondaryHalSoundDose = ndk::SharedRefBase::make<HalSoundDoseMock>();
ON_CALL(*mHalSoundDose.get(), setOutputRs2UpperBound)
.WillByDefault([] (float rs2) {
EXPECT_EQ(rs2, ISoundDose::DEFAULT_MAX_RS2);
return ndk::ScopedAStatus::ok();
});
+ ON_CALL(*mSecondaryHalSoundDose.get(), setOutputRs2UpperBound)
+ .WillByDefault([] (float rs2) {
+ EXPECT_EQ(rs2, ISoundDose::DEFAULT_MAX_RS2);
+ return ndk::ScopedAStatus::ok();
+ });
}
sp<MelReporterCallback> mMelReporterCallback;
sp<SoundDoseManager> mSoundDoseManager;
std::shared_ptr<HalSoundDoseMock> mHalSoundDose;
+ std::shared_ptr<HalSoundDoseMock> mSecondaryHalSoundDose;
};
TEST_F(SoundDoseManagerTest, GetProcessorForExistingStream) {
@@ -110,7 +119,7 @@
}
TEST_F(SoundDoseManagerTest, InvalidHalInterfaceIsNotSet) {
- EXPECT_FALSE(mSoundDoseManager->setHalSoundDoseInterface(nullptr));
+ EXPECT_FALSE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, nullptr));
}
TEST_F(SoundDoseManagerTest, SetHalSoundDoseDisablesNewMelProcessorCallbacks) {
@@ -122,7 +131,7 @@
return ndk::ScopedAStatus::ok();
});
- EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
+ EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));
EXPECT_EQ(nullptr, mSoundDoseManager->getOrCreateProcessorForDevice(/*deviceId=*/2,
/*streamHandle=*/1,
@@ -139,8 +148,17 @@
EXPECT_NE(nullptr, callback);
return ndk::ScopedAStatus::ok();
});
+ EXPECT_CALL(*mSecondaryHalSoundDose.get(), setOutputRs2UpperBound).Times(1);
+ EXPECT_CALL(*mSecondaryHalSoundDose.get(), registerSoundDoseCallback)
+ .Times(1)
+ .WillOnce([&] (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& callback) {
+ EXPECT_NE(nullptr, callback);
+ return ndk::ScopedAStatus::ok();
+ });
- EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
+ EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));
+ EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kSecondaryModule,
+ mSecondaryHalSoundDose));
}
TEST_F(SoundDoseManagerTest, MomentaryExposureFromHalWithNoAddressIllegalArgument) {
@@ -154,7 +172,7 @@
return ndk::ScopedAStatus::ok();
});
- EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
+ EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));
EXPECT_NE(nullptr, halCallback);
AudioDevice audioDevice = {};
@@ -175,9 +193,9 @@
return ndk::ScopedAStatus::ok();
});
- EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
+ EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));
EXPECT_NE(nullptr, halCallback);
- EXPECT_FALSE(mSoundDoseManager->setHalSoundDoseInterface(nullptr));
+ mSoundDoseManager->resetHalSoundDoseInterfaces();
AudioDevice audioDevice = {};
audioDevice.address.set<AudioDeviceAddress::id>("test");
@@ -197,7 +215,7 @@
return ndk::ScopedAStatus::ok();
});
- EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
+ EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));
EXPECT_NE(nullptr, halCallback);
AudioDevice audioDevice = {};