blob: 39c80d874d826959357fe828bf224ea3ca5b54e5 [file] [log] [blame]
Vlad Popa2900c0a2022-10-24 13:38:00 +02001/*
2**
3** Copyright 2022, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18// #define LOG_NDEBUG 0
19#define LOG_TAG "SoundDoseManager"
20
21#include "SoundDoseManager.h"
22
Vlad Popa1d5f0d52022-12-18 12:21:26 +010023#include "android/media/SoundDoseRecord.h"
Vlad Popa2900c0a2022-10-24 13:38:00 +020024#include <android-base/stringprintf.h>
Vlad Popa1d5f0d52022-12-18 12:21:26 +010025#include <media/AidlConversionCppNdk.h>
26#include <cinttypes>
Vlad Popa4847de12023-03-16 18:30:08 +010027#include <ctime>
Vlad Popa4defd0b2022-11-06 14:22:31 +010028#include <utils/Log.h>
Vlad Popa2900c0a2022-10-24 13:38:00 +020029
30namespace android {
31
Vlad Popa1d5f0d52022-12-18 12:21:26 +010032using aidl::android::media::audio::common::AudioDevice;
Vlad Popa1d5f0d52022-12-18 12:21:26 +010033
Vlad Popa2900c0a2022-10-24 13:38:00 +020034namespace {
35
36int64_t getMonotonicSecond() {
37 struct timespec now_ts;
38 if (clock_gettime(CLOCK_MONOTONIC, &now_ts) != 0) {
39 ALOGE("%s: cannot get timestamp", __func__);
40 return -1;
41 }
42 return now_ts.tv_sec;
43}
44
45} // namespace
46
Vlad Popaf09e93f2022-10-31 16:27:12 +010047sp<audio_utils::MelProcessor> SoundDoseManager::getOrCreateProcessorForDevice(
Vlad Popa4defd0b2022-11-06 14:22:31 +010048 audio_port_handle_t deviceId, audio_io_handle_t streamHandle, uint32_t sampleRate,
49 size_t channelCount, audio_format_t format) {
Vlad Popaffcacdc2023-06-10 00:24:35 +020050 const std::lock_guard _l(mLock);
Vlad Popa2900c0a2022-10-24 13:38:00 +020051
Vlad Popa63c48dd2023-08-21 19:52:14 -070052 if (mHalSoundDose.size() > 0 && mEnabledCsd) {
Vlad Popa1c2f7e12023-03-28 02:08:56 +020053 ALOGD("%s: using HAL MEL computation, no MelProcessor needed.", __func__);
Vlad Popa1d5f0d52022-12-18 12:21:26 +010054 return nullptr;
55 }
56
Vlad Popaf09e93f2022-10-31 16:27:12 +010057 auto streamProcessor = mActiveProcessors.find(streamHandle);
Vlad Popa1c2f7e12023-03-28 02:08:56 +020058 if (streamProcessor != mActiveProcessors.end()) {
59 auto processor = streamProcessor->second.promote();
60 // if processor is nullptr it means it was removed by the playback
61 // thread and can be replaced in the mActiveProcessors map
62 if (processor != nullptr) {
63 ALOGV("%s: found callback for stream id %d", __func__, streamHandle);
64 const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
65 if (activeTypeIt != mActiveDeviceTypes.end()) {
66 processor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
67 }
68 processor->setDeviceId(deviceId);
69 processor->setOutputRs2UpperBound(mRs2UpperBound);
70 return processor;
Vlad Popa58e72dc2023-02-01 13:18:40 +010071 }
Vlad Popa2900c0a2022-10-24 13:38:00 +020072 }
Vlad Popa1c2f7e12023-03-28 02:08:56 +020073
74 ALOGV("%s: creating new callback for stream id %d", __func__, streamHandle);
75 sp<audio_utils::MelProcessor> melProcessor = sp<audio_utils::MelProcessor>::make(
76 sampleRate, channelCount, format, this, deviceId, mRs2UpperBound);
77 const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
78 if (activeTypeIt != mActiveDeviceTypes.end()) {
79 melProcessor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
80 }
81 mActiveProcessors[streamHandle] = melProcessor;
82 return melProcessor;
Vlad Popa2900c0a2022-10-24 13:38:00 +020083}
84
Vlad Popa63c48dd2023-08-21 19:52:14 -070085bool SoundDoseManager::setHalSoundDoseInterface(const std::string &module,
86 const std::shared_ptr<ISoundDose> &halSoundDose) {
Vlad Popa1d5f0d52022-12-18 12:21:26 +010087 ALOGV("%s", __func__);
88
Vlad Popa63c48dd2023-08-21 19:52:14 -070089 if (halSoundDose == nullptr) {
90 ALOGI("%s: passed ISoundDose object is null", __func__);
91 return false;
92 }
93
Vlad Popaffcacdc2023-06-10 00:24:35 +020094 std::shared_ptr<HalSoundDoseCallback> halSoundDoseCallback;
Vlad Popa1d5f0d52022-12-18 12:21:26 +010095 {
Vlad Popaffcacdc2023-06-10 00:24:35 +020096 const std::lock_guard _l(mLock);
Vlad Popa1d5f0d52022-12-18 12:21:26 +010097
Vlad Popa63c48dd2023-08-21 19:52:14 -070098 if (mHalSoundDose.find(module) != mHalSoundDose.end()) {
99 ALOGW("%s: Module %s already has a sound dose HAL assigned, skipping", __func__,
100 module.c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100101 return false;
102 }
Vlad Popa63c48dd2023-08-21 19:52:14 -0700103 mHalSoundDose[module] = halSoundDose;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100104
Vlad Popa63c48dd2023-08-21 19:52:14 -0700105 if (!halSoundDose->setOutputRs2UpperBound(mRs2UpperBound).isOk()) {
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100106 ALOGW("%s: Cannot set RS2 value for momentary exposure %f",
107 __func__,
Vlad Popa4847de12023-03-16 18:30:08 +0100108 mRs2UpperBound);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100109 }
110
111 // initialize the HAL sound dose callback lazily
112 if (mHalSoundDoseCallback == nullptr) {
113 mHalSoundDoseCallback =
114 ndk::SharedRefBase::make<HalSoundDoseCallback>(this);
115 }
Vlad Popaffcacdc2023-06-10 00:24:35 +0200116 halSoundDoseCallback = mHalSoundDoseCallback;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100117 }
118
Vlad Popaffcacdc2023-06-10 00:24:35 +0200119 auto status = halSoundDose->registerSoundDoseCallback(halSoundDoseCallback);
120
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100121 if (!status.isOk()) {
122 // Not a warning since this can happen if the callback was registered before
123 ALOGI("%s: Cannot register HAL sound dose callback with status message: %s",
124 __func__,
125 status.getMessage());
126 }
127
128 return true;
129}
130
Vlad Popa63c48dd2023-08-21 19:52:14 -0700131void SoundDoseManager::resetHalSoundDoseInterfaces() {
132 ALOGV("%s", __func__);
133
134 const std::lock_guard _l(mLock);
135 mHalSoundDose.clear();
136}
137
Vlad Popa4847de12023-03-16 18:30:08 +0100138void SoundDoseManager::setOutputRs2UpperBound(float rs2Value) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200139 ALOGV("%s", __func__);
Vlad Popaffcacdc2023-06-10 00:24:35 +0200140 const std::lock_guard _l(mLock);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100141
Vlad Popa63c48dd2023-08-21 19:52:14 -0700142 if (mHalSoundDose.size() > 0) {
143 for (auto& halSoundDose : mHalSoundDose) {
144 // using the HAL sound dose interface
145 if (!halSoundDose.second->setOutputRs2UpperBound(rs2Value).isOk()) {
146 ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
147 continue;
148 }
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100149 }
Vlad Popa63c48dd2023-08-21 19:52:14 -0700150
Vlad Popa4847de12023-03-16 18:30:08 +0100151 mRs2UpperBound = rs2Value;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100152 return;
153 }
Vlad Popae3fd1c22022-11-07 21:03:18 +0100154
Vlad Popaf09e93f2022-10-31 16:27:12 +0100155 for (auto& streamProcessor : mActiveProcessors) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200156 const sp<audio_utils::MelProcessor> processor = streamProcessor.second.promote();
Vlad Popaf09e93f2022-10-31 16:27:12 +0100157 if (processor != nullptr) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200158 const status_t result = processor->setOutputRs2UpperBound(rs2Value);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100159 if (result != NO_ERROR) {
Vlad Popa4847de12023-03-16 18:30:08 +0100160 ALOGW("%s: could not set RS2 upper bound %f for stream %d", __func__, rs2Value,
Vlad Popaf09e93f2022-10-31 16:27:12 +0100161 streamProcessor.first);
Vlad Popa3c3995d2023-01-13 11:10:05 +0100162 return;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100163 }
Vlad Popa4847de12023-03-16 18:30:08 +0100164 mRs2UpperBound = rs2Value;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100165 }
166 }
167}
168
Vlad Popa4defd0b2022-11-06 14:22:31 +0100169void SoundDoseManager::removeStreamProcessor(audio_io_handle_t streamHandle) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200170 const std::lock_guard _l(mLock);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100171 auto callbackToRemove = mActiveProcessors.find(streamHandle);
Vlad Popa4defd0b2022-11-06 14:22:31 +0100172 if (callbackToRemove != mActiveProcessors.end()) {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100173 mActiveProcessors.erase(callbackToRemove);
174 }
175}
176
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100177audio_port_handle_t SoundDoseManager::getIdForAudioDevice(const AudioDevice& audioDevice) const {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200178 const std::lock_guard _l(mLock);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100179
180 audio_devices_t type;
181 std::string address;
182 auto result = aidl::android::aidl2legacy_AudioDevice_audio_device(
183 audioDevice, &type, &address);
184 if (result != NO_ERROR) {
185 ALOGE("%s: could not convert from AudioDevice to AudioDeviceTypeAddr", __func__);
186 return AUDIO_PORT_HANDLE_NONE;
187 }
188
189 auto adt = AudioDeviceTypeAddr(type, address);
190 auto deviceIt = mActiveDevices.find(adt);
191 if (deviceIt == mActiveDevices.end()) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100192 ALOGI("%s: could not find port id for device %s", __func__, adt.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100193 return AUDIO_PORT_HANDLE_NONE;
194 }
195 return deviceIt->second;
196}
197
198void SoundDoseManager::mapAddressToDeviceId(const AudioDeviceTypeAddr& adt,
199 const audio_port_handle_t deviceId) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200200 const std::lock_guard _l(mLock);
Vlad Popaeafa0482023-02-23 14:35:56 +0100201 ALOGI("%s: map address: %d to device id: %d", __func__, adt.mType, deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100202 mActiveDevices[adt] = deviceId;
Vlad Popa58e72dc2023-02-01 13:18:40 +0100203 mActiveDeviceTypes[deviceId] = adt.mType;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100204}
205
206void SoundDoseManager::clearMapDeviceIdEntries(audio_port_handle_t deviceId) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200207 const std::lock_guard _l(mLock);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100208 for (auto activeDevice = mActiveDevices.begin(); activeDevice != mActiveDevices.end();) {
209 if (activeDevice->second == deviceId) {
Vlad Popaeafa0482023-02-23 14:35:56 +0100210 ALOGI("%s: clear mapping type: %d to deviceId: %d",
211 __func__, activeDevice->first.mType, deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100212 activeDevice = mActiveDevices.erase(activeDevice);
213 continue;
214 }
215 ++activeDevice;
216 }
Vlad Popa58e72dc2023-02-01 13:18:40 +0100217 mActiveDeviceTypes.erase(deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100218}
219
220ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
221 float in_currentDbA, const AudioDevice& in_audioDevice) {
Vlad Popa63c48dd2023-08-21 19:52:14 -0700222 sp<SoundDoseManager> soundDoseManager;
223 {
224 const std::lock_guard _l(mCbLock);
225 soundDoseManager = mSoundDoseManager.promote();
226 if (soundDoseManager == nullptr) {
227 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
228 }
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100229 }
230
Vlad Popa63c48dd2023-08-21 19:52:14 -0700231 if (!soundDoseManager->useHalSoundDose()) {
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100232 ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
233 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
234 }
235
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100236 auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
237 if (id == AUDIO_PORT_HANDLE_NONE) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100238 ALOGI("%s: no mapped id for audio device with type %d and address %s",
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100239 __func__, in_audioDevice.type.type,
Vlad Popa69fbbee2023-04-25 12:23:24 +0200240 in_audioDevice.address.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100241 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
242 }
243 soundDoseManager->onMomentaryExposure(in_currentDbA, id);
244
245 return ndk::ScopedAStatus::ok();
246}
247
248ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onNewMelValues(
249 const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
250 const AudioDevice& in_audioDevice) {
Vlad Popa63c48dd2023-08-21 19:52:14 -0700251 sp<SoundDoseManager> soundDoseManager;
252 {
253 const std::lock_guard _l(mCbLock);
254 soundDoseManager = mSoundDoseManager.promote();
255 if (soundDoseManager == nullptr) {
256 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
257 }
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100258 }
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100259
Vlad Popa63c48dd2023-08-21 19:52:14 -0700260 if (!soundDoseManager->useHalSoundDose()) {
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100261 ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
262 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
263 }
264
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100265 auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
266 if (id == AUDIO_PORT_HANDLE_NONE) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100267 ALOGI("%s: no mapped id for audio device with type %d and address %s",
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100268 __func__, in_audioDevice.type.type,
Vlad Popa69fbbee2023-04-25 12:23:24 +0200269 in_audioDevice.address.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100270 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
271 }
272 // TODO: introduce timestamp in onNewMelValues callback
273 soundDoseManager->onNewMelValues(in_melRecord.melValues, 0,
274 in_melRecord.melValues.size(), id);
275
276 return ndk::ScopedAStatus::ok();
277}
278
Vlad Popae3fd1c22022-11-07 21:03:18 +0100279void SoundDoseManager::SoundDose::binderDied(__unused const wp<IBinder>& who) {
280 ALOGV("%s", __func__);
281
282 auto soundDoseManager = mSoundDoseManager.promote();
283 if (soundDoseManager != nullptr) {
284 soundDoseManager->resetSoundDose();
285 }
286}
287
Vlad Popa4847de12023-03-16 18:30:08 +0100288binder::Status SoundDoseManager::SoundDose::setOutputRs2UpperBound(float value) {
Vlad Popae3fd1c22022-11-07 21:03:18 +0100289 ALOGV("%s", __func__);
290 auto soundDoseManager = mSoundDoseManager.promote();
291 if (soundDoseManager != nullptr) {
Vlad Popa4847de12023-03-16 18:30:08 +0100292 soundDoseManager->setOutputRs2UpperBound(value);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100293 }
294 return binder::Status::ok();
295}
296
297binder::Status SoundDoseManager::SoundDose::resetCsd(
298 float currentCsd, const std::vector<media::SoundDoseRecord>& records) {
299 ALOGV("%s", __func__);
300 auto soundDoseManager = mSoundDoseManager.promote();
301 if (soundDoseManager != nullptr) {
302 soundDoseManager->resetCsd(currentCsd, records);
303 }
304 return binder::Status::ok();
305}
306
Vlad Popa58e72dc2023-02-01 13:18:40 +0100307binder::Status SoundDoseManager::SoundDose::updateAttenuation(float attenuationDB, int device) {
308 ALOGV("%s", __func__);
309 auto soundDoseManager = mSoundDoseManager.promote();
310 if (soundDoseManager != nullptr) {
311 soundDoseManager->updateAttenuation(attenuationDB, static_cast<audio_devices_t>(device));
312 }
313 return binder::Status::ok();
314}
315
Vlad Popa617bbf02023-04-24 19:10:36 +0200316binder::Status SoundDoseManager::SoundDose::setCsdEnabled(bool enabled) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100317 ALOGV("%s", __func__);
318 auto soundDoseManager = mSoundDoseManager.promote();
319 if (soundDoseManager != nullptr) {
Vlad Popa617bbf02023-04-24 19:10:36 +0200320 soundDoseManager->setCsdEnabled(enabled);
Vlad Popa2a06fca2023-02-06 16:45:45 +0100321 }
322 return binder::Status::ok();
323}
324
Vlad Popa197faf82023-07-27 18:27:59 -0700325binder::Status SoundDoseManager::SoundDose::initCachedAudioDeviceCategories(
326 const std::vector<media::ISoundDose::AudioDeviceCategory>& btDeviceCategories) {
327 ALOGV("%s", __func__);
328 auto soundDoseManager = mSoundDoseManager.promote();
329 if (soundDoseManager != nullptr) {
330 soundDoseManager->initCachedAudioDeviceCategories(btDeviceCategories);
331 }
332 return binder::Status::ok();
333}
334binder::Status SoundDoseManager::SoundDose::setAudioDeviceCategory(
335 const media::ISoundDose::AudioDeviceCategory& btAudioDevice) {
336 ALOGV("%s", __func__);
337 auto soundDoseManager = mSoundDoseManager.promote();
338 if (soundDoseManager != nullptr) {
339 soundDoseManager->setAudioDeviceCategory(btAudioDevice);
340 }
341 return binder::Status::ok();
342}
343
Vlad Popa4847de12023-03-16 18:30:08 +0100344binder::Status SoundDoseManager::SoundDose::getOutputRs2UpperBound(float* value) {
Vlad Popa91930462022-12-20 22:42:48 +0100345 ALOGV("%s", __func__);
346 auto soundDoseManager = mSoundDoseManager.promote();
347 if (soundDoseManager != nullptr) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200348 const std::lock_guard _l(soundDoseManager->mLock);
Vlad Popa4847de12023-03-16 18:30:08 +0100349 *value = soundDoseManager->mRs2UpperBound;
Vlad Popa91930462022-12-20 22:42:48 +0100350 }
351 return binder::Status::ok();
352}
353
354binder::Status SoundDoseManager::SoundDose::getCsd(float* value) {
355 ALOGV("%s", __func__);
356 auto soundDoseManager = mSoundDoseManager.promote();
357 if (soundDoseManager != nullptr) {
358 *value = soundDoseManager->mMelAggregator->getCsd();
359 }
360 return binder::Status::ok();
361}
362
363binder::Status SoundDoseManager::SoundDose::forceUseFrameworkMel(bool useFrameworkMel) {
364 ALOGV("%s", __func__);
365 auto soundDoseManager = mSoundDoseManager.promote();
366 if (soundDoseManager != nullptr) {
367 soundDoseManager->setUseFrameworkMel(useFrameworkMel);
368 }
369 return binder::Status::ok();
370}
371
372binder::Status SoundDoseManager::SoundDose::forceComputeCsdOnAllDevices(
373 bool computeCsdOnAllDevices) {
374 ALOGV("%s", __func__);
375 auto soundDoseManager = mSoundDoseManager.promote();
376 if (soundDoseManager != nullptr) {
377 soundDoseManager->setComputeCsdOnAllDevices(computeCsdOnAllDevices);
378 }
379 return binder::Status::ok();
380}
381
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000382binder::Status SoundDoseManager::SoundDose::isSoundDoseHalSupported(bool* value) {
383 ALOGV("%s", __func__);
384 *value = false;
385 auto soundDoseManager = mSoundDoseManager.promote();
386 if (soundDoseManager != nullptr) {
387 *value = soundDoseManager->isSoundDoseHalSupported();
388 }
389 return binder::Status::ok();
390}
391
Vlad Popa58e72dc2023-02-01 13:18:40 +0100392void SoundDoseManager::updateAttenuation(float attenuationDB, audio_devices_t deviceType) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200393 const std::lock_guard _l(mLock);
Vlad Popaeafa0482023-02-23 14:35:56 +0100394 ALOGV("%s: updating MEL processor attenuation for device type %d to %f",
Vlad Popa58e72dc2023-02-01 13:18:40 +0100395 __func__, deviceType, attenuationDB);
396 mMelAttenuationDB[deviceType] = attenuationDB;
397 for (const auto& mp : mActiveProcessors) {
398 auto melProcessor = mp.second.promote();
399 if (melProcessor != nullptr) {
400 auto deviceId = melProcessor->getDeviceId();
Vlad Popa197faf82023-07-27 18:27:59 -0700401 const auto deviceTypeIt = mActiveDeviceTypes.find(deviceId);
402 if (deviceTypeIt != mActiveDeviceTypes.end() &&
403 deviceTypeIt->second == deviceType) {
Vlad Popaeafa0482023-02-23 14:35:56 +0100404 ALOGV("%s: set attenuation for deviceId %d to %f",
Vlad Popa58e72dc2023-02-01 13:18:40 +0100405 __func__, deviceId, attenuationDB);
406 melProcessor->setAttenuation(attenuationDB);
407 }
408 }
409 }
410}
411
Vlad Popa617bbf02023-04-24 19:10:36 +0200412void SoundDoseManager::setCsdEnabled(bool enabled) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100413 ALOGV("%s", __func__);
414
Vlad Popaffcacdc2023-06-10 00:24:35 +0200415 const std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200416 mEnabledCsd = enabled;
Vlad Popa2a06fca2023-02-06 16:45:45 +0100417
Vlad Popa2a06fca2023-02-06 16:45:45 +0100418 for (auto& activeEntry : mActiveProcessors) {
419 auto melProcessor = activeEntry.second.promote();
420 if (melProcessor != nullptr) {
Vlad Popa617bbf02023-04-24 19:10:36 +0200421 if (enabled) {
422 melProcessor->resume();
423 } else {
424 melProcessor->pause();
425 }
Vlad Popa2a06fca2023-02-06 16:45:45 +0100426 }
427 }
428}
429
Vlad Popa617bbf02023-04-24 19:10:36 +0200430bool SoundDoseManager::isCsdEnabled() {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200431 const std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200432 return mEnabledCsd;
Vlad Popa2a06fca2023-02-06 16:45:45 +0100433}
434
Vlad Popa197faf82023-07-27 18:27:59 -0700435void SoundDoseManager::initCachedAudioDeviceCategories(
436 const std::vector<media::ISoundDose::AudioDeviceCategory>& deviceCategories) {
437 ALOGV("%s", __func__);
438 {
439 const std::lock_guard _l(mLock);
440 mBluetoothDevicesWithCsd.clear();
441 }
442 for (const auto& btDeviceCategory : deviceCategories) {
443 setAudioDeviceCategory(btDeviceCategory);
444 }
445}
446
447void SoundDoseManager::setAudioDeviceCategory(
448 const media::ISoundDose::AudioDeviceCategory& audioDevice) {
449 ALOGV("%s: set BT audio device type with address %s to headphone %d", __func__,
450 audioDevice.address.c_str(), audioDevice.csdCompatible);
451
452 std::vector<audio_port_handle_t> devicesToStart;
453 std::vector<audio_port_handle_t> devicesToStop;
454 {
455 const std::lock_guard _l(mLock);
456 const auto deviceIt = mBluetoothDevicesWithCsd.find(
457 std::make_pair(audioDevice.address,
458 static_cast<audio_devices_t>(audioDevice.internalAudioType)));
459 if (deviceIt != mBluetoothDevicesWithCsd.end()) {
460 deviceIt->second = audioDevice.csdCompatible;
461 } else {
462 mBluetoothDevicesWithCsd.emplace(
463 std::make_pair(audioDevice.address,
464 static_cast<audio_devices_t>(audioDevice.internalAudioType)),
465 audioDevice.csdCompatible);
466 }
467
468 for (const auto &activeDevice: mActiveDevices) {
469 if (activeDevice.first.address() == audioDevice.address &&
470 activeDevice.first.mType ==
471 static_cast<audio_devices_t>(audioDevice.internalAudioType)) {
472 if (audioDevice.csdCompatible) {
473 devicesToStart.push_back(activeDevice.second);
474 } else {
475 devicesToStop.push_back(activeDevice.second);
476 }
477 }
478 }
479 }
480
481 for (const auto& deviceToStart : devicesToStart) {
482 mMelReporterCallback->startMelComputationForDeviceId(deviceToStart);
483 }
484 for (const auto& deviceToStop : devicesToStop) {
485 mMelReporterCallback->stopMelComputationForDeviceId(deviceToStop);
486 }
487}
488
489bool SoundDoseManager::shouldComputeCsdForDeviceType(audio_devices_t device) {
490 if (!isCsdEnabled()) {
491 ALOGV("%s csd is disabled", __func__);
492 return false;
493 }
494 if (forceComputeCsdOnAllDevices()) {
495 return true;
496 }
497
498 switch (device) {
499 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
500 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
Vlad Popaac6389f2023-07-31 17:33:25 -0700501 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
Vlad Popa197faf82023-07-27 18:27:59 -0700502 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
503 case AUDIO_DEVICE_OUT_USB_HEADSET:
504 case AUDIO_DEVICE_OUT_BLE_HEADSET:
505 case AUDIO_DEVICE_OUT_BLE_BROADCAST:
506 return true;
507 default:
508 return false;
509 }
510}
511
512bool SoundDoseManager::shouldComputeCsdForDeviceWithAddress(const audio_devices_t type,
513 const std::string& deviceAddress) {
514 if (!isCsdEnabled()) {
515 ALOGV("%s csd is disabled", __func__);
516 return false;
517 }
518 if (forceComputeCsdOnAllDevices()) {
519 return true;
520 }
521
522 if (!audio_is_ble_out_device(type) && !audio_is_a2dp_device(type)) {
523 return shouldComputeCsdForDeviceType(type);
524 }
525
526 const std::lock_guard _l(mLock);
527 const auto deviceIt = mBluetoothDevicesWithCsd.find(std::make_pair(deviceAddress, type));
528 return deviceIt != mBluetoothDevicesWithCsd.end() && deviceIt->second;
529}
530
Vlad Popa91930462022-12-20 22:42:48 +0100531void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100532 // invalidate any HAL sound dose interface used
Vlad Popa63c48dd2023-08-21 19:52:14 -0700533 resetHalSoundDoseInterfaces();
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100534
Vlad Popaffcacdc2023-06-10 00:24:35 +0200535 const std::lock_guard _l(mLock);
Vlad Popa91930462022-12-20 22:42:48 +0100536 mUseFrameworkMel = useFrameworkMel;
537}
538
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100539bool SoundDoseManager::forceUseFrameworkMel() const {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200540 const std::lock_guard _l(mLock);
Vlad Popa91930462022-12-20 22:42:48 +0100541 return mUseFrameworkMel;
542}
543
544void SoundDoseManager::setComputeCsdOnAllDevices(bool computeCsdOnAllDevices) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200545 const std::lock_guard _l(mLock);
Vlad Popa91930462022-12-20 22:42:48 +0100546 mComputeCsdOnAllDevices = computeCsdOnAllDevices;
547}
548
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100549bool SoundDoseManager::forceComputeCsdOnAllDevices() const {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200550 const std::lock_guard _l(mLock);
Vlad Popa91930462022-12-20 22:42:48 +0100551 return mComputeCsdOnAllDevices;
552}
553
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000554bool SoundDoseManager::isSoundDoseHalSupported() const {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200555 {
556 const std::lock_guard _l(mLock);
557 if (!mEnabledCsd) return false;
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000558 }
559
Vlad Popa63c48dd2023-08-21 19:52:14 -0700560 return useHalSoundDose();
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000561}
562
Vlad Popa63c48dd2023-08-21 19:52:14 -0700563bool SoundDoseManager::useHalSoundDose() const {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200564 const std::lock_guard _l(mLock);
Vlad Popa63c48dd2023-08-21 19:52:14 -0700565 return mHalSoundDose.size() > 0;
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100566}
567
Vlad Popae3fd1c22022-11-07 21:03:18 +0100568void SoundDoseManager::resetSoundDose() {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200569 const std::lock_guard lock(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100570 mSoundDose = nullptr;
571}
572
573void SoundDoseManager::resetCsd(float currentCsd,
574 const std::vector<media::SoundDoseRecord>& records) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200575 const std::lock_guard lock(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100576 std::vector<audio_utils::CsdRecord> resetRecords;
Vlad Popaffcacdc2023-06-10 00:24:35 +0200577 resetRecords.reserve(records.size());
Vlad Popae3fd1c22022-11-07 21:03:18 +0100578 for (const auto& record : records) {
579 resetRecords.emplace_back(record.timestamp, record.duration, record.value,
580 record.averageMel);
581 }
582
583 mMelAggregator->reset(currentCsd, resetRecords);
584}
585
Vlad Popa4defd0b2022-11-06 14:22:31 +0100586void SoundDoseManager::onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
587 audio_port_handle_t deviceId) const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100588 ALOGV("%s", __func__);
Vlad Popa2900c0a2022-10-24 13:38:00 +0200589
Vlad Popa2a06fca2023-02-06 16:45:45 +0100590
Vlad Popa4defd0b2022-11-06 14:22:31 +0100591 sp<media::ISoundDoseCallback> soundDoseCallback;
592 std::vector<audio_utils::CsdRecord> records;
593 float currentCsd;
594 {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200595 const std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200596 if (!mEnabledCsd) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100597 return;
598 }
599
Vlad Popa2900c0a2022-10-24 13:38:00 +0200600
Vlad Popaffcacdc2023-06-10 00:24:35 +0200601 const int64_t timestampSec = getMonotonicSecond();
Vlad Popa4defd0b2022-11-06 14:22:31 +0100602
603 // only for internal callbacks
604 records = mMelAggregator->aggregateAndAddNewMelRecord(audio_utils::MelRecord(
605 deviceId, std::vector<float>(mels.begin() + offset, mels.begin() + offset + length),
606 timestampSec - length));
607
608 currentCsd = mMelAggregator->getCsd();
609 }
610
611 soundDoseCallback = getSoundDoseCallback();
612
613 if (records.size() > 0 && soundDoseCallback != nullptr) {
614 std::vector<media::SoundDoseRecord> newRecordsToReport;
Vlad Popaffcacdc2023-06-10 00:24:35 +0200615 newRecordsToReport.resize(records.size());
Vlad Popa4defd0b2022-11-06 14:22:31 +0100616 for (const auto& record : records) {
617 newRecordsToReport.emplace_back(csdRecordToSoundDoseRecord(record));
618 }
619
620 soundDoseCallback->onNewCsdValue(currentCsd, newRecordsToReport);
621 }
Vlad Popa2900c0a2022-10-24 13:38:00 +0200622}
623
Vlad Popa4defd0b2022-11-06 14:22:31 +0100624sp<media::ISoundDoseCallback> SoundDoseManager::getSoundDoseCallback() const {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200625 const std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100626 if (mSoundDose == nullptr) {
627 return nullptr;
628 }
629
630 return mSoundDose->mSoundDoseCallback;
Vlad Popa4defd0b2022-11-06 14:22:31 +0100631}
632
633void SoundDoseManager::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const {
634 ALOGV("%s: Momentary exposure for device %d triggered: %f MEL", __func__, deviceId, currentMel);
Vlad Popa63f047e2022-11-05 14:09:19 +0100635
Vlad Popa2a06fca2023-02-06 16:45:45 +0100636 {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200637 const std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200638 if (!mEnabledCsd) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100639 return;
640 }
641 }
642
Vlad Popae3fd1c22022-11-07 21:03:18 +0100643 auto soundDoseCallback = getSoundDoseCallback();
Vlad Popa63f047e2022-11-05 14:09:19 +0100644 if (soundDoseCallback != nullptr) {
Vlad Popae3fd1c22022-11-07 21:03:18 +0100645 soundDoseCallback->onMomentaryExposure(currentMel, deviceId);
Vlad Popa63f047e2022-11-05 14:09:19 +0100646 }
647}
648
Vlad Popae3fd1c22022-11-07 21:03:18 +0100649sp<media::ISoundDose> SoundDoseManager::getSoundDoseInterface(
650 const sp<media::ISoundDoseCallback>& callback) {
Vlad Popa63f047e2022-11-05 14:09:19 +0100651 ALOGV("%s: Register ISoundDoseCallback", __func__);
652
Vlad Popaffcacdc2023-06-10 00:24:35 +0200653 const std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100654 if (mSoundDose == nullptr) {
655 mSoundDose = sp<SoundDose>::make(this, callback);
656 }
657 return mSoundDose;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100658}
659
Vlad Popa4defd0b2022-11-06 14:22:31 +0100660std::string SoundDoseManager::dump() const {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200661 std::string output;
Vlad Popa2a06fca2023-02-06 16:45:45 +0100662 {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200663 const std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200664 if (!mEnabledCsd) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100665 base::StringAppendF(&output, "CSD is disabled");
666 return output;
667 }
668 }
669
Vlad Popaf09e93f2022-10-31 16:27:12 +0100670 mMelAggregator->foreachCsd([&output](audio_utils::CsdRecord csdRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200671 base::StringAppendF(&output,
672 "CSD %f with average MEL %f in interval [%" PRId64 ", %" PRId64 "]",
Vlad Popa4defd0b2022-11-06 14:22:31 +0100673 csdRecord.value, csdRecord.averageMel, csdRecord.timestamp,
Vlad Popa2900c0a2022-10-24 13:38:00 +0200674 csdRecord.timestamp + csdRecord.duration);
675 base::StringAppendF(&output, "\n");
676 });
677
678 base::StringAppendF(&output, "\nCached Mel Records:\n");
Vlad Popaf09e93f2022-10-31 16:27:12 +0100679 mMelAggregator->foreachCachedMel([&output](const audio_utils::MelRecord& melRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200680 base::StringAppendF(&output, "Continuous MELs for portId=%d, ", melRecord.portId);
681 base::StringAppendF(&output, "starting at timestamp %" PRId64 ": ", melRecord.timestamp);
682
683 for (const auto& mel : melRecord.mels) {
684 base::StringAppendF(&output, "%.2f ", mel);
685 }
686 base::StringAppendF(&output, "\n");
687 });
688
689 return output;
690}
691
692size_t SoundDoseManager::getCachedMelRecordsSize() const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100693 return mMelAggregator->getCachedMelRecordsSize();
Vlad Popa2900c0a2022-10-24 13:38:00 +0200694}
695
Vlad Popa4defd0b2022-11-06 14:22:31 +0100696media::SoundDoseRecord SoundDoseManager::csdRecordToSoundDoseRecord(
697 const audio_utils::CsdRecord& legacy) {
698 media::SoundDoseRecord soundDoseRecord{};
699 soundDoseRecord.timestamp = legacy.timestamp;
700 soundDoseRecord.duration = legacy.duration;
701 soundDoseRecord.value = legacy.value;
702 soundDoseRecord.averageMel = legacy.averageMel;
703 return soundDoseRecord;
704}
705
Vlad Popa2900c0a2022-10-24 13:38:00 +0200706} // namespace android