xref: /aosp_15_r20/frameworks/av/media/libaudiohal/impl/EffectHalAidl.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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 #include <cstddef>
18 #include <cstring>
19 #define LOG_TAG "EffectHalAidl"
20 //#define LOG_NDEBUG 0
21 
22 #include <memory>
23 
24 #include <audio_utils/primitives.h>
25 #include <error/expected_utils.h>
26 #include <media/AidlConversionCppNdk.h>
27 #include <media/AidlConversionEffect.h>
28 #include <media/AidlConversionUtil.h>
29 #include <media/EffectsFactoryApi.h>
30 #include <mediautils/TimeCheck.h>
31 #include <system/audio.h>
32 #include <system/audio_effects/effect_uuid.h>
33 #include <utils/Log.h>
34 
35 #include "EffectHalAidl.h"
36 #include "EffectProxy.h"
37 
38 #include <aidl/android/hardware/audio/effect/IEffect.h>
39 
40 #include "effectsAidlConversion/AidlConversionAec.h"
41 #include "effectsAidlConversion/AidlConversionAgc1.h"
42 #include "effectsAidlConversion/AidlConversionAgc2.h"
43 #include "effectsAidlConversion/AidlConversionBassBoost.h"
44 #include "effectsAidlConversion/AidlConversionDownmix.h"
45 #include "effectsAidlConversion/AidlConversionDynamicsProcessing.h"
46 #include "effectsAidlConversion/AidlConversionEnvReverb.h"
47 #include "effectsAidlConversion/AidlConversionEq.h"
48 #include "effectsAidlConversion/AidlConversionHapticGenerator.h"
49 #include "effectsAidlConversion/AidlConversionLoudnessEnhancer.h"
50 #include "effectsAidlConversion/AidlConversionNoiseSuppression.h"
51 #include "effectsAidlConversion/AidlConversionPresetReverb.h"
52 #include "effectsAidlConversion/AidlConversionSpatializer.h"
53 #include "effectsAidlConversion/AidlConversionVendorExtension.h"
54 #include "effectsAidlConversion/AidlConversionVirtualizer.h"
55 #include "effectsAidlConversion/AidlConversionVisualizer.h"
56 
57 using ::aidl::android::aidl_utils::statusTFromBinderStatus;
58 using ::aidl::android::hardware::audio::effect::CommandId;
59 using ::aidl::android::hardware::audio::effect::Descriptor;
60 using ::aidl::android::hardware::audio::effect::IEffect;
61 using ::aidl::android::hardware::audio::effect::IFactory;
62 using ::aidl::android::hardware::audio::effect::kEventFlagDataMqNotEmpty;
63 using ::aidl::android::hardware::audio::effect::kEventFlagDataMqUpdate;
64 using ::aidl::android::hardware::audio::effect::kEventFlagNotEmpty;
65 using ::aidl::android::hardware::audio::effect::kReopenSupportedVersion;
66 using ::aidl::android::hardware::audio::effect::State;
67 
68 namespace android {
69 namespace effect {
70 
EffectHalAidl(const std::shared_ptr<IFactory> & factory,const std::shared_ptr<IEffect> & effect,int32_t sessionId,int32_t ioId,const Descriptor & desc,bool isProxyEffect)71 EffectHalAidl::EffectHalAidl(const std::shared_ptr<IFactory>& factory,
72                              const std::shared_ptr<IEffect>& effect, int32_t sessionId,
73                              int32_t ioId, const Descriptor& desc, bool isProxyEffect)
74     : mFactory(factory),
75       mEffect(effect),
76       mSessionId(sessionId),
77       mIoId(ioId),
78       mIsProxyEffect(isProxyEffect),
79       mHalVersion([factory]() {
80           int version = 0;
81           // use factory HAL version because effect can be an EffectProxy instance
82           return factory->getInterfaceVersion(&version).isOk() ? version : 0;
83       }()),
84       mEventFlagDataMqNotEmpty(mHalVersion >= kReopenSupportedVersion ? kEventFlagDataMqNotEmpty
85                                                                       : kEventFlagNotEmpty) {
86     assert(mFactory != nullptr);
87     assert(mEffect != nullptr);
88     createAidlConversion(effect, sessionId, ioId, desc);
89 }
90 
~EffectHalAidl()91 EffectHalAidl::~EffectHalAidl() {
92     if (mEffect) {
93         if (mIsProxyEffect) {
94             std::static_pointer_cast<EffectProxy>(mEffect)->destroy();
95         } else if (mFactory) {
96             mFactory->destroyEffect(mEffect);
97         }
98     }
99 }
100 
createAidlConversion(std::shared_ptr<IEffect> effect,int32_t sessionId,int32_t ioId,const Descriptor & desc)101 status_t EffectHalAidl::createAidlConversion(
102         std::shared_ptr<IEffect> effect,
103         int32_t sessionId, int32_t ioId,
104         const Descriptor& desc) {
105     const auto& typeUuid = desc.common.id.type;
106     ALOGI("%s create UUID %s", __func__, typeUuid.toString().c_str());
107     if (typeUuid ==
108         ::aidl::android::hardware::audio::effect::getEffectTypeUuidAcousticEchoCanceler()) {
109         mConversion = std::make_unique<android::effect::AidlConversionAec>(effect, sessionId, ioId,
110                                                                            desc, mIsProxyEffect);
111     } else if (typeUuid == ::aidl::android::hardware::audio::effect::
112                                    getEffectTypeUuidAutomaticGainControlV1()) {
113         mConversion = std::make_unique<android::effect::AidlConversionAgc1>(effect, sessionId, ioId,
114                                                                             desc, mIsProxyEffect);
115     } else if (typeUuid == ::aidl::android::hardware::audio::effect::
116                                    getEffectTypeUuidAutomaticGainControlV2()) {
117         mConversion = std::make_unique<android::effect::AidlConversionAgc2>(effect, sessionId, ioId,
118                                                                             desc, mIsProxyEffect);
119     } else if (typeUuid == ::aidl::android::hardware::audio::effect::getEffectTypeUuidBassBoost()) {
120         mConversion = std::make_unique<android::effect::AidlConversionBassBoost>(
121                 effect, sessionId, ioId, desc, mIsProxyEffect);
122     } else if (typeUuid == ::aidl::android::hardware::audio::effect::getEffectTypeUuidDownmix()) {
123         mConversion = std::make_unique<android::effect::AidlConversionDownmix>(
124                 effect, sessionId, ioId, desc, mIsProxyEffect);
125     } else if (typeUuid ==
126                ::aidl::android::hardware::audio::effect::getEffectTypeUuidDynamicsProcessing()) {
127         mConversion = std::make_unique<android::effect::AidlConversionDp>(effect, sessionId, ioId,
128                                                                           desc, mIsProxyEffect);
129     } else if (typeUuid == ::aidl::android::hardware::audio::effect::getEffectTypeUuidEnvReverb()) {
130         mConversion = std::make_unique<android::effect::AidlConversionEnvReverb>(
131                 effect, sessionId, ioId, desc, mIsProxyEffect);
132     } else if (typeUuid == ::aidl::android::hardware::audio::effect::getEffectTypeUuidEqualizer()) {
133         mConversion = std::make_unique<android::effect::AidlConversionEq>(effect, sessionId, ioId,
134                                                                           desc, mIsProxyEffect);
135     } else if (typeUuid ==
136                ::aidl::android::hardware::audio::effect::getEffectTypeUuidHapticGenerator()) {
137         mConversion = std::make_unique<android::effect::AidlConversionHapticGenerator>(
138                 effect, sessionId, ioId, desc, mIsProxyEffect);
139         mIsHapticGenerator = true;
140     } else if (typeUuid ==
141                ::aidl::android::hardware::audio::effect::getEffectTypeUuidLoudnessEnhancer()) {
142         mConversion = std::make_unique<android::effect::AidlConversionLoudnessEnhancer>(
143                 effect, sessionId, ioId, desc, mIsProxyEffect);
144     } else if (typeUuid ==
145                ::aidl::android::hardware::audio::effect::getEffectTypeUuidNoiseSuppression()) {
146         mConversion = std::make_unique<android::effect::AidlConversionNoiseSuppression>(
147                 effect, sessionId, ioId, desc, mIsProxyEffect);
148     } else if (typeUuid ==
149                ::aidl::android::hardware::audio::effect::getEffectTypeUuidPresetReverb()) {
150         mConversion = std::make_unique<android::effect::AidlConversionPresetReverb>(
151                 effect, sessionId, ioId, desc, mIsProxyEffect);
152     } else if (typeUuid ==
153                ::aidl::android::hardware::audio::effect::getEffectTypeUuidSpatializer()) {
154         mConversion = std::make_unique<android::effect::AidlConversionSpatializer>(
155                 effect, sessionId, ioId, desc, mIsProxyEffect);
156     } else if (typeUuid ==
157                ::aidl::android::hardware::audio::effect::getEffectTypeUuidVirtualizer()) {
158         mConversion = std::make_unique<android::effect::AidlConversionVirtualizer>(
159                 effect, sessionId, ioId, desc, mIsProxyEffect);
160     } else if (typeUuid ==
161                ::aidl::android::hardware::audio::effect::getEffectTypeUuidVisualizer()) {
162         mConversion = std::make_unique<android::effect::AidlConversionVisualizer>(
163                 effect, sessionId, ioId, desc, mIsProxyEffect);
164     } else {
165         // For unknown UUID, use vendor extension implementation
166         mConversion = std::make_unique<android::effect::AidlConversionVendorExtension>(
167                 effect, sessionId, ioId, desc, mIsProxyEffect);
168     }
169     mEffectName = mConversion->getDescriptor().common.name;
170     return OK;
171 }
172 
setInBuffer(const sp<EffectBufferHalInterface> & buffer)173 status_t EffectHalAidl::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
174     mInBuffer = buffer;
175     return OK;
176 }
177 
setOutBuffer(const sp<EffectBufferHalInterface> & buffer)178 status_t EffectHalAidl::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
179     mOutBuffer = buffer;
180     return OK;
181 }
182 
183 // write to input FMQ here, wait for statusMQ STATUS_OK, and read from output FMQ
process()184 status_t EffectHalAidl::process() {
185     State state = State::INIT;
186     if (mConversion->isBypassing() || !mEffect->getState(&state).isOk() ||
187         (state != State::PROCESSING && state != State::DRAINING)) {
188         ALOGI("%s skipping process because it's %s", mEffectName.c_str(),
189               mConversion->isBypassing()
190                       ? "bypassing"
191                       : aidl::android::hardware::audio::effect::toString(state).c_str());
192         return -ENODATA;
193     }
194 
195     const std::shared_ptr<android::hardware::EventFlag> efGroup = mConversion->getEventFlagGroup();
196     if (!efGroup) {
197         ALOGE("%s invalid efGroup", mEffectName.c_str());
198         return INVALID_OPERATION;
199     }
200 
201     // reopen if halVersion >= kReopenSupportedVersion and receive kEventFlagDataMqUpdate
202     RETURN_STATUS_IF_ERROR(maybeReopen(efGroup));
203     const size_t samplesWritten = writeToHalInputFmqAndSignal(efGroup);
204     if (0 == samplesWritten) {
205         return INVALID_OPERATION;
206     }
207 
208     RETURN_STATUS_IF_ERROR(waitHalStatusFmq(samplesWritten));
209     RETURN_STATUS_IF_ERROR(readFromHalOutputFmq(samplesWritten));
210     return OK;
211 }
212 
maybeReopen(const std::shared_ptr<android::hardware::EventFlag> & efGroup) const213 status_t EffectHalAidl::maybeReopen(
214         const std::shared_ptr<android::hardware::EventFlag>& efGroup) const {
215     if (mHalVersion < kReopenSupportedVersion) {
216         return OK;
217     }
218 
219     // check if the DataMq needs any update, timeout at 1ns to avoid being blocked
220     if (uint32_t efState = 0; ::android::OK == efGroup->wait(kEventFlagDataMqUpdate, &efState,
221                                                              1 /* ns */, true /* retry */) &&
222                               efState & kEventFlagDataMqUpdate) {
223         ALOGD("%s V%d receive dataMQUpdate eventFlag from HAL", mEffectName.c_str(), mHalVersion);
224         return mConversion->reopen();
225     }
226     return OK;
227 }
228 
writeToHalInputFmqAndSignal(const std::shared_ptr<android::hardware::EventFlag> & efGroup) const229 size_t EffectHalAidl::writeToHalInputFmqAndSignal(
230         const std::shared_ptr<android::hardware::EventFlag>& efGroup) const {
231     const auto inputQ = mConversion->getInputMQ();
232     if (!inputQ || !inputQ->isValid()) {
233         ALOGE("%s invalid input FMQ", mEffectName.c_str());
234         return 0;
235     }
236 
237     const size_t fmqSpaceSamples = inputQ->availableToWrite();
238     const size_t samplesInBuffer =
239             mInBuffer->audioBuffer()->frameCount * mConversion->getInputChannelCount();
240     const size_t samplesToWrite = std::min(fmqSpaceSamples, samplesInBuffer);
241     if (samplesToWrite == 0) {
242         ALOGE("%s not able to write, samplesInBuffer %zu, fmqSpaceSamples %zu", mEffectName.c_str(),
243               samplesInBuffer, fmqSpaceSamples);
244         return 0;
245     }
246 
247     const float* const inputRawBuffer = static_cast<const float*>(mInBuffer->audioBuffer()->f32);
248     if (!inputQ->write(inputRawBuffer, samplesToWrite)) {
249         ALOGE("%s failed to write %zu samples to inputQ [avail %zu]", mEffectName.c_str(),
250               samplesToWrite, inputQ->availableToWrite());
251         return 0;
252     }
253 
254     efGroup->wake(mEventFlagDataMqNotEmpty);
255     return samplesToWrite;
256 }
257 
writeHapticGeneratorData(size_t totalSamples,float * const outputRawBuffer,float * const fmqOutputBuffer) const258 void EffectHalAidl::writeHapticGeneratorData(size_t totalSamples, float* const outputRawBuffer,
259                                              float* const fmqOutputBuffer) const {
260     const auto audioChNum = mConversion->getAudioChannelCount();
261     const auto audioSamples =
262             totalSamples * audioChNum / (audioChNum + mConversion->getHapticChannelCount());
263 
264     static constexpr float kHalFloatSampleLimit = 2.0f;
265     // for HapticGenerator, the input data buffer will be updated
266     float* const inputRawBuffer = static_cast<float*>(mInBuffer->audioBuffer()->f32);
267     // accumulate or copy input to output, haptic samples remains all zero
268     if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
269         accumulate_float(outputRawBuffer, inputRawBuffer, audioSamples);
270     } else {
271         memcpy_to_float_from_float_with_clamping(outputRawBuffer, inputRawBuffer, audioSamples,
272                                                  kHalFloatSampleLimit);
273     }
274     // append the haptic sample at the end of input audio samples
275     memcpy_to_float_from_float_with_clamping(inputRawBuffer + audioSamples,
276                                              fmqOutputBuffer + audioSamples,
277                                              totalSamples - audioSamples, kHalFloatSampleLimit);
278 }
279 
waitHalStatusFmq(size_t samplesWritten) const280 status_t EffectHalAidl::waitHalStatusFmq(size_t samplesWritten) const {
281     const auto statusQ = mConversion->getStatusMQ();
282     if (const bool statusValid = statusQ && statusQ->isValid(); !statusValid) {
283         ALOGE("%s statusFMQ %s", mEffectName.c_str(), statusValid ? "valid" : "invalid");
284         return INVALID_OPERATION;
285     }
286 
287     IEffect::Status retStatus{};
288     if (!statusQ->readBlocking(&retStatus, 1)) {
289         ALOGE("%s V%d read status from status FMQ failed", mEffectName.c_str(), mHalVersion);
290         return INVALID_OPERATION;
291     }
292     if (retStatus.status != OK || (size_t)retStatus.fmqConsumed != samplesWritten ||
293         retStatus.fmqProduced == 0) {
294         ALOGE("%s read status failed: %s, FMQ consumed %d (of %zu) produced %d",
295               mEffectName.c_str(), retStatus.toString().c_str(), retStatus.fmqConsumed,
296               samplesWritten, retStatus.fmqProduced);
297         return INVALID_OPERATION;
298     }
299 
300     return OK;
301 }
302 
readFromHalOutputFmq(size_t samplesWritten) const303 status_t EffectHalAidl::readFromHalOutputFmq(size_t samplesWritten) const {
304     const auto outputQ = mConversion->getOutputMQ();
305     if (const bool outputValid = outputQ && outputQ->isValid(); !outputValid) {
306         ALOGE("%s outputFMQ %s", mEffectName.c_str(), outputValid ? "valid" : "invalid");
307         return INVALID_OPERATION;
308     }
309 
310     const size_t fmqProducedSamples = outputQ->availableToRead();
311     const size_t bufferSpaceSamples =
312             mOutBuffer->audioBuffer()->frameCount * mConversion->getOutputChannelCount();
313     const size_t samplesToRead = std::min(fmqProducedSamples, bufferSpaceSamples);
314     if (samplesToRead == 0) {
315         ALOGE("%s unable to read, bufferSpace %zu, fmqProduced %zu samplesWritten %zu",
316               mEffectName.c_str(), bufferSpaceSamples, fmqProducedSamples, samplesWritten);
317         return INVALID_OPERATION;
318     }
319 
320     float* const outputRawBuffer = static_cast<float*>(mOutBuffer->audioBuffer()->f32);
321     float* fmqOutputBuffer = outputRawBuffer;
322     std::vector<float> tempBuffer;
323     // keep original data in the output buffer for accumulate mode or HapticGenerator effect
324     if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE || mIsHapticGenerator) {
325         tempBuffer.resize(samplesToRead, 0);
326         fmqOutputBuffer = tempBuffer.data();
327     }
328     // always read floating point data for AIDL
329     if (!outputQ->read(fmqOutputBuffer, samplesToRead)) {
330         ALOGE("%s failed to read %zu from outputQ to audioBuffer %p", mEffectName.c_str(),
331               samplesToRead, fmqOutputBuffer);
332         return INVALID_OPERATION;
333     }
334 
335     // HapticGenerator needs special handling because the generated haptic samples should append to
336     // the end of audio samples, the generated haptic data pass back from HAL in output FMQ at same
337     // offset as input buffer, here we skip the audio samples in output FMQ and append haptic
338     // samples to the end of input buffer
339     if (mIsHapticGenerator) {
340         assert(samplesRead == samplesWritten);
341         writeHapticGeneratorData(samplesToRead, outputRawBuffer, fmqOutputBuffer);
342     } else if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
343         accumulate_float(outputRawBuffer, fmqOutputBuffer, samplesToRead);
344     }
345 
346     return OK;
347 }
348 
349 // TODO: no one using, maybe deprecate this interface
processReverse()350 status_t EffectHalAidl::processReverse() {
351     ALOGW("%s not implemented yet", __func__);
352     return OK;
353 }
354 
command(uint32_t cmdCode,uint32_t cmdSize,void * pCmdData,uint32_t * replySize,void * pReplyData)355 status_t EffectHalAidl::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData,
356                                 uint32_t* replySize, void* pReplyData) {
357     TIME_CHECK();
358     if (!mConversion) {
359         ALOGE("%s can not handle command %d when conversion not exist", __func__, cmdCode);
360         return INVALID_OPERATION;
361     }
362 
363     return mConversion->handleCommand(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
364 }
365 
getDescriptor(effect_descriptor_t * pDescriptor)366 status_t EffectHalAidl::getDescriptor(effect_descriptor_t* pDescriptor) {
367     TIME_CHECK();
368     if (pDescriptor == nullptr) {
369         ALOGE("%s null descriptor pointer", __func__);
370         return BAD_VALUE;
371     }
372     Descriptor aidlDesc;
373     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getDescriptor(&aidlDesc)));
374 
375     *pDescriptor = VALUE_OR_RETURN_STATUS(
376             ::aidl::android::aidl2legacy_Descriptor_effect_descriptor(aidlDesc));
377     return OK;
378 }
379 
close()380 status_t EffectHalAidl::close() {
381     TIME_CHECK();
382     mEffect->command(CommandId::STOP);
383     return statusTFromBinderStatus(mEffect->close());
384 }
385 
dump(int fd)386 status_t EffectHalAidl::dump(int fd) {
387     TIME_CHECK();
388     return mEffect->dump(fd, nullptr, 0);
389 }
390 
391 } // namespace effect
392 } // namespace android
393