blob: 6c3a06713947d57a9a92e6213fbd72f13ecdbafc [file] [log] [blame]
Vlad Popa83a21462022-12-08 14:24:12 +01001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "AHAL_SoundDose"
18
19#include "core-impl/SoundDose.h"
20
Vlad Popace338642023-09-21 18:54:03 -070021#include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h>
Vlad Popa83a21462022-12-08 14:24:12 +010022#include <android-base/logging.h>
Vlad Popace338642023-09-21 18:54:03 -070023#include <media/AidlConversionCppNdk.h>
24#include <utils/Timers.h>
25
26using aidl::android::hardware::audio::core::sounddose::ISoundDose;
27using aidl::android::media::audio::common::AudioDevice;
28using aidl::android::media::audio::common::AudioDeviceDescription;
29using aidl::android::media::audio::common::AudioFormatDescription;
Vlad Popa83a21462022-12-08 14:24:12 +010030
Vlad Popac88ea612022-12-28 17:04:58 +010031namespace aidl::android::hardware::audio::core::sounddose {
Vlad Popa83a21462022-12-08 14:24:12 +010032
Vlad Popa34f4c1d2023-03-16 18:43:53 +010033ndk::ScopedAStatus SoundDose::setOutputRs2UpperBound(float in_rs2ValueDbA) {
Vlad Popa83a21462022-12-08 14:24:12 +010034 if (in_rs2ValueDbA < MIN_RS2 || in_rs2ValueDbA > DEFAULT_MAX_RS2) {
35 LOG(ERROR) << __func__ << ": RS2 value is invalid: " << in_rs2ValueDbA;
36 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
37 }
38
Vlad Popace338642023-09-21 18:54:03 -070039 ::android::audio_utils::lock_guard l(mMutex);
Vlad Popa83a21462022-12-08 14:24:12 +010040 mRs2Value = in_rs2ValueDbA;
Vlad Popace338642023-09-21 18:54:03 -070041 if (mMelProcessor != nullptr) {
42 mMelProcessor->setOutputRs2UpperBound(in_rs2ValueDbA);
43 }
Vlad Popa83a21462022-12-08 14:24:12 +010044 return ndk::ScopedAStatus::ok();
45}
46
Vlad Popa34f4c1d2023-03-16 18:43:53 +010047ndk::ScopedAStatus SoundDose::getOutputRs2UpperBound(float* _aidl_return) {
Vlad Popace338642023-09-21 18:54:03 -070048 ::android::audio_utils::lock_guard l(mMutex);
Vlad Popa83a21462022-12-08 14:24:12 +010049 *_aidl_return = mRs2Value;
50 LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
51 return ndk::ScopedAStatus::ok();
52}
53
54ndk::ScopedAStatus SoundDose::registerSoundDoseCallback(
55 const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& in_callback) {
56 if (in_callback.get() == nullptr) {
57 LOG(ERROR) << __func__ << ": Callback is nullptr";
58 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
59 }
Vlad Popace338642023-09-21 18:54:03 -070060
61 ::android::audio_utils::lock_guard l(mCbMutex);
Vlad Popa83a21462022-12-08 14:24:12 +010062 if (mCallback != nullptr) {
63 LOG(ERROR) << __func__ << ": Sound dose callback was already registered";
64 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
65 }
66
67 mCallback = in_callback;
68 LOG(DEBUG) << __func__ << ": Registered sound dose callback ";
Vlad Popace338642023-09-21 18:54:03 -070069
Vlad Popa83a21462022-12-08 14:24:12 +010070 return ndk::ScopedAStatus::ok();
71}
72
Vlad Popace338642023-09-21 18:54:03 -070073void SoundDose::setAudioDevice(const AudioDevice& audioDevice) {
74 ::android::audio_utils::lock_guard l(mCbMutex);
75 mAudioDevice = audioDevice;
76}
77
78void SoundDose::startDataProcessor(uint32_t sampleRate, uint32_t channelCount,
79 const AudioFormatDescription& aidlFormat) {
80 ::android::audio_utils::lock_guard l(mMutex);
81 const auto result = aidl2legacy_AudioFormatDescription_audio_format_t(aidlFormat);
82 const audio_format_t format = result.value_or(AUDIO_FORMAT_INVALID);
83
84 if (mMelProcessor == nullptr) {
85 // we don't have the deviceId concept on the vendor side so just pass 0
86 mMelProcessor = ::android::sp<::android::audio_utils::MelProcessor>::make(
87 sampleRate, channelCount, format, mMelCallback, /*deviceId=*/0, mRs2Value);
88 } else {
89 mMelProcessor->updateAudioFormat(sampleRate, channelCount, format);
90 }
91}
92
93void SoundDose::process(const void* buffer, size_t bytes) {
94 ::android::audio_utils::lock_guard l(mMutex);
95 if (mMelProcessor != nullptr) {
96 mMelProcessor->process(buffer, bytes);
97 }
98}
99
100void SoundDose::onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
101 audio_port_handle_t deviceId __attribute__((__unused__))) const {
102 ::android::audio_utils::lock_guard l(mCbMutex);
103 if (!mAudioDevice.has_value()) {
104 LOG(WARNING) << __func__ << ": New mel values without a registered device";
105 return;
106 }
107 if (mCallback == nullptr) {
108 LOG(ERROR) << __func__ << ": New mel values without a registered callback";
109 return;
110 }
111
112 ISoundDose::IHalSoundDoseCallback::MelRecord melRecord;
113 melRecord.timestamp = nanoseconds_to_seconds(systemTime());
114 melRecord.melValues = std::vector<float>(mels.begin() + offset, mels.begin() + offset + length);
115
116 mCallback->onNewMelValues(melRecord, mAudioDevice.value());
117}
118
119void SoundDose::MelCallback::onNewMelValues(const std::vector<float>& mels, size_t offset,
120 size_t length,
121 audio_port_handle_t deviceId
Vlad Popa3ee76902024-01-03 05:49:22 -0800122 __attribute__((__unused__)),
123 bool attenuated __attribute__((__unused__))) const {
Vlad Popace338642023-09-21 18:54:03 -0700124 mSoundDose.onNewMelValues(mels, offset, length, deviceId);
125}
126
127void SoundDose::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId
128 __attribute__((__unused__))) const {
129 ::android::audio_utils::lock_guard l(mCbMutex);
130 if (!mAudioDevice.has_value()) {
131 LOG(WARNING) << __func__ << ": Momentary exposure without a registered device";
132 return;
133 }
134 if (mCallback == nullptr) {
135 LOG(ERROR) << __func__ << ": Momentary exposure without a registered callback";
136 return;
137 }
138
139 mCallback->onMomentaryExposureWarning(currentMel, mAudioDevice.value());
140}
141
142void SoundDose::MelCallback::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId
143 __attribute__((__unused__))) const {
144 mSoundDose.onMomentaryExposure(currentMel, deviceId);
145}
146
Vlad Popac88ea612022-12-28 17:04:58 +0100147} // namespace aidl::android::hardware::audio::core::sounddose