blob: cb9178b9b262990d565361aec9cecb7b3b58022a [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;
33using aidl::android::media::audio::common::AudioDeviceAddress;
34
Vlad Popa2900c0a2022-10-24 13:38:00 +020035namespace {
36
37int64_t getMonotonicSecond() {
38 struct timespec now_ts;
39 if (clock_gettime(CLOCK_MONOTONIC, &now_ts) != 0) {
40 ALOGE("%s: cannot get timestamp", __func__);
41 return -1;
42 }
43 return now_ts.tv_sec;
44}
45
46} // namespace
47
Vlad Popaf09e93f2022-10-31 16:27:12 +010048sp<audio_utils::MelProcessor> SoundDoseManager::getOrCreateProcessorForDevice(
Vlad Popa4defd0b2022-11-06 14:22:31 +010049 audio_port_handle_t deviceId, audio_io_handle_t streamHandle, uint32_t sampleRate,
50 size_t channelCount, audio_format_t format) {
Vlad Popa2900c0a2022-10-24 13:38:00 +020051 std::lock_guard _l(mLock);
52
Vlad Popa08c8c4b2023-08-21 19:52:14 -070053 if (mHalSoundDose.size() > 0 && mEnabledCsd) {
Vlad Popa1c2f7e12023-03-28 02:08:56 +020054 ALOGD("%s: using HAL MEL computation, no MelProcessor needed.", __func__);
Vlad Popa1d5f0d52022-12-18 12:21:26 +010055 return nullptr;
56 }
57
Vlad Popaf09e93f2022-10-31 16:27:12 +010058 auto streamProcessor = mActiveProcessors.find(streamHandle);
Vlad Popa1c2f7e12023-03-28 02:08:56 +020059 if (streamProcessor != mActiveProcessors.end()) {
60 auto processor = streamProcessor->second.promote();
61 // if processor is nullptr it means it was removed by the playback
62 // thread and can be replaced in the mActiveProcessors map
63 if (processor != nullptr) {
64 ALOGV("%s: found callback for stream id %d", __func__, streamHandle);
65 const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
66 if (activeTypeIt != mActiveDeviceTypes.end()) {
67 processor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
68 }
69 processor->setDeviceId(deviceId);
70 processor->setOutputRs2UpperBound(mRs2UpperBound);
71 return processor;
Vlad Popa58e72dc2023-02-01 13:18:40 +010072 }
Vlad Popa2900c0a2022-10-24 13:38:00 +020073 }
Vlad Popa1c2f7e12023-03-28 02:08:56 +020074
75 ALOGV("%s: creating new callback for stream id %d", __func__, streamHandle);
76 sp<audio_utils::MelProcessor> melProcessor = sp<audio_utils::MelProcessor>::make(
77 sampleRate, channelCount, format, this, deviceId, mRs2UpperBound);
78 const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
79 if (activeTypeIt != mActiveDeviceTypes.end()) {
80 melProcessor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
81 }
82 mActiveProcessors[streamHandle] = melProcessor;
83 return melProcessor;
Vlad Popa2900c0a2022-10-24 13:38:00 +020084}
85
Vlad Popa08c8c4b2023-08-21 19:52:14 -070086bool SoundDoseManager::setHalSoundDoseInterface(const std::string &module,
87 const std::shared_ptr<ISoundDose> &halSoundDose) {
Vlad Popa1d5f0d52022-12-18 12:21:26 +010088 ALOGV("%s", __func__);
89
Vlad Popa08c8c4b2023-08-21 19:52:14 -070090 if (halSoundDose == nullptr) {
91 ALOGI("%s: passed ISoundDose object is null", __func__);
92 return false;
93 }
94
95 std::shared_ptr<HalSoundDoseCallback> halSoundDoseCallback;
Vlad Popa1d5f0d52022-12-18 12:21:26 +010096 {
97 std::lock_guard _l(mLock);
98
Vlad Popa08c8c4b2023-08-21 19:52:14 -070099 if (mHalSoundDose.find(module) != mHalSoundDose.end()) {
100 ALOGW("%s: Module %s already has a sound dose HAL assigned, skipping", __func__,
101 module.c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100102 return false;
103 }
Vlad Popa08c8c4b2023-08-21 19:52:14 -0700104 mHalSoundDose[module] = halSoundDose;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100105
Vlad Popa08c8c4b2023-08-21 19:52:14 -0700106 if (!halSoundDose->setOutputRs2UpperBound(mRs2UpperBound).isOk()) {
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100107 ALOGW("%s: Cannot set RS2 value for momentary exposure %f",
108 __func__,
Vlad Popa4847de12023-03-16 18:30:08 +0100109 mRs2UpperBound);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100110 }
111
112 // initialize the HAL sound dose callback lazily
113 if (mHalSoundDoseCallback == nullptr) {
114 mHalSoundDoseCallback =
115 ndk::SharedRefBase::make<HalSoundDoseCallback>(this);
116 }
117 }
118
119 auto status = halSoundDose->registerSoundDoseCallback(mHalSoundDoseCallback);
120 if (!status.isOk()) {
121 // Not a warning since this can happen if the callback was registered before
122 ALOGI("%s: Cannot register HAL sound dose callback with status message: %s",
123 __func__,
124 status.getMessage());
125 }
126
127 return true;
128}
129
Vlad Popa08c8c4b2023-08-21 19:52:14 -0700130void SoundDoseManager::resetHalSoundDoseInterfaces() {
131 ALOGV("%s", __func__);
132
133 const std::lock_guard _l(mLock);
134 mHalSoundDose.clear();
135}
136
Vlad Popa4847de12023-03-16 18:30:08 +0100137void SoundDoseManager::setOutputRs2UpperBound(float rs2Value) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200138 ALOGV("%s", __func__);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100139 std::lock_guard _l(mLock);
140
Vlad Popa08c8c4b2023-08-21 19:52:14 -0700141 if (mHalSoundDose.size() > 0) {
142 for (auto& halSoundDose : mHalSoundDose) {
143 // using the HAL sound dose interface
144 if (!halSoundDose.second->setOutputRs2UpperBound(rs2Value).isOk()) {
145 ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
146 continue;
147 }
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100148 }
Vlad Popa08c8c4b2023-08-21 19:52:14 -0700149
Vlad Popa4847de12023-03-16 18:30:08 +0100150 mRs2UpperBound = rs2Value;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100151 return;
152 }
Vlad Popae3fd1c22022-11-07 21:03:18 +0100153
Vlad Popaf09e93f2022-10-31 16:27:12 +0100154 for (auto& streamProcessor : mActiveProcessors) {
155 sp<audio_utils::MelProcessor> processor = streamProcessor.second.promote();
156 if (processor != nullptr) {
Vlad Popa4847de12023-03-16 18:30:08 +0100157 status_t result = processor->setOutputRs2UpperBound(rs2Value);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100158 if (result != NO_ERROR) {
Vlad Popa4847de12023-03-16 18:30:08 +0100159 ALOGW("%s: could not set RS2 upper bound %f for stream %d", __func__, rs2Value,
Vlad Popaf09e93f2022-10-31 16:27:12 +0100160 streamProcessor.first);
Vlad Popa3c3995d2023-01-13 11:10:05 +0100161 return;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100162 }
Vlad Popa4847de12023-03-16 18:30:08 +0100163 mRs2UpperBound = rs2Value;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100164 }
165 }
166}
167
Vlad Popa4defd0b2022-11-06 14:22:31 +0100168void SoundDoseManager::removeStreamProcessor(audio_io_handle_t streamHandle) {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100169 std::lock_guard _l(mLock);
170 auto callbackToRemove = mActiveProcessors.find(streamHandle);
Vlad Popa4defd0b2022-11-06 14:22:31 +0100171 if (callbackToRemove != mActiveProcessors.end()) {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100172 mActiveProcessors.erase(callbackToRemove);
173 }
174}
175
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100176audio_port_handle_t SoundDoseManager::getIdForAudioDevice(const AudioDevice& audioDevice) const {
177 std::lock_guard _l(mLock);
178
179 audio_devices_t type;
180 std::string address;
181 auto result = aidl::android::aidl2legacy_AudioDevice_audio_device(
182 audioDevice, &type, &address);
183 if (result != NO_ERROR) {
184 ALOGE("%s: could not convert from AudioDevice to AudioDeviceTypeAddr", __func__);
185 return AUDIO_PORT_HANDLE_NONE;
186 }
187
188 auto adt = AudioDeviceTypeAddr(type, address);
189 auto deviceIt = mActiveDevices.find(adt);
190 if (deviceIt == mActiveDevices.end()) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100191 ALOGI("%s: could not find port id for device %s", __func__, adt.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100192 return AUDIO_PORT_HANDLE_NONE;
193 }
194 return deviceIt->second;
195}
196
197void SoundDoseManager::mapAddressToDeviceId(const AudioDeviceTypeAddr& adt,
198 const audio_port_handle_t deviceId) {
199 std::lock_guard _l(mLock);
Vlad Popaeafa0482023-02-23 14:35:56 +0100200 ALOGI("%s: map address: %d to device id: %d", __func__, adt.mType, deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100201 mActiveDevices[adt] = deviceId;
Vlad Popa58e72dc2023-02-01 13:18:40 +0100202 mActiveDeviceTypes[deviceId] = adt.mType;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100203}
204
205void SoundDoseManager::clearMapDeviceIdEntries(audio_port_handle_t deviceId) {
206 std::lock_guard _l(mLock);
207 for (auto activeDevice = mActiveDevices.begin(); activeDevice != mActiveDevices.end();) {
208 if (activeDevice->second == deviceId) {
Vlad Popaeafa0482023-02-23 14:35:56 +0100209 ALOGI("%s: clear mapping type: %d to deviceId: %d",
210 __func__, activeDevice->first.mType, deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100211 activeDevice = mActiveDevices.erase(activeDevice);
212 continue;
213 }
214 ++activeDevice;
215 }
Vlad Popa58e72dc2023-02-01 13:18:40 +0100216 mActiveDeviceTypes.erase(deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100217}
218
219ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
220 float in_currentDbA, const AudioDevice& in_audioDevice) {
Vlad Popa08c8c4b2023-08-21 19:52:14 -0700221 sp<SoundDoseManager> soundDoseManager;
222 {
223 const std::lock_guard _l(mCbLock);
224 soundDoseManager = mSoundDoseManager.promote();
225 if (soundDoseManager == nullptr) {
226 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
227 }
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100228 }
229
Vlad Popa08c8c4b2023-08-21 19:52:14 -0700230 if (!soundDoseManager->useHalSoundDose()) {
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100231 ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
232 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
233 }
234
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100235 auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
236 if (id == AUDIO_PORT_HANDLE_NONE) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100237 ALOGI("%s: no mapped id for audio device with type %d and address %s",
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100238 __func__, in_audioDevice.type.type,
Vlad Popa69fbbee2023-04-25 12:23:24 +0200239 in_audioDevice.address.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100240 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
241 }
242 soundDoseManager->onMomentaryExposure(in_currentDbA, id);
243
244 return ndk::ScopedAStatus::ok();
245}
246
247ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onNewMelValues(
248 const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
249 const AudioDevice& in_audioDevice) {
Vlad Popa08c8c4b2023-08-21 19:52:14 -0700250 sp<SoundDoseManager> soundDoseManager;
251 {
252 const std::lock_guard _l(mCbLock);
253 soundDoseManager = mSoundDoseManager.promote();
254 if (soundDoseManager == nullptr) {
255 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
256 }
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100257 }
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100258
Vlad Popa08c8c4b2023-08-21 19:52:14 -0700259 if (!soundDoseManager->useHalSoundDose()) {
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100260 ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
261 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
262 }
263
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100264 auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
265 if (id == AUDIO_PORT_HANDLE_NONE) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100266 ALOGI("%s: no mapped id for audio device with type %d and address %s",
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100267 __func__, in_audioDevice.type.type,
Vlad Popa69fbbee2023-04-25 12:23:24 +0200268 in_audioDevice.address.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100269 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
270 }
271 // TODO: introduce timestamp in onNewMelValues callback
272 soundDoseManager->onNewMelValues(in_melRecord.melValues, 0,
273 in_melRecord.melValues.size(), id);
274
275 return ndk::ScopedAStatus::ok();
276}
277
Vlad Popae3fd1c22022-11-07 21:03:18 +0100278void SoundDoseManager::SoundDose::binderDied(__unused const wp<IBinder>& who) {
279 ALOGV("%s", __func__);
280
281 auto soundDoseManager = mSoundDoseManager.promote();
282 if (soundDoseManager != nullptr) {
283 soundDoseManager->resetSoundDose();
284 }
285}
286
Vlad Popa4847de12023-03-16 18:30:08 +0100287binder::Status SoundDoseManager::SoundDose::setOutputRs2UpperBound(float value) {
Vlad Popae3fd1c22022-11-07 21:03:18 +0100288 ALOGV("%s", __func__);
289 auto soundDoseManager = mSoundDoseManager.promote();
290 if (soundDoseManager != nullptr) {
Vlad Popa4847de12023-03-16 18:30:08 +0100291 soundDoseManager->setOutputRs2UpperBound(value);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100292 }
293 return binder::Status::ok();
294}
295
296binder::Status SoundDoseManager::SoundDose::resetCsd(
297 float currentCsd, const std::vector<media::SoundDoseRecord>& records) {
298 ALOGV("%s", __func__);
299 auto soundDoseManager = mSoundDoseManager.promote();
300 if (soundDoseManager != nullptr) {
301 soundDoseManager->resetCsd(currentCsd, records);
302 }
303 return binder::Status::ok();
304}
305
Vlad Popa58e72dc2023-02-01 13:18:40 +0100306binder::Status SoundDoseManager::SoundDose::updateAttenuation(float attenuationDB, int device) {
307 ALOGV("%s", __func__);
308 auto soundDoseManager = mSoundDoseManager.promote();
309 if (soundDoseManager != nullptr) {
310 soundDoseManager->updateAttenuation(attenuationDB, static_cast<audio_devices_t>(device));
311 }
312 return binder::Status::ok();
313}
314
Vlad Popa617bbf02023-04-24 19:10:36 +0200315binder::Status SoundDoseManager::SoundDose::setCsdEnabled(bool enabled) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100316 ALOGV("%s", __func__);
317 auto soundDoseManager = mSoundDoseManager.promote();
318 if (soundDoseManager != nullptr) {
Vlad Popa617bbf02023-04-24 19:10:36 +0200319 soundDoseManager->setCsdEnabled(enabled);
Vlad Popa2a06fca2023-02-06 16:45:45 +0100320 }
321 return binder::Status::ok();
322}
323
Vlad Popa197faf82023-07-27 18:27:59 -0700324binder::Status SoundDoseManager::SoundDose::initCachedAudioDeviceCategories(
325 const std::vector<media::ISoundDose::AudioDeviceCategory>& btDeviceCategories) {
326 ALOGV("%s", __func__);
327 auto soundDoseManager = mSoundDoseManager.promote();
328 if (soundDoseManager != nullptr) {
329 soundDoseManager->initCachedAudioDeviceCategories(btDeviceCategories);
330 }
331 return binder::Status::ok();
332}
333binder::Status SoundDoseManager::SoundDose::setAudioDeviceCategory(
334 const media::ISoundDose::AudioDeviceCategory& btAudioDevice) {
335 ALOGV("%s", __func__);
336 auto soundDoseManager = mSoundDoseManager.promote();
337 if (soundDoseManager != nullptr) {
338 soundDoseManager->setAudioDeviceCategory(btAudioDevice);
339 }
340 return binder::Status::ok();
341}
342
Vlad Popa4847de12023-03-16 18:30:08 +0100343binder::Status SoundDoseManager::SoundDose::getOutputRs2UpperBound(float* value) {
Vlad Popa91930462022-12-20 22:42:48 +0100344 ALOGV("%s", __func__);
345 auto soundDoseManager = mSoundDoseManager.promote();
346 if (soundDoseManager != nullptr) {
347 std::lock_guard _l(soundDoseManager->mLock);
Vlad Popa4847de12023-03-16 18:30:08 +0100348 *value = soundDoseManager->mRs2UpperBound;
Vlad Popa91930462022-12-20 22:42:48 +0100349 }
350 return binder::Status::ok();
351}
352
353binder::Status SoundDoseManager::SoundDose::getCsd(float* value) {
354 ALOGV("%s", __func__);
355 auto soundDoseManager = mSoundDoseManager.promote();
356 if (soundDoseManager != nullptr) {
357 *value = soundDoseManager->mMelAggregator->getCsd();
358 }
359 return binder::Status::ok();
360}
361
362binder::Status SoundDoseManager::SoundDose::forceUseFrameworkMel(bool useFrameworkMel) {
363 ALOGV("%s", __func__);
364 auto soundDoseManager = mSoundDoseManager.promote();
365 if (soundDoseManager != nullptr) {
366 soundDoseManager->setUseFrameworkMel(useFrameworkMel);
367 }
368 return binder::Status::ok();
369}
370
371binder::Status SoundDoseManager::SoundDose::forceComputeCsdOnAllDevices(
372 bool computeCsdOnAllDevices) {
373 ALOGV("%s", __func__);
374 auto soundDoseManager = mSoundDoseManager.promote();
375 if (soundDoseManager != nullptr) {
376 soundDoseManager->setComputeCsdOnAllDevices(computeCsdOnAllDevices);
377 }
378 return binder::Status::ok();
379}
380
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000381binder::Status SoundDoseManager::SoundDose::isSoundDoseHalSupported(bool* value) {
382 ALOGV("%s", __func__);
383 *value = false;
384 auto soundDoseManager = mSoundDoseManager.promote();
385 if (soundDoseManager != nullptr) {
386 *value = soundDoseManager->isSoundDoseHalSupported();
387 }
388 return binder::Status::ok();
389}
390
Vlad Popa58e72dc2023-02-01 13:18:40 +0100391void SoundDoseManager::updateAttenuation(float attenuationDB, audio_devices_t deviceType) {
392 std::lock_guard _l(mLock);
Vlad Popaeafa0482023-02-23 14:35:56 +0100393 ALOGV("%s: updating MEL processor attenuation for device type %d to %f",
Vlad Popa58e72dc2023-02-01 13:18:40 +0100394 __func__, deviceType, attenuationDB);
395 mMelAttenuationDB[deviceType] = attenuationDB;
396 for (const auto& mp : mActiveProcessors) {
397 auto melProcessor = mp.second.promote();
398 if (melProcessor != nullptr) {
399 auto deviceId = melProcessor->getDeviceId();
Vlad Popa197faf82023-07-27 18:27:59 -0700400 const auto deviceTypeIt = mActiveDeviceTypes.find(deviceId);
401 if (deviceTypeIt != mActiveDeviceTypes.end() &&
402 deviceTypeIt->second == deviceType) {
Vlad Popaeafa0482023-02-23 14:35:56 +0100403 ALOGV("%s: set attenuation for deviceId %d to %f",
Vlad Popa58e72dc2023-02-01 13:18:40 +0100404 __func__, deviceId, attenuationDB);
405 melProcessor->setAttenuation(attenuationDB);
406 }
407 }
408 }
409}
410
Vlad Popa617bbf02023-04-24 19:10:36 +0200411void SoundDoseManager::setCsdEnabled(bool enabled) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100412 ALOGV("%s", __func__);
413
414 std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200415 mEnabledCsd = enabled;
Vlad Popa2a06fca2023-02-06 16:45:45 +0100416
Vlad Popa2a06fca2023-02-06 16:45:45 +0100417 for (auto& activeEntry : mActiveProcessors) {
418 auto melProcessor = activeEntry.second.promote();
419 if (melProcessor != nullptr) {
Vlad Popa617bbf02023-04-24 19:10:36 +0200420 if (enabled) {
421 melProcessor->resume();
422 } else {
423 melProcessor->pause();
424 }
Vlad Popa2a06fca2023-02-06 16:45:45 +0100425 }
426 }
427}
428
Vlad Popa617bbf02023-04-24 19:10:36 +0200429bool SoundDoseManager::isCsdEnabled() {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100430 std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200431 return mEnabledCsd;
Vlad Popa2a06fca2023-02-06 16:45:45 +0100432}
433
Vlad Popa197faf82023-07-27 18:27:59 -0700434void SoundDoseManager::initCachedAudioDeviceCategories(
435 const std::vector<media::ISoundDose::AudioDeviceCategory>& deviceCategories) {
436 ALOGV("%s", __func__);
437 {
438 const std::lock_guard _l(mLock);
439 mBluetoothDevicesWithCsd.clear();
440 }
441 for (const auto& btDeviceCategory : deviceCategories) {
442 setAudioDeviceCategory(btDeviceCategory);
443 }
444}
445
446void SoundDoseManager::setAudioDeviceCategory(
447 const media::ISoundDose::AudioDeviceCategory& audioDevice) {
448 ALOGV("%s: set BT audio device type with address %s to headphone %d", __func__,
449 audioDevice.address.c_str(), audioDevice.csdCompatible);
450
451 std::vector<audio_port_handle_t> devicesToStart;
452 std::vector<audio_port_handle_t> devicesToStop;
453 {
454 const std::lock_guard _l(mLock);
455 const auto deviceIt = mBluetoothDevicesWithCsd.find(
456 std::make_pair(audioDevice.address,
457 static_cast<audio_devices_t>(audioDevice.internalAudioType)));
458 if (deviceIt != mBluetoothDevicesWithCsd.end()) {
459 deviceIt->second = audioDevice.csdCompatible;
460 } else {
461 mBluetoothDevicesWithCsd.emplace(
462 std::make_pair(audioDevice.address,
463 static_cast<audio_devices_t>(audioDevice.internalAudioType)),
464 audioDevice.csdCompatible);
465 }
466
467 for (const auto &activeDevice: mActiveDevices) {
468 if (activeDevice.first.address() == audioDevice.address &&
469 activeDevice.first.mType ==
470 static_cast<audio_devices_t>(audioDevice.internalAudioType)) {
471 if (audioDevice.csdCompatible) {
472 devicesToStart.push_back(activeDevice.second);
473 } else {
474 devicesToStop.push_back(activeDevice.second);
475 }
476 }
477 }
478 }
479
480 for (const auto& deviceToStart : devicesToStart) {
481 mMelReporterCallback->startMelComputationForDeviceId(deviceToStart);
482 }
483 for (const auto& deviceToStop : devicesToStop) {
484 mMelReporterCallback->stopMelComputationForDeviceId(deviceToStop);
485 }
486}
487
488bool SoundDoseManager::shouldComputeCsdForDeviceType(audio_devices_t device) {
489 if (!isCsdEnabled()) {
490 ALOGV("%s csd is disabled", __func__);
491 return false;
492 }
493 if (forceComputeCsdOnAllDevices()) {
494 return true;
495 }
496
497 switch (device) {
498 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
499 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
Vlad Popaac6389f2023-07-31 17:33:25 -0700500 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
Vlad Popa197faf82023-07-27 18:27:59 -0700501 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
502 case AUDIO_DEVICE_OUT_USB_HEADSET:
503 case AUDIO_DEVICE_OUT_BLE_HEADSET:
504 case AUDIO_DEVICE_OUT_BLE_BROADCAST:
505 return true;
506 default:
507 return false;
508 }
509}
510
511bool SoundDoseManager::shouldComputeCsdForDeviceWithAddress(const audio_devices_t type,
512 const std::string& deviceAddress) {
513 if (!isCsdEnabled()) {
514 ALOGV("%s csd is disabled", __func__);
515 return false;
516 }
517 if (forceComputeCsdOnAllDevices()) {
518 return true;
519 }
520
521 if (!audio_is_ble_out_device(type) && !audio_is_a2dp_device(type)) {
522 return shouldComputeCsdForDeviceType(type);
523 }
524
525 const std::lock_guard _l(mLock);
526 const auto deviceIt = mBluetoothDevicesWithCsd.find(std::make_pair(deviceAddress, type));
527 return deviceIt != mBluetoothDevicesWithCsd.end() && deviceIt->second;
528}
529
Vlad Popa91930462022-12-20 22:42:48 +0100530void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100531 // invalidate any HAL sound dose interface used
Vlad Popa08c8c4b2023-08-21 19:52:14 -0700532 resetHalSoundDoseInterfaces();
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100533
Vlad Popa91930462022-12-20 22:42:48 +0100534 std::lock_guard _l(mLock);
535 mUseFrameworkMel = useFrameworkMel;
536}
537
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100538bool SoundDoseManager::forceUseFrameworkMel() const {
Vlad Popa91930462022-12-20 22:42:48 +0100539 std::lock_guard _l(mLock);
540 return mUseFrameworkMel;
541}
542
543void SoundDoseManager::setComputeCsdOnAllDevices(bool computeCsdOnAllDevices) {
544 std::lock_guard _l(mLock);
545 mComputeCsdOnAllDevices = computeCsdOnAllDevices;
546}
547
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100548bool SoundDoseManager::forceComputeCsdOnAllDevices() const {
Vlad Popa91930462022-12-20 22:42:48 +0100549 std::lock_guard _l(mLock);
550 return mComputeCsdOnAllDevices;
551}
552
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000553bool SoundDoseManager::isSoundDoseHalSupported() const {
Vlad Popa617bbf02023-04-24 19:10:36 +0200554 if (!mEnabledCsd) {
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000555 return false;
556 }
557
Vlad Popa08c8c4b2023-08-21 19:52:14 -0700558 return useHalSoundDose();
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000559}
560
Vlad Popa08c8c4b2023-08-21 19:52:14 -0700561bool SoundDoseManager::useHalSoundDose() const {
562 const std::lock_guard _l(mLock);
563 return mHalSoundDose.size() > 0;
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100564}
565
Vlad Popae3fd1c22022-11-07 21:03:18 +0100566void SoundDoseManager::resetSoundDose() {
567 std::lock_guard lock(mLock);
568 mSoundDose = nullptr;
569}
570
571void SoundDoseManager::resetCsd(float currentCsd,
572 const std::vector<media::SoundDoseRecord>& records) {
573 std::lock_guard lock(mLock);
574 std::vector<audio_utils::CsdRecord> resetRecords;
575 for (const auto& record : records) {
576 resetRecords.emplace_back(record.timestamp, record.duration, record.value,
577 record.averageMel);
578 }
579
580 mMelAggregator->reset(currentCsd, resetRecords);
581}
582
Vlad Popa4defd0b2022-11-06 14:22:31 +0100583void SoundDoseManager::onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
584 audio_port_handle_t deviceId) const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100585 ALOGV("%s", __func__);
Vlad Popa2900c0a2022-10-24 13:38:00 +0200586
Vlad Popa2a06fca2023-02-06 16:45:45 +0100587
Vlad Popa4defd0b2022-11-06 14:22:31 +0100588 sp<media::ISoundDoseCallback> soundDoseCallback;
589 std::vector<audio_utils::CsdRecord> records;
590 float currentCsd;
591 {
592 std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200593 if (!mEnabledCsd) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100594 return;
595 }
596
Vlad Popa2900c0a2022-10-24 13:38:00 +0200597
Vlad Popa4defd0b2022-11-06 14:22:31 +0100598 int64_t timestampSec = getMonotonicSecond();
599
600 // only for internal callbacks
601 records = mMelAggregator->aggregateAndAddNewMelRecord(audio_utils::MelRecord(
602 deviceId, std::vector<float>(mels.begin() + offset, mels.begin() + offset + length),
603 timestampSec - length));
604
605 currentCsd = mMelAggregator->getCsd();
606 }
607
608 soundDoseCallback = getSoundDoseCallback();
609
610 if (records.size() > 0 && soundDoseCallback != nullptr) {
611 std::vector<media::SoundDoseRecord> newRecordsToReport;
612 for (const auto& record : records) {
613 newRecordsToReport.emplace_back(csdRecordToSoundDoseRecord(record));
614 }
615
616 soundDoseCallback->onNewCsdValue(currentCsd, newRecordsToReport);
617 }
Vlad Popa2900c0a2022-10-24 13:38:00 +0200618}
619
Vlad Popa4defd0b2022-11-06 14:22:31 +0100620sp<media::ISoundDoseCallback> SoundDoseManager::getSoundDoseCallback() const {
621 std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100622 if (mSoundDose == nullptr) {
623 return nullptr;
624 }
625
626 return mSoundDose->mSoundDoseCallback;
Vlad Popa4defd0b2022-11-06 14:22:31 +0100627}
628
629void SoundDoseManager::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const {
630 ALOGV("%s: Momentary exposure for device %d triggered: %f MEL", __func__, deviceId, currentMel);
Vlad Popa63f047e2022-11-05 14:09:19 +0100631
Vlad Popa2a06fca2023-02-06 16:45:45 +0100632 {
633 std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200634 if (!mEnabledCsd) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100635 return;
636 }
637 }
638
Vlad Popae3fd1c22022-11-07 21:03:18 +0100639 auto soundDoseCallback = getSoundDoseCallback();
Vlad Popa63f047e2022-11-05 14:09:19 +0100640 if (soundDoseCallback != nullptr) {
Vlad Popae3fd1c22022-11-07 21:03:18 +0100641 soundDoseCallback->onMomentaryExposure(currentMel, deviceId);
Vlad Popa63f047e2022-11-05 14:09:19 +0100642 }
643}
644
Vlad Popae3fd1c22022-11-07 21:03:18 +0100645sp<media::ISoundDose> SoundDoseManager::getSoundDoseInterface(
646 const sp<media::ISoundDoseCallback>& callback) {
Vlad Popa63f047e2022-11-05 14:09:19 +0100647 ALOGV("%s: Register ISoundDoseCallback", __func__);
648
649 std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100650 if (mSoundDose == nullptr) {
651 mSoundDose = sp<SoundDose>::make(this, callback);
652 }
653 return mSoundDose;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100654}
655
Vlad Popa4defd0b2022-11-06 14:22:31 +0100656std::string SoundDoseManager::dump() const {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200657 std::string output;
Vlad Popa2a06fca2023-02-06 16:45:45 +0100658 {
659 std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200660 if (!mEnabledCsd) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100661 base::StringAppendF(&output, "CSD is disabled");
662 return output;
663 }
664 }
665
Vlad Popaf09e93f2022-10-31 16:27:12 +0100666 mMelAggregator->foreachCsd([&output](audio_utils::CsdRecord csdRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200667 base::StringAppendF(&output,
668 "CSD %f with average MEL %f in interval [%" PRId64 ", %" PRId64 "]",
Vlad Popa4defd0b2022-11-06 14:22:31 +0100669 csdRecord.value, csdRecord.averageMel, csdRecord.timestamp,
Vlad Popa2900c0a2022-10-24 13:38:00 +0200670 csdRecord.timestamp + csdRecord.duration);
671 base::StringAppendF(&output, "\n");
672 });
673
674 base::StringAppendF(&output, "\nCached Mel Records:\n");
Vlad Popaf09e93f2022-10-31 16:27:12 +0100675 mMelAggregator->foreachCachedMel([&output](const audio_utils::MelRecord& melRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200676 base::StringAppendF(&output, "Continuous MELs for portId=%d, ", melRecord.portId);
677 base::StringAppendF(&output, "starting at timestamp %" PRId64 ": ", melRecord.timestamp);
678
679 for (const auto& mel : melRecord.mels) {
680 base::StringAppendF(&output, "%.2f ", mel);
681 }
682 base::StringAppendF(&output, "\n");
683 });
684
685 return output;
686}
687
688size_t SoundDoseManager::getCachedMelRecordsSize() const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100689 return mMelAggregator->getCachedMelRecordsSize();
Vlad Popa2900c0a2022-10-24 13:38:00 +0200690}
691
Vlad Popa4defd0b2022-11-06 14:22:31 +0100692media::SoundDoseRecord SoundDoseManager::csdRecordToSoundDoseRecord(
693 const audio_utils::CsdRecord& legacy) {
694 media::SoundDoseRecord soundDoseRecord{};
695 soundDoseRecord.timestamp = legacy.timestamp;
696 soundDoseRecord.duration = legacy.duration;
697 soundDoseRecord.value = legacy.value;
698 soundDoseRecord.averageMel = legacy.averageMel;
699 return soundDoseRecord;
700}
701
Vlad Popa2900c0a2022-10-24 13:38:00 +0200702} // namespace android