blob: 61f27cbc829f5a9103d44aef6839492e1c7edd55 [file] [log] [blame]
Vlad Popa2900c0a2022-10-24 13:38:00 +02001/*
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-base/stringprintf.h>
Vlad Popa2900c0a2022-10-24 13:38:00 +020024#include <time.h>
Vlad Popa4defd0b2022-11-06 14:22:31 +010025#include <utils/Log.h>
26#include <cinttypes>
27#include "android/media/SoundDoseRecord.h"
Vlad Popa2900c0a2022-10-24 13:38:00 +020028
29namespace android {
30
31namespace {
32
33int64_t getMonotonicSecond() {
34 struct timespec now_ts;
35 if (clock_gettime(CLOCK_MONOTONIC, &now_ts) != 0) {
36 ALOGE("%s: cannot get timestamp", __func__);
37 return -1;
38 }
39 return now_ts.tv_sec;
40}
41
42} // namespace
43
Vlad Popaf09e93f2022-10-31 16:27:12 +010044sp<audio_utils::MelProcessor> SoundDoseManager::getOrCreateProcessorForDevice(
Vlad Popa4defd0b2022-11-06 14:22:31 +010045 audio_port_handle_t deviceId, audio_io_handle_t streamHandle, uint32_t sampleRate,
46 size_t channelCount, audio_format_t format) {
Vlad Popa2900c0a2022-10-24 13:38:00 +020047 std::lock_guard _l(mLock);
48
Vlad Popaf09e93f2022-10-31 16:27:12 +010049 auto streamProcessor = mActiveProcessors.find(streamHandle);
50 sp<audio_utils::MelProcessor> processor;
Vlad Popa4defd0b2022-11-06 14:22:31 +010051 if (streamProcessor != mActiveProcessors.end() &&
52 (processor = streamProcessor->second.promote())) {
Vlad Popa2900c0a2022-10-24 13:38:00 +020053 ALOGV("%s: found callback for stream %d", __func__, streamHandle);
Vlad Popaf09e93f2022-10-31 16:27:12 +010054 processor->setDeviceId(deviceId);
Vlad Popae3fd1c22022-11-07 21:03:18 +010055 processor->setOutputRs2(mRs2Value);
Vlad Popaf09e93f2022-10-31 16:27:12 +010056 return processor;
Vlad Popa2900c0a2022-10-24 13:38:00 +020057 } else {
58 ALOGV("%s: creating new callback for device %d", __func__, streamHandle);
Vlad Popa4defd0b2022-11-06 14:22:31 +010059 sp<audio_utils::MelProcessor> melProcessor = sp<audio_utils::MelProcessor>::make(
60 sampleRate, channelCount, format, *this, deviceId, mRs2Value);
Vlad Popaf09e93f2022-10-31 16:27:12 +010061 mActiveProcessors[streamHandle] = melProcessor;
62 return melProcessor;
Vlad Popa2900c0a2022-10-24 13:38:00 +020063 }
64}
65
Vlad Popa4defd0b2022-11-06 14:22:31 +010066void SoundDoseManager::setOutputRs2(float rs2Value) {
Vlad Popa2900c0a2022-10-24 13:38:00 +020067 ALOGV("%s", __func__);
Vlad Popaf09e93f2022-10-31 16:27:12 +010068 std::lock_guard _l(mLock);
69
Vlad Popae3fd1c22022-11-07 21:03:18 +010070 mRs2Value = rs2Value;
71
Vlad Popaf09e93f2022-10-31 16:27:12 +010072 for (auto& streamProcessor : mActiveProcessors) {
73 sp<audio_utils::MelProcessor> processor = streamProcessor.second.promote();
74 if (processor != nullptr) {
Vlad Popae3fd1c22022-11-07 21:03:18 +010075 status_t result = processor->setOutputRs2(mRs2Value);
Vlad Popaf09e93f2022-10-31 16:27:12 +010076 if (result != NO_ERROR) {
Vlad Popae3fd1c22022-11-07 21:03:18 +010077 ALOGW("%s: could not set RS2 value %f for stream %d", __func__, mRs2Value,
Vlad Popaf09e93f2022-10-31 16:27:12 +010078 streamProcessor.first);
79 }
80 }
81 }
82}
83
Vlad Popa4defd0b2022-11-06 14:22:31 +010084void SoundDoseManager::removeStreamProcessor(audio_io_handle_t streamHandle) {
Vlad Popaf09e93f2022-10-31 16:27:12 +010085 std::lock_guard _l(mLock);
86 auto callbackToRemove = mActiveProcessors.find(streamHandle);
Vlad Popa4defd0b2022-11-06 14:22:31 +010087 if (callbackToRemove != mActiveProcessors.end()) {
Vlad Popaf09e93f2022-10-31 16:27:12 +010088 mActiveProcessors.erase(callbackToRemove);
89 }
90}
91
Vlad Popae3fd1c22022-11-07 21:03:18 +010092void SoundDoseManager::SoundDose::binderDied(__unused const wp<IBinder>& who) {
93 ALOGV("%s", __func__);
94
95 auto soundDoseManager = mSoundDoseManager.promote();
96 if (soundDoseManager != nullptr) {
97 soundDoseManager->resetSoundDose();
98 }
99}
100
101binder::Status SoundDoseManager::SoundDose::setOutputRs2(float value) {
102 ALOGV("%s", __func__);
103 auto soundDoseManager = mSoundDoseManager.promote();
104 if (soundDoseManager != nullptr) {
105 soundDoseManager->setOutputRs2(value);
106 }
107 return binder::Status::ok();
108}
109
110binder::Status SoundDoseManager::SoundDose::resetCsd(
111 float currentCsd, const std::vector<media::SoundDoseRecord>& records) {
112 ALOGV("%s", __func__);
113 auto soundDoseManager = mSoundDoseManager.promote();
114 if (soundDoseManager != nullptr) {
115 soundDoseManager->resetCsd(currentCsd, records);
116 }
117 return binder::Status::ok();
118}
119
Vlad Popa91930462022-12-20 22:42:48 +0100120binder::Status SoundDoseManager::SoundDose::getOutputRs2(float* value) {
121 ALOGV("%s", __func__);
122 auto soundDoseManager = mSoundDoseManager.promote();
123 if (soundDoseManager != nullptr) {
124 std::lock_guard _l(soundDoseManager->mLock);
125 *value = soundDoseManager->mRs2Value;
126 }
127 return binder::Status::ok();
128}
129
130binder::Status SoundDoseManager::SoundDose::getCsd(float* value) {
131 ALOGV("%s", __func__);
132 auto soundDoseManager = mSoundDoseManager.promote();
133 if (soundDoseManager != nullptr) {
134 *value = soundDoseManager->mMelAggregator->getCsd();
135 }
136 return binder::Status::ok();
137}
138
139binder::Status SoundDoseManager::SoundDose::forceUseFrameworkMel(bool useFrameworkMel) {
140 ALOGV("%s", __func__);
141 auto soundDoseManager = mSoundDoseManager.promote();
142 if (soundDoseManager != nullptr) {
143 soundDoseManager->setUseFrameworkMel(useFrameworkMel);
144 }
145 return binder::Status::ok();
146}
147
148binder::Status SoundDoseManager::SoundDose::forceComputeCsdOnAllDevices(
149 bool computeCsdOnAllDevices) {
150 ALOGV("%s", __func__);
151 auto soundDoseManager = mSoundDoseManager.promote();
152 if (soundDoseManager != nullptr) {
153 soundDoseManager->setComputeCsdOnAllDevices(computeCsdOnAllDevices);
154 }
155 return binder::Status::ok();
156}
157
158void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
159 std::lock_guard _l(mLock);
160 mUseFrameworkMel = useFrameworkMel;
161}
162
163bool SoundDoseManager::useFrameworkMel() const {
164 std::lock_guard _l(mLock);
165 return mUseFrameworkMel;
166}
167
168void SoundDoseManager::setComputeCsdOnAllDevices(bool computeCsdOnAllDevices) {
169 std::lock_guard _l(mLock);
170 mComputeCsdOnAllDevices = computeCsdOnAllDevices;
171}
172
173bool SoundDoseManager::computeCsdOnAllDevices() const {
174 std::lock_guard _l(mLock);
175 return mComputeCsdOnAllDevices;
176}
177
Vlad Popae3fd1c22022-11-07 21:03:18 +0100178void SoundDoseManager::resetSoundDose() {
179 std::lock_guard lock(mLock);
180 mSoundDose = nullptr;
181}
182
183void SoundDoseManager::resetCsd(float currentCsd,
184 const std::vector<media::SoundDoseRecord>& records) {
185 std::lock_guard lock(mLock);
186 std::vector<audio_utils::CsdRecord> resetRecords;
187 for (const auto& record : records) {
188 resetRecords.emplace_back(record.timestamp, record.duration, record.value,
189 record.averageMel);
190 }
191
192 mMelAggregator->reset(currentCsd, resetRecords);
193}
194
Vlad Popa4defd0b2022-11-06 14:22:31 +0100195void SoundDoseManager::onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
196 audio_port_handle_t deviceId) const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100197 ALOGV("%s", __func__);
Vlad Popa2900c0a2022-10-24 13:38:00 +0200198
Vlad Popa4defd0b2022-11-06 14:22:31 +0100199 sp<media::ISoundDoseCallback> soundDoseCallback;
200 std::vector<audio_utils::CsdRecord> records;
201 float currentCsd;
202 {
203 std::lock_guard _l(mLock);
Vlad Popa2900c0a2022-10-24 13:38:00 +0200204
Vlad Popa4defd0b2022-11-06 14:22:31 +0100205 int64_t timestampSec = getMonotonicSecond();
206
207 // only for internal callbacks
208 records = mMelAggregator->aggregateAndAddNewMelRecord(audio_utils::MelRecord(
209 deviceId, std::vector<float>(mels.begin() + offset, mels.begin() + offset + length),
210 timestampSec - length));
211
212 currentCsd = mMelAggregator->getCsd();
213 }
214
215 soundDoseCallback = getSoundDoseCallback();
216
217 if (records.size() > 0 && soundDoseCallback != nullptr) {
218 std::vector<media::SoundDoseRecord> newRecordsToReport;
219 for (const auto& record : records) {
220 newRecordsToReport.emplace_back(csdRecordToSoundDoseRecord(record));
221 }
222
223 soundDoseCallback->onNewCsdValue(currentCsd, newRecordsToReport);
224 }
Vlad Popa2900c0a2022-10-24 13:38:00 +0200225}
226
Vlad Popa4defd0b2022-11-06 14:22:31 +0100227sp<media::ISoundDoseCallback> SoundDoseManager::getSoundDoseCallback() const {
228 std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100229 if (mSoundDose == nullptr) {
230 return nullptr;
231 }
232
233 return mSoundDose->mSoundDoseCallback;
Vlad Popa4defd0b2022-11-06 14:22:31 +0100234}
235
236void SoundDoseManager::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const {
237 ALOGV("%s: Momentary exposure for device %d triggered: %f MEL", __func__, deviceId, currentMel);
Vlad Popa63f047e2022-11-05 14:09:19 +0100238
Vlad Popae3fd1c22022-11-07 21:03:18 +0100239 auto soundDoseCallback = getSoundDoseCallback();
Vlad Popa63f047e2022-11-05 14:09:19 +0100240 if (soundDoseCallback != nullptr) {
Vlad Popae3fd1c22022-11-07 21:03:18 +0100241 soundDoseCallback->onMomentaryExposure(currentMel, deviceId);
Vlad Popa63f047e2022-11-05 14:09:19 +0100242 }
243}
244
Vlad Popae3fd1c22022-11-07 21:03:18 +0100245sp<media::ISoundDose> SoundDoseManager::getSoundDoseInterface(
246 const sp<media::ISoundDoseCallback>& callback) {
Vlad Popa63f047e2022-11-05 14:09:19 +0100247 ALOGV("%s: Register ISoundDoseCallback", __func__);
248
249 std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100250 if (mSoundDose == nullptr) {
251 mSoundDose = sp<SoundDose>::make(this, callback);
252 }
253 return mSoundDose;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100254}
255
Vlad Popa4defd0b2022-11-06 14:22:31 +0100256std::string SoundDoseManager::dump() const {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200257 std::string output;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100258 mMelAggregator->foreachCsd([&output](audio_utils::CsdRecord csdRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200259 base::StringAppendF(&output,
260 "CSD %f with average MEL %f in interval [%" PRId64 ", %" PRId64 "]",
Vlad Popa4defd0b2022-11-06 14:22:31 +0100261 csdRecord.value, csdRecord.averageMel, csdRecord.timestamp,
Vlad Popa2900c0a2022-10-24 13:38:00 +0200262 csdRecord.timestamp + csdRecord.duration);
263 base::StringAppendF(&output, "\n");
264 });
265
266 base::StringAppendF(&output, "\nCached Mel Records:\n");
Vlad Popaf09e93f2022-10-31 16:27:12 +0100267 mMelAggregator->foreachCachedMel([&output](const audio_utils::MelRecord& melRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200268 base::StringAppendF(&output, "Continuous MELs for portId=%d, ", melRecord.portId);
269 base::StringAppendF(&output, "starting at timestamp %" PRId64 ": ", melRecord.timestamp);
270
271 for (const auto& mel : melRecord.mels) {
272 base::StringAppendF(&output, "%.2f ", mel);
273 }
274 base::StringAppendF(&output, "\n");
275 });
276
277 return output;
278}
279
280size_t SoundDoseManager::getCachedMelRecordsSize() const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100281 return mMelAggregator->getCachedMelRecordsSize();
Vlad Popa2900c0a2022-10-24 13:38:00 +0200282}
283
Vlad Popa4defd0b2022-11-06 14:22:31 +0100284media::SoundDoseRecord SoundDoseManager::csdRecordToSoundDoseRecord(
285 const audio_utils::CsdRecord& legacy) {
286 media::SoundDoseRecord soundDoseRecord{};
287 soundDoseRecord.timestamp = legacy.timestamp;
288 soundDoseRecord.duration = legacy.duration;
289 soundDoseRecord.value = legacy.value;
290 soundDoseRecord.averageMel = legacy.averageMel;
291 return soundDoseRecord;
292}
293
Vlad Popa2900c0a2022-10-24 13:38:00 +0200294} // namespace android