EffectHalHidl.cpp revision d621ac82e648c8ef395068edb1af2747f49b700a
1/*
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
17#define LOG_TAG "EffectHalHidl"
18//#define LOG_NDEBUG 0
19
20#include <media/EffectsFactoryApi.h>
21#include <utils/Log.h>
22
23#include "ConversionHelperHidl.h"
24#include "EffectBufferHalHidl.h"
25#include "EffectHalHidl.h"
26#include "HidlUtils.h"
27
28using ::android::hardware::audio::effect::V2_0::AudioBuffer;
29using ::android::hardware::audio::effect::V2_0::MessageQueueFlagBits;
30using ::android::hardware::audio::effect::V2_0::Result;
31using ::android::hardware::hidl_vec;
32using ::android::hardware::MQDescriptorSync;
33using ::android::hardware::Return;
34using ::android::hardware::Status;
35
36namespace android {
37
38EffectHalHidl::EffectHalHidl(const sp<IEffect>& effect, uint64_t effectId)
39        : mEffect(effect), mEffectId(effectId), mBuffersChanged(true) {
40}
41
42EffectHalHidl::~EffectHalHidl() {
43    close();
44}
45
46// static
47void EffectHalHidl::effectDescriptorToHal(
48        const EffectDescriptor& descriptor, effect_descriptor_t* halDescriptor) {
49    HidlUtils::uuidToHal(descriptor.type, &halDescriptor->type);
50    HidlUtils::uuidToHal(descriptor.uuid, &halDescriptor->uuid);
51    halDescriptor->flags = static_cast<uint32_t>(descriptor.flags);
52    halDescriptor->cpuLoad = descriptor.cpuLoad;
53    halDescriptor->memoryUsage = descriptor.memoryUsage;
54    memcpy(halDescriptor->name, descriptor.name.data(), descriptor.name.size());
55    memcpy(halDescriptor->implementor,
56            descriptor.implementor.data(), descriptor.implementor.size());
57}
58
59// static
60status_t EffectHalHidl::analyzeResult(const Result& result) {
61    switch (result) {
62        case Result::OK: return OK;
63        case Result::INVALID_ARGUMENTS: return BAD_VALUE;
64        case Result::INVALID_STATE: return NOT_ENOUGH_DATA;
65        case Result::NOT_INITIALIZED: return NO_INIT;
66        case Result::NOT_SUPPORTED: return INVALID_OPERATION;
67        case Result::RESULT_TOO_BIG: return NO_MEMORY;
68        default: return NO_INIT;
69    }
70}
71
72status_t EffectHalHidl::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
73    if (mInBuffer == 0 || buffer->audioBuffer() != mInBuffer->audioBuffer()) {
74        mBuffersChanged = true;
75    }
76    mInBuffer = buffer;
77    return OK;
78}
79
80status_t EffectHalHidl::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
81    if (mOutBuffer == 0 || buffer->audioBuffer() != mOutBuffer->audioBuffer()) {
82        mBuffersChanged = true;
83    }
84    mOutBuffer = buffer;
85    return OK;
86}
87
88status_t EffectHalHidl::process() {
89    return processImpl(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS));
90}
91
92status_t EffectHalHidl::processReverse() {
93    return processImpl(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_REVERSE));
94}
95
96status_t EffectHalHidl::prepareForProcessing() {
97    std::unique_ptr<StatusMQ> tempStatusMQ;
98    Result retval;
99    Return<void> ret = mEffect->prepareForProcessing(
100            [&](Result r, const MQDescriptorSync<Result>& statusMQ) {
101                retval = r;
102                if (retval == Result::OK) {
103                    tempStatusMQ.reset(new StatusMQ(statusMQ));
104                    if (tempStatusMQ->isValid() && tempStatusMQ->getEventFlagWord()) {
105                        EventFlag::createEventFlag(tempStatusMQ->getEventFlagWord(), &mEfGroup);
106                    }
107                }
108            });
109    if (!ret.isOk() || retval != Result::OK) {
110        return ret.isOk() ? analyzeResult(retval) : FAILED_TRANSACTION;
111    }
112    if (!tempStatusMQ || !tempStatusMQ->isValid() || !mEfGroup) {
113        ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for effects");
114        ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
115                "Status message queue for effects is invalid");
116        ALOGE_IF(!mEfGroup, "Event flag creation for effects failed");
117        return NO_INIT;
118    }
119    mStatusMQ = std::move(tempStatusMQ);
120    return OK;
121}
122
123status_t EffectHalHidl::processImpl(uint32_t mqFlag) {
124    if (mEffect == 0 || mInBuffer == 0 || mOutBuffer == 0) return NO_INIT;
125    status_t status;
126    if (!mStatusMQ && (status = prepareForProcessing()) != OK) {
127        return status;
128    }
129    if (mBuffersChanged && (status = setProcessBuffers()) != OK) {
130        return status;
131    }
132    // The data is already in the buffers, just need to flush it and wake up the server side.
133    std::atomic_thread_fence(std::memory_order_release);
134    mEfGroup->wake(mqFlag);
135    uint32_t efState = 0;
136retry:
137    status_t ret = mEfGroup->wait(
138            static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING), &efState, NS_PER_SEC);
139    if (efState & static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING)) {
140        Result retval = Result::NOT_INITIALIZED;
141        mStatusMQ->read(&retval);
142        if (retval == Result::OK || retval == Result::INVALID_STATE) {
143            // Sync back the changed contents of the buffer.
144            std::atomic_thread_fence(std::memory_order_acquire);
145        }
146        return analyzeResult(retval);
147    }
148    if (ret == -EAGAIN) {
149        // This normally retries no more than once.
150        goto retry;
151    }
152    return ret;
153}
154
155status_t EffectHalHidl::setProcessBuffers() {
156    Return<Result> ret = mEffect->setProcessBuffers(
157            reinterpret_cast<EffectBufferHalHidl*>(mInBuffer.get())->hidlBuffer(),
158            reinterpret_cast<EffectBufferHalHidl*>(mOutBuffer.get())->hidlBuffer());
159    if (ret.isOk() && ret == Result::OK) {
160        mBuffersChanged = false;
161        return OK;
162    }
163    return ret.isOk() ? analyzeResult(ret) : FAILED_TRANSACTION;
164}
165
166status_t EffectHalHidl::command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
167        uint32_t *replySize, void *pReplyData) {
168    if (mEffect == 0) return NO_INIT;
169    hidl_vec<uint8_t> hidlData;
170    if (pCmdData != nullptr && cmdSize > 0) {
171        hidlData.setToExternal(reinterpret_cast<uint8_t*>(pCmdData), cmdSize);
172    }
173    status_t status;
174    Return<void> ret = mEffect->command(cmdCode, hidlData, *replySize,
175            [&](int32_t s, const hidl_vec<uint8_t>& result) {
176                status = s;
177                if (status == 0) {
178                    if (*replySize > result.size()) *replySize = result.size();
179                    if (pReplyData != nullptr && *replySize > 0) {
180                        memcpy(pReplyData, &result[0], *replySize);
181                    }
182                }
183            });
184    return ret.isOk() ? status : FAILED_TRANSACTION;
185}
186
187status_t EffectHalHidl::getDescriptor(effect_descriptor_t *pDescriptor) {
188    if (mEffect == 0) return NO_INIT;
189    Result retval = Result::NOT_INITIALIZED;
190    Return<void> ret = mEffect->getDescriptor(
191            [&](Result r, const EffectDescriptor& result) {
192                retval = r;
193                if (retval == Result::OK) {
194                    effectDescriptorToHal(result, pDescriptor);
195                }
196            });
197    return ret.isOk() ? analyzeResult(retval) : FAILED_TRANSACTION;
198}
199
200status_t EffectHalHidl::close() {
201    if (mEffect == 0) return NO_INIT;
202    Return<Result> ret = mEffect->close();
203    return ret.isOk() ? analyzeResult(ret) : FAILED_TRANSACTION;
204}
205
206} // namespace android
207