Re-implement HIDL effect processing using FMQ and IMemory
Result: no hwbinder calls due music processing.
Test: make, use Play Music with effects, check traces
Bug: 30222631
Change-Id: I06d0e94e603688874b31824427f3b0878b5f7c8e
diff --git a/media/libaudiohal/EffectHalHidl.cpp b/media/libaudiohal/EffectHalHidl.cpp
index 0a58fa0..272bf5c 100644
--- a/media/libaudiohal/EffectHalHidl.cpp
+++ b/media/libaudiohal/EffectHalHidl.cpp
@@ -21,21 +21,26 @@
#include <utils/Log.h>
#include "ConversionHelperHidl.h"
+#include "EffectBufferHalHidl.h"
#include "EffectHalHidl.h"
#include "HidlUtils.h"
+using ::android::hardware::audio::effect::V2_0::AudioBuffer;
+using ::android::hardware::audio::effect::V2_0::MessageQueueFlagBits;
using ::android::hardware::audio::effect::V2_0::Result;
using ::android::hardware::hidl_vec;
+using ::android::hardware::MQDescriptorSync;
using ::android::hardware::Return;
using ::android::hardware::Status;
namespace android {
EffectHalHidl::EffectHalHidl(const sp<IEffect>& effect, uint64_t effectId)
- : mEffect(effect), mEffectId(effectId) {
+ : mEffect(effect), mEffectId(effectId), mBuffersChanged(true) {
}
EffectHalHidl::~EffectHalHidl() {
+ close();
}
// static
@@ -64,16 +69,100 @@
}
}
-status_t EffectHalHidl::process(audio_buffer_t */*inBuffer*/, audio_buffer_t */*outBuffer*/) {
- // Idea -- intercept set buffer config command, capture audio format, use it
- // for determining frame size in bytes on input and output.
+status_t EffectHalHidl::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
+ if (mInBuffer == 0 || buffer->audioBuffer() != mInBuffer->audioBuffer()) {
+ mBuffersChanged = true;
+ }
+ mInBuffer = buffer;
return OK;
}
-status_t EffectHalHidl::processReverse(audio_buffer_t */*inBuffer*/, audio_buffer_t */*outBuffer*/) {
+status_t EffectHalHidl::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
+ if (mOutBuffer == 0 || buffer->audioBuffer() != mOutBuffer->audioBuffer()) {
+ mBuffersChanged = true;
+ }
+ mOutBuffer = buffer;
return OK;
}
+status_t EffectHalHidl::process() {
+ return processImpl(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS));
+}
+
+status_t EffectHalHidl::processReverse() {
+ return processImpl(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_REVERSE));
+}
+
+status_t EffectHalHidl::prepareForProcessing() {
+ std::unique_ptr<StatusMQ> tempStatusMQ;
+ Result retval;
+ Return<void> ret = mEffect->prepareForProcessing(
+ [&](Result r, const MQDescriptorSync<Result>& statusMQ) {
+ retval = r;
+ if (retval == Result::OK) {
+ tempStatusMQ.reset(new StatusMQ(statusMQ));
+ if (tempStatusMQ->isValid() && tempStatusMQ->getEventFlagWord()) {
+ EventFlag::createEventFlag(tempStatusMQ->getEventFlagWord(), &mEfGroup);
+ }
+ }
+ });
+ if (!ret.getStatus().isOk() || retval != Result::OK) {
+ return ret.getStatus().isOk() ? analyzeResult(retval) : ret.getStatus().transactionError();
+ }
+ if (!tempStatusMQ || !tempStatusMQ->isValid() || !mEfGroup) {
+ ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for effects");
+ ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
+ "Status message queue for effects is invalid");
+ ALOGE_IF(!mEfGroup, "Event flag creation for effects failed");
+ return NO_INIT;
+ }
+ mStatusMQ = std::move(tempStatusMQ);
+ return OK;
+}
+
+status_t EffectHalHidl::processImpl(uint32_t mqFlag) {
+ if (mEffect == 0 || mInBuffer == 0 || mOutBuffer == 0) return NO_INIT;
+ status_t status;
+ if (!mStatusMQ && (status = prepareForProcessing()) != OK) {
+ return status;
+ }
+ if (mBuffersChanged && (status = setProcessBuffers()) != OK) {
+ return status;
+ }
+ // The data is already in the buffers, just need to flush it and wake up the server side.
+ std::atomic_thread_fence(std::memory_order_release);
+ mEfGroup->wake(mqFlag);
+ uint32_t efState = 0;
+retry:
+ status_t ret = mEfGroup->wait(
+ static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING), &efState, NS_PER_SEC);
+ if (efState & static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING)) {
+ Result retval = Result::NOT_INITIALIZED;
+ mStatusMQ->read(&retval);
+ if (retval == Result::OK || retval == Result::INVALID_STATE) {
+ // Sync back the changed contents of the buffer.
+ std::atomic_thread_fence(std::memory_order_acquire);
+ }
+ return analyzeResult(retval);
+ }
+ if (ret == -EAGAIN) {
+ // This normally retries no more than once.
+ goto retry;
+ }
+ return ret;
+}
+
+status_t EffectHalHidl::setProcessBuffers() {
+ Return<Result> ret = mEffect->setProcessBuffers(
+ reinterpret_cast<EffectBufferHalHidl*>(mInBuffer.get())->hidlBuffer(),
+ reinterpret_cast<EffectBufferHalHidl*>(mOutBuffer.get())->hidlBuffer());
+ if (ret.getStatus().isOk() && ret == Result::OK) {
+ mBuffersChanged = false;
+ return OK;
+ }
+ return ret.isOk() ? analyzeResult(ret) : UNKNOWN_ERROR;
+}
+
status_t EffectHalHidl::command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
uint32_t *replySize, void *pReplyData) {
if (mEffect == 0) return NO_INIT;
@@ -106,4 +195,10 @@
return ret.isOk() ? analyzeResult(retval) : UNKNOWN_ERROR;
}
+status_t EffectHalHidl::close() {
+ if (mEffect == 0) return NO_INIT;
+ Return<Result> ret = mEffect->close();
+ return ret.isOk() ? analyzeResult(ret) : UNKNOWN_ERROR;
+}
+
} // namespace android