Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a331de14 authored by Mikhail Naganov's avatar Mikhail Naganov
Browse files

audiohal: Re-implement effect process using FMQ and IMemory

Result: no hwbinder calls due music processing.

Added IEffect.close method for explicitly freeing up of resources
consumed by the effect before automatic server objects reaping
gets to it.

Added IEffect.setProcessBuffers method for updating the input /
output buffers on the go.

Test: make, use Play Music with effects, check traces
Bug: 30222631
Change-Id: Ia1e1bc7098fab59aa970e0ce4acdb48007409644
parent b5dad57d
Loading
Loading
Loading
Loading
+44 −36
Original line number Diff line number Diff line
@@ -226,49 +226,47 @@ interface IEffect {
    getDescriptor() generates (Result retval, EffectDescriptor descriptor);

    /*
     * Effect process function. Takes input samples as specified (count and
     * location) in input buffer and returns processed samples as specified in
     * output buffer. If the buffer descriptor is empty the function must use
     * either the buffer or the buffer provider callback installed by the
     * setConfig command.  The effect framework must call the 'process' function
     * after the 'enable' command is received and until the 'disable' is
     * received. When the engine receives the 'disable' command it should turn
     * off the effect gracefully and when done indicate that it is OK to stop
     * calling the 'process' function by returning the INVALID_STATE status.
     *
     * Output audio buffer must contain no more frames than the input audio
     * buffer. Since the effect may transform input channels into a different
     * amount of channels, the caller provides the output frame size.
     *
     * @param inBuffer input audio buffer.
     * @param outFrameSize output frame size in bytes.
     * @return retval operation completion status.
     * @return outBuffer output audio buffer.
     * Set up required transports for passing audio buffers to the effect.
     *
     * The transport consists of shared memory and a message queue for reporting
     * effect processing operation status. The shared memory is set up
     * separately using 'setProcessBuffers' method.
     *
     * Processing is requested by setting 'REQUEST_PROCESS' or
     * 'REQUEST_PROCESS_REVERSE' EventFlags associated with the status message
     * queue. The result of processing may be one of the following:
     *   OK if there were no errors during processing;
     *   INVALID_ARGUMENTS if audio buffers are invalid;
     *   INVALID_STATE if the engine has finished the disable phase;
     *   NOT_INITIALIZED if the audio buffers were not set;
     *   NOT_SUPPORTED if the requested processing type is not supported by
     *                 the effect.
     *
     * @return retval OK if both message queues were created successfully.
     *                INVALID_STATE if the method was already called.
     *                INVALID_ARGUMENTS if there was a problem setting up
     *                                  the queue.
     * @return statusMQ a message queue used for passing status from the effect.
     */
    // TODO(mnaganov): replace with FMQ version.
    @callflow(next={"*"})
    process(AudioBuffer inBuffer, uint32_t outFrameSize)
            generates (Result retval, AudioBuffer outBuffer);
    prepareForProcessing() generates (Result retval, fmq_sync<Result> statusMQ);

    /*
     * Process reverse stream function. This function is used to pass a
     * reference stream to the effect engine. If the engine does not need a
     * reference stream, this function MUST return NOT_SUPPORTED. For example,
     * this function would typically implemented by an Echo Canceler.
     * Set up input and output buffers for processing audio data. The effect
     * may modify both the input and the output buffer during the operation.
     * Buffers may be set multiple times during effect lifetime.
     *
     * Output audio buffer must contain no more frames than the input audio
     * buffer. Since the effect may transform input channels into a different
     * amount of channels, the caller provides the output frame size.
     * The input and the output buffer may be reused between different effects,
     * and the input buffer may be used as an output buffer. Buffers are
     * distinguished using 'AudioBuffer.id' field.
     *
     * @param inBuffer input audio buffer.
     * @param outFrameSize output frame size in bytes.
     * @return retval operation completion status.
     * @return outBuffer output audio buffer.
     * @param outBuffer output audio buffer.
     * @return retval OK if both buffers were mapped successfully.
     *                INVALID_ARGUMENTS if there was a problem with mapping
     *                                  any of the buffers.
     */
    // TODO(mnaganov): replace with FMQ version.
    @callflow(next={"*"})
    processReverse(AudioBuffer inBuffer, uint32_t outFrameSize)
            generates (Result retval, AudioBuffer outBuffer);
    setProcessBuffers(AudioBuffer inBuffer, AudioBuffer outBuffer) generates (
            Result retval);

    /*
     * Execute a vendor specific command on the effect. The command code
@@ -406,4 +404,14 @@ interface IEffect {
     */
    setCurrentConfigForFeature(uint32_t featureId, vec<uint8_t> configData)
            generates (Result retval);

    /*
     * Called by the framework to deinitialize the effect and free up
     * all the currently allocated resources. It is recommended to close
     * the effect on the client side as soon as it is becomes unused.
     *
     * @return retval OK in case the success.
     *                INVALID_STATE if the effect was already closed.
     */
    close() generates (Result retval);
};
+10 −8
Original line number Diff line number Diff line
@@ -115,16 +115,14 @@ Return<void> AcousticEchoCancelerEffect::getDescriptor(getDescriptor_cb _hidl_cb
    return mEffect->getDescriptor(_hidl_cb);
}

