blob: 21252d6bb4fa4633fb01d5b6f1fb682c883a6d32 [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 Popa2a06fca2023-02-06 16:45:45 +010053 if (mHalSoundDose != nullptr && !mDisableCsd) {
Vlad Popa1d5f0d52022-12-18 12:21:26 +010054 ALOGW("%s: using HAL MEL computation, no MelProcessor needed.", __func__);
55 return nullptr;
56 }
57
Vlad Popaf09e93f2022-10-31 16:27:12 +010058 auto streamProcessor = mActiveProcessors.find(streamHandle);
59 sp<audio_utils::MelProcessor> processor;
Vlad Popa4defd0b2022-11-06 14:22:31 +010060 if (streamProcessor != mActiveProcessors.end() &&
61 (processor = streamProcessor->second.promote())) {
Vlad Popaeafa0482023-02-23 14:35:56 +010062 ALOGV("%s: found callback for stream id %d", __func__, streamHandle);
Vlad Popa58e72dc2023-02-01 13:18:40 +010063 const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
64 if (activeTypeIt != mActiveDeviceTypes.end()) {
65 processor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
66 }
Vlad Popaf09e93f2022-10-31 16:27:12 +010067 processor->setDeviceId(deviceId);
Vlad Popa4847de12023-03-16 18:30:08 +010068 processor->setOutputRs2UpperBound(mRs2UpperBound);
Vlad Popaf09e93f2022-10-31 16:27:12 +010069 return processor;
Vlad Popa2900c0a2022-10-24 13:38:00 +020070 } else {
Vlad Popaeafa0482023-02-23 14:35:56 +010071 ALOGV("%s: creating new callback for stream id %d", __func__, streamHandle);
Vlad Popa4defd0b2022-11-06 14:22:31 +010072 sp<audio_utils::MelProcessor> melProcessor = sp<audio_utils::MelProcessor>::make(
Vlad Popa4847de12023-03-16 18:30:08 +010073 sampleRate, channelCount, format, this, deviceId, mRs2UpperBound);
Vlad Popa58e72dc2023-02-01 13:18:40 +010074 const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
75 if (activeTypeIt != mActiveDeviceTypes.end()) {
76 melProcessor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
77 }
Vlad Popaf09e93f2022-10-31 16:27:12 +010078 mActiveProcessors[streamHandle] = melProcessor;
79 return melProcessor;
Vlad Popa2900c0a2022-10-24 13:38:00 +020080 }
81}
82
Vlad Popa1d5f0d52022-12-18 12:21:26 +010083bool SoundDoseManager::setHalSoundDoseInterface(const std::shared_ptr<ISoundDose>& halSoundDose) {
84 ALOGV("%s", __func__);
85
86 {
87 std::lock_guard _l(mLock);
88
89 mHalSoundDose = halSoundDose;
90 if (halSoundDose == nullptr) {
91 ALOGI("%s: passed ISoundDose object is null, switching to internal CSD", __func__);
92 return false;
93 }
94
Vlad Popa4847de12023-03-16 18:30:08 +010095 if (!mHalSoundDose->setOutputRs2UpperBound(mRs2UpperBound).isOk()) {
Vlad Popa1d5f0d52022-12-18 12:21:26 +010096 ALOGW("%s: Cannot set RS2 value for momentary exposure %f",
97 __func__,
Vlad Popa4847de12023-03-16 18:30:08 +010098 mRs2UpperBound);
Vlad Popa1d5f0d52022-12-18 12:21:26 +010099 }
100
101 // initialize the HAL sound dose callback lazily
102 if (mHalSoundDoseCallback == nullptr) {
103 mHalSoundDoseCallback =
104 ndk::SharedRefBase::make<HalSoundDoseCallback>(this);
105 }
106 }
107
108 auto status = halSoundDose->registerSoundDoseCallback(mHalSoundDoseCallback);
109 if (!status.isOk()) {
110 // Not a warning since this can happen if the callback was registered before
111 ALOGI("%s: Cannot register HAL sound dose callback with status message: %s",
112 __func__,
113 status.getMessage());
114 }
115
116 return true;
117}
118
Vlad Popa4847de12023-03-16 18:30:08 +0100119void SoundDoseManager::setOutputRs2UpperBound(float rs2Value) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200120 ALOGV("%s", __func__);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100121 std::lock_guard _l(mLock);
122
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100123 if (mHalSoundDose != nullptr) {
124 // using the HAL sound dose interface
Vlad Popa4847de12023-03-16 18:30:08 +0100125 if (!mHalSoundDose->setOutputRs2UpperBound(rs2Value).isOk()) {
Vlad Popa3c3995d2023-01-13 11:10:05 +0100126 ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
127 return;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100128 }
Vlad Popa4847de12023-03-16 18:30:08 +0100129 mRs2UpperBound = rs2Value;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100130 return;
131 }
Vlad Popae3fd1c22022-11-07 21:03:18 +0100132
Vlad Popaf09e93f2022-10-31 16:27:12 +0100133 for (auto& streamProcessor : mActiveProcessors) {
134 sp<audio_utils::MelProcessor> processor = streamProcessor.second.promote();
135 if (processor != nullptr) {
Vlad Popa4847de12023-03-16 18:30:08 +0100136 status_t result = processor->setOutputRs2UpperBound(rs2Value);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100137 if (result != NO_ERROR) {
Vlad Popa4847de12023-03-16 18:30:08 +0100138 ALOGW("%s: could not set RS2 upper bound %f for stream %d", __func__, rs2Value,
Vlad Popaf09e93f2022-10-31 16:27:12 +0100139 streamProcessor.first);
Vlad Popa3c3995d2023-01-13 11:10:05 +0100140 return;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100141 }
Vlad Popa4847de12023-03-16 18:30:08 +0100142 mRs2UpperBound = rs2Value;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100143 }
144 }
145}
146
Vlad Popa4defd0b2022-11-06 14:22:31 +0100147void SoundDoseManager::removeStreamProcessor(audio_io_handle_t streamHandle) {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100148 std::lock_guard _l(mLock);
149 auto callbackToRemove = mActiveProcessors.find(streamHandle);
Vlad Popa4defd0b2022-11-06 14:22:31 +0100150 if (callbackToRemove != mActiveProcessors.end()) {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100151 mActiveProcessors.erase(callbackToRemove);
152 }
153}
154
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100155audio_port_handle_t SoundDoseManager::getIdForAudioDevice(const AudioDevice& audioDevice) const {
156 std::lock_guard _l(mLock);
157
158 audio_devices_t type;
159 std::string address;
160 auto result = aidl::android::aidl2legacy_AudioDevice_audio_device(
161 audioDevice, &type, &address);
162 if (result != NO_ERROR) {
163 ALOGE("%s: could not convert from AudioDevice to AudioDeviceTypeAddr", __func__);
164 return AUDIO_PORT_HANDLE_NONE;
165 }
166
167 auto adt = AudioDeviceTypeAddr(type, address);
168 auto deviceIt = mActiveDevices.find(adt);
169 if (deviceIt == mActiveDevices.end()) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100170 ALOGI("%s: could not find port id for device %s", __func__, adt.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100171 return AUDIO_PORT_HANDLE_NONE;
172 }
173 return deviceIt->second;
174}
175
176void SoundDoseManager::mapAddressToDeviceId(const AudioDeviceTypeAddr& adt,
177 const audio_port_handle_t deviceId) {
178 std::lock_guard _l(mLock);
Vlad Popaeafa0482023-02-23 14:35:56 +0100179 ALOGI("%s: map address: %d to device id: %d", __func__, adt.mType, deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100180 mActiveDevices[adt] = deviceId;
Vlad Popa58e72dc2023-02-01 13:18:40 +0100181 mActiveDeviceTypes[deviceId] = adt.mType;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100182}
183
184void SoundDoseManager::clearMapDeviceIdEntries(audio_port_handle_t deviceId) {
185 std::lock_guard _l(mLock);
186 for (auto activeDevice = mActiveDevices.begin(); activeDevice != mActiveDevices.end();) {
187 if (activeDevice->second == deviceId) {
Vlad Popaeafa0482023-02-23 14:35:56 +0100188 ALOGI("%s: clear mapping type: %d to deviceId: %d",
189 __func__, activeDevice->first.mType, deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100190 activeDevice = mActiveDevices.erase(activeDevice);
191 continue;
192 }
193 ++activeDevice;
194 }
Vlad Popa58e72dc2023-02-01 13:18:40 +0100195 mActiveDeviceTypes.erase(deviceId);
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100196}
197
198ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
199 float in_currentDbA, const AudioDevice& in_audioDevice) {
200 auto soundDoseManager = mSoundDoseManager.promote();
201 if (soundDoseManager == nullptr) {
202 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
203 }
204
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100205 std::shared_ptr<ISoundDose> halSoundDose;
206 soundDoseManager->getHalSoundDose(&halSoundDose);
207 if(halSoundDose == nullptr) {
208 ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
209 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
210 }
211
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100212 auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
213 if (id == AUDIO_PORT_HANDLE_NONE) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100214 ALOGI("%s: no mapped id for audio device with type %d and address %s",
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100215 __func__, in_audioDevice.type.type,
216 in_audioDevice.address.get<AudioDeviceAddress::id>().c_str());
217 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
218 }
219 soundDoseManager->onMomentaryExposure(in_currentDbA, id);
220
221 return ndk::ScopedAStatus::ok();
222}
223
224ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onNewMelValues(
225 const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
226 const AudioDevice& in_audioDevice) {
227 auto soundDoseManager = mSoundDoseManager.promote();
228 if (soundDoseManager == nullptr) {
229 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
230 }
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100231
232 std::shared_ptr<ISoundDose> halSoundDose;
233 soundDoseManager->getHalSoundDose(&halSoundDose);
234 if(halSoundDose == nullptr) {
235 ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
236 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
237 }
238
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100239 auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
240 if (id == AUDIO_PORT_HANDLE_NONE) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100241 ALOGI("%s: no mapped id for audio device with type %d and address %s",
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100242 __func__, in_audioDevice.type.type,
243 in_audioDevice.address.get<AudioDeviceAddress::id>().c_str());
244 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
245 }
246 // TODO: introduce timestamp in onNewMelValues callback
247 soundDoseManager->onNewMelValues(in_melRecord.melValues, 0,
248 in_melRecord.melValues.size(), id);
249
250 return ndk::ScopedAStatus::ok();
251}
252
Vlad Popae3fd1c22022-11-07 21:03:18 +0100253void SoundDoseManager::SoundDose::binderDied(__unused const wp<IBinder>& who) {
254 ALOGV("%s", __func__);
255
256 auto soundDoseManager = mSoundDoseManager.promote();
257 if (soundDoseManager != nullptr) {
258 soundDoseManager->resetSoundDose();
259 }
260}
261
Vlad Popa4847de12023-03-16 18:30:08 +0100262binder::Status SoundDoseManager::SoundDose::setOutputRs2UpperBound(float value) {
Vlad Popae3fd1c22022-11-07 21:03:18 +0100263 ALOGV("%s", __func__);
264 auto soundDoseManager = mSoundDoseManager.promote();
265 if (soundDoseManager != nullptr) {
Vlad Popa4847de12023-03-16 18:30:08 +0100266 soundDoseManager->setOutputRs2UpperBound(value);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100267 }
268 return binder::Status::ok();
269}
270
271binder::Status SoundDoseManager::SoundDose::resetCsd(
272 float currentCsd, const std::vector<media::SoundDoseRecord>& records) {
273 ALOGV("%s", __func__);
274 auto soundDoseManager = mSoundDoseManager.promote();
275 if (soundDoseManager != nullptr) {
276 soundDoseManager->resetCsd(currentCsd, records);
277 }
278 return binder::Status::ok();
279}
280
Vlad Popa58e72dc2023-02-01 13:18:40 +0100281binder::Status SoundDoseManager::SoundDose::updateAttenuation(float attenuationDB, int device) {
282 ALOGV("%s", __func__);
283 auto soundDoseManager = mSoundDoseManager.promote();
284 if (soundDoseManager != nullptr) {
285 soundDoseManager->updateAttenuation(attenuationDB, static_cast<audio_devices_t>(device));
286 }
287 return binder::Status::ok();
288}
289
Vlad Popa2a06fca2023-02-06 16:45:45 +0100290binder::Status SoundDoseManager::SoundDose::disableCsd() {
291 ALOGV("%s", __func__);
292 auto soundDoseManager = mSoundDoseManager.promote();
293 if (soundDoseManager != nullptr) {
294 soundDoseManager->disableCsd();
295 }
296 return binder::Status::ok();
297}
298
Vlad Popa4847de12023-03-16 18:30:08 +0100299binder::Status SoundDoseManager::SoundDose::getOutputRs2UpperBound(float* value) {
Vlad Popa91930462022-12-20 22:42:48 +0100300 ALOGV("%s", __func__);
301 auto soundDoseManager = mSoundDoseManager.promote();
302 if (soundDoseManager != nullptr) {
303 std::lock_guard _l(soundDoseManager->mLock);
Vlad Popa4847de12023-03-16 18:30:08 +0100304 *value = soundDoseManager->mRs2UpperBound;
Vlad Popa91930462022-12-20 22:42:48 +0100305 }
306 return binder::Status::ok();
307}
308
309binder::Status SoundDoseManager::SoundDose::getCsd(float* value) {
310 ALOGV("%s", __func__);
311 auto soundDoseManager = mSoundDoseManager.promote();
312 if (soundDoseManager != nullptr) {
313 *value = soundDoseManager->mMelAggregator->getCsd();
314 }
315 return binder::Status::ok();
316}
317
318binder::Status SoundDoseManager::SoundDose::forceUseFrameworkMel(bool useFrameworkMel) {
319 ALOGV("%s", __func__);
320 auto soundDoseManager = mSoundDoseManager.promote();
321 if (soundDoseManager != nullptr) {
322 soundDoseManager->setUseFrameworkMel(useFrameworkMel);
323 }
324 return binder::Status::ok();
325}
326
327binder::Status SoundDoseManager::SoundDose::forceComputeCsdOnAllDevices(
328 bool computeCsdOnAllDevices) {
329 ALOGV("%s", __func__);
330 auto soundDoseManager = mSoundDoseManager.promote();
331 if (soundDoseManager != nullptr) {
332 soundDoseManager->setComputeCsdOnAllDevices(computeCsdOnAllDevices);
333 }
334 return binder::Status::ok();
335}
336
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000337binder::Status SoundDoseManager::SoundDose::isSoundDoseHalSupported(bool* value) {
338 ALOGV("%s", __func__);
339 *value = false;
340 auto soundDoseManager = mSoundDoseManager.promote();
341 if (soundDoseManager != nullptr) {
342 *value = soundDoseManager->isSoundDoseHalSupported();
343 }
344 return binder::Status::ok();
345}
346
Vlad Popa58e72dc2023-02-01 13:18:40 +0100347void SoundDoseManager::updateAttenuation(float attenuationDB, audio_devices_t deviceType) {
348 std::lock_guard _l(mLock);
Vlad Popaeafa0482023-02-23 14:35:56 +0100349 ALOGV("%s: updating MEL processor attenuation for device type %d to %f",
Vlad Popa58e72dc2023-02-01 13:18:40 +0100350 __func__, deviceType, attenuationDB);
351 mMelAttenuationDB[deviceType] = attenuationDB;
352 for (const auto& mp : mActiveProcessors) {
353 auto melProcessor = mp.second.promote();
354 if (melProcessor != nullptr) {
355 auto deviceId = melProcessor->getDeviceId();
356 if (mActiveDeviceTypes[deviceId] == deviceType) {
Vlad Popaeafa0482023-02-23 14:35:56 +0100357 ALOGV("%s: set attenuation for deviceId %d to %f",
Vlad Popa58e72dc2023-02-01 13:18:40 +0100358 __func__, deviceId, attenuationDB);
359 melProcessor->setAttenuation(attenuationDB);
360 }
361 }
362 }
363}
364
Vlad Popa2a06fca2023-02-06 16:45:45 +0100365void SoundDoseManager::disableCsd() {
366 ALOGV("%s", __func__);
367
368 std::lock_guard _l(mLock);
369 mDisableCsd = true;
370
371 // Normally, there should be no active MelProcessors when this method is called
372 // We pause however every cached MelProcessor as a defensive mechanism to not
373 // have unnecessary processing
374 for (auto& activeEntry : mActiveProcessors) {
375 auto melProcessor = activeEntry.second.promote();
376 if (melProcessor != nullptr) {
377 melProcessor->pause();
378 }
379 }
380}
381
382bool SoundDoseManager::isCsdDisabled() {
383 std::lock_guard _l(mLock);
384 return mDisableCsd;
385}
386
Vlad Popa91930462022-12-20 22:42:48 +0100387void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100388 // invalidate any HAL sound dose interface used
389 setHalSoundDoseInterface(nullptr);
390
Vlad Popa91930462022-12-20 22:42:48 +0100391 std::lock_guard _l(mLock);
392 mUseFrameworkMel = useFrameworkMel;
393}
394
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100395bool SoundDoseManager::forceUseFrameworkMel() const {
Vlad Popa91930462022-12-20 22:42:48 +0100396 std::lock_guard _l(mLock);
397 return mUseFrameworkMel;
398}
399
400void SoundDoseManager::setComputeCsdOnAllDevices(bool computeCsdOnAllDevices) {
401 std::lock_guard _l(mLock);
402 mComputeCsdOnAllDevices = computeCsdOnAllDevices;
403}
404
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100405bool SoundDoseManager::forceComputeCsdOnAllDevices() const {
Vlad Popa91930462022-12-20 22:42:48 +0100406 std::lock_guard _l(mLock);
407 return mComputeCsdOnAllDevices;
408}
409
Vlad Popa95ee3ca2023-03-20 19:29:38 +0000410bool SoundDoseManager::isSoundDoseHalSupported() const {
411 if (mDisableCsd) {
412 return false;
413 }
414
415 std::shared_ptr<ISoundDose> halSoundDose;
416 getHalSoundDose(&halSoundDose);
417 if (mHalSoundDose == nullptr) {
418 return false;
419 }
420 return true;
421}
422
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100423void SoundDoseManager::getHalSoundDose(std::shared_ptr<ISoundDose>* halSoundDose) const {
424 std::lock_guard _l(mLock);
425 *halSoundDose = mHalSoundDose;
426}
427
Vlad Popae3fd1c22022-11-07 21:03:18 +0100428void SoundDoseManager::resetSoundDose() {
429 std::lock_guard lock(mLock);
430 mSoundDose = nullptr;
431}
432
433void SoundDoseManager::resetCsd(float currentCsd,
434 const std::vector<media::SoundDoseRecord>& records) {
435 std::lock_guard lock(mLock);
436 std::vector<audio_utils::CsdRecord> resetRecords;
437 for (const auto& record : records) {
438 resetRecords.emplace_back(record.timestamp, record.duration, record.value,
439 record.averageMel);
440 }
441
442 mMelAggregator->reset(currentCsd, resetRecords);
443}
444
Vlad Popa4defd0b2022-11-06 14:22:31 +0100445void SoundDoseManager::onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
446 audio_port_handle_t deviceId) const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100447 ALOGV("%s", __func__);
Vlad Popa2900c0a2022-10-24 13:38:00 +0200448
Vlad Popa2a06fca2023-02-06 16:45:45 +0100449
Vlad Popa4defd0b2022-11-06 14:22:31 +0100450 sp<media::ISoundDoseCallback> soundDoseCallback;
451 std::vector<audio_utils::CsdRecord> records;
452 float currentCsd;
453 {
454 std::lock_guard _l(mLock);
Vlad Popa2a06fca2023-02-06 16:45:45 +0100455 if (mDisableCsd) {
456 return;
457 }
458
Vlad Popa2900c0a2022-10-24 13:38:00 +0200459
Vlad Popa4defd0b2022-11-06 14:22:31 +0100460 int64_t timestampSec = getMonotonicSecond();
461
462 // only for internal callbacks
463 records = mMelAggregator->aggregateAndAddNewMelRecord(audio_utils::MelRecord(
464 deviceId, std::vector<float>(mels.begin() + offset, mels.begin() + offset + length),
465 timestampSec - length));
466
467 currentCsd = mMelAggregator->getCsd();
468 }
469
470 soundDoseCallback = getSoundDoseCallback();
471
472 if (records.size() > 0 && soundDoseCallback != nullptr) {
473 std::vector<media::SoundDoseRecord> newRecordsToReport;
474 for (const auto& record : records) {
475 newRecordsToReport.emplace_back(csdRecordToSoundDoseRecord(record));
476 }
477
478 soundDoseCallback->onNewCsdValue(currentCsd, newRecordsToReport);
479 }
Vlad Popa2900c0a2022-10-24 13:38:00 +0200480}
481
Vlad Popa4defd0b2022-11-06 14:22:31 +0100482sp<media::ISoundDoseCallback> SoundDoseManager::getSoundDoseCallback() const {
483 std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100484 if (mSoundDose == nullptr) {
485 return nullptr;
486 }
487
488 return mSoundDose->mSoundDoseCallback;
Vlad Popa4defd0b2022-11-06 14:22:31 +0100489}
490
491void SoundDoseManager::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const {
492 ALOGV("%s: Momentary exposure for device %d triggered: %f MEL", __func__, deviceId, currentMel);
Vlad Popa63f047e2022-11-05 14:09:19 +0100493
Vlad Popa2a06fca2023-02-06 16:45:45 +0100494 {
495 std::lock_guard _l(mLock);
496 if (mDisableCsd) {
497 return;
498 }
499 }
500
Vlad Popae3fd1c22022-11-07 21:03:18 +0100501 auto soundDoseCallback = getSoundDoseCallback();
Vlad Popa63f047e2022-11-05 14:09:19 +0100502 if (soundDoseCallback != nullptr) {
Vlad Popae3fd1c22022-11-07 21:03:18 +0100503 soundDoseCallback->onMomentaryExposure(currentMel, deviceId);
Vlad Popa63f047e2022-11-05 14:09:19 +0100504 }
505}
506
Vlad Popae3fd1c22022-11-07 21:03:18 +0100507sp<media::ISoundDose> SoundDoseManager::getSoundDoseInterface(
508 const sp<media::ISoundDoseCallback>& callback) {
Vlad Popa63f047e2022-11-05 14:09:19 +0100509 ALOGV("%s: Register ISoundDoseCallback", __func__);
510
511 std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100512 if (mSoundDose == nullptr) {
513 mSoundDose = sp<SoundDose>::make(this, callback);
514 }
515 return mSoundDose;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100516}
517
Vlad Popa4defd0b2022-11-06 14:22:31 +0100518std::string SoundDoseManager::dump() const {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200519 std::string output;
Vlad Popa2a06fca2023-02-06 16:45:45 +0100520 {
521 std::lock_guard _l(mLock);
522 if (mDisableCsd) {
523 base::StringAppendF(&output, "CSD is disabled");
524 return output;
525 }
526 }
527
Vlad Popaf09e93f2022-10-31 16:27:12 +0100528 mMelAggregator->foreachCsd([&output](audio_utils::CsdRecord csdRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200529 base::StringAppendF(&output,
530 "CSD %f with average MEL %f in interval [%" PRId64 ", %" PRId64 "]",
Vlad Popa4defd0b2022-11-06 14:22:31 +0100531 csdRecord.value, csdRecord.averageMel, csdRecord.timestamp,
Vlad Popa2900c0a2022-10-24 13:38:00 +0200532 csdRecord.timestamp + csdRecord.duration);
533 base::StringAppendF(&output, "\n");
534 });
535
536 base::StringAppendF(&output, "\nCached Mel Records:\n");
Vlad Popaf09e93f2022-10-31 16:27:12 +0100537 mMelAggregator->foreachCachedMel([&output](const audio_utils::MelRecord& melRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200538 base::StringAppendF(&output, "Continuous MELs for portId=%d, ", melRecord.portId);
539 base::StringAppendF(&output, "starting at timestamp %" PRId64 ": ", melRecord.timestamp);
540
541 for (const auto& mel : melRecord.mels) {
542 base::StringAppendF(&output, "%.2f ", mel);
543 }
544 base::StringAppendF(&output, "\n");
545 });
546
547 return output;
548}
549
550size_t SoundDoseManager::getCachedMelRecordsSize() const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100551 return mMelAggregator->getCachedMelRecordsSize();
Vlad Popa2900c0a2022-10-24 13:38:00 +0200552}
553
Vlad Popa4defd0b2022-11-06 14:22:31 +0100554media::SoundDoseRecord SoundDoseManager::csdRecordToSoundDoseRecord(
555 const audio_utils::CsdRecord& legacy) {
556 media::SoundDoseRecord soundDoseRecord{};
557 soundDoseRecord.timestamp = legacy.timestamp;
558 soundDoseRecord.duration = legacy.duration;
559 soundDoseRecord.value = legacy.value;
560 soundDoseRecord.averageMel = legacy.averageMel;
561 return soundDoseRecord;
562}
563
Vlad Popa2900c0a2022-10-24 13:38:00 +0200564} // namespace android