• 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     (void)close();
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(mHandle);
332     ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status));
333 #endif
334     EffectMap::getInstance().remove(mHandle);
335     mHandle = 0;
336 }
337 
338 // static
339 template <typename T>
alignedSizeIn(size_t s)340 size_t Effect::alignedSizeIn(size_t s) {
341     return (s + sizeof(T) - 1) / sizeof(T);
342 }
343 
344 // static
345 template <typename T>
hidlVecToHal(const hidl_vec<T> & vec,uint32_t * halDataSize)346 std::unique_ptr<uint8_t[]> Effect::hidlVecToHal(const hidl_vec<T>& vec, uint32_t* halDataSize) {
347     // Due to bugs in HAL, they may attempt to write into the provided
348     // input buffer. The original binder buffer is r/o, thus it is needed
349     // to create a r/w version.
350     *halDataSize = vec.size() * sizeof(T);
351     std::unique_ptr<uint8_t[]> halData(new uint8_t[*halDataSize]);
352     memcpy(&halData[0], &vec[0], *halDataSize);
353     return halData;
354 }
355 
356 #if MAJOR_VERSION <= 6
357 
effectAuxChannelsConfigFromHal(const channel_config_t & halConfig,EffectAuxChannelsConfig * config)358 void Effect::effectAuxChannelsConfigFromHal(const channel_config_t& halConfig,
359                                             EffectAuxChannelsConfig* config) {
360     config->mainChannels = AudioChannelBitfield(halConfig.main_channels);
361     config->auxChannels = AudioChannelBitfield(halConfig.aux_channels);
362 }
363 
364 // static
effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig & config,channel_config_t * halConfig)365 void Effect::effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig& config,
366                                           channel_config_t* halConfig) {
367     halConfig->main_channels = static_cast<audio_channel_mask_t>(config.mainChannels);
368     halConfig->aux_channels = static_cast<audio_channel_mask_t>(config.auxChannels);
369 }
370 
371 #else  // MAJOR_VERSION <= 6
372 
effectAuxChannelsConfigFromHal(const channel_config_t & halConfig,EffectAuxChannelsConfig * config)373 void Effect::effectAuxChannelsConfigFromHal(const channel_config_t& halConfig,
374                                             EffectAuxChannelsConfig* config) {
375     (void)HidlUtils::audioChannelMaskFromHal(halConfig.main_channels, mIsInput,
376                                              &config->mainChannels);
377     (void)HidlUtils::audioChannelMaskFromHal(halConfig.aux_channels, mIsInput,
378                                              &config->auxChannels);
379 }
380 
381 // static
effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig & config,channel_config_t * halConfig)382 void Effect::effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig& config,
383                                           channel_config_t* halConfig) {
384     (void)HidlUtils::audioChannelMaskToHal(config.mainChannels, &halConfig->main_channels);
385     (void)HidlUtils::audioChannelMaskToHal(config.auxChannels, &halConfig->aux_channels);
386 }
387 
388 #endif  // MAJOR_VERSION <= 6
389 
390 // static
effectOffloadParamToHal(const EffectOffloadParameter & offload,effect_offload_param_t * halOffload)391 void Effect::effectOffloadParamToHal(const EffectOffloadParameter& offload,
392                                      effect_offload_param_t* halOffload) {
393     halOffload->isOffload = offload.isOffload;
394     halOffload->ioHandle = offload.ioHandle;
395 }
396 
397 // static
parameterToHal(uint32_t paramSize,const void * paramData,uint32_t valueSize,const void ** valueData,std::vector<uint8_t> * halParamBuffer)398 bool Effect::parameterToHal(uint32_t paramSize, const void* paramData, uint32_t valueSize,
399                             const void** valueData, std::vector<uint8_t>* halParamBuffer) {
400     constexpr size_t kMaxSize = EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t);
401     if (paramSize > kMaxSize) {
402         ALOGE("%s: Parameter size is too big: %" PRIu32, __func__, paramSize);
403         return false;
404     }
405     size_t valueOffsetFromData = alignedSizeIn<uint32_t>(paramSize) * sizeof(uint32_t);
406     if (valueOffsetFromData > kMaxSize) {
407         ALOGE("%s: Aligned parameter size is too big: %zu", __func__, valueOffsetFromData);
408         return false;
409     }
410     if (valueSize > kMaxSize - valueOffsetFromData) {
411         ALOGE("%s: Value size is too big: %" PRIu32 ", max size is %zu", __func__, valueSize,
412               kMaxSize - valueOffsetFromData);
413         android_errorWriteLog(0x534e4554, "237291425");
414         return false;
415     }
416     size_t halParamBufferSize = sizeof(effect_param_t) + valueOffsetFromData + valueSize;
417     halParamBuffer->resize(halParamBufferSize, 0);
418     effect_param_t* halParam = reinterpret_cast<effect_param_t*>(halParamBuffer->data());
419     halParam->psize = paramSize;
420     halParam->vsize = valueSize;
421     memcpy(halParam->data, paramData, paramSize);
422     if (valueData) {
423         if (*valueData) {
424             // Value data is provided.
425             memcpy(halParam->data + valueOffsetFromData, *valueData, valueSize);
426         } else {
427             // The caller needs the pointer to the value data location.
428             *valueData = halParam->data + valueOffsetFromData;
429         }
430     }
431     return true;
432 }
433 
analyzeCommandStatus(const char * commandName,const char * context,status_t status)434 Result Effect::analyzeCommandStatus(const char* commandName, const char* context, status_t status) {
435     return analyzeStatus("command", commandName, context, status);
436 }
437 
analyzeStatus(const char * funcName,const char * subFuncName,const char * contextDescription,status_t status)438 Result Effect::analyzeStatus(const char* funcName, const char* subFuncName,
439                              const char* contextDescription, status_t status) {
440     if (status != OK) {
441         ALOGW("Effect %p %s %s %s: %s", mHandle, funcName, subFuncName, contextDescription,
442               strerror(-status));
443     }
444     switch (status) {
445         case OK:
446             return Result::OK;
447         case -EINVAL:
448             return Result::INVALID_ARGUMENTS;
449         case -ENODATA:
450             return Result::INVALID_STATE;
451         case -ENODEV:
452             return Result::NOT_INITIALIZED;
453         case -ENOMEM:
454             return Result::RESULT_TOO_BIG;
455         case -ENOSYS:
456             return Result::NOT_SUPPORTED;
457         default:
458             return Result::INVALID_STATE;
459     }
460 }
461 
getConfigImpl(int commandCode,const char * commandName,GetConfigCallback cb)462 void Effect::getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb) {
463     uint32_t halResultSize = sizeof(effect_config_t);
464     effect_config_t halConfig{};
465     status_t status =
466         (*mHandle)->command(mHandle, commandCode, 0, NULL, &halResultSize, &halConfig);
467     EffectConfig config;
468     if (status == OK) {
469         status = EffectUtils::effectConfigFromHal(halConfig, mIsInput, &config);
470     }
471     cb(analyzeCommandStatus(commandName, sContextCallToCommand, status), config);
472 }
473 
getCurrentConfigImpl(uint32_t featureId,uint32_t configSize,GetCurrentConfigSuccessCallback onSuccess)474 Result Effect::getCurrentConfigImpl(uint32_t featureId, uint32_t configSize,
475                                     GetCurrentConfigSuccessCallback onSuccess) {
476     if (configSize > kMaxDataSize - sizeof(uint32_t)) {
477         ALOGE("%s: Config size is too big: %" PRIu32, __func__, configSize);
478         android_errorWriteLog(0x534e4554, "240266798");
479         return Result::INVALID_ARGUMENTS;
480     }
481     uint32_t halCmd = featureId;
482     std::vector<uint32_t> halResult(alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize), 0);
483     uint32_t halResultSize = 0;
484     return sendCommandReturningStatusAndData(
485             EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG", sizeof(uint32_t), &halCmd,
486             &halResultSize, &halResult[0], sizeof(uint32_t), [&] { onSuccess(&halResult[1]); });
487 }
488 
getParameterImpl(uint32_t paramSize,const void * paramData,uint32_t requestValueSize,uint32_t replyValueSize,GetParameterSuccessCallback onSuccess)489 Result Effect::getParameterImpl(uint32_t paramSize, const void* paramData,
490                                 uint32_t requestValueSize, uint32_t replyValueSize,
491                                 GetParameterSuccessCallback onSuccess) {
492     // As it is unknown what method HAL uses for copying the provided parameter data,
493     // it is safer to make sure that input and output buffers do not overlap.
494     std::vector<uint8_t> halCmdBuffer;
495     if (!parameterToHal(paramSize, paramData, requestValueSize, nullptr, &halCmdBuffer)) {
496         return Result::INVALID_ARGUMENTS;
497     }
498     const void* valueData = nullptr;
499     std::vector<uint8_t> halParamBuffer;
500     if (!parameterToHal(paramSize, paramData, replyValueSize, &valueData, &halParamBuffer)) {
501         return Result::INVALID_ARGUMENTS;
502     }
503     uint32_t halParamBufferSize = halParamBuffer.size();
504 
505     return sendCommandReturningStatusAndData(
506         EFFECT_CMD_GET_PARAM, "GET_PARAM", halCmdBuffer.size(), &halCmdBuffer[0],
507         &halParamBufferSize, &halParamBuffer[0], sizeof(effect_param_t), [&] {
508             effect_param_t* halParam = reinterpret_cast<effect_param_t*>(&halParamBuffer[0]);
509             onSuccess(halParam->vsize, valueData);
510         });
511 }
512 
getSupportedConfigsImpl(uint32_t featureId,uint32_t maxConfigs,uint32_t configSize,GetSupportedConfigsSuccessCallback onSuccess)513 Result Effect::getSupportedConfigsImpl(uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
514                                        GetSupportedConfigsSuccessCallback onSuccess) {
515     if (maxConfigs != 0 && configSize > (kMaxDataSize - 2 * sizeof(uint32_t)) / maxConfigs) {
516         ALOGE("%s: Config size is too big: %" PRIu32, __func__, configSize);
517         return Result::INVALID_ARGUMENTS;
518     }
519     uint32_t halCmd[2] = {featureId, maxConfigs};
520     uint32_t halResultSize = 2 * sizeof(uint32_t) + maxConfigs * configSize;
521     std::vector<uint8_t> halResult(static_cast<size_t>(halResultSize), 0);
522     return sendCommandReturningStatusAndData(
523         EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, "GET_FEATURE_SUPPORTED_CONFIGS", sizeof(halCmd),
524         halCmd, &halResultSize, &halResult[0], 2 * sizeof(uint32_t), [&] {
525             uint32_t* halResult32 = reinterpret_cast<uint32_t*>(&halResult[0]);
526             uint32_t supportedConfigs = *(++halResult32);  // skip status field
527             if (supportedConfigs > maxConfigs) supportedConfigs = maxConfigs;
528             onSuccess(supportedConfigs, ++halResult32);
529         });
530 }
531 
prepareForProcessing(prepareForProcessing_cb _hidl_cb)532 Return<void> Effect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
533     status_t status;
534     // Create message queue.
535     if (mStatusMQ) {
536         ALOGE("the client attempts to call prepareForProcessing_cb twice");
537         _hidl_cb(Result::INVALID_STATE, StatusMQ::Descriptor());
538         return Void();
539     }
540     std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1, true /*EventFlag*/));
541     if (!tempStatusMQ->isValid()) {
542         ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
543         _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
544         return Void();
545     }
546     status = EventFlag::createEventFlag(tempStatusMQ->getEventFlagWord(), &mEfGroup);
547     if (status != OK || !mEfGroup) {
548         ALOGE("failed creating event flag for status MQ: %s", strerror(-status));
549         _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
550         return Void();
551     }
552 
553     // Create and launch the thread.
554     mProcessThread = new ProcessThread(&mStopProcessThread, mHandle, &mHalInBufferPtr,
555                                        &mHalOutBufferPtr, tempStatusMQ.get(), mEfGroup, this);
556     status = mProcessThread->run("effect", PRIORITY_URGENT_AUDIO);
557     if (status != OK) {
558         ALOGW("failed to start effect processing thread: %s", strerror(-status));
559         _hidl_cb(Result::INVALID_ARGUMENTS, MQDescriptorSync<Result>());
560         return Void();
561     }
562 
563     // For a spatializer effect, we perform scheduler adjustments to reduce glitches and power.
564     // We do it here instead of the ProcessThread::threadLoop to ensure that mHandle is valid.
565     if (effect_descriptor_t halDescriptor{};
566         (*mHandle)->get_descriptor(mHandle, &halDescriptor) == NO_ERROR &&
567         memcmp(&halDescriptor.type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0) {
568         const status_t status = scheduler::updateSpatializerPriority(mProcessThread->getTid());
569         ALOGW_IF(status != OK, "Failed to update Spatializer priority");
570     }
571 
572     mStatusMQ = std::move(tempStatusMQ);
573     _hidl_cb(Result::OK, *mStatusMQ->getDesc());
574     return Void();
575 }
576 
setProcessBuffers(const AudioBuffer & inBuffer,const AudioBuffer & outBuffer)577 Return<Result> Effect::setProcessBuffers(const AudioBuffer& inBuffer,
578                                          const AudioBuffer& outBuffer) {
579     AudioBufferManager& manager = AudioBufferManager::getInstance();
580     sp<AudioBufferWrapper> tempInBuffer, tempOutBuffer;
581     if (!manager.wrap(inBuffer, &tempInBuffer)) {
582         ALOGE("Could not map memory of the input buffer");
583         return Result::INVALID_ARGUMENTS;
584     }
585     if (!manager.wrap(outBuffer, &tempOutBuffer)) {
586         ALOGE("Could not map memory of the output buffer");
587         return Result::INVALID_ARGUMENTS;
588     }
589     mInBuffer = tempInBuffer;
590     mOutBuffer = tempOutBuffer;
591     // The processing thread only reads these pointers after waking up by an event flag,
592     // so it's OK to update the pair non-atomically.
593     mHalInBufferPtr.store(mInBuffer->getHalBuffer(), std::memory_order_release);
594     mHalOutBufferPtr.store(mOutBuffer->getHalBuffer(), std::memory_order_release);
595     return Result::OK;
596 }
597 
sendCommand(int commandCode,const char * commandName)598 Result Effect::sendCommand(int commandCode, const char* commandName) {
599     return sendCommand(commandCode, commandName, 0, NULL);
600 }
601 
sendCommand(int commandCode,const char * commandName,uint32_t size,void * data)602 Result Effect::sendCommand(int commandCode, const char* commandName, uint32_t size, void* data) {
603     status_t status = (*mHandle)->command(mHandle, commandCode, size, data, 0, NULL);
604     return analyzeCommandStatus(commandName, sContextCallToCommand, status);
605 }
606 
sendCommandReturningData(int commandCode,const char * commandName,uint32_t * replySize,void * replyData)607 Result Effect::sendCommandReturningData(int commandCode, const char* commandName,
608                                         uint32_t* replySize, void* replyData) {
609     return sendCommandReturningData(commandCode, commandName, 0, NULL, replySize, replyData);
610 }
611 
sendCommandReturningData(int commandCode,const char * commandName,uint32_t size,void * data,uint32_t * replySize,void * replyData)612 Result Effect::sendCommandReturningData(int commandCode, const char* commandName, uint32_t size,
613                                         void* data, uint32_t* replySize, void* replyData) {
614     uint32_t expectedReplySize = *replySize;
615     status_t status = (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
616     if (status == OK && *replySize != expectedReplySize) {
617         status = -ENODATA;
618     }
619     return analyzeCommandStatus(commandName, sContextCallToCommand, status);
620 }
621 
sendCommandReturningStatus(int commandCode,const char * commandName)622 Result Effect::sendCommandReturningStatus(int commandCode, const char* commandName) {
623     return sendCommandReturningStatus(commandCode, commandName, 0, NULL);
624 }
625 
sendCommandReturningStatus(int commandCode,const char * commandName,uint32_t size,void * data)626 Result Effect::sendCommandReturningStatus(int commandCode, const char* commandName, uint32_t size,
627                                           void* data) {
628     uint32_t replyCmdStatus;
629     uint32_t replySize = sizeof(uint32_t);
630     return sendCommandReturningStatusAndData(commandCode, commandName, size, data, &replySize,
631                                              &replyCmdStatus, replySize, [] {});
632 }
633 
sendCommandReturningStatusAndData(int commandCode,const char * commandName,uint32_t size,void * data,uint32_t * replySize,void * replyData,uint32_t minReplySize,CommandSuccessCallback onSuccess)634 Result Effect::sendCommandReturningStatusAndData(int commandCode, const char* commandName,
635                                                  uint32_t size, void* data, uint32_t* replySize,
636                                                  void* replyData, uint32_t minReplySize,
637                                                  CommandSuccessCallback onSuccess) {
638     status_t status = (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
639     Result retval;
640     if (status == OK && minReplySize >= sizeof(uint32_t) && *replySize >= minReplySize) {
641         uint32_t commandStatus = *reinterpret_cast<uint32_t*>(replyData);
642         retval = analyzeCommandStatus(commandName, sContextResultOfCommand, commandStatus);
643         if (commandStatus == OK) {
644             onSuccess();
645         }
646     } else {
647         retval = analyzeCommandStatus(commandName, sContextCallToCommand, status);
648     }
649     return retval;
650 }
651 
setConfigImpl(int commandCode,const char * commandName,const EffectConfig & config,const sp<IEffectBufferProviderCallback> & inputBufferProvider,const sp<IEffectBufferProviderCallback> & outputBufferProvider)652 Result Effect::setConfigImpl(int commandCode, const char* commandName, const EffectConfig& config,
653                              const sp<IEffectBufferProviderCallback>& inputBufferProvider,
654                              const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
655     effect_config_t halConfig;
656     EffectUtils::effectConfigToHal(config, &halConfig);
657     if (inputBufferProvider != 0) {
658         LOG_FATAL("Using input buffer provider is not supported");
659     }
660     if (outputBufferProvider != 0) {
661         LOG_FATAL("Using output buffer provider is not supported");
662     }
663     return sendCommandReturningStatus(commandCode, commandName, sizeof(effect_config_t),
664                                       &halConfig);
665 }
666 
setParameterImpl(uint32_t paramSize,const void * paramData,uint32_t valueSize,const void * valueData)667 Result Effect::setParameterImpl(uint32_t paramSize, const void* paramData, uint32_t valueSize,
668                                 const void* valueData) {
669     std::vector<uint8_t> halParamBuffer;
670     if (!parameterToHal(paramSize, paramData, valueSize, &valueData, &halParamBuffer)) {
671         return Result::INVALID_ARGUMENTS;
672     }
673     return sendCommandReturningStatus(EFFECT_CMD_SET_PARAM, "SET_PARAM", halParamBuffer.size(),
674                                       &halParamBuffer[0]);
675 }
676 
677 // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow.
init()678 Return<Result> Effect::init() {
679     return sendCommandReturningStatus(EFFECT_CMD_INIT, "INIT");
680 }
681 
setConfig(const EffectConfig & config,const sp<IEffectBufferProviderCallback> & inputBufferProvider,const sp<IEffectBufferProviderCallback> & outputBufferProvider)682 Return<Result> Effect::setConfig(const EffectConfig& config,
683                                  const sp<IEffectBufferProviderCallback>& inputBufferProvider,
684                                  const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
685     return setConfigImpl(EFFECT_CMD_SET_CONFIG, "SET_CONFIG", config, inputBufferProvider,
686                          outputBufferProvider);
687 }
688 
reset()689 Return<Result> Effect::reset() {
690     return sendCommand(EFFECT_CMD_RESET, "RESET");
691 }
692 
enable()693 Return<Result> Effect::enable() {
694     return sendCommandReturningStatus(EFFECT_CMD_ENABLE, "ENABLE");
695 }
696 
disable()697 Return<Result> Effect::disable() {
698     return sendCommandReturningStatus(EFFECT_CMD_DISABLE, "DISABLE");
699 }
700 
setAudioSource(AudioSource source)701 Return<Result> Effect::setAudioSource(
702 #if MAJOR_VERSION <= 6
703         AudioSource source
704 #else
705         const AudioSource& source
706 #endif
707 ) {
708     audio_source_t halSource;
709     if (status_t status = HidlUtils::audioSourceToHal(source, &halSource); status == NO_ERROR) {
710         uint32_t halSourceParam = static_cast<uint32_t>(halSource);
711         return sendCommand(EFFECT_CMD_SET_AUDIO_SOURCE, "SET_AUDIO_SOURCE", sizeof(uint32_t),
712                            &halSourceParam);
713     } else {
714         return analyzeStatus(__func__, "audioSourceToHal", sContextConversion, status);
715     }
716 }
717 
718 #if MAJOR_VERSION <= 6
719 
setDevice(AudioDeviceBitfield device)720 Return<Result> Effect::setDevice(AudioDeviceBitfield device) {
721     uint32_t halDevice = static_cast<uint32_t>(device);
722     return sendCommand(EFFECT_CMD_SET_DEVICE, "SET_DEVICE", sizeof(uint32_t), &halDevice);
723 }
724 
setInputDevice(AudioDeviceBitfield device)725 Return<Result> Effect::setInputDevice(AudioDeviceBitfield device) {
726     uint32_t halDevice = static_cast<uint32_t>(device);
727     return sendCommand(EFFECT_CMD_SET_INPUT_DEVICE, "SET_INPUT_DEVICE", sizeof(uint32_t),
728                        &halDevice);
729 }
730 
731 #else  // MAJOR_VERSION <= 6
732 
setDevice(const DeviceAddress & device)733 Return<Result> Effect::setDevice(const DeviceAddress& device) {
734     audio_devices_t halDevice;
735     char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
736     if (status_t status = HidlUtils::deviceAddressToHal(device, &halDevice, halDeviceAddress);
737         status == NO_ERROR) {
738         uint32_t halDeviceParam = static_cast<uint32_t>(halDevice);
739         return sendCommand(EFFECT_CMD_SET_DEVICE, "SET_DEVICE", sizeof(uint32_t), &halDeviceParam);
740     } else {
741         return analyzeStatus(__func__, "deviceAddressToHal", sContextConversion, status);
742     }
743 }
744 
setInputDevice(const DeviceAddress & device)745 Return<Result> Effect::setInputDevice(const DeviceAddress& device) {
746     audio_devices_t halDevice;
747     char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
748     if (status_t status = HidlUtils::deviceAddressToHal(device, &halDevice, halDeviceAddress);
749         status == NO_ERROR) {
750         uint32_t halDeviceParam = static_cast<uint32_t>(halDevice);
751         return sendCommand(EFFECT_CMD_SET_INPUT_DEVICE, "SET_INPUT_DEVICE", sizeof(uint32_t),
752                            &halDeviceParam);
753     } else {
754         return analyzeStatus(__func__, "deviceAddressToHal", sContextConversion, status);
755     }
756 }
757 
758 #endif  // MAJOR_VERSION <= 6
759 
setAndGetVolume(const hidl_vec<uint32_t> & volumes,setAndGetVolume_cb _hidl_cb)760 Return<void> Effect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
761                                      setAndGetVolume_cb _hidl_cb) {
762     uint32_t halDataSize;
763     std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
764     uint32_t halResultSize = halDataSize;
765     std::vector<uint32_t> halResult(volumes.size(), 0);
766     Result retval = sendCommandReturningData(EFFECT_CMD_SET_VOLUME, "SET_VOLUME", halDataSize,
767                                              &halData[0], &halResultSize, &halResult[0]);
768     hidl_vec<uint32_t> result;
769     if (retval == Result::OK) {
770         result.setToExternal(&halResult[0], halResultSize);
771     }
772     _hidl_cb(retval, result);
773     return Void();
774 }
775 
volumeChangeNotification(const hidl_vec<uint32_t> & volumes)776 Return<Result> Effect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
777     uint32_t halDataSize;
778     std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
779     return sendCommand(EFFECT_CMD_SET_VOLUME, "SET_VOLUME", halDataSize, &halData[0]);
780 }
781 
setAudioMode(AudioMode mode)782 Return<Result> Effect::setAudioMode(AudioMode mode) {
783     uint32_t halMode = static_cast<uint32_t>(mode);
784     return sendCommand(EFFECT_CMD_SET_AUDIO_MODE, "SET_AUDIO_MODE", sizeof(uint32_t), &halMode);
785 }
786 
setConfigReverse(const EffectConfig & config,const sp<IEffectBufferProviderCallback> & inputBufferProvider,const sp<IEffectBufferProviderCallback> & outputBufferProvider)787 Return<Result> Effect::setConfigReverse(
788     const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
789     const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
790     return setConfigImpl(EFFECT_CMD_SET_CONFIG_REVERSE, "SET_CONFIG_REVERSE", config,
791                          inputBufferProvider, outputBufferProvider);
792 }
793 
getConfig(getConfig_cb _hidl_cb)794 Return<void> Effect::getConfig(getConfig_cb _hidl_cb) {
795     getConfigImpl(EFFECT_CMD_GET_CONFIG, "GET_CONFIG", _hidl_cb);
796     return Void();
797 }
798 
getConfigReverse(getConfigReverse_cb _hidl_cb)799 Return<void> Effect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
800     getConfigImpl(EFFECT_CMD_GET_CONFIG_REVERSE, "GET_CONFIG_REVERSE", _hidl_cb);
801     return Void();
802 }
803 
getSupportedAuxChannelsConfigs(uint32_t maxConfigs,getSupportedAuxChannelsConfigs_cb _hidl_cb)804 Return<void> Effect::getSupportedAuxChannelsConfigs(uint32_t maxConfigs,
805                                                     getSupportedAuxChannelsConfigs_cb _hidl_cb) {
806     hidl_vec<EffectAuxChannelsConfig> result;
807     Result retval = getSupportedConfigsImpl(
808         EFFECT_FEATURE_AUX_CHANNELS, maxConfigs, sizeof(channel_config_t),
809         [&](uint32_t supportedConfigs, void* configsData) {
810             result.resize(supportedConfigs);
811             channel_config_t* config = reinterpret_cast<channel_config_t*>(configsData);
812             for (size_t i = 0; i < result.size(); ++i) {
813                 effectAuxChannelsConfigFromHal(*config++, &result[i]);
814             }
815         });
816     _hidl_cb(retval, result);
817     return Void();
818 }
819 
getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)820 Return<void> Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
821     EffectAuxChannelsConfig result;
822     Result retval = getCurrentConfigImpl(
823         EFFECT_FEATURE_AUX_CHANNELS, sizeof(channel_config_t), [&](void* configData) {
824             effectAuxChannelsConfigFromHal(*reinterpret_cast<channel_config_t*>(configData),
825                                            &result);
826         });
827     _hidl_cb(retval, result);
828     return Void();
829 }
830 
setAuxChannelsConfig(const EffectAuxChannelsConfig & config)831 Return<Result> Effect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
832     std::vector<uint32_t> halCmd(
833             alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t)), 0);
834     halCmd[0] = EFFECT_FEATURE_AUX_CHANNELS;
835     effectAuxChannelsConfigToHal(config, reinterpret_cast<channel_config_t*>(&halCmd[1]));
836     return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG,
837                                       "SET_FEATURE_CONFIG AUX_CHANNELS", halCmd.size(), &halCmd[0]);
838 }
839 
offload(const EffectOffloadParameter & param)840 Return<Result> Effect::offload(const EffectOffloadParameter& param) {
841     effect_offload_param_t halParam;
842     effectOffloadParamToHal(param, &halParam);
843     return sendCommandReturningStatus(EFFECT_CMD_OFFLOAD, "OFFLOAD", sizeof(effect_offload_param_t),
844                                       &halParam);
845 }
846 
getDescriptor(getDescriptor_cb _hidl_cb)847 Return<void> Effect::getDescriptor(getDescriptor_cb _hidl_cb) {
848     effect_descriptor_t halDescriptor;
849     memset(&halDescriptor, 0, sizeof(effect_descriptor_t));
850     status_t status = (*mHandle)->get_descriptor(mHandle, &halDescriptor);
851     EffectDescriptor descriptor;
852     if (status == OK) {
853         status = EffectUtils::effectDescriptorFromHal(halDescriptor, &descriptor);
854     }
855     _hidl_cb(analyzeStatus("get_descriptor", "", sContextCallFunction, status), descriptor);
856     return Void();
857 }
858 
command(uint32_t commandId,const hidl_vec<uint8_t> & data,uint32_t resultMaxSize,command_cb _hidl_cb)859 Return<void> Effect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
860                              uint32_t resultMaxSize, command_cb _hidl_cb) {
861     uint32_t halDataSize;
862     std::unique_ptr<uint8_t[]> halData = hidlVecToHal(data, &halDataSize);
863     uint32_t halResultSize = resultMaxSize;
864     std::unique_ptr<uint8_t[]> halResult(new uint8_t[halResultSize]);
865     memset(&halResult[0], 0, halResultSize);
866 
867     void* dataPtr = halDataSize > 0 ? &halData[0] : NULL;
868     void* resultPtr = halResultSize > 0 ? &halResult[0] : NULL;
869     status_t status = BAD_VALUE;
870     switch (commandId) {
871         case 'gtid':  // retrieve the tid, used for spatializer priority boost
872             if (halDataSize == 0 && resultMaxSize == sizeof(int32_t)) {
873                 auto ptid = (int32_t*)resultPtr;
874                 ptid[0] = mProcessThread ? mProcessThread->getTid() : -1;
875                 status = OK;
876                 break;  // we have handled 'gtid' here.
877             }
878             [[fallthrough]];  // allow 'gtid' overload (checked halDataSize and resultMaxSize).
879         default:
880             status = (*mHandle)->command(mHandle, commandId, halDataSize, dataPtr, &halResultSize,
881                                          resultPtr);
882             break;
883     }
884     hidl_vec<uint8_t> result;
885     if (status == OK && resultPtr != NULL) {
886         result.setToExternal(&halResult[0], halResultSize);
887     }
888     _hidl_cb(status, result);
889     return Void();
890 }
891 
setParameter(const hidl_vec<uint8_t> & parameter,const hidl_vec<uint8_t> & value)892 Return<Result> Effect::setParameter(const hidl_vec<uint8_t>& parameter,
893                                     const hidl_vec<uint8_t>& value) {
894     return setParameterImpl(parameter.size(), &parameter[0], value.size(), &value[0]);
895 }
896 
getParameter(const hidl_vec<uint8_t> & parameter,uint32_t valueMaxSize,getParameter_cb _hidl_cb)897 Return<void> Effect::getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
898                                   getParameter_cb _hidl_cb) {
899     hidl_vec<uint8_t> value;
900     Result retval = getParameterImpl(
901         parameter.size(), &parameter[0], valueMaxSize,
902         [&](uint32_t valueSize, const void* valueData) {
903             value.setToExternal(reinterpret_cast<uint8_t*>(const_cast<void*>(valueData)),
904                                 valueSize);
905         });
906     _hidl_cb(retval, value);
907     return Void();
908 }
909 
getSupportedConfigsForFeature(uint32_t featureId,uint32_t maxConfigs,uint32_t configSize,getSupportedConfigsForFeature_cb _hidl_cb)910 Return<void> Effect::getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
911                                                    uint32_t configSize,
912                                                    getSupportedConfigsForFeature_cb _hidl_cb) {
913     uint32_t configCount = 0;
914     hidl_vec<uint8_t> result;
915     Result retval = getSupportedConfigsImpl(featureId, maxConfigs, configSize,
916                                             [&](uint32_t supportedConfigs, void* configsData) {
917                                                 configCount = supportedConfigs;
918                                                 result.resize(configCount * configSize);
919                                                 memcpy(&result[0], configsData, result.size());
920                                             });
921     _hidl_cb(retval, configCount, result);
922     return Void();
923 }
924 
getCurrentConfigForFeature(uint32_t featureId,uint32_t configSize,getCurrentConfigForFeature_cb _hidl_cb)925 Return<void> Effect::getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
926                                                 getCurrentConfigForFeature_cb _hidl_cb) {
927     hidl_vec<uint8_t> result;
928     Result retval = getCurrentConfigImpl(featureId, configSize, [&](void* configData) {
929         result.resize(configSize);
930         memcpy(&result[0], configData, result.size());
931     });
932     _hidl_cb(retval, result);
933     return Void();
934 }
935 
setCurrentConfigForFeature(uint32_t featureId,const hidl_vec<uint8_t> & configData)936 Return<Result> Effect::setCurrentConfigForFeature(uint32_t featureId,
937                                                   const hidl_vec<uint8_t>& configData) {
938     std::vector<uint32_t> halCmd(alignedSizeIn<uint32_t>(sizeof(uint32_t) + configData.size()), 0);
939     halCmd[0] = featureId;
940     memcpy(&halCmd[1], &configData[0], configData.size());
941     return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG, "SET_FEATURE_CONFIG",
942                                       halCmd.size(), &halCmd[0]);
943 }
944 
close()945 Return<Result> Effect::close() {
946     if (mStopProcessThread.load(std::memory_order_relaxed)) {  // only this thread modifies
947         return Result::INVALID_STATE;
948     }
949     mStopProcessThread.store(true, std::memory_order_release);
950     if (mEfGroup) {
951         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT));
952     }
953 #if MAJOR_VERSION <= 5
954     return Result::OK;
955 #elif MAJOR_VERSION >= 6
956     // No need to join the processing thread, it is part of the API contract that the client
957     // must finish processing before closing the effect.
958     Result retval =
959             analyzeStatus("EffectRelease", "", sContextCallFunction, EffectRelease(mHandle));
960     EffectMap::getInstance().remove(mHandle);
961     return retval;
962 #endif
963 }
964 
debug(const hidl_handle & fd,const hidl_vec<hidl_string> &)965 Return<void> Effect::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /* options */) {
966     if (fd.getNativeHandle() != nullptr && fd->numFds == 1) {
967         uint32_t cmdData = fd->data[0];
968         (void)sendCommand(EFFECT_CMD_DUMP, "DUMP", sizeof(cmdData), &cmdData);
969         const std::string s = mStatistics->dump();
970         if (s.size() != 0) write(cmdData, s.c_str(), s.size());
971     }
972     return Void();
973 }
974 
975 }  // namespace implementation
976 }  // namespace CPP_VERSION
977 }  // namespace effect
978 }  // namespace audio
979 }  // namespace hardware
980 }  // namespace android
981