Return<void> AcousticEchoCancelerEffect::process(
        const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb) {
    return mEffect->process(inBuffer, outFrameSize, _hidl_cb);
Return<void> AcousticEchoCancelerEffect::prepareForProcessing(
        prepareForProcessing_cb _hidl_cb) {
    return mEffect->prepareForProcessing(_hidl_cb);
}

Return<void> AcousticEchoCancelerEffect::processReverse(
        const AudioBuffer& inBuffer,
        uint32_t outFrameSize,
        processReverse_cb _hidl_cb) {
    return mEffect->processReverse(inBuffer, outFrameSize, _hidl_cb);
Return<Result> AcousticEchoCancelerEffect::setProcessBuffers(
        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
    return mEffect->setProcessBuffers(inBuffer, outBuffer);
}

Return<void> AcousticEchoCancelerEffect::command(
@@ -167,6 +165,10 @@ Return<Result> AcousticEchoCancelerEffect::setCurrentConfigForFeature(
    return mEffect->setCurrentConfigForFeature(featureId, configData);
}

Return<Result> AcousticEchoCancelerEffect::close() {
    return mEffect->close();
}

// Methods from ::android::hardware::audio::effect::V2_0::IAcousticEchoCancelerEffect follow.
Return<Result> AcousticEchoCancelerEffect::setEchoDelay(uint32_t echoDelayMs)  {
    return mEffect->setParam(AEC_PARAM_ECHO_DELAY, echoDelayMs);
+4 −6
Original line number Diff line number Diff line
@@ -69,12 +69,9 @@ struct AcousticEchoCancelerEffect : public IAcousticEchoCancelerEffect {
    Return<Result> setAudioSource(AudioSource source)  override;
    Return<Result> offload(const EffectOffloadParameter& param)  override;
    Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
    Return<void> process(
            const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb)  override;
    Return<void> processReverse(
            const AudioBuffer& inBuffer,
            uint32_t outFrameSize,
            processReverse_cb _hidl_cb)  override;
    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
    Return<Result> setProcessBuffers(
            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
    Return<void> command(
            uint32_t commandId,
            const hidl_vec<uint8_t>& data,
@@ -97,6 +94,7 @@ struct AcousticEchoCancelerEffect : public IAcousticEchoCancelerEffect {
            getCurrentConfigForFeature_cb _hidl_cb)  override;
    Return<Result> setCurrentConfigForFeature(
            uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
    Return<Result> close()  override;

    // Methods from ::android::hardware::audio::effect::V2_0::IAcousticEchoCancelerEffect follow.
    Return<Result> setEchoDelay(uint32_t echoDelayMs)  override;
+8 −2
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ LOCAL_MODULE := android.hardware.audio.effect@2.0-impl
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SRC_FILES := \
    AcousticEchoCancelerEffect.cpp \
    AudioBufferManager.cpp \
    AutomaticGainControlEffect.cpp \
    BassBoostEffect.cpp \
    Conversions.cpp \
@@ -20,14 +21,19 @@ LOCAL_SRC_FILES := \
    VisualizerEffect.cpp \

LOCAL_SHARED_LIBRARIES := \
    libbase \
    libcutils \
    libeffects \
    libfmq \
    libhidlbase \
    libhidlmemory \
    libhidltransport \
    libhwbinder \
    libutils \
    libeffects \
    liblog \
    libutils \
    android.hardware.audio.common@2.0 \
    android.hardware.audio.common@2.0-util \
    android.hardware.audio.effect@2.0 \
    android.hidl.memory@1.0 \

include $(BUILD_SHARED_LIBRARY)
+88 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <atomic>

#include <hidlmemory/mapping.h>

#include "AudioBufferManager.h"

namespace android {

ANDROID_SINGLETON_STATIC_INSTANCE(AudioBufferManager);

bool AudioBufferManager::wrap(const AudioBuffer& buffer, sp<AudioBufferWrapper>* wrapper) {
    // Check if we have this buffer already
    std::lock_guard<std::mutex> lock(mLock);
    ssize_t idx = mBuffers.indexOfKey(buffer.id);
    if (idx >= 0) {
        *wrapper = mBuffers[idx].promote();
        if (*wrapper != nullptr) return true;
        mBuffers.removeItemsAt(idx);
    }
    // Need to create and init a new AudioBufferWrapper.
    sp<AudioBufferWrapper> tempBuffer(new AudioBufferWrapper(buffer));
    if (!tempBuffer->init()) return false;
    *wrapper = tempBuffer;
    mBuffers.add(buffer.id, *wrapper);
    return true;
}

void AudioBufferManager::removeEntry(uint64_t id) {
    std::lock_guard<std::mutex> lock(mLock);
    ssize_t idx = mBuffers.indexOfKey(id);
    if (idx >= 0) mBuffers.removeItemsAt(idx);
}

namespace hardware {
namespace audio {
namespace effect {
namespace V2_0 {
namespace implementation {

AudioBufferWrapper::AudioBufferWrapper(const AudioBuffer& buffer) :
        mHidlBuffer(buffer), mHalBuffer{ 0, { nullptr } } {
}

AudioBufferWrapper::~AudioBufferWrapper() {
    AudioBufferManager::getInstance().removeEntry(mHidlBuffer.id);
}

bool AudioBufferWrapper::init() {
    if (mHalBuffer.raw != nullptr) {
        ALOGE("An attempt to init AudioBufferWrapper twice");
        return false;
    }
    mHidlMemory = mapMemory(mHidlBuffer.data);
    if (mHidlMemory == nullptr) {
        ALOGE("Could not map HIDL memory to IMemory");
        return false;
    }
    mHalBuffer.raw = static_cast<void*>(mHidlMemory->getPointer());
    if (mHalBuffer.raw == nullptr) {
        ALOGE("IMemory buffer pointer is null");
        return false;
    }
    mHalBuffer.frameCount = mHidlBuffer.frameCount;
    return true;
}

}  // namespace implementation
}  // namespace V2_0
}  // namespace effect
}  // namespace audio
}  // namespace hardware
}  // namespace android
Loading