1 /*
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
21 #include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h>
22 #include <android-base/logging.h>
23 #include <media/AidlConversionCppNdk.h>
24 #include <utils/Timers.h>
25
26 using aidl::android::hardware::audio::core::sounddose::ISoundDose;
27 using aidl::android::media::audio::common::AudioDevice;
28 using aidl::android::media::audio::common::AudioDeviceDescription;
29 using aidl::android::media::audio::common::AudioFormatDescription;
30
31 namespace aidl::android::hardware::audio::core::sounddose {
32
setOutputRs2UpperBound(float in_rs2ValueDbA)33 ndk::ScopedAStatus SoundDose::setOutputRs2UpperBound(float in_rs2ValueDbA) {
34 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
39 ::android::audio_utils::lock_guard l(mMutex);
40 mRs2Value = in_rs2ValueDbA;
41 if (mMelProcessor != nullptr) {
42 mMelProcessor->setOutputRs2UpperBound(in_rs2ValueDbA);
43 }
44 return ndk::ScopedAStatus::ok();
45 }
46
getOutputRs2UpperBound(float * _aidl_return)47 ndk::ScopedAStatus SoundDose::getOutputRs2UpperBound(float* _aidl_return) {
48 ::android::audio_utils::lock_guard l(mMutex);
49 *_aidl_return = mRs2Value;
50 LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
51 return ndk::ScopedAStatus::ok();
52 }
53
registerSoundDoseCallback(const std::shared_ptr<ISoundDose::IHalSoundDoseCallback> & in_callback)54 ndk::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 }
60
61 ::android::audio_utils::lock_guard l(mCbMutex);
62 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 ";
69
70 return ndk::ScopedAStatus::ok();
71 }
72
setAudioDevice(const AudioDevice & audioDevice)73 void SoundDose::setAudioDevice(const AudioDevice& audioDevice) {
74 ::android::audio_utils::lock_guard l(mCbMutex);
75 mAudioDevice = audioDevice;
76 }
77
startDataProcessor(uint32_t sampleRate,uint32_t channelCount,const AudioFormatDescription & aidlFormat)78 void 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
process(const void * buffer,size_t bytes)93 void 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
onNewMelValues(const std::vector<float> & mels,size_t offset,size_t length,audio_port_handle_t deviceId) const100 void 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
onNewMelValues(const std::vector<float> & mels,size_t offset,size_t length,audio_port_handle_t deviceId,bool attenuated) const119 void SoundDose::MelCallback::onNewMelValues(const std::vector<float>& mels, size_t offset,
120 size_t length,
121 audio_port_handle_t deviceId
122 __attribute__((__unused__)),
123 bool attenuated __attribute__((__unused__))) const {
124 mSoundDose.onNewMelValues(mels, offset, length, deviceId);
125 }
126
onMomentaryExposure(float currentMel,audio_port_handle_t deviceId) const127 void 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
onMomentaryExposure(float currentMel,audio_port_handle_t deviceId) const142 void SoundDose::MelCallback::onMomentaryExposure(float currentMel, audio_port_handle_t deviceId
143 __attribute__((__unused__))) const {
144 mSoundDose.onMomentaryExposure(currentMel, deviceId);
145 }
146
147 } // namespace aidl::android::hardware::audio::core::sounddose
148