blob: 3c97fc401dbcea2fe440fc9c5840bf6c98f87d3a [file] [log] [blame]
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -07001/*
2 * Copyright (C) 2016 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
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -070017#include <memory.h>
18
19#define LOG_TAG "EffectHAL"
Yifan Hongf9d30342016-11-30 13:45:34 -080020#include <android/log.h>
Mikhail Naganova331de12017-01-04 16:33:55 -080021#include <media/EffectsFactoryApi.h>
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -070022
23#include "Conversions.h"
24#include "Effect.h"
Mikhail Naganov10548292016-10-31 10:39:47 -070025#include "EffectMap.h"
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -070026
27namespace android {
28namespace hardware {
29namespace audio {
30namespace effect {
31namespace V2_0 {
32namespace implementation {
33
34using ::android::hardware::audio::common::V2_0::AudioChannelMask;
35using ::android::hardware::audio::common::V2_0::AudioFormat;
Mikhail Naganova331de12017-01-04 16:33:55 -080036using ::android::hardware::audio::effect::V2_0::MessageQueueFlagBits;
37
38namespace {
39
40class ProcessThread : public Thread {
41 public:
42 // ProcessThread's lifespan never exceeds Effect's lifespan.
43 ProcessThread(std::atomic<bool>* stop,
44 effect_handle_t effect,
45 std::atomic<audio_buffer_t*>* inBuffer,
46 std::atomic<audio_buffer_t*>* outBuffer,
47 Effect::StatusMQ* statusMQ,
48 EventFlag* efGroup)
49 : Thread(false /*canCallJava*/),
50 mStop(stop),
51 mEffect(effect),
52 mHasProcessReverse((*mEffect)->process_reverse != NULL),
53 mInBuffer(inBuffer),
54 mOutBuffer(outBuffer),
55 mStatusMQ(statusMQ),
56 mEfGroup(efGroup) {
57 }
58 virtual ~ProcessThread() {}
59
60 private:
61 std::atomic<bool>* mStop;
62 effect_handle_t mEffect;
63 bool mHasProcessReverse;
64 std::atomic<audio_buffer_t*>* mInBuffer;
65 std::atomic<audio_buffer_t*>* mOutBuffer;
66 Effect::StatusMQ* mStatusMQ;
67 EventFlag* mEfGroup;
68
69 bool threadLoop() override;
70};
71
72bool ProcessThread::threadLoop() {
73 // This implementation doesn't return control back to the Thread until it decides to stop,
74 // as the Thread uses mutexes, and this can lead to priority inversion.
75 while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
76 uint32_t efState = 0;
77 mEfGroup->wait(
78 static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL),
79 &efState,
80 NS_PER_SEC);
81 if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL))) {
82 continue; // Nothing to do.
83 }
84 Result retval = Result::OK;
85 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_REVERSE)
86 && !mHasProcessReverse) {
87 retval = Result::NOT_SUPPORTED;
88 }
89
90 if (retval == Result::OK) {
91 // affects both buffer pointers and their contents.
92 std::atomic_thread_fence(std::memory_order_acquire);
93 int32_t processResult;
94 audio_buffer_t* inBuffer =
95 std::atomic_load_explicit(mInBuffer, std::memory_order_relaxed);
96 audio_buffer_t* outBuffer =
97 std::atomic_load_explicit(mOutBuffer, std::memory_order_relaxed);
98 if (inBuffer != nullptr && outBuffer != nullptr) {
99 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS)) {
100 processResult = (*mEffect)->process(mEffect, inBuffer, outBuffer);
101 } else {
102 processResult = (*mEffect)->process_reverse(mEffect, inBuffer, outBuffer);
103 }
104 std::atomic_thread_fence(std::memory_order_release);
105 } else {
106 ALOGE("processing buffers were not set before calling 'process'");
107 processResult = -ENODEV;
108 }
109 switch(processResult) {
110 case 0: retval = Result::OK; break;
111 case -ENODATA: retval = Result::INVALID_STATE; break;
112 case -EINVAL: retval = Result::INVALID_ARGUMENTS; break;
113 default: retval = Result::NOT_INITIALIZED;
114 }
115 }
116 if (!mStatusMQ->write(&retval)) {
117 ALOGW("status message queue write failed");
118 }
119 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING));
120 }
121
122 return false;
123}
124
125} // namespace
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700126
127// static
128const char *Effect::sContextResultOfCommand = "returned status";
129const char *Effect::sContextCallToCommand = "error";
130const char *Effect::sContextCallFunction = sContextCallToCommand;
131
Mikhail Naganova331de12017-01-04 16:33:55 -0800132Effect::Effect(effect_handle_t handle)
133 : mIsClosed(false), mHandle(handle), mEfGroup(nullptr), mStopProcessThread(false) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700134}
135
136Effect::~Effect() {
Mikhail Naganova331de12017-01-04 16:33:55 -0800137 close();
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700138}
139
140// static
141template<typename T> size_t Effect::alignedSizeIn(size_t s) {
142 return (s + sizeof(T) - 1) / sizeof(T);
143}
144
145// static
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800146template<typename T> std::unique_ptr<uint8_t[]> Effect::hidlVecToHal(
147 const hidl_vec<T>& vec, uint32_t* halDataSize) {
148 // Due to bugs in HAL, they may attempt to write into the provided
149 // input buffer. The original binder buffer is r/o, thus it is needed
150 // to create a r/w version.
151 *halDataSize = vec.size() * sizeof(T);
152 std::unique_ptr<uint8_t[]> halData(new uint8_t[*halDataSize]);
153 memcpy(&halData[0], &vec[0], *halDataSize);
154 return halData;
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700155}
156
157// static
158void Effect::effectAuxChannelsConfigFromHal(
159 const channel_config_t& halConfig, EffectAuxChannelsConfig* config) {
160 config->mainChannels = AudioChannelMask(halConfig.main_channels);
161 config->auxChannels = AudioChannelMask(halConfig.aux_channels);
162}
163
164// static
165void Effect::effectAuxChannelsConfigToHal(
166 const EffectAuxChannelsConfig& config, channel_config_t* halConfig) {
167 halConfig->main_channels = static_cast<audio_channel_mask_t>(config.mainChannels);
168 halConfig->aux_channels = static_cast<audio_channel_mask_t>(config.auxChannels);
169}
170
171// static
172void Effect::effectBufferConfigFromHal(
173 const buffer_config_t& halConfig, EffectBufferConfig* config) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700174 config->samplingRateHz = halConfig.samplingRate;
175 config->channels = AudioChannelMask(halConfig.channels);
176 config->format = AudioFormat(halConfig.format);
177 config->accessMode = EffectBufferAccess(halConfig.accessMode);
178 config->mask = EffectConfigParameters(halConfig.mask);
179}
180
181// static
182void Effect::effectBufferConfigToHal(const EffectBufferConfig& config, buffer_config_t* halConfig) {
Mikhail Naganova331de12017-01-04 16:33:55 -0800183 // Note: setting the buffers directly is considered obsolete. They need to be set
184 // using 'setProcessBuffers'.
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700185 halConfig->buffer.frameCount = 0;
186 halConfig->buffer.raw = NULL;
187 halConfig->samplingRate = config.samplingRateHz;
188 halConfig->channels = static_cast<uint32_t>(config.channels);
Mikhail Naganova331de12017-01-04 16:33:55 -0800189 // TODO(mnaganov): The framework code currently does not use BP, implement later.
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700190 halConfig->bufferProvider.cookie = NULL;
191 halConfig->bufferProvider.getBuffer = NULL;
192 halConfig->bufferProvider.releaseBuffer = NULL;
193 halConfig->format = static_cast<uint8_t>(config.format);
194 halConfig->accessMode = static_cast<uint8_t>(config.accessMode);
195 halConfig->mask = static_cast<uint8_t>(config.mask);
196}
197
198// static
199void Effect::effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config) {
200 effectBufferConfigFromHal(halConfig.inputCfg, &config->inputCfg);
201 effectBufferConfigFromHal(halConfig.outputCfg, &config->outputCfg);
202}
203
204// static
205void Effect::effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig) {
206 effectBufferConfigToHal(config.inputCfg, &halConfig->inputCfg);
207 effectBufferConfigToHal(config.outputCfg, &halConfig->outputCfg);
208}
209
210// static
211void Effect::effectOffloadParamToHal(
212 const EffectOffloadParameter& offload, effect_offload_param_t* halOffload) {
213 halOffload->isOffload = offload.isOffload;
214 halOffload->ioHandle = offload.ioHandle;
215}
216
217// static
218std::vector<uint8_t> Effect::parameterToHal(
219 uint32_t paramSize,
220 const void* paramData,
221 uint32_t valueSize,
222 const void** valueData) {
223 size_t valueOffsetFromData = alignedSizeIn<uint32_t>(paramSize) * sizeof(uint32_t);
224 size_t halParamBufferSize = sizeof(effect_param_t) + valueOffsetFromData + valueSize;
225 std::vector<uint8_t> halParamBuffer(halParamBufferSize, 0);
226 effect_param_t *halParam = reinterpret_cast<effect_param_t*>(&halParamBuffer[0]);
227 halParam->psize = paramSize;
228 halParam->vsize = valueSize;
229 memcpy(halParam->data, paramData, paramSize);
230 if (valueData) {
231 if (*valueData) {
232 // Value data is provided.
233 memcpy(halParam->data + valueOffsetFromData, *valueData, valueSize);
234 } else {
235 // The caller needs the pointer to the value data location.
236 *valueData = halParam->data + valueOffsetFromData;
237 }
238 }
239 return halParamBuffer;
240}
241
242Result Effect::analyzeCommandStatus(const char* commandName, const char* context, status_t status) {
243 return analyzeStatus("command", commandName, context, status);
244}
245
246Result Effect::analyzeStatus(
247 const char* funcName,
248 const char* subFuncName,
249 const char* contextDescription,
250 status_t status) {
251 if (status != OK) {
252 ALOGW("Effect %p %s %s %s: %s",
253 mHandle, funcName, subFuncName, contextDescription, strerror(-status));
254 }
255 switch (status) {
256 case OK: return Result::OK;
257 case -EINVAL: return Result::INVALID_ARGUMENTS;
258 case -ENODATA: return Result::INVALID_STATE;
259 case -ENODEV: return Result::NOT_INITIALIZED;
260 case -ENOMEM: return Result::RESULT_TOO_BIG;
261 case -ENOSYS: return Result::NOT_SUPPORTED;
262 default: return Result::INVALID_STATE;
263 }
264}
265
266void Effect::getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb) {
267 uint32_t halResultSize = sizeof(effect_config_t);
268 effect_config_t halConfig;
269 status_t status = (*mHandle)->command(
270 mHandle, commandCode, 0, NULL, &halResultSize, &halConfig);
271 EffectConfig config;
272 if (status == OK) {
273 effectConfigFromHal(halConfig, &config);
274 }
275 cb(analyzeCommandStatus(commandName, sContextCallToCommand, status), config);
276}
277
278Result Effect::getCurrentConfigImpl(
279 uint32_t featureId, uint32_t configSize, GetCurrentConfigSuccessCallback onSuccess) {
280 uint32_t halCmd = featureId;
281 uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize)];
282 memset(halResult, 0, sizeof(halResult));
283 uint32_t halResultSize = 0;
284 return sendCommandReturningStatusAndData(
285 EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG",
286 sizeof(uint32_t), &halCmd,
287 &halResultSize, halResult,
288 sizeof(uint32_t),
289 [&]{ onSuccess(&halResult[1]); });
290}
291
292Result Effect::getParameterImpl(
293 uint32_t paramSize,
294 const void* paramData,
295 uint32_t valueSize,
296 GetParameterSuccessCallback onSuccess) {
297 // As it is unknown what method HAL uses for copying the provided parameter data,
298 // it is safer to make sure that input and output buffers do not overlap.
299 std::vector<uint8_t> halCmdBuffer =
300 parameterToHal(paramSize, paramData, valueSize, nullptr);
301 const void *valueData = nullptr;
302 std::vector<uint8_t> halParamBuffer =
303 parameterToHal(paramSize, paramData, valueSize, &valueData);
304 uint32_t halParamBufferSize = halParamBuffer.size();
305
306 return sendCommandReturningStatusAndData(
307 EFFECT_CMD_GET_PARAM, "GET_PARAM",
308 halCmdBuffer.size(), &halCmdBuffer[0],
309 &halParamBufferSize, &halParamBuffer[0],
310 sizeof(effect_param_t),
311 [&]{
312 effect_param_t *halParam = reinterpret_cast<effect_param_t*>(&halParamBuffer[0]);
313 onSuccess(halParam->vsize, valueData);
314 });
315}
316
317Result Effect::getSupportedConfigsImpl(
318 uint32_t featureId,
319 uint32_t maxConfigs,
320 uint32_t configSize,
321 GetSupportedConfigsSuccessCallback onSuccess) {
322 uint32_t halCmd[2] = { featureId, maxConfigs };
323 uint32_t halResultSize = 2 * sizeof(uint32_t) + maxConfigs * sizeof(configSize);
324 uint8_t halResult[halResultSize];
325 memset(&halResult[0], 0, halResultSize);
326 return sendCommandReturningStatusAndData(
327 EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, "GET_FEATURE_SUPPORTED_CONFIGS",
328 sizeof(halCmd), halCmd,
329 &halResultSize, &halResult[0],
330 2 * sizeof(uint32_t),
331 [&]{
332 uint32_t *halResult32 = reinterpret_cast<uint32_t*>(&halResult[0]);
333 uint32_t supportedConfigs = *(++halResult32); // skip status field
334 if (supportedConfigs > maxConfigs) supportedConfigs = maxConfigs;
335 onSuccess(supportedConfigs, ++halResult32);
336 });
337}
338
Mikhail Naganova331de12017-01-04 16:33:55 -0800339Return<void> Effect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
340 status_t status;
341 // Create message queue.
342 if (mStatusMQ) {
343 ALOGE("the client attempts to call prepareForProcessing_cb twice");
344 _hidl_cb(Result::INVALID_STATE, StatusMQ::Descriptor());
345 return Void();
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700346 }
Mikhail Naganova331de12017-01-04 16:33:55 -0800347 std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1, true /*EventFlag*/));
348 if (!tempStatusMQ->isValid()) {
349 ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
350 _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
351 return Void();
352 }
353 status = EventFlag::createEventFlag(tempStatusMQ->getEventFlagWord(), &mEfGroup);
354 if (status != OK || !mEfGroup) {
355 ALOGE("failed creating event flag for status MQ: %s", strerror(-status));
356 _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
357 return Void();
358 }
359
360 // Create and launch the thread.
361 mProcessThread = new ProcessThread(
362 &mStopProcessThread,
363 mHandle,
364 &mHalInBufferPtr,
365 &mHalOutBufferPtr,
366 tempStatusMQ.get(),
367 mEfGroup);
368 status = mProcessThread->run("effect", PRIORITY_URGENT_AUDIO);
369 if (status != OK) {
370 ALOGW("failed to start effect processing thread: %s", strerror(-status));
371 _hidl_cb(Result::INVALID_ARGUMENTS, MQDescriptorSync<Result>());
372 return Void();
373 }
374
375 mStatusMQ = std::move(tempStatusMQ);
376 _hidl_cb(Result::OK, *mStatusMQ->getDesc());
377 return Void();
378}
379
380Return<Result> Effect::setProcessBuffers(
381 const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
382 AudioBufferManager& manager = AudioBufferManager::getInstance();
383 sp<AudioBufferWrapper> tempInBuffer, tempOutBuffer;
384 if (!manager.wrap(inBuffer, &tempInBuffer)) {
385 ALOGE("Could not map memory of the input buffer");
386 return Result::INVALID_ARGUMENTS;
387 }
388 if (!manager.wrap(outBuffer, &tempOutBuffer)) {
389 ALOGE("Could not map memory of the output buffer");
390 return Result::INVALID_ARGUMENTS;
391 }
392 mInBuffer = tempInBuffer;
393 mOutBuffer = tempOutBuffer;
394 // The processing thread only reads these pointers after waking up by an event flag,
395 // so it's OK to update the pair non-atomically.
396 mHalInBufferPtr.store(mInBuffer->getHalBuffer(), std::memory_order_release);
397 mHalOutBufferPtr.store(mOutBuffer->getHalBuffer(), std::memory_order_release);
398 return Result::OK;
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700399}
400
401Result Effect::sendCommand(int commandCode, const char* commandName) {
402 return sendCommand(commandCode, commandName, 0, NULL);
403}
404
405Result Effect::sendCommand(
406 int commandCode, const char* commandName, uint32_t size, void* data) {
407 status_t status = (*mHandle)->command(mHandle, commandCode, size, data, 0, NULL);
408 return analyzeCommandStatus(commandName, sContextCallToCommand, status);
409}
410
411Result Effect::sendCommandReturningData(
412 int commandCode, const char* commandName,
413 uint32_t* replySize, void* replyData) {
414 return sendCommandReturningData(commandCode, commandName, 0, NULL, replySize, replyData);
415}
416
417Result Effect::sendCommandReturningData(
418 int commandCode, const char* commandName,
419 uint32_t size, void* data,
420 uint32_t* replySize, void* replyData) {
421 uint32_t expectedReplySize = *replySize;
422 status_t status = (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
423 if (status == OK && *replySize != expectedReplySize) {
424 status = -ENODATA;
425 }
426 return analyzeCommandStatus(commandName, sContextCallToCommand, status);
427}
428
429Result Effect::sendCommandReturningStatus(int commandCode, const char* commandName) {
430 return sendCommandReturningStatus(commandCode, commandName, 0, NULL);
431}
432
433Result Effect::sendCommandReturningStatus(
434 int commandCode, const char* commandName, uint32_t size, void* data) {
435 uint32_t replyCmdStatus;
436 uint32_t replySize = sizeof(uint32_t);
437 return sendCommandReturningStatusAndData(
438 commandCode, commandName, size, data, &replySize, &replyCmdStatus, replySize, []{});
439}
440
441Result Effect::sendCommandReturningStatusAndData(
442 int commandCode, const char* commandName,
443 uint32_t size, void* data,
444 uint32_t* replySize, void* replyData,
445 uint32_t minReplySize,
446 CommandSuccessCallback onSuccess) {
447 status_t status =
448 (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
449 Result retval;
450 if (status == OK && minReplySize >= sizeof(uint32_t) && *replySize >= minReplySize) {
451 uint32_t commandStatus = *reinterpret_cast<uint32_t*>(replyData);
452 retval = analyzeCommandStatus(commandName, sContextResultOfCommand, commandStatus);
453 if (commandStatus == OK) {
454 onSuccess();
455 }
456 } else {
457 retval = analyzeCommandStatus(commandName, sContextCallToCommand, status);
458 }
459 return retval;
460}
461
462Result Effect::setConfigImpl(
463 int commandCode, const char* commandName,
464 const EffectConfig& config,
465 const sp<IEffectBufferProviderCallback>& inputBufferProvider,
466 const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
467 effect_config_t halConfig;
468 effectConfigToHal(config, &halConfig);
469 if (inputBufferProvider != 0) {
470 LOG_FATAL("Using input buffer provider is not supported");
471 }
472 if (outputBufferProvider != 0) {
473 LOG_FATAL("Using output buffer provider is not supported");
474 }
475 return sendCommandReturningStatus(
476 commandCode, commandName, sizeof(effect_config_t), &halConfig);
477}
478
479
480Result Effect::setParameterImpl(
481 uint32_t paramSize, const void* paramData, uint32_t valueSize, const void* valueData) {
482 std::vector<uint8_t> halParamBuffer = parameterToHal(
483 paramSize, paramData, valueSize, &valueData);
484 return sendCommandReturningStatus(
485 EFFECT_CMD_SET_PARAM, "SET_PARAM", halParamBuffer.size(), &halParamBuffer[0]);
486}
487
488// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
489Return<Result> Effect::init() {
490 return sendCommandReturningStatus(EFFECT_CMD_INIT, "INIT");
491}
492
493Return<Result> Effect::setConfig(
494 const EffectConfig& config,
495 const sp<IEffectBufferProviderCallback>& inputBufferProvider,
496 const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
497 return setConfigImpl(
498 EFFECT_CMD_SET_CONFIG, "SET_CONFIG", config, inputBufferProvider, outputBufferProvider);
499}
500
501Return<Result> Effect::reset() {
502 return sendCommand(EFFECT_CMD_RESET, "RESET");
503}
504
505Return<Result> Effect::enable() {
506 return sendCommandReturningStatus(EFFECT_CMD_ENABLE, "ENABLE");
507}
508
509Return<Result> Effect::disable() {
510 return sendCommandReturningStatus(EFFECT_CMD_DISABLE, "DISABLE");
511}
512
513Return<Result> Effect::setDevice(AudioDevice device) {
514 uint32_t halDevice = static_cast<uint32_t>(device);
515 return sendCommand(EFFECT_CMD_SET_DEVICE, "SET_DEVICE", sizeof(uint32_t), &halDevice);
516}
517
518Return<void> Effect::setAndGetVolume(
519 const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
520 uint32_t halDataSize;
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800521 std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700522 uint32_t halResultSize = halDataSize;
523 uint32_t halResult[volumes.size()];
524 Result retval = sendCommandReturningData(
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800525 EFFECT_CMD_SET_VOLUME, "SET_VOLUME",
526 halDataSize, &halData[0],
527 &halResultSize, halResult);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700528 hidl_vec<uint32_t> result;
529 if (retval == Result::OK) {
530 result.setToExternal(&halResult[0], halResultSize);
531 }
532 _hidl_cb(retval, result);
533 return Void();
534}
535
Mikhail Naganovf4f2ff32017-01-19 12:38:39 -0800536Return<Result> Effect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
537 uint32_t halDataSize;
538 std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
539 return sendCommand(
540 EFFECT_CMD_SET_VOLUME, "SET_VOLUME",
541 halDataSize, &halData[0]);
542}
543
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700544Return<Result> Effect::setAudioMode(AudioMode mode) {
545 uint32_t halMode = static_cast<uint32_t>(mode);
546 return sendCommand(
547 EFFECT_CMD_SET_AUDIO_MODE, "SET_AUDIO_MODE", sizeof(uint32_t), &halMode);
548}
549
550Return<Result> Effect::setConfigReverse(
551 const EffectConfig& config,
552 const sp<IEffectBufferProviderCallback>& inputBufferProvider,
553 const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
554 return setConfigImpl(EFFECT_CMD_SET_CONFIG_REVERSE, "SET_CONFIG_REVERSE",
555 config, inputBufferProvider, outputBufferProvider);
556}
557
558Return<Result> Effect::setInputDevice(AudioDevice device) {
559 uint32_t halDevice = static_cast<uint32_t>(device);
560 return sendCommand(
561 EFFECT_CMD_SET_INPUT_DEVICE, "SET_INPUT_DEVICE", sizeof(uint32_t), &halDevice);
562}
563
564Return<void> Effect::getConfig(getConfig_cb _hidl_cb) {
565 getConfigImpl(EFFECT_CMD_GET_CONFIG, "GET_CONFIG", _hidl_cb);
566 return Void();
567}
568
569Return<void> Effect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
570 getConfigImpl(EFFECT_CMD_GET_CONFIG_REVERSE, "GET_CONFIG_REVERSE", _hidl_cb);
571 return Void();
572}
573
574Return<void> Effect::getSupportedAuxChannelsConfigs(
575 uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
576 hidl_vec<EffectAuxChannelsConfig> result;
577 Result retval = getSupportedConfigsImpl(
578 EFFECT_FEATURE_AUX_CHANNELS,
579 maxConfigs,
580 sizeof(channel_config_t),
581 [&] (uint32_t supportedConfigs, void* configsData) {
582 result.resize(supportedConfigs);
583 channel_config_t *config = reinterpret_cast<channel_config_t*>(configsData);
584 for (size_t i = 0; i < result.size(); ++i) {
585 effectAuxChannelsConfigFromHal(*config++, &result[i]);
586 }
587 });
588 _hidl_cb(retval, result);
589 return Void();
590}
591
592Return<void> Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
593 uint32_t halCmd = EFFECT_FEATURE_AUX_CHANNELS;
594 uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))];
595 memset(halResult, 0, sizeof(halResult));
596 uint32_t halResultSize = 0;
597 EffectAuxChannelsConfig result;
598 Result retval = getCurrentConfigImpl(
599 EFFECT_FEATURE_AUX_CHANNELS,
600 sizeof(channel_config_t),
601 [&] (void* configData) {
602 effectAuxChannelsConfigFromHal(
603 *reinterpret_cast<channel_config_t*>(configData), &result);
604 });
605 _hidl_cb(retval, result);
606 return Void();
607}
608
609Return<Result> Effect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
610 uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))];
611 halCmd[0] = EFFECT_FEATURE_AUX_CHANNELS;
612 effectAuxChannelsConfigToHal(config, reinterpret_cast<channel_config_t*>(&halCmd[1]));
613 return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG,
614 "SET_FEATURE_CONFIG AUX_CHANNELS", sizeof(halCmd), halCmd);
615}
616
617Return<Result> Effect::setAudioSource(AudioSource source) {
618 uint32_t halSource = static_cast<uint32_t>(source);
619 return sendCommand(
620 EFFECT_CMD_SET_AUDIO_SOURCE, "SET_AUDIO_SOURCE", sizeof(uint32_t), &halSource);
621}
622
623Return<Result> Effect::offload(const EffectOffloadParameter& param) {
624 effect_offload_param_t halParam;
625 effectOffloadParamToHal(param, &halParam);
626 return sendCommandReturningStatus(
627 EFFECT_CMD_OFFLOAD, "OFFLOAD", sizeof(effect_offload_param_t), &halParam);
628}
629
630Return<void> Effect::getDescriptor(getDescriptor_cb _hidl_cb) {
631 effect_descriptor_t halDescriptor;
632 memset(&halDescriptor, 0, sizeof(effect_descriptor_t));
633 status_t status = (*mHandle)->get_descriptor(mHandle, &halDescriptor);
634 EffectDescriptor descriptor;
635 if (status == OK) {
636 effectDescriptorFromHal(halDescriptor, &descriptor);
637 }
638 _hidl_cb(analyzeStatus("get_descriptor", "", sContextCallFunction, status), descriptor);
639 return Void();
640}
641
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700642Return<void> Effect::command(
643 uint32_t commandId,
644 const hidl_vec<uint8_t>& data,
645 uint32_t resultMaxSize,
646 command_cb _hidl_cb) {
647 uint32_t halDataSize;
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800648 std::unique_ptr<uint8_t[]> halData = hidlVecToHal(data, &halDataSize);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700649 uint32_t halResultSize = resultMaxSize;
650 std::unique_ptr<uint8_t[]> halResult(new uint8_t[halResultSize]);
651 memset(&halResult[0], 0, halResultSize);
Mikhail Naganovf4f2ff32017-01-19 12:38:39 -0800652
653 void* dataPtr = halDataSize > 0 ? &halData[0] : NULL;
654 void* resultPtr = halResultSize > 0 ? &halResult[0] : NULL;
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700655 status_t status = (*mHandle)->command(
Mikhail Naganovf4f2ff32017-01-19 12:38:39 -0800656 mHandle, commandId, halDataSize, dataPtr, &halResultSize, resultPtr);
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700657 hidl_vec<uint8_t> result;
Mikhail Naganovf4f2ff32017-01-19 12:38:39 -0800658 if (status == OK && resultPtr != NULL) {
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700659 result.setToExternal(&halResult[0], halResultSize);
660 }
661 _hidl_cb(status, result);
662 return Void();
663}
664
665Return<Result> Effect::setParameter(
666 const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
667 return setParameterImpl(parameter.size(), &parameter[0], value.size(), &value[0]);
668}
669
670Return<void> Effect::getParameter(
671 const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize, getParameter_cb _hidl_cb) {
672 hidl_vec<uint8_t> value;
673 Result retval = getParameterImpl(
674 parameter.size(),
675 &parameter[0],
676 valueMaxSize,
677 [&] (uint32_t valueSize, const void* valueData) {
678 value.setToExternal(
679 reinterpret_cast<uint8_t*>(const_cast<void*>(valueData)), valueSize);
680 });
681 _hidl_cb(retval, value);
682 return Void();
683}
684
685Return<void> Effect::getSupportedConfigsForFeature(
686 uint32_t featureId,
687 uint32_t maxConfigs,
688 uint32_t configSize,
689 getSupportedConfigsForFeature_cb _hidl_cb) {
690 uint32_t configCount = 0;
691 hidl_vec<uint8_t> result;
692 Result retval = getSupportedConfigsImpl(
693 featureId,
694 maxConfigs,
695 configSize,
696 [&] (uint32_t supportedConfigs, void* configsData) {
697 configCount = supportedConfigs;
698 result.resize(configCount * configSize);
699 memcpy(&result[0], configsData, result.size());
700 });
701 _hidl_cb(retval, configCount, result);
702 return Void();
703}
704
705Return<void> Effect::getCurrentConfigForFeature(
706 uint32_t featureId, uint32_t configSize, getCurrentConfigForFeature_cb _hidl_cb) {
707 hidl_vec<uint8_t> result;
708 Result retval = getCurrentConfigImpl(
709 featureId,
710 configSize,
711 [&] (void* configData) {
712 result.resize(configSize);
713 memcpy(&result[0], configData, result.size());
714 });
715 _hidl_cb(retval, result);
716 return Void();
717}
718
719Return<Result> Effect::setCurrentConfigForFeature(
720 uint32_t featureId, const hidl_vec<uint8_t>& configData) {
721 uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configData.size())];
722 memset(halCmd, 0, sizeof(halCmd));
723 halCmd[0] = featureId;
724 memcpy(&halCmd[1], &configData[0], configData.size());
725 return sendCommandReturningStatus(
726 EFFECT_CMD_SET_FEATURE_CONFIG, "SET_FEATURE_CONFIG", sizeof(halCmd), halCmd);
727}
728
Mikhail Naganova331de12017-01-04 16:33:55 -0800729Return<Result> Effect::close() {
730 if (mIsClosed) return Result::INVALID_STATE;
731 mIsClosed = true;
732 if (mProcessThread.get()) {
733 mStopProcessThread.store(true, std::memory_order_release);
734 status_t status = mProcessThread->requestExitAndWait();
735 ALOGE_IF(status, "processing thread exit error: %s", strerror(-status));
736 }
737 if (mEfGroup) {
738 status_t status = EventFlag::deleteEventFlag(&mEfGroup);
739 ALOGE_IF(status, "processing MQ event flag deletion error: %s", strerror(-status));
740 }
741 mInBuffer.clear();
742 mOutBuffer.clear();
743 int status = EffectRelease(mHandle);
744 ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status));
745 EffectMap::getInstance().remove(mHandle);
746 mHandle = 0;
747 return Result::OK;
748}
749
Mikhail Naganov7cbf2f12016-10-27 20:05:35 -0700750} // namespace implementation
751} // namespace V2_0
752} // namespace effect
753} // namespace audio
754} // namespace hardware
755} // namespace android