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

Commit dce8f8cc authored by jiabin's avatar jiabin
Browse files

Add buffer provider that can adjust channels.

1. Add adjust channels buffer provider, which will expand or contract
sample data from one interleaved channel format to another. Expanded
channels are filled with zeros and put at the end of each frames.
Contracted channels are omitted from the end of each audio frame.

2. Add adjust channels non destructive buffer provider, which could
expand or contract sample data from one interleaved channel format to
another while not destructing the buffer. Extra expanded channels are
interleaved in from the end of the input buffer. Contracted channels are
copied to the end of the output buffer. Contracted channels could be
written to an output buffer with certain audio format.

Test: Manually
Bug: 111454766
Change-Id: I3f963307e73b3f7aa662d4127f78f0c61ac84510
parent 6b6a0f05
Loading
Loading
Loading
Loading
+29 −4
Original line number Diff line number Diff line
@@ -137,6 +137,13 @@ public:
    void        setBufferProvider(int name, AudioBufferProvider* bufferProvider);

    void        process() {
        for (const auto &pair : mTracks) {
            // Clear contracted buffer before processing if contracted channels are saved
            const std::shared_ptr<Track> &t = pair.second;
            if (t->mKeepContractedChannels) {
                t->clearContractedBuffer();
            }
        }
        (this->*mHook)();
    }

@@ -235,6 +242,8 @@ private:
            mPostDownmixReformatBufferProvider.reset(nullptr);
            mDownmixerBufferProvider.reset(nullptr);
            mReformatBufferProvider.reset(nullptr);
            mAdjustChannelsNonDestructiveBufferProvider.reset(nullptr);
            mAdjustChannelsBufferProvider.reset(nullptr);
        }

        bool        needsRamp() { return (volumeInc[0] | volumeInc[1] | auxInc) != 0; }
@@ -249,6 +258,11 @@ private:
        void        unprepareForDownmix();
        status_t    prepareForReformat();
        void        unprepareForReformat();
        status_t    prepareForAdjustChannels();
        void        unprepareForAdjustChannels();
        status_t    prepareForAdjustChannelsNonDestructive(size_t frames);
        void        unprepareForAdjustChannelsNonDestructive();
        void        clearContractedBuffer();
        bool        setPlaybackRate(const AudioPlaybackRate &playbackRate);
        void        reconfigureBufferProviders();

@@ -302,17 +316,21 @@ private:
         * all pre-mixer track buffer conversions outside the AudioMixer class.
         *
         * 1) mInputBufferProvider: The AudioTrack buffer provider.
         * 2) mReformatBufferProvider: If not NULL, performs the audio reformat to
         * 2) mAdjustChannelsBufferProvider: Expend or contracts data
         * 3) mAdjustChannelsNonDestructiveBufferProvider: Non-destructively adjust sample data
         * 4) mReformatBufferProvider: If not NULL, performs the audio reformat to
         *    match either mMixerInFormat or mDownmixRequiresFormat, if the downmixer
         *    requires reformat. For example, it may convert floating point input to
         *    PCM_16_bit if that's required by the downmixer.
         * 3) mDownmixerBufferProvider: If not NULL, performs the channel remixing to match
         * 5) mDownmixerBufferProvider: If not NULL, performs the channel remixing to match
         *    the number of channels required by the mixer sink.
         * 4) mPostDownmixReformatBufferProvider: If not NULL, performs reformatting from
         * 6) mPostDownmixReformatBufferProvider: If not NULL, performs reformatting from
         *    the downmixer requirements to the mixer engine input requirements.
         * 5) mTimestretchBufferProvider: Adds timestretching for playback rate
         * 7) mTimestretchBufferProvider: Adds timestretching for playback rate
         */
        AudioBufferProvider*     mInputBufferProvider;    // externally provided buffer provider.
        std::unique_ptr<PassthruBufferProvider> mAdjustChannelsBufferProvider;
        std::unique_ptr<PassthruBufferProvider> mAdjustChannelsNonDestructiveBufferProvider;
        std::unique_ptr<PassthruBufferProvider> mReformatBufferProvider;
        std::unique_ptr<PassthruBufferProvider> mDownmixerBufferProvider;
        std::unique_ptr<PassthruBufferProvider> mPostDownmixReformatBufferProvider;
