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     assert(mFactory != nullptr);
80     assert(mEffect != nullptr);
81     createAidlConversion(effect, sessionId, ioId, desc);
82 }
83 
~EffectHalAidl()84 EffectHalAidl::~EffectHalAidl() {
85     if (mEffect) {
86         if (mIsProxyEffect) {
87             std::static_pointer_cast<EffectProxy>(mEffect)->destroy();
88         } else if (mFactory) {
89             mFactory->destroyEffect(mEffect);
90         }
91     }
92 }
93 
createAidlConversion(std::shared_ptr<IEffect> effect,int32_t sessionId,int32_t ioId,const Descriptor & desc)94 status_t EffectHalAidl::createAidlConversion(
95         std::shared_ptr<IEffect> effect,
96         int32_t sessionId, int32_t ioId,
97         const Descriptor& desc) {
98     const auto& typeUuid = desc.common.id.type;
99     ALOGI("%s create UUID %s", __func__, typeUuid.toString().c_str());
100     if (typeUuid ==
101         ::aidl::android::hardware::audio::effect::getEffectTypeUuidAcousticEchoCanceler()) {
102         mConversion = std::make_unique<android::effect::AidlConversionAec>(effect, sessionId, ioId,
103                                                                            desc, mIsProxyEffect);
104     } else if (typeUuid == ::aidl::android::hardware::audio::effect::
105                                    getEffectTypeUuidAutomaticGainControlV1()) {
106         mConversion = std::make_unique<android::effect::AidlConversionAgc1>(effect, sessionId, ioId,
107                                                                             desc, mIsProxyEffect);
108     } else if (typeUuid == ::aidl::android::hardware::audio::effect::
109                                    getEffectTypeUuidAutomaticGainControlV2()) {
110         mConversion = std::make_unique<android::effect::AidlConversionAgc2>(effect, sessionId, ioId,
111                                                                             desc, mIsProxyEffect);
112     } else if (typeUuid == ::aidl::android::hardware::audio::effect::getEffectTypeUuidBassBoost()) {
113         mConversion = std::make_unique<android::effect::AidlConversionBassBoost>(
114                 effect, sessionId, ioId, desc, mIsProxyEffect);
115     } else if (typeUuid == ::aidl::android::hardware::audio::effect::getEffectTypeUuidDownmix()) {
116         mConversion = std::make_unique<android::effect::AidlConversionDownmix>(
117                 effect, sessionId, ioId, desc, mIsProxyEffect);
118     } else if (typeUuid ==
119                ::aidl::android::hardware::audio::effect::getEffectTypeUuidDynamicsProcessing()) {
120         mConversion = std::make_unique<android::effect::AidlConversionDp>(effect, sessionId, ioId,
121                                                                           desc, mIsProxyEffect);
122     } else if (typeUuid == ::aidl::android::hardware::audio::effect::getEffectTypeUuidEnvReverb()) {
123         mConversion = std::make_unique<android::effect::AidlConversionEnvReverb>(
124                 effect, sessionId, ioId, desc, mIsProxyEffect);
125     } else if (typeUuid == ::aidl::android::hardware::audio::effect::getEffectTypeUuidEqualizer()) {
126         mConversion = std::make_unique<android::effect::AidlConversionEq>(effect, sessionId, ioId,
127                                                                           desc, mIsProxyEffect);
128     } else if (typeUuid ==
129                ::aidl::android::hardware::audio::effect::getEffectTypeUuidHapticGenerator()) {
130         mConversion = std::make_unique<android::effect::AidlConversionHapticGenerator>(
131                 effect, sessionId, ioId, desc, mIsProxyEffect);
132         mIsHapticGenerator = true;
133     } else if (typeUuid ==
134                ::aidl::android::hardware::audio::effect::getEffectTypeUuidLoudnessEnhancer()) {
135         mConversion = std::make_unique<android::effect::AidlConversionLoudnessEnhancer>(
136                 effect, sessionId, ioId, desc, mIsProxyEffect);
137     } else if (typeUuid ==
138                ::aidl::android::hardware::audio::effect::getEffectTypeUuidNoiseSuppression()) {
139         mConversion = std::make_unique<android::effect::AidlConversionNoiseSuppression>(
140                 effect, sessionId, ioId, desc, mIsProxyEffect);
141     } else if (typeUuid ==
142                ::aidl::android::hardware::audio::effect::getEffectTypeUuidPresetReverb()) {
143         mConversion = std::make_unique<android::effect::AidlConversionPresetReverb>(
144                 effect, sessionId, ioId, desc, mIsProxyEffect);
145     } else if (typeUuid ==
146                ::aidl::android::hardware::audio::effect::getEffectTypeUuidSpatializer()) {
147         mConversion = std::make_unique<android::effect::AidlConversionSpatializer>(
148                 effect, sessionId, ioId, desc, mIsProxyEffect);
149     } else if (typeUuid ==
150                ::aidl::android::hardware::audio::effect::getEffectTypeUuidVirtualizer()) {
151         mConversion = std::make_unique<android::effect::AidlConversionVirtualizer>(
152                 effect, sessionId, ioId, desc, mIsProxyEffect);
153     } else if (typeUuid ==
154                ::aidl::android::hardware::audio::effect::getEffectTypeUuidVisualizer()) {
155         mConversion = std::make_unique<android::effect::AidlConversionVisualizer>(
156                 effect, sessionId, ioId, desc, mIsProxyEffect);
157     } else {
158         // For unknown UUID, use vendor extension implementation
159         mConversion = std::make_unique<android::effect::AidlConversionVendorExtension>(
160                 effect, sessionId, ioId, desc, mIsProxyEffect);
161     }
162     return OK;
163 }
164 
setInBuffer(const sp<EffectBufferHalInterface> & buffer)165 status_t EffectHalAidl::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
166     mInBuffer = buffer;
167     return OK;
168 }
169 
setOutBuffer(const sp<EffectBufferHalInterface> & buffer)170 status_t EffectHalAidl::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
171     mOutBuffer = buffer;
172     return OK;
173 }
174 
175 // write to input FMQ here, wait for statusMQ STATUS_OK, and read from output FMQ
process()176 status_t EffectHalAidl::process() {
177     const std::string effectName = mConversion->getDescriptor().common.name;
178     State state = State::INIT;
179     if (mConversion->isBypassing() || !mEffect->getState(&state).isOk() ||
180         state != State::PROCESSING) {
181         ALOGI("%s skipping %s process because it's %s", __func__, effectName.c_str(),
182               mConversion->isBypassing()
183                       ? "bypassing"
184                       : aidl::android::hardware::audio::effect::toString(state).c_str());
185         return -ENODATA;
186     }
187 
188     // check if the DataMq needs any update, timeout at 1ns to avoid being blocked
189     auto efGroup = mConversion->getEventFlagGroup();
190     if (!efGroup) {
191         ALOGE("%s invalid efGroup", __func__);
192         return INVALID_OPERATION;
193     }
194 
195     // use IFactory HAL version because IEffect can be an EffectProxy instance
196     static const int halVersion = [&]() {
197         int version = 0;
198         return mFactory->getInterfaceVersion(&version).isOk() ? version : 0;
199     }();
200 
201     if (uint32_t efState = 0; halVersion >= kReopenSupportedVersion &&
202                               ::android::OK == efGroup->wait(kEventFlagDataMqUpdate, &efState,
203                                                              1 /* ns */, true /* retry */) &&
204                               efState & kEventFlagDataMqUpdate) {
205         ALOGD("%s %s V%d receive dataMQUpdate eventFlag from HAL", __func__, effectName.c_str(),
206               halVersion);
207 
208         mConversion->reopen();
209     }
210     auto statusQ = mConversion->getStatusMQ();
211     auto inputQ = mConversion->getInputMQ();
212     auto outputQ = mConversion->getOutputMQ();
213     if (!statusQ || !statusQ->isValid() || !inputQ || !inputQ->isValid() || !outputQ ||
214         !outputQ->isValid()) {
215         ALOGE("%s invalid FMQ [Status %d I %d O %d]", __func__, statusQ ? statusQ->isValid() : 0,
216               inputQ ? inputQ->isValid() : 0, outputQ ? outputQ->isValid() : 0);
217         return INVALID_OPERATION;
218     }
219 
220     size_t available = inputQ->availableToWrite();
221     const size_t floatsToWrite = std::min(available, mInBuffer->getSize() / sizeof(float));
222     if (floatsToWrite == 0) {
223         ALOGE("%s not able to write, floats in buffer %zu, space in FMQ %zu", __func__,
224               mInBuffer->getSize() / sizeof(float), available);
225         return INVALID_OPERATION;
226     }
227     if (!mInBuffer->audioBuffer() ||
228         !inputQ->write((float*)mInBuffer->audioBuffer()->f32, floatsToWrite)) {
229         ALOGE("%s failed to write %zu floats from audiobuffer %p to inputQ [avail %zu]", __func__,
230               floatsToWrite, mInBuffer->audioBuffer(), inputQ->availableToWrite());
231         return INVALID_OPERATION;
232     }
233 
234     // for V2 audio effect HAL, expect different EventFlag to avoid bit conflict with FMQ_NOT_EMPTY
235     efGroup->wake(halVersion >= kReopenSupportedVersion ? kEventFlagDataMqNotEmpty
236                                                         : kEventFlagNotEmpty);
237 
238     IEffect::Status retStatus{};
239     if (!statusQ->readBlocking(&retStatus, 1)) {
240         ALOGE("%s %s V%d read status from status FMQ failed", __func__, effectName.c_str(),
241               halVersion);
242         return INVALID_OPERATION;
243     }
244     if (retStatus.status != OK || (size_t)retStatus.fmqConsumed != floatsToWrite ||
245         retStatus.fmqProduced == 0) {
246         ALOGE("%s read status failed: %s, consumed %d (of %zu) produced %d", __func__,
247               retStatus.toString().c_str(), retStatus.fmqConsumed, floatsToWrite,
248               retStatus.fmqProduced);
249         return INVALID_OPERATION;
250     }
251 
252     available = outputQ->availableToRead();
253     const size_t floatsToRead = std::min(available, mOutBuffer->getSize() / sizeof(float));
254     if (floatsToRead == 0) {
255         ALOGE("%s not able to read, buffer space %zu, floats in FMQ %zu", __func__,
256               mOutBuffer->getSize() / sizeof(float), available);
257         return INVALID_OPERATION;
258     }
259 
260     float *outputRawBuffer = mOutBuffer->audioBuffer()->f32;
261     std::vector<float> tempBuffer;
262     // keep original data in the output buffer for accumulate mode or HapticGenerator effect
263     if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE || mIsHapticGenerator) {
264         tempBuffer.resize(floatsToRead);
265         outputRawBuffer = tempBuffer.data();
266     }
267     // always read floating point data for AIDL
268     if (!outputQ->read(outputRawBuffer, floatsToRead)) {
269         ALOGE("%s failed to read %zu from outputQ to audioBuffer %p", __func__, floatsToRead,
270               mOutBuffer->audioBuffer());
271         return INVALID_OPERATION;
272     }
273 
274     // HapticGenerator needs special handling because the generated haptic samples should append to
275     // the end of audio samples, the generated haptic data pass back from HAL in output FMQ at same
276     // offset as input buffer, here we skip the audio samples in output FMQ and append haptic
277     // samples to the end of input buffer
278     if (mIsHapticGenerator) {
279         static constexpr float kHalFloatSampleLimit = 2.0f;
280         assert(floatsToRead == floatsToWrite);
281         const auto audioChNum = mConversion->getAudioChannelCount();
282         const auto audioSamples =
283                 floatsToWrite * audioChNum / (audioChNum + mConversion->getHapticChannelCount());
284         // accumulate or copy input to output, haptic samples remains all zero
285         if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
286             accumulate_float(mOutBuffer->audioBuffer()->f32, mInBuffer->audioBuffer()->f32,
287                              audioSamples);
288         } else {
289             memcpy_to_float_from_float_with_clamping(mOutBuffer->audioBuffer()->f32,
290                                                      mInBuffer->audioBuffer()->f32, audioSamples,
291                                                      kHalFloatSampleLimit);
292         }
293         // append the haptic sample at the end of input audio samples
294         memcpy_to_float_from_float_with_clamping(mInBuffer->audioBuffer()->f32 + audioSamples,
295                                                  outputRawBuffer + audioSamples,
296                                                  floatsToRead - audioSamples, kHalFloatSampleLimit);
297     } else if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
298         accumulate_float(mOutBuffer->audioBuffer()->f32, outputRawBuffer, floatsToRead);
299     }
300 
301     return OK;
302 }
303 
304 // TODO: no one using, maybe deprecate this interface
processReverse()305 status_t EffectHalAidl::processReverse() {
306     ALOGW("%s not implemented yet", __func__);
307     return OK;
308 }
309 
command(uint32_t cmdCode,uint32_t cmdSize,void * pCmdData,uint32_t * replySize,void * pReplyData)310 status_t EffectHalAidl::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData,
311                                 uint32_t* replySize, void* pReplyData) {
312     TIME_CHECK();
313     if (!mConversion) {
314         ALOGE("%s can not handle command %d when conversion not exist", __func__, cmdCode);
315         return INVALID_OPERATION;
316     }
317 
318     return mConversion->handleCommand(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
319 }
320 
getDescriptor(effect_descriptor_t * pDescriptor)321 status_t EffectHalAidl::getDescriptor(effect_descriptor_t* pDescriptor) {
322     TIME_CHECK();
323     if (pDescriptor == nullptr) {
324         ALOGE("%s null descriptor pointer", __func__);
325         return BAD_VALUE;
326     }
327     Descriptor aidlDesc;
328     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getDescriptor(&aidlDesc)));
329 
330     *pDescriptor = VALUE_OR_RETURN_STATUS(
331             ::aidl::android::aidl2legacy_Descriptor_effect_descriptor(aidlDesc));
332     return OK;
333 }
334 
close()335 status_t EffectHalAidl::close() {
336     TIME_CHECK();
337     mEffect->command(CommandId::STOP);
338     return statusTFromBinderStatus(mEffect->close());
339 }
340 
dump(int fd)341 status_t EffectHalAidl::dump(int fd) {
342     TIME_CHECK();
343     return mEffect->dump(fd, nullptr, 0);
344 }
345 
346 } // namespace effect
347 } // namespace android
348