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