blob: 6f9e11fb795f12abd8e8f5f9f1e81c90b328ffc0 [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
Vlad Popa1d5f0d52022-12-18 12:21:26 +010023#if !defined(BACKEND_NDK)
24#define BACKEND_NDK
25#endif
26
27#include "android/media/SoundDoseRecord.h"
Vlad Popa2900c0a2022-10-24 13:38:00 +020028#include <android-base/stringprintf.h>
Vlad Popa1d5f0d52022-12-18 12:21:26 +010029#include <media/AidlConversionCppNdk.h>
30#include <cinttypes>
Vlad Popa2900c0a2022-10-24 13:38:00 +020031#include <time.h>
Vlad Popa4defd0b2022-11-06 14:22:31 +010032#include <utils/Log.h>
Vlad Popa2900c0a2022-10-24 13:38:00 +020033
34namespace android {
35
Vlad Popa1d5f0d52022-12-18 12:21:26 +010036using aidl::android::media::audio::common::AudioDevice;
37using aidl::android::media::audio::common::AudioDeviceAddress;
38
Vlad Popa2900c0a2022-10-24 13:38:00 +020039namespace {
40
41int64_t getMonotonicSecond() {
42 struct timespec now_ts;
43 if (clock_gettime(CLOCK_MONOTONIC, &now_ts) != 0) {
44 ALOGE("%s: cannot get timestamp", __func__);
45 return -1;
46 }
47 return now_ts.tv_sec;
48}
49
50} // namespace
51
Vlad Popaf09e93f2022-10-31 16:27:12 +010052sp<audio_utils::MelProcessor> SoundDoseManager::getOrCreateProcessorForDevice(
Vlad Popa4defd0b2022-11-06 14:22:31 +010053 audio_port_handle_t deviceId, audio_io_handle_t streamHandle, uint32_t sampleRate,
54 size_t channelCount, audio_format_t format) {
Vlad Popa2900c0a2022-10-24 13:38:00 +020055 std::lock_guard _l(mLock);
56
Vlad Popa1d5f0d52022-12-18 12:21:26 +010057 if (mHalSoundDose != nullptr) {
58 ALOGW("%s: using HAL MEL computation, no MelProcessor needed.", __func__);
59 return nullptr;
60 }
61
Vlad Popaf09e93f2022-10-31 16:27:12 +010062 auto streamProcessor = mActiveProcessors.find(streamHandle);
63 sp<audio_utils::MelProcessor> processor;
Vlad Popa4defd0b2022-11-06 14:22:31 +010064 if (streamProcessor != mActiveProcessors.end() &&
65 (processor = streamProcessor->second.promote())) {
Vlad Popa2900c0a2022-10-24 13:38:00 +020066 ALOGV("%s: found callback for stream %d", __func__, streamHandle);
Vlad Popaf09e93f2022-10-31 16:27:12 +010067 processor->setDeviceId(deviceId);
Vlad Popae3fd1c22022-11-07 21:03:18 +010068 processor->setOutputRs2(mRs2Value);
Vlad Popaf09e93f2022-10-31 16:27:12 +010069 return processor;
Vlad Popa2900c0a2022-10-24 13:38:00 +020070 } else {
71 ALOGV("%s: creating new callback for device %d", __func__, streamHandle);
Vlad Popa4defd0b2022-11-06 14:22:31 +010072 sp<audio_utils::MelProcessor> melProcessor = sp<audio_utils::MelProcessor>::make(
73 sampleRate, channelCount, format, *this, deviceId, mRs2Value);
Vlad Popaf09e93f2022-10-31 16:27:12 +010074 mActiveProcessors[streamHandle] = melProcessor;
75 return melProcessor;
Vlad Popa2900c0a2022-10-24 13:38:00 +020076 }
77}
78
Vlad Popa1d5f0d52022-12-18 12:21:26 +010079bool SoundDoseManager::setHalSoundDoseInterface(const std::shared_ptr<ISoundDose>& halSoundDose) {
80 ALOGV("%s", __func__);
81
82 {
83 std::lock_guard _l(mLock);
84
85 mHalSoundDose = halSoundDose;
86 if (halSoundDose == nullptr) {
87 ALOGI("%s: passed ISoundDose object is null, switching to internal CSD", __func__);
88 return false;
89 }
90
91 if (!mHalSoundDose->setOutputRs2(mRs2Value).isOk()) {
92 ALOGW("%s: Cannot set RS2 value for momentary exposure %f",
93 __func__,
94 mRs2Value);
95 }
96
97 // initialize the HAL sound dose callback lazily
98 if (mHalSoundDoseCallback == nullptr) {
99 mHalSoundDoseCallback =
100 ndk::SharedRefBase::make<HalSoundDoseCallback>(this);
101 }
102 }
103
104 auto status = halSoundDose->registerSoundDoseCallback(mHalSoundDoseCallback);
105 if (!status.isOk()) {
106 // Not a warning since this can happen if the callback was registered before
107 ALOGI("%s: Cannot register HAL sound dose callback with status message: %s",
108 __func__,
109 status.getMessage());
110 }
111
112 return true;
113}
114
Vlad Popa4defd0b2022-11-06 14:22:31 +0100115void SoundDoseManager::setOutputRs2(float rs2Value) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200116 ALOGV("%s", __func__);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100117 std::lock_guard _l(mLock);
118
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100119 if (mHalSoundDose != nullptr) {
120 // using the HAL sound dose interface
Vlad Popa3c3995d2023-01-13 11:10:05 +0100121 if (!mHalSoundDose->setOutputRs2(rs2Value).isOk()) {
122 ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
123 return;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100124 }
Vlad Popa3c3995d2023-01-13 11:10:05 +0100125 mRs2Value = rs2Value;
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100126 return;
127 }
Vlad Popae3fd1c22022-11-07 21:03:18 +0100128
Vlad Popaf09e93f2022-10-31 16:27:12 +0100129 for (auto& streamProcessor : mActiveProcessors) {
130 sp<audio_utils::MelProcessor> processor = streamProcessor.second.promote();
131 if (processor != nullptr) {
Vlad Popa3c3995d2023-01-13 11:10:05 +0100132 status_t result = processor->setOutputRs2(rs2Value);
Vlad Popaf09e93f2022-10-31 16:27:12 +0100133 if (result != NO_ERROR) {
Vlad Popa3c3995d2023-01-13 11:10:05 +0100134 ALOGW("%s: could not set RS2 value %f for stream %d", __func__, rs2Value,
Vlad Popaf09e93f2022-10-31 16:27:12 +0100135 streamProcessor.first);
Vlad Popa3c3995d2023-01-13 11:10:05 +0100136 return;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100137 }
Vlad Popa3c3995d2023-01-13 11:10:05 +0100138 mRs2Value = rs2Value;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100139 }
140 }
141}
142
Vlad Popa4defd0b2022-11-06 14:22:31 +0100143void SoundDoseManager::removeStreamProcessor(audio_io_handle_t streamHandle) {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100144 std::lock_guard _l(mLock);
145 auto callbackToRemove = mActiveProcessors.find(streamHandle);
Vlad Popa4defd0b2022-11-06 14:22:31 +0100146 if (callbackToRemove != mActiveProcessors.end()) {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100147 mActiveProcessors.erase(callbackToRemove);
148 }
149}
150
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100151audio_port_handle_t SoundDoseManager::getIdForAudioDevice(const AudioDevice& audioDevice) const {
152 std::lock_guard _l(mLock);
153
154 audio_devices_t type;
155 std::string address;
156 auto result = aidl::android::aidl2legacy_AudioDevice_audio_device(
157 audioDevice, &type, &address);
158 if (result != NO_ERROR) {
159 ALOGE("%s: could not convert from AudioDevice to AudioDeviceTypeAddr", __func__);
160 return AUDIO_PORT_HANDLE_NONE;
161 }
162
163 auto adt = AudioDeviceTypeAddr(type, address);
164 auto deviceIt = mActiveDevices.find(adt);
165 if (deviceIt == mActiveDevices.end()) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100166 ALOGI("%s: could not find port id for device %s", __func__, adt.toString().c_str());
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100167 return AUDIO_PORT_HANDLE_NONE;
168 }
169 return deviceIt->second;
170}
171
172void SoundDoseManager::mapAddressToDeviceId(const AudioDeviceTypeAddr& adt,
173 const audio_port_handle_t deviceId) {
174 std::lock_guard _l(mLock);
175 ALOGI("%s: map address: %s to device id: %d", __func__, adt.toString().c_str(), deviceId);
176 mActiveDevices[adt] = deviceId;
177}
178
179void SoundDoseManager::clearMapDeviceIdEntries(audio_port_handle_t deviceId) {
180 std::lock_guard _l(mLock);
181 for (auto activeDevice = mActiveDevices.begin(); activeDevice != mActiveDevices.end();) {
182 if (activeDevice->second == deviceId) {
183 ALOGI("%s: clear mapping addr: %s to deviceId: %d",
184 __func__, activeDevice->first.toString().c_str(), deviceId);
185 activeDevice = mActiveDevices.erase(activeDevice);
186 continue;
187 }
188 ++activeDevice;
189 }
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100190}
191
192ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
193 float in_currentDbA, const AudioDevice& in_audioDevice) {
194 auto soundDoseManager = mSoundDoseManager.promote();
195 if (soundDoseManager == nullptr) {
196 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
197 }
198
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100199 std::shared_ptr<ISoundDose> halSoundDose;
200 soundDoseManager->getHalSoundDose(&halSoundDose);
201 if(halSoundDose == nullptr) {
202 ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
203 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
204 }
205
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100206 auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
207 if (id == AUDIO_PORT_HANDLE_NONE) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100208 ALOGI("%s: no mapped id for audio device with type %d and address %s",
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100209 __func__, in_audioDevice.type.type,
210 in_audioDevice.address.get<AudioDeviceAddress::id>().c_str());
211 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
212 }
213 soundDoseManager->onMomentaryExposure(in_currentDbA, id);
214
215 return ndk::ScopedAStatus::ok();
216}
217
218ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onNewMelValues(
219 const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
220 const AudioDevice& in_audioDevice) {
221 auto soundDoseManager = mSoundDoseManager.promote();
222 if (soundDoseManager == nullptr) {
223 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
224 }
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100225
226 std::shared_ptr<ISoundDose> halSoundDose;
227 soundDoseManager->getHalSoundDose(&halSoundDose);
228 if(halSoundDose == nullptr) {
229 ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
230 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
231 }
232
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100233 auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
234 if (id == AUDIO_PORT_HANDLE_NONE) {
Vlad Popa7e81cea2023-01-19 16:34:16 +0100235 ALOGI("%s: no mapped id for audio device with type %d and address %s",
Vlad Popa1d5f0d52022-12-18 12:21:26 +0100236 __func__, in_audioDevice.type.type,
237 in_audioDevice.address.get<AudioDeviceAddress::id>().c_str());
238 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
239 }
240 // TODO: introduce timestamp in onNewMelValues callback
241 soundDoseManager->onNewMelValues(in_melRecord.melValues, 0,
242 in_melRecord.melValues.size(), id);
243
244 return ndk::ScopedAStatus::ok();
245}
246
Vlad Popae3fd1c22022-11-07 21:03:18 +0100247void SoundDoseManager::SoundDose::binderDied(__unused const wp<IBinder>& who) {
248 ALOGV("%s", __func__);
249
250 auto soundDoseManager = mSoundDoseManager.promote();
251 if (soundDoseManager != nullptr) {
252 soundDoseManager->resetSoundDose();
253 }
254}
255
256binder::Status SoundDoseManager::SoundDose::setOutputRs2(float value) {
257 ALOGV("%s", __func__);
258 auto soundDoseManager = mSoundDoseManager.promote();
259 if (soundDoseManager != nullptr) {
260 soundDoseManager->setOutputRs2(value);
261 }
262 return binder::Status::ok();
263}
264
265binder::Status SoundDoseManager::SoundDose::resetCsd(
266 float currentCsd, const std::vector<media::SoundDoseRecord>& records) {
267 ALOGV("%s", __func__);
268 auto soundDoseManager = mSoundDoseManager.promote();
269 if (soundDoseManager != nullptr) {
270 soundDoseManager->resetCsd(currentCsd, records);
271 }
272 return binder::Status::ok();
273}
274
Vlad Popa91930462022-12-20 22:42:48 +0100275binder::Status SoundDoseManager::SoundDose::getOutputRs2(float* value) {
276 ALOGV("%s", __func__);
277 auto soundDoseManager = mSoundDoseManager.promote();
278 if (soundDoseManager != nullptr) {
279 std::lock_guard _l(soundDoseManager->mLock);
280 *value = soundDoseManager->mRs2Value;
281 }
282 return binder::Status::ok();
283}
284
285binder::Status SoundDoseManager::SoundDose::getCsd(float* value) {
286 ALOGV("%s", __func__);
287 auto soundDoseManager = mSoundDoseManager.promote();
288 if (soundDoseManager != nullptr) {
289 *value = soundDoseManager->mMelAggregator->getCsd();
290 }
291 return binder::Status::ok();
292}
293
294binder::Status SoundDoseManager::SoundDose::forceUseFrameworkMel(bool useFrameworkMel) {
295 ALOGV("%s", __func__);
296 auto soundDoseManager = mSoundDoseManager.promote();
297 if (soundDoseManager != nullptr) {
298 soundDoseManager->setUseFrameworkMel(useFrameworkMel);
299 }
300 return binder::Status::ok();
301}
302
303binder::Status SoundDoseManager::SoundDose::forceComputeCsdOnAllDevices(
304 bool computeCsdOnAllDevices) {
305 ALOGV("%s", __func__);
306 auto soundDoseManager = mSoundDoseManager.promote();
307 if (soundDoseManager != nullptr) {
308 soundDoseManager->setComputeCsdOnAllDevices(computeCsdOnAllDevices);
309 }
310 return binder::Status::ok();
311}
312
313void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100314 // invalidate any HAL sound dose interface used
315 setHalSoundDoseInterface(nullptr);
316
Vlad Popa91930462022-12-20 22:42:48 +0100317 std::lock_guard _l(mLock);
318 mUseFrameworkMel = useFrameworkMel;
319}
320
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100321bool SoundDoseManager::forceUseFrameworkMel() const {
Vlad Popa91930462022-12-20 22:42:48 +0100322 std::lock_guard _l(mLock);
323 return mUseFrameworkMel;
324}
325
326void SoundDoseManager::setComputeCsdOnAllDevices(bool computeCsdOnAllDevices) {
327 std::lock_guard _l(mLock);
328 mComputeCsdOnAllDevices = computeCsdOnAllDevices;
329}
330
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100331bool SoundDoseManager::forceComputeCsdOnAllDevices() const {
Vlad Popa91930462022-12-20 22:42:48 +0100332 std::lock_guard _l(mLock);
333 return mComputeCsdOnAllDevices;
334}
335
Vlad Popa3d6d39d2022-12-21 18:59:16 +0100336void SoundDoseManager::getHalSoundDose(std::shared_ptr<ISoundDose>* halSoundDose) const {
337 std::lock_guard _l(mLock);
338 *halSoundDose = mHalSoundDose;
339}
340
Vlad Popae3fd1c22022-11-07 21:03:18 +0100341void SoundDoseManager::resetSoundDose() {
342 std::lock_guard lock(mLock);
343 mSoundDose = nullptr;
344}
345
346void SoundDoseManager::resetCsd(float currentCsd,
347 const std::vector<media::SoundDoseRecord>& records) {
348 std::lock_guard lock(mLock);
349 std::vector<audio_utils::CsdRecord> resetRecords;
350 for (const auto& record : records) {
351 resetRecords.emplace_back(record.timestamp, record.duration, record.value,
352 record.averageMel);
353 }
354
355 mMelAggregator->reset(currentCsd, resetRecords);
356}
357
Vlad Popa4defd0b2022-11-06 14:22:31 +0100358void SoundDoseManager::onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
359 audio_port_handle_t deviceId) const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100360 ALOGV("%s", __func__);
Vlad Popa2900c0a2022-10-24 13:38:00 +0200361
Vlad Popa4defd0b2022-11-06 14:22:31 +0100362 sp<media::ISoundDoseCallback> soundDoseCallback;
363 std::vector<audio_utils::CsdRecord> records;
364 float currentCsd;
365 {
366 std::lock_guard _l(mLock);
Vlad Popa2900c0a2022-10-24 13:38:00 +0200367
Vlad Popa4defd0b2022-11-06 14:22:31 +0100368 int64_t timestampSec = getMonotonicSecond();
369
370 // only for internal callbacks
371 records = mMelAggregator->aggregateAndAddNewMelRecord(audio_utils::MelRecord(
372 deviceId, std::vector<float>(mels.begin() + offset, mels.begin() + offset + length),
373 timestampSec - length));
374
375 currentCsd = mMelAggregator->getCsd();
376 }
377
378 soundDoseCallback = getSoundDoseCallback();
379
380 if (records.size() > 0 && soundDoseCallback != nullptr) {
381 std::vector<media::SoundDoseRecord> newRecordsToReport;
382 for (const auto& record : records) {
383 newRecordsToReport.emplace_back(csdRecordToSoundDoseRecord(record));
384 }
385
386 soundDoseCallback->onNewCsdValue(currentCsd, newRecordsToReport);
387 }
Vlad Popa2900c0a2022-10-24 13:38:00 +0200388}
389
Vlad Popa4defd0b2022-11-06 14:22:31 +0100390sp<media::ISoundDoseCallback> SoundDoseManager::getSoundDoseCallback() const {
391 std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100392 if (mSoundDose == nullptr) {
393 return nullptr;
394 }
395
396 return mSoundDose->mSoundDoseCallback;
Vlad Popa4defd0b2022-11-06 14:22:31 +0100397}
398
399void SoundDoseManager::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const {
400 ALOGV("%s: Momentary exposure for device %d triggered: %f MEL", __func__, deviceId, currentMel);
Vlad Popa63f047e2022-11-05 14:09:19 +0100401
Vlad Popae3fd1c22022-11-07 21:03:18 +0100402 auto soundDoseCallback = getSoundDoseCallback();
Vlad Popa63f047e2022-11-05 14:09:19 +0100403 if (soundDoseCallback != nullptr) {
Vlad Popae3fd1c22022-11-07 21:03:18 +0100404 soundDoseCallback->onMomentaryExposure(currentMel, deviceId);
Vlad Popa63f047e2022-11-05 14:09:19 +0100405 }
406}
407
Vlad Popae3fd1c22022-11-07 21:03:18 +0100408sp<media::ISoundDose> SoundDoseManager::getSoundDoseInterface(
409 const sp<media::ISoundDoseCallback>& callback) {
Vlad Popa63f047e2022-11-05 14:09:19 +0100410 ALOGV("%s: Register ISoundDoseCallback", __func__);
411
412 std::lock_guard _l(mLock);
Vlad Popae3fd1c22022-11-07 21:03:18 +0100413 if (mSoundDose == nullptr) {
414 mSoundDose = sp<SoundDose>::make(this, callback);
415 }
416 return mSoundDose;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100417}
418
Vlad Popa4defd0b2022-11-06 14:22:31 +0100419std::string SoundDoseManager::dump() const {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200420 std::string output;
Vlad Popaf09e93f2022-10-31 16:27:12 +0100421 mMelAggregator->foreachCsd([&output](audio_utils::CsdRecord csdRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200422 base::StringAppendF(&output,
423 "CSD %f with average MEL %f in interval [%" PRId64 ", %" PRId64 "]",
Vlad Popa4defd0b2022-11-06 14:22:31 +0100424 csdRecord.value, csdRecord.averageMel, csdRecord.timestamp,
Vlad Popa2900c0a2022-10-24 13:38:00 +0200425 csdRecord.timestamp + csdRecord.duration);
426 base::StringAppendF(&output, "\n");
427 });
428
429 base::StringAppendF(&output, "\nCached Mel Records:\n");
Vlad Popaf09e93f2022-10-31 16:27:12 +0100430 mMelAggregator->foreachCachedMel([&output](const audio_utils::MelRecord& melRecord) {
Vlad Popa2900c0a2022-10-24 13:38:00 +0200431 base::StringAppendF(&output, "Continuous MELs for portId=%d, ", melRecord.portId);
432 base::StringAppendF(&output, "starting at timestamp %" PRId64 ": ", melRecord.timestamp);
433
434 for (const auto& mel : melRecord.mels) {
435 base::StringAppendF(&output, "%.2f ", mel);
436 }
437 base::StringAppendF(&output, "\n");
438 });
439
440 return output;
441}
442
443size_t SoundDoseManager::getCachedMelRecordsSize() const {
Vlad Popaf09e93f2022-10-31 16:27:12 +0100444 return mMelAggregator->getCachedMelRecordsSize();
Vlad Popa2900c0a2022-10-24 13:38:00 +0200445}
446
Vlad Popa4defd0b2022-11-06 14:22:31 +0100447media::SoundDoseRecord SoundDoseManager::csdRecordToSoundDoseRecord(
448 const audio_utils::CsdRecord& legacy) {
449 media::SoundDoseRecord soundDoseRecord{};
450 soundDoseRecord.timestamp = legacy.timestamp;
451 soundDoseRecord.duration = legacy.duration;
452 soundDoseRecord.value = legacy.value;
453 soundDoseRecord.averageMel = legacy.averageMel;
454 return soundDoseRecord;
455}
456
Vlad Popa2900c0a2022-10-24 13:38:00 +0200457} // namespace android