@@ -341,6 +359,13 @@ private:

        AudioPlaybackRate    mPlaybackRate;

        // Haptic
        uint32_t             mAdjustInChannelCount;
        uint32_t             mAdjustOutChannelCount;
        uint32_t             mAdjustNonDestructiveInChannelCount;
        uint32_t             mAdjustNonDestructiveOutChannelCount;
        bool                 mKeepContractedChannels;

    private:
        // hooks
        void track__genericResample(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
+93 −0
Original line number Diff line number Diff line
@@ -162,6 +162,12 @@ status_t AudioMixer::create(
                AUDIO_CHANNEL_REPRESENTATION_POSITION, AUDIO_CHANNEL_OUT_STEREO);
        t->mMixerChannelCount = audio_channel_count_from_out_mask(t->mMixerChannelMask);
        t->mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
        // haptic
        t->mAdjustInChannelCount = 0;
        t->mAdjustOutChannelCount = 0;
        t->mAdjustNonDestructiveInChannelCount = 0;
        t->mAdjustNonDestructiveOutChannelCount = 0;
        t->mKeepContractedChannels = false;
        // Check the downmixing (or upmixing) requirements.
        status_t status = t->prepareForDownmix();
        if (status != OK) {
@@ -171,6 +177,8 @@ status_t AudioMixer::create(
        // prepareForDownmix() may change mDownmixRequiresFormat
        ALOGVV("mMixerFormat:%#x  mMixerInFormat:%#x\n", t->mMixerFormat, t->mMixerInFormat);
        t->prepareForReformat();
        t->prepareForAdjustChannelsNonDestructive(mFrameCount);
        t->prepareForAdjustChannels();

        mTracks[name] = t;
        return OK;
@@ -212,6 +220,9 @@ bool AudioMixer::setChannelMasks(int name,
    // do it after downmix since track format may change!
    track->prepareForReformat();

    track->prepareForAdjustChannelsNonDestructive(mFrameCount);
    track->prepareForAdjustChannels();

    if (track->mResampler.get() != nullptr) {
        // resampler channels may have changed.
        const uint32_t resetToSampleRate = track->sampleRate;
@@ -335,10 +346,82 @@ status_t AudioMixer::Track::prepareForReformat()
    return NO_ERROR;
}

void AudioMixer::Track::unprepareForAdjustChannels()
{
    ALOGV("AUDIOMIXER::unprepareForAdjustChannels");
    if (mAdjustChannelsBufferProvider.get() != nullptr) {
        mAdjustChannelsBufferProvider.reset(nullptr);
        reconfigureBufferProviders();
    }
}

status_t AudioMixer::Track::prepareForAdjustChannels()
{
    ALOGV("AudioMixer::prepareForAdjustChannels(%p) with inChannelCount: %u, outChannelCount: %u",
            this, mAdjustInChannelCount, mAdjustOutChannelCount);
    unprepareForAdjustChannels();
    if (mAdjustInChannelCount != mAdjustOutChannelCount) {
        mAdjustChannelsBufferProvider.reset(new AdjustChannelsBufferProvider(
                mFormat, mAdjustInChannelCount, mAdjustOutChannelCount, kCopyBufferFrameCount));
        reconfigureBufferProviders();
    }
    return NO_ERROR;
}

void AudioMixer::Track::unprepareForAdjustChannelsNonDestructive()
{
    ALOGV("AUDIOMIXER::unprepareForAdjustChannelsNonDestructive");
    if (mAdjustChannelsNonDestructiveBufferProvider.get() != nullptr) {
        mAdjustChannelsNonDestructiveBufferProvider.reset(nullptr);
        reconfigureBufferProviders();
    }
}

status_t AudioMixer::Track::prepareForAdjustChannelsNonDestructive(size_t frames)
{
    ALOGV("AudioMixer::prepareForAdjustChannelsNonDestructive(%p) with inChannelCount: %u, "
          "outChannelCount: %u, keepContractedChannels: %d",
            this, mAdjustNonDestructiveInChannelCount, mAdjustNonDestructiveOutChannelCount,
            mKeepContractedChannels);
    unprepareForAdjustChannelsNonDestructive();
    if (mAdjustNonDestructiveInChannelCount != mAdjustNonDestructiveOutChannelCount) {
        uint8_t* buffer = mKeepContractedChannels
                ? (uint8_t*)mainBuffer + frames * audio_bytes_per_frame(
                        mMixerChannelCount, mMixerFormat)
                : NULL;
        mAdjustChannelsNonDestructiveBufferProvider.reset(
                new AdjustChannelsNonDestructiveBufferProvider(
                        mFormat,
                        mAdjustNonDestructiveInChannelCount,
                        mAdjustNonDestructiveOutChannelCount,
                        mKeepContractedChannels ? mMixerFormat : AUDIO_FORMAT_INVALID,
                        frames,
                        buffer));
        reconfigureBufferProviders();
    }
    return NO_ERROR;
}

void AudioMixer::Track::clearContractedBuffer()
{
    if (mAdjustChannelsNonDestructiveBufferProvider.get() != nullptr) {
        static_cast<AdjustChannelsNonDestructiveBufferProvider*>(
                mAdjustChannelsNonDestructiveBufferProvider.get())->clearContractedFrames();
    }
}

void AudioMixer::Track::reconfigureBufferProviders()
{
    // configure from upstream to downstream buffer providers.
    bufferProvider = mInputBufferProvider;
    if (mAdjustChannelsBufferProvider.get() != nullptr) {
        mAdjustChannelsBufferProvider->setBufferProvider(bufferProvider);
        bufferProvider = mAdjustChannelsBufferProvider.get();
    }
    if (mAdjustChannelsNonDestructiveBufferProvider.get() != nullptr) {
        mAdjustChannelsNonDestructiveBufferProvider->setBufferProvider(bufferProvider);
        bufferProvider = mAdjustChannelsNonDestructiveBufferProvider.get();
    }
    if (mReformatBufferProvider.get() != nullptr) {
        mReformatBufferProvider->setBufferProvider(bufferProvider);
        bufferProvider = mReformatBufferProvider.get();
@@ -542,6 +625,9 @@ void AudioMixer::setParameter(int name, int target, int param, void *value)
            if (track->mainBuffer != valueBuf) {
                track->mainBuffer = valueBuf;
                ALOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf);
                if (track->mKeepContractedChannels) {
                    track->prepareForAdjustChannelsNonDestructive(mFrameCount);
                }
                invalidate();
            }
            break;
@@ -571,6 +657,9 @@ void AudioMixer::setParameter(int name, int target, int param, void *value)
            if (track->mMixerFormat != format) {
                track->mMixerFormat = format;
                ALOGV("setParameter(TRACK, MIXER_FORMAT, %#x)", format);
                if (track->mKeepContractedChannels) {
                    track->prepareForAdjustChannelsNonDestructive(mFrameCount);
                }
            }
            } break;
        case MIXER_CHANNEL_MASK: {
@@ -823,6 +912,10 @@ void AudioMixer::setBufferProvider(int name, AudioBufferProvider* bufferProvider
        track->mDownmixerBufferProvider->reset();
    } else if (track->mReformatBufferProvider.get() != nullptr) {
        track->mReformatBufferProvider->reset();
    } else if (track->mAdjustChannelsNonDestructiveBufferProvider.get() != nullptr) {
        track->mAdjustChannelsNonDestructiveBufferProvider->reset();
    } else if (track->mAdjustChannelsBufferProvider.get() != nullptr) {
        track->mAdjustChannelsBufferProvider->reset();
    }

    track->mInputBufferProvider = bufferProvider;
+79 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

#include <audio_utils/primitives.h>
#include <audio_utils/format.h>
#include <audio_utils/channels.h>
#include <external/sonic/sonic.h>
#include <media/audiohal/EffectBufferHalInterface.h>
#include <media/audiohal/EffectHalInterface.h>
@@ -609,5 +610,83 @@ void TimestretchBufferProvider::processFrames(void *dstBuffer, size_t *dstFrames
        }
    }
}

AdjustChannelsBufferProvider::AdjustChannelsBufferProvider(audio_format_t format,
        size_t inChannelCount, size_t outChannelCount, size_t frameCount) :
        CopyBufferProvider(
                audio_bytes_per_frame(inChannelCount, format),
                audio_bytes_per_frame(outChannelCount, format),
                frameCount),
        mFormat(format),
        mInChannelCount(inChannelCount),
        mOutChannelCount(outChannelCount),
        mSampleSizeInBytes(audio_bytes_per_sample(format))
{
    ALOGV("AdjustBufferProvider(%p)(%#x, %zu, %zu, %zu)",
            this, format, inChannelCount, outChannelCount, frameCount);
}

void AdjustChannelsBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
{
    adjust_channels(src, mInChannelCount, dst, mOutChannelCount, mSampleSizeInBytes,
            frames * mInChannelCount * mSampleSizeInBytes);
}

AdjustChannelsNonDestructiveBufferProvider::AdjustChannelsNonDestructiveBufferProvider(
        audio_format_t format, size_t inChannelCount, size_t outChannelCount,
        audio_format_t contractedFormat, size_t contractedFrameCount, void* contractedBuffer) :
        CopyBufferProvider(
                audio_bytes_per_frame(inChannelCount, format),
                audio_bytes_per_frame(outChannelCount, format),
                0 /*bufferFrameCount*/),
        mFormat(format),
        mInChannelCount(inChannelCount),
        mOutChannelCount(outChannelCount),
        mSampleSizeInBytes(audio_bytes_per_sample(format)),
        mContractedChannelCount(inChannelCount - outChannelCount),
        mContractedFormat(contractedFormat),
        mContractedFrameCount(contractedFrameCount),
        mContractedBuffer(contractedBuffer),
        mContractedWrittenFrames(0)
{
    ALOGV("AdjustChannelsNonDestructiveBufferProvider(%p)(%#x, %zu, %zu, %#x, %p)",
            this, format, inChannelCount, outChannelCount, contractedFormat, contractedBuffer);
    if (mContractedFormat != AUDIO_FORMAT_INVALID && mInChannelCount > mOutChannelCount) {
        mContractedFrameSize = audio_bytes_per_frame(mContractedChannelCount, mContractedFormat);
    }
}

status_t AdjustChannelsNonDestructiveBufferProvider::getNextBuffer(
        AudioBufferProvider::Buffer* pBuffer)
{
    const size_t outFramesLeft = mContractedFrameCount - mContractedWrittenFrames;
    if (outFramesLeft < pBuffer->frameCount) {
        // Restrict the frame count so that we don't write over the size of the output buffer.
        pBuffer->frameCount = outFramesLeft;
    }
    return CopyBufferProvider::getNextBuffer(pBuffer);
}

void AdjustChannelsNonDestructiveBufferProvider::copyFrames(
        void *dst, const void *src, size_t frames)
{
    adjust_channels_non_destructive(src, mInChannelCount, dst, mOutChannelCount, mSampleSizeInBytes,
            frames * mInChannelCount * mSampleSizeInBytes);
    if (mContractedFormat != AUDIO_FORMAT_INVALID && mContractedBuffer != NULL
            && mInChannelCount > mOutChannelCount) {
        const size_t contractedIdx = frames * mOutChannelCount * mSampleSizeInBytes;
        memcpy_by_audio_format(
                (uint8_t*)mContractedBuffer + mContractedWrittenFrames * mContractedFrameSize,
                mContractedFormat, (uint8_t*)dst + contractedIdx, mFormat,
                mContractedChannelCount * frames);
        mContractedWrittenFrames += frames;
    }
}

void AdjustChannelsNonDestructiveBufferProvider::reset()
{
    mContractedWrittenFrames = 0;
    CopyBufferProvider::reset();
}
// ----------------------------------------------------------------------------
} // namespace android
+47 −0
Original line number Diff line number Diff line
@@ -216,6 +216,53 @@ private:
    bool                 mAudioPlaybackRateValid; // flag for current parameters validity
};

// AdjustBufferProvider derives from CopyBufferProvider to adjust sample data.
// Expands or contracts sample data from one interleaved channel format to another.
// Expanded channels are filled with zeros and put at the end of each audio frame.
// Contracted channels are omitted from the end of each audio frame.
class AdjustChannelsBufferProvider : public CopyBufferProvider {
public:
    AdjustChannelsBufferProvider(audio_format_t format, size_t inChannelCount,
            size_t outChannelCount, size_t frameCount);
    //Overrides
    void copyFrames(void *dst, const void *src, size_t frames) override;

protected:
    const audio_format_t mFormat;
    const size_t         mInChannelCount;
    const size_t         mOutChannelCount;
    const size_t         mSampleSizeInBytes;
};

// AdjustChannelsNonDestructiveBufferProvider derives from CopyBufferProvider to adjust sample data.
// Expands or contracts sample data from one interleaved channel format to another.
// Extra expanded channels are interleaved in from the end of the input buffer.
// Contracted channels are copied to the end of the output buffer.
// Contracted channels could be written to output buffer.
class AdjustChannelsNonDestructiveBufferProvider : public CopyBufferProvider {
public:
    AdjustChannelsNonDestructiveBufferProvider(audio_format_t format, size_t inChannelCount,
            size_t outChannelCount, audio_format_t contractedFormat, size_t contractedFrameCount,
            void* contractedBuffer);
    //Overrides
    status_t getNextBuffer(Buffer* pBuffer) override;
    void copyFrames(void *dst, const void *src, size_t frames) override;
    void reset() override;

    void clearContractedFrames() { mContractedWrittenFrames = 0; }

protected:
    const audio_format_t mFormat;
    const size_t         mInChannelCount;
    const size_t         mOutChannelCount;
    const size_t         mSampleSizeInBytes;
    const size_t         mContractedChannelCount;
    const audio_format_t mContractedFormat;
    const size_t         mContractedFrameCount;
    void                *mContractedBuffer;
    size_t               mContractedWrittenFrames;
    size_t               mContractedFrameSize;
};
// ----------------------------------------------------------------------------
} // namespace android