• 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 <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