1 /*
2 * Copyright (C) 2024 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 #include <memory>
18 #define LOG_TAG "AHAL_EffectContext"
19 #include "effect-impl/EffectContext.h"
20 #include "include/effect-impl/EffectTypes.h"
21
22 using aidl::android::hardware::audio::common::getChannelCount;
23 using aidl::android::hardware::audio::common::getFrameSizeInBytes;
24 using aidl::android::hardware::audio::effect::IEffect;
25 using aidl::android::hardware::audio::effect::kReopenSupportedVersion;
26 using aidl::android::media::audio::common::PcmType;
27 using ::android::hardware::EventFlag;
28
29 namespace aidl::android::hardware::audio::effect {
30
EffectContext(size_t statusDepth,const Parameter::Common & common)31 EffectContext::EffectContext(size_t statusDepth, const Parameter::Common& common) {
32 LOG_ALWAYS_FATAL_IF(RetCode::SUCCESS != setCommon(common), "illegalCommonParameter");
33
34 // in/outBuffer size in float (FMQ data format defined for DataMQ)
35 size_t inBufferSizeInFloat = common.input.frameCount * mInputFrameSize / sizeof(float);
36 size_t outBufferSizeInFloat = common.output.frameCount * mOutputFrameSize / sizeof(float);
37
38 // only status FMQ use the EventFlag
39 mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
40 mInputMQ = std::make_shared<DataMQ>(inBufferSizeInFloat);
41 mOutputMQ = std::make_shared<DataMQ>(outBufferSizeInFloat);
42
43 if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
44 LOG(ERROR) << __func__ << " created invalid FMQ, statusMQ: " << mStatusMQ->isValid()
45 << " inputMQ: " << mInputMQ->isValid() << " outputMQ: " << mOutputMQ->isValid();
46 }
47
48 ::android::status_t status =
49 EventFlag::createEventFlag(mStatusMQ->getEventFlagWord(), &mEfGroup);
50 LOG_ALWAYS_FATAL_IF(status != ::android::OK || !mEfGroup, " create EventFlagGroup failed ");
51 mWorkBuffer.resize(std::max(inBufferSizeInFloat, outBufferSizeInFloat));
52 }
53
54 // reset buffer status by abandon input data in FMQ
resetBuffer()55 void EffectContext::resetBuffer() {
56 auto buffer = static_cast<float*>(mWorkBuffer.data());
57 if (mStatusMQ) {
58 std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
59 }
60 if (mInputMQ) {
61 mInputMQ->read(buffer, mInputMQ->availableToRead());
62 }
63 }
64
dupeFmqWithReopen(IEffect::OpenEffectReturn * effectRet)65 void EffectContext::dupeFmqWithReopen(IEffect::OpenEffectReturn* effectRet) {
66 const size_t inBufferSizeInFloat = mCommon.input.frameCount * mInputFrameSize / sizeof(float);
67 const size_t outBufferSizeInFloat =
68 mCommon.output.frameCount * mOutputFrameSize / sizeof(float);
69 const size_t bufferSize = std::max(inBufferSizeInFloat, outBufferSizeInFloat);
70 if (!mInputMQ) {
71 mInputMQ = std::make_shared<DataMQ>(inBufferSizeInFloat);
72 }
73 if (!mOutputMQ) {
74 mOutputMQ = std::make_shared<DataMQ>(outBufferSizeInFloat);
75 }
76 if (mWorkBuffer.size() != bufferSize) {
77 mWorkBuffer.resize(bufferSize);
78 }
79 dupeFmq(effectRet);
80 }
81
dupeFmq(IEffect::OpenEffectReturn * effectRet)82 void EffectContext::dupeFmq(IEffect::OpenEffectReturn* effectRet) {
83 if (effectRet && mStatusMQ && mInputMQ && mOutputMQ) {
84 effectRet->statusMQ = mStatusMQ->dupeDesc();
85 effectRet->inputDataMQ = mInputMQ->dupeDesc();
86 effectRet->outputDataMQ = mOutputMQ->dupeDesc();
87 }
88 }
89
getWorkBuffer()90 float* EffectContext::getWorkBuffer() {
91 return static_cast<float*>(mWorkBuffer.data());
92 }
93
getWorkBufferSize() const94 size_t EffectContext::getWorkBufferSize() const {
95 return mWorkBuffer.size();
96 }
97
getStatusFmq() const98 std::shared_ptr<EffectContext::StatusMQ> EffectContext::getStatusFmq() const {
99 return mStatusMQ;
100 }
101
getInputDataFmq() const102 std::shared_ptr<EffectContext::DataMQ> EffectContext::getInputDataFmq() const {
103 return mInputMQ;
104 }
105
getOutputDataFmq() const106 std::shared_ptr<EffectContext::DataMQ> EffectContext::getOutputDataFmq() const {
107 return mOutputMQ;
108 }
109
getInputFrameSize() const110 size_t EffectContext::getInputFrameSize() const {
111 return mInputFrameSize;
112 }
113
getOutputFrameSize() const114 size_t EffectContext::getOutputFrameSize() const {
115 return mOutputFrameSize;
116 }
117
getSessionId() const118 int EffectContext::getSessionId() const {
119 return mCommon.session;
120 }
121
getIoHandle() const122 int EffectContext::getIoHandle() const {
123 return mCommon.ioHandle;
124 }
125
setOutputDevice(const std::vector<aidl::android::media::audio::common::AudioDeviceDescription> & device)126 RetCode EffectContext::setOutputDevice(
127 const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>& device) {
128 mOutputDevice = device;
129 return RetCode::SUCCESS;
130 }
131
132 std::vector<aidl::android::media::audio::common::AudioDeviceDescription>
getOutputDevice()133 EffectContext::getOutputDevice() {
134 return mOutputDevice;
135 }
136
setAudioMode(const aidl::android::media::audio::common::AudioMode & mode)137 RetCode EffectContext::setAudioMode(const aidl::android::media::audio::common::AudioMode& mode) {
138 mMode = mode;
139 return RetCode::SUCCESS;
140 }
getAudioMode()141 aidl::android::media::audio::common::AudioMode EffectContext::getAudioMode() {
142 return mMode;
143 }
144
setAudioSource(const aidl::android::media::audio::common::AudioSource & source)145 RetCode EffectContext::setAudioSource(
146 const aidl::android::media::audio::common::AudioSource& source) {
147 mSource = source;
148 return RetCode::SUCCESS;
149 }
150
getAudioSource()151 aidl::android::media::audio::common::AudioSource EffectContext::getAudioSource() {
152 return mSource;
153 }
154
setVolumeStereo(const Parameter::VolumeStereo & volumeStereo)155 RetCode EffectContext::setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) {
156 mVolumeStereo = volumeStereo;
157 return RetCode::SUCCESS;
158 }
159
getVolumeStereo()160 Parameter::VolumeStereo EffectContext::getVolumeStereo() {
161 return mVolumeStereo;
162 }
163
setCommon(const Parameter::Common & common)164 RetCode EffectContext::setCommon(const Parameter::Common& common) {
165 auto& input = common.input;
166 auto& output = common.output;
167
168 if (input.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT ||
169 output.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT) {
170 LOG(ERROR) << __func__ << " illegal IO, input "
171 << ::android::internal::ToString(input.base.format) << ", output "
172 << ::android::internal::ToString(output.base.format);
173 return RetCode::ERROR_ILLEGAL_PARAMETER;
174 }
175
176 if (auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
177 return ret;
178 }
179
180 mInputChannelCount = getChannelCount(input.base.channelMask);
181 mOutputChannelCount = getChannelCount(output.base.channelMask);
182 if (mInputChannelCount == 0 || mOutputChannelCount == 0) {
183 LOG(ERROR) << __func__ << " illegal channel count input " << mInputChannelCount
184 << ", output " << mOutputChannelCount;
185 return RetCode::ERROR_ILLEGAL_PARAMETER;
186 }
187
188 mCommon = common;
189 return RetCode::SUCCESS;
190 }
191
getCommon()192 Parameter::Common EffectContext::getCommon() {
193 return mCommon;
194 }
195
getStatusEventFlag()196 EventFlag* EffectContext::getStatusEventFlag() {
197 return mEfGroup;
198 }
199
updateIOFrameSize(const Parameter::Common & common)200 RetCode EffectContext::updateIOFrameSize(const Parameter::Common& common) {
201 const auto prevInputFrameSize = mInputFrameSize;
202 const auto prevOutputFrameSize = mOutputFrameSize;
203 mInputFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
204 common.input.base.format, common.input.base.channelMask);
205 mOutputFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
206 common.output.base.format, common.output.base.channelMask);
207
208 // workBuffer and data MQ not allocated yet, no need to update
209 if (mWorkBuffer.size() == 0 || !mInputMQ || !mOutputMQ) {
210 return RetCode::SUCCESS;
211 }
212 // IEffect::reopen introduced in android.hardware.audio.effect-V2
213 if (mVersion < kReopenSupportedVersion) {
214 LOG(WARNING) << __func__ << " skipped for HAL version " << mVersion;
215 return RetCode::SUCCESS;
216 }
217 bool needUpdateMq = false;
218 if (mInputFrameSize != prevInputFrameSize ||
219 mCommon.input.frameCount != common.input.frameCount) {
220 mInputMQ.reset();
221 needUpdateMq = true;
222 }
223 if (mOutputFrameSize != prevOutputFrameSize ||
224 mCommon.output.frameCount != common.output.frameCount) {
225 mOutputMQ.reset();
226 needUpdateMq = true;
227 }
228
229 if (needUpdateMq) {
230 return notifyDataMqUpdate();
231 }
232 return RetCode::SUCCESS;
233 }
234
notifyDataMqUpdate()235 RetCode EffectContext::notifyDataMqUpdate() {
236 if (!mEfGroup) {
237 LOG(ERROR) << __func__ << ": invalid EventFlag group";
238 return RetCode::ERROR_EVENT_FLAG_ERROR;
239 }
240
241 if (const auto ret = mEfGroup->wake(kEventFlagDataMqUpdate); ret != ::android::OK) {
242 LOG(ERROR) << __func__ << ": wake failure with ret " << ret;
243 return RetCode::ERROR_EVENT_FLAG_ERROR;
244 }
245 LOG(VERBOSE) << __func__ << " : signal client for reopen";
246 return RetCode::SUCCESS;
247 }
248
enable()249 RetCode EffectContext::enable() {
250 return RetCode::SUCCESS;
251 }
252
disable()253 RetCode EffectContext::disable() {
254 return RetCode::SUCCESS;
255 }
256
reset()257 RetCode EffectContext::reset() {
258 return RetCode::SUCCESS;
259 }
260
startDraining()261 RetCode EffectContext::startDraining() {
262 mIsDraining = true;
263 return RetCode::SUCCESS;
264 }
265
finishDraining()266 RetCode EffectContext::finishDraining() {
267 mIsDraining = false;
268 return RetCode::SUCCESS;
269 }
270
isDraining()271 bool EffectContext::isDraining() {
272 return mIsDraining;
273 }
274
275 } // namespace aidl::android::hardware::audio::effect
276