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

Commit 5863c4ca authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Android (Google) Code Review
Browse files

Merge "audiohal: Re-implement effect process using FMQ and IMemory"

parents 0ebed38d a331de14
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