• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // #define LOG_NDEBUG 0
18 #define LOG_TAG "SoundDoseManager_tests"
19 
20 #include <SoundDoseManager.h>
21 
22 #include <aidl/android/hardware/audio/core/sounddose/BnSoundDose.h>
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25 #include <media/AidlConversionCppNdk.h>
26 
27 namespace android {
28 namespace {
29 
30 using aidl::android::hardware::audio::core::sounddose::BnSoundDose;
31 using aidl::android::media::audio::common::AudioDevice;
32 using aidl::android::media::audio::common::AudioDeviceAddress;
33 
34 class HalSoundDoseMock : public BnSoundDose {
35 public:
36     MOCK_METHOD(ndk::ScopedAStatus, getOutputRs2UpperBound, (float*), (override));
37     MOCK_METHOD(ndk::ScopedAStatus, setOutputRs2UpperBound, (float), (override));
38     MOCK_METHOD(ndk::ScopedAStatus, registerSoundDoseCallback,
39                 (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>&), (override));
40 };
41 
42 class MelReporterCallback : public IMelReporterCallback {
43 public:
44     MOCK_METHOD(void, startMelComputationForDeviceId, (audio_port_handle_t), (override));
45     MOCK_METHOD(void, stopMelComputationForDeviceId, (audio_port_handle_t), (override));
46 };
47 
48 constexpr char kPrimaryModule[] = "primary";
49 constexpr char kSecondaryModule[] = "secondary";
50 
51 class SoundDoseManagerTest : public ::testing::Test {
52 protected:
SetUp()53     void SetUp() override {
54         mMelReporterCallback = sp<MelReporterCallback>::make();
55         mSoundDoseManager = sp<SoundDoseManager>::make(mMelReporterCallback);
56         mHalSoundDose = ndk::SharedRefBase::make<HalSoundDoseMock>();
57         mSecondaryHalSoundDose = ndk::SharedRefBase::make<HalSoundDoseMock>();
58 
59         ON_CALL(*mHalSoundDose.get(), setOutputRs2UpperBound)
60             .WillByDefault([] (float rs2) {
61                 EXPECT_EQ(rs2, ISoundDose::DEFAULT_MAX_RS2);
62                 return ndk::ScopedAStatus::ok();
63             });
64         ON_CALL(*mSecondaryHalSoundDose.get(), setOutputRs2UpperBound)
65                 .WillByDefault([] (float rs2) {
66                     EXPECT_EQ(rs2, ISoundDose::DEFAULT_MAX_RS2);
67                     return ndk::ScopedAStatus::ok();
68                 });
69     }
70 
71     sp<MelReporterCallback> mMelReporterCallback;
72     sp<SoundDoseManager> mSoundDoseManager;
73     std::shared_ptr<HalSoundDoseMock> mHalSoundDose;
74     std::shared_ptr<HalSoundDoseMock> mSecondaryHalSoundDose;
75 };
76 
TEST_F(SoundDoseManagerTest,GetProcessorForExistingStream)77 TEST_F(SoundDoseManagerTest, GetProcessorForExistingStream) {
78     sp<audio_utils::MelProcessor> processor1 =
79         mSoundDoseManager->getOrCreateProcessorForDevice(/*deviceId=*/1,
80             /*streamHandle=*/1,
81             /*sampleRate*/44100,
82             /*channelCount*/2,
83             /*format*/AUDIO_FORMAT_PCM_FLOAT);
84     sp<audio_utils::MelProcessor> processor2 =
85         mSoundDoseManager->getOrCreateProcessorForDevice(/*deviceId=*/2,
86             /*streamHandle=*/1,
87             /*sampleRate*/44100,
88             /*channelCount*/2,
89             /*format*/AUDIO_FORMAT_PCM_FLOAT);
90 
91     EXPECT_EQ(processor1, processor2);
92 }
93 
TEST_F(SoundDoseManagerTest,RemoveExistingStream)94 TEST_F(SoundDoseManagerTest, RemoveExistingStream) {
95     sp<audio_utils::MelProcessor> processor1 =
96         mSoundDoseManager->getOrCreateProcessorForDevice(/*deviceId=*/1,
97             /*streamHandle=*/1,
98             /*sampleRate*/44100,
99             /*channelCount*/2,
100             /*format*/AUDIO_FORMAT_PCM_FLOAT);
101 
102     mSoundDoseManager->removeStreamProcessor(1);
103     sp<audio_utils::MelProcessor> processor2 =
104         mSoundDoseManager->getOrCreateProcessorForDevice(/*deviceId=*/2,
105             /*streamHandle=*/1,
106             /*sampleRate*/44100,
107             /*channelCount*/2,
108             /*format*/AUDIO_FORMAT_PCM_FLOAT);
109 
110     EXPECT_NE(processor1, processor2);
111 }
112 
TEST_F(SoundDoseManagerTest,NewMelValuesCacheNewRecord)113 TEST_F(SoundDoseManagerTest, NewMelValuesCacheNewRecord) {
114     std::vector<float>mels{1, 1};
115 
116     mSoundDoseManager->onNewMelValues(mels, 0, mels.size(), /*deviceId=*/1);
117 
118     EXPECT_EQ(mSoundDoseManager->getCachedMelRecordsSize(), size_t{1});
119 }
120 
TEST_F(SoundDoseManagerTest,InvalidHalInterfaceIsNotSet)121 TEST_F(SoundDoseManagerTest, InvalidHalInterfaceIsNotSet) {
122     EXPECT_FALSE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, nullptr));
123 }
124 
TEST_F(SoundDoseManagerTest,SetHalSoundDoseDisablesNewMelProcessorCallbacks)125 TEST_F(SoundDoseManagerTest, SetHalSoundDoseDisablesNewMelProcessorCallbacks) {
126     EXPECT_CALL(*mHalSoundDose.get(), setOutputRs2UpperBound).Times(1);
127     EXPECT_CALL(*mHalSoundDose.get(), registerSoundDoseCallback)
128         .Times(1)
129         .WillOnce([&] (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& callback) {
130             EXPECT_NE(nullptr, callback);
131             return ndk::ScopedAStatus::ok();
132         });
133 
134     EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));
135 
136     EXPECT_EQ(nullptr, mSoundDoseManager->getOrCreateProcessorForDevice(/*deviceId=*/2,
137             /*streamHandle=*/1,
138             /*sampleRate*/44100,
139             /*channelCount*/2,
140             /*format*/AUDIO_FORMAT_PCM_FLOAT));
141 }
142 
TEST_F(SoundDoseManagerTest,SetHalSoundDoseRegistersHalCallbacks)143 TEST_F(SoundDoseManagerTest, SetHalSoundDoseRegistersHalCallbacks) {
144     EXPECT_CALL(*mHalSoundDose.get(), setOutputRs2UpperBound).Times(1);
145     EXPECT_CALL(*mHalSoundDose.get(), registerSoundDoseCallback)
146         .Times(1)
147         .WillOnce([&] (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& callback) {
148             EXPECT_NE(nullptr, callback);
149             return ndk::ScopedAStatus::ok();
150         });
151     EXPECT_CALL(*mSecondaryHalSoundDose.get(), setOutputRs2UpperBound).Times(1);
152     EXPECT_CALL(*mSecondaryHalSoundDose.get(), registerSoundDoseCallback)
153             .Times(1)
154             .WillOnce([&] (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& callback) {
155                 EXPECT_NE(nullptr, callback);
156                 return ndk::ScopedAStatus::ok();
157         });
158 
159     EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));
160     EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kSecondaryModule,
161                                                             mSecondaryHalSoundDose));
162 }
163 
TEST_F(SoundDoseManagerTest,MomentaryExposureFromHalWithNoAddressIllegalArgument)164 TEST_F(SoundDoseManagerTest, MomentaryExposureFromHalWithNoAddressIllegalArgument) {
165     std::shared_ptr<ISoundDose::IHalSoundDoseCallback> halCallback;
166 
167     EXPECT_CALL(*mHalSoundDose.get(), setOutputRs2UpperBound).Times(1);
168     EXPECT_CALL(*mHalSoundDose.get(), registerSoundDoseCallback)
169        .Times(1)
170        .WillOnce([&] (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& callback) {
171            halCallback = callback;
172            return ndk::ScopedAStatus::ok();
173        });
174 
175     EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));
176 
177     EXPECT_NE(nullptr, halCallback);
178     AudioDevice audioDevice = {};
179     audioDevice.address.set<AudioDeviceAddress::id>("test");
180     auto status = halCallback->onMomentaryExposureWarning(
181         /*in_currentDbA=*/101.f, audioDevice);
182     EXPECT_FALSE(status.isOk());
183 }
184 
TEST_F(SoundDoseManagerTest,MomentaryExposureFromHalAfterInternalSelectedReturnsException)185 TEST_F(SoundDoseManagerTest, MomentaryExposureFromHalAfterInternalSelectedReturnsException) {
186     std::shared_ptr<ISoundDose::IHalSoundDoseCallback> halCallback;
187 
188     EXPECT_CALL(*mHalSoundDose.get(), setOutputRs2UpperBound).Times(1);
189     EXPECT_CALL(*mHalSoundDose.get(), registerSoundDoseCallback)
190        .Times(1)
191        .WillOnce([&] (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& callback) {
192            halCallback = callback;
193            return ndk::ScopedAStatus::ok();
194        });
195 
196     EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));
197     EXPECT_NE(nullptr, halCallback);
198     mSoundDoseManager->resetHalSoundDoseInterfaces();
199 
200     AudioDevice audioDevice = {};
201     audioDevice.address.set<AudioDeviceAddress::id>("test");
202     auto status = halCallback->onMomentaryExposureWarning(
203         /*in_currentDbA=*/101.f, audioDevice);
204     EXPECT_FALSE(status.isOk());
205 }
206 
TEST_F(SoundDoseManagerTest,OnNewMelValuesFromHalWithNoAddressIllegalArgument)207 TEST_F(SoundDoseManagerTest, OnNewMelValuesFromHalWithNoAddressIllegalArgument) {
208     std::shared_ptr<ISoundDose::IHalSoundDoseCallback> halCallback;
209 
210     EXPECT_CALL(*mHalSoundDose.get(), setOutputRs2UpperBound).Times(1);
211     EXPECT_CALL(*mHalSoundDose.get(), registerSoundDoseCallback)
212        .Times(1)
213        .WillOnce([&] (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& callback) {
214            halCallback = callback;
215            return ndk::ScopedAStatus::ok();
216        });
217 
218     EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(kPrimaryModule, mHalSoundDose));
219 
220     EXPECT_NE(nullptr, halCallback);
221     AudioDevice audioDevice = {};
222     audioDevice.address.set<AudioDeviceAddress::id>("test");
223     auto status = halCallback->onNewMelValues(/*in_melRecord=*/{}, audioDevice);
224     EXPECT_FALSE(status.isOk());
225 }
226 
TEST_F(SoundDoseManagerTest,GetIdReturnsMappedAddress)227 TEST_F(SoundDoseManagerTest, GetIdReturnsMappedAddress) {
228     const std::string address = "testAddress";
229     const audio_port_handle_t deviceId = 2;
230     const audio_devices_t deviceType = AUDIO_DEVICE_OUT_WIRED_HEADSET;
231     const AudioDeviceTypeAddr adt{deviceType, address};
232     auto audioDevice = aidl::android::legacy2aidl_audio_device_AudioDevice(
233             deviceType, address.c_str());
234     ASSERT_TRUE(audioDevice.ok());
235 
236     mSoundDoseManager->mapAddressToDeviceId(adt, deviceId);
237 
238     EXPECT_EQ(deviceId, mSoundDoseManager->getIdForAudioDevice(audioDevice.value()));
239 }
240 
TEST_F(SoundDoseManagerTest,GetAfterClearIdReturnsNone)241 TEST_F(SoundDoseManagerTest, GetAfterClearIdReturnsNone) {
242     const std::string address = "testAddress";
243     const audio_devices_t deviceType = AUDIO_DEVICE_OUT_WIRED_HEADSET;
244     const AudioDeviceTypeAddr adt{deviceType, address};
245     const audio_port_handle_t deviceId = 2;
246     auto audioDevice = aidl::android::legacy2aidl_audio_device_AudioDevice(
247             deviceType, address.c_str());
248     ASSERT_TRUE(audioDevice.ok());
249 
250     mSoundDoseManager->mapAddressToDeviceId(adt, deviceId);
251     mSoundDoseManager->clearMapDeviceIdEntries(deviceId);
252 
253     EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, mSoundDoseManager->getIdForAudioDevice(audioDevice.value()));
254 }
255 
TEST_F(SoundDoseManagerTest,GetUnmappedIdReturnsHandleNone)256 TEST_F(SoundDoseManagerTest, GetUnmappedIdReturnsHandleNone) {
257     const std::string address = "testAddress";
258     AudioDevice audioDevice;
259     audioDevice.address.set<AudioDeviceAddress::id>(address);
260 
261     EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, mSoundDoseManager->getIdForAudioDevice(audioDevice));
262 }
263 
TEST_F(SoundDoseManagerTest,GetDefaultForceComputeCsdOnAllDevices)264 TEST_F(SoundDoseManagerTest, GetDefaultForceComputeCsdOnAllDevices) {
265     EXPECT_FALSE(mSoundDoseManager->forceComputeCsdOnAllDevices());
266 }
267 
TEST_F(SoundDoseManagerTest,GetDefaultForceUseFrameworkMel)268 TEST_F(SoundDoseManagerTest, GetDefaultForceUseFrameworkMel) {
269     EXPECT_FALSE(mSoundDoseManager->forceUseFrameworkMel());
270 }
271 
TEST_F(SoundDoseManagerTest,SetAudioDeviceCategoryStopsNonHeadphone)272 TEST_F(SoundDoseManagerTest, SetAudioDeviceCategoryStopsNonHeadphone) {
273     media::ISoundDose::AudioDeviceCategory device1;
274     device1.address = "dev1";
275     device1.csdCompatible = false;
276     device1.internalAudioType = AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
277     const AudioDeviceTypeAddr dev1Adt{AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, device1.address};
278 
279     // this will mark the device as active
280     mSoundDoseManager->mapAddressToDeviceId(dev1Adt, /*deviceId=*/1);
281     EXPECT_CALL(*mMelReporterCallback.get(), stopMelComputationForDeviceId).Times(1);
282 
283     mSoundDoseManager->setAudioDeviceCategory(device1);
284 }
285 
TEST_F(SoundDoseManagerTest,SetAudioDeviceCategoryStartsHeadphone)286 TEST_F(SoundDoseManagerTest, SetAudioDeviceCategoryStartsHeadphone) {
287     media::ISoundDose::AudioDeviceCategory device1;
288     device1.address = "dev1";
289     device1.csdCompatible = true;
290     device1.internalAudioType = AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
291     const AudioDeviceTypeAddr dev1Adt{AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, device1.address};
292 
293         // this will mark the device as active
294     mSoundDoseManager->mapAddressToDeviceId(dev1Adt, /*deviceId=*/1);
295     EXPECT_CALL(*mMelReporterCallback.get(), startMelComputationForDeviceId).Times(1);
296 
297     mSoundDoseManager->setAudioDeviceCategory(device1);
298 }
299 
TEST_F(SoundDoseManagerTest,InitCachedAudioDevicesStartsOnlyActiveDevices)300 TEST_F(SoundDoseManagerTest, InitCachedAudioDevicesStartsOnlyActiveDevices) {
301     media::ISoundDose::AudioDeviceCategory device1;
302     media::ISoundDose::AudioDeviceCategory device2;
303     device1.address = "dev1";
304     device1.csdCompatible = true;
305     device1.internalAudioType = AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
306     device2.address = "dev2";
307     device2.csdCompatible = true;
308     device2.internalAudioType = AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
309     const AudioDeviceTypeAddr dev1Adt{AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, device1.address};
310     std::vector<media::ISoundDose::AudioDeviceCategory> btDevices = {device1, device2};
311 
312     // this will mark the device as active
313     mSoundDoseManager->mapAddressToDeviceId(dev1Adt, /*deviceId=*/1);
314     EXPECT_CALL(*mMelReporterCallback.get(), startMelComputationForDeviceId).Times(1);
315 
316     mSoundDoseManager->initCachedAudioDeviceCategories(btDevices);
317 }
318 
319 
320 }  // namespace
321 }  // namespace android
322