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

Commit 9aad48c3 authored by Andy Hung's avatar Andy Hung
Browse files

Allow multichannel effects

Test: Solo Tester with mutichannel file
Bug: 70038539
Change-Id: Id2e47eef62e55710bb6eda54c1f737aa3a3ce6bc
parent 13fca0cd
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -47,6 +47,9 @@
#ifdef FLOAT_EFFECT_CHAIN
// define FLOAT_AUX to process aux effect buffers in float (FLOAT_EFFECT_CHAIN must be defined)
#define FLOAT_AUX

// define MULTICHANNEL_EFFECT_CHAIN to allow multichannel effects (FLOAT_EFFECT_CHAIN defined)
#define MULTICHANNEL_EFFECT_CHAIN
#endif

#endif // ANDROID_AUDIOFLINGER_CONFIGURATION_H
+111 −28
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <system/audio_effects/effect_aec.h>
#include <system/audio_effects/effect_ns.h>
#include <system/audio_effects/effect_visualizer.h>
#include <audio_utils/channels.h>
#include <audio_utils/primitives.h>
#include <media/AudioEffect.h>
#include <media/audiohal/EffectHalInterface.h>
@@ -292,7 +293,6 @@ void AudioFlinger::EffectModule::process()
        return;
    }

    // TODO: Implement multichannel effects; here outChannelCount == FCC_2 == 2
    const uint32_t inChannelCount =
            audio_channel_count_from_out_mask(mConfig.inputCfg.channels);
    const uint32_t outChannelCount =
@@ -342,6 +342,7 @@ void AudioFlinger::EffectModule::process()
        if (isProcessImplemented()) {
            if (auxType) {
                // We overwrite the aux input buffer here and clear after processing.
                // aux input is always mono.
#ifdef FLOAT_EFFECT_CHAIN
                if (mSupportsFloat) {
#ifndef FLOAT_AUX
@@ -371,6 +372,28 @@ void AudioFlinger::EffectModule::process()
                }
            }
#ifdef FLOAT_EFFECT_CHAIN
            sp<EffectBufferHalInterface> inBuffer = mInBuffer;
            sp<EffectBufferHalInterface> outBuffer = mOutBuffer;

            if (!auxType && mInChannelCountRequested != inChannelCount) {
                adjust_channels(
                        inBuffer->audioBuffer()->f32, mInChannelCountRequested,
                        mInConversionBuffer->audioBuffer()->f32, inChannelCount,
                        sizeof(float),
                        sizeof(float)
                        * mInChannelCountRequested * mConfig.inputCfg.buffer.frameCount);
                inBuffer = mInConversionBuffer;
            }
            if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE
                    && mOutChannelCountRequested != outChannelCount) {
                adjust_selected_channels(
                        outBuffer->audioBuffer()->f32, mOutChannelCountRequested,
                        mOutConversionBuffer->audioBuffer()->f32, outChannelCount,
                        sizeof(float),
                        sizeof(float)
                        * mOutChannelCountRequested * mConfig.outputCfg.buffer.frameCount);
                outBuffer = mOutConversionBuffer;
            }
            if (!mSupportsFloat) { // convert input to int16_t as effect doesn't support float.
                if (!auxType) {
                    if (mInConversionBuffer.get() == nullptr) {
@@ -379,8 +402,9 @@ void AudioFlinger::EffectModule::process()
                    }
                    memcpy_to_i16_from_float(
                            mInConversionBuffer->audioBuffer()->s16,
                            mInBuffer->audioBuffer()->f32,
                            inBuffer->audioBuffer()->f32,
                            inChannelCount * mConfig.inputCfg.buffer.frameCount);
                    inBuffer = mInConversionBuffer;
                }
                if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
                    if (mOutConversionBuffer.get() == nullptr) {
@@ -389,21 +413,30 @@ void AudioFlinger::EffectModule::process()
                    }
                    memcpy_to_i16_from_float(
                            mOutConversionBuffer->audioBuffer()->s16,
                            mOutBuffer->audioBuffer()->f32,
                            outBuffer->audioBuffer()->f32,
                            outChannelCount * mConfig.outputCfg.buffer.frameCount);
                    outBuffer = mOutConversionBuffer;
                }
            }
#endif

            ret = mEffectInterface->process();

#ifdef FLOAT_EFFECT_CHAIN
            if (!mSupportsFloat) { // convert output int16_t back to float.
                sp<EffectBufferHalInterface> target =
                        mOutChannelCountRequested != outChannelCount
                        ? mOutConversionBuffer : mOutBuffer;

                memcpy_to_float_from_i16(
                        mOutBuffer->audioBuffer()->f32,
                        target->audioBuffer()->f32,
                        mOutConversionBuffer->audioBuffer()->s16,
                        outChannelCount * mConfig.outputCfg.buffer.frameCount);
            }
            if (mOutChannelCountRequested != outChannelCount) {
                adjust_selected_channels(mOutConversionBuffer->audioBuffer()->f32, outChannelCount,
                        mOutBuffer->audioBuffer()->f32, mOutChannelCountRequested,
                        sizeof(float),
                        sizeof(float) * outChannelCount * mConfig.outputCfg.buffer.frameCount);
            }
