blob: 780d7965030954edc6b925f2ba8494258f59f9e9 [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>
24#include <cinttypes>
25#include <utils/Log.h>
26#include <time.h>
27
28namespace android {
29
30namespace {
31
32int64_t getMonotonicSecond() {
33 struct timespec now_ts;
34 if (clock_gettime(CLOCK_MONOTONIC, &now_ts) != 0) {
35 ALOGE("%s: cannot get timestamp", __func__);
36 return -1;
37 }
38 return now_ts.tv_sec;
39}
40
41} // namespace
42
43sp<audio_utils::MelProcessor::MelCallback> SoundDoseManager::getOrCreateCallbackForDevice(
44 audio_port_handle_t deviceId,
45 audio_io_handle_t streamHandle)
46{
47 std::lock_guard _l(mLock);
48
49 auto streamHandleCallback = mActiveCallbacks.find(streamHandle);
50 if (streamHandleCallback != mActiveCallbacks.end()) {
51 ALOGV("%s: found callback for stream %d", __func__, streamHandle);
52 auto callback = streamHandleCallback->second;
53 callback->mDeviceHandle = deviceId;
54 return callback;
55 } else {
56 ALOGV("%s: creating new callback for device %d", __func__, streamHandle);
57 sp<Callback> melCallback = sp<Callback>::make(*this, deviceId);
58 mActiveCallbacks[streamHandle] = melCallback;
59 return melCallback;
60 }
61}
62
63void SoundDoseManager::removeStreamCallback(audio_io_handle_t streamHandle)
64{
65 std::unordered_map<audio_io_handle_t, sp<Callback>>::iterator callbackToRemove;
66
67 std::lock_guard _l(mLock);
68 callbackToRemove = mActiveCallbacks.find(streamHandle);
69 if (callbackToRemove != mActiveCallbacks.end()) {
70 mActiveCallbacks.erase(callbackToRemove);
71 }
72}
73
74void SoundDoseManager::Callback::onNewMelValues(const std::vector<float>& mels,
75 size_t offset,
76 size_t length) const
77{
78 ALOGV("%s", __func__);
79 std::lock_guard _l(mSoundDoseManager.mLock);
80
81 int64_t timestampSec = getMonotonicSecond();
82
83 // only for internal callbacks
84 mSoundDoseManager.mMelAggregator.aggregateAndAddNewMelRecord(
85 audio_utils::MelRecord(mDeviceHandle, std::vector<float>(
86 mels.begin() + offset,
87 mels.begin() + offset + length),
88 timestampSec - length));
89}
90
91std::string SoundDoseManager::dump() const
92{
93 std::string output;
94 mMelAggregator.foreachCsd([&output](audio_utils::CsdRecord csdRecord) {
95 base::StringAppendF(&output,
96 "CSD %f with average MEL %f in interval [%" PRId64 ", %" PRId64 "]",
97 csdRecord.value,
98 csdRecord.averageMel,
99 csdRecord.timestamp,
100 csdRecord.timestamp + csdRecord.duration);
101 base::StringAppendF(&output, "\n");
102 });
103
104 base::StringAppendF(&output, "\nCached Mel Records:\n");
105 mMelAggregator.foreachCachedMel([&output](const audio_utils::MelRecord& melRecord) {
106 base::StringAppendF(&output, "Continuous MELs for portId=%d, ", melRecord.portId);
107 base::StringAppendF(&output, "starting at timestamp %" PRId64 ": ", melRecord.timestamp);
108
109 for (const auto& mel : melRecord.mels) {
110 base::StringAppendF(&output, "%.2f ", mel);
111 }
112 base::StringAppendF(&output, "\n");
113 });
114
115 return output;
116}
117
118size_t SoundDoseManager::getCachedMelRecordsSize() const {
119 return mMelAggregator.getCachedMelRecordsSize();
120}
121
122} // namespace android