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 #pragma once 19 20 #include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h> 21 #include <aidl/android/media/audio/common/AudioDevice.h> 22 #include <android/media/BnSoundDose.h> 23 #include <android/media/ISoundDoseCallback.h> 24 #include <media/AudioDeviceTypeAddr.h> 25 #include <audio_utils/MelAggregator.h> 26 #include <audio_utils/MelProcessor.h> 27 #include <binder/Status.h> 28 #include <mutex> 29 #include <unordered_map> 30 31 namespace android { 32 33 using aidl::android::hardware::audio::core::sounddose::ISoundDose; 34 35 class IMelReporterCallback : public virtual RefBase { 36 public: IMelReporterCallback()37 IMelReporterCallback() {}; ~IMelReporterCallback()38 virtual ~IMelReporterCallback() {}; 39 40 virtual void stopMelComputationForDeviceId(audio_port_handle_t deviceId) = 0; 41 virtual void startMelComputationForDeviceId(audio_port_handle_t deviceId) = 0; 42 43 virtual void applyAllAudioPatches() = 0; 44 }; 45 46 class SoundDoseManager : public audio_utils::MelProcessor::MelCallback { 47 public: 48 /** CSD is computed with a rolling window of 7 days. */ 49 static constexpr int64_t kCsdWindowSeconds = 604800; // 60s * 60m * 24h * 7d 50 /** Default RS2 upper bound in dBA as defined in IEC 62368-1 3rd edition. */ 51 static constexpr float kDefaultRs2UpperBound = 100.f; 52 SoundDoseManager(const sp<IMelReporterCallback> & melReporterCallback)53 explicit SoundDoseManager(const sp<IMelReporterCallback>& melReporterCallback) 54 : mMelReporterCallback(melReporterCallback), 55 mMelAggregator(sp<audio_utils::MelAggregator>::make(kCsdWindowSeconds)), 56 mRs2UpperBound(kDefaultRs2UpperBound) {}; 57 58 // Used only for testing SoundDoseManager(const sp<IMelReporterCallback> & melReporterCallback,const sp<audio_utils::MelAggregator> & melAggregator)59 SoundDoseManager(const sp<IMelReporterCallback>& melReporterCallback, 60 const sp<audio_utils::MelAggregator>& melAggregator) 61 : mMelReporterCallback(melReporterCallback), 62 mMelAggregator(melAggregator), 63 mRs2UpperBound(kDefaultRs2UpperBound) {}; 64 65 /** 66 * \brief Creates or gets the MelProcessor assigned to the streamHandle 67 * 68 * \param deviceId id for the devices where the stream is active. 69 * \param streamHandle handle to the stream 70 * \param sampleRate sample rate for the processor 71 * \param channelCount number of channels to be processed. 72 * \param format format of the input samples. 73 * 74 * \return MelProcessor assigned to the stream and device id. 75 */ 76 sp<audio_utils::MelProcessor> getOrCreateProcessorForDevice(audio_port_handle_t deviceId, 77 audio_io_handle_t streamHandle, 78 uint32_t sampleRate, 79 size_t channelCount, 80 audio_format_t format); 81 82 /** 83 * \brief Removes stream processor when MEL computation is not needed anymore 84 * 85 * \param streamHandle handle to the stream 86 */ 87 void removeStreamProcessor(audio_io_handle_t streamHandle); 88 89 /** 90 * Sets the output RS2 upper bound for momentary exposure warnings. Must not be 91 * higher than 100dBA and not lower than 80dBA. 92 * 93 * \param rs2Value value to use for momentary exposure 94 */ 95 void setOutputRs2UpperBound(float rs2Value); 96 97 /** 98 * \brief Registers the interface for passing callbacks to the AudioService and gets 99 * the ISoundDose interface. 100 * 101 * \returns the sound dose binder to send commands to the SoundDoseManager 102 **/ 103 sp<media::ISoundDose> getSoundDoseInterface(const sp<media::ISoundDoseCallback>& callback); 104 105 /** 106 * Sets the HAL sound dose interface for a specific module to use for the MEL computation. 107 * 108 * @return true if setting the HAL sound dose value was successful, false otherwise. 109 */ 110 bool setHalSoundDoseInterface(const std::string &module, 111 const std::shared_ptr<ISoundDose> &halSoundDose); 112 113 /** Reset all the stored HAL sound dose interface. */ 114 void resetHalSoundDoseInterfaces(); 115 116 /** Returns the cached audio port id from the active devices. */ 117 audio_port_handle_t getIdForAudioDevice( 118 const aidl::android::media::audio::common::AudioDevice& audioDevice) const; 119 120 /** Caches mapping between address, device port id and device type. */ 121 void mapAddressToDeviceId(const AudioDeviceTypeAddr& adt, const audio_port_handle_t deviceId); 122 123 /** Clear all map entries with passed audio_port_handle_t. */ 124 void clearMapDeviceIdEntries(audio_port_handle_t deviceId); 125 126 /** Returns true if CSD is enabled. */ 127 bool isCsdEnabled(); 128 129 void initCachedAudioDeviceCategories( 130 const std::vector<media::ISoundDose::AudioDeviceCategory>& deviceCategories); 131 132 void setAudioDeviceCategory( 133 const media::ISoundDose::AudioDeviceCategory& audioDevice); 134 135 /** 136 * Returns true if the type can compute CSD. For bluetooth devices we rely on whether we 137 * categorized the address as headphones/headsets, only in this case we return true. 138 */ 139 bool shouldComputeCsdForDeviceWithAddress(const audio_devices_t type, 140 const std::string& deviceAddress); 141 /** Returns true for all device types which could support CSD computation. */ 142 bool shouldComputeCsdForDeviceType(audio_devices_t device); 143 144 std::string dump() const; 145 146 // used for testing only 147 size_t getCachedMelRecordsSize() const; 148 bool isFrameworkMelForced() const; 149 bool isComputeCsdForcedOnAllDevices() const; 150 151 /** Method for converting from audio_utils::CsdRecord to media::SoundDoseRecord. */ 152 static media::SoundDoseRecord csdRecordToSoundDoseRecord(const audio_utils::CsdRecord& legacy); 153 154 // ------ Override audio_utils::MelProcessor::MelCallback ------ 155 void onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length, 156 audio_port_handle_t deviceId, bool attenuated) const override; 157 158 void onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const override; 159 160 void resetReferencesForTest(); 161 162 private: 163 class SoundDose : public media::BnSoundDose, 164 public IBinder::DeathRecipient { 165 public: SoundDose(SoundDoseManager * manager,const sp<media::ISoundDoseCallback> & callback)166 SoundDose(SoundDoseManager* manager, const sp<media::ISoundDoseCallback>& callback) 167 : mSoundDoseManager(manager), 168 mSoundDoseCallback(callback) {} 169 170 /** IBinder::DeathRecipient. Listen to the death of ISoundDoseCallback. */ 171 void binderDied(const wp<IBinder>& who) override; 172 173 /** BnSoundDose override */ 174 binder::Status setOutputRs2UpperBound(float value) override; 175 binder::Status resetCsd(float currentCsd, 176 const std::vector<media::SoundDoseRecord>& records) override; 177 binder::Status updateAttenuation(float attenuationDB, int device) override; 178 binder::Status getOutputRs2UpperBound(float* value) override; 179 binder::Status setCsdEnabled(bool enabled) override; 180 181 binder::Status initCachedAudioDeviceCategories( 182 const std::vector<media::ISoundDose::AudioDeviceCategory> &btDeviceCategories) 183 override; 184 185 binder::Status setAudioDeviceCategory( 186 const media::ISoundDose::AudioDeviceCategory& btAudioDevice) override; 187 188 binder::Status getCsd(float* value) override; 189 binder::Status forceUseFrameworkMel(bool useFrameworkMel) override; 190 binder::Status forceComputeCsdOnAllDevices(bool computeCsdOnAllDevices) override; 191 binder::Status isSoundDoseHalSupported(bool* value) override; 192 193 wp<SoundDoseManager> mSoundDoseManager; 194 const sp<media::ISoundDoseCallback> mSoundDoseCallback; 195 }; 196 197 class HalSoundDoseCallback : public ISoundDose::BnHalSoundDoseCallback { 198 public: HalSoundDoseCallback(SoundDoseManager * manager)199 explicit HalSoundDoseCallback(SoundDoseManager* manager) 200 : mSoundDoseManager(manager) {} 201 202 ndk::ScopedAStatus onMomentaryExposureWarning( 203 float in_currentDbA, 204 const aidl::android::media::audio::common::AudioDevice& in_audioDevice) override; 205 ndk::ScopedAStatus onNewMelValues( 206 const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord, 207 const aidl::android::media::audio::common::AudioDevice& in_audioDevice) override; 208 209 wp<SoundDoseManager> mSoundDoseManager; 210 std::mutex mCbLock; 211 }; 212 213 void resetSoundDose(); 214 215 void resetCsd(float currentCsd, const std::vector<media::SoundDoseRecord>& records); 216 217 sp<media::ISoundDoseCallback> getSoundDoseCallback() const; 218 219 float getAttenuationForDeviceId(audio_port_handle_t id) const; 220 221 void updateAttenuation(float attenuationDB, audio_devices_t deviceType); 222 void setCsdEnabled(bool enabled); 223 void setUseFrameworkMel(bool useFrameworkMel); 224 void setComputeCsdOnAllDevices(bool computeCsdOnAllDevices); 225 bool isSoundDoseHalSupported() const; 226 /** 227 * Returns true if there is one active HAL sound dose interface or null if internal MEL 228 * computation is used. 229 **/ 230 bool useHalSoundDose() const; 231 232 mutable std::mutex mLock; 233 234 sp<IMelReporterCallback> mMelReporterCallback; 235 236 // no need for lock since MelAggregator is thread-safe 237 const sp<audio_utils::MelAggregator> mMelAggregator; 238 239 std::unordered_map<audio_io_handle_t, wp<audio_utils::MelProcessor>> mActiveProcessors 240 GUARDED_BY(mLock); 241 242 // map active device address and type to device id, used also for managing the pause/resume 243 // logic for deviceId's that should not report MEL values (e.g.: do not have an active MUSIC 244 // or GAME stream). 245 std::map<AudioDeviceTypeAddr, audio_port_handle_t> mActiveDevices GUARDED_BY(mLock); 246 std::unordered_map<audio_port_handle_t, audio_devices_t> mActiveDeviceTypes GUARDED_BY(mLock); 247 248 struct bt_device_type_hash { operatorbt_device_type_hash249 std::size_t operator() (const std::pair<std::string, audio_devices_t> &deviceType) const { 250 return std::hash<std::string>()(deviceType.first) ^ 251 std::hash<audio_devices_t>()(deviceType.second); 252 } 253 }; 254 // storing the BT cached information as received from the java side 255 // see SoundDoseManager::setCachedAudioDeviceCategories 256 std::unordered_map<std::pair<std::string, audio_devices_t>, bool, bt_device_type_hash> 257 mBluetoothDevicesWithCsd GUARDED_BY(mLock); 258 259 float mRs2UpperBound GUARDED_BY(mLock); 260 std::unordered_map<audio_devices_t, float> mMelAttenuationDB GUARDED_BY(mLock); 261 262 sp<SoundDose> mSoundDose GUARDED_BY(mLock); 263 264 std::unordered_map<std::string, std::shared_ptr<ISoundDose>> mHalSoundDose GUARDED_BY(mLock); 265 std::shared_ptr<HalSoundDoseCallback> mHalSoundDoseCallback GUARDED_BY(mLock); 266 267 bool mUseFrameworkMel GUARDED_BY(mLock) = false; 268 bool mComputeCsdOnAllDevices GUARDED_BY(mLock) = false; 269 270 bool mEnabledCsd GUARDED_BY(mLock) = true; 271 }; 272 273 } // namespace android 274