#endif
        } else {
#ifdef FLOAT_EFFECT_CHAIN
@@ -476,15 +509,28 @@ status_t AudioFlinger::EffectModule::configure()
    }

    // TODO: handle configuration of effects replacing track process
    // TODO: handle configuration of input (record) SW effects above the HAL,
    // similar to output EFFECT_FLAG_TYPE_INSERT/REPLACE,
    // in which case input channel masks should be used here.
    channelMask = thread->channelMask();
    mConfig.inputCfg.channels = channelMask;
    mConfig.outputCfg.channels = channelMask;

    if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
        if (mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_MONO) {
            mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_MONO;
            ALOGV("Overriding auxiliary effect input channels %#x as MONO",
                    mConfig.inputCfg.channels);
        }
#ifndef MULTICHANNEL_EFFECT_CHAIN
        if (mConfig.outputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) {
            mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
        ALOGV("Overriding auxiliary effect input as MONO and output as STEREO");
            ALOGV("Overriding auxiliary effect output channels %#x as STEREO",
                    mConfig.outputCfg.channels);
        }
#endif
    } else {
        mConfig.inputCfg.channels = channelMask;
#ifndef MULTICHANNEL_EFFECT_CHAIN
        // TODO: Update this logic when multichannel effects are implemented.
        // For offloaded tracks consider mono output as stereo for proper effect initialization
        if (channelMask == AUDIO_CHANNEL_OUT_MONO) {
@@ -492,7 +538,12 @@ status_t AudioFlinger::EffectModule::configure()
            mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
            ALOGV("Overriding effect input and output as STEREO");
        }
#endif
    }
    mInChannelCountRequested =
            audio_channel_count_from_out_mask(mConfig.inputCfg.channels);
    mOutChannelCountRequested =
            audio_channel_count_from_out_mask(mConfig.outputCfg.channels);

    mConfig.inputCfg.format = EFFECT_BUFFER_FORMAT;
    mConfig.outputCfg.format = EFFECT_BUFFER_FORMAT;
@@ -530,28 +581,58 @@ status_t AudioFlinger::EffectModule::configure()
    status_t cmdStatus;
    size = sizeof(int);
    status = mEffectInterface->command(EFFECT_CMD_SET_CONFIG,
                                       sizeof(effect_config_t),
                                       sizeof(mConfig),
                                       &mConfig,
                                       &size,
                                       &cmdStatus);
    if (status == NO_ERROR) {
        status = cmdStatus;
    }

#ifdef MULTICHANNEL_EFFECT_CHAIN
    if (status != NO_ERROR &&
            (mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO
                    || mConfig.outputCfg.channels != AUDIO_CHANNEL_OUT_STEREO)) {
        // Older effects may require exact STEREO position mask.
        if (mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) {
            ALOGV("Overriding effect input channels %#x as STEREO", mConfig.inputCfg.channels);
            mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
        }
        if (mConfig.outputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) {
            ALOGV("Overriding effect output channels %#x as STEREO", mConfig.outputCfg.channels);
            mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
        }
        size = sizeof(int);
        status = mEffectInterface->command(EFFECT_CMD_SET_CONFIG,
                                           sizeof(mConfig),
                                           &mConfig,
                                           &size,
                                           &cmdStatus);
        if (status == NO_ERROR) {
            status = cmdStatus;
        }
    }
#endif

#ifdef FLOAT_EFFECT_CHAIN
    if (status == NO_ERROR) {
        mSupportsFloat = true;
#endif
    }
