blob: a551857716d871c948ab09678e433077c774ac5c [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 Popa617bbf02023-04-24 19:10:36 +020053 if (mHalSoundDose != nullptr && 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 Popa1d5f0d52022-12-18 12:21:26 +010086bool SoundDoseManager::setHalSoundDoseInterface(const std::shared_ptr<ISoundDose>& halSoundDose) {
87 ALOGV("%s", __func__);
88
89 {
90 std::lock_guard _l(mLock);
91
92 mHalSoundDose = halSoundDose;
93 if (halSoundDose == nullptr) {
94 ALOGI("%s: passed ISoundDose object is null, switching to internal CSD", __func__);
95 return false;
96 }
97
Vlad Popa4847de12023-03-16 18:30:08 +010098 if (!mHalSoundDose->setOutputRs2UpperBound(mRs2UpperBound).isOk()) {
Vlad Popa1d5f0d52022-12-18 12:21:26 +010099 ALOGW("%s: Cannot set RS2 value for momentary exposure %f",
100 __func__,
Vlad Popa4847de12023-03-16 18:30:08 +0100101 mRs2UpperBound);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100102 }
103
104 // initialize the HAL sound dose callback lazily
105 if (mHalSoundDoseCallback == nullptr) {
106 mHalSoundDoseCallback =
107 ndk::SharedRefBase::make<HalSoundDoseCallback>(this);
108 }
109 }
110
111 auto status = halSoundDose->registerSoundDoseCallback(mHalSoundDoseCallback);
112 if (!status.isOk()) {
113 // Not a warning since this can happen if the callback was registered before
114 ALOGI("%s: Cannot register HAL sound dose callback with status message: %s",
115 __func__,
116 status.getMessage());
117 }
118
119 return true;
120}
121
Vlad Popa4847de12023-03-16 18:30:08 +0100122void SoundDoseManager::setOutputRs2UpperBound(float rs2Value) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200123 ALOGV("%s", __func__);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100124 std::lock_guard _l(mLock);
125
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100126 if (mHalSoundDose != nullptr) {
127 // using the HAL sound dose interface
Vlad Popa4847de12023-03-16 18:30:08 +0100128 if (!mHalSoundDose->setOutputRs2UpperBound(rs2Value).isOk()) {
Vlad Popa3c3995d2023-01-13 11:10:05 +0100129 ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
130 return;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100131 }
Vlad Popa4847de12023-03-16 18:30:08 +0100132 mRs2UpperBound = rs2Value;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100133 return;
134 }
Vlad Popae3fd1c22022-11-07 21:03:18 +0100135
Vlad Popaf09e93f2022-10-31 16:27:12 +0100136 for (auto& streamProcessor : mActiveProcessors) {
137 sp<audio_utils::MelProcessor> processor = streamProcessor.second.promote();
138 if (processor != nullptr) {
Vlad Popa4847de12023-03-16 18:30:08 +0100139 status_t result = processor->setOutputRs2UpperBound(rs2Value);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100140 if (result != NO_ERROR) {
Vlad Popa4847de12023-03-16 18:30:08 +0100141 ALOGW("%s: could not set RS2 upper bound %f for stream %d", __func__, rs2Value,
Vlad Popaf09e93f2022-10-31 16:27:12 +0100142 streamProcessor.first);
Vlad Popa3c3995d2023-01-13 11:10:05 +0100143 return;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100144 }
Vlad Popa4847de12023-03-16 18:30:08 +0100145 mRs2UpperBound = rs2Value;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100146 }
147 }
148}
149
Vlad Popa4defd0b2022-11-06 14:22:31 +0100150void SoundDoseManager::removeStreamProcessor(audio_io_handle_t streamHandle) {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100151 std::lock_guard _l(mLock);
152 auto callbackToRemove = mActiveProcessors.find(streamHandle);
Vlad Popa4defd0b2022-11-06 14:22:31 +0100153 if (callbackToRemove != mActiveProcessors.end()) {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100154 mActiveProcessors.erase(callbackToRemove);
155 }
156}
157
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100158audio_port_handle_t SoundDoseManager::getIdForAudioDevice(const AudioDevice& audioDevice) const {
159 std::lock_guard _l(mLock);
160
161 audio_devices_t type;
162 std::string address;
163 auto result = aidl::android::aidl2legacy_AudioDevice_audio_device(
164 audioDevice, &type, &address);
165 if (result != NO_ERROR) {
166 ALOGE("%s: could not convert from AudioDevice to AudioDeviceTypeAddr", __func__);
167 return AUDIO_PORT_HANDLE_NONE;
168 }
169
170 auto adt = AudioDeviceTypeAddr(type, address);
171 auto deviceIt = mActiveDevices.find(adt);
172 if (deviceIt == mActiveDevices.end()) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100173 ALOGI("%s: could not find port id for device %s", __func__, adt.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100174 return AUDIO_PORT_HANDLE_NONE;
175 }
176 return deviceIt->second;
177}
178
179void SoundDoseManager::mapAddressToDeviceId(const AudioDeviceTypeAddr& adt,
180 const audio_port_handle_t deviceId) {
181 std::lock_guard _l(mLock);
Vlad Popaeafa0482023-02-23 14:35:56 +0100182 ALOGI("%s: map address: %d to device id: %d", __func__, adt.mType, deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100183 mActiveDevices[adt] = deviceId;
Vlad Popa58e72dc2023-02-01 13:18:40 +0100184 mActiveDeviceTypes[deviceId] = adt.mType;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100185}
186
187void SoundDoseManager::clearMapDeviceIdEntries(audio_port_handle_t deviceId) {
188 std::lock_guard _l(mLock);
189 for (auto activeDevice = mActiveDevices.begin(); activeDevice != mActiveDevices.end();) {
190 if (activeDevice->second == deviceId) {
Vlad Popaeafa0482023-02-23 14:35:56 +0100191 ALOGI("%s: clear mapping type: %d to deviceId: %d",
192 __func__, activeDevice->first.mType, deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100193 activeDevice = mActiveDevices.erase(activeDevice);
194 continue;
195 }
196 ++activeDevice;
197 }
Vlad Popa58e72dc2023-02-01 13:18:40 +0100198 mActiveDeviceTypes.erase(deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100199}
200
201ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
202 float in_currentDbA, const AudioDevice& in_audioDevice) {
203 auto soundDoseManager = mSoundDoseManager.promote();
204 if (soundDoseManager == nullptr) {
205 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
206 }
207
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100208 std::shared_ptr<ISoundDose> halSoundDose;
209 soundDoseManager->getHalSoundDose(&halSoundDose);
210 if(halSoundDose == nullptr) {
211 ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
212 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
213 }
214
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100215 auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
216 if (id == AUDIO_PORT_HANDLE_NONE) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100217 ALOGI("%s: no mapped id for audio device with type %d and address %s",
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100218 __func__, in_audioDevice.type.type,
Vlad Popa69fbbee2023-04-25 12:23:24 +0200219 in_audioDevice.address.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100220 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
221 }
222 soundDoseManager->onMomentaryExposure(in_currentDbA, id);
223
224 return ndk::ScopedAStatus::ok();
225}
226
227ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onNewMelValues(
228 const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
229 const AudioDevice& in_audioDevice) {
230 auto soundDoseManager = mSoundDoseManager.promote();
231 if (soundDoseManager == nullptr) {
232 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
233 }
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100234
235 std::shared_ptr<ISoundDose> halSoundDose;
236 soundDoseManager->getHalSoundDose(&halSoundDose);
237 if(halSoundDose == nullptr) {
238 ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
239 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
240 }
241
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100242 auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
243 if (id == AUDIO_PORT_HANDLE_NONE) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100244 ALOGI("%s: no mapped id for audio device with type %d and address %s",
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100245 __func__, in_audioDevice.type.type,
Vlad Popa69fbbee2023-04-25 12:23:24 +0200246 in_audioDevice.address.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100247 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
248 }
249 // TODO: introduce timestamp in onNewMelValues callback
250 soundDoseManager->onNewMelValues(in_melRecord.melValues, 0,
251 in_melRecord.melValues.size(), id);
252
253 return ndk::ScopedAStatus::ok();
254}
255
Vlad Popae3fd1c22022-11-07 21:03:18 +0100256void SoundDoseManager::SoundDose::binderDied(__unused const wp<IBinder>& who) {
257 ALOGV("%s", __func__);
258
259 auto soundDoseManager = mSoundDoseManager.promote();
260 if (soundDoseManager != nullptr) {
261 soundDoseManager->resetSoundDose();
262 }
263}
264
Vlad Popa4847de12023-03-16 18:30:08 +0100265binder::Status SoundDoseManager::SoundDose::setOutputRs2UpperBound(float value) {
Vlad Popae3fd1c22022-11-07 21:03:18 +0100266 ALOGV("%s", __func__);
267 auto soundDoseManager = mSoundDoseManager.promote();
268 if (soundDoseManager != nullptr) {
Vlad Popa4847de12023-03-16 18:30:08 +0100269 soundDoseManager->setOutputRs2UpperBound(value);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100270 }
271 return binder::Status::ok();
272}
273
274binder::Status SoundDoseManager::SoundDose::resetCsd(
275 float currentCsd, const std::vector<media::SoundDoseRecord>& records) {
276 ALOGV("%s", __func__);
277 auto soundDoseManager = mSoundDoseManager.promote();
278 if (soundDoseManager != nullptr) {
279 soundDoseManager->resetCsd(currentCsd, records);
280 }
281 return binder::Status::ok();
282}
283
Vlad Popa58e72dc2023-02-01 13:18:40 +0100284binder::Status SoundDoseManager::SoundDose::updateAttenuation(float attenuationDB, int device) {
285 ALOGV("%s", __func__);
286 auto soundDoseManager = mSoundDoseManager.promote();
287 if (soundDoseManager != nullptr) {
288 soundDoseManager->updateAttenuation(attenuationDB, static_cast<audio_devices_t>(device));
289 }
290 return binder::Status::ok();
291}
292
Vlad Popa617bbf02023-04-24 19:10:36 +0200293binder::Status SoundDoseManager::SoundDose::setCsdEnabled(bool enabled) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100294 ALOGV("%s", __func__);
295 auto soundDoseManager = mSoundDoseManager.promote();
296 if (soundDoseManager != nullptr) {
Vlad Popa617bbf02023-04-24 19:10:36 +0200297 soundDoseManager->setCsdEnabled(enabled);
Vlad Popa2a06fca2023-02-06 16:45:45 +0100298 }
299 return binder::Status::ok();
300}
301
Vlad Popa197faf82023-07-27 18:27:59 -0700302binder::Status SoundDoseManager::SoundDose::initCachedAudioDeviceCategories(
303 const std::vector<media::ISoundDose::AudioDeviceCategory>& btDeviceCategories) {
304 ALOGV("%s", __func__);
305 auto soundDoseManager = mSoundDoseManager.promote();
306 if (soundDoseManager != nullptr) {
307 soundDoseManager->initCachedAudioDeviceCategories(btDeviceCategories);
308 }
309 return binder::Status::ok();
310}
311binder::Status SoundDoseManager::SoundDose::setAudioDeviceCategory(
312 const media::ISoundDose::AudioDeviceCategory& btAudioDevice) {
313 ALOGV("%s", __func__);
314 auto soundDoseManager = mSoundDoseManager.promote();
315 if (soundDoseManager != nullptr) {
316 soundDoseManager->setAudioDeviceCategory(btAudioDevice);
317 }
318 return binder::Status::ok();
319}
320
Vlad Popa4847de12023-03-16 18:30:08 +0100321binder::Status SoundDoseManager::SoundDose::getOutputRs2UpperBound(float* value) {
Vlad Popa91930462022-12-20 22:42:48 +0100322 ALOGV("%s", __func__);
323 auto soundDoseManager = mSoundDoseManager.promote();
324 if (soundDoseManager != nullptr) {
325 std::lock_guard _l(soundDoseManager->mLock);
Vlad Popa4847de12023-03-16 18:30:08 +0100326 *value = soundDoseManager->mRs2UpperBound;
Vlad Popa91930462022-12-20 22:42:48 +0100327 }
328 return binder::Status::ok();
329}
330
331binder::Status SoundDoseManager::SoundDose::getCsd(float* value) {
332 ALOGV("%s", __func__);
333 auto soundDoseManager = mSoundDoseManager.promote();
334 if (soundDoseManager != nullptr) {
335 *value = soundDoseManager->mMelAggregator->getCsd();
336 }
337 return binder::Status::ok();
338}
339
340binder::Status SoundDoseManager::SoundDose::forceUseFrameworkMel(bool useFrameworkMel) {
341 ALOGV("%s", __func__);
342 auto soundDoseManager = mSoundDoseManager.promote();
343 if (soundDoseManager != nullptr) {
344 soundDoseManager->setUseFrameworkMel(useFrameworkMel);
345 }
346 return binder::Status::ok();
347}
348
349binder::Status SoundDoseManager::SoundDose::forceComputeCsdOnAllDevices(
350 bool computeCsdOnAllDevices) {
351 ALOGV("%s", __func__);
352 auto soundDoseManager = mSoundDoseManager.promote();
353 if (soundDoseManager != nullptr) {
354 soundDoseManager->setComputeCsdOnAllDevices(computeCsdOnAllDevices);
355 }
356 return binder::Status::ok();
357}
358
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000359binder::Status SoundDoseManager::SoundDose::isSoundDoseHalSupported(bool* value) {
360 ALOGV("%s", __func__);
361 *value = false;
362 auto soundDoseManager = mSoundDoseManager.promote();
363 if (soundDoseManager != nullptr) {
364 *value = soundDoseManager->isSoundDoseHalSupported();
365 }
366 return binder::Status::ok();
367}
368
Vlad Popa58e72dc2023-02-01 13:18:40 +0100369void SoundDoseManager::updateAttenuation(float attenuationDB, audio_devices_t deviceType) {
370 std::lock_guard _l(mLock);
Vlad Popaeafa0482023-02-23 14:35:56 +0100371 ALOGV("%s: updating MEL processor attenuation for device type %d to %f",
Vlad Popa58e72dc2023-02-01 13:18:40 +0100372 __func__, deviceType, attenuationDB);
373 mMelAttenuationDB[deviceType] = attenuationDB;
374 for (const auto& mp : mActiveProcessors) {
375 auto melProcessor = mp.second.promote();
376 if (melProcessor != nullptr) {
377 auto deviceId = melProcessor->getDeviceId();
Vlad Popa197faf82023-07-27 18:27:59 -0700378 const auto deviceTypeIt = mActiveDeviceTypes.find(deviceId);
379 if (deviceTypeIt != mActiveDeviceTypes.end() &&
380 deviceTypeIt->second == deviceType) {
Vlad Popaeafa0482023-02-23 14:35:56 +0100381 ALOGV("%s: set attenuation for deviceId %d to %f",
Vlad Popa58e72dc2023-02-01 13:18:40 +0100382 __func__, deviceId, attenuationDB);
383 melProcessor->setAttenuation(attenuationDB);
384 }
385 }
386 }
387}
388
Vlad Popa617bbf02023-04-24 19:10:36 +0200389void SoundDoseManager::setCsdEnabled(bool enabled) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100390 ALOGV("%s", __func__);
391
392 std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200393 mEnabledCsd = enabled;
Vlad Popa2a06fca2023-02-06 16:45:45 +0100394
Vlad Popa2a06fca2023-02-06 16:45:45 +0100395 for (auto& activeEntry : mActiveProcessors) {
396 auto melProcessor = activeEntry.second.promote();
397 if (melProcessor != nullptr) {
Vlad Popa617bbf02023-04-24 19:10:36 +0200398 if (enabled) {
399 melProcessor->resume();
400 } else {
401 melProcessor->pause();
402 }
Vlad Popa2a06fca2023-02-06 16:45:45 +0100403 }
404 }
405}
406
Vlad Popa617bbf02023-04-24 19:10:36 +0200407bool SoundDoseManager::isCsdEnabled() {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100408 std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200409 return mEnabledCsd;
Vlad Popa2a06fca2023-02-06 16:45:45 +0100410}
411
Vlad Popa197faf82023-07-27 18:27:59 -0700412void SoundDoseManager::initCachedAudioDeviceCategories(
413 const std::vector<media::ISoundDose::AudioDeviceCategory>& deviceCategories) {
414 ALOGV("%s", __func__);
415 {
416 const std::lock_guard _l(mLock);
417 mBluetoothDevicesWithCsd.clear();
418 }
419 for (const auto& btDeviceCategory : deviceCategories) {
420 setAudioDeviceCategory(btDeviceCategory);
421 }
422}
423
424void SoundDoseManager::setAudioDeviceCategory(
425 const media::ISoundDose::AudioDeviceCategory& audioDevice) {
426 ALOGV("%s: set BT audio device type with address %s to headphone %d", __func__,
427 audioDevice.address.c_str(), audioDevice.csdCompatible);
428
429 std::vector<audio_port_handle_t> devicesToStart;
430 std::vector<audio_port_handle_t> devicesToStop;
431 {
432 const std::lock_guard _l(mLock);
433 const auto deviceIt = mBluetoothDevicesWithCsd.find(
434 std::make_pair(audioDevice.address,
435 static_cast<audio_devices_t>(audioDevice.internalAudioType)));
436 if (deviceIt != mBluetoothDevicesWithCsd.end()) {
437 deviceIt->second = audioDevice.csdCompatible;
438 } else {
439 mBluetoothDevicesWithCsd.emplace(
440 std::make_pair(audioDevice.address,
441 static_cast<audio_devices_t>(audioDevice.internalAudioType)),
442 audioDevice.csdCompatible);
443 }
444
445 for (const auto &activeDevice: mActiveDevices) {
446 if (activeDevice.first.address() == audioDevice.address &&
447 activeDevice.first.mType ==
448 static_cast<audio_devices_t>(audioDevice.internalAudioType)) {
449 if (audioDevice.csdCompatible) {
450 devicesToStart.push_back(activeDevice.second);
451 } else {
452 devicesToStop.push_back(activeDevice.second);
453 }
454 }
455 }
456 }
457
458 for (const auto& deviceToStart : devicesToStart) {
459 mMelReporterCallback->startMelComputationForDeviceId(deviceToStart);
460 }
461 for (const auto& deviceToStop : devicesToStop) {
462 mMelReporterCallback->stopMelComputationForDeviceId(deviceToStop);
463 }
464}
465
466bool SoundDoseManager::shouldComputeCsdForDeviceType(audio_devices_t device) {
467 if (!isCsdEnabled()) {
468 ALOGV("%s csd is disabled", __func__);
469 return false;
470 }
471 if (forceComputeCsdOnAllDevices()) {
472 return true;
473 }
474
475 switch (device) {
476 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
477 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
478 // TODO(b/278265907): enable A2DP when we can distinguish A2DP headsets
479 // case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
480 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
481 case AUDIO_DEVICE_OUT_USB_HEADSET:
482 case AUDIO_DEVICE_OUT_BLE_HEADSET:
483 case AUDIO_DEVICE_OUT_BLE_BROADCAST:
484 return true;
485 default:
486 return false;
487 }
488}
489
490bool SoundDoseManager::shouldComputeCsdForDeviceWithAddress(const audio_devices_t type,
491 const std::string& deviceAddress) {
492 if (!isCsdEnabled()) {
493 ALOGV("%s csd is disabled", __func__);
494 return false;
495 }
496 if (forceComputeCsdOnAllDevices()) {
497 return true;
498 }
499
500 if (!audio_is_ble_out_device(type) && !audio_is_a2dp_device(type)) {
501 return shouldComputeCsdForDeviceType(type);
502 }
503
504 const std::lock_guard _l(mLock);
505 const auto deviceIt = mBluetoothDevicesWithCsd.find(std::make_pair(deviceAddress, type));
506 return deviceIt != mBluetoothDevicesWithCsd.end() && deviceIt->second;
507}
508
Vlad Popa91930462022-12-20 22:42:48 +0100509void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100510 // invalidate any HAL sound dose interface used
511 setHalSoundDoseInterface(nullptr);
512
Vlad Popa91930462022-12-20 22:42:48 +0100513 std::lock_guard _l(mLock);
514 mUseFrameworkMel = useFrameworkMel;
515}
516
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100517bool SoundDoseManager::forceUseFrameworkMel() const {
Vlad Popa91930462022-12-20 22:42:48 +0100518 std::lock_guard _l(mLock);
519 return mUseFrameworkMel;
520}
521
522void SoundDoseManager::setComputeCsdOnAllDevices(bool computeCsdOnAllDevices) {
523 std::lock_guard _l(mLock);
524 mComputeCsdOnAllDevices = computeCsdOnAllDevices;
525}
526
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100527bool SoundDoseManager::forceComputeCsdOnAllDevices() const {
Vlad Popa91930462022-12-20 22:42:48 +0100528 std::lock_guard _l(mLock);
529 return mComputeCsdOnAllDevices;
530}
531
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000532bool SoundDoseManager::isSoundDoseHalSupported() const {
Vlad Popa617bbf02023-04-24 19:10:36 +0200533 if (!mEnabledCsd) {
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000534 return false;
535 }
536
537 std::shared_ptr<ISoundDose> halSoundDose;
538 getHalSoundDose(&halSoundDose);
539 if (mHalSoundDose == nullptr) {
540 return false;
541 }
542 return true;
543}
544
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100545void SoundDoseManager::getHalSoundDose(std::shared_ptr<ISoundDose>* halSoundDose) const {
546 std::lock_guard _l(mLock);
547 *halSoundDose = mHalSoundDose;
548}
549
Vlad Popae3fd1c22022-11-07 21:03:18 +0100550void SoundDoseManager::resetSoundDose() {
551 std::lock_guard lock(mLock);
552 mSoundDose = nullptr;
553}
554
555void SoundDoseManager::resetCsd(float currentCsd,
556 const std::vector<media::SoundDoseRecord>& records) {
557 std::lock_guard lock(mLock);
558 std::vector<audio_utils::CsdRecord> resetRecords;
559 for (const auto& record : records) {
560 resetRecords.emplace_back(record.timestamp, record.duration, record.value,
561 record.averageMel);
562 }
563
564 mMelAggregator->reset(currentCsd, resetRecords);
565}
566
Vlad Popa4defd0b2022-11-06 14:22:31 +0100567void SoundDoseManager::onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
568 audio_port_handle_t deviceId) const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100569 ALOGV("%s", __func__);
Vlad Popa2900c0a2022-10-24 13:38:00 +0200570
Vlad Popa2a06fca2023-02-06 16:45:45 +0100571
Vlad Popa4defd0b2022-11-06 14:22:31 +0100572 sp<media::ISoundDoseCallback> soundDoseCallback;
573 std::vector<audio_utils::CsdRecord> records;
574 float currentCsd;
575 {
576 std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200577 if (!mEnabledCsd) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100578 return;
579 }
580
Vlad Popa2900c0a2022-10-24 13:38:00 +0200581
Vlad Popa4defd0b2022-11-06 14:22:31 +0100582 int64_t timestampSec = getMonotonicSecond();
583
584 // only for internal callbacks
585 records = mMelAggregator->aggregateAndAddNewMelRecord(audio_utils::MelRecord(
586 deviceId, std::vector<float>(mels.begin() + offset, mels.begin() + offset + length),
587 timestampSec - length));
588
589 currentCsd = mMelAggregator->getCsd();
590 }
591
592 soundDoseCallback = getSoundDoseCallback();
593
594 if (records.size() > 0 && soundDoseCallback != nullptr) {
595 std::vector<media::SoundDoseRecord> newRecordsToReport;
596 for (const auto& record : records) {
597 newRecordsToReport.emplace_back(csdRecordToSoundDoseRecord(record));
598 }
599
600 soundDoseCallback->onNewCsdValue(currentCsd, newRecordsToReport);
601 }
Vlad Popa2900c0a2022-10-24 13:38:00 +0200602}
603
Vlad Popa4defd0b2022-11-06 14:22:31 +0100604sp<media::ISoundDoseCallback> SoundDoseManager::getSoundDoseCallback() const {
605 std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100606 if (mSoundDose == nullptr) {
607 return nullptr;
608 }
609
610 return mSoundDose->mSoundDoseCallback;
Vlad Popa4defd0b2022-11-06 14:22:31 +0100611}
612
613void SoundDoseManager::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const {
614 ALOGV("%s: Momentary exposure for device %d triggered: %f MEL", __func__, deviceId, currentMel);
Vlad Popa63f047e2022-11-05 14:09:19 +0100615
Vlad Popa2a06fca2023-02-06 16:45:45 +0100616 {
617 std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200618 if (!mEnabledCsd) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100619 return;
620 }
621 }
622
Vlad Popae3fd1c22022-11-07 21:03:18 +0100623 auto soundDoseCallback = getSoundDoseCallback();
Vlad Popa63f047e2022-11-05 14:09:19 +0100624 if (soundDoseCallback != nullptr) {
Vlad Popae3fd1c22022-11-07 21:03:18 +0100625 soundDoseCallback->onMomentaryExposure(currentMel, deviceId);
Vlad Popa63f047e2022-11-05 14:09:19 +0100626 }
627}
628
Vlad Popae3fd1c22022-11-07 21:03:18 +0100629sp<media::ISoundDose> SoundDoseManager::getSoundDoseInterface(
630 const sp<media::ISoundDoseCallback>& callback) {
Vlad Popa63f047e2022-11-05 14:09:19 +0100631 ALOGV("%s: Register ISoundDoseCallback", __func__);
632
633 std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100634 if (mSoundDose == nullptr) {
635 mSoundDose = sp<SoundDose>::make(this, callback);
636 }
637 return mSoundDose;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100638}
639
Vlad Popa4defd0b2022-11-06 14:22:31 +0100640std::string SoundDoseManager::dump() const {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200641 std::string output;
Vlad Popa2a06fca2023-02-06 16:45:45 +0100642 {
643 std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200644 if (!mEnabledCsd) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100645 base::StringAppendF(&output, "CSD is disabled");
646 return output;
647 }
648 }
649
Vlad Popaf09e93f2022-10-31 16:27:12 +0100650 mMelAggregator->foreachCsd([&output](audio_utils::CsdRecord csdRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200651 base::StringAppendF(&output,
652 "CSD %f with average MEL %f in interval [%" PRId64 ", %" PRId64 "]",
Vlad Popa4defd0b2022-11-06 14:22:31 +0100653 csdRecord.value, csdRecord.averageMel, csdRecord.timestamp,
Vlad Popa2900c0a2022-10-24 13:38:00 +0200654 csdRecord.timestamp + csdRecord.duration);
655 base::StringAppendF(&output, "\n");
656 });
657
658 base::StringAppendF(&output, "\nCached Mel Records:\n");
Vlad Popaf09e93f2022-10-31 16:27:12 +0100659 mMelAggregator->foreachCachedMel([&output](const audio_utils::MelRecord& melRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200660 base::StringAppendF(&output, "Continuous MELs for portId=%d, ", melRecord.portId);
661 base::StringAppendF(&output, "starting at timestamp %" PRId64 ": ", melRecord.timestamp);
662
663 for (const auto& mel : melRecord.mels) {
664 base::StringAppendF(&output, "%.2f ", mel);
665 }
666 base::StringAppendF(&output, "\n");
667 });
668
669 return output;
670}
671
672size_t SoundDoseManager::getCachedMelRecordsSize() const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100673 return mMelAggregator->getCachedMelRecordsSize();
Vlad Popa2900c0a2022-10-24 13:38:00 +0200674}
675
Vlad Popa4defd0b2022-11-06 14:22:31 +0100676media::SoundDoseRecord SoundDoseManager::csdRecordToSoundDoseRecord(
677 const audio_utils::CsdRecord& legacy) {
678 media::SoundDoseRecord soundDoseRecord{};
679 soundDoseRecord.timestamp = legacy.timestamp;
680 soundDoseRecord.duration = legacy.duration;
681 soundDoseRecord.value = legacy.value;
682 soundDoseRecord.averageMel = legacy.averageMel;
683 return soundDoseRecord;
684}
685
Vlad Popa2900c0a2022-10-24 13:38:00 +0200686} // namespace android