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 <algorithm>
25 #include <android-base/stringprintf.h>
26 #include <cinttypes>
27 #include <ctime>
28 #include <functional>
29 #include <media/AidlConversionCppNdk.h>
30 #include <utils/Log.h>
31 
32 namespace android {
33 
34 using aidl::android::media::audio::common::AudioDevice;
35 
36 namespace {
37 
38 // Port handle used when CSD is computed on all devices. Should be a different value than
39 // AUDIO_PORT_HANDLE_NONE which is associated with a sound dose callback failure
40 constexpr audio_port_handle_t CSD_ON_ALL_DEVICES_PORT_HANDLE = -1;
41 
getMonotonicSecond()42 int64_t getMonotonicSecond() {
43     struct timespec now_ts;
44     if (clock_gettime(CLOCK_MONOTONIC, &now_ts) != 0) {
45         ALOGE("%s: cannot get timestamp", __func__);
46         return -1;
47     }
48     return now_ts.tv_sec;
49 }
50 
51 constexpr float kDefaultRs2LowerBound = 80.f;  // dBA
52 
53 }  // namespace
54 
getOrCreateProcessorForDevice(audio_port_handle_t deviceId,audio_io_handle_t streamHandle,uint32_t sampleRate,size_t channelCount,audio_format_t format)55 sp<audio_utils::MelProcessor> SoundDoseManager::getOrCreateProcessorForDevice(
56         audio_port_handle_t deviceId, audio_io_handle_t streamHandle, uint32_t sampleRate,
57         size_t channelCount, audio_format_t format) {
58     const std::lock_guard _l(mLock);
59 
60     if (!mUseFrameworkMel && mHalSoundDose.size() > 0 && mEnabledCsd) {
61         ALOGD("%s: using HAL MEL computation, no MelProcessor needed.", __func__);
62         return nullptr;
63     }
64 
65     auto streamProcessor = mActiveProcessors.find(streamHandle);
66     if (streamProcessor != mActiveProcessors.end()) {
67         auto processor = streamProcessor->second.promote();
68         // if processor is nullptr it means it was removed by the playback
69         // thread and can be replaced in the mActiveProcessors map
70         if (processor != nullptr) {
71             ALOGV("%s: found callback for stream id %d", __func__, streamHandle);
72             const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
73             if (activeTypeIt != mActiveDeviceTypes.end()) {
74                 processor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
75             }
76             processor->setDeviceId(deviceId);
77             processor->setOutputRs2UpperBound(mRs2UpperBound);
78             return processor;
79         }
80     }
81 
82     ALOGV("%s: creating new callback for stream id %d", __func__, streamHandle);
83     sp<audio_utils::MelProcessor> melProcessor = sp<audio_utils::MelProcessor>::make(
84             sampleRate, channelCount, format, this, deviceId, mRs2UpperBound);
85     const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
86     if (activeTypeIt != mActiveDeviceTypes.end()) {
87         melProcessor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
88     }
89     mActiveProcessors[streamHandle] = melProcessor;
90     return melProcessor;
91 }
92 
setHalSoundDoseInterface(const std::string & module,const std::shared_ptr<ISoundDose> & halSoundDose)93 bool SoundDoseManager::setHalSoundDoseInterface(const std::string &module,
94                                                 const std::shared_ptr<ISoundDose> &halSoundDose) {
95     ALOGV("%s", __func__);
96 
97     if (halSoundDose == nullptr) {
98         ALOGI("%s: passed ISoundDose object is null", __func__);
99         return false;
100     }
101 
102     std::shared_ptr<HalSoundDoseCallback> halSoundDoseCallback;
103     {
104         const std::lock_guard _l(mLock);
105 
106         if (mHalSoundDose.find(module) != mHalSoundDose.end()) {
107             ALOGW("%s: Module %s already has a sound dose HAL assigned, skipping", __func__,
108                   module.c_str());
109             return false;
110         }
111         mHalSoundDose[module] = halSoundDose;
112 
113         if (!halSoundDose->setOutputRs2UpperBound(mRs2UpperBound).isOk()) {
114             ALOGW("%s: Cannot set RS2 value for momentary exposure %f",
115                   __func__,
116                   mRs2UpperBound);
117         }
118 
119         // initialize the HAL sound dose callback lazily
120         if (mHalSoundDoseCallback == nullptr) {
121             mHalSoundDoseCallback =
122                 ndk::SharedRefBase::make<HalSoundDoseCallback>(this);
123         }
124         halSoundDoseCallback = mHalSoundDoseCallback;
125     }
126 
127     auto status = halSoundDose->registerSoundDoseCallback(halSoundDoseCallback);
128 
129     if (!status.isOk()) {
130         // Not a warning since this can happen if the callback was registered before
131         ALOGI("%s: Cannot register HAL sound dose callback with status message: %s",
132               __func__,
133               status.getMessage());
134     }
135 
136     return true;
137 }
138 
resetHalSoundDoseInterfaces()139 void SoundDoseManager::resetHalSoundDoseInterfaces() {
140     ALOGV("%s", __func__);
141 
142     const std::lock_guard _l(mLock);
143     mHalSoundDose.clear();
144 }
145 
setOutputRs2UpperBound(float rs2Value)146 void SoundDoseManager::setOutputRs2UpperBound(float rs2Value) {
147     ALOGV("%s", __func__);
148     const std::lock_guard _l(mLock);
149 
150     if (!mUseFrameworkMel && mHalSoundDose.size() > 0) {
151         bool success = true;
152         for (auto& halSoundDose : mHalSoundDose) {
153             // using the HAL sound dose interface
154             if (!halSoundDose.second->setOutputRs2UpperBound(rs2Value).isOk()) {
155                 ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
156                 success = false;
157                 break;
158             }
159         }
160 
161         if (success) {
162             mRs2UpperBound = rs2Value;
163         } else {
164             // restore all RS2 upper bounds to the previous value
165             for (auto& halSoundDose : mHalSoundDose) {
166                 halSoundDose.second->setOutputRs2UpperBound(mRs2UpperBound);
167             }
168         }
169         return;
170     }
171 
172     for (auto& streamProcessor : mActiveProcessors) {
173         const sp<audio_utils::MelProcessor> processor = streamProcessor.second.promote();
174         if (processor != nullptr) {
175             const status_t result = processor->setOutputRs2UpperBound(rs2Value);
176             if (result != NO_ERROR) {
177                 ALOGW("%s: could not set RS2 upper bound %f for stream %d", __func__, rs2Value,
178                       streamProcessor.first);
179                 return;
180             }
181             mRs2UpperBound = rs2Value;
182         }
183     }
184 }
185 
removeStreamProcessor(audio_io_handle_t streamHandle)186 void SoundDoseManager::removeStreamProcessor(audio_io_handle_t streamHandle) {
187     const std::lock_guard _l(mLock);
188     auto callbackToRemove = mActiveProcessors.find(streamHandle);
189     if (callbackToRemove != mActiveProcessors.end()) {
190         mActiveProcessors.erase(callbackToRemove);
191     }
192 }
193 
getAttenuationForDeviceId(audio_port_handle_t id) const194 float SoundDoseManager::getAttenuationForDeviceId(audio_port_handle_t id) const {
195     float attenuation = 0.f;
196 
197     const std::lock_guard _l(mLock);
198     const auto deviceTypeIt = mActiveDeviceTypes.find(id);
199     if (deviceTypeIt != mActiveDeviceTypes.end()) {
200         auto attenuationIt = mMelAttenuationDB.find(deviceTypeIt->second);
201         if (attenuationIt != mMelAttenuationDB.end()) {
202             attenuation = attenuationIt->second;
203         }
204     }
205 
206     return attenuation;
207 }
208 
getIdForAudioDevice(const AudioDevice & audioDevice) const209 audio_port_handle_t SoundDoseManager::getIdForAudioDevice(const AudioDevice& audioDevice) const {
210     if (isComputeCsdForcedOnAllDevices()) {
211         // If CSD is forced on all devices return random port id. Used only in testing.
212         // This is necessary since the patches that are registered before
213         // setComputeCsdOnAllDevices will not be contributing to mActiveDevices
214         return CSD_ON_ALL_DEVICES_PORT_HANDLE;
215     }
216 
217     const std::lock_guard _l(mLock);
218 
219     audio_devices_t type;
220     std::string address;
221     auto result = aidl::android::aidl2legacy_AudioDevice_audio_device(
222             audioDevice, &type, &address);
223     if (result != NO_ERROR) {
224         ALOGE("%s: could not convert from AudioDevice to AudioDeviceTypeAddr", __func__);
225         return AUDIO_PORT_HANDLE_NONE;
226     }
227 
228     auto adt = AudioDeviceTypeAddr(type, address);
229     auto deviceIt = mActiveDevices.find(adt);
230     if (deviceIt == mActiveDevices.end()) {
231         ALOGI("%s: could not find port id for device %s", __func__, adt.toString().c_str());
232         return AUDIO_PORT_HANDLE_NONE;
233     }
234 
235     if (audio_is_ble_out_device(type) || audio_is_a2dp_device(type)) {
236         const auto btDeviceIt = mBluetoothDevicesWithCsd.find(std::make_pair(address, type));
237         if (btDeviceIt == mBluetoothDevicesWithCsd.end() || !btDeviceIt->second) {
238             ALOGI("%s: bt device %s does not support sound dose", __func__,
239                   adt.toString().c_str());
240             return AUDIO_PORT_HANDLE_NONE;
241         }
242     }
243     return deviceIt->second;
244 }
245 
mapAddressToDeviceId(const AudioDeviceTypeAddr & adt,const audio_port_handle_t deviceId)246 void SoundDoseManager::mapAddressToDeviceId(const AudioDeviceTypeAddr& adt,
247                                             const audio_port_handle_t deviceId) {
248     const std::lock_guard _l(mLock);
249     ALOGI("%s: map address: %d to device id: %d", __func__, adt.mType, deviceId);
250     mActiveDevices[adt] = deviceId;
251     mActiveDeviceTypes[deviceId] = adt.mType;
252 }
253 
clearMapDeviceIdEntries(audio_port_handle_t deviceId)254 void SoundDoseManager::clearMapDeviceIdEntries(audio_port_handle_t deviceId) {
255     const std::lock_guard _l(mLock);
256     for (auto activeDevice = mActiveDevices.begin(); activeDevice != mActiveDevices.end();) {
257         if (activeDevice->second == deviceId) {
258             ALOGI("%s: clear mapping type: %d to deviceId: %d",
259                   __func__, activeDevice->first.mType, deviceId);
260             activeDevice = mActiveDevices.erase(activeDevice);
261             continue;
262         }
263         ++activeDevice;
264     }
265     mActiveDeviceTypes.erase(deviceId);
266 }
267 
onMomentaryExposureWarning(float in_currentDbA,const AudioDevice & in_audioDevice)268 ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
269         float in_currentDbA, const AudioDevice& in_audioDevice) {
270     sp<SoundDoseManager> soundDoseManager;
271     {
272         const std::lock_guard _l(mCbLock);
273         soundDoseManager = mSoundDoseManager.promote();
274         if (soundDoseManager == nullptr) {
275             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
276         }
277     }
278 
279     if (!soundDoseManager->useHalSoundDose()) {
280         ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
281         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
282     }
283 
284     auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
285     if (id == AUDIO_PORT_HANDLE_NONE) {
286         ALOGI("%s: no mapped id for audio device with type %d and address %s",
287                 __func__, static_cast<int>(in_audioDevice.type.type),
288                 in_audioDevice.address.toString().c_str());
289         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
290     }
291 
292     float attenuation = soundDoseManager->getAttenuationForDeviceId(id);
293     ALOGV("%s: attenuating received momentary exposure with %f dB", __func__, attenuation);
294     // TODO: remove attenuation when enforcing HAL MELs to always be attenuated
295     soundDoseManager->onMomentaryExposure(in_currentDbA - attenuation, id);
296 
297     return ndk::ScopedAStatus::ok();
298 }
299 
onNewMelValues(const ISoundDose::IHalSoundDoseCallback::MelRecord & in_melRecord,const AudioDevice & in_audioDevice)300 ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onNewMelValues(
301         const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
302         const AudioDevice& in_audioDevice) {
303     sp<SoundDoseManager> soundDoseManager;
304     {
305         const std::lock_guard _l(mCbLock);
306         soundDoseManager = mSoundDoseManager.promote();
307         if (soundDoseManager == nullptr) {
308             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
309         }
310     }
311 
312     if (!soundDoseManager->useHalSoundDose()) {
313         ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
314         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
315     }
316 
317     auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
318     if (id == AUDIO_PORT_HANDLE_NONE) {
319         ALOGI("%s: no mapped id for audio device with type %d and address %s",
320                 __func__, static_cast<int>(in_audioDevice.type.type),
321                 in_audioDevice.address.toString().c_str());
322         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
323     }
324 
325     // TODO: introduce timestamp in onNewMelValues callback
326     soundDoseManager->onNewMelValues(in_melRecord.melValues, 0, in_melRecord.melValues.size(),
327                                      id, /*attenuated=*/false);
328 
329     return ndk::ScopedAStatus::ok();
330 }
331 
binderDied(__unused const wp<IBinder> & who)332 void SoundDoseManager::SoundDose::binderDied(__unused const wp<IBinder>& who) {
333     ALOGV("%s", __func__);
334 
335     auto soundDoseManager = mSoundDoseManager.promote();
336     if (soundDoseManager != nullptr) {
337         soundDoseManager->resetSoundDose();
338     }
339 }
340 
setOutputRs2UpperBound(float value)341 binder::Status SoundDoseManager::SoundDose::setOutputRs2UpperBound(float value) {
342     ALOGV("%s", __func__);
343     auto soundDoseManager = mSoundDoseManager.promote();
344     if (soundDoseManager != nullptr) {
345         soundDoseManager->setOutputRs2UpperBound(value);
346     }
347     return binder::Status::ok();
348 }
349 
resetCsd(float currentCsd,const std::vector<media::SoundDoseRecord> & records)350 binder::Status SoundDoseManager::SoundDose::resetCsd(
351         float currentCsd, const std::vector<media::SoundDoseRecord>& records) {
352     ALOGV("%s", __func__);
353     auto soundDoseManager = mSoundDoseManager.promote();
354     if (soundDoseManager != nullptr) {
355         soundDoseManager->resetCsd(currentCsd, records);
356     }
357     return binder::Status::ok();
358 }
359 
updateAttenuation(float attenuationDB,int device)360 binder::Status SoundDoseManager::SoundDose::updateAttenuation(float attenuationDB, int device) {
361     ALOGV("%s", __func__);
362     auto soundDoseManager = mSoundDoseManager.promote();
363     if (soundDoseManager != nullptr) {
364         soundDoseManager->updateAttenuation(attenuationDB, static_cast<audio_devices_t>(device));
365     }
366     return binder::Status::ok();
367 }
368 
setCsdEnabled(bool enabled)369 binder::Status SoundDoseManager::SoundDose::setCsdEnabled(bool enabled) {
370     ALOGV("%s", __func__);
371     auto soundDoseManager = mSoundDoseManager.promote();
372     if (soundDoseManager != nullptr) {
373         soundDoseManager->setCsdEnabled(enabled);
374     }
375     return binder::Status::ok();
376 }
377 
initCachedAudioDeviceCategories(const std::vector<media::ISoundDose::AudioDeviceCategory> & btDeviceCategories)378 binder::Status SoundDoseManager::SoundDose::initCachedAudioDeviceCategories(
379         const std::vector<media::ISoundDose::AudioDeviceCategory>& btDeviceCategories) {
380     ALOGV("%s", __func__);
381     auto soundDoseManager = mSoundDoseManager.promote();
382     if (soundDoseManager != nullptr) {
383         soundDoseManager->initCachedAudioDeviceCategories(btDeviceCategories);
384     }
385     return binder::Status::ok();
386 }
setAudioDeviceCategory(const media::ISoundDose::AudioDeviceCategory & btAudioDevice)387 binder::Status SoundDoseManager::SoundDose::setAudioDeviceCategory(
388         const media::ISoundDose::AudioDeviceCategory& btAudioDevice) {
389     ALOGV("%s", __func__);
390     auto soundDoseManager = mSoundDoseManager.promote();
391     if (soundDoseManager != nullptr) {
392         soundDoseManager->setAudioDeviceCategory(btAudioDevice);
393     }
394     return binder::Status::ok();
395 }
396 
getOutputRs2UpperBound(float * value)397 binder::Status SoundDoseManager::SoundDose::getOutputRs2UpperBound(float* value) {
398     ALOGV("%s", __func__);
399     auto soundDoseManager = mSoundDoseManager.promote();
400     if (soundDoseManager != nullptr) {
401         const std::lock_guard _l(soundDoseManager->mLock);
402         *value = soundDoseManager->mRs2UpperBound;
403     }
404     return binder::Status::ok();
405 }
406 
getCsd(float * value)407 binder::Status SoundDoseManager::SoundDose::getCsd(float* value) {
408     ALOGV("%s", __func__);
409     auto soundDoseManager = mSoundDoseManager.promote();
410     if (soundDoseManager != nullptr) {
411         *value = soundDoseManager->mMelAggregator->getCsd();
412     }
413     return binder::Status::ok();
414 }
415 
forceUseFrameworkMel(bool useFrameworkMel)416 binder::Status SoundDoseManager::SoundDose::forceUseFrameworkMel(bool useFrameworkMel) {
417     ALOGV("%s", __func__);
418     auto soundDoseManager = mSoundDoseManager.promote();
419     if (soundDoseManager != nullptr) {
420         soundDoseManager->setUseFrameworkMel(useFrameworkMel);
421     }
422     return binder::Status::ok();
423 }
424 
forceComputeCsdOnAllDevices(bool computeCsdOnAllDevices)425 binder::Status SoundDoseManager::SoundDose::forceComputeCsdOnAllDevices(
426         bool computeCsdOnAllDevices) {
427     ALOGV("%s", __func__);
428     auto soundDoseManager = mSoundDoseManager.promote();
429     if (soundDoseManager != nullptr) {
430         soundDoseManager->setComputeCsdOnAllDevices(computeCsdOnAllDevices);
431     }
432     return binder::Status::ok();
433 }
434 
isSoundDoseHalSupported(bool * value)435 binder::Status SoundDoseManager::SoundDose::isSoundDoseHalSupported(bool* value) {
436     ALOGV("%s", __func__);
437     *value = false;
438     auto soundDoseManager = mSoundDoseManager.promote();
439     if (soundDoseManager != nullptr) {
440         *value = soundDoseManager->isSoundDoseHalSupported();
441     }
442     return binder::Status::ok();
443 }
444 
updateAttenuation(float attenuationDB,audio_devices_t deviceType)445 void SoundDoseManager::updateAttenuation(float attenuationDB, audio_devices_t deviceType) {
446     const std::lock_guard _l(mLock);
447     ALOGV("%s: updating MEL processor attenuation for device type %d to %f",
448             __func__, deviceType, attenuationDB);
449     mMelAttenuationDB[deviceType] = attenuationDB;
450     for (const auto& mp : mActiveProcessors) {
451         auto melProcessor = mp.second.promote();
452         if (melProcessor != nullptr) {
453             auto deviceId = melProcessor->getDeviceId();
454             const auto deviceTypeIt = mActiveDeviceTypes.find(deviceId);
455             if (deviceTypeIt != mActiveDeviceTypes.end() &&
456                 deviceTypeIt->second == deviceType) {
457                 ALOGV("%s: set attenuation for deviceId %d to %f",
458                         __func__, deviceId, attenuationDB);
459                 melProcessor->setAttenuation(attenuationDB);
460             }
461         }
462     }
463 }
464 
setCsdEnabled(bool enabled)465 void SoundDoseManager::setCsdEnabled(bool enabled) {
466     ALOGV("%s",  __func__);
467 
468     const std::lock_guard _l(mLock);
469     mEnabledCsd = enabled;
470 
471     for (auto& activeEntry : mActiveProcessors) {
472         auto melProcessor = activeEntry.second.promote();
473         if (melProcessor != nullptr) {
474             if (enabled) {
475                 melProcessor->resume();
476             } else {
477                 melProcessor->pause();
478             }
479         }
480     }
481 }
482 
isCsdEnabled()483 bool SoundDoseManager::isCsdEnabled() {
484     const std::lock_guard _l(mLock);
485     return mEnabledCsd;
486 }
487 
initCachedAudioDeviceCategories(const std::vector<media::ISoundDose::AudioDeviceCategory> & deviceCategories)488 void SoundDoseManager::initCachedAudioDeviceCategories(
489         const std::vector<media::ISoundDose::AudioDeviceCategory>& deviceCategories) {
490     ALOGV("%s", __func__);
491     {
492         const std::lock_guard _l(mLock);
493         mBluetoothDevicesWithCsd.clear();
494     }
495     for (const auto& btDeviceCategory : deviceCategories) {
496         setAudioDeviceCategory(btDeviceCategory);
497     }
498 }
499 
setAudioDeviceCategory(const media::ISoundDose::AudioDeviceCategory & audioDevice)500 void SoundDoseManager::setAudioDeviceCategory(
501         const media::ISoundDose::AudioDeviceCategory& audioDevice) {
502     ALOGV("%s: set BT audio device type with address %s to headphone %d", __func__,
503           audioDevice.address.c_str(), audioDevice.csdCompatible);
504 
505     std::vector<audio_port_handle_t> devicesToStart;
506     std::vector<audio_port_handle_t> devicesToStop;
507     {
508         const std::lock_guard _l(mLock);
509         const auto deviceIt = mBluetoothDevicesWithCsd.find(
510                 std::make_pair(audioDevice.address,
511                                static_cast<audio_devices_t>(audioDevice.internalAudioType)));
512         if (deviceIt != mBluetoothDevicesWithCsd.end()) {
513             deviceIt->second = audioDevice.csdCompatible;
514         } else {
515             mBluetoothDevicesWithCsd.emplace(
516                     std::make_pair(audioDevice.address,
517                                    static_cast<audio_devices_t>(audioDevice.internalAudioType)),
518                     audioDevice.csdCompatible);
519         }
520 
521         for (const auto &activeDevice: mActiveDevices) {
522             if (activeDevice.first.address() == audioDevice.address &&
523                 activeDevice.first.mType ==
524                 static_cast<audio_devices_t>(audioDevice.internalAudioType)) {
525                 if (audioDevice.csdCompatible) {
526                     devicesToStart.push_back(activeDevice.second);
527                 } else {
528                     devicesToStop.push_back(activeDevice.second);
529                 }
530             }
531         }
532     }
533 
534     for (const auto& deviceToStart : devicesToStart) {
535         mMelReporterCallback->startMelComputationForDeviceId(deviceToStart);
536     }
537     for (const auto& deviceToStop : devicesToStop) {
538         mMelReporterCallback->stopMelComputationForDeviceId(deviceToStop);
539     }
540 }
541 
shouldComputeCsdForDeviceType(audio_devices_t device)542 bool SoundDoseManager::shouldComputeCsdForDeviceType(audio_devices_t device) {
543     if (!isCsdEnabled()) {
544         ALOGV("%s csd is disabled", __func__);
545         return false;
546     }
547     if (isComputeCsdForcedOnAllDevices()) {
548         return true;
549     }
550 
551     switch (device) {
552         case AUDIO_DEVICE_OUT_WIRED_HEADSET:
553         case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
554         case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
555         case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
556         case AUDIO_DEVICE_OUT_USB_HEADSET:
557         case AUDIO_DEVICE_OUT_BLE_HEADSET:
558         case AUDIO_DEVICE_OUT_BLE_BROADCAST:
559             return true;
560         default:
561             return false;
562     }
563 }
564 
shouldComputeCsdForDeviceWithAddress(const audio_devices_t type,const std::string & deviceAddress)565 bool SoundDoseManager::shouldComputeCsdForDeviceWithAddress(const audio_devices_t type,
566                                                             const std::string& deviceAddress) {
567     if (!isCsdEnabled()) {
568         ALOGV("%s csd is disabled", __func__);
569         return false;
570     }
571     if (isComputeCsdForcedOnAllDevices()) {
572         return true;
573     }
574 
575     if (!audio_is_ble_out_device(type) && !audio_is_a2dp_device(type)) {
576         return shouldComputeCsdForDeviceType(type);
577     }
578 
579     const std::lock_guard _l(mLock);
580     const auto deviceIt = mBluetoothDevicesWithCsd.find(std::make_pair(deviceAddress, type));
581     return deviceIt != mBluetoothDevicesWithCsd.end() && deviceIt->second;
582 }
583 
setUseFrameworkMel(bool useFrameworkMel)584 void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
585     const std::lock_guard _l(mLock);
586     mUseFrameworkMel = useFrameworkMel;
587 }
588 
isFrameworkMelForced() const589 bool SoundDoseManager::isFrameworkMelForced() const {
590     const std::lock_guard _l(mLock);
591     return mUseFrameworkMel;
592 }
593 
setComputeCsdOnAllDevices(bool computeCsdOnAllDevices)594 void SoundDoseManager::setComputeCsdOnAllDevices(bool computeCsdOnAllDevices) {
595     bool changed = false;
596     {
597         const std::lock_guard _l(mLock);
598         if (mHalSoundDose.size() != 0) {
599             // when using the HAL path we cannot enforce to deliver values for all devices
600             changed = mUseFrameworkMel != computeCsdOnAllDevices;
601             mUseFrameworkMel = computeCsdOnAllDevices;
602         }
603         mComputeCsdOnAllDevices = computeCsdOnAllDevices;
604     }
605     if (changed && computeCsdOnAllDevices) {
606         mMelReporterCallback->applyAllAudioPatches();
607     }
608 }
609 
isComputeCsdForcedOnAllDevices() const610 bool SoundDoseManager::isComputeCsdForcedOnAllDevices() const {
611     const std::lock_guard _l(mLock);
612     return mComputeCsdOnAllDevices;
613 }
614 
isSoundDoseHalSupported() const615 bool SoundDoseManager::isSoundDoseHalSupported() const {
616     {
617         const std::lock_guard _l(mLock);
618         if (!mEnabledCsd) return false;
619     }
620 
621     return useHalSoundDose();
622 }
623 
useHalSoundDose() const624 bool SoundDoseManager::useHalSoundDose() const {
625     const std::lock_guard _l(mLock);
626     return !mUseFrameworkMel && mHalSoundDose.size() > 0;
627 }
628 
resetSoundDose()629 void SoundDoseManager::resetSoundDose() {
630     const std::lock_guard lock(mLock);
631     mSoundDose = nullptr;
632 }
633 
resetCsd(float currentCsd,const std::vector<media::SoundDoseRecord> & records)634 void SoundDoseManager::resetCsd(float currentCsd,
635                                 const std::vector<media::SoundDoseRecord>& records) {
636     const std::lock_guard lock(mLock);
637     std::vector<audio_utils::CsdRecord> resetRecords;
638     resetRecords.reserve(records.size());
639     for (const auto& record : records) {
640         resetRecords.emplace_back(record.timestamp, record.duration, record.value,
641                                   record.averageMel);
642     }
643 
644     mMelAggregator->reset(currentCsd, resetRecords);
645 }
646 
onNewMelValues(const std::vector<float> & mels,size_t offset,size_t length,audio_port_handle_t deviceId,bool attenuated) const647 void SoundDoseManager::onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
648                                       audio_port_handle_t deviceId, bool attenuated) const {
649     ALOGV("%s", __func__);
650 
651     sp<media::ISoundDoseCallback> soundDoseCallback;
652     std::vector<audio_utils::CsdRecord> records;
653     float currentCsd;
654 
655     // TODO: delete this case when enforcing HAL MELs to always be attenuated
656     float attenuation = attenuated ? 0.0f : getAttenuationForDeviceId(deviceId);
657 
658     {
659         const std::lock_guard _l(mLock);
660         if (!mEnabledCsd) {
661             return;
662         }
663 
664         const int64_t timestampSec = getMonotonicSecond();
665 
666         if (attenuated) {
667             records = mMelAggregator->aggregateAndAddNewMelRecord(audio_utils::MelRecord(
668                     deviceId,
669                     std::vector<float>(mels.begin() + offset, mels.begin() + offset + length),
670                     timestampSec - length));
671         } else {
672             ALOGV("%s: attenuating received values with %f dB", __func__, attenuation);
673 
674             // Extracting all intervals that contain values >= RS2 low limit (80dBA) after the
675             // attenuation is applied
676             size_t start = offset;
677             size_t stop = offset;
678             for (; stop < mels.size() && stop < offset + length; ++stop) {
679                 if (mels[stop] - attenuation < kDefaultRs2LowerBound) {
680                     if (start < stop) {
681                         std::vector<float> attMel(stop-start, -attenuation);
682                         // attMel[i] = mels[i] + attenuation, i in [start, stop)
683                         std::transform(mels.begin() + start, mels.begin() + stop, attMel.begin(),
684                                        attMel.begin(), std::plus<float>());
685                         std::vector<audio_utils::CsdRecord> newRec =
686                                 mMelAggregator->aggregateAndAddNewMelRecord(
687                                         audio_utils::MelRecord(deviceId,
688                                                                attMel,
689                                                                timestampSec - length + start -
690                                                                offset));
691                         std::copy(newRec.begin(), newRec.end(), std::back_inserter(records));
692                     }
693                     start = stop+1;
694                 }
695             }
696             if (start < stop) {
697                 std::vector<float> attMel(stop-start, -attenuation);
698                 // attMel[i] = mels[i] + attenuation, i in [start, stop)
699                 std::transform(mels.begin() + start, mels.begin() + stop, attMel.begin(),
700                                attMel.begin(), std::plus<float>());
701                 std::vector<audio_utils::CsdRecord> newRec =
702                         mMelAggregator->aggregateAndAddNewMelRecord(
703                                 audio_utils::MelRecord(deviceId,
704                                                        attMel,
705                                                        timestampSec - length + start -
706                                                        offset));
707                 std::copy(newRec.begin(), newRec.end(), std::back_inserter(records));
708             }
709         }
710 
711         currentCsd = mMelAggregator->getCsd();
712     }
713 
714     soundDoseCallback = getSoundDoseCallback();
715 
716     if (records.size() > 0 && soundDoseCallback != nullptr) {
717         std::vector<media::SoundDoseRecord> newRecordsToReport;
718         newRecordsToReport.resize(records.size());
719         for (const auto& record : records) {
720             newRecordsToReport.emplace_back(csdRecordToSoundDoseRecord(record));
721         }
722 
723         soundDoseCallback->onNewCsdValue(currentCsd, newRecordsToReport);
724     }
725 }
726 
getSoundDoseCallback() const727 sp<media::ISoundDoseCallback> SoundDoseManager::getSoundDoseCallback() const {
728     const std::lock_guard _l(mLock);
729     if (mSoundDose == nullptr) {
730         return nullptr;
731     }
732 
733     return mSoundDose->mSoundDoseCallback;
734 }
735 
onMomentaryExposure(float currentMel,audio_port_handle_t deviceId) const736 void SoundDoseManager::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const {
737     ALOGV("%s: Momentary exposure for device %d triggered: %f MEL", __func__, deviceId, currentMel);
738 
739     {
740         const std::lock_guard _l(mLock);
741         if (!mEnabledCsd) {
742             return;
743         }
744 
745         if (currentMel < mRs2UpperBound) {
746             return;
747         }
748     }
749 
750     auto soundDoseCallback = getSoundDoseCallback();
751     if (soundDoseCallback != nullptr) {
752         soundDoseCallback->onMomentaryExposure(currentMel, deviceId);
753     }
754 }
755 
resetReferencesForTest()756 void SoundDoseManager::resetReferencesForTest() {
757     mMelReporterCallback.clear();
758 }
759 
getSoundDoseInterface(const sp<media::ISoundDoseCallback> & callback)760 sp<media::ISoundDose> SoundDoseManager::getSoundDoseInterface(
761         const sp<media::ISoundDoseCallback>& callback) {
762     ALOGV("%s: Register ISoundDoseCallback", __func__);
763 
764     const std::lock_guard _l(mLock);
765     if (mSoundDose == nullptr) {
766         mSoundDose = sp<SoundDose>::make(this, callback);
767     }
768     return mSoundDose;
769 }
770 
dump() const771 std::string SoundDoseManager::dump() const {
772     std::string output;
773     {
774         const std::lock_guard _l(mLock);
775         if (!mEnabledCsd) {
776             base::StringAppendF(&output, "CSD is disabled");
777             return output;
778         }
779     }
780 
781     mMelAggregator->foreachCsd([&output](audio_utils::CsdRecord csdRecord) {
782         base::StringAppendF(&output,
783                             "CSD %f with average MEL %f in interval [%" PRId64 ", %" PRId64 "]",
784                             csdRecord.value, csdRecord.averageMel, csdRecord.timestamp,
785                             csdRecord.timestamp + csdRecord.duration);
786         base::StringAppendF(&output, "\n");
787     });
788 
789     base::StringAppendF(&output, "\nCached Mel Records:\n");
790     mMelAggregator->foreachCachedMel([&output](const audio_utils::MelRecord& melRecord) {
791         base::StringAppendF(&output, "Continuous MELs for portId=%d, ", melRecord.portId);
792         base::StringAppendF(&output, "starting at timestamp %" PRId64 ": ", melRecord.timestamp);
793 
794         for (const auto& mel : melRecord.mels) {
795             base::StringAppendF(&output, "%.2f ", mel);
796         }
797         base::StringAppendF(&output, "\n");
798     });
799 
800     return output;
801 }
802 
getCachedMelRecordsSize() const803 size_t SoundDoseManager::getCachedMelRecordsSize() const {
804     return mMelAggregator->getCachedMelRecordsSize();
805 }
806 
csdRecordToSoundDoseRecord(const audio_utils::CsdRecord & legacy)807 media::SoundDoseRecord SoundDoseManager::csdRecordToSoundDoseRecord(
808         const audio_utils::CsdRecord& legacy) {
809     media::SoundDoseRecord soundDoseRecord{};
810     soundDoseRecord.timestamp = legacy.timestamp;
811     soundDoseRecord.duration = legacy.duration;
812     soundDoseRecord.value = legacy.value;
813     soundDoseRecord.averageMel = legacy.averageMel;
814     return soundDoseRecord;
815 }
816 
817 }  // namespace android
818