blob: 87e1ab7a7d0022d82883ad213f42eb962d15e208 [file] [log] [blame]
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -07001/*
Kevin Rocard96d2cd92018-11-14 16:22:07 -08002 * Copyright (C) 2018 The Android Open Source Project
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -07003 *
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
Kevin Rocard96d2cd92018-11-14 16:22:07 -080017#include <memory.h>
18
19#define LOG_TAG "EffectHAL"
20#define ATRACE_TAG ATRACE_TAG_AUDIO
21
Kevin Rocard96d2cd92018-11-14 16:22:07 -080022#include "Effect.h"
23#include "common/all-versions/default/EffectMap.h"
Kevin Rocard62588b62017-12-20 11:07:12 -080024
Mikhail Naganovb0abafb2017-01-31 17:24:48 -080025#define ATRACE_TAG ATRACE_TAG_AUDIO
Mikhail Naganovf363ed42020-12-10 18:47:51 -080026#include <HidlUtils.h>
Yifan Hongf9d30342016-11-30 13:45:34 -080027#include <android/log.h>
Andy Hungafc2da82022-12-01 13:46:55 -080028#include <cutils/properties.h>
Mikhail Naganova331de12017-01-04 16:33:55 -080029#include <media/EffectsFactoryApi.h>
Andy Hung502f9d02022-04-26 18:37:36 -070030#include <mediautils/ScopedStatistics.h>
Andy Hungafc2da82022-12-01 13:46:55 -080031#include <sys/syscall.h>
32#include <system/audio_effects/effect_spatializer.h>
Mikhail Naganov5ec48c22021-01-15 19:05:04 +000033#include <util/EffectUtils.h>
Mikhail Naganovb0abafb2017-01-31 17:24:48 -080034#include <utils/Trace.h>
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -070035
Kevin Rocard30a7fcc2018-03-01 15:08:07 -080036#include "VersionUtils.h"
37
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -070038namespace android {
39namespace hardware {
40namespace audio {
41namespace effect {
Kevin Rocard96d2cd92018-11-14 16:22:07 -080042namespace CPP_VERSION {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -070043namespace implementation {
44
Mikhail Naganovf363ed42020-12-10 18:47:51 -080045#if MAJOR_VERSION <= 6
Mikhail Naganov7d015382022-01-15 01:15:12 +000046using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::
47 AudioChannelBitfield;
Mikhail Naganovf363ed42020-12-10 18:47:51 -080048#endif
Mikhail Naganov7d015382022-01-15 01:15:12 +000049using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::HidlUtils;
Mikhail Naganova331de12017-01-04 16:33:55 -080050
51namespace {
52
Andy Hungafc2da82022-12-01 13:46:55 -080053/**
54 * Some basic scheduling tools.
55 */
56namespace scheduler {
57
58int getCpu() {
59 return sched_getcpu();
60}
61
62uint64_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
82status_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
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
114status_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*/
146status_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
Andy Hung502f9d02022-04-26 18:37:36 -0700207#define SCOPED_STATS() \
208 ::android::mediautils::ScopedStatistics scopedStatistics { \
209 std::string("EffectHal::").append(__func__), mEffectHal->mStatistics \
210 }
211
Mikhail Naganova331de12017-01-04 16:33:55 -0800212class ProcessThread : public Thread {
Kevin Rocard22505e62017-12-14 18:50:12 -0800213 public:
Mikhail Naganova331de12017-01-04 16:33:55 -0800214 // ProcessThread's lifespan never exceeds Effect's lifespan.
Andy Hung502f9d02022-04-26 18:37:36 -0700215 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) {}
227 virtual ~ProcessThread() {}
Mikhail Naganova331de12017-01-04 16:33:55 -0800228
Kevin Rocard22505e62017-12-14 18:50:12 -0800229 private:
Mikhail Naganova331de12017-01-04 16:33:55 -0800230 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;
Andy Hung502f9d02022-04-26 18:37:36 -0700237 Effect* const mEffectHal;
Mikhail Naganova331de12017-01-04 16:33:55 -0800238
239 bool threadLoop() override;
240};
241
242bool ProcessThread::threadLoop() {
Andy Hungafc2da82022-12-01 13:46:55 -0800243 // For a spatializer effect, we perform scheduler adjustments to reduce glitches and power.
244 {
245 effect_descriptor_t halDescriptor{};
246 if ((*mEffect)->get_descriptor(mEffect, &halDescriptor) == NO_ERROR &&
247 memcmp(&halDescriptor.type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0) {
248 const status_t status = scheduler::updateSpatializerPriority(gettid());
249 ALOGW_IF(status != OK, "Failed to update Spatializer priority");
250 }
251 }
252
Mikhail Naganova331de12017-01-04 16:33:55 -0800253 // This implementation doesn't return control back to the Thread until it decides to stop,
254 // as the Thread uses mutexes, and this can lead to priority inversion.
Kevin Rocard22505e62017-12-14 18:50:12 -0800255 while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
Mikhail Naganova331de12017-01-04 16:33:55 -0800256 uint32_t efState = 0;
Mikhail Naganove8674562017-02-10 08:37:19 -0800257 mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL), &efState);
Kevin Rocard22505e62017-12-14 18:50:12 -0800258 if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL)) ||
259 (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT))) {
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800260 continue; // Nothing to do or time to quit.
Mikhail Naganova331de12017-01-04 16:33:55 -0800261 }
262 Result retval = Result::OK;
Kevin Rocard22505e62017-12-14 18:50:12 -0800263 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_REVERSE) &&
264 !mHasProcessReverse) {
Mikhail Naganova331de12017-01-04 16:33:55 -0800265 retval = Result::NOT_SUPPORTED;
266 }
267
268 if (retval == Result::OK) {
269 // affects both buffer pointers and their contents.
270 std::atomic_thread_fence(std::memory_order_acquire);
271 int32_t processResult;
272 audio_buffer_t* inBuffer =
Kevin Rocard22505e62017-12-14 18:50:12 -0800273 std::atomic_load_explicit(mInBuffer, std::memory_order_relaxed);
Mikhail Naganova331de12017-01-04 16:33:55 -0800274 audio_buffer_t* outBuffer =
Kevin Rocard22505e62017-12-14 18:50:12 -0800275 std::atomic_load_explicit(mOutBuffer, std::memory_order_relaxed);
Mikhail Naganova331de12017-01-04 16:33:55 -0800276 if (inBuffer != nullptr && outBuffer != nullptr) {
Andy Hung502f9d02022-04-26 18:37:36 -0700277 // Time this effect process
278 SCOPED_STATS();
279
Mikhail Naganova331de12017-01-04 16:33:55 -0800280 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS)) {
281 processResult = (*mEffect)->process(mEffect, inBuffer, outBuffer);
282 } else {
283 processResult = (*mEffect)->process_reverse(mEffect, inBuffer, outBuffer);
284 }
285 std::atomic_thread_fence(std::memory_order_release);
286 } else {
287 ALOGE("processing buffers were not set before calling 'process'");
288 processResult = -ENODEV;
289 }
Kevin Rocard22505e62017-12-14 18:50:12 -0800290 switch (processResult) {
291 case 0:
292 retval = Result::OK;
293 break;
294 case -ENODATA:
295 retval = Result::INVALID_STATE;
296 break;
297 case -EINVAL:
298 retval = Result::INVALID_ARGUMENTS;
299 break;
300 default:
301 retval = Result::NOT_INITIALIZED;
Mikhail Naganova331de12017-01-04 16:33:55 -0800302 }
303 }
304 if (!mStatusMQ->write(&retval)) {
305 ALOGW("status message queue write failed");
306 }
307 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING));
308 }
309
310 return false;
311}
312
313} // namespace
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700314
315// static
Kevin Rocard22505e62017-12-14 18:50:12 -0800316const char* Effect::sContextResultOfCommand = "returned status";
317const char* Effect::sContextCallToCommand = "error";
318const char* Effect::sContextCallFunction = sContextCallToCommand;
Mikhail Naganovf363ed42020-12-10 18:47:51 -0800319const char* Effect::sContextConversion = "conversion";
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700320
Mikhail Naganovf363ed42020-12-10 18:47:51 -0800321Effect::Effect(bool isInput, effect_handle_t handle)
322 : mIsInput(isInput), mHandle(handle), mEfGroup(nullptr), mStopProcessThread(false) {
323 (void)mIsInput; // prevent 'unused field' warnings in pre-V7 versions.
324}
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700325
326Effect::~Effect() {
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800327 ATRACE_CALL();
Mikhail Naganov7623ed92019-11-14 13:57:15 -0800328 (void)close();
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800329 if (mProcessThread.get()) {
330 ATRACE_NAME("mProcessThread->join");
331 status_t status = mProcessThread->join();
332 ALOGE_IF(status, "processing thread exit error: %s", strerror(-status));
333 }
334 if (mEfGroup) {
335 status_t status = EventFlag::deleteEventFlag(&mEfGroup);
336 ALOGE_IF(status, "processing MQ event flag deletion error: %s", strerror(-status));
337 }
338 mInBuffer.clear();
339 mOutBuffer.clear();
Mikhail Naganov7623ed92019-11-14 13:57:15 -0800340#if MAJOR_VERSION <= 5
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800341 int status = EffectRelease(mHandle);
342 ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status));
Mikhail Naganov7623ed92019-11-14 13:57:15 -0800343#endif
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800344 EffectMap::getInstance().remove(mHandle);
345 mHandle = 0;
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700346}
347
348// static
Kevin Rocard22505e62017-12-14 18:50:12 -0800349template <typename T>
350size_t Effect::alignedSizeIn(size_t s) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700351 return (s + sizeof(T) - 1) / sizeof(T);
352}
353
354// static
Kevin Rocard22505e62017-12-14 18:50:12 -0800355template <typename T>
356std::unique_ptr<uint8_t[]> Effect::hidlVecToHal(const hidl_vec<T>& vec, uint32_t* halDataSize) {
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800357 // Due to bugs in HAL, they may attempt to write into the provided
358 // input buffer. The original binder buffer is r/o, thus it is needed
359 // to create a r/w version.
360 *halDataSize = vec.size() * sizeof(T);
361 std::unique_ptr<uint8_t[]> halData(new uint8_t[*halDataSize]);
362 memcpy(&halData[0], &vec[0], *halDataSize);
363 return halData;
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700364}
365
Mikhail Naganovf363ed42020-12-10 18:47:51 -0800366#if MAJOR_VERSION <= 6
367
Kevin Rocard22505e62017-12-14 18:50:12 -0800368void Effect::effectAuxChannelsConfigFromHal(const channel_config_t& halConfig,
369 EffectAuxChannelsConfig* config) {
Kevin Rocard30a7fcc2018-03-01 15:08:07 -0800370 config->mainChannels = AudioChannelBitfield(halConfig.main_channels);
371 config->auxChannels = AudioChannelBitfield(halConfig.aux_channels);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700372}
373
374// static
Kevin Rocard22505e62017-12-14 18:50:12 -0800375void Effect::effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig& config,
376 channel_config_t* halConfig) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700377 halConfig->main_channels = static_cast<audio_channel_mask_t>(config.mainChannels);
378 halConfig->aux_channels = static_cast<audio_channel_mask_t>(config.auxChannels);
379}
380
Mikhail Naganovf363ed42020-12-10 18:47:51 -0800381#else // MAJOR_VERSION <= 6
382
383void Effect::effectAuxChannelsConfigFromHal(const channel_config_t& halConfig,
384 EffectAuxChannelsConfig* config) {
385 (void)HidlUtils::audioChannelMaskFromHal(halConfig.main_channels, mIsInput,
386 &config->mainChannels);
387 (void)HidlUtils::audioChannelMaskFromHal(halConfig.aux_channels, mIsInput,
388 &config->auxChannels);
389}
390
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700391// static
Mikhail Naganovf363ed42020-12-10 18:47:51 -0800392void Effect::effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig& config,
393 channel_config_t* halConfig) {
394 (void)HidlUtils::audioChannelMaskToHal(config.mainChannels, &halConfig->main_channels);
395 (void)HidlUtils::audioChannelMaskToHal(config.auxChannels, &halConfig->aux_channels);
396}
397
Mikhail Naganovf363ed42020-12-10 18:47:51 -0800398#endif // MAJOR_VERSION <= 6
399
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700400// static
Kevin Rocard22505e62017-12-14 18:50:12 -0800401void Effect::effectOffloadParamToHal(const EffectOffloadParameter& offload,
402 effect_offload_param_t* halOffload) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700403 halOffload->isOffload = offload.isOffload;
404 halOffload->ioHandle = offload.ioHandle;
405}
406
407// static
Mikhail Naganov4f110342022-07-07 20:37:42 +0000408bool Effect::parameterToHal(uint32_t paramSize, const void* paramData, uint32_t valueSize,
409 const void** valueData, std::vector<uint8_t>* halParamBuffer) {
410 constexpr size_t kMaxSize = EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t);
411 if (paramSize > kMaxSize) {
412 ALOGE("%s: Parameter size is too big: %" PRIu32, __func__, paramSize);
413 return false;
414 }
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700415 size_t valueOffsetFromData = alignedSizeIn<uint32_t>(paramSize) * sizeof(uint32_t);
Mikhail Naganov4f110342022-07-07 20:37:42 +0000416 if (valueOffsetFromData > kMaxSize) {
417 ALOGE("%s: Aligned parameter size is too big: %zu", __func__, valueOffsetFromData);
418 return false;
419 }
420 if (valueSize > kMaxSize - valueOffsetFromData) {
421 ALOGE("%s: Value size is too big: %" PRIu32 ", max size is %zu", __func__, valueSize,
422 kMaxSize - valueOffsetFromData);
423 android_errorWriteLog(0x534e4554, "237291425");
424 return false;
425 }
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700426 size_t halParamBufferSize = sizeof(effect_param_t) + valueOffsetFromData + valueSize;
Mikhail Naganov4f110342022-07-07 20:37:42 +0000427 halParamBuffer->resize(halParamBufferSize, 0);
428 effect_param_t* halParam = reinterpret_cast<effect_param_t*>(halParamBuffer->data());
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700429 halParam->psize = paramSize;
430 halParam->vsize = valueSize;
431 memcpy(halParam->data, paramData, paramSize);
432 if (valueData) {
433 if (*valueData) {
434 // Value data is provided.
435 memcpy(halParam->data + valueOffsetFromData, *valueData, valueSize);
436 } else {
437 // The caller needs the pointer to the value data location.
438 *valueData = halParam->data + valueOffsetFromData;
439 }
440 }
Mikhail Naganov4f110342022-07-07 20:37:42 +0000441 return true;
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700442}
443
444Result Effect::analyzeCommandStatus(const char* commandName, const char* context, status_t status) {
445 return analyzeStatus("command", commandName, context, status);
446}
447
Kevin Rocard22505e62017-12-14 18:50:12 -0800448Result Effect::analyzeStatus(const char* funcName, const char* subFuncName,
449 const char* contextDescription, status_t status) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700450 if (status != OK) {
Kevin Rocard22505e62017-12-14 18:50:12 -0800451 ALOGW("Effect %p %s %s %s: %s", mHandle, funcName, subFuncName, contextDescription,
452 strerror(-status));
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700453 }
454 switch (status) {
Kevin Rocard22505e62017-12-14 18:50:12 -0800455 case OK:
456 return Result::OK;
457 case -EINVAL:
458 return Result::INVALID_ARGUMENTS;
459 case -ENODATA:
460 return Result::INVALID_STATE;
461 case -ENODEV:
462 return Result::NOT_INITIALIZED;
463 case -ENOMEM:
464 return Result::RESULT_TOO_BIG;
465 case -ENOSYS:
466 return Result::NOT_SUPPORTED;
467 default:
468 return Result::INVALID_STATE;
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700469 }
470}
471
472void Effect::getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb) {
473 uint32_t halResultSize = sizeof(effect_config_t);
Mikhail Naganov9f289042017-02-23 08:39:36 -0800474 effect_config_t halConfig{};
Kevin Rocard22505e62017-12-14 18:50:12 -0800475 status_t status =
476 (*mHandle)->command(mHandle, commandCode, 0, NULL, &halResultSize, &halConfig);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700477 EffectConfig config;
478 if (status == OK) {
Mikhail Naganov5ec48c22021-01-15 19:05:04 +0000479 status = EffectUtils::effectConfigFromHal(halConfig, mIsInput, &config);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700480 }
481 cb(analyzeCommandStatus(commandName, sContextCallToCommand, status), config);
482}
483
Kevin Rocard22505e62017-12-14 18:50:12 -0800484Result Effect::getCurrentConfigImpl(uint32_t featureId, uint32_t configSize,
485 GetCurrentConfigSuccessCallback onSuccess) {
Mikhail Naganov8e3480e2022-09-01 00:31:43 +0000486 if (configSize > kMaxDataSize - sizeof(uint32_t)) {
487 ALOGE("%s: Config size is too big: %" PRIu32, __func__, configSize);
488 android_errorWriteLog(0x534e4554, "240266798");
489 return Result::INVALID_ARGUMENTS;
490 }
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700491 uint32_t halCmd = featureId;
Mikhail Naganov2a652ce2019-11-21 14:03:19 -0800492 std::vector<uint32_t> halResult(alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize), 0);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700493 uint32_t halResultSize = 0;
Mikhail Naganov2a652ce2019-11-21 14:03:19 -0800494 return sendCommandReturningStatusAndData(
495 EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG", sizeof(uint32_t), &halCmd,
496 &halResultSize, &halResult[0], sizeof(uint32_t), [&] { onSuccess(&halResult[1]); });
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700497}
498
Kevin Rocard22505e62017-12-14 18:50:12 -0800499Result Effect::getParameterImpl(uint32_t paramSize, const void* paramData,
500 uint32_t requestValueSize, uint32_t replyValueSize,
501 GetParameterSuccessCallback onSuccess) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700502 // As it is unknown what method HAL uses for copying the provided parameter data,
503 // it is safer to make sure that input and output buffers do not overlap.
Mikhail Naganov4f110342022-07-07 20:37:42 +0000504 std::vector<uint8_t> halCmdBuffer;
505 if (!parameterToHal(paramSize, paramData, requestValueSize, nullptr, &halCmdBuffer)) {
506 return Result::INVALID_ARGUMENTS;
507 }
Kevin Rocard22505e62017-12-14 18:50:12 -0800508 const void* valueData = nullptr;
Mikhail Naganov4f110342022-07-07 20:37:42 +0000509 std::vector<uint8_t> halParamBuffer;
510 if (!parameterToHal(paramSize, paramData, replyValueSize, &valueData, &halParamBuffer)) {
511 return Result::INVALID_ARGUMENTS;
512 }
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700513 uint32_t halParamBufferSize = halParamBuffer.size();
514
515 return sendCommandReturningStatusAndData(
Kevin Rocard22505e62017-12-14 18:50:12 -0800516 EFFECT_CMD_GET_PARAM, "GET_PARAM", halCmdBuffer.size(), &halCmdBuffer[0],
517 &halParamBufferSize, &halParamBuffer[0], sizeof(effect_param_t), [&] {
518 effect_param_t* halParam = reinterpret_cast<effect_param_t*>(&halParamBuffer[0]);
519 onSuccess(halParam->vsize, valueData);
520 });
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700521}
522
Kevin Rocard22505e62017-12-14 18:50:12 -0800523Result Effect::getSupportedConfigsImpl(uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
524 GetSupportedConfigsSuccessCallback onSuccess) {
Mikhail Naganov8e3480e2022-09-01 00:31:43 +0000525 if (maxConfigs != 0 && configSize > (kMaxDataSize - 2 * sizeof(uint32_t)) / maxConfigs) {
526 ALOGE("%s: Config size is too big: %" PRIu32, __func__, configSize);
527 return Result::INVALID_ARGUMENTS;
528 }
Kevin Rocard22505e62017-12-14 18:50:12 -0800529 uint32_t halCmd[2] = {featureId, maxConfigs};
Mikhail Naganov8e3480e2022-09-01 00:31:43 +0000530 uint32_t halResultSize = 2 * sizeof(uint32_t) + maxConfigs * configSize;
Mikhail Naganov2a652ce2019-11-21 14:03:19 -0800531 std::vector<uint8_t> halResult(static_cast<size_t>(halResultSize), 0);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700532 return sendCommandReturningStatusAndData(
Kevin Rocard22505e62017-12-14 18:50:12 -0800533 EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, "GET_FEATURE_SUPPORTED_CONFIGS", sizeof(halCmd),
534 halCmd, &halResultSize, &halResult[0], 2 * sizeof(uint32_t), [&] {
535 uint32_t* halResult32 = reinterpret_cast<uint32_t*>(&halResult[0]);
536 uint32_t supportedConfigs = *(++halResult32); // skip status field
537 if (supportedConfigs > maxConfigs) supportedConfigs = maxConfigs;
538 onSuccess(supportedConfigs, ++halResult32);
539 });
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700540}
541
Mikhail Naganova331de12017-01-04 16:33:55 -0800542Return<void> Effect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
543 status_t status;
544 // Create message queue.
545 if (mStatusMQ) {
546 ALOGE("the client attempts to call prepareForProcessing_cb twice");
547 _hidl_cb(Result::INVALID_STATE, StatusMQ::Descriptor());
548 return Void();
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700549 }
Mikhail Naganova331de12017-01-04 16:33:55 -0800550 std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1, true /*EventFlag*/));
551 if (!tempStatusMQ->isValid()) {
552 ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
553 _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
554 return Void();
555 }
556 status = EventFlag::createEventFlag(tempStatusMQ->getEventFlagWord(), &mEfGroup);
557 if (status != OK || !mEfGroup) {
558 ALOGE("failed creating event flag for status MQ: %s", strerror(-status));
559 _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
560 return Void();
561 }
562
563 // Create and launch the thread.
Kevin Rocard22505e62017-12-14 18:50:12 -0800564 mProcessThread = new ProcessThread(&mStopProcessThread, mHandle, &mHalInBufferPtr,
Andy Hung502f9d02022-04-26 18:37:36 -0700565 &mHalOutBufferPtr, tempStatusMQ.get(), mEfGroup, this);
Mikhail Naganova331de12017-01-04 16:33:55 -0800566 status = mProcessThread->run("effect", PRIORITY_URGENT_AUDIO);
567 if (status != OK) {
568 ALOGW("failed to start effect processing thread: %s", strerror(-status));
569 _hidl_cb(Result::INVALID_ARGUMENTS, MQDescriptorSync<Result>());
570 return Void();
571 }
572
573 mStatusMQ = std::move(tempStatusMQ);
574 _hidl_cb(Result::OK, *mStatusMQ->getDesc());
575 return Void();
576}
577
Kevin Rocard22505e62017-12-14 18:50:12 -0800578Return<Result> Effect::setProcessBuffers(const AudioBuffer& inBuffer,
579 const AudioBuffer& outBuffer) {
Mikhail Naganova331de12017-01-04 16:33:55 -0800580 AudioBufferManager& manager = AudioBufferManager::getInstance();
581 sp<AudioBufferWrapper> tempInBuffer, tempOutBuffer;
582 if (!manager.wrap(inBuffer, &tempInBuffer)) {
583 ALOGE("Could not map memory of the input buffer");
584 return Result::INVALID_ARGUMENTS;
585 }
586 if (!manager.wrap(outBuffer, &tempOutBuffer)) {
587 ALOGE("Could not map memory of the output buffer");
588 return Result::INVALID_ARGUMENTS;
589 }
590 mInBuffer = tempInBuffer;
591 mOutBuffer = tempOutBuffer;
592 // The processing thread only reads these pointers after waking up by an event flag,
593 // so it's OK to update the pair non-atomically.
594 mHalInBufferPtr.store(mInBuffer->getHalBuffer(), std::memory_order_release);
595 mHalOutBufferPtr.store(mOutBuffer->getHalBuffer(), std::memory_order_release);
596 return Result::OK;
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700597}
598
599Result Effect::sendCommand(int commandCode, const char* commandName) {
600 return sendCommand(commandCode, commandName, 0, NULL);
601}
602
Kevin Rocard22505e62017-12-14 18:50:12 -0800603Result Effect::sendCommand(int commandCode, const char* commandName, uint32_t size, void* data) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700604 status_t status = (*mHandle)->command(mHandle, commandCode, size, data, 0, NULL);
605 return analyzeCommandStatus(commandName, sContextCallToCommand, status);
606}
607
Kevin Rocard22505e62017-12-14 18:50:12 -0800608Result Effect::sendCommandReturningData(int commandCode, const char* commandName,
609 uint32_t* replySize, void* replyData) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700610 return sendCommandReturningData(commandCode, commandName, 0, NULL, replySize, replyData);
611}
612
Kevin Rocard22505e62017-12-14 18:50:12 -0800613Result Effect::sendCommandReturningData(int commandCode, const char* commandName, uint32_t size,
614 void* data, uint32_t* replySize, void* replyData) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700615 uint32_t expectedReplySize = *replySize;
616 status_t status = (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
617 if (status == OK && *replySize != expectedReplySize) {
618 status = -ENODATA;
619 }
620 return analyzeCommandStatus(commandName, sContextCallToCommand, status);
621}
622
623Result Effect::sendCommandReturningStatus(int commandCode, const char* commandName) {
624 return sendCommandReturningStatus(commandCode, commandName, 0, NULL);
625}
626
Kevin Rocard22505e62017-12-14 18:50:12 -0800627Result Effect::sendCommandReturningStatus(int commandCode, const char* commandName, uint32_t size,
628 void* data) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700629 uint32_t replyCmdStatus;
630 uint32_t replySize = sizeof(uint32_t);
Kevin Rocard22505e62017-12-14 18:50:12 -0800631 return sendCommandReturningStatusAndData(commandCode, commandName, size, data, &replySize,
632 &replyCmdStatus, replySize, [] {});
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700633}
634
Kevin Rocard22505e62017-12-14 18:50:12 -0800635Result Effect::sendCommandReturningStatusAndData(int commandCode, const char* commandName,
636 uint32_t size, void* data, uint32_t* replySize,
637 void* replyData, uint32_t minReplySize,
638 CommandSuccessCallback onSuccess) {
639 status_t status = (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700640 Result retval;
641 if (status == OK && minReplySize >= sizeof(uint32_t) && *replySize >= minReplySize) {
642 uint32_t commandStatus = *reinterpret_cast<uint32_t*>(replyData);
643 retval = analyzeCommandStatus(commandName, sContextResultOfCommand, commandStatus);
644 if (commandStatus == OK) {
645 onSuccess();
646 }
647 } else {
648 retval = analyzeCommandStatus(commandName, sContextCallToCommand, status);
649 }
650 return retval;
651}
652
Kevin Rocard22505e62017-12-14 18:50:12 -0800653Result Effect::setConfigImpl(int commandCode, const char* commandName, const EffectConfig& config,
654 const sp<IEffectBufferProviderCallback>& inputBufferProvider,
655 const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700656 effect_config_t halConfig;
Mikhail Naganov5ec48c22021-01-15 19:05:04 +0000657 EffectUtils::effectConfigToHal(config, &halConfig);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700658 if (inputBufferProvider != 0) {
659 LOG_FATAL("Using input buffer provider is not supported");
660 }
661 if (outputBufferProvider != 0) {
662 LOG_FATAL("Using output buffer provider is not supported");
663 }
Kevin Rocard22505e62017-12-14 18:50:12 -0800664 return sendCommandReturningStatus(commandCode, commandName, sizeof(effect_config_t),
665 &halConfig);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700666}
667
Kevin Rocard22505e62017-12-14 18:50:12 -0800668Result Effect::setParameterImpl(uint32_t paramSize, const void* paramData, uint32_t valueSize,
669 const void* valueData) {
Mikhail Naganov4f110342022-07-07 20:37:42 +0000670 std::vector<uint8_t> halParamBuffer;
671 if (!parameterToHal(paramSize, paramData, valueSize, &valueData, &halParamBuffer)) {
672 return Result::INVALID_ARGUMENTS;
673 }
Kevin Rocard22505e62017-12-14 18:50:12 -0800674 return sendCommandReturningStatus(EFFECT_CMD_SET_PARAM, "SET_PARAM", halParamBuffer.size(),
675 &halParamBuffer[0]);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700676}
677
Kevin Rocard96d2cd92018-11-14 16:22:07 -0800678// Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffect follow.
Kevin Rocard22505e62017-12-14 18:50:12 -0800679Return<Result> Effect::init() {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700680 return sendCommandReturningStatus(EFFECT_CMD_INIT, "INIT");
681}
682
Kevin Rocard22505e62017-12-14 18:50:12 -0800683Return<Result> Effect::setConfig(const EffectConfig& config,
684 const sp<IEffectBufferProviderCallback>& inputBufferProvider,
685 const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
686 return setConfigImpl(EFFECT_CMD_SET_CONFIG, "SET_CONFIG", config, inputBufferProvider,
687 outputBufferProvider);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700688}
689
Kevin Rocard22505e62017-12-14 18:50:12 -0800690Return<Result> Effect::reset() {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700691 return sendCommand(EFFECT_CMD_RESET, "RESET");
692}
693
Kevin Rocard22505e62017-12-14 18:50:12 -0800694Return<Result> Effect::enable() {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700695 return sendCommandReturningStatus(EFFECT_CMD_ENABLE, "ENABLE");
696}
697
Kevin Rocard22505e62017-12-14 18:50:12 -0800698Return<Result> Effect::disable() {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700699 return sendCommandReturningStatus(EFFECT_CMD_DISABLE, "DISABLE");
700}
701
Mikhail Naganovf363ed42020-12-10 18:47:51 -0800702Return<Result> Effect::setAudioSource(
703#if MAJOR_VERSION <= 6
704 AudioSource source
705#else
706 const AudioSource& source
707#endif
708) {
709 audio_source_t halSource;
710 if (status_t status = HidlUtils::audioSourceToHal(source, &halSource); status == NO_ERROR) {
711 uint32_t halSourceParam = static_cast<uint32_t>(halSource);
712 return sendCommand(EFFECT_CMD_SET_AUDIO_SOURCE, "SET_AUDIO_SOURCE", sizeof(uint32_t),
713 &halSourceParam);
714 } else {
715 return analyzeStatus(__func__, "audioSourceToHal", sContextConversion, status);
716 }
717}
718
719#if MAJOR_VERSION <= 6
720
Kevin Rocard30a7fcc2018-03-01 15:08:07 -0800721Return<Result> Effect::setDevice(AudioDeviceBitfield device) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700722 uint32_t halDevice = static_cast<uint32_t>(device);
723 return sendCommand(EFFECT_CMD_SET_DEVICE, "SET_DEVICE", sizeof(uint32_t), &halDevice);
724}
725
Mikhail Naganovf363ed42020-12-10 18:47:51 -0800726Return<Result> Effect::setInputDevice(AudioDeviceBitfield device) {
727 uint32_t halDevice = static_cast<uint32_t>(device);
728 return sendCommand(EFFECT_CMD_SET_INPUT_DEVICE, "SET_INPUT_DEVICE", sizeof(uint32_t),
729 &halDevice);
730}
731
732#else // MAJOR_VERSION <= 6
733
734Return<Result> Effect::setDevice(const DeviceAddress& device) {
735 audio_devices_t halDevice;
736 char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
737 if (status_t status = HidlUtils::deviceAddressToHal(device, &halDevice, halDeviceAddress);
738 status == NO_ERROR) {
739 uint32_t halDeviceParam = static_cast<uint32_t>(halDevice);
740 return sendCommand(EFFECT_CMD_SET_DEVICE, "SET_DEVICE", sizeof(uint32_t), &halDeviceParam);
741 } else {
742 return analyzeStatus(__func__, "deviceAddressToHal", sContextConversion, status);
743 }
744}
745
746Return<Result> Effect::setInputDevice(const DeviceAddress& device) {
747 audio_devices_t halDevice;
748 char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
749 if (status_t status = HidlUtils::deviceAddressToHal(device, &halDevice, halDeviceAddress);
750 status == NO_ERROR) {
751 uint32_t halDeviceParam = static_cast<uint32_t>(halDevice);
752 return sendCommand(EFFECT_CMD_SET_INPUT_DEVICE, "SET_INPUT_DEVICE", sizeof(uint32_t),
753 &halDeviceParam);
754 } else {
755 return analyzeStatus(__func__, "deviceAddressToHal", sContextConversion, status);
756 }
757}
758
759#endif // MAJOR_VERSION <= 6
760
Kevin Rocard22505e62017-12-14 18:50:12 -0800761Return<void> Effect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
762 setAndGetVolume_cb _hidl_cb) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700763 uint32_t halDataSize;
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800764 std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700765 uint32_t halResultSize = halDataSize;
Mikhail Naganov2a652ce2019-11-21 14:03:19 -0800766 std::vector<uint32_t> halResult(volumes.size(), 0);
Kevin Rocard22505e62017-12-14 18:50:12 -0800767 Result retval = sendCommandReturningData(EFFECT_CMD_SET_VOLUME, "SET_VOLUME", halDataSize,
Mikhail Naganov2a652ce2019-11-21 14:03:19 -0800768 &halData[0], &halResultSize, &halResult[0]);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700769 hidl_vec<uint32_t> result;
770 if (retval == Result::OK) {
771 result.setToExternal(&halResult[0], halResultSize);
772 }
773 _hidl_cb(retval, result);
774 return Void();
775}
776
Kevin Rocard22505e62017-12-14 18:50:12 -0800777Return<Result> Effect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
Mikhail Naganovf4f2ff32017-01-19 12:38:39 -0800778 uint32_t halDataSize;
779 std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
Kevin Rocard22505e62017-12-14 18:50:12 -0800780 return sendCommand(EFFECT_CMD_SET_VOLUME, "SET_VOLUME", halDataSize, &halData[0]);
Mikhail Naganovf4f2ff32017-01-19 12:38:39 -0800781}
782
Kevin Rocard22505e62017-12-14 18:50:12 -0800783Return<Result> Effect::setAudioMode(AudioMode mode) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700784 uint32_t halMode = static_cast<uint32_t>(mode);
Kevin Rocard22505e62017-12-14 18:50:12 -0800785 return sendCommand(EFFECT_CMD_SET_AUDIO_MODE, "SET_AUDIO_MODE", sizeof(uint32_t), &halMode);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700786}
787
788Return<Result> Effect::setConfigReverse(
Kevin Rocard22505e62017-12-14 18:50:12 -0800789 const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
790 const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
791 return setConfigImpl(EFFECT_CMD_SET_CONFIG_REVERSE, "SET_CONFIG_REVERSE", config,
792 inputBufferProvider, outputBufferProvider);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700793}
794
Kevin Rocard22505e62017-12-14 18:50:12 -0800795Return<void> Effect::getConfig(getConfig_cb _hidl_cb) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700796 getConfigImpl(EFFECT_CMD_GET_CONFIG, "GET_CONFIG", _hidl_cb);
797 return Void();
798}
799
Kevin Rocard22505e62017-12-14 18:50:12 -0800800Return<void> Effect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700801 getConfigImpl(EFFECT_CMD_GET_CONFIG_REVERSE, "GET_CONFIG_REVERSE", _hidl_cb);
802 return Void();
803}
804
Kevin Rocard22505e62017-12-14 18:50:12 -0800805Return<void> Effect::getSupportedAuxChannelsConfigs(uint32_t maxConfigs,
806 getSupportedAuxChannelsConfigs_cb _hidl_cb) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700807 hidl_vec<EffectAuxChannelsConfig> result;
808 Result retval = getSupportedConfigsImpl(
Kevin Rocard22505e62017-12-14 18:50:12 -0800809 EFFECT_FEATURE_AUX_CHANNELS, maxConfigs, sizeof(channel_config_t),
810 [&](uint32_t supportedConfigs, void* configsData) {
811 result.resize(supportedConfigs);
812 channel_config_t* config = reinterpret_cast<channel_config_t*>(configsData);
813 for (size_t i = 0; i < result.size(); ++i) {
814 effectAuxChannelsConfigFromHal(*config++, &result[i]);
815 }
816 });
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700817 _hidl_cb(retval, result);
818 return Void();
819}
820
Kevin Rocard22505e62017-12-14 18:50:12 -0800821Return<void> Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700822 EffectAuxChannelsConfig result;
823 Result retval = getCurrentConfigImpl(
Kevin Rocard22505e62017-12-14 18:50:12 -0800824 EFFECT_FEATURE_AUX_CHANNELS, sizeof(channel_config_t), [&](void* configData) {
825 effectAuxChannelsConfigFromHal(*reinterpret_cast<channel_config_t*>(configData),
826 &result);
827 });
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700828 _hidl_cb(retval, result);
829 return Void();
830}
831
Kevin Rocard22505e62017-12-14 18:50:12 -0800832Return<Result> Effect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
Mikhail Naganov2a652ce2019-11-21 14:03:19 -0800833 std::vector<uint32_t> halCmd(
834 alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t)), 0);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700835 halCmd[0] = EFFECT_FEATURE_AUX_CHANNELS;
836 effectAuxChannelsConfigToHal(config, reinterpret_cast<channel_config_t*>(&halCmd[1]));
837 return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG,
Mikhail Naganov2a652ce2019-11-21 14:03:19 -0800838 "SET_FEATURE_CONFIG AUX_CHANNELS", halCmd.size(), &halCmd[0]);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700839}
840
Kevin Rocard22505e62017-12-14 18:50:12 -0800841Return<Result> Effect::offload(const EffectOffloadParameter& param) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700842 effect_offload_param_t halParam;
843 effectOffloadParamToHal(param, &halParam);
Kevin Rocard22505e62017-12-14 18:50:12 -0800844 return sendCommandReturningStatus(EFFECT_CMD_OFFLOAD, "OFFLOAD", sizeof(effect_offload_param_t),
845 &halParam);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700846}
847
Kevin Rocard22505e62017-12-14 18:50:12 -0800848Return<void> Effect::getDescriptor(getDescriptor_cb _hidl_cb) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700849 effect_descriptor_t halDescriptor;
850 memset(&halDescriptor, 0, sizeof(effect_descriptor_t));
851 status_t status = (*mHandle)->get_descriptor(mHandle, &halDescriptor);
852 EffectDescriptor descriptor;
853 if (status == OK) {
Mikhail Naganov5ec48c22021-01-15 19:05:04 +0000854 status = EffectUtils::effectDescriptorFromHal(halDescriptor, &descriptor);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700855 }
856 _hidl_cb(analyzeStatus("get_descriptor", "", sContextCallFunction, status), descriptor);
857 return Void();
858}
859
Kevin Rocard22505e62017-12-14 18:50:12 -0800860Return<void> Effect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
861 uint32_t resultMaxSize, command_cb _hidl_cb) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700862 uint32_t halDataSize;
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800863 std::unique_ptr<uint8_t[]> halData = hidlVecToHal(data, &halDataSize);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700864 uint32_t halResultSize = resultMaxSize;
865 std::unique_ptr<uint8_t[]> halResult(new uint8_t[halResultSize]);
866 memset(&halResult[0], 0, halResultSize);
Mikhail Naganovf4f2ff32017-01-19 12:38:39 -0800867
868 void* dataPtr = halDataSize > 0 ? &halData[0] : NULL;
869 void* resultPtr = halResultSize > 0 ? &halResult[0] : NULL;
Andy Hung7d5eb5c2022-10-18 18:03:54 -0700870 status_t status = BAD_VALUE;
871 switch (commandId) {
872 case 'gtid': // retrieve the tid, used for spatializer priority boost
873 if (halDataSize == 0 && resultMaxSize == sizeof(int32_t)) {
874 auto ptid = (int32_t*)resultPtr;
875 ptid[0] = mProcessThread ? mProcessThread->getTid() : -1;
876 status = OK;
877 break; // we have handled 'gtid' here.
878 }
879 [[fallthrough]]; // allow 'gtid' overload (checked halDataSize and resultMaxSize).
880 default:
881 status = (*mHandle)->command(mHandle, commandId, halDataSize, dataPtr, &halResultSize,
882 resultPtr);
883 break;
884 }
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700885 hidl_vec<uint8_t> result;
Mikhail Naganovf4f2ff32017-01-19 12:38:39 -0800886 if (status == OK && resultPtr != NULL) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700887 result.setToExternal(&halResult[0], halResultSize);
888 }
889 _hidl_cb(status, result);
890 return Void();
891}
892
Kevin Rocard22505e62017-12-14 18:50:12 -0800893Return<Result> Effect::setParameter(const hidl_vec<uint8_t>& parameter,
894 const hidl_vec<uint8_t>& value) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700895 return setParameterImpl(parameter.size(), &parameter[0], value.size(), &value[0]);
896}
897
Kevin Rocard22505e62017-12-14 18:50:12 -0800898Return<void> Effect::getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
899 getParameter_cb _hidl_cb) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700900 hidl_vec<uint8_t> value;
901 Result retval = getParameterImpl(
Kevin Rocard22505e62017-12-14 18:50:12 -0800902 parameter.size(), &parameter[0], valueMaxSize,
903 [&](uint32_t valueSize, const void* valueData) {
904 value.setToExternal(reinterpret_cast<uint8_t*>(const_cast<void*>(valueData)),
905 valueSize);
906 });
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700907 _hidl_cb(retval, value);
908 return Void();
909}
910
Kevin Rocard22505e62017-12-14 18:50:12 -0800911Return<void> Effect::getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
912 uint32_t configSize,
913 getSupportedConfigsForFeature_cb _hidl_cb) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700914 uint32_t configCount = 0;
915 hidl_vec<uint8_t> result;
Kevin Rocard22505e62017-12-14 18:50:12 -0800916 Result retval = getSupportedConfigsImpl(featureId, maxConfigs, configSize,
917 [&](uint32_t supportedConfigs, void* configsData) {
918 configCount = supportedConfigs;
919 result.resize(configCount * configSize);
920 memcpy(&result[0], configsData, result.size());
921 });
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700922 _hidl_cb(retval, configCount, result);
923 return Void();
924}
925
Kevin Rocard22505e62017-12-14 18:50:12 -0800926Return<void> Effect::getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
927 getCurrentConfigForFeature_cb _hidl_cb) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700928 hidl_vec<uint8_t> result;
Kevin Rocard22505e62017-12-14 18:50:12 -0800929 Result retval = getCurrentConfigImpl(featureId, configSize, [&](void* configData) {
930 result.resize(configSize);
931 memcpy(&result[0], configData, result.size());
932 });
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700933 _hidl_cb(retval, result);
934 return Void();
935}
936
Kevin Rocard22505e62017-12-14 18:50:12 -0800937Return<Result> Effect::setCurrentConfigForFeature(uint32_t featureId,
938 const hidl_vec<uint8_t>& configData) {
Mikhail Naganov2a652ce2019-11-21 14:03:19 -0800939 std::vector<uint32_t> halCmd(alignedSizeIn<uint32_t>(sizeof(uint32_t) + configData.size()), 0);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700940 halCmd[0] = featureId;
941 memcpy(&halCmd[1], &configData[0], configData.size());
Kevin Rocard22505e62017-12-14 18:50:12 -0800942 return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG, "SET_FEATURE_CONFIG",
Mikhail Naganov2a652ce2019-11-21 14:03:19 -0800943 halCmd.size(), &halCmd[0]);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700944}
945
Mikhail Naganova331de12017-01-04 16:33:55 -0800946Return<Result> Effect::close() {
Mikhail Naganov7623ed92019-11-14 13:57:15 -0800947 if (mStopProcessThread.load(std::memory_order_relaxed)) { // only this thread modifies
948 return Result::INVALID_STATE;
Mikhail Naganova331de12017-01-04 16:33:55 -0800949 }
Mikhail Naganov7623ed92019-11-14 13:57:15 -0800950 mStopProcessThread.store(true, std::memory_order_release);
Mikhail Naganova331de12017-01-04 16:33:55 -0800951 if (mEfGroup) {
Mikhail Naganovb0abafb2017-01-31 17:24:48 -0800952 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT));
Mikhail Naganova331de12017-01-04 16:33:55 -0800953 }
Mikhail Naganov7623ed92019-11-14 13:57:15 -0800954#if MAJOR_VERSION <= 5
Mikhail Naganova331de12017-01-04 16:33:55 -0800955 return Result::OK;
Mikhail Naganov7623ed92019-11-14 13:57:15 -0800956#elif MAJOR_VERSION >= 6
957 // No need to join the processing thread, it is part of the API contract that the client
958 // must finish processing before closing the effect.
Mikhail Naganov532240f2019-12-04 16:18:50 -0800959 Result retval =
960 analyzeStatus("EffectRelease", "", sContextCallFunction, EffectRelease(mHandle));
961 EffectMap::getInstance().remove(mHandle);
962 return retval;
Mikhail Naganov7623ed92019-11-14 13:57:15 -0800963#endif
Mikhail Naganova331de12017-01-04 16:33:55 -0800964}
965
Mikhail Naganovfa021442019-02-22 14:28:26 -0800966Return<void> Effect::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /* options */) {
967 if (fd.getNativeHandle() != nullptr && fd->numFds == 1) {
968 uint32_t cmdData = fd->data[0];
969 (void)sendCommand(EFFECT_CMD_DUMP, "DUMP", sizeof(cmdData), &cmdData);
Andy Hung502f9d02022-04-26 18:37:36 -0700970 const std::string s = mStatistics->dump();
971 if (s.size() != 0) write(cmdData, s.c_str(), s.size());
Mikhail Naganovfa021442019-02-22 14:28:26 -0800972 }
973 return Void();
974}
975
Kevin Rocard22505e62017-12-14 18:50:12 -0800976} // namespace implementation
Kevin Rocard96d2cd92018-11-14 16:22:07 -0800977} // namespace CPP_VERSION
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700978} // namespace effect
979} // namespace audio
980} // namespace hardware
981} // namespace android