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