Add default implementation and VTS for ISoundDose

The ISoundDose HAL interface is used for reporting the sound dose
relevant information from/to the HAL. This is necessary for all devices
that certify with the IEC62368-1 3rd edition and EN50332-3 standard
for safe hearing.

Bug: 248567177
Test: atest VtsHalAudioCoreTargetTest
Change-Id: Ib89e09243a01cebc2f7996b6b572384a1471867a
Merged-In: Ib89e09243a01cebc2f7996b6b572384a1471867a
(cherry picked from commit 83a2146546)
This commit is contained in:
Vlad Popa
2022-12-08 14:24:12 +01:00
committed by Mikhail Naganov
parent 83a6d82793
commit 943b7e2b91
6 changed files with 199 additions and 2 deletions

View File

@@ -43,6 +43,7 @@ cc_library_static {
"Configuration.cpp",
"EngineConfigXmlConverter.cpp",
"Module.cpp",
"SoundDose.cpp",
"Stream.cpp",
"Telephony.cpp",
],

View File

@@ -26,6 +26,7 @@
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
#include "core-impl/Module.h"
#include "core-impl/SoundDose.h"
#include "core-impl/Telephony.h"
#include "core-impl/utils.h"
@@ -932,8 +933,11 @@ ndk::ScopedAStatus Module::updateScreenState(bool in_isTurnedOn) {
}
ndk::ScopedAStatus Module::getSoundDose(std::shared_ptr<ISoundDose>* _aidl_return) {
*_aidl_return = nullptr;
LOG(DEBUG) << __func__ << ": ISoundDose not implemented";
if (mSoundDose == nullptr) {
mSoundDose = ndk::SharedRefBase::make<SoundDose>();
}
*_aidl_return = mSoundDose;
LOG(DEBUG) << __func__ << ": returning instance of ISoundDose: " << _aidl_return->get();
return ndk::ScopedAStatus::ok();
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2022 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_TAG "AHAL_SoundDose"
#include "core-impl/SoundDose.h"
#include <android-base/logging.h>
namespace aidl::android::hardware::audio::core {
ndk::ScopedAStatus SoundDose::setOutputRs2(float in_rs2ValueDbA) {
if (in_rs2ValueDbA < MIN_RS2 || in_rs2ValueDbA > DEFAULT_MAX_RS2) {
LOG(ERROR) << __func__ << ": RS2 value is invalid: " << in_rs2ValueDbA;
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
mRs2Value = in_rs2ValueDbA;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus SoundDose::getOutputRs2(float* _aidl_return) {
*_aidl_return = mRs2Value;
LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus SoundDose::registerSoundDoseCallback(
const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& in_callback) {
if (in_callback.get() == nullptr) {
LOG(ERROR) << __func__ << ": Callback is nullptr";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
if (mCallback != nullptr) {
LOG(ERROR) << __func__ << ": Sound dose callback was already registered";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
mCallback = in_callback;
LOG(DEBUG) << __func__ << ": Registered sound dose callback ";
return ndk::ScopedAStatus::ok();
}
} // namespace aidl::android::hardware::audio::core

View File

@@ -124,6 +124,7 @@ class Module : public BnModule {
bool mMasterMute = false;
float mMasterVolume = 1.0f;
bool mMicMute = false;
std::shared_ptr<ISoundDose> mSoundDose;
};
} // namespace aidl::android::hardware::audio::core

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2022 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.
*/
#pragma once
#include <mutex>
#include <aidl/android/hardware/audio/core/BnSoundDose.h>
#include <aidl/android/media/audio/common/AudioDevice.h>
using aidl::android::media::audio::common::AudioDevice;
namespace aidl::android::hardware::audio::core {
class SoundDose : public BnSoundDose {
public:
SoundDose() : mRs2Value(DEFAULT_MAX_RS2){};
ndk::ScopedAStatus setOutputRs2(float in_rs2ValueDbA) override;
ndk::ScopedAStatus getOutputRs2(float* _aidl_return) override;
ndk::ScopedAStatus registerSoundDoseCallback(
const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& in_callback) override;
private:
std::shared_ptr<ISoundDose::IHalSoundDoseCallback> mCallback;
float mRs2Value;
};
} // namespace aidl::android::hardware::audio::core

View File

@@ -36,6 +36,7 @@
#include <aidl/Vintf.h>
#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
#include <aidl/android/hardware/audio/core/IModule.h>
#include <aidl/android/hardware/audio/core/ISoundDose.h>
#include <aidl/android/hardware/audio/core/ITelephony.h>
#include <aidl/android/media/audio/common/AudioIoFlags.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
@@ -56,6 +57,7 @@ using aidl::android::hardware::audio::core::AudioMode;
using aidl::android::hardware::audio::core::AudioPatch;
using aidl::android::hardware::audio::core::AudioRoute;
using aidl::android::hardware::audio::core::IModule;
using aidl::android::hardware::audio::core::ISoundDose;
using aidl::android::hardware::audio::core::IStreamIn;
using aidl::android::hardware::audio::core::IStreamOut;
using aidl::android::hardware::audio::core::ITelephony;
@@ -2468,6 +2470,92 @@ TEST_P(AudioModulePatch, ResetInvalidPatchId) {
}
}
class AudioCoreSoundDose : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
public:
class NoOpHalSoundDoseCallback : public ISoundDose::BnHalSoundDoseCallback {
public:
ndk::ScopedAStatus onMomentaryExposureWarning(float in_currentDbA,
const AudioDevice& in_audioDevice) override;
ndk::ScopedAStatus onNewMelValues(
const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
const AudioDevice& in_audioDevice) override;
};
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
ASSERT_IS_OK(module->getSoundDose(&soundDose));
callback = ndk::SharedRefBase::make<NoOpHalSoundDoseCallback>();
}
void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
std::shared_ptr<ISoundDose> soundDose;
std::shared_ptr<ISoundDose::IHalSoundDoseCallback> callback;
};
ndk::ScopedAStatus AudioCoreSoundDose::NoOpHalSoundDoseCallback::onMomentaryExposureWarning(
float in_currentDbA, const AudioDevice& in_audioDevice) {
// Do nothing
(void)in_currentDbA;
(void)in_audioDevice;
LOG(INFO) << "NoOpHalSoundDoseCallback::onMomentaryExposureWarning called";
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus AudioCoreSoundDose::NoOpHalSoundDoseCallback::onNewMelValues(
const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
const AudioDevice& in_audioDevice) {
// Do nothing
(void)in_melRecord;
(void)in_audioDevice;
LOG(INFO) << "NoOpHalSoundDoseCallback::onNewMelValues called";
return ndk::ScopedAStatus::ok();
}
TEST_P(AudioCoreSoundDose, GetSetOutputRs2) {
if (soundDose == nullptr) {
GTEST_SKIP() << "SoundDose is not supported";
}
bool isSupported = false;
EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(soundDose.get(), &ISoundDose::getOutputRs2,
&ISoundDose::setOutputRs2,
/*validValues=*/{80.f, 90.f, 100.f},
/*invalidValues=*/{79.f, 101.f}, &isSupported));
EXPECT_TRUE(isSupported) << "Getting/Setting RS2 must be supported";
}
TEST_P(AudioCoreSoundDose, CheckDefaultRs2Value) {
if (soundDose == nullptr) {
GTEST_SKIP() << "SoundDose is not supported";
}
float rs2Value;
ASSERT_IS_OK(soundDose->getOutputRs2(&rs2Value));
EXPECT_EQ(rs2Value, ISoundDose::DEFAULT_MAX_RS2);
}
TEST_P(AudioCoreSoundDose, RegisterSoundDoseCallbackTwiceThrowsException) {
if (soundDose == nullptr) {
GTEST_SKIP() << "SoundDose is not supported";
}
ASSERT_IS_OK(soundDose->registerSoundDoseCallback(callback));
EXPECT_STATUS(EX_ILLEGAL_STATE, soundDose->registerSoundDoseCallback(callback))
<< "Registering sound dose callback twice should throw EX_ILLEGAL_STATE";
}
TEST_P(AudioCoreSoundDose, RegisterSoundDoseNullCallbackThrowsException) {
if (soundDose == nullptr) {
GTEST_SKIP() << "SoundDose is not supported";
}
EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, soundDose->registerSoundDoseCallback(nullptr))
<< "Registering nullptr sound dose callback should throw EX_ILLEGAL_ARGUMENT";
}
INSTANTIATE_TEST_SUITE_P(AudioCoreModuleTest, AudioCoreModule,
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
android::PrintInstanceNameToString);
@@ -2484,6 +2572,10 @@ INSTANTIATE_TEST_SUITE_P(AudioStreamOutTest, AudioStreamOut,
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamOut);
INSTANTIATE_TEST_SUITE_P(AudioCoreSoundDoseTest, AudioCoreSoundDose,
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreSoundDose);
// This is the value used in test sequences for which the test needs to ensure
// that the HAL stays in a transient state long enough to receive the next command.