#ifdef FLOAT_EFFECT_CHAIN
    else {

    if (status != NO_ERROR) {
        ALOGV("EFFECT_CMD_SET_CONFIG failed with float format, retry with int16_t.");
        mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
        mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
        size = sizeof(int);
        status = mEffectInterface->command(EFFECT_CMD_SET_CONFIG,
                                           sizeof(effect_config_t),
                                           sizeof(mConfig),
                                           &mConfig,
                                           &size,
                                           &cmdStatus);
        if (status == NO_ERROR) {
            status = cmdStatus;
        }
        if (status == NO_ERROR) {
            mSupportsFloat = false;
            ALOGVV("config worked with 16 bit");
        } else {
@@ -929,11 +1010,15 @@ void AudioFlinger::EffectModule::setInBuffer(const sp<EffectBufferHalInterface>&
    // the original buffer) when the output buffer is identical to the input buffer,
    // but we don't optimize for it here.
    const bool auxType = (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY;
    if (!auxType && !mSupportsFloat && mInBuffer.get() != nullptr) {
    const uint32_t inChannelCount =
            audio_channel_count_from_out_mask(mConfig.inputCfg.channels);
    const bool formatMismatch = !mSupportsFloat || mInChannelCountRequested != inChannelCount;
    if (!auxType && formatMismatch && mInBuffer.get() != nullptr) {
        // we need to translate - create hidl shared buffer and intercept
        const size_t inFrameCount = mConfig.inputCfg.buffer.frameCount;
        const int inChannels = audio_channel_count_from_out_mask(mConfig.inputCfg.channels);
        const size_t size = inChannels * inFrameCount * sizeof(int16_t);
        // Use FCC_2 in case mInChannelCountRequested is mono and the effect is stereo.
        const uint32_t inChannels = std::max((uint32_t)FCC_2, mInChannelCountRequested);
        const size_t size = inChannels * inFrameCount * std::max(sizeof(int16_t), sizeof(float));

        ALOGV("%s: setInBuffer updating for inChannels:%d inFrameCount:%zu total size:%zu",
                __func__, inChannels, inFrameCount, size);
@@ -970,10 +1055,14 @@ void AudioFlinger::EffectModule::setOutBuffer(const sp<EffectBufferHalInterface>
#ifdef FLOAT_EFFECT_CHAIN
    // Note: Any effect that does not accumulate does not need mOutConversionBuffer and
    // can do in-place conversion from int16_t to float.  We don't optimize here.
    if (!mSupportsFloat && mOutBuffer.get() != nullptr) {
    const uint32_t outChannelCount =
            audio_channel_count_from_out_mask(mConfig.outputCfg.channels);
    const bool formatMismatch = !mSupportsFloat || mOutChannelCountRequested != outChannelCount;
    if (formatMismatch && mOutBuffer.get() != nullptr) {
        const size_t outFrameCount = mConfig.outputCfg.buffer.frameCount;
        const int outChannels = audio_channel_count_from_out_mask(mConfig.outputCfg.channels);
        const size_t size = outChannels * outFrameCount * sizeof(int16_t);
        // Use FCC_2 in case mOutChannelCountRequested is mono and the effect is stereo.
        const uint32_t outChannels = std::max((uint32_t)FCC_2, mOutChannelCountRequested);
        const size_t size = outChannels * outFrameCount * std::max(sizeof(int16_t), sizeof(float));

        ALOGV("%s: setOutBuffer updating for outChannels:%d outFrameCount:%zu total size:%zu",
                __func__, outChannels, outFrameCount, size);
@@ -1813,14 +1902,8 @@ void AudioFlinger::EffectChain::clearInputBuffer_l(const sp<ThreadBase>& thread)
    if (mInBuffer == NULL) {
        return;
    }
    // TODO: This will change in the future, depending on multichannel
    // and sample format changes for effects.
    // Currently effects processing is only available for stereo, AUDIO_FORMAT_PCM_16_BIT
    // (4 bytes frame size)

    const size_t frameSize =
            audio_bytes_per_sample(EFFECT_BUFFER_FORMAT)
            * std::min((uint32_t)FCC_2, thread->channelCount());
            audio_bytes_per_sample(EFFECT_BUFFER_FORMAT) * thread->channelCount();

    memset(mInBuffer->audioBuffer()->raw, 0, thread->frameCount() * frameSize);
    mInBuffer->commit();
+2 −0
Original line number Diff line number Diff line
@@ -173,6 +173,8 @@ mutable Mutex mLock; // mutex for process, commands and handl
    bool    mSupportsFloat;         // effect supports float processing
    sp<EffectBufferHalInterface> mInConversionBuffer;  // Buffers for HAL conversion if needed.
    sp<EffectBufferHalInterface> mOutConversionBuffer;
    uint32_t mInChannelCountRequested;
    uint32_t mOutChannelCountRequested;
#endif
};

+4 −0
Original line number Diff line number Diff line
@@ -1176,6 +1176,7 @@ status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l(

    switch (mType) {
    case MIXER: {
#ifndef MULTICHANNEL_EFFECT_CHAIN
        // Reject any effect on mixer multichannel sinks.
        // TODO: fix both format and multichannel issues with effects.
        if (mChannelCount != FCC_2) {
@@ -1183,6 +1184,7 @@ status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l(
                    " thread %s", desc->name, mChannelCount, mThreadName);
            return BAD_VALUE;
        }
#endif
        audio_output_flags_t flags = mOutput->flags;
        if (hasFastMixer() || (flags & AUDIO_OUTPUT_FLAG_FAST)) {
            if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
@@ -1229,6 +1231,7 @@ status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l(
                desc->name, mThreadName);
        return BAD_VALUE;
    case DUPLICATING:
#ifndef MULTICHANNEL_EFFECT_CHAIN
        // Reject any effect on mixer multichannel sinks.
        // TODO: fix both format and multichannel issues with effects.
        if (mChannelCount != FCC_2) {
@@ -1236,6 +1239,7 @@ status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l(
                    " on DUPLICATING thread %s", desc->name, mChannelCount, mThreadName);
            return BAD_VALUE;
        }
#endif
        if ((sessionId == AUDIO_SESSION_OUTPUT_STAGE) || (sessionId == AUDIO_SESSION_OUTPUT_MIX)) {
            ALOGW("checkEffectCompatibility_l(): global effect %s on DUPLICATING"
                    " thread %s", desc->name, mThreadName);