blob: 97470a2094bf3ee3038a85fcb387e587bec830ae [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 Popa617bbf02023-04-24 19:10:36 +020052 if (mHalSoundDose != nullptr && 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 Popa1d5f0d52022-12-18 12:21:26 +010085bool SoundDoseManager::setHalSoundDoseInterface(const std::shared_ptr<ISoundDose>& halSoundDose) {
86 ALOGV("%s", __func__);
87
Vlad Popaffcacdc2023-06-10 00:24:35 +020088 std::shared_ptr<HalSoundDoseCallback> halSoundDoseCallback;
Vlad Popa1d5f0d52022-12-18 12:21:26 +010089 {
Vlad Popaffcacdc2023-06-10 00:24:35 +020090 const std::lock_guard _l(mLock);
Vlad Popa1d5f0d52022-12-18 12:21:26 +010091
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 }
Vlad Popaffcacdc2023-06-10 00:24:35 +0200109 halSoundDoseCallback = mHalSoundDoseCallback;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100110 }
111
Vlad Popaffcacdc2023-06-10 00:24:35 +0200112 auto status = halSoundDose->registerSoundDoseCallback(halSoundDoseCallback);
113
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100114 if (!status.isOk()) {
115 // Not a warning since this can happen if the callback was registered before
116 ALOGI("%s: Cannot register HAL sound dose callback with status message: %s",
117 __func__,
118 status.getMessage());
119 }
120
121 return true;
122}
123
Vlad Popa4847de12023-03-16 18:30:08 +0100124void SoundDoseManager::setOutputRs2UpperBound(float rs2Value) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200125 ALOGV("%s", __func__);
Vlad Popaffcacdc2023-06-10 00:24:35 +0200126 const std::lock_guard _l(mLock);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100127
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100128 if (mHalSoundDose != nullptr) {
129 // using the HAL sound dose interface
Vlad Popa4847de12023-03-16 18:30:08 +0100130 if (!mHalSoundDose->setOutputRs2UpperBound(rs2Value).isOk()) {
Vlad Popa3c3995d2023-01-13 11:10:05 +0100131 ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
132 return;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100133 }
Vlad Popa4847de12023-03-16 18:30:08 +0100134 mRs2UpperBound = rs2Value;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100135 return;
136 }
Vlad Popae3fd1c22022-11-07 21:03:18 +0100137
Vlad Popaf09e93f2022-10-31 16:27:12 +0100138 for (auto& streamProcessor : mActiveProcessors) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200139 const sp<audio_utils::MelProcessor> processor = streamProcessor.second.promote();
Vlad Popaf09e93f2022-10-31 16:27:12 +0100140 if (processor != nullptr) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200141 const status_t result = processor->setOutputRs2UpperBound(rs2Value);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100142 if (result != NO_ERROR) {
Vlad Popa4847de12023-03-16 18:30:08 +0100143 ALOGW("%s: could not set RS2 upper bound %f for stream %d", __func__, rs2Value,
Vlad Popaf09e93f2022-10-31 16:27:12 +0100144 streamProcessor.first);
Vlad Popa3c3995d2023-01-13 11:10:05 +0100145 return;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100146 }
Vlad Popa4847de12023-03-16 18:30:08 +0100147 mRs2UpperBound = rs2Value;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100148 }
149 }
150}
151
Vlad Popa4defd0b2022-11-06 14:22:31 +0100152void SoundDoseManager::removeStreamProcessor(audio_io_handle_t streamHandle) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200153 const std::lock_guard _l(mLock);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100154 auto callbackToRemove = mActiveProcessors.find(streamHandle);
Vlad Popa4defd0b2022-11-06 14:22:31 +0100155 if (callbackToRemove != mActiveProcessors.end()) {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100156 mActiveProcessors.erase(callbackToRemove);
157 }
158}
159
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100160audio_port_handle_t SoundDoseManager::getIdForAudioDevice(const AudioDevice& audioDevice) const {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200161 const std::lock_guard _l(mLock);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100162
163 audio_devices_t type;
164 std::string address;
165 auto result = aidl::android::aidl2legacy_AudioDevice_audio_device(
166 audioDevice, &type, &address);
167 if (result != NO_ERROR) {
168 ALOGE("%s: could not convert from AudioDevice to AudioDeviceTypeAddr", __func__);
169 return AUDIO_PORT_HANDLE_NONE;
170 }
171
172 auto adt = AudioDeviceTypeAddr(type, address);
173 auto deviceIt = mActiveDevices.find(adt);
174 if (deviceIt == mActiveDevices.end()) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100175 ALOGI("%s: could not find port id for device %s", __func__, adt.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100176 return AUDIO_PORT_HANDLE_NONE;
177 }
178 return deviceIt->second;
179}
180
181void SoundDoseManager::mapAddressToDeviceId(const AudioDeviceTypeAddr& adt,
182 const audio_port_handle_t deviceId) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200183 const std::lock_guard _l(mLock);
Vlad Popaeafa0482023-02-23 14:35:56 +0100184 ALOGI("%s: map address: %d to device id: %d", __func__, adt.mType, deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100185 mActiveDevices[adt] = deviceId;
Vlad Popa58e72dc2023-02-01 13:18:40 +0100186 mActiveDeviceTypes[deviceId] = adt.mType;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100187}
188
189void SoundDoseManager::clearMapDeviceIdEntries(audio_port_handle_t deviceId) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200190 const std::lock_guard _l(mLock);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100191 for (auto activeDevice = mActiveDevices.begin(); activeDevice != mActiveDevices.end();) {
192 if (activeDevice->second == deviceId) {
Vlad Popaeafa0482023-02-23 14:35:56 +0100193 ALOGI("%s: clear mapping type: %d to deviceId: %d",
194 __func__, activeDevice->first.mType, deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100195 activeDevice = mActiveDevices.erase(activeDevice);
196 continue;
197 }
198 ++activeDevice;
199 }
Vlad Popa58e72dc2023-02-01 13:18:40 +0100200 mActiveDeviceTypes.erase(deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100201}
202
203ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
204 float in_currentDbA, const AudioDevice& in_audioDevice) {
205 auto soundDoseManager = mSoundDoseManager.promote();
206 if (soundDoseManager == nullptr) {
207 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
208 }
209
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100210 std::shared_ptr<ISoundDose> halSoundDose;
211 soundDoseManager->getHalSoundDose(&halSoundDose);
212 if(halSoundDose == nullptr) {
213 ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
214 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
215 }
216
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100217 auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
218 if (id == AUDIO_PORT_HANDLE_NONE) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100219 ALOGI("%s: no mapped id for audio device with type %d and address %s",
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100220 __func__, in_audioDevice.type.type,
Vlad Popa69fbbee2023-04-25 12:23:24 +0200221 in_audioDevice.address.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100222 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
223 }
224 soundDoseManager->onMomentaryExposure(in_currentDbA, id);
225
226 return ndk::ScopedAStatus::ok();
227}
228
229ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onNewMelValues(
230 const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
231 const AudioDevice& in_audioDevice) {
232 auto soundDoseManager = mSoundDoseManager.promote();
233 if (soundDoseManager == nullptr) {
234 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
235 }
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100236
237 std::shared_ptr<ISoundDose> halSoundDose;
238 soundDoseManager->getHalSoundDose(&halSoundDose);
239 if(halSoundDose == nullptr) {
240 ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
241 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
242 }
243
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100244 auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
245 if (id == AUDIO_PORT_HANDLE_NONE) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100246 ALOGI("%s: no mapped id for audio device with type %d and address %s",
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100247 __func__, in_audioDevice.type.type,
Vlad Popa69fbbee2023-04-25 12:23:24 +0200248 in_audioDevice.address.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100249 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
250 }
251 // TODO: introduce timestamp in onNewMelValues callback
252 soundDoseManager->onNewMelValues(in_melRecord.melValues, 0,
253 in_melRecord.melValues.size(), id);
254
255 return ndk::ScopedAStatus::ok();
256}
257
Vlad Popae3fd1c22022-11-07 21:03:18 +0100258void SoundDoseManager::SoundDose::binderDied(__unused const wp<IBinder>& who) {
259 ALOGV("%s", __func__);
260
261 auto soundDoseManager = mSoundDoseManager.promote();
262 if (soundDoseManager != nullptr) {
263 soundDoseManager->resetSoundDose();
264 }
265}
266
Vlad Popa4847de12023-03-16 18:30:08 +0100267binder::Status SoundDoseManager::SoundDose::setOutputRs2UpperBound(float value) {
Vlad Popae3fd1c22022-11-07 21:03:18 +0100268 ALOGV("%s", __func__);
269 auto soundDoseManager = mSoundDoseManager.promote();
270 if (soundDoseManager != nullptr) {
Vlad Popa4847de12023-03-16 18:30:08 +0100271 soundDoseManager->setOutputRs2UpperBound(value);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100272 }
273 return binder::Status::ok();
274}
275
276binder::Status SoundDoseManager::SoundDose::resetCsd(
277 float currentCsd, const std::vector<media::SoundDoseRecord>& records) {
278 ALOGV("%s", __func__);
279 auto soundDoseManager = mSoundDoseManager.promote();
280 if (soundDoseManager != nullptr) {
281 soundDoseManager->resetCsd(currentCsd, records);
282 }
283 return binder::Status::ok();
284}
285
Vlad Popa58e72dc2023-02-01 13:18:40 +0100286binder::Status SoundDoseManager::SoundDose::updateAttenuation(float attenuationDB, int device) {
287 ALOGV("%s", __func__);
288 auto soundDoseManager = mSoundDoseManager.promote();
289 if (soundDoseManager != nullptr) {
290 soundDoseManager->updateAttenuation(attenuationDB, static_cast<audio_devices_t>(device));
291 }
292 return binder::Status::ok();
293}
294
Vlad Popa617bbf02023-04-24 19:10:36 +0200295binder::Status SoundDoseManager::SoundDose::setCsdEnabled(bool enabled) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100296 ALOGV("%s", __func__);
297 auto soundDoseManager = mSoundDoseManager.promote();
298 if (soundDoseManager != nullptr) {
Vlad Popa617bbf02023-04-24 19:10:36 +0200299 soundDoseManager->setCsdEnabled(enabled);
Vlad Popa2a06fca2023-02-06 16:45:45 +0100300 }
301 return binder::Status::ok();
302}
303
Vlad Popa197faf82023-07-27 18:27:59 -0700304binder::Status SoundDoseManager::SoundDose::initCachedAudioDeviceCategories(
305 const std::vector<media::ISoundDose::AudioDeviceCategory>& btDeviceCategories) {
306 ALOGV("%s", __func__);
307 auto soundDoseManager = mSoundDoseManager.promote();
308 if (soundDoseManager != nullptr) {
309 soundDoseManager->initCachedAudioDeviceCategories(btDeviceCategories);
310 }
311 return binder::Status::ok();
312}
313binder::Status SoundDoseManager::SoundDose::setAudioDeviceCategory(
314 const media::ISoundDose::AudioDeviceCategory& btAudioDevice) {
315 ALOGV("%s", __func__);
316 auto soundDoseManager = mSoundDoseManager.promote();
317 if (soundDoseManager != nullptr) {
318 soundDoseManager->setAudioDeviceCategory(btAudioDevice);
319 }
320 return binder::Status::ok();
321}
322
Vlad Popa4847de12023-03-16 18:30:08 +0100323binder::Status SoundDoseManager::SoundDose::getOutputRs2UpperBound(float* value) {
Vlad Popa91930462022-12-20 22:42:48 +0100324 ALOGV("%s", __func__);
325 auto soundDoseManager = mSoundDoseManager.promote();
326 if (soundDoseManager != nullptr) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200327 const std::lock_guard _l(soundDoseManager->mLock);
Vlad Popa4847de12023-03-16 18:30:08 +0100328 *value = soundDoseManager->mRs2UpperBound;
Vlad Popa91930462022-12-20 22:42:48 +0100329 }
330 return binder::Status::ok();
331}
332
333binder::Status SoundDoseManager::SoundDose::getCsd(float* value) {
334 ALOGV("%s", __func__);
335 auto soundDoseManager = mSoundDoseManager.promote();
336 if (soundDoseManager != nullptr) {
337 *value = soundDoseManager->mMelAggregator->getCsd();
338 }
339 return binder::Status::ok();
340}
341
342binder::Status SoundDoseManager::SoundDose::forceUseFrameworkMel(bool useFrameworkMel) {
343 ALOGV("%s", __func__);
344 auto soundDoseManager = mSoundDoseManager.promote();
345 if (soundDoseManager != nullptr) {
346 soundDoseManager->setUseFrameworkMel(useFrameworkMel);
347 }
348 return binder::Status::ok();
349}
350
351binder::Status SoundDoseManager::SoundDose::forceComputeCsdOnAllDevices(
352 bool computeCsdOnAllDevices) {
353 ALOGV("%s", __func__);
354 auto soundDoseManager = mSoundDoseManager.promote();
355 if (soundDoseManager != nullptr) {
356 soundDoseManager->setComputeCsdOnAllDevices(computeCsdOnAllDevices);
357 }
358 return binder::Status::ok();
359}
360
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000361binder::Status SoundDoseManager::SoundDose::isSoundDoseHalSupported(bool* value) {
362 ALOGV("%s", __func__);
363 *value = false;
364 auto soundDoseManager = mSoundDoseManager.promote();
365 if (soundDoseManager != nullptr) {
366 *value = soundDoseManager->isSoundDoseHalSupported();
367 }
368 return binder::Status::ok();
369}
370
Vlad Popa58e72dc2023-02-01 13:18:40 +0100371void SoundDoseManager::updateAttenuation(float attenuationDB, audio_devices_t deviceType) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200372 const std::lock_guard _l(mLock);
Vlad Popaeafa0482023-02-23 14:35:56 +0100373 ALOGV("%s: updating MEL processor attenuation for device type %d to %f",
Vlad Popa58e72dc2023-02-01 13:18:40 +0100374 __func__, deviceType, attenuationDB);
375 mMelAttenuationDB[deviceType] = attenuationDB;
376 for (const auto& mp : mActiveProcessors) {
377 auto melProcessor = mp.second.promote();
378 if (melProcessor != nullptr) {
379 auto deviceId = melProcessor->getDeviceId();
Vlad Popa197faf82023-07-27 18:27:59 -0700380 const auto deviceTypeIt = mActiveDeviceTypes.find(deviceId);
381 if (deviceTypeIt != mActiveDeviceTypes.end() &&
382 deviceTypeIt->second == deviceType) {
Vlad Popaeafa0482023-02-23 14:35:56 +0100383 ALOGV("%s: set attenuation for deviceId %d to %f",
Vlad Popa58e72dc2023-02-01 13:18:40 +0100384 __func__, deviceId, attenuationDB);
385 melProcessor->setAttenuation(attenuationDB);
386 }
387 }
388 }
389}
390
Vlad Popa617bbf02023-04-24 19:10:36 +0200391void SoundDoseManager::setCsdEnabled(bool enabled) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100392 ALOGV("%s", __func__);
393
Vlad Popaffcacdc2023-06-10 00:24:35 +0200394 const std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200395 mEnabledCsd = enabled;
Vlad Popa2a06fca2023-02-06 16:45:45 +0100396
Vlad Popa2a06fca2023-02-06 16:45:45 +0100397 for (auto& activeEntry : mActiveProcessors) {
398 auto melProcessor = activeEntry.second.promote();
399 if (melProcessor != nullptr) {
Vlad Popa617bbf02023-04-24 19:10:36 +0200400 if (enabled) {
401 melProcessor->resume();
402 } else {
403 melProcessor->pause();
404 }
Vlad Popa2a06fca2023-02-06 16:45:45 +0100405 }
406 }
407}
408
Vlad Popa617bbf02023-04-24 19:10:36 +0200409bool SoundDoseManager::isCsdEnabled() {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200410 const std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200411 return mEnabledCsd;
Vlad Popa2a06fca2023-02-06 16:45:45 +0100412}
413
Vlad Popa197faf82023-07-27 18:27:59 -0700414void SoundDoseManager::initCachedAudioDeviceCategories(
415 const std::vector<media::ISoundDose::AudioDeviceCategory>& deviceCategories) {
416 ALOGV("%s", __func__);
417 {
418 const std::lock_guard _l(mLock);
419 mBluetoothDevicesWithCsd.clear();
420 }
421 for (const auto& btDeviceCategory : deviceCategories) {
422 setAudioDeviceCategory(btDeviceCategory);
423 }
424}
425
426void SoundDoseManager::setAudioDeviceCategory(
427 const media::ISoundDose::AudioDeviceCategory& audioDevice) {
428 ALOGV("%s: set BT audio device type with address %s to headphone %d", __func__,
429 audioDevice.address.c_str(), audioDevice.csdCompatible);
430
431 std::vector<audio_port_handle_t> devicesToStart;
432 std::vector<audio_port_handle_t> devicesToStop;
433 {
434 const std::lock_guard _l(mLock);
435 const auto deviceIt = mBluetoothDevicesWithCsd.find(
436 std::make_pair(audioDevice.address,
437 static_cast<audio_devices_t>(audioDevice.internalAudioType)));
438 if (deviceIt != mBluetoothDevicesWithCsd.end()) {
439 deviceIt->second = audioDevice.csdCompatible;
440 } else {
441 mBluetoothDevicesWithCsd.emplace(
442 std::make_pair(audioDevice.address,
443 static_cast<audio_devices_t>(audioDevice.internalAudioType)),
444 audioDevice.csdCompatible);
445 }
446
447 for (const auto &activeDevice: mActiveDevices) {
448 if (activeDevice.first.address() == audioDevice.address &&
449 activeDevice.first.mType ==
450 static_cast<audio_devices_t>(audioDevice.internalAudioType)) {
451 if (audioDevice.csdCompatible) {
452 devicesToStart.push_back(activeDevice.second);
453 } else {
454 devicesToStop.push_back(activeDevice.second);
455 }
456 }
457 }
458 }
459
460 for (const auto& deviceToStart : devicesToStart) {
461 mMelReporterCallback->startMelComputationForDeviceId(deviceToStart);
462 }
463 for (const auto& deviceToStop : devicesToStop) {
464 mMelReporterCallback->stopMelComputationForDeviceId(deviceToStop);
465 }
466}
467
468bool SoundDoseManager::shouldComputeCsdForDeviceType(audio_devices_t device) {
469 if (!isCsdEnabled()) {
470 ALOGV("%s csd is disabled", __func__);
471 return false;
472 }
473 if (forceComputeCsdOnAllDevices()) {
474 return true;
475 }
476
477 switch (device) {
478 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
479 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
480 // TODO(b/278265907): enable A2DP when we can distinguish A2DP headsets
481 // case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
482 case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
483 case AUDIO_DEVICE_OUT_USB_HEADSET:
484 case AUDIO_DEVICE_OUT_BLE_HEADSET:
485 case AUDIO_DEVICE_OUT_BLE_BROADCAST:
486 return true;
487 default:
488 return false;
489 }
490}
491
492bool SoundDoseManager::shouldComputeCsdForDeviceWithAddress(const audio_devices_t type,
493 const std::string& deviceAddress) {
494 if (!isCsdEnabled()) {
495 ALOGV("%s csd is disabled", __func__);
496 return false;
497 }
498 if (forceComputeCsdOnAllDevices()) {
499 return true;
500 }
501
502 if (!audio_is_ble_out_device(type) && !audio_is_a2dp_device(type)) {
503 return shouldComputeCsdForDeviceType(type);
504 }
505
506 const std::lock_guard _l(mLock);
507 const auto deviceIt = mBluetoothDevicesWithCsd.find(std::make_pair(deviceAddress, type));
508 return deviceIt != mBluetoothDevicesWithCsd.end() && deviceIt->second;
509}
510
Vlad Popa91930462022-12-20 22:42:48 +0100511void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100512 // invalidate any HAL sound dose interface used
513 setHalSoundDoseInterface(nullptr);
514
Vlad Popaffcacdc2023-06-10 00:24:35 +0200515 const std::lock_guard _l(mLock);
Vlad Popa91930462022-12-20 22:42:48 +0100516 mUseFrameworkMel = useFrameworkMel;
517}
518
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100519bool SoundDoseManager::forceUseFrameworkMel() const {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200520 const std::lock_guard _l(mLock);
Vlad Popa91930462022-12-20 22:42:48 +0100521 return mUseFrameworkMel;
522}
523
524void SoundDoseManager::setComputeCsdOnAllDevices(bool computeCsdOnAllDevices) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200525 const std::lock_guard _l(mLock);
Vlad Popa91930462022-12-20 22:42:48 +0100526 mComputeCsdOnAllDevices = computeCsdOnAllDevices;
527}
528
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100529bool SoundDoseManager::forceComputeCsdOnAllDevices() const {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200530 const std::lock_guard _l(mLock);
Vlad Popa91930462022-12-20 22:42:48 +0100531 return mComputeCsdOnAllDevices;
532}
533
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000534bool SoundDoseManager::isSoundDoseHalSupported() const {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200535 {
536 const std::lock_guard _l(mLock);
537 if (!mEnabledCsd) return false;
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000538 }
539
540 std::shared_ptr<ISoundDose> halSoundDose;
541 getHalSoundDose(&halSoundDose);
Vlad Popaffcacdc2023-06-10 00:24:35 +0200542 return halSoundDose != nullptr;
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000543}
544
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100545void SoundDoseManager::getHalSoundDose(std::shared_ptr<ISoundDose>* halSoundDose) const {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200546 const std::lock_guard _l(mLock);
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100547 *halSoundDose = mHalSoundDose;
548}
549
Vlad Popae3fd1c22022-11-07 21:03:18 +0100550void SoundDoseManager::resetSoundDose() {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200551 const std::lock_guard lock(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100552 mSoundDose = nullptr;
553}
554
555void SoundDoseManager::resetCsd(float currentCsd,
556 const std::vector<media::SoundDoseRecord>& records) {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200557 const std::lock_guard lock(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100558 std::vector<audio_utils::CsdRecord> resetRecords;
Vlad Popaffcacdc2023-06-10 00:24:35 +0200559 resetRecords.reserve(records.size());
Vlad Popae3fd1c22022-11-07 21:03:18 +0100560 for (const auto& record : records) {
561 resetRecords.emplace_back(record.timestamp, record.duration, record.value,
562 record.averageMel);
563 }
564
565 mMelAggregator->reset(currentCsd, resetRecords);
566}
567
Vlad Popa4defd0b2022-11-06 14:22:31 +0100568void SoundDoseManager::onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
569 audio_port_handle_t deviceId) const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100570 ALOGV("%s", __func__);
Vlad Popa2900c0a2022-10-24 13:38:00 +0200571
Vlad Popa2a06fca2023-02-06 16:45:45 +0100572
Vlad Popa4defd0b2022-11-06 14:22:31 +0100573 sp<media::ISoundDoseCallback> soundDoseCallback;
574 std::vector<audio_utils::CsdRecord> records;
575 float currentCsd;
576 {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200577 const std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200578 if (!mEnabledCsd) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100579 return;
580 }
581
Vlad Popa2900c0a2022-10-24 13:38:00 +0200582
Vlad Popaffcacdc2023-06-10 00:24:35 +0200583 const int64_t timestampSec = getMonotonicSecond();
Vlad Popa4defd0b2022-11-06 14:22:31 +0100584
585 // only for internal callbacks
586 records = mMelAggregator->aggregateAndAddNewMelRecord(audio_utils::MelRecord(
587 deviceId, std::vector<float>(mels.begin() + offset, mels.begin() + offset + length),
588 timestampSec - length));
589
590 currentCsd = mMelAggregator->getCsd();
591 }
592
593 soundDoseCallback = getSoundDoseCallback();
594
595 if (records.size() > 0 && soundDoseCallback != nullptr) {
596 std::vector<media::SoundDoseRecord> newRecordsToReport;
Vlad Popaffcacdc2023-06-10 00:24:35 +0200597 newRecordsToReport.resize(records.size());
Vlad Popa4defd0b2022-11-06 14:22:31 +0100598 for (const auto& record : records) {
599 newRecordsToReport.emplace_back(csdRecordToSoundDoseRecord(record));
600 }
601
602 soundDoseCallback->onNewCsdValue(currentCsd, newRecordsToReport);
603 }
Vlad Popa2900c0a2022-10-24 13:38:00 +0200604}
605
Vlad Popa4defd0b2022-11-06 14:22:31 +0100606sp<media::ISoundDoseCallback> SoundDoseManager::getSoundDoseCallback() const {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200607 const std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100608 if (mSoundDose == nullptr) {
609 return nullptr;
610 }
611
612 return mSoundDose->mSoundDoseCallback;
Vlad Popa4defd0b2022-11-06 14:22:31 +0100613}
614
615void SoundDoseManager::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const {
616 ALOGV("%s: Momentary exposure for device %d triggered: %f MEL", __func__, deviceId, currentMel);
Vlad Popa63f047e2022-11-05 14:09:19 +0100617
Vlad Popa2a06fca2023-02-06 16:45:45 +0100618 {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200619 const std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200620 if (!mEnabledCsd) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100621 return;
622 }
623 }
624
Vlad Popae3fd1c22022-11-07 21:03:18 +0100625 auto soundDoseCallback = getSoundDoseCallback();
Vlad Popa63f047e2022-11-05 14:09:19 +0100626 if (soundDoseCallback != nullptr) {
Vlad Popae3fd1c22022-11-07 21:03:18 +0100627 soundDoseCallback->onMomentaryExposure(currentMel, deviceId);
Vlad Popa63f047e2022-11-05 14:09:19 +0100628 }
629}
630
Vlad Popae3fd1c22022-11-07 21:03:18 +0100631sp<media::ISoundDose> SoundDoseManager::getSoundDoseInterface(
632 const sp<media::ISoundDoseCallback>& callback) {
Vlad Popa63f047e2022-11-05 14:09:19 +0100633 ALOGV("%s: Register ISoundDoseCallback", __func__);
634
Vlad Popaffcacdc2023-06-10 00:24:35 +0200635 const std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100636 if (mSoundDose == nullptr) {
637 mSoundDose = sp<SoundDose>::make(this, callback);
638 }
639 return mSoundDose;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100640}
641
Vlad Popa4defd0b2022-11-06 14:22:31 +0100642std::string SoundDoseManager::dump() const {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200643 std::string output;
Vlad Popa2a06fca2023-02-06 16:45:45 +0100644 {
Vlad Popaffcacdc2023-06-10 00:24:35 +0200645 const std::lock_guard _l(mLock);
Vlad Popa617bbf02023-04-24 19:10:36 +0200646 if (!mEnabledCsd) {
Vlad Popa2a06fca2023-02-06 16:45:45 +0100647 base::StringAppendF(&output, "CSD is disabled");
648 return output;
649 }
650 }
651
Vlad Popaf09e93f2022-10-31 16:27:12 +0100652 mMelAggregator->foreachCsd([&output](audio_utils::CsdRecord csdRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200653 base::StringAppendF(&output,
654 "CSD %f with average MEL %f in interval [%" PRId64 ", %" PRId64 "]",
Vlad Popa4defd0b2022-11-06 14:22:31 +0100655 csdRecord.value, csdRecord.averageMel, csdRecord.timestamp,
Vlad Popa2900c0a2022-10-24 13:38:00 +0200656 csdRecord.timestamp + csdRecord.duration);
657 base::StringAppendF(&output, "\n");
658 });
659
660 base::StringAppendF(&output, "\nCached Mel Records:\n");
Vlad Popaf09e93f2022-10-31 16:27:12 +0100661 mMelAggregator->foreachCachedMel([&output](const audio_utils::MelRecord& melRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200662 base::StringAppendF(&output, "Continuous MELs for portId=%d, ", melRecord.portId);
663 base::StringAppendF(&output, "starting at timestamp %" PRId64 ": ", melRecord.timestamp);
664
665 for (const auto& mel : melRecord.mels) {
666 base::StringAppendF(&output, "%.2f ", mel);
667 }
668 base::StringAppendF(&output, "\n");
669 });
670
671 return output;
672}
673
674size_t SoundDoseManager::getCachedMelRecordsSize() const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100675 return mMelAggregator->getCachedMelRecordsSize();
Vlad Popa2900c0a2022-10-24 13:38:00 +0200676}
677
Vlad Popa4defd0b2022-11-06 14:22:31 +0100678media::SoundDoseRecord SoundDoseManager::csdRecordToSoundDoseRecord(
679 const audio_utils::CsdRecord& legacy) {
680 media::SoundDoseRecord soundDoseRecord{};
681 soundDoseRecord.timestamp = legacy.timestamp;
682 soundDoseRecord.duration = legacy.duration;
683 soundDoseRecord.value = legacy.value;
684 soundDoseRecord.averageMel = legacy.averageMel;
685 return soundDoseRecord;
686}
687
Vlad Popa2900c0a2022-10-24 13:38:00 +0200688} // namespace android