blob: 3dbe8d960d4c7542cfff39f073199cb0224374b1 [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#if !defined(BACKEND_NDK)
24#define BACKEND_NDK
25#endif
26
27#include "android/media/SoundDoseRecord.h"
Vlad Popa2900c0a2022-10-24 13:38:00 +020028#include <android-base/stringprintf.h>
Vlad Popa1d5f0d52022-12-18 12:21:26 +010029#include <media/AidlConversionCppNdk.h>
30#include <cinttypes>
Vlad Popa2900c0a2022-10-24 13:38:00 +020031#include <time.h>
Vlad Popa4defd0b2022-11-06 14:22:31 +010032#include <utils/Log.h>
Vlad Popa2900c0a2022-10-24 13:38:00 +020033
34namespace android {
35
Vlad Popa1d5f0d52022-12-18 12:21:26 +010036using aidl::android::media::audio::common::AudioDevice;
37using aidl::android::media::audio::common::AudioDeviceAddress;
38
Vlad Popa2900c0a2022-10-24 13:38:00 +020039namespace {
40
41int64_t getMonotonicSecond() {
42 struct timespec now_ts;
43 if (clock_gettime(CLOCK_MONOTONIC, &now_ts) != 0) {
44 ALOGE("%s: cannot get timestamp", __func__);
45 return -1;
46 }
47 return now_ts.tv_sec;
48}
49
50} // namespace
51
Vlad Popaf09e93f2022-10-31 16:27:12 +010052sp<audio_utils::MelProcessor> SoundDoseManager::getOrCreateProcessorForDevice(
Vlad Popa4defd0b2022-11-06 14:22:31 +010053 audio_port_handle_t deviceId, audio_io_handle_t streamHandle, uint32_t sampleRate,
54 size_t channelCount, audio_format_t format) {
Vlad Popa2900c0a2022-10-24 13:38:00 +020055 std::lock_guard _l(mLock);
56
Vlad Popa1d5f0d52022-12-18 12:21:26 +010057 if (mHalSoundDose != nullptr) {
58 ALOGW("%s: using HAL MEL computation, no MelProcessor needed.", __func__);
59 return nullptr;
60 }
61
Vlad Popaf09e93f2022-10-31 16:27:12 +010062 auto streamProcessor = mActiveProcessors.find(streamHandle);
63 sp<audio_utils::MelProcessor> processor;
Vlad Popa4defd0b2022-11-06 14:22:31 +010064 if (streamProcessor != mActiveProcessors.end() &&
65 (processor = streamProcessor->second.promote())) {
Vlad Popa2900c0a2022-10-24 13:38:00 +020066 ALOGV("%s: found callback for stream %d", __func__, streamHandle);
Vlad Popa58e72dc2023-02-01 13:18:40 +010067 const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
68 if (activeTypeIt != mActiveDeviceTypes.end()) {
69 processor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
70 }
Vlad Popaf09e93f2022-10-31 16:27:12 +010071 processor->setDeviceId(deviceId);
Vlad Popae3fd1c22022-11-07 21:03:18 +010072 processor->setOutputRs2(mRs2Value);
Vlad Popaf09e93f2022-10-31 16:27:12 +010073 return processor;
Vlad Popa2900c0a2022-10-24 13:38:00 +020074 } else {
75 ALOGV("%s: creating new callback for device %d", __func__, streamHandle);
Vlad Popa4defd0b2022-11-06 14:22:31 +010076 sp<audio_utils::MelProcessor> melProcessor = sp<audio_utils::MelProcessor>::make(
77 sampleRate, channelCount, format, *this, deviceId, mRs2Value);
Vlad Popa58e72dc2023-02-01 13:18:40 +010078 const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
79 if (activeTypeIt != mActiveDeviceTypes.end()) {
80 melProcessor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
81 }
Vlad Popaf09e93f2022-10-31 16:27:12 +010082 mActiveProcessors[streamHandle] = melProcessor;
83 return melProcessor;
Vlad Popa2900c0a2022-10-24 13:38:00 +020084 }
85}
86
Vlad Popa1d5f0d52022-12-18 12:21:26 +010087bool SoundDoseManager::setHalSoundDoseInterface(const std::shared_ptr<ISoundDose>& halSoundDose) {
88 ALOGV("%s", __func__);
89
90 {
91 std::lock_guard _l(mLock);
92
93 mHalSoundDose = halSoundDose;
94 if (halSoundDose == nullptr) {
95 ALOGI("%s: passed ISoundDose object is null, switching to internal CSD", __func__);
96 return false;
97 }
98
99 if (!mHalSoundDose->setOutputRs2(mRs2Value).isOk()) {
100 ALOGW("%s: Cannot set RS2 value for momentary exposure %f",
101 __func__,
102 mRs2Value);
103 }
104
105 // initialize the HAL sound dose callback lazily
106 if (mHalSoundDoseCallback == nullptr) {
107 mHalSoundDoseCallback =
108 ndk::SharedRefBase::make<HalSoundDoseCallback>(this);
109 }
110 }
111
112 auto status = halSoundDose->registerSoundDoseCallback(mHalSoundDoseCallback);
113 if (!status.isOk()) {
114 // Not a warning since this can happen if the callback was registered before
115 ALOGI("%s: Cannot register HAL sound dose callback with status message: %s",
116 __func__,
117 status.getMessage());
118 }
119
120 return true;
121}
122
Vlad Popa4defd0b2022-11-06 14:22:31 +0100123void SoundDoseManager::setOutputRs2(float rs2Value) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200124 ALOGV("%s", __func__);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100125 std::lock_guard _l(mLock);
126
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100127 if (mHalSoundDose != nullptr) {
128 // using the HAL sound dose interface
Vlad Popa3c3995d2023-01-13 11:10:05 +0100129 if (!mHalSoundDose->setOutputRs2(rs2Value).isOk()) {
130 ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
131 return;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100132 }
Vlad Popa3c3995d2023-01-13 11:10:05 +0100133 mRs2Value = rs2Value;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100134 return;
135 }
Vlad Popae3fd1c22022-11-07 21:03:18 +0100136
Vlad Popaf09e93f2022-10-31 16:27:12 +0100137 for (auto& streamProcessor : mActiveProcessors) {
138 sp<audio_utils::MelProcessor> processor = streamProcessor.second.promote();
139 if (processor != nullptr) {
Vlad Popa3c3995d2023-01-13 11:10:05 +0100140 status_t result = processor->setOutputRs2(rs2Value);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100141 if (result != NO_ERROR) {
Vlad Popa3c3995d2023-01-13 11:10:05 +0100142 ALOGW("%s: could not set RS2 value %f for stream %d", __func__, rs2Value,
Vlad Popaf09e93f2022-10-31 16:27:12 +0100143 streamProcessor.first);
Vlad Popa3c3995d2023-01-13 11:10:05 +0100144 return;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100145 }
Vlad Popa3c3995d2023-01-13 11:10:05 +0100146 mRs2Value = rs2Value;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100147 }
148 }
149}
150
Vlad Popa4defd0b2022-11-06 14:22:31 +0100151void SoundDoseManager::removeStreamProcessor(audio_io_handle_t streamHandle) {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100152 std::lock_guard _l(mLock);
153 auto callbackToRemove = mActiveProcessors.find(streamHandle);
Vlad Popa4defd0b2022-11-06 14:22:31 +0100154 if (callbackToRemove != mActiveProcessors.end()) {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100155 mActiveProcessors.erase(callbackToRemove);
156 }
157}
158
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100159audio_port_handle_t SoundDoseManager::getIdForAudioDevice(const AudioDevice& audioDevice) const {
160 std::lock_guard _l(mLock);
161
162 audio_devices_t type;
163 std::string address;
164 auto result = aidl::android::aidl2legacy_AudioDevice_audio_device(
165 audioDevice, &type, &address);
166 if (result != NO_ERROR) {
167 ALOGE("%s: could not convert from AudioDevice to AudioDeviceTypeAddr", __func__);
168 return AUDIO_PORT_HANDLE_NONE;
169 }
170
171 auto adt = AudioDeviceTypeAddr(type, address);
172 auto deviceIt = mActiveDevices.find(adt);
173 if (deviceIt == mActiveDevices.end()) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100174 ALOGI("%s: could not find port id for device %s", __func__, adt.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100175 return AUDIO_PORT_HANDLE_NONE;
176 }
177 return deviceIt->second;
178}
179
180void SoundDoseManager::mapAddressToDeviceId(const AudioDeviceTypeAddr& adt,
181 const audio_port_handle_t deviceId) {
182 std::lock_guard _l(mLock);
183 ALOGI("%s: map address: %s to device id: %d", __func__, adt.toString().c_str(), deviceId);
184 mActiveDevices[adt] = deviceId;
Vlad Popa58e72dc2023-02-01 13:18:40 +0100185 mActiveDeviceTypes[deviceId] = adt.mType;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100186}
187
188void SoundDoseManager::clearMapDeviceIdEntries(audio_port_handle_t deviceId) {
189 std::lock_guard _l(mLock);
190 for (auto activeDevice = mActiveDevices.begin(); activeDevice != mActiveDevices.end();) {
191 if (activeDevice->second == deviceId) {
192 ALOGI("%s: clear mapping addr: %s to deviceId: %d",
193 __func__, activeDevice->first.toString().c_str(), deviceId);
194 activeDevice = mActiveDevices.erase(activeDevice);
195 continue;
196 }
197 ++activeDevice;
198 }
Vlad Popa58e72dc2023-02-01 13:18:40 +0100199 mActiveDeviceTypes.erase(deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100200}
201
202ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
203 float in_currentDbA, const AudioDevice& in_audioDevice) {
204 auto soundDoseManager = mSoundDoseManager.promote();
205 if (soundDoseManager == nullptr) {
206 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
207 }
208
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100209 std::shared_ptr<ISoundDose> halSoundDose;
210 soundDoseManager->getHalSoundDose(&halSoundDose);
211 if(halSoundDose == nullptr) {
212 ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
213 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
214 }
215
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100216 auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
217 if (id == AUDIO_PORT_HANDLE_NONE) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100218 ALOGI("%s: no mapped id for audio device with type %d and address %s",
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100219 __func__, in_audioDevice.type.type,
220 in_audioDevice.address.get<AudioDeviceAddress::id>().c_str());
221 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
222 }
223 soundDoseManager->onMomentaryExposure(in_currentDbA, id);
224
225 return ndk::ScopedAStatus::ok();
226}
227
228ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onNewMelValues(
229 const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
230 const AudioDevice& in_audioDevice) {
231 auto soundDoseManager = mSoundDoseManager.promote();
232 if (soundDoseManager == nullptr) {
233 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
234 }
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100235
236 std::shared_ptr<ISoundDose> halSoundDose;
237 soundDoseManager->getHalSoundDose(&halSoundDose);
238 if(halSoundDose == nullptr) {
239 ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
240 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
241 }
242
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100243 auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
244 if (id == AUDIO_PORT_HANDLE_NONE) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100245 ALOGI("%s: no mapped id for audio device with type %d and address %s",
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100246 __func__, in_audioDevice.type.type,
247 in_audioDevice.address.get<AudioDeviceAddress::id>().c_str());
248 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
249 }
250 // TODO: introduce timestamp in onNewMelValues callback
251 soundDoseManager->onNewMelValues(in_melRecord.melValues, 0,
252 in_melRecord.melValues.size(), id);
253
254 return ndk::ScopedAStatus::ok();
255}
256
Vlad Popae3fd1c22022-11-07 21:03:18 +0100257void SoundDoseManager::SoundDose::binderDied(__unused const wp<IBinder>& who) {
258 ALOGV("%s", __func__);
259
260 auto soundDoseManager = mSoundDoseManager.promote();
261 if (soundDoseManager != nullptr) {
262 soundDoseManager->resetSoundDose();
263 }
264}
265
266binder::Status SoundDoseManager::SoundDose::setOutputRs2(float value) {
267 ALOGV("%s", __func__);
268 auto soundDoseManager = mSoundDoseManager.promote();
269 if (soundDoseManager != nullptr) {
270 soundDoseManager->setOutputRs2(value);
271 }
272 return binder::Status::ok();
273}
274
275binder::Status SoundDoseManager::SoundDose::resetCsd(
276 float currentCsd, const std::vector<media::SoundDoseRecord>& records) {
277 ALOGV("%s", __func__);
278 auto soundDoseManager = mSoundDoseManager.promote();
279 if (soundDoseManager != nullptr) {
280 soundDoseManager->resetCsd(currentCsd, records);
281 }
282 return binder::Status::ok();
283}
284
Vlad Popa58e72dc2023-02-01 13:18:40 +0100285binder::Status SoundDoseManager::SoundDose::updateAttenuation(float attenuationDB, int device) {
286 ALOGV("%s", __func__);
287 auto soundDoseManager = mSoundDoseManager.promote();
288 if (soundDoseManager != nullptr) {
289 soundDoseManager->updateAttenuation(attenuationDB, static_cast<audio_devices_t>(device));
290 }
291 return binder::Status::ok();
292}
293
Vlad Popa91930462022-12-20 22:42:48 +0100294binder::Status SoundDoseManager::SoundDose::getOutputRs2(float* value) {
295 ALOGV("%s", __func__);
296 auto soundDoseManager = mSoundDoseManager.promote();
297 if (soundDoseManager != nullptr) {
298 std::lock_guard _l(soundDoseManager->mLock);
299 *value = soundDoseManager->mRs2Value;
300 }
301 return binder::Status::ok();
302}
303
304binder::Status SoundDoseManager::SoundDose::getCsd(float* value) {
305 ALOGV("%s", __func__);
306 auto soundDoseManager = mSoundDoseManager.promote();
307 if (soundDoseManager != nullptr) {
308 *value = soundDoseManager->mMelAggregator->getCsd();
309 }
310 return binder::Status::ok();
311}
312
313binder::Status SoundDoseManager::SoundDose::forceUseFrameworkMel(bool useFrameworkMel) {
314 ALOGV("%s", __func__);
315 auto soundDoseManager = mSoundDoseManager.promote();
316 if (soundDoseManager != nullptr) {
317 soundDoseManager->setUseFrameworkMel(useFrameworkMel);
318 }
319 return binder::Status::ok();
320}
321
322binder::Status SoundDoseManager::SoundDose::forceComputeCsdOnAllDevices(
323 bool computeCsdOnAllDevices) {
324 ALOGV("%s", __func__);
325 auto soundDoseManager = mSoundDoseManager.promote();
326 if (soundDoseManager != nullptr) {
327 soundDoseManager->setComputeCsdOnAllDevices(computeCsdOnAllDevices);
328 }
329 return binder::Status::ok();
330}
331
Vlad Popa58e72dc2023-02-01 13:18:40 +0100332void SoundDoseManager::updateAttenuation(float attenuationDB, audio_devices_t deviceType) {
333 std::lock_guard _l(mLock);
334 ALOGV("%s: updating MEL processor attenuation for device %d to %f",
335 __func__, deviceType, attenuationDB);
336 mMelAttenuationDB[deviceType] = attenuationDB;
337 for (const auto& mp : mActiveProcessors) {
338 auto melProcessor = mp.second.promote();
339 if (melProcessor != nullptr) {
340 auto deviceId = melProcessor->getDeviceId();
341 if (mActiveDeviceTypes[deviceId] == deviceType) {
342 ALOGV("%s: updating MEL processor attenuation for deviceId %d to %f",
343 __func__, deviceId, attenuationDB);
344 melProcessor->setAttenuation(attenuationDB);
345 }
346 }
347 }
348}
349
Vlad Popa91930462022-12-20 22:42:48 +0100350void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100351 // invalidate any HAL sound dose interface used
352 setHalSoundDoseInterface(nullptr);
353
Vlad Popa91930462022-12-20 22:42:48 +0100354 std::lock_guard _l(mLock);
355 mUseFrameworkMel = useFrameworkMel;
356}
357
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100358bool SoundDoseManager::forceUseFrameworkMel() const {
Vlad Popa91930462022-12-20 22:42:48 +0100359 std::lock_guard _l(mLock);
360 return mUseFrameworkMel;
361}
362
363void SoundDoseManager::setComputeCsdOnAllDevices(bool computeCsdOnAllDevices) {
364 std::lock_guard _l(mLock);
365 mComputeCsdOnAllDevices = computeCsdOnAllDevices;
366}
367
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100368bool SoundDoseManager::forceComputeCsdOnAllDevices() const {
Vlad Popa91930462022-12-20 22:42:48 +0100369 std::lock_guard _l(mLock);
370 return mComputeCsdOnAllDevices;
371}
372
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100373void SoundDoseManager::getHalSoundDose(std::shared_ptr<ISoundDose>* halSoundDose) const {
374 std::lock_guard _l(mLock);
375 *halSoundDose = mHalSoundDose;
376}
377
Vlad Popae3fd1c22022-11-07 21:03:18 +0100378void SoundDoseManager::resetSoundDose() {
379 std::lock_guard lock(mLock);
380 mSoundDose = nullptr;
381}
382
383void SoundDoseManager::resetCsd(float currentCsd,
384 const std::vector<media::SoundDoseRecord>& records) {
385 std::lock_guard lock(mLock);
386 std::vector<audio_utils::CsdRecord> resetRecords;
387 for (const auto& record : records) {
388 resetRecords.emplace_back(record.timestamp, record.duration, record.value,
389 record.averageMel);
390 }
391
392 mMelAggregator->reset(currentCsd, resetRecords);
393}
394
Vlad Popa4defd0b2022-11-06 14:22:31 +0100395void SoundDoseManager::onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
396 audio_port_handle_t deviceId) const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100397 ALOGV("%s", __func__);
Vlad Popa2900c0a2022-10-24 13:38:00 +0200398
Vlad Popa4defd0b2022-11-06 14:22:31 +0100399 sp<media::ISoundDoseCallback> soundDoseCallback;
400 std::vector<audio_utils::CsdRecord> records;
401 float currentCsd;
402 {
403 std::lock_guard _l(mLock);
Vlad Popa2900c0a2022-10-24 13:38:00 +0200404
Vlad Popa4defd0b2022-11-06 14:22:31 +0100405 int64_t timestampSec = getMonotonicSecond();
406
407 // only for internal callbacks
408 records = mMelAggregator->aggregateAndAddNewMelRecord(audio_utils::MelRecord(
409 deviceId, std::vector<float>(mels.begin() + offset, mels.begin() + offset + length),
410 timestampSec - length));
411
412 currentCsd = mMelAggregator->getCsd();
413 }
414
415 soundDoseCallback = getSoundDoseCallback();
416
417 if (records.size() > 0 && soundDoseCallback != nullptr) {
418 std::vector<media::SoundDoseRecord> newRecordsToReport;
419 for (const auto& record : records) {
420 newRecordsToReport.emplace_back(csdRecordToSoundDoseRecord(record));
421 }
422
423 soundDoseCallback->onNewCsdValue(currentCsd, newRecordsToReport);
424 }
Vlad Popa2900c0a2022-10-24 13:38:00 +0200425}
426
Vlad Popa4defd0b2022-11-06 14:22:31 +0100427sp<media::ISoundDoseCallback> SoundDoseManager::getSoundDoseCallback() const {
428 std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100429 if (mSoundDose == nullptr) {
430 return nullptr;
431 }
432
433 return mSoundDose->mSoundDoseCallback;
Vlad Popa4defd0b2022-11-06 14:22:31 +0100434}
435
436void SoundDoseManager::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const {
437 ALOGV("%s: Momentary exposure for device %d triggered: %f MEL", __func__, deviceId, currentMel);
Vlad Popa63f047e2022-11-05 14:09:19 +0100438
Vlad Popae3fd1c22022-11-07 21:03:18 +0100439 auto soundDoseCallback = getSoundDoseCallback();
Vlad Popa63f047e2022-11-05 14:09:19 +0100440 if (soundDoseCallback != nullptr) {
Vlad Popae3fd1c22022-11-07 21:03:18 +0100441 soundDoseCallback->onMomentaryExposure(currentMel, deviceId);
Vlad Popa63f047e2022-11-05 14:09:19 +0100442 }
443}
444
Vlad Popae3fd1c22022-11-07 21:03:18 +0100445sp<media::ISoundDose> SoundDoseManager::getSoundDoseInterface(
446 const sp<media::ISoundDoseCallback>& callback) {
Vlad Popa63f047e2022-11-05 14:09:19 +0100447 ALOGV("%s: Register ISoundDoseCallback", __func__);
448
449 std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100450 if (mSoundDose == nullptr) {
451 mSoundDose = sp<SoundDose>::make(this, callback);
452 }
453 return mSoundDose;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100454}
455
Vlad Popa4defd0b2022-11-06 14:22:31 +0100456std::string SoundDoseManager::dump() const {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200457 std::string output;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100458 mMelAggregator->foreachCsd([&output](audio_utils::CsdRecord csdRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200459 base::StringAppendF(&output,
460 "CSD %f with average MEL %f in interval [%" PRId64 ", %" PRId64 "]",
Vlad Popa4defd0b2022-11-06 14:22:31 +0100461 csdRecord.value, csdRecord.averageMel, csdRecord.timestamp,
Vlad Popa2900c0a2022-10-24 13:38:00 +0200462 csdRecord.timestamp + csdRecord.duration);
463 base::StringAppendF(&output, "\n");
464 });
465
466 base::StringAppendF(&output, "\nCached Mel Records:\n");
Vlad Popaf09e93f2022-10-31 16:27:12 +0100467 mMelAggregator->foreachCachedMel([&output](const audio_utils::MelRecord& melRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200468 base::StringAppendF(&output, "Continuous MELs for portId=%d, ", melRecord.portId);
469 base::StringAppendF(&output, "starting at timestamp %" PRId64 ": ", melRecord.timestamp);
470
471 for (const auto& mel : melRecord.mels) {
472 base::StringAppendF(&output, "%.2f ", mel);
473 }
474 base::StringAppendF(&output, "\n");
475 });
476
477 return output;
478}
479
480size_t SoundDoseManager::getCachedMelRecordsSize() const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100481 return mMelAggregator->getCachedMelRecordsSize();
Vlad Popa2900c0a2022-10-24 13:38:00 +0200482}
483
Vlad Popa4defd0b2022-11-06 14:22:31 +0100484media::SoundDoseRecord SoundDoseManager::csdRecordToSoundDoseRecord(
485 const audio_utils::CsdRecord& legacy) {
486 media::SoundDoseRecord soundDoseRecord{};
487 soundDoseRecord.timestamp = legacy.timestamp;
488 soundDoseRecord.duration = legacy.duration;
489 soundDoseRecord.value = legacy.value;
490 soundDoseRecord.averageMel = legacy.averageMel;
491 return soundDoseRecord;
492}
493
Vlad Popa2900c0a2022-10-24 13:38:00 +0200494} // namespace android