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