• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
23 #include "android/media/SoundDoseRecord.h"
24 #include <android-base/stringprintf.h>
25 #include <media/AidlConversionCppNdk.h>
26 #include <cinttypes>
27 #include <ctime>
28 #include <utils/Log.h>
29 
30 namespace android {
31 
32 using aidl::android::media::audio::common::AudioDevice;
33 using aidl::android::media::audio::common::AudioDeviceAddress;
34 
35 namespace {
36 
getMonotonicSecond()37 int64_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 
getOrCreateProcessorForDevice(audio_port_handle_t deviceId,audio_io_handle_t streamHandle,uint32_t sampleRate,size_t channelCount,audio_format_t format)48 sp<audio_utils::MelProcessor> SoundDoseManager::getOrCreateProcessorForDevice(
49         audio_port_handle_t deviceId, audio_io_handle_t streamHandle, uint32_t sampleRate,
50         size_t channelCount, audio_format_t format) {
51     std::lock_guard _l(mLock);
52 
53     if (mHalSoundDose.size() > 0 && mEnabledCsd) {
54         ALOGD("%s: using HAL MEL computation, no MelProcessor needed.", __func__);
55         return nullptr;
56     }
57 
58     auto streamProcessor = mActiveProcessors.find(streamHandle);
59     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;
72         }
73     }
74 
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;
84 }
85 
setHalSoundDoseInterface(const std::string & module,const std::shared_ptr<ISoundDose> & halSoundDose)86 bool SoundDoseManager::setHalSoundDoseInterface(const std::string &module,
87                                                 const std::shared_ptr<ISoundDose> &halSoundDose) {
88     ALOGV("%s", __func__);
89 
90     if (halSoundDose == nullptr) {
91         ALOGI("%s: passed ISoundDose object is null", __func__);
92         return false;
93     }
94 
95     std::shared_ptr<HalSoundDoseCallback> halSoundDoseCallback;
96     {
97         std::lock_guard _l(mLock);
98 
99         if (mHalSoundDose.find(module) != mHalSoundDose.end()) {
100             ALOGW("%s: Module %s already has a sound dose HAL assigned, skipping", __func__,
101                   module.c_str());
102             return false;
103         }
104         mHalSoundDose[module] = halSoundDose;
105 
106         if (!halSoundDose->setOutputRs2UpperBound(mRs2UpperBound).isOk()) {
107             ALOGW("%s: Cannot set RS2 value for momentary exposure %f",
108                   __func__,
109                   mRs2UpperBound);
110         }
111 
112         // initialize the HAL sound dose callback lazily
113         if (mHalSoundDoseCallback == nullptr) {
114             mHalSoundDoseCallback =
115                 ndk::SharedRefBase::make<HalSoundDoseCallback>(this);
116         }
117     }
118 
119     auto status = halSoundDose->registerSoundDoseCallback(mHalSoundDoseCallback);
120     if (!status.isOk()) {
121         // Not a warning since this can happen if the callback was registered before
122         ALOGI("%s: Cannot register HAL sound dose callback with status message: %s",
123               __func__,
124               status.getMessage());
125     }
126 
127     return true;
128 }
129 
resetHalSoundDoseInterfaces()130 void SoundDoseManager::resetHalSoundDoseInterfaces() {
131     ALOGV("%s", __func__);
132 
133     const std::lock_guard _l(mLock);
134     mHalSoundDose.clear();
135 }
136 
setOutputRs2UpperBound(float rs2Value)137 void SoundDoseManager::setOutputRs2UpperBound(float rs2Value) {
138     ALOGV("%s", __func__);
139     std::lock_guard _l(mLock);
140 
141     if (mHalSoundDose.size() > 0) {
142         for (auto& halSoundDose : mHalSoundDose) {
143             // using the HAL sound dose interface
144             if (!halSoundDose.second->setOutputRs2UpperBound(rs2Value).isOk()) {
145                 ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
146                 continue;
147             }
148         }
149 
150         mRs2UpperBound = rs2Value;
151         return;
152     }
153 
154     for (auto& streamProcessor : mActiveProcessors) {
155         sp<audio_utils::MelProcessor> processor = streamProcessor.second.promote();
156         if (processor != nullptr) {
157             status_t result = processor->setOutputRs2UpperBound(rs2Value);
158             if (result != NO_ERROR) {
159                 ALOGW("%s: could not set RS2 upper bound %f for stream %d", __func__, rs2Value,
160                       streamProcessor.first);
161                 return;
162             }
163             mRs2UpperBound = rs2Value;
164         }
165     }
166 }
167 
removeStreamProcessor(audio_io_handle_t streamHandle)168 void SoundDoseManager::removeStreamProcessor(audio_io_handle_t streamHandle) {
169     std::lock_guard _l(mLock);
170     auto callbackToRemove = mActiveProcessors.find(streamHandle);
171     if (callbackToRemove != mActiveProcessors.end()) {
172         mActiveProcessors.erase(callbackToRemove);
173     }
174 }
175 
getIdForAudioDevice(const AudioDevice & audioDevice) const176 audio_port_handle_t SoundDoseManager::getIdForAudioDevice(const AudioDevice& audioDevice) const {
177     std::lock_guard _l(mLock);
178 
179     audio_devices_t type;
180     std::string address;
181     auto result = aidl::android::aidl2legacy_AudioDevice_audio_device(
182             audioDevice, &type, &address);
183     if (result != NO_ERROR) {
184         ALOGE("%s: could not convert from AudioDevice to AudioDeviceTypeAddr", __func__);
185         return AUDIO_PORT_HANDLE_NONE;
186     }
187 
188     auto adt = AudioDeviceTypeAddr(type, address);
189     auto deviceIt = mActiveDevices.find(adt);
190     if (deviceIt == mActiveDevices.end()) {
191         ALOGI("%s: could not find port id for device %s", __func__, adt.toString().c_str());
192         return AUDIO_PORT_HANDLE_NONE;
193     }
194     return deviceIt->second;
195 }
196 
mapAddressToDeviceId(const AudioDeviceTypeAddr & adt,const audio_port_handle_t deviceId)197 void SoundDoseManager::mapAddressToDeviceId(const AudioDeviceTypeAddr& adt,
198                                             const audio_port_handle_t deviceId) {
199     std::lock_guard _l(mLock);
200     ALOGI("%s: map address: %d to device id: %d", __func__, adt.mType, deviceId);
201     mActiveDevices[adt] = deviceId;
202     mActiveDeviceTypes[deviceId] = adt.mType;
203 }
204 
clearMapDeviceIdEntries(audio_port_handle_t deviceId)205 void SoundDoseManager::clearMapDeviceIdEntries(audio_port_handle_t deviceId) {
206     std::lock_guard _l(mLock);
207     for (auto activeDevice = mActiveDevices.begin(); activeDevice != mActiveDevices.end();) {
208         if (activeDevice->second == deviceId) {
209             ALOGI("%s: clear mapping type: %d to deviceId: %d",
210                   __func__, activeDevice->first.mType, deviceId);
211             activeDevice = mActiveDevices.erase(activeDevice);
212             continue;
213         }
214         ++activeDevice;
215     }
216     mActiveDeviceTypes.erase(deviceId);
217 }
218 
onMomentaryExposureWarning(float in_currentDbA,const AudioDevice & in_audioDevice)219 ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
220         float in_currentDbA, const AudioDevice& in_audioDevice) {
221     sp<SoundDoseManager> soundDoseManager;
222     {
223         const std::lock_guard _l(mCbLock);
224         soundDoseManager = mSoundDoseManager.promote();
225         if (soundDoseManager == nullptr) {
226             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
227         }
228     }
229 
230     if (!soundDoseManager->useHalSoundDose()) {
231         ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
232         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
233     }
234 
235     auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
236     if (id == AUDIO_PORT_HANDLE_NONE) {
237         ALOGI("%s: no mapped id for audio device with type %d and address %s",
238                 __func__, in_audioDevice.type.type,
239                 in_audioDevice.address.toString().c_str());
240         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
241     }
242     soundDoseManager->onMomentaryExposure(in_currentDbA, id);
243 
244     return ndk::ScopedAStatus::ok();
245 }
246 
onNewMelValues(const ISoundDose::IHalSoundDoseCallback::MelRecord & in_melRecord,const AudioDevice & in_audioDevice)247 ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onNewMelValues(
248         const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
249         const AudioDevice& in_audioDevice) {
250     sp<SoundDoseManager> soundDoseManager;
251     {
252         const std::lock_guard _l(mCbLock);
253         soundDoseManager = mSoundDoseManager.promote();
254         if (soundDoseManager == nullptr) {
255             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
256         }
257     }
258 
259     if (!soundDoseManager->useHalSoundDose()) {
260         ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
261         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
262     }
263 
264     auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
265     if (id == AUDIO_PORT_HANDLE_NONE) {
266         ALOGI("%s: no mapped id for audio device with type %d and address %s",
267                 __func__, in_audioDevice.type.type,
268                 in_audioDevice.address.toString().c_str());
269         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
270     }
271     // TODO: introduce timestamp in onNewMelValues callback
272     soundDoseManager->onNewMelValues(in_melRecord.melValues, 0,
273                                      in_melRecord.melValues.size(), id);
274 
275     return ndk::ScopedAStatus::ok();
276 }
277 
binderDied(__unused const wp<IBinder> & who)278 void SoundDoseManager::SoundDose::binderDied(__unused const wp<IBinder>& who) {
279     ALOGV("%s", __func__);
280 
281     auto soundDoseManager = mSoundDoseManager.promote();
282     if (soundDoseManager != nullptr) {
283         soundDoseManager->resetSoundDose();
284     }
285 }
286 
setOutputRs2UpperBound(float value)287 binder::Status SoundDoseManager::SoundDose::setOutputRs2UpperBound(float value) {
288     ALOGV("%s", __func__);
289     auto soundDoseManager = mSoundDoseManager.promote();
290     if (soundDoseManager != nullptr) {
291         soundDoseManager->setOutputRs2UpperBound(value);
292     }
293     return binder::Status::ok();
294 }
295 
resetCsd(float currentCsd,const std::vector<media::SoundDoseRecord> & records)296 binder::Status SoundDoseManager::SoundDose::resetCsd(
297         float currentCsd, const std::vector<media::SoundDoseRecord>& records) {
298     ALOGV("%s", __func__);
299     auto soundDoseManager = mSoundDoseManager.promote();
300     if (soundDoseManager != nullptr) {
301         soundDoseManager->resetCsd(currentCsd, records);
302     }
303     return binder::Status::ok();
304 }
305 
updateAttenuation(float attenuationDB,int device)306 binder::Status SoundDoseManager::SoundDose::updateAttenuation(float attenuationDB, int device) {
307     ALOGV("%s", __func__);
308     auto soundDoseManager = mSoundDoseManager.promote();
309     if (soundDoseManager != nullptr) {
310         soundDoseManager->updateAttenuation(attenuationDB, static_cast<audio_devices_t>(device));
311     }
312     return binder::Status::ok();
313 }
314 
setCsdEnabled(bool enabled)315 binder::Status SoundDoseManager::SoundDose::setCsdEnabled(bool enabled) {
316     ALOGV("%s", __func__);
317     auto soundDoseManager = mSoundDoseManager.promote();
318     if (soundDoseManager != nullptr) {
319         soundDoseManager->setCsdEnabled(enabled);
320     }
321     return binder::Status::ok();
322 }
323 
initCachedAudioDeviceCategories(const std::vector<media::ISoundDose::AudioDeviceCategory> & btDeviceCategories)324 binder::Status SoundDoseManager::SoundDose::initCachedAudioDeviceCategories(
325         const std::vector<media::ISoundDose::AudioDeviceCategory>& btDeviceCategories) {
326     ALOGV("%s", __func__);
327     auto soundDoseManager = mSoundDoseManager.promote();
328     if (soundDoseManager != nullptr) {
329         soundDoseManager->initCachedAudioDeviceCategories(btDeviceCategories);
330     }
331     return binder::Status::ok();
332 }
setAudioDeviceCategory(const media::ISoundDose::AudioDeviceCategory & btAudioDevice)333 binder::Status SoundDoseManager::SoundDose::setAudioDeviceCategory(
334         const media::ISoundDose::AudioDeviceCategory& btAudioDevice) {
335     ALOGV("%s", __func__);
336     auto soundDoseManager = mSoundDoseManager.promote();
337     if (soundDoseManager != nullptr) {
338         soundDoseManager->setAudioDeviceCategory(btAudioDevice);
339     }
340     return binder::Status::ok();
341 }
342 
getOutputRs2UpperBound(float * value)343 binder::Status SoundDoseManager::SoundDose::getOutputRs2UpperBound(float* value) {
344     ALOGV("%s", __func__);
345     auto soundDoseManager = mSoundDoseManager.promote();
346     if (soundDoseManager != nullptr) {
347         std::lock_guard _l(soundDoseManager->mLock);
348         *value = soundDoseManager->mRs2UpperBound;
349     }
350     return binder::Status::ok();
351 }
352 
getCsd(float * value)353 binder::Status SoundDoseManager::SoundDose::getCsd(float* value) {
354     ALOGV("%s", __func__);
355     auto soundDoseManager = mSoundDoseManager.promote();
356     if (soundDoseManager != nullptr) {
357         *value = soundDoseManager->mMelAggregator->getCsd();
358     }
359     return binder::Status::ok();
360 }
361 
forceUseFrameworkMel(bool useFrameworkMel)362 binder::Status SoundDoseManager::SoundDose::forceUseFrameworkMel(bool useFrameworkMel) {
363     ALOGV("%s", __func__);
364     auto soundDoseManager = mSoundDoseManager.promote();
365     if (soundDoseManager != nullptr) {
366         soundDoseManager->setUseFrameworkMel(useFrameworkMel);
367     }
368     return binder::Status::ok();
369 }
370 
forceComputeCsdOnAllDevices(bool computeCsdOnAllDevices)371 binder::Status SoundDoseManager::SoundDose::forceComputeCsdOnAllDevices(
372         bool computeCsdOnAllDevices) {
373     ALOGV("%s", __func__);
374     auto soundDoseManager = mSoundDoseManager.promote();
375     if (soundDoseManager != nullptr) {
376         soundDoseManager->setComputeCsdOnAllDevices(computeCsdOnAllDevices);
377     }
378     return binder::Status::ok();
379 }
380 
isSoundDoseHalSupported(bool * value)381 binder::Status SoundDoseManager::SoundDose::isSoundDoseHalSupported(bool* value) {
382     ALOGV("%s", __func__);
383     *value = false;
384     auto soundDoseManager = mSoundDoseManager.promote();
385     if (soundDoseManager != nullptr) {
386         *value = soundDoseManager->isSoundDoseHalSupported();
387     }
388     return binder::Status::ok();
389 }
390 
updateAttenuation(float attenuationDB,audio_devices_t deviceType)391 void SoundDoseManager::updateAttenuation(float attenuationDB, audio_devices_t deviceType) {
392     std::lock_guard _l(mLock);
393     ALOGV("%s: updating MEL processor attenuation for device type %d to %f",
394             __func__, deviceType, attenuationDB);
395     mMelAttenuationDB[deviceType] = attenuationDB;
396     for (const auto& mp : mActiveProcessors) {
397         auto melProcessor = mp.second.promote();
398         if (melProcessor != nullptr) {
399             auto deviceId = melProcessor->getDeviceId();
400             const auto deviceTypeIt = mActiveDeviceTypes.find(deviceId);
401             if (deviceTypeIt != mActiveDeviceTypes.end() &&
402                 deviceTypeIt->second == deviceType) {
403                 ALOGV("%s: set attenuation for deviceId %d to %f",
404                         __func__, deviceId, attenuationDB);
405                 melProcessor->setAttenuation(attenuationDB);
406             }
407         }
408     }
409 }
410 
setCsdEnabled(bool enabled)411 void SoundDoseManager::setCsdEnabled(bool enabled) {
412     ALOGV("%s",  __func__);
413 
414     std::lock_guard _l(mLock);
415     mEnabledCsd = enabled;
416 
417     for (auto& activeEntry : mActiveProcessors) {
418         auto melProcessor = activeEntry.second.promote();
419         if (melProcessor != nullptr) {
420             if (enabled) {
421                 melProcessor->resume();
422             } else {
423                 melProcessor->pause();
424             }
425         }
426     }
427 }
428 
isCsdEnabled()429 bool SoundDoseManager::isCsdEnabled() {
430     std::lock_guard _l(mLock);
431     return mEnabledCsd;
432 }
433 
initCachedAudioDeviceCategories(const std::vector<media::ISoundDose::AudioDeviceCategory> & deviceCategories)434 void SoundDoseManager::initCachedAudioDeviceCategories(
435         const std::vector<media::ISoundDose::AudioDeviceCategory>& deviceCategories) {
436     ALOGV("%s", __func__);
437     {
438         const std::lock_guard _l(mLock);
439         mBluetoothDevicesWithCsd.clear();
440     }
441     for (const auto& btDeviceCategory : deviceCategories) {
442         setAudioDeviceCategory(btDeviceCategory);
443     }
444 }
445 
setAudioDeviceCategory(const media::ISoundDose::AudioDeviceCategory & audioDevice)446 void SoundDoseManager::setAudioDeviceCategory(
447         const media::ISoundDose::AudioDeviceCategory& audioDevice) {
448     ALOGV("%s: set BT audio device type with address %s to headphone %d", __func__,
449           audioDevice.address.c_str(), audioDevice.csdCompatible);
450 
451     std::vector<audio_port_handle_t> devicesToStart;
452     std::vector<audio_port_handle_t> devicesToStop;
453     {
454         const std::lock_guard _l(mLock);
455         const auto deviceIt = mBluetoothDevicesWithCsd.find(
456                 std::make_pair(audioDevice.address,
457                                static_cast<audio_devices_t>(audioDevice.internalAudioType)));
458         if (deviceIt != mBluetoothDevicesWithCsd.end()) {
459             deviceIt->second = audioDevice.csdCompatible;
460         } else {
461             mBluetoothDevicesWithCsd.emplace(
462                     std::make_pair(audioDevice.address,
463                                    static_cast<audio_devices_t>(audioDevice.internalAudioType)),
464                     audioDevice.csdCompatible);
465         }
466 
467         for (const auto &activeDevice: mActiveDevices) {
468             if (activeDevice.first.address() == audioDevice.address &&
469                 activeDevice.first.mType ==
470                 static_cast<audio_devices_t>(audioDevice.internalAudioType)) {
471                 if (audioDevice.csdCompatible) {
472                     devicesToStart.push_back(activeDevice.second);
473                 } else {
474                     devicesToStop.push_back(activeDevice.second);
475                 }
476             }
477         }
478     }
479 
480     for (const auto& deviceToStart : devicesToStart) {
481         mMelReporterCallback->startMelComputationForDeviceId(deviceToStart);
482     }
483     for (const auto& deviceToStop : devicesToStop) {
484         mMelReporterCallback->stopMelComputationForDeviceId(deviceToStop);
485     }
486 }
487 
shouldComputeCsdForDeviceType(audio_devices_t device)488 bool SoundDoseManager::shouldComputeCsdForDeviceType(audio_devices_t device) {
489     if (!isCsdEnabled()) {
490         ALOGV("%s csd is disabled", __func__);
491         return false;
492     }
493     if (forceComputeCsdOnAllDevices()) {
494         return true;
495     }
496 
497     switch (device) {
498         case AUDIO_DEVICE_OUT_WIRED_HEADSET:
499         case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
500         case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
501         case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
502         case AUDIO_DEVICE_OUT_USB_HEADSET:
503         case AUDIO_DEVICE_OUT_BLE_HEADSET:
504         case AUDIO_DEVICE_OUT_BLE_BROADCAST:
505             return true;
506         default:
507             return false;
508     }
509 }
510 
shouldComputeCsdForDeviceWithAddress(const audio_devices_t type,const std::string & deviceAddress)511 bool SoundDoseManager::shouldComputeCsdForDeviceWithAddress(const audio_devices_t type,
512                                                             const std::string& deviceAddress) {
513     if (!isCsdEnabled()) {
514         ALOGV("%s csd is disabled", __func__);
515         return false;
516     }
517     if (forceComputeCsdOnAllDevices()) {
518         return true;
519     }
520 
521     if (!audio_is_ble_out_device(type) && !audio_is_a2dp_device(type)) {
522         return shouldComputeCsdForDeviceType(type);
523     }
524 
525     const std::lock_guard _l(mLock);
526     const auto deviceIt = mBluetoothDevicesWithCsd.find(std::make_pair(deviceAddress, type));
527     return deviceIt != mBluetoothDevicesWithCsd.end() && deviceIt->second;
528 }
529 
setUseFrameworkMel(bool useFrameworkMel)530 void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
531     // invalidate any HAL sound dose interface used
532     resetHalSoundDoseInterfaces();
533 
534     std::lock_guard _l(mLock);
535     mUseFrameworkMel = useFrameworkMel;
536 }
537 
forceUseFrameworkMel() const538 bool SoundDoseManager::forceUseFrameworkMel() const {
539     std::lock_guard _l(mLock);
540     return mUseFrameworkMel;
541 }
542 
setComputeCsdOnAllDevices(bool computeCsdOnAllDevices)543 void SoundDoseManager::setComputeCsdOnAllDevices(bool computeCsdOnAllDevices) {
544     std::lock_guard _l(mLock);
545     mComputeCsdOnAllDevices = computeCsdOnAllDevices;
546 }
547 
forceComputeCsdOnAllDevices() const548 bool SoundDoseManager::forceComputeCsdOnAllDevices() const {
549     std::lock_guard _l(mLock);
550     return mComputeCsdOnAllDevices;
551 }
552 
isSoundDoseHalSupported() const553 bool SoundDoseManager::isSoundDoseHalSupported() const {
554     if (!mEnabledCsd) {
555         return false;
556     }
557 
558     return useHalSoundDose();
559 }
560 
useHalSoundDose() const561 bool SoundDoseManager::useHalSoundDose() const {
562     const std::lock_guard _l(mLock);
563     return mHalSoundDose.size() > 0;
564 }
565 
resetSoundDose()566 void SoundDoseManager::resetSoundDose() {
567     std::lock_guard lock(mLock);
568     mSoundDose = nullptr;
569 }
570 
resetCsd(float currentCsd,const std::vector<media::SoundDoseRecord> & records)571 void SoundDoseManager::resetCsd(float currentCsd,
572                                 const std::vector<media::SoundDoseRecord>& records) {
573     std::lock_guard lock(mLock);
574     std::vector<audio_utils::CsdRecord> resetRecords;
575     for (const auto& record : records) {
576         resetRecords.emplace_back(record.timestamp, record.duration, record.value,
577                                   record.averageMel);
578     }
579 
580     mMelAggregator->reset(currentCsd, resetRecords);
581 }
582 
onNewMelValues(const std::vector<float> & mels,size_t offset,size_t length,audio_port_handle_t deviceId) const583 void SoundDoseManager::onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
584                                       audio_port_handle_t deviceId) const {
585     ALOGV("%s", __func__);
586 
587 
588     sp<media::ISoundDoseCallback> soundDoseCallback;
589     std::vector<audio_utils::CsdRecord> records;
590     float currentCsd;
591     {
592         std::lock_guard _l(mLock);
593         if (!mEnabledCsd) {
594             return;
595         }
596 
597 
598         int64_t timestampSec = getMonotonicSecond();
599 
600         // only for internal callbacks
601         records = mMelAggregator->aggregateAndAddNewMelRecord(audio_utils::MelRecord(
602                 deviceId, std::vector<float>(mels.begin() + offset, mels.begin() + offset + length),
603                 timestampSec - length));
604 
605         currentCsd = mMelAggregator->getCsd();
606     }
607 
608     soundDoseCallback = getSoundDoseCallback();
609 
610     if (records.size() > 0 && soundDoseCallback != nullptr) {
611         std::vector<media::SoundDoseRecord> newRecordsToReport;
612         for (const auto& record : records) {
613             newRecordsToReport.emplace_back(csdRecordToSoundDoseRecord(record));
614         }
615 
616         soundDoseCallback->onNewCsdValue(currentCsd, newRecordsToReport);
617     }
618 }
619 
getSoundDoseCallback() const620 sp<media::ISoundDoseCallback> SoundDoseManager::getSoundDoseCallback() const {
621     std::lock_guard _l(mLock);
622     if (mSoundDose == nullptr) {
623         return nullptr;
624     }
625 
626     return mSoundDose->mSoundDoseCallback;
627 }
628 
onMomentaryExposure(float currentMel,audio_port_handle_t deviceId) const629 void SoundDoseManager::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const {
630     ALOGV("%s: Momentary exposure for device %d triggered: %f MEL", __func__, deviceId, currentMel);
631 
632     {
633         std::lock_guard _l(mLock);
634         if (!mEnabledCsd) {
635             return;
636         }
637     }
638 
639     auto soundDoseCallback = getSoundDoseCallback();
640     if (soundDoseCallback != nullptr) {
641         soundDoseCallback->onMomentaryExposure(currentMel, deviceId);
642     }
643 }
644 
getSoundDoseInterface(const sp<media::ISoundDoseCallback> & callback)645 sp<media::ISoundDose> SoundDoseManager::getSoundDoseInterface(
646         const sp<media::ISoundDoseCallback>& callback) {
647     ALOGV("%s: Register ISoundDoseCallback", __func__);
648 
649     std::lock_guard _l(mLock);
650     if (mSoundDose == nullptr) {
651         mSoundDose = sp<SoundDose>::make(this, callback);
652     }
653     return mSoundDose;
654 }
655 
dump() const656 std::string SoundDoseManager::dump() const {
657     std::string output;
658     {
659         std::lock_guard _l(mLock);
660         if (!mEnabledCsd) {
661             base::StringAppendF(&output, "CSD is disabled");
662             return output;
663         }
664     }
665 
666     mMelAggregator->foreachCsd([&output](audio_utils::CsdRecord csdRecord) {
667         base::StringAppendF(&output,
668                             "CSD %f with average MEL %f in interval [%" PRId64 ", %" PRId64 "]",
669                             csdRecord.value, csdRecord.averageMel, csdRecord.timestamp,
670                             csdRecord.timestamp + csdRecord.duration);
671         base::StringAppendF(&output, "\n");
672     });
673 
674     base::StringAppendF(&output, "\nCached Mel Records:\n");
675     mMelAggregator->foreachCachedMel([&output](const audio_utils::MelRecord& melRecord) {
676         base::StringAppendF(&output, "Continuous MELs for portId=%d, ", melRecord.portId);
677         base::StringAppendF(&output, "starting at timestamp %" PRId64 ": ", melRecord.timestamp);
678 
679         for (const auto& mel : melRecord.mels) {
680             base::StringAppendF(&output, "%.2f ", mel);
681         }
682         base::StringAppendF(&output, "\n");
683     });
684 
685     return output;
686 }
687 
getCachedMelRecordsSize() const688 size_t SoundDoseManager::getCachedMelRecordsSize() const {
689     return mMelAggregator->getCachedMelRecordsSize();
690 }
691 
csdRecordToSoundDoseRecord(const audio_utils::CsdRecord & legacy)692 media::SoundDoseRecord SoundDoseManager::csdRecordToSoundDoseRecord(
693         const audio_utils::CsdRecord& legacy) {
694     media::SoundDoseRecord soundDoseRecord{};
695     soundDoseRecord.timestamp = legacy.timestamp;
696     soundDoseRecord.duration = legacy.duration;
697     soundDoseRecord.value = legacy.value;
698     soundDoseRecord.averageMel = legacy.averageMel;
699     return soundDoseRecord;
700 }
701 
702 }  // namespace android
703