• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.h>
18 
19 #define LOG_TAG "EffectHAL"
20 #define ATRACE_TAG ATRACE_TAG_AUDIO
21 
22 #include "Effect.h"
23 #include "common/all-versions/default/EffectMap.h"
24 
25 #define ATRACE_TAG ATRACE_TAG_AUDIO
26 #include <HidlUtils.h>
27 #include <android/log.h>
28 #include <cutils/properties.h>
29 #include <media/EffectsFactoryApi.h>
30 #include <mediautils/ScopedStatistics.h>
31 #include <sys/syscall.h>
32 #include <system/audio_effects/effect_spatializer.h>
33 #include <util/EffectUtils.h>
34 #include <utils/Trace.h>
35 
36 #include "VersionUtils.h"
37 
38 namespace android {
39 namespace hardware {
40 namespace audio {
41 namespace effect {
42 namespace CPP_VERSION {
43 namespace implementation {
44 
45 #if MAJOR_VERSION <= 6
46 using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::
47         AudioChannelBitfield;
48 #endif
49 using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::HidlUtils;
50 
51 namespace {
52 
53 /**
54  * Some basic scheduling tools.
55  */
56 namespace scheduler {
57 
getCpu()58 int getCpu() {
59     return sched_getcpu();
60 }
61 
getAffinity(pid_t tid)62 uint64_t getAffinity(pid_t tid) {
63     cpu_set_t set;
64     CPU_ZERO_S(sizeof(set), &set);
65 
66     if (sched_getaffinity(tid, sizeof(set), &set)) {
67         ALOGW("%s: for tid:%d returning 0, failed %s", __func__, tid, strerror(errno));
68         return 0;
69     }
70     const int count = CPU_COUNT_S(sizeof(set), &set);
71     uint64_t mask = 0;
72     for (int i = 0; i < CPU_SETSIZE; ++i) {
73         if (CPU_ISSET_S(i, sizeof(set), &set)) {
74             mask |= 1 << i;
75         }
76     }
77     ALOGV("%s: for tid:%d returning cpu count %d mask %llu", __func__, tid, count,
78           (unsigned long long)mask);
79     return mask;
80 }
81 
setAffinity(pid_t tid,uint64_t mask)82 status_t setAffinity(pid_t tid, uint64_t mask) {
83     cpu_set_t set;
84     CPU_ZERO_S(sizeof(set), &set);
85 
86     for (uint64_t m = mask; m != 0;) {
87         uint64_t tz = __builtin_ctz(m);
88         CPU_SET_S(tz, sizeof(set), &set);
89         m &= ~(1 << tz);
90     }
91     if (sched_setaffinity(tid, sizeof(set), &set)) {
92         ALOGW("%s: for tid:%d setting cpu mask %llu failed %s", __func__, tid,
93               (unsigned long long)mask, strerror(errno));
94         return -errno;
95     }
96     ALOGV("%s: for tid:%d setting cpu mask %llu", __func__, tid, (unsigned long long)mask);
97     return OK;
98 }
99 
setPriority(pid_t tid,int policy,int priority)100 __unused status_t setPriority(pid_t tid, int policy, int priority) {
101     struct sched_param param {
102         .sched_priority = priority,
103     };
104     if (sched_setscheduler(tid, policy, &param) != 0) {
105         ALOGW("%s: Cannot set FIFO priority for tid %d to policy %d priority %d  %s", __func__, tid,
106               policy, priority, strerror(errno));
107         return -errno;
108     }
109     ALOGV("%s: Successfully set priority for tid %d to policy %d priority %d", __func__, tid,
110           policy, priority);
111     return NO_ERROR;
112 }
113 
setUtilMin(pid_t tid,uint32_t utilMin)114 status_t setUtilMin(pid_t tid, uint32_t utilMin) {
115     // Currently, there is no wrapper in bionic: b/183240349.
116     struct {
117         uint32_t size;
118         uint32_t sched_policy;
119         uint64_t sched_flags;
120         int32_t sched_nice;
121         uint32_t sched_priority;
122         uint64_t sched_runtime;
123         uint64_t sched_deadline;
124         uint64_t sched_period;
125         uint32_t sched_util_min;
126         uint32_t sched_util_max;
127     } attr{
128             .size = sizeof(attr),
129             .sched_flags = SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP_MIN,
130             .sched_util_min = utilMin,
131     };
132 
133     if (syscall(__NR_sched_setattr, tid, &attr, 0 /* flags */)) {
134         ALOGW("%s: Cannot set sched_util_min for pid %d to %u  %s", __func__, tid, utilMin,
135               strerror(errno));
136         return -errno;
137     }
138     ALOGV("%s: Successfully set sched_util_min for pid %d to %u", __func__, tid, utilMin);
139     return NO_ERROR;
140 }
141 
142 /*
143    Attempts to raise the priority and usage of tid for spatialization.
144    Returns OK if everything works.
145 */
updateSpatializerPriority(pid_t tid)146 status_t updateSpatializerPriority(pid_t tid) {
147     status_t status = OK;
148 
149     const int cpu = getCpu();
150     ALOGV("%s: current CPU:%d", __func__, cpu);
151 
152     const auto currentAffinity = getAffinity(tid);
153     ALOGV("%s: current Affinity:%llx", __func__, (unsigned long long)currentAffinity);
154 
155     // Set the desired CPU core affinity.
156     // Typically this would be done to move the Spatializer effect off of the little cores.
157     // The mid cores and large cores typically have more FP/NEON units
158     // and will advantageously reduce power and prevent glitches due CPU limitations.
159     //
160     // Since this is SOC dependent, we do not set the core affinity here but
161     // prefer to set the util_clamp_min below.
162     //
163     constexpr uint64_t kDefaultAffinity = 0;
164     const int32_t desiredAffinity =
165             property_get_int32("audio.spatializer.effect.affinity", kDefaultAffinity);
166     if (desiredAffinity != 0 && (desiredAffinity & ~currentAffinity) == 0) {
167         const status_t localStatus = setAffinity(tid, desiredAffinity);
168         status = status ? status : localStatus;
169     }
170 
171     // Set the util_clamp_min.
172     // This is beneficial to reduce glitches when starting up, or due to scheduler
173     // thread statistics reset (e.g. core migration), which cause the CPU frequency to drop
174     // to minimum.
175     //
176     // Experimentation has found that moving to a mid core over a little core reduces
177     // power if the mid core (e.g. A76/78) has more (e.g. 2x) FP/NEON units
178     // than the little core (e.g. A55).
179     // A possible value is 300.
180     //
181     constexpr uint32_t kUtilMin = 0;
182     const int32_t utilMin = property_get_int32("audio.spatializer.effect.util_clamp_min", kUtilMin);
183     if (utilMin > 0 && utilMin <= 1024) {
184         const status_t localStatus = setUtilMin(tid, utilMin);
185         status = status ? status : localStatus;
186     }
187 
188 #if 0
189     // Provided for local vendor testing but not enabled as audioserver does this for us.
190     //
191     // Set priority if specified.
192     constexpr int32_t kRTPriorityMin = 1;
193     constexpr int32_t kRTPriorityMax = 3;
194     const int32_t priorityBoost =
195             property_get_int32("audio.spatializer.priority", kRTPriorityMin);
196     if (priorityBoost >= kRTPriorityMin && priorityBoost <= kRTPriorityMax) {
197         const status_t localStatus = scheduler::setPriority(threadId, SCHED_FIFO, priorityBoost);
198         status = status ? status : localStatus;
199     }
200 #endif
201 
202     return status;
203 }
204 
205 }  // namespace scheduler
206 
207 #define SCOPED_STATS()                                                       \
208     ::android::mediautils::ScopedStatistics scopedStatistics {               \
209         std::string("EffectHal::").append(__func__), mEffectHal->mStatistics \
210     }
211 
212 class ProcessThread : public Thread {
213    public:
214     // ProcessThread's lifespan never exceeds Effect's lifespan.
ProcessThread(std::atomic<bool> * stop,effect_handle_t effect,std::atomic<audio_buffer_t * > * inBuffer,std::atomic<audio_buffer_t * > * outBuffer,Effect::StatusMQ * statusMQ,EventFlag * efGroup,Effect * effectHal)215      ProcessThread(std::atomic<bool>* stop, effect_handle_t effect,
216                    std::atomic<audio_buffer_t*>* inBuffer, std::atomic<audio_buffer_t*>* outBuffer,
217                    Effect::StatusMQ* statusMQ, EventFlag* efGroup, Effect* effectHal)
218          : Thread(false /*canCallJava*/),
219            mStop(stop),
220            mEffect(effect),
221            mHasProcessReverse((*mEffect)->process_reverse != NULL),
222            mInBuffer(inBuffer),
223            mOutBuffer(outBuffer),
224            mStatusMQ(statusMQ),
225            mEfGroup(efGroup),
226            mEffectHal(effectHal) {}
~ProcessThread()227      virtual ~ProcessThread() {}
228 
229    private:
230     std::atomic<bool>* mStop;
231     effect_handle_t mEffect;
232     bool mHasProcessReverse;
233     std::atomic<audio_buffer_t*>* mInBuffer;
234     std::atomic<audio_buffer_t*>* mOutBuffer;
235     Effect::StatusMQ* mStatusMQ;
236     EventFlag* mEfGroup;
237     Effect* const mEffectHal;
238 
239     bool threadLoop() override;
240 };
241 
threadLoop()242 bool ProcessThread::threadLoop() {
243     // This implementation doesn't return control back to the Thread until it decides to stop,
244     // as the Thread uses mutexes, and this can lead to priority inversion.
245     while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
246         uint32_t efState = 0;
247         mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL), &efState);
248         if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL)) ||
249             (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT))) {
250             continue;  // Nothing to do or time to quit.
251         }
252         Result retval = Result::OK;
253         if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_REVERSE) &&
254             !mHasProcessReverse) {
255             retval = Result::NOT_SUPPORTED;
256         }
257 
258         if (retval == Result::OK) {
259             // affects both buffer pointers and their contents.
260             std::atomic_thread_fence(std::memory_order_acquire);
261             int32_t processResult;
262             audio_buffer_t* inBuffer =
263                 std::atomic_load_explicit(mInBuffer, std::memory_order_relaxed);
264             audio_buffer_t* outBuffer =
265                 std::atomic_load_explicit(mOutBuffer, std::memory_order_relaxed);
266             if (inBuffer != nullptr && outBuffer != nullptr) {
267                 // Time this effect process
268                 SCOPED_STATS();
269 
270                 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS)) {
271                     processResult = (*mEffect)->process(mEffect, inBuffer, outBuffer);
272                 } else {
273                     processResult = (*mEffect)->process_reverse(mEffect, inBuffer, outBuffer);
274                 }
275                 std::atomic_thread_fence(std::memory_order_release);
276             } else {
277                 ALOGE("processing buffers were not set before calling 'process'");
278                 processResult = -ENODEV;
279             }
280             switch (processResult) {
281                 case 0:
282                     retval = Result::OK;
283                     break;
284                 case -ENODATA:
285                     retval = Result::INVALID_STATE;
286                     break;
287                 case -EINVAL:
288                     retval = Result::INVALID_ARGUMENTS;
289                     break;
290                 default:
291                     retval = Result::NOT_INITIALIZED;
292             }
293         }
294         if (!mStatusMQ->write(&retval)) {
295             ALOGW("status message queue write failed");
296         }
297         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING));
298     }
299 
300     return false;
301 }
302 
303 }  // namespace
304 
305 // static
306 const char* Effect::sContextResultOfCommand = "returned status";
307 const char* Effect::sContextCallToCommand = "error";
308 const char* Effect::sContextCallFunction = sContextCallToCommand;
309 const char* Effect::sContextConversion = "conversion";
310 
Effect(bool isInput,effect_handle_t handle)311 Effect::Effect(bool isInput, effect_handle_t handle)
312     : mIsInput(isInput), mHandle(handle), mEfGroup(nullptr), mStopProcessThread(false) {
313     (void)mIsInput;  // prevent 'unused field' warnings in pre-V7 versions.
314 }
315 
~Effect()316 Effect::~Effect() {
317     ATRACE_CALL();
318     auto [_, handle] = closeImpl();
319     if (mProcessThread.get()) {
320         ATRACE_NAME("mProcessThread->join");
321         status_t status = mProcessThread->join();
322         ALOGE_IF(status, "processing thread exit error: %s", strerror(-status));
323     }
324     if (mEfGroup) {
325         status_t status = EventFlag::deleteEventFlag(&mEfGroup);
326         ALOGE_IF(status, "processing MQ event flag deletion error: %s", strerror(-status));
327     }
328     mInBuffer.clear();
329     mOutBuffer.clear();
330 #if MAJOR_VERSION <= 5
331     int status = EffectRelease(handle);
332     ALOGW_IF(status, "Error releasing effect %p: %s", handle, strerror(-status));
333 #endif
334     EffectMap::getInstance().remove(handle);
335 }
336 
337 // static
338 template <typename T>
alignedSizeIn(size_t s)339 size_t Effect::alignedSizeIn(size_t s) {
340     return (s + sizeof(T) - 1) / sizeof(T);
341 }
342 
343 // static
344 template <typename T>
hidlVecToHal(const hidl_vec<T> & vec,uint32_t * halDataSize)345 std::unique_ptr<uint8_t[]> Effect::hidlVecToHal(const hidl_vec<T>& vec, uint32_t* halDataSize) {
346     // Due to bugs in HAL, they may attempt to write into the provided
347     // input buffer. The original binder buffer is r/o, thus it is needed
348     // to create a r/w version.
349     *halDataSize = vec.size() * sizeof(T);
350     std::unique_ptr<uint8_t[]> halData(new uint8_t[*halDataSize]);
351     memcpy(&halData[0], &vec[0], *halDataSize);
352     return halData;
353 }
354 
355 #if MAJOR_VERSION <= 6
356 
effectAuxChannelsConfigFromHal(const channel_config_t & halConfig,EffectAuxChannelsConfig * config)357 void Effect::effectAuxChannelsConfigFromHal(const channel_config_t& halConfig,
358                                             EffectAuxChannelsConfig* config) {
359     config->mainChannels = AudioChannelBitfield(halConfig.main_channels);
360     config->auxChannels = AudioChannelBitfield(halConfig.aux_channels);
361 }
362 
363 // static
effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig & config,channel_config_t * halConfig)364 void Effect::effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig& config,
365                                           channel_config_t* halConfig) {
366     halConfig->main_channels = static_cast<audio_channel_mask_t>(config.mainChannels);
367     halConfig->aux_channels = static_cast<audio_channel_mask_t>(config.auxChannels);
368 }
369 
370 #else  // MAJOR_VERSION <= 6
371 
effectAuxChannelsConfigFromHal(const channel_config_t & halConfig,EffectAuxChannelsConfig * config)372 void Effect::effectAuxChannelsConfigFromHal(const channel_config_t& halConfig,
373                                             EffectAuxChannelsConfig* config) {
374     (void)HidlUtils::audioChannelMaskFromHal(halConfig.main_channels, mIsInput,
375                                              &config->mainChannels);
376     (void)HidlUtils::audioChannelMaskFromHal(halConfig.aux_channels, mIsInput,
377                                              &config->auxChannels);
378 }
379 
380 // static
effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig & config,channel_config_t * halConfig)381 void Effect::effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig& config,
382                                           channel_config_t* halConfig) {
383     (void)HidlUtils::audioChannelMaskToHal(config.mainChannels, &halConfig->main_channels);
384     (void)HidlUtils::audioChannelMaskToHal(config.auxChannels, &halConfig->aux_channels);
385 }
386 
387 #endif  // MAJOR_VERSION <= 6
388 
389 // static
effectOffloadParamToHal(const EffectOffloadParameter & offload,effect_offload_param_t * halOffload)390 void Effect::effectOffloadParamToHal(const EffectOffloadParameter& offload,
391                                      effect_offload_param_t* halOffload) {
392     halOffload->isOffload = offload.isOffload;
393     halOffload->ioHandle = offload.ioHandle;
394 }
395 
396 // static
parameterToHal(uint32_t paramSize,const void * paramData,uint32_t valueSize,const void ** valueData,std::vector<uint8_t> * halParamBuffer)397 bool Effect::parameterToHal(uint32_t paramSize, const void* paramData, uint32_t valueSize,
398                             const void** valueData, std::vector<uint8_t>* halParamBuffer) {
399     constexpr size_t kMaxSize = EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t);
400     if (paramSize > kMaxSize) {
401         ALOGE("%s: Parameter size is too big: %" PRIu32, __func__, paramSize);
402         return false;
403     }
404     size_t valueOffsetFromData = alignedSizeIn<uint32_t>(paramSize) * sizeof(uint32_t);
405     if (valueOffsetFromData > kMaxSize) {
406         ALOGE("%s: Aligned parameter size is too big: %zu", __func__, valueOffsetFromData);
407         return false;
408     }
409     if (valueSize > kMaxSize - valueOffsetFromData) {
410         ALOGE("%s: Value size is too big: %" PRIu32 ", max size is %zu", __func__, valueSize,
411               kMaxSize - valueOffsetFromData);
412         android_errorWriteLog(0x534e4554, "237291425");
413         return false;
414     }
415     size_t halParamBufferSize = sizeof(effect_param_t) + valueOffsetFromData + valueSize;
416     halParamBuffer->resize(halParamBufferSize, 0);
417     effect_param_t* halParam = reinterpret_cast<effect_param_t*>(halParamBuffer->data());
418     halParam->psize = paramSize;
419     halParam->vsize = valueSize;
420     memcpy(halParam->data, paramData, paramSize);
421     if (valueData) {
422         if (*valueData) {
423             // Value data is provided.
424             memcpy(halParam->data + valueOffsetFromData, *valueData, valueSize);
425         } else {
426             // The caller needs the pointer to the value data location.
427             *valueData = halParam->data + valueOffsetFromData;
428         }
429     }
430     return true;
431 }
432 
analyzeCommandStatus(const char * commandName,const char * context,status_t status)433 Result Effect::analyzeCommandStatus(const char* commandName, const char* context, status_t status) {
434     return analyzeStatus("command", commandName, context, status);
435 }
436 
analyzeStatus(const char * funcName,const char * subFuncName,const char * contextDescription,status_t status)437 Result Effect::analyzeStatus(const char* funcName, const char* subFuncName,
438                              const char* contextDescription, status_t status) {
439     if (status != OK) {
440         ALOGW("Effect %p %s %s %s: %s", mHandle, funcName, subFuncName, contextDescription,
441               strerror(-status));
442     }
443     switch (status) {
444         case OK:
445             return Result::OK;
446         case -EINVAL:
447             return Result::INVALID_ARGUMENTS;
448         case -ENODATA:
449             return Result::INVALID_STATE;
450         case -ENODEV:
451             return Result::NOT_INITIALIZED;
452         case -ENOMEM:
453             return Result::RESULT_TOO_BIG;
454         case -ENOSYS:
455             return Result::NOT_SUPPORTED;
456         default:
457             return Result::INVALID_STATE;
458     }
459 }
460 
461 #define RETURN_IF_EFFECT_CLOSED()          \
462     if (mHandle == kInvalidEffectHandle) { \
463         return Result::INVALID_STATE;      \
464     }
465 #define RETURN_RESULT_IF_EFFECT_CLOSED(result)   \
466     if (mHandle == kInvalidEffectHandle) {       \
467         _hidl_cb(Result::INVALID_STATE, result); \
468         return Void();                           \
469     }
470 
getConfigImpl(int commandCode,const char * commandName,GetConfigCallback _hidl_cb)471 Return<void> Effect::getConfigImpl(int commandCode, const char* commandName,
472                                    GetConfigCallback _hidl_cb) {
473     RETURN_RESULT_IF_EFFECT_CLOSED(EffectConfig());
474     uint32_t halResultSize = sizeof(effect_config_t);
475     effect_config_t halConfig{};
476     status_t status =
477         (*mHandle)->command(mHandle, commandCode, 0, NULL, &halResultSize, &halConfig);
478     EffectConfig config;
479     if (status == OK) {
480         status = EffectUtils::effectConfigFromHal(halConfig, mIsInput, &config);
481     }
482     _hidl_cb(analyzeCommandStatus(commandName, sContextCallToCommand, status), config);
483     return Void();
484 }
485 
getCurrentConfigImpl(uint32_t featureId,uint32_t configSize,GetCurrentConfigSuccessCallback onSuccess)486 Result Effect::getCurrentConfigImpl(uint32_t featureId, uint32_t configSize,
487                                     GetCurrentConfigSuccessCallback onSuccess) {
488     if (configSize > kMaxDataSize - sizeof(uint32_t)) {
489         ALOGE("%s: Config size is too big: %" PRIu32, __func__, configSize);
490         android_errorWriteLog(0x534e4554, "240266798");
491         return Result::INVALID_ARGUMENTS;
492     }
493     uint32_t halCmd = featureId;
494     std::vector<uint32_t> halResult(alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize), 0);
495     uint32_t halResultSize = 0;
496     return sendCommandReturningStatusAndData(
497             EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG", sizeof(uint32_t), &halCmd,
498             &halResultSize, &halResult[0], sizeof(uint32_t), [&] { onSuccess(&halResult[1]); });
499 }
500 
getParameterImpl(uint32_t paramSize,const void * paramData,uint32_t requestValueSize,uint32_t replyValueSize,GetParameterSuccessCallback onSuccess)501 Result Effect::getParameterImpl(uint32_t paramSize, const void* paramData,
502                                 uint32_t requestValueSize, uint32_t replyValueSize,
503                                 GetParameterSuccessCallback onSuccess) {
504     // As it is unknown what method HAL uses for copying the provided parameter data,
505     // it is safer to make sure that input and output buffers do not overlap.
506     std::vector<uint8_t> halCmdBuffer;
507     if (!parameterToHal(paramSize, paramData, requestValueSize, nullptr, &halCmdBuffer)) {
508         return Result::INVALID_ARGUMENTS;
509     }
510     const void* valueData = nullptr;
511     std::vector<uint8_t> halParamBuffer;
512     if (!parameterToHal(paramSize, paramData, replyValueSize, &valueData, &halParamBuffer)) {
513         return Result::INVALID_ARGUMENTS;
514     }
515     uint32_t halParamBufferSize = halParamBuffer.size();
516 
517     return sendCommandReturningStatusAndData(
518         EFFECT_CMD_GET_PARAM, "GET_PARAM", halCmdBuffer.size(), &halCmdBuffer[0],
519         &halParamBufferSize, &halParamBuffer[0], sizeof(effect_param_t), [&] {
520             effect_param_t* halParam = reinterpret_cast<effect_param_t*>(&halParamBuffer[0]);
521             onSuccess(halParam->vsize, valueData);
522         });
523 }
524 
getSupportedConfigsImpl(uint32_t featureId,uint32_t maxConfigs,uint32_t configSize,GetSupportedConfigsSuccessCallback onSuccess)525 Result Effect::getSupportedConfigsImpl(uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
526                                        GetSupportedConfigsSuccessCallback onSuccess) {
527     if (maxConfigs != 0 && configSize > (kMaxDataSize - 2 * sizeof(uint32_t)) / maxConfigs) {
528         ALOGE("%s: Config size is too big: %" PRIu32, __func__, configSize);
529         return Result::INVALID_ARGUMENTS;
530     }
531     uint32_t halCmd[2] = {featureId, maxConfigs};
532     uint32_t halResultSize = 2 * sizeof(uint32_t) + maxConfigs * configSize;
533     std::vector<uint8_t> halResult(static_cast<size_t>(halResultSize), 0);
534     return sendCommandReturningStatusAndData(
535         EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, "GET_FEATURE_SUPPORTED_CONFIGS", sizeof(halCmd),
536         halCmd, &halResultSize, &halResult[0], 2 * sizeof(uint32_t), [&] {
537             uint32_t* halResult32 = reinterpret_cast<uint32_t*>(&halResult[0]);
538             uint32_t supportedConfigs = *(++halResult32);  // skip status field
539             if (supportedConfigs > maxConfigs) supportedConfigs = maxConfigs;
540             onSuccess(supportedConfigs, ++halResult32);
541         });
542 }
543 
prepareForProcessing(prepareForProcessing_cb _hidl_cb)544 Return<void> Effect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
545     RETURN_RESULT_IF_EFFECT_CLOSED(StatusMQ::Descriptor());
546     status_t status;
547     // Create message queue.
548     if (mStatusMQ) {
549         ALOGE("the client attempts to call prepareForProcessing_cb twice");
550         _hidl_cb(Result::INVALID_STATE, StatusMQ::Descriptor());
551         return Void();
552     }
553     std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1, true /*EventFlag*/));
554     if (!tempStatusMQ->isValid()) {
555         ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
556         _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
557         return Void();
558     }
559     status = EventFlag::createEventFlag(tempStatusMQ->getEventFlagWord(), &mEfGroup);
560     if (status != OK || !mEfGroup) {
561         ALOGE("failed creating event flag for status MQ: %s", strerror(-status));
562         _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
563         return Void();
564     }
565 
566     // Create and launch the thread.
567     mProcessThread = new ProcessThread(&mStopProcessThread, mHandle, &mHalInBufferPtr,
568                                        &mHalOutBufferPtr, tempStatusMQ.get(), mEfGroup, this);
569     status = mProcessThread->run("effect", PRIORITY_URGENT_AUDIO);
570     if (status != OK) {
571         ALOGW("failed to start effect processing thread: %s", strerror(-status));
572         _hidl_cb(Result::INVALID_ARGUMENTS, MQDescriptorSync<Result>());
573         return Void();
574     }
575 
576     // For a spatializer effect, we perform scheduler adjustments to reduce glitches and power.
577     // We do it here instead of the ProcessThread::threadLoop to ensure that mHandle is valid.
578     if (effect_descriptor_t halDescriptor{};
579         (*mHandle)->get_descriptor(mHandle, &halDescriptor) == NO_ERROR &&
580         memcmp(&halDescriptor.type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0) {
581         const status_t status = scheduler::updateSpatializerPriority(mProcessThread->getTid());
582         ALOGW_IF(status != OK, "Failed to update Spatializer priority");
583     }
584 
585     mStatusMQ = std::move(tempStatusMQ);
586     _hidl_cb(Result::OK, *mStatusMQ->getDesc());
587     return Void();
588 }
589 
setProcessBuffers(const AudioBuffer & inBuffer,const AudioBuffer & outBuffer)590 Return<Result> Effect::setProcessBuffers(const AudioBuffer& inBuffer,
591                                          const AudioBuffer& outBuffer) {
592     RETURN_IF_EFFECT_CLOSED();
593     AudioBufferManager& manager = AudioBufferManager::getInstance();
594     sp<AudioBufferWrapper> tempInBuffer, tempOutBuffer;
595     if (!manager.wrap(inBuffer, &tempInBuffer)) {
596         ALOGE("Could not map memory of the input buffer");
597         return Result::INVALID_ARGUMENTS;
598     }
599     if (!manager.wrap(outBuffer, &tempOutBuffer)) {
600         ALOGE("Could not map memory of the output buffer");
601         return Result::INVALID_ARGUMENTS;
602     }
603     mInBuffer = tempInBuffer;
604     mOutBuffer = tempOutBuffer;
605     // The processing thread only reads these pointers after waking up by an event flag,
606     // so it's OK to update the pair non-atomically.
607     mHalInBufferPtr.store(mInBuffer->getHalBuffer(), std::memory_order_release);
608     mHalOutBufferPtr.store(mOutBuffer->getHalBuffer(), std::memory_order_release);
609     return Result::OK;
610 }
611 
sendCommand(int commandCode,const char * commandName)612 Result Effect::sendCommand(int commandCode, const char* commandName) {
613     return sendCommand(commandCode, commandName, 0, NULL);
614 }
615 
sendCommand(int commandCode,const char * commandName,uint32_t size,void * data)616 Result Effect::sendCommand(int commandCode, const char* commandName, uint32_t size, void* data) {
617     RETURN_IF_EFFECT_CLOSED();
618     status_t status = (*mHandle)->command(mHandle, commandCode, size, data, 0, NULL);
619     return analyzeCommandStatus(commandName, sContextCallToCommand, status);
620 }
621 
sendCommandReturningData(int commandCode,const char * commandName,uint32_t * replySize,void * replyData)622 Result Effect::sendCommandReturningData(int commandCode, const char* commandName,
623                                         uint32_t* replySize, void* replyData) {
624     return sendCommandReturningData(commandCode, commandName, 0, NULL, replySize, replyData);
625 }
626 
sendCommandReturningData(int commandCode,const char * commandName,uint32_t size,void * data,uint32_t * replySize,void * replyData)627 Result Effect::sendCommandReturningData(int commandCode, const char* commandName, uint32_t size,
628                                         void* data, uint32_t* replySize, void* replyData) {
629     RETURN_IF_EFFECT_CLOSED();
630     uint32_t expectedReplySize = *replySize;
631     status_t status = (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
632     if (status == OK && *replySize != expectedReplySize) {
633         status = -ENODATA;
634     }
635     return analyzeCommandStatus(commandName, sContextCallToCommand, status);
636 }
637 
sendCommandReturningStatus(int commandCode,const char * commandName)638 Result Effect::sendCommandReturningStatus(int commandCode, const char* commandName) {
639     return sendCommandReturningStatus(commandCode, commandName, 0, NULL);
640 }
641 
sendCommandReturningStatus(int commandCode,const char * commandName,uint32_t size,void * data)642 Result Effect::sendCommandReturningStatus(int commandCode, const char* commandName, uint32_t size,
643                                           void* data) {
644     uint32_t replyCmdStatus;
645     uint32_t replySize = sizeof(uint32_t);
646     return sendCommandReturningStatusAndData(commandCode, commandName, size, data, &replySize,
647                                              &replyCmdStatus, replySize, [] {});
648 }
649 
sendCommandReturningStatusAndData(int commandCode,const char * commandName,uint32_t size,void * data,uint32_t * replySize,void * replyData,uint32_t minReplySize,CommandSuccessCallback onSuccess)650 Result Effect::sendCommandReturningStatusAndData(int commandCode, const char* commandName,
651                                                  uint32_t size, void* data, uint32_t* replySize,
652                                                  void* replyData, uint32_t minReplySize,
653                                                  CommandSuccessCallback onSuccess) {
654     RETURN_IF_EFFECT_CLOSED();
655     status_t status = (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
656     Result retval;
657     if (status == OK && minReplySize >= sizeof(uint32_t) && *replySize >= minReplySize) {
658         uint32_t commandStatus = *reinterpret_cast<uint32_t*>(replyData);
659         retval = analyzeCommandStatus(commandName, sContextResultOfCommand, commandStatus);
660         if (commandStatus == OK) {
661             onSuccess();
662         }
663     } else {
664         retval = analyzeCommandStatus(commandName, sContextCallToCommand, status);
665     }
666     return retval;
667 }
668 
setConfigImpl(int commandCode,const char * commandName,const EffectConfig & config,const sp<IEffectBufferProviderCallback> & inputBufferProvider,const sp<IEffectBufferProviderCallback> & outputBufferProvider)669 Result Effect::setConfigImpl(int commandCode, const char* commandName, const EffectConfig& config,
670                              const sp<IEffectBufferProviderCallback>& inputBufferProvider,
671                              const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
672     effect_config_t halConfig;
673     EffectUtils::effectConfigToHal(config, &halConfig);
674     if (inputBufferProvider != 0) {
675         LOG_FATAL("Using input buffer provider is not supported");
676     }
677     if (outputBufferProvider != 0) {
678         LOG_FATAL("Using output buffer provider is not supported");
679     }
680     return sendCommandReturningStatus(commandCode, commandName, sizeof(effect_config_t),
681                                       &halConfig);
682 }
683 
setParameterImpl(uint32_t paramSize,const void * paramData,uint32_t valueSize,const void * valueData)684 Result Effect::setParameterImpl(uint32_t paramSize, const void* paramData, uint32_t valueSize,
685                                 const void* valueData) {
686     std::vector<uint8_t> halParamBuffer;
687     if (!parameterToHal(paramSize, paramData, valueSize, &valueData, &halParamBuffer)) {
688         return Result::INVALID_ARGUMENTS;
689     }
690     return sendCommandReturningStatus(EFFECT_CMD_SET_PARAM, "SET_PARAM", halParamBuffer.size(),
691                                       &halParamBuffer[0]);
692 }
693 
694 // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow.
init()695 Return<Result> Effect::init() {
696     return sendCommandReturningStatus(EFFECT_CMD_INIT, "INIT");
697 }
698 
setConfig(const EffectConfig & config,const sp<IEffectBufferProviderCallback> & inputBufferProvider,const sp<IEffectBufferProviderCallback> & outputBufferProvider)699 Return<Result> Effect::setConfig(const EffectConfig& config,
700                                  const sp<IEffectBufferProviderCallback>& inputBufferProvider,
701                                  const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
702     return setConfigImpl(EFFECT_CMD_SET_CONFIG, "SET_CONFIG", config, inputBufferProvider,
703                          outputBufferProvider);
704 }
705 
reset()706 Return<Result> Effect::reset() {
707     return sendCommand(EFFECT_CMD_RESET, "RESET");
708 }
709 
enable()710 Return<Result> Effect::enable() {
711     return sendCommandReturningStatus(EFFECT_CMD_ENABLE, "ENABLE");
712 }
713 
disable()714 Return<Result> Effect::disable() {
715     return sendCommandReturningStatus(EFFECT_CMD_DISABLE, "DISABLE");
716 }
717 
setAudioSource(AudioSource source)718 Return<Result> Effect::setAudioSource(
719 #if MAJOR_VERSION <= 6
720         AudioSource source
721 #else
722         const AudioSource& source
723 #endif
724 ) {
725     audio_source_t halSource;
726     if (status_t status = HidlUtils::audioSourceToHal(source, &halSource); status == NO_ERROR) {
727         uint32_t halSourceParam = static_cast<uint32_t>(halSource);
728         return sendCommand(EFFECT_CMD_SET_AUDIO_SOURCE, "SET_AUDIO_SOURCE", sizeof(uint32_t),
729                            &halSourceParam);
730     } else {
731         return analyzeStatus(__func__, "audioSourceToHal", sContextConversion, status);
732     }
733 }
734 
735 #if MAJOR_VERSION <= 6
736 
setDevice(AudioDeviceBitfield device)737 Return<Result> Effect::setDevice(AudioDeviceBitfield device) {
738     uint32_t halDevice = static_cast<uint32_t>(device);
739     return sendCommand(EFFECT_CMD_SET_DEVICE, "SET_DEVICE", sizeof(uint32_t), &halDevice);
740 }
741 
setInputDevice(AudioDeviceBitfield device)742 Return<Result> Effect::setInputDevice(AudioDeviceBitfield device) {
743     uint32_t halDevice = static_cast<uint32_t>(device);
744     return sendCommand(EFFECT_CMD_SET_INPUT_DEVICE, "SET_INPUT_DEVICE", sizeof(uint32_t),
745                        &halDevice);
746 }
747 
748 #else  // MAJOR_VERSION <= 6
749 
setDevice(const DeviceAddress & device)750 Return<Result> Effect::setDevice(const DeviceAddress& device) {
751     audio_devices_t halDevice;
752     char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
753     if (status_t status = HidlUtils::deviceAddressToHal(device, &halDevice, halDeviceAddress);
754         status == NO_ERROR) {
755         uint32_t halDeviceParam = static_cast<uint32_t>(halDevice);
756         return sendCommand(EFFECT_CMD_SET_DEVICE, "SET_DEVICE", sizeof(uint32_t), &halDeviceParam);
757     } else {
758         return analyzeStatus(__func__, "deviceAddressToHal", sContextConversion, status);
759     }
760 }
761 
setInputDevice(const DeviceAddress & device)762 Return<Result> Effect::setInputDevice(const DeviceAddress& device) {
763     audio_devices_t halDevice;
764     char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
765     if (status_t status = HidlUtils::deviceAddressToHal(device, &halDevice, halDeviceAddress);
766         status == NO_ERROR) {
767         uint32_t halDeviceParam = static_cast<uint32_t>(halDevice);
768         return sendCommand(EFFECT_CMD_SET_INPUT_DEVICE, "SET_INPUT_DEVICE", sizeof(uint32_t),
769                            &halDeviceParam);
770     } else {
771         return analyzeStatus(__func__, "deviceAddressToHal", sContextConversion, status);
772     }
773 }
774 
775 #endif  // MAJOR_VERSION <= 6
776 
setAndGetVolume(const hidl_vec<uint32_t> & volumes,setAndGetVolume_cb _hidl_cb)777 Return<void> Effect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
778                                      setAndGetVolume_cb _hidl_cb) {
779     uint32_t halDataSize;
780     std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
781     uint32_t halResultSize = halDataSize;
782     std::vector<uint32_t> halResult(volumes.size(), 0);
783     Result retval = sendCommandReturningData(EFFECT_CMD_SET_VOLUME, "SET_VOLUME", halDataSize,
784                                              &halData[0], &halResultSize, &halResult[0]);
785     hidl_vec<uint32_t> result;
786     if (retval == Result::OK) {
787         result.setToExternal(&halResult[0], halResultSize);
788     }
789     _hidl_cb(retval, result);
790     return Void();
791 }
792 
volumeChangeNotification(const hidl_vec<uint32_t> & volumes)793 Return<Result> Effect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
794     uint32_t halDataSize;
795     std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
796     return sendCommand(EFFECT_CMD_SET_VOLUME, "SET_VOLUME", halDataSize, &halData[0]);
797 }
798 
setAudioMode(AudioMode mode)799 Return<Result> Effect::setAudioMode(AudioMode mode) {
800     uint32_t halMode = static_cast<uint32_t>(mode);
801     return sendCommand(EFFECT_CMD_SET_AUDIO_MODE, "SET_AUDIO_MODE", sizeof(uint32_t), &halMode);
802 }
803 
setConfigReverse(const EffectConfig & config,const sp<IEffectBufferProviderCallback> & inputBufferProvider,const sp<IEffectBufferProviderCallback> & outputBufferProvider)804 Return<Result> Effect::setConfigReverse(
805     const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
806     const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
807     return setConfigImpl(EFFECT_CMD_SET_CONFIG_REVERSE, "SET_CONFIG_REVERSE", config,
808                          inputBufferProvider, outputBufferProvider);
809 }
810 
getConfig(getConfig_cb _hidl_cb)811 Return<void> Effect::getConfig(getConfig_cb _hidl_cb) {
812     return getConfigImpl(EFFECT_CMD_GET_CONFIG, "GET_CONFIG", _hidl_cb);
813 }
814 
getConfigReverse(getConfigReverse_cb _hidl_cb)815 Return<void> Effect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
816     return getConfigImpl(EFFECT_CMD_GET_CONFIG_REVERSE, "GET_CONFIG_REVERSE", _hidl_cb);
817 }
818 
getSupportedAuxChannelsConfigs(uint32_t maxConfigs,getSupportedAuxChannelsConfigs_cb _hidl_cb)819 Return<void> Effect::getSupportedAuxChannelsConfigs(uint32_t maxConfigs,
820                                                     getSupportedAuxChannelsConfigs_cb _hidl_cb) {
821     hidl_vec<EffectAuxChannelsConfig> result;
822     Result retval = getSupportedConfigsImpl(
823         EFFECT_FEATURE_AUX_CHANNELS, maxConfigs, sizeof(channel_config_t),
824         [&](uint32_t supportedConfigs, void* configsData) {
825             result.resize(supportedConfigs);
826             channel_config_t* config = reinterpret_cast<channel_config_t*>(configsData);
827             for (size_t i = 0; i < result.size(); ++i) {
828                 effectAuxChannelsConfigFromHal(*config++, &result[i]);
829             }
830         });
831     _hidl_cb(retval, result);
832     return Void();
833 }
834 
getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)835 Return<void> Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
836     EffectAuxChannelsConfig result;
837     Result retval = getCurrentConfigImpl(
838         EFFECT_FEATURE_AUX_CHANNELS, sizeof(channel_config_t), [&](void* configData) {
839             effectAuxChannelsConfigFromHal(*reinterpret_cast<channel_config_t*>(configData),
840                                            &result);
841         });
842     _hidl_cb(retval, result);
843     return Void();
844 }
845 
setAuxChannelsConfig(const EffectAuxChannelsConfig & config)846 Return<Result> Effect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
847     std::vector<uint32_t> halCmd(
848             alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t)), 0);
849     halCmd[0] = EFFECT_FEATURE_AUX_CHANNELS;
850     effectAuxChannelsConfigToHal(config, reinterpret_cast<channel_config_t*>(&halCmd[1]));
851     return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG,
852                                       "SET_FEATURE_CONFIG AUX_CHANNELS", halCmd.size(), &halCmd[0]);
853 }
854 
offload(const EffectOffloadParameter & param)855 Return<Result> Effect::offload(const EffectOffloadParameter& param) {
856     effect_offload_param_t halParam;
857     effectOffloadParamToHal(param, &halParam);
858     return sendCommandReturningStatus(EFFECT_CMD_OFFLOAD, "OFFLOAD", sizeof(effect_offload_param_t),
859                                       &halParam);
860 }
861 
getDescriptor(getDescriptor_cb _hidl_cb)862 Return<void> Effect::getDescriptor(getDescriptor_cb _hidl_cb) {
863     RETURN_RESULT_IF_EFFECT_CLOSED(EffectDescriptor());
864     effect_descriptor_t halDescriptor;
865     memset(&halDescriptor, 0, sizeof(effect_descriptor_t));
866     status_t status = (*mHandle)->get_descriptor(mHandle, &halDescriptor);
867     EffectDescriptor descriptor;
868     if (status == OK) {
869         status = EffectUtils::effectDescriptorFromHal(halDescriptor, &descriptor);
870     }
871     _hidl_cb(analyzeStatus("get_descriptor", "", sContextCallFunction, status), descriptor);
872     return Void();
873 }
874 
command(uint32_t commandId,const hidl_vec<uint8_t> & data,uint32_t resultMaxSize,command_cb _hidl_cb)875 Return<void> Effect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
876                              uint32_t resultMaxSize, command_cb _hidl_cb) {
877     if (mHandle == kInvalidEffectHandle) {
878         _hidl_cb(-ENODATA, hidl_vec<uint8_t>());
879         return Void();
880     }
881     uint32_t halDataSize;
882     std::unique_ptr<uint8_t[]> halData = hidlVecToHal(data, &halDataSize);
883     uint32_t halResultSize = resultMaxSize;
884     std::unique_ptr<uint8_t[]> halResult(new uint8_t[halResultSize]);
885     memset(&halResult[0], 0, halResultSize);
886 
887     void* dataPtr = halDataSize > 0 ? &halData[0] : NULL;
888     void* resultPtr = halResultSize > 0 ? &halResult[0] : NULL;
889     status_t status = BAD_VALUE;
890     switch (commandId) {
891         case 'gtid':  // retrieve the tid, used for spatializer priority boost
892             if (halDataSize == 0 && resultMaxSize == sizeof(int32_t)) {
893                 auto ptid = (int32_t*)resultPtr;
894                 ptid[0] = mProcessThread ? mProcessThread->getTid() : -1;
895                 status = OK;
896                 break;  // we have handled 'gtid' here.
897             }
898             [[fallthrough]];  // allow 'gtid' overload (checked halDataSize and resultMaxSize).
899         default:
900             status = (*mHandle)->command(mHandle, commandId, halDataSize, dataPtr, &halResultSize,
901                                          resultPtr);
902             break;
903     }
904     hidl_vec<uint8_t> result;
905     if (status == OK && resultPtr != NULL) {
906         result.setToExternal(&halResult[0], halResultSize);
907     }
908     _hidl_cb(status, result);
909     return Void();
910 }
911 
setParameter(const hidl_vec<uint8_t> & parameter,const hidl_vec<uint8_t> & value)912 Return<Result> Effect::setParameter(const hidl_vec<uint8_t>& parameter,
913                                     const hidl_vec<uint8_t>& value) {
914     return setParameterImpl(parameter.size(), &parameter[0], value.size(), &value[0]);
915 }
916 
getParameter(const hidl_vec<uint8_t> & parameter,uint32_t valueMaxSize,getParameter_cb _hidl_cb)917 Return<void> Effect::getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
918                                   getParameter_cb _hidl_cb) {
919     hidl_vec<uint8_t> value;
920     Result retval = getParameterImpl(
921         parameter.size(), &parameter[0], valueMaxSize,
922         [&](uint32_t valueSize, const void* valueData) {
923             value.setToExternal(reinterpret_cast<uint8_t*>(const_cast<void*>(valueData)),
924                                 valueSize);
925         });
926     _hidl_cb(retval, value);
927     return Void();
928 }
929 
getSupportedConfigsForFeature(uint32_t featureId,uint32_t maxConfigs,uint32_t configSize,getSupportedConfigsForFeature_cb _hidl_cb)930 Return<void> Effect::getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
931                                                    uint32_t configSize,
932                                                    getSupportedConfigsForFeature_cb _hidl_cb) {
933     uint32_t configCount = 0;
934     hidl_vec<uint8_t> result;
935     Result retval = getSupportedConfigsImpl(featureId, maxConfigs, configSize,
936                                             [&](uint32_t supportedConfigs, void* configsData) {
937                                                 configCount = supportedConfigs;
938                                                 result.resize(configCount * configSize);
939                                                 memcpy(&result[0], configsData, result.size());
940                                             });
941     _hidl_cb(retval, configCount, result);
942     return Void();
943 }
944 
getCurrentConfigForFeature(uint32_t featureId,uint32_t configSize,getCurrentConfigForFeature_cb _hidl_cb)945 Return<void> Effect::getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
946                                                 getCurrentConfigForFeature_cb _hidl_cb) {
947     hidl_vec<uint8_t> result;
948     Result retval = getCurrentConfigImpl(featureId, configSize, [&](void* configData) {
949         result.resize(configSize);
950         memcpy(&result[0], configData, result.size());
951     });
952     _hidl_cb(retval, result);
953     return Void();
954 }
955 
setCurrentConfigForFeature(uint32_t featureId,const hidl_vec<uint8_t> & configData)956 Return<Result> Effect::setCurrentConfigForFeature(uint32_t featureId,
957                                                   const hidl_vec<uint8_t>& configData) {
958     std::vector<uint32_t> halCmd(alignedSizeIn<uint32_t>(sizeof(uint32_t) + configData.size()), 0);
959     halCmd[0] = featureId;
960     memcpy(&halCmd[1], &configData[0], configData.size());
961     return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG, "SET_FEATURE_CONFIG",
962                                       halCmd.size(), &halCmd[0]);
963 }
964 
closeImpl()965 std::tuple<Result, effect_handle_t> Effect::closeImpl() {
966     if (mStopProcessThread.load(std::memory_order_relaxed)) {  // only this thread modifies
967         return {Result::INVALID_STATE, kInvalidEffectHandle};
968     }
969     mStopProcessThread.store(true, std::memory_order_release);
970     if (mEfGroup) {
971         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT));
972     }
973     effect_handle_t handle = mHandle;
974     mHandle = kInvalidEffectHandle;
975 #if MAJOR_VERSION <= 5
976     return {Result::OK, handle};
977 #elif MAJOR_VERSION >= 6
978     // No need to join the processing thread, it is part of the API contract that the client
979     // must finish processing before closing the effect.
980     Result retval = analyzeStatus("EffectRelease", "", sContextCallFunction, EffectRelease(handle));
981     EffectMap::getInstance().remove(handle);
982     return {retval, handle};
983 #endif
984 }
985 
close()986 Return<Result> Effect::close() {
987     RETURN_IF_EFFECT_CLOSED();
988     auto [result, _] = closeImpl();
989     return result;
990 }
991 
debug(const hidl_handle & fd,const hidl_vec<hidl_string> &)992 Return<void> Effect::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /* options */) {
993     if (fd.getNativeHandle() != nullptr && fd->numFds == 1) {
994         uint32_t cmdData = fd->data[0];
995         (void)sendCommand(EFFECT_CMD_DUMP, "DUMP", sizeof(cmdData), &cmdData);
996         const std::string s = mStatistics->dump();
997         if (s.size() != 0) write(cmdData, s.c_str(), s.size());
998     }
999     return Void();
1000 }
1001 
1002 }  // namespace implementation
1003 }  // namespace CPP_VERSION
1004 }  // namespace effect
1005 }  // namespace audio
1006 }  // namespace hardware
1007 }  // namespace android
1008